目录
0、写在前面
1、参考帧列表修改/重排
1.1、短期参考帧的修改
1.1.1、计算 picNumLXPred
1.1.2、计算 picNumLXNoWrap
1.1.3、计算 picNumLX
1.1.4、修改参考帧列表
1.2、长期参考帧的修改
0、写在前面
有的文章写的是 “参考帧列表修改”,有的文章写的是“参考帧列表重排”,其实是同一个意思,在 H.264 的 slice_header 结构语法中,定义了 ”参考帧列表修改/重排“:
- 低版本的 H.264 定义了这个过程为重排:slice_header->ref_pic_list_reordering() 过程
- 高版本的 H.264 定义了这个过程为修改:slice_header->ref_pic_list_modification() 过程
通过比较高低版本的 SPEC,slice_header->ref_pic_list_reordering() 过程和 slice_header->ref_pic_list_modification() 过程高度相似,几乎没有区别;
这里我们以新版本的 slice_header->ref_pic_list_modification() 过程为例:
1、参考帧列表修改/重排
参考图象重排序的大致过程为:对参考图像列表中的参考图像进行遍历,每遍历到一个参考图像,读入句法元素 modification_of_pic_nums_idc,更新其参考图像序号并调整列表。
ref_pic_list_modification_flag_l0 = 1 时,对参考帧列表 RefPicList0 进行修改;
ref_pic_list_modification_flag_l1 = 1 时,对参考帧列表 RefPicList1 进行修改;
本节中以P帧解码时修改参考帧列表 RefPicList0 为例讨论其执行过程。
- 首先设定一个值 refIdxL0 表示参考帧列表中参考帧的索引值,并初始化为 0;
- 读取码流中的 modification_of_pic_nums_idc 值,并根据其取值进行计算:
- 若 modification_of_pic_nums_idc 为 0 或 1,执行短期参考帧的修改过程;
- 若 modification_of_pic_nums_idc 为 2,执行长期参考帧的修改过程;
- 若 modification_of_pic_nums_idc 为 3,参考帧列表的修改过程完成;
- ref_pic_list_modification_flag_lx = 1,则一直读取 modification_of_pic_nums_idc 的值做循环,直到读到3时,退出循环;可能有多个长期多个短期
参考帧列表修改过程以 refIdxL0 作为输入参数,执行完成后的结果也返回给 refIdxL0;
1.1、短期参考帧的修改
修改短期参考帧主要步骤如下:可参考JM代码中reorder_short_term
1.1.1、计算 picNumLXPred
- picNumLXPred 可以认为是下一步骤中要计算的变量 picNumLXNoWrap 的预测值;
- 当 slice_header 中出现第一个 modification_of_pic_nums_idc 值时,picNumLXPred 设置为CurrPicNum,即当前帧的 frame_num;
- 随后,每当计算得到一个 picNumLXNoWrap 后,这一个 picNumLXNoWrap 值都会赋值给picNumLXPred。
1.1.2、计算 picNumLXNoWrap
- 计算picNumLXNoWrap的方法根据modification_of_pic_nums_idc的取值不同而不同;
- 当modification_of_pic_nums_idc取值为0时,其含义为码流中读出的abs_diff_pic_num_minus1为picNumLXNoWrap为相对于picNumLXPred的负增量,即需要从picNumLXPred中减去该值。计算方法如下:(标准协议8.2.4.3.1)
if( picNumLXPred − ( abs_diff_pic_num_minus1 + 1 ) < 0 )
picNumLXNoWrap = picNumLXPred − ( abs_diff_pic_num_minus1 + 1 ) + MaxPicNum
else
picNumLXNoWrap = picNumLXPred − ( abs_diff_pic_num_minus1 + 1 )
当modification_of_pic_nums_idc取值为1时,其含义为码流中读出的abs_diff_pic_num_minus1为picNumLXNoWrap为相对于picNumLXPred的正增量,即需要从picNumLXPred中加上该值。计算方法如下:
if( picNumLXPred + ( abs_diff_pic_num_minus1 + 1 ) >= MaxPicNum )
picNumLXNoWrap = picNumLXPred + ( abs_diff_pic_num_minus1 + 1 ) − MaxPicNum
else
picNumLXNoWrap = picNumLXPred + ( abs_diff_pic_num_minus1 + 1 )
1.1.3、计算 picNumLX
picNumLX的值通过picNumLXNoWrap与当前frame_num的值比较后计算得到,具体计算方式如下:
if( picNumLXNoWrap > CurrPicNum )
picNumLX = picNumLXNoWrap − MaxPicNum
else
picNumLX = picNumLXNoWrap
该步骤中得到的picNumLX应等于参考帧列表中的某一个短期参考帧的PicNum值。
1.1.4、修改参考帧列表
在计算得到picNumLX后,配合传入的的索引值refIdxLX,接着进行参考帧列表的修改。其方法为将picNumLX对应的短期参考帧置于refIdxLX位置,并且清除掉列表中PicNum等于picNumLX的参考帧。具体计算方法如下:
for( cIdx = num_ref_idx_lX_active_minus1 + 1; cIdx > refIdxLX; cIdx− − )
RefPicListX[ cIdx ] = RefPicListX[ cIdx − 1]
RefPicListX[ refIdxLX++ ] = short-term reference picture with PicNum equal to picNumLX
nIdx = refIdxLX
for( cIdx = refIdxLX; cIdx <= num_ref_idx_lX_active_minus1 + 1; cIdx++ )
if( PicNumF( RefPicListX[ cIdx ] ) != picNumLX )
RefPicListX[ nIdx++ ] = RefPicListX[ cIdx ]
1.2、长期参考帧的修改
修改长期参考帧的方法相对简单。在ref_pic_list_modification结构中的long_term_pic_num即表示待操作的长期参考帧索引。修改的方式类似短期参考帧的修改。具体计算方法如下:
for( cIdx = num_ref_idx_lX_active_minus1 + 1; cIdx > refIdxLX; cIdx− − )
RefPicListX[ cIdx ] = RefPicListX[ cIdx − 1]
RefPicListX[ refIdxLX++ ] = long-term reference picture with LongTermPicNum equal to long_term_pic_num
nIdx = refIdxLX
for( cIdx = refIdxLX; cIdx <= num_ref_idx_lX_active_minus1 + 1; cIdx++ )
if( LongTermPicNumF( RefPicListX[ cIdx ] ) != long_term_pic_num )
RefPicListX[ nIdx++ ] = RefPicListX[ cIdx ]