当前位置:网站首页>H264-解码顺序 显示顺序 参考顺序
H264-解码顺序 显示顺序 参考顺序
2022-07-15 16:45:00 【LUCKY-LIVING】
H264-解码顺序 显示顺序 参考顺序
解码参考帧标记过程
当一个解码图像的nal_ref_idc 不为0时,这个解码图像会被当做参考图像,即会被用作长参考帧或者段参考帧。
IDR帧
长参考帧技术
DPB解码图像缓冲区,片被解码后生成的数据保存在DPB中。DPB中的图像数据可用于后边图像编码时的帧间预测,或者输出到显示。

解码顺序
片头的frame_num参数决定了图像的解码顺序。frame_num 以解码顺序增加,不需要表示显示顺序。
IDR: 立即刷新帧,frame_num 要清零
其他: 从之前的参考帧开始逐次加一
显示顺序
Picture Order Count决定了解码图像的播放顺序。从IDR图像的第一场POC=0开始。
POC可以从片头中以可选的三种方式推导出来。POC推导为TopfiledOrderCount 顶场顺序和BottomfieldOrderCount底场顺序。
方式:0:在片头中直接发送POC
TopFieldOrderCount = POCMsb + POCLsb
POClsb 在每个片头发送
POCMsb加一,每当POCLsb达到它的最大值时。
如上表中,Access unit 表示接收到的顺序,frame_num 在每遇到一个参考帧时加一。POC_lsb在每个片头发送,顶场顺序等于POC_lsb,显示顺序是顶场顺序右移一位。
frame_num 的限制
- 如果当前帧为IDR 帧,PrevRefFrameNum = 0
- 否则,PrevRefFrameNum的推导如下:
方式1:在序列参数集中设置需要的增量,只发送一个delta值如果这个增量需要变化时
这种方式中的变量计算参考标准中的8.2.1.2
方式2:显示顺序等于解码顺序
POC从frame_num中推导得到。参考标准中的8.2.1.3
void decode_poc(VideoParameters *p_Vid, Slice *pSlice)
{
seq_parameter_set_rbsp_t *active_sps = p_Vid->active_sps;
int i;
// for POC mode 0:
unsigned int MaxPicOrderCntLsb = (1<<(active_sps->log2_max_pic_order_cnt_lsb_minus4+4));
switch ( active_sps->pic_order_cnt_type )
{
case 0: // POC MODE 0
// 1st
if(pSlice->idr_flag)
{
当为i帧时
p_Vid->PrevPicOrderCntMsb = 0;
p_Vid->PrevPicOrderCntLsb = 0;
}
else
{
if (p_Vid->last_has_mmco_5)
{
if (p_Vid->last_pic_bottom_field)
{
p_Vid->PrevPicOrderCntMsb = 0;
p_Vid->PrevPicOrderCntLsb = 0;
}
else
{
p_Vid->PrevPicOrderCntMsb = 0;
p_Vid->PrevPicOrderCntLsb = pSlice->toppoc;
}
}
}
// Calculate the MSBs of current picture
if( pSlice->pic_order_cnt_lsb < p_Vid->PrevPicOrderCntLsb &&
( p_Vid->PrevPicOrderCntLsb - pSlice->pic_order_cnt_lsb ) >= ( MaxPicOrderCntLsb / 2 ) )
pSlice->PicOrderCntMsb = p_Vid->PrevPicOrderCntMsb + MaxPicOrderCntLsb;
else if ( pSlice->pic_order_cnt_lsb > p_Vid->PrevPicOrderCntLsb &&
( pSlice->pic_order_cnt_lsb - p_Vid->PrevPicOrderCntLsb ) > ( MaxPicOrderCntLsb / 2 ) )
pSlice->PicOrderCntMsb = p_Vid->PrevPicOrderCntMsb - MaxPicOrderCntLsb;
else
pSlice->PicOrderCntMsb = p_Vid->PrevPicOrderCntMsb;
// 2nd
if(pSlice->field_pic_flag==0)
{
//frame pix
pSlice->toppoc = pSlice->PicOrderCntMsb + pSlice->pic_order_cnt_lsb;
pSlice->bottompoc = pSlice->toppoc + pSlice->delta_pic_order_cnt_bottom;
pSlice->ThisPOC = pSlice->framepoc = (pSlice->toppoc < pSlice->bottompoc)? pSlice->toppoc : pSlice->bottompoc; // POC200301
}
else if (pSlice->bottom_field_flag == FALSE)
{
//top field
pSlice->ThisPOC= pSlice->toppoc = pSlice->PicOrderCntMsb + pSlice->pic_order_cnt_lsb;
}
else
{
//bottom field
pSlice->ThisPOC= pSlice->bottompoc = pSlice->PicOrderCntMsb + pSlice->pic_order_cnt_lsb;
}
pSlice->framepoc = pSlice->ThisPOC;
p_Vid->ThisPOC = pSlice->ThisPOC;
//if ( pSlice->frame_num != p_Vid->PreviousFrameNum) //Seems redundant
p_Vid->PreviousFrameNum = pSlice->frame_num;
if(pSlice->nal_reference_idc)
{
p_Vid->PrevPicOrderCntLsb = pSlice->pic_order_cnt_lsb;
p_Vid->PrevPicOrderCntMsb = pSlice->PicOrderCntMsb;
}
break;
case 1: // POC MODE 1
// 1st
if(pSlice->idr_flag)
{
p_Vid->FrameNumOffset=0; // first pix of IDRGOP,
if(pSlice->frame_num)
error("frame_num not equal to zero in IDR picture", -1020);
}
else
{
if (p_Vid->last_has_mmco_5)
{
p_Vid->PreviousFrameNumOffset = 0;
p_Vid->PreviousFrameNum = 0;
}
if (pSlice->frame_num<p_Vid->PreviousFrameNum)
{
//not first pix of IDRGOP
p_Vid->FrameNumOffset = p_Vid->PreviousFrameNumOffset + p_Vid->max_frame_num;
}
else
{
p_Vid->FrameNumOffset = p_Vid->PreviousFrameNumOffset;
}
}
// 2nd
if(active_sps->num_ref_frames_in_pic_order_cnt_cycle)
pSlice->AbsFrameNum = p_Vid->FrameNumOffset+pSlice->frame_num;
else
pSlice->AbsFrameNum=0;
if( (!pSlice->nal_reference_idc) && pSlice->AbsFrameNum > 0)
pSlice->AbsFrameNum--;
// 3rd
p_Vid->ExpectedDeltaPerPicOrderCntCycle=0;
if(active_sps->num_ref_frames_in_pic_order_cnt_cycle)
for(i=0;i<(int) active_sps->num_ref_frames_in_pic_order_cnt_cycle;i++)
p_Vid->ExpectedDeltaPerPicOrderCntCycle += active_sps->offset_for_ref_frame[i];
if(pSlice->AbsFrameNum)
{
p_Vid->PicOrderCntCycleCnt = (pSlice->AbsFrameNum-1)/active_sps->num_ref_frames_in_pic_order_cnt_cycle;
p_Vid->FrameNumInPicOrderCntCycle = (pSlice->AbsFrameNum-1)%active_sps->num_ref_frames_in_pic_order_cnt_cycle;
p_Vid->ExpectedPicOrderCnt = p_Vid->PicOrderCntCycleCnt*p_Vid->ExpectedDeltaPerPicOrderCntCycle;
for(i=0;i<=(int)p_Vid->FrameNumInPicOrderCntCycle;i++)
p_Vid->ExpectedPicOrderCnt += active_sps->offset_for_ref_frame[i];
}
else
p_Vid->ExpectedPicOrderCnt=0;
if(!pSlice->nal_reference_idc)
p_Vid->ExpectedPicOrderCnt += active_sps->offset_for_non_ref_pic;
if(pSlice->field_pic_flag==0)
{
//frame pix
pSlice->toppoc = p_Vid->ExpectedPicOrderCnt + pSlice->delta_pic_order_cnt[0];
pSlice->bottompoc = pSlice->toppoc + active_sps->offset_for_top_to_bottom_field + pSlice->delta_pic_order_cnt[1];
pSlice->ThisPOC = pSlice->framepoc = (pSlice->toppoc < pSlice->bottompoc)? pSlice->toppoc : pSlice->bottompoc; // POC200301
}
else if (pSlice->bottom_field_flag == FALSE)
{
//top field
pSlice->ThisPOC = pSlice->toppoc = p_Vid->ExpectedPicOrderCnt + pSlice->delta_pic_order_cnt[0];
}
else
{
//bottom field
pSlice->ThisPOC = pSlice->bottompoc = p_Vid->ExpectedPicOrderCnt + active_sps->offset_for_top_to_bottom_field + pSlice->delta_pic_order_cnt[0];
}
pSlice->framepoc=pSlice->ThisPOC;
p_Vid->PreviousFrameNum=pSlice->frame_num;
p_Vid->PreviousFrameNumOffset=p_Vid->FrameNumOffset;
break;
case 2: // POC MODE 2
if(pSlice->idr_flag) // IDR picture
{
p_Vid->FrameNumOffset=0; // first pix of IDRGOP,
pSlice->ThisPOC = pSlice->framepoc = pSlice->toppoc = pSlice->bottompoc = 0;
if(pSlice->frame_num)
error("frame_num not equal to zero in IDR picture", -1020);
}
else
{
if (p_Vid->last_has_mmco_5)
{
p_Vid->PreviousFrameNum = 0;
p_Vid->PreviousFrameNumOffset = 0;
}
if (pSlice->frame_num<p_Vid->PreviousFrameNum)
p_Vid->FrameNumOffset = p_Vid->PreviousFrameNumOffset + p_Vid->max_frame_num;
else
p_Vid->FrameNumOffset = p_Vid->PreviousFrameNumOffset;
pSlice->AbsFrameNum = p_Vid->FrameNumOffset+pSlice->frame_num;
if(!pSlice->nal_reference_idc)
pSlice->ThisPOC = (2*pSlice->AbsFrameNum - 1);
else
pSlice->ThisPOC = (2*pSlice->AbsFrameNum);
if (pSlice->field_pic_flag==0)
pSlice->toppoc = pSlice->bottompoc = pSlice->framepoc = pSlice->ThisPOC;
else if (pSlice->bottom_field_flag == FALSE)
pSlice->toppoc = pSlice->framepoc = pSlice->ThisPOC;
else
pSlice->bottompoc = pSlice->framepoc = pSlice->ThisPOC;
}
p_Vid->PreviousFrameNum=pSlice->frame_num;
p_Vid->PreviousFrameNumOffset=p_Vid->FrameNumOffset;
break;
default:
//error must occurs
assert( 1==0 );
break;
}
}
参考顺序
在编码和解码之前,参考帧排列在一个或者两个链表中。P帧使用单独的链表list0,B帧使用两条链表list0 和list1. 在每一个链表中,短参考帧后边是长参考帧,长参考帧按照LongPicNum升序排列。
list0(P slice):默认顺序是以PicNum的降序排列,PicNum是frame_num模MaxFrameNum的结果
list0(B slice):默认顺序是(1)POC(显示顺序)在当前帧之前的以POC的降序排列。(2)POC在当前帧之后的以POC的升序排列。
list1(B slice): 默认顺序是(1)POC在当前帧之后的以POC升序排列。(2)POC在当前帧之前的以POC的降序排列。
list0(P slice)

最初的参考帧列表是空的。当前frame num是150,解码图像缓冲区的长度是5帧,罗马数字是长参考帧号。list0的入口是最近的编码图像,是最佳的参考图像。
B帧 list

当前帧的POC是68,DPB中包含短参考帧60,62,70,72,78 长参考帧1,3。当前帧的poc为68.
list0的默认顺序为:62,60,70,72,78,1,3
list1的默认顺序为:70,72,78,62,60,1,3
上图中显示list0和list1从DPB中构成的过程。
按照默认顺序,list0的入口62,是当前帧前面第一个图像。list1入口是当前帧后面第一个图像。它们是最佳的B帧参考图像。
改变参考图像列表顺序
未完待续。。。。。
边栏推荐
- Domestic light! High score spatiotemporal representation learning model uniformer
- 开源小工具记录
- dried food! Teach you how to build a highly available architecture
- Redis-安装&&启动
- leetcode:330. 按要求补齐数组
- IDEA类文档注释模板设置
- 虹科案例|nanoGUNE应用Onyx系统实现石墨烯电学性质的无损表征
- MySQL index
- 敏捷开发中的sprint的含义
- Canal realizes real-time synchronization of data from Mysql to es
猜你喜欢

resnet50结构图

MPC_ORCA
![[cloud native] 3.4 ruoyi cloud deployment practice (Part 1)](/img/42/bd8ab0b5e51e181b71b9028bd363ad.png)
[cloud native] 3.4 ruoyi cloud deployment practice (Part 1)

C语言 第八章 数组
Redis data structure practice, see how microblogging, wechat, shopping cart, lottery applet is used?

Ffmpeg audio and video transfer package (MP4 and flv are transferred to each other, and streaming data is transferred to FLV and MP4)

Gurobi——GRBLinExpr

Yotact structure diagram

2pc and 3pc of consistency agreement

Explore ZGC
随机推荐
Reading notes: review of process consulting I II III
D3.js打造酷炫圆弧图
抖音带火的这种无线领夹麦克风,央视主持人都在用
room android sqlite
markdown学习笔记 第二章 基本语法 (非markdown编辑器下显示)
循环语句及数组
flask基本用法
C语言 第九章 字符串
dried food! Teach you how to build a highly available architecture
About some string related functions, memory functions and some simulations
Distributed basic theory that cannot be ignored
Swin transformer, the best paper model of iccv 2021, finally started video
Among the top 50 intelligent operation and maintenance enterprises in 2022, Borui data strength was selected
C语言 第十章 指针
机器学习最重要的一张图,如何选择模型 sklearn结构图
Redis data structure practice, see how microblogging, wechat, shopping cart, lottery applet is used?
Redis (II) three special types of redis
Domestic light! High score spatiotemporal representation learning model uniformer
Huawei cloud stack opens its framework to the south to help ecological partners enter the cloud efficiently
数组和字符串赋值的问题(定义时不初始化)