天天看點

h264幀邊界識别

幀邊界識别簡介

H.264 将構成一幀圖像所有nalu 的集合稱為一個AU,幀邊界識别實際上就是識别AU。因為H.264 取消幀級文法,是以無法簡單地從碼流中擷取AU。解碼器隻有在解碼的過

程中,通過某些文法元素的組合才能判斷一幀圖像是否結束。一般來說,解碼器必須在完成一幀新圖像的第一個slice_header 文法解碼之後,才能知道前一幀圖像已經結束。

是以,最嚴謹的AU 識别步驟如下:

步驟 1 對碼流實施“去03 處理”。

步驟 2 解析nalu 文法。

步驟 3 解析slice_header 文法。

步驟 4 綜合判斷前後兩個nalu 以及對應的slice_header 中的若幹個文法元素,看是否發生變化。

如果發生變化,則說明這兩個nalu 屬于不同的幀,否則說明這兩個nalu 屬于同一幀。

----結束

顯然,在解碼前完成上述的AU 識别消耗許多CPU 資源,是以不推薦使用AU 方式解碼

為了提供一種簡單的AU 識别方案,H.264 規定一種類型為09 的nalu,即編碼器在每次完成一個AU 編碼後,在碼流中插入一個類型為09 的nalu,在這個前提下,解碼器隻需要從碼流中搜尋類型為09 的nalu 即可獲得一個AU。

H.264 并不強制要求編碼器插入類型為09 的nalu,是以并非所有的碼流都具備這種特征。對于編碼器和解碼器協同工作的應用場景,建議讓編碼器插入類型為09 的nalu,這樣可以降低解碼器識别AU 的代價。

為了降低解碼器在解碼前識别AU 的代價,本文提出一種高效的AU 識别方法,其主要思路是利用一幀圖像的第一個slice_header 中的文法元素first_mb_in_slice 一般等于0 這

個特征(對于包含ASO 或者FMO 特性的碼流,這個條件不一定成立)。

  1. typedef struct ParseContext{  
  2.     unsigned int FrameStartFound;   
  3.     unsigned int iFrameLength;   
  4. } ParseContext;  
  5. signed int  DecLoadAU(unsigned char* pStream, unsigned int iStreamLen, ParseContext *pc)  
  6.     {  
  7.         unsigned int i;  
  8.         unsigned int state = 0xffffffff;  
  9.         if( NULL == pStream )  
  10.         {  
  11.             return -1;  
  12.         }  
  13.         for( i = 0; i < iStreamLen; i++)  
  14.         {  
  15.             if( (state & 0xFFFFFF1F) == 0x101 || (state & 0xFFFFFF1F) == 0x105 )  
  16.             {  
  17.                 if (i >= iStreamLen)   
  18.                 {  
  19.                     break;  
  20.                 }if( pStream[i] & 0x80)   
  21.                 {  
  22.                     if(pc->FrameStartFound)   
  23.                     {  
  24.                         pc->iFrameLength = i - 4;  
  25.                         pc->FrameStartFound = 0;  
  26.                         state = 0xffffffff;  
  27.                         return 0;   
  28.                     }  
  29.                     else  
  30.                     {  
  31.                         pc->FrameStartFound = 1;  
  32.                     }  
  33.                 }  
  34.             }  
  35.             if (i < iStreamLen)  
  36.             {  
  37.                 state = (state << 8) | pStream[i];   
  38.             }  
  39.         }  
  40.         pc->FrameStartFound = 0;  
  41.         return -1;   
  42.     } 

繼續閱讀