// 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/h265_builder.h"
#include "media/filters/h26x_annex_b_bitstream_builder.h"
namespace media {
void BuildPackedH265ProfileTierLevel(
H26xAnnexBBitstreamBuilder& builder,
const H265ProfileTierLevel& profile_tier_level,
bool profile_present_flag,
uint8_t max_num_sub_layers_minus1) {
// 7.3.3 Profile, tier and level syntax
if (profile_present_flag) {
builder.AppendBits(2, 0); // general_profile_space
builder.AppendBits(1, 0); // general_tier_flag
builder.AppendBits(5, profile_tier_level.general_profile_idc);
builder.AppendBits(32,
profile_tier_level.general_profile_compatibility_flags);
builder.AppendBits(1, profile_tier_level.general_progressive_source_flag);
builder.AppendBits(1, profile_tier_level.general_interlaced_source_flag);
builder.AppendBits(1,
profile_tier_level.general_non_packed_constraint_flag);
builder.AppendBits(1,
profile_tier_level.general_frame_only_constraint_flag);
CHECK_LT(profile_tier_level.general_profile_idc, 4);
// Check general_profile_compatibility_flag[ 2 ] == 0
CHECK(!(profile_tier_level.general_profile_compatibility_flags & 1 << 29));
builder.AppendBits(43, 0); // general_reserved_zero_43bits
builder.AppendBits(1, 0); // general_inbld_flag
}
builder.AppendBits(8, profile_tier_level.general_level_idc);
CHECK_EQ(max_num_sub_layers_minus1, 0);
}
void BuildPackedH265VPS(H26xAnnexBBitstreamBuilder& builder,
const H265VPS& vps) {
// 7.3.2.1 Video parameter set RBSP syntax
builder.BeginNALU(H265NALU::VPS_NUT);
builder.AppendBits(4, vps.vps_video_parameter_set_id);
builder.AppendBits(1, vps.vps_base_layer_internal_flag);
builder.AppendBits(1, vps.vps_base_layer_available_flag);
builder.AppendBits(6, vps.vps_max_layers_minus1);
builder.AppendBits(3, vps.vps_max_sub_layers_minus1);
builder.AppendBits(1, vps.vps_temporal_id_nesting_flag);
builder.AppendBits(16, 0xffff); // vps_reserved_0xffff_16bits
BuildPackedH265ProfileTierLevel(builder, vps.profile_tier_level, true,
vps.vps_max_sub_layers_minus1);
builder.AppendBits(1, 0); // vps_sub_layer_ordering_info_present_flag
{
int i = vps.vps_max_sub_layers_minus1;
builder.AppendUE(vps.vps_max_dec_pic_buffering_minus1[i]);
builder.AppendUE(vps.vps_max_num_reorder_pics[i]);
builder.AppendUE(vps.vps_max_latency_increase_plus1[i]);
}
builder.AppendBits(6, vps.vps_max_layer_id);
CHECK_EQ(vps.vps_num_layer_sets_minus1, 0);
builder.AppendUE(vps.vps_num_layer_sets_minus1);
builder.AppendBits(1, 0); // vps_timing_info_present_flag
builder.AppendBits(1, 0); // vps_extension_flag
builder.FinishNALU();
}
void BuildPackedH265SPS(H26xAnnexBBitstreamBuilder& builder,
const H265SPS& sps) {
// 7.3.2.2.1 General sequence parameter set RBSP syntax
builder.BeginNALU(H265NALU::SPS_NUT);
builder.AppendBits(4, sps.sps_video_parameter_set_id);
builder.AppendBits(3, sps.sps_max_sub_layers_minus1);
builder.AppendBits(1, sps.sps_temporal_id_nesting_flag);
BuildPackedH265ProfileTierLevel(builder, sps.profile_tier_level, true,
sps.sps_max_sub_layers_minus1);
builder.AppendUE(sps.sps_seq_parameter_set_id);
builder.AppendUE(sps.chroma_format_idc);
if (sps.chroma_format_idc == 3) {
builder.AppendBits(1, sps.separate_colour_plane_flag);
}
builder.AppendUE(sps.pic_width_in_luma_samples);
builder.AppendUE(sps.pic_height_in_luma_samples);
bool conformance_window_flag =
sps.conf_win_left_offset > 0 || sps.conf_win_right_offset > 0 ||
sps.conf_win_top_offset > 0 || sps.conf_win_bottom_offset > 0;
builder.AppendBits(1, conformance_window_flag);
if (conformance_window_flag) {
builder.AppendUE(sps.conf_win_left_offset);
builder.AppendUE(sps.conf_win_right_offset);
builder.AppendUE(sps.conf_win_top_offset);
builder.AppendUE(sps.conf_win_bottom_offset);
}
builder.AppendUE(sps.bit_depth_luma_minus8);
builder.AppendUE(sps.bit_depth_chroma_minus8);
builder.AppendUE(sps.log2_max_pic_order_cnt_lsb_minus4);
builder.AppendBits(1, 0); // sps_sub_layer_ordering_info_present_flag
{
int i = sps.sps_max_sub_layers_minus1;
builder.AppendUE(sps.sps_max_dec_pic_buffering_minus1[i]);
builder.AppendUE(sps.sps_max_num_reorder_pics[i]);
builder.AppendUE(sps.sps_max_latency_increase_plus1[i]);
}
builder.AppendUE(sps.log2_min_luma_coding_block_size_minus3);
builder.AppendUE(sps.log2_diff_max_min_luma_coding_block_size);
builder.AppendUE(sps.log2_min_luma_transform_block_size_minus2);
builder.AppendUE(sps.log2_diff_max_min_luma_transform_block_size);
builder.AppendUE(sps.max_transform_hierarchy_depth_inter);
builder.AppendUE(sps.max_transform_hierarchy_depth_intra);
builder.AppendBits(1, sps.scaling_list_enabled_flag);
CHECK(!sps.scaling_list_enabled_flag);
builder.AppendBits(1, sps.amp_enabled_flag);
builder.AppendBits(1, sps.sample_adaptive_offset_enabled_flag);
builder.AppendBits(1, sps.pcm_enabled_flag);
if (sps.pcm_enabled_flag) {
builder.AppendBits(4, sps.pcm_sample_bit_depth_luma_minus1);
builder.AppendBits(4, sps.pcm_sample_bit_depth_chroma_minus1);
builder.AppendUE(sps.log2_min_pcm_luma_coding_block_size_minus3);
builder.AppendUE(sps.log2_diff_max_min_pcm_luma_coding_block_size);
builder.AppendBits(1, sps.pcm_loop_filter_disabled_flag);
}
builder.AppendUE(sps.num_short_term_ref_pic_sets);
CHECK_EQ(sps.num_short_term_ref_pic_sets, 0);
builder.AppendBits(1, sps.long_term_ref_pics_present_flag);
if (sps.long_term_ref_pics_present_flag) {
builder.AppendUE(sps.num_long_term_ref_pics_sps);
for (int i = 0; i < sps.num_long_term_ref_pics_sps; i++) {
builder.AppendBits(sps.log2_max_pic_order_cnt_lsb_minus4 + 4,
sps.lt_ref_pic_poc_lsb_sps[i]);
builder.AppendBits(1, sps.used_by_curr_pic_lt_sps_flag[i]);
}
}
builder.AppendBits(1, sps.sps_temporal_mvp_enabled_flag);
builder.AppendBits(1, sps.strong_intra_smoothing_enabled_flag);
builder.AppendBits(1, 0); // vui_parameters_present_flag
builder.AppendBits(1, 0); // sps_extension_present_flag
builder.FinishNALU();
}
void BuildPackedH265PPS(H26xAnnexBBitstreamBuilder& builder,
const H265PPS& pps) {
// 7.3.2.3.1 General picture parameter set RBSP syntax
builder.BeginNALU(H265NALU::PPS_NUT);
builder.AppendUE(pps.pps_pic_parameter_set_id);
builder.AppendUE(pps.pps_seq_parameter_set_id);
builder.AppendBits(1, pps.dependent_slice_segments_enabled_flag);
builder.AppendBits(1, pps.output_flag_present_flag);
builder.AppendBits(3, pps.num_extra_slice_header_bits);
builder.AppendBits(1, pps.sign_data_hiding_enabled_flag);
builder.AppendBits(1, pps.cabac_init_present_flag);
builder.AppendUE(pps.num_ref_idx_l0_default_active_minus1);
builder.AppendUE(pps.num_ref_idx_l1_default_active_minus1);
builder.AppendSE(pps.init_qp_minus26);
builder.AppendBits(1, pps.constrained_intra_pred_flag);
builder.AppendBits(1, pps.transform_skip_enabled_flag);
builder.AppendBits(1, pps.cu_qp_delta_enabled_flag);
if (pps.cu_qp_delta_enabled_flag) {
builder.AppendUE(pps.diff_cu_qp_delta_depth);
}
builder.AppendSE(pps.pps_cb_qp_offset);
builder.AppendSE(pps.pps_cr_qp_offset);
builder.AppendBits(1, pps.pps_slice_chroma_qp_offsets_present_flag);
builder.AppendBits(1, pps.weighted_pred_flag);
builder.AppendBits(1, pps.weighted_bipred_flag);
builder.AppendBits(1, pps.transquant_bypass_enabled_flag);
builder.AppendBits(1, pps.tiles_enabled_flag);
builder.AppendBits(1, pps.entropy_coding_sync_enabled_flag);
if (pps.tiles_enabled_flag) {
builder.AppendUE(pps.num_tile_columns_minus1);
builder.AppendUE(pps.num_tile_rows_minus1);
builder.AppendBits(1, pps.uniform_spacing_flag);
if (!pps.uniform_spacing_flag) {
for (int i = 0; i < pps.num_tile_columns_minus1; i++) {
builder.AppendUE(pps.column_width_minus1[i]);
}
for (int i = 0; i < pps.num_tile_rows_minus1; i++) {
builder.AppendUE(pps.row_height_minus1[i]);
}
}
builder.AppendBits(1, pps.loop_filter_across_tiles_enabled_flag);
}
builder.AppendBits(1, pps.pps_loop_filter_across_slices_enabled_flag);
builder.AppendBits(1, pps.deblocking_filter_control_present_flag);
if (pps.deblocking_filter_control_present_flag) {
builder.AppendBits(1, pps.deblocking_filter_override_enabled_flag);
builder.AppendBits(1, pps.pps_deblocking_filter_disabled_flag);
if (!pps.pps_deblocking_filter_disabled_flag) {
builder.AppendSE(pps.pps_beta_offset_div2);
builder.AppendSE(pps.pps_tc_offset_div2);
}
}
builder.AppendBits(1, pps.pps_scaling_list_data_present_flag);
CHECK(!pps.pps_scaling_list_data_present_flag);
builder.AppendBits(1, pps.lists_modification_present_flag);
builder.AppendUE(pps.log2_parallel_merge_level_minus2);
builder.AppendBits(1, pps.slice_segment_header_extension_present_flag);
builder.AppendBits(1, pps.pps_extension_present_flag);
CHECK(!pps.pps_extension_present_flag);
builder.FinishNALU();
}
} // namespace media