Files
PinPoint/app/src/androidTest/java/com/example/jnicpp/bowling/VideoStepReplayTest.kt
T

79 lines
3.2 KiB
Kotlin
Raw Normal View History

2026-09-07 17:35:44 +08:00
package com.example.jnicpp.bowling
import android.media.MediaMetadataRetriever
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import com.google.android.gms.tasks.Tasks
import com.google.mlkit.vision.common.InputImage
import com.google.mlkit.vision.pose.PoseDetection
import com.google.mlkit.vision.pose.accurate.AccuratePoseDetectorOptions
import org.junit.Test
import org.junit.runner.RunWith
/**
* Replays a pre-recorded reference video through the exact same
* detection/smoothing/step-counting pipeline the live camera screen uses
* (PoseAnalyzer's detector config -> PoseLandmarkSmoother ->
* AnkleHipMovingAverageFilter -> buildPoseFrame -> LiveStepDetector), so the
* algorithm can be validated against a video with a known, hand-counted
* step count without needing a live device recording session each time.
*
* Not run as part of the normal test suite -- this is a diagnostic tool,
* invoked directly via `connectedAndroidTest` with a specific video pushed
* to the device first.
*/
@RunWith(AndroidJUnit4::class)
class VideoStepReplayTest {
@Test
fun replayReferenceVideo() {
val context = InstrumentationRegistry.getInstrumentation().targetContext
val videoPath = context.getExternalFilesDir(null)!!.resolve("reference_test.mp4").absolutePath
val retriever = MediaMetadataRetriever()
retriever.setDataSource(videoPath)
val durationMs = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)
?.toLongOrNull() ?: 0L
val detector = PoseDetection.getClient(
AccuratePoseDetectorOptions.Builder()
.setDetectorMode(AccuratePoseDetectorOptions.STREAM_MODE)
.build()
)
val landmarkSmoother = PoseLandmarkSmoother()
val ankleHipSmoother = AnkleHipMovingAverageFilter()
val liveStepDetector = LiveStepDetector()
val logger = DebugSessionLogger(context)
logger.start()
val stepMs = 33L
var t = 0L
var finalStepCount = 0
var framesProcessed = 0
while (t < durationMs) {
val bitmap = retriever.getFrameAtTime(t * 1000, MediaMetadataRetriever.OPTION_CLOSEST)
if (bitmap != null) {
val inputImage = InputImage.fromBitmap(bitmap, 0)
val pose = Tasks.await(detector.process(inputImage))
val landmarks = landmarkSmoother.smooth(pose)
val angles = PoseAngleCalculator.compute(landmarks)
val smoothedAnkleHip = ankleHipSmoother.smooth(landmarks)
val frame = buildPoseFrame(t, landmarks, smoothedAnkleHip, angles)
val result = liveStepDetector.update(frame)
finalStepCount = result.stepCount
logger.log(landmarks, t, finalStepCount, result.handRaiseProgress)
2026-09-07 17:35:44 +08:00
framesProcessed++
}
t += stepMs
}
logger.stop()
detector.close()
retriever.release()
println(
"VideoStepReplayTest: processed $framesProcessed frames over ${durationMs}ms, " +
"final step count = $finalStepCount"
)
}
}