FFmpeg coverage


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