From 992934e00efcec1e17a1f1d984a60f4861de8e20 Mon Sep 17 00:00:00 2001 From: Marc Rousavy Date: Thu, 18 Jan 2024 10:41:26 +0100 Subject: [PATCH] feat: `SharedArray:wrapData:withSize` init for iOS (#2410) * feat: `ArrayBuffer:wrapData:withSize` init for iOS * Format * fix build error * Update ExampleFrameProcessorPlugin.m * docs: Add class docs for SharedArray --- .../camera/frameprocessor/SharedArray.java | 4 +-- package/cpp/MutableRawBuffer.cpp | 10 +++--- package/cpp/MutableRawBuffer.h | 4 +-- .../ExampleFrameProcessorPlugin.m | 2 +- package/example/ios/Podfile.lock | 6 ++-- .../Frame Processor/JSINSObjectConversion.mm | 2 +- package/ios/Frame Processor/SharedArray.h | 32 +++++++++++++++++-- package/ios/Frame Processor/SharedArray.mm | 17 +++++++--- 8 files changed, 56 insertions(+), 21 deletions(-) diff --git a/package/android/src/main/java/com/mrousavy/camera/frameprocessor/SharedArray.java b/package/android/src/main/java/com/mrousavy/camera/frameprocessor/SharedArray.java index 97679d2..505d82b 100644 --- a/package/android/src/main/java/com/mrousavy/camera/frameprocessor/SharedArray.java +++ b/package/android/src/main/java/com/mrousavy/camera/frameprocessor/SharedArray.java @@ -25,7 +25,7 @@ public final class SharedArray { } /** - * Allocate a new SharedArray. Use `getByteBuffer` to obtain a reference to the direct ByteBuffer for writing. + * Allocate a new SharedArray with the given size. Use `getByteBuffer` to obtain a reference to the direct ByteBuffer for writing. * @param proxy The VisionCamera Proxy from the Frame Processor Plugin's initializer. * @param size The size of the ArrayBuffer. */ @@ -34,7 +34,7 @@ public final class SharedArray { } /** - * Wraps the given ByteBuffer in a JSI ArrayBuffer. Using `getByteBuffer` will return the same instance which can be used for writing. + * Wraps the given ByteBuffer in a SharedArray without copying. Using `getByteBuffer` will return the same instance which can be used for writing. * @param proxy The VisionCamera Proxy from the Frame Processor Plugin's initializer. * @param byteBuffer The ByteBuffer to wrap. */ diff --git a/package/cpp/MutableRawBuffer.cpp b/package/cpp/MutableRawBuffer.cpp index 8bdb4b8..fdc7f31 100644 --- a/package/cpp/MutableRawBuffer.cpp +++ b/package/cpp/MutableRawBuffer.cpp @@ -12,17 +12,19 @@ namespace vision { -MutableRawBuffer::MutableRawBuffer(uint8_t* data, size_t size, std::function cleanup) - : _data(data), _size(size), _cleanup(std::move(cleanup)) {} +MutableRawBuffer::MutableRawBuffer(uint8_t* data, size_t size, bool freeOnDealloc) + : _data(data), _size(size), _freeOnDealloc(freeOnDealloc) {} MutableRawBuffer::MutableRawBuffer(size_t size) { _size = size; _data = (uint8_t*)malloc(size * sizeof(uint8_t)); - _cleanup = [=]() { free(_data); }; + _freeOnDealloc = true; } MutableRawBuffer::~MutableRawBuffer() { - _cleanup(); + if (_freeOnDealloc) { + free(_data); + } } size_t MutableRawBuffer::size() const { diff --git a/package/cpp/MutableRawBuffer.h b/package/cpp/MutableRawBuffer.h index 56a8a6d..a6adbf6 100644 --- a/package/cpp/MutableRawBuffer.h +++ b/package/cpp/MutableRawBuffer.h @@ -20,7 +20,7 @@ class MutableRawBuffer : public jsi::MutableBuffer { public: explicit MutableRawBuffer(size_t size); - explicit MutableRawBuffer(uint8_t* data, size_t size, std::function cleanup); + explicit MutableRawBuffer(uint8_t* data, size_t size, bool freeOnDealloc); ~MutableRawBuffer(); public: @@ -30,7 +30,7 @@ public: private: uint8_t* _data; size_t _size; - std::function _cleanup; + bool _freeOnDealloc; }; } // namespace vision 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 f264355..9a66b10 100644 --- a/package/example/ios/Frame Processor Plugins/Example Plugin/ExampleFrameProcessorPlugin.m +++ b/package/example/ios/Frame Processor Plugins/Example Plugin/ExampleFrameProcessorPlugin.m @@ -25,7 +25,7 @@ withOptions:(NSDictionary* _Nullable)options { if (self = [super initWithProxy:proxy withOptions:options]) { _sharedArray = [[SharedArray alloc] initWithProxy:proxy - size:5]; + allocateWithSize:5]; NSLog(@"ExampleFrameProcessorPlugin initialized with options: %@", options); } return self; diff --git a/package/example/ios/Podfile.lock b/package/example/ios/Podfile.lock index c27028b..e4e078b 100644 --- a/package/example/ios/Podfile.lock +++ b/package/example/ios/Podfile.lock @@ -484,7 +484,7 @@ PODS: - libwebp (~> 1.0) - SDWebImage/Core (~> 5.10) - SocketRocket (0.6.1) - - VisionCamera (3.8.0): + - VisionCamera (3.8.1): - React - React-callinvoker - React-Core @@ -724,9 +724,9 @@ SPEC CHECKSUMS: SDWebImage: a7f831e1a65eb5e285e3fb046a23fcfbf08e696d SDWebImageWebPCoder: 908b83b6adda48effe7667cd2b7f78c897e5111d SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17 - VisionCamera: 8e3454abf4baa43a2b9ad9cfc9723d1cc89d9eb6 + VisionCamera: f6ca954813603e753578623fcbb9364d3e08d6ce Yoga: 4c3aa327e4a6a23eeacd71f61c81df1bcdf677d5 PODFILE CHECKSUM: 27f53791141a3303d814e09b55770336416ff4eb -COCOAPODS: 1.11.3 +COCOAPODS: 1.14.3 diff --git a/package/ios/Frame Processor/JSINSObjectConversion.mm b/package/ios/Frame Processor/JSINSObjectConversion.mm index 5d9a291..9ddeb48 100644 --- a/package/ios/Frame Processor/JSINSObjectConversion.mm +++ b/package/ios/Frame Processor/JSINSObjectConversion.mm @@ -170,7 +170,7 @@ id convertJSIValueToObjCObject(jsi::Runtime& runtime, const jsi::Value& value, s } else if (o.isArrayBuffer(runtime)) { // ArrayBuffer auto arrayBuffer = std::make_shared(o.getArrayBuffer(runtime)); - return [[SharedArray alloc] initWithRuntime:runtime arrayBuffer:arrayBuffer]; + return [[SharedArray alloc] initWithRuntime:runtime wrapArrayBuffer:arrayBuffer]; } else { // object return convertJSIObjectToNSDictionary(runtime, o, jsInvoker); diff --git a/package/ios/Frame Processor/SharedArray.h b/package/ios/Frame Processor/SharedArray.h index 0f00ca9..132cb4e 100644 --- a/package/ios/Frame Processor/SharedArray.h +++ b/package/ios/Frame Processor/SharedArray.h @@ -12,25 +12,51 @@ #import #ifdef __cplusplus -#import "../../cpp/MutableRawBuffer.h" #import using namespace facebook; #endif NS_ASSUME_NONNULL_BEGIN +/** + * An ArrayBuffer of type uint8 that can be shared between native and JS without copying. + */ @interface SharedArray : NSObject - (instancetype)init NS_UNAVAILABLE; -- (instancetype)initWithProxy:(VisionCameraProxyHolder*)proxy size:(NSInteger)size; + +/** + * Allocates a new SharedArray with the given size. + * Use `data` to write to the SharedArray. + */ +- (instancetype)initWithProxy:(VisionCameraProxyHolder*)proxy allocateWithSize:(NSInteger)size; + +/** + * Wraps the given data in a SharedArray without copying. + * Use `data` to write to the SharedArray. + */ +- (instancetype)initWithProxy:(VisionCameraProxyHolder*)proxy + wrapData:(uint8_t*)data + withSize:(NSInteger)size + freeOnDealloc:(BOOL)freeOnDealloc; #ifdef __cplusplus -- (instancetype)initWithRuntime:(jsi::Runtime&)runtime arrayBuffer:(std::shared_ptr)arrayBuffer; +/** + * Wraps the given JSI ArrayBuffer in a SharedArray for native access. + * Use `data` to write to the SharedArray. + */ +- (instancetype)initWithRuntime:(jsi::Runtime&)runtime wrapArrayBuffer:(std::shared_ptr)arrayBuffer; - (std::shared_ptr)arrayBuffer; #endif +/** + * The underlying contents of the ArrayBuffer which can be used for reading and writing. + */ @property(nonatomic, readonly, nonnull) uint8_t* data; +/** + * The size of the ArrayBuffer. + */ @property(nonatomic, readonly) NSInteger size; @end diff --git a/package/ios/Frame Processor/SharedArray.mm b/package/ios/Frame Processor/SharedArray.mm index 27c6cbc..ad00d9a 100644 --- a/package/ios/Frame Processor/SharedArray.mm +++ b/package/ios/Frame Processor/SharedArray.mm @@ -7,7 +7,7 @@ // #import "SharedArray.h" -#import "../../cpp/MutableRawBuffer.h" +#import "MutableRawBuffer.h" #import #import @@ -19,12 +19,19 @@ using namespace facebook; std::shared_ptr _arrayBuffer; } -- (instancetype)initWithProxy:(VisionCameraProxyHolder*)proxy size:(NSInteger)size { +- (instancetype)initWithProxy:(VisionCameraProxyHolder*)proxy allocateWithSize:(NSInteger)size { + uint8_t* data = (uint8_t*)malloc(size * sizeof(uint8_t)); + return [self initWithProxy:proxy wrapData:data withSize:size freeOnDealloc:YES]; +} + +- (instancetype)initWithProxy:(VisionCameraProxyHolder*)proxy + wrapData:(uint8_t*)data + withSize:(NSInteger)size + freeOnDealloc:(BOOL)freeOnDealloc { if (self = [super init]) { jsi::Runtime& runtime = proxy.proxy->getWorkletRuntime(); - uint8_t* data = (uint8_t*)malloc(size * sizeof(uint8_t)); - auto mutableBuffer = std::make_shared(data, size, [=]() { free(data); }); + auto mutableBuffer = std::make_shared(data, size, freeOnDealloc); _arrayBuffer = std::make_shared(runtime, mutableBuffer); _data = data; _size = size; @@ -32,7 +39,7 @@ using namespace facebook; return self; } -- (instancetype)initWithRuntime:(jsi::Runtime&)runtime arrayBuffer:(std::shared_ptr)arrayBuffer { +- (instancetype)initWithRuntime:(jsi::Runtime&)runtime wrapArrayBuffer:(std::shared_ptr)arrayBuffer { if (self = [super init]) { _arrayBuffer = arrayBuffer; _data = _arrayBuffer->data(runtime);