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.
package/android/build.gradle
CHANGED
|
@@ -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
|
-
|
|
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.
|
|
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
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
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
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
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
|
-
|
|
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.
|
|
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",
|