You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Google MLKit姿态检测未触发onSuccessListener/onFailureListener问题

排查MLKit姿态检测Listener未触发的问题

我正在使用MediaMetadataRetriever和MLKit对本地视频文件做姿态检测,已经通过ImageView验证提取的Bitmap是正确的,但poseDetector.process()的OnSuccessListener和OnFailureListener都没有执行,看不到对应的日志输出。相关代码如下:

public ArrayList<ArrayList<Float>> extractPoses() throws FileNotFoundException {
    Log.e("DATA SOURCE: ", videoUri.getPath());

    URIPathHelper uph = new URIPathHelper();
    String videoInputPath = uph.getPath(applicationContext, videoUri).toString();
    File vidInputFile = new File(videoInputPath);

    File inputFile = new File(vidInputFile.getAbsolutePath());
    if (!inputFile.canRead()) {
        throw new FileNotFoundException("Unable to read " + inputFile);
    }

    mdr.setDataSource(inputFile.getAbsolutePath());

    ArrayList<ArrayList<Float>> totalVideoPose = new ArrayList<>();

    int count = 0;
    while (true) {
        try {
            Bitmap bmp = mdr.getFrameAtIndex(count);

            InputImage inputImg = InputImage.fromBitmap(bmp, 0);
            
            poseDetector.process(inputImg)
                    .addOnSuccessListener(new OnSuccessListener<Pose>() {
                        @Override
                        public void onSuccess(Pose pose) {
                            Log.e("POSE DETECT: ", "success");
                            if(!(pose.getAllPoseLandmarks().isEmpty())) {
                                ArrayList<Float> framePoseMarks = new ArrayList<Float>();
                                PoseLandmark left_shoulder = pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER);

                                framePoseMarks.add(left_shoulder.getPosition().x);
                                framePoseMarks.add(left_shoulder.getPosition().y);

                                totalVideoPose.add(framePoseMarks);
                            }

                        }
                    })
                    .addOnFailureListener(new OnFailureListener() {
                        @Override
                        public void onFailure(@NonNull Exception e) {
                            Log.e("POSE DETECT: ", "pose detect on failure listener");
                        }
                    });

            Log.e("Pose processing: ", "incrementing count");
            count++;

        } catch (IllegalArgumentException e) {
            Log.e("POSE DETEC:", "Pose detec ended");
            Log.e("POSE DETEC length: ", String.valueOf(totalVideoPose.size()));

            for (ArrayList<Float> frame: totalVideoPose) {
                Log.e("POSE DETEC SUBS: ", String.valueOf(frame.size()));
            }
            break;
        }
    }
    return totalVideoPose;
}

可能的原因及排查方案

1. PoseDetector初始化不规范

MLKit姿态检测器需要正确配置才能正常工作,检查初始化代码:

  • 确认使用了匹配场景的检测模式(静态/动态):
PoseDetectorOptions options = new PoseDetectorOptions.Builder()
        .setDetectorMode(PoseDetectorOptions.STREAM_MODE) // 视频流场景选STREAM_MODE
        .build();
poseDetector = PoseDetection.getClient(options);
  • 避免在主线程阻塞环境下初始化检测器,确保初始化完成后再调用process。

2. 主线程阻塞导致异步回调无法执行

poseDetector.process()是异步操作,回调会在后台线程执行,但你的代码中无限while循环一直占用主线程,会阻塞Android消息队列,导致回调无法分发。

解决方法:将循环放到后台线程,同时同步每帧的处理流程,比如用CountDownLatch等待回调完成:

// 把extractPoses方法放到后台线程执行(比如用AsyncTask、Coroutine)
try {
    Bitmap bmp = mdr.getFrameAtIndex(count);
    // 可选:压缩Bitmap减少内存占用
    Bitmap scaledBitmap = Bitmap.createScaledBitmap(bmp, 640, 480, true);
    bmp.recycle();
    
    // 获取视频真实旋转角度
    int rotation = mdr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION);
    InputImage inputImg = InputImage.fromBitmap(scaledBitmap, rotation);
    
    final CountDownLatch latch = new CountDownLatch(1);
    
    poseDetector.process(inputImg)
            .addOnSuccessListener(pose -> {
                Log.e("POSE DETECT: ", "success");
                if(!pose.getAllPoseLandmarks().isEmpty()) {
                    ArrayList<Float> framePoseMarks = new ArrayList<>();
                    PoseLandmark left_shoulder = pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER);
                    framePoseMarks.add(left_shoulder.getPosition().x);
                    framePoseMarks.add(left_shoulder.getPosition().y);
                    totalVideoPose.add(framePoseMarks);
                }
                latch.countDown();
            })
            .addOnFailureListener(e -> {
                Log.e("POSE DETECT: ", "pose detect failed", e); // 打印具体异常信息
                latch.countDown();
            });
    
    // 等待当前帧处理完成,设置超时避免无限等待
    latch.await(5, TimeUnit.SECONDS);
    
    Log.e("Pose processing: ", "incrementing count");
    count++;
} catch (IllegalArgumentException | InterruptedException e) {
    // 异常处理
}

3. 内存溢出导致检测器崩溃

循环提取Bitmap会快速占用内存,若发生OutOfMemoryError,检测器可能直接崩溃而不触发回调。

  • 查看Logcat搜索OutOfMemoryError确认问题
  • 处理完每帧后调用bmp.recycle()释放内存
  • 对提取的帧进行压缩,缩小尺寸后再传入检测器

4. InputImage旋转参数错误

如果视频本身有旋转(比如竖屏拍摄),传入0作为旋转角度会导致检测失效,但可能不会触发失败回调。解决方法:获取视频的真实旋转角度传入InputImage:

int rotation = mdr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION);
InputImage inputImg = InputImage.fromBitmap(bmp, rotation);

5. PoseDetector生命周期异常

确保poseDetector是全局变量,在整个视频处理过程中保持存活,避免因局部变量被回收导致回调无法触发。

内容的提问来源于stack exchange,提问作者stackoverflowta8

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 13:03:22