H.264 NAL格式及分析器程序源代码

H.264 AVC SPEC 3 关于NAL解码的说明
ANNEX B Byte stream format
(This annex forms an integral part of this Recommendation | International Standard)

H.264 NAL格式及分析器程序源代码
This annex specifies syntax and semantics of a byte stream format specified for use by applications that deliver some or all of the NAL unit stream as an ordered stream of bytes or bits within which the locations of NAL unit boundaries need to be identifiable from patterns in the data, such as ITU-T Recommendation H.222.0 | ISO/IEC 13818-1 systems or ITU-T Recommendation H.320 systems. For bit-oriented delivery, the bit order for the byte stream format is specified to start with the MSB of the first byte, proceed to the LSB of the first byte, followed by the MSB of the second byte, etc.
The byte stream format consists of a sequence of byte stream NAL unit syntax structures. Each byte stream NAL unit syntax structure contains one start code prefix followed by one nal_unit( NumBytesInNALunit ) syntax structure. It may (and under some circumstances, it shall) also contain an additional zero_byte syntax element. It may also contain one or more additional trailing_zero_8bits syntax elements. When it is the first byte stream NAL unit in the bitstream, it may also contain one or more additional leading_zero_8bits syntax elements
B.1.2 Byte stream NAL unit semantics
The order of byte stream NAL units in the byte stream shall follow the decoding order of the NAL units contained in the byte stream NAL units (see subclause 7.4.1.2). The content of each byte stream NAL unit is associated with the same access unit as the NAL unit contained in the byte stream NAL unit (see subclause 7.4.1.2.3).
leading_zero_8bits is a byte equal to 0x00.
NOTE – The leading_zero_8bits syntax element can only be present in the first byte stream NAL unit of the

bitstream, because (as
shown in the syntax diagram of subclause B.1.1) any bytes equal to 0x00 that follow a NAL unit syntax structure

and precede the
four-byte sequence 0x00000001 (which is to be interpreted as a zero_byte followed by a

start_code_prefix_one_3bytes) will be
considered to be trailing_zero_8bits syntax elements that are part of the preceding byte stream NAL unit.
zero_byte is a single byte equal to 0x00.
When any of the following conditions are fulfilled, the zero_byte syntax element shall be present.
– the nal_unit_type within the nal_unit( ) is equal to 7 (sequence parameter set) or 8 (picture parameter set)
– the byte stream NAL unit syntax structure contains the first NAL unit of an access unit in decoding order, as
specified by subclause 7.4.1.2.3.
start_code_prefix_one_3bytes is a fixed-value sequence of 3 bytes equal to 0x000001. This syntax element is called

a
start code prefix.
trailing_zero_8bits is a byte equal to 0x00.

B.2 Byte stream NAL unit decoding process
Input to this process consists of an ordered stream of bytes consisting of a sequence of byte stream NAL unit

syntax
structures.
Output of this process consists of a sequence of NAL unit syntax structures.
At the beginning of the decoding process, the decoder initialises its current position in the byte stream to the

beginning of
the byte stream. It then extracts and discards each leading_zero_8bits syntax element (if present), moving the

current
position in the byte stream forward one byte at a time, until the current position in the byte stream is such that

the next
four bytes in the bitstream form the four-byte sequence 0x00000001.
The decoder then performs the following step-wise process repeatedly to extract and decode each NAL unit syntax
structure in the byte stream until the end of the byte stream has been encountered (as determined by unspecified

means)
and the last NAL unit in the byte stream has been decoded:
1. When the next four bytes in the bitstream form the four-byte sequence 0x00000001, the next byte in the byte
stream (which is a zero_byte syntax element) is extracted and discarded and the current position in the byte
stream is set equal to the position of the byte following this discarded byte.
2. The next three-byte sequence in the byte stream (which is a start_code_prefix_one_3bytes) is extracted and
discarded and the current position in the byte stream is set equal to the position of the byte following this

threebyte
sequence.
3. NumBytesInNALunit is set equal to the number of bytes starting with the byte at the current position in the

byte
stream up to and including the last byte that precedes the location of any of the following conditions:


a. A subsequent byte-aligned three-byte sequence equal to 0x000000, or
b. A subsequent byte-aligned three-byte sequence equal to 0x000001, or
c. The end of the byte stream, as determined by unspecified means.
4. NumBytesInNALunit bytes are removed from the bitstream and the current position in the byte stream is
advanced by NumBytesInNALunit bytes. This sequence of bytes is nal_unit( NumBytesInNALunit ) and is
decoded using the NAL unit decoding process.


5. When the current position in the byte stream is not at the end of the byte stream (as determined by unspecified
means) and the next bytes in the byte stream do not start with a three-byte sequence equal to 0x000001 and the
next bytes in the byte stream do not start with a four byte sequence equal to 0x00000001, the decoder extracts
and discards each trailing_zero_8bits syntax element, moving the current position in the byte stream forward
one byte at a time, until the current position in the byte stream is such that the next bytes in the byte stream

form
the four-byte sequence 0x00000001 or the end of the byte stream has been encountered (as determined by
unspecified means).
B.3 Decoder byte-alignment recovery (informative)
This subclause does not form an integral part of this Recommendation | International Standard.
Many applications provide data to a decoder in a manner that is inherently byte aligned, and thus have no need for

the
bit-oriented byte alignment detection procedure described in this subclause.
A decoder is said to have byte-alignment with a bitstream when the decoder is able to determine whether or not the
positions of data in the bitstream are byte-aligned. When a decoder does not have byte alignment with the encoder

’s byte
stream, the decoder may examine the incoming bitstream for the binary pattern '00000000 00000000 00000000
00000001' (31 consecutive bits equal to 0 followed by a bit equal to 1). The bit immediately following this

pattern is the
first bit of an aligned byte following a start code prefix. Upon detecting this pattern, the decoder will be byte

aligned
with the encoder and positioned at the start of a NAL unit in the byte stream.
Once byte aligned with the encoder, the decoder can examine the incoming byte stream for subsequent three-byte
sequences 0x000001 and 0x000003.
When the three-byte sequence 0x000001 is detected, this is a start code prefix.
250 VERSION 3 OF ITU-T Rec. H.264 (E)
When the three-byte sequence 0x000003 is detected, the third byte (0x03) is an emulation_prevention_three_byte to

be
discarded as specified in subclause 7.4.1.
The byte alignment detection procedure described in this subclause is functionally equivalent to searching a byte
sequence for three consecutive zero-valued bytes (0x000000), starting at any alignment position. Detection of this
pattern indicates that the next non-zero byte contains the end of a start code prefix (as a conforming byte stream

cannot
contain more than 23 consecutive zero-valued bits without containing 31 or more consecutive zero-valued bits,

allowing
detection of 0x000000 relative to any starting alignment position), and the first non-zero bit in that next non-

zero byte is
the last bit of an aligned byte and is the last bit of a start code prefix.

NAL分析器程序源代码
/*!
**************************************************************************************
* \file
*   nalchek.c
* \brief
*    NALU handling common to encoder and decoder
l Zsw_davy@hotmail.com
l Aug.18.2006 ***************************************************************************************
*/

#include "stdio.h"
#include "stdlib.h"

#include "nalucommon.h"

//#####################################
//#本程序检查一个缓冲区里面有几个NALU #
//#输出每个NALU的类型到输出文件    #
//#输入为一个带有标记/NALU+标记/的文件#
//#####################################

void main(void)
{
FILE *pSrc;
FILE *pRep;


if((pSrc=fopen("H264.rec","r+b"))==NULL)
exit(-1);
else printf("open src file succeed\n");
if((pRep=fopen("H264.rep","w+t"))==NULL)
exit(-1);
else printf("open report file succeed\n");
ReportNalu(pSrc,pRep);
fclose(pSrc);
fclose(pRep);
}


/*! **************************************************************************************
* \file
*    nalucommon.h.h
* \brief
*    NALU handling common to encoder and decoder
* zsw_davy@hotmail.com
*   Aug.18.2006 ***************************************************************************************
*/
#include <memory.h>


#ifndef _NALUCOMMON_H_
#define _NALUCOMMON_H_

typedef struct
{
int startcodeprefix_len;      //! 4 for parameter sets and first slice in picture, 3 for everything else (suggested)
unsigned len;                 //! Length of the NAL unit (Excluding the start code, which does not belong to the NALU)
unsigned max_size;            //! Nal Unit Buffer size
int nal_unit_type;            //! NALU_TYPE_xxxx
int nal_reference_idc;        //! NALU_PRIORITY_xxxx
int forbidden_bit;            //! should be always FALSE
unsigned char *buf;        //! conjtains the first byte followed by the EBSP
} NALU_t;

#define MAXRBSPSIZE 64000

#define NALU_TYPE_SLICE    1
#define NALU_TYPE_DPA      2
#define NALU_TYPE_DPB      3
#define NALU_TYPE_DPC      4
#define NALU_TYPE_IDR      5
#define NALU_TYPE_SEI      6
#define NALU_TYPE_SPS      7
#define NALU_TYPE_PPS      8
#define NALU_TYPE_AUD      9
#define NALU_TYPE_EOSEQ    10
#define NALU_TYPE_EOSTREAM 11
#define NALU_TYPE_FILL     12

#define NALU_PRIORITY_HIGHEST     3
#define NALU_PRIORITY_HIGH        2
#define NALU_PRIRITY_LOW          1
#define NALU_PRIORITY_DISPOSABLE 0


#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif

#ifndef BOOL
#define BOOL unsigned int
#endif

void ReportNalu(FILE* src,FILE* rep);
void ParseRecBuf(unsigned char *p,int bufsize,FILE* pReport);
int ShowBits (unsigned char buffer[],int totbitoffset,int bytecount, int numbits);
BOOL next_bits(unsigned char *p,int bufpos,int bs,int id );
static int FindStartCode (unsigned char *Buf, int bufpos, int bufsize, int next_start_pos, BOOL fIRFD);
BOOL gETNALandPROC(unsigned char *p,int bufpos,int bufsize, BOOL fisrtfd,NALU_t *mNal,int inc_SIZE,FILE *pReport);
#endif


//############################################################
//#       src 文件格式如下  
//#        #-#-#-#-#-B-INT32LEN-T264DST - #-#-#-#-B-INT32LEN #
//#    1 1 1 1 1 1     4   INT32LEN                           #
//############################################################

void ReportNalu(FILE* src,FILE* rep)
{
unsigned char tempbuf[1];
unsigned char *pBuf;
int *dstlen;
    int fpos=0;
int fstart=0;
int FileSize=0;
int BufSize;
int dstpacketid=0;
unsigned int SymState=0;
fseek(src,0,SEEK_END);
FileSize=ftell(src);
printf("the src file size is %d \n",FileSize);
fseek(src,0,SEEK_SET);
do {

while (fread(tempbuf,sizeof(unsigned char),1,src))
{
   if(tempbuf=="#") SymState++;
   else
   {
    fpos=fstart+1;
    SymState=0;
    fseek(src,fpos,SEEK_SET);
   }
   if(SymState==4)
   {fpos+=4;break;}
}

fread(tempbuf,sizeof(unsigned char),1,src);

if(tempbuf=="B")
{
   SymState++;
   fpos+=1;
}
else
{
   fpos=fstart+1;
   fseek(src,fpos,SEEK_SET);
}

if(SymState==5)  
{  
   dstpacketid++;
   fprintf(rep,"the %d dstpacket\n",dstpacketid);
   dstlen=(int*)malloc(sizeof(int));
   fread(dstlen,sizeof(unsigned char),4,src);
   BufSize=(int*)dstlen;
   pBuf=(unsigned char*)malloc(sizeof(unsigned char)*BufSize);
   fpos+=4;
   fread(pBuf,sizeof(unsigned char),BufSize,src);
   ParseRecBuf(pBuf,BufSize,rep);
   fstart=fpos;
   free(dstlen);
   free(pBuf);
}

} while(fpos!=FileSize);//

}


//####################################################
//# unsigned char *p --T264 encode的一个dst长度为len#
//# int bufsize   --buffer的大小     #
//##FILE* pReport     --文件指针,存放NAL的分析结果 #
//####################################################

void ParseRecBuf(unsigned char *p,int bufsize,FILE* pReport)
{


int bufpos=0;
int bUFSTART=0;
    struct NALU_t *mNal;
BOOL isfirst;
BOOL starcode_ex;
BOOL zero_ex;
BOOL trail_ex;
int nALSIZE=0;
int nal_id=0;
BOOL firstfd=FALSE;

while (bufpos<bufsize)
{
if( !next_bits(p,bufpos,bufsize, 24 ) &&
   !next_bits(p,bufpos,bufsize,32 ) &&
   next_bits( p,bufpos,bufsize,8 ))
{bufpos+=8;isfirst=TRUE;firstfd=TRUE;}// leading_zero_8bits /* equal to 0x00 */ //f(8)
else{ isfirst=FALSE; }

if(!next_bits( p,bufpos,bufsize,24 ) &&   
   next_bits( p,bufpos,bufsize,8 )
   )
{   
   bufpos+=8;//zero_byte /* equal to 0x00 */ f(8)
   zero_ex=TRUE;
   if( bufpos<bufsize &&
    next_bits(p,bufpos,bufsize, 24 ) )
   {     
    bufpos+=24; // start_code_prefix_one_3bytes /* equal to 0x000001 */ f(24)
    starcode_ex=TRUE;
    mNal=(struct NALU_t* )malloc(sizeof( NALU_t));
   if(gETNALandPROC(p,bufpos,bufsize,firstfd,mNal,nALSIZE,pReport))   


   {
   
    nal_id++;
       fprintf(pReport," id of the nal packet above is %d\n",nal_id);
    bufpos+=(nALSIZE>>3);
    if(( bufpos<bufsize) &&
     (!next_bits(p,bufpos,bufsize, 24 )) &&
     (!next_bits(p,bufpos,bufsize, 32 ) ) &&
     (next_bits(p,bufpos, bufsize,8 )))
    {
     bufpos+=8; trail_ex=TRUE ;/* trailing_zero_8bitsequal to 0x00 */
    }
    else trail_ex=FALSE;
    free(mNal);
   }
   else printf("cannot get any nal units\n");
   }
   else{starcode_ex=FALSE;}     
}
else
{ zero_ex=FALSE; }

if (!zero_ex || !starcode_ex)
   bufpos=bUFSTART+1;
else bUFSTART=bufpos;
}
}

//############################################
//#unsigned char *p =--buffer containing NALU#
//#int bufpos--current buffer position   #
//#int bs---buffersize                   #
//#int id                                #
//# id=24   ----0x000001----FALSE   #
//#     id=32   ----0x00000001---FALSE   #
//#     id=8 ----0x00------TRUE    #
//############################################
BOOL next_bits(unsigned char *p,int bufpos,int bs,int id )
{
BOOL rERULT;
switch(id) {
case 8:  
if(ShowBits(p,bufpos,bs,8)==0x00) rERULT=TRUE ;
else rERULT=FALSE;
break;
case 24:
if(ShowBits(p,bufpos,bs,24)!=0x000001) rERULT=FALSE;
else rERULT=TRUE;
break;
case 32 :
if(ShowBits(p,bufpos,bs,32)!=0x00000001) rERULT=FALSE;
else rERULT=TRUE;
break;
default:
break;
}
return rERULT;
}

//##############################################
// # \brief         #
// # Reads bits from the bitstream buffer     #
// # \param buffer        #
// #    buffer containing VLC-coded data bits #
// # \param totbitoffset      #
// #    bit offset from start of partition     #
// # \param bytecount                          #
// #    total bytes in bitstream               #
// # \param numbits                            #
// #    number of bits to read                 #
// #############################################
int ShowBits (unsigned char buffer[],int totbitoffset,int bytecount, int numbits)
{

register int inf;
long byteoffset;      // byte from start of buffer
int bitoffset;      // bit from start of byte

byteoffset= totbitoffset/8;
bitoffset= 7-(totbitoffset%8);

inf=0;
while (numbits)
{
inf <<=1;
inf |= (buffer[byteoffset] & (0x01<<bitoffset))>>bitoffset;
numbits--;
bitoffset--;
if (bitoffset < 0)
{
   byteoffset++;
   bitoffset += 8;
   if (byteoffset > bytecount)
   {
    return -1;
   }
}
}

return inf;   // return absolute offset in bit from start of frame
}    


//#########################################################################
// # \brief             

    #
// #    returns if new start code is found at byte aligned position buf. #
// #    new-startcode is of form N 0x00 bytes, followed by a 0x01 byte.   #
// # \return             

    #
// #     1 if start-code is found or                      \n              #
// #     0, indicating that there is no start code                        #
// #                                                                      #
// # \param Buf                                                          #
// #     pointer to byte-stream                                           #
// # \param   bufpos                                             #
// #     indicates current bufpos.
//#     \bufsize
// #   indicates   total buffer size                          #
// # \param      next_star_pos                                           #
// #      indicates the next_start_code pos                               #
// # \param      fIRFD
// #    is firs nal already found
// ########################################################################
static int FindStartCode (unsigned char *Buf, int bufpos, int bufsize, int next_start_pos, BOOL fIRFD)
{
int info;
int tPOS;
int tSTART=bufpos;
BOOL sTARFOUND=FALSE;
info = 1;
while (!sTARFOUND && tSTART<bufsize) {
for (tPOS = 0; tPOS < 3; tPOS++)
   if(Buf[tSTART+tPOS] != 0)
    info = 0;   
   if(Buf[tSTART+tPOS] != 1)
    info = 0;
   if (info==0)    tSTART++;   
   else sTARFOUND=TRUE;
}
if (fIRFD && sTARFOUND)
{
if(Buf[tSTART-1]==0 &&
   Buf[tSTART-2]==0)
{ info=2;//trailing zero found
next_start_pos=tSTART-2;}
else {info=1;
next_start_pos=tSTART;}  
}
return info;
}


//#####################################
//# unsigned char *p      #
//# int bufpos                    #
//# NALU_t *mNal          #
//# int n_SIZE       #
//#           #
//#           #
//#####################################
BOOL gETNALandPROC(unsigned char *p,
       int bufpos,
       int bufsize,
       BOOL fisrtfd,
       NALU_t *mNal,
       int inc_SIZE,
       FILE *pReport)
{
BOOL getNfailed=FALSE;
    int nal_BUFSIZE=0;
int next_start_point=0;
int mNal_size=0;
int b_bufpos=bufpos/8;
unsigned int finresult;
BOOL info=TRUE;
finresult=FindStartCode (p,b_bufpos,bufsize,next_start_point,fisrtfd);
if (finresult==1 || finresult==2) {  
nal_BUFSIZE=next_start_point-b_bufpos-1;
inc_SIZE=nal_BUFSIZE;
mNal->buf=(unsigned char *)malloc(sizeof(unsigned char)*nal_BUFSIZE);
mNal->len=nal_BUFSIZE;
memcpy (mNal->buf, &p[b_bufpos+1], mNal->len);
mNal->forbidden_bit = (mNal->buf[0]>>7) & 1;
mNal->nal_reference_idc = (mNal->buf[0]>>5) & 3;
mNal->nal_unit_type = (mNal->buf[0]) & 0x1f;
fprintf(pReport,"#########################################################################\n");
fprintf(pReport,"nal len is %d\n",mNal->len);
fprintf(pReport,"fobidden bit is % d\n",mNal->forbidden_bit);
fprintf(pReport,"nal_reference_idc is d%\n",mNal->nal_reference_idc);
switch(mNal->nal_unit_type) {
case NALU_TYPE_SLICE :
   fprintf(pReport," nal type is * NALU_TYPE_SLICE\n");
   break;
case NALU_TYPE_DPA:
   fprintf(pReport,"nal type is * NALU_TYPE_DPA\n");
   break;
case NALU_TYPE_DPB :
   fprintf(pReport,"nal type is * NALU_TYPE_DPB\n");
   break;
case NALU_TYPE_DPC:
   fprintf(pReport,"nal type is * NALU_TYPE_DPC\n");
   break;
case NALU_TYPE_IDR:
   fprintf(pReport,"nal type is * NALU_TYPE_IDR\n");
   break;
case NALU_TYPE_SEI:
   fprintf(pReport,"nal type is * NALU_TYPE_SEI\n");
   break;
case NALU_TYPE_SPS:
   fprintf(pReport,"nal type is * NALU_TYPE_SPS\n");
   break;
case NALU_TYPE_PPS:
   fprintf(pReport,"nal type is * NALU_TYPE_PPS\n");
   break;
case NALU_TYPE_AUD:
   fprintf(pReport,"nal type is * NALU_TYPE_AUD\n");
   break;
case NALU_TYPE_EOSEQ:
   fprintf(pReport,"nal type is * NALU_TYPE_EOSEQ\n");
   break;
case NALU_TYPE_EOSTREAM:
   fprintf(pReport,"nal type is * NALU_TYPE_EOSTREAM\n");
   break;
case NALU_TYPE_FILL :
   fprintf(pReport,"nal type is * NALU_TYPE_FILL\n");
   break;
default:
   break;
}
fprintf(pReport,"nal start code len is %d\n",mNal->startcodeprefix_len);
fprintf(pReport,"#########################################################################\n");
free(mNal->buf);
mNal->buf=NULL;
}
else info=FALSE;
return info;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值