react-native-nitro-pose-exercises 1.0.6 → 1.0.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.
@@ -116,6 +116,12 @@ dependencies {
116
116
  implementation "com.facebook.react:react-android"
117
117
  implementation project(":react-native-nitro-modules")
118
118
 
119
+ // MediaPipe — bundled with your library
119
120
  implementation 'com.google.mediapipe:tasks-vision:0.10.21'
120
- implementation project(':react-native-vision-camera')
121
+
122
+ // CameraX for ImageProxy access
123
+ implementation 'androidx.camera:camera-core:1.4.1'
124
+
125
+ // VisionCamera — provided by the consuming app
126
+ compileOnly project(':react-native-vision-camera')
121
127
  }
@@ -3,7 +3,7 @@ package com.margelo.nitro.nitroposeexercises
3
3
  import android.graphics.Bitmap
4
4
  import androidx.annotation.Keep
5
5
  import com.facebook.proguard.annotations.DoNotStrip
6
- import com.google.mediapipe.framework.image.MediaImageBuilder
6
+ import com.google.mediapipe.framework.image.BitmapImageBuilder
7
7
  import com.google.mediapipe.tasks.core.BaseOptions
8
8
  import com.google.mediapipe.tasks.vision.core.RunningMode
9
9
  import com.google.mediapipe.tasks.vision.poselandmarker.PoseLandmarker
@@ -11,7 +11,6 @@ import com.google.mediapipe.tasks.vision.poselandmarker.PoseLandmarkerOptions
11
11
  import com.margelo.nitro.NitroModules
12
12
  import com.margelo.nitro.core.Promise
13
13
  import com.margelo.nitro.camera.HybridFrameSpec
14
- import com.margelo.nitro.camera.`public`.NativeFrame
15
14
  import kotlin.math.acos
16
15
  import kotlin.math.max
17
16
  import kotlin.math.min
@@ -162,54 +161,54 @@ override fun processFrame(frame: HybridFrameSpec) {
162
161
  frameCount++
163
162
  if (frameCount % processEveryNFrames != 0) return
164
163
 
165
- val nativeFrame = frame as? NativeFrame ?: return
166
- val imageProxy = nativeFrame.image ?: return
167
-
168
164
  try {
169
- val bitmapBuffer = Bitmap.createBitmap(
170
- imageProxy.width,
171
- imageProxy.height,
172
- Bitmap.Config.ARGB_8888
173
- )
165
+ val nativeBuffer = frame.getNativeBuffer()
166
+ val width = frame.getWidth().toInt()
167
+ val height = frame.getHeight().toInt()
168
+
169
+ // On Android, nativeBuffer.pointer is an AHardwareBuffer*
170
+ // Convert to Bitmap via Android's HardwareBuffer API
171
+ val hardwareBuffer = android.hardware.HardwareBuffer.wrap(nativeBuffer.pointer)
172
+ val bitmap = Bitmap.wrapHardwareBuffer(hardwareBuffer, null)
173
+ ?: throw Exception("Failed to wrap HardwareBuffer to Bitmap")
174
+
175
+ // MediaPipe needs ARGB_8888, not hardware bitmap
176
+ val softBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, false)
177
+
178
+ val mpImage = com.google.mediapipe.framework.image.BitmapImageBuilder(softBitmap).build()
179
+ val result = poseLandmarker!!.detect(mpImage)
174
180
 
175
- // Use MediaPipe's BitmapImageBuilder
176
- imageProxy.use {
177
- val mpImage = com.google.mediapipe.framework.image.MediaImageBuilder(
178
- imageProxy.image!!
179
- ).build()
180
-
181
- val result = poseLandmarker!!.detect(mpImage)
182
-
183
- if (result.landmarks().isNotEmpty()) {
184
- val poseLandmarks = result.landmarks()[0]
185
-
186
- if (poseWasLost) {
187
- poseWasLost = false
188
- onPoseRegained?.invoke()
189
- }
190
-
191
- _landmarks = poseLandmarks.map { lm ->
192
- Landmark(
193
- x = lm.x().toDouble(),
194
- y = lm.y().toDouble(),
195
- z = lm.z().toDouble(),
196
- visibility = (lm.visibility().orElse(0f)).toDouble()
197
- )
198
- }.toTypedArray()
199
-
200
- if (_status == SessionStatus.ACTIVE) {
201
- processExerciseLogic()
202
- }
203
- } else {
204
- if (!poseWasLost) {
205
- poseWasLost = true
206
- onPoseLost?.invoke()
207
- }
208
- _landmarks = emptyArray()
181
+ if (result.landmarks().isNotEmpty()) {
182
+ val poseLandmarks = result.landmarks()[0]
183
+
184
+ if (poseWasLost) {
185
+ poseWasLost = false
186
+ onPoseRegained?.invoke()
187
+ }
188
+
189
+ _landmarks = poseLandmarks.map { lm ->
190
+ Landmark(
191
+ x = lm.x().toDouble(),
192
+ y = lm.y().toDouble(),
193
+ z = lm.z().toDouble(),
194
+ visibility = (lm.visibility().orElse(0f)).toDouble()
195
+ )
196
+ }.toTypedArray()
197
+
198
+ if (_status == SessionStatus.ACTIVE) {
199
+ processExerciseLogic()
200
+ }
201
+ } else {
202
+ if (!poseWasLost) {
203
+ poseWasLost = true
204
+ onPoseLost?.invoke()
209
205
  }
206
+ _landmarks = emptyArray()
210
207
  }
211
208
 
212
- bitmapBuffer.recycle()
209
+ softBitmap.recycle()
210
+ bitmap.recycle()
211
+ nativeBuffer.release()
213
212
 
214
213
  } catch (e: Exception) {
215
214
  // MediaPipe detection failed — skip this frame
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-nitro-pose-exercises",
3
- "version": "1.0.6",
3
+ "version": "1.0.7",
4
4
  "description": "Real-time on-device exercise tracking for React Native. Rep counting, form validation, and skeleton overlay powered by MediaPipe Pose Landmarker and VisionCamera v5 via Nitro Modules.",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./lib/typescript/src/index.d.ts",