From 8a5ef9413b840af27c3ae0cafc7507cacdcf8d50 Mon Sep 17 00:00:00 2001 From: Ruijing Dong Date: Tue, 16 Jul 2024 22:02:27 -0400 Subject: [PATCH] radeonsi/vcn: add HDR metadata obu in av1enc Enable HDR metadata obu in av1 encoder for both vcn4/5. Reviewed-by: David Rosca Signed-off-by: Ruijing Dong Part-of: --- src/amd/common/ac_vcn_enc.h | 5 + src/gallium/drivers/radeonsi/radeon_vcn_enc.c | 3 - src/gallium/drivers/radeonsi/radeon_vcn_enc.h | 2 + .../drivers/radeonsi/radeon_vcn_enc_4_0.c | 100 ++++++++++++++++++ .../drivers/radeonsi/radeon_vcn_enc_5_0.c | 1 + src/gallium/frontends/va/picture.c | 14 +++ 6 files changed, 122 insertions(+), 3 deletions(-) diff --git a/src/amd/common/ac_vcn_enc.h b/src/amd/common/ac_vcn_enc.h index a0a6849a4e9..80bac3f124c 100644 --- a/src/amd/common/ac_vcn_enc.h +++ b/src/amd/common/ac_vcn_enc.h @@ -115,6 +115,11 @@ #define RENCODE_OBU_TYPE_TILE_LIST 8 #define RENCODE_OBU_TYPE_PADDING 15 +#define RENCODE_METADATA_TYPE_HDR_CLL 1 +#define RENCODE_METADATA_TYPE_HDR_MDCV 2 +#define RENCODE_METADATA_TYPE_ITUT_T35 4 +#define RENCODE_METADATA_TYPE_TIMECODE 5 + #define RENCODE_AV1_MV_PRECISION_ALLOW_HIGH_PRECISION 0x00 #define RENCODE_AV1_MV_PRECISION_DISALLOW_HIGH_PRECISION 0x10 #define RENCODE_AV1_MV_PRECISION_FORCE_INTEGER_MV 0x30 diff --git a/src/gallium/drivers/radeonsi/radeon_vcn_enc.c b/src/gallium/drivers/radeonsi/radeon_vcn_enc.c index ee63845437a..ce16716372d 100644 --- a/src/gallium/drivers/radeonsi/radeon_vcn_enc.c +++ b/src/gallium/drivers/radeonsi/radeon_vcn_enc.c @@ -892,9 +892,6 @@ static void radeon_vcn_enc_av1_get_meta_param(struct radeon_encoder *enc, enc->enc_pic.enc_sei.hdr_mdcv.luminance_min = pic->metadata_hdr_mdcv.luminance_min; } - - /* meta data per picture will need to clear it after fetching it up */ - pic->metadata_flags.value = 0; } static void radeon_vcn_enc_av1_get_param(struct radeon_encoder *enc, diff --git a/src/gallium/drivers/radeonsi/radeon_vcn_enc.h b/src/gallium/drivers/radeonsi/radeon_vcn_enc.h index b7513a460ac..5dbe54a6676 100644 --- a/src/gallium/drivers/radeonsi/radeon_vcn_enc.h +++ b/src/gallium/drivers/radeonsi/radeon_vcn_enc.h @@ -364,6 +364,8 @@ void radeon_enc_av1_sequence_header(struct radeon_encoder *enc, bool separate_de void radeon_enc_av1_tile_group(struct radeon_encoder *enc); +void radeon_enc_av1_metadata_obu(struct radeon_encoder *enc); + unsigned char *radeon_enc_av1_header_size_offset(struct radeon_encoder *enc); unsigned int radeon_enc_value_bits(unsigned int value); diff --git a/src/gallium/drivers/radeonsi/radeon_vcn_enc_4_0.c b/src/gallium/drivers/radeonsi/radeon_vcn_enc_4_0.c index 0e147bdb519..6e866e86c49 100644 --- a/src/gallium/drivers/radeonsi/radeon_vcn_enc_4_0.c +++ b/src/gallium/drivers/radeonsi/radeon_vcn_enc_4_0.c @@ -943,6 +943,105 @@ void radeon_enc_av1_tile_group(struct radeon_encoder *enc) radeon_enc_av1_bs_instruction_type(enc, RENCODE_AV1_BITSTREAM_INSTRUCTION_OBU_END, 0); } +static void radeon_enc_av1_metadata_obu_hdr_cll(struct radeon_encoder *enc) +{ + uint8_t *size_offset; + uint8_t obu_size_bin; + uint8_t metadata_type; + uint8_t *p; + uint32_t obu_size; + uint32_t nb_obu_size_byte = sizeof(obu_size_bin); + rvcn_enc_sei_hdr_cll_t *p_cll = &enc->enc_pic.enc_sei.hdr_cll; + + radeon_enc_av1_obu_header(enc, RENCODE_OBU_TYPE_METADATA); + /* obu_size, use nb_obu_size_byte bytes for header, + * the size will be written in afterwards */ + size_offset = radeon_enc_av1_header_size_offset(enc); + radeon_enc_code_fixed_bits(enc, 0, nb_obu_size_byte * 8); + radeon_enc_code_leb128(&metadata_type, RENCODE_METADATA_TYPE_HDR_CLL, 1); + radeon_enc_code_fixed_bits(enc, metadata_type, 8); + + radeon_enc_code_fixed_bits(enc, p_cll->max_cll, 16); + radeon_enc_code_fixed_bits(enc, p_cll->max_fall, 16); + + /* trailing_one_bit */ + radeon_enc_code_fixed_bits(enc, 1, 1); + radeon_enc_byte_align(enc); + + /* obu_size doesn't include the bytes within obu_header + * or obu_size syntax element (6.2.1), here we use + * nb_obu_size_byte bytes for obu_size syntax + * which needs to be removed from the size. + */ + obu_size = (uint32_t)(radeon_enc_av1_header_size_offset(enc) + - size_offset - nb_obu_size_byte); + + radeon_enc_code_leb128(&obu_size_bin, obu_size, nb_obu_size_byte); + + p = (uint8_t *)((((uintptr_t)size_offset & 3) ^ 3) | ((uintptr_t)size_offset & ~3)); + *p = obu_size_bin; +} + +static void radeon_enc_av1_metadata_obu_hdr_mdcv(struct radeon_encoder *enc) +{ + uint8_t *size_offset; + uint8_t obu_size_bin; + uint8_t metadata_type; + uint8_t *p; + uint32_t obu_size; + uint32_t nb_obu_size_byte = sizeof(obu_size_bin); + rvcn_enc_sei_hdr_mdcv_t *p_mdcv = &enc->enc_pic.enc_sei.hdr_mdcv; + + radeon_enc_av1_obu_header(enc, RENCODE_OBU_TYPE_METADATA); + /* obu_size, use nb_obu_size_byte bytes for header, + * the size will be written in afterwards */ + size_offset = radeon_enc_av1_header_size_offset(enc); + radeon_enc_code_fixed_bits(enc, 0, nb_obu_size_byte * 8); + radeon_enc_code_leb128(&metadata_type, RENCODE_METADATA_TYPE_HDR_MDCV, 1); + radeon_enc_code_fixed_bits(enc, metadata_type, 8); + + for (int32_t i = 0; i < 3; i++) { + radeon_enc_code_fixed_bits(enc, p_mdcv->primary_chromaticity_x[i], 16); + radeon_enc_code_fixed_bits(enc, p_mdcv->primary_chromaticity_y[i], 16); + } + + radeon_enc_code_fixed_bits(enc, p_mdcv->white_point_chromaticity_x, 16); + radeon_enc_code_fixed_bits(enc, p_mdcv->white_point_chromaticity_y, 16); + + radeon_enc_code_fixed_bits(enc, p_mdcv->luminance_max, 32); + radeon_enc_code_fixed_bits(enc, p_mdcv->luminance_min, 32); + + /* trailing_one_bit */ + radeon_enc_code_fixed_bits(enc, 1, 1); + radeon_enc_byte_align(enc); + + /* obu_size doesn't include the bytes within obu_header + * or obu_size syntax element (6.2.1), here we use + * nb_obu_size_byte bytes for obu_size syntax + * which needs to be removed from the size. + */ + obu_size = (uint32_t)(radeon_enc_av1_header_size_offset(enc) + - size_offset - nb_obu_size_byte); + + radeon_enc_code_leb128(&obu_size_bin, obu_size, nb_obu_size_byte); + + p = (uint8_t *)((((uintptr_t)size_offset & 3) ^ 3) | ((uintptr_t)size_offset & ~3)); + *p = obu_size_bin; +} + +void radeon_enc_av1_metadata_obu(struct radeon_encoder *enc) +{ + if (!enc->enc_pic.enc_sei.flags.value) + return; + + if (enc->enc_pic.enc_sei.flags.hdr_mdcv) + radeon_enc_av1_metadata_obu_hdr_mdcv(enc); + + if (enc->enc_pic.enc_sei.flags.hdr_cll) + radeon_enc_av1_metadata_obu_hdr_cll(enc); + +} + static void radeon_enc_obu_instruction(struct radeon_encoder *enc) { bool frame_header = !enc->enc_pic.stream_obu_frame || @@ -959,6 +1058,7 @@ static void radeon_enc_obu_instruction(struct radeon_encoder *enc) * * if (others) * radeon_enc_av1_others(enc); */ + radeon_enc_av1_metadata_obu(enc); radeon_enc_av1_bs_instruction_type(enc, RENCODE_AV1_BITSTREAM_INSTRUCTION_OBU_START, diff --git a/src/gallium/drivers/radeonsi/radeon_vcn_enc_5_0.c b/src/gallium/drivers/radeonsi/radeon_vcn_enc_5_0.c index bfbbc42c21c..a9f98fa97a1 100644 --- a/src/gallium/drivers/radeonsi/radeon_vcn_enc_5_0.c +++ b/src/gallium/drivers/radeonsi/radeon_vcn_enc_5_0.c @@ -977,6 +977,7 @@ static void radeon_enc_obu_instruction(struct radeon_encoder *enc) * * if (others) * radeon_enc_av1_others(enc); */ + radeon_enc_av1_metadata_obu(enc); radeon_enc_av1_bs_instruction_type(enc, RENCODE_AV1_BITSTREAM_INSTRUCTION_OBU_START, diff --git a/src/gallium/frontends/va/picture.c b/src/gallium/frontends/va/picture.c index f816b7fb922..0263baa1906 100644 --- a/src/gallium/frontends/va/picture.c +++ b/src/gallium/frontends/va/picture.c @@ -140,6 +140,20 @@ vlVaBeginPicture(VADriverContextP ctx, VAContextID context_id, VASurfaceID rende if (context->decoder->entrypoint != PIPE_VIDEO_ENTRYPOINT_ENCODE) context->needs_begin_frame = true; + /* meta data and seis are per picture basis, it needs to be + * cleared before rendering the picture. */ + if (context->decoder->entrypoint == PIPE_VIDEO_ENTRYPOINT_ENCODE) { + switch (u_reduce_video_profile(context->templat.profile)) { + case PIPE_VIDEO_FORMAT_AV1: + context->desc.av1enc.metadata_flags.value = 0; + break; + case PIPE_VIDEO_FORMAT_HEVC: + case PIPE_VIDEO_FORMAT_MPEG4_AVC: + default: + break; + } + } + context->slice_data_offset = 0; context->have_slice_params = false;