fix: Fix runAtTargetFps
for multiple invocations per FP
This commit is contained in:
parent
e1973b9b8d
commit
af4e366312
@ -6,7 +6,7 @@ import type { ErrorWithCause } from './CameraError';
|
|||||||
import { CameraCaptureError, CameraRuntimeError, tryParseNativeCameraError, isErrorWithCause } from './CameraError';
|
import { CameraCaptureError, CameraRuntimeError, tryParseNativeCameraError, isErrorWithCause } from './CameraError';
|
||||||
import type { CameraProps } from './CameraProps';
|
import type { CameraProps } from './CameraProps';
|
||||||
import type { Frame } from './Frame';
|
import type { Frame } from './Frame';
|
||||||
import { assertFrameProcessorsAvailable } from './JSIHelper';
|
import { assertFrameProcessorsAvailable, assertJSIAvailable } from './JSIHelper';
|
||||||
import { CameraModule } from './NativeCameraModule';
|
import { CameraModule } from './NativeCameraModule';
|
||||||
import type { PhotoFile, TakePhotoOptions } from './PhotoFile';
|
import type { PhotoFile, TakePhotoOptions } from './PhotoFile';
|
||||||
import type { Point } from './Point';
|
import type { Point } from './Point';
|
||||||
@ -310,6 +310,7 @@ export class Camera extends React.PureComponent<CameraProps> {
|
|||||||
* Install JSI Bindings for Frame Processors
|
* Install JSI Bindings for Frame Processors
|
||||||
*/
|
*/
|
||||||
public static installFrameProcessorBindings(): void {
|
public static installFrameProcessorBindings(): void {
|
||||||
|
assertJSIAvailable();
|
||||||
const result = CameraModule.installFrameProcessorBindings() as unknown;
|
const result = CameraModule.installFrameProcessorBindings() as unknown;
|
||||||
if (result !== true) throw new Error('Failed to install Frame Processor JSI bindings!');
|
if (result !== true) throw new Error('Failed to install Frame Processor JSI bindings!');
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
import type { Frame, FrameInternal } from './Frame';
|
import type { Frame, FrameInternal } from './Frame';
|
||||||
import { Camera } from './Camera';
|
import { Camera } from './Camera';
|
||||||
import { Worklets } from 'react-native-worklets/src';
|
import { Worklets } from 'react-native-worklets/src';
|
||||||
import { assertJSIAvailable } from './JSIHelper';
|
|
||||||
|
|
||||||
assertJSIAvailable();
|
|
||||||
|
|
||||||
// Install VisionCamera Frame Processor JSI Bindings and Plugins
|
// Install VisionCamera Frame Processor JSI Bindings and Plugins
|
||||||
Camera.installFrameProcessorBindings();
|
Camera.installFrameProcessorBindings();
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
// eslint-disable-next-line no-var
|
||||||
|
var __frameProcessorRunAtTargetFpsMap: Record<string, number | undefined> | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
type BasicParameterType = string | number | boolean | undefined;
|
type BasicParameterType = string | number | boolean | undefined;
|
||||||
type ParameterType = BasicParameterType | BasicParameterType[] | Record<string, BasicParameterType | undefined>;
|
type ParameterType = BasicParameterType | BasicParameterType[] | Record<string, BasicParameterType | undefined>;
|
||||||
type FrameProcessor = (frame: Frame, parameters?: Record<string, ParameterType | undefined>) => unknown;
|
type FrameProcessor = (frame: Frame, parameters?: Record<string, ParameterType | undefined>) => unknown;
|
||||||
@ -19,7 +21,15 @@ type TFrameProcessorPlugins = Record<string, FrameProcessor>;
|
|||||||
// @ts-expect-error The global JSI Proxy object is not typed.
|
// @ts-expect-error The global JSI Proxy object is not typed.
|
||||||
export const FrameProcessorPlugins = global.FrameProcessorPlugins as TFrameProcessorPlugins;
|
export const FrameProcessorPlugins = global.FrameProcessorPlugins as TFrameProcessorPlugins;
|
||||||
|
|
||||||
const lastFrameProcessorCall = Worklets.createSharedValue(performance.now());
|
function getLastFrameProcessorCall(frameProcessorFuncId: string): number {
|
||||||
|
'worklet';
|
||||||
|
return global.__frameProcessorRunAtTargetFpsMap?.[frameProcessorFuncId] ?? 0;
|
||||||
|
}
|
||||||
|
function setLastFrameProcessorCall(frameProcessorFuncId: string, value: number): void {
|
||||||
|
'worklet';
|
||||||
|
if (global.__frameProcessorRunAtTargetFpsMap == null) global.__frameProcessorRunAtTargetFpsMap = {};
|
||||||
|
global.__frameProcessorRunAtTargetFpsMap[frameProcessorFuncId] = value;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Runs the given function at the given target FPS rate.
|
* Runs the given function at the given target FPS rate.
|
||||||
@ -37,22 +47,25 @@ const lastFrameProcessorCall = Worklets.createSharedValue(performance.now());
|
|||||||
* const frameProcessor = useFrameProcessor((frame) => {
|
* const frameProcessor = useFrameProcessor((frame) => {
|
||||||
* 'worklet'
|
* 'worklet'
|
||||||
* console.log('New Frame')
|
* console.log('New Frame')
|
||||||
* const face = runAtTargetFps(5, () => {
|
* runAtTargetFps(5, () => {
|
||||||
* 'worklet'
|
* 'worklet'
|
||||||
* const faces = detectFaces(frame)
|
* const faces = detectFaces(frame)
|
||||||
* return faces[0]
|
* console.log(`Detected a new face: ${faces[0]}`)
|
||||||
* })
|
* })
|
||||||
* if (face != null) console.log(`Detected a new face: ${face}`)
|
|
||||||
* })
|
* })
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
export function runAtTargetFps<T>(fps: number, func: () => T): T | undefined {
|
export function runAtTargetFps<T>(fps: number, func: () => T): T | undefined {
|
||||||
'worklet';
|
'worklet';
|
||||||
|
// @ts-expect-error
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||||
|
const funcId = func.__workletHash ?? '1';
|
||||||
|
|
||||||
const targetIntervalMs = 1000 / fps; // <-- 60 FPS => 16,6667ms interval
|
const targetIntervalMs = 1000 / fps; // <-- 60 FPS => 16,6667ms interval
|
||||||
const now = performance.now();
|
const now = performance.now();
|
||||||
const diffToLastCall = now - lastFrameProcessorCall.value;
|
const diffToLastCall = now - getLastFrameProcessorCall(funcId);
|
||||||
if (diffToLastCall >= targetIntervalMs) {
|
if (diffToLastCall >= targetIntervalMs) {
|
||||||
lastFrameProcessorCall.value = now;
|
setLastFrameProcessorCall(funcId, now);
|
||||||
// Last Frame Processor call is already so long ago that we want to make a new call
|
// Last Frame Processor call is already so long ago that we want to make a new call
|
||||||
return func();
|
return func();
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,8 @@ export function assertJSIAvailable(): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function assertFrameProcessorsAvailable(): void {
|
export function assertFrameProcessorsAvailable(): void {
|
||||||
|
assertJSIAvailable();
|
||||||
|
|
||||||
// @ts-expect-error JSI functions aren't typed
|
// @ts-expect-error JSI functions aren't typed
|
||||||
if (global.setFrameProcessor == null || global.unsetFrameProcessor == null) {
|
if (global.setFrameProcessor == null || global.unsetFrameProcessor == null) {
|
||||||
throw new CameraRuntimeError(
|
throw new CameraRuntimeError(
|
||||||
|
Loading…
Reference in New Issue
Block a user