2013-12-10 100 views
1

我想开发一个应用程序,需要15秒的视频,允许用户应用不同的过滤器,显示效果的预览,然后允许保存处理的视频到SD卡。我使用ffmpeg将视频分割为JPEG帧,使用GPUImage将所需的滤镜应用于所有帧,然后使用ffmpeg将帧编码回视频。除了用户选择过滤器的部分以外,一切正常。当用户选择过滤器时,应用程序应该显示应用了过滤器的视频预览。尽管450帧可以非常快速地应用滤镜,但以30 fps的顺序显示图像(让用户感觉视频正在播放)表现不佳。我尝试了不同的方法,但即使在最快的设备上,我可以达到的最大帧速率也是10到12 fps。在Android上显示从SD卡的450图像文件在30fps

在这种情况下,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); 
    } 
} 

据我所知,从SD卡得到一个图像,对其进行解码,然后显示它在屏幕上的过程中涉及的SD卡读取,该装置的CPU中的性能和图形性能的性能。但我想知道是否有一种方法可以在每次迭代中节省几毫秒。任何建议在这一点上都会有很大的帮助。

+1

您可以在显示当前时缓存下一张图像。看看这个https://developer.android.com/training/displaying-bitmaps/manage-memory.html –

回答

0

我的坏!找到罪魁祸首。正在使用的NSTimer在iOS上,我忽略的代码行的重要性:

handler.postDelayed(runnable, interval); 

负责调度正在当前帧之后执行的下一帧的过程,代码从SD卡得到读取,解码和显示的上到imageview。

即。如果显示当前帧的整个过程耗时25毫秒,则下一帧处理将在先前帧之后的25 + 33 = 58ms后计划。

我将该行代码移动到可运行线程的run {}方法的第一行,并且BINGO !!即使在100美元的Android设备上,FPS也能提高到24-30 FPS。

不管怎样,感谢@Valentin,@Pedro Bernardo和@Shashika指出了一些有效的解决方案。

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

您说的SDCard读取性能很慢是正确的。事实上,看看你想完成多少事情 - 从外部位置创建一个新文件,解码它并创建一个新的位图。所有这些都在UI线程上完成。

我不知道你的图片有多大,但是你是否尝试过预先加载其中的一部分,把它们放在一个列表中,然后从列表中选取它们并将它们显示在你的处理程序代码中?

我意识到在内存中存储450张图像相当多,但任务可能会被拆分。假设您预先加载了100个位图并开始显示它们,然后让异步任务同时将另一个100预加载到下一个列表(或可能是同一个列表)中。

相关问题