void H264VideoStreamParser ::analyze_seq_parameter_set_data(unsigned& num_units_in_tick, unsigned& time_scale, unsigned& fixed_frame_rate_flag) { num_units_in_tick = time_scale = fixed_frame_rate_flag = 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); 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; 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 unsigned seq_scaling_matrix_present_flag = bv.get1Bit(); 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); unsigned seq_scaling_list_present_flag = bv.get1Bit(); 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); log2_max_frame_num = log2_max_frame_num_minus4 + 4; 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); unsigned gaps_in_frame_num_value_allowed_flag = bv.get1Bit(); 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); 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 unsigned frame_cropping_flag = bv.get1Bit(); 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 } unsigned vui_parameters_present_flag = bv.get1Bit(); DEBUG_PRINT(vui_parameters_present_flag); if (vui_parameters_present_flag) { DEBUG_TAB; analyze_vui_parameters(bv,num_units_in_tick, time_scale, fixed_frame_rate_flag); } }
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); } }