From 2785d54b71c19a2f9d191af21794bf5b919d7952 Mon Sep 17 00:00:00 2001 From: David Rosca Date: Sun, 16 Jul 2023 20:26:18 +0200 Subject: [PATCH] frontends/va: Parse H264 SPS for video signal parameters Since packed headers support is now advertised for H264, it also fixes encoding into mkv with ffmpeg. Closes: https://gitlab.freedesktop.org/mesa/mesa/-/issues/3524 Reviewed-by: Ruijing Dong Part-of: --- src/gallium/frontends/va/config.c | 4 + src/gallium/frontends/va/picture.c | 13 ++ src/gallium/frontends/va/picture_h264_enc.c | 129 ++++++++++++++++++++ src/gallium/frontends/va/va_private.h | 1 + src/gallium/include/pipe/p_video_state.h | 7 ++ 5 files changed, 154 insertions(+) diff --git a/src/gallium/frontends/va/config.c b/src/gallium/frontends/va/config.c index 0e484763c13..84742148e3f 100644 --- a/src/gallium/frontends/va/config.c +++ b/src/gallium/frontends/va/config.c @@ -235,6 +235,8 @@ vlVaGetConfigAttributes(VADriverContextP ctx, VAProfile profile, VAEntrypoint en break; case VAConfigAttribEncPackedHeaders: value = VA_ENC_PACKED_HEADER_NONE; + if ((u_reduce_video_profile(ProfileToPipe(profile)) == PIPE_VIDEO_FORMAT_MPEG4_AVC)) + value |= VA_ENC_PACKED_HEADER_SEQUENCE; if ((u_reduce_video_profile(ProfileToPipe(profile)) == PIPE_VIDEO_FORMAT_HEVC)) value |= VA_ENC_PACKED_HEADER_SEQUENCE; else if (u_reduce_video_profile(ProfileToPipe(profile)) == PIPE_VIDEO_FORMAT_AV1) @@ -620,6 +622,8 @@ vlVaCreateConfig(VADriverContextP ctx, VAProfile profile, VAEntrypoint entrypoin if (attrib_list[i].type == VAConfigAttribEncPackedHeaders) { if (config->entrypoint != PIPE_VIDEO_ENTRYPOINT_ENCODE || (((attrib_list[i].value != 0)) && + ((attrib_list[i].value != 1) || u_reduce_video_profile(ProfileToPipe(profile)) + != PIPE_VIDEO_FORMAT_MPEG4_AVC) && ((attrib_list[i].value != 1) || u_reduce_video_profile(ProfileToPipe(profile)) != PIPE_VIDEO_FORMAT_HEVC) && ((attrib_list[i].value != 3) || u_reduce_video_profile(ProfileToPipe(profile)) diff --git a/src/gallium/frontends/va/picture.c b/src/gallium/frontends/va/picture.c index 737a1d1b301..76220dcfb1b 100644 --- a/src/gallium/frontends/va/picture.c +++ b/src/gallium/frontends/va/picture.c @@ -702,6 +702,12 @@ handleVAEncPackedHeaderParameterBufferType(vlVaContext *context, vlVaBuffer *buf VAEncPackedHeaderParameterBuffer *param = buf->data; switch (u_reduce_video_profile(context->templat.profile)) { + case PIPE_VIDEO_FORMAT_MPEG4_AVC: + if (param->type == VAEncPackedHeaderSequence) + context->packed_header_type = param->type; + else + status = VA_STATUS_ERROR_UNIMPLEMENTED; + break; case PIPE_VIDEO_FORMAT_HEVC: if (param->type == VAEncPackedHeaderSequence) context->packed_header_type = param->type; @@ -725,6 +731,13 @@ handleVAEncPackedHeaderDataBufferType(vlVaContext *context, vlVaBuffer *buf) VAStatus status = VA_STATUS_SUCCESS; switch (u_reduce_video_profile(context->templat.profile)) { + case PIPE_VIDEO_FORMAT_MPEG4_AVC: + if (context->packed_header_type != VAEncPackedHeaderSequence) + return VA_STATUS_ERROR_UNIMPLEMENTED; + + status = vlVaHandleVAEncPackedHeaderDataBufferTypeH264(context, buf); + break; + case PIPE_VIDEO_FORMAT_HEVC: if (context->packed_header_type != VAEncPackedHeaderSequence) return VA_STATUS_ERROR_UNIMPLEMENTED; diff --git a/src/gallium/frontends/va/picture_h264_enc.c b/src/gallium/frontends/va/picture_h264_enc.c index 28084c82cbb..1db984c90b5 100644 --- a/src/gallium/frontends/va/picture_h264_enc.c +++ b/src/gallium/frontends/va/picture_h264_enc.c @@ -29,6 +29,13 @@ #include "util/u_video.h" #include "va_private.h" +#include "util/vl_rbsp.h" + +enum H264NALUnitType { + H264_NAL_SPS = 7, + H264_NAL_PPS = 8, +}; + VAStatus vlVaHandleVAEncPictureParameterBufferTypeH264(vlVaDriver *drv, vlVaContext *context, vlVaBuffer *buf) { @@ -311,6 +318,128 @@ vlVaHandleVAEncMiscParameterTypeFrameRateH264(vlVaContext *context, VAEncMiscPar return VA_STATUS_SUCCESS; } +static void parseEncSpsParamsH264(vlVaContext *context, struct vl_rbsp *rbsp) +{ + unsigned i, profile_idc, num_ref_frames_in_pic_order_cnt_cycle; + + profile_idc = vl_rbsp_u(rbsp, 8); + + vl_rbsp_u(rbsp, 8); /* constraint_set_flags */ + vl_rbsp_u(rbsp, 8); /* level_idc */ + + vl_rbsp_ue(rbsp); /* 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 || profile_idc == 138 || profile_idc == 139 || + profile_idc == 134 || profile_idc == 135) { + + if (vl_rbsp_ue(rbsp) == 3) /* chroma_format_idc */ + vl_rbsp_u(rbsp, 1); /* separate_colour_plane_flag */ + + vl_rbsp_ue(rbsp); /* bit_depth_luma_minus8 */ + vl_rbsp_ue(rbsp); /* bit_depth_chroma_minus8 */ + vl_rbsp_u(rbsp, 1); /* qpprime_y_zero_transform_bypass_flag */ + + if (vl_rbsp_u(rbsp, 1)) /* seq_scaling_matrix_present_flag */ + return; /* TODO */ + } + + vl_rbsp_ue(rbsp); /* log2_max_frame_num_minus4 */ + vl_rbsp_ue(rbsp); /* pic_order_cnt_type */ + + if (context->desc.h264enc.seq.pic_order_cnt_type == 0) + vl_rbsp_ue(rbsp); /* log2_max_pic_order_cnt_lsb_minus4 */ + else if (context->desc.h264enc.seq.pic_order_cnt_type == 1) { + vl_rbsp_u(rbsp, 1); /* delta_pic_order_always_zero_flag */ + vl_rbsp_se(rbsp); /* offset_for_non_ref_pic */ + vl_rbsp_se(rbsp); /* offset_for_top_to_bottom_field */ + num_ref_frames_in_pic_order_cnt_cycle = vl_rbsp_ue(rbsp); + for (i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; ++i) + vl_rbsp_se(rbsp); /* offset_for_ref_frame[i] */ + } + + vl_rbsp_ue(rbsp); /* max_num_ref_frames */ + vl_rbsp_u(rbsp, 1); /* gaps_in_frame_num_value_allowed_flag */ + vl_rbsp_ue(rbsp); /* pic_width_in_mbs_minus1 */ + vl_rbsp_ue(rbsp); /* pic_height_in_map_units_minus1 */ + if (!vl_rbsp_u(rbsp, 1)) /* frame_mbs_only_flag */ + vl_rbsp_u(rbsp, 1); /* mb_adaptive_frame_field_flag */ + + vl_rbsp_u(rbsp, 1); /* direct_8x8_inference_flag */ + if (vl_rbsp_u(rbsp, 1)) { /* frame_cropping_flag */ + vl_rbsp_ue(rbsp); /* frame_crop_left_offset */ + vl_rbsp_ue(rbsp); /* frame_crop_right_offset */ + vl_rbsp_ue(rbsp); /* frame_crop_top_offset */ + vl_rbsp_ue(rbsp); /* frame_crop_bottom_offset */ + } + + context->desc.h264enc.seq.vui_parameters_present_flag = vl_rbsp_u(rbsp, 1); + if (context->desc.h264enc.seq.vui_parameters_present_flag) { + context->desc.h264enc.seq.vui_flags.aspect_ratio_info_present_flag = vl_rbsp_u(rbsp, 1); + if (context->desc.h264enc.seq.vui_flags.aspect_ratio_info_present_flag) { + if (vl_rbsp_u(rbsp, 8) == 255) { /* aspect_ratio_idc == Extended_SAR */ + vl_rbsp_u(rbsp, 16); /* sar_width */ + vl_rbsp_u(rbsp, 16); /* sar_height */ + } + } + + if (vl_rbsp_u(rbsp, 1)) /* overscan_info_present_flag */ + vl_rbsp_u(rbsp, 1); /* overscan_appropriate_flag */ + + context->desc.h264enc.seq.vui_flags.video_signal_type_present_flag = vl_rbsp_u(rbsp, 1); + if (context->desc.h264enc.seq.vui_flags.video_signal_type_present_flag) { + context->desc.h264enc.seq.video_format = vl_rbsp_u(rbsp, 3); + context->desc.h264enc.seq.video_full_range_flag = vl_rbsp_u(rbsp, 1); + context->desc.h264enc.seq.vui_flags.colour_description_present_flag = vl_rbsp_u(rbsp, 1); + if (context->desc.h264enc.seq.vui_flags.colour_description_present_flag) { + context->desc.h264enc.seq.colour_primaries = vl_rbsp_u(rbsp, 8); + context->desc.h264enc.seq.transfer_characteristics = vl_rbsp_u(rbsp, 8); + context->desc.h264enc.seq.matrix_coefficients = vl_rbsp_u(rbsp, 8); + } + } + } +} + +VAStatus +vlVaHandleVAEncPackedHeaderDataBufferTypeH264(vlVaContext *context, vlVaBuffer *buf) +{ + struct vl_vlc vlc = {0}; + vl_vlc_init(&vlc, 1, (const void * const*)&buf->data, &buf->size); + + while (vl_vlc_bits_left(&vlc) > 0) { + /* search the first 64 bytes for a startcode */ + for (int i = 0; i < 64 && vl_vlc_bits_left(&vlc) >= 24; ++i) { + if (vl_vlc_peekbits(&vlc, 24) == 0x000001) + break; + vl_vlc_eatbits(&vlc, 8); + vl_vlc_fillbits(&vlc); + } + vl_vlc_eatbits(&vlc, 24); /* eat the startcode */ + + if (vl_vlc_valid_bits(&vlc) < 15) + vl_vlc_fillbits(&vlc); + + vl_vlc_eatbits(&vlc, 3); + unsigned nal_unit_type = vl_vlc_get_uimsbf(&vlc, 5); + + struct vl_rbsp rbsp; + vl_rbsp_init(&rbsp, &vlc, ~0); + + switch(nal_unit_type) { + case H264_NAL_SPS: + parseEncSpsParamsH264(context, &rbsp); + break; + case H264_NAL_PPS: + default: + break; + } + } + + return VA_STATUS_SUCCESS; +} + VAStatus vlVaHandleVAEncMiscParameterTypeTemporalLayerH264(vlVaContext *context, VAEncMiscParameterBuffer *misc) { diff --git a/src/gallium/frontends/va/va_private.h b/src/gallium/frontends/va/va_private.h index 33c48eea910..2341efe47c6 100644 --- a/src/gallium/frontends/va/va_private.h +++ b/src/gallium/frontends/va/va_private.h @@ -540,6 +540,7 @@ VAStatus vlVaHandleVAEncSliceParameterBufferTypeH264(vlVaDriver *drv, vlVaContex VAStatus vlVaHandleVAEncSequenceParameterBufferTypeH264(vlVaDriver *drv, vlVaContext *context, vlVaBuffer *buf); VAStatus vlVaHandleVAEncMiscParameterTypeRateControlH264(vlVaContext *context, VAEncMiscParameterBuffer *buf); VAStatus vlVaHandleVAEncMiscParameterTypeFrameRateH264(vlVaContext *context, VAEncMiscParameterBuffer *buf); +VAStatus vlVaHandleVAEncPackedHeaderDataBufferTypeH264(vlVaContext *context, vlVaBuffer *buf); VAStatus vlVaHandleVAEncMiscParameterTypeTemporalLayerH264(vlVaContext *context, VAEncMiscParameterBuffer *buf); VAStatus vlVaHandleVAEncMiscParameterTypeQualityLevelH264(vlVaContext *context, VAEncMiscParameterBuffer *buf); VAStatus vlVaHandleVAEncMiscParameterTypeMaxFrameSizeH264(vlVaContext *context, VAEncMiscParameterBuffer *buf); diff --git a/src/gallium/include/pipe/p_video_state.h b/src/gallium/include/pipe/p_video_state.h index deae42d1cf7..4da7467a904 100644 --- a/src/gallium/include/pipe/p_video_state.h +++ b/src/gallium/include/pipe/p_video_state.h @@ -511,12 +511,19 @@ struct pipe_h264_enc_seq_param struct { uint32_t aspect_ratio_info_present_flag: 1; uint32_t timing_info_present_flag: 1; + uint32_t video_signal_type_present_flag: 1; + uint32_t colour_description_present_flag: 1; } vui_flags; uint32_t aspect_ratio_idc; uint32_t sar_width; uint32_t sar_height; uint32_t num_units_in_tick; uint32_t time_scale; + uint32_t video_format; + uint32_t video_full_range_flag; + uint32_t colour_primaries; + uint32_t transfer_characteristics; + uint32_t matrix_coefficients; }; struct pipe_h264_enc_picture_desc