我正在尝试开发一款需要15秒视频的应用,允许用户应用不同的滤镜,显示效果的预览,然后允许将处理后的视频保存到SD卡。我使用ffmpeg将视频分割成JPEG帧,使用GPUImage将所需的滤镜应用到所有帧,然后使用ffmpeg将帧编码回视频。除了用户选择过滤器的部分外,一切正常。当用户选择过滤器时,应用程序应显示应用了过滤器的视频预览。虽然450帧可以相当快地应用滤波器,但以30 fps顺序显示图像(以使用户感觉视频正在播放)表现不佳。我尝试了不同的方法,但即使在最快的设备上,我可以达到的最大帧速率是10到12 fps。
在这种情况下,AnimationDrawable技术不起作用,因为它需要将整个图像缓冲到内存中,在这种情况下是巨大的。应用程序崩溃。
以下代码是目前表现最佳的代码(10到12 fps)。
package com.example.animseqvideo;
import ......
public class MainActivity extends Activity {
Handler handler;
Runnable runnable;
final int interval = 33; // 30.30 FPS
ImageView myImage;
int i=0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myImage = (ImageView) findViewById(R.id.imageView1);
handler = new Handler();
runnable = new Runnable(){
public void run() {
i++; if(i>450)i=1;
File imgFile = new File(Environment.getExternalStorageDirectory().getPath() + "/com.example.animseqvideo/image"+ String.format("%03d", i) +".jpg");
if(imgFile.exists()){
Bitmap myBitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath());
myImage.setImageBitmap(myBitmap);
}
//SOLUTION EDIT - MOVE THE BELOW LINE OF CODE AS THE FIRST LINE OF run() AND FPS=30 !!!
handler.postDelayed(runnable, interval);
}
};
handler.postAtTime(runnable, System.currentTimeMillis()+interval);
handler.postDelayed(runnable, interval);
}
}
据我所知,从SDCard获取图像,对其进行解码,然后将其显示在屏幕上的过程涉及SDCard读取的性能,CPU的性能和设备的图形性能。但我想知道是否有一种方法可以在每次迭代中节省几毫秒。在这一点上,任何建议都会有很大的帮助。
答案 0 :(得分:1)
我也做了类似的事情。我使用了ValueAnimator。图像是图像ID的数组。例如:R.drawable.park1
ValueAnimator animation = ValueAnimator.ofInt(0,44);
animation.setInterpolator(new LinearInterpolator());
animation.setDuration(1000);
animation.setRepeatCount(200);
animation.addUpdateListener(new AnimatorUpdateListener() {
int i;
public void onAnimationUpdate(ValueAnimator animation) {
Log.i("TAG", "::onAnimationUpdate: "+(++i)+" value = "+animation.getAnimatedValue());
mImageViewPreview.setImageResource(images[(Integer) animation.getAnimatedValue()]);
mImageViewPreview.invalidate();
if(mImageViewPreview.getVisibility()!=View.VISIBLE){
animation.cancel();
}
}
});
animation.start();
答案 1 :(得分:1)
你说SDCard阅读的速度很慢是正确的。实际上,看看你想做多少事情 - 从外部位置创建一个新文件,解码它并创建一个新的位图。所有这些都在UI线程上完成。
我不知道您的图片有多大,但您是否尝试过将其中一些图片预加载,将它们放入列表中,然后从列表中选择它们并将其显示在处理程序代码中?
我意识到在内存中存储450张图片相当多,但任务可能会分开。假设您已预加载100位图并开始显示它们,然后让异步任务同时将其他100位预加载到下一个列表(或可能是同一列表)中。
答案 2 :(得分:0)
我的坏!找到了罪魁祸首。习惯于iOS上的NSTimer,我忽略了代码行的重要性:
handler.postDelayed(runnable, interval);
在从SDCard读取当前帧,解码并显示在imageview上之后,正在执行负责调度下一帧处理的代码。
即。如果显示当前帧的整个过程花费25毫秒,则在前一帧之后的25 + 33 = 58ms之后安排下一帧处理。
我将那行代码移动到runnable线程的run {}方法的第一行,并且BINGO !!即使在100美元的Android设备上,FPS也提升到24-30 FPS。
无论如何,感谢@Valentin,@ Pedro Bernardo和@Shashika指出了一些有效的解决方案。