| // Copyright 2024 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "media/gpu/h264_builder.h" |
| |
| #include "base/bits.h" |
| #include "base/notreached.h" |
| #include "media/filters/h264_bitstream_buffer.h" |
| |
| namespace media { |
| |
| void BuildPackedH264SPS(H264BitstreamBuffer& bitstream_buffer, |
| const H264SPS& sps) { |
| bitstream_buffer.BeginNALU(H264NALU::kSPS, 3); |
| |
| bitstream_buffer.AppendBits(8, sps.profile_idc); |
| bitstream_buffer.AppendBool(sps.constraint_set0_flag); |
| bitstream_buffer.AppendBool(sps.constraint_set1_flag); |
| bitstream_buffer.AppendBool(sps.constraint_set2_flag); |
| bitstream_buffer.AppendBool(sps.constraint_set3_flag); |
| bitstream_buffer.AppendBool(sps.constraint_set4_flag); |
| bitstream_buffer.AppendBool(sps.constraint_set5_flag); |
| bitstream_buffer.AppendBits(2, 0); // reserved_zero_2bits |
| bitstream_buffer.AppendBits(8, sps.level_idc); |
| bitstream_buffer.AppendUE(sps.seq_parameter_set_id); |
| |
| if (sps.profile_idc == H264SPS::kProfileIDCHigh) { |
| bitstream_buffer.AppendUE(sps.chroma_format_idc); |
| if (sps.chroma_format_idc == 3) { |
| bitstream_buffer.AppendBool(sps.separate_colour_plane_flag); |
| } |
| bitstream_buffer.AppendUE(sps.bit_depth_luma_minus8); |
| bitstream_buffer.AppendUE(sps.bit_depth_chroma_minus8); |
| bitstream_buffer.AppendBool(sps.qpprime_y_zero_transform_bypass_flag); |
| bitstream_buffer.AppendBool(sps.seq_scaling_matrix_present_flag); |
| CHECK(!sps.seq_scaling_matrix_present_flag); |
| } |
| |
| bitstream_buffer.AppendUE(sps.log2_max_frame_num_minus4); |
| bitstream_buffer.AppendUE(sps.pic_order_cnt_type); |
| if (sps.pic_order_cnt_type == 0) { |
| bitstream_buffer.AppendUE(sps.log2_max_pic_order_cnt_lsb_minus4); |
| } else if (sps.pic_order_cnt_type == 1) { |
| // Ignoring the content of this branch as we don't produce |
| // sps.pic_order_cnt_type == 1 |
| NOTREACHED_NORETURN(); |
| } |
| |
| bitstream_buffer.AppendUE(sps.max_num_ref_frames); |
| bitstream_buffer.AppendBool(sps.gaps_in_frame_num_value_allowed_flag); |
| bitstream_buffer.AppendUE(sps.pic_width_in_mbs_minus1); |
| bitstream_buffer.AppendUE(sps.pic_height_in_map_units_minus1); |
| |
| bitstream_buffer.AppendBool(sps.frame_mbs_only_flag); |
| if (!sps.frame_mbs_only_flag) { |
| bitstream_buffer.AppendBool(sps.mb_adaptive_frame_field_flag); |
| } |
| |
| bitstream_buffer.AppendBool(sps.direct_8x8_inference_flag); |
| |
| bitstream_buffer.AppendBool(sps.frame_cropping_flag); |
| if (sps.frame_cropping_flag) { |
| bitstream_buffer.AppendUE(sps.frame_crop_left_offset); |
| bitstream_buffer.AppendUE(sps.frame_crop_right_offset); |
| bitstream_buffer.AppendUE(sps.frame_crop_top_offset); |
| bitstream_buffer.AppendUE(sps.frame_crop_bottom_offset); |
| } |
| |
| bitstream_buffer.AppendBool(sps.vui_parameters_present_flag); |
| if (sps.vui_parameters_present_flag) { |
| bitstream_buffer.AppendBool(false); // aspect_ratio_info_present_flag |
| bitstream_buffer.AppendBool(false); // overscan_info_present_flag |
| bitstream_buffer.AppendBool(false); // video_signal_type_present_flag |
| bitstream_buffer.AppendBool(false); // chroma_loc_info_present_flag |
| |
| bitstream_buffer.AppendBool(sps.timing_info_present_flag); |
| if (sps.timing_info_present_flag) { |
| bitstream_buffer.AppendBits(32, sps.num_units_in_tick); |
| bitstream_buffer.AppendBits(32, sps.time_scale); |
| bitstream_buffer.AppendBool(sps.fixed_frame_rate_flag); |
| } |
| |
| bitstream_buffer.AppendBool(sps.nal_hrd_parameters_present_flag); |
| if (sps.nal_hrd_parameters_present_flag) { |
| bitstream_buffer.AppendUE(sps.cpb_cnt_minus1); |
| bitstream_buffer.AppendBits(4, sps.bit_rate_scale); |
| bitstream_buffer.AppendBits(4, sps.cpb_size_scale); |
| CHECK_LT(base::checked_cast<size_t>(sps.cpb_cnt_minus1), |
| std::size(sps.bit_rate_value_minus1)); |
| for (int i = 0; i <= sps.cpb_cnt_minus1; ++i) { |
| bitstream_buffer.AppendUE(sps.bit_rate_value_minus1[i]); |
| bitstream_buffer.AppendUE(sps.cpb_size_value_minus1[i]); |
| bitstream_buffer.AppendBool(sps.cbr_flag[i]); |
| } |
| bitstream_buffer.AppendBits(5, |
| sps.initial_cpb_removal_delay_length_minus_1); |
| bitstream_buffer.AppendBits(5, sps.cpb_removal_delay_length_minus1); |
| bitstream_buffer.AppendBits(5, sps.dpb_output_delay_length_minus1); |
| bitstream_buffer.AppendBits(5, sps.time_offset_length); |
| } |
| |
| bitstream_buffer.AppendBool(false); // vcl_hrd_parameters_flag |
| if (sps.nal_hrd_parameters_present_flag) { |
| bitstream_buffer.AppendBool(sps.low_delay_hrd_flag); |
| } |
| |
| bitstream_buffer.AppendBool(false); // pic_struct_present_flag |
| bitstream_buffer.AppendBool(true); // bitstream_restriction_flag |
| |
| bitstream_buffer.AppendBool( |
| false); // motion_vectors_over_pic_boundaries_flag |
| bitstream_buffer.AppendUE(2); // max_bytes_per_pic_denom |
| bitstream_buffer.AppendUE(1); // max_bits_per_mb_denom |
| bitstream_buffer.AppendUE(16); // log2_max_mv_length_horizontal |
| bitstream_buffer.AppendUE(16); // log2_max_mv_length_vertical |
| |
| // Explicitly set max_num_reorder_frames to 0 to allow the decoder to |
| // output pictures early. |
| bitstream_buffer.AppendUE(0); // max_num_reorder_frames |
| |
| // The value of max_dec_frame_buffering shall be greater than or equal to |
| // max_num_ref_frames. |
| const unsigned int max_dec_frame_buffering = sps.max_num_ref_frames; |
| bitstream_buffer.AppendUE(max_dec_frame_buffering); |
| } |
| |
| bitstream_buffer.FinishNALU(); |
| } |
| |
| void BuildPackedH264PPS(H264BitstreamBuffer& bitstream_buffer, |
| const H264SPS& sps, |
| const H264PPS& pps) { |
| bitstream_buffer.BeginNALU(H264NALU::kPPS, 3); |
| |
| bitstream_buffer.AppendUE(pps.pic_parameter_set_id); |
| bitstream_buffer.AppendUE(pps.seq_parameter_set_id); |
| bitstream_buffer.AppendBool(pps.entropy_coding_mode_flag); |
| bitstream_buffer.AppendBool(pps.bottom_field_pic_order_in_frame_present_flag); |
| CHECK_EQ(pps.num_slice_groups_minus1, 0); |
| bitstream_buffer.AppendUE(pps.num_slice_groups_minus1); |
| |
| bitstream_buffer.AppendUE(pps.num_ref_idx_l0_default_active_minus1); |
| bitstream_buffer.AppendUE(pps.num_ref_idx_l1_default_active_minus1); |
| |
| bitstream_buffer.AppendBool(pps.weighted_pred_flag); |
| bitstream_buffer.AppendBits(2, pps.weighted_bipred_idc); |
| |
| bitstream_buffer.AppendSE(pps.pic_init_qp_minus26); |
| bitstream_buffer.AppendSE(pps.pic_init_qs_minus26); |
| bitstream_buffer.AppendSE(pps.chroma_qp_index_offset); |
| |
| bitstream_buffer.AppendBool(pps.deblocking_filter_control_present_flag); |
| bitstream_buffer.AppendBool(pps.constrained_intra_pred_flag); |
| bitstream_buffer.AppendBool(pps.redundant_pic_cnt_present_flag); |
| |
| if (sps.profile_idc >= H264SPS::kProfileIDCHigh) { |
| bitstream_buffer.AppendBool(pps.transform_8x8_mode_flag); |
| bitstream_buffer.AppendBool(pps.pic_scaling_matrix_present_flag); |
| // Ignoring the scaling matrix branch as we don't produce it. |
| CHECK(!pps.pic_scaling_matrix_present_flag); |
| bitstream_buffer.AppendSE(pps.second_chroma_qp_index_offset); |
| } |
| |
| bitstream_buffer.FinishNALU(); |
| } |
| |
| } // namespace media |