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);
 

Reply via email to