GetAnnexbNALU分析(網上資料加個人分析)
http://www.chinavideo.org/archiver/?tid-7943.html
[color=#38761d]/*!
************************************************************************
* \brief
* Returns the size of the NALU (bits between start codes in case of
* Annex B. nalu->buf and nalu->len are filled. Other field in
* nalu-> remain uninitialized (will be taken care of by NALUtoRBSP.
*
* \return
* 0 if there is nothing any more to read (EOF)
* -1 in case of any error
*
* \note Side-effect: Returns length of start-code in bytes.
*
* \note
* GetAnnexbNALU expects start codes at byte aligned positions in the file
*
************************************************************************
*/[/color]
[color=#38761d]//bits為讀入的位元組流,在此前面已被初始化,此段函數即從byte_stream_nal_unit( NumBytesInNALunit )中解碼,即將NALU解開,得到EBSP的一個過程[/color]
int GetAnnexbNALU (NALU_t *nalu)
{
int info2, info3, pos = 0;
int StartCodeFound, rewind;
char *Buf;
int LeadingZero8BitsCount=0, TrailingZero8Bits=0;
if ((Buf = (char*)calloc (nalu->max_size , sizeof(char))) == NULL) no_mem_exit("GetAnnexbNALU: Buf");
[color=#38761d]//*從 /*a start*/ 到/*a end*/實現 識別起始碼首碼startcodeprefix的功能.
// NALU對應的slice為一幀的開始則用4位位元組表示startcodeprefix=ox00000001,startcodeprefix_len=4
//否則用3位位元組表示startcodeprefix=ox000001,startcodeprefix_len=3 */
//統計一個byte stream NALU unit第一個非零位元組前一共有pos位元組(包括這個非零位元組)[/color]
while(!feof(bits) && (Buf[pos++]=fgetc(bits))==0); [color=#38761d]//將bits內的資料讀入Buf,直到第一個非零位元組或末尾,跟蹤結果為pos=4,即該位元組流前面資料格式為 00 00 00 01……[/color]
if(feof(bits)) [color=#38761d]//feof(bits):如果到檔案末尾,函數值為真
[/color]{
if(pos==0)
return 0;
else
{
printf( "GetAnnexbNALU can't read start code\n");
free(Buf);
return -1;
}
}
if(Buf[pos-1]!=1)
{
printf ("GetAnnexbNALU: no Start Code at the begin of the NALU, return -1\n");
free(Buf);
return -1;
}
if(pos<3)
{
printf ("GetAnnexbNALU: no Start Code at the begin of the NALU, return -1\n");
free(Buf);
return -1;
}
else if(pos==3)
{
nalu->startcodeprefix_len = 3; [color=#38761d]//startcodeprefix=0x000001
[/color] LeadingZero8BitsCount = 0;
}
else
{
LeadingZero8BitsCount = pos-4; [color=#38761d] //NALU對應的slice為一幀的開始則用4位位元組表示[/color]startcodeprefix=0x00000001
nalu->startcodeprefix_len = 4;
}
[color=#38761d]//the 1st byte stream NAL unit can has leading_zero_8bits, but subsequent ones are not
//allowed to contain it since these zeros(if any) are considered trailing_zero_8bits
//of the previous byte stream NAL unit.[/color]
if(!IsFirstByteStreamNALU && LeadingZero8BitsCount>0)
{
printf ("GetAnnexbNALU: The leading_zero_8bits syntax can only be present in the first byte stream NAL unit, return -1\n");
free(Buf);
return -1;
}
IsFirstByteStreamNALU=0;
StartCodeFound = 0;
info2 = 0;
info3 = 0;
while (!StartCodeFound)
{
if (feof (bits))
{
[color=#38761d] //Count the trailing_zero_8bits[/color]
while(Buf[pos-2-TrailingZero8Bits]==0)
TrailingZero8Bits++;
nalu->len = (pos-1)-nalu->startcodeprefix_len-LeadingZero8BitsCount-TrailingZero8Bits;
memcpy (nalu->buf, &Buf[LeadingZero8BitsCount+nalu->startcodeprefix_len], nalu->len);
nalu->forbidden_bit = (nalu->buf[0]>>7) & 1;
nalu->nal_reference_idc = (nalu->buf[0]>>5) & 3;
nalu->nal_unit_type = (nalu->buf[0]) & 0x1f;
[color=#38761d]// printf ("GetAnnexbNALU, eof case: pos %d nalu->len %d, nalu->reference_idc %d, nal_unit_type %d \n", pos, nalu->len, nalu->nal_reference_idc, nalu->nal_unit_type);[/color]
#if TRACE
fprintf (p_trace, "\n\nLast NALU in File\n\n");
fprintf (p_trace, "Annex B NALU w/ %s startcode, len %d, forbidden_bit %d, nal_reference_idc %d, nal_unit_type %d\n\n",
nalu->startcodeprefix_len == 4?"long":"short", nalu->len, nalu->forbidden_bit, nalu->nal_reference_idc, nalu->nal_unit_type);
fflush (p_trace);
#endif
free(Buf);
return pos-1;
}
[color=#ff0000] Buf[pos++] = fgetc (bits);
info3 = FindStartCode(&Buf[[color=#38761d]pos-4][/color], 3);[/color] [color=#38761d]//++ info3=1表示找到的下一個NALU的開始碼前有8位元填零碼(00000001)
[/color][color=#ff0000] if(info3 != 1)
info2 = FindStartCode(&Buf[[color=#38761d]pos-3[/color]], 2);[/color][color=#38761d] //++ info2=1表示找到的下一個NALU的開始碼前沒有8位元填零碼(000001)
[/color] [color=#ff0000]StartCodeFound = (info2 == 1 || info3 == 1);[/color]
}
[color=#ff0000]//紅色這一段很重要,它主要目的是找到下一NALU的起始碼,因為前面pos指向 00 00 00 01 _ _ 中的最後一個底線所對應位元組,此時pos=5 ,求info3時將 [/color][color=#38761d]pos-4[/color] [color=#ff0000]此時pos指向 00 00 即第二個位元組資料,而info3要找的是pos 後緊接著的 00 00 00 01 ,當然是沒有的,因為此時pos 後面連的是00 00 01,infro2同理,要想使info3,info2為1,只要找到下一個NALU的起始碼,
通過Buf[pos++] = fgetc [/color][color=#ff0000](bits);不斷的將bits中的資料複製到Buf中,最後[/color][color=#ff0000]pos+rewind也就是nal_unit( NumBytesInNALunit )中的參數。[/color]
[color=#ff0000]我們來看一下FindStartCode[/color]
[color=#ff0000]static int FindStartCode (unsigned char *Buf, int zeros_in_startcode)
{
int info;
int i;[/color]
[color=#ff0000]info = 1;
for (i = 0; i < zeros_in_startcode; i++) [color=#38761d]//hainei_10_3_14_找連續的3個0x00(zeros_in_startcode=3)
[/color] if(Buf[ i ] != 0)
info = 0;[/color]
[color=#ff0000]if(Buf[ i ] != 1) [color=#38761d] //3個0x00後的0x01
[/color] info = 0;
return info;
}[/color]
//Count the trailing_zero_8bits
if(info3==1) //if the detected start code is 00 00 01, trailing_zero_8bits is sure not to be present
{ [color=#38761d] //++ 即info2=1時,當前NALU必然不存在拖尾8位元填零碼,因此不必計數;反之,即info3=1時,要分析當前NALU是否有拖尾8位元填零碼,有則計數
[/color] while(Buf[pos-5-TrailingZero8Bits]==0)
TrailingZero8Bits++;
}
[color=#38761d]// Here, we have found another start code (and read length of startcode bytes more than we should
// have. Hence, go back in the file[/color]
rewind = 0;
if(info3 == 1)
rewind = -4;
else if (info2 == 1)
rewind = -3;
else
printf(" Panic: Error in next start code search \n");
if (0 != fseek (bits, rewind, SEEK_CUR))[color=#38761d] //++ SEEK_CUR=1,代表檔案指標當前位置
[/color]{
snprintf (errortext, ET_SIZE, "GetAnnexbNALU: Cannot fseek %d in the bit stream file", rewind);
free(Buf);
error(errortext, 600);
}
[color=#38761d]// Here the leading zeros(if any), Start code, the complete NALU, trailing zeros(if any)
// and the next start code is in the Buf.
// The size of Buf is pos, pos+rewind are the number of bytes excluding the next
// start code, and (pos+rewind)-startcodeprefix_len-LeadingZero8BitsCount-TrailingZero8Bits
// is the size of the NALU.[/color]
nalu->len = (pos+rewind)-nalu->startcodeprefix_len-LeadingZero8BitsCount-TrailingZero8Bits;
memcpy (nalu->buf, &Buf[LeadingZero8BitsCount+nalu->startcodeprefix_len], nalu->len);
[color=#38761d]//第一行就是解碼器在處理 7.3.1 小節中的第一個文法元素
//第二行就是解碼器在處理 7.3.1 小節中的第二個被加粗的文法元素[/color]
nalu->forbidden_bit = (nalu->buf[0]>>7) & 1; //+++++++++++++++++++++++++++
nalu->nal_reference_idc = (nalu->buf[0]>>5) & 3; //++ 該三值定義參見標準7.4.1
nalu->nal_unit_type = (nalu->buf[0]) & 0x1f; //+++++++++++++++++++++++++++
//printf ("GetAnnexbNALU, regular case: pos %d nalu->len %d, nalu->reference_idc %d, nal_unit_type %d \n", pos, nalu->len, nalu->nal_reference_idc, nalu->nal_unit_type);
#if TRACE
fprintf (p_trace, "\n\nAnnex B NALU w/ %s startcode, len %d, forbidden_bit %d, nal_reference_idc %d, nal_unit_type %d\n\n",
nalu->startcodeprefix_len == 4?"long":"short", nalu->len, nalu->forbidden_bit, nalu->nal_reference_idc, nalu->nal_unit_type);
fflush (p_trace);
#endif
free(Buf);
return (pos+rewind);
}
guxiongxxx 發表於 2010-5-7 05:01 PM
真是不錯,收啦
sam_wheat 發表於 2010-5-10 09:52 AM
支援一個,代碼就該這麼研究。
yanyun231 發表於 2010-5-11 05:12 PM
講的很好耶。感謝
yuanzhenhai 發表於 2010-6-13 09:02 AM
頂一個
jstulhw 發表於 2010-12-27 03:38 PM
不錯