Android:Bitmap解码java.lang.OutofMemoryError错误

时间:2012-12-17 13:23:22

标签: android bitmap out-of-memory bitmapfactory

我目前的Android应用程序主要功能是使用内置摄像头从录制的视频中拉出帧(10fps)。每当用户选择视频时,我都会调用我的类“FrameCollector”,它循环播放视频并将帧拉出并将它们存储到位图的ArrayList中。让这项工作好几天让我觉得我走在正确的轨道上,但现在我得到了可怕的“java.lang.OutofMemoryError”

我的代码如下:

这里设置MediaMetaDataRetriever从主类传递的视频路径中选择每秒10帧

public class FrameCollector {

MediaMetadataRetriever _mmr;

double _fps;
double _duration;
long _counter = 0;
long _incrementer;

public FrameCollector(String path, Context context) 
{
    try
    {
    _mmr = new MediaMetadataRetriever();
    _mmr.setDataSource(path);

    SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(context);
    String fpsString = pref.getString("prefFPS", "10");
    _fps = Double.parseDouble(fpsString);
    _incrementer = (long) (1000000 / _fps);

    String stringDuration = _mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
    _duration = Double.parseDouble(stringDuration) * 1000;
    }
    catch(Exception ex)
    {
        ex.printStackTrace();
    }
}

下面的方法是将当时的帧添加到位图并将位图添加到位图“bitFrames”的arraylist

public ArrayList<Bitmap> getBitmaps() 
{
    try 
    {
        ArrayList<Bitmap> bitFrames = new ArrayList<Bitmap>();


        Bitmap b = _mmr.getFrameAtTime(_counter);

        while (_counter < _duration && b != null) 
        {
            bitFrames.add(b);
            _counter += _incrementer;
            b = _mmr.getFrameAtTime(_counter);
        }
        return bitFrames;   
    }
    catch (Exception ex) 
    {
        ex.printStackTrace();
        return null;
    }
}

我认为我的问题在于这个方法。我相信在将它们存储到ArrayList之前我需要解码位图,但我不确定如何

Bitmap b = BitmapFactory.decode____(_mmr.getFrameAtTime(_counter)); 
-- Whether it be decodeStream, decodeResource, decodeFile all bring errors.

非常感谢任何帮助

非常感谢,

2 个答案:

答案 0 :(得分:0)

除非位图的数量非常小,否则永远不要将位图存储在ArrayList中。位图会占用大量内存。

之前我没有使用过视频录制,但我建议您尝试使用ffmpeg这样的原生编解码库来为您完成。

但是,如果你必须自己抓取帧,我建议将它们存储在相机内存中固定大小的缓冲区中,并有一个后台线程,它从缓冲区中提取位图并将其并行存储到磁盘上。 p>

答案 1 :(得分:0)

将位图的ArrayList存储在RAM中是不好的。

无论如何,如果你需要超过默认堆大小来存储ArrayList中的位图,你可以尝试这个hack。 http://habrahabr.ru/post/139717/ 它是用俄语写的,但我想代码很清楚。