Skip to content

Commit

Permalink
Make DrawableFrameHostObject subclass
Browse files Browse the repository at this point in the history
  • Loading branch information
mrousavy committed Jul 19, 2023
1 parent cc0da99 commit 98c804e
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 79 deletions.
13 changes: 0 additions & 13 deletions ios/Frame Processor/FrameHostObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,29 +13,16 @@

#import "Frame.h"

#if VISION_CAMERA_ENABLE_SKIA
#import "SkCanvas.h"
#import "JsiSkCanvas.h"
#endif

using namespace facebook;

class JSI_EXPORT FrameHostObject: public jsi::HostObject {
public:
explicit FrameHostObject(Frame* frame): frame(frame) {}
#if VISION_CAMERA_ENABLE_SKIA
explicit FrameHostObject(Frame* frame,
std::shared_ptr<RNSkia::JsiSkCanvas> canvas):
frame(frame), canvas(canvas) {}
#endif

public:
jsi::Value get(jsi::Runtime&, const jsi::PropNameID& name) override;
std::vector<jsi::PropNameID> getPropertyNames(jsi::Runtime& rt) override;

public:
Frame* frame;
#if VISION_CAMERA_ENABLE_SKIA
std::shared_ptr<RNSkia::JsiSkCanvas> canvas;
#endif
};
61 changes: 0 additions & 61 deletions ios/Frame Processor/FrameHostObject.mm
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,6 @@

#import "../../cpp/JSITypedArray.h"

#if VISION_CAMERA_ENABLE_SKIA
#import "SkCanvas.h"
#import "../Skia Render Layer/SkImageHelpers.h"
#endif

std::vector<jsi::PropNameID> FrameHostObject::getPropertyNames(jsi::Runtime& rt) {
std::vector<jsi::PropNameID> result;
result.push_back(jsi::PropNameID::forUtf8(rt, std::string("width")));
Expand All @@ -34,29 +29,10 @@
result.push_back(jsi::PropNameID::forUtf8(rt, std::string("isValid")));
result.push_back(jsi::PropNameID::forUtf8(rt, std::string("incrementRefCount")));
result.push_back(jsi::PropNameID::forUtf8(rt, std::string("decrementRefCount")));
// Skia
result.push_back(jsi::PropNameID::forUtf8(rt, std::string("render")));

#if VISION_CAMERA_ENABLE_SKIA
if (canvas != nullptr) {
auto canvasPropNames = canvas->getPropertyNames(rt);
for (auto& prop : canvasPropNames) {
result.push_back(std::move(prop));
}
}
#endif

return result;
}

SkRect inscribe(SkSize size, SkRect rect) {
auto halfWidthDelta = (rect.width() - size.width()) / 2.0;
auto halfHeightDelta = (rect.height() - size.height()) / 2.0;
return SkRect::MakeXYWH(rect.x() + halfWidthDelta,
rect.y() + halfHeightDelta, size.width(),
size.height());
}

jsi::Value FrameHostObject::get(jsi::Runtime& runtime, const jsi::PropNameID& propName) {
auto name = propName.utf8(runtime);

Expand Down Expand Up @@ -85,7 +61,6 @@ SkRect inscribe(SkSize size, SkRect rect) {
0,
incrementRefCount);
}

if (name == "decrementRefCount") {
auto decrementRefCount = JSI_HOST_FUNCTION_LAMBDA {
// Decrement retain count by one. If the retain count is zero, ARC will destroy the Frame Buffer.
Expand All @@ -97,35 +72,6 @@ SkRect inscribe(SkSize size, SkRect rect) {
0,
decrementRefCount);
}
if (name == "render") {
auto render = JSI_HOST_FUNCTION_LAMBDA {
#if VISION_CAMERA_ENABLE_SKIA
if (canvas == nullptr) {
throw jsi::JSError(runtime, "Trying to render a Frame without a Skia Canvas! Did you install Skia?");
}

// convert CMSampleBuffer to SkImage
auto context = canvas->getCanvas()->recordingContext();
auto image = SkImageHelpers::convertCMSampleBufferToSkImage(context, frame.buffer);

// draw SkImage
if (count > 0) {
// ..with paint/shader
auto paintHostObject = arguments[0].asObject(runtime).asHostObject<RNSkia::JsiSkPaint>(runtime);
auto paint = paintHostObject->getObject();
canvas->getCanvas()->drawImage(image, 0, 0, SkSamplingOptions(), paint.get());
} else {
// ..without paint/shader
canvas->getCanvas()->drawImage(image, 0, 0);
}

return jsi::Value::undefined();
#else
throw jsi::JSError(runtime, "Failed to render Frame - Skia Integration is not enabled!");
#endif
};
return jsi::Function::createFromHostFunction(runtime, jsi::PropNameID::forUtf8(runtime, "render"), 1, render);
}
if (name == "toArrayBuffer") {
auto toArrayBuffer = JSI_HOST_FUNCTION_LAMBDA {
auto pixelBuffer = CMSampleBufferGetImageBuffer(frame.buffer);
Expand Down Expand Up @@ -215,13 +161,6 @@ SkRect inscribe(SkSize size, SkRect rect) {
return jsi::Value((double) planesCount);
}

#if VISION_CAMERA_ENABLE_SKIA
if (canvas != nullptr) {
// If we have a Canvas, try to access the property on there.
return canvas->get(runtime, propName);
}
#endif

// fallback to base implementation
return HostObject::get(runtime, propName);
}
35 changes: 35 additions & 0 deletions ios/Skia Render Layer/DrawableFrameHostObject.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//
// DrawableFrameHostObject.h
// VisionCamera
//
// Created by Marc Rousavy on 20.07.23.
// Copyright © 2023 mrousavy. All rights reserved.
//

#pragma once

#import <jsi/jsi.h>
#import "../Frame Processor/FrameHostObject.h"
#import "../Frame Processor/Frame.h"
#import <CoreMedia/CMSampleBuffer.h>

#import "SkCanvas.h"
#import "JsiSkCanvas.h"

using namespace facebook;

class JSI_EXPORT DrawableFrameHostObject: public FrameHostObject {
public:
explicit DrawableFrameHostObject(Frame* frame,
std::shared_ptr<RNSkia::JsiSkCanvas> canvas):
FrameHostObject(frame), _canvas(canvas) {}

public:
jsi::Value get(jsi::Runtime&, const jsi::PropNameID& name) override;
std::vector<jsi::PropNameID> getPropertyNames(jsi::Runtime& rt) override;

void invalidateCanvas();

private:
std::shared_ptr<RNSkia::JsiSkCanvas> _canvas;
};
80 changes: 80 additions & 0 deletions ios/Skia Render Layer/DrawableFrameHostObject.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
//
// DrawableFrameHostObject.mm
// VisionCamera
//
// Created by Marc Rousavy on 20.07.23.
// Copyright © 2023 mrousavy. All rights reserved.
//

#import "DrawableFrameHostObject.h"
#import "SkCanvas.h"
#import "SkImageHelpers.h"

std::vector<jsi::PropNameID> DrawableFrameHostObject::getPropertyNames(jsi::Runtime& rt) {
auto result = FrameHostObject::getPropertyNames(rt);

// Skia - Render Frame
result.push_back(jsi::PropNameID::forUtf8(rt, std::string("render")));

if (_canvas != nullptr) {
auto canvasPropNames = _canvas->getPropertyNames(rt);
for (auto& prop : canvasPropNames) {
result.push_back(std::move(prop));
}
}

return result;
}

SkRect inscribe(SkSize size, SkRect rect) {
auto halfWidthDelta = (rect.width() - size.width()) / 2.0;
auto halfHeightDelta = (rect.height() - size.height()) / 2.0;
return SkRect::MakeXYWH(rect.x() + halfWidthDelta,
rect.y() + halfHeightDelta, size.width(),
size.height());
}

jsi::Value DrawableFrameHostObject::get(jsi::Runtime& runtime, const jsi::PropNameID& propName) {
auto name = propName.utf8(runtime);

if (name == "render") {
auto render = JSI_HOST_FUNCTION_LAMBDA {
if (_canvas == nullptr) {
throw jsi::JSError(runtime, "Trying to render a Frame without a Skia Canvas! Did you install Skia?");
}

// convert CMSampleBuffer to SkImage
auto context = _canvas->getCanvas()->recordingContext();
auto image = SkImageHelpers::convertCMSampleBufferToSkImage(context, frame.buffer);

// draw SkImage
if (count > 0) {
// ..with paint/shader
auto paintHostObject = arguments[0].asObject(runtime).asHostObject<RNSkia::JsiSkPaint>(runtime);
auto paint = paintHostObject->getObject();
_canvas->getCanvas()->drawImage(image, 0, 0, SkSamplingOptions(), paint.get());
} else {
// ..without paint/shader
_canvas->getCanvas()->drawImage(image, 0, 0);
}

return jsi::Value::undefined();
};
return jsi::Function::createFromHostFunction(runtime, jsi::PropNameID::forUtf8(runtime, "render"), 1, render);
}

if (_canvas != nullptr) {
// If we have a Canvas, try to access the property on there.
auto result = _canvas->get(runtime, propName);
if (!result.isUndefined()) {
return result;
}
}

// fallback to base implementation
return FrameHostObject::get(runtime, propName);
}

void DrawableFrameHostObject::invalidateCanvas() {
_canvas = nullptr;
}
9 changes: 4 additions & 5 deletions ios/Skia Render Layer/SkiaFrameProcessor.mm
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
#import <memory>

#import <jsi/jsi.h>
#import "../Frame Processor/FrameHostObject.h"
#import "DrawableFrameHostObject.h"

#import <react-native-skia/JsiSkCanvas.h>
#import <react-native-skia/RNSkiOSPlatformContext.h>
Expand Down Expand Up @@ -42,15 +42,14 @@ - (void)call:(Frame*)frame {
[_skiaRenderer renderCameraFrameToOffscreenCanvas:frame.buffer
withDrawCallback:^(SkiaCanvas _Nonnull canvas) {
// Create the Frame Host Object wrapping the internal Frame and Skia Canvas
auto frameHostObject = std::make_shared<FrameHostObject>(frame);
self->_skiaCanvas->setCanvas(static_cast<SkCanvas*>(canvas));
frameHostObject->canvas = self->_skiaCanvas;
auto frameHostObject = std::make_shared<DrawableFrameHostObject>(frame, self->_skiaCanvas);

// Call JS Frame Processor
[self callWithFrameHostObject:frameHostObject];

// Remove Skia Canvas from Host Object (runAsync calls might still be trying to access it)
frameHostObject->canvas = nullptr;
// Remove Skia Canvas from Host Object because it is no longer valid
frameHostObject->invalidateCanvas();
}];
}

Expand Down
4 changes: 4 additions & 0 deletions ios/VisionCamera.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,8 @@
B8DB3BC7263DC28C004C18D7 /* AVAssetWriter.Status+descriptor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AVAssetWriter.Status+descriptor.swift"; sourceTree = "<group>"; };
B8DB3BC9263DC4D8004C18D7 /* RecordingSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecordingSession.swift; sourceTree = "<group>"; };
B8DB3BCB263DC97E004C18D7 /* AVFileType+descriptor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AVFileType+descriptor.swift"; sourceTree = "<group>"; };
B8DFBA362A68A17E00941736 /* DrawableFrameHostObject.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = DrawableFrameHostObject.mm; sourceTree = "<group>"; };
B8DFBA372A68A17E00941736 /* DrawableFrameHostObject.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DrawableFrameHostObject.h; sourceTree = "<group>"; };
B8F0825E2A6046FC00C17EB6 /* FrameProcessor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FrameProcessor.h; sourceTree = "<group>"; };
B8F0825F2A60491900C17EB6 /* FrameProcessor.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = FrameProcessor.mm; sourceTree = "<group>"; };
B8F7DDD1266F715D00120533 /* Frame.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Frame.m; sourceTree = "<group>"; };
Expand Down Expand Up @@ -287,6 +289,8 @@
B89A28742A68795E0092207F /* SkiaRenderer.mm */,
B8127E382A68871C00B06972 /* SkiaPreviewView.swift */,
B865BC5F2A6888DA0093DF1A /* SkiaPreviewDisplayLink.swift */,
B8DFBA372A68A17E00941736 /* DrawableFrameHostObject.h */,
B8DFBA362A68A17E00941736 /* DrawableFrameHostObject.mm */,
);
path = "Skia Render Layer";
sourceTree = "<group>";
Expand Down

0 comments on commit 98c804e

Please sign in to comment.