一、参考帧列表
以frame_num作为排序方式存在的问题:
1、frame_num循环计数,当处于临界状态时,会出现前向参考帧的frame_num比当前帧大,不好处理
👉故用FrameNumwrap代替frame_num()
2、以场编码时无法区分顶场和底场
👉用PicNum代替FrameNumwrap(计算时*2,且与参考场合当前场一致时+1)
对于每一个P帧和B帧的解码都需要从解码图像缓存DPB中选择某个参考帧。
DPB中的参考帧可分为短期参考帧和长期参考帧两种,分别按照PicNum和LongTermFrameIdx索引。
通过这两个索引值可以在参考帧列表中获取对应的参考帧图像。
解码不同的帧类型时,参考帧列表不同。
当解码P、SP帧时,使用一个参考帧列表RefPicList0;
当解码B帧时,使用两个参考帧列表RefPicList0和RefPicList1。
执行过程如下:
1、对参考帧列表进行初始化;
2、重排序
二、P/SP/B帧的参考帧列表的初始化(标准文档的8.2.4.2节)
参考图像分为短期参考图像(short-term reference)与长期参考图像(long-term reference),在某一个时间点上,参考图像只能是这两种的其中一种(非短即长)。
参考队列的长度:传输和不同模式下的实际长度
2个参考队列的长度 = num_ref_idx_lx_active_minus1 +1 (x=0/1)
0、默认16
1、首次(必定)在PPS中传参
2、其次(可能)在slice_header中传参(num_ref_idx_active_override_flag选择是否在此传参并覆盖PPS)
实际最大长度取决于宏块的编码方式:
1、如果当前宏块为帧宏块(纯帧图像 或 mbaff && !mb_field),默认情况下参考图像列表的长度为16,也可以通过num_ref_idx_lx_active_minus1指定最大长度为(num_ref_idx_l0_active_minus1 + 1)
2、如果当前宏块为场宏块(场图像 或 mbaff && mb_field),默认情况下参考图像列表长度为32,也可以通过num_ref_idx_lx_active_minus1指定长度为(2 * num_ref_idx_l0_active_minus1 + 2)
——标准7.4.5.2
参考图像列表中的条目数目可能存在大于,或小于等于最大长度的情况:
如果条目数大于最大长度,将删除最大长度之外位置的条目
如果条目数小于最大长度,将把空余的条目设置为“非参考图像”
——标准8.2.4.2
在初始化P/SP帧或B帧的参考帧列表过程中,DPB中至少要存在一个有效的、即被标记为“用于短期或长期参考”的参考帧。
2.1 P/SP帧的参考帧列表初始化(将DPB中的参考图像进行排序)
一般来说,距离当前图像最近的参考图像会被当前图像用作最多的参考,距离越远则参考得越少,短期参考图像列表就是依据这种规律来进行排序的。
P帧的前向参考帧列表RefPicList0:
先短期参考帧(索引值小,PicNum降序排列),后长期参考帧(索引值小,LongTermPicNum升序排列)
例如:
考虑到场的存在,不能直接沿用feame_num对参考队列进行排序,而是用一个能够表达场的PicNum和LongTermPicNum排序
以PicNum降序的方式,达到了距离当前pic越近越靠前的目的
1、首先,FrameNum 设置为 与已经解码的相应短期参考图像条带头部语法元素 frame_num 相等
【以GOP为一个周期,GOP的第一帧的FrameNum = FrameNumWrap = 0】
2、过渡变量FrameNumWrap:(考虑到frame循环特性,引入确保得到的 PicNum 的大小和先后顺序对应)
/*
FrameNum 为已经解码的相应短期参考图像条带头语法元素frame_num
考虑到frame_num 为0到MaxFrameNum之间循环变化使用,当恰好当前图像的frame_num正好处于临界值,比如0时,
那前几帧(按解码顺序)参考图像的frame_num就会比当前图像的frame_num(此处假设是0)大,
由此计算出来的PicNum也就会比CurrPicNum大,这在处理上会带来一些麻烦,
而对于FrameNumWrap,当前图像前几个参考帧对应的FrameNumWrap始终会比当前图像的frame_num小(如果当前图像处于临界位置0,
那前几帧参考图像的FrameNumWrap就变成了负值),
因此使用FrameNumWrap计算PicNum的话,只要某个参考图像在解码顺序上比当前图像靠前,那它对应的PicNum就比CurrPicNum小,
不需要再分情况讨论。【这个特点为场图像内P和SP片的参考帧列表中短期参考图像的排序提供了方便。】
*/
if( FrameNum > frame_num )
FrameNumWrap = FrameNum − MaxFrameNum //当前图像处于临界位置,如此处理以保证参考图像的序号 < 当前图像
else
FrameNumWrap = FrameNum
3、短期PicNum 和 长期LongTermPicNum的计算
短期PicNum计算:
对参考帧或互补参考场对(即MBAFF): PicNum = FrameNumWrap
对参考场以下规则适用:【对一个场解码时,可用的参考图像数将是解码一个帧时的两倍】
1、参考场和当前场奇偶性相同 PicNum = 2 * FrameNumWrap + 1
2、参考场与当前场奇偶性相反 PicNum = 2 * FrameNumWrap
长期LongTermPicNum计算:
对参考帧或长期互补参考场对: LongTermPicNum = LongTermFrameIdx
对参考场,应用如下规则:
如果参考场和当前场有相同的奇偶性 LongTermPicNum = 2 * LongTermFrameIdx + 1
否则(参考场与当前场的奇偶性相反) LongTermPicNum = 2 * LongTermFrameIdx
【(LongTermPicNum由MMCO分配)???】
“场”中P和SP片的参考帧列表的初始化
1、参考图像列表中的每个场都有单独的列表索引,而且对一个场解码时,可用的参考图像数将是解码一个帧时的两倍。
2、在对场中P和SP片参考图像列表初始化时,先要将短期参考图像和长期参考图像分别生成一个refFrameList0ShortTerm和refFrameList0LongTerm,这两个列表拼接生成最后的RefPicList0。
1、短期参考队列refFrameList0ShortTerm的生成
1、所有包含一个或多个标记为“用于短期参考”场的帧,均包含在短期参考帧列表refFrameList0ShortTerm中。
2、若当前场是互补参考场对中的第二场(解码顺序),并且第一场被标记为“用于短期参考”时,则该“第一场”包含在短期参考帧列表refFrameList0ShortTerm中。
3、以FrameNumWrap 递减排序(P帧是单向参考, FrameNumWrap越大,说明越靠近当前图像,但临界时与当图像相邻的参考图像的FrameNumWrap就成为负数了呀???)。
2、长期参考队列rrefFrameListLongTerm的生成
1、所有包含一个或多个帧被标记为“用于长期参考”场的帧,均包含在长期参考帧列表LongTermFrameIdx中。
2、当当前场是互补参考场对中的第二场(解码顺序),并且第一场被标记为“用于长期参考”时,则该第一场包含在长期参考帧列表refFrameList0LongTerm中。
3、以LongTermFrameIdx递增排序
2.2、B帧的参考帧列表初始化(短期参考帧分2部分且按函数PicOrderCnt( )排序)
函数PicOrderCnt( picX )如下:
if( picX 是一帧或互补场对 )
PicOrderCnt(picX)= picX 互补场对的Min(TopFieldOrderCnt,BottomFieldOrderCnt )
else if( picX 是顶场)
PicOrderCnt( picX ) = 场picX 的TopFieldOrderCnt
else if