FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/vaapi_encode_av1.c
Date: 2026-09-28 11:37:26
Exec Total Coverage
Lines: 0 530 0.0%
Functions: 0 15 0.0%
Branches: 0 221 0.0%

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