5

我有一个循环,我试图每 1/10 秒从视频中提取一帧。但是在 19 帧(视频的 1.9 秒)之后,我在 Logcat 上收到以下错误:

01-22 11:59:15.498: E/OMXCodec(38): [OMX.google.h264.decoder] Timed out waiting for output buffers: 0/0
01-22 11:59:15.598: E/MetadataRetrieverClient(38): failed to capture a video frame
01-22 11:59:15.598: E/MediaMetadataRetrieverJNI(572): getFrameAtTime: videoFrame is a NULL pointer
01-22 11:59:15.598: D/AndroidRuntime(572): Shutting down VM
01-22 11:59:15.598: W/dalvikvm(572): threadid=1: thread exiting with uncaught exception (group=0x409961f8)
01-22 11:59:15.608: E/AndroidRuntime(572): FATAL EXCEPTION: main
01-22 11:59:15.608: E/AndroidRuntime(572): java.lang.NullPointerException

这是我正在使用的代码:

File videoPath = new File(Environment.getExternalStorageDirectory(), "test.mp4");
String video = videoPath.getAbsolutePath();
MediaMetadataRetriever vidFile = new MediaMetadataRetriever();
vidFile.setDataSource(video);

//Create folder to store images
String storageFolder = "/Storage";
String extStorageDirectory = Environment.getExternalStorageDirectory().toString();
File newFolder = new File(extStorageDirectory + storageFolder);
newFolder.mkdir();

String value = vidFile.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
long vidLength = (Long.parseLong(value)/1000); //Returns milliseconds - divide by 1,000
//Video length = 30037ms - result is 30.037s

for(int i = 0; i <= 10*vidLength; i++, image++) //10*vidLength since I'm getting frames every 1/10th sec
{
    Bitmap bmp = vidFile.getFrameAtTime(100000*i, MediaMetadataRetriever.OPTION_CLOSEST);
    ByteArrayOutputStream bytes = new ByteArrayOutputStream();
    bmp.compress(Bitmap.CompressFormat.PNG, 100, bytes);
    String imagename = String.format(Locale.ENGLISH, "%03d", image);
    File f = new File(Environment.getExternalStorageDirectory() + storageFolder + File.separator + imagename + ".png");
    f.createNewFile();
    FileOutputStream fo = new FileOutputStream(f);
    fo.write(bytes.toByteArray());
    fo.close();

    //Don't seem to make a difference one way or the other
    bytes.flush(); 
    bytes.close();  
}

就像我说的,它应该得到大约 300 帧,但在崩溃之前只能提取 19 帧,但我不明白为什么会发生 NULL 指针错误。

提前致谢

4

5 回答 5

2

您是否尝试过使用FFmpegMediaMetadataRetriever lib 而不是 MediaMetadataRetriever?

此外,从您的 logcat 上的这一行:

01-22 11:59:15.598: E/MediaMetadataRetrieverJNI(572): getFrameAtTime: videoFrame 是一个空指针

我会尝试让它记录 for 循环的每一行,例如 Log.d("MyApp","Param of getFrameAtTime"+(100000*i));

我知道您已经知道哪个帧是问题(19/20),但只是想看看该变量在成为空指针之前会发生什么(也许您可以使用 Long i 而不是 int i?)。

另外,您是否尝试过上述建议来使用 MediaMetadataRetriever.OPTION_CLOSEST_SYNC 而不是 OPTION_CLOSEST?

于 2014-05-04T18:08:31.613 回答
1

我在运行 Android 4.0 的 Evo V 上得到了类似的行为:我的测试视频的前六帧转换得很好,然后我开始返回空指针,即使我构造了一个新的 MediaMetadataRetriever 再试一次。

我的日志还显示:“MediaMetadataRetriever 服务器死了!”

有一种方法可以避免此问题,并且根据您尝试执行的操作,它可能是合适的:传递 MediaMetadataRetriever.OPTION_CLOSEST_SYNC 而不是 OPTION_CLOSEST。

在我的测试中,当我使用 OPTION_CLOSEST_SYNC 时,崩溃总是会消失。

这对我的应用程序没有太大帮助,因为我确实需要非常接近的帧,而不仅仅是指定的“同步帧”。但它可能更容易被你接受。

于 2013-03-03T17:31:23.200 回答
0

我发现您的错误是除法而不是乘法。将毫转换为微需要乘以 1000,而您正在除法...

使用 MediaPlayer 获取视频的时长..

 file = new File(Environment.getExternalStorageDirectory(), "myvideo.mp4");
 MediaPlayer mp = MediaPlayer.create(MainActivity.this,Uri.parse(file.getAbsolutePath()));
            int duration = mp.getDuration();// it gives duration in milliseconds 
            mp.release();

乘以duration*1000

循环直到

     for(int i=0 ;i <5; i++)
                {
                  if(looper < duration *1000)
                  {
                      ImageView imageView = (ImageView)findViewById(ids_of_images[i]);


imageView.setImageBitmap(retriever.getFrameAtTime(looper,MediaMetadataRetriever.OPTION_CLOSEST));

                        looper +=1000000;  
                  }

                }
于 2014-06-19T13:05:49.950 回答
0

报告了一个 OPTION_CLOSEST 错误,请参阅https://code.google.com/p/android/issues/detail?id=193194

Google 于 2016 年 8 月 31 日做出的回应

您好,开发团队已经修复了您报告的问题,它将在未来的版本中提供感谢状态:FutureRelease

于 2016-09-17T02:52:39.933 回答
0

这在 android 错误数据库中报告为MediaMetadataRetriever.getFrameAtTime() 失败/崩溃。此问题已过时关闭。我在运行 Android 4.2.2 的 Tesco HUDL 1.0 (HT7S3) 上遇到了它。

添加以下重试允许我的代码工作。

        if( bmp == null){
            mMediaData = new MediaMetadataRetriever();
            mMediaData.setDataSource( /* same parameters as before */ );
            bmp = mMediaData.getFrameAtTime( /* same parameters */ );
        }

在我的测试中,我只在早期版本的 Android 上看到过这个问题,并且从错误的“过时”关闭开始,它在更新的版本中得到了修复。

因此,在后续重新查询之前重新创建媒体检索器的解决方法可能是最好的解决方法。

在我的设备上重新构建 mediaRetriever 大约需要 3 秒,获取位图需要 0.1 秒,所以我真的负担不起每次都构建它。

于 2016-08-16T07:03:33.347 回答