H264系列十八 解析NALU(SPS,PPS,IDR)实例

节选自一步一步解析H.264码流的NALU(SPS,PSS,IDR)

我看编/解码有个习惯就是从编/解码出来的数据文件下手。因为无论如何复杂,最终的文件(字节流)肯定是符合某种规范的。

这里我查看码流用的工具是StreamEye,码流文件是foreman_part_qcif.yuv编码得来的。这些工具怎么用就不介绍了,无非就是看视频有哪些/类帧组成,各个属性(Header/MacroBlock/Picture)是什么。

下面这段信息是从Headers Info拷贝出来的,粗看下它是SPS,PPS和Slice Header,那这有什么用,这些数据是什么意思?

[00]seq_parameter_set_rbsp() {
  profile_idc                                    = 66 (Baseline)
  constraint_set0_flag                           = 0 (false)
  constraint_set1_flag                           = 0 (false)
  constraint_set2_flag                           = 0 (false)
  constraint_set3_flag                           = 0 (false)
  constraint_set4_flag                           = 0 (false)
  constraint_set5_flag                           = 0 (false)
  reserved_zero_2bits                            = 0
  level_idc                                      = 30
  seq_parameter_set_id                           = 0
  if (profile_idc == 100 || profile_idc == 110 ||
  profile_idc == 122 || profile_idc == 144) {
    chroma_format_idc                            = na
    if (chroma_format_idc == 3)
      separate_colour_plane_flag                 = na
    bit_depth_luma_minus8                        = na
    bit_depth_chroma_minus8                      = na
    qpprime_y_zero_transform_bypass_flag         = na
    seq_scaling_matrix_present_flag              = na
    if (seq_scaling_matrix_present_flag)
      for (i = 0; i < 8; i++) {
        seq_scaling_list_present_flag[0]         = na
        if (seq_scaling_list_present_flag[0])
          scaling_list_4x4[00]                   = na
          scaling_list_4x4[01]                   = na
          scaling_list_4x4[02]                   = na
          scaling_list_4x4[03]                   = na
          scaling_list_4x4[04]                   = na
          scaling_list_4x4[05]                   = na
          scaling_list_4x4[06]                   = na
          scaling_list_4x4[07]                   = na
          scaling_list_4x4[08]                   = na
          scaling_list_4x4[09]                   = na
          scaling_list_4x4[10]                   = na
          scaling_list_4x4[11]                   = na
          scaling_list_4x4[12]                   = na
          scaling_list_4x4[13]                   = na
          scaling_list_4x4[14]                   = na
          scaling_list_4x4[15]                   = na
        seq_scaling_list_present_flag[1]         = na
        if (seq_scaling_list_present_flag[1])
          scaling_list_4x4[00]                   = na
          scaling_list_4x4[01]                   = na
          scaling_list_4x4[02]                   = na
          scaling_list_4x4[03]                   = na
          scaling_list_4x4[04]                   = na
          scaling_list_4x4[05]                   = na
          scaling_list_4x4[06]                   = na
          scaling_list_4x4[07]                   = na
          scaling_list_4x4[08]                   = na
          scaling_list_4x4[09]                   = na
          scaling_list_4x4[10]                   = na
          scaling_list_4x4[11]                   = na
          scaling_list_4x4[12]                   = na
          scaling_list_4x4[13]                   = na
          scaling_list_4x4[14]                   = na
          scaling_list_4x4[15]                   = na
        seq_scaling_list_present_flag[2]         = na
        if (seq_scaling_list_present_flag[2])
          scaling_list_4x4[00]                   = na
          scaling_list_4x4[01]                   = na
          scaling_list_4x4[02]                   = na
          scaling_list_4x4[03]                   = na
          scaling_list_4x4[04]                   = na
          scaling_list_4x4[05]                   = na
          scaling_list_4x4[06]                   = na
          scaling_list_4x4[07]                   = na
          scaling_list_4x4[08]                   = na
          scaling_list_4x4[09]                   = na
          scaling_list_4x4[10]                   = na
          scaling_list_4x4[11]                   = na
          scaling_list_4x4[12]                   = na
          scaling_list_4x4[13]                   = na
          scaling_list_4x4[14]                   = na
          scaling_list_4x4[15]                   = na
        seq_scaling_list_present_flag[3]         = na
        if (seq_scaling_list_present_flag[3])
          scaling_list_4x4[00]                   = na
          scaling_list_4x4[01]                   = na
          scaling_list_4x4[02]                   = na
          scaling_list_4x4[03]                   = na
          scaling_list_4x4[04]                   = na
          scaling_list_4x4[05]                   = na
          scaling_list_4x4[06]                   = na
          scaling_list_4x4[07]                   = na
          scaling_list_4x4[08]                   = na
          scaling_list_4x4[09]                   = na
          scaling_list_4x4[10]                   = na
          scaling_list_4x4[11]                   = na
          scaling_list_4x4[12]                   = na
          scaling_list_4x4[13]                   = na
          scaling_list_4x4[14]                   = na
          scaling_list_4x4[15]                   = na
        seq_scaling_list_present_flag[4]         = na
        if (seq_scaling_list_present_flag[4])
          scaling_list_4x4[00]                   = na
          scaling_list_4x4[01]                   = na
          scaling_list_4x4[02]                   = na
          scaling_list_4x4[03]                   = na
          scaling_list_4x4[04]                   = na
          scaling_list_4x4[05]                   = na
          scaling_list_4x4[06]                   = na
          scaling_list_4x4[07]                   = na
          scaling_list_4x4[08]                   = na
          scaling_list_4x4[09]                   = na
          scaling_list_4x4[10]                   = na
          scaling_list_4x4[11]                   = na
          scaling_list_4x4[12]                   = na
          scaling_list_4x4[13]                   = na
          scaling_list_4x4[14]                   = na
          scaling_list_4x4[15]                   = na
        seq_scaling_list_present_flag[5]         = na
        if (seq_scaling_list_present_flag[5])
          scaling_list_4x4[00]                   = na
          scaling_list_4x4[01]                   = na
          scaling_list_4x4[02]                   = na
          scaling_list_4x4[03]                   = na
          scaling_list_4x4[04]                   = na
          scaling_list_4x4[05]                   = na
          scaling_list_4x4[06]                   = na
          scaling_list_4x4[07]                   = na
          scaling_list_4x4[08]                   = na
          scaling_list_4x4[09]                   = na
          scaling_list_4x4[10]                   = na
          scaling_list_4x4[11]                   = na
          scaling_list_4x4[12]                   = na
          scaling_list_4x4[13]                   = na
          scaling_list_4x4[14]                   = na
          scaling_list_4x4[15]                   = na
        seq_scaling_list_present_flag[6]         = na
        if (seq_scaling_list_present_flag[6])
          scaling_list_8x8[00]                   = na
          scaling_list_8x8[01]                   = na
          scaling_list_8x8[02]                   = na
          scaling_list_8x8[03]                   = na
          scaling_list_8x8[04]                   = na
          scaling_list_8x8[05]                   = na
          scaling_list_8x8[06]                   = na
          scaling_list_8x8[07]                   = na
          scaling_list_8x8[08]                   = na
          scaling_list_8x8[09]                   = na
          scaling_list_8x8[10]                   = na
          scaling_list_8x8[11]                   = na
          scaling_list_8x8[12]                   = na
          scaling_list_8x8[13]                   = na
          scaling_list_8x8[14]                   = na
          scaling_list_8x8[15]                   = na
          scaling_list_8x8[16]                   = na
          scaling_list_8x8[17]                   = na
          scaling_list_8x8[18]                   = na
          scaling_list_8x8[19]                   = na
          scaling_list_8x8[20]                   = na
          scaling_list_8x8[21]                   = na
          scaling_list_8x8[22]                   = na
          scaling_list_8x8[23]                   = na
          scaling_list_8x8[24]                   = na
          scaling_list_8x8[25]                   = na
          scaling_list_8x8[26]                   = na
          scaling_list_8x8[27]                   = na
          scaling_list_8x8[28]                   = na
          scaling_list_8x8[29]                   = na
          scaling_list_8x8[30]                   = na
          scaling_list_8x8[31]                   = na
          scaling_list_8x8[32]                   = na
          scaling_list_8x8[33]                   = na
          scaling_list_8x8[34]                   = na
          scaling_list_8x8[35]                   = na
          scaling_list_8x8[36]                   = na
          scaling_list_8x8[37]                   = na
          scaling_list_8x8[38]                   = na
          scaling_list_8x8[39]                   = na
          scaling_list_8x8[40]                   = na
          scaling_list_8x8[41]                   = na
          scaling_list_8x8[42]                   = na
          scaling_list_8x8[43]                   = na
          scaling_list_8x8[44]                   = na
          scaling_list_8x8[45]                   = na
          scaling_list_8x8[46]                   = na
          scaling_list_8x8[47]                   = na
          scaling_list_8x8[48]                   = na
          scaling_list_8x8[49]                   = na
          scaling_list_8x8[50]                   = na
          scaling_list_8x8[51]                   = na
          scaling_list_8x8[52]                   = na
          scaling_list_8x8[53]                   = na
          scaling_list_8x8[54]                   = na
          scaling_list_8x8[55]                   = na
          scaling_list_8x8[56]                   = na
          scaling_list_8x8[57]                   = na
          scaling_list_8x8[58]                   = na
          scaling_list_8x8[59]                   = na
          scaling_list_8x8[60]                   = na
          scaling_list_8x8[61]                   = na
          scaling_list_8x8[62]                   = na
          scaling_list_8x8[63]                   = na
        seq_scaling_list_present_flag[7]         = na
        if (seq_scaling_list_present_flag[7])
          scaling_list_8x8[00]                   = na
          scaling_list_8x8[01]                   = na
          scaling_list_8x8[02]                   = na
          scaling_list_8x8[03]                   = na
          scaling_list_8x8[04]                   = na
          scaling_list_8x8[05]                   = na
          scaling_list_8x8[06]                   = na
          scaling_list_8x8[07]                   = na
          scaling_list_8x8[08]                   = na
          scaling_list_8x8[09]                   = na
          scaling_list_8x8[10]                   = na
          scaling_list_8x8[11]                   = na
          scaling_list_8x8[12]                   = na
          scaling_list_8x8[13]                   = na
          scaling_list_8x8[14]                   = na
          scaling_list_8x8[15]                   = na
          scaling_list_8x8[16]                   = na
          scaling_list_8x8[17]                   = na
          scaling_list_8x8[18]                   = na
          scaling_list_8x8[19]                   = na
          scaling_list_8x8[20]                   = na
          scaling_list_8x8[21]                   = na
          scaling_list_8x8[22]                   = na
          scaling_list_8x8[23]                   = na
          scaling_list_8x8[24]                   = na
          scaling_list_8x8[25]                   = na
          scaling_list_8x8[26]                   = na
          scaling_list_8x8[27]                   = na
          scaling_list_8x8[28]                   = na
          scaling_list_8x8[29]                   = na
          scaling_list_8x8[30]                   = na
          scaling_list_8x8[31]                   = na
          scaling_list_8x8[32]                   = na
          scaling_list_8x8[33]                   = na
          scaling_list_8x8[34]                   = na
          scaling_list_8x8[35]                   = na
          scaling_list_8x8[36]                   = na
          scaling_list_8x8[37]                   = na
          scaling_list_8x8[38]                   = na
          scaling_list_8x8[39]                   = na
          scaling_list_8x8[40]                   = na
          scaling_list_8x8[41]                   = na
          scaling_list_8x8[42]                   = na
          scaling_list_8x8[43]                   = na
          scaling_list_8x8[44]                   = na
          scaling_list_8x8[45]                   = na
          scaling_list_8x8[46]                   = na
          scaling_list_8x8[47]                   = na
          scaling_list_8x8[48]                   = na
          scaling_list_8x8[49]                   = na
          scaling_list_8x8[50]                   = na
          scaling_list_8x8[51]                   = na
          scaling_list_8x8[52]                   = na
          scaling_list_8x8[53]                   = na
          scaling_list_8x8[54]                   = na
          scaling_list_8x8[55]                   = na
          scaling_list_8x8[56]                   = na
          scaling_list_8x8[57]                   = na
          scaling_list_8x8[58]                   = na
          scaling_list_8x8[59]                   = na
          scaling_list_8x8[60]                   = na
          scaling_list_8x8[61]                   = na
          scaling_list_8x8[62]                   = na
          scaling_list_8x8[63]                   = na
        }
      }
    }
  log2_max_frame_num_minus4                      = 0 (4)
  pic_order_cnt_type                             = 0
  if (pic_order_cnt_type == 0)
    log2_max_pic_order_cnt_lsb_minus4            = 0 (4)
  else if (pic_order_cnt_type == 1) {
    delta_pic_order_always_zero_flag             = na
    offset_for_non_ref_pic                       = na
    offset_for_top_to_bottom_field               = na
    num_ref_frames_in_pic_order_cnt_cycle        = na
    for(i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++)
    }
  max_num_ref_frames                             = 10
  gaps_in_frame_num_value_allowed_flag           = 0
  pic_width_in_mbs_minus1                        = 10 (176)
  pic_height_in_map_units_minus1                 = 8 (144)
  frame_mbs_only_flag                            = 1
  if (!frame_mbs_only_flag)
    mb_adaptive_frame_field_flag                 = na
  direct_8x8_inference_flag                      = 0 (false)
  frame_cropping_flag                            = 0 (false)
  if (frame_cropping_flag) {
    frame_crop_left_offset                       = na
    frame_crop_right_offset                      = na
    frame_crop_top_offset                        = na
    frame_crop_bottom_offset                     = na
    }
  vui_parameters_present_flag                    = 0 (false)
  if (vui_parameters_present_flag)
    }
    vui_parameters()
  }
[00]pic_parameter_set_rbsp() {
  pic_parameter_set_id                           = 0
  seq_parameter_set_id                           = 0
  entropy_coding_mode_flag                       = 0 (CAVLC)
  pic_order_present_flag                         = 0 (false)
  num_slice_groups_minus1                        = 0 (1)
  if (num_slice_groups_minus1 > 0) {
    slice_group_map_type                         = na
    if (slice_group_map_type == 0)
      for (iGroup = 0; iGroup <= num_slice_groups_minus1; iGroup++) {
      }
    else if (slice_group_map_type == 2)
      for (iGroup = 0; iGroup < num_slice_groups_minus1; iGroup++) {
      }
    else if ((slice_group_map_type == 3) || 
    (slice_group_map_type == 4) || (slice_group_map_type == 5)) {
      slice_group_change_direction_flag          = na
      slice_group_change_rate_minus1             = na
    } else if (slice_group_map_type == 6) {
      pic_size_in_map_units_minus1               = na
      for (i = 0; i <= pic_size_in_map_units_minus1; i++)
      }
    }
  num_ref_idx_l0_active_minus1                   = 9 (10)
  num_ref_idx_l1_active_minus1                   = 9 (10)
  weighted_pred_flag                             = 0 (false)
  weighted_bipred_idc                            = 0
  pic_init_qp_minus26                            = 0 (26)
  pic_init_qs_minus26                            = 0 (26)
  chroma_qp_index_offset                         = 0
  deblocking_filter_control_present_flag         = 0 (false)
  constrained_intra_pred_flag                    = 0 (false)
  redundant_pic_cnt_present_flag                 = 0 (false)
  }
  if (more_rbsp_data()) {
    transform_8x8_mode_flag                      = na
    pic_scaling_matrix_present_flag              = na
    if (pic_scaling_matrix_present_flag) {
      for (i = 0; i < 6 + 2 * transform_8x8_mode_flag; i++) {
        pic_scaling_list_present_flag[0]         = na
        if (pic_scaling_list_present_flag[0])
          scaling_list_4x4[0][00]                = na
          scaling_list_4x4[0][01]                = na
          scaling_list_4x4[0][02]                = na
          scaling_list_4x4[0][03]                = na
          scaling_list_4x4[0][04]                = na
          scaling_list_4x4[0][05]                = na
          scaling_list_4x4[0][06]                = na
          scaling_list_4x4[0][07]                = na
          scaling_list_4x4[0][08]                = na
          scaling_list_4x4[0][09]                = na
          scaling_list_4x4[0][10]                = na
          scaling_list_4x4[0][11]                = na
          scaling_list_4x4[0][12]                = na
          scaling_list_4x4[0][13]                = na
          scaling_list_4x4[0][14]                = na
          scaling_list_4x4[0][15]                = na
        pic_scaling_list_present_flag[1]         = na
        if (pic_scaling_list_present_flag[1])
          scaling_list_4x4[1][00]                = na
          scaling_list_4x4[1][01]                = na
          scaling_list_4x4[1][02]                = na
          scaling_list_4x4[1][03]                = na
          scaling_list_4x4[1][04]                = na
          scaling_list_4x4[1][05]                = na
          scaling_list_4x4[1][06]                = na
          scaling_list_4x4[1][07]                = na
          scaling_list_4x4[1][08]                = na
          scaling_list_4x4[1][09]                = na
          scaling_list_4x4[1][10]                = na
          scaling_list_4x4[1][11]                = na
          scaling_list_4x4[1][12]                = na
          scaling_list_4x4[1][13]                = na
          scaling_list_4x4[1][14]                = na
          scaling_list_4x4[1][15]                = na
        pic_scaling_list_present_flag[2]         = na
        if (pic_scaling_list_present_flag[2])
          scaling_list_4x4[2][00]                = na
          scaling_list_4x4[2][01]                = na
          scaling_list_4x4[2][02]                = na
          scaling_list_4x4[2][03]                = na
          scaling_list_4x4[2][04]                = na
          scaling_list_4x4[2][05]                = na
          scaling_list_4x4[2][06]                = na
          scaling_list_4x4[2][07]                = na
          scaling_list_4x4[2][08]                = na
          scaling_list_4x4[2][09]                = na
          scaling_list_4x4[2][10]                = na
          scaling_list_4x4[2][11]                = na
          scaling_list_4x4[2][12]                = na
          scaling_list_4x4[2][13]                = na
          scaling_list_4x4[2][14]                = na
          scaling_list_4x4[2][15]                = na
        pic_scaling_list_present_flag[3]         = na
        if (pic_scaling_list_present_flag[3])
          scaling_list_4x4[3][00]                = na
          scaling_list_4x4[3][01]                = na
          scaling_list_4x4[3][02]                = na
          scaling_list_4x4[3][03]                = na
          scaling_list_4x4[3][04]                = na
          scaling_list_4x4[3][05]                = na
          scaling_list_4x4[3][06]                = na
          scaling_list_4x4[3][07]                = na
          scaling_list_4x4[3][08]                = na
          scaling_list_4x4[3][09]                = na
          scaling_list_4x4[3][10]                = na
          scaling_list_4x4[3][11]                = na
          scaling_list_4x4[3][12]                = na
          scaling_list_4x4[3][13]                = na
          scaling_list_4x4[3][14]                = na
          scaling_list_4x4[3][15]                = na
        pic_scaling_list_present_flag[4]         = na
        if (pic_scaling_list_present_flag[4])
          scaling_list_4x4[4][00]                = na
          scaling_list_4x4[4][01]                = na
          scaling_list_4x4[4][02]                = na
          scaling_list_4x4[4][03]                = na
          scaling_list_4x4[4][04]                = na
          scaling_list_4x4[4][05]                = na
          scaling_list_4x4[4][06]                = na
          scaling_list_4x4[4][07]                = na
          scaling_list_4x4[4][08]                = na
          scaling_list_4x4[4][09]                = na
          scaling_list_4x4[4][10]                = na
          scaling_list_4x4[4][11]                = na
          scaling_list_4x4[4][12]                = na
          scaling_list_4x4[4][13]                = na
          scaling_list_4x4[4][14]                = na
          scaling_list_4x4[4][15]                = na
        pic_scaling_list_present_flag[5]         = na
        if (pic_scaling_list_present_flag[5])
          scaling_list_4x4[5][00]                = na
          scaling_list_4x4[5][01]                = na
          scaling_list_4x4[5][02]                = na
          scaling_list_4x4[5][03]                = na
          scaling_list_4x4[5][04]                = na
          scaling_list_4x4[5][05]                = na
          scaling_list_4x4[5][06]                = na
          scaling_list_4x4[5][07]                = na
          scaling_list_4x4[5][08]                = na
          scaling_list_4x4[5][09]                = na
          scaling_list_4x4[5][10]                = na
          scaling_list_4x4[5][11]                = na
          scaling_list_4x4[5][12]                = na
          scaling_list_4x4[5][13]                = na
          scaling_list_4x4[5][14]                = na
          scaling_list_4x4[5][15]                = na
        }
      }
    second_chroma_qp_index_offset                = na
    }
  }
[00]slice_header() {
  nal_unit_header_svc_extension() {
    idr_flag                                     = na
    priority_id                                  = na
    no_inter_layer_pred_flag                     = na
    dependency_id                                = na
    quality_id                                   = na
    temporal_id                                  = na
    use_ref_base_pic_flag                        = na
    discardable_flag                             = na
    output_flag                                  = na
    }
  first_mb_in_slice                              = 0
  slice_type                                     = 7 (I slice)
  pic_parameter_set_id                           = 0
  frame_num                                      = 0
  if (!frame_mbs_only_flag) {
    field_pic_flag                               = na
    if (field_pic_flag)
      bottom_field_flag                          = na
    }
  if (nal_unit_type == 5)
    idr_pic_id                                   = 0
  if (pic_order_cnt_type == 0) {
    pic_order_cnt_lsb                            = 0
    if (pic_order_present_flag && !field_pic_flag)
      delta_pic_order_cnt_bottom                 = na
    }
  if (pic_order_cnt_type == 1 && !delta_pic_order_always_zero_flag) {
    delta_pic_order_cnt[0]                       = na
    if (pic_order_present_flag && !field_pic_flag)
      delta_pic_order_cnt[1]                     = na
    }
  if (redundant_pic_cnt_present_flag)
    redundant_pic_cnt                            = na
  if (slice_type == B)
    direct_spatial_mv_pred_flag                  = na
  if (slice_type == P || slice_type == SP || slice_type == B) {
    num_ref_idx_active_override_flag             = na
    if (num_ref_idx_active_override_flag) {
      num_ref_idx_l0_active_minus1               = na
      if (slice_type == B )
        num_ref_idx_l1_active_minus1             = na
      }
    }
  if (nal_unit_type == 20)
    ref_pic_list_mvc_modification()
  else
    ref_pic_list_modification()
  if ((weighted_pred_flag && (slice_type == P ||
  slice_type == SP)) || (weighted_bipred_idc == 1 && slice_type == B))
    pred_weight_table()
  if (nal_ref_idc != 0)
    dec_ref_pic_marking()
  if (entropy_coding_mode_flag && slice_type != I && slice_type != SI)
    cabac_init_idc                               = na
  slice_qp_delta                                 = 2
  if (slice_type == SP || slice_type == SI) {
    if (slice_type == SP)
      sp_for_switch_flag                         = na
    slice_qs_delta                               = na
    }
  if (deblocking_filter_control_present_flag) {
    disable_deblocking_filter_idc                = na
    if (disable_deblocking_filter_idc != 1) {
      slice_alpha_c0_offset_div2                 = na
      slice_beta_offset_div2                     = na
      }
    }
  if (num_slice_groups_minus1 > 0 &&
  slice_group_map_type >= 3 && slice_group_map_type <= 5)
    slice_group_change_cycle                     = na
  }

我们现在来分析,我们知道码流是由一个个的NAL Unit组成的,NALU是由NALU头和RBSP数据组成,而RBSP可能是SPS,PPS,Slice或SEI,目前我们这里SEI不会出现,而且SPS位于第一个NALU,PPS位于第二个NALU,其他就是Slice(严谨点区分的话可以把IDR等等再分出来)了。foreman_part_qcif.yuv只有3帧,那这里编码出来是不是就有5个NALU?我们这里可以大胆假设,然后仔细验证。

现在我们来开始分析,下面是一段H.264码流文件的十六进制数据,所以你得有个十六进制编辑器。00 00 00 01 67 42 00 1E F1 61 62 62 00 00 00 01 68 C8 A1 43 88 00

我们知道00 00 00 01是NALU的开始标记,所以你打开这个完整的码流文件应该可以看到5个00 00 00 01,所以这就是我们之前说的有5个NALU,分别是SPS,PPS和3个Slice。

一、SPS

这里SPS结构可以参考H264系列十五 句法元素SPS

去除掉NALU开始标记后的67 42 00 1E F1 61 62 62,转换为二进制是01100111 01000010 00000000 00011110 11110001 01100001 01100010 01100010

1.先看NALU头
forbidden_zero_bit ,nal_ref_idc,nal_unit_type这三个属性共占8位(Spec上都有写,分别占1,2和5位),那我们对着解析下就看出

forbidden_zero_bit = 0 // 0
nal_ref_idc = 3 // 11
nal_unit_type = 7 // 00111

这就对了,看看#define NALU_TYPE_SPS 7
Spec当中后面有些放在if判断里的就是只有符合某个值的时候才会出现,我们这里nal_unit_type为7,不符合,所以直接跳过,进入到RBSP当中,这里是SPS,所以对照Spec

profile_idc
constraint_set0_flag
constraint_set1_flag
constraint_set2_flag
constraint_set3_flag
constraint_set4_flag
constraint_set5_flag
reserved_zero_2bits
level_idc
seq_parameter_set_id

这几个属性,直到seq_parameter_set_id之前都还比较好解析,我们就直接写出它们的值了

profile_idc = 66 // 01000010
constraint_set0_flag = 0 // 0
constraint_set1_flag = 0 // 0
constraint_set2_flag = 0 // 0
constraint_set3_flag = 0 // 0
constraint_set4_flag = 0 // 0
constraint_set5_flag = 0 // 0
reserved_zero_2bits = 0 // 00
level_idc = 30 // 00011110

对于seq_parameter_set_id,我们看到它是ue(v),这是一种Exp-Golomb编码,每个编码所占的位数不是固定的,我们现在还剩下的数据是11110001 01100001 01100010 01100010

2.指数哥伦布编码
关于指数哥伦布编码,可以参考H264系列九 热力学熵 信息熵 哈夫曼编码 哥伦布编码,这里节选如下
对数字20进行编码:

codeNum = 20
prefixLen = floor[log2(codeNum+1)] = floor[log2(21)]=4
surfix = codeNum+1-2^prefixLen=20+1-2^4=5=二进制的101
编码值=0000,1,0101(为方便观看,以逗号分隔了)

也就是说,哥伦布编码以中间的1为对称轴,前缀全写0,需要先算出一共要写几个0。然后再算后缀的信息位。至于解码,先计算前缀个数4个0,这样后缀的信息位是0101,也就是5。所以解码得出2^4-1+5=20

3.公式参考Spec(9.1 Parsing process for Exp-Golomb codes)

leadingZeroBits = −1
for (b = 0; !b; leadingZeroBits++)
    b = read_bits(1)
 
codeNum = 2^(leadingZeroBits) − 1 + read_bits(leadingZeroBits)

对照上述解释,leadingZeroBits就是在找前缀个数,codeNum自然是我们最终解码值。现在还剩下的数据是11110001 01100001 01100010 01100010

这里read_bits直接读取到1了,说明前缀个数是0,跳出for循环,同时leadingZeroBits=0,后缀信息位不用读了,也是0。最终codeNum=2^0-1+0=0。也就是说这里编码1,解析出来的是seq_parameter_set_id = 0 // Exp-Golomb解1。后面几个属性类似,都是指数哥伦布解析1,结果都是0:

log2_max_frame_num_minus4 = 0 
pic_order_cnt_type = 0 
log2_max_pic_order_cnt_lsb_minus4 = 0 

4.现在第3步用掉了4个1,要从0001 01100001开始了
这里继续用Golomb解析max_num_ref_frames,很明显前缀有3个0。所以codenum=2^3-1+read_bits(011)=10

5.后面不再细述,结果如下

gaps_in_frame_num_value_allowed_flag = 0 // 0
pic_width_in_mbs_minus1 = 10 // Exp-Golomb解0001 011
pic_height_in_map_units_minus1 = 8 // Exp-Golomb解00010 01
frame_mbs_only_flag = 1 // 1
direct_8x8_inference_flag = 0 // 0
frame_cropping_flag = 0 // 0
vui_parameters_present_flag = 0 // 0

还剩下10两个位的数据没有用到,之前的这么多数据(除了NALU头之外的)都是seq_parameter_set_data,而根据Spec我们知道还有结尾补齐位

seq_parameter_set_rbsp( ) {
    seq_parameter_set_data( ) // 数据
    rbsp_trailing_bits( ) // 按字节补齐
}

补齐规则参见7.3.2.11 RBSP trailing bits syntax,实际就是按照字节对齐来补齐,所以这就是10这两位数据的由来。

回头看起来,这就是SPS的数据,也就是第一个NALU,同前面从Headers Info拷贝出来的SPS也是完全吻合的,所以这里我们就算是把Spec和实际的用法/码流对照起来了。另外值得说一下的就是从Headers Info拷贝出来的数据当中”na”就是未定义的,也就是if条件没有覆盖的情况。

二、PPS

这里PPS结构可以参考H264系列十六 句法元素PPS
去除掉NALU开始标记后的68 C8 A1 43 88,转换为二进制是01101000 11001000 10100001 01000011 10001000

1.先看NALU头

forbidden_zero_bit = 0 // 0
nal_ref_idc = 3 // 11
nal_unit_type = 8 // 01000

也就对应于#define NALU_TYPE_PPS 8,就可以知道此处的RBSP是PPS。

2.解码结果

pic_parameter_set_id = 0 // Exp-Golomb解1
seq_parameter_set_id = 0 // Exp-Golomb解1
entropy_coding_mode_flag = 0 // 0
bottom_field_pic_order_in_frame_present_flag = 0 // 0
num_slice_groups_minus1 = 0 // Exp-Golomb解1

num_ref_idx_l0_default_active_minus1 = 9 // Exp-Golomb解000 1010
num_ref_idx_l1_default_active_minus1 = 9 // Exp-Golomb解0001 010

weighted_pred_flag = 0 // 0
weighted_bipred_idc = 0 // 00

pic_init_qp_minus26 = 0 // Exp-Golomb解1
pic_init_qs_minus26 = 0 // Exp-Golomb解1
chroma_qp_index_offset = 0 // Exp-Golomb解1

deblocking_filter_control_present_flag = 0 // 0
constrained_intra_pred_flag = 0 // 0
redundant_pic_cnt_present_flag = 0 // 0

还剩下1000这四位,这就是按字节补齐的数据。

三、Slice

这里Slice结构可以参考H264系列十七 Slice(条带或片层)
去除掉NALU开始标记后的65 88 84 02,转换为二进制是01100101 10001000 10000100 00000010
1.先看NALU头

forbidden_zero_bit = 0 // 0
nal_ref_idc = 3 // 11
nal_unit_type = 5 // 00101

也就对应于#define NALU_TYPE_IDR 5,可以知道这个是IDR帧

first_mb_in_slice = 0 // Exp-Golomb解1
slice_type = 7 // Exp-Golomb解0001000

slice_type =7说明是个I帧

pic_parameter_set_id = 0 // Exp-Golomb解1

frame_num = 0 // u(v)根据占用的位数
//(log2_max_frame_num_minus4 + 4)解出值 // 0000

对于frame_num这个属性要特别说下,它的Descriptor是u(v),那么我们查看u(v)得知

u(n): unsigned integer using n bits. When n is “v” in the syntax table, the number of bits varies in a manner dependent on the value of other syntax elements.

也就是说这个属性占用的位数是取决于其它属性的,那就再搜索下frame_num得到

frame_num is used as an identifier for pictures and shall be represented by log2_max_frame_num_minus4 + 4 bits in the bitstream.

于是我们就大概清楚了,frame_num占用的位数跟log2_max_frame_num_minus4相关,之前在SPS当中我们知道log2_max_frame_num_minus4 = 0,所以这里frame_num占用4位,也就是0000,解析出来也就是0,另外也需要知道frame_num有很多限制,比如在IDR当中必须为0,具体参见7.4.3 Slice header semantics。这里要指出的是,这是一份完整优秀的Spec,基本上已经涵盖了我们需要的所有东西,只是需要我们去找,去分析(尽管这个过程可能很麻烦,有时让人摸不着头脑,但是需要相信我们需要的答案就在里面)。

idr_pic_id = 0 // Exp-Golomb解1

pic_order_cnt_lsb = 0 // u(v)根据占用的位数
//(log2_max_pic_order_cnt_lsb_minus4 + 4)解出值 // 0000

剩下的000010。现在要进入ref_pic_list_modification( )这个function了,但是里面所有if判断条件不符合

然后进入

dec_ref_pic_marking( )
no_output_of_prior_pics_flag = 0 // 0
long_term_reference_flag = 0 // 0

现在只剩下0010这四位了,我们继续补充3个字节(63 61 7C)进来01100011 01100001 01111100。于是我们继续做slice_qp_delta的解码,注意这里它的Descriptor是se(v),所以要先对进Exp-Golomb解码,然后进行mapping得出值。

0010 01100011 01100001 01111100 // 这里两个0,求出Exp-Golomb编码值为00100 // 长度5,后缀为0可以被解析成2 实际可以通过Exp-Golomb(2^2 – 1 + 0)算出值为3 然后代入(-1)^(k + 1) * Ceil(k divide 2)求出值为2。详细可以参见9.1.1 Mapping process for signed Exp-Golomb codes。

slice_qp_delta = 2 // 00100 // se(v)

到这里Slice Header就解析完成了。

暂时就到这里,需要说明的是,我们只写出了前三个NALU部分解析方法(第一个Slice,也就是IDR,我们只写出了Header部分,还有数据部分我们留到后面来分析),还剩两个Slice我们留着有必要的时候来分析。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容