diff --git a/.github/workflows/build-ios.yml b/.github/workflows/build-ios.yml index d805a5f6ce..93101d808e 100644 --- a/.github/workflows/build-ios.yml +++ b/.github/workflows/build-ios.yml @@ -100,6 +100,8 @@ jobs: run: yarn install --frozen-lockfile --cwd .. - name: Remove worklets, skia and reanimated run: yarn remove react-native-worklets-core @shopify/react-native-skia react-native-reanimated --cwd .. + - name: Remove Example Plugins + run: rm -rf "Frame Processor Plugins/" - name: Restore buildcache uses: mikehardy/buildcache-action@v2 diff --git a/package/VisionCamera.podspec b/package/VisionCamera.podspec index 1cf89644f2..fee1c1fd12 100644 --- a/package/VisionCamera.podspec +++ b/package/VisionCamera.podspec @@ -4,24 +4,33 @@ package = JSON.parse(File.read(File.join(__dir__, "package.json"))) nodeModules = File.join(File.dirname(`cd "#{Pod::Config.instance.installation_root.to_s}" && node --print "require.resolve('react-native/package.json')"`), '..') -enableFrameProcessors = true -if defined?($VCEnableFrameProcessors) - Pod::UI.puts "[VisionCamera] $VCEnableFrameProcessors is set to #{$VCEnableFrameProcessors}!" - enableFrameProcessors = $VCEnableFrameProcessors -end +Pod::UI.puts "[VisionCamera] Thank you for using VisionCamera ❤️" enableLocation = true if defined?($VCEnableLocation) Pod::UI.puts "[VisionCamera] $VCEnableLocation is set to #{$VCEnableLocation}!" enableLocation = $VCEnableLocation else - Pod::UI.puts "[VisionCamera] Building with CLLocation APIs as $VCEnableLocation is not set.." + Pod::UI.puts "[VisionCamera] $VCEnableLocation is not set, enabling CLLocation APIs by default..." +end + +enableFrameProcessors = true +if defined?($VCEnableFrameProcessors) + Pod::UI.puts "[VisionCamera] $VCEnableFrameProcessors is set to #{$VCEnableFrameProcessors}!" + enableFrameProcessors = $VCEnableFrameProcessors +else + Pod::UI.puts "[VisionCamera] $VCEnableFrameProcessors is not set, enabling Frame Processors if Worklets is installed..." end Pod::UI.puts("[VisionCamera] node modules #{Dir.exist?(nodeModules) ? "found at #{nodeModules}" : "not found!"}") workletsPath = File.join(nodeModules, "react-native-worklets-core") -hasWorklets = File.exist?(workletsPath) && enableFrameProcessors -Pod::UI.puts("[VisionCamera] react-native-worklets-core #{hasWorklets ? "found" : "not found"}, Frame Processors #{hasWorklets ? "enabled" : "disabled"}!") +hasWorklets = File.exist?(workletsPath) +if hasWorklets + Pod::UI.puts("[VisionCamera] react-native-worklets-core found, Frame Processors #{enableFrameProcessors ? "enabled" : "disabled"}!") +else + Pod::UI.puts("[VisionCamera] react-native-worklets-core not found - Frame Processors are #{hasWorklets ? "enabled" : "disabled"}!") + enableFrameProcessors = false +end Pod::Spec.new do |s| s.name = "VisionCamera" @@ -36,49 +45,63 @@ Pod::Spec.new do |s| s.source = { :git => "https://github.com/mrousavy/react-native-vision-camera.git", :tag => "#{s.version}" } s.pod_target_xcconfig = { - "GCC_PREPROCESSOR_DEFINITIONS" => "$(inherited) VISION_CAMERA_ENABLE_FRAME_PROCESSORS=#{hasWorklets}", - "SWIFT_ACTIVE_COMPILATION_CONDITIONS" => "$(inherited) #{hasWorklets ? "VISION_CAMERA_ENABLE_FRAME_PROCESSORS" : ""} #{enableLocation ? "VISION_CAMERA_ENABLE_LOCATION" : ""}", - "CLANG_CXX_LANGUAGE_STANDARD" => "c++17", - "HEADER_SEARCH_PATHS" => "\"$(PODS_TARGET_SRCROOT)/cpp/\"/** " + "GCC_PREPROCESSOR_DEFINITIONS" => "$(inherited) VISION_CAMERA_ENABLE_FRAME_PROCESSORS=#{enableFrameProcessors}", + "SWIFT_ACTIVE_COMPILATION_CONDITIONS" => "$(inherited) #{enableFrameProcessors ? "VISION_CAMERA_ENABLE_FRAME_PROCESSORS" : ""}", } s.requires_arc = true - # All source files that should be publicly visible - # Note how this does not include headers, since those can nameclash. - s.source_files = [ - # Core - "ios/*.{m,mm,swift}", - "ios/Core/*.{m,mm,swift}", - "ios/Extensions/*.{m,mm,swift}", - "ios/Parsers/*.{m,mm,swift}", - "ios/React Utils/*.{m,mm,swift}", - "ios/Types/*.{m,mm,swift}", - "ios/CameraBridge.h", - - # Frame Processors - hasWorklets ? "ios/Frame Processor/*.{m,mm,swift}" : "", - hasWorklets ? "ios/Frame Processor/Frame.h" : "", - hasWorklets ? "ios/Frame Processor/FrameProcessor.h" : "", - hasWorklets ? "ios/Frame Processor/FrameProcessorPlugin.h" : "", - hasWorklets ? "ios/Frame Processor/FrameProcessorPluginRegistry.h" : "", - hasWorklets ? "ios/Frame Processor/SharedArray.h" : "", - hasWorklets ? "ios/Frame Processor/VisionCameraProxy.h" : "", - hasWorklets ? "cpp/**/*.{cpp}" : "", - ] - # Any private headers that are not globally unique should be mentioned here. - # Otherwise there will be a nameclash, since CocoaPods flattens out any header directories - # See https://github.com/firebase/firebase-ios-sdk/issues/4035 for more details. - s.preserve_paths = [ - "cpp/**/*.h", - "ios/**/*.h" - ] - - s.dependency "React" s.dependency "React-Core" - s.dependency "React-callinvoker" - if hasWorklets - s.dependency "react-native-worklets-core" + s.subspec 'Core' do |core| + # VisionCamera Core Swift codebase + core.source_files = [ + "ios/*.{m,mm,swift}", + "ios/Core/*.{m,mm,swift}", + "ios/Extensions/*.{m,mm,swift}", + "ios/Parsers/*.{m,mm,swift}", + "ios/React Utils/*.{m,mm,swift}", + "ios/Types/*.{m,mm,swift}", + "ios/CameraBridge.h", + ] + + core.pod_target_xcconfig = { + "SWIFT_ACTIVE_COMPILATION_CONDITIONS" => "$(inherited) #{enableLocation ? "VISION_CAMERA_ENABLE_LOCATION" : ""}", + } + + if enableFrameProcessors + core.dependency "VisionCamera/FrameProcessors" + end + end + + if enableFrameProcessors + s.subspec 'FrameProcessors' do |fp| + # VisionCamera Frame Processors C++ codebase (optional) + fp.dependency "React" + fp.dependency "React-callinvoker" + fp.dependency "react-native-worklets-core" + + fp.source_files = [ + # C++ sources + "ios/Frame Processor/*.{h,m,mm,cpp}", + "cpp/**/*.{h,cpp}", + ] + fp.public_header_files = [ + # Swift/Objective-C visible headers + "ios/Frame Processor/Frame.h", + "ios/Frame Processor/FrameProcessor.h", + "ios/Frame Processor/FrameProcessorPlugin.h", + "ios/Frame Processor/FrameProcessorPluginRegistry.h", + "ios/Frame Processor/SharedArray.h", + "ios/Frame Processor/VisionCameraProxyDelegate.h", + "ios/Frame Processor/VisionCameraProxyHolder.h", + "ios/Frame Processor/VisionCameraInstaller.h", + ] + + fp.pod_target_xcconfig = { + "CLANG_CXX_LANGUAGE_STANDARD" => "c++17", + "HEADER_SEARCH_PATHS" => "$(inherited) \"$(PODS_TARGET_SRCROOT)/cpp/\"/** " + } + end end end diff --git a/package/example/ios/Frame Processor Plugins/Example Plugin/ExampleFrameProcessorPlugin.m b/package/example/ios/Frame Processor Plugins/Example Plugin/ExampleFrameProcessorPlugin.m index 9a66b1035c..9233113d09 100644 --- a/package/example/ios/Frame Processor Plugins/Example Plugin/ExampleFrameProcessorPlugin.m +++ b/package/example/ios/Frame Processor Plugins/Example Plugin/ExampleFrameProcessorPlugin.m @@ -8,7 +8,6 @@ #if __has_include() #import #import -#import #import #import diff --git a/package/example/ios/Podfile.lock b/package/example/ios/Podfile.lock index ffe725686e..140b4de631 100644 --- a/package/example/ios/Podfile.lock +++ b/package/example/ios/Podfile.lock @@ -467,7 +467,14 @@ PODS: - RCT-Folly (= 2021.07.22.00) - React-Core - SocketRocket (0.6.1) - - VisionCamera (4.0.0-beta.15): + - VisionCamera (4.0.0-beta.16): + - React-Core + - VisionCamera/Core (= 4.0.0-beta.16) + - VisionCamera/FrameProcessors (= 4.0.0-beta.16) + - VisionCamera/Core (4.0.0-beta.16): + - React-Core + - VisionCamera/FrameProcessors + - VisionCamera/FrameProcessors (4.0.0-beta.16): - React - React-callinvoker - React-Core @@ -701,9 +708,9 @@ SPEC CHECKSUMS: RNStaticSafeAreaInsets: 055ddbf5e476321720457cdaeec0ff2ba40ec1b8 RNVectorIcons: 23b6e11af4aaf104d169b1b0afa7e5cf96c676ce SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17 - VisionCamera: e31119ce6f25cf982100e62db2846bee6653f52b + VisionCamera: 129f7e33050d9f45660e4510565ebbd1a0c15126 Yoga: 4c3aa327e4a6a23eeacd71f61c81df1bcdf677d5 -PODFILE CHECKSUM: 299b350392623e1b01615935e236438d90fd2cff +PODFILE CHECKSUM: 29d07573cd9f2aa1ecf53c481819da07fd66822e -COCOAPODS: 1.11.3 +COCOAPODS: 1.14.3 diff --git a/package/ios/CameraBridge.h b/package/ios/CameraBridge.h index 17a10b7623..ae02876246 100644 --- a/package/ios/CameraBridge.h +++ b/package/ios/CameraBridge.h @@ -12,13 +12,16 @@ #import #import -#import #import #import #if VISION_CAMERA_ENABLE_FRAME_PROCESSORS #import "Frame.h" #import "FrameProcessor.h" +#import "FrameProcessorPlugin.h" +#import "FrameProcessorPluginRegistry.h" #import "SharedArray.h" -#import "VisionCameraProxy.h" +#import "VisionCameraInstaller.h" +#import "VisionCameraProxyDelegate.h" +#import "VisionCameraProxyHolder.h" #endif diff --git a/package/ios/CameraViewManager+VisionCameraProxyDelegate.swift b/package/ios/CameraViewManager+VisionCameraProxyDelegate.swift new file mode 100644 index 0000000000..d2eb45e5fc --- /dev/null +++ b/package/ios/CameraViewManager+VisionCameraProxyDelegate.swift @@ -0,0 +1,36 @@ +// +// CameraViewManager+VisionCameraProxyDelegate.swift +// VisionCamera +// +// Created by Marc Rousavy on 20.04.24. +// + +import Foundation + +#if VISION_CAMERA_ENABLE_FRAME_PROCESSORS + + extension CameraViewManager: VisionCameraProxyDelegate { + func getDispatchQueue() -> DispatchQueue { + return CameraQueues.videoQueue + } + + func getBridge() -> RCTBridge { + return bridge + } + + func setFrameProcessor(_ frameProcessor: FrameProcessor, forView viewTag: NSNumber) { + DispatchQueue.main.async { + let view = self.getCameraView(withTag: viewTag) + view.frameProcessor = frameProcessor + } + } + + func removeFrameProcessor(forView viewTag: NSNumber) { + DispatchQueue.main.async { + let view = self.getCameraView(withTag: viewTag) + view.frameProcessor = nil + } + } + } + +#endif diff --git a/package/ios/CameraViewManager.swift b/package/ios/CameraViewManager.swift index 6a3704ff88..f7bd9e8d0e 100644 --- a/package/ios/CameraViewManager.swift +++ b/package/ios/CameraViewManager.swift @@ -32,7 +32,7 @@ final class CameraViewManager: RCTViewManager { final func installFrameProcessorBindings() -> NSNumber { #if VISION_CAMERA_ENABLE_FRAME_PROCESSORS // Called on JS Thread (blocking sync method) - let result = VisionCameraInstaller.install(to: bridge) + let result = VisionCameraInstaller.install(with: self) return NSNumber(value: result) #else return false as NSNumber @@ -148,7 +148,7 @@ final class CameraViewManager: RCTViewManager { // MARK: Private - private func getCameraView(withTag tag: NSNumber) -> CameraView { + func getCameraView(withTag tag: NSNumber) -> CameraView { // swiftlint:disable force_cast return bridge.uiManager.view(forReactTag: tag) as! CameraView // swiftlint:enable force_cast diff --git a/package/ios/Core/LocationProvider.swift b/package/ios/Core/LocationProvider.swift index a3c1968736..e84fb9bd88 100644 --- a/package/ios/Core/LocationProvider.swift +++ b/package/ios/Core/LocationProvider.swift @@ -23,11 +23,15 @@ class LocationProvider { } private var authorizationStatus: CLAuthorizationStatus { - if #available(iOS 14.0, *) { - return locationManager.authorizationStatus - } else { - return CLLocationManager.authorizationStatus() - } + #if VISION_CAMERA_ENABLE_LOCATION + if #available(iOS 14.0, *) { + return locationManager.authorizationStatus + } else { + return CLLocationManager.authorizationStatus() + } + #else + return .restricted + #endif } var hasPermission: Bool { diff --git a/package/ios/Frame Processor/FrameProcessorPlugin.h b/package/ios/Frame Processor/FrameProcessorPlugin.h index 06834451d1..4fe0ee4802 100644 --- a/package/ios/Frame Processor/FrameProcessorPlugin.h +++ b/package/ios/Frame Processor/FrameProcessorPlugin.h @@ -9,7 +9,8 @@ #pragma once #import "Frame.h" -#import "VisionCameraProxy.h" +#import "FrameProcessorPluginRegistry.h" +#import "VisionCameraProxyHolder.h" #import NS_ASSUME_NONNULL_BEGIN diff --git a/package/ios/Frame Processor/FrameProcessorPluginRegistry.h b/package/ios/Frame Processor/FrameProcessorPluginRegistry.h index 9b766b2e56..f3990bb035 100644 --- a/package/ios/Frame Processor/FrameProcessorPluginRegistry.h +++ b/package/ios/Frame Processor/FrameProcessorPluginRegistry.h @@ -10,11 +10,14 @@ #import "Frame.h" #import "FrameProcessorPlugin.h" -#import "VisionCameraProxy.h" +#import "VisionCameraProxyHolder.h" #import NS_ASSUME_NONNULL_BEGIN +// forward-declare the Plugin - caller should always include anyways. +@class FrameProcessorPlugin; + @interface FrameProcessorPluginRegistry : NSObject typedef FrameProcessorPlugin* _Nonnull (^PluginInitializerFunction)(VisionCameraProxyHolder* proxy, NSDictionary* _Nullable options); diff --git a/package/ios/Frame Processor/JSINSObjectConversion.mm b/package/ios/Frame Processor/JSINSObjectConversion.mm index 9ddeb4891e..222d8155dd 100644 --- a/package/ios/Frame Processor/JSINSObjectConversion.mm +++ b/package/ios/Frame Processor/JSINSObjectConversion.mm @@ -16,9 +16,9 @@ // #import "JSINSObjectConversion.h" -#import "../Frame Processor/Frame.h" -#import "../Frame Processor/FrameHostObject.h" -#import "../Frame Processor/SharedArray.h" +#import "Frame.h" +#import "FrameHostObject.h" +#import "SharedArray.h" #import #import #import diff --git a/package/ios/Frame Processor/SharedArray.h b/package/ios/Frame Processor/SharedArray.h index 132cb4effb..44d6992966 100644 --- a/package/ios/Frame Processor/SharedArray.h +++ b/package/ios/Frame Processor/SharedArray.h @@ -8,7 +8,7 @@ #pragma once -#import "VisionCameraProxy.h" +#import "VisionCameraProxyHolder.h" #import #ifdef __cplusplus diff --git a/package/ios/Frame Processor/VisionCameraInstaller.h b/package/ios/Frame Processor/VisionCameraInstaller.h new file mode 100644 index 0000000000..b6c02cd79e --- /dev/null +++ b/package/ios/Frame Processor/VisionCameraInstaller.h @@ -0,0 +1,23 @@ +// +// VisionCameraInstaller.h +// Pods +// +// Created by Marc Rousavy on 20.04.24. +// + +#pragma once + +#import "VisionCameraProxyDelegate.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + A static class to install/inject the VisionCameraProxy into the global JS runtime. + */ +@interface VisionCameraInstaller : NSObject + ++ (BOOL)installWithDelegate:(id)delegate; + +@end + +NS_ASSUME_NONNULL_END diff --git a/package/ios/Frame Processor/VisionCameraInstaller.mm b/package/ios/Frame Processor/VisionCameraInstaller.mm new file mode 100644 index 0000000000..f27c043fc6 --- /dev/null +++ b/package/ios/Frame Processor/VisionCameraInstaller.mm @@ -0,0 +1,35 @@ +// +// VisionCameraInstaller.mm +// DoubleConversion +// +// Created by Marc Rousavy on 20.04.24. +// + +#import "VisionCameraInstaller.h" +#import "VisionCameraProxy.h" +#import + +#import +#import +#import + +@implementation VisionCameraInstaller + ++ (BOOL)installWithDelegate:(id)delegate { + // TODO: Migrate away from RCTBridge to support new arch. + RCTBridge* bridge = delegate.getBridge; + RCTCxxBridge* cxxBridge = (RCTCxxBridge*)bridge; + if (!cxxBridge.runtime) { + return NO; + } + + jsi::Runtime& runtime = *(jsi::Runtime*)cxxBridge.runtime; + + // global.VisionCameraProxy + auto visionCameraProxy = std::make_shared(runtime, bridge.jsCallInvoker, delegate); + runtime.global().setProperty(runtime, "VisionCameraProxy", jsi::Object::createFromHostObject(runtime, visionCameraProxy)); + + return YES; +} + +@end diff --git a/package/ios/Frame Processor/VisionCameraProxy.h b/package/ios/Frame Processor/VisionCameraProxy.h index 08a5c1139a..fbadd52d39 100644 --- a/package/ios/Frame Processor/VisionCameraProxy.h +++ b/package/ios/Frame Processor/VisionCameraProxy.h @@ -8,10 +8,13 @@ #pragma once +#ifndef __cplusplus +#error VisionCameraProxy.h has to be compiled with C++! +#endif + #import -#import -#ifdef __cplusplus +#import "VisionCameraProxyDelegate.h" #import "WKTJsiWorkletContext.h" #import #import @@ -20,7 +23,8 @@ using namespace facebook; class VisionCameraProxy : public jsi::HostObject { public: - explicit VisionCameraProxy(jsi::Runtime& runtime, std::shared_ptr callInvoker); + explicit VisionCameraProxy(jsi::Runtime& runtime, std::shared_ptr callInvoker, + id delegate); ~VisionCameraProxy(); public: @@ -32,32 +36,12 @@ class VisionCameraProxy : public jsi::HostObject { } private: - void setFrameProcessor(jsi::Runtime& runtime, int viewTag, const std::shared_ptr& frameProcessor); - void removeFrameProcessor(jsi::Runtime& runtime, int viewTag); - jsi::Value initFrameProcessorPlugin(jsi::Runtime& runtime, std::string name, const jsi::Object& options); + void setFrameProcessor(jsi::Runtime& runtime, double viewTag, jsi::Function&& frameProcessor); + void removeFrameProcessor(jsi::Runtime& runtime, double viewTag); + jsi::Value initFrameProcessorPlugin(jsi::Runtime& runtime, const jsi::String& name, const jsi::Object& options); private: std::shared_ptr _workletContext; std::shared_ptr _callInvoker; + id _delegate; }; -#endif - -NS_ASSUME_NONNULL_BEGIN - -@interface VisionCameraProxyHolder : NSObject - -- (_Nonnull instancetype)initWithProxy:(void*)proxy; - -#ifdef __cplusplus -- (VisionCameraProxy*)proxy; -#endif - -@end - -@interface VisionCameraInstaller : NSObject - -+ (BOOL)installToBridge:(RCTBridge*)bridge; - -@end - -NS_ASSUME_NONNULL_END diff --git a/package/ios/Frame Processor/VisionCameraProxy.mm b/package/ios/Frame Processor/VisionCameraProxy.mm index 310c2ca08b..378ba3e65e 100644 --- a/package/ios/Frame Processor/VisionCameraProxy.mm +++ b/package/ios/Frame Processor/VisionCameraProxy.mm @@ -10,43 +10,28 @@ #import #import -#import "FrameHostObject.h" #import "FrameProcessor.h" #import "FrameProcessorPluginHostObject.h" #import "FrameProcessorPluginRegistry.h" #import "JSINSObjectConversion.h" +#import "VisionCameraProxyHolder.h" #import "WKTJsiWorklet.h" -#import -#import -#import -#import -#import - -// Swift forward-declarations -__attribute__((objc_runtime_name("_TtC12VisionCamera12CameraQueues"))) -@interface CameraQueues : NSObject -@property(nonatomic, class, readonly, strong) dispatch_queue_t _Nonnull videoQueue; -@end - -__attribute__((objc_runtime_name("_TtC12VisionCamera10CameraView"))) -@interface CameraView : UIView -@property(nonatomic, copy) FrameProcessor* _Nullable frameProcessor; -@end - using namespace facebook; -VisionCameraProxy::VisionCameraProxy(jsi::Runtime& runtime, std::shared_ptr callInvoker) { +VisionCameraProxy::VisionCameraProxy(jsi::Runtime& runtime, std::shared_ptr callInvoker, + id delegate) { _callInvoker = callInvoker; + _delegate = delegate; NSLog(@"VisionCameraProxy: Creating Worklet Context..."); auto runOnJS = [callInvoker](std::function&& f) { // Run on React JS Runtime callInvoker->invokeAsync(std::move(f)); }; - auto runOnWorklet = [](std::function&& f) { + auto runOnWorklet = [delegate](std::function&& f) { // Run on Frame Processor Worklet Runtime - dispatch_async(CameraQueues.videoQueue, [f = std::move(f)]() { f(); }); + dispatch_async(delegate.getDispatchQueue, [f = std::move(f)]() { f(); }); }; _workletContext = std::make_shared("VisionCamera", &runtime, runOnJS, runOnWorklet); @@ -66,29 +51,24 @@ @interface CameraView : UIView return result; } -void VisionCameraProxy::setFrameProcessor(jsi::Runtime& runtime, int viewTag, const std::shared_ptr& function) { - auto worklet = std::make_shared(runtime, function); - FrameProcessor* frameProcessor = [[FrameProcessor alloc] initWithWorklet:worklet context:_workletContext]; +void VisionCameraProxy::setFrameProcessor(jsi::Runtime& runtime, double jsViewTag, jsi::Function&& function) { + auto sharedFunction = std::make_shared(std::move(function)); + auto worklet = std::make_shared(runtime, sharedFunction); - RCTExecuteOnMainQueue(^{ - auto currentBridge = [RCTBridge currentBridge]; - auto anonymousView = [currentBridge.uiManager viewForReactTag:[NSNumber numberWithDouble:viewTag]]; - auto view = static_cast(anonymousView); - view.frameProcessor = frameProcessor; - }); + // Call Swift delegate to set the Frame Processor (maybe on UI Thread) + FrameProcessor* frameProcessor = [[FrameProcessor alloc] initWithWorklet:worklet context:_workletContext]; + NSNumber* viewTag = [NSNumber numberWithDouble:jsViewTag]; + [_delegate setFrameProcessor:frameProcessor forView:viewTag]; } -void VisionCameraProxy::removeFrameProcessor(jsi::Runtime& runtime, int viewTag) { - RCTExecuteOnMainQueue(^{ - auto currentBridge = [RCTBridge currentBridge]; - auto anonymousView = [currentBridge.uiManager viewForReactTag:[NSNumber numberWithDouble:viewTag]]; - auto view = static_cast(anonymousView); - view.frameProcessor = nil; - }); +void VisionCameraProxy::removeFrameProcessor(jsi::Runtime& runtime, double jsViewTag) { + NSNumber* viewTag = [NSNumber numberWithDouble:jsViewTag]; + [_delegate removeFrameProcessorForView:viewTag]; } -jsi::Value VisionCameraProxy::initFrameProcessorPlugin(jsi::Runtime& runtime, std::string name, const jsi::Object& options) { - NSString* key = [NSString stringWithUTF8String:name.c_str()]; +jsi::Value VisionCameraProxy::initFrameProcessorPlugin(jsi::Runtime& runtime, const jsi::String& name, const jsi::Object& options) { + std::string nameString = name.utf8(runtime); + NSString* key = [NSString stringWithUTF8String:nameString.c_str()]; NSDictionary* optionsObjc = JSINSObjectConversion::convertJSIObjectToNSDictionary(runtime, options, _callInvoker); VisionCameraProxyHolder* proxy = [[VisionCameraProxyHolder alloc] initWithProxy:this]; @@ -114,18 +94,22 @@ @interface CameraView : UIView return jsi::Function::createFromHostFunction( runtime, jsi::PropNameID::forUtf8(runtime, "setFrameProcessor"), 1, [this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments, size_t count) -> jsi::Value { - auto viewTag = arguments[0].asNumber(); - auto frameProcessor = arguments[1].asObject(runtime).asFunction(runtime); - auto sharedFunction = std::make_shared(std::move(frameProcessor)); - this->setFrameProcessor(runtime, static_cast(viewTag), sharedFunction); + if (count != 2) { + throw jsi::JSError(runtime, "setFrameProcessor expected 2 arguments, but received " + std::to_string(count)); + } + auto jsViewTag = arguments[0].asNumber(); + auto jsWorklet = arguments[1].asObject(runtime).asFunction(runtime); + setFrameProcessor(runtime, jsViewTag, std::move(jsWorklet)); + return jsi::Value::undefined(); }); } else if (name == "removeFrameProcessor") { return jsi::Function::createFromHostFunction( runtime, jsi::PropNameID::forUtf8(runtime, "removeFrameProcessor"), 1, [this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments, size_t count) -> jsi::Value { - auto viewTag = arguments[0].asNumber(); - this->removeFrameProcessor(runtime, static_cast(viewTag)); + auto jsViewTag = arguments[0].asNumber(); + removeFrameProcessor(runtime, jsViewTag); + return jsi::Value::undefined(); }); } else if (name == "initFrameProcessorPlugin") { @@ -135,7 +119,7 @@ @interface CameraView : UIView if (count < 1 || !arguments[0].isString()) { throw jsi::JSError(runtime, "First argument needs to be a string (pluginName)!"); } - auto pluginName = arguments[0].asString(runtime).utf8(runtime); + auto pluginName = arguments[0].asString(runtime); auto options = count > 1 ? arguments[1].asObject(runtime) : jsi::Object(runtime); return this->initFrameProcessorPlugin(runtime, pluginName, options); @@ -146,39 +130,3 @@ @interface CameraView : UIView return jsi::Value::undefined(); } - -@implementation VisionCameraProxyHolder { - VisionCameraProxy* _proxy; -} - -- (instancetype)initWithProxy:(void*)proxy { - if (self = [super init]) { - _proxy = (VisionCameraProxy*)proxy; - } - return self; -} - -- (VisionCameraProxy*)proxy { - return _proxy; -} - -@end - -@implementation VisionCameraInstaller - -+ (BOOL)installToBridge:(RCTBridge* _Nonnull)bridge { - RCTCxxBridge* cxxBridge = (RCTCxxBridge*)[RCTBridge currentBridge]; - if (!cxxBridge.runtime) { - return NO; - } - - jsi::Runtime& runtime = *(jsi::Runtime*)cxxBridge.runtime; - - // global.VisionCameraProxy - auto visionCameraProxy = std::make_shared(runtime, bridge.jsCallInvoker); - runtime.global().setProperty(runtime, "VisionCameraProxy", jsi::Object::createFromHostObject(runtime, visionCameraProxy)); - - return YES; -} - -@end diff --git a/package/ios/Frame Processor/VisionCameraProxyDelegate.h b/package/ios/Frame Processor/VisionCameraProxyDelegate.h new file mode 100644 index 0000000000..b5ded8b16f --- /dev/null +++ b/package/ios/Frame Processor/VisionCameraProxyDelegate.h @@ -0,0 +1,29 @@ +// +// VisionCameraProxyDelegate.h +// Pods +// +// Created by Marc Rousavy on 20.04.24. +// + +#pragma once + +#import "FrameProcessor.h" +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + A delegate to implement which will be used by the VisionCameraProxy. + */ +@protocol VisionCameraProxyDelegate + +- (void)setFrameProcessor:(FrameProcessor*)frameProcessor forView:(NSNumber*)viewTag; +- (void)removeFrameProcessorForView:(NSNumber*)viewTag; + +- (dispatch_queue_t)getDispatchQueue; +- (RCTBridge*)getBridge; + +@end + +NS_ASSUME_NONNULL_END diff --git a/package/ios/Frame Processor/VisionCameraProxyHolder.h b/package/ios/Frame Processor/VisionCameraProxyHolder.h new file mode 100644 index 0000000000..4c0b8c95df --- /dev/null +++ b/package/ios/Frame Processor/VisionCameraProxyHolder.h @@ -0,0 +1,32 @@ +// +// VisionCameraProxyHolder.h +// Pods +// +// Created by Marc Rousavy on 20.04.24. +// + +#pragma once + +#import "FrameProcessor.h" +#import + +#ifdef __cplusplus +#import "VisionCameraProxy.h" +#endif + +NS_ASSUME_NONNULL_BEGIN + +/** + An Objective-C/Swift class that holds the C++ VisionCameraProxy. + */ +@interface VisionCameraProxyHolder : NSObject + +- (_Nonnull instancetype)initWithProxy:(void*)proxy; + +#ifdef __cplusplus +- (VisionCameraProxy*)proxy; +#endif + +@end + +NS_ASSUME_NONNULL_END diff --git a/package/ios/Frame Processor/VisionCameraProxyHolder.mm b/package/ios/Frame Processor/VisionCameraProxyHolder.mm new file mode 100644 index 0000000000..3fd753b594 --- /dev/null +++ b/package/ios/Frame Processor/VisionCameraProxyHolder.mm @@ -0,0 +1,27 @@ +// +// VisionCameraProxyHolder.mm +// DoubleConversion +// +// Created by Marc Rousavy on 20.04.24. +// + +#import "VisionCameraProxyHolder.h" +#import "VisionCameraProxy.h" +#import + +@implementation VisionCameraProxyHolder { + VisionCameraProxy* _proxy; +} + +- (instancetype)initWithProxy:(void*)proxy { + if (self = [super init]) { + _proxy = (VisionCameraProxy*)proxy; + } + return self; +} + +- (VisionCameraProxy*)proxy { + return _proxy; +} + +@end