| @@ -0,0 +1,949 @@ |
| | 1 | /* |
| | 2 | * Copyright (c) 2023 Intel Corporation |
| | 3 | * |
| | 4 | * This file is part of FFmpeg. |
| | 5 | * |
| | 6 | * FFmpeg is free software; you can redistribute it and/or |
| | 7 | * modify it under the terms of the GNU Lesser General Public |
| | 8 | * License as published by the Free Software Foundation; either |
| | 9 | * version 2.1 of the License, or (at your option) any later version. |
| | 10 | * |
| | 11 | * FFmpeg is distributed in the hope that it will be useful, |
| | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| | 14 | * Lesser General Public License for more details. |
| | 15 | * |
| | 16 | * You should have received a copy of the GNU Lesser General Public |
| | 17 | * License along with FFmpeg; if not, write to the Free Software |
| | 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
| | 19 | */ |
| | 20 | |
| | 21 | #include <va/va.h> |
| | 22 | #include <va/va_enc_av1.h> |
| | 23 | |
| | 24 | #include "libavutil/pixdesc.h" |
| | 25 | #include "libavutil/opt.h" |
| | 26 | |
| | 27 | #include "cbs_av1.h" |
| | 28 | #include "put_bits.h" |
| | 29 | #include "codec_internal.h" |
| | 30 | #include "av1_levels.h" |
| | 31 | #include "vaapi_encode.h" |
| | 32 | |
| | 33 | #define AV1_MAX_QUANT 255 |
| | 34 | |
| | 35 | typedef struct VAAPIEncodeAV1Picture { |
| | 36 | int64_t last_idr_frame; |
| | 37 | int slot; |
| | 38 | } VAAPIEncodeAV1Picture; |
| | 39 | |
| | 40 | typedef struct VAAPIEncodeAV1Context { |
| | 41 | VAAPIEncodeContext common; |
| | 42 | AV1RawOBU sh; /**< sequence header.*/ |
| | 43 | AV1RawOBU fh; /**< frame header.*/ |
| | 44 | CodedBitstreamContext *cbc; |
| | 45 | CodedBitstreamFragment current_obu; |
| | 46 | VAConfigAttribValEncAV1 attr; |
| | 47 | VAConfigAttribValEncAV1Ext1 attr_ext1; |
| | 48 | VAConfigAttribValEncAV1Ext2 attr_ext2; |
| | 49 | |
| | 50 | char sh_data[MAX_PARAM_BUFFER_SIZE]; /**< coded sequence header data. */ |
| | 51 | size_t sh_data_len; /**< bit length of sh_data. */ |
| | 52 | char fh_data[MAX_PARAM_BUFFER_SIZE]; /**< coded frame header data. */ |
| | 53 | size_t fh_data_len; /**< bit length of fh_data. */ |
| | 54 | |
| | 55 | uint8_t uniform_tile; |
| | 56 | uint8_t use_128x128_superblock; |
| | 57 | int sb_cols; |
| | 58 | int sb_rows; |
| | 59 | int tile_cols_log2; |
| | 60 | int tile_rows_log2; |
| | 61 | int max_tile_width_sb; |
| | 62 | int max_tile_height_sb; |
| | 63 | uint8_t width_in_sbs_minus_1[AV1_MAX_TILE_COLS]; |
| | 64 | uint8_t height_in_sbs_minus_1[AV1_MAX_TILE_ROWS]; |
| | 65 | |
| | 66 | int min_log2_tile_cols; |
| | 67 | int max_log2_tile_cols; |
| | 68 | int min_log2_tile_rows; |
| | 69 | int max_log2_tile_rows; |
| | 70 | |
| | 71 | int q_idx_idr; |
| | 72 | int q_idx_p; |
| | 73 | int q_idx_b; |
| | 74 | |
| | 75 | /** bit positions in current frame header */ |
| | 76 | int qindex_offset; |
| | 77 | int loopfilter_offset; |
| | 78 | int cdef_start_offset; |
| | 79 | int cdef_param_size; |
| | 80 | |
| | 81 | /** user options */ |
| | 82 | int profile; |
| | 83 | int level; |
| | 84 | int tier; |
| | 85 | int tile_cols, tile_rows; |
| | 86 | int tile_groups; |
| | 87 | } VAAPIEncodeAV1Context; |
| | 88 | |
| | 89 | static void vaapi_encode_av1_trace_write_log(void *ctx, |
| | 90 | PutBitContext *pbc, int length, |
| | 91 | const char *str, const int *subscripts, |
| | 92 | int64_t value) |
| | 93 | { |
| | 94 | VAAPIEncodeAV1Context *priv = ctx; |
| | 95 | int position; |
| | 96 | |
| | 97 | position = put_bits_count(pbc); |
| | 98 | av_assert0(position >= length); |
| | 99 | |
| | 100 | if (!strcmp(str, "base_q_idx")) |
| | 101 | priv->qindex_offset = position - length; |
| | 102 | else if (!strcmp(str, "loop_filter_level[0]")) |
| | 103 | priv->loopfilter_offset = position - length; |
| | 104 | else if (!strcmp(str, "cdef_damping_minus_3")) |
| | 105 | priv->cdef_start_offset = position - length; |
| | 106 | else if (!strcmp(str, "cdef_uv_sec_strength[i]")) |
| | 107 | priv->cdef_param_size = position - priv->cdef_start_offset; |
| | 108 | } |
| | 109 | |
| | 110 | static av_cold int vaapi_encode_av1_get_encoder_caps(AVCodecContext *avctx) |
| | 111 | { |
| | 112 | VAAPIEncodeContext *ctx = avctx->priv_data; |
| | 113 | VAAPIEncodeAV1Context *priv = avctx->priv_data; |
| | 114 | |
| | 115 | // Surfaces must be aligned to superblock boundaries. |
| | 116 | ctx->surface_width = FFALIGN(avctx->width, priv->use_128x128_superblock ? 128 : 64); |
| | 117 | ctx->surface_height = FFALIGN(avctx->height, priv->use_128x128_superblock ? 128 : 64); |
| | 118 | |
| | 119 | return 0; |
| | 120 | } |
| | 121 | |
| | 122 | static av_cold int vaapi_encode_av1_configure(AVCodecContext *avctx) |
| | 123 | { |
| | 124 | VAAPIEncodeContext *ctx = avctx->priv_data; |
| | 125 | VAAPIEncodeAV1Context *priv = avctx->priv_data; |
| | 126 | int ret; |
| | 127 | |
| | 128 | ret = ff_cbs_init(&priv->cbc, AV_CODEC_ID_AV1, avctx); |
| | 129 | if (ret < 0) |
| | 130 | return ret; |
| | 131 | priv->cbc->trace_enable = 1; |
| | 132 | priv->cbc->trace_level = AV_LOG_DEBUG; |
| | 133 | priv->cbc->trace_context = ctx; |
| | 134 | priv->cbc->trace_write_callback = vaapi_encode_av1_trace_write_log; |
| | 135 | |
| | 136 | if (ctx->rc_mode->quality) { |
| | 137 | priv->q_idx_p = av_clip(ctx->rc_quality, 0, AV1_MAX_QUANT); |
| | 138 | if (fabs(avctx->i_quant_factor) > 0.0) |
| | 139 | priv->q_idx_idr = |
| | 140 | av_clip((fabs(avctx->i_quant_factor) * priv->q_idx_p + |
| | 141 | avctx->i_quant_offset) + 0.5, |
| | 142 | 0, AV1_MAX_QUANT); |
| | 143 | else |
| | 144 | priv->q_idx_idr = priv->q_idx_p; |
| | 145 | |
| | 146 | if (fabs(avctx->b_quant_factor) > 0.0) |
| | 147 | priv->q_idx_b = |
| | 148 | av_clip((fabs(avctx->b_quant_factor) * priv->q_idx_p + |
| | 149 | avctx->b_quant_offset) + 0.5, |
| | 150 | 0, AV1_MAX_QUANT); |
| | 151 | else |
| | 152 | priv->q_idx_b = priv->q_idx_p; |
| | 153 | } else { |
| | 154 | /** Arbitrary value */ |
| | 155 | priv->q_idx_idr = priv->q_idx_p = priv->q_idx_b = 128; |
| | 156 | } |
| | 157 | |
| | 158 | return 0; |
| | 159 | } |
| | 160 | |
| | 161 | static int vaapi_encode_av1_add_obu(AVCodecContext *avctx, |
| | 162 | CodedBitstreamFragment *au, |
| | 163 | uint8_t type, |
| | 164 | void *obu_unit) |
| | 165 | { |
| | 166 | int ret; |
| | 167 | |
| | 168 | ret = ff_cbs_insert_unit_content(au, -1, |
| | 169 | type, obu_unit, NULL); |
| | 170 | if (ret < 0) { |
| | 171 | av_log(avctx, AV_LOG_ERROR, "Failed to add OBU unit: " |
| | 172 | "type = %d.\n", type); |
| | 173 | return ret; |
| | 174 | } |
| | 175 | |
| | 176 | return 0; |
| | 177 | } |
| | 178 | |
| | 179 | static int vaapi_encode_av1_write_obu(AVCodecContext *avctx, |
| | 180 | char *data, size_t *data_len, |
| | 181 | CodedBitstreamFragment *bs) |
| | 182 | { |
| | 183 | VAAPIEncodeAV1Context *priv = avctx->priv_data; |
| | 184 | int ret; |
| | 185 | |
| | 186 | ret = ff_cbs_write_fragment_data(priv->cbc, bs); |
| | 187 | if (ret < 0) { |
| | 188 | av_log(avctx, AV_LOG_ERROR, "Failed to write packed header.\n"); |
| | 189 | return ret; |
| | 190 | } |
| | 191 | |
| | 192 | if ((size_t)8 * MAX_PARAM_BUFFER_SIZE < 8 * bs->data_size - bs->data_bit_padding) { |
| | 193 | av_log(avctx, AV_LOG_ERROR, "Access unit too large: " |
| | 194 | "%zu < %zu.\n", (size_t)8 * MAX_PARAM_BUFFER_SIZE, |
| | 195 | 8 * bs->data_size - bs->data_bit_padding); |
| | 196 | return AVERROR(ENOSPC); |
| | 197 | } |
| | 198 | |
| | 199 | memcpy(data, bs->data, bs->data_size); |
| | 200 | *data_len = 8 * bs->data_size - bs->data_bit_padding; |
| | 201 | |
| | 202 | return 0; |
| | 203 | } |
| | 204 | |
| | 205 | static int tile_log2(int blkSize, int target) { |
| | 206 | int k; |
| | 207 | for (k = 0; (blkSize << k) < target; k++); |
| | 208 | return k; |
| | 209 | } |
| | 210 | |
| | 211 | static int vaapi_encode_av1_set_tile(AVCodecContext *avctx) |
| | 212 | { |
| | 213 | VAAPIEncodeAV1Context *priv = avctx->priv_data; |
| | 214 | int mi_cols, mi_rows, sb_shift, sb_size; |
| | 215 | int max_tile_area_sb, max_tile_area_sb_varied; |
| | 216 | int tile_width_sb, tile_height_sb, widest_tile_sb; |
| | 217 | int tile_cols, tile_rows; |
| | 218 | int min_log2_tiles; |
| | 219 | int i; |
| | 220 | |
| | 221 | if (priv->tile_cols > AV1_MAX_TILE_COLS || |
| | 222 | priv->tile_rows > AV1_MAX_TILE_ROWS) { |
| | 223 | av_log(avctx, AV_LOG_ERROR, "Invalid tile number %dx%d, should less than %dx%d.\n", |
| | 224 | priv->tile_cols, priv->tile_rows, AV1_MAX_TILE_COLS, AV1_MAX_TILE_ROWS); |
| | 225 | return AVERROR(EINVAL); |
| | 226 | } |
| | 227 | |
| | 228 | mi_cols = 2 * ((avctx->width + 7) >> 3); |
| | 229 | mi_rows = 2 * ((avctx->height + 7) >> 3); |
| | 230 | priv->sb_cols = priv->use_128x128_superblock ? |
| | 231 | ((mi_cols + 31) >> 5) : ((mi_cols + 15) >> 4); |
| | 232 | priv->sb_rows = priv->use_128x128_superblock ? |
| | 233 | ((mi_rows + 31) >> 5) : ((mi_rows + 15) >> 4); |
| | 234 | sb_shift = priv->use_128x128_superblock ? 5 : 4; |
| | 235 | sb_size = sb_shift + 2; |
| | 236 | priv->max_tile_width_sb = AV1_MAX_TILE_WIDTH >> sb_size; |
| | 237 | max_tile_area_sb = AV1_MAX_TILE_AREA >> (2 * sb_size); |
| | 238 | |
| | 239 | priv->min_log2_tile_cols = tile_log2(priv->max_tile_width_sb, priv->sb_cols); |
| | 240 | priv->max_log2_tile_cols = tile_log2(1, FFMIN(priv->sb_cols, AV1_MAX_TILE_COLS)); |
| | 241 | priv->max_log2_tile_rows = tile_log2(1, FFMIN(priv->sb_rows, AV1_MAX_TILE_ROWS)); |
| | 242 | min_log2_tiles = FFMAX(priv->min_log2_tile_cols, |
| | 243 | tile_log2(max_tile_area_sb, priv->sb_rows * priv->sb_cols)); |
| | 244 | |
| | 245 | tile_cols = av_clip(priv->tile_cols, (priv->sb_cols + priv->max_tile_width_sb - 1) / priv->max_tile_width_sb, priv->sb_cols); |
| | 246 | |
| | 247 | if (!priv->tile_cols) |
| | 248 | priv->tile_cols = tile_cols; |
| | 249 | else if (priv->tile_cols != tile_cols){ |
| | 250 | av_log(avctx, AV_LOG_ERROR, "Invalid tile cols %d, should be in range of %d~%d\n", |
| | 251 | priv->tile_cols, |
| | 252 | (priv->sb_cols + priv->max_tile_width_sb - 1) / priv->max_tile_width_sb, |
| | 253 | priv->sb_cols); |
| | 254 | return AVERROR(EINVAL); |
| | 255 | } |
| | 256 | |
| | 257 | priv->tile_cols_log2 = tile_log2(1, priv->tile_cols); |
| | 258 | tile_width_sb = (priv->sb_cols + (1 << priv->tile_cols_log2) - 1) >> |
| | 259 | priv->tile_cols_log2; |
| | 260 | |
| | 261 | if (priv->tile_rows > priv->sb_rows) { |
| | 262 | av_log(avctx, AV_LOG_ERROR, "Invalid tile rows %d, should be less than %d.\n", |
| | 263 | priv->tile_rows, priv->sb_rows); |
| | 264 | return AVERROR(EINVAL); |
| | 265 | } |
| | 266 | |
| | 267 | /** Try user setting tile rows number first. */ |
| | 268 | tile_rows = priv->tile_rows ? priv->tile_rows : 1; |
| | 269 | for (; tile_rows <= priv->sb_rows && tile_rows <= AV1_MAX_TILE_ROWS; tile_rows++) { |
| | 270 | /** try uniformed tile. */ |
| | 271 | priv->tile_rows_log2 = tile_log2(1, tile_rows); |
| | 272 | if ((priv->sb_cols + tile_width_sb - 1) / tile_width_sb == priv->tile_cols) { |
| | 273 | for (i = 0; i < priv->tile_cols - 1; i++) |
| | 274 | priv->width_in_sbs_minus_1[i] = tile_width_sb - 1; |
| | 275 | priv->width_in_sbs_minus_1[i] = priv->sb_cols - (priv->tile_cols - 1) * tile_width_sb - 1; |
| | 276 | |
| | 277 | tile_height_sb = (priv->sb_rows + (1 << priv->tile_rows_log2) - 1) >> |
| | 278 | priv->tile_rows_log2; |
| | 279 | |
| | 280 | if ((priv->sb_rows + tile_height_sb - 1) / tile_height_sb == tile_rows && |
| | 281 | tile_height_sb <= max_tile_area_sb / tile_width_sb) { |
| | 282 | for (i = 0; i < tile_rows - 1; i++) |
| | 283 | priv->height_in_sbs_minus_1[i] = tile_height_sb - 1; |
| | 284 | priv->height_in_sbs_minus_1[i] = priv->sb_rows - (tile_rows - 1) * tile_height_sb - 1; |
| | 285 | |
| | 286 | priv->uniform_tile = 1; |
| | 287 | priv->min_log2_tile_rows = FFMAX(min_log2_tiles - priv->tile_cols_log2, 0); |
| | 288 | |
| | 289 | break; |
| | 290 | } |
| | 291 | } |
| | 292 | |
| | 293 | /** try non-uniformed tile. */ |
| | 294 | widest_tile_sb = 0; |
| | 295 | for (i = 0; i < priv->tile_cols; i++) { |
| | 296 | priv->width_in_sbs_minus_1[i] = (i + 1) * priv->sb_cols / priv->tile_cols - i * priv->sb_cols / priv->tile_cols - 1; |
| | 297 | widest_tile_sb = FFMAX(widest_tile_sb, priv->width_in_sbs_minus_1[i] + 1); |
| | 298 | } |
| | 299 | |
| | 300 | if (min_log2_tiles) |
| | 301 | max_tile_area_sb_varied = (priv->sb_rows * priv->sb_cols) >> (min_log2_tiles + 1); |
| | 302 | else |
| | 303 | max_tile_area_sb_varied = priv->sb_rows * priv->sb_cols; |
| | 304 | priv->max_tile_height_sb = FFMAX(1, max_tile_area_sb_varied / widest_tile_sb); |
| | 305 | |
| | 306 | if (tile_rows == av_clip(tile_rows, (priv->sb_rows + priv->max_tile_height_sb - 1) / priv->max_tile_height_sb, priv->sb_rows)) { |
| | 307 | for (i = 0; i < tile_rows; i++) |
| | 308 | priv->height_in_sbs_minus_1[i] = (i + 1) * priv->sb_rows / tile_rows - i * priv->sb_rows / tile_rows - 1; |
| | 309 | |
| | 310 | break; |
| | 311 | } |
| | 312 | |
| | 313 | /** Return invalid parameter if explicit tile rows is set. */ |
| | 314 | if (priv->tile_rows) { |
| | 315 | av_log(avctx, AV_LOG_ERROR, "Invalid tile rows %d.\n", priv->tile_rows); |
| | 316 | return AVERROR(EINVAL); |
| | 317 | } |
| | 318 | } |
| | 319 | |
| | 320 | priv->tile_rows = tile_rows; |
| | 321 | av_log(avctx, AV_LOG_DEBUG, "Setting tile cols/rows to %d/%d.\n", |
| | 322 | priv->tile_cols, priv->tile_rows); |
| | 323 | |
| | 324 | /** check if tile cols/rows is supported by driver. */ |
| | 325 | if (priv->attr_ext2.bits.max_tile_num_minus1) { |
| | 326 | if ((priv->tile_cols * priv->tile_rows - 1) > priv->attr_ext2.bits.max_tile_num_minus1) { |
| | 327 | av_log(avctx, AV_LOG_ERROR, "Unsupported tile num %d * %d = %d by driver, " |
| | 328 | "should be at most %d.\n", priv->tile_cols, priv->tile_rows, |
| | 329 | priv->tile_cols * priv->tile_rows, |
| | 330 | priv->attr_ext2.bits.max_tile_num_minus1 + 1); |
| | 331 | return AVERROR(EINVAL); |
| | 332 | } |
| | 333 | } |
| | 334 | |
| | 335 | /** check if tile group numbers is valid. */ |
| | 336 | if (priv->tile_groups > priv->tile_cols * priv->tile_rows) { |
| | 337 | av_log(avctx, AV_LOG_WARNING, "Invalid tile groups number %d, " |
| | 338 | "correct to %d.\n", priv->tile_groups, priv->tile_cols * priv->tile_rows); |
| | 339 | priv->tile_groups = priv->tile_cols * priv->tile_rows; |
| | 340 | } |
| | 341 | |
| | 342 | return 0; |
| | 343 | } |
| | 344 | |
| | 345 | static int vaapi_encode_av1_write_sequence_header(AVCodecContext *avctx, |
| | 346 | char *data, size_t *data_len) |
| | 347 | { |
| | 348 | VAAPIEncodeAV1Context *priv = avctx->priv_data; |
| | 349 | |
| | 350 | memcpy(data, &priv->sh_data, MAX_PARAM_BUFFER_SIZE * sizeof(char)); |
| | 351 | *data_len = priv->sh_data_len; |
| | 352 | |
| | 353 | return 0; |
| | 354 | } |
| | 355 | |
| | 356 | static int vaapi_encode_av1_init_sequence_params(AVCodecContext *avctx) |
| | 357 | { |
| | 358 | VAAPIEncodeContext *ctx = avctx->priv_data; |
| | 359 | VAAPIEncodeAV1Context *priv = avctx->priv_data; |
| | 360 | AV1RawOBU *sh_obu = &priv->sh; |
| | 361 | AV1RawSequenceHeader *sh = &sh_obu->obu.sequence_header; |
| | 362 | VAEncSequenceParameterBufferAV1 *vseq = ctx->codec_sequence_params; |
| | 363 | CodedBitstreamFragment *obu = &priv->current_obu; |
| | 364 | const AVPixFmtDescriptor *desc; |
| | 365 | int ret; |
| | 366 | |
| | 367 | memset(sh_obu, 0, sizeof(*sh_obu)); |
| | 368 | sh_obu->header.obu_type = AV1_OBU_SEQUENCE_HEADER; |
| | 369 | |
| | 370 | desc = av_pix_fmt_desc_get(priv->common.input_frames->sw_format); |
| | 371 | av_assert0(desc); |
| | 372 | |
| | 373 | sh->seq_profile = avctx->profile; |
| | 374 | if (!sh->seq_force_screen_content_tools) |
| | 375 | sh->seq_force_integer_mv = AV1_SELECT_INTEGER_MV; |
| | 376 | sh->frame_width_bits_minus_1 = av_log2(avctx->width); |
| | 377 | sh->frame_height_bits_minus_1 = av_log2(avctx->height); |
| | 378 | sh->max_frame_width_minus_1 = avctx->width - 1; |
| | 379 | sh->max_frame_height_minus_1 = avctx->height - 1; |
| | 380 | sh->seq_tier[0] = priv->tier; |
| | 381 | /** enable order hint and reserve maximum 8 bits for it by default. */ |
| | 382 | sh->enable_order_hint = 1; |
| | 383 | sh->order_hint_bits_minus_1 = 7; |
| | 384 | |
| | 385 | sh->color_config = (AV1RawColorConfig) { |
| | 386 | .high_bitdepth = desc->comp[0].depth == 8 ? 0 : 1, |
| | 387 | .color_primaries = avctx->color_primaries, |
| | 388 | .transfer_characteristics = avctx->color_trc, |
| | 389 | .matrix_coefficients = avctx->colorspace, |
| | 390 | .color_description_present_flag = (avctx->color_primaries != AVCOL_PRI_UNSPECIFIED || |
| | 391 | avctx->color_trc != AVCOL_TRC_UNSPECIFIED || |
| | 392 | avctx->colorspace != AVCOL_SPC_UNSPECIFIED), |
| | 393 | .color_range = avctx->color_range == AVCOL_RANGE_JPEG, |
| | 394 | .subsampling_x = desc->log2_chroma_w, |
| | 395 | .subsampling_y = desc->log2_chroma_h, |
| | 396 | }; |
| | 397 | |
| | 398 | switch (avctx->chroma_sample_location) { |
| | 399 | case AVCHROMA_LOC_LEFT: |
| | 400 | sh->color_config.chroma_sample_position = AV1_CSP_VERTICAL; |
| | 401 | break; |
| | 402 | case AVCHROMA_LOC_TOPLEFT: |
| | 403 | sh->color_config.chroma_sample_position = AV1_CSP_COLOCATED; |
| | 404 | break; |
| | 405 | default: |
| | 406 | sh->color_config.chroma_sample_position = AV1_CSP_UNKNOWN; |
| | 407 | break; |
| | 408 | } |
| | 409 | |
| | 410 | if (avctx->level != AV_LEVEL_UNKNOWN) { |
| | 411 | sh->seq_level_idx[0] = avctx->level; |
| | 412 | } else { |
| | 413 | const AV1LevelDescriptor *level; |
| | 414 | float framerate; |
| | 415 | |
| | 416 | if (avctx->framerate.num > 0 && avctx->framerate.den > 0) |
| | 417 | framerate = avctx->framerate.num / avctx->framerate.den; |
| | 418 | else |
| | 419 | framerate = 0; |
| | 420 | |
| | 421 | level = ff_av1_guess_level(avctx->bit_rate, priv->tier, |
| | 422 | ctx->surface_width, ctx->surface_height, |
| | 423 | priv->tile_rows * priv->tile_cols, |
| | 424 | priv->tile_cols, framerate); |
| | 425 | if (level) { |
| | 426 | av_log(avctx, AV_LOG_VERBOSE, "Using level %s.\n", level->name); |
| | 427 | sh->seq_level_idx[0] = level->level_idx; |
| | 428 | } else { |
| | 429 | av_log(avctx, AV_LOG_VERBOSE, "Stream will not conform to " |
| | 430 | "any normal level, using maximum parameters level by default.\n"); |
| | 431 | sh->seq_level_idx[0] = 31; |
| | 432 | sh->seq_tier[0] = 1; |
| | 433 | } |
| | 434 | } |
| | 435 | vseq->seq_profile = sh->seq_profile; |
| | 436 | vseq->seq_level_idx = sh->seq_level_idx[0]; |
| | 437 | vseq->seq_tier = sh->seq_tier[0]; |
| | 438 | vseq->order_hint_bits_minus_1 = sh->order_hint_bits_minus_1; |
| | 439 | vseq->intra_period = ctx->gop_size; |
| | 440 | vseq->ip_period = ctx->b_per_p + 1; |
| | 441 | |
| | 442 | vseq->seq_fields.bits.enable_order_hint = sh->enable_order_hint; |
| | 443 | |
| | 444 | if (!(ctx->va_rc_mode & VA_RC_CQP)) { |
| | 445 | vseq->bits_per_second = ctx->va_bit_rate; |
| | 446 | vseq->seq_fields.bits.enable_cdef = sh->enable_cdef = 1; |
| | 447 | } |
| | 448 | |
| | 449 | ret = vaapi_encode_av1_add_obu(avctx, obu, AV1_OBU_SEQUENCE_HEADER, &priv->sh); |
| | 450 | if (ret < 0) |
| | 451 | goto end; |
| | 452 | |
| | 453 | ret = vaapi_encode_av1_write_obu(avctx, priv->sh_data, &priv->sh_data_len, obu); |
| | 454 | if (ret < 0) |
| | 455 | goto end; |
| | 456 | |
| | 457 | end: |
| | 458 | ff_cbs_fragment_reset(obu); |
| | 459 | return ret; |
| | 460 | } |
| | 461 | |
| | 462 | static int vaapi_encode_av1_init_picture_params(AVCodecContext *avctx, |
| | 463 | VAAPIEncodePicture *pic) |
| | 464 | { |
| | 465 | VAAPIEncodeContext *ctx = avctx->priv_data; |
| | 466 | VAAPIEncodeAV1Context *priv = avctx->priv_data; |
| | 467 | VAAPIEncodeAV1Picture *hpic = pic->priv_data; |
| | 468 | AV1RawOBU *fh_obu = &priv->fh; |
| | 469 | AV1RawFrameHeader *fh = &fh_obu->obu.frame.header; |
| | 470 | VAEncPictureParameterBufferAV1 *vpic = pic->codec_picture_params; |
| | 471 | CodedBitstreamFragment *obu = &priv->current_obu; |
| | 472 | VAAPIEncodePicture *ref; |
| | 473 | VAAPIEncodeAV1Picture *href; |
| | 474 | int slot, i; |
| | 475 | int ret; |
| | 476 | static const int8_t default_loop_filter_ref_deltas[AV1_TOTAL_REFS_PER_FRAME] = |
| | 477 | { 1, 0, 0, 0, -1, 0, -1, -1 }; |
| | 478 | |
| | 479 | memset(fh_obu, 0, sizeof(*fh_obu)); |
| | 480 | pic->nb_slices = priv->tile_groups; |
| | 481 | pic->non_independent_frame = pic->encode_order < pic->display_order; |
| | 482 | fh_obu->header.obu_type = AV1_OBU_FRAME_HEADER; |
| | 483 | fh_obu->header.obu_has_size_field = 1; |
| | 484 | |
| | 485 | switch (pic->type) { |
| | 486 | case PICTURE_TYPE_IDR: |
| | 487 | av_assert0(pic->nb_refs[0] == 0 || pic->nb_refs[1]); |
| | 488 | fh->frame_type = AV1_FRAME_KEY; |
| | 489 | fh->refresh_frame_flags = 0xFF; |
| | 490 | fh->base_q_idx = priv->q_idx_idr; |
| | 491 | hpic->slot = 0; |
| | 492 | hpic->last_idr_frame = pic->display_order; |
| | 493 | break; |
| | 494 | case PICTURE_TYPE_P: |
| | 495 | av_assert0(pic->nb_refs[0]); |
| | 496 | fh->frame_type = AV1_FRAME_INTER; |
| | 497 | fh->base_q_idx = priv->q_idx_p; |
| | 498 | ref = pic->refs[0][pic->nb_refs[0] - 1]; |
| | 499 | href = ref->priv_data; |
| | 500 | hpic->slot = !href->slot; |
| | 501 | hpic->last_idr_frame = href->last_idr_frame; |
| | 502 | fh->refresh_frame_flags = 1 << hpic->slot; |
| | 503 | |
| | 504 | /** set the nearest frame in L0 as all reference frame. */ |
| | 505 | for (i = 0; i < AV1_REFS_PER_FRAME; i++) { |
| | 506 | fh->ref_frame_idx[i] = href->slot; |
| | 507 | } |
| | 508 | fh->primary_ref_frame = href->slot; |
| | 509 | fh->ref_order_hint[href->slot] = ref->display_order - href->last_idr_frame; |
| | 510 | vpic->ref_frame_ctrl_l0.fields.search_idx0 = AV1_REF_FRAME_LAST; |
| | 511 | |
| | 512 | /** set the 2nd nearest frame in L0 as Golden frame. */ |
| | 513 | if (pic->nb_refs[0] > 1) { |
| | 514 | ref = pic->refs[0][pic->nb_refs[0] - 2]; |
| | 515 | href = ref->priv_data; |
| | 516 | fh->ref_frame_idx[3] = href->slot; |
| | 517 | fh->ref_order_hint[href->slot] = ref->display_order - href->last_idr_frame; |
| | 518 | vpic->ref_frame_ctrl_l0.fields.search_idx1 = AV1_REF_FRAME_GOLDEN; |
| | 519 | } |
| | 520 | break; |
| | 521 | case PICTURE_TYPE_B: |
| | 522 | av_assert0(pic->nb_refs[0] && pic->nb_refs[1]); |
| | 523 | fh->frame_type = AV1_FRAME_INTER; |
| | 524 | fh->base_q_idx = priv->q_idx_b; |
| | 525 | fh->refresh_frame_flags = 0x0; |
| | 526 | fh->reference_select = 1; |
| | 527 | |
| | 528 | /** B frame will not be referenced, disable its recon frame. */ |
| | 529 | vpic->picture_flags.bits.disable_frame_recon = 1; |
| | 530 | |
| | 531 | /** Use LAST_FRAME and BWDREF_FRAME for reference. */ |
| | 532 | vpic->ref_frame_ctrl_l0.fields.search_idx0 = AV1_REF_FRAME_LAST; |
| | 533 | vpic->ref_frame_ctrl_l1.fields.search_idx0 = AV1_REF_FRAME_BWDREF; |
| | 534 | |
| | 535 | ref = pic->refs[0][pic->nb_refs[0] - 1]; |
| | 536 | href = ref->priv_data; |
| | 537 | hpic->last_idr_frame = href->last_idr_frame; |
| | 538 | fh->primary_ref_frame = href->slot; |
| | 539 | fh->ref_order_hint[href->slot] = ref->display_order - href->last_idr_frame; |
| | 540 | for (i = 0; i < AV1_REF_FRAME_GOLDEN; i++) { |
| | 541 | fh->ref_frame_idx[i] = href->slot; |
| | 542 | } |
| | 543 | |
| | 544 | ref = pic->refs[1][pic->nb_refs[1] - 1]; |
| | 545 | href = ref->priv_data; |
| | 546 | fh->ref_order_hint[href->slot] = ref->display_order - href->last_idr_frame; |
| | 547 | for (i = AV1_REF_FRAME_GOLDEN; i < AV1_REFS_PER_FRAME; i++) { |
| | 548 | fh->ref_frame_idx[i] = href->slot; |
| | 549 | } |
| | 550 | break; |
| | 551 | default: |
| | 552 | av_assert0(0 && "invalid picture type"); |
| | 553 | } |
| | 554 | |
| | 555 | fh->show_frame = pic->display_order <= pic->encode_order; |
| | 556 | fh->showable_frame = fh->frame_type != AV1_FRAME_KEY; |
| | 557 | fh->frame_width_minus_1 = avctx->width - 1; |
| | 558 | fh->frame_height_minus_1 = avctx->height - 1; |
| | 559 | fh->render_width_minus_1 = fh->frame_width_minus_1; |
| | 560 | fh->render_height_minus_1 = fh->frame_height_minus_1; |
| | 561 | fh->order_hint = pic->display_order - hpic->last_idr_frame; |
| | 562 | fh->tile_cols = priv->tile_cols; |
| | 563 | fh->tile_rows = priv->tile_rows; |
| | 564 | fh->tile_cols_log2 = priv->tile_cols_log2; |
| | 565 | fh->tile_rows_log2 = priv->tile_rows_log2; |
| | 566 | fh->uniform_tile_spacing_flag = priv->uniform_tile; |
| | 567 | fh->tile_size_bytes_minus1 = priv->attr_ext2.bits.tile_size_bytes_minus1; |
| | 568 | |
| | 569 | /** ignore ONLY_4x4 mode for codedlossless is not fully implemented. */ |
| | 570 | if (priv->attr_ext2.bits.tx_mode_support & 0x04) |
| | 571 | fh->tx_mode = AV1_TX_MODE_SELECT; |
| | 572 | else if (priv->attr_ext2.bits.tx_mode_support & 0x02) |
| | 573 | fh->tx_mode = AV1_TX_MODE_LARGEST; |
| | 574 | else { |
| | 575 | av_log(avctx, AV_LOG_ERROR, "No available tx mode found.\n"); |
| | 576 | return AVERROR(EINVAL); |
| | 577 | } |
| | 578 | |
| | 579 | for (i = 0; i < fh->tile_cols; i++) |
| | 580 | fh->width_in_sbs_minus_1[i] = vpic->width_in_sbs_minus_1[i] = priv->width_in_sbs_minus_1[i]; |
| | 581 | |
| | 582 | for (i = 0; i < fh->tile_rows; i++) |
| | 583 | fh->height_in_sbs_minus_1[i] = vpic->height_in_sbs_minus_1[i] = priv->height_in_sbs_minus_1[i]; |
| | 584 | |
| | 585 | memcpy(fh->loop_filter_ref_deltas, default_loop_filter_ref_deltas, |
| | 586 | AV1_TOTAL_REFS_PER_FRAME * sizeof(int8_t)); |
| | 587 | |
| | 588 | if (fh->frame_type == AV1_FRAME_KEY && fh->show_frame) { |
| | 589 | fh->error_resilient_mode = 1; |
| | 590 | } |
| | 591 | |
| | 592 | if (fh->frame_type == AV1_FRAME_KEY || fh->error_resilient_mode) |
| | 593 | fh->primary_ref_frame = AV1_PRIMARY_REF_NONE; |
| | 594 | |
| | 595 | vpic->base_qindex = fh->base_q_idx; |
| | 596 | vpic->frame_width_minus_1 = fh->frame_width_minus_1; |
| | 597 | vpic->frame_height_minus_1 = fh->frame_height_minus_1; |
| | 598 | vpic->primary_ref_frame = fh->primary_ref_frame; |
| | 599 | vpic->reconstructed_frame = pic->recon_surface; |
| | 600 | vpic->coded_buf = pic->output_buffer; |
| | 601 | vpic->tile_cols = fh->tile_cols; |
| | 602 | vpic->tile_rows = fh->tile_rows; |
| | 603 | vpic->order_hint = fh->order_hint; |
| | 604 | #if VA_CHECK_VERSION(1, 15, 0) |
| | 605 | vpic->refresh_frame_flags = fh->refresh_frame_flags; |
| | 606 | #endif |
| | 607 | |
| | 608 | vpic->picture_flags.bits.enable_frame_obu = 0; |
| | 609 | vpic->picture_flags.bits.frame_type = fh->frame_type; |
| | 610 | vpic->picture_flags.bits.reduced_tx_set = fh->reduced_tx_set; |
| | 611 | vpic->picture_flags.bits.error_resilient_mode = fh->error_resilient_mode; |
| | 612 | |
| | 613 | /** let driver decide to use single or compound reference prediction mode. */ |
| | 614 | vpic->mode_control_flags.bits.reference_mode = fh->reference_select ? 2 : 0; |
| | 615 | vpic->mode_control_flags.bits.tx_mode = fh->tx_mode; |
| | 616 | |
| | 617 | vpic->tile_group_obu_hdr_info.bits.obu_has_size_field = 1; |
| | 618 | |
| | 619 | /** set reference. */ |
| | 620 | for (i = 0; i < AV1_REFS_PER_FRAME; i++) |
| | 621 | vpic->ref_frame_idx[i] = fh->ref_frame_idx[i]; |
| | 622 | |
| | 623 | for (i = 0; i < FF_ARRAY_ELEMS(vpic->reference_frames); i++) |
| | 624 | vpic->reference_frames[i] = VA_INVALID_SURFACE; |
| | 625 | |
| | 626 | for (i = 0; i < MAX_REFERENCE_LIST_NUM; i++) { |
| | 627 | for (int j = 0; j < pic->nb_refs[i]; j++) { |
| | 628 | VAAPIEncodePicture *ref_pic = pic->refs[i][j]; |
| | 629 | |
| | 630 | slot = ((VAAPIEncodeAV1Picture*)ref_pic->priv_data)->slot; |
| | 631 | av_assert0(vpic->reference_frames[slot] == VA_INVALID_SURFACE); |
| | 632 | |
| | 633 | vpic->reference_frames[slot] = ref_pic->recon_surface; |
| | 634 | } |
| | 635 | } |
| | 636 | |
| | 637 | fh_obu->obu_size_byte_len = priv->attr_ext2.bits.obu_size_bytes_minus1 + 1; |
| | 638 | ret = vaapi_encode_av1_add_obu(avctx, obu, AV1_OBU_FRAME_HEADER, &priv->fh); |
| | 639 | if (ret < 0) |
| | 640 | goto end; |
| | 641 | |
| | 642 | ret = vaapi_encode_av1_write_obu(avctx, priv->fh_data, &priv->fh_data_len, obu); |
| | 643 | if (ret < 0) |
| | 644 | goto end; |
| | 645 | |
| | 646 | if (!(ctx->va_rc_mode & VA_RC_CQP)) { |
| | 647 | vpic->min_base_qindex = av_clip(avctx->qmin, 1, AV1_MAX_QUANT); |
| | 648 | vpic->max_base_qindex = av_clip(avctx->qmax, 1, AV1_MAX_QUANT); |
| | 649 | |
| | 650 | vpic->bit_offset_qindex = priv->qindex_offset; |
| | 651 | vpic->bit_offset_loopfilter_params = priv->loopfilter_offset; |
| | 652 | vpic->bit_offset_cdef_params = priv->cdef_start_offset; |
| | 653 | vpic->size_in_bits_cdef_params = priv->cdef_param_size; |
| | 654 | vpic->size_in_bits_frame_hdr_obu = priv->fh_data_len; |
| | 655 | vpic->byte_offset_frame_hdr_obu_size = (((pic->type == PICTURE_TYPE_IDR) ? |
| | 656 | priv->sh_data_len / 8 : 0) + |
| | 657 | (fh_obu->header.obu_extension_flag ? |
| | 658 | 2 : 1)); |
| | 659 | } |
| | 660 | |
| | 661 | end: |
| | 662 | ff_cbs_fragment_reset(obu); |
| | 663 | return ret; |
| | 664 | } |
| | 665 | |
| | 666 | static int vaapi_encode_av1_init_slice_params(AVCodecContext *avctx, |
| | 667 | VAAPIEncodePicture *pic, |
| | 668 | VAAPIEncodeSlice *slice) |
| | 669 | { |
| | 670 | VAAPIEncodeAV1Context *priv = avctx->priv_data; |
| | 671 | VAEncTileGroupBufferAV1 *vslice = slice->codec_slice_params; |
| | 672 | CodedBitstreamAV1Context *cbctx = priv->cbc->priv_data; |
| | 673 | int div; |
| | 674 | |
| | 675 | /** Set tile group info. */ |
| | 676 | div = priv->tile_cols * priv->tile_rows / priv->tile_groups; |
| | 677 | vslice->tg_start = slice->index * div; |
| | 678 | if (slice->index == (priv->tile_groups - 1)) { |
| | 679 | vslice->tg_end = priv->tile_cols * priv->tile_rows - 1; |
| | 680 | cbctx->seen_frame_header = 0; |
| | 681 | } else { |
| | 682 | vslice->tg_end = (slice->index + 1) * div - 1; |
| | 683 | } |
| | 684 | |
| | 685 | return 0; |
| | 686 | } |
| | 687 | |
| | 688 | static int vaapi_encode_av1_write_picture_header(AVCodecContext *avctx, |
| | 689 | VAAPIEncodePicture *pic, |
| | 690 | char *data, size_t *data_len) |
| | 691 | { |
| | 692 | VAAPIEncodeAV1Context *priv = avctx->priv_data; |
| | 693 | CodedBitstreamFragment *obu = &priv->current_obu; |
| | 694 | CodedBitstreamAV1Context *cbctx = priv->cbc->priv_data; |
| | 695 | AV1RawOBU *fh_obu = &priv->fh; |
| | 696 | AV1RawFrameHeader *rep_fh = &fh_obu->obu.frame_header; |
| | 697 | VAAPIEncodeAV1Picture *href; |
| | 698 | int ret = 0; |
| | 699 | |
| | 700 | pic->tail_size = 0; |
| | 701 | /** Pack repeat frame header. */ |
| | 702 | if (pic->display_order > pic->encode_order) { |
| | 703 | memset(fh_obu, 0, sizeof(*fh_obu)); |
| | 704 | href = pic->refs[0][pic->nb_refs[0] - 1]->priv_data; |
| | 705 | fh_obu->header.obu_type = AV1_OBU_FRAME_HEADER; |
| | 706 | fh_obu->header.obu_has_size_field = 1; |
| | 707 | |
| | 708 | rep_fh->show_existing_frame = 1; |
| | 709 | rep_fh->frame_to_show_map_idx = href->slot == 0; |
| | 710 | rep_fh->frame_type = AV1_FRAME_INTER; |
| | 711 | rep_fh->frame_width_minus_1 = avctx->width - 1; |
| | 712 | rep_fh->frame_height_minus_1 = avctx->height - 1; |
| | 713 | rep_fh->render_width_minus_1 = rep_fh->frame_width_minus_1; |
| | 714 | rep_fh->render_height_minus_1 = rep_fh->frame_height_minus_1; |
| | 715 | |
| | 716 | cbctx->seen_frame_header = 0; |
| | 717 | |
| | 718 | ret = vaapi_encode_av1_add_obu(avctx, obu, AV1_OBU_FRAME_HEADER, &priv->fh); |
| | 719 | if (ret < 0) |
| | 720 | goto end; |
| | 721 | |
| | 722 | ret = vaapi_encode_av1_write_obu(avctx, pic->tail_data, &pic->tail_size, obu); |
| | 723 | if (ret < 0) |
| | 724 | goto end; |
| | 725 | |
| | 726 | pic->tail_size /= 8; |
| | 727 | } |
| | 728 | |
| | 729 | memcpy(data, &priv->fh_data, MAX_PARAM_BUFFER_SIZE * sizeof(char)); |
| | 730 | *data_len = priv->fh_data_len; |
| | 731 | |
| | 732 | end: |
| | 733 | ff_cbs_fragment_reset(obu); |
| | 734 | return ret; |
| | 735 | } |
| | 736 | |
| | 737 | static const VAAPIEncodeProfile vaapi_encode_av1_profiles[] = { |
| | 738 | { AV_PROFILE_AV1_MAIN, 8, 3, 1, 1, VAProfileAV1Profile0 }, |
| | 739 | { AV_PROFILE_AV1_MAIN, 10, 3, 1, 1, VAProfileAV1Profile0 }, |
| | 740 | { AV_PROFILE_UNKNOWN } |
| | 741 | }; |
| | 742 | |
| | 743 | static const VAAPIEncodeType vaapi_encode_type_av1 = { |
| | 744 | .profiles = vaapi_encode_av1_profiles, |
| | 745 | .flags = FLAG_B_PICTURES | FLAG_TIMESTAMP_NO_DELAY, |
| | 746 | .default_quality = 25, |
| | 747 | |
| | 748 | .get_encoder_caps = &vaapi_encode_av1_get_encoder_caps, |
| | 749 | .configure = &vaapi_encode_av1_configure, |
| | 750 | |
| | 751 | .sequence_header_type = VAEncPackedHeaderSequence, |
| | 752 | .sequence_params_size = sizeof(VAEncSequenceParameterBufferAV1), |
| | 753 | .init_sequence_params = &vaapi_encode_av1_init_sequence_params, |
| | 754 | .write_sequence_header = &vaapi_encode_av1_write_sequence_header, |
| | 755 | |
| | 756 | .picture_priv_data_size = sizeof(VAAPIEncodeAV1Picture), |
| | 757 | .picture_header_type = VAEncPackedHeaderPicture, |
| | 758 | .picture_params_size = sizeof(VAEncPictureParameterBufferAV1), |
| | 759 | .init_picture_params = &vaapi_encode_av1_init_picture_params, |
| | 760 | .write_picture_header = &vaapi_encode_av1_write_picture_header, |
| | 761 | |
| | 762 | .slice_params_size = sizeof(VAEncTileGroupBufferAV1), |
| | 763 | .init_slice_params = &vaapi_encode_av1_init_slice_params, |
| | 764 | }; |
| | 765 | |
| | 766 | static av_cold int vaapi_encode_av1_init(AVCodecContext *avctx) |
| | 767 | { |
| | 768 | VAAPIEncodeContext *ctx = avctx->priv_data; |
| | 769 | VAAPIEncodeAV1Context *priv = avctx->priv_data; |
| | 770 | VAConfigAttrib attr; |
| | 771 | VAStatus vas; |
| | 772 | int ret; |
| | 773 | |
| | 774 | ctx->codec = &vaapi_encode_type_av1; |
| | 775 | |
| | 776 | ctx->desired_packed_headers = |
| | 777 | VA_ENC_PACKED_HEADER_SEQUENCE | |
| | 778 | VA_ENC_PACKED_HEADER_PICTURE; |
| | 779 | |
| | 780 | if (avctx->profile == AV_PROFILE_UNKNOWN) |
| | 781 | avctx->profile = priv->profile; |
| | 782 | if (avctx->level == AV_LEVEL_UNKNOWN) |
| | 783 | avctx->level = priv->level; |
| | 784 | |
| | 785 | if (avctx->level != AV_LEVEL_UNKNOWN && avctx->level & ~0x1f) { |
| | 786 | av_log(avctx, AV_LOG_ERROR, "Invalid level %d\n", avctx->level); |
| | 787 | return AVERROR(EINVAL); |
| | 788 | } |
| | 789 | |
| | 790 | ret = ff_vaapi_encode_init(avctx); |
| | 791 | if (ret < 0) |
| | 792 | return ret; |
| | 793 | |
| | 794 | attr.type = VAConfigAttribEncAV1; |
| | 795 | vas = vaGetConfigAttributes(ctx->hwctx->display, |
| | 796 | ctx->va_profile, |
| | 797 | ctx->va_entrypoint, |
| | 798 | &attr, 1); |
| | 799 | if (vas != VA_STATUS_SUCCESS) { |
| | 800 | av_log(avctx, AV_LOG_ERROR, "Failed to query " |
| | 801 | "config attribute: %d (%s).\n", vas, vaErrorStr(vas)); |
| | 802 | return AVERROR_EXTERNAL; |
| | 803 | } else if (attr.value == VA_ATTRIB_NOT_SUPPORTED) { |
| | 804 | priv->attr.value = 0; |
| | 805 | av_log(avctx, AV_LOG_WARNING, "Attribute type:%d is not " |
| | 806 | "supported.\n", attr.type); |
| | 807 | } else { |
| | 808 | priv->attr.value = attr.value; |
| | 809 | } |
| | 810 | |
| | 811 | attr.type = VAConfigAttribEncAV1Ext1; |
| | 812 | vas = vaGetConfigAttributes(ctx->hwctx->display, |
| | 813 | ctx->va_profile, |
| | 814 | ctx->va_entrypoint, |
| | 815 | &attr, 1); |
| | 816 | if (vas != VA_STATUS_SUCCESS) { |
| | 817 | av_log(avctx, AV_LOG_ERROR, "Failed to query " |
| | 818 | "config attribute: %d (%s).\n", vas, vaErrorStr(vas)); |
| | 819 | return AVERROR_EXTERNAL; |
| | 820 | } else if (attr.value == VA_ATTRIB_NOT_SUPPORTED) { |
| | 821 | priv->attr_ext1.value = 0; |
| | 822 | av_log(avctx, AV_LOG_WARNING, "Attribute type:%d is not " |
| | 823 | "supported.\n", attr.type); |
| | 824 | } else { |
| | 825 | priv->attr_ext1.value = attr.value; |
| | 826 | } |
| | 827 | |
| | 828 | /** This attr provides essential indicators, return error if not support. */ |
| | 829 | attr.type = VAConfigAttribEncAV1Ext2; |
| | 830 | vas = vaGetConfigAttributes(ctx->hwctx->display, |
| | 831 | ctx->va_profile, |
| | 832 | ctx->va_entrypoint, |
| | 833 | &attr, 1); |
| | 834 | if (vas != VA_STATUS_SUCCESS || attr.value == VA_ATTRIB_NOT_SUPPORTED) { |
| | 835 | av_log(avctx, AV_LOG_ERROR, "Failed to query " |
| | 836 | "config attribute: %d (%s).\n", vas, vaErrorStr(vas)); |
| | 837 | return AVERROR_EXTERNAL; |
| | 838 | } else { |
| | 839 | priv->attr_ext2.value = attr.value; |
| | 840 | } |
| | 841 | |
| | 842 | ret = vaapi_encode_av1_set_tile(avctx); |
| | 843 | if (ret < 0) |
| | 844 | return ret; |
| | 845 | |
| | 846 | return 0; |
| | 847 | } |
| | 848 | |
| | 849 | static av_cold int vaapi_encode_av1_close(AVCodecContext *avctx) |
| | 850 | { |
| | 851 | VAAPIEncodeAV1Context *priv = avctx->priv_data; |
| | 852 | |
| | 853 | ff_cbs_fragment_free(&priv->current_obu); |
| | 854 | ff_cbs_close(&priv->cbc); |
| | 855 | |
| | 856 | return ff_vaapi_encode_close(avctx); |
| | 857 | } |
| | 858 | |
| | 859 | #define OFFSET(x) offsetof(VAAPIEncodeAV1Context, x) |
| | 860 | #define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM) |
| | 861 | |
| | 862 | static const AVOption vaapi_encode_av1_options[] = { |
| | 863 | VAAPI_ENCODE_COMMON_OPTIONS, |
| | 864 | VAAPI_ENCODE_RC_OPTIONS, |
| | 865 | { "profile", "Set profile (seq_profile)", |
| | 866 | OFFSET(profile), AV_OPT_TYPE_INT, |
| | 867 | { .i64 = AV_PROFILE_UNKNOWN }, AV_PROFILE_UNKNOWN, 0xff, FLAGS, "profile" }, |
| | 868 | |
| | 869 | #define PROFILE(name, value) name, NULL, 0, AV_OPT_TYPE_CONST, \ |
| | 870 | { .i64 = value }, 0, 0, FLAGS, "profile" |
| | 871 | { PROFILE("main", AV_PROFILE_AV1_MAIN) }, |
| | 872 | { PROFILE("high", AV_PROFILE_AV1_HIGH) }, |
| | 873 | { PROFILE("professional", AV_PROFILE_AV1_PROFESSIONAL) }, |
| | 874 | #undef PROFILE |
| | 875 | |
| | 876 | { "tier", "Set tier (seq_tier)", |
| | 877 | OFFSET(tier), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, FLAGS, "tier" }, |
| | 878 | { "main", NULL, 0, AV_OPT_TYPE_CONST, |
| | 879 | { .i64 = 0 }, 0, 0, FLAGS, "tier" }, |
| | 880 | { "high", NULL, 0, AV_OPT_TYPE_CONST, |
| | 881 | { .i64 = 1 }, 0, 0, FLAGS, "tier" }, |
| | 882 | { "level", "Set level (seq_level_idx)", |
| | 883 | OFFSET(level), AV_OPT_TYPE_INT, |
| | 884 | { .i64 = AV_LEVEL_UNKNOWN }, AV_LEVEL_UNKNOWN, 0x1f, FLAGS, "level" }, |
| | 885 | |
| | 886 | #define LEVEL(name, value) name, NULL, 0, AV_OPT_TYPE_CONST, \ |
| | 887 | { .i64 = value }, 0, 0, FLAGS, "level" |
| | 888 | { LEVEL("2.0", 0) }, |
| | 889 | { LEVEL("2.1", 1) }, |
| | 890 | { LEVEL("3.0", 4) }, |
| | 891 | { LEVEL("3.1", 5) }, |
| | 892 | { LEVEL("4.0", 8) }, |
| | 893 | { LEVEL("4.1", 9) }, |
| | 894 | { LEVEL("5.0", 12) }, |
| | 895 | { LEVEL("5.1", 13) }, |
| | 896 | { LEVEL("5.2", 14) }, |
| | 897 | { LEVEL("5.3", 15) }, |
| | 898 | { LEVEL("6.0", 16) }, |
| | 899 | { LEVEL("6.1", 17) }, |
| | 900 | { LEVEL("6.2", 18) }, |
| | 901 | { LEVEL("6.3", 19) }, |
| | 902 | #undef LEVEL |
| | 903 | |
| | 904 | { "tiles", "Tile columns x rows (Use minimal tile column/row number automatically by default)", |
| | 905 | OFFSET(tile_cols), AV_OPT_TYPE_IMAGE_SIZE, { .str = NULL }, 0, 0, FLAGS }, |
| | 906 | { "tile_groups", "Number of tile groups for encoding", |
| | 907 | OFFSET(tile_groups), AV_OPT_TYPE_INT, { .i64 = 1 }, 1, AV1_MAX_TILE_ROWS * AV1_MAX_TILE_COLS, FLAGS }, |
| | 908 | |
| | 909 | { NULL }, |
| | 910 | }; |
| | 911 | |
| | 912 | static const FFCodecDefault vaapi_encode_av1_defaults[] = { |
| | 913 | { "b", "0" }, |
| | 914 | { "bf", "2" }, |
| | 915 | { "g", "120" }, |
| | 916 | { "qmin", "1" }, |
| | 917 | { "qmax", "255" }, |
| | 918 | { NULL }, |
| | 919 | }; |
| | 920 | |
| | 921 | static const AVClass vaapi_encode_av1_class = { |
| | 922 | .class_name = "av1_vaapi", |
| | 923 | .item_name = av_default_item_name, |
| | 924 | .option = vaapi_encode_av1_options, |
| | 925 | .version = LIBAVUTIL_VERSION_INT, |
| | 926 | }; |
| | 927 | |
| | 928 | const FFCodec ff_av1_vaapi_encoder = { |
| | 929 | .p.name = "av1_vaapi", |
| | 930 | CODEC_LONG_NAME("AV1 (VAAPI)"), |
| | 931 | .p.type = AVMEDIA_TYPE_VIDEO, |
| | 932 | .p.id = AV_CODEC_ID_AV1, |
| | 933 | .priv_data_size = sizeof(VAAPIEncodeAV1Context), |
| | 934 | .init = &vaapi_encode_av1_init, |
| | 935 | FF_CODEC_RECEIVE_PACKET_CB(&ff_vaapi_encode_receive_packet), |
| | 936 | .close = &vaapi_encode_av1_close, |
| | 937 | .p.priv_class = &vaapi_encode_av1_class, |
| | 938 | .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE | |
| | 939 | AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, |
| | 940 | .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | |
| | 941 | FF_CODEC_CAP_INIT_CLEANUP, |
| | 942 | .defaults = vaapi_encode_av1_defaults, |
| | 943 | .p.pix_fmts = (const enum AVPixelFormat[]) { |
| | 944 | AV_PIX_FMT_VAAPI, |
| | 945 | AV_PIX_FMT_NONE, |
| | 946 | }, |
| | 947 | .hw_configs = ff_vaapi_encode_hw_configs, |
| | 948 | .p.wrapper_name = "vaapi", |
| | 949 | }; |