react-native-vision-camera-spoof-detector 1.0.28 → 1.1.7
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.
Potentially problematic release.
This version of react-native-vision-camera-spoof-detector might be problematic. Click here for more details.
- package/.npmignore +16 -99
- package/README.md +5 -4
- package/android/CMakeLists.txt +29 -0
- package/android/build.gradle +26 -12
- package/android/fix-prefab.gradle +4 -0
- package/android/src/main/AndroidManifest.xml +1 -1
- package/android/src/main/cpp/CMakeLists.txt +18 -86
- package/android/src/main/cpp/FaceAntiSpoofJSI.cpp +80 -6
- package/android/src/main/cpp/cpp-adapter.cpp +9 -0
- package/android/src/main/java/com/faceantispoof/FaceAntiSpoofModule.kt +108 -103
- package/android/src/main/java/com/faceantispoof/FaceAntiSpoofPackage.kt +12 -27
- package/android/src/main/java/com/faceantispoof/FaceAntiSpoofingAdvanced.kt +58 -1
- package/android/src/main/java/com/margelo/nitro/camera/spoofdetector/HybridSpoofDetectorFactory.kt +15 -0
- package/android/src/main/java/com/margelo/nitro/camera/spoofdetector/HybridSpoofDetectorOutput.kt +107 -0
- package/index.d.ts +14 -1
- package/index.js +26 -57
- package/nitro.json +20 -0
- package/nitrogen/generated/.gitattributes +1 -0
- package/nitrogen/generated/android/VisionCameraSpoofDetector+autolinking.cmake +81 -0
- package/nitrogen/generated/android/VisionCameraSpoofDetector+autolinking.gradle +27 -0
- package/nitrogen/generated/android/VisionCameraSpoofDetectorOnLoad.cpp +58 -0
- package/nitrogen/generated/android/VisionCameraSpoofDetectorOnLoad.hpp +34 -0
- package/nitrogen/generated/android/c++/JAntiSpoofingResult.hpp +77 -0
- package/nitrogen/generated/android/c++/JFunc_void_AntiSpoofingResult.hpp +78 -0
- package/nitrogen/generated/android/c++/JFunc_void_std__exception_ptr.hpp +76 -0
- package/nitrogen/generated/android/c++/JHybridSpoofDetectorFactorySpec.cpp +75 -0
- package/nitrogen/generated/android/c++/JHybridSpoofDetectorFactorySpec.hpp +63 -0
- package/nitrogen/generated/android/c++/JSize.hpp +61 -0
- package/nitrogen/generated/android/c++/JSpoofDetectorOutputOptions.hpp +91 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/camera/spoofdetector/AntiSpoofingResult.kt +76 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/camera/spoofdetector/Func_void_AntiSpoofingResult.kt +78 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/camera/spoofdetector/Func_void_std__exception_ptr.kt +78 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/camera/spoofdetector/HybridSpoofDetectorFactorySpec.kt +57 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/camera/spoofdetector/Size.kt +56 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/camera/spoofdetector/SpoofDetectorOutputOptions.kt +65 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/camera/spoofdetector/VisionCameraSpoofDetectorOnLoad.kt +35 -0
- package/nitrogen/generated/shared/c++/AntiSpoofingResult.hpp +103 -0
- package/nitrogen/generated/shared/c++/HybridSpoofDetectorFactorySpec.cpp +21 -0
- package/nitrogen/generated/shared/c++/HybridSpoofDetectorFactorySpec.hpp +67 -0
- package/nitrogen/generated/shared/c++/Size.hpp +87 -0
- package/nitrogen/generated/shared/c++/SpoofDetectorOutputOptions.hpp +98 -0
- package/package.json +12 -13
- package/react-native-vision-camera-spoof-detector.podspec +4 -4
- package/src/specs/SpoofDetectorFactory.nitro.ts +23 -0
- package/.gitattributes +0 -2
- package/CONTRIBUTING.md +0 -280
- package/android/.gradle/8.9/checksums/checksums.lock +0 -0
- package/android/.gradle/8.9/checksums/sha1-checksums.bin +0 -0
- package/android/.gradle/8.9/dependencies-accessors/gc.properties +0 -0
- package/android/.gradle/8.9/fileChanges/last-build.bin +0 -0
- package/android/.gradle/8.9/fileHashes/fileHashes.lock +0 -0
- package/android/.gradle/8.9/gc.properties +0 -0
- package/android/.gradle/9.2.0/checksums/checksums.lock +0 -0
- package/android/.gradle/9.2.0/checksums/md5-checksums.bin +0 -0
- package/android/.gradle/9.2.0/checksums/sha1-checksums.bin +0 -0
- package/android/.gradle/9.2.0/fileChanges/last-build.bin +0 -0
- package/android/.gradle/9.2.0/fileHashes/fileHashes.bin +0 -0
- package/android/.gradle/9.2.0/fileHashes/fileHashes.lock +0 -0
- package/android/.gradle/9.2.0/gc.properties +0 -0
- package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
- package/android/.gradle/buildOutputCleanup/cache.properties +0 -2
- package/android/.gradle/vcs-1/gc.properties +0 -0
- package/android/build/reports/problems/problems-report.html +0 -659
- package/android/src/main/assets/spoof_model_scale_2_7.tflite +0 -0
- package/android/src/main/assets/spoof_model_scale_4_0.tflite +0 -0
- package/android/src/main/java/com/faceantispoof/FaceAntiSpoofFrameProcessor.kt +0 -198
- /package/{android/src/main → lib}/assets/FaceAntiSpoofing.tflite +0 -0
|
Binary file
|
|
Binary file
|
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
package com.faceantispoof
|
|
2
|
-
|
|
3
|
-
import com.mrousavy.camera.frameprocessors.Frame
|
|
4
|
-
import com.mrousavy.camera.frameprocessors.FrameProcessorPlugin
|
|
5
|
-
import android.util.Log
|
|
6
|
-
import java.util.concurrent.Executors
|
|
7
|
-
import java.util.concurrent.ConcurrentHashMap
|
|
8
|
-
import java.util.concurrent.atomic.AtomicReference
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Frame processor that performs face anti-spoofing detection directly on YUV frames
|
|
12
|
-
* without creating intermediate Bitmaps. Uses ByteBuffer and FloatArray for efficient processing.
|
|
13
|
-
*
|
|
14
|
-
* IMPORTANT: All heavy processing is offloaded to a dedicated background thread (not the VisionCamera callback thread)
|
|
15
|
-
* to prevent frame drop issues and ensure smooth camera preview.
|
|
16
|
-
*/
|
|
17
|
-
class FaceAntiSpoofFrameProcessor : FrameProcessorPlugin() {
|
|
18
|
-
|
|
19
|
-
private var faceAntiSpoofing: FaceAntiSpoofingAdvanced? = null
|
|
20
|
-
private var isInitialized = false
|
|
21
|
-
|
|
22
|
-
// Single-threaded executor for offloading processing tasks
|
|
23
|
-
private val processingExecutor = Executors.newSingleThreadExecutor { runnable ->
|
|
24
|
-
Thread(runnable, "FaceAntiSpoofProcessor").apply { isDaemon = true }
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// Store the latest result to avoid race conditions
|
|
28
|
-
private val latestResult: AtomicReference<Map<String, Any?>> = AtomicReference(
|
|
29
|
-
mapOf(
|
|
30
|
-
"error" to "Not initialized",
|
|
31
|
-
"isLive" to false,
|
|
32
|
-
"label" to "Not Initialized"
|
|
33
|
-
)
|
|
34
|
-
)
|
|
35
|
-
|
|
36
|
-
// Track if processing is in flight to prevent queue overflow
|
|
37
|
-
private val isProcessing = AtomicReference(false)
|
|
38
|
-
|
|
39
|
-
fun initialize(assets: android.content.res.AssetManager) {
|
|
40
|
-
try {
|
|
41
|
-
faceAntiSpoofing = FaceAntiSpoofingAdvanced(assets)
|
|
42
|
-
isInitialized = true
|
|
43
|
-
Log.i("FaceAntiSpoof", "Initialized successfully")
|
|
44
|
-
} catch (e: Exception) {
|
|
45
|
-
Log.e("FaceAntiSpoof", "Initialization failed: ${e.message}", e)
|
|
46
|
-
isInitialized = false
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
override fun callback(frame: Frame, params: Map<String, Any?>?): Any? {
|
|
51
|
-
// Return immediately without blocking the VisionCamera thread
|
|
52
|
-
// The callback should return quickly to avoid frame drops
|
|
53
|
-
|
|
54
|
-
if (!isInitialized) {
|
|
55
|
-
return latestResult.get()
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// Only process if the previous frame has finished processing
|
|
59
|
-
// This prevents accumulating a queue of frames to process
|
|
60
|
-
if (!isProcessing.compareAndSet(false, true)) {
|
|
61
|
-
// Processing already in flight, return the latest result
|
|
62
|
-
return latestResult.get()
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// CRITICAL: Copy frame data BEFORE submitting to background thread
|
|
66
|
-
// The frame reference becomes invalid after the callback returns
|
|
67
|
-
val nv21: ByteArray
|
|
68
|
-
val width: Int
|
|
69
|
-
val height: Int
|
|
70
|
-
|
|
71
|
-
try {
|
|
72
|
-
// Extract YUV data immediately while the frame is still valid
|
|
73
|
-
val image = frame.getImage() ?: throw Exception("Frame image is null")
|
|
74
|
-
val planes = image.planes
|
|
75
|
-
|
|
76
|
-
if (planes == null) {
|
|
77
|
-
throw Exception("Frame planes are null")
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
if (planes.size < 3) {
|
|
81
|
-
throw Exception("Invalid frame planes: expected 3, got ${planes.size}")
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
val yBuffer = planes[0]?.buffer ?: throw Exception("Y buffer is null")
|
|
85
|
-
val uBuffer = planes[1]?.buffer ?: throw Exception("U buffer is null")
|
|
86
|
-
val vBuffer = planes[2]?.buffer ?: throw Exception("V buffer is null")
|
|
87
|
-
|
|
88
|
-
// Ensure buffers are accessible
|
|
89
|
-
if (!yBuffer.isDirect && !yBuffer.hasArray()) {
|
|
90
|
-
throw Exception("Y buffer is not accessible")
|
|
91
|
-
}
|
|
92
|
-
if (!uBuffer.isDirect && !uBuffer.hasArray()) {
|
|
93
|
-
throw Exception("U buffer is not accessible")
|
|
94
|
-
}
|
|
95
|
-
if (!vBuffer.isDirect && !vBuffer.hasArray()) {
|
|
96
|
-
throw Exception("V buffer is not accessible")
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
yBuffer.rewind()
|
|
100
|
-
uBuffer.rewind()
|
|
101
|
-
vBuffer.rewind()
|
|
102
|
-
|
|
103
|
-
val ySize = yBuffer.remaining()
|
|
104
|
-
val uSize = uBuffer.remaining()
|
|
105
|
-
val vSize = vBuffer.remaining()
|
|
106
|
-
|
|
107
|
-
if (ySize <= 0 || uSize <= 0 || vSize <= 0) {
|
|
108
|
-
throw Exception("Invalid buffer sizes: Y=$ySize, U=$uSize, V=$vSize")
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
nv21 = ByteArray(ySize + uSize + vSize)
|
|
112
|
-
|
|
113
|
-
try {
|
|
114
|
-
yBuffer.get(nv21, 0, ySize)
|
|
115
|
-
vBuffer.get(nv21, ySize, vSize)
|
|
116
|
-
uBuffer.get(nv21, ySize + vSize, uSize)
|
|
117
|
-
} catch (e: Exception) {
|
|
118
|
-
throw Exception("Error copying YUV buffers: ${e.message}", e)
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
width = frame.getWidth()
|
|
122
|
-
height = frame.getHeight()
|
|
123
|
-
|
|
124
|
-
if (width <= 0 || height <= 0) {
|
|
125
|
-
throw Exception("Invalid frame dimensions: width=$width, height=$height")
|
|
126
|
-
}
|
|
127
|
-
} catch (e: Exception) {
|
|
128
|
-
Log.e("FaceAntiSpoof", "Error extracting frame data: ${e.message}", e)
|
|
129
|
-
val errorMap = mapOf(
|
|
130
|
-
"error" to e.message,
|
|
131
|
-
"isLive" to false,
|
|
132
|
-
"label" to "Error: ${e.message}"
|
|
133
|
-
)
|
|
134
|
-
latestResult.set(errorMap)
|
|
135
|
-
isProcessing.set(false)
|
|
136
|
-
return latestResult.get()
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// Submit the heavy processing to the background thread executor
|
|
140
|
-
// Now using the copied nv21 data, not the frame reference
|
|
141
|
-
processingExecutor.submit {
|
|
142
|
-
try {
|
|
143
|
-
val faceAntispoof = faceAntiSpoofing ?: throw Exception("FaceAntiSpoofing not initialized")
|
|
144
|
-
|
|
145
|
-
// Process copied NV21 data directly (no Bitmap conversion)
|
|
146
|
-
val result = faceAntispoof.advancedAntiSpoofing(nv21, width, height)
|
|
147
|
-
|
|
148
|
-
val resultMap = mapOf(
|
|
149
|
-
"neuralNetworkScore" to result.neuralNetworkScore.toDouble(),
|
|
150
|
-
"laplacianScore" to result.laplacianScore,
|
|
151
|
-
"combinedScore" to result.combinedScore.toDouble(),
|
|
152
|
-
"confidence" to result.confidence.toDouble()
|
|
153
|
-
)
|
|
154
|
-
|
|
155
|
-
// Update the latest result for the next callback
|
|
156
|
-
latestResult.set(resultMap)
|
|
157
|
-
} catch (e: Exception) {
|
|
158
|
-
Log.e("FaceAntiSpoof", "Processing error: ${e.message}", e)
|
|
159
|
-
val errorMap = mapOf(
|
|
160
|
-
"error" to e.message,
|
|
161
|
-
"isLive" to false,
|
|
162
|
-
"label" to "Error: ${e.message}"
|
|
163
|
-
)
|
|
164
|
-
latestResult.set(errorMap)
|
|
165
|
-
} finally {
|
|
166
|
-
// Mark processing as complete for the next frame
|
|
167
|
-
isProcessing.set(false)
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
// Return the latest result immediately without waiting
|
|
172
|
-
return latestResult.get()
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
* Cleanup resources when the frame processor is no longer needed
|
|
177
|
-
* This should be called when the camera is closed or the app is destroyed
|
|
178
|
-
*/
|
|
179
|
-
fun cleanup() {
|
|
180
|
-
try {
|
|
181
|
-
// Shutdown the executor and wait for any running tasks to complete
|
|
182
|
-
processingExecutor.shutdown()
|
|
183
|
-
if (!processingExecutor.awaitTermination(5, java.util.concurrent.TimeUnit.SECONDS)) {
|
|
184
|
-
Log.w("FaceAntiSpoof", "Executor did not terminate in time, forcing shutdown")
|
|
185
|
-
processingExecutor.shutdownNow()
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
// Clean up the face anti-spoofing model
|
|
189
|
-
faceAntiSpoofing?.close()
|
|
190
|
-
faceAntiSpoofing = null
|
|
191
|
-
isInitialized = false
|
|
192
|
-
|
|
193
|
-
Log.i("FaceAntiSpoof", "Cleanup completed successfully")
|
|
194
|
-
} catch (e: Exception) {
|
|
195
|
-
Log.e("FaceAntiSpoof", "Error during cleanup: ${e.message}", e)
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
}
|
|
File without changes
|