【问题标题】:Get all frames from video using MediaMetadataRetriever使用 MediaMetadataRetriever 从视频中获取所有帧
【发布时间】:2022-11-27 00:26:45
【问题描述】:
我正在尝试使用 MediaMetadataRetriever 和 getFrameAt() 方法从视频中获取所有帧。
使用FFMPEG,我有以下信息:
-
视频帧数:234 帧
-
以毫秒为单位的视频持续时间:90000
int counter = 0;
long mVideoDuration = 9000;
for (long i = 0; i < mVideoDuration * 1000; i += 1000) {
Bitmap thumbnail = mMediaMetadataRetriever.getFrameAtTime(i);
}
上面的代码不起作用,它几乎是循环的8944次,这太多了,我不想得到所有这些帧,我只想得到234帧。
getFrameAtIndex()效果很好, 但由于 API 级别的兼容性,我想让它与 getFrameAt() 方法一起使用
【问题讨论】:
标签:
java
android
mediametadataretriever
【解决方案1】:
要使用 getFrameeAtTime() 获取帧,您必须知道视频中每一帧的时间。您可以粗略地计算出,如果您已经通过获取帧时间(持续时间/帧)知道帧数,则可以对其使用 math.ceil() 方法并将其作为您的增量器。但是,您必须检查是否读取了最后一帧,因为您不能总是获得准确的帧时间,因为它们往往有很多小数位,这会导致错误表示为浮点数。
例如,60fps 视频的帧时间为 16+1/3 毫秒。其具有无限小数位。
此外,如果您的视频帧率过高,此方法甚至根本不起作用,因为在这种情况下,由 math.ceil() 完成的汇总可能会导致足够大的余量以跳过帧。
准确地说,此方法仅在以下情况下有效:
(math.ceil(frameTime)-frameTime)⋅frameCount<frameTime
我希望,到现在为止你已经知道这是一个非常糟糕的主意,你应该使用另一种方法来获取单个帧。
但是,这里仍然是一个实现:
int lastTime;
long mVideoDuration = 9000;
mVideoDuration*=1000;
int frameTime=math.ceil(mVideoDuration/frameCount)
for(int i =0, i<=mVideoDuration, i+=frameTime){
Bitmap thumbnail = mMediaMetadataRetriever.getFrameAtTime(i);
lastTime=i;
}
if (lastTime<mVideoDuration){
mMediaMetadataRetriever.getFrameAtTime(mVideoDuration);
}
当然这已经假设了,
(math.ceil(frameTime)-frameTime)⋅frameCount<frameTime
给出。
而且我不能保证 declaframeTime 会产生正确的值,因为我不确切知道内部如何处理小数除法,并且完全有可能由于浮点溢出而导致问题
【解决方案2】:
您可以使用 getFramesAtIndex(int frameIndex, int numFrames) 而不是 getFrameAt(),它将返回包含请求的视频帧的位图列表。
此方法类似于 getFramesAtIndex(int, int, MediaMetadataRetriever.BitmapParams),只是将使用 MediaMetadataRetriever.BitmapParams 的默认值。
参数:
frameIndex – 要检索的第一个视频帧的从 0 开始的索引。帧索引必须是有效帧的索引。可以通过 METADATA_KEY_VIDEO_FRAME_COUNT 键查询可用于检索的帧总数。
numFrames – 要检索的连续视频帧数。必须是正值。流必须至少包含从 frameIndex 开始的 numFrames 帧。
退货:
包含请求的视频帧的位图列表。如果检索失败,返回的数组包含的帧可能少于请求的帧。
投掷:
IllegalStateException – 如果容器不包含视频或图像序列。
IllegalArgumentException – 如果 frameIndex 或 numFrames 无效,或者流不包含至少从 frameIndex 开始的 numFrames。
也可以看看:
getFrameAtIndex(int,MediaMetadataRetriever.BitmapParams),getFrameAtIndex(int),getFramesAtIndex(int,int,MediaMetadataRetriever.BitmapParams)
关于numFrames,你可以通过这种方式获得帧数:
m_mediaMetadataRetriever = new MediaMetadataRetriever();
m_mediaMetadataRetriever.setDataSource(getApplicationContext(), your_video_path);
int numFrames = Integer.parseInt(m_mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_FRAME_COUNT));