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

使用MediaStore.Video仅获取到MP4、3GP视频,如何读取手机全格式视频

Android全格式本地视频读取解决方案

问题根因

MediaStore.Video默认仅收录Android系统内置解码器支持的视频格式(MP4、3GP等),MKV、FLV、AVI、MOV等第三方格式不会被默认收录,因此直接查询MediaStore.Video会出现遗漏。

现有代码调整方案

你的代码存在两处可优化点,调整后可覆盖绝大多数主流视频格式:

  1. 移除projection中冗余的MediaStore.Video.Thumbnails.DATA字段,该字段无法在MediaStore.Video.Media的查询中直接返回,反而会干扰查询结果,缩略图需单独通过MediaStore.Video.Thumbnails查询或者调用ContentResolver.loadThumbnail方法获取。
  2. 主动在查询参数中加入所有视频格式的MIME类型,避免部分厂商ROM默认过滤非系统原生支持的格式。

调整后的代码示例:

Uri uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
String orderBy = MediaStore.Video.Media.DATE_ADDED + " DESC";
String[] projection = {
    MediaStore.Video.Media._ID,
    MediaStore.Video.Media.TITLE,
    MediaStore.Video.Media.SIZE,
    MediaStore.Video.Media.DISPLAY_NAME,
    MediaStore.Video.Media.DURATION,
    MediaStore.Video.Media.DATA, // 仅Android 10及以下版本可用,高版本用Content Uri访问视频
    MediaStore.Video.Media.DATE_ADDED
};
// 手动列出所有需要查询的视频MIME类型,覆盖更多主流格式
String selection = MediaStore.Video.Media.MIME_TYPE + " IN (?,?,?,?,?,?,?,?)";
String[] selectionArgs = new String[]{
    "video/mp4", "video/3gpp", "video/x-matroska",
    "video/avi", "video/quicktime", "video/x-flv",
    "video/wmv", "video/webm"
};

Cursor cursor = getActivity().getContentResolver().query(uri, projection, selection, selectionArgs, orderBy);
if (cursor != null) {
    while (cursor.moveToNext()) {
        String id = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Video.VideoColumns._ID));
        String title = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Video.VideoColumns.TITLE));
        String displayName = cursor.getString(cursor.getColumnIndex(MediaStore.Video.VideoColumns.DISPLAY_NAME));
        String size = cursor.getString(cursor.getColumnIndex(MediaStore.Video.VideoColumns.SIZE));
        String duration = cursor.getString(cursor.getColumnIndex(MediaStore.Video.VideoColumns.DURATION));
        String path = cursor.getString(cursor.getColumnIndex(MediaStore.Video.VideoColumns.DATA));
        String dateAdded = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Video.VideoColumns.DATE_ADDED));
        
        // 缩略图单独查询
        String videoThumb = null;
        Cursor thumbCursor = getActivity().getContentResolver().query(
            MediaStore.Video.Thumbnails.EXTERNAL_CONTENT_URI,
            new String[]{MediaStore.Video.Thumbnails.DATA},
            MediaStore.Video.Thumbnails.VIDEO_ID + "=?",
            new String[]{id},
            null
        );
        if (thumbCursor != null && thumbCursor.moveToFirst()) {
            videoThumb = thumbCursor.getString(0);
            thumbCursor.close();
        }
        
        MediaFiles mediaFiles = new MediaFiles(videoThumb, id, title, duration, size, dateAdded, displayName, path);
        videoFiles.add(mediaFiles);
    }
    cursor.close();
}
  1. 权限适配:Android 13及以上版本需申请READ_MEDIA_VIDEO权限,Android 12及以下版本需申请READ_EXTERNAL_STORAGE权限,权限缺失会导致部分目录视频读取失败。

全格式覆盖替代方案

如果调整后仍有冷门类视频格式无法读取,可采用直接遍历外部存储匹配视频后缀的方案,该方案可100%覆盖所有自定义格式的视频:

前置要求

  • Android 13及以上版本:除READ_MEDIA_VIDEO外,若需要读取公共目录外的视频,需申请MANAGE_EXTERNAL_STORAGE权限(需引导用户手动到系统设置页开启)
  • Android 11-12版本:需申请MANAGE_EXTERNAL_STORAGE权限
  • Android 10及以下版本:仅需READ_EXTERNAL_STORAGE权限

实现逻辑

  • 提前定义所有常见视频后缀的集合:
HashSet<String> VIDEO_SUFFIX = new HashSet<>(Arrays.asList(
    "mp4", "3gp", "mkv", "avi", "mov", "flv", "wmv", "rmvb", "m4v", "ts", "webm"
    // 可自行添加需要支持的冷门后缀
));
  • 优先遍历DCIM、Movies、Download等公共媒体目录,再递归遍历外部存储根目录的所有子目录,判断文件后缀是否在上述集合中,符合条件则收集文件信息,视频时长可通过MediaMetadataRetriever类读取。

方案优缺点

  • 优势:可覆盖所有后缀符合规则的视频,无格式遗漏
  • 劣势:大存储设备遍历速度慢,需要申请特殊存储权限,应用上架需符合应用商店的权限使用规范。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 20:24:03