h.264的POC計算

本文參考自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,其中又分爲如下幾個步驟:

  • 計算一個循環的長度,即offset_for_ref_frame[i]全部元素加起來,4+6+8 = 18
  • 計算AbsFrameNum所在循環的位置(9-1)/ 3 = 2 ,即第三個循環
  • 計算AbsFrameNum在循環內的偏移(9-1)%3 = 2,偏移2,即須要加上offset_for_ref_frame[0],offset_for_ref_frame[1]兩個
  • 計算前兩個循環的長度 2x18 = 36
  • 前兩個循環長度加上偏移長度 36 + 4 + 6 = 46
  • 因爲是B幀,最後要加上offset_for_non_ref_pic,offset_for_non_ref_pic = -2*(連續B幀的數量),而這裏因爲有多個連續B幀,因此取平均值2,即 offset_for_non_ref_pic = -2*2 = -4
  • 最後加上delta_pic_order_cnt[0] = 0,delta_pic_order_cnt[1] = 0 , 即POC = 42

 

代碼以下:

  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;
相關文章
相關標籤/搜索