思路:
使用MediaMetadataRetriever.getFrameAtTime(Long timeUs,int option)
参数解释:
timeUs:帧将被检索的时间位。注意单位是微秒
option:关于帧如何寻找的逻辑。有如下参数可选:
OPTION_CLOSEST
在给定的时间,检索最近一个帧,这个帧不一定是关键帧。
OPTION_CLOSEST_SYNC
在给定的时间,检索最近一个同步与数据源相关联的的帧(关键帧)。
OPTION_NEXT_SYNC
在给定时间之后检索一个同步与数据源相关联的关键帧。
OPTION_PREVIOUS_SYNC
在给定时间之前检索一个同步与数据源相关的关键帧
/**
* 获取帧图片
* @param videoPath 视频路径
* @return 帧图片集合
*/
@RequiresApi(api = Build.VERSION_CODES.P)
public static ArrayList<Bitmap> convertVideoToBitmaps(String videoPath) {
// float frameRate = getFrameRate(videoPath);
// LogUtil.i(TAG, "getFrameImages 获取视频的帧率:" + frameRate);
// TODO
try (MediaMetadataRetriever retriever = new MediaMetadataRetriever()) {
ArrayList<Bitmap> bitmapList = new ArrayList<>();
retriever.setDataSource(videoPath);
String duration = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
// 转换为微秒
long videoDuration = Long.parseLong(duration) * 1000;
LogUtil.i(TAG, "getFrameRate videoDuration:" + videoDuration);
String frameCount = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_FRAME_COUNT);
LogUtil.i(TAG, "getFrameRate 视频帧总数:" + frameCount);
int totalFrames = Integer.parseInt(frameCount);
// 获取每帧的间隔时间
long fps = (long) (videoDuration / (totalFrames - 1));
LogUtil.i(TAG, "getFrameRate 获取每帧的间隔时间:" + fps);
Matrix matrix = new Matrix();
long compressStart = System.currentTimeMillis();
// 均匀抽帧
for (int timeMs = 0; timeMs < totalFrames; timeMs += 1) {
long timeFPS = fps * timeMs;
// 对于时刻参数要注意的是:单位是微秒,而不是我们常用的毫秒。而通过 extractMetadata 方法得到的多媒体文件时间长度 duration 单位却是毫秒。
Bitmap frameAtTime = retriever.getFrameAtTime(timeFPS, MediaMetadataRetriever.OPTION_CLOSEST);
if (frameAtTime != null) {
// LogUtil.i(TAG, "timeFPS:" + timeFPS + " timeMs:" + timeMs);
// 调用回调方法传递每一帧的Bitmap对象
// LogUtil.i(TAG, "frame:" + frameAtTime);
// printBitmapSize1(frameAtTime);
// printBitmapSize2(compressImage(frameAtTime));
bitmapList.add(frameAtTime);
}
}
long compressEnd = System.currentTimeMillis();
LogUtil.i(TAG, "帧图片总数:" + bitmapList.size() + " 解析使用的时间:" + (compressEnd - compressStart) / 1000);
return bitmapList;
} catch (IOException e) {
e.printStackTrace();
return new ArrayList<>();
}
}