这更像是一个建筑问题。
我正在开发一个使用FFmpegFrameGrabberfrom 包JavaCV来迭代视频帧的 android 应用程序。任务如下:当 SeekBar 移动时,将其设置bitmap为imageview。
好的,这是我尽可能简化的示例:
seekHandBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
if (b) {
try {
grabber.setFrameNumber(i);
Bitmap bmp = Bitmap.createScaledBitmap(
converter.convert(grabber.grabImage()),
imageView.getWidth(), imageView.getHeight(), true);
// converter здесь - это AndroidFrameConverter();
imageView.setImageBitmap(bmp);
} catch (FFmpegFrameGrabber.Exception e) {
e.printStackTrace();
}
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {}
});
问题是,如果你grabImage()在移动时在主线程中使用它seekbar,会有轻微的延迟,这是你想要避免的。当然,你可以把这个放到一个方法onStopTrackingTouch中,但是我想试着弄清楚Bitmap在移动的时候如何改变它seekbar。
决定同时尝试Thread, and ExecutorService(我尝试了newCachedThreadPooland newSingleThreadScheduledExecutor,也许我在我的任务中错误地使用了它) and Runnable,但这一切都不起作用,因为queue需要某种同步 ( ) 时才会处理下一帧在上一个设置之后。所有这些解决方案本质上只是创建随机运行的新线程,例如,首先可以设置第 30 帧,然后再设置视频的第 25 帧。
可以做什么?也许需要使用一些东西synchronized?也许我在寻找信息时挖错了地方,或者错过了什么Executors?我最近在 中遇到了线程问题java,而且我一般是 Android 新手。
解决方案的想法是,每次我们收到有关我们
onProgressChanged保存需要读取的帧号的通知时。在开始之前,我们启动一个后台任务,等待这个帧号出现,一旦出现,就读取并使用该帧。重要的一点是帧的读取是在一个线程中完成的。如果在读取一帧的过程中出现了多个新帧,那么您需要跳过除最后一帧之外的所有内容,它将被读取。
如果我们谈论这个想法的实现,那么就有了选择。也许最简单的方法是使用队列
LinkedBlockingQueue来存储我们收到通知的帧号。