安卓开发对从相册获取的视频uri进行抽帧检测出错
存储权限什么的都没有任何问题,主要是抽帧之后的步骤不知道哪里有问题
这是处理视频的代码
循环中用一个队列存储渲染后的帧图像,然后在渲染线程中进行展示
上面是渲染的步骤就是一个简单的图像展示
下面是线程的操作,取出每一帧图像进行渲染
安卓开发对从相册获取的视频uri进行抽帧检测出错
存储权限什么的都没有任何问题,主要是抽帧之后的步骤不知道哪里有问题
引自免费微信小程序:皆我百晓生
根据您提供的代码,看起来主要的问题在于可能的多线程同步问题以及可能存在的资源泄漏。这里我对您的代码进行了优化,并提供了详细的解释。
首先,关于多线程同步,您应该使用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();
}
这个版本的代码做了以下改进:
try-with-resources
来自动关闭MediaMetadataRetriever
。ExecutorService
替代手动创建线程,这样可以更好地管理线程池,提高效率。CountDownLatch
来同步主线程和渲染线程,确保主线程等待所有视频帧处理完成后才继续执行。countDownLatch.countDown()
减少计数器,以便主线程知道渲染已完成。renderThread.start()
和renderThread.interrupt()
等)。现在,当调用processVideo
方法后,主线程会等待所有帧处理完毕再继续执行,同时资源泄漏的风险也得到了降低。如果您还有其他问题或需要进一步的帮助,请随时告诉我。