1 在H.264的标准文档中,定义了如下的函数用来处理语法元素:
如下描述符规定了每个语法元素的解析处理。对于某些语法元素,需要使用通过竖线分开的两个描述符。在
这些情况下,左边的描述符在entropy_coding_mode_flag 等于0 的时候使用,右边的描述符在
entropy_coding_mode_flag等于1的时候使用。
— ae(v):上下文自适应算术熵编码语法元素。该描述符的解析过程在9.3节中规定。
— b(8):任意形式的8比特字节。该描述符的解析过程通过函数read_bits( 8 )的返回值来规定。
— ce(v):左位在先的上下文自适应可变长度熵编码语法元素。该描述符的解析过程在9.2节中规定。
— f(n):n位固定模式比特串(由左至右),左位在先, 该描述符的解析过程通过函数read_bits( n )的返
回值来规定。
— i(n):使用n比特的有符号整数。在语法表中,如果n是‘v’,其比特数由其它语法元素值确定。解析
过程由函数read_bits(n)的返回值规定,该返回值用最高有效位在前的2的补码表示。
— me(v):映射的指数哥伦布码编码的语法元素,左位在先。解析过程在9.1中定义。
— se(v):有符号整数指数哥伦布码编码的语法元素位在先。解析过程在9.1中定义。
— te(v):舍位指数哥伦布码编码语法元素,左位在先。解析过程在9.1中定义。
— u(n):n位无符号整数。在语法表中,如果n是‘v’,其比特数由其它语法元素值确定。解析过程由函
数read_bits(n)的返回值规定,该返回值用最高有效位在前的二进制表示。
— ue(v):无符号整数指数哥伦布码编码的语法元素,左位在先。解析过程在9.1中定义。
2 在JM代码中,这些函数的具体实现如下,下面我们逐个来分析下。
1) u(v)语法元素
/*!
*************************************************************************************
* \brief
* ue_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 tracestring
* the string for the trace file
*
* \param bitstream
* the stream to be read from
*
* \return
* the value of the coded syntax element
*
*************************************************************************************
*/
int u_v (int LenInBits, char*tracestring, Bitstream *bitstream) // 语法元素的长度(单位是位),给trace文件的字符串,要读入的码流;函数的返回值为编码的语法元素的值
{
SyntaxElement symbol, *sym=&symbol;
assert (bitstream->streamBuffer != NULL);
sym->type = SE_HEADER;
sym->mapping = linfo_ue; // Mapping rle // mapping是一个函数指针成员
sym->len = LenInBits;
SYMTRACESTRING(tracestring);
readSyntaxElement_FLC (sym, bitstream);
UsedBits+=sym->len;
return sym->inf;
};
看在sps的语法元素profile_idc的解析中是如何调用的:
sps->profile_idc = u_v (8, "SPS: profile_idc" , s);
我们来分析下这个readSyntaxElement_FLC(sym,bitstream);这个函数:
/*!
************************************************************************
* \brief
* read FLC codeword from UVLC-partition
************************************************************************
*/
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;
}
分析下GetBits这个函数:
/*!
************************************************************************
* \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
*
************************************************************************
*/
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;
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
}