【写在前面】
由于H.264采用了多参考帧预测技术,所以其参考图象的管理比较复杂。GO50只是说明了怎么用,没有讲明为什么这么用,大家看过之后往往会有很多疑惑。本文比较细致的讲解了参考图象管理的问题,旨在进一步揭开其朦胧的面纱:)
NOTE:为了便于从宏观角度讲解参考图象的管理,本文没有考虑B帧和场模式。
PS:在H.264中,编解码器要维护参考图像列表的同步,所以在编码器和解码器中参考图像的管理是基本一致。在看此篇之前,大家可以先看看我以前写的《JM85中的多参考帧问题》:
http://blog.csdn.net/sunshine1314/archive/2004/11/08/172498.aspx
【outline】
一、相关变量含义
二、解码流程(突出参考图像管理部分)
三、参考图像的标记
四、参考图像的初始化
五、参考图像的重排序
一、相关变量含义
DPB(Decoded Picture Buffer): 保存所有的重建图像,
ListX[i]: 参考帧列表,其包含的参考帧指向dpb中的重建图像,而且是经过排序的。ListX[0]是前向参考帧列表,P、B帧都会用到;ListX[1]是后向参考帧列表,只有B帧都会用到,
MaxFrameNum: 1 << (active_sps->log2_max_frame_num_minus4 + 4);
frame_num:表示参考帧的序号(指的是解码顺序)。具体见图1的例子。
![](https://p-blog.csdn.net/images/p_blog_csdn_net/sunshine1314/66634/r_fig2.gif)
图1 frame_num取值示例
note:
B帧不作参考时,我们可以忽略B帧,然后I/P帧按排列顺序是依次递增得。
B帧作参考时,frame_num就完全等同与编解码得顺序。
PicNum: 短期参考图像的序号,其计算过程如下:
//note: frame_num为当前图象的序号
if(listX[i]->frame_num > frame_num)
{
FrameNumWrap=listX[i]->frame_num - frame_num;
}
else
FrameNumWrap=listX[i]->frame_num;
listX[i]->PicNum=FrameNumWrap;
LongTermPicNum: 长期参考图象的序号,外部指定。
二、解码流程(突出参考图像管理部分)
![](https://p-blog.csdn.net/images/p_blog_csdn_net/sunshine1314/66634/r_dbp-diagram.gif)
图2 解码流程
参考图像列表初始化:将DBP中符合要求的重建图像放到listX[0],并进行排序。
参考图像列表重排序:根据当前slice码流中的句法元素,对listX[0]进行重排序。
参考图像的标记:对DBP中的重建图像进行标记,可标记为:不作参考,短期参考,或长期参考。
二、参考图像的标记
note: 之所以先讲参考图像的标记,是为了和实际解码的过程相一致,因为第1帧I帧是不需要用到参考帧的,只会保存参考帧。
如果当前图像不作参考,则跳过该环节。
1、保存重建图像到DPB
如果当前图像是IDR帧,则根据读入的语法元素,指明是否清空DPB,另外,还确定将IDR帧作为长期参考还是短期参考。
非IDR帧情况,当前帧作为短期参考插入DPB。
2、参考图像标记
参考图像标记有两种方法,自动滑窗法和自定义标记法,由相应的句法元素确定采用何种方法。
自动滑窗法:即FIFO的方法,当DPB已满时,将DPB中PicNum最小的短期参考图像(即最早的参考图像)移出DPB。
自定义标记法
(adaptive_ref_pic_marking_mode):在句法元素中指定将某一参考图像设置为何种类型的参考图像或移出。其命令如下表:
表1 自定义参考图象标记命令
命令
|
标记操作
|
0
|
结束标记操作
|
1
|
将一个短期参考标记为非参考(即移出)
|
2
|
将一个长期参考标记为非参考(即移出)
|
3
|
将一个短期参考标记为长期参考
|
4
|
指定长期参考图像的最大数目
|
5
|
清空DBP,并禁用长期参考
|
6
|
将当前图像存为长期参考
|
三、参考图像的初始化
1、将DBP中符合要求的重建图像放到listX[0]
2、排序
listX[0]中,先放短期参考,再放长期参考,
短期参考按PicNum降序排列,
长期参考按LongTermPicNum升序排列。
具体见表2的示例:
表2 参考图象初始化排序实例
![](https://p-blog.csdn.net/images/p_blog_csdn_net/sunshine1314/fig_list1.gif)
四、参考图像的重排序
为什么要重排序:节省码流,当一个序号(ref_idx)比较大的参考图象被用到的比例很大,这个时候将该参考图象的序号调小可以降低码率。这个过程即重排序。
参考图象重排序的大致过程如下:
对listX[0]中的参考图象进行遍历,每遍历到一个参考图象,读入句法元素reordering_of_pic_nums_idc,更新其参考图象序号。
reordering_of_pic_nums_idc
具体命令如下:
0/1:指定短期参考图象序号,分别用加偏移量和减偏移量的方法
2:指定长期参考图象序号
3:结束重排序。
参考图象重排序实例:
![](https://p-blog.csdn.net/images/p_blog_csdn_net/sunshine1314/66634/r_fig_list_reordering.gif)