H.264 bitstream 分析
使用工具: H264VISA,UltraEdit,JM,以及H264 spec.
就用JM裡面附的foreman_part_qcif.yuv
編碼變成 test.264.
使用H264VISA跟UltraEdit分別打開test.264
UltraEdit
H264VISA畫面
可以在UltraEdit搜尋(Ctrl+F) 00
00 00 01 這是每個NAL unit 的啟始碼,一共可以找到5個對應到 H264VISA Header Info的五個NAL unit.
接下來我們從UltraEdit的bitstream搭配spec. 看能不能跟H264VISA搭上.
首先看到前幾個NAL unit
#1 .
00 00 00 01 67 64 00 28 AC E6 0B 13 90
去掉起始碼後 將之轉換成2進位
01100111 01100100 00000000 00101000 10101100 11100110 00001011 00010011 10010000
然後看到Spec的 7.3.1 NAL unit syntax可以將之對應上
forbidden_zero_bit = 0 f(1)
-> 0
nal_ref_idx = 11 u(2) -> 3 : 最高安全性
nal_unit_type = 00111 u(5)
-> 7 : 標明這個NAL unit 是個Sequence parameter
set (PPS)
(看Table
7-1 – NAL unit type codes)
所以其後面就會跟上seq_parameter_set_rbsp()的內容 (7.3.2.1)
profile_idc = 01100100 u(8) -> 100
constraint_set0_flag = 0 u(1) -> 0
constraint_set1_flag = 0 u(1) -> 0
constraint_set2_flag = 0 u(1) -> 0
constraint_set3_flag = 0 u(1) -> 0
reserved_zero_4bits = 0000 u(4) -> 0
level_idc = 00101000 u(8) -> 40
((因為profile_idc = 100
所以會到 if中))
Chroma_format_idc = 010 ue(v) -> 1
bit_depth_luma_minus8 = 1 ue(v) -> 0
bit_depth_chroma_minus8 = 1 ue(v) -> 0
qpprime_y_zero_transform_bypass_flag = 0 u(1) -> 0
seq_caling_matrix_present_flag = 0 u(1) -> 0
log2_max_frame_num_minus4 = 1 ue(v) -> 0
pic_order_cnt_type = 1 ue(v) -> 0
log2_max_pic_order_cnt_lsb_minus4 = 1 ue(v) -> 0
num_ref_frames = 00110 ue(v) -> 5
gaps_in_frame_num_value_allowed_flag = 0 u(1) -> 0
pic_width_in_mbs_minus1 = 0001011 ue(v) -> 10
pic_height_in_map_units_minus1 = 0001001 ue(v) ->8
frame_mbs_only_flag = 1 u(1) -> 1
direct_8x8_inference_flag = 1 u(1) -> 1
frame_cropping_flag = 0 u(1) -> 0
vui_parameter_present_flag = 0 u(1) -> 0
rbsp_trailing_bits 會補到最末位為8個bits, 所以補上 10000
再對照 H264VISA
這NALU done!
接下來下一個是
00 00 00 01 68 E9 4A 38 B0
一樣去掉起始碼之後轉成2進位
01101000 11101001 01001010 00111000 10110000
先看前8個bits (01101000)
forbidden_zero_bit = 0 -> 0
nal_ref_idc = 11 -> 3
nal_unit_type = 01000 -> 8 表示此NAUL type為 Picture
parameter set 即後面跟的rbsp
為pic_parameter_set_rbsp()
接下來看到(7.3.2.2 的 Picture parameter set RBSP syntax)
pic_parameter_set_id = 1 ue(v) -> 0
seq_parameter_set_id =1 ue(v) -> 0
entropy_coding_mode_flag = 1 u(1) -> 1
pic_order_present_flag = 0 u(1) -> 0
num_slice_groups_minus1 = 1 ue(v) -> 0
num_ref_idx_l0_active_minus1 = 00101 ue(v) ->4
num_ref_idx_l1_active_minus1 = 00101 ue(v) ->4
weighted_pred_flag = 0 u(1) -> 0
weighted_bipred_idc = 00 u(2) -> 0
pic_init_qp_minus26 = 1 se(v) -> 0
pic_init_qs_minus26 = 1 se(v) -> 0
chroma_qp_index_offset = 1 se(v) -> 0
deblocking_filtr_control_present_flag = 0 u(1) ->0
constrained_intra_pred_flag = 0 u(1) -> 0
redundant_pic_cnt_present_flag = 0 u(1) -> 0
transform_8x8_mode_flag = 1 u(1) -> 1
pic_scaling_matrix_present_flag = 0 u(1) -> 0
second_chroma_qp_index_offset = 1 se(v) ->0
rbsp_trailing_bits = (rbsp_stop_one_bit)
1 (rbsp_alignment_zero_bit) 0000
只有在second_chroma_qp_index_offset的時候他沒有標出來,不知道是沒寫好還是怎麼了?
接下來看第三個NALU 從00000010h 的 00 00 00 01 開始 到 00000a30h 的 00 00 00 01 之前都是第三個NALU
我們從前面開始看起
00 00 00 01 65 88 84 02 7F EA …
看看除了起始碼之後的轉成二進位的前八碼 也就是 0x65 -> 01100101
forbidden_zero_bit = 0 f(1) -> 0
nal_ref_idc = 11 u(2) -> 3
nal_unit_type = 00101 -> 5 (Coded slice of an IDR picture)
內容如下:
slice_layer_without_partitioning_rbsp(){
slice_header() <-7.3.3
slice_data() <-7.3.4
rbsp_slice_trailing_bits()<-7.3.2.10
}
接下來看 slice_header()的部分
把65之後的轉成二進位變成 10001000 10000100 00000010 01111111 11101010然後對照7.3.3
first_mb_in_slice = 1 ue(v) -> 0
slice_type = 0001000 ue(v) -> 7 (Table 7-6 I slice )
pic_parameter_set_id = 1 ue(v) -> 0
frame_num = 0000 u(v) -> 0
<<這邊frame_num的u(v)長度要看log2_max_frame_num_minus4+4>>
然後後面要跟上一大陀東西, 然後接著要跟slice_data()
slice_data中又有macroblock_layer 7.3.5,macroblock_layer中又有sub_mb_pred 7.3.5.2、mb_pred 7.3.5.1、residual 7.3.5.3,residual中又分為residual_block_cavlc 7.3.5.3.1、residual_block_cabac
7.3.5.3.2
我們就把每個NALU(slice)的前面的nal_ref_idc、nal_unit_type、first_mb_in_slice、slice_type、pic_parameter_set_id、frame_num給解析一下就好.
接下來看到第四個NALU的開頭 : 41 9A 29 92 7F … 對應到 pic 3 (Dec 2)
01000001
10011010 00101001 10010010 01111111
fobidden_zero_bit
= 0 f(1) -> 0
nal_ref_idc
= 10 u(2) -> 2
nal_unit_type
= 00001 u(5) -> 1 (Coded slice of a non-IDR picture)
後面rbsp為slice_layer_without_patitioning_rbsp()
frst_mb_in_slice
= 1 ue(v) -> 0
slice_type
= 00110 ue(v) -> 5 (P slice)
pic_parameter_set_id
= 1 ue(v) -> 0
frame_num
= 0001 u(v) -> 1
第五個NALU開頭 01 9E 45 A9 … 對應到pic 2(Dec 3)
00000001
10011110 01000101 10101001
fobidden_zero_bit
= 0 f(1) ->0
nal_ref_idc
= 00 u(2) -> 0
nal_unit_type
= 00001 u(5) ->1 (Coded slice of a non-IDR picture)
first_mb_in_slice
= 1 ue(v) -> 0
slice_type
= 00111 ue(v) -> 6 (B slice)
pic_parameter_set_id
= 1 ue(v) -> 0
frame_num
= 0010 u(v) -> 2
...
比較簡單的 H264 elemantary stream大概就長成這個樣子,
還會有multislice可能要用多個NALU才能拼成一個Frame,
可以從slice data的header中某些數值去判斷.
詳細的在參照H.264 Spec. 會有更深的了解.