编码foreman_part_qcif.yuv的第一帧,分析生成的码流,为了便于分析,我们需要打开JM8.6编码器中的trace_enc.txt文件记录功能,怎么开启呢?在JM8.6 encoder的define.h文件中有这样的代码:
#if defined _DEBUG
#define TRACE 0 //!< 0:Trace off 1:Trace on
#else
#define TRACE 0 //!< 0:Trace off 1:Trace on
#endif
只需要把代码改为下面的形式就可以开启trace_enc.txt文件的功能:
#if defined _DEBUG
#define TRACE 1 //!< 0:Trace off 1:Trace on
#else
#define TRACE 0 //!< 0:Trace off 1:Trace on
#endif
trace_enc.txt文件对码流分析具有很大的作用,运行一下程序,看看trace_enc.txt中的内容就知道了. 我们知道,码流在test.264文件中,如果要看的话,需要用UltrlEdit来看其中二进制比特对应的十六进制,而且不能复制,这样就不太方便了. 为了便于分析码流,便于观看,本人把码流写成对应的字符形式,直观,而且可以复制. 具体在代码中的操作为:
void printDataIntoFile(FILE *fp, int i)
{
char str[20];
int r = 2;
int length;
int j;
assert(i >= 0 && i <= 255);
itoa(i, str, r); // 重要函数(转成二进制)
if(i <= 15)
fprintf(fp, "0%X: ", i);
else
fprintf(fp, "%X: ", i);
length = strlen(str);
for(j = length; j < 8; j++)
fprintf(fp, "0"); // 前面补0
fprintf(fp, "%s <---", str);
fprintf(fp, "(%3d)\n", i);
}
/*!
********************************************************************************************
* \brief
* Writes a NALU to the Annex B Byte Stream
*
* \return
* number of bits written
*
********************************************************************************************
*/
int WriteAnnexbNALU (NALU_t *n)
{
int BitsWritten = 0;
int i;
assert (n != NULL);
assert (n->forbidden_bit == 0);
assert (f != NULL);
assert (n->startcodeprefix_len == 3 || n->startcodeprefix_len == 4);
// printf ("WriteAnnexbNALU: writing %d bytes w/ startcode_len %d\n", n->len+1, n->startcodeprefix_len);
if (n->startcodeprefix_len > 3)
{
putc (0, f);
BitsWritten =+ 8;
printDataIntoFile(fp, 0);
}
putc (0, f);
printDataIntoFile(fp, 0); // 写到myData.txt中
putc (0, f);
printDataIntoFile(fp, 0); // 写到myData.txt中
putc (1, f);
printDataIntoFile(fp, 1); // 写到myData.txt中
BitsWritten += 24;
n->buf[0] =
n->forbidden_bit << 7 |
n->nal_reference_idc << 5 |
n->nal_unit_type;
// printf ("First Byte %x, nal_ref_idc %x, nal_unit_type %d\n", n->buf[0], n->nal_reference_idc, n->nal_unit_type);
if (n->len != fwrite (n->buf, 1, n->len, f))
{
printf ("Fatal: cannot write %d bytes to bitstream file, exit (-1)\n", n->len);
exit (-1);
}
BitsWritten += n->len * 8;
for(i = 0; i < n->len; i++ )
{
// 写到myData.txt中
printDataIntoFile(fp, n->buf[i]);
}
fflush (f);
#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",
n->startcodeprefix_len == 4?"long":"short", n->len, n->forbidden_bit, n->nal_reference_idc, n->nal_unit_type);
fflush (p_trace);
#endif
return BitsWritten;
}
在myData.txt中的部分内容为:
00: 00000000 <---( 0)
00: 00000000 <---( 0)
00: 00000000 <---( 0)
01: 00000001 <---( 1)
67: 01100111 <---(103)
42: 01000010 <---( 66)
00: 00000000 <---( 0)
1E: 00011110 <---( 30)
............
而trace_enc.txt中的部分内容为:
@0 SPS: profile_idc 01000010 ( 66)
@8 SPS: constrained_set0_flag 0 ( 0)
@9 SPS: constrained_set1_flag 0 ( 0)
@10 SPS: constrained_set2_flag 0 ( 0)
@11 SPS: reserved_zero 00000 ( 0)
@16 SPS: level_idc 00011110 ( 30)
............
经本人严格对比后发现:myData.txt中的内容和trace_enc.txt中的内容实际上是高度一致的. 下面参照trace_enc.txt的内容来解析码流. (由于博客的篇幅限制,故只作简要解析)
00000000
00000000
00000000
00000001 这些表示接下来的比特流是一个NALU(SPS对应的NALU)
0 forbidden_zero = 0--->0
11 nal_ref_idc = 11--->3
00111 nal_unit_type = 00111--->7
对照trace_enc.txt, 继续分析:
01000010 @0 SPS: profile_idc 01000010 ( 66)
0 @8 SPS: constrained_set0_flag 0 ( 0)
0 @9 SPS: constrained_set1_flag 0 ( 0)
0 @10 SPS: constrained_set2_flag 0 ( 0)
00000 @11 SPS: reserved_zero 00000 ( 0)
00011110 @16 SPS: level_idc 00011110 ( 30)
111100010110000101100010011000
10 补齐 (SODBtoRBSP) 第一帧共有3处补齐,从代码中可以看到SODBtoRBSP函数刚好被调用3次
00000000000000000000000000000001011010001100100010100001010000111000 PPS
1000 补齐 (SODBtoRBSP)
00000000000000000000000000000001011001011000100010000100000000100 SliceHeader
*********** Pic: 0 (I/P) MB: 0 Slice: 0 **********
1100011011000010111110000000000000111010110111011111100000000000111001111100000110000010111011100110000111100100001010000111011011001011010010001001001011101010011111000010110000001101001100000000111111111111001111100101111100101100000000010101001101010010111010011100110011011100000100101010101000110100000010110010001011001011100100001001010110011100010000001001111110000000100001000001011001001001100011010101100001001001111000001110000000010010000011101001000110111111001000100011101101010011111010100001010011011110100001110101101011111100110010100110010011110001011000000111001001000001100000000101110100011011010010011111001011100111000000100000101000111010100001000101000111001011111111
*********** Pic: 0 (I/P) MB: 98 Slice: 0 **********
110011101110111010010111011111111001000010101110011011011100110111010001101010000011101001001101010010110000100011010010011100011011111101110010011100101100001001000001100101010000110011011010010001110011010111110101100000111000111100000100110011111110101001010000010100000011001101000001100110011111101011101000101100111010110000000101100000101010011010000101001111010101110100111000000110101101000110010110001110000110000011111110111000110110011000001110011101
100 补齐 (SODBtoRBSP)