Android захватить видеокадр - PullRequest
7 голосов
/ 17 марта 2011

Мне нужно получить кадр видеофайла (это может быть на SDCard, директории кэша или директории приложения).У меня есть пакет 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 ]

13 голосов
/ 07 октября 2011

У меня работает следующее:

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;
    }

Также работает, если вы используете путь вместо дескриптора файла.

6 голосов
/ 30 мая 2013

Попробуйте, я использовал его и он работает

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 вы можете напрямую передать свой URL.

0 голосов
/ 02 мая 2015

Я использовал этот код, и это работает для меня. Вы можете попробовать это.

if (Build.VERSION.SDK_INT >= 14) {
                ffmpegMetaDataRetriever.setDataSource(
                        videoFile.getAbsolutePath(),
                        new HashMap<String, String>());
            } else {
                ffmpegMetaDataRetriever.setDataSource(videoFile
                        .getAbsolutePath());
            }
0 голосов
/ 29 декабря 2013

Исключение выдается также, когда File не существует. Поэтому, прежде чем звонить setDataSource(), вам лучше проверить, если new File(url).exists().

0 голосов
/ 08 октября 2013

Я получаю ту же ошибку, используя 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;
}
0 голосов
/ 20 марта 2012

так есть ли конкретный способ получить кадр из видео как

 File sdcard = Environment.getExternalStorageDirectory();
 File file = new File(sdcard, "myvideo.mp4");
0 голосов
/ 16 марта 2012

Ури не очень специфичны. Иногда они ссылаются на что-то в связке. Их часто нужно переводить в форму абсолютного пути. Другой случай, когда вы использовали Uri, вероятно, он был достаточно умен, чтобы проверить, что это за Uri. Этот случай, который вы показали, выглядит не очень сложным.

0 голосов
/ 18 марта 2011

У меня та же ошибка в моем заявлении. Я видел на этом сайте, что

это неофициальный способ сделать это и это будет работать только в кекс (и возможно, более поздняя версия). Команда Android не гарантирует, что libmedia_jni.so, который является Java-файлом использует, будет включен или иметь тот же интерфейс в будущих версиях.

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

Я обновил свой телефон до GingerBread, и он больше не работает.

...