使用MediaStore.Video仅获取到MP4、3GP视频,如何读取手机全格式视频
Android全格式本地视频读取解决方案
问题根因
MediaStore.Video默认仅收录Android系统内置解码器支持的视频格式(MP4、3GP等),MKV、FLV、AVI、MOV等第三方格式不会被默认收录,因此直接查询MediaStore.Video会出现遗漏。
现有代码调整方案
你的代码存在两处可优化点,调整后可覆盖绝大多数主流视频格式:
- 移除
projection中冗余的MediaStore.Video.Thumbnails.DATA字段,该字段无法在MediaStore.Video.Media的查询中直接返回,反而会干扰查询结果,缩略图需单独通过MediaStore.Video.Thumbnails查询或者调用ContentResolver.loadThumbnail方法获取。 - 主动在查询参数中加入所有视频格式的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(); }
- 权限适配: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
相关产品推荐
相关产品推荐

