引言
H.264相对于以前的标准,采用了多参考帧的技术,提高了编码器的性能,但也增加了实现的复杂度,在理解上也加大了难度。下面是我近来参阅一些资料的总结;
frame_num:标志片的解码顺序,当前图像是IDR(立即刷新图像)时,设置为0;相对于前面一个参考帧(解码顺序),增加1;
POC:picture order count的缩写,标志片的播放顺序,IDR图像的第一个场的POC为0;POC由片头信息得出,根据pic_order_cnt_type有三种计算方法;
Type0:TopFieldOrderCnt=POCMsb+POCLsb
POCLsb由片头提供,即pic_order_cnt_lsb;当pic_order_cnt_lsb溢出时,POCMsb增加;delta_pic_order_cnt指示顶场和低场POC的变化,默认值为0;
例:
播放顺序:IBPBPBPB…
B帧不作参考帧,则POC相对于前面的一个参考帧增加2;
Access Unit |
Type |
Used for reference |
frame_num |
POC_lsb |
TopPOC |
Display order |
1 |
I |
Yes |
0 |
0 |
0 |
0 |
2 |
P |
Yes |
1 |
4 |
4 |
2 |
3 |
B |
No |
2 |
2 |
2 |
1 |
4 |
P |
Yes |
2 |
8 |
8 |
4 |
5 |
B |
No |
3 |
6 |
6 |
3 |
6 |
P |
Yes |
3 |
12 |
12 |
6 |
7 |
B |
No |
4 |
10 |
10 |
5 |
8 |
P |
Yes |
4 |
16 |
16 |
8 |
… |
… |
… |
|
|
|
|
Type1:
在序列参数集中设置一个POC预期值,若POC的值有变化,则只传送相对变化值;序列参数集规定了POC循环的参考帧数目;对于一帧图像,计算POC预期值如下:
1. 计算POC循环数(自最近的IDR图像起)
2. 计算当前图像在POC循环中的位置
3. 计算当前图像POC的预期值
4. 如果是非参考帧,加上offset_for_non_ref_pic
TopFieldOrderCount=expected POC+delta_pic_order_cnt[0]
BottomFieldOrderCount=expected POC+delta_pic_order_cnt[1](if field_pic = 1)
= expected POC+offset to bottom field+delta_pic_order_cnt[0](otherwise)
例1:
播放顺序:IBPBPBPB…
B帧不作参考帧,一个POC循环中有一个参考帧,offset_for_non_ref_pic=-2,offset to next ref frame=4
Access Unit |
Type |
Used for Reference |
Frame_num |
delta_pic_order_cnt[0] |
topFOC |
Display order |
1 |
I |
Yes |
0 |
0 |
0 |
0 |
2 |
P |
Yes |
1 |
0 |
4 |
2 |
3 |
B |
No |
2 |
0 |
2 |
1 |
4 |
P |
Yes |
2 |
0 |
8 |
4 |
5 |
B |
No |
3 |
0 |
6 |
3 |
6 |
P |
Yes |
3 |
0 |
12 |
6 |
7 |
B |
No |
4 |
0 |
10 |
5 |
8 |
P |
Yes |
4 |
0 |
16 |
8 |
… |
… |
|
|
|
|
|
例2:
播放顺序:IBPBPBPB…
B帧不作参考帧,一个POC循环中有一个参考帧,offset_for_non_ref_pic=-4,offset to next ref frame=6
Access Unit |
Type |
Used for Reference |
Frame_num |
delta_pic_order_cnt[0] |
topFOC |
Display order |
1 |
I |
Yes |
0 |
0 |
0 |
0 |
2 |
P |
Yes |
1 |
0 |
6 |
3 |
3 |
B |
No |
2 |
0 |
2 |
1 |
4 |
P |
Yes |
2 |
2 |
4 |
2 |
5 |
B |
No |
3 |
0 |
12 |
6 |
6 |
P |
Yes |
3 |
0 |
8 |
1 |
7 |
B |
No |
4 |
2 |
10 |
2 |
8 |
P |
Yes |
4 |
0 |
18 |
9 |
… |
… |
|
|
|
|
|
Type2:
播放顺序与解码顺序相同;POC由frame_num直接得到
if(used for ref)
set TopPOC and/or BottomPOC to (2*frame_num)
else
set TopPOC and/or BottomPOC to (2*frame_num-1)
参考帧重排序
由于在解码每个MB时,都要用到参考帧的索引ref_idx_l0或ref_idx_l1。可能发生这样的情况,有个参考帧(短期参考帧或者长期参考帧)对于解码一个图像特别有用,但是这个参考帧在缺省的队列中并不位于索引值为0的位置,所以编码大的索引值需要花费多的比特。参考帧的重排序可以使这个参考帧位于索引值比较小的位置,以节省编码比特数。
下面我们以list0的重排序为例来说明
如果ref_pic_list_reordering_flag非0,则进入重排序的循环,直到ref_pic_list_reordering_flag为3时为止。
短期参考帧重排序(short-term):
初始化一个指针refIdxL0使其指向参考帧索引值0,abs_diff_pic_num_minus1是相对于预测参考帧的偏移量,对于第一次重排序操作,预测参考帧就是当前图像,对于后续的重排序操作,预测图像就是最近重排序的图像;
if(reordering_of_pic_nums_idc==0)
remapped_pic=predicted_pic- abs_diff_pic_num_minus1;
else if(reordering_of_pic_nums_idc==1)
remapped_pic=predicted_pic+ abs_diff_pic_num_minus1;
else if(reordering_of_pic_nums_idc==2)
remapped_pic= long_tem_pic_run;
else
return;
得到remapped_pic后,就将remapped_pic移至索引值为refIdxL0的位置,同时更新refIdxL0,并将后面的图像向后移动一个位置;
长期参考帧重排序(long-term):
与短期参考帧重排序类似,参见上面流程;
例:
P片,DPB包含5个参考帧,当前帧的frame_num=158,
list0的缺省顺序是:
157,155,153,1,3
初始化predicted_pic=158,refIdxL0=0
1. reordering_of_pic_nums_idc=0,abs_diff_pic_num_minus1=5
remapped_pic=158-5=153
重排序如下:
153,157,155,1,3
更新remapped_pic=153,refIdxL0=1