FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/vaapi_encode.c
Date: 2024-11-20 23:03:26
Exec Total Coverage
Lines: 0 1149 0.0%
Functions: 0 31 0.0%
Branches: 0 700 0.0%

Line Branch Exec Source
1 /*
2 * This file is part of FFmpeg.
3 *
4 * FFmpeg is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * FFmpeg is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with FFmpeg; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 #include <inttypes.h>
20 #include <string.h>
21
22 #include "config.h"
23
24 #include "libavutil/avassert.h"
25 #include "libavutil/common.h"
26 #include "libavutil/internal.h"
27 #include "libavutil/log.h"
28 #include "libavutil/mem.h"
29 #include "libavutil/pixdesc.h"
30
31 #include "vaapi_encode.h"
32 #include "encode.h"
33 #include "avcodec.h"
34 #include "refstruct.h"
35
36 const AVCodecHWConfigInternal *const ff_vaapi_encode_hw_configs[] = {
37 HW_CONFIG_ENCODER_FRAMES(VAAPI, VAAPI),
38 NULL,
39 };
40
41 static int vaapi_encode_make_packed_header(AVCodecContext *avctx,
42 VAAPIEncodePicture *pic,
43 int type, char *data, size_t bit_len)
44 {
45 VAAPIEncodeContext *ctx = avctx->priv_data;
46 VAStatus vas;
47 VABufferID param_buffer, data_buffer;
48 VABufferID *tmp;
49 VAEncPackedHeaderParameterBuffer params = {
50 .type = type,
51 .bit_length = bit_len,
52 .has_emulation_bytes = 1,
53 };
54
55 tmp = av_realloc_array(pic->param_buffers, sizeof(*tmp), pic->nb_param_buffers + 2);
56 if (!tmp)
57 return AVERROR(ENOMEM);
58 pic->param_buffers = tmp;
59
60 vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context,
61 VAEncPackedHeaderParameterBufferType,
62 sizeof(params), 1, &params, &param_buffer);
63 if (vas != VA_STATUS_SUCCESS) {
64 av_log(avctx, AV_LOG_ERROR, "Failed to create parameter buffer "
65 "for packed header (type %d): %d (%s).\n",
66 type, vas, vaErrorStr(vas));
67 return AVERROR(EIO);
68 }
69 pic->param_buffers[pic->nb_param_buffers++] = param_buffer;
70
71 vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context,
72 VAEncPackedHeaderDataBufferType,
73 (bit_len + 7) / 8, 1, data, &data_buffer);
74 if (vas != VA_STATUS_SUCCESS) {
75 av_log(avctx, AV_LOG_ERROR, "Failed to create data buffer "
76 "for packed header (type %d): %d (%s).\n",
77 type, vas, vaErrorStr(vas));
78 return AVERROR(EIO);
79 }
80 pic->param_buffers[pic->nb_param_buffers++] = data_buffer;
81
82 av_log(avctx, AV_LOG_DEBUG, "Packed header buffer (%d) is %#x/%#x "
83 "(%zu bits).\n", type, param_buffer, data_buffer, bit_len);
84 return 0;
85 }
86
87 static int vaapi_encode_make_param_buffer(AVCodecContext *avctx,
88 VAAPIEncodePicture *pic,
89 int type, char *data, size_t len)
90 {
91 VAAPIEncodeContext *ctx = avctx->priv_data;
92 VAStatus vas;
93 VABufferID *tmp;
94 VABufferID buffer;
95
96 tmp = av_realloc_array(pic->param_buffers, sizeof(*tmp), pic->nb_param_buffers + 1);
97 if (!tmp)
98 return AVERROR(ENOMEM);
99 pic->param_buffers = tmp;
100
101 vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context,
102 type, len, 1, data, &buffer);
103 if (vas != VA_STATUS_SUCCESS) {
104 av_log(avctx, AV_LOG_ERROR, "Failed to create parameter buffer "
105 "(type %d): %d (%s).\n", type, vas, vaErrorStr(vas));
106 return AVERROR(EIO);
107 }
108 pic->param_buffers[pic->nb_param_buffers++] = buffer;
109
110 av_log(avctx, AV_LOG_DEBUG, "Param buffer (%d) is %#x.\n",
111 type, buffer);
112 return 0;
113 }
114
115 static int vaapi_encode_make_misc_param_buffer(AVCodecContext *avctx,
116 VAAPIEncodePicture *pic,
117 int type,
118 const void *data, size_t len)
119 {
120 // Construct the buffer on the stack - 1KB is much larger than any
121 // current misc parameter buffer type (the largest is EncQuality at
122 // 224 bytes).
123 uint8_t buffer[1024];
124 VAEncMiscParameterBuffer header = {
125 .type = type,
126 };
127 size_t buffer_size = sizeof(header) + len;
128 av_assert0(buffer_size <= sizeof(buffer));
129
130 memcpy(buffer, &header, sizeof(header));
131 memcpy(buffer + sizeof(header), data, len);
132
133 return vaapi_encode_make_param_buffer(avctx, pic,
134 VAEncMiscParameterBufferType,
135 buffer, buffer_size);
136 }
137
138 static int vaapi_encode_wait(AVCodecContext *avctx, FFHWBaseEncodePicture *base_pic)
139 {
140 #if VA_CHECK_VERSION(1, 9, 0)
141 FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
142 #endif
143 VAAPIEncodeContext *ctx = avctx->priv_data;
144 VAAPIEncodePicture *pic = base_pic->priv;
145 VAStatus vas;
146
147 av_assert0(base_pic->encode_issued);
148
149 if (base_pic->encode_complete) {
150 // Already waited for this picture.
151 return 0;
152 }
153
154 av_log(avctx, AV_LOG_DEBUG, "Sync to pic %"PRId64"/%"PRId64" "
155 "(input surface %#x).\n", base_pic->display_order,
156 base_pic->encode_order, pic->input_surface);
157
158 #if VA_CHECK_VERSION(1, 9, 0)
159 if (base_ctx->async_encode) {
160 vas = vaSyncBuffer(ctx->hwctx->display,
161 pic->output_buffer,
162 VA_TIMEOUT_INFINITE);
163 if (vas != VA_STATUS_SUCCESS) {
164 av_log(avctx, AV_LOG_ERROR, "Failed to sync to output buffer completion: "
165 "%d (%s).\n", vas, vaErrorStr(vas));
166 return AVERROR(EIO);
167 }
168 } else
169 #endif
170 { // If vaSyncBuffer is not implemented, try old version API.
171 vas = vaSyncSurface(ctx->hwctx->display, pic->input_surface);
172 if (vas != VA_STATUS_SUCCESS) {
173 av_log(avctx, AV_LOG_ERROR, "Failed to sync to picture completion: "
174 "%d (%s).\n", vas, vaErrorStr(vas));
175 return AVERROR(EIO);
176 }
177 }
178
179 // Input is definitely finished with now.
180 av_frame_free(&base_pic->input_image);
181
182 base_pic->encode_complete = 1;
183 return 0;
184 }
185
186 static int vaapi_encode_make_row_slice(AVCodecContext *avctx,
187 VAAPIEncodePicture *pic)
188 {
189 VAAPIEncodeContext *ctx = avctx->priv_data;
190 VAAPIEncodeSlice *slice;
191 int i, rounding;
192
193 for (i = 0; i < pic->nb_slices; i++)
194 pic->slices[i].row_size = ctx->slice_size;
195
196 rounding = ctx->slice_block_rows - ctx->nb_slices * ctx->slice_size;
197 if (rounding > 0) {
198 // Place rounding error at top and bottom of frame.
199 av_assert0(rounding < pic->nb_slices);
200 // Some Intel drivers contain a bug where the encoder will fail
201 // if the last slice is smaller than the one before it. Since
202 // that's straightforward to avoid here, just do so.
203 if (rounding <= 2) {
204 for (i = 0; i < rounding; i++)
205 ++pic->slices[i].row_size;
206 } else {
207 for (i = 0; i < (rounding + 1) / 2; i++)
208 ++pic->slices[pic->nb_slices - i - 1].row_size;
209 for (i = 0; i < rounding / 2; i++)
210 ++pic->slices[i].row_size;
211 }
212 } else if (rounding < 0) {
213 // Remove rounding error from last slice only.
214 av_assert0(rounding < ctx->slice_size);
215 pic->slices[pic->nb_slices - 1].row_size += rounding;
216 }
217
218 for (i = 0; i < pic->nb_slices; i++) {
219 slice = &pic->slices[i];
220 slice->index = i;
221 if (i == 0) {
222 slice->row_start = 0;
223 slice->block_start = 0;
224 } else {
225 const VAAPIEncodeSlice *prev = &pic->slices[i - 1];
226 slice->row_start = prev->row_start + prev->row_size;
227 slice->block_start = prev->block_start + prev->block_size;
228 }
229 slice->block_size = slice->row_size * ctx->slice_block_cols;
230
231 av_log(avctx, AV_LOG_DEBUG, "Slice %d: %d-%d (%d rows), "
232 "%d-%d (%d blocks).\n", i, slice->row_start,
233 slice->row_start + slice->row_size - 1, slice->row_size,
234 slice->block_start, slice->block_start + slice->block_size - 1,
235 slice->block_size);
236 }
237
238 return 0;
239 }
240
241 static int vaapi_encode_make_tile_slice(AVCodecContext *avctx,
242 VAAPIEncodePicture *pic)
243 {
244 VAAPIEncodeContext *ctx = avctx->priv_data;
245 VAAPIEncodeSlice *slice;
246 int i, j, index;
247
248 for (i = 0; i < ctx->tile_cols; i++) {
249 for (j = 0; j < ctx->tile_rows; j++) {
250 index = j * ctx->tile_cols + i;
251 slice = &pic->slices[index];
252 slice->index = index;
253
254 pic->slices[index].block_start = ctx->col_bd[i] +
255 ctx->row_bd[j] * ctx->slice_block_cols;
256 pic->slices[index].block_size = ctx->row_height[j] * ctx->col_width[i];
257
258 av_log(avctx, AV_LOG_DEBUG, "Slice %2d: (%2d, %2d) start at: %4d "
259 "width:%2d height:%2d (%d blocks).\n", index, ctx->col_bd[i],
260 ctx->row_bd[j], slice->block_start, ctx->col_width[i],
261 ctx->row_height[j], slice->block_size);
262 }
263 }
264
265 return 0;
266 }
267
268 static int vaapi_encode_issue(AVCodecContext *avctx,
269 FFHWBaseEncodePicture *base_pic)
270 {
271 FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
272 VAAPIEncodeContext *ctx = avctx->priv_data;
273 VAAPIEncodePicture *pic = base_pic->priv;
274 VAAPIEncodeSlice *slice;
275 VAStatus vas;
276 int err = 0, i;
277 char data[MAX_PARAM_BUFFER_SIZE];
278 size_t bit_len;
279 av_unused AVFrameSideData *sd;
280
281 av_log(avctx, AV_LOG_DEBUG, "Issuing encode for pic %"PRId64"/%"PRId64" "
282 "as type %s.\n", base_pic->display_order, base_pic->encode_order,
283 ff_hw_base_encode_get_pictype_name(base_pic->type));
284 if (base_pic->nb_refs[0] == 0 && base_pic->nb_refs[1] == 0) {
285 av_log(avctx, AV_LOG_DEBUG, "No reference pictures.\n");
286 } else {
287 av_log(avctx, AV_LOG_DEBUG, "L0 refers to");
288 for (i = 0; i < base_pic->nb_refs[0]; i++) {
289 av_log(avctx, AV_LOG_DEBUG, " %"PRId64"/%"PRId64,
290 base_pic->refs[0][i]->display_order, base_pic->refs[0][i]->encode_order);
291 }
292 av_log(avctx, AV_LOG_DEBUG, ".\n");
293
294 if (base_pic->nb_refs[1]) {
295 av_log(avctx, AV_LOG_DEBUG, "L1 refers to");
296 for (i = 0; i < base_pic->nb_refs[1]; i++) {
297 av_log(avctx, AV_LOG_DEBUG, " %"PRId64"/%"PRId64,
298 base_pic->refs[1][i]->display_order, base_pic->refs[1][i]->encode_order);
299 }
300 av_log(avctx, AV_LOG_DEBUG, ".\n");
301 }
302 }
303
304 av_assert0(!base_pic->encode_issued);
305 for (i = 0; i < base_pic->nb_refs[0]; i++) {
306 av_assert0(base_pic->refs[0][i]);
307 av_assert0(base_pic->refs[0][i]->encode_issued);
308 }
309 for (i = 0; i < base_pic->nb_refs[1]; i++) {
310 av_assert0(base_pic->refs[1][i]);
311 av_assert0(base_pic->refs[1][i]->encode_issued);
312 }
313
314 av_log(avctx, AV_LOG_DEBUG, "Input surface is %#x.\n", pic->input_surface);
315
316 pic->recon_surface = (VASurfaceID)(uintptr_t)base_pic->recon_image->data[3];
317 av_log(avctx, AV_LOG_DEBUG, "Recon surface is %#x.\n", pic->recon_surface);
318
319 pic->output_buffer_ref = ff_refstruct_pool_get(ctx->output_buffer_pool);
320 if (!pic->output_buffer_ref) {
321 err = AVERROR(ENOMEM);
322 goto fail;
323 }
324 pic->output_buffer = *pic->output_buffer_ref;
325 av_log(avctx, AV_LOG_DEBUG, "Output buffer is %#x.\n",
326 pic->output_buffer);
327
328 if (ctx->codec->picture_params_size > 0) {
329 pic->codec_picture_params = av_malloc(ctx->codec->picture_params_size);
330 if (!pic->codec_picture_params)
331 goto fail;
332 memcpy(pic->codec_picture_params, ctx->codec_picture_params,
333 ctx->codec->picture_params_size);
334 } else {
335 av_assert0(!ctx->codec_picture_params);
336 }
337
338 pic->nb_param_buffers = 0;
339
340 if (base_pic->type == FF_HW_PICTURE_TYPE_IDR && ctx->codec->init_sequence_params) {
341 err = vaapi_encode_make_param_buffer(avctx, pic,
342 VAEncSequenceParameterBufferType,
343 ctx->codec_sequence_params,
344 ctx->codec->sequence_params_size);
345 if (err < 0)
346 goto fail;
347 }
348
349 if (base_pic->type == FF_HW_PICTURE_TYPE_IDR) {
350 for (i = 0; i < ctx->nb_global_params; i++) {
351 err = vaapi_encode_make_misc_param_buffer(avctx, pic,
352 ctx->global_params_type[i],
353 ctx->global_params[i],
354 ctx->global_params_size[i]);
355 if (err < 0)
356 goto fail;
357 }
358 }
359
360 if (ctx->codec->init_picture_params) {
361 err = ctx->codec->init_picture_params(avctx, base_pic);
362 if (err < 0) {
363 av_log(avctx, AV_LOG_ERROR, "Failed to initialise picture "
364 "parameters: %d.\n", err);
365 goto fail;
366 }
367 err = vaapi_encode_make_param_buffer(avctx, pic,
368 VAEncPictureParameterBufferType,
369 pic->codec_picture_params,
370 ctx->codec->picture_params_size);
371 if (err < 0)
372 goto fail;
373 }
374
375 #if VA_CHECK_VERSION(1, 5, 0)
376 if (ctx->max_frame_size) {
377 err = vaapi_encode_make_misc_param_buffer(avctx, pic,
378 VAEncMiscParameterTypeMaxFrameSize,
379 &ctx->mfs_params,
380 sizeof(ctx->mfs_params));
381 if (err < 0)
382 goto fail;
383 }
384 #endif
385
386 if (base_pic->type == FF_HW_PICTURE_TYPE_IDR) {
387 if (ctx->va_packed_headers & VA_ENC_PACKED_HEADER_SEQUENCE &&
388 ctx->codec->write_sequence_header) {
389 bit_len = 8 * sizeof(data);
390 err = ctx->codec->write_sequence_header(avctx, data, &bit_len);
391 if (err < 0) {
392 av_log(avctx, AV_LOG_ERROR, "Failed to write per-sequence "
393 "header: %d.\n", err);
394 goto fail;
395 }
396 err = vaapi_encode_make_packed_header(avctx, pic,
397 ctx->codec->sequence_header_type,
398 data, bit_len);
399 if (err < 0)
400 goto fail;
401 }
402 }
403
404 if (ctx->va_packed_headers & VA_ENC_PACKED_HEADER_PICTURE &&
405 ctx->codec->write_picture_header) {
406 bit_len = 8 * sizeof(data);
407 err = ctx->codec->write_picture_header(avctx, base_pic, data, &bit_len);
408 if (err < 0) {
409 av_log(avctx, AV_LOG_ERROR, "Failed to write per-picture "
410 "header: %d.\n", err);
411 goto fail;
412 }
413 err = vaapi_encode_make_packed_header(avctx, pic,
414 ctx->codec->picture_header_type,
415 data, bit_len);
416 if (err < 0)
417 goto fail;
418 }
419
420 if (ctx->codec->write_extra_buffer) {
421 for (i = 0;; i++) {
422 size_t len = sizeof(data);
423 int type;
424 err = ctx->codec->write_extra_buffer(avctx, base_pic, i, &type,
425 data, &len);
426 if (err == AVERROR_EOF)
427 break;
428 if (err < 0) {
429 av_log(avctx, AV_LOG_ERROR, "Failed to write extra "
430 "buffer %d: %d.\n", i, err);
431 goto fail;
432 }
433
434 err = vaapi_encode_make_param_buffer(avctx, pic, type,
435 data, len);
436 if (err < 0)
437 goto fail;
438 }
439 }
440
441 if (ctx->va_packed_headers & VA_ENC_PACKED_HEADER_MISC &&
442 ctx->codec->write_extra_header) {
443 for (i = 0;; i++) {
444 int type;
445 bit_len = 8 * sizeof(data);
446 err = ctx->codec->write_extra_header(avctx, base_pic, i, &type,
447 data, &bit_len);
448 if (err == AVERROR_EOF)
449 break;
450 if (err < 0) {
451 av_log(avctx, AV_LOG_ERROR, "Failed to write extra "
452 "header %d: %d.\n", i, err);
453 goto fail;
454 }
455
456 err = vaapi_encode_make_packed_header(avctx, pic, type,
457 data, bit_len);
458 if (err < 0)
459 goto fail;
460 }
461 }
462
463 if (pic->nb_slices == 0)
464 pic->nb_slices = ctx->nb_slices;
465 if (pic->nb_slices > 0) {
466 pic->slices = av_calloc(pic->nb_slices, sizeof(*pic->slices));
467 if (!pic->slices) {
468 err = AVERROR(ENOMEM);
469 goto fail;
470 }
471
472 if (ctx->tile_rows && ctx->tile_cols)
473 vaapi_encode_make_tile_slice(avctx, pic);
474 else
475 vaapi_encode_make_row_slice(avctx, pic);
476 }
477
478 for (i = 0; i < pic->nb_slices; i++) {
479 slice = &pic->slices[i];
480
481 if (ctx->codec->slice_params_size > 0) {
482 slice->codec_slice_params = av_mallocz(ctx->codec->slice_params_size);
483 if (!slice->codec_slice_params) {
484 err = AVERROR(ENOMEM);
485 goto fail;
486 }
487 }
488
489 if (ctx->codec->init_slice_params) {
490 err = ctx->codec->init_slice_params(avctx, base_pic, slice);
491 if (err < 0) {
492 av_log(avctx, AV_LOG_ERROR, "Failed to initialise slice "
493 "parameters: %d.\n", err);
494 goto fail;
495 }
496 }
497
498 if (ctx->va_packed_headers & VA_ENC_PACKED_HEADER_SLICE &&
499 ctx->codec->write_slice_header) {
500 bit_len = 8 * sizeof(data);
501 err = ctx->codec->write_slice_header(avctx, pic, slice,
502 data, &bit_len);
503 if (err < 0) {
504 av_log(avctx, AV_LOG_ERROR, "Failed to write per-slice "
505 "header: %d.\n", err);
506 goto fail;
507 }
508 err = vaapi_encode_make_packed_header(avctx, pic,
509 ctx->codec->slice_header_type,
510 data, bit_len);
511 if (err < 0)
512 goto fail;
513 }
514
515 if (ctx->codec->init_slice_params) {
516 err = vaapi_encode_make_param_buffer(avctx, pic,
517 VAEncSliceParameterBufferType,
518 slice->codec_slice_params,
519 ctx->codec->slice_params_size);
520 if (err < 0)
521 goto fail;
522 }
523 }
524
525 #if VA_CHECK_VERSION(1, 0, 0)
526 sd = av_frame_get_side_data(base_pic->input_image,
527 AV_FRAME_DATA_REGIONS_OF_INTEREST);
528 if (sd && base_ctx->roi_allowed) {
529 const AVRegionOfInterest *roi;
530 uint32_t roi_size;
531 VAEncMiscParameterBufferROI param_roi;
532 int nb_roi, i, v;
533
534 roi = (const AVRegionOfInterest*)sd->data;
535 roi_size = roi->self_size;
536 av_assert0(roi_size && sd->size % roi_size == 0);
537 nb_roi = sd->size / roi_size;
538 if (nb_roi > ctx->roi_max_regions) {
539 if (!base_ctx->roi_warned) {
540 av_log(avctx, AV_LOG_WARNING, "More ROIs set than "
541 "supported by driver (%d > %d).\n",
542 nb_roi, ctx->roi_max_regions);
543 base_ctx->roi_warned = 1;
544 }
545 nb_roi = ctx->roi_max_regions;
546 }
547
548 pic->roi = av_calloc(nb_roi, sizeof(*pic->roi));
549 if (!pic->roi) {
550 err = AVERROR(ENOMEM);
551 goto fail;
552 }
553 // For overlapping regions, the first in the array takes priority.
554 for (i = 0; i < nb_roi; i++) {
555 roi = (const AVRegionOfInterest*)(sd->data + roi_size * i);
556
557 av_assert0(roi->qoffset.den != 0);
558 v = roi->qoffset.num * ctx->roi_quant_range / roi->qoffset.den;
559 av_log(avctx, AV_LOG_DEBUG, "ROI: (%d,%d)-(%d,%d) -> %+d.\n",
560 roi->top, roi->left, roi->bottom, roi->right, v);
561
562 pic->roi[i] = (VAEncROI) {
563 .roi_rectangle = {
564 .x = roi->left,
565 .y = roi->top,
566 .width = roi->right - roi->left,
567 .height = roi->bottom - roi->top,
568 },
569 .roi_value = av_clip_int8(v),
570 };
571 }
572
573 param_roi = (VAEncMiscParameterBufferROI) {
574 .num_roi = nb_roi,
575 .max_delta_qp = INT8_MAX,
576 .min_delta_qp = INT8_MIN,
577 .roi = pic->roi,
578 .roi_flags.bits.roi_value_is_qp_delta = 1,
579 };
580
581 err = vaapi_encode_make_misc_param_buffer(avctx, pic,
582 VAEncMiscParameterTypeROI,
583 &param_roi,
584 sizeof(param_roi));
585 if (err < 0)
586 goto fail;
587 }
588 #endif
589
590 vas = vaBeginPicture(ctx->hwctx->display, ctx->va_context,
591 pic->input_surface);
592 if (vas != VA_STATUS_SUCCESS) {
593 av_log(avctx, AV_LOG_ERROR, "Failed to begin picture encode issue: "
594 "%d (%s).\n", vas, vaErrorStr(vas));
595 err = AVERROR(EIO);
596 goto fail_with_picture;
597 }
598
599 vas = vaRenderPicture(ctx->hwctx->display, ctx->va_context,
600 pic->param_buffers, pic->nb_param_buffers);
601 if (vas != VA_STATUS_SUCCESS) {
602 av_log(avctx, AV_LOG_ERROR, "Failed to upload encode parameters: "
603 "%d (%s).\n", vas, vaErrorStr(vas));
604 err = AVERROR(EIO);
605 goto fail_with_picture;
606 }
607
608 vas = vaEndPicture(ctx->hwctx->display, ctx->va_context);
609 if (vas != VA_STATUS_SUCCESS) {
610 av_log(avctx, AV_LOG_ERROR, "Failed to end picture encode issue: "
611 "%d (%s).\n", vas, vaErrorStr(vas));
612 err = AVERROR(EIO);
613 // vaRenderPicture() has been called here, so we should not destroy
614 // the parameter buffers unless separate destruction is required.
615 if (CONFIG_VAAPI_1 || ctx->hwctx->driver_quirks &
616 AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS)
617 goto fail;
618 else
619 goto fail_at_end;
620 }
621
622 if (CONFIG_VAAPI_1 || ctx->hwctx->driver_quirks &
623 AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS) {
624 for (i = 0; i < pic->nb_param_buffers; i++) {
625 vas = vaDestroyBuffer(ctx->hwctx->display,
626 pic->param_buffers[i]);
627 if (vas != VA_STATUS_SUCCESS) {
628 av_log(avctx, AV_LOG_ERROR, "Failed to destroy "
629 "param buffer %#x: %d (%s).\n",
630 pic->param_buffers[i], vas, vaErrorStr(vas));
631 // And ignore.
632 }
633 }
634 }
635
636 return 0;
637
638 fail_with_picture:
639 vaEndPicture(ctx->hwctx->display, ctx->va_context);
640 fail:
641 for(i = 0; i < pic->nb_param_buffers; i++)
642 vaDestroyBuffer(ctx->hwctx->display, pic->param_buffers[i]);
643 if (pic->slices) {
644 for (i = 0; i < pic->nb_slices; i++)
645 av_freep(&pic->slices[i].codec_slice_params);
646 }
647 fail_at_end:
648 av_freep(&pic->codec_picture_params);
649 av_freep(&pic->param_buffers);
650 av_freep(&pic->slices);
651 av_freep(&pic->roi);
652 ff_refstruct_unref(&pic->output_buffer_ref);
653 pic->output_buffer = VA_INVALID_ID;
654 return err;
655 }
656
657 static int vaapi_encode_get_coded_buffer_size(AVCodecContext *avctx, VABufferID buf_id)
658 {
659 VAAPIEncodeContext *ctx = avctx->priv_data;
660 VACodedBufferSegment *buf_list, *buf;
661 int size = 0;
662 VAStatus vas;
663 int err;
664
665 vas = vaMapBuffer(ctx->hwctx->display, buf_id,
666 (void**)&buf_list);
667 if (vas != VA_STATUS_SUCCESS) {
668 av_log(avctx, AV_LOG_ERROR, "Failed to map output buffers: "
669 "%d (%s).\n", vas, vaErrorStr(vas));
670 err = AVERROR(EIO);
671 return err;
672 }
673
674 for (buf = buf_list; buf; buf = buf->next)
675 size += buf->size;
676
677 vas = vaUnmapBuffer(ctx->hwctx->display, buf_id);
678 if (vas != VA_STATUS_SUCCESS) {
679 av_log(avctx, AV_LOG_ERROR, "Failed to unmap output buffers: "
680 "%d (%s).\n", vas, vaErrorStr(vas));
681 err = AVERROR(EIO);
682 return err;
683 }
684
685 return size;
686 }
687
688 static int vaapi_encode_get_coded_buffer_data(AVCodecContext *avctx,
689 VABufferID buf_id, uint8_t **dst)
690 {
691 VAAPIEncodeContext *ctx = avctx->priv_data;
692 VACodedBufferSegment *buf_list, *buf;
693 VAStatus vas;
694 int err;
695
696 vas = vaMapBuffer(ctx->hwctx->display, buf_id,
697 (void**)&buf_list);
698 if (vas != VA_STATUS_SUCCESS) {
699 av_log(avctx, AV_LOG_ERROR, "Failed to map output buffers: "
700 "%d (%s).\n", vas, vaErrorStr(vas));
701 err = AVERROR(EIO);
702 return err;
703 }
704
705 for (buf = buf_list; buf; buf = buf->next) {
706 av_log(avctx, AV_LOG_DEBUG, "Output buffer: %u bytes "
707 "(status %08x).\n", buf->size, buf->status);
708
709 memcpy(*dst, buf->buf, buf->size);
710 *dst += buf->size;
711 }
712
713 vas = vaUnmapBuffer(ctx->hwctx->display, buf_id);
714 if (vas != VA_STATUS_SUCCESS) {
715 av_log(avctx, AV_LOG_ERROR, "Failed to unmap output buffers: "
716 "%d (%s).\n", vas, vaErrorStr(vas));
717 err = AVERROR(EIO);
718 return err;
719 }
720
721 return 0;
722 }
723
724 static int vaapi_encode_get_coded_data(AVCodecContext *avctx,
725 VAAPIEncodePicture *pic, AVPacket *pkt)
726 {
727 VAAPIEncodeContext *ctx = avctx->priv_data;
728 VABufferID output_buffer_prev;
729 int total_size = 0;
730 uint8_t *ptr;
731 int ret;
732
733 if (ctx->coded_buffer_ref) {
734 output_buffer_prev = *ctx->coded_buffer_ref;
735 ret = vaapi_encode_get_coded_buffer_size(avctx, output_buffer_prev);
736 if (ret < 0)
737 goto end;
738 total_size += ret;
739 }
740
741 ret = vaapi_encode_get_coded_buffer_size(avctx, pic->output_buffer);
742 if (ret < 0)
743 goto end;
744 total_size += ret;
745
746 ret = ff_get_encode_buffer(avctx, pkt, total_size, 0);
747 if (ret < 0)
748 goto end;
749 ptr = pkt->data;
750
751 if (ctx->coded_buffer_ref) {
752 ret = vaapi_encode_get_coded_buffer_data(avctx, output_buffer_prev, &ptr);
753 if (ret < 0)
754 goto end;
755 }
756
757 ret = vaapi_encode_get_coded_buffer_data(avctx, pic->output_buffer, &ptr);
758 if (ret < 0)
759 goto end;
760
761 end:
762 ff_refstruct_unref(&ctx->coded_buffer_ref);
763 ff_refstruct_unref(&pic->output_buffer_ref);
764 pic->output_buffer = VA_INVALID_ID;
765
766 return ret;
767 }
768
769 static int vaapi_encode_output(AVCodecContext *avctx,
770 FFHWBaseEncodePicture *base_pic, AVPacket *pkt)
771 {
772 FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
773 VAAPIEncodeContext *ctx = avctx->priv_data;
774 VAAPIEncodePicture *pic = base_pic->priv;
775 AVPacket *pkt_ptr = pkt;
776 int err;
777
778 err = vaapi_encode_wait(avctx, base_pic);
779 if (err < 0)
780 return err;
781
782 if (pic->non_independent_frame) {
783 av_assert0(!ctx->coded_buffer_ref);
784 ctx->coded_buffer_ref = ff_refstruct_ref(pic->output_buffer_ref);
785
786 if (pic->tail_size) {
787 if (base_ctx->tail_pkt->size) {
788 err = AVERROR_BUG;
789 goto end;
790 }
791
792 err = ff_get_encode_buffer(avctx, base_ctx->tail_pkt, pic->tail_size, 0);
793 if (err < 0)
794 goto end;
795
796 memcpy(base_ctx->tail_pkt->data, pic->tail_data, pic->tail_size);
797 pkt_ptr = base_ctx->tail_pkt;
798 }
799 } else {
800 err = vaapi_encode_get_coded_data(avctx, pic, pkt);
801 if (err < 0)
802 goto end;
803 }
804
805 av_log(avctx, AV_LOG_DEBUG, "Output read for pic %"PRId64"/%"PRId64".\n",
806 base_pic->display_order, base_pic->encode_order);
807
808 ff_hw_base_encode_set_output_property(base_ctx, avctx, (FFHWBaseEncodePicture*)base_pic, pkt_ptr,
809 ctx->codec->flags & FLAG_TIMESTAMP_NO_DELAY);
810
811 end:
812 ff_refstruct_unref(&pic->output_buffer_ref);
813 pic->output_buffer = VA_INVALID_ID;
814 return err;
815 }
816
817 static int vaapi_encode_discard(AVCodecContext *avctx, FFHWBaseEncodePicture *base_pic)
818 {
819 VAAPIEncodePicture *pic = base_pic->priv;
820
821 vaapi_encode_wait(avctx, base_pic);
822
823 if (pic->output_buffer_ref) {
824 av_log(avctx, AV_LOG_DEBUG, "Discard output for pic "
825 "%"PRId64"/%"PRId64".\n",
826 base_pic->display_order, base_pic->encode_order);
827
828 ff_refstruct_unref(&pic->output_buffer_ref);
829 pic->output_buffer = VA_INVALID_ID;
830 }
831
832 return 0;
833 }
834
835 static int vaapi_encode_init(AVCodecContext *avctx, FFHWBaseEncodePicture *pic)
836 {
837 VAAPIEncodeContext *ctx = avctx->priv_data;
838 VAAPIEncodePicture *priv = pic->priv;
839 AVFrame *frame = pic->input_image;
840
841 if (ctx->codec->picture_priv_data_size > 0) {
842 pic->codec_priv = av_mallocz(ctx->codec->picture_priv_data_size);
843 if (!pic->codec_priv)
844 return AVERROR(ENOMEM);
845 }
846
847 priv->input_surface = (VASurfaceID)(uintptr_t)frame->data[3];
848 priv->recon_surface = VA_INVALID_ID;
849 priv->output_buffer = VA_INVALID_ID;
850
851 return 0;
852 }
853
854 static int vaapi_encode_free(AVCodecContext *avctx, FFHWBaseEncodePicture *pic)
855 {
856 VAAPIEncodePicture *priv = pic->priv;
857 int i;
858
859 if (pic->encode_issued)
860 vaapi_encode_discard(avctx, pic);
861
862 if (priv->slices) {
863 for (i = 0; i < priv->nb_slices; i++)
864 av_freep(&priv->slices[i].codec_slice_params);
865 }
866
867 av_freep(&priv->param_buffers);
868 av_freep(&priv->slices);
869 // Output buffer should already be destroyed.
870 av_assert0(priv->output_buffer == VA_INVALID_ID);
871
872 av_freep(&priv->codec_picture_params);
873 av_freep(&priv->roi);
874
875 return 0;
876 }
877
878 static av_cold void vaapi_encode_add_global_param(AVCodecContext *avctx, int type,
879 void *buffer, size_t size)
880 {
881 VAAPIEncodeContext *ctx = avctx->priv_data;
882
883 av_assert0(ctx->nb_global_params < MAX_GLOBAL_PARAMS);
884
885 ctx->global_params_type[ctx->nb_global_params] = type;
886 ctx->global_params [ctx->nb_global_params] = buffer;
887 ctx->global_params_size[ctx->nb_global_params] = size;
888
889 ++ctx->nb_global_params;
890 }
891
892 typedef struct VAAPIEncodeRTFormat {
893 const char *name;
894 unsigned int value;
895 int depth;
896 int nb_components;
897 int log2_chroma_w;
898 int log2_chroma_h;
899 } VAAPIEncodeRTFormat;
900
901 static const VAAPIEncodeRTFormat vaapi_encode_rt_formats[] = {
902 { "YUV400", VA_RT_FORMAT_YUV400, 8, 1, },
903 { "YUV420", VA_RT_FORMAT_YUV420, 8, 3, 1, 1 },
904 { "YUV422", VA_RT_FORMAT_YUV422, 8, 3, 1, 0 },
905 #if VA_CHECK_VERSION(1, 2, 0)
906 { "YUV420_12", VA_RT_FORMAT_YUV420_12, 12, 3, 1, 1 },
907 { "YUV422_10", VA_RT_FORMAT_YUV422_10, 10, 3, 1, 0 },
908 { "YUV422_12", VA_RT_FORMAT_YUV422_12, 12, 3, 1, 0 },
909 { "YUV444_10", VA_RT_FORMAT_YUV444_10, 10, 3, 0, 0 },
910 { "YUV444_12", VA_RT_FORMAT_YUV444_12, 12, 3, 0, 0 },
911 #endif
912 { "YUV444", VA_RT_FORMAT_YUV444, 8, 3, 0, 0 },
913 { "XYUV", VA_RT_FORMAT_YUV444, 8, 3, 0, 0 },
914 { "YUV411", VA_RT_FORMAT_YUV411, 8, 3, 2, 0 },
915 #if VA_CHECK_VERSION(0, 38, 1)
916 { "YUV420_10", VA_RT_FORMAT_YUV420_10BPP, 10, 3, 1, 1 },
917 #endif
918 };
919
920 static const VAEntrypoint vaapi_encode_entrypoints_normal[] = {
921 VAEntrypointEncSlice,
922 VAEntrypointEncPicture,
923 #if VA_CHECK_VERSION(0, 39, 2)
924 VAEntrypointEncSliceLP,
925 #endif
926 0
927 };
928 #if VA_CHECK_VERSION(0, 39, 2)
929 static const VAEntrypoint vaapi_encode_entrypoints_low_power[] = {
930 VAEntrypointEncSliceLP,
931 0
932 };
933 #endif
934
935 static av_cold int vaapi_encode_profile_entrypoint(AVCodecContext *avctx)
936 {
937 FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
938 VAAPIEncodeContext *ctx = avctx->priv_data;
939 VAProfile *va_profiles = NULL;
940 VAEntrypoint *va_entrypoints = NULL;
941 VAStatus vas;
942 const VAEntrypoint *usable_entrypoints;
943 const VAAPIEncodeProfile *profile;
944 const AVPixFmtDescriptor *desc;
945 VAConfigAttrib rt_format_attr;
946 const VAAPIEncodeRTFormat *rt_format;
947 const char *profile_string, *entrypoint_string;
948 int i, j, n, depth, err;
949
950
951 if (ctx->low_power) {
952 #if VA_CHECK_VERSION(0, 39, 2)
953 usable_entrypoints = vaapi_encode_entrypoints_low_power;
954 #else
955 av_log(avctx, AV_LOG_ERROR, "Low-power encoding is not "
956 "supported with this VAAPI version.\n");
957 return AVERROR(EINVAL);
958 #endif
959 } else {
960 usable_entrypoints = vaapi_encode_entrypoints_normal;
961 }
962
963 desc = av_pix_fmt_desc_get(base_ctx->input_frames->sw_format);
964 if (!desc) {
965 av_log(avctx, AV_LOG_ERROR, "Invalid input pixfmt (%d).\n",
966 base_ctx->input_frames->sw_format);
967 return AVERROR(EINVAL);
968 }
969 depth = desc->comp[0].depth;
970 for (i = 1; i < desc->nb_components; i++) {
971 if (desc->comp[i].depth != depth) {
972 av_log(avctx, AV_LOG_ERROR, "Invalid input pixfmt (%s).\n",
973 desc->name);
974 return AVERROR(EINVAL);
975 }
976 }
977 av_log(avctx, AV_LOG_VERBOSE, "Input surface format is %s.\n",
978 desc->name);
979
980 n = vaMaxNumProfiles(ctx->hwctx->display);
981 va_profiles = av_malloc_array(n, sizeof(VAProfile));
982 if (!va_profiles) {
983 err = AVERROR(ENOMEM);
984 goto fail;
985 }
986 vas = vaQueryConfigProfiles(ctx->hwctx->display, va_profiles, &n);
987 if (vas != VA_STATUS_SUCCESS) {
988 av_log(avctx, AV_LOG_ERROR, "Failed to query profiles: %d (%s).\n",
989 vas, vaErrorStr(vas));
990 err = AVERROR_EXTERNAL;
991 goto fail;
992 }
993
994 av_assert0(ctx->codec->profiles);
995 for (i = 0; (ctx->codec->profiles[i].av_profile !=
996 AV_PROFILE_UNKNOWN); i++) {
997 profile = &ctx->codec->profiles[i];
998 if (depth != profile->depth ||
999 desc->nb_components != profile->nb_components)
1000 continue;
1001 if (desc->nb_components > 1 &&
1002 (desc->log2_chroma_w != profile->log2_chroma_w ||
1003 desc->log2_chroma_h != profile->log2_chroma_h))
1004 continue;
1005 if (avctx->profile != profile->av_profile &&
1006 avctx->profile != AV_PROFILE_UNKNOWN)
1007 continue;
1008
1009 #if VA_CHECK_VERSION(1, 0, 0)
1010 profile_string = vaProfileStr(profile->va_profile);
1011 #else
1012 profile_string = "(no profile names)";
1013 #endif
1014
1015 for (j = 0; j < n; j++) {
1016 if (va_profiles[j] == profile->va_profile)
1017 break;
1018 }
1019 if (j >= n) {
1020 av_log(avctx, AV_LOG_VERBOSE, "Compatible profile %s (%d) "
1021 "is not supported by driver.\n", profile_string,
1022 profile->va_profile);
1023 continue;
1024 }
1025
1026 ctx->profile = profile;
1027 break;
1028 }
1029 if (!ctx->profile) {
1030 av_log(avctx, AV_LOG_ERROR, "No usable encoding profile found.\n");
1031 err = AVERROR(ENOSYS);
1032 goto fail;
1033 }
1034
1035 avctx->profile = profile->av_profile;
1036 ctx->va_profile = profile->va_profile;
1037 av_log(avctx, AV_LOG_VERBOSE, "Using VAAPI profile %s (%d).\n",
1038 profile_string, ctx->va_profile);
1039
1040 n = vaMaxNumEntrypoints(ctx->hwctx->display);
1041 va_entrypoints = av_malloc_array(n, sizeof(VAEntrypoint));
1042 if (!va_entrypoints) {
1043 err = AVERROR(ENOMEM);
1044 goto fail;
1045 }
1046 vas = vaQueryConfigEntrypoints(ctx->hwctx->display, ctx->va_profile,
1047 va_entrypoints, &n);
1048 if (vas != VA_STATUS_SUCCESS) {
1049 av_log(avctx, AV_LOG_ERROR, "Failed to query entrypoints for "
1050 "profile %s (%d): %d (%s).\n", profile_string,
1051 ctx->va_profile, vas, vaErrorStr(vas));
1052 err = AVERROR_EXTERNAL;
1053 goto fail;
1054 }
1055
1056 for (i = 0; i < n; i++) {
1057 for (j = 0; usable_entrypoints[j]; j++) {
1058 if (va_entrypoints[i] == usable_entrypoints[j])
1059 break;
1060 }
1061 if (usable_entrypoints[j])
1062 break;
1063 }
1064 if (i >= n) {
1065 av_log(avctx, AV_LOG_ERROR, "No usable encoding entrypoint found "
1066 "for profile %s (%d).\n", profile_string, ctx->va_profile);
1067 err = AVERROR(ENOSYS);
1068 goto fail;
1069 }
1070
1071 ctx->va_entrypoint = va_entrypoints[i];
1072 #if VA_CHECK_VERSION(1, 0, 0)
1073 entrypoint_string = vaEntrypointStr(ctx->va_entrypoint);
1074 #else
1075 entrypoint_string = "(no entrypoint names)";
1076 #endif
1077 av_log(avctx, AV_LOG_VERBOSE, "Using VAAPI entrypoint %s (%d).\n",
1078 entrypoint_string, ctx->va_entrypoint);
1079
1080 for (i = 0; i < FF_ARRAY_ELEMS(vaapi_encode_rt_formats); i++) {
1081 rt_format = &vaapi_encode_rt_formats[i];
1082 if (rt_format->depth == depth &&
1083 rt_format->nb_components == profile->nb_components &&
1084 rt_format->log2_chroma_w == profile->log2_chroma_w &&
1085 rt_format->log2_chroma_h == profile->log2_chroma_h)
1086 break;
1087 }
1088 if (i >= FF_ARRAY_ELEMS(vaapi_encode_rt_formats)) {
1089 av_log(avctx, AV_LOG_ERROR, "No usable render target format "
1090 "found for profile %s (%d) entrypoint %s (%d).\n",
1091 profile_string, ctx->va_profile,
1092 entrypoint_string, ctx->va_entrypoint);
1093 err = AVERROR(ENOSYS);
1094 goto fail;
1095 }
1096
1097 rt_format_attr = (VAConfigAttrib) { VAConfigAttribRTFormat };
1098 vas = vaGetConfigAttributes(ctx->hwctx->display,
1099 ctx->va_profile, ctx->va_entrypoint,
1100 &rt_format_attr, 1);
1101 if (vas != VA_STATUS_SUCCESS) {
1102 av_log(avctx, AV_LOG_ERROR, "Failed to query RT format "
1103 "config attribute: %d (%s).\n", vas, vaErrorStr(vas));
1104 err = AVERROR_EXTERNAL;
1105 goto fail;
1106 }
1107
1108 if (rt_format_attr.value == VA_ATTRIB_NOT_SUPPORTED) {
1109 av_log(avctx, AV_LOG_VERBOSE, "RT format config attribute not "
1110 "supported by driver: assuming surface RT format %s "
1111 "is valid.\n", rt_format->name);
1112 } else if (!(rt_format_attr.value & rt_format->value)) {
1113 av_log(avctx, AV_LOG_ERROR, "Surface RT format %s not supported "
1114 "by driver for encoding profile %s (%d) entrypoint %s (%d).\n",
1115 rt_format->name, profile_string, ctx->va_profile,
1116 entrypoint_string, ctx->va_entrypoint);
1117 err = AVERROR(ENOSYS);
1118 goto fail;
1119 } else {
1120 av_log(avctx, AV_LOG_VERBOSE, "Using VAAPI render target "
1121 "format %s (%#x).\n", rt_format->name, rt_format->value);
1122 ctx->config_attributes[ctx->nb_config_attributes++] =
1123 (VAConfigAttrib) {
1124 .type = VAConfigAttribRTFormat,
1125 .value = rt_format->value,
1126 };
1127 }
1128
1129 err = 0;
1130 fail:
1131 av_freep(&va_profiles);
1132 av_freep(&va_entrypoints);
1133 return err;
1134 }
1135
1136 static const VAAPIEncodeRCMode vaapi_encode_rc_modes[] = {
1137 // Bitrate Quality
1138 // | Maxrate | HRD/VBV
1139 { 0 }, // | | | |
1140 { RC_MODE_CQP, "CQP", 1, VA_RC_CQP, 0, 0, 1, 0 },
1141 { RC_MODE_CBR, "CBR", 1, VA_RC_CBR, 1, 0, 0, 1 },
1142 { RC_MODE_VBR, "VBR", 1, VA_RC_VBR, 1, 1, 0, 1 },
1143 #if VA_CHECK_VERSION(1, 1, 0)
1144 { RC_MODE_ICQ, "ICQ", 1, VA_RC_ICQ, 0, 0, 1, 0 },
1145 #else
1146 { RC_MODE_ICQ, "ICQ", 0 },
1147 #endif
1148 #if VA_CHECK_VERSION(1, 3, 0)
1149 { RC_MODE_QVBR, "QVBR", 1, VA_RC_QVBR, 1, 1, 1, 1 },
1150 { RC_MODE_AVBR, "AVBR", 0, VA_RC_AVBR, 1, 0, 0, 0 },
1151 #else
1152 { RC_MODE_QVBR, "QVBR", 0 },
1153 { RC_MODE_AVBR, "AVBR", 0 },
1154 #endif
1155 };
1156
1157 static av_cold int vaapi_encode_init_rate_control(AVCodecContext *avctx)
1158 {
1159 VAAPIEncodeContext *ctx = avctx->priv_data;
1160 uint32_t supported_va_rc_modes;
1161 const VAAPIEncodeRCMode *rc_mode;
1162 int64_t rc_bits_per_second;
1163 int rc_target_percentage;
1164 int rc_window_size;
1165 int rc_quality;
1166 int64_t hrd_buffer_size;
1167 int64_t hrd_initial_buffer_fullness;
1168 int fr_num, fr_den;
1169 VAConfigAttrib rc_attr = { VAConfigAttribRateControl };
1170 VAStatus vas;
1171 char supported_rc_modes_string[64];
1172
1173 vas = vaGetConfigAttributes(ctx->hwctx->display,
1174 ctx->va_profile, ctx->va_entrypoint,
1175 &rc_attr, 1);
1176 if (vas != VA_STATUS_SUCCESS) {
1177 av_log(avctx, AV_LOG_ERROR, "Failed to query rate control "
1178 "config attribute: %d (%s).\n", vas, vaErrorStr(vas));
1179 return AVERROR_EXTERNAL;
1180 }
1181 if (rc_attr.value == VA_ATTRIB_NOT_SUPPORTED) {
1182 av_log(avctx, AV_LOG_VERBOSE, "Driver does not report any "
1183 "supported rate control modes: assuming CQP only.\n");
1184 supported_va_rc_modes = VA_RC_CQP;
1185 strcpy(supported_rc_modes_string, "unknown");
1186 } else {
1187 char *str = supported_rc_modes_string;
1188 size_t len = sizeof(supported_rc_modes_string);
1189 int i, first = 1, res;
1190
1191 supported_va_rc_modes = rc_attr.value;
1192 if (ctx->blbrc) {
1193 #if VA_CHECK_VERSION(0, 39, 2)
1194 if (!(supported_va_rc_modes & VA_RC_MB)) {
1195 ctx->blbrc = 0;
1196 av_log(avctx, AV_LOG_WARNING, "Driver does not support BLBRC.\n");
1197 }
1198 #else
1199 ctx->blbrc = 0;
1200 av_log(avctx, AV_LOG_WARNING, "Please consider to update to VAAPI 0.39.2 "
1201 "or above, which can support BLBRC.\n");
1202 #endif
1203 }
1204
1205 for (i = 0; i < FF_ARRAY_ELEMS(vaapi_encode_rc_modes); i++) {
1206 rc_mode = &vaapi_encode_rc_modes[i];
1207 if (supported_va_rc_modes & rc_mode->va_mode) {
1208 res = snprintf(str, len, "%s%s",
1209 first ? "" : ", ", rc_mode->name);
1210 first = 0;
1211 if (res < 0) {
1212 *str = 0;
1213 break;
1214 }
1215 len -= res;
1216 str += res;
1217 if (len == 0)
1218 break;
1219 }
1220 }
1221
1222 av_log(avctx, AV_LOG_DEBUG, "Driver supports RC modes %s.\n",
1223 supported_rc_modes_string);
1224 }
1225
1226 // Rate control mode selection:
1227 // * If the user has set a mode explicitly with the rc_mode option,
1228 // use it and fail if it is not available.
1229 // * If an explicit QP option has been set, use CQP.
1230 // * If the codec is CQ-only, use CQP.
1231 // * If the QSCALE avcodec option is set, use CQP.
1232 // * If bitrate and quality are both set, try QVBR.
1233 // * If quality is set, try ICQ, then CQP.
1234 // * If bitrate and maxrate are set and have the same value, try CBR.
1235 // * If a bitrate is set, try AVBR, then VBR, then CBR.
1236 // * If no bitrate is set, try ICQ, then CQP.
1237
1238 #define TRY_RC_MODE(mode, fail) do { \
1239 rc_mode = &vaapi_encode_rc_modes[mode]; \
1240 if (!(rc_mode->va_mode & supported_va_rc_modes)) { \
1241 if (fail) { \
1242 av_log(avctx, AV_LOG_ERROR, "Driver does not support %s " \
1243 "RC mode (supported modes: %s).\n", rc_mode->name, \
1244 supported_rc_modes_string); \
1245 return AVERROR(EINVAL); \
1246 } \
1247 av_log(avctx, AV_LOG_DEBUG, "Driver does not support %s " \
1248 "RC mode.\n", rc_mode->name); \
1249 rc_mode = NULL; \
1250 } else { \
1251 goto rc_mode_found; \
1252 } \
1253 } while (0)
1254
1255 if (ctx->explicit_rc_mode)
1256 TRY_RC_MODE(ctx->explicit_rc_mode, 1);
1257
1258 if (ctx->explicit_qp)
1259 TRY_RC_MODE(RC_MODE_CQP, 1);
1260
1261 if (ctx->codec->flags & FF_HW_FLAG_CONSTANT_QUALITY_ONLY)
1262 TRY_RC_MODE(RC_MODE_CQP, 1);
1263
1264 if (avctx->flags & AV_CODEC_FLAG_QSCALE)
1265 TRY_RC_MODE(RC_MODE_CQP, 1);
1266
1267 if (avctx->bit_rate > 0 && avctx->global_quality > 0)
1268 TRY_RC_MODE(RC_MODE_QVBR, 0);
1269
1270 if (avctx->global_quality > 0) {
1271 TRY_RC_MODE(RC_MODE_ICQ, 0);
1272 TRY_RC_MODE(RC_MODE_CQP, 0);
1273 }
1274
1275 if (avctx->bit_rate > 0 && avctx->rc_max_rate == avctx->bit_rate)
1276 TRY_RC_MODE(RC_MODE_CBR, 0);
1277
1278 if (avctx->bit_rate > 0) {
1279 TRY_RC_MODE(RC_MODE_AVBR, 0);
1280 TRY_RC_MODE(RC_MODE_VBR, 0);
1281 TRY_RC_MODE(RC_MODE_CBR, 0);
1282 } else {
1283 TRY_RC_MODE(RC_MODE_ICQ, 0);
1284 TRY_RC_MODE(RC_MODE_CQP, 0);
1285 }
1286
1287 av_log(avctx, AV_LOG_ERROR, "Driver does not support any "
1288 "RC mode compatible with selected options "
1289 "(supported modes: %s).\n", supported_rc_modes_string);
1290 return AVERROR(EINVAL);
1291
1292 rc_mode_found:
1293 if (rc_mode->bitrate) {
1294 if (avctx->bit_rate <= 0) {
1295 av_log(avctx, AV_LOG_ERROR, "Bitrate must be set for %s "
1296 "RC mode.\n", rc_mode->name);
1297 return AVERROR(EINVAL);
1298 }
1299
1300 if (rc_mode->mode == RC_MODE_AVBR) {
1301 // For maximum confusion AVBR is hacked into the existing API
1302 // by overloading some of the fields with completely different
1303 // meanings.
1304
1305 // Target percentage does not apply in AVBR mode.
1306 rc_bits_per_second = avctx->bit_rate;
1307
1308 // Accuracy tolerance range for meeting the specified target
1309 // bitrate. It's very unclear how this is actually intended
1310 // to work - since we do want to get the specified bitrate,
1311 // set the accuracy to 100% for now.
1312 rc_target_percentage = 100;
1313
1314 // Convergence period in frames. The GOP size reflects the
1315 // user's intended block size for cutting, so reusing that
1316 // as the convergence period seems a reasonable default.
1317 rc_window_size = avctx->gop_size > 0 ? avctx->gop_size : 60;
1318
1319 } else if (rc_mode->maxrate) {
1320 if (avctx->rc_max_rate > 0) {
1321 if (avctx->rc_max_rate < avctx->bit_rate) {
1322 av_log(avctx, AV_LOG_ERROR, "Invalid bitrate settings: "
1323 "bitrate (%"PRId64") must not be greater than "
1324 "maxrate (%"PRId64").\n", avctx->bit_rate,
1325 avctx->rc_max_rate);
1326 return AVERROR(EINVAL);
1327 }
1328 rc_bits_per_second = avctx->rc_max_rate;
1329 rc_target_percentage = (avctx->bit_rate * 100) /
1330 avctx->rc_max_rate;
1331 } else {
1332 // We only have a target bitrate, but this mode requires
1333 // that a maximum rate be supplied as well. Since the
1334 // user does not want this to be a constraint, arbitrarily
1335 // pick a maximum rate of double the target rate.
1336 rc_bits_per_second = 2 * avctx->bit_rate;
1337 rc_target_percentage = 50;
1338 }
1339 } else {
1340 if (avctx->rc_max_rate > avctx->bit_rate) {
1341 av_log(avctx, AV_LOG_WARNING, "Max bitrate is ignored "
1342 "in %s RC mode.\n", rc_mode->name);
1343 }
1344 rc_bits_per_second = avctx->bit_rate;
1345 rc_target_percentage = 100;
1346 }
1347 } else {
1348 rc_bits_per_second = 0;
1349 rc_target_percentage = 100;
1350 }
1351
1352 if (rc_mode->quality) {
1353 if (ctx->explicit_qp) {
1354 rc_quality = ctx->explicit_qp;
1355 } else if (avctx->global_quality > 0) {
1356 if (avctx->flags & AV_CODEC_FLAG_QSCALE)
1357 rc_quality = avctx->global_quality / FF_QP2LAMBDA;
1358 else
1359 rc_quality = avctx->global_quality;
1360 } else {
1361 rc_quality = ctx->codec->default_quality;
1362 av_log(avctx, AV_LOG_WARNING, "No quality level set; "
1363 "using default (%d).\n", rc_quality);
1364 }
1365 } else {
1366 rc_quality = 0;
1367 }
1368
1369 if (rc_mode->hrd) {
1370 if (avctx->rc_buffer_size)
1371 hrd_buffer_size = avctx->rc_buffer_size;
1372 else if (avctx->rc_max_rate > 0)
1373 hrd_buffer_size = avctx->rc_max_rate;
1374 else
1375 hrd_buffer_size = avctx->bit_rate;
1376 if (avctx->rc_initial_buffer_occupancy) {
1377 if (avctx->rc_initial_buffer_occupancy > hrd_buffer_size) {
1378 av_log(avctx, AV_LOG_ERROR, "Invalid RC buffer settings: "
1379 "must have initial buffer size (%d) <= "
1380 "buffer size (%"PRId64").\n",
1381 avctx->rc_initial_buffer_occupancy, hrd_buffer_size);
1382 return AVERROR(EINVAL);
1383 }
1384 hrd_initial_buffer_fullness = avctx->rc_initial_buffer_occupancy;
1385 } else {
1386 hrd_initial_buffer_fullness = hrd_buffer_size * 3 / 4;
1387 }
1388
1389 rc_window_size = (hrd_buffer_size * 1000) / rc_bits_per_second;
1390 } else {
1391 if (avctx->rc_buffer_size || avctx->rc_initial_buffer_occupancy) {
1392 av_log(avctx, AV_LOG_WARNING, "Buffering settings are ignored "
1393 "in %s RC mode.\n", rc_mode->name);
1394 }
1395
1396 hrd_buffer_size = 0;
1397 hrd_initial_buffer_fullness = 0;
1398
1399 if (rc_mode->mode != RC_MODE_AVBR) {
1400 // Already set (with completely different meaning) for AVBR.
1401 rc_window_size = 1000;
1402 }
1403 }
1404
1405 if (rc_bits_per_second > UINT32_MAX ||
1406 hrd_buffer_size > UINT32_MAX ||
1407 hrd_initial_buffer_fullness > UINT32_MAX) {
1408 av_log(avctx, AV_LOG_ERROR, "RC parameters of 2^32 or "
1409 "greater are not supported by VAAPI.\n");
1410 return AVERROR(EINVAL);
1411 }
1412
1413 ctx->rc_mode = rc_mode;
1414 ctx->rc_quality = rc_quality;
1415 ctx->va_rc_mode = rc_mode->va_mode;
1416 ctx->va_bit_rate = rc_bits_per_second;
1417
1418 av_log(avctx, AV_LOG_VERBOSE, "RC mode: %s.\n", rc_mode->name);
1419
1420 if (ctx->blbrc && ctx->va_rc_mode == VA_RC_CQP)
1421 ctx->blbrc = 0;
1422 av_log(avctx, AV_LOG_VERBOSE, "Block Level bitrate control: %s.\n", ctx->blbrc ? "ON" : "OFF");
1423
1424 if (rc_attr.value == VA_ATTRIB_NOT_SUPPORTED) {
1425 // This driver does not want the RC mode attribute to be set.
1426 } else {
1427 ctx->config_attributes[ctx->nb_config_attributes++] =
1428 (VAConfigAttrib) {
1429 .type = VAConfigAttribRateControl,
1430 #if VA_CHECK_VERSION(0, 39, 2)
1431 .value = ctx->blbrc ? ctx->va_rc_mode | VA_RC_MB : ctx->va_rc_mode,
1432 #else
1433 .value = ctx->va_rc_mode,
1434 #endif
1435 };
1436 }
1437
1438 if (rc_mode->quality)
1439 av_log(avctx, AV_LOG_VERBOSE, "RC quality: %d.\n", rc_quality);
1440
1441 if (rc_mode->va_mode != VA_RC_CQP) {
1442 if (rc_mode->mode == RC_MODE_AVBR) {
1443 av_log(avctx, AV_LOG_VERBOSE, "RC target: %"PRId64" bps "
1444 "converging in %d frames with %d%% accuracy.\n",
1445 rc_bits_per_second, rc_window_size,
1446 rc_target_percentage);
1447 } else if (rc_mode->bitrate) {
1448 av_log(avctx, AV_LOG_VERBOSE, "RC target: %d%% of "
1449 "%"PRId64" bps over %d ms.\n", rc_target_percentage,
1450 rc_bits_per_second, rc_window_size);
1451 }
1452
1453 ctx->rc_params = (VAEncMiscParameterRateControl) {
1454 .bits_per_second = rc_bits_per_second,
1455 .target_percentage = rc_target_percentage,
1456 .window_size = rc_window_size,
1457 .initial_qp = 0,
1458 .min_qp = (avctx->qmin > 0 ? avctx->qmin : 0),
1459 .basic_unit_size = 0,
1460 #if VA_CHECK_VERSION(1, 1, 0)
1461 .ICQ_quality_factor = av_clip(rc_quality, 1, 51),
1462 .max_qp = (avctx->qmax > 0 ? avctx->qmax : 0),
1463 #endif
1464 #if VA_CHECK_VERSION(1, 3, 0)
1465 .quality_factor = rc_quality,
1466 #endif
1467 #if VA_CHECK_VERSION(0, 39, 2)
1468 .rc_flags.bits.mb_rate_control = ctx->blbrc ? 1 : 2,
1469 #endif
1470 };
1471 vaapi_encode_add_global_param(avctx,
1472 VAEncMiscParameterTypeRateControl,
1473 &ctx->rc_params,
1474 sizeof(ctx->rc_params));
1475 }
1476
1477 if (rc_mode->hrd) {
1478 av_log(avctx, AV_LOG_VERBOSE, "RC buffer: %"PRId64" bits, "
1479 "initial fullness %"PRId64" bits.\n",
1480 hrd_buffer_size, hrd_initial_buffer_fullness);
1481
1482 ctx->hrd_params = (VAEncMiscParameterHRD) {
1483 .initial_buffer_fullness = hrd_initial_buffer_fullness,
1484 .buffer_size = hrd_buffer_size,
1485 };
1486 vaapi_encode_add_global_param(avctx,
1487 VAEncMiscParameterTypeHRD,
1488 &ctx->hrd_params,
1489 sizeof(ctx->hrd_params));
1490 }
1491
1492 if (avctx->framerate.num > 0 && avctx->framerate.den > 0)
1493 av_reduce(&fr_num, &fr_den,
1494 avctx->framerate.num, avctx->framerate.den, 65535);
1495 else
1496 av_reduce(&fr_num, &fr_den,
1497 avctx->time_base.den, avctx->time_base.num, 65535);
1498
1499 av_log(avctx, AV_LOG_VERBOSE, "RC framerate: %d/%d (%.2f fps).\n",
1500 fr_num, fr_den, (double)fr_num / fr_den);
1501
1502 ctx->fr_params = (VAEncMiscParameterFrameRate) {
1503 .framerate = (unsigned int)fr_den << 16 | fr_num,
1504 };
1505 #if VA_CHECK_VERSION(0, 40, 0)
1506 vaapi_encode_add_global_param(avctx,
1507 VAEncMiscParameterTypeFrameRate,
1508 &ctx->fr_params,
1509 sizeof(ctx->fr_params));
1510 #endif
1511
1512 return 0;
1513 }
1514
1515 static av_cold int vaapi_encode_init_max_frame_size(AVCodecContext *avctx)
1516 {
1517 #if VA_CHECK_VERSION(1, 5, 0)
1518 VAAPIEncodeContext *ctx = avctx->priv_data;
1519 VAConfigAttrib attr = { VAConfigAttribMaxFrameSize };
1520 VAStatus vas;
1521
1522 if (ctx->va_rc_mode == VA_RC_CQP) {
1523 ctx->max_frame_size = 0;
1524 av_log(avctx, AV_LOG_ERROR, "Max frame size is invalid in CQP rate "
1525 "control mode.\n");
1526 return AVERROR(EINVAL);
1527 }
1528
1529 vas = vaGetConfigAttributes(ctx->hwctx->display,
1530 ctx->va_profile,
1531 ctx->va_entrypoint,
1532 &attr, 1);
1533 if (vas != VA_STATUS_SUCCESS) {
1534 ctx->max_frame_size = 0;
1535 av_log(avctx, AV_LOG_ERROR, "Failed to query max frame size "
1536 "config attribute: %d (%s).\n", vas, vaErrorStr(vas));
1537 return AVERROR_EXTERNAL;
1538 }
1539
1540 if (attr.value == VA_ATTRIB_NOT_SUPPORTED) {
1541 ctx->max_frame_size = 0;
1542 av_log(avctx, AV_LOG_ERROR, "Max frame size attribute "
1543 "is not supported.\n");
1544 return AVERROR(EINVAL);
1545 } else {
1546 VAConfigAttribValMaxFrameSize attr_mfs;
1547 attr_mfs.value = attr.value;
1548 // Prefer to use VAEncMiscParameterTypeMaxFrameSize for max frame size.
1549 if (!attr_mfs.bits.max_frame_size && attr_mfs.bits.multiple_pass) {
1550 ctx->max_frame_size = 0;
1551 av_log(avctx, AV_LOG_ERROR, "Driver only supports multiple pass "
1552 "max frame size which has not been implemented in FFmpeg.\n");
1553 return AVERROR(EINVAL);
1554 }
1555
1556 ctx->mfs_params = (VAEncMiscParameterBufferMaxFrameSize){
1557 .max_frame_size = ctx->max_frame_size * 8,
1558 };
1559
1560 av_log(avctx, AV_LOG_VERBOSE, "Set max frame size: %d bytes.\n",
1561 ctx->max_frame_size);
1562 }
1563 #else
1564 av_log(avctx, AV_LOG_ERROR, "The max frame size option is not supported with "
1565 "this VAAPI version.\n");
1566 return AVERROR(EINVAL);
1567 #endif
1568
1569 return 0;
1570 }
1571
1572 static av_cold int vaapi_encode_init_gop_structure(AVCodecContext *avctx)
1573 {
1574 FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
1575 VAAPIEncodeContext *ctx = avctx->priv_data;
1576 VAStatus vas;
1577 VAConfigAttrib attr = { VAConfigAttribEncMaxRefFrames };
1578 uint32_t ref_l0, ref_l1;
1579 int prediction_pre_only, err;
1580
1581 vas = vaGetConfigAttributes(ctx->hwctx->display,
1582 ctx->va_profile,
1583 ctx->va_entrypoint,
1584 &attr, 1);
1585 if (vas != VA_STATUS_SUCCESS) {
1586 av_log(avctx, AV_LOG_ERROR, "Failed to query reference frames "
1587 "attribute: %d (%s).\n", vas, vaErrorStr(vas));
1588 return AVERROR_EXTERNAL;
1589 }
1590
1591 if (attr.value == VA_ATTRIB_NOT_SUPPORTED) {
1592 ref_l0 = ref_l1 = 0;
1593 } else {
1594 ref_l0 = attr.value & 0xffff;
1595 ref_l1 = attr.value >> 16 & 0xffff;
1596 }
1597
1598 base_ctx->p_to_gpb = 0;
1599 prediction_pre_only = 0;
1600
1601 #if VA_CHECK_VERSION(1, 9, 0)
1602 if (!(ctx->codec->flags & FF_HW_FLAG_INTRA_ONLY ||
1603 avctx->gop_size <= 1)) {
1604 attr = (VAConfigAttrib) { VAConfigAttribPredictionDirection };
1605 vas = vaGetConfigAttributes(ctx->hwctx->display,
1606 ctx->va_profile,
1607 ctx->va_entrypoint,
1608 &attr, 1);
1609 if (vas != VA_STATUS_SUCCESS) {
1610 av_log(avctx, AV_LOG_WARNING, "Failed to query prediction direction "
1611 "attribute: %d (%s).\n", vas, vaErrorStr(vas));
1612 return AVERROR_EXTERNAL;
1613 } else if (attr.value == VA_ATTRIB_NOT_SUPPORTED) {
1614 av_log(avctx, AV_LOG_VERBOSE, "Driver does not report any additional "
1615 "prediction constraints.\n");
1616 } else {
1617 if (((ref_l0 > 0 || ref_l1 > 0) && !(attr.value & VA_PREDICTION_DIRECTION_PREVIOUS)) ||
1618 ((ref_l1 == 0) && (attr.value & (VA_PREDICTION_DIRECTION_FUTURE | VA_PREDICTION_DIRECTION_BI_NOT_EMPTY)))) {
1619 av_log(avctx, AV_LOG_ERROR, "Driver report incorrect prediction "
1620 "direction attribute.\n");
1621 return AVERROR_EXTERNAL;
1622 }
1623
1624 if (!(attr.value & VA_PREDICTION_DIRECTION_FUTURE)) {
1625 if (ref_l0 > 0 && ref_l1 > 0) {
1626 prediction_pre_only = 1;
1627 av_log(avctx, AV_LOG_VERBOSE, "Driver only support same reference "
1628 "lists for B-frames.\n");
1629 }
1630 }
1631
1632 if (attr.value & VA_PREDICTION_DIRECTION_BI_NOT_EMPTY) {
1633 if (ref_l0 > 0 && ref_l1 > 0) {
1634 base_ctx->p_to_gpb = 1;
1635 av_log(avctx, AV_LOG_VERBOSE, "Driver does not support P-frames, "
1636 "replacing them with B-frames.\n");
1637 }
1638 }
1639 }
1640 }
1641 #endif
1642
1643 err = ff_hw_base_init_gop_structure(base_ctx, avctx, ref_l0, ref_l1,
1644 ctx->codec->flags, prediction_pre_only);
1645 if (err < 0)
1646 return err;
1647
1648 return 0;
1649 }
1650
1651 static av_cold int vaapi_encode_init_row_slice_structure(AVCodecContext *avctx,
1652 uint32_t slice_structure)
1653 {
1654 VAAPIEncodeContext *ctx = avctx->priv_data;
1655 int req_slices;
1656
1657 // For fixed-size slices currently we only support whole rows, making
1658 // rectangular slices. This could be extended to arbitrary runs of
1659 // blocks, but since slices tend to be a conformance requirement and
1660 // most cases (such as broadcast or bluray) want rectangular slices
1661 // only it would need to be gated behind another option.
1662 if (avctx->slices > ctx->slice_block_rows) {
1663 av_log(avctx, AV_LOG_WARNING, "Not enough rows to use "
1664 "configured number of slices (%d < %d); using "
1665 "maximum.\n", ctx->slice_block_rows, avctx->slices);
1666 req_slices = ctx->slice_block_rows;
1667 } else {
1668 req_slices = avctx->slices;
1669 }
1670 if (slice_structure & VA_ENC_SLICE_STRUCTURE_ARBITRARY_ROWS ||
1671 slice_structure & VA_ENC_SLICE_STRUCTURE_ARBITRARY_MACROBLOCKS) {
1672 ctx->nb_slices = req_slices;
1673 ctx->slice_size = ctx->slice_block_rows / ctx->nb_slices;
1674 } else if (slice_structure & VA_ENC_SLICE_STRUCTURE_POWER_OF_TWO_ROWS) {
1675 int k;
1676 for (k = 1;; k *= 2) {
1677 if (2 * k * (req_slices - 1) + 1 >= ctx->slice_block_rows)
1678 break;
1679 }
1680 ctx->nb_slices = (ctx->slice_block_rows + k - 1) / k;
1681 ctx->slice_size = k;
1682 #if VA_CHECK_VERSION(1, 0, 0)
1683 } else if (slice_structure & VA_ENC_SLICE_STRUCTURE_EQUAL_ROWS) {
1684 ctx->nb_slices = ctx->slice_block_rows;
1685 ctx->slice_size = 1;
1686 #endif
1687 } else {
1688 av_log(avctx, AV_LOG_ERROR, "Driver does not support any usable "
1689 "slice structure modes (%#x).\n", slice_structure);
1690 return AVERROR(EINVAL);
1691 }
1692
1693 return 0;
1694 }
1695
1696 static av_cold int vaapi_encode_init_tile_slice_structure(AVCodecContext *avctx,
1697 uint32_t slice_structure)
1698 {
1699 VAAPIEncodeContext *ctx = avctx->priv_data;
1700 int i, req_tiles;
1701
1702 if (!(slice_structure & VA_ENC_SLICE_STRUCTURE_ARBITRARY_MACROBLOCKS ||
1703 (slice_structure & VA_ENC_SLICE_STRUCTURE_ARBITRARY_ROWS &&
1704 ctx->tile_cols == 1))) {
1705 av_log(avctx, AV_LOG_ERROR, "Supported slice structure (%#x) doesn't work for "
1706 "current tile requirement.\n", slice_structure);
1707 return AVERROR(EINVAL);
1708 }
1709
1710 if (ctx->tile_rows > ctx->slice_block_rows ||
1711 ctx->tile_cols > ctx->slice_block_cols) {
1712 av_log(avctx, AV_LOG_WARNING, "Not enough block rows/cols (%d x %d) "
1713 "for configured number of tile (%d x %d); ",
1714 ctx->slice_block_rows, ctx->slice_block_cols,
1715 ctx->tile_rows, ctx->tile_cols);
1716 ctx->tile_rows = ctx->tile_rows > ctx->slice_block_rows ?
1717 ctx->slice_block_rows : ctx->tile_rows;
1718 ctx->tile_cols = ctx->tile_cols > ctx->slice_block_cols ?
1719 ctx->slice_block_cols : ctx->tile_cols;
1720 av_log(avctx, AV_LOG_WARNING, "using allowed maximum (%d x %d).\n",
1721 ctx->tile_rows, ctx->tile_cols);
1722 }
1723
1724 req_tiles = ctx->tile_rows * ctx->tile_cols;
1725
1726 // Tile slice is not allowed to cross the boundary of a tile due to
1727 // the constraints of media-driver. Currently we support one slice
1728 // per tile. This could be extended to multiple slices per tile.
1729 if (avctx->slices != req_tiles)
1730 av_log(avctx, AV_LOG_WARNING, "The number of requested slices "
1731 "mismatches with configured number of tile (%d != %d); "
1732 "using requested tile number for slice.\n",
1733 avctx->slices, req_tiles);
1734
1735 ctx->nb_slices = req_tiles;
1736
1737 // Default in uniform spacing
1738 // 6-3, 6-5
1739 for (i = 0; i < ctx->tile_cols; i++) {
1740 ctx->col_width[i] = ( i + 1 ) * ctx->slice_block_cols / ctx->tile_cols -
1741 i * ctx->slice_block_cols / ctx->tile_cols;
1742 ctx->col_bd[i + 1] = ctx->col_bd[i] + ctx->col_width[i];
1743 }
1744 // 6-4, 6-6
1745 for (i = 0; i < ctx->tile_rows; i++) {
1746 ctx->row_height[i] = ( i + 1 ) * ctx->slice_block_rows / ctx->tile_rows -
1747 i * ctx->slice_block_rows / ctx->tile_rows;
1748 ctx->row_bd[i + 1] = ctx->row_bd[i] + ctx->row_height[i];
1749 }
1750
1751 av_log(avctx, AV_LOG_VERBOSE, "Encoding pictures with %d x %d tile.\n",
1752 ctx->tile_rows, ctx->tile_cols);
1753
1754 return 0;
1755 }
1756
1757 static av_cold int vaapi_encode_init_slice_structure(AVCodecContext *avctx)
1758 {
1759 FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
1760 VAAPIEncodeContext *ctx = avctx->priv_data;
1761 VAConfigAttrib attr[3] = { { VAConfigAttribEncMaxSlices },
1762 { VAConfigAttribEncSliceStructure },
1763 #if VA_CHECK_VERSION(1, 1, 0)
1764 { VAConfigAttribEncTileSupport },
1765 #endif
1766 };
1767 VAStatus vas;
1768 uint32_t max_slices, slice_structure;
1769 int ret;
1770
1771 if (!(ctx->codec->flags & FF_HW_FLAG_SLICE_CONTROL)) {
1772 if (avctx->slices > 0) {
1773 av_log(avctx, AV_LOG_WARNING, "Multiple slices were requested "
1774 "but this codec does not support controlling slices.\n");
1775 }
1776 return 0;
1777 }
1778
1779 av_assert0(base_ctx->slice_block_height > 0 && base_ctx->slice_block_width > 0);
1780
1781 ctx->slice_block_rows = (avctx->height + base_ctx->slice_block_height - 1) /
1782 base_ctx->slice_block_height;
1783 ctx->slice_block_cols = (avctx->width + base_ctx->slice_block_width - 1) /
1784 base_ctx->slice_block_width;
1785
1786 if (avctx->slices <= 1 && !ctx->tile_rows && !ctx->tile_cols) {
1787 ctx->nb_slices = 1;
1788 ctx->slice_size = ctx->slice_block_rows;
1789 return 0;
1790 }
1791
1792 vas = vaGetConfigAttributes(ctx->hwctx->display,
1793 ctx->va_profile,
1794 ctx->va_entrypoint,
1795 attr, FF_ARRAY_ELEMS(attr));
1796 if (vas != VA_STATUS_SUCCESS) {
1797 av_log(avctx, AV_LOG_ERROR, "Failed to query slice "
1798 "attributes: %d (%s).\n", vas, vaErrorStr(vas));
1799 return AVERROR_EXTERNAL;
1800 }
1801 max_slices = attr[0].value;
1802 slice_structure = attr[1].value;
1803 if (max_slices == VA_ATTRIB_NOT_SUPPORTED ||
1804 slice_structure == VA_ATTRIB_NOT_SUPPORTED) {
1805 av_log(avctx, AV_LOG_ERROR, "Driver does not support encoding "
1806 "pictures as multiple slices.\n.");
1807 return AVERROR(EINVAL);
1808 }
1809
1810 if (ctx->tile_rows && ctx->tile_cols) {
1811 #if VA_CHECK_VERSION(1, 1, 0)
1812 uint32_t tile_support = attr[2].value;
1813 if (tile_support == VA_ATTRIB_NOT_SUPPORTED) {
1814 av_log(avctx, AV_LOG_ERROR, "Driver does not support encoding "
1815 "pictures as multiple tiles.\n.");
1816 return AVERROR(EINVAL);
1817 }
1818 #else
1819 av_log(avctx, AV_LOG_ERROR, "Tile encoding option is "
1820 "not supported with this VAAPI version.\n");
1821 return AVERROR(EINVAL);
1822 #endif
1823 }
1824
1825 if (ctx->tile_rows && ctx->tile_cols)
1826 ret = vaapi_encode_init_tile_slice_structure(avctx, slice_structure);
1827 else
1828 ret = vaapi_encode_init_row_slice_structure(avctx, slice_structure);
1829 if (ret < 0)
1830 return ret;
1831
1832 if (ctx->nb_slices > avctx->slices) {
1833 av_log(avctx, AV_LOG_WARNING, "Slice count rounded up to "
1834 "%d (from %d) due to driver constraints on slice "
1835 "structure.\n", ctx->nb_slices, avctx->slices);
1836 }
1837 if (ctx->nb_slices > max_slices) {
1838 av_log(avctx, AV_LOG_ERROR, "Driver does not support "
1839 "encoding with %d slices (max %"PRIu32").\n",
1840 ctx->nb_slices, max_slices);
1841 return AVERROR(EINVAL);
1842 }
1843
1844 av_log(avctx, AV_LOG_VERBOSE, "Encoding pictures with %d slices.\n",
1845 ctx->nb_slices);
1846 return 0;
1847 }
1848
1849 static av_cold int vaapi_encode_init_packed_headers(AVCodecContext *avctx)
1850 {
1851 VAAPIEncodeContext *ctx = avctx->priv_data;
1852 VAStatus vas;
1853 VAConfigAttrib attr = { VAConfigAttribEncPackedHeaders };
1854
1855 vas = vaGetConfigAttributes(ctx->hwctx->display,
1856 ctx->va_profile,
1857 ctx->va_entrypoint,
1858 &attr, 1);
1859 if (vas != VA_STATUS_SUCCESS) {
1860 av_log(avctx, AV_LOG_ERROR, "Failed to query packed headers "
1861 "attribute: %d (%s).\n", vas, vaErrorStr(vas));
1862 return AVERROR_EXTERNAL;
1863 }
1864
1865 if (attr.value == VA_ATTRIB_NOT_SUPPORTED) {
1866 if (ctx->desired_packed_headers) {
1867 av_log(avctx, AV_LOG_WARNING, "Driver does not support any "
1868 "packed headers (wanted %#x).\n",
1869 ctx->desired_packed_headers);
1870 } else {
1871 av_log(avctx, AV_LOG_VERBOSE, "Driver does not support any "
1872 "packed headers (none wanted).\n");
1873 }
1874 ctx->va_packed_headers = 0;
1875 } else {
1876 if (ctx->desired_packed_headers & ~attr.value) {
1877 av_log(avctx, AV_LOG_WARNING, "Driver does not support some "
1878 "wanted packed headers (wanted %#x, found %#x).\n",
1879 ctx->desired_packed_headers, attr.value);
1880 } else {
1881 av_log(avctx, AV_LOG_VERBOSE, "All wanted packed headers "
1882 "available (wanted %#x, found %#x).\n",
1883 ctx->desired_packed_headers, attr.value);
1884 }
1885 ctx->va_packed_headers = ctx->desired_packed_headers & attr.value;
1886 }
1887
1888 if (ctx->va_packed_headers) {
1889 ctx->config_attributes[ctx->nb_config_attributes++] =
1890 (VAConfigAttrib) {
1891 .type = VAConfigAttribEncPackedHeaders,
1892 .value = ctx->va_packed_headers,
1893 };
1894 }
1895
1896 if ( (ctx->desired_packed_headers & VA_ENC_PACKED_HEADER_SEQUENCE) &&
1897 !(ctx->va_packed_headers & VA_ENC_PACKED_HEADER_SEQUENCE) &&
1898 (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER)) {
1899 av_log(avctx, AV_LOG_WARNING, "Driver does not support packed "
1900 "sequence headers, but a global header is requested.\n");
1901 av_log(avctx, AV_LOG_WARNING, "No global header will be written: "
1902 "this may result in a stream which is not usable for some "
1903 "purposes (e.g. not muxable to some containers).\n");
1904 }
1905
1906 return 0;
1907 }
1908
1909 static av_cold int vaapi_encode_init_quality(AVCodecContext *avctx)
1910 {
1911 #if VA_CHECK_VERSION(0, 36, 0)
1912 VAAPIEncodeContext *ctx = avctx->priv_data;
1913 VAStatus vas;
1914 VAConfigAttrib attr = { VAConfigAttribEncQualityRange };
1915 int quality = avctx->compression_level;
1916
1917 vas = vaGetConfigAttributes(ctx->hwctx->display,
1918 ctx->va_profile,
1919 ctx->va_entrypoint,
1920 &attr, 1);
1921 if (vas != VA_STATUS_SUCCESS) {
1922 av_log(avctx, AV_LOG_ERROR, "Failed to query quality "
1923 "config attribute: %d (%s).\n", vas, vaErrorStr(vas));
1924 return AVERROR_EXTERNAL;
1925 }
1926
1927 if (attr.value == VA_ATTRIB_NOT_SUPPORTED) {
1928 if (quality != 0) {
1929 av_log(avctx, AV_LOG_WARNING, "Quality attribute is not "
1930 "supported: will use default quality level.\n");
1931 }
1932 } else {
1933 if (quality > attr.value) {
1934 av_log(avctx, AV_LOG_WARNING, "Invalid quality level: "
1935 "valid range is 0-%d, using %d.\n",
1936 attr.value, attr.value);
1937 quality = attr.value;
1938 }
1939
1940 ctx->quality_params = (VAEncMiscParameterBufferQualityLevel) {
1941 .quality_level = quality,
1942 };
1943 vaapi_encode_add_global_param(avctx,
1944 VAEncMiscParameterTypeQualityLevel,
1945 &ctx->quality_params,
1946 sizeof(ctx->quality_params));
1947 }
1948 #else
1949 av_log(avctx, AV_LOG_WARNING, "The encode quality option is "
1950 "not supported with this VAAPI version.\n");
1951 #endif
1952
1953 return 0;
1954 }
1955
1956 static av_cold int vaapi_encode_init_roi(AVCodecContext *avctx)
1957 {
1958 #if VA_CHECK_VERSION(1, 0, 0)
1959 FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
1960 VAAPIEncodeContext *ctx = avctx->priv_data;
1961 VAStatus vas;
1962 VAConfigAttrib attr = { VAConfigAttribEncROI };
1963
1964 vas = vaGetConfigAttributes(ctx->hwctx->display,
1965 ctx->va_profile,
1966 ctx->va_entrypoint,
1967 &attr, 1);
1968 if (vas != VA_STATUS_SUCCESS) {
1969 av_log(avctx, AV_LOG_ERROR, "Failed to query ROI "
1970 "config attribute: %d (%s).\n", vas, vaErrorStr(vas));
1971 return AVERROR_EXTERNAL;
1972 }
1973
1974 if (attr.value == VA_ATTRIB_NOT_SUPPORTED) {
1975 base_ctx->roi_allowed = 0;
1976 } else {
1977 VAConfigAttribValEncROI roi = {
1978 .value = attr.value,
1979 };
1980
1981 ctx->roi_max_regions = roi.bits.num_roi_regions;
1982 base_ctx->roi_allowed = ctx->roi_max_regions > 0 &&
1983 (ctx->va_rc_mode == VA_RC_CQP ||
1984 roi.bits.roi_rc_qp_delta_support);
1985 }
1986 #endif
1987 return 0;
1988 }
1989
1990 static void vaapi_encode_free_output_buffer(FFRefStructOpaque opaque,
1991 void *obj)
1992 {
1993 AVCodecContext *avctx = opaque.nc;
1994 VAAPIEncodeContext *ctx = avctx->priv_data;
1995 VABufferID *buffer_id_ref = obj;
1996 VABufferID buffer_id = *buffer_id_ref;
1997
1998 vaDestroyBuffer(ctx->hwctx->display, buffer_id);
1999
2000 av_log(avctx, AV_LOG_DEBUG, "Freed output buffer %#x\n", buffer_id);
2001 }
2002
2003 static int vaapi_encode_alloc_output_buffer(FFRefStructOpaque opaque, void *obj)
2004 {
2005 AVCodecContext *avctx = opaque.nc;
2006 FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
2007 VAAPIEncodeContext *ctx = avctx->priv_data;
2008 VABufferID *buffer_id = obj;
2009 VAStatus vas;
2010
2011 // The output buffer size is fixed, so it needs to be large enough
2012 // to hold the largest possible compressed frame. We assume here
2013 // that the uncompressed frame plus some header data is an upper
2014 // bound on that.
2015 vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context,
2016 VAEncCodedBufferType,
2017 3 * base_ctx->surface_width * base_ctx->surface_height +
2018 (1 << 16), 1, 0, buffer_id);
2019 if (vas != VA_STATUS_SUCCESS) {
2020 av_log(avctx, AV_LOG_ERROR, "Failed to create bitstream "
2021 "output buffer: %d (%s).\n", vas, vaErrorStr(vas));
2022 return AVERROR(ENOMEM);
2023 }
2024
2025 av_log(avctx, AV_LOG_DEBUG, "Allocated output buffer %#x\n", *buffer_id);
2026
2027 return 0;
2028 }
2029
2030 static av_cold int vaapi_encode_create_recon_frames(AVCodecContext *avctx)
2031 {
2032 FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
2033 VAAPIEncodeContext *ctx = avctx->priv_data;
2034 AVVAAPIHWConfig *hwconfig = NULL;
2035 enum AVPixelFormat recon_format;
2036 int err;
2037
2038 hwconfig = av_hwdevice_hwconfig_alloc(base_ctx->device_ref);
2039 if (!hwconfig) {
2040 err = AVERROR(ENOMEM);
2041 goto fail;
2042 }
2043 hwconfig->config_id = ctx->va_config;
2044
2045 err = ff_hw_base_get_recon_format(base_ctx, (const void*)hwconfig, &recon_format);
2046 if (err < 0)
2047 goto fail;
2048
2049 base_ctx->recon_frames_ref = av_hwframe_ctx_alloc(base_ctx->device_ref);
2050 if (!base_ctx->recon_frames_ref) {
2051 err = AVERROR(ENOMEM);
2052 goto fail;
2053 }
2054 base_ctx->recon_frames = (AVHWFramesContext*)base_ctx->recon_frames_ref->data;
2055
2056 base_ctx->recon_frames->format = AV_PIX_FMT_VAAPI;
2057 base_ctx->recon_frames->sw_format = recon_format;
2058 base_ctx->recon_frames->width = base_ctx->surface_width;
2059 base_ctx->recon_frames->height = base_ctx->surface_height;
2060
2061 err = av_hwframe_ctx_init(base_ctx->recon_frames_ref);
2062 if (err < 0) {
2063 av_log(avctx, AV_LOG_ERROR, "Failed to initialise reconstructed "
2064 "frame context: %d.\n", err);
2065 goto fail;
2066 }
2067
2068 err = 0;
2069 fail:
2070 av_freep(&hwconfig);
2071 return err;
2072 }
2073
2074 static const FFHWEncodePictureOperation vaapi_op = {
2075 .priv_size = sizeof(VAAPIEncodePicture),
2076
2077 .init = &vaapi_encode_init,
2078
2079 .issue = &vaapi_encode_issue,
2080
2081 .output = &vaapi_encode_output,
2082
2083 .free = &vaapi_encode_free,
2084 };
2085
2086 int ff_vaapi_encode_receive_packet(AVCodecContext *avctx, AVPacket *pkt)
2087 {
2088 return ff_hw_base_encode_receive_packet(avctx->priv_data, avctx, pkt);
2089 }
2090
2091 av_cold int ff_vaapi_encode_init(AVCodecContext *avctx)
2092 {
2093 FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
2094 VAAPIEncodeContext *ctx = avctx->priv_data;
2095 AVVAAPIFramesContext *recon_hwctx = NULL;
2096 VAStatus vas;
2097 int err;
2098
2099 err = ff_hw_base_encode_init(avctx, base_ctx);
2100 if (err < 0)
2101 goto fail;
2102
2103 ctx->va_config = VA_INVALID_ID;
2104 ctx->va_context = VA_INVALID_ID;
2105
2106 base_ctx->op = &vaapi_op;
2107
2108 ctx->hwctx = base_ctx->device->hwctx;
2109
2110 err = vaapi_encode_profile_entrypoint(avctx);
2111 if (err < 0)
2112 goto fail;
2113
2114 if (ctx->codec->get_encoder_caps) {
2115 err = ctx->codec->get_encoder_caps(avctx);
2116 if (err < 0)
2117 goto fail;
2118 } else {
2119 // Assume 16x16 blocks.
2120 base_ctx->surface_width = FFALIGN(avctx->width, 16);
2121 base_ctx->surface_height = FFALIGN(avctx->height, 16);
2122 if (ctx->codec->flags & FF_HW_FLAG_SLICE_CONTROL) {
2123 base_ctx->slice_block_width = 16;
2124 base_ctx->slice_block_height = 16;
2125 }
2126 }
2127
2128 err = vaapi_encode_init_rate_control(avctx);
2129 if (err < 0)
2130 goto fail;
2131
2132 err = vaapi_encode_init_gop_structure(avctx);
2133 if (err < 0)
2134 goto fail;
2135
2136 err = vaapi_encode_init_slice_structure(avctx);
2137 if (err < 0)
2138 goto fail;
2139
2140 err = vaapi_encode_init_packed_headers(avctx);
2141 if (err < 0)
2142 goto fail;
2143
2144 err = vaapi_encode_init_roi(avctx);
2145 if (err < 0)
2146 goto fail;
2147
2148 if (avctx->compression_level >= 0) {
2149 err = vaapi_encode_init_quality(avctx);
2150 if (err < 0)
2151 goto fail;
2152 }
2153
2154 if (ctx->max_frame_size) {
2155 err = vaapi_encode_init_max_frame_size(avctx);
2156 if (err < 0)
2157 goto fail;
2158 }
2159
2160 vas = vaCreateConfig(ctx->hwctx->display,
2161 ctx->va_profile, ctx->va_entrypoint,
2162 ctx->config_attributes, ctx->nb_config_attributes,
2163 &ctx->va_config);
2164 if (vas != VA_STATUS_SUCCESS) {
2165 av_log(avctx, AV_LOG_ERROR, "Failed to create encode pipeline "
2166 "configuration: %d (%s).\n", vas, vaErrorStr(vas));
2167 err = AVERROR(EIO);
2168 goto fail;
2169 }
2170
2171 err = vaapi_encode_create_recon_frames(avctx);
2172 if (err < 0)
2173 goto fail;
2174
2175 recon_hwctx = base_ctx->recon_frames->hwctx;
2176 vas = vaCreateContext(ctx->hwctx->display, ctx->va_config,
2177 base_ctx->surface_width, base_ctx->surface_height,
2178 VA_PROGRESSIVE,
2179 recon_hwctx->surface_ids,
2180 recon_hwctx->nb_surfaces,
2181 &ctx->va_context);
2182 if (vas != VA_STATUS_SUCCESS) {
2183 av_log(avctx, AV_LOG_ERROR, "Failed to create encode pipeline "
2184 "context: %d (%s).\n", vas, vaErrorStr(vas));
2185 err = AVERROR(EIO);
2186 goto fail;
2187 }
2188
2189 ctx->output_buffer_pool =
2190 ff_refstruct_pool_alloc_ext(sizeof(VABufferID), 0, avctx,
2191 &vaapi_encode_alloc_output_buffer, NULL,
2192 vaapi_encode_free_output_buffer, NULL);
2193 if (!ctx->output_buffer_pool) {
2194 err = AVERROR(ENOMEM);
2195 goto fail;
2196 }
2197
2198 if (ctx->codec->configure) {
2199 err = ctx->codec->configure(avctx);
2200 if (err < 0)
2201 goto fail;
2202 }
2203
2204 base_ctx->output_delay = base_ctx->b_per_p;
2205 base_ctx->decode_delay = base_ctx->max_b_depth;
2206
2207 if (ctx->codec->sequence_params_size > 0) {
2208 ctx->codec_sequence_params =
2209 av_mallocz(ctx->codec->sequence_params_size);
2210 if (!ctx->codec_sequence_params) {
2211 err = AVERROR(ENOMEM);
2212 goto fail;
2213 }
2214 }
2215 if (ctx->codec->picture_params_size > 0) {
2216 ctx->codec_picture_params =
2217 av_mallocz(ctx->codec->picture_params_size);
2218 if (!ctx->codec_picture_params) {
2219 err = AVERROR(ENOMEM);
2220 goto fail;
2221 }
2222 }
2223
2224 if (ctx->codec->init_sequence_params) {
2225 err = ctx->codec->init_sequence_params(avctx);
2226 if (err < 0) {
2227 av_log(avctx, AV_LOG_ERROR, "Codec sequence initialisation "
2228 "failed: %d.\n", err);
2229 goto fail;
2230 }
2231 }
2232
2233 if (ctx->va_packed_headers & VA_ENC_PACKED_HEADER_SEQUENCE &&
2234 ctx->codec->write_sequence_header &&
2235 avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) {
2236 char data[MAX_PARAM_BUFFER_SIZE];
2237 size_t bit_len = 8 * sizeof(data);
2238
2239 err = ctx->codec->write_sequence_header(avctx, data, &bit_len);
2240 if (err < 0) {
2241 av_log(avctx, AV_LOG_ERROR, "Failed to write sequence header "
2242 "for extradata: %d.\n", err);
2243 goto fail;
2244 } else {
2245 avctx->extradata_size = (bit_len + 7) / 8;
2246 avctx->extradata = av_mallocz(avctx->extradata_size +
2247 AV_INPUT_BUFFER_PADDING_SIZE);
2248 if (!avctx->extradata) {
2249 err = AVERROR(ENOMEM);
2250 goto fail;
2251 }
2252 memcpy(avctx->extradata, data, avctx->extradata_size);
2253 }
2254 }
2255
2256 #if VA_CHECK_VERSION(1, 9, 0)
2257 // check vaSyncBuffer function
2258 vas = vaSyncBuffer(ctx->hwctx->display, VA_INVALID_ID, 0);
2259 if (vas != VA_STATUS_ERROR_UNIMPLEMENTED) {
2260 base_ctx->async_encode = 1;
2261 base_ctx->encode_fifo = av_fifo_alloc2(base_ctx->async_depth,
2262 sizeof(VAAPIEncodePicture*),
2263 0);
2264 if (!base_ctx->encode_fifo)
2265 return AVERROR(ENOMEM);
2266 }
2267 #endif
2268
2269 return 0;
2270
2271 fail:
2272 return err;
2273 }
2274
2275 av_cold int ff_vaapi_encode_close(AVCodecContext *avctx)
2276 {
2277 FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
2278 VAAPIEncodeContext *ctx = avctx->priv_data;
2279 FFHWBaseEncodePicture *pic, *next;
2280
2281 /* We check ctx->frame to know whether ff_vaapi_encode_init()
2282 * has been called and va_config/va_context initialized. */
2283 if (!base_ctx->frame)
2284 return 0;
2285
2286 for (pic = base_ctx->pic_start; pic; pic = next) {
2287 next = pic->next;
2288 vaapi_encode_free(avctx, pic);
2289 }
2290
2291 ff_refstruct_pool_uninit(&ctx->output_buffer_pool);
2292
2293 if (ctx->va_context != VA_INVALID_ID) {
2294 if (ctx->hwctx)
2295 vaDestroyContext(ctx->hwctx->display, ctx->va_context);
2296 ctx->va_context = VA_INVALID_ID;
2297 }
2298
2299 if (ctx->va_config != VA_INVALID_ID) {
2300 if (ctx->hwctx)
2301 vaDestroyConfig(ctx->hwctx->display, ctx->va_config);
2302 ctx->va_config = VA_INVALID_ID;
2303 }
2304
2305 av_freep(&ctx->codec_sequence_params);
2306 av_freep(&ctx->codec_picture_params);
2307
2308 ff_hw_base_encode_close(base_ctx);
2309
2310 return 0;
2311 }
2312