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
This commit is contained in:
Marc Rousavy 2024-01-02 13:54:07 +01:00 committed by GitHub
parent 5486be7506
commit 3dc75112ae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 62 additions and 44 deletions

View File

@ -31,30 +31,36 @@ FrameHostObject::~FrameHostObject() {
std::vector<jsi::PropNameID> FrameHostObject::getPropertyNames(jsi::Runtime& rt) { std::vector<jsi::PropNameID> FrameHostObject::getPropertyNames(jsi::Runtime& rt) {
std::vector<jsi::PropNameID> result; std::vector<jsi::PropNameID> 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 // Ref Management
result.push_back(jsi::PropNameID::forUtf8(rt, std::string("isValid"))); 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("incrementRefCount")));
result.push_back(jsi::PropNameID::forUtf8(rt, std::string("decrementRefCount"))); 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; 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) { jsi::Value FrameHostObject::get(jsi::Runtime& runtime, const jsi::PropNameID& propName) {
auto name = propName.utf8(runtime); auto name = propName.utf8(runtime);
if (name == "incrementRefCount") { if (name == "incrementRefCount") {
jsi::HostFunctionType incrementRefCount = [=](jsi::Runtime& runtime, const jsi::Value& thisArg, const jsi::Value* args, jsi::HostFunctionType incrementRefCount = JSI_FUNC {
size_t count) -> jsi::Value {
// Increment retain count by one. // Increment retain count by one.
this->frame->incrementRefCount(); this->frame->incrementRefCount();
return jsi::Value::undefined(); 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); return jsi::Function::createFromHostFunction(runtime, jsi::PropNameID::forUtf8(runtime, "incrementRefCount"), 0, incrementRefCount);
} }
if (name == "decrementRefCount") { 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. // Decrement retain count by one. If the retain count is zero, the Frame gets closed.
this->frame->decrementRefCount(); this->frame->decrementRefCount();
return jsi::Value::undefined(); 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); return jsi::Function::createFromHostFunction(runtime, jsi::PropNameID::forUtf8(runtime, "decrementRefCount"), 0, decrementRefCount);
} }
if (name == "toString") { if (name == "toString") {
jsi::HostFunctionType toString = [=](jsi::Runtime& runtime, const jsi::Value& thisArg, const jsi::Value* args, jsi::HostFunctionType toString = JSI_FUNC {
size_t count) -> jsi::Value {
if (!this->frame) { if (!this->frame) {
return jsi::String::createFromUtf8(runtime, "[closed 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); return jsi::Function::createFromHostFunction(runtime, jsi::PropNameID::forUtf8(runtime, "toString"), 0, toString);
} }
if (name == "toArrayBuffer") { if (name == "toArrayBuffer") {
jsi::HostFunctionType toArrayBuffer = [=](jsi::Runtime& runtime, const jsi::Value& thisArg, const jsi::Value* args, jsi::HostFunctionType toArrayBuffer = JSI_FUNC {
size_t count) -> jsi::Value {
#if __ANDROID_API__ >= 26 #if __ANDROID_API__ >= 26
AHardwareBuffer* hardwareBuffer = this->frame->getHardwareBuffer(); AHardwareBuffer* hardwareBuffer = this->frame->getHardwareBuffer();

View File

@ -90,14 +90,25 @@ data class CameraConfiguration(
fun difference(left: CameraConfiguration?, right: CameraConfiguration): Difference { fun difference(left: CameraConfiguration?, right: CameraConfiguration): Difference {
val deviceChanged = left?.cameraId != right.cameraId val deviceChanged = left?.cameraId != right.cameraId
val outputsChanged = deviceChanged || // input device val outputsChanged = deviceChanged ||
left?.photo != right.photo || left.video != right.video || left.codeScanner != right.codeScanner || // input device
left.preview != right.preview || // outputs left?.photo != right.photo ||
left.videoHdr != right.videoHdr || left.photoHdr != right.photoHdr || left.format != right.format // props that affect the outputs 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 val sidePropsChanged = outputsChanged ||
left?.torch != right.torch || left.enableLowLightBoost != right.enableLowLightBoost || left.fps != right.fps || // depend on outputs
left.zoom != right.zoom || left.videoStabilizationMode != right.videoStabilizationMode || left.isActive != right.isActive || 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 left.exposure != right.exposure
val isActiveChanged = left?.isActive != right.isActive val isActiveChanged = left?.isActive != right.isActive

View File

@ -16,28 +16,32 @@
std::vector<jsi::PropNameID> FrameHostObject::getPropertyNames(jsi::Runtime& rt) { std::vector<jsi::PropNameID> FrameHostObject::getPropertyNames(jsi::Runtime& rt) {
std::vector<jsi::PropNameID> result; std::vector<jsi::PropNameID> 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 // Ref Management
result.push_back(jsi::PropNameID::forUtf8(rt, std::string("isValid"))); 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("incrementRefCount")));
result.push_back(jsi::PropNameID::forUtf8(rt, std::string("decrementRefCount"))); 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; return result;
} }
Frame* FrameHostObject::getFrame() { Frame* FrameHostObject::getFrame() {
Frame* frame = this->frame; Frame* frame = this->frame;
if (frame == nil || !CMSampleBufferIsValid(frame.buffer)) { if (frame == nil || !frame.isValid) {
throw std::runtime_error("Frame is already closed! " throw std::runtime_error("Frame is already closed! "
"Are you trying to access the Image data outside of a Frame Processor's lifetime?\n" "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" "- If you want to use `console.log(frame)`, use `console.log(frame.toString())` instead.\n"
@ -47,11 +51,13 @@ Frame* FrameHostObject::getFrame() {
return frame; 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) { jsi::Value FrameHostObject::get(jsi::Runtime& runtime, const jsi::PropNameID& propName) {
auto name = propName.utf8(runtime); auto name = propName.utf8(runtime);
if (name == "toString") { 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 // Lock Frame so it cannot be deallocated while we access it
std::lock_guard lock(this->_mutex); 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); return jsi::Function::createFromHostFunction(runtime, jsi::PropNameID::forUtf8(runtime, "toString"), 0, toString);
} }
if (name == "incrementRefCount") { if (name == "incrementRefCount") {
auto incrementRefCount = [this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments, auto incrementRefCount = JSI_FUNC {
size_t count) -> jsi::Value {
// Lock Frame so it cannot be deallocated while we access it // Lock Frame so it cannot be deallocated while we access it
std::lock_guard lock(this->_mutex); 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); return jsi::Function::createFromHostFunction(runtime, jsi::PropNameID::forUtf8(runtime, "incrementRefCount"), 0, incrementRefCount);
} }
if (name == "decrementRefCount") { if (name == "decrementRefCount") {
auto decrementRefCount = [this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments, auto decrementRefCount = JSI_FUNC {
size_t count) -> jsi::Value {
// Lock Frame so it cannot be deallocated while we access it // Lock Frame so it cannot be deallocated while we access it
std::lock_guard lock(this->_mutex); 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); return jsi::Function::createFromHostFunction(runtime, jsi::PropNameID::forUtf8(runtime, "decrementRefCount"), 0, decrementRefCount);
} }
if (name == "toArrayBuffer") { if (name == "toArrayBuffer") {
auto toArrayBuffer = [this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments, auto toArrayBuffer = JSI_FUNC {
size_t count) -> jsi::Value {
// Lock Frame so it cannot be deallocated while we access it // Lock Frame so it cannot be deallocated while we access it
std::lock_guard lock(this->_mutex); std::lock_guard lock(this->_mutex);