| 
									
										
										
										
											2023-07-21 17:52:30 +02:00
										 |  |  | // | 
					
						
							|  |  |  | //  VisionCameraProxy.mm | 
					
						
							|  |  |  | //  VisionCamera | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | //  Created by Marc Rousavy on 20.07.23. | 
					
						
							|  |  |  | //  Copyright © 2023 mrousavy. All rights reserved. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #import "VisionCameraProxy.h" | 
					
						
							|  |  |  | #import <Foundation/Foundation.h> | 
					
						
							|  |  |  | #import <jsi/jsi.h> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #import "FrameHostObject.h" | 
					
						
							| 
									
										
										
										
											2023-09-01 12:58:32 +02:00
										 |  |  | #import "FrameProcessor.h" | 
					
						
							|  |  |  | #import "FrameProcessorPluginHostObject.h" | 
					
						
							|  |  |  | #import "FrameProcessorPluginRegistry.h" | 
					
						
							| 
									
										
										
										
											2023-07-21 17:52:30 +02:00
										 |  |  | #import "JSINSObjectConversion.h" | 
					
						
							|  |  |  | #import "WKTJsiWorklet.h" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #import <React/RCTBridge+Private.h> | 
					
						
							| 
									
										
										
										
											2023-09-01 12:58:32 +02:00
										 |  |  | #import <React/RCTBridge.h> | 
					
						
							| 
									
										
										
										
											2023-07-21 17:52:30 +02:00
										 |  |  | #import <React/RCTUIManager.h> | 
					
						
							| 
									
										
										
										
											2023-09-01 12:58:32 +02:00
										 |  |  | #import <React/RCTUtils.h> | 
					
						
							| 
									
										
										
										
											2023-07-21 17:52:30 +02:00
										 |  |  | #import <ReactCommon/RCTTurboModuleManager.h> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Swift forward-declarations | 
					
						
							|  |  |  | __attribute__((objc_runtime_name("_TtC12VisionCamera12CameraQueues"))) | 
					
						
							| 
									
										
										
										
											2023-09-01 12:58:32 +02:00
										 |  |  | @interface CameraQueues : NSObject | 
					
						
							|  |  |  | @property(nonatomic, class, readonly, strong) dispatch_queue_t _Nonnull videoQueue; | 
					
						
							| 
									
										
										
										
											2023-07-21 17:52:30 +02:00
										 |  |  | @end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | __attribute__((objc_runtime_name("_TtC12VisionCamera10CameraView"))) | 
					
						
							| 
									
										
										
										
											2023-09-01 12:58:32 +02:00
										 |  |  | @interface CameraView : UIView | 
					
						
							|  |  |  | @property(nonatomic, copy) FrameProcessor* _Nullable frameProcessor; | 
					
						
							| 
									
										
										
										
											2023-07-21 17:52:30 +02:00
										 |  |  | @end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | using namespace facebook; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-01 19:39:25 +02:00
										 |  |  | VisionCameraProxy::VisionCameraProxy(jsi::Runtime& runtime, std::shared_ptr<react::CallInvoker> callInvoker) { | 
					
						
							| 
									
										
										
										
											2023-07-21 17:52:30 +02:00
										 |  |  |   _callInvoker = callInvoker; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   NSLog(@"VisionCameraProxy: Creating Worklet Context..."); | 
					
						
							|  |  |  |   auto runOnJS = [callInvoker](std::function<void()>&& f) { | 
					
						
							|  |  |  |     // Run on React JS Runtime | 
					
						
							|  |  |  |     callInvoker->invokeAsync(std::move(f)); | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  |   auto runOnWorklet = [](std::function<void()>&& f) { | 
					
						
							|  |  |  |     // Run on Frame Processor Worklet Runtime | 
					
						
							| 
									
										
										
										
											2023-09-01 12:58:32 +02:00
										 |  |  |     dispatch_async(CameraQueues.videoQueue, [f = std::move(f)]() { f(); }); | 
					
						
							| 
									
										
										
										
											2023-07-21 17:52:30 +02:00
										 |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-01 19:39:25 +02:00
										 |  |  |   _workletContext = std::make_shared<RNWorklet::JsiWorkletContext>("VisionCamera", &runtime, runOnJS, runOnWorklet); | 
					
						
							| 
									
										
										
										
											2023-07-21 17:52:30 +02:00
										 |  |  |   NSLog(@"VisionCameraProxy: Worklet Context Created!"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | VisionCameraProxy::~VisionCameraProxy() { | 
					
						
							| 
									
										
										
										
											2024-01-17 20:18:46 +01:00
										 |  |  |   NSLog(@"VisionCameraProxy: Destroying VisionCameraProxy..."); | 
					
						
							| 
									
										
										
										
											2023-07-21 17:52:30 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | std::vector<jsi::PropNameID> VisionCameraProxy::getPropertyNames(jsi::Runtime& runtime) { | 
					
						
							|  |  |  |   std::vector<jsi::PropNameID> result; | 
					
						
							|  |  |  |   result.push_back(jsi::PropNameID::forUtf8(runtime, std::string("setFrameProcessor"))); | 
					
						
							|  |  |  |   result.push_back(jsi::PropNameID::forUtf8(runtime, std::string("removeFrameProcessor"))); | 
					
						
							| 
									
										
										
										
											2023-10-19 11:19:47 +02:00
										 |  |  |   result.push_back(jsi::PropNameID::forUtf8(runtime, std::string("initFrameProcessorPlugin"))); | 
					
						
							| 
									
										
										
										
											2023-07-21 17:52:30 +02:00
										 |  |  |   return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-01 19:39:25 +02:00
										 |  |  | void VisionCameraProxy::setFrameProcessor(jsi::Runtime& runtime, int viewTag, const jsi::Object& object) { | 
					
						
							| 
									
										
										
										
											2023-07-21 17:52:30 +02:00
										 |  |  |   auto frameProcessorType = object.getProperty(runtime, "type").asString(runtime).utf8(runtime); | 
					
						
							| 
									
										
										
										
											2023-09-01 19:39:25 +02:00
										 |  |  |   auto worklet = std::make_shared<RNWorklet::JsiWorklet>(runtime, object.getProperty(runtime, "frameProcessor")); | 
					
						
							| 
									
										
										
										
											2023-07-21 17:52:30 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   RCTExecuteOnMainQueue(^{ | 
					
						
							|  |  |  |     auto currentBridge = [RCTBridge currentBridge]; | 
					
						
							| 
									
										
										
										
											2023-09-01 19:39:25 +02:00
										 |  |  |     auto anonymousView = [currentBridge.uiManager viewForReactTag:[NSNumber numberWithDouble:viewTag]]; | 
					
						
							| 
									
										
										
										
											2023-07-21 17:52:30 +02:00
										 |  |  |     auto view = static_cast<CameraView*>(anonymousView); | 
					
						
							|  |  |  |     if (frameProcessorType == "frame-processor") { | 
					
						
							| 
									
										
										
										
											2023-09-01 19:39:25 +02:00
										 |  |  |       view.frameProcessor = [[FrameProcessor alloc] initWithWorklet:worklet context:_workletContext]; | 
					
						
							| 
									
										
										
										
											2023-07-21 17:52:30 +02:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2023-09-01 19:39:25 +02:00
										 |  |  |       throw std::runtime_error("Unknown FrameProcessor.type passed! Received: " + frameProcessorType); | 
					
						
							| 
									
										
										
										
											2023-07-21 17:52:30 +02:00
										 |  |  |     } | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void VisionCameraProxy::removeFrameProcessor(jsi::Runtime& runtime, int viewTag) { | 
					
						
							|  |  |  |   RCTExecuteOnMainQueue(^{ | 
					
						
							|  |  |  |     auto currentBridge = [RCTBridge currentBridge]; | 
					
						
							| 
									
										
										
										
											2023-09-01 19:39:25 +02:00
										 |  |  |     auto anonymousView = [currentBridge.uiManager viewForReactTag:[NSNumber numberWithDouble:viewTag]]; | 
					
						
							| 
									
										
										
										
											2023-07-21 17:52:30 +02:00
										 |  |  |     auto view = static_cast<CameraView*>(anonymousView); | 
					
						
							|  |  |  |     view.frameProcessor = nil; | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-19 11:19:47 +02:00
										 |  |  | jsi::Value VisionCameraProxy::initFrameProcessorPlugin(jsi::Runtime& runtime, std::string name, const jsi::Object& options) { | 
					
						
							| 
									
										
										
										
											2023-07-21 17:52:30 +02:00
										 |  |  |   NSString* key = [NSString stringWithUTF8String:name.c_str()]; | 
					
						
							| 
									
										
										
										
											2023-09-01 19:39:25 +02:00
										 |  |  |   NSDictionary* optionsObjc = JSINSObjectConversion::convertJSIObjectToNSDictionary(runtime, options, _callInvoker); | 
					
						
							| 
									
										
										
										
											2024-01-12 16:00:36 +01:00
										 |  |  |   VisionCameraProxyHolder* proxy = [[VisionCameraProxyHolder alloc] initWithProxy:this]; | 
					
						
							|  |  |  |   FrameProcessorPlugin* plugin = [FrameProcessorPluginRegistry getPlugin:key withProxy:proxy withOptions:optionsObjc]; | 
					
						
							| 
									
										
										
										
											2023-07-21 17:52:30 +02:00
										 |  |  |   if (plugin == nil) { | 
					
						
							|  |  |  |     return jsi::Value::undefined(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   auto pluginHostObject = std::make_shared<FrameProcessorPluginHostObject>(plugin, _callInvoker); | 
					
						
							|  |  |  |   return jsi::Object::createFromHostObject(runtime, pluginHostObject); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | jsi::Value VisionCameraProxy::get(jsi::Runtime& runtime, const jsi::PropNameID& propName) { | 
					
						
							|  |  |  |   auto name = propName.utf8(runtime); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (name == "setFrameProcessor") { | 
					
						
							| 
									
										
										
										
											2023-09-01 12:58:32 +02:00
										 |  |  |     return jsi::Function::createFromHostFunction( | 
					
						
							|  |  |  |         runtime, jsi::PropNameID::forUtf8(runtime, "setFrameProcessor"), 1, | 
					
						
							| 
									
										
										
										
											2023-09-01 19:39:25 +02:00
										 |  |  |         [this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments, size_t count) -> jsi::Value { | 
					
						
							| 
									
										
										
										
											2023-09-01 12:58:32 +02:00
										 |  |  |           auto viewTag = arguments[0].asNumber(); | 
					
						
							|  |  |  |           auto object = arguments[1].asObject(runtime); | 
					
						
							|  |  |  |           this->setFrameProcessor(runtime, static_cast<int>(viewTag), object); | 
					
						
							|  |  |  |           return jsi::Value::undefined(); | 
					
						
							|  |  |  |         }); | 
					
						
							| 
									
										
										
										
											2023-07-21 17:52:30 +02:00
										 |  |  |   } | 
					
						
							|  |  |  |   if (name == "removeFrameProcessor") { | 
					
						
							| 
									
										
										
										
											2023-09-01 12:58:32 +02:00
										 |  |  |     return jsi::Function::createFromHostFunction( | 
					
						
							|  |  |  |         runtime, jsi::PropNameID::forUtf8(runtime, "removeFrameProcessor"), 1, | 
					
						
							| 
									
										
										
										
											2023-09-01 19:39:25 +02:00
										 |  |  |         [this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments, size_t count) -> jsi::Value { | 
					
						
							| 
									
										
										
										
											2023-09-01 12:58:32 +02:00
										 |  |  |           auto viewTag = arguments[0].asNumber(); | 
					
						
							|  |  |  |           this->removeFrameProcessor(runtime, static_cast<int>(viewTag)); | 
					
						
							|  |  |  |           return jsi::Value::undefined(); | 
					
						
							|  |  |  |         }); | 
					
						
							| 
									
										
										
										
											2023-07-21 17:52:30 +02:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2023-10-19 11:19:47 +02:00
										 |  |  |   if (name == "initFrameProcessorPlugin") { | 
					
						
							| 
									
										
										
										
											2023-09-01 12:58:32 +02:00
										 |  |  |     return jsi::Function::createFromHostFunction( | 
					
						
							| 
									
										
										
										
											2023-10-19 11:19:47 +02:00
										 |  |  |         runtime, jsi::PropNameID::forUtf8(runtime, "initFrameProcessorPlugin"), 1, | 
					
						
							| 
									
										
										
										
											2023-09-01 19:39:25 +02:00
										 |  |  |         [this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments, size_t count) -> jsi::Value { | 
					
						
							| 
									
										
										
										
											2023-09-01 12:58:32 +02:00
										 |  |  |           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 options = count > 1 ? arguments[1].asObject(runtime) : jsi::Object(runtime); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-19 11:19:47 +02:00
										 |  |  |           return this->initFrameProcessorPlugin(runtime, pluginName, options); | 
					
						
							| 
									
										
										
										
											2023-09-01 12:58:32 +02:00
										 |  |  |         }); | 
					
						
							| 
									
										
										
										
											2023-07-21 17:52:30 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return jsi::Value::undefined(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-12 16:00:36 +01:00
										 |  |  | @implementation VisionCameraProxyHolder { | 
					
						
							|  |  |  |   VisionCameraProxy* _proxy; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (instancetype)initWithProxy:(void*)proxy { | 
					
						
							|  |  |  |   if (self = [super init]) { | 
					
						
							|  |  |  |     _proxy = (VisionCameraProxy*)proxy; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return self; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (VisionCameraProxy*)proxy { | 
					
						
							|  |  |  |   return _proxy; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-21 17:52:30 +02:00
										 |  |  | @implementation VisionCameraInstaller | 
					
						
							| 
									
										
										
										
											2024-01-12 16:00:36 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-21 17:52:30 +02:00
										 |  |  | + (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<VisionCameraProxy>(runtime, bridge.jsCallInvoker); | 
					
						
							| 
									
										
										
										
											2023-09-01 19:39:25 +02:00
										 |  |  |   runtime.global().setProperty(runtime, "VisionCameraProxy", jsi::Object::createFromHostObject(runtime, visionCameraProxy)); | 
					
						
							| 
									
										
										
										
											2023-07-21 17:52:30 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   return YES; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2024-01-12 16:00:36 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-21 17:52:30 +02:00
										 |  |  | @end |