FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/vaapi_encode.c
Date: 2025-01-20 09:27:23
Exec Total Coverage
Lines: 0 1186 0.0%
Functions: 0 32 0.0%
Branches: 0 714 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 "libavutil/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 = av_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 av_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 av_refstruct_unref(&ctx->coded_buffer_ref);
763 av_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 = av_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 av_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 av_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 av_cold int vaapi_encode_surface_alignment(av_unused AVCodecContext *avctx)
1137 {
1138 #if VA_CHECK_VERSION(1, 21, 0)
1139 VAAPIEncodeContext *ctx = avctx->priv_data;
1140 VASurfaceAttrib *attr_list = NULL;
1141 unsigned int attr_count = 0;
1142 VAConfigID va_config;
1143 VAStatus vas;
1144 int err = 0;
1145
1146 vas = vaCreateConfig(ctx->hwctx->display,
1147 ctx->va_profile, ctx->va_entrypoint,
1148 NULL, 0, &va_config);
1149 if (vas != VA_STATUS_SUCCESS) {
1150 av_log(avctx, AV_LOG_ERROR, "Failed to create temp encode pipeline "
1151 "configuration: %d (%s).\n", vas, vaErrorStr(vas));
1152 return AVERROR(EIO);
1153 }
1154
1155 vas = vaQuerySurfaceAttributes(ctx->hwctx->display, va_config,
1156 0, &attr_count);
1157 if (vas != VA_STATUS_SUCCESS) {
1158 av_log(avctx, AV_LOG_ERROR, "Failed to query surface attributes: "
1159 "%d (%s).\n", vas, vaErrorStr(vas));
1160 err = AVERROR_EXTERNAL;
1161 goto fail;
1162 }
1163
1164 attr_list = av_malloc(attr_count * sizeof(*attr_list));
1165 if (!attr_list) {
1166 err = AVERROR(ENOMEM);
1167 goto fail;
1168 }
1169
1170 vas = vaQuerySurfaceAttributes(ctx->hwctx->display, va_config,
1171 attr_list, &attr_count);
1172 if (vas != VA_STATUS_SUCCESS) {
1173 av_log(avctx, AV_LOG_ERROR, "Failed to query surface attributes: "
1174 "%d (%s).\n", vas, vaErrorStr(vas));
1175 err = AVERROR_EXTERNAL;
1176 goto fail;
1177 }
1178
1179 for (unsigned int i = 0; i < attr_count; i++) {
1180 if (attr_list[i].type == VASurfaceAttribAlignmentSize) {
1181 ctx->surface_alignment_width =
1182 1 << (attr_list[i].value.value.i & 0xf);
1183 ctx->surface_alignment_height =
1184 1 << ((attr_list[i].value.value.i & 0xf0) >> 4);
1185 break;
1186 }
1187 }
1188
1189 fail:
1190 av_freep(&attr_list);
1191 vaDestroyConfig(ctx->hwctx->display, va_config);
1192 return err;
1193 #else
1194 return 0;
1195 #endif
1196 }
1197
1198 static const VAAPIEncodeRCMode vaapi_encode_rc_modes[] = {
1199 // Bitrate Quality
1200 // | Maxrate | HRD/VBV
1201 { 0 }, // | | | |
1202 { RC_MODE_CQP, "CQP", 1, VA_RC_CQP, 0, 0, 1, 0 },
1203 { RC_MODE_CBR, "CBR", 1, VA_RC_CBR, 1, 0, 0, 1 },
1204 { RC_MODE_VBR, "VBR", 1, VA_RC_VBR, 1, 1, 0, 1 },
1205 #if VA_CHECK_VERSION(1, 1, 0)
1206 { RC_MODE_ICQ, "ICQ", 1, VA_RC_ICQ, 0, 0, 1, 0 },
1207 #else
1208 { RC_MODE_ICQ, "ICQ", 0 },
1209 #endif
1210 #if VA_CHECK_VERSION(1, 3, 0)
1211 { RC_MODE_QVBR, "QVBR", 1, VA_RC_QVBR, 1, 1, 1, 1 },
1212 { RC_MODE_AVBR, "AVBR", 0, VA_RC_AVBR, 1, 0, 0, 0 },
1213 #else
1214 { RC_MODE_QVBR, "QVBR", 0 },
1215 { RC_MODE_AVBR, "AVBR", 0 },
1216 #endif
1217 };
1218
1219 static av_cold int vaapi_encode_init_rate_control(AVCodecContext *avctx)
1220 {
1221 VAAPIEncodeContext *ctx = avctx->priv_data;
1222 uint32_t supported_va_rc_modes;
1223 const VAAPIEncodeRCMode *rc_mode;
1224 int64_t rc_bits_per_second;
1225 int rc_target_percentage;
1226 int rc_window_size;
1227 int rc_quality;
1228 int64_t hrd_buffer_size;
1229 int64_t hrd_initial_buffer_fullness;
1230 int fr_num, fr_den;
1231 VAConfigAttrib rc_attr = { VAConfigAttribRateControl };
1232 VAStatus vas;
1233 char supported_rc_modes_string[64];
1234
1235 vas = vaGetConfigAttributes(ctx->hwctx->display,
1236 ctx->va_profile, ctx->va_entrypoint,
1237 &rc_attr, 1);
1238 if (vas != VA_STATUS_SUCCESS) {
1239 av_log(avctx, AV_LOG_ERROR, "Failed to query rate control "
1240 "config attribute: %d (%s).\n", vas, vaErrorStr(vas));
1241 return AVERROR_EXTERNAL;
1242 }
1243 if (rc_attr.value == VA_ATTRIB_NOT_SUPPORTED) {
1244 av_log(avctx, AV_LOG_VERBOSE, "Driver does not report any "
1245 "supported rate control modes: assuming CQP only.\n");
1246 supported_va_rc_modes = VA_RC_CQP;
1247 strcpy(supported_rc_modes_string, "unknown");
1248 } else {
1249 char *str = supported_rc_modes_string;
1250 size_t len = sizeof(supported_rc_modes_string);
1251 int i, first = 1, res;
1252
1253 supported_va_rc_modes = rc_attr.value;
1254 if (ctx->blbrc) {
1255 #if VA_CHECK_VERSION(0, 39, 2)
1256 if (!(supported_va_rc_modes & VA_RC_MB)) {
1257 ctx->blbrc = 0;
1258 av_log(avctx, AV_LOG_WARNING, "Driver does not support BLBRC.\n");
1259 }
1260 #else
1261 ctx->blbrc = 0;
1262 av_log(avctx, AV_LOG_WARNING, "Please consider to update to VAAPI 0.39.2 "
1263 "or above, which can support BLBRC.\n");
1264 #endif
1265 }
1266
1267 for (i = 0; i < FF_ARRAY_ELEMS(vaapi_encode_rc_modes); i++) {
1268 rc_mode = &vaapi_encode_rc_modes[i];
1269 if (supported_va_rc_modes & rc_mode->va_mode) {
1270 res = snprintf(str, len, "%s%s",
1271 first ? "" : ", ", rc_mode->name);
1272 first = 0;
1273 if (res < 0) {
1274 *str = 0;
1275 break;
1276 }
1277 len -= res;
1278 str += res;
1279 if (len == 0)
1280 break;
1281 }
1282 }
1283
1284 av_log(avctx, AV_LOG_DEBUG, "Driver supports RC modes %s.\n",
1285 supported_rc_modes_string);
1286 }
1287
1288 // Rate control mode selection:
1289 // * If the user has set a mode explicitly with the rc_mode option,
1290 // use it and fail if it is not available.
1291 // * If an explicit QP option has been set, use CQP.
1292 // * If the codec is CQ-only, use CQP.
1293 // * If the QSCALE avcodec option is set, use CQP.
1294 // * If bitrate and quality are both set, try QVBR.
1295 // * If quality is set, try ICQ, then CQP.
1296 // * If bitrate and maxrate are set and have the same value, try CBR.
1297 // * If a bitrate is set, try AVBR, then VBR, then CBR.
1298 // * If no bitrate is set, try ICQ, then CQP.
1299
1300 #define TRY_RC_MODE(mode, fail) do { \
1301 rc_mode = &vaapi_encode_rc_modes[mode]; \
1302 if (!(rc_mode->va_mode & supported_va_rc_modes)) { \
1303 if (fail) { \
1304 av_log(avctx, AV_LOG_ERROR, "Driver does not support %s " \
1305 "RC mode (supported modes: %s).\n", rc_mode->name, \
1306 supported_rc_modes_string); \
1307 return AVERROR(EINVAL); \
1308 } \
1309 av_log(avctx, AV_LOG_DEBUG, "Driver does not support %s " \
1310 "RC mode.\n", rc_mode->name); \
1311 rc_mode = NULL; \
1312 } else { \
1313 goto rc_mode_found; \
1314 } \
1315 } while (0)
1316
1317 if (ctx->explicit_rc_mode)
1318 TRY_RC_MODE(ctx->explicit_rc_mode, 1);
1319
1320 if (ctx->explicit_qp)
1321 TRY_RC_MODE(RC_MODE_CQP, 1);
1322
1323 if (ctx->codec->flags & FF_HW_FLAG_CONSTANT_QUALITY_ONLY)
1324 TRY_RC_MODE(RC_MODE_CQP, 1);
1325
1326 if (avctx->flags & AV_CODEC_FLAG_QSCALE)
1327 TRY_RC_MODE(RC_MODE_CQP, 1);
1328
1329 if (avctx->bit_rate > 0 && avctx->global_quality > 0)
1330 TRY_RC_MODE(RC_MODE_QVBR, 0);
1331
1332 if (avctx->global_quality > 0) {
1333 TRY_RC_MODE(RC_MODE_ICQ, 0);
1334 TRY_RC_MODE(RC_MODE_CQP, 0);
1335 }
1336
1337 if (avctx->bit_rate > 0 && avctx->rc_max_rate == avctx->bit_rate)
1338 TRY_RC_MODE(RC_MODE_CBR, 0);
1339
1340 if (avctx->bit_rate > 0) {
1341 TRY_RC_MODE(RC_MODE_AVBR, 0);
1342 TRY_RC_MODE(RC_MODE_VBR, 0);
1343 TRY_RC_MODE(RC_MODE_CBR, 0);
1344 } else {
1345 TRY_RC_MODE(RC_MODE_ICQ, 0);
1346 TRY_RC_MODE(RC_MODE_CQP, 0);
1347 }
1348
1349 av_log(avctx, AV_LOG_ERROR, "Driver does not support any "
1350 "RC mode compatible with selected options "
1351 "(supported modes: %s).\n", supported_rc_modes_string);
1352 return AVERROR(EINVAL);
1353
1354 rc_mode_found:
1355 if (rc_mode->bitrate) {
1356 if (avctx->bit_rate <= 0) {
1357 av_log(avctx, AV_LOG_ERROR, "Bitrate must be set for %s "
1358 "RC mode.\n", rc_mode->name);
1359 return AVERROR(EINVAL);
1360 }
1361
1362 if (rc_mode->mode == RC_MODE_AVBR) {
1363 // For maximum confusion AVBR is hacked into the existing API
1364 // by overloading some of the fields with completely different
1365 // meanings.
1366
1367 // Target percentage does not apply in AVBR mode.
1368 rc_bits_per_second = avctx->bit_rate;
1369
1370 // Accuracy tolerance range for meeting the specified target
1371 // bitrate. It's very unclear how this is actually intended
1372 // to work - since we do want to get the specified bitrate,
1373 // set the accuracy to 100% for now.
1374 rc_target_percentage = 100;
1375
1376 // Convergence period in frames. The GOP size reflects the
1377 // user's intended block size for cutting, so reusing that
1378 // as the convergence period seems a reasonable default.
1379 rc_window_size = avctx->gop_size > 0 ? avctx->gop_size : 60;
1380
1381 } else if (rc_mode->maxrate) {
1382 if (avctx->rc_max_rate > 0) {
1383 if (avctx->rc_max_rate < avctx->bit_rate) {
1384 av_log(avctx, AV_LOG_ERROR, "Invalid bitrate settings: "
1385 "bitrate (%"PRId64") must not be greater than "
1386 "maxrate (%"PRId64").\n", avctx->bit_rate,
1387 avctx->rc_max_rate);
1388 return AVERROR(EINVAL);
1389 }
1390 rc_bits_per_second = avctx->rc_max_rate;
1391 rc_target_percentage = (avctx->bit_rate * 100) /
1392 avctx->rc_max_rate;
1393 } else {
1394 // We only have a target bitrate, but this mode requires
1395 // that a maximum rate be supplied as well. Since the
1396 // user does not want this to be a constraint, arbitrarily
1397 // pick a maximum rate of double the target rate.
1398 rc_bits_per_second = 2 * avctx->bit_rate;
1399 rc_target_percentage = 50;
1400 }
1401 } else {
1402 if (avctx->rc_max_rate > avctx->bit_rate) {
1403 av_log(avctx, AV_LOG_WARNING, "Max bitrate is ignored "
1404 "in %s RC mode.\n", rc_mode->name);
1405 }
1406 rc_bits_per_second = avctx->bit_rate;
1407 rc_target_percentage = 100;
1408 }
1409 } else {
1410 rc_bits_per_second = 0;
1411 rc_target_percentage = 100;
1412 }
1413
1414 if (rc_mode->quality) {
1415 if (ctx->explicit_qp) {
1416 rc_quality = ctx->explicit_qp;
1417 } else if (avctx->global_quality > 0) {
1418 if (avctx->flags & AV_CODEC_FLAG_QSCALE)
1419 rc_quality = avctx->global_quality / FF_QP2LAMBDA;
1420 else
1421 rc_quality = avctx->global_quality;
1422 } else {
1423 rc_quality = ctx->codec->default_quality;
1424 av_log(avctx, AV_LOG_WARNING, "No quality level set; "
1425 "using default (%d).\n", rc_quality);
1426 }
1427 } else {
1428 rc_quality = 0;
1429 }
1430
1431 if (rc_mode->hrd) {
1432 if (avctx->rc_buffer_size)
1433 hrd_buffer_size = avctx->rc_buffer_size;
1434 else if (avctx->rc_max_rate > 0)
1435 hrd_buffer_size = avctx->rc_max_rate;
1436 else
1437 hrd_buffer_size = avctx->bit_rate;
1438 if (avctx->rc_initial_buffer_occupancy) {
1439 if (avctx->rc_initial_buffer_occupancy > hrd_buffer_size) {
1440 av_log(avctx, AV_LOG_ERROR, "Invalid RC buffer settings: "
1441 "must have initial buffer size (%d) <= "
1442 "buffer size (%"PRId64").\n",
1443 avctx->rc_initial_buffer_occupancy, hrd_buffer_size);
1444 return AVERROR(EINVAL);
1445 }
1446 hrd_initial_buffer_fullness = avctx->rc_initial_buffer_occupancy;
1447 } else {
1448 hrd_initial_buffer_fullness = hrd_buffer_size * 3 / 4;
1449 }
1450
1451 rc_window_size = (hrd_buffer_size * 1000) / rc_bits_per_second;
1452 } else {
1453 if (avctx->rc_buffer_size || avctx->rc_initial_buffer_occupancy) {
1454 av_log(avctx, AV_LOG_WARNING, "Buffering settings are ignored "
1455 "in %s RC mode.\n", rc_mode->name);
1456 }
1457
1458 hrd_buffer_size = 0;
1459 hrd_initial_buffer_fullness = 0;
1460
1461 if (rc_mode->mode != RC_MODE_AVBR) {
1462 // Already set (with completely different meaning) for AVBR.
1463 rc_window_size = 1000;
1464 }
1465 }
1466
1467 if (rc_bits_per_second > UINT32_MAX ||
1468 hrd_buffer_size > UINT32_MAX ||
1469 hrd_initial_buffer_fullness > UINT32_MAX) {
1470 av_log(avctx, AV_LOG_ERROR, "RC parameters of 2^32 or "
1471 "greater are not supported by VAAPI.\n");
1472 return AVERROR(EINVAL);
1473 }
1474
1475 ctx->rc_mode = rc_mode;
1476 ctx->rc_quality = rc_quality;
1477 ctx->va_rc_mode = rc_mode->va_mode;
1478 ctx->va_bit_rate = rc_bits_per_second;
1479
1480 av_log(avctx, AV_LOG_VERBOSE, "RC mode: %s.\n", rc_mode->name);
1481
1482 if (ctx->blbrc && ctx->va_rc_mode == VA_RC_CQP)
1483 ctx->blbrc = 0;
1484 av_log(avctx, AV_LOG_VERBOSE, "Block Level bitrate control: %s.\n", ctx->blbrc ? "ON" : "OFF");
1485
1486 if (rc_attr.value == VA_ATTRIB_NOT_SUPPORTED) {
1487 // This driver does not want the RC mode attribute to be set.
1488 } else {
1489 ctx->config_attributes[ctx->nb_config_attributes++] =
1490 (VAConfigAttrib) {
1491 .type = VAConfigAttribRateControl,
1492 #if VA_CHECK_VERSION(0, 39, 2)
1493 .value = ctx->blbrc ? ctx->va_rc_mode | VA_RC_MB : ctx->va_rc_mode,
1494 #else
1495 .value = ctx->va_rc_mode,
1496 #endif
1497 };
1498 }
1499
1500 if (rc_mode->quality)
1501 av_log(avctx, AV_LOG_VERBOSE, "RC quality: %d.\n", rc_quality);
1502
1503 if (rc_mode->va_mode != VA_RC_CQP) {
1504 if (rc_mode->mode == RC_MODE_AVBR) {
1505 av_log(avctx, AV_LOG_VERBOSE, "RC target: %"PRId64" bps "
1506 "converging in %d frames with %d%% accuracy.\n",
1507 rc_bits_per_second, rc_window_size,
1508 rc_target_percentage);
1509 } else if (rc_mode->bitrate) {
1510 av_log(avctx, AV_LOG_VERBOSE, "RC target: %d%% of "
1511 "%"PRId64" bps over %d ms.\n", rc_target_percentage,
1512 rc_bits_per_second, rc_window_size);
1513 }
1514
1515 ctx->rc_params = (VAEncMiscParameterRateControl) {
1516 .bits_per_second = rc_bits_per_second,
1517 .target_percentage = rc_target_percentage,
1518 .window_size = rc_window_size,
1519 .initial_qp = 0,
1520 .min_qp = (avctx->qmin > 0 ? avctx->qmin : 0),
1521 .basic_unit_size = 0,
1522 #if VA_CHECK_VERSION(1, 1, 0)
1523 .ICQ_quality_factor = av_clip(rc_quality, 1, 51),
1524 .max_qp = (avctx->qmax > 0 ? avctx->qmax : 0),
1525 #endif
1526 #if VA_CHECK_VERSION(1, 3, 0)
1527 .quality_factor = rc_quality,
1528 #endif
1529 #if VA_CHECK_VERSION(0, 39, 2)
1530 .rc_flags.bits.mb_rate_control = ctx->blbrc ? 1 : 2,
1531 #endif
1532 };
1533 vaapi_encode_add_global_param(avctx,
1534 VAEncMiscParameterTypeRateControl,
1535 &ctx->rc_params,
1536 sizeof(ctx->rc_params));
1537 }
1538
1539 if (rc_mode->hrd) {
1540 av_log(avctx, AV_LOG_VERBOSE, "RC buffer: %"PRId64" bits, "
1541 "initial fullness %"PRId64" bits.\n",
1542 hrd_buffer_size, hrd_initial_buffer_fullness);
1543
1544 ctx->hrd_params = (VAEncMiscParameterHRD) {
1545 .initial_buffer_fullness = hrd_initial_buffer_fullness,
1546 .buffer_size = hrd_buffer_size,
1547 };
1548 vaapi_encode_add_global_param(avctx,
1549 VAEncMiscParameterTypeHRD,
1550 &ctx->hrd_params,
1551 sizeof(ctx->hrd_params));
1552 }
1553
1554 if (avctx->framerate.num > 0 && avctx->framerate.den > 0)
1555 av_reduce(&fr_num, &fr_den,
1556 avctx->framerate.num, avctx->framerate.den, 65535);
1557 else
1558 av_reduce(&fr_num, &fr_den,
1559 avctx->time_base.den, avctx->time_base.num, 65535);
1560
1561 av_log(avctx, AV_LOG_VERBOSE, "RC framerate: %d/%d (%.2f fps).\n",
1562 fr_num, fr_den, (double)fr_num / fr_den);
1563
1564 ctx->fr_params = (VAEncMiscParameterFrameRate) {
1565 .framerate = (unsigned int)fr_den << 16 | fr_num,
1566 };
1567 #if VA_CHECK_VERSION(0, 40, 0)
1568 vaapi_encode_add_global_param(avctx,
1569 VAEncMiscParameterTypeFrameRate,
1570 &ctx->fr_params,
1571 sizeof(ctx->fr_params));
1572 #endif
1573
1574 return 0;
1575 }
1576
1577 static av_cold int vaapi_encode_init_max_frame_size(AVCodecContext *avctx)
1578 {
1579 #if VA_CHECK_VERSION(1, 5, 0)
1580 VAAPIEncodeContext *ctx = avctx->priv_data;
1581 VAConfigAttrib attr = { VAConfigAttribMaxFrameSize };
1582 VAStatus vas;
1583
1584 if (ctx->va_rc_mode == VA_RC_CQP) {
1585 ctx->max_frame_size = 0;
1586 av_log(avctx, AV_LOG_ERROR, "Max frame size is invalid in CQP rate "
1587 "control mode.\n");
1588 return AVERROR(EINVAL);
1589 }
1590
1591 vas = vaGetConfigAttributes(ctx->hwctx->display,
1592 ctx->va_profile,
1593 ctx->va_entrypoint,
1594 &attr, 1);
1595 if (vas != VA_STATUS_SUCCESS) {
1596 ctx->max_frame_size = 0;
1597 av_log(avctx, AV_LOG_ERROR, "Failed to query max frame size "
1598 "config attribute: %d (%s).\n", vas, vaErrorStr(vas));
1599 return AVERROR_EXTERNAL;
1600 }
1601
1602 if (attr.value == VA_ATTRIB_NOT_SUPPORTED) {
1603 ctx->max_frame_size = 0;
1604 av_log(avctx, AV_LOG_ERROR, "Max frame size attribute "
1605 "is not supported.\n");
1606 return AVERROR(EINVAL);
1607 } else {
1608 VAConfigAttribValMaxFrameSize attr_mfs;
1609 attr_mfs.value = attr.value;
1610 // Prefer to use VAEncMiscParameterTypeMaxFrameSize for max frame size.
1611 if (!attr_mfs.bits.max_frame_size && attr_mfs.bits.multiple_pass) {
1612 ctx->max_frame_size = 0;
1613 av_log(avctx, AV_LOG_ERROR, "Driver only supports multiple pass "
1614 "max frame size which has not been implemented in FFmpeg.\n");
1615 return AVERROR(EINVAL);
1616 }
1617
1618 ctx->mfs_params = (VAEncMiscParameterBufferMaxFrameSize){
1619 .max_frame_size = ctx->max_frame_size * 8,
1620 };
1621
1622 av_log(avctx, AV_LOG_VERBOSE, "Set max frame size: %d bytes.\n",
1623 ctx->max_frame_size);
1624 }
1625 #else
1626 av_log(avctx, AV_LOG_ERROR, "The max frame size option is not supported with "
1627 "this VAAPI version.\n");
1628 return AVERROR(EINVAL);
1629 #endif
1630
1631 return 0;
1632 }
1633
1634 static av_cold int vaapi_encode_init_gop_structure(AVCodecContext *avctx)
1635 {
1636 FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
1637 VAAPIEncodeContext *ctx = avctx->priv_data;
1638 VAStatus vas;
1639 VAConfigAttrib attr = { VAConfigAttribEncMaxRefFrames };
1640 uint32_t ref_l0, ref_l1;
1641 int prediction_pre_only, err;
1642
1643 vas = vaGetConfigAttributes(ctx->hwctx->display,
1644 ctx->va_profile,
1645 ctx->va_entrypoint,
1646 &attr, 1);
1647 if (vas != VA_STATUS_SUCCESS) {
1648 av_log(avctx, AV_LOG_ERROR, "Failed to query reference frames "
1649 "attribute: %d (%s).\n", vas, vaErrorStr(vas));
1650 return AVERROR_EXTERNAL;
1651 }
1652
1653 if (attr.value == VA_ATTRIB_NOT_SUPPORTED) {
1654 ref_l0 = ref_l1 = 0;
1655 } else {
1656 ref_l0 = attr.value & 0xffff;
1657 ref_l1 = attr.value >> 16 & 0xffff;
1658 }
1659
1660 base_ctx->p_to_gpb = 0;
1661 prediction_pre_only = 0;
1662
1663 #if VA_CHECK_VERSION(1, 9, 0)
1664 if (!(ctx->codec->flags & FF_HW_FLAG_INTRA_ONLY ||
1665 avctx->gop_size <= 1)) {
1666 attr = (VAConfigAttrib) { VAConfigAttribPredictionDirection };
1667 vas = vaGetConfigAttributes(ctx->hwctx->display,
1668 ctx->va_profile,
1669 ctx->va_entrypoint,
1670 &attr, 1);
1671 if (vas != VA_STATUS_SUCCESS) {
1672 av_log(avctx, AV_LOG_WARNING, "Failed to query prediction direction "
1673 "attribute: %d (%s).\n", vas, vaErrorStr(vas));
1674 return AVERROR_EXTERNAL;
1675 } else if (attr.value == VA_ATTRIB_NOT_SUPPORTED) {
1676 av_log(avctx, AV_LOG_VERBOSE, "Driver does not report any additional "
1677 "prediction constraints.\n");
1678 } else {
1679 if (((ref_l0 > 0 || ref_l1 > 0) && !(attr.value & VA_PREDICTION_DIRECTION_PREVIOUS)) ||
1680 ((ref_l1 == 0) && (attr.value & (VA_PREDICTION_DIRECTION_FUTURE | VA_PREDICTION_DIRECTION_BI_NOT_EMPTY)))) {
1681 av_log(avctx, AV_LOG_ERROR, "Driver report incorrect prediction "
1682 "direction attribute.\n");
1683 return AVERROR_EXTERNAL;
1684 }
1685
1686 if (!(attr.value & VA_PREDICTION_DIRECTION_FUTURE)) {
1687 if (ref_l0 > 0 && ref_l1 > 0) {
1688 prediction_pre_only = 1;
1689 av_log(avctx, AV_LOG_VERBOSE, "Driver only support same reference "
1690 "lists for B-frames.\n");
1691 }
1692 }
1693
1694 if (attr.value & VA_PREDICTION_DIRECTION_BI_NOT_EMPTY) {
1695 if (ref_l0 > 0 && ref_l1 > 0) {
1696 base_ctx->p_to_gpb = 1;
1697 av_log(avctx, AV_LOG_VERBOSE, "Driver does not support P-frames, "
1698 "replacing them with B-frames.\n");
1699 }
1700 }
1701 }
1702 }
1703 #endif
1704
1705 err = ff_hw_base_init_gop_structure(base_ctx, avctx, ref_l0, ref_l1,
1706 ctx->codec->flags, prediction_pre_only);
1707 if (err < 0)
1708 return err;
1709
1710 return 0;
1711 }
1712
1713 static av_cold int vaapi_encode_init_row_slice_structure(AVCodecContext *avctx,
1714 uint32_t slice_structure)
1715 {
1716 VAAPIEncodeContext *ctx = avctx->priv_data;
1717 int req_slices;
1718
1719 // For fixed-size slices currently we only support whole rows, making
1720 // rectangular slices. This could be extended to arbitrary runs of
1721 // blocks, but since slices tend to be a conformance requirement and
1722 // most cases (such as broadcast or bluray) want rectangular slices
1723 // only it would need to be gated behind another option.
1724 if (avctx->slices > ctx->slice_block_rows) {
1725 av_log(avctx, AV_LOG_WARNING, "Not enough rows to use "
1726 "configured number of slices (%d < %d); using "
1727 "maximum.\n", ctx->slice_block_rows, avctx->slices);
1728 req_slices = ctx->slice_block_rows;
1729 } else {
1730 req_slices = avctx->slices;
1731 }
1732 if (slice_structure & VA_ENC_SLICE_STRUCTURE_ARBITRARY_ROWS ||
1733 slice_structure & VA_ENC_SLICE_STRUCTURE_ARBITRARY_MACROBLOCKS) {
1734 ctx->nb_slices = req_slices;
1735 ctx->slice_size = ctx->slice_block_rows / ctx->nb_slices;
1736 } else if (slice_structure & VA_ENC_SLICE_STRUCTURE_POWER_OF_TWO_ROWS) {
1737 int k;
1738 for (k = 1;; k *= 2) {
1739 if (2 * k * (req_slices - 1) + 1 >= ctx->slice_block_rows)
1740 break;
1741 }
1742 ctx->nb_slices = (ctx->slice_block_rows + k - 1) / k;
1743 ctx->slice_size = k;
1744 #if VA_CHECK_VERSION(1, 0, 0)
1745 } else if (slice_structure & VA_ENC_SLICE_STRUCTURE_EQUAL_ROWS) {
1746 ctx->nb_slices = ctx->slice_block_rows;
1747 ctx->slice_size = 1;
1748 #endif
1749 } else {
1750 av_log(avctx, AV_LOG_ERROR, "Driver does not support any usable "
1751 "slice structure modes (%#x).\n", slice_structure);
1752 return AVERROR(EINVAL);
1753 }
1754
1755 return 0;
1756 }
1757
1758 static av_cold int vaapi_encode_init_tile_slice_structure(AVCodecContext *avctx,
1759 uint32_t slice_structure)
1760 {
1761 VAAPIEncodeContext *ctx = avctx->priv_data;
1762 int i, req_tiles;
1763
1764 if (!(slice_structure & VA_ENC_SLICE_STRUCTURE_ARBITRARY_MACROBLOCKS ||
1765 (slice_structure & VA_ENC_SLICE_STRUCTURE_ARBITRARY_ROWS &&
1766 ctx->tile_cols == 1))) {
1767 av_log(avctx, AV_LOG_ERROR, "Supported slice structure (%#x) doesn't work for "
1768 "current tile requirement.\n", slice_structure);
1769 return AVERROR(EINVAL);
1770 }
1771
1772 if (ctx->tile_rows > ctx->slice_block_rows ||
1773 ctx->tile_cols > ctx->slice_block_cols) {
1774 av_log(avctx, AV_LOG_WARNING, "Not enough block rows/cols (%d x %d) "
1775 "for configured number of tile (%d x %d); ",
1776 ctx->slice_block_rows, ctx->slice_block_cols,
1777 ctx->tile_rows, ctx->tile_cols);
1778 ctx->tile_rows = ctx->tile_rows > ctx->slice_block_rows ?
1779 ctx->slice_block_rows : ctx->tile_rows;
1780 ctx->tile_cols = ctx->tile_cols > ctx->slice_block_cols ?
1781 ctx->slice_block_cols : ctx->tile_cols;
1782 av_log(avctx, AV_LOG_WARNING, "using allowed maximum (%d x %d).\n",
1783 ctx->tile_rows, ctx->tile_cols);
1784 }
1785
1786 req_tiles = ctx->tile_rows * ctx->tile_cols;
1787
1788 // Tile slice is not allowed to cross the boundary of a tile due to
1789 // the constraints of media-driver. Currently we support one slice
1790 // per tile. This could be extended to multiple slices per tile.
1791 if (avctx->slices != req_tiles)
1792 av_log(avctx, AV_LOG_WARNING, "The number of requested slices "
1793 "mismatches with configured number of tile (%d != %d); "
1794 "using requested tile number for slice.\n",
1795 avctx->slices, req_tiles);
1796
1797 ctx->nb_slices = req_tiles;
1798
1799 // Default in uniform spacing
1800 // 6-3, 6-5
1801 for (i = 0; i < ctx->tile_cols; i++) {
1802 ctx->col_width[i] = ( i + 1 ) * ctx->slice_block_cols / ctx->tile_cols -
1803 i * ctx->slice_block_cols / ctx->tile_cols;
1804 ctx->col_bd[i + 1] = ctx->col_bd[i] + ctx->col_width[i];
1805 }
1806 // 6-4, 6-6
1807 for (i = 0; i < ctx->tile_rows; i++) {
1808 ctx->row_height[i] = ( i + 1 ) * ctx->slice_block_rows / ctx->tile_rows -
1809 i * ctx->slice_block_rows / ctx->tile_rows;
1810 ctx->row_bd[i + 1] = ctx->row_bd[i] + ctx->row_height[i];
1811 }
1812
1813 av_log(avctx, AV_LOG_VERBOSE, "Encoding pictures with %d x %d tile.\n",
1814 ctx->tile_rows, ctx->tile_cols);
1815
1816 return 0;
1817 }
1818
1819 static av_cold int vaapi_encode_init_slice_structure(AVCodecContext *avctx)
1820 {
1821 FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
1822 VAAPIEncodeContext *ctx = avctx->priv_data;
1823 VAConfigAttrib attr[3] = { { VAConfigAttribEncMaxSlices },
1824 { VAConfigAttribEncSliceStructure },
1825 #if VA_CHECK_VERSION(1, 1, 0)
1826 { VAConfigAttribEncTileSupport },
1827 #endif
1828 };
1829 VAStatus vas;
1830 uint32_t max_slices, slice_structure;
1831 int ret;
1832
1833 if (!(ctx->codec->flags & FF_HW_FLAG_SLICE_CONTROL)) {
1834 if (avctx->slices > 0) {
1835 av_log(avctx, AV_LOG_WARNING, "Multiple slices were requested "
1836 "but this codec does not support controlling slices.\n");
1837 }
1838 return 0;
1839 }
1840
1841 av_assert0(base_ctx->slice_block_height > 0 && base_ctx->slice_block_width > 0);
1842
1843 ctx->slice_block_rows = (avctx->height + base_ctx->slice_block_height - 1) /
1844 base_ctx->slice_block_height;
1845 ctx->slice_block_cols = (avctx->width + base_ctx->slice_block_width - 1) /
1846 base_ctx->slice_block_width;
1847
1848 if (avctx->slices <= 1 && !ctx->tile_rows && !ctx->tile_cols) {
1849 ctx->nb_slices = 1;
1850 ctx->slice_size = ctx->slice_block_rows;
1851 return 0;
1852 }
1853
1854 vas = vaGetConfigAttributes(ctx->hwctx->display,
1855 ctx->va_profile,
1856 ctx->va_entrypoint,
1857 attr, FF_ARRAY_ELEMS(attr));
1858 if (vas != VA_STATUS_SUCCESS) {
1859 av_log(avctx, AV_LOG_ERROR, "Failed to query slice "
1860 "attributes: %d (%s).\n", vas, vaErrorStr(vas));
1861 return AVERROR_EXTERNAL;
1862 }
1863 max_slices = attr[0].value;
1864 slice_structure = attr[1].value;
1865 if (max_slices == VA_ATTRIB_NOT_SUPPORTED ||
1866 slice_structure == VA_ATTRIB_NOT_SUPPORTED) {
1867 av_log(avctx, AV_LOG_ERROR, "Driver does not support encoding "
1868 "pictures as multiple slices.\n.");
1869 return AVERROR(EINVAL);
1870 }
1871
1872 if (ctx->tile_rows && ctx->tile_cols) {
1873 #if VA_CHECK_VERSION(1, 1, 0)
1874 uint32_t tile_support = attr[2].value;
1875 if (tile_support == VA_ATTRIB_NOT_SUPPORTED) {
1876 av_log(avctx, AV_LOG_ERROR, "Driver does not support encoding "
1877 "pictures as multiple tiles.\n.");
1878 return AVERROR(EINVAL);
1879 }
1880 #else
1881 av_log(avctx, AV_LOG_ERROR, "Tile encoding option is "
1882 "not supported with this VAAPI version.\n");
1883 return AVERROR(EINVAL);
1884 #endif
1885 }
1886
1887 if (ctx->tile_rows && ctx->tile_cols)
1888 ret = vaapi_encode_init_tile_slice_structure(avctx, slice_structure);
1889 else
1890 ret = vaapi_encode_init_row_slice_structure(avctx, slice_structure);
1891 if (ret < 0)
1892 return ret;
1893
1894 if (ctx->nb_slices > avctx->slices) {
1895 av_log(avctx, AV_LOG_WARNING, "Slice count rounded up to "
1896 "%d (from %d) due to driver constraints on slice "
1897 "structure.\n", ctx->nb_slices, avctx->slices);
1898 }
1899 if (ctx->nb_slices > max_slices) {
1900 av_log(avctx, AV_LOG_ERROR, "Driver does not support "
1901 "encoding with %d slices (max %"PRIu32").\n",
1902 ctx->nb_slices, max_slices);
1903 return AVERROR(EINVAL);
1904 }
1905
1906 av_log(avctx, AV_LOG_VERBOSE, "Encoding pictures with %d slices.\n",
1907 ctx->nb_slices);
1908 return 0;
1909 }
1910
1911 static av_cold int vaapi_encode_init_packed_headers(AVCodecContext *avctx)
1912 {
1913 VAAPIEncodeContext *ctx = avctx->priv_data;
1914 VAStatus vas;
1915 VAConfigAttrib attr = { VAConfigAttribEncPackedHeaders };
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 packed headers "
1923 "attribute: %d (%s).\n", vas, vaErrorStr(vas));
1924 return AVERROR_EXTERNAL;
1925 }
1926
1927 if (attr.value == VA_ATTRIB_NOT_SUPPORTED) {
1928 if (ctx->desired_packed_headers) {
1929 av_log(avctx, AV_LOG_WARNING, "Driver does not support any "
1930 "packed headers (wanted %#x).\n",
1931 ctx->desired_packed_headers);
1932 } else {
1933 av_log(avctx, AV_LOG_VERBOSE, "Driver does not support any "
1934 "packed headers (none wanted).\n");
1935 }
1936 ctx->va_packed_headers = 0;
1937 } else {
1938 if (ctx->desired_packed_headers & ~attr.value) {
1939 av_log(avctx, AV_LOG_WARNING, "Driver does not support some "
1940 "wanted packed headers (wanted %#x, found %#x).\n",
1941 ctx->desired_packed_headers, attr.value);
1942 } else {
1943 av_log(avctx, AV_LOG_VERBOSE, "All wanted packed headers "
1944 "available (wanted %#x, found %#x).\n",
1945 ctx->desired_packed_headers, attr.value);
1946 }
1947 ctx->va_packed_headers = ctx->desired_packed_headers & attr.value;
1948 }
1949
1950 if (ctx->va_packed_headers) {
1951 ctx->config_attributes[ctx->nb_config_attributes++] =
1952 (VAConfigAttrib) {
1953 .type = VAConfigAttribEncPackedHeaders,
1954 .value = ctx->va_packed_headers,
1955 };
1956 }
1957
1958 if ( (ctx->desired_packed_headers & VA_ENC_PACKED_HEADER_SEQUENCE) &&
1959 !(ctx->va_packed_headers & VA_ENC_PACKED_HEADER_SEQUENCE) &&
1960 (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER)) {
1961 av_log(avctx, AV_LOG_WARNING, "Driver does not support packed "
1962 "sequence headers, but a global header is requested.\n");
1963 av_log(avctx, AV_LOG_WARNING, "No global header will be written: "
1964 "this may result in a stream which is not usable for some "
1965 "purposes (e.g. not muxable to some containers).\n");
1966 }
1967
1968 return 0;
1969 }
1970
1971 static av_cold int vaapi_encode_init_quality(AVCodecContext *avctx)
1972 {
1973 #if VA_CHECK_VERSION(0, 36, 0)
1974 VAAPIEncodeContext *ctx = avctx->priv_data;
1975 VAStatus vas;
1976 VAConfigAttrib attr = { VAConfigAttribEncQualityRange };
1977 int quality = avctx->compression_level;
1978
1979 vas = vaGetConfigAttributes(ctx->hwctx->display,
1980 ctx->va_profile,
1981 ctx->va_entrypoint,
1982 &attr, 1);
1983 if (vas != VA_STATUS_SUCCESS) {
1984 av_log(avctx, AV_LOG_ERROR, "Failed to query quality "
1985 "config attribute: %d (%s).\n", vas, vaErrorStr(vas));
1986 return AVERROR_EXTERNAL;
1987 }
1988
1989 if (attr.value == VA_ATTRIB_NOT_SUPPORTED) {
1990 if (quality != 0) {
1991 av_log(avctx, AV_LOG_WARNING, "Quality attribute is not "
1992 "supported: will use default quality level.\n");
1993 }
1994 } else {
1995 if (quality > attr.value) {
1996 av_log(avctx, AV_LOG_WARNING, "Invalid quality level: "
1997 "valid range is 0-%d, using %d.\n",
1998 attr.value, attr.value);
1999 quality = attr.value;
2000 }
2001
2002 ctx->quality_params = (VAEncMiscParameterBufferQualityLevel) {
2003 .quality_level = quality,
2004 };
2005 vaapi_encode_add_global_param(avctx,
2006 VAEncMiscParameterTypeQualityLevel,
2007 &ctx->quality_params,
2008 sizeof(ctx->quality_params));
2009 }
2010 #else
2011 av_log(avctx, AV_LOG_WARNING, "The encode quality option is "
2012 "not supported with this VAAPI version.\n");
2013 #endif
2014
2015 return 0;
2016 }
2017
2018 static av_cold int vaapi_encode_init_roi(AVCodecContext *avctx)
2019 {
2020 #if VA_CHECK_VERSION(1, 0, 0)
2021 FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
2022 VAAPIEncodeContext *ctx = avctx->priv_data;
2023 VAStatus vas;
2024 VAConfigAttrib attr = { VAConfigAttribEncROI };
2025
2026 vas = vaGetConfigAttributes(ctx->hwctx->display,
2027 ctx->va_profile,
2028 ctx->va_entrypoint,
2029 &attr, 1);
2030 if (vas != VA_STATUS_SUCCESS) {
2031 av_log(avctx, AV_LOG_ERROR, "Failed to query ROI "
2032 "config attribute: %d (%s).\n", vas, vaErrorStr(vas));
2033 return AVERROR_EXTERNAL;
2034 }
2035
2036 if (attr.value == VA_ATTRIB_NOT_SUPPORTED) {
2037 base_ctx->roi_allowed = 0;
2038 } else {
2039 VAConfigAttribValEncROI roi = {
2040 .value = attr.value,
2041 };
2042
2043 ctx->roi_max_regions = roi.bits.num_roi_regions;
2044 base_ctx->roi_allowed = ctx->roi_max_regions > 0 &&
2045 (ctx->va_rc_mode == VA_RC_CQP ||
2046 roi.bits.roi_rc_qp_delta_support);
2047 }
2048 #endif
2049 return 0;
2050 }
2051
2052 static void vaapi_encode_free_output_buffer(AVRefStructOpaque opaque,
2053 void *obj)
2054 {
2055 AVCodecContext *avctx = opaque.nc;
2056 VAAPIEncodeContext *ctx = avctx->priv_data;
2057 VABufferID *buffer_id_ref = obj;
2058 VABufferID buffer_id = *buffer_id_ref;
2059
2060 vaDestroyBuffer(ctx->hwctx->display, buffer_id);
2061
2062 av_log(avctx, AV_LOG_DEBUG, "Freed output buffer %#x\n", buffer_id);
2063 }
2064
2065 static int vaapi_encode_alloc_output_buffer(AVRefStructOpaque opaque, void *obj)
2066 {
2067 AVCodecContext *avctx = opaque.nc;
2068 FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
2069 VAAPIEncodeContext *ctx = avctx->priv_data;
2070 VABufferID *buffer_id = obj;
2071 VAStatus vas;
2072
2073 // The output buffer size is fixed, so it needs to be large enough
2074 // to hold the largest possible compressed frame. We assume here
2075 // that the uncompressed frame plus some header data is an upper
2076 // bound on that.
2077 vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context,
2078 VAEncCodedBufferType,
2079 3 * base_ctx->surface_width * base_ctx->surface_height +
2080 (1 << 16), 1, 0, buffer_id);
2081 if (vas != VA_STATUS_SUCCESS) {
2082 av_log(avctx, AV_LOG_ERROR, "Failed to create bitstream "
2083 "output buffer: %d (%s).\n", vas, vaErrorStr(vas));
2084 return AVERROR(ENOMEM);
2085 }
2086
2087 av_log(avctx, AV_LOG_DEBUG, "Allocated output buffer %#x\n", *buffer_id);
2088
2089 return 0;
2090 }
2091
2092 static av_cold int vaapi_encode_create_recon_frames(AVCodecContext *avctx)
2093 {
2094 FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
2095 VAAPIEncodeContext *ctx = avctx->priv_data;
2096 AVVAAPIHWConfig *hwconfig = NULL;
2097 enum AVPixelFormat recon_format;
2098 int err;
2099
2100 hwconfig = av_hwdevice_hwconfig_alloc(base_ctx->device_ref);
2101 if (!hwconfig) {
2102 err = AVERROR(ENOMEM);
2103 goto fail;
2104 }
2105 hwconfig->config_id = ctx->va_config;
2106
2107 err = ff_hw_base_get_recon_format(base_ctx, (const void*)hwconfig, &recon_format);
2108 if (err < 0)
2109 goto fail;
2110
2111 base_ctx->recon_frames_ref = av_hwframe_ctx_alloc(base_ctx->device_ref);
2112 if (!base_ctx->recon_frames_ref) {
2113 err = AVERROR(ENOMEM);
2114 goto fail;
2115 }
2116 base_ctx->recon_frames = (AVHWFramesContext*)base_ctx->recon_frames_ref->data;
2117
2118 base_ctx->recon_frames->format = AV_PIX_FMT_VAAPI;
2119 base_ctx->recon_frames->sw_format = recon_format;
2120 base_ctx->recon_frames->width = base_ctx->surface_width;
2121 base_ctx->recon_frames->height = base_ctx->surface_height;
2122
2123 err = av_hwframe_ctx_init(base_ctx->recon_frames_ref);
2124 if (err < 0) {
2125 av_log(avctx, AV_LOG_ERROR, "Failed to initialise reconstructed "
2126 "frame context: %d.\n", err);
2127 goto fail;
2128 }
2129
2130 err = 0;
2131 fail:
2132 av_freep(&hwconfig);
2133 return err;
2134 }
2135
2136 static const FFHWEncodePictureOperation vaapi_op = {
2137 .priv_size = sizeof(VAAPIEncodePicture),
2138
2139 .init = &vaapi_encode_init,
2140
2141 .issue = &vaapi_encode_issue,
2142
2143 .output = &vaapi_encode_output,
2144
2145 .free = &vaapi_encode_free,
2146 };
2147
2148 int ff_vaapi_encode_receive_packet(AVCodecContext *avctx, AVPacket *pkt)
2149 {
2150 return ff_hw_base_encode_receive_packet(avctx->priv_data, avctx, pkt);
2151 }
2152
2153 av_cold int ff_vaapi_encode_init(AVCodecContext *avctx)
2154 {
2155 FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
2156 VAAPIEncodeContext *ctx = avctx->priv_data;
2157 AVVAAPIFramesContext *recon_hwctx = NULL;
2158 VAStatus vas;
2159 int err;
2160
2161 err = ff_hw_base_encode_init(avctx, base_ctx);
2162 if (err < 0)
2163 goto fail;
2164
2165 ctx->va_config = VA_INVALID_ID;
2166 ctx->va_context = VA_INVALID_ID;
2167
2168 base_ctx->op = &vaapi_op;
2169
2170 ctx->hwctx = base_ctx->device->hwctx;
2171
2172 err = vaapi_encode_profile_entrypoint(avctx);
2173 if (err < 0)
2174 goto fail;
2175
2176 err = vaapi_encode_surface_alignment(avctx);
2177 if (err < 0)
2178 goto fail;
2179
2180 if (ctx->codec->get_encoder_caps) {
2181 err = ctx->codec->get_encoder_caps(avctx);
2182 if (err < 0)
2183 goto fail;
2184 } else {
2185 // Assume 16x16 blocks.
2186 base_ctx->surface_width = FFALIGN(avctx->width, 16);
2187 base_ctx->surface_height = FFALIGN(avctx->height, 16);
2188 if (ctx->codec->flags & FF_HW_FLAG_SLICE_CONTROL) {
2189 base_ctx->slice_block_width = 16;
2190 base_ctx->slice_block_height = 16;
2191 }
2192 }
2193
2194 err = vaapi_encode_init_rate_control(avctx);
2195 if (err < 0)
2196 goto fail;
2197
2198 err = vaapi_encode_init_gop_structure(avctx);
2199 if (err < 0)
2200 goto fail;
2201
2202 err = vaapi_encode_init_slice_structure(avctx);
2203 if (err < 0)
2204 goto fail;
2205
2206 err = vaapi_encode_init_packed_headers(avctx);
2207 if (err < 0)
2208 goto fail;
2209
2210 err = vaapi_encode_init_roi(avctx);
2211 if (err < 0)
2212 goto fail;
2213
2214 if (avctx->compression_level >= 0) {
2215 err = vaapi_encode_init_quality(avctx);
2216 if (err < 0)
2217 goto fail;
2218 }
2219
2220 if (ctx->max_frame_size) {
2221 err = vaapi_encode_init_max_frame_size(avctx);
2222 if (err < 0)
2223 goto fail;
2224 }
2225
2226 vas = vaCreateConfig(ctx->hwctx->display,
2227 ctx->va_profile, ctx->va_entrypoint,
2228 ctx->config_attributes, ctx->nb_config_attributes,
2229 &ctx->va_config);
2230 if (vas != VA_STATUS_SUCCESS) {
2231 av_log(avctx, AV_LOG_ERROR, "Failed to create encode pipeline "
2232 "configuration: %d (%s).\n", vas, vaErrorStr(vas));
2233 err = AVERROR(EIO);
2234 goto fail;
2235 }
2236
2237 err = vaapi_encode_create_recon_frames(avctx);
2238 if (err < 0)
2239 goto fail;
2240
2241 recon_hwctx = base_ctx->recon_frames->hwctx;
2242 vas = vaCreateContext(ctx->hwctx->display, ctx->va_config,
2243 base_ctx->surface_width, base_ctx->surface_height,
2244 VA_PROGRESSIVE,
2245 recon_hwctx->surface_ids,
2246 recon_hwctx->nb_surfaces,
2247 &ctx->va_context);
2248 if (vas != VA_STATUS_SUCCESS) {
2249 av_log(avctx, AV_LOG_ERROR, "Failed to create encode pipeline "
2250 "context: %d (%s).\n", vas, vaErrorStr(vas));
2251 err = AVERROR(EIO);
2252 goto fail;
2253 }
2254
2255 ctx->output_buffer_pool =
2256 av_refstruct_pool_alloc_ext(sizeof(VABufferID), 0, avctx,
2257 &vaapi_encode_alloc_output_buffer, NULL,
2258 vaapi_encode_free_output_buffer, NULL);
2259 if (!ctx->output_buffer_pool) {
2260 err = AVERROR(ENOMEM);
2261 goto fail;
2262 }
2263
2264 if (ctx->codec->configure) {
2265 err = ctx->codec->configure(avctx);
2266 if (err < 0)
2267 goto fail;
2268 }
2269
2270 base_ctx->output_delay = base_ctx->b_per_p;
2271 base_ctx->decode_delay = base_ctx->max_b_depth;
2272
2273 if (ctx->codec->sequence_params_size > 0) {
2274 ctx->codec_sequence_params =
2275 av_mallocz(ctx->codec->sequence_params_size);
2276 if (!ctx->codec_sequence_params) {
2277 err = AVERROR(ENOMEM);
2278 goto fail;
2279 }
2280 }
2281 if (ctx->codec->picture_params_size > 0) {
2282 ctx->codec_picture_params =
2283 av_mallocz(ctx->codec->picture_params_size);
2284 if (!ctx->codec_picture_params) {
2285 err = AVERROR(ENOMEM);
2286 goto fail;
2287 }
2288 }
2289
2290 if (ctx->codec->init_sequence_params) {
2291 err = ctx->codec->init_sequence_params(avctx);
2292 if (err < 0) {
2293 av_log(avctx, AV_LOG_ERROR, "Codec sequence initialisation "
2294 "failed: %d.\n", err);
2295 goto fail;
2296 }
2297 }
2298
2299 if (ctx->va_packed_headers & VA_ENC_PACKED_HEADER_SEQUENCE &&
2300 ctx->codec->write_sequence_header &&
2301 avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) {
2302 char data[MAX_PARAM_BUFFER_SIZE];
2303 size_t bit_len = 8 * sizeof(data);
2304
2305 err = ctx->codec->write_sequence_header(avctx, data, &bit_len);
2306 if (err < 0) {
2307 av_log(avctx, AV_LOG_ERROR, "Failed to write sequence header "
2308 "for extradata: %d.\n", err);
2309 goto fail;
2310 } else {
2311 avctx->extradata_size = (bit_len + 7) / 8;
2312 avctx->extradata = av_mallocz(avctx->extradata_size +
2313 AV_INPUT_BUFFER_PADDING_SIZE);
2314 if (!avctx->extradata) {
2315 err = AVERROR(ENOMEM);
2316 goto fail;
2317 }
2318 memcpy(avctx->extradata, data, avctx->extradata_size);
2319 }
2320 }
2321
2322 #if VA_CHECK_VERSION(1, 9, 0)
2323 // check vaSyncBuffer function
2324 vas = vaSyncBuffer(ctx->hwctx->display, VA_INVALID_ID, 0);
2325 if (vas != VA_STATUS_ERROR_UNIMPLEMENTED) {
2326 base_ctx->async_encode = 1;
2327 base_ctx->encode_fifo = av_fifo_alloc2(base_ctx->async_depth,
2328 sizeof(VAAPIEncodePicture*),
2329 0);
2330 if (!base_ctx->encode_fifo)
2331 return AVERROR(ENOMEM);
2332 }
2333 #endif
2334
2335 return 0;
2336
2337 fail:
2338 return err;
2339 }
2340
2341 av_cold int ff_vaapi_encode_close(AVCodecContext *avctx)
2342 {
2343 FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
2344 VAAPIEncodeContext *ctx = avctx->priv_data;
2345 FFHWBaseEncodePicture *pic, *next;
2346
2347 /* We check ctx->frame to know whether ff_vaapi_encode_init()
2348 * has been called and va_config/va_context initialized. */
2349 if (!base_ctx->frame)
2350 return 0;
2351
2352 for (pic = base_ctx->pic_start; pic; pic = next) {
2353 next = pic->next;
2354 vaapi_encode_free(avctx, pic);
2355 }
2356
2357 av_refstruct_pool_uninit(&ctx->output_buffer_pool);
2358
2359 if (ctx->va_context != VA_INVALID_ID) {
2360 if (ctx->hwctx)
2361 vaDestroyContext(ctx->hwctx->display, ctx->va_context);
2362 ctx->va_context = VA_INVALID_ID;
2363 }
2364
2365 if (ctx->va_config != VA_INVALID_ID) {
2366 if (ctx->hwctx)
2367 vaDestroyConfig(ctx->hwctx->display, ctx->va_config);
2368 ctx->va_config = VA_INVALID_ID;
2369 }
2370
2371 av_freep(&ctx->codec_sequence_params);
2372 av_freep(&ctx->codec_picture_params);
2373
2374 ff_hw_base_encode_close(base_ctx);
2375
2376 return 0;
2377 }
2378