void H264or5VideoStreamParser
::analyze_video_parameter_set_data(unsigned& num_units_in_tick, unsigned& time_scale) {
  num_units_in_tick = time_scale = 0; // default values

  // Begin by making a copy of the NAL unit data, removing any 'emulation prevention' bytes:
  u_int8_t vps[VPS_MAX_SIZE];
  unsigned vpsSize;
  removeEmulationBytes(vps, sizeof vps, vpsSize);

  BitVector bv(vps, 0, 8*vpsSize);

  // Assert: fHNumber == 265 (because this function is called only when parsing H.265)
  unsigned i;

  bv.skipBits(28); // nal_unit_header, vps_video_parameter_set_id, vps_reserved_three_2bits, vps_max_layers_minus1
  unsigned vps_max_sub_layers_minus1 = bv.getBits(3);
  DEBUG_PRINT(vps_max_sub_layers_minus1);
  bv.skipBits(17); // vps_temporal_id_nesting_flag, vps_reserved_0xffff_16bits
  profile_tier_level(bv, vps_max_sub_layers_minus1);
  Boolean vps_sub_layer_ordering_info_present_flag = bv.get1BitBoolean();
  DEBUG_PRINT(vps_sub_layer_ordering_info_present_flag);
  for (i = vps_sub_layer_ordering_info_present_flag ? 0 : vps_max_sub_layers_minus1;
       i <= vps_max_sub_layers_minus1; ++i) {
    (void)bv.get_expGolomb(); // vps_max_dec_pic_buffering_minus1[i]
    (void)bv.get_expGolomb(); // vps_max_num_reorder_pics[i]
    (void)bv.get_expGolomb(); // vps_max_latency_increase_plus1[i]
  }    
  unsigned vps_max_layer_id = bv.getBits(6);
  DEBUG_PRINT(vps_max_layer_id);
  unsigned vps_num_layer_sets_minus1 = bv.get_expGolomb();
  DEBUG_PRINT(vps_num_layer_sets_minus1);
  for (i = 1; i <= vps_num_layer_sets_minus1; ++i) {
    bv.skipBits(vps_max_layer_id+1); // layer_id_included_flag[i][0..vps_max_layer_id]
  }
  Boolean vps_timing_info_present_flag = bv.get1BitBoolean();
  DEBUG_PRINT(vps_timing_info_present_flag);
  if (vps_timing_info_present_flag) {
    DEBUG_TAB;
    num_units_in_tick = bv.getBits(32);
    DEBUG_PRINT(num_units_in_tick);
    time_scale = bv.getBits(32);
    DEBUG_PRINT(time_scale);
    Boolean vps_poc_proportional_to_timing_flag = bv.get1BitBoolean();
    DEBUG_PRINT(vps_poc_proportional_to_timing_flag);
    if (vps_poc_proportional_to_timing_flag) {
      unsigned vps_num_ticks_poc_diff_one_minus1 = bv.get_expGolomb();
      DEBUG_PRINT(vps_num_ticks_poc_diff_one_minus1);
    }
  }
  Boolean vps_extension_flag = bv.get1BitBoolean();
  DEBUG_PRINT(vps_extension_flag);
}
예제 #2
0
bool nalEntry::sequence_parameter_set_rbsp(bitBuffer::iterator& bIter) {
#ifdef  _DEBUG
    fprintf(stderr, "nalEntry::sequence_parameter_set()\n");
#endif

    SEQ_PARAMETER_SET*      sps = 0L;

    sps = (SEQ_PARAMETER_SET*)calloc(1, sizeof(SEQ_PARAMETER_SET));
    assert(sps != 0L);

    m_pNalInfo     = (void*)sps;
    m_nalInfo_size = sizeof(SEQ_PARAMETER_SET);

    sps->sps_video_parameter_set_id         = bIter.get_bits(4);
    sps->sps_max_sub_layers_minus1          = bIter.get_bits(3);
    sps->sps_temporal_id_nesting_flag       = bIter.get_bits(1);

    profile_tier_level( bIter, sps->sps_max_sub_layers_minus1 );

    sps->sps_seq_parameter_set_id           = bIter.ue();
    sps->chroma_format_idc                  = bIter.ue();

    if (sps->chroma_format_idc == 3) {
        sps->seperate_color_plane_flag = bIter.get_bits(1);
    }

    sps->pic_width_in_luma_samples          = bIter.ue();
    sps->pic_height_in_luma_samples         = bIter.ue();

#ifdef  _DEBUG
    fprintf(stderr, "sps_video_parameter_set_id         : %x\n", sps->sps_video_parameter_set_id);
    fprintf(stderr, "sps_max_sub_layers_minus1          : %x\n", sps->sps_max_sub_layers_minus1);
    fprintf(stderr, "sps_temporal_id_nesting_flag       : %x\n", sps->sps_temporal_id_nesting_flag);
    fprintf(stderr, "sps_seq_parameter_set_id           : %x\n", sps->sps_seq_parameter_set_id);
    fprintf(stderr, "chroma_format_idc                  : %x\n", sps->chroma_format_idc);
    fprintf(stderr, "pic_width_in_luma_samples          : %d\n", sps->pic_width_in_luma_samples);
    fprintf(stderr, "pic_height_in_luma_samples         : %d\n", sps->pic_height_in_luma_samples);
#endif

    bIter.byte_align();
    return true;
}
void H264or5VideoStreamParser
::analyze_seq_parameter_set_data(unsigned& num_units_in_tick, unsigned& time_scale) {
  num_units_in_tick = time_scale = 0; // default values

  // Begin by making a copy of the NAL unit data, removing any 'emulation prevention' bytes:
  u_int8_t sps[SPS_MAX_SIZE];
  unsigned spsSize;
  removeEmulationBytes(sps, sizeof sps, spsSize);

  BitVector bv(sps, 0, 8*spsSize);

  if (fHNumber == 264) {
    bv.skipBits(8); // forbidden_zero_bit; nal_ref_idc; nal_unit_type
    unsigned profile_idc = bv.getBits(8);
    DEBUG_PRINT(profile_idc);
    unsigned constraint_setN_flag = bv.getBits(8); // also "reserved_zero_2bits" at end
    DEBUG_PRINT(constraint_setN_flag);
    unsigned level_idc = bv.getBits(8);
    DEBUG_PRINT(level_idc);
    unsigned seq_parameter_set_id = bv.get_expGolomb();
    DEBUG_PRINT(seq_parameter_set_id);
    if (profile_idc == 100 || profile_idc == 110 || profile_idc == 122 || profile_idc == 244 || profile_idc == 44 || profile_idc == 83 || profile_idc == 86 || profile_idc == 118 || profile_idc == 128 ) {
      DEBUG_TAB;
      unsigned chroma_format_idc = bv.get_expGolomb();
      DEBUG_PRINT(chroma_format_idc);
      if (chroma_format_idc == 3) {
	DEBUG_TAB;
	Boolean separate_colour_plane_flag = bv.get1BitBoolean();
	DEBUG_PRINT(separate_colour_plane_flag);
      }
      (void)bv.get_expGolomb(); // bit_depth_luma_minus8
      (void)bv.get_expGolomb(); // bit_depth_chroma_minus8
      bv.skipBits(1); // qpprime_y_zero_transform_bypass_flag
      Boolean seq_scaling_matrix_present_flag = bv.get1BitBoolean();
      DEBUG_PRINT(seq_scaling_matrix_present_flag);
      if (seq_scaling_matrix_present_flag) {
	for (int i = 0; i < ((chroma_format_idc != 3) ? 8 : 12); ++i) {
	  DEBUG_TAB;
	  DEBUG_PRINT(i);
	  Boolean seq_scaling_list_present_flag = bv.get1BitBoolean();
	  DEBUG_PRINT(seq_scaling_list_present_flag);
	  if (seq_scaling_list_present_flag) {
	    DEBUG_TAB;
	    unsigned sizeOfScalingList = i < 6 ? 16 : 64;
	    unsigned lastScale = 8;
	    unsigned nextScale = 8;
	    for (unsigned j = 0; j < sizeOfScalingList; ++j) {
	      DEBUG_TAB;
	      DEBUG_PRINT(j);
	      DEBUG_PRINT(nextScale);
	      if (nextScale != 0) {
		DEBUG_TAB;
		unsigned delta_scale = bv.get_expGolomb();
		DEBUG_PRINT(delta_scale);
		nextScale = (lastScale + delta_scale + 256) % 256;
	      }
	      lastScale = (nextScale == 0) ? lastScale : nextScale;
	      DEBUG_PRINT(lastScale);
	    }
	  }
	}
      }
    }
    unsigned log2_max_frame_num_minus4 = bv.get_expGolomb();
    DEBUG_PRINT(log2_max_frame_num_minus4);
    unsigned pic_order_cnt_type = bv.get_expGolomb();
    DEBUG_PRINT(pic_order_cnt_type);
    if (pic_order_cnt_type == 0) {
      DEBUG_TAB;
      unsigned log2_max_pic_order_cnt_lsb_minus4 = bv.get_expGolomb();
      DEBUG_PRINT(log2_max_pic_order_cnt_lsb_minus4);
    } else if (pic_order_cnt_type == 1) {
      DEBUG_TAB;
      bv.skipBits(1); // delta_pic_order_always_zero_flag
      (void)bv.get_expGolomb(); // offset_for_non_ref_pic
      (void)bv.get_expGolomb(); // offset_for_top_to_bottom_field
      unsigned num_ref_frames_in_pic_order_cnt_cycle = bv.get_expGolomb();
      DEBUG_PRINT(num_ref_frames_in_pic_order_cnt_cycle);
      for (unsigned i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; ++i) {
	(void)bv.get_expGolomb(); // offset_for_ref_frame[i]
      }
    }
    unsigned max_num_ref_frames = bv.get_expGolomb();
    DEBUG_PRINT(max_num_ref_frames);
    Boolean gaps_in_frame_num_value_allowed_flag = bv.get1BitBoolean();
    DEBUG_PRINT(gaps_in_frame_num_value_allowed_flag);
    unsigned pic_width_in_mbs_minus1 = bv.get_expGolomb();
    DEBUG_PRINT(pic_width_in_mbs_minus1);
    unsigned pic_height_in_map_units_minus1 = bv.get_expGolomb();
    DEBUG_PRINT(pic_height_in_map_units_minus1);
    Boolean frame_mbs_only_flag = bv.get1BitBoolean();
    DEBUG_PRINT(frame_mbs_only_flag);
    if (!frame_mbs_only_flag) {
      bv.skipBits(1); // mb_adaptive_frame_field_flag
    }
    bv.skipBits(1); // direct_8x8_inference_flag
    Boolean frame_cropping_flag = bv.get1BitBoolean();
    DEBUG_PRINT(frame_cropping_flag);
    if (frame_cropping_flag) {
      (void)bv.get_expGolomb(); // frame_crop_left_offset
      (void)bv.get_expGolomb(); // frame_crop_right_offset
      (void)bv.get_expGolomb(); // frame_crop_top_offset
      (void)bv.get_expGolomb(); // frame_crop_bottom_offset
    }
    Boolean vui_parameters_present_flag = bv.get1BitBoolean();
    DEBUG_PRINT(vui_parameters_present_flag);
    if (vui_parameters_present_flag) {
      DEBUG_TAB;
      analyze_vui_parameters(bv, num_units_in_tick, time_scale);
    }
  } else { // 265
    unsigned i;

    bv.skipBits(16); // nal_unit_header
    bv.skipBits(4); // sps_video_parameter_set_id
    unsigned sps_max_sub_layers_minus1 = bv.getBits(3);
    DEBUG_PRINT(sps_max_sub_layers_minus1);
    bv.skipBits(1); // sps_temporal_id_nesting_flag
    profile_tier_level(bv, sps_max_sub_layers_minus1);
    (void)bv.get_expGolomb(); // sps_seq_parameter_set_id
    unsigned chroma_format_idc = bv.get_expGolomb();
    DEBUG_PRINT(chroma_format_idc);
    if (chroma_format_idc == 3) bv.skipBits(1); // separate_colour_plane_flag
    unsigned pic_width_in_luma_samples = bv.get_expGolomb();
    DEBUG_PRINT(pic_width_in_luma_samples);
    unsigned pic_height_in_luma_samples = bv.get_expGolomb();
    DEBUG_PRINT(pic_height_in_luma_samples);
    Boolean conformance_window_flag = bv.get1BitBoolean();
    DEBUG_PRINT(conformance_window_flag);
    if (conformance_window_flag) {
      DEBUG_TAB;
      unsigned conf_win_left_offset = bv.get_expGolomb();
      DEBUG_PRINT(conf_win_left_offset);
      unsigned conf_win_right_offset = bv.get_expGolomb();
      DEBUG_PRINT(conf_win_right_offset);
      unsigned conf_win_top_offset = bv.get_expGolomb();
      DEBUG_PRINT(conf_win_top_offset);
      unsigned conf_win_bottom_offset = bv.get_expGolomb();
      DEBUG_PRINT(conf_win_bottom_offset);
    }
    (void)bv.get_expGolomb(); // bit_depth_luma_minus8
    (void)bv.get_expGolomb(); // bit_depth_chroma_minus8
    unsigned log2_max_pic_order_cnt_lsb_minus4 = bv.get_expGolomb();
    Boolean sps_sub_layer_ordering_info_present_flag = bv.get1BitBoolean();
    DEBUG_PRINT(sps_sub_layer_ordering_info_present_flag);
    for (i = (sps_sub_layer_ordering_info_present_flag ? 0 : sps_max_sub_layers_minus1);
	 i <= sps_max_sub_layers_minus1; ++i) {
      (void)bv.get_expGolomb(); // sps_max_dec_pic_buffering_minus1[i]
      (void)bv.get_expGolomb(); // sps_max_num_reorder_pics[i]
      (void)bv.get_expGolomb(); // sps_max_latency_increase[i]
    }
    (void)bv.get_expGolomb(); // log2_min_luma_coding_block_size_minus3
    (void)bv.get_expGolomb(); // log2_diff_max_min_luma_coding_block_size
    (void)bv.get_expGolomb(); // log2_min_transform_block_size_minus2
    (void)bv.get_expGolomb(); // log2_diff_max_min_transform_block_size
    (void)bv.get_expGolomb(); // max_transform_hierarchy_depth_inter
    (void)bv.get_expGolomb(); // max_transform_hierarchy_depth_intra
    Boolean scaling_list_enabled_flag = bv.get1BitBoolean();
    DEBUG_PRINT(scaling_list_enabled_flag);
    if (scaling_list_enabled_flag) {
      DEBUG_TAB;
      Boolean sps_scaling_list_data_present_flag = bv.get1BitBoolean();
      DEBUG_PRINT(sps_scaling_list_data_present_flag);
      if (sps_scaling_list_data_present_flag) {
	// scaling_list_data()
	DEBUG_TAB;
	for (unsigned sizeId = 0; sizeId < 4; ++sizeId) {
	  DEBUG_PRINT(sizeId);
	  for (unsigned matrixId = 0; matrixId < (sizeId == 3 ? 2 : 6); ++matrixId) {
	    DEBUG_TAB;
	    DEBUG_PRINT(matrixId);
	    Boolean scaling_list_pred_mode_flag = bv.get1BitBoolean();
	    DEBUG_PRINT(scaling_list_pred_mode_flag);
	    if (!scaling_list_pred_mode_flag) {
	      (void)bv.get_expGolomb(); // scaling_list_pred_matrix_id_delta[sizeId][matrixId]
	    } else {
	      unsigned const c = 1 << (4+(sizeId<<1));
	      unsigned coefNum = c < 64 ? c : 64;
	      if (sizeId > 1) {
		(void)bv.get_expGolomb(); // scaling_list_dc_coef_minus8[sizeId][matrixId]
	      }
	      for (i = 0; i < coefNum; ++i) {
		(void)bv.get_expGolomb(); // scaling_list_delta_coef
	      }
	    }
	  } 
	}
      }
    }
    bv.skipBits(2); // amp_enabled_flag, sample_adaptive_offset_enabled_flag
    Boolean pcm_enabled_flag = bv.get1BitBoolean();
    DEBUG_PRINT(pcm_enabled_flag);
    if (pcm_enabled_flag) {
      bv.skipBits(8); // pcm_sample_bit_depth_luma_minus1, pcm_sample_bit_depth_chroma_minus1
      (void)bv.get_expGolomb(); // log2_min_pcm_luma_coding_block_size_minus3
      (void)bv.get_expGolomb(); // log2_diff_max_min_pcm_luma_coding_block_size
      bv.skipBits(1); // pcm_loop_filter_disabled_flag
    }
    unsigned num_short_term_ref_pic_sets = bv.get_expGolomb();
    DEBUG_PRINT(num_short_term_ref_pic_sets);
    unsigned num_negative_pics = 0, prev_num_negative_pics = 0;
    unsigned num_positive_pics = 0, prev_num_positive_pics = 0;
    for (i = 0; i < num_short_term_ref_pic_sets; ++i) {
      // short_term_ref_pic_set(i):
      DEBUG_TAB;
      DEBUG_PRINT(i);
      Boolean inter_ref_pic_set_prediction_flag = False;
      if (i != 0) {
	inter_ref_pic_set_prediction_flag = bv.get1BitBoolean();
      }
      DEBUG_PRINT(inter_ref_pic_set_prediction_flag);
      if (inter_ref_pic_set_prediction_flag) {
	DEBUG_TAB;
	if (i == num_short_term_ref_pic_sets) {
	  // This can't happen here, but it's in the spec, so we include it for completeness
	  (void)bv.get_expGolomb(); // delta_idx_minus1
	}
	bv.skipBits(1); // delta_rps_sign
	(void)bv.get_expGolomb(); // abs_delta_rps_minus1
	unsigned NumDeltaPocs = prev_num_negative_pics + prev_num_positive_pics; // correct???
	for (unsigned j = 0; j < NumDeltaPocs; ++j) {
	  DEBUG_PRINT(j);
	  Boolean used_by_curr_pic_flag = bv.get1BitBoolean();
	  DEBUG_PRINT(used_by_curr_pic_flag);
	  if (!used_by_curr_pic_flag) bv.skipBits(1); // use_delta_flag[j]
	}
      } else {
	prev_num_negative_pics = num_negative_pics;
	num_negative_pics = bv.get_expGolomb();
	DEBUG_PRINT(num_negative_pics);
	prev_num_positive_pics = num_positive_pics;
	num_positive_pics = bv.get_expGolomb();
	DEBUG_PRINT(num_positive_pics);
	unsigned k;
	for (k = 0; k < num_negative_pics; ++k) {
	  (void)bv.get_expGolomb(); // delta_poc_s0_minus1[k]
	  bv.skipBits(1); // used_by_curr_pic_s0_flag[k]
	}
	for (k = 0; k < num_positive_pics; ++k) {
	  (void)bv.get_expGolomb(); // delta_poc_s1_minus1[k]
	  bv.skipBits(1); // used_by_curr_pic_s1_flag[k]
	}
      }
    }
    Boolean long_term_ref_pics_present_flag = bv.get1BitBoolean();
    DEBUG_PRINT(long_term_ref_pics_present_flag);
    if (long_term_ref_pics_present_flag) {
      DEBUG_TAB;
      unsigned num_long_term_ref_pics_sps = bv.get_expGolomb();
      DEBUG_PRINT(num_long_term_ref_pics_sps);
      for (i = 0; i < num_long_term_ref_pics_sps; ++i) {
	bv.skipBits(log2_max_pic_order_cnt_lsb_minus4); // lt_ref_pic_poc_lsb_sps[i]
	bv.skipBits(1); // used_by_curr_pic_lt_sps_flag[1]
      }
    }
    bv.skipBits(2); // sps_temporal_mvp_enabled_flag, strong_intra_smoothing_enabled_flag
    Boolean vui_parameters_present_flag = bv.get1BitBoolean();
    DEBUG_PRINT(vui_parameters_present_flag);
    if (vui_parameters_present_flag) {
      DEBUG_TAB;
      analyze_vui_parameters(bv, num_units_in_tick, time_scale);
    }
    Boolean sps_extension_flag = bv.get1BitBoolean();
    DEBUG_PRINT(sps_extension_flag);
  }
}
예제 #4
0
파일: sps.c 프로젝트: luuvish/libvio
void seq_parameter_set_rbsp(sps_t *sps, rbsp_t *rbsp) {
	sps->video_parameter_set_id    = rbsp->u(4, "video_parameter_set_id");
	assert(sps->video_parameter_set_id < MAX_VPS_ID);
	sps->sps_max_sub_layers_minus1 = rbsp->u(3, "sps_max_sub_layers_minus1");
	assert(sps->sps_max_sub_layers_minus1 < MAX_SUB_LAYERS);
	uint32_t sps_reverved_zero_bit = rbsp->u(1, "sps_reverved_zero_bit");
	assert(sps_reverved_zero_bit == 0);

	profile_tier_level(&sps->ptl, 1, sps->sps_max_sub_layers_minus1, rbsp);

	sps->seq_parameter_set_id       = rbsp->ue("seq_parameter_set_id");
	assert(sps->seq_parameter_set_id < MAX_SPS_ID);
	sps->chroma_format_idc          = rbsp->ue("chroma_format_idc");
	assert(sps->chroma_format_idc <= CHROMA_FORMAT_IDC_444);
	sps->separate_colour_plane_flag = 0;
	if (sps->chroma_format_idc == CHROMA_FORMAT_IDC_444)
		sps->separate_colour_plane_flag = rbsp->u(1, "separate_colour_plane_flag");

	sps->ChromaArrayType = CHROMA_FORMAT_IDC_MONO;
	if (sps->separate_colour_plane_flag == 0)
		sps->ChromaArrayType = sps->chroma_format_idc;
	int SubWidthC [] = {1, 2, 2, 1, 1};
	int SubHeightC[] = {1, 2, 1, 1, 1};
	sps->SubWidthC  = SubWidthC [sps->chroma_format_idc];
	sps->SubHeightC = SubHeightC[sps->chroma_format_idc];

	sps->pic_width_in_luma_samples  = rbsp->ue("pic_width_in_luma_samples");
	sps->pic_height_in_luma_samples = rbsp->ue("pic_height_in_luma_samples");
	sps->pic_cropping_flag          = rbsp->u(1, "pic_cropping_flag");
	sps->pic_crop_left_offset       = 0;
	sps->pic_crop_right_offset      = 0;
	sps->pic_crop_top_offset        = 0;
	sps->pic_crop_bottom_offset     = 0;
	if (sps->pic_cropping_flag) {
		sps->pic_crop_left_offset   = rbsp->ue("pic_crop_left_offset");
		sps->pic_crop_right_offset  = rbsp->ue("pic_crop_right_offset");
		sps->pic_crop_top_offset    = rbsp->ue("pic_crop_top_offset");
		sps->pic_crop_bottom_offset = rbsp->ue("pic_crop_bottom_offset");

		int CropUnitX = 1;
		int CropUnitY = 1;
		if (sps->ChromaArrayType != CHROMA_FORMAT_IDC_MONO) {
			CropUnitX = sps->SubWidthC;
			CropUnitY = sps->SubHeightC;
		}
		assert(sps->pic_crop_left_offset + sps->pic_crop_right_offset  < sps->pic_width_in_luma_samples  / CropUnitX);
		assert(sps->pic_crop_top_offset  + sps->pic_crop_bottom_offset < sps->pic_height_in_luma_samples / CropUnitY);
	}

	sps->bit_depth_luma_minus8   = rbsp->ue("bit_depth_luma_minus8");
	sps->bit_depth_chroma_minus8 = rbsp->ue("bit_depth_chroma_minus8");
	assert(sps->bit_depth_luma_minus8   <= 6);
	assert(sps->bit_depth_chroma_minus8 <= 6);

	sps->BitDepthY   = 8 + sps->bit_depth_luma_minus8;
	sps->QpBdOffsetY = 6 * sps->bit_depth_luma_minus8;
	sps->BitDepthC   = 8 + sps->bit_depth_chroma_minus8;
	sps->QpBdOffsetC = 6 * sps->bit_depth_chroma_minus8;

#if 1
	sps->pcm_enabled_flag                    = rbsp->u(1, "pcm_enabled_flag");
	sps->pcm_loop_filter_disable_flag        = 0;
	if (sps->pcm_enabled_flag) {
		sps->pcm_sample_bit_depth_luma_minus1   = rbsp->u(4, "pcm_bit_depth_luma_minus1");
		sps->pcm_sample_bit_depth_chroma_minus1 = rbsp->u(4, "pcm_bit_depth_chroma_minus1");
	}
#endif

	sps->log2_max_pic_order_cnt_lsb_minus4 = rbsp->ue("log2_max_pic_order_cnt_lsb_minus4");
	assert(sps->log2_max_pic_order_cnt_lsb_minus4 <= 12);

	sps->MaxPicOrderCntLsb = 1 << (sps->log2_max_pic_order_cnt_lsb_minus4 + 4);

	for (int i = 0; i <= sps->sps_max_sub_layers_minus1; i++) {
		sps->sps_max_dec_pic_buffering[i] = rbsp->ue("max_dec_pic_buffering");
		sps->sps_num_reorder_pics     [i] = rbsp->ue("num_reorder_pics");
		sps->sps_max_latency_increase [i] = rbsp->ue("max_latency_increase");
		assert(sps->sps_max_dec_pic_buffering[i] <= MaxDpbSize);
		assert(sps->sps_num_reorder_pics     [i] <= sps->sps_max_dec_pic_buffering[i]);
		assert(sps->sps_max_latency_increase [i] <= ((1<<32)-2));
		if (i > 0) {
			assert(sps->sps_max_dec_pic_buffering[i-1] <= sps->sps_max_dec_pic_buffering[i]);
			assert(sps->sps_num_reorder_pics     [i-1] <= sps->sps_num_reorder_pics     [i]);
		}
	}

	sps->restricted_ref_pic_lists_flag       = rbsp->u(1, "restricted_ref_pic_lists_flag");
	sps->lists_modification_present_flag     = 0;
	if (sps->restricted_ref_pic_lists_flag)
		sps->lists_modification_present_flag = rbsp->u(1, "lists_modification_present_flag");

	sps->log2_min_luma_coding_block_size_minus3   = rbsp->ue("log2_min_coding_block_size_minus3");
	sps->log2_diff_max_min_luma_coding_block_size = rbsp->ue("log2_diff_max_min_coding_block_size");

	sps->Log2MinCbSizeY     = sps->log2_min_luma_coding_block_size_minus3 + 3;
	sps->Log2CtbSizeY       = sps->Log2MinCbSizeY + sps->log2_diff_max_min_luma_coding_block_size;
	sps->MinCbSizeY         = 1 << sps->Log2MinCbSizeY;
	sps->CtbSizeY           = 1 << sps->Log2CtbSizeY;
	sps->PicWidthInMinCbsY  = sps->pic_width_in_luma_samples  / sps->MinCbSizeY;
	sps->PicWidthInCtbsY    = (sps->pic_width_in_luma_samples  + sps->CtbSizeY) / sps->CtbSizeY;
	sps->PicHeightInMinCbsY = sps->pic_height_in_luma_samples / sps->MinCbSizeY;
	sps->PicHeightInCtbsY   = (sps->pic_height_in_luma_samples + sps->CtbSizeY) / sps->CtbSizeY;
	sps->PicSizeInMinCbsY   = sps->PicWidthInMinCbsY * sps->PicHeightInMinCbsY;
	sps->PicSizeInCtbsY     = sps->PicWidthInCtbsY   * sps->PicHeightInCtbsY;
	sps->PicSizeInSamplesY  = sps->pic_width_in_luma_samples * sps->pic_height_in_luma_samples;
	sps->CtbWidthC          = 0;
	sps->CtbHeightC         = 0;
	if (sps->chroma_format_idc != CHROMA_FORMAT_IDC_MONO && sps->separate_colour_plane_flag == 0) {
		sps->CtbWidthC      = sps->CtbSizeY / sps->SubWidthC;
		sps->CtbHeightC     = sps->CtbSizeY / sps->SubHeightC;
	}
	assert(sps->pic_width_in_luma_samples  % sps->MinCbSizeY == 0);
	assert(sps->pic_height_in_luma_samples % sps->MinCbSizeY == 0);

	sps->log2_min_transform_block_size_minus2   = rbsp->ue("log2_min_transform_block_size_minus2");
	sps->log2_diff_max_min_transform_block_size = rbsp->ue("log2_diff_max_min_transform_block_size");

	sps->Log2MinTrafoSize = sps->log2_min_transform_block_size_minus2 + 2;
	sps->Log2MaxTrafoSize = sps->Log2MinTrafoSize + sps->log2_diff_max_min_transform_block_size;
	assert(sps->Log2MinTrafoSize < sps->Log2MinCbSizeY);
	assert(sps->Log2MaxTrafoSize <= min(sps->Log2CtbSizeY, 5));
	// ScanOrder[log2BlockSize][scanIdx][sPos][sComp]
	// log2BlockSize ranging from min(2, Log2MinTrafoSize-2) to max(2, Log2MaxTrafoSize-2)
	for (int log2BlockSize = min(2, sps->Log2MinTrafoSize-2); log2BlockSize <= 3; log2BlockSize++)
		scan_order(sps->ScanOrder[log2BlockSize], 1 << log2BlockSize);

#if 1
	if (sps->pcm_enabled_flag) {
		sps->log2_min_pcm_luma_coding_block_size_minus3   = rbsp->ue("log2_min_pcm_coding_block_size_minus3");
		sps->log2_diff_max_min_pcm_luma_coding_block_size = rbsp->ue("log2_diff_max_min_pcm_coding_block_size");
	}
#endif

	sps->max_transform_hierarchy_depth_inter = rbsp->ue("max_transform_hierarchy_depth_inter");
	sps->max_transform_hierarchy_depth_intra = rbsp->ue("max_transform_hierarchy_depth_intra");
	assert(sps->max_transform_hierarchy_depth_inter <= sps->Log2CtbSizeY - sps->Log2MinTrafoSize);
	assert(sps->max_transform_hierarchy_depth_intra <= sps->Log2CtbSizeY - sps->Log2MinTrafoSize);

	sps->scaling_list_enable_flag               = rbsp->u(1, "scaling_list_enable_flag");
	sps->sps_scaling_list_data_present_flag     = 0;
	if (sps->scaling_list_enable_flag) {
		sps->sps_scaling_list_data_present_flag = rbsp->u(1, "sps_scaling_list_data_present_flag");
		if (sps->sps_scaling_list_data_present_flag)
			scaling_list_data(&sps->sps_scaling_list, rbsp);
	}

	sps->amp_enabled_flag                    = rbsp->u(1, "asymmetric_motion_partitions_enabled_flag");
	sps->sample_adaptive_offset_enabled_flag = rbsp->u(1, "sample_adaptive_offset_enabled_flag");
#if 1
	sps->pcm_loop_filter_disable_flag     = 0;
	if (sps->pcm_enabled_flag)
		sps->pcm_loop_filter_disable_flag = rbsp->u(1, "pcm_loop_filter_disable_flag");
#endif
#if 0
	sps->pcm_enabled_flag                    = rbsp->u(1, "pcm_enabled_flag");
	sps->pcm_loop_filter_disable_flag        = 0;
	if (sps->pcm_enabled_flag) {
		sps->pcm_sample_bit_depth_luma_minus1   = rbsp->u(4, "pcm_sample_bit_depth_luma_minus1");
		sps->pcm_sample_bit_depth_chroma_minus1 = rbsp->u(4, "pcm_sample_bit_depth_chroma_minus1");

		sps->PCMBitDepthY = 1 + sps->pcm_sample_bit_depth_luma_minus1;
		sps->PCMBitDepthC = 1 + sps->pcm_sample_bit_depth_chroma_minus1;
		assert(sps->PCMBitDepthY <= sps->BitDepthY);
		assert(sps->PCMBitDepthC <= sps->BitDepthC);

		sps->log2_min_pcm_luma_coding_block_size_minus3   = rbsp->ue("log2_min_pcm_coding_block_size_minus3");
		sps->log2_diff_max_min_pcm_luma_coding_block_size = rbsp->ue("log2_diff_max_min_pcm_coding_block_size");
		sps->pcm_loop_filter_disable_flag                 = rbsp->u(1, "pcm_loop_filter_disable_flag");

		sps->Log2MinIpcmCbSizeY = sps->log2_min_pcm_luma_coding_block_size_minus3 + 3;
		sps->Log2MaxIpcmCbSizeY = sps->Log2MaxIpcmCbSizeY + sps->log2_diff_max_min_pcm_luma_coding_block_size;
		assert(sps->Log2MinIpcmCbSizeY >= sps->Log2MinCbSizeY);
		assert(sps->Log2MinIpcmCbSizeY <= min(sps->Log2CtbSizeY, 5));
		assert(sps->Log2MaxIpcmCbSizeY <= min(sps->Log2CtbSizeY, 5));
	}
#endif
	sps->sps_temporal_id_nesting_flag = rbsp->u(1, "temporal_id_nesting_flag");
	assert(sps->sps_temporal_id_nesting_flag == vps->vps_temporal_id_nesting_flag);

	sps->num_short_term_ref_pic_sets = rbsp->ue("num_short_term_ref_pic_sets");
	assert(sps->num_short_term_ref_pic_sets <= MAX_SHORT_TERM_REF_PIC_SETS);
	for (int i = 0; i < sps->num_short_term_ref_pic_sets; i++)
		short_term_ref_pic_set(&sps->rps[i], i, rbsp);
	sps->long_term_ref_pics_present_flag = rbsp->u(1, "long_term_ref_pics_present_flag");
	if (sps->long_term_ref_pics_present_flag) {
		sps->num_long_term_ref_pics_sps = rbsp->ue("num_long_term_ref_pic_sps");
		for (int i = 0; i < sps->num_long_term_ref_pics_sps; i++) {
			sps->lt_ref_pic_poc_lsb_sps[i]       = rbsp->u(sps->log2_max_pic_order_cnt_lsb_minus4 + 4, "lt_ref_pic_poc_lsb_sps");
			sps->used_by_curr_pic_lt_sps_flag[i] = rbsp->u(1, "used_by_curr_pic_lt_sps_flag[i]");
		}
	}
	sps->sps_temporal_mvp_enable_flag       = rbsp->u(1, "sps_temporal_mvp_enable_flag");
#if 0
	sps->strong_intra_smoothing_enable_flag = rbsp->u(1, "strong_intra_smoothing_enable_flag");
#endif

	sps->vui_parameters_present_flag = rbsp->u(1, "vui_parameters_present_flag");
	if (sps->vui_parameters_present_flag)
		vui_parameters(&sps->vui, sps, rbsp);

	uint32_t sps_extension_flag = rbsp->u(1, "sps_extension_flag");
	if (sps_extension_flag) {
		while (rbsp->more_rbsp_data())
			uint32_t sps_extension_data_flag = rbsp->u(1, "sps_extension_data_flag");
	}

	rbsp->rbsp_trailing_bits();
}