react-native-image-stitcher 0.10.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +96 -0
- package/dist/camera/Camera.d.ts +30 -14
- package/dist/camera/Camera.js +18 -18
- package/dist/index.d.ts +2 -0
- package/dist/index.js +9 -1
- package/dist/stitching/useFrameProcessorDriver.d.ts +50 -95
- package/dist/stitching/useFrameProcessorDriver.js +76 -294
- package/dist/stitching/useStitcherWorklet.d.ts +185 -0
- package/dist/stitching/useStitcherWorklet.js +275 -0
- package/package.json +1 -1
- package/src/camera/Camera.tsx +48 -32
- package/src/index.ts +13 -0
- package/src/stitching/useFrameProcessorDriver.ts +79 -320
- package/src/stitching/useStitcherWorklet.ts +390 -0
package/CHANGELOG.md
CHANGED
|
@@ -16,6 +16,102 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
16
16
|
|
|
17
17
|
## [Unreleased]
|
|
18
18
|
|
|
19
|
+
## [0.11.0] — 2026-05-28
|
|
20
|
+
|
|
21
|
+
### Added — `useStitcherWorklet` for non-AR composition
|
|
22
|
+
|
|
23
|
+
Closes the v0.8.0 Phase 5 either-or constraint: hosts that want to
|
|
24
|
+
write their OWN `useFrameProcessor` worklet body can now COMPOSE
|
|
25
|
+
first-party stitching back in with a single `stitcher.call(frame)`
|
|
26
|
+
call, instead of having to choose between their worklet and the
|
|
27
|
+
lib's stitching.
|
|
28
|
+
|
|
29
|
+
```tsx
|
|
30
|
+
import {
|
|
31
|
+
Camera, useFrameProcessor, useStitcherWorklet,
|
|
32
|
+
type StitcherFrame,
|
|
33
|
+
} from 'react-native-image-stitcher';
|
|
34
|
+
|
|
35
|
+
function MyScreen() {
|
|
36
|
+
const stitcher = useStitcherWorklet();
|
|
37
|
+
const fp = useFrameProcessor((frame: StitcherFrame) => {
|
|
38
|
+
'worklet';
|
|
39
|
+
hostPreLogic(frame);
|
|
40
|
+
stitcher.call(frame); // ← first-party stitching
|
|
41
|
+
hostPostLogic(frame);
|
|
42
|
+
}, [stitcher.call]);
|
|
43
|
+
return <Camera frameProcessor={fp} ... />;
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Migrating from v0.10.x is a one-line diff:
|
|
48
|
+
|
|
49
|
+
```diff
|
|
50
|
+
+ const stitcher = useStitcherWorklet();
|
|
51
|
+
const fp = useFrameProcessor((frame: StitcherFrame) => {
|
|
52
|
+
'worklet';
|
|
53
|
+
+ stitcher.call(frame); // ← first-party stitching back in
|
|
54
|
+
hostLogic(frame);
|
|
55
|
+
- }, [hostLogic]);
|
|
56
|
+
+ }, [stitcher.call, hostLogic]);
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Changed
|
|
60
|
+
|
|
61
|
+
- `useFrameProcessorDriver` is now a thin wrapper around
|
|
62
|
+
`useStitcherWorklet`. Public API (`start` / `stop` /
|
|
63
|
+
`isRunning` / `frameProcessor`) is unchanged. Pose-reset
|
|
64
|
+
semantics preserved via the new `stitcher.reset()` method which
|
|
65
|
+
the driver calls internally from `start()` and `stop()`.
|
|
66
|
+
- The gyro subscription that powers pose tracking now lives in
|
|
67
|
+
`useStitcherWorklet` and runs for the lifetime of the hook
|
|
68
|
+
(mount → unmount) rather than being tied to the driver's
|
|
69
|
+
`start()` / `stop()`. In practice this matches all observed
|
|
70
|
+
host integrations (capture screens mount `<Camera>` for the
|
|
71
|
+
duration of capture; idle screens don't). Battery delta is
|
|
72
|
+
small (≪1% CPU at 33 ms gyro sampling).
|
|
73
|
+
- `<Camera frameProcessor>` JSDoc rewritten: the "Non-AR mode
|
|
74
|
+
tradeoff (HONEST)" section is replaced by a "Non-AR mode
|
|
75
|
+
composition" section that shows the v0.11.0 composition
|
|
76
|
+
pattern. The runtime `console.info` text is softened from
|
|
77
|
+
"your worklet REPLACES first-party stitching, panorama capture
|
|
78
|
+
will not produce stitched output" to "if you want first-party
|
|
79
|
+
stitching alongside, call `useStitcherWorklet()` from your
|
|
80
|
+
worklet body".
|
|
81
|
+
- Example app (`example/App.tsx`) now demonstrates the
|
|
82
|
+
composition pattern end-to-end: one
|
|
83
|
+
`useFrameProcessor` body that calls both `stitcher.call(frame)`
|
|
84
|
+
and the existing 1 Hz host tick log. `<Camera>` mounts with
|
|
85
|
+
`frameProcessor={exampleFrameProcessor}` (previously left
|
|
86
|
+
unwired with an "intentionally unused" comment block).
|
|
87
|
+
- `docs/frame-access-tiers.md` adds a `useStitcherWorklet`
|
|
88
|
+
reference section + 1-line migration diff. Softens the
|
|
89
|
+
"either-or" language in the Tier 3 + AR-vs-non-AR sections.
|
|
90
|
+
|
|
91
|
+
### Files changed
|
|
92
|
+
- NEW: `src/stitching/useStitcherWorklet.ts`
|
|
93
|
+
- `src/stitching/useFrameProcessorDriver.ts` (refactored thin wrapper)
|
|
94
|
+
- `src/index.ts` (export new hook + types)
|
|
95
|
+
- `src/camera/Camera.tsx` (docstring + console.info softened)
|
|
96
|
+
- `example/App.tsx` (composition demo)
|
|
97
|
+
- `docs/frame-access-tiers.md` (new section + softened wording)
|
|
98
|
+
- `docs/v0.11.0-manual-verification-checklist.md` (Phase 4 human-loop checklist)
|
|
99
|
+
|
|
100
|
+
### Not touched
|
|
101
|
+
- All native code (`ios/Sources/`, `android/src/main/cpp/`,
|
|
102
|
+
`android/src/main/java/io/imagestitcher/rn/`) — pure TS refactor.
|
|
103
|
+
- AR-mode dispatch path — already composes natively.
|
|
104
|
+
- `useFrameProcessor` (v0.8.0 public hook) — unchanged.
|
|
105
|
+
|
|
106
|
+
### Verified
|
|
107
|
+
- JS Jest: **69 / 69 pass**
|
|
108
|
+
- C++ Gtest: **17 / 17 pass**
|
|
109
|
+
- Android JUnit: **6 / 6 pass**
|
|
110
|
+
- iOS build (Debug, generic iOS device): clean
|
|
111
|
+
- Android `:app:assembleDebug`: clean
|
|
112
|
+
- Real-device panorama capture verification deferred to the
|
|
113
|
+
human-in-the-loop checklist (`docs/v0.11.0-manual-verification-checklist.md`).
|
|
114
|
+
|
|
19
115
|
## [0.10.0] — 2026-05-28
|
|
20
116
|
|
|
21
117
|
### Added — v0.10.0 PR A: host-side test infrastructure (`#9A` + `#11A`)
|
package/dist/camera/Camera.d.ts
CHANGED
|
@@ -221,26 +221,42 @@ export interface CameraProps {
|
|
|
221
221
|
* }
|
|
222
222
|
* ```
|
|
223
223
|
*
|
|
224
|
-
* ## Non-AR mode
|
|
224
|
+
* ## Non-AR mode composition (v0.11.0+)
|
|
225
225
|
*
|
|
226
226
|
* vision-camera's `<Camera>` accepts ONLY ONE frame processor.
|
|
227
227
|
* The lib's internal `useFrameProcessorDriver` produces the
|
|
228
228
|
* processor that drives first-party panorama stitching in non-AR
|
|
229
|
-
* mode. If you supply your own via this prop,
|
|
230
|
-
*
|
|
231
|
-
*
|
|
232
|
-
*
|
|
229
|
+
* mode. If you supply your own via this prop, the lib's
|
|
230
|
+
* default processor is REPLACED — but as of v0.11.0 you can
|
|
231
|
+
* COMPOSE first-party stitching back into your worklet body
|
|
232
|
+
* using `useStitcherWorklet`:
|
|
233
233
|
*
|
|
234
|
-
*
|
|
235
|
-
*
|
|
236
|
-
*
|
|
237
|
-
*
|
|
238
|
-
*
|
|
234
|
+
* ```tsx
|
|
235
|
+
* import {
|
|
236
|
+
* Camera, useFrameProcessor, useStitcherWorklet,
|
|
237
|
+
* type StitcherFrame,
|
|
238
|
+
* } from 'react-native-image-stitcher';
|
|
239
|
+
*
|
|
240
|
+
* function MyScreen() {
|
|
241
|
+
* const stitcher = useStitcherWorklet();
|
|
242
|
+
* const fp = useFrameProcessor((frame: StitcherFrame) => {
|
|
243
|
+
* 'worklet';
|
|
244
|
+
* hostPreLogic(frame);
|
|
245
|
+
* stitcher.call(frame); // ← first-party stitching
|
|
246
|
+
* hostPostLogic(frame);
|
|
247
|
+
* }, [stitcher.call]);
|
|
248
|
+
* return <Camera frameProcessor={fp} ... />;
|
|
249
|
+
* }
|
|
250
|
+
* ```
|
|
239
251
|
*
|
|
240
|
-
*
|
|
241
|
-
*
|
|
242
|
-
*
|
|
243
|
-
*
|
|
252
|
+
* Hosts that DON'T call `useStitcherWorklet` from their worklet
|
|
253
|
+
* body replace first-party stitching for non-AR captures (a
|
|
254
|
+
* one-shot console.info documents this when the prop is first
|
|
255
|
+
* supplied). AR mode is unaffected either way — the AR-mode
|
|
256
|
+
* dispatch path (v0.8.0 Phase 4b.i / 4b.iii) natively fans out
|
|
257
|
+
* to both the lib's first-party stitching AND every registered
|
|
258
|
+
* host worklet on every frame, with per-worklet failure
|
|
259
|
+
* isolation.
|
|
244
260
|
*
|
|
245
261
|
* ## AR mode behaviour
|
|
246
262
|
*
|
package/dist/camera/Camera.js
CHANGED
|
@@ -435,36 +435,36 @@ function Camera(props) {
|
|
|
435
435
|
// Safety: stop the driver if the component unmounts mid-recording.
|
|
436
436
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
437
437
|
(0, react_1.useEffect)(() => () => { fpDriver.stop(); }, []);
|
|
438
|
-
// v0.8.0 Phase 5 — frameProcessor prop semantics:
|
|
438
|
+
// v0.8.0 Phase 5 / v0.11.0 — frameProcessor prop semantics:
|
|
439
439
|
//
|
|
440
|
-
// - Host supplied? → use host's processor
|
|
441
|
-
//
|
|
442
|
-
//
|
|
443
|
-
//
|
|
444
|
-
//
|
|
445
|
-
//
|
|
446
|
-
//
|
|
440
|
+
// - Host supplied? → use host's processor. The host's worklet
|
|
441
|
+
// body controls whether first-party stitching also fires:
|
|
442
|
+
// call `stitcher.call(frame)` (from `useStitcherWorklet`)
|
|
443
|
+
// inside the body to compose; omit to replace. One-shot
|
|
444
|
+
// console.info documents the choice so the host can spot a
|
|
445
|
+
// missing `useStitcherWorklet` call before they go hunting
|
|
446
|
+
// for "why is non-AR panorama capture not producing output".
|
|
447
|
+
// AR-mode capture is unaffected either way — the AR-session
|
|
448
|
+
// dispatch path fans out to BOTH first-party stitching AND
|
|
449
|
+
// every host worklet independently.
|
|
447
450
|
//
|
|
448
451
|
// - No host processor? → use `fpDriver.frameProcessor` which is
|
|
449
452
|
// the lib's internal worklet driving first-party stitching
|
|
450
453
|
// via `useFrameProcessorDriver`. Default behaviour for the
|
|
451
454
|
// common "I just want panorama capture" case.
|
|
452
|
-
//
|
|
453
|
-
// The pre-v0.8.0 behaviour (host's prop silently ignored with
|
|
454
|
-
// a warning) is gone — Phase 5 plumbs the prop through. The
|
|
455
|
-
// tradeoff is honestly documented in the CameraProps docstring.
|
|
456
455
|
const hostFrameProcessorAcceptedWarnedRef = (0, react_1.useRef)(false);
|
|
457
456
|
if (hostFrameProcessor != null
|
|
458
457
|
&& !hostFrameProcessorAcceptedWarnedRef.current) {
|
|
459
458
|
hostFrameProcessorAcceptedWarnedRef.current = true;
|
|
460
459
|
// eslint-disable-next-line no-console
|
|
461
460
|
console.info('[react-native-image-stitcher] Host frameProcessor supplied — '
|
|
462
|
-
+ 'non-AR mode will run YOUR worklet
|
|
463
|
-
+ 'first-party stitching
|
|
464
|
-
+ '
|
|
465
|
-
+ '
|
|
466
|
-
+ '
|
|
467
|
-
+ '
|
|
461
|
+
+ 'non-AR mode will run YOUR composed worklet. If you want '
|
|
462
|
+
+ 'first-party panorama stitching alongside your own logic, '
|
|
463
|
+
+ 'call `useStitcherWorklet()` and invoke `stitcher.call(frame)` '
|
|
464
|
+
+ 'from your worklet body (see `<Camera>` `frameProcessor` '
|
|
465
|
+
+ 'JSDoc for the composition pattern). AR-mode capture is '
|
|
466
|
+
+ 'unaffected (AR-session dispatch fans out to both '
|
|
467
|
+
+ 'first-party and host worklets independently).');
|
|
468
468
|
}
|
|
469
469
|
// The Frame Processor worklet bound to vision-camera's Camera.
|
|
470
470
|
// Host's wins if supplied; lib's internal driver otherwise.
|
package/dist/index.d.ts
CHANGED
|
@@ -73,5 +73,7 @@ export { useFrameStream } from './stitching/useFrameStream';
|
|
|
73
73
|
export type { FrameStreamOptions, SampledFrame } from './types';
|
|
74
74
|
export { useFrameProcessorDriver } from './stitching/useFrameProcessorDriver';
|
|
75
75
|
export type { UseFrameProcessorDriverOptions, FrameProcessorDriverHandle, } from './stitching/useFrameProcessorDriver';
|
|
76
|
+
export { useStitcherWorklet } from './stitching/useStitcherWorklet';
|
|
77
|
+
export type { UseStitcherWorkletOptions, StitcherWorkletHandle, StitcherWorkletInput, } from './stitching/useStitcherWorklet';
|
|
76
78
|
export { stitchVideo } from './stitching/stitchVideo';
|
|
77
79
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
* adds RetaiLens-specific features on top.
|
|
23
23
|
*/
|
|
24
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
-
exports.stitchVideo = exports.useFrameProcessorDriver = exports.useFrameStream = exports.useThrottledFrameProcessor = exports.useFrameProcessor = exports.useKeyframeStream = exports.useIncrementalStitcher = exports.cleanupOldKeyframes = exports.getIncrementalNativeModule = exports.subscribeIncrementalState = exports.incrementalStitcherIsAvailable = exports.IncrementalOutcome = exports.useDeviceOrientation = exports.useVideoCapture = exports.useCapture = exports.ViewportCropOverlay = exports.hybridSettingsToNativeConfig = exports.slitscanSettingsToNativeConfig = exports.panoramaSettingsToNativeConfig = exports.DEFAULT_HYBRID_SETTINGS = exports.DEFAULT_SLITSCAN_SETTINGS = exports.DEFAULT_FLOW_GATE_SETTINGS = exports.DEFAULT_PANORAMA_SETTINGS = exports.PanoramaSettingsModal = exports.PanoramaGuidance = exports.PanoramaBandOverlay = exports.IncrementalPanGuide = exports.CaptureThumbnailStrip = exports.useStitchStatsToast = exports.CaptureStitchStatsToast = exports.CaptureOrientationPill = exports.CaptureKeyframePill = exports.CaptureMemoryPill = exports.CaptureDebugOverlay = exports.CaptureStatusOverlay = exports.CapturePreview = exports.CaptureControlsBar = exports.CaptureHeader = exports.CameraView = exports.ARCameraView = exports.useIMUTranslationGate = exports.ARTrackingState = exports.useARSession = exports.CameraError = exports.Camera = void 0;
|
|
25
|
+
exports.stitchVideo = exports.useStitcherWorklet = exports.useFrameProcessorDriver = exports.useFrameStream = exports.useThrottledFrameProcessor = exports.useFrameProcessor = exports.useKeyframeStream = exports.useIncrementalStitcher = exports.cleanupOldKeyframes = exports.getIncrementalNativeModule = exports.subscribeIncrementalState = exports.incrementalStitcherIsAvailable = exports.IncrementalOutcome = exports.useDeviceOrientation = exports.useVideoCapture = exports.useCapture = exports.ViewportCropOverlay = exports.hybridSettingsToNativeConfig = exports.slitscanSettingsToNativeConfig = exports.panoramaSettingsToNativeConfig = exports.DEFAULT_HYBRID_SETTINGS = exports.DEFAULT_SLITSCAN_SETTINGS = exports.DEFAULT_FLOW_GATE_SETTINGS = exports.DEFAULT_PANORAMA_SETTINGS = exports.PanoramaSettingsModal = exports.PanoramaGuidance = exports.PanoramaBandOverlay = exports.IncrementalPanGuide = exports.CaptureThumbnailStrip = exports.useStitchStatsToast = exports.CaptureStitchStatsToast = exports.CaptureOrientationPill = exports.CaptureKeyframePill = exports.CaptureMemoryPill = exports.CaptureDebugOverlay = exports.CaptureStatusOverlay = exports.CapturePreview = exports.CaptureControlsBar = exports.CaptureHeader = exports.CameraView = exports.ARCameraView = exports.useIMUTranslationGate = exports.ARTrackingState = exports.useARSession = exports.CameraError = exports.Camera = void 0;
|
|
26
26
|
// ─────────────────────────────────────────────────────────────────────
|
|
27
27
|
// Layer 1 — the high-level <Camera> component
|
|
28
28
|
// ─────────────────────────────────────────────────────────────────────
|
|
@@ -179,6 +179,14 @@ Object.defineProperty(exports, "useFrameStream", { enumerable: true, get: functi
|
|
|
179
179
|
// `useIncrementalJSDriver` was removed; was deprecated in v0.5).
|
|
180
180
|
var useFrameProcessorDriver_1 = require("./stitching/useFrameProcessorDriver");
|
|
181
181
|
Object.defineProperty(exports, "useFrameProcessorDriver", { enumerable: true, get: function () { return useFrameProcessorDriver_1.useFrameProcessorDriver; } });
|
|
182
|
+
// v0.11.0 — composable first-party stitching as a worklet function.
|
|
183
|
+
// Hosts that want to COMPOSE their own per-frame logic with the
|
|
184
|
+
// lib's stitching (instead of REPLACING it via the <Camera>
|
|
185
|
+
// `frameProcessor` prop) call this hook + invoke `stitcher.call`
|
|
186
|
+
// inside their own `useFrameProcessor` body. See
|
|
187
|
+
// `docs/host-app-integration.md` § Tier 3 for the full pattern.
|
|
188
|
+
var useStitcherWorklet_1 = require("./stitching/useStitcherWorklet");
|
|
189
|
+
Object.defineProperty(exports, "useStitcherWorklet", { enumerable: true, get: function () { return useStitcherWorklet_1.useStitcherWorklet; } });
|
|
182
190
|
// ── Batch stitching ───────────────────────────────────────────────────
|
|
183
191
|
// Feed a video file straight to OpenCV's cv::Stitcher, bypassing the
|
|
184
192
|
// incremental pipeline. Useful when you have content captured
|
|
@@ -4,99 +4,54 @@
|
|
|
4
4
|
* from v0.6 onward (replaced the deprecated `useIncrementalJSDriver`
|
|
5
5
|
* hook, which was removed in v0.6).
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
* qw = cy*cp*cr + sy*sp*sr
|
|
56
|
-
*
|
|
57
|
-
* When roll=0 this collapses to the 2-axis form
|
|
58
|
-
* `(cy*sp, sy*cp, -sy*sp, cy*cp)` the legacy driver used, so
|
|
59
|
-
* captures held perfectly level produce identical poses to the
|
|
60
|
-
* pre-roll behaviour.
|
|
61
|
-
*
|
|
62
|
-
* Intrinsics are synthesised from the actual frame dimensions
|
|
63
|
-
* (`frame.width`, `frame.height`) plus the host-provided
|
|
64
|
-
* horizontal/vertical FoV defaults. The stitcher derives its FoV-
|
|
65
|
-
* overlap window from these, so the assumed FoV matters for the
|
|
66
|
-
* gate's overlap math but not for the panorama itself (the
|
|
67
|
-
* stitcher feature-matches + RANSACs the final alignment).
|
|
68
|
-
*
|
|
69
|
-
* Throttling
|
|
70
|
-
*
|
|
71
|
-
* `evalEveryNFrames` controls how often the worklet calls the
|
|
72
|
-
* plugin. Default 1 (every frame). Set higher to amortise the
|
|
73
|
-
* plugin call + consumeFrame's gate evaluation across multiple
|
|
74
|
-
* producer-thread frames on lower-end devices. Independent of —
|
|
75
|
-
* and stacks on top of — the stitcher's own internal
|
|
76
|
-
* `flowEvalEveryNFrames` (see `KeyframeGate.swift`); both
|
|
77
|
-
* throttles can be active simultaneously and the effective cadence
|
|
78
|
-
* is `evalEveryNFrames * flowEvalEveryNFrames`.
|
|
79
|
-
*
|
|
80
|
-
* Lifecycle
|
|
81
|
-
*
|
|
82
|
-
* `start()` subscribes to the gyro and resets pose accumulators.
|
|
83
|
-
* `stop()` unsubscribes and resets. The returned `frameProcessor`
|
|
84
|
-
* is meant to be passed to `<Camera frameProcessor={...} />` —
|
|
85
|
-
* it's stable as long as the plugin reference and the FoV props
|
|
86
|
-
* haven't changed. Returns `null` when the plugin isn't loaded
|
|
87
|
-
* yet; pass `null`-or-fallback to the Camera in that case.
|
|
88
|
-
*
|
|
89
|
-
* Pairing with `IncrementalStitcher.start({frameSourceMode})`
|
|
90
|
-
*
|
|
91
|
-
* The plugin's per-frame call into `consumeFrameFromPlugin` is
|
|
92
|
-
* gated by `IncrementalStitcher.frameProcessorIngestEnabled`,
|
|
93
|
-
* which is TRUE only when the stitcher was started with
|
|
94
|
-
* `frameSourceMode === 'frameProcessor'`. Hosts MUST call
|
|
95
|
-
* `incrementalStitcher.start({ frameSourceMode: 'frameProcessor',
|
|
96
|
-
* ... })` to actually get frames into the engine — otherwise the
|
|
97
|
-
* worklet runs to completion but the wrapper drops the call.
|
|
98
|
-
* `Camera.tsx` does this wiring automatically when the host opts
|
|
99
|
-
* into this driver.
|
|
7
|
+
* v0.11.0 — refactored to a thin wrapper around `useStitcherWorklet`.
|
|
8
|
+
* The plugin acquisition + shared-value declarations + gyro
|
|
9
|
+
* subscription + worklet body all live in `useStitcherWorklet` now;
|
|
10
|
+
* this hook just binds the returned worklet via vision-camera's
|
|
11
|
+
* `useFrameProcessor` and exposes the legacy `start` / `stop` /
|
|
12
|
+
* `isRunning` API for backwards compatibility with v0.10.x.
|
|
13
|
+
*
|
|
14
|
+
* ## Why the v0.11.0 split
|
|
15
|
+
*
|
|
16
|
+
* vision-camera v4 allows ONE frame processor per `<Camera>` mount.
|
|
17
|
+
* Pre-v0.11.0, hosts that wanted to compose their own worklet with
|
|
18
|
+
* the lib's first-party stitching couldn't — passing a host
|
|
19
|
+
* `frameProcessor` REPLACED the lib's processor. v0.11.0 closes
|
|
20
|
+
* this gap by exposing the worklet body via `useStitcherWorklet`
|
|
21
|
+
* so hosts can write:
|
|
22
|
+
*
|
|
23
|
+
* const stitcher = useStitcherWorklet();
|
|
24
|
+
* const fp = useFrameProcessor((frame) => {
|
|
25
|
+
* 'worklet';
|
|
26
|
+
* hostPreLogic(frame);
|
|
27
|
+
* stitcher.call(frame); // ← first-party stitching
|
|
28
|
+
* hostPostLogic(frame);
|
|
29
|
+
* }, [stitcher.call]);
|
|
30
|
+
*
|
|
31
|
+
* `useFrameProcessorDriver` keeps the legacy default-integration
|
|
32
|
+
* shape (start / stop / isRunning) for the `<Camera>` component's
|
|
33
|
+
* built-in non-AR path and for any host still using the v0.10.x API
|
|
34
|
+
* directly. No behavioural change for those callers.
|
|
35
|
+
*
|
|
36
|
+
* ## start / stop behaviour
|
|
37
|
+
*
|
|
38
|
+
* - `start()` calls `stitcher.reset()` to zero the accumulated
|
|
39
|
+
* pose (preserves the pre-v0.11.0 "each capture starts with
|
|
40
|
+
* pose = (0, 0, 0)" contract).
|
|
41
|
+
* - `stop()` also resets the pose (idempotent; matches the
|
|
42
|
+
* pre-v0.11.0 stop() side effect of zeroing yaw / pitch / roll).
|
|
43
|
+
* - The gyro subscription itself is owned by `useStitcherWorklet`
|
|
44
|
+
* and runs for the lifetime of the hook. In the default
|
|
45
|
+
* `<Camera>` integration this means gyro is on while the camera
|
|
46
|
+
* screen is mounted — same practical scope as pre-v0.11.0 in
|
|
47
|
+
* all observed host integrations (capture screens mount
|
|
48
|
+
* `<Camera>` for the duration of capture; idle screens don't).
|
|
49
|
+
*
|
|
50
|
+
* ## Pose synthesis / intrinsics / throttling
|
|
51
|
+
*
|
|
52
|
+
* Owned by `useStitcherWorklet`. See that file's header for the
|
|
53
|
+
* quaternion math, FoV-to-intrinsics derivation, throttle gate, and
|
|
54
|
+
* pairing-with-IncrementalStitcher.start docs.
|
|
100
55
|
*/
|
|
101
56
|
import type { ReadonlyFrameProcessor } from 'react-native-vision-camera';
|
|
102
57
|
export interface UseFrameProcessorDriverOptions {
|
|
@@ -131,9 +86,9 @@ export interface UseFrameProcessorDriverOptions {
|
|
|
131
86
|
evalEveryNFrames?: number;
|
|
132
87
|
}
|
|
133
88
|
export interface FrameProcessorDriverHandle {
|
|
134
|
-
/**
|
|
89
|
+
/** Reset pose accumulators + mark the driver as running. Idempotent. */
|
|
135
90
|
start: () => void;
|
|
136
|
-
/**
|
|
91
|
+
/** Reset pose + mark the driver as stopped. Idempotent. */
|
|
137
92
|
stop: () => void;
|
|
138
93
|
/**
|
|
139
94
|
* Pass this to `<Camera frameProcessor={...} />`. `null` until
|