MPEG-2视频解码
Ffmpeg的mpeg-2视频解码(mpeg_decode_frame)过程如下:
1、读取前4个字节的头信息,一般为00 00 01 xx,其中xx 表示:
00 —— picture_start_code //表示一帧图像的开始
01~AF —— slice_start_code//表示一个slice的开始
B0、B1—— reserved
B2 —— user_data_start_code
B3 —— sequence_header_code//表示一个sequence的开始
B4 —— sequence_error_code
B5 —— extention_start_code
B6 —— reserved
B7 —— sequence_end_code//表示一个sequence的结束
B8 —— group_start_code
B9~FF —— system_start_code
2、判断以上头信息,如果xx= B7,表示前一个sequence结束,如果解码器中的next_picture_ptr还保存了一帧图像时,则输出该帧,且结束该次解码过程。
3、如果xx!= B7时,判断当前解码器是否支持内部组帧操作,如果支持,则组帧开始。组帧时用到两个函数:
² int next = ff_mpeg1_find_frame_end(&s2->parse_context, buf, buf_size, NULL, avctx->parserRtStart, avctx);
² ff_combine_frame(&s2->parse_context, next, (const uint8_t **)&buf, &buf_size)
以下为这两个函数的说明:
函数ff_mpeg1_find_frame_end:
输入参数:
码流解析上下文指针parse_context
传入的码流指针buf
传入的码流大小buf_size
音视频解码的统一上下文指针
返回值:
如果找到头的位置,则返回头位置+4(即00 00 01 xx之后的字节);否则,返回错误信息
函数功能:
查找一个帧(xx==00)头。
说明:
根据状态机所处的不同状态进行转换。如果没有找到下一个帧开始符,则只将当前的数据拷贝入解析器的buffer中;如果找到了下一个帧的开始符,则返回;
函数ff_combine_frame:
输入参数:
码流解析上下文指针parse_context
由函数ff_mpeg1_find_frame_end返回的下一个帧头的起始位置信息
输出参数:
组帧之后的buf
组帧之后的数据大小
返回值:
0 —— 组帧完成;
-1—— 没有得到组完的一帧数据;
4、主体解码过程(decode_chunks)(状态机的转换)
4.1 寻找起始码,根据起始码的不同,进入不同的解码流程:
SEQ_START_CODE:
表示一个序列的开始,进入mpeg1_decode_sequence过程。在改过程中,可以获取视频图像的大小、帧率索引、图像宽高比、比特率信息等,对解码用到的参数进行进一步赋值等。
PICTURE_START_CODE:
首先进行mpeg_decode_postinit,即进行该帧解码前的初始化工作;
之后进行mpeg1_decode_picture,即解码当前帧信息,获取视频的图像类型(注:图像类型的获取方法为:去掉00 00 01 00之后的第一、二个字节,取第11、12、13位,该三位即为图像类型信息,1——I帧,2——P帧,3——B帧)、vbv_delay、是否关键帧等信息;
EXT_START_CODE:
解码一些扩展信息,如:
mpeg_decode_sequence_extension
mpeg_decode_sequence_display_extension
mpeg_decode_quant_matrix_extension
mpeg_decode_picture_display_extension
mpeg_decode_picture_coding_extension等
USER_START_CODE:
用户数据信息解码,mpeg_decode_user_data。
GOP_START_CODE:
图像组信息解码,mpeg_decode_gop。
SLICE_MIN_START_CODE:
Slice信息解码,主函数为mpeg_decode_slice,即对每一个slice进行解码操作,之后会分解为一个宏块,再到一个子块。
5、当解码完一帧信息后,需要根据当前解码的图像类型判断是否需要输出
如果当前解码的视频序列中没有B帧,则每编完一帧即可进行输出;
如果当前解码的视频序列中有B帧,则需要进行判断:
如果当前解码完成的帧为I或P帧,并且该帧之前还有一个I或P帧没有输出,则输出其前一个I或P帧(若当前帧为第一帧则不用输出);如果当前解码完成的帧为B帧,则输出该帧。参考如下:
I B B P B B P B B P B B P……(显示顺序)
I P B B P B B P B B P B B……(编码顺序)
同样,
I P B B P B B P B B P B B……(解码顺序)
I B B P B B P B B P B B P……(还原显示顺序)