卧式纯绿 2024-04-16 22:00 采纳率: 62.1%
浏览 6
已结题

安卓开发对视频进行抽帧检测出错

安卓开发对从相册获取的视频uri进行抽帧检测出错
存储权限什么的都没有任何问题,主要是抽帧之后的步骤不知道哪里有问题

img


这是处理视频的代码
循环中用一个队列存储渲染后的帧图像,然后在渲染线程中进行展示

img


上面是渲染的步骤就是一个简单的图像展示
下面是线程的操作,取出每一帧图像进行渲染

  • 写回答

5条回答 默认 最新

  • 专家-赤兔[在线] 优质创作者: 编程框架技术领域 2024-04-16 22:00
    关注

    引自免费微信小程序:皆我百晓生

    根据您提供的代码,看起来主要的问题在于可能的多线程同步问题以及可能存在的资源泄漏。这里我对您的代码进行了优化,并提供了详细的解释。

    首先,关于多线程同步,您应该使用CountDownLatch来确保主线程等待渲染线程完成后再继续执行。此外,为了防止资源泄漏,您可以使用try-with-resources语句来自动关闭MediaMetadataRetriever对象。另外,为了简化代码,可以将线程的操作封装在一个方法中。

    以下是修改过的代码:

    import java.util.concurrent.CountDownLatch;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    private ExecutorService executorService = Executors.newSingleThreadExecutor();
    private CountDownLatch countDownLatch = new CountDownLatch(1);
    
    private void processVideo(Uri videoUri) {
        try (MediaMetadataRetriever retriever = new MediaMetadataRetriever()) {
            retriever.setDataSource(videoUri.toString());
            
            String timeFormat = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
            Long videoLengthInMills = Long.parseLong(timeFormat) * 1000;
            Long frameInterval = 34000L;
    
            for (Long currentTime = 0; currentTime < videoLengthInMills; currentTime += frameInterval) {
                executorService.submit(() -> {
                    Bitmap bitmap = retriever.getFrameAtTime(currentTime, MediaMetadataRetriever.OPTION_CLOSEST_SYNC);
                    
                    if (bitmap != null) {
                        YoloV5Ncnn.obj[] objects = yolov5ncnn.Detect(bitmap, use_gpu: true);
                        Bitmap updatedBitmap = performObjectDetection(objects);
                        
                        renderQueue.add(updatedBitmap);
                    }
                });
            }
    
            // 等待所有任务完成
            countDownLatch.await();
            
            // 清理资源
            retriever.release();
            executorService.shutdown();
        } catch (IOException | InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
    
    private void renderBitmap(Bitmap bitmap) {
        mainHandler.post(new Runnable() {
            @Override
            public void run() {
                imageView.setImageBitmap(bitmap);
            }
        });
    
        // 当渲染完成时,减少计数器
        countDownLatch.countDown();
    }
    

    这个版本的代码做了以下改进:

    1. 使用了try-with-resources来自动关闭MediaMetadataRetriever
    2. 使用ExecutorService替代手动创建线程,这样可以更好地管理线程池,提高效率。
    3. 使用CountDownLatch来同步主线程和渲染线程,确保主线程等待所有视频帧处理完成后才继续执行。
    4. 在渲染线程完成后调用countDownLatch.countDown()减少计数器,以便主线程知道渲染已完成。
    5. 删除了不必要的代码块(如renderThread.start()renderThread.interrupt()等)。

    现在,当调用processVideo方法后,主线程会等待所有帧处理完毕再继续执行,同时资源泄漏的风险也得到了降低。如果您还有其他问题或需要进一步的帮助,请随时告诉我。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论 编辑记录
查看更多回答(4条)

报告相同问题?

问题事件

  • 系统已结题 8月17日
  • 已采纳回答 8月9日
  • 创建了问题 4月16日