From 3dc75112ae79b8e0ab0f4849bbe5e64c02470daa Mon Sep 17 00:00:00 2001 From: Marc Rousavy Date: Tue, 2 Jan 2024 13:54:07 +0100 Subject: [PATCH] fix: Fix crash when trying to `console.log(frame)` (#2335) * feat: Override `toJSON` to support `console.log(frame)` * Update FrameHostObject.mm * Also use on Android * Update FrameHostObject.mm --- .../cpp/frameprocessor/FrameHostObject.cpp | 40 ++++++++++-------- .../camera/core/CameraConfiguration.kt | 25 +++++++---- .../ios/Frame Processor/FrameHostObject.mm | 41 ++++++++++--------- 3 files changed, 62 insertions(+), 44 deletions(-) diff --git a/package/android/src/main/cpp/frameprocessor/FrameHostObject.cpp b/package/android/src/main/cpp/frameprocessor/FrameHostObject.cpp index 9a2ed04..2bd2f2f 100644 --- a/package/android/src/main/cpp/frameprocessor/FrameHostObject.cpp +++ b/package/android/src/main/cpp/frameprocessor/FrameHostObject.cpp @@ -31,30 +31,36 @@ FrameHostObject::~FrameHostObject() { std::vector FrameHostObject::getPropertyNames(jsi::Runtime& rt) { std::vector result; - result.push_back(jsi::PropNameID::forUtf8(rt, std::string("width"))); - result.push_back(jsi::PropNameID::forUtf8(rt, std::string("height"))); - result.push_back(jsi::PropNameID::forUtf8(rt, std::string("bytesPerRow"))); - result.push_back(jsi::PropNameID::forUtf8(rt, std::string("planesCount"))); - result.push_back(jsi::PropNameID::forUtf8(rt, std::string("orientation"))); - result.push_back(jsi::PropNameID::forUtf8(rt, std::string("isMirrored"))); - result.push_back(jsi::PropNameID::forUtf8(rt, std::string("timestamp"))); - result.push_back(jsi::PropNameID::forUtf8(rt, std::string("pixelFormat"))); - // Conversion - result.push_back(jsi::PropNameID::forUtf8(rt, std::string("toString"))); - result.push_back(jsi::PropNameID::forUtf8(rt, std::string("toArrayBuffer"))); // Ref Management 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"))); + + if (frame != nullptr && frame->getIsValid()) { + // Frame Properties + result.push_back(jsi::PropNameID::forUtf8(rt, std::string("width"))); + result.push_back(jsi::PropNameID::forUtf8(rt, std::string("height"))); + result.push_back(jsi::PropNameID::forUtf8(rt, std::string("bytesPerRow"))); + result.push_back(jsi::PropNameID::forUtf8(rt, std::string("planesCount"))); + result.push_back(jsi::PropNameID::forUtf8(rt, std::string("orientation"))); + result.push_back(jsi::PropNameID::forUtf8(rt, std::string("isMirrored"))); + result.push_back(jsi::PropNameID::forUtf8(rt, std::string("timestamp"))); + result.push_back(jsi::PropNameID::forUtf8(rt, std::string("pixelFormat"))); + // Conversion + result.push_back(jsi::PropNameID::forUtf8(rt, std::string("toString"))); + result.push_back(jsi::PropNameID::forUtf8(rt, std::string("toArrayBuffer"))); + } + return result; } +#define JSI_FUNC [=](jsi::Runtime & runtime, const jsi::Value& thisValue, const jsi::Value* arguments, size_t count) -> jsi::Value + jsi::Value FrameHostObject::get(jsi::Runtime& runtime, const jsi::PropNameID& propName) { auto name = propName.utf8(runtime); if (name == "incrementRefCount") { - jsi::HostFunctionType incrementRefCount = [=](jsi::Runtime& runtime, const jsi::Value& thisArg, const jsi::Value* args, - size_t count) -> jsi::Value { + jsi::HostFunctionType incrementRefCount = JSI_FUNC { // Increment retain count by one. this->frame->incrementRefCount(); return jsi::Value::undefined(); @@ -62,7 +68,7 @@ jsi::Value FrameHostObject::get(jsi::Runtime& runtime, const jsi::PropNameID& pr return jsi::Function::createFromHostFunction(runtime, jsi::PropNameID::forUtf8(runtime, "incrementRefCount"), 0, incrementRefCount); } if (name == "decrementRefCount") { - auto decrementRefCount = [=](jsi::Runtime& runtime, const jsi::Value& thisArg, const jsi::Value* args, size_t count) -> jsi::Value { + auto decrementRefCount = JSI_FUNC { // Decrement retain count by one. If the retain count is zero, the Frame gets closed. this->frame->decrementRefCount(); return jsi::Value::undefined(); @@ -70,8 +76,7 @@ jsi::Value FrameHostObject::get(jsi::Runtime& runtime, const jsi::PropNameID& pr return jsi::Function::createFromHostFunction(runtime, jsi::PropNameID::forUtf8(runtime, "decrementRefCount"), 0, decrementRefCount); } if (name == "toString") { - jsi::HostFunctionType toString = [=](jsi::Runtime& runtime, const jsi::Value& thisArg, const jsi::Value* args, - size_t count) -> jsi::Value { + jsi::HostFunctionType toString = JSI_FUNC { if (!this->frame) { return jsi::String::createFromUtf8(runtime, "[closed frame]"); } @@ -85,8 +90,7 @@ jsi::Value FrameHostObject::get(jsi::Runtime& runtime, const jsi::PropNameID& pr return jsi::Function::createFromHostFunction(runtime, jsi::PropNameID::forUtf8(runtime, "toString"), 0, toString); } if (name == "toArrayBuffer") { - jsi::HostFunctionType toArrayBuffer = [=](jsi::Runtime& runtime, const jsi::Value& thisArg, const jsi::Value* args, - size_t count) -> jsi::Value { + jsi::HostFunctionType toArrayBuffer = JSI_FUNC { #if __ANDROID_API__ >= 26 AHardwareBuffer* hardwareBuffer = this->frame->getHardwareBuffer(); diff --git a/package/android/src/main/java/com/mrousavy/camera/core/CameraConfiguration.kt b/package/android/src/main/java/com/mrousavy/camera/core/CameraConfiguration.kt index 3504f25..ae75ece 100644 --- a/package/android/src/main/java/com/mrousavy/camera/core/CameraConfiguration.kt +++ b/package/android/src/main/java/com/mrousavy/camera/core/CameraConfiguration.kt @@ -90,14 +90,25 @@ data class CameraConfiguration( fun difference(left: CameraConfiguration?, right: CameraConfiguration): Difference { val deviceChanged = left?.cameraId != right.cameraId - val outputsChanged = deviceChanged || // input device - left?.photo != right.photo || left.video != right.video || left.codeScanner != right.codeScanner || - left.preview != right.preview || // outputs - left.videoHdr != right.videoHdr || left.photoHdr != right.photoHdr || left.format != right.format // props that affect the outputs + val outputsChanged = deviceChanged || + // input device + left?.photo != right.photo || + left.video != right.video || + left.codeScanner != right.codeScanner || + left.preview != right.preview || + // outputs + left.videoHdr != right.videoHdr || + left.photoHdr != right.photoHdr || + left.format != right.format // props that affect the outputs - val sidePropsChanged = outputsChanged || // depend on outputs - left?.torch != right.torch || left.enableLowLightBoost != right.enableLowLightBoost || left.fps != right.fps || - left.zoom != right.zoom || left.videoStabilizationMode != right.videoStabilizationMode || left.isActive != right.isActive || + val sidePropsChanged = outputsChanged || + // depend on outputs + left?.torch != right.torch || + left.enableLowLightBoost != right.enableLowLightBoost || + left.fps != right.fps || + left.zoom != right.zoom || + left.videoStabilizationMode != right.videoStabilizationMode || + left.isActive != right.isActive || left.exposure != right.exposure val isActiveChanged = left?.isActive != right.isActive diff --git a/package/ios/Frame Processor/FrameHostObject.mm b/package/ios/Frame Processor/FrameHostObject.mm index 776be3a..54a2bbc 100644 --- a/package/ios/Frame Processor/FrameHostObject.mm +++ b/package/ios/Frame Processor/FrameHostObject.mm @@ -16,28 +16,32 @@ std::vector FrameHostObject::getPropertyNames(jsi::Runtime& rt) { std::vector result; - result.push_back(jsi::PropNameID::forUtf8(rt, std::string("width"))); - result.push_back(jsi::PropNameID::forUtf8(rt, std::string("height"))); - result.push_back(jsi::PropNameID::forUtf8(rt, std::string("bytesPerRow"))); - result.push_back(jsi::PropNameID::forUtf8(rt, std::string("planesCount"))); - result.push_back(jsi::PropNameID::forUtf8(rt, std::string("orientation"))); - result.push_back(jsi::PropNameID::forUtf8(rt, std::string("isMirrored"))); - result.push_back(jsi::PropNameID::forUtf8(rt, std::string("timestamp"))); - result.push_back(jsi::PropNameID::forUtf8(rt, std::string("pixelFormat"))); - // Conversion - result.push_back(jsi::PropNameID::forUtf8(rt, std::string("toString"))); - result.push_back(jsi::PropNameID::forUtf8(rt, std::string("toArrayBuffer"))); // Ref Management 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"))); + if (frame != nil && frame.isValid) { + // Frame Properties + result.push_back(jsi::PropNameID::forUtf8(rt, std::string("width"))); + result.push_back(jsi::PropNameID::forUtf8(rt, std::string("height"))); + result.push_back(jsi::PropNameID::forUtf8(rt, std::string("bytesPerRow"))); + result.push_back(jsi::PropNameID::forUtf8(rt, std::string("planesCount"))); + result.push_back(jsi::PropNameID::forUtf8(rt, std::string("orientation"))); + result.push_back(jsi::PropNameID::forUtf8(rt, std::string("isMirrored"))); + result.push_back(jsi::PropNameID::forUtf8(rt, std::string("timestamp"))); + result.push_back(jsi::PropNameID::forUtf8(rt, std::string("pixelFormat"))); + // Conversion + result.push_back(jsi::PropNameID::forUtf8(rt, std::string("toString"))); + result.push_back(jsi::PropNameID::forUtf8(rt, std::string("toArrayBuffer"))); + } + return result; } Frame* FrameHostObject::getFrame() { Frame* frame = this->frame; - if (frame == nil || !CMSampleBufferIsValid(frame.buffer)) { + if (frame == nil || !frame.isValid) { throw std::runtime_error("Frame is already closed! " "Are you trying to access the Image data outside of a Frame Processor's lifetime?\n" "- If you want to use `console.log(frame)`, use `console.log(frame.toString())` instead.\n" @@ -47,11 +51,13 @@ Frame* FrameHostObject::getFrame() { return frame; } +#define JSI_FUNC [=](jsi::Runtime & runtime, const jsi::Value& thisValue, const jsi::Value* arguments, size_t count) -> jsi::Value + jsi::Value FrameHostObject::get(jsi::Runtime& runtime, const jsi::PropNameID& propName) { auto name = propName.utf8(runtime); if (name == "toString") { - auto toString = [this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments, size_t count) -> jsi::Value { + auto toString = JSI_FUNC { // Lock Frame so it cannot be deallocated while we access it std::lock_guard lock(this->_mutex); @@ -63,8 +69,7 @@ jsi::Value FrameHostObject::get(jsi::Runtime& runtime, const jsi::PropNameID& pr return jsi::Function::createFromHostFunction(runtime, jsi::PropNameID::forUtf8(runtime, "toString"), 0, toString); } if (name == "incrementRefCount") { - auto incrementRefCount = [this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments, - size_t count) -> jsi::Value { + auto incrementRefCount = JSI_FUNC { // Lock Frame so it cannot be deallocated while we access it std::lock_guard lock(this->_mutex); @@ -75,8 +80,7 @@ jsi::Value FrameHostObject::get(jsi::Runtime& runtime, const jsi::PropNameID& pr return jsi::Function::createFromHostFunction(runtime, jsi::PropNameID::forUtf8(runtime, "incrementRefCount"), 0, incrementRefCount); } if (name == "decrementRefCount") { - auto decrementRefCount = [this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments, - size_t count) -> jsi::Value { + auto decrementRefCount = JSI_FUNC { // Lock Frame so it cannot be deallocated while we access it std::lock_guard lock(this->_mutex); @@ -92,8 +96,7 @@ jsi::Value FrameHostObject::get(jsi::Runtime& runtime, const jsi::PropNameID& pr return jsi::Function::createFromHostFunction(runtime, jsi::PropNameID::forUtf8(runtime, "decrementRefCount"), 0, decrementRefCount); } if (name == "toArrayBuffer") { - auto toArrayBuffer = [this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments, - size_t count) -> jsi::Value { + auto toArrayBuffer = JSI_FUNC { // Lock Frame so it cannot be deallocated while we access it std::lock_guard lock(this->_mutex);