通过 MediaMetadataRetriever
提取视频帧,逐帧转换为 Bitmap 并保存为图片文件,需注意权限管理、性能优化及存储路径处理。
权限申请
READ_EXTERNAL_STORAGE
WRITE_EXTERNAL_STORAGE
(Android 10+ 需适配分区存储)初始化工具类
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
设置数据源
retriever.setDataSource(videoFilePath); // 视频文件路径
获取视频元数据
retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)
ffprobe
工具)。逐帧提取与保存
public void extractFrames(String videoPath, String outputDir) { MediaMetadataRetriever retriever = new MediaMetadataRetriever(); try { retriever.setDataSource(videoPath); int duration = Integer.parseInt(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)); int frameRate = 25; // 假设帧率,可动态计算 int frameInterval = 1000 / frameRate; // 每帧间隔(毫秒) for (int i = 0; i < duration; i += frameInterval) { Bitmap bitmap = retriever.getFrameAtTime(i 1000, MediaMetadataRetriever.OPTION_CLOSEST_SYNC); if (bitmap != null) { saveBitmap(bitmap, outputDir + "/frame_" + i + ".jpg"); bitmap.recycle(); } } } catch (Exception e) { e.printStackTrace(); } finally { retriever.release(); } } private void saveBitmap(Bitmap bitmap, String path) { FileOutputStream fos = null; try { fos = new FileOutputStream(path); bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fos); } catch (IOException e) { e.printStackTrace(); } finally { if (fos != null) { try { fos.close(); } catch (IOException ignored) {} } } }
问题 | 解决方案 |
---|---|
权限拒绝 | Android 10+ 使用 MediaStore API 或请求分区存储权限 |
大视频卡顿 | 子线程处理,分批加载帧 |
帧率不准确 | 使用第三方库(如 FFmpeg )解析真实帧率 |
OOM风险 | 及时回收 Bitmap,限制并发任务 |
Q1:如何动态获取视频的真实帧率?
A1:可通过 MediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_FPS)
尝试获取,若失败则需使用 FFmpeg
解析视频流。
Q2:Android 11+ 如何保存图片到公有目录?
A2:使用 MediaStore.Images.Media.insertImage()
或 ContentResolver
写入系统相册,避免直接操作文件路径