Module: Mesa Branch: main Commit: d46162981a78e24850dca085b2da95857c56a158 URL: http://cgit.freedesktop.org/mesa/mesa/commit/?id=d46162981a78e24850dca085b2da95857c56a158
Author: Dave Airlie <[email protected]> Date: Tue Oct 17 11:30:20 2023 +1000 vulkan/video: add h264 headers encode Vulkan video has parameter overrides, where the driver can override the driver provided parameters with an encoded bitstream where it has made changes. This is the support code to encode the bitstream headers for h264 from parameters (sps/pps). Reviewed-by: Hyunjun Ko <[email protected]> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/25874> --- src/vulkan/runtime/vk_video.c | 197 ++++++++++++++++++++++++++++++++++++++++++ src/vulkan/runtime/vk_video.h | 13 +++ 2 files changed, 210 insertions(+) diff --git a/src/vulkan/runtime/vk_video.c b/src/vulkan/runtime/vk_video.c index 436183623c3..033dc15f30c 100644 --- a/src/vulkan/runtime/vk_video.c +++ b/src/vulkan/runtime/vk_video.c @@ -27,6 +27,7 @@ #include "vk_alloc.h" #include "vk_device.h" #include "util/vl_rbsp.h" +#include "util/vl_bitstream.h" VkResult vk_video_session_init(struct vk_device *device, @@ -1366,4 +1367,200 @@ vk_video_get_h265_level(StdVideoH265LevelIdc level) return vk_video_h265_levels[level]; } +static void +emit_nalu_header(struct vl_bitstream_encoder *enc, + int nal_ref, int nal_unit) +{ + enc->prevent_start_code = false; + + vl_bitstream_put_bits(enc, 24, 0); + vl_bitstream_put_bits(enc, 8, 1); + vl_bitstream_put_bits(enc, 1, 0); + vl_bitstream_put_bits(enc, 2, nal_ref); /* SPS NAL REF */ + vl_bitstream_put_bits(enc, 5, nal_unit); /* SPS NAL UNIT */ + vl_bitstream_flush(enc); + + enc->prevent_start_code = true; +} + +static void +encode_hrd_params(struct vl_bitstream_encoder *enc, + const StdVideoH264HrdParameters *hrd) +{ + vl_bitstream_exp_golomb_ue(enc, hrd->cpb_cnt_minus1); + vl_bitstream_put_bits(enc, 4, hrd->bit_rate_scale); + vl_bitstream_put_bits(enc, 4, hrd->cpb_size_scale); + for (int sched_sel_idx = 0; sched_sel_idx <= hrd->cpb_cnt_minus1; sched_sel_idx++) { + vl_bitstream_exp_golomb_ue(enc, hrd->bit_rate_value_minus1[sched_sel_idx]); + vl_bitstream_exp_golomb_ue(enc, hrd->cpb_size_value_minus1[sched_sel_idx]); + vl_bitstream_put_bits(enc, 1, hrd->cbr_flag[sched_sel_idx]); + } + vl_bitstream_put_bits(enc, 5, hrd->initial_cpb_removal_delay_length_minus1); + vl_bitstream_put_bits(enc, 5, hrd->cpb_removal_delay_length_minus1); + vl_bitstream_put_bits(enc, 5, hrd->dpb_output_delay_length_minus1); + vl_bitstream_put_bits(enc, 5, hrd->time_offset_length); +} + +void +vk_video_encode_h264_sps(StdVideoH264SequenceParameterSet *sps, + size_t size_limit, + size_t *data_size_ptr, + void *data_ptr) +{ + struct vl_bitstream_encoder enc; + uint32_t data_size = *data_size_ptr; + + vl_bitstream_encoder_clear(&enc, data_ptr, data_size, size_limit); + + emit_nalu_header(&enc, 3, H264_NAL_SPS); + + vl_bitstream_put_bits(&enc, 8, sps->profile_idc); + vl_bitstream_put_bits(&enc, 1, sps->flags.constraint_set0_flag); + vl_bitstream_put_bits(&enc, 1, sps->flags.constraint_set1_flag); + vl_bitstream_put_bits(&enc, 1, sps->flags.constraint_set2_flag); + vl_bitstream_put_bits(&enc, 1, sps->flags.constraint_set3_flag); + vl_bitstream_put_bits(&enc, 1, sps->flags.constraint_set4_flag); + vl_bitstream_put_bits(&enc, 1, sps->flags.constraint_set5_flag); + vl_bitstream_put_bits(&enc, 2, 0); + vl_bitstream_put_bits(&enc, 8, vk_video_get_h264_level(sps->level_idc)); + vl_bitstream_exp_golomb_ue(&enc, sps->seq_parameter_set_id); + + if (sps->profile_idc == STD_VIDEO_H264_PROFILE_IDC_HIGH /* high10 as well */) { + vl_bitstream_exp_golomb_ue(&enc, sps->chroma_format_idc); + vl_bitstream_exp_golomb_ue(&enc, sps->bit_depth_luma_minus8); + vl_bitstream_exp_golomb_ue(&enc, sps->bit_depth_chroma_minus8); + vl_bitstream_put_bits(&enc, 1, sps->flags.qpprime_y_zero_transform_bypass_flag); + vl_bitstream_put_bits(&enc, 1, sps->flags.seq_scaling_matrix_present_flag); + } + + vl_bitstream_exp_golomb_ue(&enc, sps->log2_max_frame_num_minus4); + + vl_bitstream_exp_golomb_ue(&enc, sps->pic_order_cnt_type); + if (sps->pic_order_cnt_type == 0) + vl_bitstream_exp_golomb_ue(&enc, sps->log2_max_pic_order_cnt_lsb_minus4); + + vl_bitstream_exp_golomb_ue(&enc, sps->max_num_ref_frames); + vl_bitstream_put_bits(&enc, 1, sps->flags.gaps_in_frame_num_value_allowed_flag); + vl_bitstream_exp_golomb_ue(&enc, sps->pic_width_in_mbs_minus1); + vl_bitstream_exp_golomb_ue(&enc, sps->pic_height_in_map_units_minus1); + + vl_bitstream_put_bits(&enc, 1, sps->flags.frame_mbs_only_flag); + vl_bitstream_put_bits(&enc, 1, sps->flags.direct_8x8_inference_flag); + + vl_bitstream_put_bits(&enc, 1, sps->flags.frame_cropping_flag); + if (sps->flags.frame_cropping_flag) { + vl_bitstream_exp_golomb_ue(&enc, sps->frame_crop_left_offset); + vl_bitstream_exp_golomb_ue(&enc, sps->frame_crop_right_offset); + vl_bitstream_exp_golomb_ue(&enc, sps->frame_crop_top_offset); + vl_bitstream_exp_golomb_ue(&enc, sps->frame_crop_bottom_offset); + } + + vl_bitstream_put_bits(&enc, 1, sps->flags.vui_parameters_present_flag); /* vui parameters preseent flag */ + if (sps->flags.vui_parameters_present_flag) { + const StdVideoH264SequenceParameterSetVui *vui = sps->pSequenceParameterSetVui; + vl_bitstream_put_bits(&enc, 1, vui->flags.aspect_ratio_info_present_flag); + if (vui->flags.aspect_ratio_info_present_flag) { + vl_bitstream_put_bits(&enc, 8, vui->aspect_ratio_idc); + if (vui->aspect_ratio_idc == STD_VIDEO_H264_ASPECT_RATIO_IDC_EXTENDED_SAR) { + vl_bitstream_put_bits(&enc, 16, vui->sar_width); + vl_bitstream_put_bits(&enc, 16, vui->sar_height); + } + vl_bitstream_put_bits(&enc, 1, vui->flags.overscan_info_present_flag); + if (vui->flags.overscan_info_present_flag) + vl_bitstream_put_bits(&enc, 1, vui->flags.overscan_appropriate_flag); + vl_bitstream_put_bits(&enc, 1, vui->flags.video_signal_type_present_flag); + if (vui->flags.video_signal_type_present_flag) { + vl_bitstream_put_bits(&enc, 3, vui->video_format); + vl_bitstream_put_bits(&enc, 1, vui->flags.video_full_range_flag); + vl_bitstream_put_bits(&enc, 1, vui->flags.color_description_present_flag); + if (vui->flags.color_description_present_flag) { + vl_bitstream_put_bits(&enc, 8, vui->colour_primaries); + vl_bitstream_put_bits(&enc, 8, vui->transfer_characteristics); + vl_bitstream_put_bits(&enc, 8, vui->matrix_coefficients); + } + } + + vl_bitstream_put_bits(&enc, 1, vui->flags.chroma_loc_info_present_flag); + if (vui->flags.chroma_loc_info_present_flag) { + vl_bitstream_exp_golomb_ue(&enc, vui->chroma_sample_loc_type_top_field); + vl_bitstream_exp_golomb_ue(&enc, vui->chroma_sample_loc_type_bottom_field); + } + vl_bitstream_put_bits(&enc, 1, vui->flags.timing_info_present_flag); + if (vui->flags.timing_info_present_flag) { + vl_bitstream_put_bits(&enc, 32, vui->num_units_in_tick); + vl_bitstream_put_bits(&enc, 32, vui->time_scale); + vl_bitstream_put_bits(&enc, 32, vui->flags.fixed_frame_rate_flag); + } + vl_bitstream_put_bits(&enc, 1, vui->flags.nal_hrd_parameters_present_flag); + if (vui->flags.nal_hrd_parameters_present_flag) + encode_hrd_params(&enc, vui->pHrdParameters); + vl_bitstream_put_bits(&enc, 1, vui->flags.vcl_hrd_parameters_present_flag); + if (vui->flags.vcl_hrd_parameters_present_flag) + encode_hrd_params(&enc, vui->pHrdParameters); + if (vui->flags.nal_hrd_parameters_present_flag || vui->flags.vcl_hrd_parameters_present_flag) + vl_bitstream_put_bits(&enc, 1, 0); + vl_bitstream_put_bits(&enc, 1, 0); + vl_bitstream_put_bits(&enc, 1, vui->flags.bitstream_restriction_flag); + if (vui->flags.bitstream_restriction_flag) { + vl_bitstream_put_bits(&enc, 1, 0); + vl_bitstream_exp_golomb_ue(&enc, 0); + vl_bitstream_exp_golomb_ue(&enc, 0); + vl_bitstream_exp_golomb_ue(&enc, 0); + vl_bitstream_exp_golomb_ue(&enc, 0); + vl_bitstream_exp_golomb_ue(&enc, vui->max_num_reorder_frames); + vl_bitstream_exp_golomb_ue(&enc, vui->max_dec_frame_buffering); + } + } + } + vl_bitstream_rbsp_trailing(&enc); + + vl_bitstream_flush(&enc); + *data_size_ptr += vl_bitstream_get_byte_count(&enc); + vl_bitstream_encoder_free(&enc); +} + +void +vk_video_encode_h264_pps(StdVideoH264PictureParameterSet *pps, + bool high_profile, + size_t size_limit, + size_t *data_size_ptr, + void *data_ptr) +{ + struct vl_bitstream_encoder enc; + uint32_t data_size = *data_size_ptr; + + vl_bitstream_encoder_clear(&enc, data_ptr, data_size, size_limit); + + emit_nalu_header(&enc, 3, H264_NAL_SPS); + + vl_bitstream_exp_golomb_ue(&enc, pps->pic_parameter_set_id); + vl_bitstream_exp_golomb_ue(&enc, pps->seq_parameter_set_id); + vl_bitstream_put_bits(&enc, 1, pps->flags.entropy_coding_mode_flag); + vl_bitstream_put_bits(&enc, 1, pps->flags.bottom_field_pic_order_in_frame_present_flag); + vl_bitstream_exp_golomb_ue(&enc, 0); /* num_slice_groups_minus1 */ + + vl_bitstream_exp_golomb_ue(&enc, pps->num_ref_idx_l0_default_active_minus1); + vl_bitstream_exp_golomb_ue(&enc, pps->num_ref_idx_l1_default_active_minus1); + vl_bitstream_put_bits(&enc, 1, pps->flags.weighted_pred_flag); + vl_bitstream_put_bits(&enc, 2, pps->weighted_bipred_idc); + vl_bitstream_exp_golomb_se(&enc, pps->pic_init_qp_minus26); + vl_bitstream_exp_golomb_se(&enc, pps->pic_init_qs_minus26); + vl_bitstream_exp_golomb_se(&enc, pps->chroma_qp_index_offset); + vl_bitstream_put_bits(&enc, 1, pps->flags.deblocking_filter_control_present_flag); + vl_bitstream_put_bits(&enc, 1, pps->flags.constrained_intra_pred_flag); + vl_bitstream_put_bits(&enc, 1, pps->flags.redundant_pic_cnt_present_flag); + + /* high profile */ + if (high_profile) { + vl_bitstream_put_bits(&enc, 1, pps->flags.transform_8x8_mode_flag); + vl_bitstream_put_bits(&enc, 1, pps->flags.pic_scaling_matrix_present_flag); + vl_bitstream_exp_golomb_se(&enc, pps->second_chroma_qp_index_offset); + } + vl_bitstream_rbsp_trailing(&enc); + + vl_bitstream_flush(&enc); + *data_size_ptr += vl_bitstream_get_byte_count(&enc); + vl_bitstream_encoder_free(&enc); +} + #endif diff --git a/src/vulkan/runtime/vk_video.h b/src/vulkan/runtime/vk_video.h index 80573d2523b..1cc760b784a 100644 --- a/src/vulkan/runtime/vk_video.h +++ b/src/vulkan/runtime/vk_video.h @@ -252,6 +252,19 @@ const StdVideoH265PictureParameterSet * vk_video_find_h265_enc_std_pps(const struct vk_video_session_parameters *params, uint32_t id); +void +vk_video_encode_h264_sps(StdVideoH264SequenceParameterSet *sps, + size_t size_limit, + size_t *data_size_ptr, + void *data_ptr); + +void +vk_video_encode_h264_pps(StdVideoH264PictureParameterSet *pps, + bool high_profile, + size_t size_limit, + size_t *data_size_ptr, + void *data_ptr); + unsigned vk_video_get_h265_nal_unit(StdVideoH265PictureType pic_type, bool irap_pic_flag);
