本文参考自http://wenku.baidu.com/link?url=ZPF0iSKzwLQg_8K02pnnd_-Zd6ISnsOGWsGYb98ucLkELZO4nOv-X-v2GKLzI3r0VMN4R0TC8cM6AQy7xOjDZ4AQJBYWT_-VOYlxQFCvaj_编码
视频编码顺序与视频的播放顺序,并不彻底相同url
视频编码时,若是采用了B帧编码,因为B帧不少时候都是双向预测得来的,这时会先编码B帧的后向预测图像(P帧),而后再进行B帧编码,spa
所以会把视频原来的播放顺序打乱,以新的编码顺序输出码流3d
而在解码断接收到码流后,须要把顺序还原成本来的播放顺序,以输出正确的视频code
在编解码中,视频的播放顺序序号叫作POC(picture order count)视频
POC有两种类型:blog
一、把POC的低位编进码流内 (pic_order_cnt_type = 0)io
二、依赖frame_num求解POC (pic_order_cnt_type = 1)ast
对于第一种类型,POC的低位pic_order_cnt_lsb能够从码流内获得,而POC的高位PicOrderCntMsb则要求解码器自行计数class
计数方式依赖于前一编码帧(PrevPicOrderCntMsb与PrevPicOrderCntLsb),代码以下
// Calculate the MSBs of current picture if( img->pic_order_cnt_lsb < img->PrevPicOrderCntLsb && ( img->PrevPicOrderCntLsb - img->pic_order_cnt_lsb ) >= ( MaxPicOrderCntLsb / 2 ) ) img->PicOrderCntMsb = img->PrevPicOrderCntMsb + MaxPicOrderCntLsb; else if ( img->pic_order_cnt_lsb > img->PrevPicOrderCntLsb && ( img->pic_order_cnt_lsb - img->PrevPicOrderCntLsb ) > ( MaxPicOrderCntLsb / 2 ) ) img->PicOrderCntMsb = img->PrevPicOrderCntMsb - MaxPicOrderCntLsb; else img->PicOrderCntMsb = img->PrevPicOrderCntMsb;
能够对比下图分析
若是序列内出现了mmco==5,
若是是场模式,而且出如今底场,PrevPicOrderCntMsb与PrevPicOrderCntLsb都要清零
若是出如今顶场,只须要清零PrevPicOrderCntMsb
若是mmco==5出如今帧模式,也是只清零PrevPicOrderCntMsb
另外若是出现了IDR,那么PrevPicOrderCntMsb与PrevPicOrderCntLsb都要清零
代码以下
// 1st if(img->idr_flag) { img->PrevPicOrderCntMsb = 0; img->PrevPicOrderCntLsb = 0; } else { if (img->last_has_mmco_5) { if (img->last_pic_bottom_field) { img->PrevPicOrderCntMsb = 0; img->PrevPicOrderCntLsb = 0; } else { img->PrevPicOrderCntMsb = 0; img->PrevPicOrderCntLsb = img->toppoc; } } }
能够对比下图分析
对于第二种类型,是经过frame_num来计算得出POC
在解析步骤以前经过下图来分析一下帧序列结构
该序列分3个循环,
除开I帧外,每一个循环有相同的结构其中frame_num是由解码器计数的,这里不在讨论范围内,直接拿来用,
另外有两个参数是从码流内(sps)获取:
num_ref_frames_in_pic_order_cnt_cycle 除I帧外,每一个循环内有多少个参考帧(P帧)
offset_for_ref_frame[i] 一个循环内参考帧之间的间隔
假设咱们须要计算POC为42的B帧的poc值
有以下步骤:
一、判断IDR,mmco==5
二、根据frame_num获取AbsFrameNum,若是是B帧则须要减一
三、计算POC,其中又分为如下几个步骤:
代码以下:
case 1: // POC MODE 1 // 1st if(img->idr_flag) { img->FrameNumOffset=0; // first pix of IDRGOP, img->delta_pic_order_cnt[0]=0; //ignore first delta if(img->frame_num) error("frame_num != 0 in idr pix", -1020); } else { if (img->last_has_mmco_5) { img->PreviousFrameNumOffset = 0; img->PreviousFrameNum = 0; } if (img->frame_num<img->PreviousFrameNum) { //not first pix of IDRGOP img->FrameNumOffset = img->PreviousFrameNumOffset + img->MaxFrameNum; } else { img->FrameNumOffset = img->PreviousFrameNumOffset; } } // 2nd if(active_sps->num_ref_frames_in_pic_order_cnt_cycle) img->AbsFrameNum = img->FrameNumOffset+img->frame_num; else img->AbsFrameNum=0; if(img->disposable_flag && img->AbsFrameNum>0) img->AbsFrameNum--; // 3rd img->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++) img->ExpectedDeltaPerPicOrderCntCycle += active_sps->offset_for_ref_frame[i]; if(img->AbsFrameNum) { img->PicOrderCntCycleCnt = (img->AbsFrameNum-1)/active_sps->num_ref_frames_in_pic_order_cnt_cycle; img->FrameNumInPicOrderCntCycle = (img->AbsFrameNum-1)%active_sps->num_ref_frames_in_pic_order_cnt_cycle; img->ExpectedPicOrderCnt = img->PicOrderCntCycleCnt*img->ExpectedDeltaPerPicOrderCntCycle; for(i=0;i<=(int)img->FrameNumInPicOrderCntCycle;i++) img->ExpectedPicOrderCnt += active_sps->offset_for_ref_frame[i]; } else img->ExpectedPicOrderCnt=0; if(img->disposable_flag) img->ExpectedPicOrderCnt += active_sps->offset_for_non_ref_pic; if(img->field_pic_flag==0) { //frame pix img->toppoc = img->ExpectedPicOrderCnt + img->delta_pic_order_cnt[0]; img->bottompoc = img->toppoc + active_sps->offset_for_top_to_bottom_field + img->delta_pic_order_cnt[1]; img->ThisPOC = img->framepoc = (img->toppoc < img->bottompoc)? img->toppoc : img->bottompoc; // POC200301 } else if (img->bottom_field_flag==0) { //top field img->ThisPOC = img->toppoc = img->ExpectedPicOrderCnt + img->delta_pic_order_cnt[0]; } else { //bottom field img->ThisPOC = img->bottompoc = img->ExpectedPicOrderCnt + active_sps->offset_for_top_to_bottom_field + img->delta_pic_order_cnt[0]; } img->framepoc=img->ThisPOC; img->PreviousFrameNum=img->frame_num; img->PreviousFrameNumOffset=img->FrameNumOffset; break;
计算POC还有一种类型,这种最简单,直接经过frame_num推导,应用在没有连续的非参考帧的状况下(即一个间隔最多只能包含一个非参考帧)。
即没有B帧的,这种最简单,直接经过frame_num推导,
可是应该注意,在这种状况下不存在连续 的非参考图象(注释),且解码输出的顺序和显示输出顺序一致(注释),意思就是说不出现B帧,但能够出现非参考的P场,这也是为何当 nal_ref_idc=0的时候
tempPicOrderCnt = 2 * ( FrameNumOffset + frame_num ) –1的状况。这里保证了参考场的POC始终为偶数,而且大于同帧的另一个场
代码以下
case 2: // POC MODE 2 if(img->idr_flag) // IDR picture { img->FrameNumOffset=0; // first pix of IDRGOP, img->ThisPOC = img->framepoc = img->toppoc = img->bottompoc = 0; if(img->frame_num) error("frame_num != 0 in idr pix", -1020); } else { if (img->last_has_mmco_5) { img->PreviousFrameNum = 0; img->PreviousFrameNumOffset = 0; } if (img->frame_num<img->PreviousFrameNum) img->FrameNumOffset = img->PreviousFrameNumOffset + img->MaxFrameNum; else img->FrameNumOffset = img->PreviousFrameNumOffset; img->AbsFrameNum = img->FrameNumOffset+img->frame_num; if(img->disposable_flag) img->ThisPOC = (2*img->AbsFrameNum - 1); else img->ThisPOC = (2*img->AbsFrameNum); if (img->field_pic_flag==0) img->toppoc = img->bottompoc = img->framepoc = img->ThisPOC; else if (img->bottom_field_flag==0) img->toppoc = img->framepoc = img->ThisPOC; else img->bottompoc = img->framepoc = img->ThisPOC; } if (!img->disposable_flag) img->PreviousFrameNum=img->frame_num; img->PreviousFrameNumOffset=img->FrameNumOffset; break;