From 5edbecb8569d88e7faa28ca7a56eb5e1672a2dd0 Mon Sep 17 00:00:00 2001 From: Ruijing Dong Date: Wed, 19 Apr 2023 14:01:50 -0400 Subject: [PATCH] frontends/va: adding va av1 encoding functions supported features: - 8/10 bit encoding - multi-layer (up to 4) encoding - vbr/cbr rate control mode Reviewed-by: Sil Vilerino Reviewed-by: Boyuan Zhang Signed-off-by: Ruijing Dong Part-of: --- src/gallium/frontends/va/context.c | 3 + src/gallium/frontends/va/meson.build | 1 + src/gallium/frontends/va/picture.c | 52 +- src/gallium/frontends/va/picture_av1_enc.c | 700 +++++++++++++++++++++ src/gallium/frontends/va/va_private.h | 10 + 5 files changed, 757 insertions(+), 9 deletions(-) create mode 100644 src/gallium/frontends/va/picture_av1_enc.c diff --git a/src/gallium/frontends/va/context.c b/src/gallium/frontends/va/context.c index d02f558cc51..e37a143d67b 100644 --- a/src/gallium/frontends/va/context.c +++ b/src/gallium/frontends/va/context.c @@ -350,6 +350,9 @@ vlVaCreateContext(VADriverContextP ctx, VAConfigID config_id, int picture_width, context->desc.h265enc.rc.rate_ctrl_method = config->rc; context->desc.h265enc.frame_idx = util_hash_table_create_ptr_keys(); break; + case PIPE_VIDEO_FORMAT_AV1: + context->desc.av1enc.rc[0].rate_ctrl_method = config->rc; + break; default: break; } diff --git a/src/gallium/frontends/va/meson.build b/src/gallium/frontends/va/meson.build index 69dee07a938..82f7d646328 100644 --- a/src/gallium/frontends/va/meson.build +++ b/src/gallium/frontends/va/meson.build @@ -27,6 +27,7 @@ libva_st = static_library( 'picture_mpeg12.c', 'picture_mpeg4.c', 'picture_h264.c', 'picture_hevc.c', 'picture_vc1.c', 'picture_mjpeg.c', 'picture_vp9.c','picture_av1.c','postproc.c', 'subpicture.c', 'surface.c', 'picture_h264_enc.c', 'picture_hevc_enc.c', + 'picture_av1_enc.c', ), c_args : [ '-DVA_DRIVER_INIT_FUNC=__vaDriverInit_@0@_@1@'.format( diff --git a/src/gallium/frontends/va/picture.c b/src/gallium/frontends/va/picture.c index 3a558f55b94..90b8fd5d585 100644 --- a/src/gallium/frontends/va/picture.c +++ b/src/gallium/frontends/va/picture.c @@ -432,6 +432,10 @@ handleVAEncMiscParameterTypeRateControl(vlVaContext *context, VAEncMiscParameter status = vlVaHandleVAEncMiscParameterTypeRateControlHEVC(context, misc); break; + case PIPE_VIDEO_FORMAT_AV1: + status = vlVaHandleVAEncMiscParameterTypeRateControlAV1(context, misc); + break; + default: break; } @@ -453,6 +457,9 @@ handleVAEncMiscParameterTypeFrameRate(vlVaContext *context, VAEncMiscParameterBu status = vlVaHandleVAEncMiscParameterTypeFrameRateHEVC(context, misc); break; + case PIPE_VIDEO_FORMAT_AV1: + status = vlVaHandleVAEncMiscParameterTypeFrameRateAV1(context, misc); + break; default: break; } @@ -494,6 +501,10 @@ handleVAEncSequenceParameterBufferType(vlVaDriver *drv, vlVaContext *context, vl status = vlVaHandleVAEncSequenceParameterBufferTypeHEVC(drv, context, buf); break; + case PIPE_VIDEO_FORMAT_AV1: + status = vlVaHandleVAEncSequenceParameterBufferTypeAV1(drv, context, buf); + break; + default: break; } @@ -515,6 +526,10 @@ handleVAEncMiscParameterTypeQualityLevel(vlVaContext *context, VAEncMiscParamete status = vlVaHandleVAEncMiscParameterTypeQualityLevelHEVC(context, misc); break; + case PIPE_VIDEO_FORMAT_AV1: + status = vlVaHandleVAEncMiscParameterTypeQualityLevelAV1(context, misc); + break; + default: break; } @@ -536,6 +551,9 @@ handleVAEncMiscParameterTypeMaxFrameSize(vlVaContext *context, VAEncMiscParamete status = vlVaHandleVAEncMiscParameterTypeMaxFrameSizeHEVC(context, misc); break; + case PIPE_VIDEO_FORMAT_AV1: + status = vlVaHandleVAEncMiscParameterTypeMaxFrameSizeAV1(context, misc); + default: break; } @@ -556,6 +574,10 @@ handleVAEncMiscParameterTypeHRD(vlVaContext *context, VAEncMiscParameterBuffer * status = vlVaHandleVAEncMiscParameterTypeHRDHEVC(context, misc); break; + case PIPE_VIDEO_FORMAT_AV1: + status = vlVaHandleVAEncMiscParameterTypeHRDAV1(context, misc); + break; + default: break; } @@ -616,6 +638,10 @@ handleVAEncPictureParameterBufferType(vlVaDriver *drv, vlVaContext *context, vlV status = vlVaHandleVAEncPictureParameterBufferTypeHEVC(drv, context, buf); break; + case PIPE_VIDEO_FORMAT_AV1: + status = vlVaHandleVAEncPictureParameterBufferTypeAV1(drv, context, buf); + break; + default: break; } @@ -648,21 +674,23 @@ static VAStatus handleVAEncPackedHeaderParameterBufferType(vlVaContext *context, vlVaBuffer *buf) { VAStatus status = VA_STATUS_SUCCESS; + VAEncPackedHeaderParameterBuffer *param = buf->data; switch (u_reduce_video_profile(context->templat.profile)) { case PIPE_VIDEO_FORMAT_HEVC: + if (param->type == VAEncPackedHeaderSequence) + context->packed_header_type = param->type; + else + status = VA_STATUS_ERROR_UNIMPLEMENTED; + break; + case PIPE_VIDEO_FORMAT_AV1: + context->packed_header_type = param->type; break; default: return VA_STATUS_ERROR_UNIMPLEMENTED; } - VAEncPackedHeaderParameterBuffer *param = (VAEncPackedHeaderParameterBuffer *)buf->data; - if (param->type == VAEncPackedHeaderSequence) - context->packed_header_type = param->type; - else - status = VA_STATUS_ERROR_UNIMPLEMENTED; - return status; } @@ -671,14 +699,18 @@ handleVAEncPackedHeaderDataBufferType(vlVaContext *context, vlVaBuffer *buf) { VAStatus status = VA_STATUS_SUCCESS; - if (context->packed_header_type != VAEncPackedHeaderSequence) - return VA_STATUS_ERROR_UNIMPLEMENTED; - switch (u_reduce_video_profile(context->templat.profile)) { case PIPE_VIDEO_FORMAT_HEVC: + if (context->packed_header_type != VAEncPackedHeaderSequence) + return VA_STATUS_ERROR_UNIMPLEMENTED; + status = vlVaHandleVAEncPackedHeaderDataBufferTypeHEVC(context, buf); break; + case PIPE_VIDEO_FORMAT_AV1: + status = vlVaHandleVAEncPackedHeaderDataBufferTypeAV1(context, buf); + break; + default: break; } @@ -1066,6 +1098,8 @@ vlVaEndPicture(VADriverContextP ctx, VAContextID context_id) context->desc.h264enc.frame_num++; else if (u_reduce_video_profile(context->templat.profile) == PIPE_VIDEO_FORMAT_HEVC) context->desc.h265enc.frame_num++; + else if (u_reduce_video_profile(context->templat.profile) == PIPE_VIDEO_FORMAT_AV1) + context->desc.av1enc.frame_num++; } mtx_unlock(&drv->mutex); diff --git a/src/gallium/frontends/va/picture_av1_enc.c b/src/gallium/frontends/va/picture_av1_enc.c new file mode 100644 index 00000000000..165d3c68dca --- /dev/null +++ b/src/gallium/frontends/va/picture_av1_enc.c @@ -0,0 +1,700 @@ +/************************************************************************** + * + * Copyright 2023 Advanced Micro Devices, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include "util/u_handle_table.h" +#include "util/u_video.h" +#include "va_private.h" +#include "util/vl_vlc.h" + +#define AV1_SELECT_SCREEN_CONTENT_TOOLS (2) +#define AV1_SELECT_INTEGER_MV (2) +#define AV1_PRIMARY_REF_NON (7) +#define AV1_MAXNUM_OPERATING_POINT (32) +#define AV1_SUPERRES_DENOM_BITS (8) +#define AV1_MAXNUM_REF_FRAMES (8) +#define AV1_REFS_PER_FRAME (7) +#define FRAME_TYPE_KEY_FRAME (0) +#define FRAME_TYPE_INTER_FRAME (1) +#define FRAME_TYPE_INTRA_ONLY (2) +#define FRAME_TYPE_SWITCH (3) +#define OBU_TYPE_SEQUENCE_HEADER (1) +#define OBU_TYPE_FRAME_HEADER (3) + +static unsigned av1_f(struct vl_vlc *vlc, unsigned n) +{ + unsigned valid = vl_vlc_valid_bits(vlc); + + if (n == 0) + return 0; + + if (valid < 32) + vl_vlc_fillbits(vlc); + + return vl_vlc_get_uimsbf(vlc, n); +} + +static unsigned av1_uvlc(struct vl_vlc *vlc) +{ + unsigned value; + unsigned leadingZeros = 0; + + while (1) { + bool done = av1_f(vlc, 1); + if (done) + break; + leadingZeros++; + } + + if (leadingZeros >= 32) + return 0xffffffff; + + value = av1_f(vlc, leadingZeros); + + return value + (1 << leadingZeros) - 1; +} + +static unsigned av1_uleb128(struct vl_vlc *vlc) +{ + unsigned value = 0; + unsigned leb128Bytes = 0; + unsigned i; + + for (i = 0; i < 8; ++i) { + leb128Bytes = av1_f(vlc, 8); + value |= ((leb128Bytes & 0x7f) << (i * 7)); + if (!(leb128Bytes & 0x80)) + break; + } + + return value; +} + +VAStatus vlVaHandleVAEncSequenceParameterBufferTypeAV1(vlVaDriver *drv, vlVaContext *context, vlVaBuffer *buf) +{ + VAEncSequenceParameterBufferAV1 *av1 = buf->data; + + if (!context->decoder) { + context->templat.level = av1->seq_level_idx; + context->decoder = drv->pipe->create_video_codec(drv->pipe, &context->templat); + + if (!context->decoder) + return VA_STATUS_ERROR_ALLOCATION_FAILED; + + getEncParamPresetAV1(context); + } + + context->desc.av1enc.seq.tier = av1->seq_tier; + context->desc.av1enc.seq.level = av1->seq_level_idx; + context->desc.av1enc.seq.intra_period = av1->intra_period; + context->desc.av1enc.seq.bit_depth_minus8 = av1->seq_fields.bits.bit_depth_minus8; + context->desc.av1enc.seq.seq_bits.enable_cdef = av1->seq_fields.bits.enable_cdef; + context->desc.av1enc.seq.seq_bits.enable_order_hint = av1->seq_fields.bits.enable_order_hint; + + for (int i = 0; i < ARRAY_SIZE(context->desc.av1enc.rc); i++) + context->desc.av1enc.rc[i].peak_bitrate = av1->bits_per_second; + + return VA_STATUS_SUCCESS; +} +VAStatus vlVaHandleVAEncPictureParameterBufferTypeAV1(vlVaDriver *drv, vlVaContext *context, vlVaBuffer *buf) +{ + VAEncPictureParameterBufferAV1 *av1 = buf->data; + vlVaBuffer *coded_buf; + int i; + + context->desc.av1enc.disable_frame_end_update_cdf = av1->picture_flags.bits.disable_frame_end_update_cdf; + context->desc.av1enc.error_resilient_mode = av1->picture_flags.bits.error_resilient_mode; + context->desc.av1enc.disable_cdf_update = av1->picture_flags.bits.disable_cdf_update; + context->desc.av1enc.enable_frame_obu = av1->picture_flags.bits.enable_frame_obu; + context->desc.av1enc.allow_high_precision_mv = av1->picture_flags.bits.allow_high_precision_mv; + context->desc.av1enc.palette_mode_enable = av1->picture_flags.bits.palette_mode_enable; + context->desc.av1enc.num_tiles_in_pic = av1->tile_cols * av1->tile_rows; + + coded_buf = handle_table_get(drv->htab, av1->coded_buf); + if (!coded_buf) + return VA_STATUS_ERROR_INVALID_BUFFER; + + if (!coded_buf->derived_surface.resource) + coded_buf->derived_surface.resource = pipe_buffer_create(drv->pipe->screen, PIPE_BIND_VERTEX_BUFFER, + PIPE_USAGE_STAGING, coded_buf->size); + context->coded_buf = coded_buf; + + for (i = 0; i < ARRAY_SIZE(context->desc.av1enc.rc); i++) { + context->desc.av1enc.rc[i].qp = av1->base_qindex ? av1->base_qindex : 60; + context->desc.av1enc.rc[i].min_qp = av1->min_base_qindex ? av1->min_base_qindex : 1; + context->desc.av1enc.rc[i].max_qp = av1->max_base_qindex ? av1->max_base_qindex : 255; + } + + /* these frame types will need to be seen as force type */ + switch(av1->picture_flags.bits.frame_type) + { + case 0: + context->desc.av1enc.frame_type = PIPE_AV1_ENC_FRAME_TYPE_KEY; + break; + case 1: + context->desc.av1enc.frame_type = PIPE_AV1_ENC_FRAME_TYPE_INTER; + break; + case 2: + context->desc.av1enc.frame_type = PIPE_AV1_ENC_FRAME_TYPE_INTRA_ONLY; + break; + case 3: + context->desc.av1enc.frame_type = PIPE_AV1_ENC_FRAME_TYPE_SWITCH; + break; + }; + + return VA_STATUS_SUCCESS; +} + +VAStatus vlVaHandleVAEncMiscParameterTypeRateControlAV1(vlVaContext *context, VAEncMiscParameterBuffer *misc) +{ + VAEncMiscParameterRateControl *rc = (VAEncMiscParameterRateControl *)misc->data; + struct pipe_av1_enc_rate_control *pipe_rc = NULL; + + for (int i = 1; i < ARRAY_SIZE(context->desc.av1enc.rc); i++) { + pipe_rc = &context->desc.av1enc.rc[i]; + pipe_rc->rate_ctrl_method = context->desc.av1enc.rc[0].rate_ctrl_method; + } + + for (int i = 0; i < ARRAY_SIZE(context->desc.av1enc.rc); i++) + { + pipe_rc = &context->desc.av1enc.rc[i]; + + if (pipe_rc->rate_ctrl_method == PIPE_H2645_ENC_RATE_CONTROL_METHOD_CONSTANT) + pipe_rc->target_bitrate = pipe_rc->peak_bitrate; + else + pipe_rc->target_bitrate = pipe_rc->peak_bitrate * (rc->target_percentage / 100.0); + + if (pipe_rc->target_bitrate < 2000000) + pipe_rc->vbv_buffer_size = MIN2((pipe_rc->target_bitrate * 2.75), 2000000); + else + pipe_rc->vbv_buffer_size = pipe_rc->target_bitrate; + + pipe_rc->fill_data_enable = !(rc->rc_flags.bits.disable_bit_stuffing); + pipe_rc->skip_frame_enable = 0;/* !(rc->rc_flags.bits.disable_frame_skip); */ + } + + return VA_STATUS_SUCCESS; +} + +VAStatus +vlVaHandleVAEncMiscParameterTypeQualityLevelAV1(vlVaContext *context, VAEncMiscParameterBuffer *misc) +{ + VAEncMiscParameterBufferQualityLevel *ql = (VAEncMiscParameterBufferQualityLevel *)misc->data; + vlVaHandleVAEncMiscParameterTypeQualityLevel(&context->desc.av1enc.quality_modes, + (vlVaQualityBits *)&ql->quality_level); + + return VA_STATUS_SUCCESS; +} + +VAStatus +vlVaHandleVAEncMiscParameterTypeMaxFrameSizeAV1(vlVaContext *context, VAEncMiscParameterBuffer *misc) +{ + VAEncMiscParameterBufferMaxFrameSize *ms = (VAEncMiscParameterBufferMaxFrameSize *)misc->data; + context->desc.av1enc.rc[0].max_au_size = ms->max_frame_size; + return VA_STATUS_SUCCESS; +} + +VAStatus +vlVaHandleVAEncMiscParameterTypeHRDAV1(vlVaContext *context, VAEncMiscParameterBuffer *misc) +{ + VAEncMiscParameterHRD *ms = (VAEncMiscParameterHRD *)misc->data; + + if (ms->buffer_size) { + context->desc.av1enc.rc[0].vbv_buffer_size = ms->buffer_size; + context->desc.av1enc.rc[0].vbv_buf_lv = (ms->initial_buffer_fullness << 6 ) / ms->buffer_size; + } + + return VA_STATUS_SUCCESS; +} + +static void av1_color_config(vlVaContext *context, struct vl_vlc *vlc) +{ + unsigned high_bitdepth; + unsigned bit_depth = 8; + unsigned mono_chrome; + unsigned subsampling_x = 0, subsampling_y = 0; + + struct pipe_av1_enc_seq_param *seq = &context->desc.av1enc.seq; + + high_bitdepth = av1_f(vlc, 1); + if (seq->profile == 2 && high_bitdepth) { + unsigned twelve_bit = av1_f(vlc, 1); + bit_depth = twelve_bit ? 12 : 10; + } else if (seq->profile <= 2) + bit_depth = high_bitdepth ? 10 : 8; + + context->desc.av1enc.seq.bit_depth_minus8 = bit_depth - 8; + + if (seq->profile == 1) + mono_chrome = 0; + else + mono_chrome = av1_f(vlc, 1); + + seq->seq_bits.color_description_present_flag = av1_f(vlc, 1); + if (seq->seq_bits.color_description_present_flag) { + seq->color_config.color_primaries = av1_f(vlc, 8); + seq->color_config.transfer_characteristics = av1_f(vlc, 8); + seq->color_config.matrix_coefficients = av1_f(vlc, 8); + } else { + seq->color_config.color_primaries = 2; + seq->color_config.transfer_characteristics = 2; + seq->color_config.matrix_coefficients = 2; + } + + if (mono_chrome) { + seq->color_config.color_range = av1_f(vlc, 1); + subsampling_x = subsampling_y = 1; + seq->color_config.chroma_sample_position = 0; + return; + } else if (seq->color_config.color_primaries == 1 && /* CP_BT_709 */ + seq->color_config.transfer_characteristics == 13 && /* TC_SRGB */ + seq->color_config.matrix_coefficients == 0) { /* MC_IDENTITY */ + seq->color_config.color_range = 1; + subsampling_x = subsampling_y = 0; + } else { + seq->color_config.color_range = av1_f(vlc, 1); + if (seq->profile == 0) + subsampling_x = subsampling_y = 1; + else if (seq->profile == 1) + subsampling_x = subsampling_y = 0; + else { + if (bit_depth == 12) { + subsampling_x = av1_f(vlc, 1); + if (subsampling_x) + subsampling_y = av1_f(vlc, 1); + else + subsampling_y = 0; + } + } + if (subsampling_x && subsampling_y) + seq->color_config.chroma_sample_position = av1_f(vlc, 2); + } + + av1_f(vlc, 1); +} + +static void av1_sequence_header(vlVaContext *context, struct vl_vlc *vlc) +{ + unsigned initial_display_delay_present_flag = 0; + unsigned layer_minus1 = 0, value = 0; + unsigned buffer_delay_length_minus1 = 0; + unsigned still_pic = 0; + struct pipe_av1_enc_seq_param *seq = &context->desc.av1enc.seq; + + seq->profile = av1_f(vlc, 3); + still_pic = av1_f(vlc, 1); + av1_f(vlc, 1); + assert(!still_pic); + + seq->seq_bits.timing_info_present_flag = av1_f(vlc, 1); + if (seq->seq_bits.timing_info_present_flag) { + seq->num_units_in_display_tick = av1_f(vlc, 32); + seq->time_scale = av1_f(vlc, 32); + seq->seq_bits.equal_picture_interval = av1_f(vlc, 1); + if (seq->seq_bits.equal_picture_interval) + seq->num_tick_per_picture_minus1 = av1_uvlc(vlc); + seq->seq_bits.decoder_model_info_present_flag = av1_f(vlc, 1); + if (seq->seq_bits.decoder_model_info_present_flag) { + struct pipe_av1_enc_decoder_model_info *info = &seq->decoder_model_info; + info->buffer_delay_length_minus1 = av1_f(vlc, 5); + info->num_units_in_decoding_tick = av1_f(vlc, 32); + info->buffer_removal_time_length_minus1 = av1_f(vlc, 5); + info->frame_presentation_time_length_minus1 = av1_f(vlc, 5); + } + } + initial_display_delay_present_flag = av1_f(vlc, 1); + layer_minus1 = av1_f(vlc, 5); + seq->num_temporal_layers = layer_minus1 + 1; + for (unsigned i = 0; i <= layer_minus1; i++) { + seq->operating_point_idc[i] = av1_f(vlc, 12); + value = av1_f(vlc, 5); + if (value > 7) + av1_f(vlc, 1); + if (seq->seq_bits.decoder_model_info_present_flag) { + seq->decoder_model_present_for_this_op[i] = av1_f(vlc, 1); + if (seq->decoder_model_present_for_this_op[i]) { + av1_f(vlc, buffer_delay_length_minus1 + 1); + av1_f(vlc, buffer_delay_length_minus1 + 1); + av1_f(vlc, 1); + } else + seq->decoder_model_present_for_this_op[i] = 0; + } + if (initial_display_delay_present_flag) { + value = av1_f(vlc, 1); + if (value) + av1_f(vlc, 4); + } + } + seq->frame_width_bits_minus1 = av1_f(vlc, 4); + seq->frame_height_bits_minus1 = av1_f(vlc, 4); + seq->pic_width_in_luma_samples = av1_f(vlc, seq->frame_width_bits_minus1 + 1) + 1; + seq->pic_height_in_luma_samples = av1_f(vlc, seq->frame_height_bits_minus1 + 1) + 1; + seq->seq_bits.frame_id_number_present_flag = av1_f(vlc, 1); + if (seq->seq_bits.frame_id_number_present_flag) { + seq->delta_frame_id_length = av1_f(vlc, 4) + 2; + seq->additional_frame_id_length = av1_f(vlc, 3) + 1; + } + av1_f(vlc, 1); + av1_f(vlc, 1); + av1_f(vlc, 1); + /* reduced_still_pictuer_header should be zero */ + av1_f(vlc, 1); + av1_f(vlc, 1); + av1_f(vlc, 1); + av1_f(vlc, 1); + seq->seq_bits.enable_order_hint = av1_f(vlc, 1); + if (seq->seq_bits.enable_order_hint) { + av1_f(vlc, 1); + seq->seq_bits.enable_ref_frame_mvs = av1_f(vlc, 1); + } else + seq->seq_bits.enable_ref_frame_mvs = 0; + + seq->seq_bits.disable_screen_content_tools = av1_f(vlc, 1); + if (seq->seq_bits.disable_screen_content_tools) + seq->seq_bits.force_screen_content_tools = AV1_SELECT_SCREEN_CONTENT_TOOLS; + else + seq->seq_bits.force_screen_content_tools = av1_f(vlc, 1); + + seq->seq_bits.force_integer_mv = AV1_SELECT_INTEGER_MV; + if (seq->seq_bits.force_screen_content_tools) { + value = av1_f(vlc, 1); + if (!value) + seq->seq_bits.force_integer_mv = av1_f(vlc, 1); + } + if (seq->seq_bits.enable_order_hint) + seq->order_hint_bits = av1_f(vlc, 3) + 1; + else + seq->order_hint_bits = 0; + + seq->seq_bits.enable_superres = av1_f(vlc, 1); + seq->seq_bits.enable_cdef = av1_f(vlc, 1); + av1_f(vlc, 1); + av1_color_config(context, vlc); +} + +static void av1_superres_params(vlVaContext *context, struct vl_vlc *vlc) +{ + struct pipe_av1_enc_picture_desc *av1 = &context->desc.av1enc; + uint8_t use_superres; + + if (av1->seq.seq_bits.enable_superres) + use_superres = av1_f(vlc, 1); + else + use_superres = 0; + + if (use_superres) + av1_f(vlc, AV1_SUPERRES_DENOM_BITS); + + av1->upscaled_width = av1->frame_width; +} + +static void av1_frame_size(vlVaContext *context, struct vl_vlc *vlc) +{ + struct pipe_av1_enc_picture_desc *av1 = &context->desc.av1enc; + + if (av1->frame_size_override_flag) { + av1->frame_width = av1_f(vlc, av1->seq.frame_width_bits_minus1 + 1) + 1; + av1_f(vlc, av1->seq.frame_height_bits_minus1 + 1); + } else + av1->frame_width = av1->seq.pic_width_in_luma_samples; + + av1_superres_params(context, vlc); +} + +static void av1_render_size(vlVaContext *context, struct vl_vlc *vlc) +{ + struct pipe_av1_enc_picture_desc *av1 = &context->desc.av1enc; + + av1->enable_render_size = av1_f(vlc, 1); + if (av1->enable_render_size) { + av1->render_width = av1_f(vlc, 16); + av1->render_height = av1_f(vlc, 16); + } +} + +static void av1_frame_size_with_refs(vlVaContext *context, struct vl_vlc *vlc) +{ + uint8_t found_ref = 0; + + for (int i = 0; i < AV1_REFS_PER_FRAME; i++) { + found_ref = av1_f(vlc, 1); + if (found_ref) + break; + } + + if (found_ref == 0) { + av1_frame_size(context, vlc); + av1_render_size(context, vlc); + } else + av1_superres_params(context, vlc); +} + +static void av1_read_interpolation_filter(vlVaContext *context, struct vl_vlc *vlc) +{ + uint8_t is_filter_switchable = av1_f(vlc, 1); + + if (!is_filter_switchable) + av1_f(vlc, 2); +} + +static void av1_frame_header(vlVaContext *context, struct vl_vlc *vlc) +{ + struct pipe_av1_enc_picture_desc *av1 = &context->desc.av1enc; + uint32_t frame_type; + uint32_t id_len, all_frames, show_frame; + uint32_t refresh_frame_flags = 0; + + bool frame_is_intra = false; + + if (av1->seq.seq_bits.frame_id_number_present_flag) + id_len = av1->seq.delta_frame_id_length + av1->seq.additional_frame_id_length; + + all_frames = 255; + av1->show_existing_frame = av1_f(vlc, 1); + /* use the last reference frame to show */ + if (av1->show_existing_frame) + return; + + frame_type = av1_f(vlc, 2); + frame_is_intra = (frame_type == FRAME_TYPE_KEY_FRAME || + frame_type == FRAME_TYPE_INTRA_ONLY); + show_frame = av1_f(vlc, 1); + if (show_frame && av1->seq.seq_bits.decoder_model_info_present_flag + && !(av1->seq.seq_bits.equal_picture_interval)) { + struct pipe_av1_enc_decoder_model_info *info = &av1->seq.decoder_model_info; + av1_f(vlc, info->frame_presentation_time_length_minus1 + 1); + } + + if (!show_frame) + av1_f(vlc, 1); /* showable_frame */ + + if (frame_type == FRAME_TYPE_SWITCH || + (frame_type == FRAME_TYPE_KEY_FRAME && show_frame)) + av1->error_resilient_mode = 1; + else + av1->error_resilient_mode = av1_f(vlc, 1); + + av1->disable_cdf_update = av1_f(vlc, 1); + if (av1->seq.seq_bits.force_screen_content_tools == AV1_SELECT_SCREEN_CONTENT_TOOLS) + av1->allow_screen_content_tools = av1_f(vlc, 1); + else + av1->allow_screen_content_tools = !!(av1->seq.seq_bits.force_screen_content_tools); + + av1->force_integer_mv = 0; + if (av1->allow_screen_content_tools) { + if (av1->seq.seq_bits.force_integer_mv == AV1_SELECT_INTEGER_MV) + av1->force_integer_mv = av1_f(vlc, 1); + else + av1->force_integer_mv = !!(av1->seq.seq_bits.force_integer_mv); + } + + if (frame_is_intra) + av1->force_integer_mv = 1; + + if (av1->seq.seq_bits.frame_id_number_present_flag) + av1_f(vlc, id_len); + + if (frame_type == FRAME_TYPE_SWITCH) + av1->frame_size_override_flag = 1; + else + av1->frame_size_override_flag = av1_f(vlc, 1); + + if (av1->seq.seq_bits.enable_order_hint) + av1_f(vlc, av1->seq.order_hint_bits); + + if (!(frame_is_intra || av1->error_resilient_mode)) + av1_f(vlc, 3); + + if (av1->seq.seq_bits.decoder_model_info_present_flag) { + unsigned buffer_removal_time_present_flag = av1_f(vlc, 1); + if (buffer_removal_time_present_flag) { + for (int opNum = 0; opNum <= av1->seq.num_temporal_layers - 1; opNum++) { + if (av1->seq.decoder_model_present_for_this_op[opNum]) { + uint16_t op_pt_idc = av1->seq.operating_point_idc[opNum]; + uint16_t temporal_layer = (op_pt_idc >> av1->temporal_id) & 1; + uint16_t spatial_layer = (op_pt_idc >> (av1->spatial_id + 8)) & 1; + if (op_pt_idc == 0 || (temporal_layer && spatial_layer)) + av1_f(vlc, av1->seq.decoder_model_info.buffer_removal_time_length_minus1 + 1); + } + } + } + } + + if (frame_type == FRAME_TYPE_SWITCH || + (frame_type == FRAME_TYPE_KEY_FRAME && show_frame)) + refresh_frame_flags = all_frames; + else + refresh_frame_flags = av1_f(vlc, 8); + + if ( !frame_is_intra || refresh_frame_flags != all_frames) { + if (av1->error_resilient_mode && av1->seq.seq_bits.enable_order_hint) + for (int i = 0; i < AV1_MAXNUM_REF_FRAMES; i++) + av1_f(vlc, av1->seq.order_hint_bits); + } + + if ( frame_is_intra) { + av1_frame_size(context, vlc); + av1_render_size(context, vlc); + if (av1->allow_screen_content_tools && av1->upscaled_width == av1->frame_width) + av1_f(vlc, 1); + } else { + unsigned frame_refs_short_signaling = 0; + if (av1->seq.seq_bits.enable_order_hint) { + frame_refs_short_signaling = av1_f(vlc, 1); + if (frame_refs_short_signaling) { + av1_f(vlc, 3); + av1_f(vlc, 3); + } + } + + for (int i = 0; i < AV1_REFS_PER_FRAME; i++) { + if (!frame_refs_short_signaling) + av1_f(vlc, 3); + if (av1->seq.seq_bits.frame_id_number_present_flag) + av1_f(vlc, av1->seq.delta_frame_id_length); + } + + if (av1->frame_size_override_flag && av1->error_resilient_mode) + av1_frame_size_with_refs(context, vlc); + else { + av1_frame_size(context, vlc); + av1_render_size(context, vlc); + } + + if (av1->force_integer_mv) + av1->allow_high_precision_mv = 0; + else + av1->allow_high_precision_mv = av1_f(vlc, 1); + + av1_read_interpolation_filter(context, vlc); + av1_f(vlc, 1); + if (av1->error_resilient_mode || !av1->seq.seq_bits.enable_ref_frame_mvs) + av1->use_ref_frame_mvs = 0; + else + av1->use_ref_frame_mvs = av1_f(vlc, 1); + + if (av1->disable_cdf_update) + av1->disable_frame_end_update_cdf = 1; + else + av1->disable_frame_end_update_cdf = av1_f(vlc, 1); + } +} + +VAStatus +vlVaHandleVAEncPackedHeaderDataBufferTypeAV1(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) { + unsigned obu_type = 0; + /* search sequece header in the first 8 bytes */ + for (int i = 0; i < 8 && vl_vlc_bits_left(&vlc) >= 8; ++i) { + /* then start decoding , first 5 bits has to be 0000 1xxx for sequence header */ + obu_type = vl_vlc_peekbits(&vlc, 5); + if (obu_type == OBU_TYPE_SEQUENCE_HEADER || obu_type == OBU_TYPE_FRAME_HEADER) + break; + vl_vlc_eatbits(&vlc, 8); + vl_vlc_fillbits(&vlc); + } + + av1_f(&vlc, 5); /* eat known bits */ + uint32_t extension_flag = av1_f(&vlc, 1); + uint32_t has_size = av1_f(&vlc, 1); + av1_f(&vlc, 1); + if (extension_flag) { + context->desc.av1enc.temporal_id = av1_f(&vlc, 3); + context->desc.av1enc.spatial_id = av1_f(&vlc, 2); + av1_f(&vlc, 3); + } + + if (has_size) + av1_uleb128(&vlc); + + if (obu_type == OBU_TYPE_SEQUENCE_HEADER) + av1_sequence_header(context, &vlc); + else if (obu_type == OBU_TYPE_FRAME_HEADER) + av1_frame_header(context, &vlc); + else + assert(0); + + break; + } + + return VA_STATUS_SUCCESS; +} + +VAStatus +vlVaHandleVAEncMiscParameterTypeFrameRateAV1(vlVaContext *context, VAEncMiscParameterBuffer *misc) +{ + VAEncMiscParameterFrameRate *fr = (VAEncMiscParameterFrameRate *)misc->data; + for (int i = 0; i < ARRAY_SIZE(context->desc.av1enc.rc); i++) { + if (fr->framerate & 0xffff0000) { + context->desc.av1enc.rc[i].frame_rate_num = fr->framerate & 0xffff; + context->desc.av1enc.rc[i].frame_rate_den = fr->framerate >> 16 & 0xffff; + } else { + context->desc.av1enc.rc[i].frame_rate_num = fr->framerate; + context->desc.av1enc.rc[i].frame_rate_den = 1; + } + } + + return VA_STATUS_SUCCESS; +} + +void getEncParamPresetAV1(vlVaContext *context) +{ + for (int i = 0; i < ARRAY_SIZE(context->desc.av1enc.rc); i++) { + struct pipe_av1_enc_rate_control *rc = &context->desc.av1enc.rc[i]; + + rc->vbv_buffer_size = 20000000; + rc->vbv_buf_lv = 48; + rc->fill_data_enable = 1; + rc->enforce_hrd = 1; + rc->max_qp = 255; + rc->min_qp = 1; + + if (rc->frame_rate_num == 0 || + rc->frame_rate_den == 0) { + rc->frame_rate_num = 30; + rc->frame_rate_den = 1; + } + + if (rc->target_bitrate == 0) + rc->target_bitrate = 20 * 1000000; + + if (rc->peak_bitrate == 0) + rc->peak_bitrate = rc->target_bitrate * 3 / 2; + + rc->target_bits_picture = rc->target_bitrate * rc->frame_rate_den / + rc->frame_rate_num; + + rc->peak_bits_picture_integer = rc->peak_bitrate * rc->frame_rate_den / + rc->frame_rate_num; + + rc->peak_bits_picture_fraction = 0; + } +} + diff --git a/src/gallium/frontends/va/va_private.h b/src/gallium/frontends/va/va_private.h index c1fe67f39c8..dac07791a77 100644 --- a/src/gallium/frontends/va/va_private.h +++ b/src/gallium/frontends/va/va_private.h @@ -340,6 +340,7 @@ typedef struct { struct pipe_av1_picture_desc av1; struct pipe_h264_enc_picture_desc h264enc; struct pipe_h265_enc_picture_desc h265enc; + struct pipe_av1_enc_picture_desc av1enc; struct pipe_vpp_desc vidproc; } desc; @@ -533,6 +534,7 @@ void vlVaHandlePictureParameterBufferAV1(vlVaDriver *drv, vlVaContext *context, void vlVaHandleSliceParameterBufferAV1(vlVaContext *context, vlVaBuffer *buf, unsigned num_slices); void getEncParamPresetH264(vlVaContext *context); void getEncParamPresetH265(vlVaContext *context); +void getEncParamPresetAV1(vlVaContext *context); void vlVaHandleVAEncMiscParameterTypeQualityLevel(struct pipe_enc_quality_modes *p, vlVaQualityBits *in); VAStatus vlVaHandleVAEncPictureParameterBufferTypeH264(vlVaDriver *drv, vlVaContext *context, vlVaBuffer *buf); VAStatus vlVaHandleVAEncSliceParameterBufferTypeH264(vlVaDriver *drv, vlVaContext *context, vlVaBuffer *buf); @@ -552,4 +554,12 @@ VAStatus vlVaHandleVAEncPackedHeaderDataBufferTypeHEVC(vlVaContext *context, vlV VAStatus vlVaHandleVAEncMiscParameterTypeQualityLevelHEVC(vlVaContext *context, VAEncMiscParameterBuffer *buf); VAStatus vlVaHandleVAEncMiscParameterTypeMaxFrameSizeHEVC(vlVaContext *context, VAEncMiscParameterBuffer *buf); VAStatus vlVaHandleVAEncMiscParameterTypeHRDHEVC(vlVaContext *context, VAEncMiscParameterBuffer *buf); +VAStatus vlVaHandleVAEncSequenceParameterBufferTypeAV1(vlVaDriver *drv, vlVaContext *context, vlVaBuffer *buf); +VAStatus vlVaHandleVAEncPictureParameterBufferTypeAV1(vlVaDriver *drv, vlVaContext *context, vlVaBuffer *buf); +VAStatus vlVaHandleVAEncMiscParameterTypeRateControlAV1(vlVaContext *context, VAEncMiscParameterBuffer *buf); +VAStatus vlVaHandleVAEncPackedHeaderDataBufferTypeAV1(vlVaContext *context, vlVaBuffer *buf); +VAStatus vlVaHandleVAEncMiscParameterTypeFrameRateAV1(vlVaContext *context, VAEncMiscParameterBuffer *buf); +VAStatus vlVaHandleVAEncMiscParameterTypeQualityLevelAV1(vlVaContext *context, VAEncMiscParameterBuffer *buf); +VAStatus vlVaHandleVAEncMiscParameterTypeMaxFrameSizeAV1(vlVaContext *context, VAEncMiscParameterBuffer *buf); +VAStatus vlVaHandleVAEncMiscParameterTypeHRDAV1(vlVaContext *context, VAEncMiscParameterBuffer *buf); #endif //VA_PRIVATE_H