h264码流分析

时间:2023-11-28 15:11:32

---------------------------------------------------------------------------------------------------------------------------

说明:本文档是基于码流文件ducks.264。文档中只有括号里面的参数才会编入码流,如

nC=0;

(coeff_token):ce(v)=1(0,0)

只有coeff_token在码流中有,nC只是为了读者方便。进制。

Writed by Bnian

---------------------------------------------------------------------------------------------------------------------------

SPS层句法

00000000   00 00 00 01 67 42 0028 da 01 40 16 e4 00 00 00

(67 42 00 28)

位(forbidden_zero_bit):         f(1)=0,应为0;

NAL参考ID内容(nal_ref_idc):        u(2)=11(3),NALU最高优先级

(nal_unit_type):         u(5)=00111(7),SPS,序列参数集(seq_parameter_set)

(profile_idc):      u(8)=01000010(66),基本简表

(set0):        u(1)=0,可以不遵从相关简表规定

(set1):        u(1)=0,可以不遵从相关简表规定

(set2):        u(1)=0,可以不遵从相关简表规定

(set3):        u(1)=0,可以不遵从相关简表规定

(reserved_zero_4bits):     u(4)=0000

(level_idc):         u(8)=00101000(40),级别号4.0,处于baseline

100100(da 01 40 16 e4)

(seq_parameter_set_id): ue(v)=1(0),序列参数集ID=0

(log2_max_frame_num_minus4):    ue(v)=1(0),最多帧数=2^4=16

(num_ref_frames):   ue(v)=010(1),参考帧的最大数

(gaps_in_frame_num_value_allowed_flag):    u(1)=0(0),帧数差异标记

(pic_width_in_mbs_minus1):   ue(v)=0000001010000(79)((79+1)*16=1280),宽度

),高度

(frame_mbs_only_flag):   u(1)=1(1),只是帧宏块,没有场宏块

(direct_8x8_inference_flag):    u(1)=1(1),

(frame_cropping_flag):     u(1)=0(0),不存在帧剪切偏移参数

(vui_parameters_present_flag):       u(1)=0(0),没有VUI信息,默认矩阵系数2

(rbsp_trailing_bits):  100

PPS层句法

00000001 01 68 ce38 80 00 00 00 01 65 88 84 27 23 c5 e5

000 10000000(68 ce 38 80)

位(forbidden_zero_bit):         f(1)=0,应为0;

NAL参考ID内容(nal_ref_idc):        u(2)=11(3),NALU最高优先级

(nal_unit_type):         u(5)=01000(8),PPS,图像参数集(pic_parameter_set)

(pic_parameter_set_id):  ue(v)=1(0),图像参数集ID=0

(seq_parameter_set_id): ue(v)=1(0),序列参数集ID=0

(entropy_coding_mode_flag):  u(1)=0(0),CAVLC

(pic_order_present_flag):         u(1)=0(0),

(num_slice_groups_minus1):   ue(v)=1(0),

(num_ref_idx_l0_active_minus1):    ue(v)=1(0),

(num_ref_idx_l1_active_minus1):    ue(v)=1(0),

(weighted_pred_flag):      u(1)=0(0),

(weighted_bipred_idc):     u(2)=00(0),

(pic_init_qp_minus26):     se(v)=1(0)

(pic_init_qs_minus26):      se(v)=1(0)

(chroma_qp_index_offset):       se(v)=1(0)

(deblocking_filter_control_present_flag):        u(1)=0(0),

(constrained_intra_pred_flag):         u(1)=0(0),

(redundant_pic_cnt_present_flag): u(1)=0(0),

(rbsp_trailing_bits):  100000000

I帧

100 00100111(65 88 84 27)

位(forbidden_zero_bit):         f(1)=0,应为0;

NAL参考ID内容(nal_ref_idc):        u(2)=11 (3),NALU最高优先级

(nal_unit_type):u(5)=00101(5),IDR图像的片

(first_mb_in_slice):   ue(v)=1(0),

(slice_type):       ue(v)=0001000(7),I条带,I slice

(pic_parameter_set_id):  ue(v)=1(0),

(frame_num):u(v)=0000(0)

(Idr_pic_id):ue(v)=1(0)

(no_output_of_prior_pics_flag):u(1)=0

(Long_term_reference_flag):u(1)=0

(slice_qp_delta):        se(v)=00100(2),QP=26+2=28

P帧(ducks.Frame2.Mb2)

0003d310   f0 00 00 00 01 41 9a 60 96 db 41 fe 0e aa 50 b6

0(41)

禁止0位(forbidden_zero_bit):         f(1)=0,应为0;

NAL参考ID内容(nal_ref_idc):        u(2)=10(2),NALU优先级

(nal_unit_type):         u(5)=00001(1),不分区、非IDR图像的片

10110 (9a,60,96)

片头句法

(first_mb_in_slice):   ue(v)=1(0),

(slice_type):       ue(v)=00110(5),I条带,P slice

(pic_parameter_set_id):  ue(v)=1(0),

(frame_num):    u(v)=0011(3),

(num_ref_idx_active_override_flag): u(1)=0,不重载参考图像

(ref_pic_list_recordering_flag_10): u(1)=0,不重排序

(adaptive_ref_pic_marking_mode_flag): u(1)=0, 先入先出(FIFO):使用滑动窗的机制,先入先出,在这种模式下没有办法对长期参考帧进行操作

(slice_qp_delta):        se(v)=00100(2),QP=26+2=28

宏块层句法

(mb_skip_run): ue(v)=1(0),不跳

P_L0_L0_8x16

(mb_type):ue(v)=011(2) , 预测模式为P_L0_L0_8x16

(db 41 fe )

宏块的第一个8x16:

(mvd_10[mbPartIdx=0][0][compIdx=0]):se(v)=011(-1),水平运动矢量

(mvd_10[mbPartIdx=0][0][compIdx=1]):se(v)=011(-1),垂直运动矢量

宏块的第二个8x16:

(mvd_10[mbPartIdx=1][0][compIdx=0]):se(v)= 011 (-1),水平运动矢量----mvd和mv是不同滴

(mvd_10[mbPartIdx=1][0][compIdx=1]):se(v)=010(1),垂直运动矢量-------------------

个色度信号全零);

(Mb_qp_delta): se(v)=1(0), QP=28+0=28

残差块CAVLC编码:16*16宏块先分解成4个8*8块(个8*8块中是否有非零系数,高2位指出色度信号Cr和Cb是否有非零系数;coeff_token指出每个4*4块非零系数的个数)

0  1  4   5

2 3  6   7

8  9  12  13

10 11  14 15

残差块句法

先对luma16*16进行编码,在对色度进行编码

块8x8(0):

块4x4(0):

nC=0;

(coeff_token):ce(v)=1(0,0)

块4x4(1):

nA(块4*4(0))=0,nC=Na=0;

(coeff_token):ce(v)=1(0,0)

(0eaa 50 b6)

块4x4(2):

nB(块4*4(0))=0 ,nC= nB=0;

(coeff_token):ce(v)=00000111 (TotalCoff(coeff_token)=2,TrailingOnes(Coeff_token)=0)

Suffixlength=0

:(Level_prefix(1)):ce(v)= 01(1)  Suffixlength=1

由CAVLC残差句法可知,因为以下条件成立:

i==TrailingOnes(coeff_token)&&TrailingOnes(coeff_token)<3

所以levelCode+=2=2;

Level(1)=-2

:(Level_prefix(0)):ce(v)=01(1)

(Level_suffix):u(v)=0(0)

Level(0)=2

Zeroleft=(Total_zeros):ce(v)=101(2)

(Run _before(1):ce(v)= 00(2)    zeroleft=0

Run _before(0)=0,不编码

综上所述,块4x4(2)的矩阵A(反zig-zag)是:

至于怎么变成H264visa软件里面的coef,留待高手去考究,我就不写了。

块4x4(3):

nB(块4*4(1))=0,nA(块4*4(2))=2,nC=(nB+nA+1)>>1=1.5,

(coeff_token):ce(v)=1 (0,0)

因为CodeBlockPatternLuma=CBP%16=13, 二进制是1101,所以块8x8(1)为全0

块8x8(2):

块4x4(8):

nB(块4*4(2))=2,nC=nB=2,

(coeff_token):ce(v)=0100(4,3)

(Trailing_ones_sign_flag(3)):u(1)=0(+)

(Trailing_ones_sign_flag(2)):u(1)=0(+)

(Trailing_ones_sign_flag(1)):u(1)=1(-)

Suffixlength=0

:(Level_prefix(0)):ce(v)=01(1)  Suffixlength=1

Level(0)=-1

Zeroleft=(Total_zeros):ce(v)=101(5)

(Run_before(3)):ce(v)= 10(1)    zeroleft=4

0003d320    44 ed 71 3d 55 fa f5 07 76 b3 41 b5 28 65 ab fe 

(44 ed )

(Run_before(2)):ce(v)=01(2)     zeroleft=2

(Run _before(1)):ce(v)=00(2)     zeroleft=0

必然有Run_before(0)=0,但不编码

综上所述,块4x4(8)的矩阵A(反zig-zag)是:

块4x4(9):

nA(块4*4(8))=4, nB(块4*4(3))=0,nC=(nA+nB+1)>>2=2.5,

(coeff_token):ce(v)=0100 (4,3),

(Trailing_ones_sign_flag(3)):u(1)=1(-)

(Trailing_ones_sign_flag(2)):u(1)=1(-)

(Trailing_ones_sign_flag(1)):u(1)=1(-)

Suffixlength=0

:(Level_prefix(0)):ce(v)=01(1)  Suffixlength=1

Level(0)=-1

Zeroleft=(Total_zeros):ce(v)=101(5)

(71 3d)

(Run_before(3)):ce(v)= 011(2)    zeroleft=3

(Run_before(2)):ce(v)=10(1)     zeroleft=2

(Run _before(1)):ce(v)=00(2)     zeroleft=0

必然有Run_before(0)=0,但不编码

综上所述,块4x4(9)的矩阵A(反zig-zag)是:

块4x4(10):

nB(块4*4(8))=4 ,nC=nB=4,

(coeff_token):ce(v)=1001(6,3)

(Trailing_ones_sign_flag(5)):u(1)=1(-)

(Trailing_ones_sign_flag(4)):u(1)=1(-)

(Trailing_ones_sign_flag(3)):u(1)=1(-)

Suffixlength=0

:(Level_prefix(2)):ce(v)=01(1)  Suffixlength=1

Level(2)=-1

(55 fa )

:(Level_prefix(1)):ce(v)=01(1)

(Level_suffix):u(v)=0(0)         Suffixlength=1

Level(1)=2

:(Level_prefix(0)):ce(v)= 1(0)

(Level_suffix):u(v)=0(0)        Suffixlength=1

Level(0)=1

Zeroleft=(Total_zeros):ce(v)=101 (4)

(Run _before(5)):ce(v)= 11(0)    zeroleft=4

(Run_before(4)):ce(v)=11(0)     zeroleft=4

(Run _before(3)):ce(v)= 10(1)    zeroleft=3

(Run _before(2)):ce(v)=10(1)     zeroleft=2

1(f5 07)

(Run _before(1)):ce(v)= 1(0)    zeroleft=2

Run _before(0)=2,不编码

综上所述,块4x4(10)的矩阵A(反zig-zag)是:

块4x4(11):

nB(块4*4(10))=6, nA块4*4(9))=4 ,nC=(nB+Nb+1)>>1=5.5,

(coeff_token):ce(v)= 1110 (1,1)

(Trailing_ones_sign_flag(0)):u(1)=1(-)

Zeroleft=(Total_zeros):ce(v)=010(2)

Run _before(0))=2,不编码

综上所述,块4x4(11)的矩阵A(反zig-zag)是:

块8x8(3):

块4x4(12):

nA(块4*4(9))=4,nB(块4*4(6))=0,nC=(nA+Nb+1)>>1=2.5,

(coeff_token):ce(v)=0000111(3,0)

1(76 b3 )

Suffixlength=0

:(Level_prefix(2)):ce(v)=01(1)     Suffixlength=0

Level(2)=-2

:(Level_prefix(1)):ce(v)=1(0)

(Level_suffix):u(v)=1(1)         Suffixlength=1

Level(1)=-1

:(Level_prefix(0)):ce(v)= 01(1)

(Level_suffix):u(v)=1(1)

Level(0)=-2

Zeroleft=(Total_zeros):ce(v)=0101(0)

综上所述,块4x4(12)的矩阵A(反zig-zag)是:

块4x4(13):

nA(块4*4(12))=3, nB(块4*4(7))=0,nC=(nB+Nb+1)>>1=2,

(coeff_token):ce(v)=10(1,1)

(Trailing_ones_sign_flag(0)):u(1)=0(+)

Zeroleft=(Total_zeros):ce(v)=1 (0)

综上所述,块4x4(13)的矩阵A(反zig-zag)是:

01(41 b5)

块4x4(14):

nA(块4*4(11))=1, nB(块4*4(12))=3,nC=(nB+Nb+1)>>1=2.5,

(coeff_token):ce(v)=10(1,1)

(Trailing_ones_sign_flag(0)):u(1)=1(-)

Zeroleft=(Total_zeros):ce(v)=0000011 (9)

综上所述,块4x4(14)的矩阵A(反zig-zag)是:

块4x4(15):

nA(块4*4(14))=1, nB(块4*4(13))=1,nC=(nB+Na+1)>>1=1.5,

(coeff_token):ce(v)=01(1,1)

(Trailing_ones_sign_flag(0)):u(1)=1(-)

Zeroleft=(Total_zeros):ce(v)=010(2)

综上所述,块4x4(15)的矩阵A(反zig-zag)是:

Chroma DC

因为4:2:0,所以nC=-1,

(coeff_token):ce(v)=1 (1,1)

(28 65)

(Trailing_ones_sign_flag(0)):u(1)=0(+)

Zeroleft=(Total_zeros):ce(v)=01 (2)

综上所述,UDC2X2的矩阵A(反zig-zag)是:

页,反量化过程参考《H.264变换和量化的分析。pdf》楼剑,陆亮

(coeff_token):ce(v)=01 (0,0)

综上所述,V  DC2X2的矩阵A(反zig-zag)是:

Chroma AC

U:

块4x4(18)

nC=0,

(coeff_token):ce(v)=000011(4,3)

(Trailing_ones_sign_flag(3)):u(1)=0(+)

(Trailing_ones_sign_flag(2)):u(1)=0(+)

(Trailing_ones_sign_flag(1)):u(1)=1(-)

Suffixlength=0

:(Level_prefix(0)):ce(v)=01(1)     Suffixlength=1

Level(0)=-1

(ab fe)

Zeroleft=(Total_zeros):ce(v)=101(5) (特别注意,此处并没有算左上角哪一位)

(Run _before(3)):ce(v)= 010(3)    zeroleft=2

(Run_before(2)):ce(v)=1(0)     zeroleft=2

(Run _before(1)):ce(v)= 1(0)    zeroleft=2

Run _before(0)=2,不编码

综上所述,块4x4(18)的矩阵A(反zig-zag)是(已经把DC部分写进去了):

块4x4(19)

nA(块4*4(18))=4,nC=(nA)=4

(coeff_token):ce(v)=1111(0,0)

综上所述,块4x4(19)的矩阵A(反zig-zag)是(已经把DC部分写进去了):

块4x4(20)

nB(块4*4(18))=4,nC=(nB)=4

(coeff_token):ce(v)=1110(1,1)

0003d330    84 7ff2 d2 a2 9c 87 54 7b 43 30 44 b4 bc 94 1a

1(84 7f)

(Trailing_ones_sign_flag(0)):u(1)=1(-)

Zeroleft=(Total_zeros):ce(v)=000010(8)(特别注意,此处并没有算左上角哪一位)

综上所述,块4x4(20)的矩阵A(反zig-zag)是(已经把DC部分写进去了):

块4x4(21)

nB(块4*4(19))=0,nB(块4*4(20))=1,nC=(nB+Na+1)>>2=1

(coeff_token):ce(v)=001(2,2)

(Trailing_ones_sign_flag(1)):u(1)=1(-)

(Trailing_ones_sign_flag(0)):u(1)=1(-)

Zeroleft=(Total_zeros):ce(v)=111(0)(特别注意,此处并没有算左上角哪一位)

综上所述,块4x4(21)的矩阵A(反zig-zag)是(已经把DC部分写进去了):

P_ 8x8ref0(ducks.Frame2.Mb2)

(mb_skip_run): ue(v)=1(0),不跳

(mb_type):ue(v)=00101(4) , 预测模式为P_8x8ref0

(e9 98 ed56 42 bb 63)

每个块8X8的预测类型:

(sub_mb_type(0)):ue(v)=011(2),预测模式为P_L0_4X8

(sub_mb_type(1)): ue(v)=1(0), 预测模式为P_L0_8X8

(sub_mb_type(2)) :ue(v)=010(1), 预测模式为P_L0_8X4

(sub_mb_type(3)) :ue(v)=011(1), 预测模式为P_L0_4X8

块8x8(0):

(mvd_10[mbPartIdx=0][submbpartidx=0][compIdx=0]):se(v)=00110(3),水平运动矢量

(mvd_10[mbPartIdx=0][0][compIdx=1]):se(v)=00111(-3),垂直运动矢量

(mvd_10[mbPartIdx=0][1][compIdx=0]):se(v)=011(-1),水平运动矢量

(mvd_10[mbPartIdx=0][1][compIdx=1]):se(v)=010(1),垂直运动矢量

块8x8(1):

(mvd_10[mbPartIdx=1][0][compIdx=0]):se(v)=1(0),水平运动矢量

(mvd_10[mbPartIdx=1][0][compIdx=1]):se(v)=010(1),垂直运动矢量

块8x8(2):

(mvd_10[mbPartIdx=2][0][compIdx=0]):se(v)=1(0),水平运动矢量

(mvd_10[mbPartIdx=2][0][compIdx=1]):se(v)=1(0),垂直运动矢量

10000(42 bb 6330)

(mvd_10[mbPartIdx=2][1][compIdx=0]):se(v)=00100(2),水平运动矢量

(mvd_10[mbPartIdx=2][1][compIdx=1]):se(v)=00101(-2),垂直运动矢量

块8x8(3):

(mvd_10[mbPartIdx=3][0][compIdx=0]):se(v)=011(-1),水平运动矢量

(mvd_10[mbPartIdx=3][0][compIdx=1]):se(v)=1(0),垂直运动矢量

(mvd_10[mbPartIdx=3][1][compIdx=0]):se(v)=011(-1),水平运动矢量

(mvd_10[mbPartIdx=3][1][compIdx=1]):se(v)=011(-1),垂直运动矢量

(Coded_block_pattern):me(v)=0001100(15),CBP=15,CodeBlockPatternLuma=CBP%16=15,CodeBlockPatternLuma=CBP/16=0(每个8*8块都有非零系数,色度信号Cr和Cb全零);

(Mb_qp_delta):se(v)=1(0), QP=28+0=28

下面主要来讲讲在宏块层句法中,各种类型宏块(intra_4x4,intra_16x16,p_8x8ref0和非p_8x8ref0的inter)中的区别:

1、   sub_mb_pred(mb_type)和mb_pred(mb_type)的选择:只有p_8x8ref0时,选择sub_mb_pred(mb_type)。p_8x8ref0类型:16x16块分为4个8x8块,然后每个8x8块还会细分成更小的块。所以在sub_mb_pred(mb_type)中首先要给出每一个更小的块的sub_mb_type,然后给出每一个更小的块的运动矢量(这步和mb_pred(mb_type)是一样的)。而当选择mb_pred(mb_type)时,若宏块是intra类型时,就不会有运动矢量的说法。而是给出了另外几个参数:

2、   残差句法中的特殊情况:

若宏块类型是intre6x6时,先要对亮度DC进行CAVLC变换,这一点在其他类型中是没有的