You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从外部存储、DocumentFile或Uri获取视频缩略图?现有代码返回Bitmap空值

解决从DocumentFile/Uri获取视频缩略图的问题

首先得说清楚你原来的代码为什么会返回null:documentFile.getUri().getPath()拿到的并不是视频文件的真实本地路径,而是content Uri的路径片段(比如/tree/primary:Videos/xxx.mp4),而ThumbnailUtils.createVideoThumbnail接受String路径的那个方法,只能识别真实的本地文件路径,没法处理content Uri,所以自然返回null了。

下面给你几个靠谱的解决方案:

方案一:用MediaMetadataRetriever(推荐,兼容性最好)

这个类可以直接通过content Uri获取视频帧作为缩略图,适配所有Android版本,而且符合Android 10及以上的存储权限规范(不需要访问真实文件路径)。代码示例:

Uri videoUri = documentFile.getUri();
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
Bitmap thumbnail = null;

try {
    // 直接传入Context和视频的content Uri
    retriever.setDataSource(getBaseContext(), videoUri);
    // 获取视频第一帧作为缩略图,也可以指定时间戳(比如getFrameAtTime(1000*1000)表示取1秒处的帧)
    thumbnail = retriever.getFrameAtTime();
    // 如果需要固定大小的缩略图,可以对Bitmap进行缩放
    // thumbnail = Bitmap.createScaledBitmap(thumbnail, 96, 96, true);
} catch (Exception e) {
    e.printStackTrace();
} finally {
    // 记得释放资源
    retriever.release();
}

方案二:Android 11+用ThumbnailUtils的Uri重载方法

如果你只需要适配Android 11(API 30)及以上版本,可以用ThumbnailUtils新增的支持Uri的重载方法:

Uri videoUri = documentFile.getUri();
Bitmap thumbnail = null;

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
    try {
        // 指定缩略图的尺寸,这里用MICRO_KIND对应的大小
        Size thumbnailSize = new Size(MediaStore.Video.Thumbnails.MICRO_KIND, MediaStore.Video.Thumbnails.MICRO_KIND);
        thumbnail = ThumbnailUtils.createVideoThumbnail(videoUri, thumbnailSize, null);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

关于用InputStream获取缩略图

当然可以!不过要注意,不是所有InputStream都支持MediaMetadataRetriever的数据源设置,最好通过FileDescriptor来处理,示例代码如下:

Uri videoUri = documentFile.getUri();
InputStream inputStream = getContentResolver().openInputStream(videoUri);
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
Bitmap thumbnail = null;

try {
    // 通过InputStream的FileDescriptor设置数据源
    retriever.setDataSource(inputStream.getFD());
    thumbnail = retriever.getFrameAtTime();
} catch (Exception e) {
    e.printStackTrace();
} finally {
    retriever.release();
    try {
        if (inputStream != null) {
            inputStream.close();
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

不过还是更推荐直接用Uri的方式,代码更简洁,兼容性也更好~

内容的提问来源于stack exchange,提问作者mostafa3dmax

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 09:43:47