react-native-image-stitcher 0.14.2 → 0.15.1
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 +164 -0
- package/README.md +35 -0
- package/RNImageStitcher.podspec +8 -7
- package/android/build.gradle +0 -16
- package/android/src/main/cpp/CMakeLists.txt +2 -63
- package/android/src/main/cpp/image_stitcher_jni.cpp +14 -0
- package/android/src/main/cpp/keyframe_gate_jni.cpp +13 -0
- package/android/src/main/java/io/imagestitcher/rn/BatchStitcher.kt +285 -3
- package/android/src/main/java/io/imagestitcher/rn/IncrementalStitcher.kt +180 -1162
- package/android/src/main/java/io/imagestitcher/rn/KeyframeGate.kt +29 -0
- package/android/src/main/java/io/imagestitcher/rn/RNImageStitcherPackage.kt +0 -4
- package/android/src/main/java/io/imagestitcher/rn/RNSARCameraView.kt +129 -71
- package/android/src/main/java/io/imagestitcher/rn/RNSARSession.kt +49 -0
- package/cpp/keyframe_gate.cpp +82 -23
- package/cpp/keyframe_gate.hpp +31 -2
- package/cpp/stitcher.cpp +208 -28
- package/cpp/tests/CMakeLists.txt +18 -12
- package/cpp/tests/keyframe_timebudget_test.cpp +65 -0
- package/cpp/tests/warp_guard_test.cpp +48 -0
- package/cpp/warp_guard.hpp +41 -0
- package/dist/camera/Camera.d.ts +31 -16
- package/dist/camera/Camera.js +11 -3
- package/dist/camera/CameraView.js +93 -3
- package/dist/camera/CaptureStitchStatsToast.d.ts +15 -2
- package/dist/camera/CaptureStitchStatsToast.js +27 -7
- package/dist/camera/PanoramaSettings.d.ts +10 -223
- package/dist/camera/PanoramaSettings.js +6 -28
- package/dist/camera/PanoramaSettingsBridge.d.ts +1 -24
- package/dist/camera/PanoramaSettingsBridge.js +3 -102
- package/dist/camera/PanoramaSettingsModal.js +7 -1
- package/dist/camera/buildPanoramaInitialSettings.d.ts +11 -0
- package/dist/camera/buildPanoramaInitialSettings.js +4 -0
- package/dist/camera/cameraErrorMessages.d.ts +32 -0
- package/dist/camera/cameraErrorMessages.js +53 -0
- package/dist/camera/selectCaptureDevice.d.ts +5 -1
- package/dist/camera/selectCaptureDevice.js +22 -2
- package/dist/camera/useCapture.js +38 -0
- package/dist/index.d.ts +5 -8
- package/dist/index.js +11 -34
- package/dist/stitching/incremental.d.ts +1 -117
- package/dist/stitching/stitchVideo.d.ts +0 -35
- package/dist/types.d.ts +0 -87
- package/ios/Sources/RNImageStitcher/IncrementalStitcher.swift +96 -674
- package/ios/Sources/RNImageStitcher/IncrementalStitcherBridge.swift +9 -12
- package/ios/Sources/RNImageStitcher/KeyframeGate.swift +14 -0
- package/ios/Sources/RNImageStitcher/KeyframeGateBridge.h +7 -0
- package/ios/Sources/RNImageStitcher/KeyframeGateBridge.mm +6 -0
- package/ios/Sources/RNImageStitcher/OpenCVKeyframeCollector.h +2 -2
- package/ios/Sources/RNImageStitcher/OpenCVKeyframeCollector.mm +3 -3
- package/ios/Sources/RNImageStitcher/OpenCVStitcher.h +28 -60
- package/ios/Sources/RNImageStitcher/OpenCVStitcher.mm +180 -921
- package/ios/Sources/RNImageStitcher/RNSARCameraView.swift +82 -7
- package/ios/Sources/RNImageStitcher/RNSARSession.swift +10 -35
- package/ios/Sources/RNImageStitcher/Stitcher.swift +84 -35
- package/ios/Sources/RNImageStitcher/StitcherBridge.m +13 -0
- package/ios/Sources/RNImageStitcher/StitcherBridge.swift +132 -5
- package/package.json +3 -2
- package/src/camera/Camera.tsx +44 -23
- package/src/camera/CameraView.tsx +113 -4
- package/src/camera/CaptureStitchStatsToast.tsx +58 -14
- package/src/camera/PanoramaSettings.ts +16 -289
- package/src/camera/PanoramaSettingsBridge.ts +3 -114
- package/src/camera/PanoramaSettingsModal.tsx +14 -1
- package/src/camera/__tests__/PanoramaSettingsBridge.test.ts +3 -188
- package/src/camera/__tests__/buildPanoramaInitialSettings.test.ts +41 -0
- package/src/camera/__tests__/cameraErrorMessages.test.ts +76 -0
- package/src/camera/__tests__/selectCaptureDevice.test.ts +33 -0
- package/src/camera/buildPanoramaInitialSettings.ts +17 -0
- package/src/camera/cameraErrorMessages.ts +84 -0
- package/src/camera/selectCaptureDevice.ts +28 -3
- package/src/camera/useCapture.ts +44 -1
- package/src/index.ts +11 -40
- package/src/stitching/incremental.ts +3 -140
- package/src/stitching/stitchVideo.ts +0 -26
- package/src/types.ts +0 -95
- package/android/src/main/cpp/stitcher_jsi_install_jni.cpp +0 -227
- package/android/src/main/java/io/imagestitcher/rn/IncrementalFirstwinsEngine.kt +0 -1081
- package/android/src/main/java/io/imagestitcher/rn/StitcherJsiInstallerModule.kt +0 -103
- package/android/src/main/java/io/imagestitcher/rn/StitcherWorkletRuntime.kt +0 -256
- package/cpp/stitcher_frame_jsi.cpp +0 -214
- package/cpp/stitcher_frame_jsi.hpp +0 -108
- package/cpp/stitcher_proxy_jsi.cpp +0 -109
- package/cpp/stitcher_proxy_jsi.hpp +0 -46
- package/cpp/stitcher_worklet_dispatch.cpp +0 -103
- package/cpp/stitcher_worklet_dispatch.hpp +0 -71
- package/cpp/stitcher_worklet_registry.cpp +0 -91
- package/cpp/stitcher_worklet_registry.hpp +0 -146
- package/cpp/tests/stitcher_worklet_registry_test.cpp +0 -195
- package/dist/stitching/IncrementalStitcherView.d.ts +0 -41
- package/dist/stitching/IncrementalStitcherView.js +0 -157
- package/dist/stitching/StitcherWorkletRegistry.d.ts +0 -117
- package/dist/stitching/StitcherWorkletRegistry.js +0 -78
- package/dist/stitching/ensureStitcherProxyInstalled.d.ts +0 -8
- package/dist/stitching/ensureStitcherProxyInstalled.js +0 -81
- package/dist/stitching/useFrameProcessor.d.ts +0 -119
- package/dist/stitching/useFrameProcessor.js +0 -196
- package/dist/stitching/useFrameStream.d.ts +0 -34
- package/dist/stitching/useFrameStream.js +0 -234
- package/dist/stitching/useThrottledFrameProcessor.d.ts +0 -33
- package/dist/stitching/useThrottledFrameProcessor.js +0 -132
- package/ios/Sources/RNImageStitcher/OpenCVIncrementalStitcher.h +0 -474
- package/ios/Sources/RNImageStitcher/OpenCVIncrementalStitcher.mm +0 -1328
- package/ios/Sources/RNImageStitcher/OpenCVSlitScanStitcher.h +0 -103
- package/ios/Sources/RNImageStitcher/OpenCVSlitScanStitcher.mm +0 -3285
- package/ios/Sources/RNImageStitcher/RNSARWorkletRuntime.h +0 -128
- package/ios/Sources/RNImageStitcher/RNSARWorkletRuntime.mm +0 -313
- package/ios/Sources/RNImageStitcher/SaveFrameAsJpegPlugin.mm +0 -185
- package/ios/Sources/RNImageStitcher/StitcherFrameHostObject.h +0 -60
- package/ios/Sources/RNImageStitcher/StitcherFrameHostObject.mm +0 -214
- package/ios/Sources/RNImageStitcher/StitcherJsiInstaller.h +0 -42
- package/ios/Sources/RNImageStitcher/StitcherJsiInstaller.mm +0 -160
- package/src/stitching/IncrementalStitcherView.tsx +0 -198
- package/src/stitching/StitcherWorkletRegistry.ts +0 -156
- package/src/stitching/__tests__/StitcherWorkletRegistry.test.ts +0 -176
- package/src/stitching/__tests__/ensureStitcherProxyInstalled.test.ts +0 -94
- package/src/stitching/__tests__/useThrottledFrameProcessor.test.ts +0 -178
- package/src/stitching/ensureStitcherProxyInstalled.ts +0 -141
- package/src/stitching/useFrameProcessor.ts +0 -226
- package/src/stitching/useFrameStream.ts +0 -271
- package/src/stitching/useThrottledFrameProcessor.ts +0 -145
|
@@ -1,227 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
//
|
|
3
|
-
// stitcher_jsi_install_jni.cpp — JNI binding for the Android-side
|
|
4
|
-
// JSI install (v0.8.0 Phase 4b.ii).
|
|
5
|
-
//
|
|
6
|
-
// Kotlin's `StitcherJsiInstallerModule.nativeInstall(jsiRuntimeRef)`
|
|
7
|
-
// calls into this file. We unbox the `jsi::Runtime*` from the
|
|
8
|
-
// Java `long` and hand it to the shared
|
|
9
|
-
// `retailens::installStitcherProxy(runtime)` function which sets
|
|
10
|
-
// `globalThis.__stitcherProxy`. Same destination as iOS — the
|
|
11
|
-
// host object class lives in `cpp/stitcher_proxy_jsi.{hpp,cpp}`.
|
|
12
|
-
//
|
|
13
|
-
// ## Why a `long` ref, not a JSI handle wrapper class
|
|
14
|
-
//
|
|
15
|
-
// `ReactApplicationContext.getJavaScriptContextHolder()` returns a
|
|
16
|
-
// `JavaScriptContextHolder` whose `.get()` returns a Java `long`
|
|
17
|
-
// that's the raw pointer to the C++ `jsi::Runtime*`. Same
|
|
18
|
-
// contract as worklets-core's `WorkletsModule.nativeInstall`
|
|
19
|
-
// (verified at the same call site). Caller is responsible for
|
|
20
|
-
// ensuring the runtime outlives this call — in practice, the
|
|
21
|
-
// runtime IS the JS thread's runtime which lives the whole
|
|
22
|
-
// process lifetime, so this is structurally always safe in our
|
|
23
|
-
// usage.
|
|
24
|
-
//
|
|
25
|
-
// ## Threading
|
|
26
|
-
//
|
|
27
|
-
// Kotlin invokes this from a `@ReactMethod(isBlockingSynchronousMethod
|
|
28
|
-
// = true)` so we're already on the JS thread. Synchronous JSI
|
|
29
|
-
// access is safe.
|
|
30
|
-
|
|
31
|
-
#include "stitcher_proxy_jsi.hpp"
|
|
32
|
-
|
|
33
|
-
// v0.8.0 Phase 4b.iii — per-frame fan-out support. The shared
|
|
34
|
-
// `dispatchToHostWorklets` posts to worklets-core's default context;
|
|
35
|
-
// this JNI file's `nativeDispatchToHostWorklets` constructs the
|
|
36
|
-
// `StitcherFrameData` from raw bytes + pose + dims and forwards it.
|
|
37
|
-
#include "stitcher_frame_data.hpp"
|
|
38
|
-
#include "stitcher_worklet_dispatch.hpp"
|
|
39
|
-
#include "stitcher_worklet_registry.hpp"
|
|
40
|
-
|
|
41
|
-
#include <react-native-worklets-core/WKTJsiWorkletContext.h>
|
|
42
|
-
|
|
43
|
-
#include <jni.h>
|
|
44
|
-
#include <jsi/jsi.h>
|
|
45
|
-
|
|
46
|
-
#include <android/log.h>
|
|
47
|
-
|
|
48
|
-
#include <cstdint>
|
|
49
|
-
#include <cstring>
|
|
50
|
-
#include <memory>
|
|
51
|
-
#include <utility>
|
|
52
|
-
#include <vector>
|
|
53
|
-
|
|
54
|
-
#define LOG_TAG "StitcherJsiInstaller"
|
|
55
|
-
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
|
|
56
|
-
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
|
|
57
|
-
|
|
58
|
-
extern "C" JNIEXPORT jboolean JNICALL
|
|
59
|
-
Java_io_imagestitcher_rn_StitcherJsiInstallerModule_nativeInstall(
|
|
60
|
-
JNIEnv* /*env*/, jobject /*thiz*/, jlong jsiRuntimeRef) {
|
|
61
|
-
if (jsiRuntimeRef == 0) {
|
|
62
|
-
// ReactApplicationContext.getJavaScriptContextHolder().get()
|
|
63
|
-
// returns 0 when the runtime isn't ready (rare — JS would have
|
|
64
|
-
// had to call us before its own runtime was up; impossible in
|
|
65
|
-
// practice). Defensive.
|
|
66
|
-
return JNI_FALSE;
|
|
67
|
-
}
|
|
68
|
-
auto* runtime = reinterpret_cast<facebook::jsi::Runtime*>(jsiRuntimeRef);
|
|
69
|
-
retailens::installStitcherProxy(*runtime);
|
|
70
|
-
LOGI("installed globalThis.__stitcherProxy on main JS runtime.");
|
|
71
|
-
return JNI_TRUE;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// ─── v0.8.0 Phase 4b.iii — Android NV21 PixelBufferReader ──────────
|
|
75
|
-
//
|
|
76
|
-
// Owns a heap-allocated `std::vector<uint8_t>` of pre-copied NV21
|
|
77
|
-
// bytes. Constructed by `nativeDispatchToHostWorklets` after one
|
|
78
|
-
// JNI byte-array copy from Kotlin; outlives the AR render thread
|
|
79
|
-
// scope via `StitcherFrameData::pixelReader`'s `shared_ptr` —
|
|
80
|
-
// dropped when the host object is invalidated.
|
|
81
|
-
|
|
82
|
-
namespace {
|
|
83
|
-
|
|
84
|
-
class AndroidNV21BufferReader : public retailens::PixelBufferReader {
|
|
85
|
-
public:
|
|
86
|
-
explicit AndroidNV21BufferReader(std::vector<uint8_t>&& bytes)
|
|
87
|
-
: _bytes(std::move(bytes)) {}
|
|
88
|
-
|
|
89
|
-
std::size_t byteSize() const override { return _bytes.size(); }
|
|
90
|
-
|
|
91
|
-
std::size_t copyTo(uint8_t* dst, std::size_t maxBytes) override {
|
|
92
|
-
if (dst == nullptr) return 0;
|
|
93
|
-
std::size_t n = std::min(maxBytes, _bytes.size());
|
|
94
|
-
if (n > 0) {
|
|
95
|
-
std::memcpy(dst, _bytes.data(), n);
|
|
96
|
-
}
|
|
97
|
-
return n;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
private:
|
|
101
|
-
std::vector<uint8_t> _bytes;
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
} // namespace
|
|
105
|
-
|
|
106
|
-
// ─── v0.8.0 Phase 4b.iii — registry count accessor ─────────────────
|
|
107
|
-
//
|
|
108
|
-
// Cheap (microsecond) accessor for the per-frame gate in
|
|
109
|
-
// `RNSARCameraView.onDrawFrame`. Avoids the NV21 byte-pack cost
|
|
110
|
-
// when no host worklets are registered AND no capture is active.
|
|
111
|
-
// Same atomic-read the JSI host object's `count()` host function
|
|
112
|
-
// goes through.
|
|
113
|
-
extern "C" JNIEXPORT jint JNICALL
|
|
114
|
-
Java_io_imagestitcher_rn_StitcherWorkletRuntime_nativeRegistryCount(
|
|
115
|
-
JNIEnv* /*env*/, jobject /*thiz*/) {
|
|
116
|
-
return static_cast<jint>(
|
|
117
|
-
retailens::StitcherWorkletRegistry::shared().count());
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// ─── v0.8.0 Phase 4b.iii — per-frame dispatch JNI binding ──────────
|
|
121
|
-
//
|
|
122
|
-
// Called from Kotlin's `StitcherWorkletRuntime.dispatchToHostWorklets`
|
|
123
|
-
// after the first-party stitching block has returned (the AR-frame
|
|
124
|
-
// data is still in scope on the Kotlin side because
|
|
125
|
-
// `RNSARCameraView.onDrawFrame` reads the ARCore Frame, builds the
|
|
126
|
-
// NV21 byte[], invokes first-party via `runFirstParty { ... }`,
|
|
127
|
-
// THEN calls into here).
|
|
128
|
-
//
|
|
129
|
-
// The byte[] is COPIED into our owned vector — ARCore's pixel data
|
|
130
|
-
// becomes inaccessible shortly after `onDrawFrame` returns, and our
|
|
131
|
-
// async dispatch must outlive that scope. Cost: one ~3MB memcpy
|
|
132
|
-
// per frame at 1080p NV21 (~90 MB/s at 30 fps; <5 ms on a mid-range
|
|
133
|
-
// Android device). Fast-path early-exit when the registry is empty
|
|
134
|
-
// skips the copy entirely.
|
|
135
|
-
//
|
|
136
|
-
// trackingState: Kotlin passes one of "" / "notAvailable" / "limited"
|
|
137
|
-
// / "normal" (empty string = field unset → JS sees undefined).
|
|
138
|
-
extern "C" JNIEXPORT void JNICALL
|
|
139
|
-
Java_io_imagestitcher_rn_StitcherWorkletRuntime_nativeDispatchToHostWorklets(
|
|
140
|
-
JNIEnv* env, jobject /*thiz*/,
|
|
141
|
-
jbyteArray nv21Bytes,
|
|
142
|
-
jint width, jint height,
|
|
143
|
-
jdouble qx, jdouble qy, jdouble qz, jdouble qw,
|
|
144
|
-
jdouble tx, jdouble ty, jdouble tz,
|
|
145
|
-
jdouble timestampNs,
|
|
146
|
-
jstring trackingState) {
|
|
147
|
-
// Fast-path early-exit BEFORE the JNI byte-array copy. Saves the
|
|
148
|
-
// ~3MB memcpy + JSI host object alloc on every frame in the
|
|
149
|
-
// common first-party-only case.
|
|
150
|
-
if (retailens::StitcherWorkletRegistry::shared().count() == 0) {
|
|
151
|
-
return;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
if (nv21Bytes == nullptr) {
|
|
155
|
-
LOGE("nativeDispatchToHostWorklets: nv21Bytes is null");
|
|
156
|
-
return;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
const jsize byteLen = env->GetArrayLength(nv21Bytes);
|
|
160
|
-
if (byteLen <= 0) {
|
|
161
|
-
LOGE("nativeDispatchToHostWorklets: nv21Bytes is empty");
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
// Copy into our owned vector. `GetByteArrayRegion` is the
|
|
166
|
-
// canonical "copy" path — `GetByteArrayElements + Release` MAY
|
|
167
|
-
// pin the JVM array (zero-copy) but the contract isn't
|
|
168
|
-
// guaranteed; we need our own buffer for the async dispatch
|
|
169
|
-
// anyway, so the explicit copy is cleaner.
|
|
170
|
-
std::vector<uint8_t> bytes(static_cast<std::size_t>(byteLen));
|
|
171
|
-
env->GetByteArrayRegion(
|
|
172
|
-
nv21Bytes, 0, byteLen,
|
|
173
|
-
reinterpret_cast<jbyte*>(bytes.data()));
|
|
174
|
-
|
|
175
|
-
// Extract trackingState string (may be null on the Kotlin side
|
|
176
|
-
// for non-AR or pre-tracking frames — guard accordingly).
|
|
177
|
-
std::string trackingStateStr;
|
|
178
|
-
if (trackingState != nullptr) {
|
|
179
|
-
const char* cs = env->GetStringUTFChars(trackingState, nullptr);
|
|
180
|
-
if (cs != nullptr) {
|
|
181
|
-
trackingStateStr = cs;
|
|
182
|
-
env->ReleaseStringUTFChars(trackingState, cs);
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
// Build StitcherFrameData. Field semantics match the iOS
|
|
187
|
-
// `StitcherFrameHostObject::fromARFrame:pose:` factory; this is
|
|
188
|
-
// the Android equivalent path.
|
|
189
|
-
retailens::StitcherFrameData data;
|
|
190
|
-
data.source = "ar";
|
|
191
|
-
data.width = static_cast<int32_t>(width);
|
|
192
|
-
data.height = static_cast<int32_t>(height);
|
|
193
|
-
// ARCore's camera image is YUV_420_888 on Android, mapped to NV21
|
|
194
|
-
// by the existing `YuvImageConverter.packNV21` path — the byte[]
|
|
195
|
-
// we receive is interleaved Y then VU. Worklets gate on this
|
|
196
|
-
// string identifier (`'yuv'` vs `'unknown'`); v0.8.0 always
|
|
197
|
-
// emits `'yuv'` for AR mode on Android (NV21).
|
|
198
|
-
data.pixelFormat = "yuv";
|
|
199
|
-
// Android AR-mode camera image is always landscape-natural; the
|
|
200
|
-
// mapping matches iOS' coarse two-value set. Hosts that need
|
|
201
|
-
// exact display orientation read it from the device-orientation
|
|
202
|
-
// sensors (see `useDeviceOrientation` hook).
|
|
203
|
-
data.orientation = (width >= height) ? "landscape-right" : "portrait";
|
|
204
|
-
data.timestampNs = timestampNs;
|
|
205
|
-
data.qx = qx;
|
|
206
|
-
data.qy = qy;
|
|
207
|
-
data.qz = qz;
|
|
208
|
-
data.qw = qw;
|
|
209
|
-
data.tx = tx;
|
|
210
|
-
data.ty = ty;
|
|
211
|
-
data.tz = tz;
|
|
212
|
-
data.hasTranslation = true; // AR mode always has translation
|
|
213
|
-
data.arTrackingState = trackingStateStr;
|
|
214
|
-
data.pixelReader =
|
|
215
|
-
std::make_shared<AndroidNV21BufferReader>(std::move(bytes));
|
|
216
|
-
|
|
217
|
-
// Dispatch on worklets-core's default context. That context is
|
|
218
|
-
// initialised by JS' `Worklets.install()` (which runs at lib
|
|
219
|
-
// bootstrap when worklets-core's module is imported); by the
|
|
220
|
-
// time host worklets are registered, the default context is up.
|
|
221
|
-
// The shared dispatch helper handles the registry snapshot,
|
|
222
|
-
// host-object construction (inside the worklet thread), per-
|
|
223
|
-
// worklet failure isolation, and invalidation.
|
|
224
|
-
retailens::dispatchToHostWorklets(
|
|
225
|
-
RNWorklet::JsiWorkletContext::getDefaultInstance(),
|
|
226
|
-
std::move(data));
|
|
227
|
-
}
|