解析JM代码比较理解H264语法元素解码ue(v),se(v),u(n)

来源:互联网 发布:微场景制作软件推荐 编辑:程序博客网 时间:2024/06/05 07:15

ue(v):无符号整数指数哥伦布码编码的语法元素,左位在先。

se(v):有符号整数指数哥伦布码编码的语法元素,左位在先。

u(n):n位无符号整数。在语法表中,如果n是‘v’,其比特数由其它语法元素值确定。解析过程由函

数read_bits(n)的返回值规定,该返回值用最高有效位在前的二进制表示。


//! Syntaxelement 。an important data structure!

typedef struct syntaxelement

{

  int                 type;           //!< type of syntax element for data part.

  int                 value1;         //!< numerical value of syntax element

  int                 value2;         //!< for blocked symbols, e.g. run/level

  int                 len;            //!< length of code

  int                 inf;            //!< info part of UVLC code

  unsigned int        bitpattern;     //!< UVLC bitpattern

  int                 context;        //!< CABAC context

  int                 k;              //!< CABAC context for coeff_count,uv


#if TRACE

  #define             TRACESTRING_SIZE 100            //!< size of trace string

  char                tracestring[TRACESTRING_SIZE];  //!< trace string

#endif


  //!< for mapping of syntaxElement to UVLC

  void    (*mapping)(int value1, int value2, int* len_ptr, int* info_ptr);

  //!< used for CABAC: refers to actual coding method of each individual syntax element type

  void    (*writing)(struct syntaxelement *, EncodingEnvironmentPtr);


SyntaxElement;


/*! 

 *****************************************************************

 * \brief

 *    ue_v, reads an ue(v) syntax element(ue(v)语法元素), the length in bits is stored in 

 *    the global UsedBits variable(UsedBits是全局变量)

 *

 * \param tracestring

 *    the string for the trace file

 *

 * \param bitstream

 *    the stream to be read from

 *

 * \return

 *    the value of the coded syntax element

 *

 ****************************************************************

 */

int ue_v (char *tracestring, Bitstream *bitstream)

{

  SyntaxElement symbol, *sym=&symbol;


  assert (bitstream->streamBuffer != NULL);

  sym->type = SE_HEADER;

  sym->mapping = linfo_ue;   // Mapping rule

  SYMTRACESTRING(tracestring);

 readSyntaxElement_VLC (sym, bitstream);/*无符号变长指数哥伦布解码*/

  UsedBits+=sym->len;

  return sym->value1;

}


int se_v (char *tracestring, Bitstream *bitstream)

{

  SyntaxElement symbol, *sym=&symbol;


  assert (bitstream->streamBuffer != NULL);

  sym->type = SE_HEADER;

  sym->mapping = linfo_se;   // Mapping rule: signed integer

  SYMTRACESTRING(tracestring);

 readSyntaxElement_VLC (sym, bitstream);

  UsedBits+=sym->len;

  return sym->value1;

}


/*! 

 ****************************************************************

 * \brief

 *    u_v, reads an u(v) syntax element, the length in bits is stored in 

 *    the global UsedBits variable

 *

 * \param LenInBits

 *    length of the syntax element

 *

 * \param bitstream

 *    the stream to be read from

 *

 * \return

 *    the value of the coded syntax element。  do analyze one syntaxElement form bitstream to sym based on rule(u_v,u_1,ue_v...)

 *

 ****************************************************************

 */

int u_v (int LenInBits, char*tracestring, Bitstream *bitstream)

{

  SyntaxElement symbol, *sym=&symbol;


  assert (bitstream->streamBuffer != NULL);

  sym->type = SE_HEADER;//++ SE_HEADER=0

  sym->mapping = linfo_ue;   // Mapping rule。this is dummy

  sym->len = LenInBits;

  SYMTRACESTRING(tracestring);

  readSyntaxElement_FLC (sym, bitstream);/*fixed length code*/

  UsedBits+=sym->len;

  return sym->inf;

};


significant differences between ue_v && u_v is respectively readSyntaxElement_VLC&& readSyntaxElement_FLC


/*!

 ************************************************************************

 * \brief

 *    read next UVLC codeword from UVLC-partition and

 *    map it to the corresponding syntax element

 ************************************************************************

 */

int readSyntaxElement_VLC(SyntaxElement *sym, Bitstream *currStream)

{

  int frame_bitoffset = currStream->frame_bitoffset;

  byte *buf = currStream->streamBuffer;

  int BitstreamLengthInBytes = currStream->bitstream_length;


  sym->len =  GetVLCSymbol (buf, frame_bitoffset, &(sym->inf), BitstreamLengthInBytes);//++ 该处主要是获得哥伦布编码的标志比特位(从后继的码流中第一个比特位开始逐个检查)。

  if (sym->len == -1)

    return -1;

  currStream->frame_bitoffset += sym->len;

  sym->mapping(sym->len,sym->inf,&(sym->value1),&(sym->value2));


#if TRACE

  tracebits(sym->tracestring, sym->len, sym->inf, sym->value1);

#endif


  return 1;

}


/*!

 ************************************************************************

 * \brief

 *    read FLC codeword from UVLC-partition .GetBits is enough,sym->mapping not needed

 ************************************************************************

 */

int readSyntaxElement_FLC(SyntaxElement *sym, Bitstream *currStream)

{

  int frame_bitoffset = currStream->frame_bitoffset;

  byte *buf = currStream->streamBuffer;

  int BitstreamLengthInBytes = currStream->bitstream_length;


  if ((GetBits(buf, frame_bitoffset, &(sym->inf), BitstreamLengthInBytes, sym->len)) < 0)

    return -1;


  currStream->frame_bitoffset += sym->len; // move bitstream pointer

  sym->value1 = sym->inf;


#if TRACE

  tracebits2(sym->tracestring, sym->len, sym->inf);

#endif


  return 1;

}


so let's keep our eyes on functionGetBits() && (GetVLCSymbol , linfo_ue)。


/*!

 ************************************************************************

 * \brief

 *  Reads bits from the bitstream buffer

 *

 * \param buffer

 *    containing VLC-coded data bits

 * \param totbitoffset

 *    bit offset from start of partition

 * \param info

 *    returns value of the read bits

 * \param bytecount

 *    total bytes in bitstream

 * \param numbits

 *    number of bits to read.       read numbits data from buffer[] to *info,totbitoffset is the bit offset from start of  byte

 *

 ************************************************************************

 */

int GetBits (byte buffer[],int totbitoffset,int *info, int bytecount, 

             int numbits)

{


  register int inf;

  long byteoffset;      // byte from start of buffer

  int bitoffset;      // bit from start of byte


  int bitcounter=numbits;


  byteoffset= totbitoffset/8;

  bitoffset= 7-(totbitoffset%8);


  inf=0;

  while (numbits)

  {

    inf <<=1;

    inf |= (buffer[byteoffset] & (0x01<<bitoffset))>>bitoffset;/*read 1 bit by 1 bit,here is to read most significant bit*/

    numbits--;

    bitoffset--;

    if (bitoffset < 0)

    {

      byteoffset++;

      bitoffset += 8;

      if (byteoffset > bytecount)

      {

        return -1;

      }

    }

  }


  *info = inf;

  return bitcounter;           // return absolute offset in bit from start of frame

}  


/*!

 ************************************************************************

 * \brief

 *  read one exp-golomb VLC symbol

 *

 * \param buffer

 *    containing VLC-coded data bits

 * \param totbitoffset

 *    bit offset from start of partition

 * \param  info 

 *    returns the value of the symbol

 * \param bytecount

 *    buffer length

 * \return

 *    bits read

 ************************************************************************

 */

int GetVLCSymbol (byte buffer[],int totbitoffset,int *info, int bytecount)

{


  register int inf;

  long byteoffset;      // byte from start of buffer

  int bitoffset;      // bit from start of byte

  int ctr_bit=0;      // control bit for current bit posision

  int bitcounter=1;

  int len;

  int info_bit;


  byteoffset= totbitoffset/8;

  bitoffset= 7-(totbitoffset%8);

  ctr_bit = (buffer[byteoffset] & (0x01<<bitoffset));   // set up control bit,used to find leading 1 


  len=1;/*len=leading zero number(M) + 1*/

  while (ctr_bit==0)

  {                 // find leading 1 bit

    len++;

    bitoffset-=1;           

    bitcounter++;

    if (bitoffset<0)

    {                 // finish with current byte ?

      bitoffset=bitoffset+8;

      byteoffset++;

    }

    ctr_bit=buffer[byteoffset] & (0x01<<(bitoffset));

  }

    // make infoword

  inf=0;                          // shortest possible code is 1, then info is always 0

  for(info_bit=0;(info_bit<(len-1)); info_bit++)     /*类似GetBits while那段代码*/

  {

    bitcounter++;

    bitoffset-=1;

    if (bitoffset<0)

    {                 // finished with current byte ?

      bitoffset=bitoffset+8;

      byteoffset++;

    }

    if (byteoffset > bytecount)

    {

      return -1;

    }

    inf=(inf<<1);

    if(buffer[byteoffset] & (0x01<<(bitoffset)))

      inf |=1;

  }


  *info = inf;/*here is just to check M bit info,to get real value refer to sym->mapping()*/

  return bitcounter;           // return absolute offset in bit from start of frame

}


so now we know how to read exp-golomb symbol,next we'll find out how to convert the symbol to actual value。


/*!

 ************************************************************************

 * \brief

 *    mapping rule for ue(v) syntax elements

 * \par Input:

 *    length and info

 * \par Output:

 *    number in the code table

 ************************************************************************

 */

void linfo_ue(int len, int info, int *value1, int *dummy)

{

  //++ 参见9.1节 codeNum = pow(2,leadingZeroBits) - 1 + read_bits( leadingZeroBits )

  //++ 所以此处:codeNum=*value1;leadingZeroBits=len/2;info=read_bits( leadingZeroBits )

  //++ info的值即为二进制码字中信息域的十进制值;len/2即为信息域码字长度,当然也等于前导零域的码字长度;


  *value1 = (int)pow(2,(len/2))+info-1; // *value1 = (int)(2<<(len>>1))+info-1;

}


/*!

 ************************************************************************

 * \brief

 *    mapping rule for se(v) syntax elements

 * \par Input:

 *    length and info

 * \par Output:

 *    signed mvd

 ************************************************************************

 */


//++ 参见9.1.1Mapping process for signed Exp-Golomb codes

void linfo_se(int len,  int info, int *value1, int *dummy)

{

  int n;

  n = (int)pow(2,(len/2))+info-1;

  *value1 = (n+1)/2;

  if((n & 0x01)==0)                           // lsb is signed bit。n为偶数的话则value1是负数

    *value1 = -*value1;

}


 follow picture may would be useful to have you understand above codes。





0 0