feat: Sync Frame Processors (plus runAsync and runAtTargetFps) (#1472)

Before, Frame Processors ran on a separate Thread.

After, Frame Processors run fully synchronous and always at the same FPS as the Camera.

Two new functions have been introduced:

* `runAtTargetFps(fps: number, func: () => void)`: Runs the given code as often as the given `fps`, effectively throttling it's calls.
* `runAsync(frame: Frame, func: () => void)`: Runs the given function on a separate Thread for Frame Processing. A strong reference to the Frame is held as long as the function takes to execute.

You can use `runAtTargetFps` to throttle calls to a specific API (e.g. if your Camera is running at 60 FPS, but you only want to run face detection at ~25 FPS, use `runAtTargetFps(25, ...)`.)

You can use `runAsync` to run a heavy algorithm asynchronous, so that the Camera is not blocked while your algorithm runs. This is useful if your main sync processor draws something, and your async processor is doing some image analysis on the side. 

You can also combine both functions.

Examples:

```js
const frameProcessor = useFrameProcessor((frame) => {
  'worklet'
  console.log("I'm running at 60 FPS!")
}, [])
```

```js
const frameProcessor = useFrameProcessor((frame) => {
  'worklet'
  console.log("I'm running at 60 FPS!")

  runAtTargetFps(10, () => {
    'worklet'
    console.log("I'm running at 10 FPS!")
  })
}, [])
```



```js
const frameProcessor = useFrameProcessor((frame) => {
  'worklet'
  console.log("I'm running at 60 FPS!")

  runAsync(frame, () => {
    'worklet'
    console.log("I'm running on another Thread, I can block for longer!")
  })
}, [])
```

```js
const frameProcessor = useFrameProcessor((frame) => {
  'worklet'
  console.log("I'm running at 60 FPS!")

  runAtTargetFps(10, () => {
    'worklet'
    runAsync(frame, () => {
      'worklet'
      console.log("I'm running on another Thread at 10 FPS, I can block for longer!")
    })
  })
}, [])
```
This commit is contained in:
Marc Rousavy 2023-02-15 16:47:09 +01:00 committed by GitHub
parent a0590dccb5
commit 30b56153db
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 660 additions and 914 deletions

View File

@ -8,12 +8,13 @@
#include <jni.h>
#include <vector>
#include <string>
#include <JsiHostObject.h>
namespace vision {
using namespace facebook;
FrameHostObject::FrameHostObject(jni::alias_ref<JImageProxy::javaobject> image): frame(make_global(image)) { }
FrameHostObject::FrameHostObject(jni::alias_ref<JImageProxy::javaobject> image): frame(make_global(image)), _refCount(0) { }
FrameHostObject::~FrameHostObject() {
// Hermes' Garbage Collector (Hades GC) calls destructors on a separate Thread
@ -25,21 +26,24 @@ FrameHostObject::~FrameHostObject() {
std::vector<jsi::PropNameID> FrameHostObject::getPropertyNames(jsi::Runtime& rt) {
std::vector<jsi::PropNameID> result;
result.push_back(jsi::PropNameID::forUtf8(rt, std::string("toString")));
result.push_back(jsi::PropNameID::forUtf8(rt, std::string("isValid")));
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("close")));
// Debugging
result.push_back(jsi::PropNameID::forUtf8(rt, std::string("toString")));
// 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")));
return result;
}
jsi::Value FrameHostObject::get(jsi::Runtime& runtime, const jsi::PropNameID& propNameId) {
auto name = propNameId.utf8(runtime);
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&, const jsi::Value*, size_t) -> jsi::Value {
auto toString = JSI_HOST_FUNCTION_LAMBDA {
if (!this->frame) {
return jsi::String::createFromUtf8(runtime, "[closed frame]");
}
@ -50,51 +54,53 @@ 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 == "close") {
auto close = [this] (jsi::Runtime& runtime, const jsi::Value&, const jsi::Value*, size_t) -> jsi::Value {
if (!this->frame) {
throw jsi::JSError(runtime, "Trying to close an already closed frame! Did you call frame.close() twice?");
}
this->close();
if (name == "incrementRefCount") {
auto incrementRefCount = JSI_HOST_FUNCTION_LAMBDA {
// Increment retain count by one so ARC doesn't destroy the Frame Buffer.
std::lock_guard lock(this->_refCountMutex);
this->_refCount++;
return jsi::Value::undefined();
};
return jsi::Function::createFromHostFunction(runtime, jsi::PropNameID::forUtf8(runtime, "close"), 0, close);
return jsi::Function::createFromHostFunction(runtime,
jsi::PropNameID::forUtf8(runtime, "incrementRefCount"),
0,
incrementRefCount);
}
if (name == "decrementRefCount") {
auto decrementRefCount = JSI_HOST_FUNCTION_LAMBDA {
// Decrement retain count by one. If the retain count is zero, ARC will destroy the Frame Buffer.
std::lock_guard lock(this->_refCountMutex);
this->_refCount--;
if (_refCount < 1) {
this->frame->close();
}
return jsi::Value::undefined();
};
return jsi::Function::createFromHostFunction(runtime,
jsi::PropNameID::forUtf8(runtime, "decrementRefCount"),
0,
decrementRefCount);
}
if (name == "isValid") {
return jsi::Value(this->frame && this->frame->getIsValid());
}
if (name == "width") {
this->assertIsFrameStrong(runtime, name);
return jsi::Value(this->frame->getWidth());
}
if (name == "height") {
this->assertIsFrameStrong(runtime, name);
return jsi::Value(this->frame->getHeight());
}
if (name == "bytesPerRow") {
this->assertIsFrameStrong(runtime, name);
return jsi::Value(this->frame->getBytesPerRow());
}
if (name == "planesCount") {
this->assertIsFrameStrong(runtime, name);
return jsi::Value(this->frame->getPlanesCount());
}
return jsi::Value::undefined();
}
void FrameHostObject::assertIsFrameStrong(jsi::Runtime& runtime, const std::string& accessedPropName) const {
if (!this->frame) {
auto message = "Cannot get `" + accessedPropName + "`, frame is already closed!";
throw jsi::JSError(runtime, message.c_str());
}
}
void FrameHostObject::close() {
if (this->frame) {
this->frame->close();
}
// fallback to base implementation
return HostObject::get(runtime, propName);
}
} // namespace vision

View File

@ -9,6 +9,7 @@
#include <fbjni/fbjni.h>
#include <vector>
#include <string>
#include <mutex>
#include "java-bindings/JImageProxy.h"
@ -25,15 +26,14 @@ class JSI_EXPORT FrameHostObject : public jsi::HostObject {
jsi::Value get(jsi::Runtime &, const jsi::PropNameID &name) override;
std::vector<jsi::PropNameID> getPropertyNames(jsi::Runtime &rt) override;
void close();
public:
jni::global_ref<JImageProxy> frame;
private:
static auto constexpr TAG = "VisionCamera";
void assertIsFrameStrong(jsi::Runtime& runtime, const std::string& accessedPropName) const; // NOLINT(runtime/references)
size_t _refCount;
std::mutex _refCountMutex;
};
} // namespace vision

View File

@ -8,6 +8,7 @@
#include <utility>
#include <string>
#include <JsiWorklet.h>
#include <JsiHostObject.h>
#include "CameraView.h"
#include "FrameHostObject.h"
@ -36,9 +37,7 @@ FrameProcessorRuntimeManager::FrameProcessorRuntimeManager(jni::alias_ref<FrameP
// Run on Frame Processor Worklet Runtime
scheduler->dispatchAsync(std::move(f));
};
_workletContext = std::make_shared<RNWorklet::JsiWorkletContext>("VisionCamera");
_workletContext->initialize("VisionCamera",
_workletContext = std::make_shared<RNWorklet::JsiWorkletContext>("VisionCamera",
jsRuntime,
runOnJS,
runOnWorklet);
@ -96,8 +95,7 @@ void FrameProcessorRuntimeManager::logErrorToJS(const std::string& message) {
void FrameProcessorRuntimeManager::setFrameProcessor(jsi::Runtime& runtime,
int viewTag,
const jsi::Value& frameProcessor) {
__android_log_write(ANDROID_LOG_INFO, TAG,
"Setting new Frame Processor...");
__android_log_write(ANDROID_LOG_INFO, TAG, "Setting new Frame Processor...");
if (!_workletContext) {
throw jsi::JSError(runtime,
@ -106,13 +104,10 @@ void FrameProcessorRuntimeManager::setFrameProcessor(jsi::Runtime& runtime,
// find camera view
auto cameraView = findCameraViewById(viewTag);
__android_log_write(ANDROID_LOG_INFO, TAG, "Found CameraView!");
// convert jsi::Function to a Worklet (can be shared across runtimes)
__android_log_write(ANDROID_LOG_INFO, TAG, "Creating Worklet...");
auto worklet = std::make_shared<RNWorklet::JsiWorklet>(runtime, frameProcessor);
auto workletInvoker = std::make_shared<RNWorklet::WorkletInvoker>(worklet);
__android_log_write(ANDROID_LOG_INFO, TAG, "Successfully created worklet!");
_workletContext->invokeOnWorkletThread([=](RNWorklet::JsiWorkletContext*, jsi::Runtime& rt) {
// Set Frame Processor as callable C++ lambda - this will then call the Worklet
@ -142,8 +137,6 @@ void FrameProcessorRuntimeManager::unsetFrameProcessor(int viewTag) {
// call Java method to unset frame processor
cameraView->cthis()->unsetFrameProcessor();
__android_log_write(ANDROID_LOG_INFO, TAG, "Frame Processor removed!");
}
// actual JSI installer
@ -158,21 +151,8 @@ void FrameProcessorRuntimeManager::installJSIBindings() {
auto& jsiRuntime = *_jsRuntime;
auto setFrameProcessor = [this](jsi::Runtime &runtime,
const jsi::Value &thisValue,
const jsi::Value *arguments,
size_t count) -> jsi::Value {
__android_log_write(ANDROID_LOG_INFO, TAG,
"Setting new Frame Processor...");
if (!arguments[0].isNumber()) {
throw jsi::JSError(runtime,
"Camera::setFrameProcessor: First argument ('viewTag') must be a number!");
}
if (!arguments[1].isObject()) {
throw jsi::JSError(runtime,
"Camera::setFrameProcessor: Second argument ('frameProcessor') must be a function!");
}
auto setFrameProcessor = JSI_HOST_FUNCTION_LAMBDA {
__android_log_write(ANDROID_LOG_INFO, TAG, "Setting new Frame Processor...");
double viewTag = arguments[0].asNumber();
const jsi::Value& frameProcessor = arguments[1];
@ -190,15 +170,8 @@ void FrameProcessorRuntimeManager::installJSIBindings() {
setFrameProcessor));
auto unsetFrameProcessor = [this](jsi::Runtime &runtime,
const jsi::Value &thisValue,
const jsi::Value *arguments,
size_t count) -> jsi::Value {
auto unsetFrameProcessor = JSI_HOST_FUNCTION_LAMBDA {
__android_log_write(ANDROID_LOG_INFO, TAG, "Removing Frame Processor...");
if (!arguments[0].isNumber()) {
throw jsi::JSError(runtime,
"Camera::unsetFrameProcessor: First argument ('viewTag') must be a number!");
}
auto viewTag = arguments[0].asNumber();
this->unsetFrameProcessor(static_cast<int>(viewTag));

View File

@ -31,17 +31,6 @@ fun CameraView.invokeOnError(error: Throwable) {
reactContext.getJSModule(RCTEventEmitter::class.java).receiveEvent(id, "cameraError", event)
}
fun CameraView.invokeOnFrameProcessorPerformanceSuggestionAvailable(currentFps: Double, suggestedFps: Double) {
Log.e(CameraView.TAG, "invokeOnFrameProcessorPerformanceSuggestionAvailable(suggestedFps: $suggestedFps):")
val event = Arguments.createMap()
val type = if (suggestedFps > currentFps) "can-use-higher-fps" else "should-use-lower-fps"
event.putString("type", type)
event.putDouble("suggestedFrameProcessorFps", suggestedFps)
val reactContext = context as ReactContext
reactContext.getJSModule(RCTEventEmitter::class.java).receiveEvent(id, "cameraPerformanceSuggestionAvailable", event)
}
fun CameraView.invokeOnViewReady() {
val event = Arguments.createMap()
val reactContext = context as ReactContext

View File

@ -25,7 +25,6 @@ import com.facebook.jni.HybridData
import com.facebook.proguard.annotations.DoNotStrip
import com.facebook.react.bridge.*
import com.facebook.react.uimanager.events.RCTEventEmitter
import com.mrousavy.camera.frameprocessor.FrameProcessorPerformanceDataCollector
import com.mrousavy.camera.frameprocessor.FrameProcessorRuntimeManager
import com.mrousavy.camera.utils.*
import kotlinx.coroutines.*
@ -103,13 +102,6 @@ class CameraView(context: Context, private val frameProcessorThread: ExecutorSer
field = value
setOnTouchListener(if (value) touchEventListener else null)
}
var frameProcessorFps = 1.0
set(value) {
field = value
actualFrameProcessorFps = if (value == -1.0) 30.0 else value
lastFrameProcessorPerformanceEvaluation = System.currentTimeMillis()
frameProcessorPerformanceDataCollector.clear()
}
// private properties
private var isMounted = false
@ -166,16 +158,6 @@ class CameraView(context: Context, private val frameProcessorThread: ExecutorSer
private var minZoom: Float = 1f
private var maxZoom: Float = 1f
private var actualFrameProcessorFps = 30.0
private val frameProcessorPerformanceDataCollector = FrameProcessorPerformanceDataCollector()
private var lastSuggestedFrameProcessorFps = 0.0
private var lastFrameProcessorPerformanceEvaluation = System.currentTimeMillis()
private val isReadyForNewEvaluation: Boolean
get() {
val lastPerformanceEvaluationElapsedTime = System.currentTimeMillis() - lastFrameProcessorPerformanceEvaluation
return lastPerformanceEvaluationElapsedTime > 1000
}
@DoNotStrip
private var mHybridData: HybridData? = null
@ -480,21 +462,8 @@ class CameraView(context: Context, private val frameProcessorThread: ExecutorSer
Log.i(TAG, "Adding ImageAnalysis use-case...")
imageAnalysis = imageAnalysisBuilder.build().apply {
setAnalyzer(cameraExecutor, { image ->
val now = System.currentTimeMillis()
val intervalMs = (1.0 / actualFrameProcessorFps) * 1000.0
if (now - lastFrameProcessorCall > intervalMs) {
lastFrameProcessorCall = now
val perfSample = frameProcessorPerformanceDataCollector.beginPerformanceSampleCollection()
// Call JS Frame Processor
frameProcessorCallback(image)
perfSample.endPerformanceSampleCollection()
}
image.close()
if (isReadyForNewEvaluation) {
// last evaluation was more than a second ago, evaluate again
evaluateNewPerformanceSamples()
}
})
}
useCases.add(imageAnalysis!!)
@ -526,22 +495,4 @@ class CameraView(context: Context, private val frameProcessorThread: ExecutorSer
}
}
}
private fun evaluateNewPerformanceSamples() {
lastFrameProcessorPerformanceEvaluation = System.currentTimeMillis()
val maxFrameProcessorFps = 30 // TODO: Get maxFrameProcessorFps from ImageAnalyser
val averageFps = 1.0 / frameProcessorPerformanceDataCollector.averageExecutionTimeSeconds
val suggestedFrameProcessorFps = floor(min(averageFps, maxFrameProcessorFps.toDouble()))
if (frameProcessorFps == -1.0) {
// frameProcessorFps="auto"
actualFrameProcessorFps = suggestedFrameProcessorFps
} else {
// frameProcessorFps={someCustomFpsValue}
if (suggestedFrameProcessorFps != lastSuggestedFrameProcessorFps && suggestedFrameProcessorFps != frameProcessorFps) {
invokeOnFrameProcessorPerformanceSuggestionAvailable(frameProcessorFps, suggestedFrameProcessorFps)
lastSuggestedFrameProcessorFps = suggestedFrameProcessorFps
}
}
}
}

View File

@ -27,7 +27,6 @@ class CameraViewManager(reactContext: ReactApplicationContext) : ViewGroupManage
.put("cameraViewReady", MapBuilder.of("registrationName", "onViewReady"))
.put("cameraInitialized", MapBuilder.of("registrationName", "onInitialized"))
.put("cameraError", MapBuilder.of("registrationName", "onError"))
.put("cameraPerformanceSuggestionAvailable", MapBuilder.of("registrationName", "onFrameProcessorPerformanceSuggestionAvailable"))
.build()
}
@ -108,13 +107,6 @@ class CameraViewManager(reactContext: ReactApplicationContext) : ViewGroupManage
view.fps = if (fps > 0) fps else null
}
@ReactProp(name = "frameProcessorFps", defaultDouble = 1.0)
fun setFrameProcessorFps(view: CameraView, frameProcessorFps: Double) {
if (view.frameProcessorFps != frameProcessorFps)
addChangedPropToTransaction(view, "frameProcessorFps")
view.frameProcessorFps = frameProcessorFps
}
@ReactProp(name = "hdr")
fun setHdr(view: CameraView, hdr: Boolean?) {
if (view.hdr != hdr)

View File

@ -1,38 +0,0 @@
package com.mrousavy.camera.frameprocessor
data class PerformanceSampleCollection(val endPerformanceSampleCollection: () -> Unit)
// keep a maximum of `maxSampleSize` historical performance data samples cached.
private const val maxSampleSize = 15
class FrameProcessorPerformanceDataCollector {
private var counter = 0
private var performanceSamples: ArrayList<Double> = ArrayList()
val averageExecutionTimeSeconds: Double
get() = performanceSamples.average()
fun beginPerformanceSampleCollection(): PerformanceSampleCollection {
val begin = System.currentTimeMillis()
return PerformanceSampleCollection {
val end = System.currentTimeMillis()
val seconds = (end - begin) / 1_000.0
val index = counter % maxSampleSize
if (performanceSamples.size > index) {
performanceSamples[index] = seconds
} else {
performanceSamples.add(seconds)
}
counter++
}
}
fun clear() {
counter = 0
performanceSamples.clear()
}
}

View File

@ -161,7 +161,7 @@ This means that **the Frame Processor API only takes ~1ms longer than a fully na
### Avoiding Frame-drops
Frame Processors will be **synchronously** called for each frame the Camera sees and have to finish executing before the next frame arrives, otherwise the next frame(s) will be dropped. For a frame rate of **30 FPS**, you have about **33ms** to finish processing frames. Use [`frameProcessorFps`](/docs/api/interfaces/CameraProps#frameprocessorfps) to throttle the frame processor's FPS. For a QR Code Scanner, **5 FPS** (200ms) might suffice, while a object tracking AI might run at the same frame rate as the Camera itself (e.g. **60 FPS** (16ms)).
Frame Processors will be **synchronously** called for each frame the Camera sees and have to finish executing before the next frame arrives, otherwise the next frame(s) will be dropped. For a frame rate of **30 FPS**, you have about **33ms** to finish processing frames. For a QR Code Scanner, **5 FPS** (200ms) might suffice, while a object tracking AI might run at the same frame rate as the Camera itself (e.g. **60 FPS** (16ms)).
### ESLint react-hooks plugin

View File

@ -1,19 +1,19 @@
PODS:
- boost (1.76.0)
- DoubleConversion (1.1.6)
- FBLazyVector (0.71.2)
- FBReactNativeSpec (0.71.2):
- FBLazyVector (0.71.3)
- FBReactNativeSpec (0.71.3):
- RCT-Folly (= 2021.07.22.00)
- RCTRequired (= 0.71.2)
- RCTTypeSafety (= 0.71.2)
- React-Core (= 0.71.2)
- React-jsi (= 0.71.2)
- ReactCommon/turbomodule/core (= 0.71.2)
- RCTRequired (= 0.71.3)
- RCTTypeSafety (= 0.71.3)
- React-Core (= 0.71.3)
- React-jsi (= 0.71.3)
- ReactCommon/turbomodule/core (= 0.71.3)
- fmt (6.2.1)
- glog (0.3.5)
- hermes-engine (0.71.2):
- hermes-engine/Pre-built (= 0.71.2)
- hermes-engine/Pre-built (0.71.2)
- hermes-engine (0.71.3):
- hermes-engine/Pre-built (= 0.71.3)
- hermes-engine/Pre-built (0.71.3)
- libevent (2.1.12)
- RCT-Folly (2021.07.22.00):
- boost
@ -32,26 +32,26 @@ PODS:
- fmt (~> 6.2.1)
- glog
- libevent
- RCTRequired (0.71.2)
- RCTTypeSafety (0.71.2):
- FBLazyVector (= 0.71.2)
- RCTRequired (= 0.71.2)
- React-Core (= 0.71.2)
- React (0.71.2):
- React-Core (= 0.71.2)
- React-Core/DevSupport (= 0.71.2)
- React-Core/RCTWebSocket (= 0.71.2)
- React-RCTActionSheet (= 0.71.2)
- React-RCTAnimation (= 0.71.2)
- React-RCTBlob (= 0.71.2)
- React-RCTImage (= 0.71.2)
- React-RCTLinking (= 0.71.2)
- React-RCTNetwork (= 0.71.2)
- React-RCTSettings (= 0.71.2)
- React-RCTText (= 0.71.2)
- React-RCTVibration (= 0.71.2)
- React-callinvoker (0.71.2)
- React-Codegen (0.71.2):
- RCTRequired (0.71.3)
- RCTTypeSafety (0.71.3):
- FBLazyVector (= 0.71.3)
- RCTRequired (= 0.71.3)
- React-Core (= 0.71.3)
- React (0.71.3):
- React-Core (= 0.71.3)
- React-Core/DevSupport (= 0.71.3)
- React-Core/RCTWebSocket (= 0.71.3)
- React-RCTActionSheet (= 0.71.3)
- React-RCTAnimation (= 0.71.3)
- React-RCTBlob (= 0.71.3)
- React-RCTImage (= 0.71.3)
- React-RCTLinking (= 0.71.3)
- React-RCTNetwork (= 0.71.3)
- React-RCTSettings (= 0.71.3)
- React-RCTText (= 0.71.3)
- React-RCTVibration (= 0.71.3)
- React-callinvoker (0.71.3)
- React-Codegen (0.71.3):
- FBReactNativeSpec
- hermes-engine
- RCT-Folly
@ -62,209 +62,209 @@ PODS:
- React-jsiexecutor
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- React-Core (0.71.2):
- React-Core (0.71.3):
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
- React-Core/Default (= 0.71.2)
- React-cxxreact (= 0.71.2)
- React-Core/Default (= 0.71.3)
- React-cxxreact (= 0.71.3)
- React-hermes
- React-jsi (= 0.71.2)
- React-jsiexecutor (= 0.71.2)
- React-perflogger (= 0.71.2)
- React-jsi (= 0.71.3)
- React-jsiexecutor (= 0.71.3)
- React-perflogger (= 0.71.3)
- Yoga
- React-Core/CoreModulesHeaders (0.71.2):
- React-Core/CoreModulesHeaders (0.71.3):
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
- React-Core/Default
- React-cxxreact (= 0.71.2)
- React-cxxreact (= 0.71.3)
- React-hermes
- React-jsi (= 0.71.2)
- React-jsiexecutor (= 0.71.2)
- React-perflogger (= 0.71.2)
- React-jsi (= 0.71.3)
- React-jsiexecutor (= 0.71.3)
- React-perflogger (= 0.71.3)
- Yoga
- React-Core/Default (0.71.2):
- React-Core/Default (0.71.3):
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
- React-cxxreact (= 0.71.2)
- React-cxxreact (= 0.71.3)
- React-hermes
- React-jsi (= 0.71.2)
- React-jsiexecutor (= 0.71.2)
- React-perflogger (= 0.71.2)
- React-jsi (= 0.71.3)
- React-jsiexecutor (= 0.71.3)
- React-perflogger (= 0.71.3)
- Yoga
- React-Core/DevSupport (0.71.2):
- React-Core/DevSupport (0.71.3):
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
- React-Core/Default (= 0.71.2)
- React-Core/RCTWebSocket (= 0.71.2)
- React-cxxreact (= 0.71.2)
- React-Core/Default (= 0.71.3)
- React-Core/RCTWebSocket (= 0.71.3)
- React-cxxreact (= 0.71.3)
- React-hermes
- React-jsi (= 0.71.2)
- React-jsiexecutor (= 0.71.2)
- React-jsinspector (= 0.71.2)
- React-perflogger (= 0.71.2)
- React-jsi (= 0.71.3)
- React-jsiexecutor (= 0.71.3)
- React-jsinspector (= 0.71.3)
- React-perflogger (= 0.71.3)
- Yoga
- React-Core/RCTActionSheetHeaders (0.71.2):
- React-Core/RCTActionSheetHeaders (0.71.3):
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
- React-Core/Default
- React-cxxreact (= 0.71.2)
- React-cxxreact (= 0.71.3)
- React-hermes
- React-jsi (= 0.71.2)
- React-jsiexecutor (= 0.71.2)
- React-perflogger (= 0.71.2)
- React-jsi (= 0.71.3)
- React-jsiexecutor (= 0.71.3)
- React-perflogger (= 0.71.3)
- Yoga
- React-Core/RCTAnimationHeaders (0.71.2):
- React-Core/RCTAnimationHeaders (0.71.3):
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
- React-Core/Default
- React-cxxreact (= 0.71.2)
- React-cxxreact (= 0.71.3)
- React-hermes
- React-jsi (= 0.71.2)
- React-jsiexecutor (= 0.71.2)
- React-perflogger (= 0.71.2)
- React-jsi (= 0.71.3)
- React-jsiexecutor (= 0.71.3)
- React-perflogger (= 0.71.3)
- Yoga
- React-Core/RCTBlobHeaders (0.71.2):
- React-Core/RCTBlobHeaders (0.71.3):
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
- React-Core/Default
- React-cxxreact (= 0.71.2)
- React-cxxreact (= 0.71.3)
- React-hermes
- React-jsi (= 0.71.2)
- React-jsiexecutor (= 0.71.2)
- React-perflogger (= 0.71.2)
- React-jsi (= 0.71.3)
- React-jsiexecutor (= 0.71.3)
- React-perflogger (= 0.71.3)
- Yoga
- React-Core/RCTImageHeaders (0.71.2):
- React-Core/RCTImageHeaders (0.71.3):
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
- React-Core/Default
- React-cxxreact (= 0.71.2)
- React-cxxreact (= 0.71.3)
- React-hermes
- React-jsi (= 0.71.2)
- React-jsiexecutor (= 0.71.2)
- React-perflogger (= 0.71.2)
- React-jsi (= 0.71.3)
- React-jsiexecutor (= 0.71.3)
- React-perflogger (= 0.71.3)
- Yoga
- React-Core/RCTLinkingHeaders (0.71.2):
- React-Core/RCTLinkingHeaders (0.71.3):
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
- React-Core/Default
- React-cxxreact (= 0.71.2)
- React-cxxreact (= 0.71.3)
- React-hermes
- React-jsi (= 0.71.2)
- React-jsiexecutor (= 0.71.2)
- React-perflogger (= 0.71.2)
- React-jsi (= 0.71.3)
- React-jsiexecutor (= 0.71.3)
- React-perflogger (= 0.71.3)
- Yoga
- React-Core/RCTNetworkHeaders (0.71.2):
- React-Core/RCTNetworkHeaders (0.71.3):
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
- React-Core/Default
- React-cxxreact (= 0.71.2)
- React-cxxreact (= 0.71.3)
- React-hermes
- React-jsi (= 0.71.2)
- React-jsiexecutor (= 0.71.2)
- React-perflogger (= 0.71.2)
- React-jsi (= 0.71.3)
- React-jsiexecutor (= 0.71.3)
- React-perflogger (= 0.71.3)
- Yoga
- React-Core/RCTSettingsHeaders (0.71.2):
- React-Core/RCTSettingsHeaders (0.71.3):
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
- React-Core/Default
- React-cxxreact (= 0.71.2)
- React-cxxreact (= 0.71.3)
- React-hermes
- React-jsi (= 0.71.2)
- React-jsiexecutor (= 0.71.2)
- React-perflogger (= 0.71.2)
- React-jsi (= 0.71.3)
- React-jsiexecutor (= 0.71.3)
- React-perflogger (= 0.71.3)
- Yoga
- React-Core/RCTTextHeaders (0.71.2):
- React-Core/RCTTextHeaders (0.71.3):
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
- React-Core/Default
- React-cxxreact (= 0.71.2)
- React-cxxreact (= 0.71.3)
- React-hermes
- React-jsi (= 0.71.2)
- React-jsiexecutor (= 0.71.2)
- React-perflogger (= 0.71.2)
- React-jsi (= 0.71.3)
- React-jsiexecutor (= 0.71.3)
- React-perflogger (= 0.71.3)
- Yoga
- React-Core/RCTVibrationHeaders (0.71.2):
- React-Core/RCTVibrationHeaders (0.71.3):
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
- React-Core/Default
- React-cxxreact (= 0.71.2)
- React-cxxreact (= 0.71.3)
- React-hermes
- React-jsi (= 0.71.2)
- React-jsiexecutor (= 0.71.2)
- React-perflogger (= 0.71.2)
- React-jsi (= 0.71.3)
- React-jsiexecutor (= 0.71.3)
- React-perflogger (= 0.71.3)
- Yoga
- React-Core/RCTWebSocket (0.71.2):
- React-Core/RCTWebSocket (0.71.3):
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
- React-Core/Default (= 0.71.2)
- React-cxxreact (= 0.71.2)
- React-Core/Default (= 0.71.3)
- React-cxxreact (= 0.71.3)
- React-hermes
- React-jsi (= 0.71.2)
- React-jsiexecutor (= 0.71.2)
- React-perflogger (= 0.71.2)
- React-jsi (= 0.71.3)
- React-jsiexecutor (= 0.71.3)
- React-perflogger (= 0.71.3)
- Yoga
- React-CoreModules (0.71.2):
- React-CoreModules (0.71.3):
- RCT-Folly (= 2021.07.22.00)
- RCTTypeSafety (= 0.71.2)
- React-Codegen (= 0.71.2)
- React-Core/CoreModulesHeaders (= 0.71.2)
- React-jsi (= 0.71.2)
- RCTTypeSafety (= 0.71.3)
- React-Codegen (= 0.71.3)
- React-Core/CoreModulesHeaders (= 0.71.3)
- React-jsi (= 0.71.3)
- React-RCTBlob
- React-RCTImage (= 0.71.2)
- ReactCommon/turbomodule/core (= 0.71.2)
- React-cxxreact (0.71.2):
- React-RCTImage (= 0.71.3)
- ReactCommon/turbomodule/core (= 0.71.3)
- React-cxxreact (0.71.3):
- boost (= 1.76.0)
- DoubleConversion
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
- React-callinvoker (= 0.71.2)
- React-jsi (= 0.71.2)
- React-jsinspector (= 0.71.2)
- React-logger (= 0.71.2)
- React-perflogger (= 0.71.2)
- React-runtimeexecutor (= 0.71.2)
- React-hermes (0.71.2):
- React-callinvoker (= 0.71.3)
- React-jsi (= 0.71.3)
- React-jsinspector (= 0.71.3)
- React-logger (= 0.71.3)
- React-perflogger (= 0.71.3)
- React-runtimeexecutor (= 0.71.3)
- React-hermes (0.71.3):
- DoubleConversion
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
- RCT-Folly/Futures (= 2021.07.22.00)
- React-cxxreact (= 0.71.2)
- React-cxxreact (= 0.71.3)
- React-jsi
- React-jsiexecutor (= 0.71.2)
- React-jsinspector (= 0.71.2)
- React-perflogger (= 0.71.2)
- React-jsi (0.71.2):
- React-jsiexecutor (= 0.71.3)
- React-jsinspector (= 0.71.3)
- React-perflogger (= 0.71.3)
- React-jsi (0.71.3):
- boost (= 1.76.0)
- DoubleConversion
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
- React-jsiexecutor (0.71.2):
- React-jsiexecutor (0.71.3):
- DoubleConversion
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
- React-cxxreact (= 0.71.2)
- React-jsi (= 0.71.2)
- React-perflogger (= 0.71.2)
- React-jsinspector (0.71.2)
- React-logger (0.71.2):
- React-cxxreact (= 0.71.3)
- React-jsi (= 0.71.3)
- React-perflogger (= 0.71.3)
- React-jsinspector (0.71.3)
- React-logger (0.71.3):
- glog
- react-native-blur (4.3.0):
- React-Core
@ -287,90 +287,90 @@ PODS:
- React
- React-callinvoker
- React-Core
- React-perflogger (0.71.2)
- React-RCTActionSheet (0.71.2):
- React-Core/RCTActionSheetHeaders (= 0.71.2)
- React-RCTAnimation (0.71.2):
- React-perflogger (0.71.3)
- React-RCTActionSheet (0.71.3):
- React-Core/RCTActionSheetHeaders (= 0.71.3)
- React-RCTAnimation (0.71.3):
- RCT-Folly (= 2021.07.22.00)
- RCTTypeSafety (= 0.71.2)
- React-Codegen (= 0.71.2)
- React-Core/RCTAnimationHeaders (= 0.71.2)
- React-jsi (= 0.71.2)
- ReactCommon/turbomodule/core (= 0.71.2)
- React-RCTAppDelegate (0.71.2):
- RCTTypeSafety (= 0.71.3)
- React-Codegen (= 0.71.3)
- React-Core/RCTAnimationHeaders (= 0.71.3)
- React-jsi (= 0.71.3)
- ReactCommon/turbomodule/core (= 0.71.3)
- React-RCTAppDelegate (0.71.3):
- RCT-Folly
- RCTRequired
- RCTTypeSafety
- React-Core
- ReactCommon/turbomodule/core
- React-RCTBlob (0.71.2):
- React-RCTBlob (0.71.3):
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
- React-Codegen (= 0.71.2)
- React-Core/RCTBlobHeaders (= 0.71.2)
- React-Core/RCTWebSocket (= 0.71.2)
- React-jsi (= 0.71.2)
- React-RCTNetwork (= 0.71.2)
- ReactCommon/turbomodule/core (= 0.71.2)
- React-RCTImage (0.71.2):
- React-Codegen (= 0.71.3)
- React-Core/RCTBlobHeaders (= 0.71.3)
- React-Core/RCTWebSocket (= 0.71.3)
- React-jsi (= 0.71.3)
- React-RCTNetwork (= 0.71.3)
- ReactCommon/turbomodule/core (= 0.71.3)
- React-RCTImage (0.71.3):
- RCT-Folly (= 2021.07.22.00)
- RCTTypeSafety (= 0.71.2)
- React-Codegen (= 0.71.2)
- React-Core/RCTImageHeaders (= 0.71.2)
- React-jsi (= 0.71.2)
- React-RCTNetwork (= 0.71.2)
- ReactCommon/turbomodule/core (= 0.71.2)
- React-RCTLinking (0.71.2):
- React-Codegen (= 0.71.2)
- React-Core/RCTLinkingHeaders (= 0.71.2)
- React-jsi (= 0.71.2)
- ReactCommon/turbomodule/core (= 0.71.2)
- React-RCTNetwork (0.71.2):
- RCTTypeSafety (= 0.71.3)
- React-Codegen (= 0.71.3)
- React-Core/RCTImageHeaders (= 0.71.3)
- React-jsi (= 0.71.3)
- React-RCTNetwork (= 0.71.3)
- ReactCommon/turbomodule/core (= 0.71.3)
- React-RCTLinking (0.71.3):
- React-Codegen (= 0.71.3)
- React-Core/RCTLinkingHeaders (= 0.71.3)
- React-jsi (= 0.71.3)
- ReactCommon/turbomodule/core (= 0.71.3)
- React-RCTNetwork (0.71.3):
- RCT-Folly (= 2021.07.22.00)
- RCTTypeSafety (= 0.71.2)
- React-Codegen (= 0.71.2)
- React-Core/RCTNetworkHeaders (= 0.71.2)
- React-jsi (= 0.71.2)
- ReactCommon/turbomodule/core (= 0.71.2)
- React-RCTSettings (0.71.2):
- RCTTypeSafety (= 0.71.3)
- React-Codegen (= 0.71.3)
- React-Core/RCTNetworkHeaders (= 0.71.3)
- React-jsi (= 0.71.3)
- ReactCommon/turbomodule/core (= 0.71.3)
- React-RCTSettings (0.71.3):
- RCT-Folly (= 2021.07.22.00)
- RCTTypeSafety (= 0.71.2)
- React-Codegen (= 0.71.2)
- React-Core/RCTSettingsHeaders (= 0.71.2)
- React-jsi (= 0.71.2)
- ReactCommon/turbomodule/core (= 0.71.2)
- React-RCTText (0.71.2):
- React-Core/RCTTextHeaders (= 0.71.2)
- React-RCTVibration (0.71.2):
- RCTTypeSafety (= 0.71.3)
- React-Codegen (= 0.71.3)
- React-Core/RCTSettingsHeaders (= 0.71.3)
- React-jsi (= 0.71.3)
- ReactCommon/turbomodule/core (= 0.71.3)
- React-RCTText (0.71.3):
- React-Core/RCTTextHeaders (= 0.71.3)
- React-RCTVibration (0.71.3):
- RCT-Folly (= 2021.07.22.00)
- React-Codegen (= 0.71.2)
- React-Core/RCTVibrationHeaders (= 0.71.2)
- React-jsi (= 0.71.2)
- ReactCommon/turbomodule/core (= 0.71.2)
- React-runtimeexecutor (0.71.2):
- React-jsi (= 0.71.2)
- ReactCommon/turbomodule/bridging (0.71.2):
- React-Codegen (= 0.71.3)
- React-Core/RCTVibrationHeaders (= 0.71.3)
- React-jsi (= 0.71.3)
- ReactCommon/turbomodule/core (= 0.71.3)
- React-runtimeexecutor (0.71.3):
- React-jsi (= 0.71.3)
- ReactCommon/turbomodule/bridging (0.71.3):
- DoubleConversion
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
- React-callinvoker (= 0.71.2)
- React-Core (= 0.71.2)
- React-cxxreact (= 0.71.2)
- React-jsi (= 0.71.2)
- React-logger (= 0.71.2)
- React-perflogger (= 0.71.2)
- ReactCommon/turbomodule/core (0.71.2):
- React-callinvoker (= 0.71.3)
- React-Core (= 0.71.3)
- React-cxxreact (= 0.71.3)
- React-jsi (= 0.71.3)
- React-logger (= 0.71.3)
- React-perflogger (= 0.71.3)
- ReactCommon/turbomodule/core (0.71.3):
- DoubleConversion
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
- React-callinvoker (= 0.71.2)
- React-Core (= 0.71.2)
- React-cxxreact (= 0.71.2)
- React-jsi (= 0.71.2)
- React-logger (= 0.71.2)
- React-perflogger (= 0.71.2)
- React-callinvoker (= 0.71.3)
- React-Core (= 0.71.3)
- React-cxxreact (= 0.71.3)
- React-jsi (= 0.71.3)
- React-logger (= 0.71.3)
- React-perflogger (= 0.71.3)
- RNGestureHandler (2.9.0):
- React-Core
- RNReanimated (3.0.0-rc.10):
@ -400,7 +400,7 @@ PODS:
- React-RCTText
- ReactCommon/turbomodule/core
- Yoga
- RNScreens (3.19.0):
- RNScreens (3.20.0):
- React-Core
- React-RCTImage
- RNStaticSafeAreaInsets (2.2.0):
@ -566,52 +566,52 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
boost: 57d2868c099736d80fcd648bf211b4431e51a558
DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54
FBLazyVector: d58428b28fe1f5070fe993495b0e2eaf701d3820
FBReactNativeSpec: 225fb0f0ab00493ce0731f954da3658638d9b191
FBLazyVector: 60195509584153283780abdac5569feffb8f08cc
FBReactNativeSpec: 9c191fb58d06dc05ab5559a5505fc32139e9e4a2
fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9
glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b
hermes-engine: 6351580c827b3b03e5f25aadcf989f582d0b0a86
hermes-engine: 38bfe887e456b33b697187570a08de33969f5db7
libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
RCT-Folly: 424b8c9a7a0b9ab2886ffe9c3b041ef628fd4fb1
RCTRequired: c154ebcfbf41d6fef86c52674fc1aa08837ff538
RCTTypeSafety: 3063e5a1e5b1dc2cbeda5c8f8926c0ad1a6b0871
React: 0a1a36e8e81cfaac244ed88b97f23ab56e5434f0
React-callinvoker: 679a09fbfe1a8bbf0c8588b588bf3ef85e7e4922
React-Codegen: 78f8966839f22b54d3303a6aca2679bce5723c3f
React-Core: 679e5ff1eb0e3122463976d0b2049bebcb7b33d6
React-CoreModules: 06cbf15185e6daf9fb3aec02c963f4807bd794b3
React-cxxreact: 645dc75c9deba4c15698b1b5902236d6a766461f
React-hermes: bc7bcfeaaa7cb98dc9f9252f2f3eca66f06f01e2
React-jsi: 82625f9f1f8d7abf716d897612a9ea06ecf6db6e
React-jsiexecutor: c7e028406112db456ac3cf5720d266bc7bc20938
React-jsinspector: ea8101acf525ec08b2d87ddf0637d45f8e3b4148
React-logger: 97987f46779d8dd24656474ad0c43a5b459f31d6
RCTRequired: bec48f07daf7bcdc2655a0cde84e07d24d2a9e2a
RCTTypeSafety: 171394eebacf71e1cfad79dbfae7ee8fc16ca80a
React: d7433ccb6a8c36e4cbed59a73c0700fc83c3e98a
React-callinvoker: 15f165009bd22ae829b2b600e50bcc98076ce4b8
React-Codegen: b5910000eaf1e0c2f47d29be6f82f5f1264420d7
React-Core: b6f2f78d580a90b83fd7b0d1c6911c799f6eac82
React-CoreModules: e0cbc1a4f4f3f60e23c476fef7ab37be363ea8c1
React-cxxreact: c87f3f124b2117d00d410b35f16c2257e25e50fa
React-hermes: c64ca6bdf16a7069773103c9bedaf30ec90ab38f
React-jsi: 39729361645568e238081b3b3180fbad803f25a4
React-jsiexecutor: 515b703d23ffadeac7687bc2d12fb08b90f0aaa1
React-jsinspector: 9f7c9137605e72ca0343db4cea88006cb94856dd
React-logger: 957e5dc96d9dbffc6e0f15e0ee4d2b42829ff207
react-native-blur: 50c9feabacbc5f49b61337ebc32192c6be7ec3c3
react-native-cameraroll: 5b25d0be40185d02e522bf2abf8a1ba4e8faa107
react-native-safe-area-context: 39c2d8be3328df5d437ac1700f4f3a4f75716acc
react-native-slider: 33b8d190b59d4f67a541061bb91775d53d617d9d
react-native-video: c26780b224543c62d5e1b2a7244a5cd1b50e8253
react-native-worklets: c7576ad4ad0f030ff41e8d74ad0077c96054a6c1
React-perflogger: c7ccda3d1d1da837f7ff4e54e816022a6803ee87
React-RCTActionSheet: 01c125aebbad462a24228f68c584c7a921d6c28e
React-RCTAnimation: 5277a9440acffc4a5b7baa6ae3880fe467277ae6
React-RCTAppDelegate: 3977201606125157aa94872b4171ca316478939b
React-RCTBlob: 8e15fc9091d8947f406ba706f11505b38b1b5e40
React-RCTImage: 65319acfe82b85219b2d410725a593abe19ac795
React-RCTLinking: a5fc2b9d7a346d6e7d34de8093bb5d1064042508
React-RCTNetwork: 5d1efcd01ca7f08ebf286d68be544f747a5d315a
React-RCTSettings: fa760b0add819ac3ad73b06715f9547316acdf20
React-RCTText: 05c244b135d75d4395eb35c012949a5326f8ab70
React-RCTVibration: 0af3babdeee1b2d052811a2f86977d1e1c81ebd1
React-runtimeexecutor: 4bf9a9086d27f74065fce1dddac274aa95216952
ReactCommon: f697c0ac52e999aa818e43e2b6f277787c735e2d
React-perflogger: af8a3d31546077f42d729b949925cc4549f14def
React-RCTActionSheet: 57cc5adfefbaaf0aae2cf7e10bccd746f2903673
React-RCTAnimation: 11c61e94da700c4dc915cf134513764d87fc5e2b
React-RCTAppDelegate: c3980adeaadcfd6cb495532e928b36ac6db3c14a
React-RCTBlob: ccc5049d742b41971141415ca86b83b201495695
React-RCTImage: 7a9226b0944f1e76e8e01e35a9245c2477cdbabb
React-RCTLinking: bbe8cc582046a9c04f79c235b73c93700263e8b4
React-RCTNetwork: fc2ca322159dc54e06508d4f5c3e934da63dc013
React-RCTSettings: f1e9db2cdf946426d3f2b210e4ff4ce0f0d842ef
React-RCTText: 1c41dd57e5d742b1396b4eeb251851ce7ff0fca1
React-RCTVibration: 5199a180d04873366a83855de55ac33ce60fe4d5
React-runtimeexecutor: 7bf0dafc7b727d93c8cb94eb00a9d3753c446c3e
ReactCommon: 6f65ea5b7d84deb9e386f670dd11ce499ded7b40
RNGestureHandler: 071d7a9ad81e8b83fe7663b303d132406a7d8f39
RNReanimated: fbc356493970e3acddc15586b1bccb5eab3ff1ec
RNScreens: ea4cd3a853063cda19a4e3c28d2e52180c80f4eb
RNScreens: 218801c16a2782546d30bd2026bb625c0302d70f
RNStaticSafeAreaInsets: 055ddbf5e476321720457cdaeec0ff2ba40ec1b8
RNVectorIcons: fcc2f6cb32f5735b586e66d14103a74ce6ad61f8
VisionCamera: 312151eb95370d1d764720de3b7dad33d8c7fb40
Yoga: 5b0304b3dbef2b52e078052138e23a19c7dacaef
Yoga: 5ed1699acbba8863755998a4245daa200ff3817b
PODFILE CHECKSUM: d53724fe402c2547f1dd1cc571bbe77d9820e636

View File

@ -20,16 +20,16 @@
"@react-navigation/native": "^6.1.3",
"@react-navigation/native-stack": "^6.9.9",
"react": "^18.2.0",
"react-native": "^0.71.2",
"react-native": "^0.71.3",
"react-native-gesture-handler": "^2.9.0",
"react-native-pressable-opacity": "^1.0.10",
"react-native-reanimated": "^3.0.0-rc.10",
"react-native-reanimated": "https://github.com/software-mansion/react-native-reanimated#6cf9713a44ec61318bbb12c311f79c08eda95d10",
"react-native-safe-area-context": "^4.5.0",
"react-native-screens": "^3.19.0",
"react-native-static-safe-area-insets": "^2.2.0",
"react-native-vector-icons": "^9.2.0",
"react-native-video": "^5.2.1",
"react-native-worklets": "https://github.com/chrfalch/react-native-worklets#50950aa"
"react-native-worklets": "https://github.com/chrfalch/react-native-worklets#15d52dd"
},
"devDependencies": {
"@babel/core": "^7.20.12",

View File

@ -5,7 +5,6 @@ import { PinchGestureHandler, PinchGestureHandlerGestureEvent, TapGestureHandler
import {
CameraDeviceFormat,
CameraRuntimeError,
FrameProcessorPerformanceSuggestion,
PhotoFile,
sortFormats,
useCameraDevices,
@ -203,10 +202,6 @@ export function CameraPage({ navigation }: Props): React.ReactElement {
console.log(`Return Values: ${JSON.stringify(values)}`);
}, []);
const onFrameProcessorSuggestionAvailable = useCallback((suggestion: FrameProcessorPerformanceSuggestion) => {
console.log(`Suggestion available! ${suggestion.type}: Can do ${suggestion.suggestedFrameProcessorFps} FPS`);
}, []);
return (
<View style={styles.container}>
{device != null && (
@ -231,8 +226,6 @@ export function CameraPage({ navigation }: Props): React.ReactElement {
audio={hasMicrophonePermission}
frameProcessor={device.supportsParallelVideoProcessing ? frameProcessor : undefined}
orientation="portrait"
frameProcessorFps={1}
onFrameProcessorPerformanceSuggestionAvailable={onFrameProcessorSuggestionAvailable}
/>
</TapGestureHandler>
</Reanimated.View>

View File

@ -781,38 +781,38 @@
integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==
"@jest/create-cache-key-function@^29.2.1":
version "29.4.2"
resolved "https://registry.yarnpkg.com/@jest/create-cache-key-function/-/create-cache-key-function-29.4.2.tgz#cc8e966c28fd3bed309b0487de2e0bd12cbf519f"
integrity sha512-o2weIg3h8/7+jXF6EjcOiz9TAlNMtcmeH5IARTVgHs3IoQGbh5E/ZLLskfEsHVIYoCKgx+v093Vf8hOgMWggvg==
version "29.4.3"
resolved "https://registry.yarnpkg.com/@jest/create-cache-key-function/-/create-cache-key-function-29.4.3.tgz#ea37769f69523019d81ee089a25a62550f209eb7"
integrity sha512-AJVFQTTy6jnZAQiAZrdOaTAPzJUrvAE/4IMe+Foav6WPhypFszqg7a4lOTyuzYQEEiT5RSrGYg9IY+/ivxiyXw==
dependencies:
"@jest/types" "^29.4.2"
"@jest/types" "^29.4.3"
"@jest/environment@^29.4.2":
version "29.4.2"
resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.4.2.tgz#ee92c316ee2fbdf0bcd9d2db0ef42d64fea26b56"
integrity sha512-JKs3VUtse0vQfCaFGJRX1bir9yBdtasxziSyu+pIiEllAQOe4oQhdCYIf3+Lx+nGglFktSKToBnRJfD5QKp+NQ==
"@jest/environment@^29.4.3":
version "29.4.3"
resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.4.3.tgz#9fe2f3169c3b33815dc4bd3960a064a83eba6548"
integrity sha512-dq5S6408IxIa+lr54zeqce+QgI+CJT4nmmA+1yzFgtcsGK8c/EyiUb9XQOgz3BMKrRDfKseeOaxj2eO8LlD3lA==
dependencies:
"@jest/fake-timers" "^29.4.2"
"@jest/types" "^29.4.2"
"@jest/fake-timers" "^29.4.3"
"@jest/types" "^29.4.3"
"@types/node" "*"
jest-mock "^29.4.2"
jest-mock "^29.4.3"
"@jest/fake-timers@^29.4.2":
version "29.4.2"
resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-29.4.2.tgz#af43ee1a5720b987d0348f80df98f2cb17d45cd0"
integrity sha512-Ny1u0Wg6kCsHFWq7A/rW/tMhIedq2siiyHyLpHCmIhP7WmcAmd2cx95P+0xtTZlj5ZbJxIRQi4OPydZZUoiSQQ==
"@jest/fake-timers@^29.4.3":
version "29.4.3"
resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-29.4.3.tgz#31e982638c60fa657d310d4b9d24e023064027b0"
integrity sha512-4Hote2MGcCTWSD2gwl0dwbCpBRHhE6olYEuTj8FMowdg3oQWNKr2YuxenPQYZ7+PfqPY1k98wKDU4Z+Hvd4Tiw==
dependencies:
"@jest/types" "^29.4.2"
"@jest/types" "^29.4.3"
"@sinonjs/fake-timers" "^10.0.2"
"@types/node" "*"
jest-message-util "^29.4.2"
jest-mock "^29.4.2"
jest-util "^29.4.2"
jest-message-util "^29.4.3"
jest-mock "^29.4.3"
jest-util "^29.4.3"
"@jest/schemas@^29.4.2":
version "29.4.2"
resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.4.2.tgz#cf7cfe97c5649f518452b176c47ed07486270fc1"
integrity sha512-ZrGzGfh31NtdVH8tn0mgJw4khQuNHiKqdzJAFbCaERbyCP9tHlxWuL/mnMu8P7e/+k4puWjI1NOzi/sFsjce/g==
"@jest/schemas@^29.4.3":
version "29.4.3"
resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.4.3.tgz#39cf1b8469afc40b6f5a2baaa146e332c4151788"
integrity sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg==
dependencies:
"@sinclair/typebox" "^0.25.16"
@ -838,12 +838,12 @@
"@types/yargs" "^16.0.0"
chalk "^4.0.0"
"@jest/types@^29.4.2":
version "29.4.2"
resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.4.2.tgz#8f724a414b1246b2bfd56ca5225d9e1f39540d82"
integrity sha512-CKlngyGP0fwlgC1BRUtPZSiWLBhyS9dKwKmyGxk8Z6M82LBEGB2aLQSg+U1MyLsU+M7UjnlLllBM2BLWKVm/Uw==
"@jest/types@^29.4.3":
version "29.4.3"
resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.4.3.tgz#9069145f4ef09adf10cec1b2901b2d390031431f"
integrity sha512-bPYfw8V65v17m2Od1cv44FH+SiKW7w2Xu7trhcdTLUmSv85rfKsP+qXSjO4KGJr4dtPSzl/gvslZBXctf1qGEA==
dependencies:
"@jest/schemas" "^29.4.2"
"@jest/schemas" "^29.4.3"
"@types/istanbul-lib-coverage" "^2.0.0"
"@types/istanbul-reports" "^3.0.0"
"@types/node" "*"
@ -1153,23 +1153,23 @@
react-is "^16.13.0"
use-latest-callback "^0.1.5"
"@react-navigation/elements@^1.3.14":
version "1.3.14"
resolved "https://registry.yarnpkg.com/@react-navigation/elements/-/elements-1.3.14.tgz#ee9ef7f57e0877700ebb359947728b255bbb9c65"
integrity sha512-RBbPhYq+KNFPAkWPaHB9gypq0jTGp/0fkMwRLToJ8jkLtWG4LV+JoQ/erFQnVARkR3Q807n0VnES15EYP4ITMQ==
"@react-navigation/elements@^1.3.15":
version "1.3.15"
resolved "https://registry.yarnpkg.com/@react-navigation/elements/-/elements-1.3.15.tgz#b8aebf101080057508b98cb5da4173c72c095db0"
integrity sha512-CR4CEYJVY0OLyeLQi9N3Z2o4K47gXctvFxfZizDuW1xFtCJbA0eGvpjSLXEWHoY0hFjrlC6KinpdepGHVxhYIg==
"@react-navigation/native-stack@^6.9.9":
version "6.9.9"
resolved "https://registry.yarnpkg.com/@react-navigation/native-stack/-/native-stack-6.9.9.tgz#346c393e48d681c15e5831d7749fb807f76dcdce"
integrity sha512-FIbTCEjqAt6guQ90lKIDvOfTo5vtKGG+aQTtHMdTV9JLGnS6gFsBgXmv5hvWLkyd426Nc04mpZXPTK7d80v/LQ==
version "6.9.10"
resolved "https://registry.yarnpkg.com/@react-navigation/native-stack/-/native-stack-6.9.10.tgz#5a5d5de9f49b72e603d0cdca9771e0324f65c1c7"
integrity sha512-dSazcWNxHg4qkid/AxFRvbhRtNXy/RqE00h/Qp+d7aBN0TwrOJn8mH/Inkkf4pHAntMbj0+mVAlKfxKmyLEGlA==
dependencies:
"@react-navigation/elements" "^1.3.14"
"@react-navigation/elements" "^1.3.15"
warn-once "^0.1.0"
"@react-navigation/native@^6.1.3":
version "6.1.3"
resolved "https://registry.yarnpkg.com/@react-navigation/native/-/native-6.1.3.tgz#06064c5e49c417a3dbe210b3f00841beefd326c5"
integrity sha512-DB5FyG6aqGfcjjVozljF5NEkjWaSymIbQHfWwsjL0YrvC1gfc7E53QXDOjxZ/wfbCo8qZs8RIC/LAgclP2YK/w==
version "6.1.4"
resolved "https://registry.yarnpkg.com/@react-navigation/native/-/native-6.1.4.tgz#49666596c9df16e22284f35f482d05d6b5d47d60"
integrity sha512-8IGpMFvD21XINpSf9gyU19yv4O+NyF9FQAxEzwbJSef19W5XEJKXPN/0RINc43Tt+YnQyFGQ2+qJM1uoB9pKcA==
dependencies:
"@react-navigation/core" "^6.4.6"
escape-string-regexp "^4.0.0"
@ -1201,9 +1201,9 @@
integrity sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==
"@sinclair/typebox@^0.25.16":
version "0.25.21"
resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.25.21.tgz#763b05a4b472c93a8db29b2c3e359d55b29ce272"
integrity sha512-gFukHN4t8K4+wVC+ECqeqwzBDeFeTzBXroBTqE6vcWrQGbEUpHO7LYdG0f4xnvYq4VOEwITSlHlp0JBAIFMS/g==
version "0.25.22"
resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.25.22.tgz#2808d895e9c2722b20a622a9c8cb332f6720eb4a"
integrity sha512-6U6r2L7rnM7EG8G1tWzIjdB3QlsHF4slgcqXNN/SF0xJOAr0nDmT2GedlkyO3mrv8mDTJ24UuOMWR3diBrCvQQ==
"@sinonjs/commons@^2.0.0":
version "2.0.0"
@ -1275,23 +1275,23 @@
"@types/react-native" "*"
"@types/react-native@*", "@types/react-native@^0.71.2":
version "0.71.2"
resolved "https://registry.yarnpkg.com/@types/react-native/-/react-native-0.71.2.tgz#b8ba52c2fd07d3d64fa87ae5d9b4fbbd3b9cbffd"
integrity sha512-RJ0slxB/aVh6gDBZcGusDLIMW+ydsigzOVva9nODPfZApvIY4UgacV5PAlyk/CScJaN7Frh4sZaD9bD73uc9HQ==
version "0.71.3"
resolved "https://registry.yarnpkg.com/@types/react-native/-/react-native-0.71.3.tgz#537f669ed6b38b5ae47444bd9d253c4cff23bed7"
integrity sha512-0Uqw1YZ0qbVla0MMWFTANFm6W8KYWNvGQmYfucdecbXivLMcQ2v4PovuYFKr7bE6Bc5nDCUEaga962Y8gcDF7A==
dependencies:
"@types/react" "*"
"@types/react-native@^0.70":
version "0.70.10"
resolved "https://registry.yarnpkg.com/@types/react-native/-/react-native-0.70.10.tgz#494576e0dc20aa319003f0cdd99192124d64038d"
integrity sha512-m9B9hJk1w/c04zj5PCYTjJNXt+1UvKtzJj4nO/BjiS4s/zmUdkLdnbLqRQCQiTA0wuvvMbrffuPdheRtYu/M1Q==
version "0.70.11"
resolved "https://registry.yarnpkg.com/@types/react-native/-/react-native-0.70.11.tgz#50c3d81e1351aac0562c3341c9bd57885651a2fe"
integrity sha512-FobPtzoNPNHugBKMfzs4Li0Q9ei4tgU8SI1M5Ayg7+t5/+noCm2sknI8uwij22wMkcHcefv8RFx4q28nNVJtCQ==
dependencies:
"@types/react" "*"
"@types/react@*", "@types/react@^18.0.27":
version "18.0.27"
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.27.tgz#d9425abe187a00f8a5ec182b010d4fd9da703b71"
integrity sha512-3vtRKHgVxu3Jp9t718R9BuzoD4NcQ8YJ5XRzsSKxNDiDonD2MXIT1TmSkenxuCycZJoQT5d2vE8LwWJxBC1gmA==
version "18.0.28"
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.28.tgz#accaeb8b86f4908057ad629a26635fe641480065"
integrity sha512-RD0ivG1kEztNBdoAK7lekI9M+azSnitIn85h4iOiaLjaTrMjzslhaqCGaI4IyCJ1RljWiLCEu4jyrLLgqxBTew==
dependencies:
"@types/prop-types" "*"
"@types/scheduler" "*"
@ -1339,13 +1339,13 @@
"@types/yargs-parser" "*"
"@typescript-eslint/eslint-plugin@^5.30.5":
version "5.51.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.51.0.tgz#da3f2819633061ced84bb82c53bba45a6fe9963a"
integrity sha512-wcAwhEWm1RgNd7dxD/o+nnLW8oH+6RK1OGnmbmkj/GGoDPV1WWMVP0FXYQBivKHdwM1pwii3bt//RC62EriIUQ==
version "5.52.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.52.0.tgz#5fb0d43574c2411f16ea80f5fc335b8eaa7b28a8"
integrity sha512-lHazYdvYVsBokwCdKOppvYJKaJ4S41CgKBcPvyd0xjZNbvQdhn/pnJlGtQksQ/NhInzdaeaSarlBjDXHuclEbg==
dependencies:
"@typescript-eslint/scope-manager" "5.51.0"
"@typescript-eslint/type-utils" "5.51.0"
"@typescript-eslint/utils" "5.51.0"
"@typescript-eslint/scope-manager" "5.52.0"
"@typescript-eslint/type-utils" "5.52.0"
"@typescript-eslint/utils" "5.52.0"
debug "^4.3.4"
grapheme-splitter "^1.0.4"
ignore "^5.2.0"
@ -1355,71 +1355,71 @@
tsutils "^3.21.0"
"@typescript-eslint/parser@^5.30.5":
version "5.51.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.51.0.tgz#2d74626652096d966ef107f44b9479f02f51f271"
integrity sha512-fEV0R9gGmfpDeRzJXn+fGQKcl0inIeYobmmUWijZh9zA7bxJ8clPhV9up2ZQzATxAiFAECqPQyMDB4o4B81AaA==
version "5.52.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.52.0.tgz#73c136df6c0133f1d7870de7131ccf356f5be5a4"
integrity sha512-e2KiLQOZRo4Y0D/b+3y08i3jsekoSkOYStROYmPUnGMEoA0h+k2qOH5H6tcjIc68WDvGwH+PaOrP1XRzLJ6QlA==
dependencies:
"@typescript-eslint/scope-manager" "5.51.0"
"@typescript-eslint/types" "5.51.0"
"@typescript-eslint/typescript-estree" "5.51.0"
"@typescript-eslint/scope-manager" "5.52.0"
"@typescript-eslint/types" "5.52.0"
"@typescript-eslint/typescript-estree" "5.52.0"
debug "^4.3.4"
"@typescript-eslint/scope-manager@5.51.0":
version "5.51.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.51.0.tgz#ad3e3c2ecf762d9a4196c0fbfe19b142ac498990"
integrity sha512-gNpxRdlx5qw3yaHA0SFuTjW4rxeYhpHxt491PEcKF8Z6zpq0kMhe0Tolxt0qjlojS+/wArSDlj/LtE69xUJphQ==
"@typescript-eslint/scope-manager@5.52.0":
version "5.52.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.52.0.tgz#a993d89a0556ea16811db48eabd7c5b72dcb83d1"
integrity sha512-AR7sxxfBKiNV0FWBSARxM8DmNxrwgnYMPwmpkC1Pl1n+eT8/I2NAUPuwDy/FmDcC6F8pBfmOcaxcxRHspgOBMw==
dependencies:
"@typescript-eslint/types" "5.51.0"
"@typescript-eslint/visitor-keys" "5.51.0"
"@typescript-eslint/types" "5.52.0"
"@typescript-eslint/visitor-keys" "5.52.0"
"@typescript-eslint/type-utils@5.51.0":
version "5.51.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.51.0.tgz#7af48005531700b62a20963501d47dfb27095988"
integrity sha512-QHC5KKyfV8sNSyHqfNa0UbTbJ6caB8uhcx2hYcWVvJAZYJRBo5HyyZfzMdRx8nvS+GyMg56fugMzzWnojREuQQ==
"@typescript-eslint/type-utils@5.52.0":
version "5.52.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.52.0.tgz#9fd28cd02e6f21f5109e35496df41893f33167aa"
integrity sha512-tEKuUHfDOv852QGlpPtB3lHOoig5pyFQN/cUiZtpw99D93nEBjexRLre5sQZlkMoHry/lZr8qDAt2oAHLKA6Jw==
dependencies:
"@typescript-eslint/typescript-estree" "5.51.0"
"@typescript-eslint/utils" "5.51.0"
"@typescript-eslint/typescript-estree" "5.52.0"
"@typescript-eslint/utils" "5.52.0"
debug "^4.3.4"
tsutils "^3.21.0"
"@typescript-eslint/types@5.51.0":
version "5.51.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.51.0.tgz#e7c1622f46c7eea7e12bbf1edfb496d4dec37c90"
integrity sha512-SqOn0ANn/v6hFn0kjvLwiDi4AzR++CBZz0NV5AnusT2/3y32jdc0G4woXPWHCumWtUXZKPAS27/9vziSsC9jnw==
"@typescript-eslint/types@5.52.0":
version "5.52.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.52.0.tgz#19e9abc6afb5bd37a1a9bea877a1a836c0b3241b"
integrity sha512-oV7XU4CHYfBhk78fS7tkum+/Dpgsfi91IIDy7fjCyq2k6KB63M6gMC0YIvy+iABzmXThCRI6xpCEyVObBdWSDQ==
"@typescript-eslint/typescript-estree@5.51.0":
version "5.51.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.51.0.tgz#0ec8170d7247a892c2b21845b06c11eb0718f8de"
integrity sha512-TSkNupHvNRkoH9FMA3w7TazVFcBPveAAmb7Sz+kArY6sLT86PA5Vx80cKlYmd8m3Ha2SwofM1KwraF24lM9FvA==
"@typescript-eslint/typescript-estree@5.52.0":
version "5.52.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.52.0.tgz#6408cb3c2ccc01c03c278cb201cf07e73347dfca"
integrity sha512-WeWnjanyEwt6+fVrSR0MYgEpUAuROxuAH516WPjUblIrClzYJj0kBbjdnbQXLpgAN8qbEuGywiQsXUVDiAoEuQ==
dependencies:
"@typescript-eslint/types" "5.51.0"
"@typescript-eslint/visitor-keys" "5.51.0"
"@typescript-eslint/types" "5.52.0"
"@typescript-eslint/visitor-keys" "5.52.0"
debug "^4.3.4"
globby "^11.1.0"
is-glob "^4.0.3"
semver "^7.3.7"
tsutils "^3.21.0"
"@typescript-eslint/utils@5.51.0", "@typescript-eslint/utils@^5.10.0":
version "5.51.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.51.0.tgz#074f4fabd5b12afe9c8aa6fdee881c050f8b4d47"
integrity sha512-76qs+5KWcaatmwtwsDJvBk4H76RJQBFe+Gext0EfJdC3Vd2kpY2Pf//OHHzHp84Ciw0/rYoGTDnIAr3uWhhJYw==
"@typescript-eslint/utils@5.52.0", "@typescript-eslint/utils@^5.10.0":
version "5.52.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.52.0.tgz#b260bb5a8f6b00a0ed51db66bdba4ed5e4845a72"
integrity sha512-As3lChhrbwWQLNk2HC8Ree96hldKIqk98EYvypd3It8Q1f8d5zWyIoaZEp2va5667M4ZyE7X8UUR+azXrFl+NA==
dependencies:
"@types/json-schema" "^7.0.9"
"@types/semver" "^7.3.12"
"@typescript-eslint/scope-manager" "5.51.0"
"@typescript-eslint/types" "5.51.0"
"@typescript-eslint/typescript-estree" "5.51.0"
"@typescript-eslint/scope-manager" "5.52.0"
"@typescript-eslint/types" "5.52.0"
"@typescript-eslint/typescript-estree" "5.52.0"
eslint-scope "^5.1.1"
eslint-utils "^3.0.0"
semver "^7.3.7"
"@typescript-eslint/visitor-keys@5.51.0":
version "5.51.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.51.0.tgz#c0147dd9a36c0de758aaebd5b48cae1ec59eba87"
integrity sha512-Oh2+eTdjHjOFjKA27sxESlA87YPSOJafGCR0md5oeMdh1ZcCfAGCIOL216uTBAkAIptvLIfKQhl7lHxMJet4GQ==
"@typescript-eslint/visitor-keys@5.52.0":
version "5.52.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.52.0.tgz#e38c971259f44f80cfe49d97dbffa38e3e75030f"
integrity sha512-qMwpw6SU5VHCPr99y274xhbm+PRViK/NATY6qzt+Et7+mThGuFSl/ompj2/hrBlRP/kq+BFdgagnOSgw9TB0eA==
dependencies:
"@typescript-eslint/types" "5.51.0"
"@typescript-eslint/types" "5.52.0"
eslint-visitor-keys "^3.3.0"
abort-controller@^3.0.0:
@ -1777,7 +1777,7 @@ braces@^3.0.2:
dependencies:
fill-range "^7.0.1"
browserslist@^4.21.3, browserslist@^4.21.4:
browserslist@^4.21.3, browserslist@^4.21.5:
version "4.21.5"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.5.tgz#75c5dae60063ee641f977e00edd3cfb2fb7af6a7"
integrity sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==
@ -1870,9 +1870,9 @@ camelcase@^6.0.0:
integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==
caniuse-lite@^1.0.30001449:
version "1.0.30001451"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001451.tgz#2e197c698fc1373d63e1406d6607ea4617c613f1"
integrity sha512-XY7UbUpGRatZzoRft//5xOa69/1iGJRBlrieH6QYrkKLIFn3m7OVEJ81dSrKoy2BnKsdbX5cLrOispZNYo9v2w==
version "1.0.30001452"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001452.tgz#dff7b8bb834b3a91808f0a9ff0453abb1fbba02a"
integrity sha512-Lkp0vFjMkBB3GTpLR8zk4NwW5EdRdnitwYJHDOOKIU85x4ckYCPQ+9WlVvSVClHxVReefkUMtWZH2l9KGlD51w==
chalk@^2.0.0:
version "2.4.2"
@ -1897,9 +1897,9 @@ ci-info@^2.0.0:
integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==
ci-info@^3.2.0:
version "3.7.1"
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.7.1.tgz#708a6cdae38915d597afdf3b145f2f8e1ff55f3f"
integrity sha512-4jYS4MOAaCIStSRwiuxc4B8MYhIe676yO1sYGzARnjXkWpmzZMMYxY6zu8WYWDhSuth5zhrQ1rhNSibyyvv4/w==
version "3.8.0"
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.8.0.tgz#81408265a5380c929f0bc665d62256628ce9ef91"
integrity sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==
class-utils@^0.3.5:
version "0.3.6"
@ -2077,11 +2077,11 @@ copy-descriptor@^0.1.0:
integrity sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==
core-js-compat@^3.25.1:
version "3.27.2"
resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.27.2.tgz#607c50ad6db8fd8326af0b2883ebb987be3786da"
integrity sha512-welaYuF7ZtbYKGrIy7y3eb40d37rG1FvzEOfe7hSLd2iD6duMDqUhRfSvCGyC46HhR6Y8JXXdZ2lnRUMkPBpvg==
version "3.28.0"
resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.28.0.tgz#c08456d854608a7264530a2afa281fadf20ecee6"
integrity sha512-myzPgE7QodMg4nnd3K1TDoES/nADRStM8Gpz0D6nhkwbmwEnE0ZGJgoWsvQ722FR8D7xS0n0LV556RcEicjTyg==
dependencies:
browserslist "^4.21.4"
browserslist "^4.21.5"
core-util-is@~1.0.0:
version "1.0.3"
@ -2170,9 +2170,9 @@ defaults@^1.0.3:
clone "^1.0.2"
define-properties@^1.1.3, define-properties@^1.1.4:
version "1.1.4"
resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.4.tgz#0b14d7bd7fbeb2f3572c3a7eda80ea5d57fb05b1"
integrity sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==
version "1.2.0"
resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.0.tgz#52988570670c9eacedd8064f4a990f2405849bd5"
integrity sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==
dependencies:
has-property-descriptors "^1.0.0"
object-keys "^1.1.1"
@ -2259,9 +2259,9 @@ ee-first@1.1.1:
integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==
electron-to-chromium@^1.4.284:
version "1.4.294"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.294.tgz#ad80317b85f0859a9454680fbc1c726fefa7e6fd"
integrity sha512-PuHZB3jEN7D8WPPjLmBQAsqQz8tWHlkkB4n0E2OYw8RwVdmBYV0Wn+rUFH8JqYyIRb4HQhhedgxlZL163wqLrQ==
version "1.4.296"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.296.tgz#dbc84a25c25a432a12fbf62903cae4a87461eb8c"
integrity sha512-i/6Q+Y9bluDa2a0NbMvdtG5TuS/1Fr3TKK8L+7UUL9QjRS5iFJzCC3r70xjyOnLiYG8qGV4/mMpe6HuAbdJW4w==
eme-encryption-scheme-polyfill@^2.0.1:
version "2.1.1"
@ -2509,9 +2509,9 @@ eslint-visitor-keys@^3.3.0:
integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==
eslint@^8.33.0:
version "8.33.0"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.33.0.tgz#02f110f32998cb598c6461f24f4d306e41ca33d7"
integrity sha512-WjOpFQgKK8VrCnAtl8We0SUOy/oVZ5NHykyMiagV1M9r8IFpIJX7DduK6n1mpfhlG7T1NLWm2SuD8QB7KFySaA==
version "8.34.0"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.34.0.tgz#fe0ab0ef478104c1f9ebc5537e303d25a8fb22d6"
integrity sha512-1Z8iFsucw+7kSqXNZVslXS8Ioa4u2KM7GPwuKtkTFAqZ/cHMcEaR+1+Br0wLlot49cNxIiZk5wp8EAbPcYZxTg==
dependencies:
"@eslint/eslintrc" "^1.4.1"
"@humanwhocodes/config-array" "^0.11.8"
@ -3451,45 +3451,45 @@ isobject@^3.0.0, isobject@^3.0.1:
integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==
jest-environment-node@^29.2.1:
version "29.4.2"
resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-29.4.2.tgz#0eab835b41e25fd0c1a72f62665fc8db08762ad2"
integrity sha512-MLPrqUcOnNBc8zTOfqBbxtoa8/Ee8tZ7UFW7hRDQSUT+NGsvS96wlbHGTf+EFAT9KC3VNb7fWEM6oyvmxtE/9w==
version "29.4.3"
resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-29.4.3.tgz#579c4132af478befc1889ddc43c2413a9cdbe014"
integrity sha512-gAiEnSKF104fsGDXNkwk49jD/0N0Bqu2K9+aMQXA6avzsA9H3Fiv1PW2D+gzbOSR705bWd2wJZRFEFpV0tXISg==
dependencies:
"@jest/environment" "^29.4.2"
"@jest/fake-timers" "^29.4.2"
"@jest/types" "^29.4.2"
"@jest/environment" "^29.4.3"
"@jest/fake-timers" "^29.4.3"
"@jest/types" "^29.4.3"
"@types/node" "*"
jest-mock "^29.4.2"
jest-util "^29.4.2"
jest-mock "^29.4.3"
jest-util "^29.4.3"
jest-get-type@^26.3.0:
version "26.3.0"
resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-26.3.0.tgz#e97dc3c3f53c2b406ca7afaed4493b1d099199e0"
integrity sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==
jest-message-util@^29.4.2:
version "29.4.2"
resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.4.2.tgz#309a2924eae6ca67cf7f25781a2af1902deee717"
integrity sha512-SElcuN4s6PNKpOEtTInjOAA8QvItu0iugkXqhYyguRvQoXapg5gN+9RQxLAkakChZA7Y26j6yUCsFWN+hlKD6g==
jest-message-util@^29.4.3:
version "29.4.3"
resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.4.3.tgz#65b5280c0fdc9419503b49d4f48d4999d481cb5b"
integrity sha512-1Y8Zd4ZCN7o/QnWdMmT76If8LuDv23Z1DRovBj/vcSFNlGCJGoO8D1nJDw1AdyAGUk0myDLFGN5RbNeJyCRGCw==
dependencies:
"@babel/code-frame" "^7.12.13"
"@jest/types" "^29.4.2"
"@jest/types" "^29.4.3"
"@types/stack-utils" "^2.0.0"
chalk "^4.0.0"
graceful-fs "^4.2.9"
micromatch "^4.0.4"
pretty-format "^29.4.2"
pretty-format "^29.4.3"
slash "^3.0.0"
stack-utils "^2.0.3"
jest-mock@^29.4.2:
version "29.4.2"
resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.4.2.tgz#e1054be66fb3e975d26d4528fcde6979e4759de8"
integrity sha512-x1FSd4Gvx2yIahdaIKoBjwji6XpboDunSJ95RpntGrYulI1ByuYQCKN/P7hvk09JB74IonU3IPLdkutEWYt++g==
jest-mock@^29.4.3:
version "29.4.3"
resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.4.3.tgz#23d84a20a74cdfff0510fdbeefb841ed57b0fe7e"
integrity sha512-LjFgMg+xed9BdkPMyIJh+r3KeHt1klXPJYBULXVVAkbTaaKjPX1o1uVCAZADMEp/kOxGTwy/Ot8XbvgItOrHEg==
dependencies:
"@jest/types" "^29.4.2"
"@jest/types" "^29.4.3"
"@types/node" "*"
jest-util "^29.4.2"
jest-util "^29.4.3"
jest-regex-util@^27.0.6:
version "27.5.1"
@ -3516,12 +3516,12 @@ jest-util@^27.2.0:
graceful-fs "^4.2.9"
picomatch "^2.2.3"
jest-util@^29.4.2:
version "29.4.2"
resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.4.2.tgz#3db8580b295df453a97de4a1b42dd2578dabd2c2"
integrity sha512-wKnm6XpJgzMUSRFB7YF48CuwdzuDIHenVuoIb1PLuJ6F+uErZsuDkU+EiExkChf6473XcawBrSfDSnXl+/YG4g==
jest-util@^29.4.3:
version "29.4.3"
resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.4.3.tgz#851a148e23fc2b633c55f6dad2e45d7f4579f496"
integrity sha512-ToSGORAz4SSSoqxDSylWX8JzkOQR7zoBtNRsA7e+1WUX5F8jrOwaNpuh1YfJHJKDHXLHmObv5eOjejUd+/Ws+Q==
dependencies:
"@jest/types" "^29.4.2"
"@jest/types" "^29.4.3"
"@types/node" "*"
chalk "^4.0.0"
ci-info "^3.2.0"
@ -3585,10 +3585,10 @@ js-yaml@^4.1.0:
dependencies:
argparse "^2.0.1"
jsc-android@^250230.2.1:
version "250230.2.1"
resolved "https://registry.yarnpkg.com/jsc-android/-/jsc-android-250230.2.1.tgz#3790313a970586a03ab0ad47defbc84df54f1b83"
integrity sha512-KmxeBlRjwoqCnBBKGsihFtvsBHyUFlBxJPK4FzeYcIuBfdjv6jFys44JITAgSTbQD+vIdwMEfyZklsuQX0yI1Q==
jsc-android@^250231.0.0:
version "250231.0.0"
resolved "https://registry.yarnpkg.com/jsc-android/-/jsc-android-250231.0.0.tgz#91720f8df382a108872fa4b3f558f33ba5e95262"
integrity sha512-rS46PvsjYmdmuz1OAWXY/1kCYG7pnf1TBqeTiOJr1iDz7s5DLxxC9n/ZMknLDxzYzNVfI7R95MH10emSSG1Wuw==
jscodeshift@^0.13.1:
version "0.13.1"
@ -4912,12 +4912,12 @@ pretty-format@^26.5.2, pretty-format@^26.6.2:
ansi-styles "^4.0.0"
react-is "^17.0.1"
pretty-format@^29.4.2:
version "29.4.2"
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.4.2.tgz#64bf5ccc0d718c03027d94ac957bdd32b3fb2401"
integrity sha512-qKlHR8yFVCbcEWba0H0TOC8dnLlO4vPlyEjRPw31FZ2Rupy9nLa8ZLbYny8gWEl8CkEhJqAE6IzdNELTBVcBEg==
pretty-format@^29.4.3:
version "29.4.3"
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.4.3.tgz#25500ada21a53c9e8423205cf0337056b201244c"
integrity sha512-cvpcHTc42lcsvOOAzd3XuNWTcvk1Jmnzqeu+WsOuiPmxUJTnkbAcFNsRKvEpBEUFVUgy/GTZLulZDcDEi+CIlA==
dependencies:
"@jest/schemas" "^29.4.2"
"@jest/schemas" "^29.4.3"
ansi-styles "^5.0.0"
react-is "^18.0.0"
@ -5011,10 +5011,10 @@ react-is@^17.0.1:
resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0"
integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==
react-native-codegen@^0.71.3:
version "0.71.3"
resolved "https://registry.yarnpkg.com/react-native-codegen/-/react-native-codegen-0.71.3.tgz#75fbc591819050791319ebdb9fe341ee4df5c288"
integrity sha512-5AvdHVU1sAaXg05i0dG664ZTaCaIFaY1znV5vNsj+wUu6MGxNEUNbDKk9dxKUkkxOyk2KZOK5uhzWL0p5H5yZQ==
react-native-codegen@^0.71.5:
version "0.71.5"
resolved "https://registry.yarnpkg.com/react-native-codegen/-/react-native-codegen-0.71.5.tgz#454a42a891cd4ca5fc436440d301044dc1349c14"
integrity sha512-rfsuc0zkuUuMjFnrT55I1mDZ+pBRp2zAiRwxck3m6qeGJBGK5OV5JH66eDQ4aa+3m0of316CqrJDRzVlYufzIg==
dependencies:
"@babel/parser" "^7.14.0"
flow-parser "^0.185.0"
@ -5032,20 +5032,19 @@ react-native-gesture-handler@^2.9.0:
lodash "^4.17.21"
prop-types "^15.7.2"
react-native-gradle-plugin@^0.71.14:
version "0.71.14"
resolved "https://registry.yarnpkg.com/react-native-gradle-plugin/-/react-native-gradle-plugin-0.71.14.tgz#cc399662f04fbfcc0e352d03eae1d3efbd5f635a"
integrity sha512-nnLawTZEPPRAKq92UqDkzoGgCBl9aa9zAihFHMwmwzn4WRVdK4O6Cd4XYiyoNOiQzx3Hh9k5WOckHE80C92ivQ==
react-native-gradle-plugin@^0.71.15:
version "0.71.15"
resolved "https://registry.yarnpkg.com/react-native-gradle-plugin/-/react-native-gradle-plugin-0.71.15.tgz#9e6b506f30729fe8eb086981702f4e3c891d2b13"
integrity sha512-7S3pAuPaQJlhax6EZ4JMsDNpj05TfuzX9gPgWLrFfAIWIFLuJ6aDQYAZy2TEI9QJALPoWrj8LWaqP/DGYh14pw==
react-native-pressable-opacity@^1.0.10:
version "1.0.10"
resolved "https://registry.yarnpkg.com/react-native-pressable-opacity/-/react-native-pressable-opacity-1.0.10.tgz#799df1a913d3b28f42ada765465fe7723eb7166d"
integrity sha512-Py9YH9TlS3Lv1so5JCj6bgiqkeYYGupF4ZImlpoyhhId/t/RiSqR68LlASOHgdctqQuqVJObQiFfzX8oZI9+6w==
react-native-reanimated@^3.0.0-rc.10:
"react-native-reanimated@https://github.com/software-mansion/react-native-reanimated#6cf9713a44ec61318bbb12c311f79c08eda95d10":
version "3.0.0-rc.10"
resolved "https://registry.yarnpkg.com/react-native-reanimated/-/react-native-reanimated-3.0.0-rc.10.tgz#40e5b628759aa81f94317fd0301231292b4eacf5"
integrity sha512-0P2jSO+dXHRxSzqSxNp08VaUy89nqeUIvqBS0wlI8lsli8CJcqulL3pjNqTGzBkxXjt13mGdIzJv4u9lSjHPzg==
resolved "https://github.com/software-mansion/react-native-reanimated#6cf9713a44ec61318bbb12c311f79c08eda95d10"
dependencies:
"@babel/plugin-transform-object-assign" "^7.16.7"
"@babel/preset-typescript" "^7.16.7"
@ -5061,9 +5060,9 @@ react-native-safe-area-context@^4.5.0:
integrity sha512-0WORnk9SkREGUg2V7jHZbuN5x4vcxj/1B0QOcXJjdYWrzZHgLcUzYWWIUecUPJh747Mwjt/42RZDOaFn3L8kPQ==
react-native-screens@^3.19.0:
version "3.19.0"
resolved "https://registry.yarnpkg.com/react-native-screens/-/react-native-screens-3.19.0.tgz#ec68685e04b074ebce4641b3a0ae7e2571629b75"
integrity sha512-Ehsmy7jr3H3j5pmN+/FqsAaIAD+k+xkcdePfLcg4rYRbN5X7fJPgaqhcmiCcZ0YxsU8ttsstP9IvRLNQuIkRRA==
version "3.20.0"
resolved "https://registry.yarnpkg.com/react-native-screens/-/react-native-screens-3.20.0.tgz#4d154177395e5541387d9a05bc2e12e54d2fb5b1"
integrity sha512-joWUKWAVHxymP3mL9gYApFHAsbd9L6ZcmpoZa6Sl3W/82bvvNVMqcfP7MeNqVCg73qZ8yL4fW+J/syusHleUgg==
dependencies:
react-freeze "^1.0.0"
warn-once "^0.1.0"
@ -5091,14 +5090,14 @@ react-native-video@^5.2.1:
prop-types "^15.7.2"
shaka-player "^2.5.9"
"react-native-worklets@https://github.com/chrfalch/react-native-worklets#50950aa":
"react-native-worklets@https://github.com/chrfalch/react-native-worklets#15d52dd":
version "0.1.0"
resolved "https://github.com/chrfalch/react-native-worklets#50950aa1b671a0d8a9e79878e63a3445991e7192"
resolved "https://github.com/chrfalch/react-native-worklets#15d52dd1289831cecc7906823f613172e0c6cd2e"
react-native@^0.71.2:
version "0.71.2"
resolved "https://registry.yarnpkg.com/react-native/-/react-native-0.71.2.tgz#b6977eda2a6dc10baa006bf4ab1ee08318607ce9"
integrity sha512-ZSianM+j+09LoEdVIhrAP/uP8sQhT7dH6olCqM2xlpxmfCgA5NubsK6NABIuZiBlmmqjigyijm5Y/GhBIHDvEg==
react-native@^0.71.3:
version "0.71.3"
resolved "https://registry.yarnpkg.com/react-native/-/react-native-0.71.3.tgz#0faab799c49e61ba12df9e6525c3ac7d595d673c"
integrity sha512-RYJXCcQGa4NTfKiPgl92eRDUuQ6JGDnHqFEzRwJSqEx9lWvlvRRIebstJfurzPDKLQWQrvITR7aI7e09E25mLw==
dependencies:
"@jest/create-cache-key-function" "^29.2.1"
"@react-native-community/cli" "10.1.3"
@ -5114,7 +5113,7 @@ react-native@^0.71.2:
event-target-shim "^5.0.1"
invariant "^2.2.4"
jest-environment-node "^29.2.1"
jsc-android "^250230.2.1"
jsc-android "^250231.0.0"
memoize-one "^5.0.0"
metro-react-native-babel-transformer "0.73.7"
metro-runtime "0.73.7"
@ -5124,8 +5123,8 @@ react-native@^0.71.2:
pretty-format "^26.5.2"
promise "^8.3.0"
react-devtools-core "^4.26.1"
react-native-codegen "^0.71.3"
react-native-gradle-plugin "^0.71.14"
react-native-codegen "^0.71.5"
react-native-gradle-plugin "^0.71.15"
react-refresh "^0.4.0"
react-shallow-renderer "^16.15.0"
regenerator-runtime "^0.13.2"

View File

@ -17,20 +17,13 @@ public class CameraQueues: NSObject {
autoreleaseFrequency: .inherit,
target: nil)
/// The serial execution queue for output processing of videos for recording.
/// The serial execution queue for output processing of videos for recording or synchronous frame processing.
@objc public static let videoQueue = DispatchQueue(label: "mrousavy/VisionCamera.video",
qos: .userInteractive,
attributes: [],
autoreleaseFrequency: .inherit,
target: nil)
/// The serial execution queue for output processing of videos for frame processing.
@objc public static let frameProcessorQueue = DispatchQueue(label: "mrousavy/VisionCamera.frame-processor",
qos: .userInteractive,
attributes: [],
autoreleaseFrequency: .inherit,
target: nil)
/// The serial execution queue for output processing of audio buffers.
@objc public static let audioQueue = DispatchQueue(label: "mrousavy/VisionCamera.audio",
qos: .userInteractive,

View File

@ -190,8 +190,8 @@ extension CameraView: AVCaptureVideoDataOutputSampleBufferDelegate, AVCaptureAud
}
public final func captureOutput(_ captureOutput: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from _: AVCaptureConnection) {
// Video Recording runs in the same queue
if isRecording {
// Write Video / Audio frame to file
guard let recordingSession = recordingSession else {
invokeOnError(.capture(.unknown(message: "isRecording was true but the RecordingSession was null!")))
return
@ -211,54 +211,9 @@ extension CameraView: AVCaptureVideoDataOutputSampleBufferDelegate, AVCaptureAud
}
if let frameProcessor = frameProcessorCallback, captureOutput is AVCaptureVideoDataOutput {
// check if last frame was x nanoseconds ago, effectively throttling FPS
let frameTime = UInt64(CMSampleBufferGetPresentationTimeStamp(sampleBuffer).seconds * 1_000_000_000.0)
let lastFrameProcessorCallElapsedTime = frameTime - lastFrameProcessorCall
let secondsPerFrame = 1.0 / actualFrameProcessorFps
let nanosecondsPerFrame = secondsPerFrame * 1_000_000_000.0
if lastFrameProcessorCallElapsedTime >= UInt64(nanosecondsPerFrame) {
if !isRunningFrameProcessor {
// we're not in the middle of executing the Frame Processor, so prepare for next call.
CameraQueues.frameProcessorQueue.async {
self.isRunningFrameProcessor = true
let perfSample = self.frameProcessorPerformanceDataCollector.beginPerformanceSampleCollection()
// Call the JavaScript Frame Processor func (worklet)
let frame = Frame(buffer: sampleBuffer, orientation: self.bufferOrientation)
frameProcessor(frame)
perfSample.endPerformanceSampleCollection()
self.isRunningFrameProcessor = false
}
lastFrameProcessorCall = frameTime
} else {
// we're still in the middle of executing a Frame Processor for a previous frame, so a frame was dropped.
ReactLogger.log(level: .warning, message: "The Frame Processor took so long to execute that a frame was dropped.")
}
}
if isReadyForNewEvaluation {
// last evaluation was more than 1sec ago, evaluate again
evaluateNewPerformanceSamples()
}
}
}
private func evaluateNewPerformanceSamples() {
lastFrameProcessorPerformanceEvaluation = DispatchTime.now()
guard let videoDevice = videoDeviceInput?.device else { return }
guard frameProcessorPerformanceDataCollector.hasEnoughData else { return }
let maxFrameProcessorFps = Double(videoDevice.activeVideoMinFrameDuration.timescale) * Double(videoDevice.activeVideoMinFrameDuration.value)
let averageFps = 1.0 / frameProcessorPerformanceDataCollector.averageExecutionTimeSeconds
let suggestedFrameProcessorFps = max(floor(min(averageFps, maxFrameProcessorFps)), 1)
if frameProcessorFps.intValue == -1 {
// frameProcessorFps="auto"
actualFrameProcessorFps = suggestedFrameProcessorFps
} else {
// frameProcessorFps={someCustomFpsValue}
invokeOnFrameProcessorPerformanceSuggestionAvailable(currentFps: frameProcessorFps.doubleValue,
suggestedFps: suggestedFrameProcessorFps)
}
}
@ -270,11 +225,6 @@ extension CameraView: AVCaptureVideoDataOutputSampleBufferDelegate, AVCaptureAud
}
}
private var isReadyForNewEvaluation: Bool {
let lastPerformanceEvaluationElapsedTime = DispatchTime.now().uptimeNanoseconds - lastFrameProcessorPerformanceEvaluation.uptimeNanoseconds
return lastPerformanceEvaluationElapsedTime > 1_000_000_000
}
/**
Gets the orientation of the CameraView's images (CMSampleBuffers).
*/

View File

@ -52,7 +52,6 @@ public final class CameraView: UIView {
// props that require format reconfiguring
@objc var format: NSDictionary?
@objc var fps: NSNumber?
@objc var frameProcessorFps: NSNumber = -1.0 // "auto"
@objc var hdr: NSNumber? // nullable bool
@objc var lowLightBoost: NSNumber? // nullable bool
@objc var colorSpace: NSString?
@ -65,7 +64,6 @@ public final class CameraView: UIView {
// events
@objc var onInitialized: RCTDirectEventBlock?
@objc var onError: RCTDirectEventBlock?
@objc var onFrameProcessorPerformanceSuggestionAvailable: RCTDirectEventBlock?
@objc var onViewReady: RCTDirectEventBlock?
// zoom
@objc var enableZoomGesture = false {
@ -105,13 +103,6 @@ public final class CameraView: UIView {
internal let videoQueue = CameraQueues.videoQueue
internal let audioQueue = CameraQueues.audioQueue
/// Specifies whether the frameProcessor() function is currently executing. used to drop late frames.
internal var isRunningFrameProcessor = false
internal let frameProcessorPerformanceDataCollector = FrameProcessorPerformanceDataCollector()
internal var actualFrameProcessorFps = 30.0
internal var lastSuggestedFrameProcessorFps = 0.0
internal var lastFrameProcessorPerformanceEvaluation = DispatchTime.now()
/// Returns whether the AVCaptureSession is currently running (reflected by isActive)
var isRunning: Bool {
return captureSession.isRunning
@ -259,18 +250,6 @@ public final class CameraView: UIView {
}
}
}
// Frame Processor FPS Configuration
if changedProps.contains("frameProcessorFps") {
if frameProcessorFps.doubleValue == -1 {
// "auto"
actualFrameProcessorFps = 30.0
} else {
actualFrameProcessorFps = frameProcessorFps.doubleValue
}
lastFrameProcessorPerformanceEvaluation = DispatchTime.now()
frameProcessorPerformanceDataCollector.clear()
}
}
internal final func setTorchMode(_ torchMode: String) {
@ -343,18 +322,4 @@ public final class CameraView: UIView {
guard let onInitialized = onInitialized else { return }
onInitialized([String: Any]())
}
internal final func invokeOnFrameProcessorPerformanceSuggestionAvailable(currentFps: Double, suggestedFps: Double) {
ReactLogger.log(level: .info, message: "Frame Processor Performance Suggestion available!")
guard let onFrameProcessorPerformanceSuggestionAvailable = onFrameProcessorPerformanceSuggestionAvailable else { return }
if lastSuggestedFrameProcessorFps == suggestedFps { return }
if suggestedFps == currentFps { return }
onFrameProcessorPerformanceSuggestionAvailable([
"type": suggestedFps > currentFps ? "can-use-higher-fps" : "should-use-lower-fps",
"suggestedFrameProcessorFps": suggestedFps,
])
lastSuggestedFrameProcessorFps = suggestedFps
}
}

View File

@ -35,7 +35,6 @@ RCT_EXPORT_VIEW_PROPERTY(enableFrameProcessor, BOOL);
// device format
RCT_EXPORT_VIEW_PROPERTY(format, NSDictionary);
RCT_EXPORT_VIEW_PROPERTY(fps, NSNumber);
RCT_EXPORT_VIEW_PROPERTY(frameProcessorFps, NSNumber);
RCT_EXPORT_VIEW_PROPERTY(hdr, NSNumber); // nullable bool
RCT_EXPORT_VIEW_PROPERTY(lowLightBoost, NSNumber); // nullable bool
RCT_EXPORT_VIEW_PROPERTY(colorSpace, NSString);
@ -49,7 +48,6 @@ RCT_EXPORT_VIEW_PROPERTY(orientation, NSString);
// Camera View Events
RCT_EXPORT_VIEW_PROPERTY(onError, RCTDirectEventBlock);
RCT_EXPORT_VIEW_PROPERTY(onInitialized, RCTDirectEventBlock);
RCT_EXPORT_VIEW_PROPERTY(onFrameProcessorPerformanceSuggestionAvailable, RCTDirectEventBlock);
RCT_EXPORT_VIEW_PROPERTY(onViewReady, RCTDirectEventBlock);
// Camera View Functions

View File

@ -16,16 +16,12 @@ using namespace facebook;
class JSI_EXPORT FrameHostObject: public jsi::HostObject {
public:
explicit FrameHostObject(Frame* frame): frame(frame) {}
explicit FrameHostObject(Frame* frame): frame(frame) { }
public:
jsi::Value get(jsi::Runtime&, const jsi::PropNameID& name) override;
std::vector<jsi::PropNameID> getPropertyNames(jsi::Runtime& rt) override;
void close();
public:
Frame* frame;
private:
void assertIsFrameStrong(jsi::Runtime& runtime, const std::string& accessedPropName);
};

View File

@ -9,16 +9,21 @@
#import "FrameHostObject.h"
#import <Foundation/Foundation.h>
#import <jsi/jsi.h>
#import "JsiHostObject.h"
#import "JsiSharedValue.h"
std::vector<jsi::PropNameID> FrameHostObject::getPropertyNames(jsi::Runtime& rt) {
std::vector<jsi::PropNameID> result;
result.push_back(jsi::PropNameID::forUtf8(rt, std::string("toString")));
result.push_back(jsi::PropNameID::forUtf8(rt, std::string("isValid")));
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("close")));
// Debugging
result.push_back(jsi::PropNameID::forUtf8(rt, std::string("toString")));
// 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")));
return result;
}
@ -26,7 +31,7 @@ jsi::Value FrameHostObject::get(jsi::Runtime& runtime, const jsi::PropNameID& pr
auto name = propName.utf8(runtime);
if (name == "toString") {
auto toString = [this] (jsi::Runtime& runtime, const jsi::Value&, const jsi::Value*, size_t) -> jsi::Value {
auto toString = JSI_HOST_FUNCTION_LAMBDA {
if (this->frame == nil) {
return jsi::String::createFromUtf8(runtime, "[closed frame]");
}
@ -39,60 +44,55 @@ 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 == "close") {
auto close = [this] (jsi::Runtime& runtime, const jsi::Value&, const jsi::Value*, size_t) -> jsi::Value {
if (this->frame == nil) {
throw jsi::JSError(runtime, "Trying to close an already closed frame! Did you call frame.close() twice?");
}
this->close();
if (name == "incrementRefCount") {
auto incrementRefCount = JSI_HOST_FUNCTION_LAMBDA {
// Increment retain count by one so ARC doesn't destroy the Frame Buffer.
CFRetain(frame.buffer);
return jsi::Value::undefined();
};
return jsi::Function::createFromHostFunction(runtime, jsi::PropNameID::forUtf8(runtime, "close"), 0, close);
return jsi::Function::createFromHostFunction(runtime,
jsi::PropNameID::forUtf8(runtime, "incrementRefCount"),
0,
incrementRefCount);
}
if (name == "decrementRefCount") {
auto decrementRefCount = JSI_HOST_FUNCTION_LAMBDA {
// Decrement retain count by one. If the retain count is zero, ARC will destroy the Frame Buffer.
CFRelease(frame.buffer);
return jsi::Value::undefined();
};
return jsi::Function::createFromHostFunction(runtime,
jsi::PropNameID::forUtf8(runtime, "decrementRefCount"),
0,
decrementRefCount);
}
if (name == "isValid") {
auto isValid = frame != nil && CMSampleBufferIsValid(frame.buffer);
auto isValid = frame != nil && frame.buffer != nil && CFGetRetainCount(frame.buffer) > 0 && CMSampleBufferIsValid(frame.buffer);
return jsi::Value(isValid);
}
if (name == "width") {
this->assertIsFrameStrong(runtime, name);
auto imageBuffer = CMSampleBufferGetImageBuffer(frame.buffer);
auto width = CVPixelBufferGetWidth(imageBuffer);
return jsi::Value((double) width);
}
if (name == "height") {
this->assertIsFrameStrong(runtime, name);
auto imageBuffer = CMSampleBufferGetImageBuffer(frame.buffer);
auto height = CVPixelBufferGetHeight(imageBuffer);
return jsi::Value((double) height);
}
if (name == "bytesPerRow") {
this->assertIsFrameStrong(runtime, name);
auto imageBuffer = CMSampleBufferGetImageBuffer(frame.buffer);
auto bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer);
return jsi::Value((double) bytesPerRow);
}
if (name == "planesCount") {
this->assertIsFrameStrong(runtime, name);
auto imageBuffer = CMSampleBufferGetImageBuffer(frame.buffer);
auto planesCount = CVPixelBufferGetPlaneCount(imageBuffer);
return jsi::Value((double) planesCount);
}
return jsi::Value::undefined();
}
void FrameHostObject::assertIsFrameStrong(jsi::Runtime &runtime, const std::string &accessedPropName) {
if (frame == nil) {
auto message = "Cannot get `" + accessedPropName + "`, frame is already closed!";
throw jsi::JSError(runtime, message.c_str());
}
}
void FrameHostObject::close() {
if (frame != nil) {
CMSampleBufferInvalidate(frame.buffer);
// ARC will hopefully delete it lol
this->frame = nil;
}
// fallback to base implementation
return HostObject::get(runtime, propName);
}

View File

@ -1,67 +0,0 @@
//
// FrameProcessorPerformanceDataCollector.swift
// VisionCamera
//
// Created by Marc Rousavy on 30.08.21.
// Copyright © 2021 mrousavy. All rights reserved.
//
import Foundation
// keep a maximum of `maxSampleSize` historical performance data samples cached.
private let maxSampleSize = 15
// MARK: - PerformanceSampleCollection
struct PerformanceSampleCollection {
var endPerformanceSampleCollection: () -> Void
init(end: @escaping () -> Void) {
endPerformanceSampleCollection = end
}
}
// MARK: - FrameProcessorPerformanceDataCollector
class FrameProcessorPerformanceDataCollector {
private var performanceSamples: [Double] = []
private var counter = 0
private var lastEvaluation = -1
var hasEnoughData: Bool {
return !performanceSamples.isEmpty
}
var averageExecutionTimeSeconds: Double {
let sum = performanceSamples.reduce(0, +)
let average = sum / Double(performanceSamples.count)
lastEvaluation = counter
return average
}
func beginPerformanceSampleCollection() -> PerformanceSampleCollection {
let begin = DispatchTime.now()
return PerformanceSampleCollection {
let end = DispatchTime.now()
let seconds = Double(end.uptimeNanoseconds - begin.uptimeNanoseconds) / 1_000_000_000.0
let index = self.counter % maxSampleSize
if self.performanceSamples.count > index {
self.performanceSamples[index] = seconds
} else {
self.performanceSamples.append(seconds)
}
self.counter += 1
}
}
func clear() {
counter = 0
performanceSamples.removeAll()
}
}

View File

@ -22,6 +22,7 @@
#import "JsiWorkletContext.h"
#import "JsiWorkletApi.h"
#import "JsiWorklet.h"
#import "JsiHostObject.h"
#import "FrameProcessorUtils.h"
#import "FrameProcessorCallback.h"
@ -30,7 +31,7 @@
// Forward declarations for the Swift classes
__attribute__((objc_runtime_name("_TtC12VisionCamera12CameraQueues")))
@interface CameraQueues : NSObject
@property (nonatomic, class, readonly, strong) dispatch_queue_t _Nonnull frameProcessorQueue;
@property (nonatomic, class, readonly, strong) dispatch_queue_t _Nonnull videoQueue;
@end
__attribute__((objc_runtime_name("_TtC12VisionCamera10CameraView")))
@interface CameraView : UIView
@ -38,6 +39,7 @@ __attribute__((objc_runtime_name("_TtC12VisionCamera10CameraView")))
@end
@implementation FrameProcessorRuntimeManager {
// Running Frame Processors on camera's video thread (synchronously)
std::shared_ptr<RNWorklet::JsiWorkletContext> workletContext;
}
@ -59,13 +61,12 @@ __attribute__((objc_runtime_name("_TtC12VisionCamera10CameraView")))
};
auto runOnWorklet = [](std::function<void()>&& f) {
// Run on Frame Processor Worklet Runtime
dispatch_async(CameraQueues.frameProcessorQueue, [f = std::move(f)](){
dispatch_async(CameraQueues.videoQueue, [f = std::move(f)](){
f();
});
};
workletContext = std::make_shared<RNWorklet::JsiWorkletContext>("VisionCamera");
workletContext->initialize("VisionCamera",
workletContext = std::make_shared<RNWorklet::JsiWorkletContext>("VisionCamera",
&runtime,
runOnJS,
runOnWorklet);
@ -136,28 +137,17 @@ __attribute__((objc_runtime_name("_TtC12VisionCamera10CameraView")))
NSLog(@"FrameProcessorBindings: Installing global functions...");
// setFrameProcessor(viewTag: number, frameProcessor: (frame: Frame) => void)
auto setFrameProcessor = [self](jsi::Runtime& runtime,
const jsi::Value& thisValue,
const jsi::Value* arguments,
size_t count) -> jsi::Value {
auto setFrameProcessor = JSI_HOST_FUNCTION_LAMBDA {
NSLog(@"FrameProcessorBindings: Setting new frame processor...");
if (!arguments[0].isNumber()) throw jsi::JSError(runtime, "Camera::setFrameProcessor: First argument ('viewTag') must be a number!");
if (!arguments[1].isObject()) throw jsi::JSError(runtime, "Camera::setFrameProcessor: Second argument ('frameProcessor') must be a function!");
auto viewTag = arguments[0].asNumber();
NSLog(@"FrameProcessorBindings: Converting JSI Function to Worklet...");
auto worklet = std::make_shared<RNWorklet::JsiWorklet>(runtime, arguments[1]);
RCTExecuteOnMainQueue([=]() {
RCTExecuteOnMainQueue(^{
auto currentBridge = [RCTBridge currentBridge];
auto anonymousView = [currentBridge.uiManager viewForReactTag:[NSNumber numberWithDouble:viewTag]];
auto view = static_cast<CameraView*>(anonymousView);
NSLog(@"FrameProcessorBindings: Converting worklet to Objective-C callback...");
view.frameProcessorCallback = convertWorkletToFrameProcessorCallback(workletContext->getWorkletRuntime(), worklet);
NSLog(@"FrameProcessorBindings: Frame processor set!");
auto callback = convertWorkletToFrameProcessorCallback(self->workletContext->getWorkletRuntime(), worklet);
view.frameProcessorCallback = callback;
});
return jsi::Value::undefined();
@ -168,12 +158,8 @@ __attribute__((objc_runtime_name("_TtC12VisionCamera10CameraView")))
setFrameProcessor));
// unsetFrameProcessor(viewTag: number)
auto unsetFrameProcessor = [](jsi::Runtime& runtime,
const jsi::Value& thisValue,
const jsi::Value* arguments,
size_t count) -> jsi::Value {
auto unsetFrameProcessor = JSI_HOST_FUNCTION_LAMBDA {
NSLog(@"FrameProcessorBindings: Removing frame processor...");
if (!arguments[0].isNumber()) throw jsi::JSError(runtime, "Camera::unsetFrameProcessor: First argument ('viewTag') must be a number!");
auto viewTag = arguments[0].asNumber();
RCTExecuteOnMainQueue(^{
@ -185,7 +171,6 @@ __attribute__((objc_runtime_name("_TtC12VisionCamera10CameraView")))
auto view = static_cast<CameraView*>(anonymousView);
view.frameProcessorCallback = nil;
NSLog(@"FrameProcessorBindings: Frame processor removed!");
});
return jsi::Value::undefined();

View File

@ -28,13 +28,15 @@ FrameProcessorCallback convertWorkletToFrameProcessorCallback(jsi::Runtime& runt
// Converts a Worklet to a callable Objective-C block function
return ^(Frame* frame) {
auto frameHostObject = std::make_shared<FrameHostObject>(frame);
try {
// Call JS Frame Processor function with boxed Frame Host Object
// Box the Frame to a JS Host Object
auto frameHostObject = std::make_shared<FrameHostObject>(frame);
auto argument = jsi::Object::createFromHostObject(runtime, frameHostObject);
jsi::Value jsValue(std::move(argument));
// Call the Worklet with the Frame JS Host Object as an argument
workletInvoker->call(runtime, jsi::Value::undefined(), &jsValue, 1);
} catch (jsi::JSError& jsError) {
// JS Error occured, print it to console.
auto stack = std::regex_replace(jsError.getStack(), std::regex("\n"), "\n ");
auto message = [NSString stringWithFormat:@"Frame Processor threw an error: %s\nIn: %s", jsError.getMessage().c_str(), stack.c_str()];
@ -48,11 +50,5 @@ FrameProcessorCallback convertWorkletToFrameProcessorCallback(jsi::Runtime& runt
NSLog(@"%@", message);
}
}
// Manually free the buffer because:
// 1. we are sure we don't need it anymore, the frame processor worklet has finished executing.
// 2. we don't know when the JS runtime garbage collects this object, it might be holding it for a few more frames
// which then blocks the camera queue from pushing new frames (memory limit)
frameHostObject->close();
};
}

View File

@ -138,7 +138,6 @@
B887518425E0102000DB86D6 /* CameraView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CameraView.swift; sourceTree = "<group>"; };
B88873E5263D46C7008B1D0E /* FrameProcessorPlugin.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FrameProcessorPlugin.h; sourceTree = "<group>"; };
B88B47462667C8E00091F538 /* AVCaptureSession+setVideoStabilizationMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AVCaptureSession+setVideoStabilizationMode.swift"; sourceTree = "<group>"; };
B8948BDF26DCEE2B00B430E2 /* FrameProcessorPerformanceDataCollector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FrameProcessorPerformanceDataCollector.swift; sourceTree = "<group>"; };
B8994E6B263F03E100069589 /* JSIUtils.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = JSIUtils.mm; sourceTree = "<group>"; };
B8A751D62609E4980011C623 /* FrameProcessorRuntimeManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FrameProcessorRuntimeManager.h; sourceTree = "<group>"; };
B8A751D72609E4B30011C623 /* FrameProcessorRuntimeManager.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = FrameProcessorRuntimeManager.mm; sourceTree = "<group>"; };
@ -273,7 +272,6 @@
B88873E5263D46C7008B1D0E /* FrameProcessorPlugin.h */,
B80416F026AB16E8000DEB6A /* VisionCameraScheduler.mm */,
B80416F126AB16F3000DEB6A /* VisionCameraScheduler.h */,
B8948BDF26DCEE2B00B430E2 /* FrameProcessorPerformanceDataCollector.swift */,
);
path = "Frame Processor";
sourceTree = "<group>";

View File

@ -80,8 +80,9 @@
"pod-install": "^0.1.38",
"prettier": "^2.8.4",
"react": "^18.2.0",
"react-native": "^0.71.2",
"react-native": "^0.71.3",
"react-native-builder-bob": "^0.20.3",
"react-native-worklets": "https://github.com/chrfalch/react-native-worklets#15d52dd",
"release-it": "^15.6.0",
"typescript": "^4.9.5"
},

View File

@ -1,6 +1,6 @@
import React from 'react';
import { requireNativeComponent, NativeModules, NativeSyntheticEvent, findNodeHandle, NativeMethods, Platform } from 'react-native';
import type { FrameProcessorPerformanceSuggestion, VideoFileType } from '.';
import type { VideoFileType } from '.';
import type { CameraDevice } from './CameraDevice';
import type { ErrorWithCause } from './CameraError';
import { CameraCaptureError, CameraRuntimeError, tryParseNativeCameraError, isErrorWithCause } from './CameraError';
@ -20,16 +20,11 @@ interface OnErrorEvent {
message: string;
cause?: ErrorWithCause;
}
type NativeCameraViewProps = Omit<
CameraProps,
'device' | 'onInitialized' | 'onError' | 'onFrameProcessorPerformanceSuggestionAvailable' | 'frameProcessor' | 'frameProcessorFps'
> & {
type NativeCameraViewProps = Omit<CameraProps, 'device' | 'onInitialized' | 'onError' | 'frameProcessor'> & {
cameraId: string;
frameProcessorFps?: number; // native cannot use number | string, so we use '-1' for 'auto'
enableFrameProcessor: boolean;
onInitialized?: (event: NativeSyntheticEvent<void>) => void;
onError?: (event: NativeSyntheticEvent<OnErrorEvent>) => void;
onFrameProcessorPerformanceSuggestionAvailable?: (event: NativeSyntheticEvent<FrameProcessorPerformanceSuggestion>) => void;
onViewReady: () => void;
};
type RefType = React.Component<NativeCameraViewProps> & Readonly<NativeMethods>;
@ -86,7 +81,6 @@ export class Camera extends React.PureComponent<CameraProps> {
this.onViewReady = this.onViewReady.bind(this);
this.onInitialized = this.onInitialized.bind(this);
this.onError = this.onError.bind(this);
this.onFrameProcessorPerformanceSuggestionAvailable = this.onFrameProcessorPerformanceSuggestionAvailable.bind(this);
this.ref = React.createRef<RefType>();
this.lastFrameProcessor = undefined;
}
@ -422,11 +416,6 @@ export class Camera extends React.PureComponent<CameraProps> {
private onInitialized(): void {
this.props.onInitialized?.();
}
private onFrameProcessorPerformanceSuggestionAvailable(event: NativeSyntheticEvent<FrameProcessorPerformanceSuggestion>): void {
if (this.props.onFrameProcessorPerformanceSuggestionAvailable != null)
this.props.onFrameProcessorPerformanceSuggestionAvailable(event.nativeEvent);
}
//#endregion
//#region Lifecycle
@ -479,17 +468,15 @@ export class Camera extends React.PureComponent<CameraProps> {
/** @internal */
public render(): React.ReactNode {
// We remove the big `device` object from the props because we only need to pass `cameraId` to native.
const { device, frameProcessor, frameProcessorFps, ...props } = this.props;
const { device, frameProcessor, ...props } = this.props;
return (
<NativeCameraView
{...props}
frameProcessorFps={frameProcessorFps === 'auto' ? -1 : frameProcessorFps}
cameraId={device.id}
ref={this.ref}
onViewReady={this.onViewReady}
onInitialized={this.onInitialized}
onError={this.onError}
onFrameProcessorPerformanceSuggestionAvailable={this.onFrameProcessorPerformanceSuggestionAvailable}
enableFrameProcessor={frameProcessor != null}
/>
);

View File

@ -4,11 +4,6 @@ import type { CameraRuntimeError } from './CameraError';
import type { CameraPreset } from './CameraPreset';
import type { Frame } from './Frame';
export interface FrameProcessorPerformanceSuggestion {
type: 'can-use-higher-fps' | 'should-use-lower-fps';
suggestedFrameProcessorFps: number;
}
export interface CameraProps extends ViewProps {
/**
* The Camera Device to use.
@ -171,11 +166,7 @@ export interface CameraProps extends ViewProps {
*/
onInitialized?: () => void;
/**
* Called when a new performance suggestion for a Frame Processor is available - either if your Frame Processor is running too fast and frames are being dropped, or because it is able to run faster. Optionally, you can adjust your `frameProcessorFps` accordingly.
*/
onFrameProcessorPerformanceSuggestionAvailable?: (suggestion: FrameProcessorPerformanceSuggestion) => void;
/**
* A worklet which will be called for every frame the Camera "sees". Throttle the Frame Processor's frame rate with {@linkcode frameProcessorFps}.
* A worklet which will be called for every frame the Camera "sees".
*
* > See [the Frame Processors documentation](https://mrousavy.github.io/react-native-vision-camera/docs/guides/frame-processors) for more information
*
@ -193,20 +184,5 @@ export interface CameraProps extends ViewProps {
* ```
*/
frameProcessor?: (frame: Frame) => void;
/**
* Specifies the maximum frame rate the frame processor can use, independent of the Camera's frame rate (`fps` property).
*
* * A value of `'auto'` (default) indicates that the frame processor should execute as fast as it can, without dropping frames. This is achieved by collecting historical data for previous frame processor calls and adjusting frame rate accordingly.
* * A value of `1` indicates that the frame processor gets executed once per second, perfect for code scanning.
* * A value of `10` indicates that the frame processor gets executed 10 times per second, perfect for more realtime use-cases.
* * A value of `25` indicates that the frame processor gets executed 25 times per second, perfect for high-speed realtime use-cases.
* * ...and so on
*
* If you're using higher values, always check your Xcode/Android Studio Logs to make sure your frame processors are executing fast enough
* without blocking the video recording queue.
*
* @default 'auto'
*/
frameProcessorFps?: number | 'auto';
//#endregion
}

View File

@ -31,19 +31,19 @@ export interface Frame {
* ```
*/
toString(): string;
/**
* Closes and disposes the Frame.
* Only close frames that you have created yourself, e.g. by copying the frame you receive in a frame processor.
*
* @example
* ```ts
* const frameProcessor = useFrameProcessor((frame) => {
* const smallerCopy = resize(frame, 480, 270)
* // run AI ...
* smallerCopy.close()
* // don't close `frame`!
* })
* ```
*/
close(): void;
}
export interface FrameInternal extends Frame {
/**
* Increment the Frame Buffer ref-count by one.
*
* This is a private API, do not use this.
*/
incrementRefCount(): void;
/**
* Increment the Frame Buffer ref-count by one.
*
* This is a private API, do not use this.
*/
decrementRefCount(): void;
}

View File

@ -1,13 +1,101 @@
import type { Frame } from './Frame';
import type { Frame, FrameInternal } from './Frame';
import { Camera } from './Camera';
import { Worklets } from 'react-native-worklets/src';
// Install VisionCamera Frame Processor JSI Bindings and Plugins
Camera.installFrameProcessorBindings();
type FrameProcessor = (frame: Frame, ...args: unknown[]) => unknown;
type BasicParameterType = string | number | boolean | undefined;
type ParameterType = BasicParameterType | BasicParameterType[] | Record<string, BasicParameterType | undefined>;
type FrameProcessor = (frame: Frame, parameters?: Record<string, ParameterType | undefined>) => unknown;
type TFrameProcessorPlugins = Record<string, FrameProcessor>;
/**
* All natively installed Frame Processor Plugins.
*/
export const FrameProcessorPlugins = global.FrameProcessorPlugins as TFrameProcessorPlugins;
const lastFrameProcessorCall = Worklets.createSharedValue(performance.now());
/**
* Runs the given function at the given target FPS rate.
*
* For example, if you want to run a heavy face detection algorithm
* only once per second, you can use `runAtTargetFps(1, ...)` to
* throttle it to 1 FPS.
*
* @param fps The target FPS rate at which the given function should be executed
* @param func The function to execute.
* @returns The result of the function if it was executed, or `undefined` otherwise.
* @example
*
* ```ts
* const frameProcessor = useFrameProcessor((frame) => {
* 'worklet'
* console.log('New Frame')
* const face = runAtTargetFps(5, () => {
* 'worklet'
* const faces = detectFaces(frame)
* return faces[0]
* })
* if (face != null) console.log(`Detected a new face: ${face}`)
* })
* ```
*/
export function runAtTargetFps<T>(fps: number, func: () => T): T | undefined {
'worklet';
const targetIntervalMs = 1000 / fps; // <-- 60 FPS => 16,6667ms interval
const now = performance.now();
const diffToLastCall = now - lastFrameProcessorCall.value;
if (diffToLastCall >= targetIntervalMs) {
lastFrameProcessorCall.value = now;
// Last Frame Processor call is already so long ago that we want to make a new call
return func();
}
return undefined;
}
const asyncContext = Worklets.createContext('VisionCamera.async');
const runOnAsyncContext = Worklets.createRunInContextFn((frame: Frame, func: () => void) => {
'worklet';
try {
// Call long-running function
func();
} finally {
// Potentially delete Frame if we were the last ref
(frame as FrameInternal).decrementRefCount();
}
}, asyncContext);
/**
* Runs the given function asynchronously, while keeping a strong reference to the Frame.
*
* For example, if you want to run a heavy face detection algorithm
* while still drawing to the screen at 60 FPS, you can use `runAsync(...)`
* to offload the face detection algorithm to a separate thread.
*
* @param frame The current Frame of the Frame Processor.
* @param func The function to execute.
* @example
*
* ```ts
* const frameProcessor = useFrameProcessor((frame) => {
* 'worklet'
* console.log('New Frame')
* runAsync(frame, () => {
* 'worklet'
* const faces = detectFaces(frame)
* const face = [faces0]
* console.log(`Detected a new face: ${face}`)
* })
* })
* ```
*/
export function runAsync(frame: Frame, func: () => void): void {
'worklet';
// Increment ref count by one
(frame as FrameInternal).incrementRefCount();
// Call in separate background context
runOnAsyncContext(frame, func);
}

View File

@ -1,5 +1,5 @@
import { DependencyList, useCallback } from 'react';
import type { Frame } from '../Frame';
import type { Frame, FrameInternal } from '../Frame';
// Install RN Worklets by importing it
import 'react-native-worklets/src';
@ -23,6 +23,17 @@ type FrameProcessor = (frame: Frame) => void;
* ```
*/
export function useFrameProcessor(frameProcessor: FrameProcessor, dependencies: DependencyList): FrameProcessor {
return useCallback((frame: Frame) => {
'worklet';
// Increment ref-count by one
(frame as FrameInternal).incrementRefCount();
try {
// Call sync frame processor
frameProcessor(frame);
} finally {
// Potentially delete Frame if we were the last ref (no runAsync)
(frame as FrameInternal).decrementRefCount();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
return useCallback(frameProcessor, dependencies);
}, dependencies);
}

View File

@ -4,7 +4,7 @@ export * from './CameraError';
export * from './CameraPosition';
export * from './CameraPreset';
export * from './CameraProps';
export * from './Frame';
export { Frame } from './Frame';
export * from './FrameProcessorPlugins';
export * from './CameraProps';
export * from './PhotoFile';

View File

@ -5217,10 +5217,10 @@ js-yaml@^4.1.0:
dependencies:
argparse "^2.0.1"
jsc-android@^250230.2.1:
version "250230.2.1"
resolved "https://registry.yarnpkg.com/jsc-android/-/jsc-android-250230.2.1.tgz#3790313a970586a03ab0ad47defbc84df54f1b83"
integrity sha512-KmxeBlRjwoqCnBBKGsihFtvsBHyUFlBxJPK4FzeYcIuBfdjv6jFys44JITAgSTbQD+vIdwMEfyZklsuQX0yI1Q==
jsc-android@^250231.0.0:
version "250231.0.0"
resolved "https://registry.yarnpkg.com/jsc-android/-/jsc-android-250231.0.0.tgz#91720f8df382a108872fa4b3f558f33ba5e95262"
integrity sha512-rS46PvsjYmdmuz1OAWXY/1kCYG7pnf1TBqeTiOJr1iDz7s5DLxxC9n/ZMknLDxzYzNVfI7R95MH10emSSG1Wuw==
jscodeshift@^0.13.1:
version "0.13.1"
@ -6867,25 +6867,29 @@ react-native-builder-bob@^0.20.3:
optionalDependencies:
jetifier "^2.0.0"
react-native-codegen@^0.71.3:
version "0.71.3"
resolved "https://registry.yarnpkg.com/react-native-codegen/-/react-native-codegen-0.71.3.tgz#75fbc591819050791319ebdb9fe341ee4df5c288"
integrity sha512-5AvdHVU1sAaXg05i0dG664ZTaCaIFaY1znV5vNsj+wUu6MGxNEUNbDKk9dxKUkkxOyk2KZOK5uhzWL0p5H5yZQ==
react-native-codegen@^0.71.5:
version "0.71.5"
resolved "https://registry.yarnpkg.com/react-native-codegen/-/react-native-codegen-0.71.5.tgz#454a42a891cd4ca5fc436440d301044dc1349c14"
integrity sha512-rfsuc0zkuUuMjFnrT55I1mDZ+pBRp2zAiRwxck3m6qeGJBGK5OV5JH66eDQ4aa+3m0of316CqrJDRzVlYufzIg==
dependencies:
"@babel/parser" "^7.14.0"
flow-parser "^0.185.0"
jscodeshift "^0.13.1"
nullthrows "^1.1.1"
react-native-gradle-plugin@^0.71.14:
version "0.71.14"
resolved "https://registry.yarnpkg.com/react-native-gradle-plugin/-/react-native-gradle-plugin-0.71.14.tgz#cc399662f04fbfcc0e352d03eae1d3efbd5f635a"
integrity sha512-nnLawTZEPPRAKq92UqDkzoGgCBl9aa9zAihFHMwmwzn4WRVdK4O6Cd4XYiyoNOiQzx3Hh9k5WOckHE80C92ivQ==
react-native-gradle-plugin@^0.71.15:
version "0.71.15"
resolved "https://registry.yarnpkg.com/react-native-gradle-plugin/-/react-native-gradle-plugin-0.71.15.tgz#9e6b506f30729fe8eb086981702f4e3c891d2b13"
integrity sha512-7S3pAuPaQJlhax6EZ4JMsDNpj05TfuzX9gPgWLrFfAIWIFLuJ6aDQYAZy2TEI9QJALPoWrj8LWaqP/DGYh14pw==
react-native@^0.71.2:
version "0.71.2"
resolved "https://registry.yarnpkg.com/react-native/-/react-native-0.71.2.tgz#b6977eda2a6dc10baa006bf4ab1ee08318607ce9"
integrity sha512-ZSianM+j+09LoEdVIhrAP/uP8sQhT7dH6olCqM2xlpxmfCgA5NubsK6NABIuZiBlmmqjigyijm5Y/GhBIHDvEg==
"react-native-worklets@https://github.com/chrfalch/react-native-worklets#15d52dd":
version "0.1.0"
resolved "https://github.com/chrfalch/react-native-worklets#15d52dd1289831cecc7906823f613172e0c6cd2e"
react-native@^0.71.3:
version "0.71.3"
resolved "https://registry.yarnpkg.com/react-native/-/react-native-0.71.3.tgz#0faab799c49e61ba12df9e6525c3ac7d595d673c"
integrity sha512-RYJXCcQGa4NTfKiPgl92eRDUuQ6JGDnHqFEzRwJSqEx9lWvlvRRIebstJfurzPDKLQWQrvITR7aI7e09E25mLw==
dependencies:
"@jest/create-cache-key-function" "^29.2.1"
"@react-native-community/cli" "10.1.3"
@ -6901,7 +6905,7 @@ react-native@^0.71.2:
event-target-shim "^5.0.1"
invariant "^2.2.4"
jest-environment-node "^29.2.1"
jsc-android "^250230.2.1"
jsc-android "^250231.0.0"
memoize-one "^5.0.0"
metro-react-native-babel-transformer "0.73.7"
metro-runtime "0.73.7"
@ -6911,8 +6915,8 @@ react-native@^0.71.2:
pretty-format "^26.5.2"
promise "^8.3.0"
react-devtools-core "^4.26.1"
react-native-codegen "^0.71.3"
react-native-gradle-plugin "^0.71.14"
react-native-codegen "^0.71.5"
react-native-gradle-plugin "^0.71.15"
react-refresh "^0.4.0"
react-shallow-renderer "^16.15.0"
regenerator-runtime "^0.13.2"