react-native-nitro-pose-exercises 1.1.1 → 1.1.2
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/README.md
CHANGED
|
@@ -127,7 +127,7 @@ module.exports = {
|
|
|
127
127
|
The iOS podspec needs the Vision and AVFoundation system frameworks:
|
|
128
128
|
|
|
129
129
|
```ruby
|
|
130
|
-
s.frameworks =
|
|
130
|
+
s.frameworks = ["AVFoundation", "Vision"]
|
|
131
131
|
```
|
|
132
132
|
|
|
133
133
|
No CocoaPods dependencies required — Vision is built into iOS.
|
|
@@ -13,7 +13,6 @@ import com.google.mlkit.vision.pose.defaults.PoseDetectorOptions
|
|
|
13
13
|
import com.margelo.nitro.NitroModules
|
|
14
14
|
import com.margelo.nitro.core.Promise
|
|
15
15
|
import com.margelo.nitro.camera.HybridFrameSpec
|
|
16
|
-
import com.margelo.nitro.camera.NativeFrame
|
|
17
16
|
import kotlin.math.acos
|
|
18
17
|
import kotlin.math.max
|
|
19
18
|
import kotlin.math.min
|
|
@@ -191,7 +190,7 @@ class HybridPoseExercise : HybridNitroPoseExercisesSpec() {
|
|
|
191
190
|
// Frame Processing (ML Kit — async with cached results)
|
|
192
191
|
// ═══════════════════════════════════════════════════════════
|
|
193
192
|
|
|
194
|
-
|
|
193
|
+
override fun processFrame(frame: HybridFrameSpec) {
|
|
195
194
|
if (_status != SessionStatus.ACTIVE && _status != SessionStatus.COUNTDOWN) return
|
|
196
195
|
if (!isInitialized || poseDetector == null) return
|
|
197
196
|
|
|
@@ -199,17 +198,26 @@ class HybridPoseExercise : HybridNitroPoseExercisesSpec() {
|
|
|
199
198
|
frameCount++
|
|
200
199
|
if (frameCount % processEveryNFrames != 0) return
|
|
201
200
|
|
|
202
|
-
// Get the ImageProxy from VisionCamera frame
|
|
203
|
-
val nativeFrame = frame as? NativeFrame ?: return
|
|
204
|
-
val imageProxy = nativeFrame.image ?: return
|
|
205
|
-
|
|
206
201
|
try {
|
|
207
|
-
//
|
|
208
|
-
|
|
209
|
-
val
|
|
210
|
-
val
|
|
202
|
+
// Get raw buffer from VisionCamera frame
|
|
203
|
+
val nativeBuffer = frame.getNativeBuffer()
|
|
204
|
+
val width = frame.getWidth()
|
|
205
|
+
val height = frame.getHeight()
|
|
206
|
+
val bytesPerRow = frame.getBytesPerRow()
|
|
207
|
+
|
|
208
|
+
// Create Bitmap from the native buffer
|
|
209
|
+
val buffer = java.nio.ByteBuffer.allocateDirect(height * bytesPerRow)
|
|
210
|
+
val pointer = nativeBuffer.pointer
|
|
211
|
+
// Copy from native pointer to ByteBuffer
|
|
212
|
+
NativeBufferHelper.copyToByteBuffer(pointer, buffer, height * bytesPerRow)
|
|
213
|
+
|
|
214
|
+
val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
|
|
215
|
+
buffer.rewind()
|
|
216
|
+
bitmap.copyPixelsFromBuffer(buffer)
|
|
211
217
|
|
|
212
|
-
|
|
218
|
+
val inputImage = InputImage.fromBitmap(bitmap, 0)
|
|
219
|
+
|
|
220
|
+
// ML Kit is async — fire detection, cache result
|
|
213
221
|
poseDetector!!.process(inputImage)
|
|
214
222
|
.addOnSuccessListener { pose ->
|
|
215
223
|
val poseLandmarks = pose.allPoseLandmarks
|
|
@@ -220,17 +228,15 @@ class HybridPoseExercise : HybridNitroPoseExercisesSpec() {
|
|
|
220
228
|
onPoseRegained?.invoke()
|
|
221
229
|
}
|
|
222
230
|
|
|
223
|
-
// Build landmark array mapped to MediaPipe indices (34 slots)
|
|
224
231
|
val landmarkArray = Array(34) { Landmark(x = 0.0, y = 0.0, z = 0.0, visibility = 0.0) }
|
|
225
232
|
|
|
226
|
-
val imageWidth =
|
|
227
|
-
val imageHeight =
|
|
233
|
+
val imageWidth = width.toDouble()
|
|
234
|
+
val imageHeight = height.toDouble()
|
|
228
235
|
|
|
229
236
|
for (poseLandmark in poseLandmarks) {
|
|
230
237
|
val mediaPipeIndex = mlKitToMediaPipeMap[poseLandmark.landmarkType] ?: continue
|
|
231
238
|
if (mediaPipeIndex >= 34) continue
|
|
232
239
|
|
|
233
|
-
// Normalize coordinates to 0-1 range
|
|
234
240
|
landmarkArray[mediaPipeIndex] = Landmark(
|
|
235
241
|
x = poseLandmark.position.x.toDouble() / imageWidth,
|
|
236
242
|
y = poseLandmark.position.y.toDouble() / imageHeight,
|
|
@@ -251,12 +257,15 @@ class HybridPoseExercise : HybridNitroPoseExercisesSpec() {
|
|
|
251
257
|
cachedLandmarks = emptyArray()
|
|
252
258
|
}
|
|
253
259
|
}
|
|
260
|
+
|
|
261
|
+
bitmap.recycle()
|
|
254
262
|
}
|
|
255
263
|
.addOnFailureListener { e ->
|
|
256
264
|
println("[PoseExercise] ML Kit error: ${e.message}")
|
|
265
|
+
bitmap.recycle()
|
|
257
266
|
}
|
|
258
267
|
|
|
259
|
-
// Use cached landmarks for exercise logic
|
|
268
|
+
// Use cached landmarks for exercise logic
|
|
260
269
|
val currentLandmarks: Array<Landmark>
|
|
261
270
|
synchronized(landmarkLock) {
|
|
262
271
|
currentLandmarks = cachedLandmarks.copyOf()
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-nitro-pose-exercises",
|
|
3
|
-
"version": "1.1.
|
|
4
|
-
"description": "Real-time on-device exercise tracking for React Native. Rep counting, form validation, and skeleton overlay powered by
|
|
3
|
+
"version": "1.1.2",
|
|
4
|
+
"description": "Real-time on-device exercise tracking for React Native. Rep counting, form validation, and skeleton overlay powered by Apple Vision (iOS) and Google ML Kit (Android) with VisionCamera v5 via Nitro Modules.",
|
|
5
5
|
"main": "./lib/module/index.js",
|
|
6
6
|
"types": "./lib/typescript/src/index.d.ts",
|
|
7
7
|
"exports": {
|