android 捕获视频帧

发布于 2024-10-22 04:07:18 字数 854 浏览 3 评论 0原文

我需要获取视频文件的帧(它可能位于 SD 卡、缓存目录或应用程序目录上)。我的应用程序中有 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失败:status = 0x80000000)。你知道如何使这段代码工作吗?或者您是否有任何类似(简单)的解决方案而不使用 ffmpeg 或其他外部库? videoUri 是一个有效的 uri(媒体播放器可以播放该 URI 中的视频)

I need to get a frame of a video file (it may be on sdcard, cache dir or app dir). I have package android.media in my application and inside I have class MediaMetadataRetriever. To get first frame into a bitmap, I use code:

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

But this it's not working. It throws an exception (java.lang.RuntimeException: setDataSource failed: status = 0x80000000) when I set data source. Do you know how to make this code to work? Or Do you have any similar (simple) solution without using ffmpeg or other external libraries? videoUri is a valid uri (media player can play video from that URI)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

眼前雾蒙蒙 2024-10-29 04:07:18

以下对我有用:

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

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

The following works for me:

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

Also works if you use a path instead of a filedescriptor.

满地尘埃落定 2024-10-29 04:07:18

试试这个,我已经使用过它并且它的工作原理

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

您可以直接传递您的 url 来代替 uri 。

Try this, I've used it and its working

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

In place of uri you can directly pass your url .

栖竹 2024-10-29 04:07:18

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

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

I used this code and that is working for me. you can try this one.

if (Build.VERSION.SDK_INT >= 14) {
                ffmpegMetaDataRetriever.setDataSource(
                        videoFile.getAbsolutePath(),
                        new HashMap<String, String>());
            } else {
                ffmpegMetaDataRetriever.setDataSource(videoFile
                        .getAbsolutePath());
            }
檐上三寸雪 2024-10-29 04:07:18

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

这是一种非官方的方式
它只适用于纸杯蛋糕(并且
也许是更高版本)。安卓团队
不保证
libmedia_jni.so,这是java文件
使用、将被包括或具有
未来版本中的界面相同。

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

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

I have the same mistake on my application. I saw on this site that

this is an unofficial way of doing it
and it will only work in cupcake (and
maybe later version). The Android team
does not guarantee that
libmedia_jni.so, which the java file
uses, will be included or have the
same interface in future versions.

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

I have updated my phone to GingerBread and it doesn't work anymore.

时光清浅 2024-10-29 04:07:18

Uri 不是很具体。有时它们指的是捆绑中的某些东西。它们通常需要转换为绝对路径形式。在您使用 Uri 的另一个实例中,它可能足够智能来检查它是什么类型的 Uri。您所展示的这个案例似乎看起来并不难。

Uri's are not very specific. Sometimes they refer to something in a bundle. They often need to be translated to an absolute path form. The other instance in which you used the Uri, it probably was smart enough to check what kind of Uri it was. This case that you have shown appears to be not looking very hard.

她说她爱他 2024-10-29 04:07:18

我使用 ThumbnailUtilshttp: //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;
}

I was getting the same error using the ThumbnailUtils class http://developer.android.com/reference/android/media/ThumbnailUtils.html
It uses MediaMetadataRetriever under the hood and most of the time you can send it a filepath using this method with no problem:

public static Bitmap createVideoThumbnail (String filePath, int kind)  

However, on Android 4.0.4, I kept getting the same error @gabi was seeing. Using a file descriptor instead solved the problem and still works for non-4.0.4 devices. I actually ended up subclassing ThumbnailUtils. Here is my subclass method:

 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;
}
狼亦尘 2024-10-29 04:07:18

File 不存在时也会引发异常。因此,在调用setDataSource()之前,最好检查一下new File(url).exists()是否存在。

The exception is thrown also when the File doesn't exist. So before calling setDataSource() you'd better check if new File(url).exists().

荭秂 2024-10-29 04:07:18

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

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

so is there a specific way to get the frame from video as

 File sdcard = Environment.getExternalStorageDirectory();
 File file = new File(sdcard, "myvideo.mp4");
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文