android捕获视频帧

时间:2011-03-17 09:59:58

标签: android video frame capture

我需要获取视频文件的框架(可能是sdcard,cache dir或app dir)。我在我的应用程序中有android.media包,我有类MediaMetadataRetriever。要将第一帧放入位图,我使用代码:

public static Bitmap getVideoFrame(Context context, Uri videoUri) {
    MediaMetadataRetriever retriever = new MediaMetadataRetriever();
    try {
        retriever.setMode(MediaMetadataRetriever.MODE_CAPTURE_FRAME_ONLY);
        retriever.setDataSource(context, videoUri);
        return retriever.captureFrame();
    } catch (IllegalArgumentException ex) {
        throw new RuntimeException();
    } catch (RuntimeException ex) {
        throw new RuntimeException();
    } finally {
        retriever.release();
    }
}

但这不起作用。当我设置数据源时,它抛出异常(java.lang.RuntimeException:setDataSource failed:status = 0x80000000)。你知道怎么让这段代码工作吗?或者你有没有使用ffmpeg或其他外部库的类似(简单)解决方案? videoUri是一个有效的uri(媒体播放器可以播放来自该URI的视频)

8 个答案:

答案 0 :(得分:13)

以下适用于我:

public static Bitmap getVideoFrame(FileDescriptor FD) {
        MediaMetadataRetriever retriever = new MediaMetadataRetriever();
        try {
            retriever.setDataSource(FD);
            return retriever.getFrameAtTime();
        } catch (IllegalArgumentException ex) {
            ex.printStackTrace();
        } catch (RuntimeException ex) {
            ex.printStackTrace();
        } finally {
            try {
                retriever.release();
            } catch (RuntimeException ex) {
            }
        }
        return null;
    }

如果您使用路径而不是文件描述符,也可以使用。

答案 1 :(得分:6)

试试这个,我已经习惯了它的工作

public static Bitmap getVideoFrame(Context context, Uri uri) {
    MediaMetadataRetriever retriever = new MediaMetadataRetriever();
    try {
        retriever.setDataSource(uri.toString(),new HashMap<String, String>());
        return retriever.getFrameAtTime();
    } catch (IllegalArgumentException ex) {
        ex.printStackTrace();
    } catch (RuntimeException ex) {
        ex.printStackTrace();
    } finally {
        try {
            retriever.release();
        } catch (RuntimeException ex) {
        }
    }
    return null;
}

取代uri,您可以直接传递您的网址。

答案 2 :(得分:0)

我的申请也有同样的错误。我在这个网站上看到了

  

这是一种非官方的做法   它只适用于蛋糕(和   也许以后的版本)。 Android团队   不能保证   libmedia_jni.so,这是java文件   使用,将被包括或拥有   未来版本中的相同界面。

http://osdir.com/ml/AndroidDevelopers/2009-06/msg02442.html

我已将手机更新为GingerBread,但它不再有效了。

答案 3 :(得分:0)

Uri不是很具体。有时它们会引用捆绑中的某些东西。它们通常需要转换为绝对路径形式。在你使用Uri的另一个例子中,它可能非常聪明,可以检查它是什么类型的Uri。你所展示的这种情况看起来并不是很难看。

答案 4 :(得分:0)

我使用 ThumbnailUtils http://developer.android.com/reference/android/media/ThumbnailUtils.html收到同样的错误 它使用了 MediaMetadataRetriever ,大​​部分时间你可以使用这种方法发送文件路径,没有问题:

public static Bitmap createVideoThumbnail (String filePath, int kind)  

然而,在Android 4.0.4上,我不断得到@gabi看到的相同错误。使用文件描述符代替解决了问题,仍适用于非4.0.4设备。我实际上最终继承了ThumbnailUtils。这是我的子类方法:

 public static Bitmap createVideoThumbnail(FileDescriptor fDescriptor, int kind) 
 {
    Bitmap bitmap = null;
    MediaMetadataRetriever retriever = new MediaMetadataRetriever();
    try {
        retriever.setDataSource(fDescriptor);
        bitmap = retriever.getFrameAtTime(-1);
    } 
    catch (IllegalArgumentException ex) {
        // Assume this is a corrupt video file
        Log.e(LOG_TAG, "Failed to create video thumbnail for file description: " + fDescriptor.toString());
    }
    catch (RuntimeException ex) {
        // Assume this is a corrupt video file.
        Log.e(LOG_TAG, "Failed to create video thumbnail for file description: " + fDescriptor.toString());
    } finally {
        try {
            retriever.release();
        } catch (RuntimeException ex) {
            // Ignore failures while cleaning up.
        }
    }

    if (bitmap == null) return null;

    if (kind == Images.Thumbnails.MINI_KIND) {
        // Scale down the bitmap if it's too large.
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();
        int max = Math.max(width, height);
        if (max > 512) {
            float scale = 512f / max;
            int w = Math.round(scale * width);
            int h = Math.round(scale * height);
            bitmap = Bitmap.createScaledBitmap(bitmap, w, h, true);
        }
    } else if (kind == Images.Thumbnails.MICRO_KIND) {
        bitmap = extractThumbnail(bitmap,
                TARGET_SIZE_MICRO_THUMBNAIL,
                TARGET_SIZE_MICRO_THUMBNAIL,
                OPTIONS_RECYCLE_INPUT);
    }
    return bitmap;
}

答案 5 :(得分:0)

File不存在时,也会抛出异常。因此,在致电setDataSource()之前,您最好先检查new File(url).exists()

答案 6 :(得分:0)

我使用了这段代码,这对我有用。你可以尝试这个。

if (Build.VERSION.SDK_INT >= 14) {
                ffmpegMetaDataRetriever.setDataSource(
                        videoFile.getAbsolutePath(),
                        new HashMap<String, String>());
            } else {
                ffmpegMetaDataRetriever.setDataSource(videoFile
                        .getAbsolutePath());
            }

答案 7 :(得分:-2)

所以有一种特定的方法可以从视频中获取帧

 File sdcard = Environment.getExternalStorageDirectory();
 File file = new File(sdcard, "myvideo.mp4");