当一个解码图像的nal_ref_idc 不为0时,这个解码图像会被当做参考图像,即会被用作长参考帧或者段参考帧。
DPB解码图像缓冲区,片被解码后生成的数据保存在DPB中。DPB中的图像数据可用于后边图像编码时的帧间预测,或者输出到显示。
片头的frame_num参数决定了图像的解码顺序。frame_num 以解码顺序增加,不需要表示显示顺序。
IDR: 立即刷新帧,frame_num 要清零
其他: 从之前的参考帧开始逐次加一
Picture Order Count决定了解码图像的播放顺序。从IDR图像的第一场POC=0开始。
POC可以从片头中以可选的三种方式推导出来。POC推导为TopfiledOrderCount 顶场顺序和BottomfieldOrderCount底场顺序。
TopFieldOrderCount = POCMsb + POCLsb
POClsb 在每个片头发送
POCMsb加一,每当POCLsb达到它的最大值时。
这种方式中的变量计算参考标准中的8.2.1.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的降序排列。
未完待续。。。。。
因篇幅问题不能全部显示,请点此查看更多更全内容