我上一篇文章写了关于视频直播点播服务器中调整关键帧间隔的方法,同时也发现也是有一部分的开发者是有这个需求的。我记得之前我粗略写过I帧的判断:H264编码NALU结构介绍与I帧判断方法,但也是粗略的写了一下,本篇文章我决定就关键帧来做个详细点的说明,最基本的就是——什么是关键帧。
关键帧,就是说这一帧是连接两段不同的内容,这一帧后面的视频内容会有新的变化或过渡;在时间轴上这一帧带有小黑点标志;空白关键帧,跟关键帧作用相同,但是这一帧没有内容,在时间轴上,这一帧没有小黑点标志;在这一帧填充内容后,就变成关键帧了;普通帧是用来计量播放时间或过渡时间用的,不能手动设置普通帧的内容,它是播放过程中由前后关键帧以及过渡类型自动填充的,手动插入或删除普通帧,会改变前后两个关键帧之间的过渡时间。
视频关键帧分为I帧,P帧,B帧,这里介绍下区别,也是我搜索得到的,仅供参考。I帧才是关键帧,P,B算不上关键帧。
I帧是帧内压缩编码得到的,通常是每个GOP组的第一帧/基础帧,在一组中只有一个I帧,I帧所占信息量大,解码时仅有I帧即可完整重构图像,所以才叫关键帧。
P帧与B帧是帧间压缩,P帧没有完整图像数据,只有与前一帧的差别信息,因此也叫预测帧,B帧则是考虑前后帧的差别(故而也叫双向预测帧),因此B帧解码时间最长,压缩比最大。
那怎么提取视频的关键帧呢?其实提取关键帧比提取视频帧快很多倍,下面我就基于Android系统来讲一下提取视频帧的方法:
第一个参数 是传入截取时间,只能是us(微秒)
第二个参数
OPTION_CLOSEST 在给定的时间,检索最近一个帧,这个帧不一定是关键帧。
OPTION_CLOSEST_SYNC 在给定的时间,检索最近一个同步与数据源相关联的的帧(关键帧)。
OPTION_NEXT_SYNC 在给定时间之后检索一个同步与数据源相关联的关键帧。
OPTION_PREVIOUS_SYNC 在给定时间之前检索一个同步与数据源相关的关键帧
这里为了提取我们想要的帧,不使用关键帧,所以用 OPTION_CLOSEST
代码语言:javascript复制public Bitmap getFrameAtTime()
//如果不加参数的话,提取第一个关键帧
public Bitmap getFrameAtTime() {
return getFrameAtTime(-1, OPTION_CLOSEST_SYNC);
}
代码语言:javascript复制 /**
* 获取视频文件截图
*
* @param path 视频文件的路径
* @return Bitmap 返回获取的Bitmap
*/
public Bitmap getVideoThumb(String path) {
MediaMetadataRetriever media = new MediaMetadataRetriever();
media.setDataSource(path);
Bitmap frameAtTime = media.getFrameAtTime(1 * 1000 * 1000, MediaMetadataRetriever.OPTION_CLOSEST);
if (frameAtTime == null) {
frameAtTime = media.getFrameAtTime(3 * 1000 * 1000, MediaMetadataRetriever.OPTION_CLOSEST);
}
return frameAtTime;
}