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 <string.h>
20
21 #include "libavutil/avassert.h"
22 #include "libavutil/pixdesc.h"
23 #include "formats.h"
24 #include "internal.h"
25 #include "vaapi_vpp.h"
26
ff_vaapi_vpp_query_formats(AVFilterContext * avctx)27 int ff_vaapi_vpp_query_formats(AVFilterContext *avctx)
28 {
29 enum AVPixelFormat pix_fmts[] = {
30 AV_PIX_FMT_VAAPI, AV_PIX_FMT_NONE,
31 };
32 int err;
33
34 if ((err = ff_formats_ref(ff_make_format_list(pix_fmts),
35 &avctx->inputs[0]->outcfg.formats)) < 0)
36 return err;
37 if ((err = ff_formats_ref(ff_make_format_list(pix_fmts),
38 &avctx->outputs[0]->incfg.formats)) < 0)
39 return err;
40
41 return 0;
42 }
43
ff_vaapi_vpp_pipeline_uninit(AVFilterContext * avctx)44 void ff_vaapi_vpp_pipeline_uninit(AVFilterContext *avctx)
45 {
46 VAAPIVPPContext *ctx = avctx->priv;
47 int i;
48 for (i = 0; i < ctx->nb_filter_buffers; i++) {
49 if (ctx->filter_buffers[i] != VA_INVALID_ID) {
50 vaDestroyBuffer(ctx->hwctx->display, ctx->filter_buffers[i]);
51 ctx->filter_buffers[i] = VA_INVALID_ID;
52 }
53 }
54 ctx->nb_filter_buffers = 0;
55
56 if (ctx->va_context != VA_INVALID_ID) {
57 vaDestroyContext(ctx->hwctx->display, ctx->va_context);
58 ctx->va_context = VA_INVALID_ID;
59 }
60
61 if (ctx->va_config != VA_INVALID_ID) {
62 vaDestroyConfig(ctx->hwctx->display, ctx->va_config);
63 ctx->va_config = VA_INVALID_ID;
64 }
65
66 av_buffer_unref(&ctx->device_ref);
67 ctx->hwctx = NULL;
68 }
69
ff_vaapi_vpp_config_input(AVFilterLink * inlink)70 int ff_vaapi_vpp_config_input(AVFilterLink *inlink)
71 {
72 AVFilterContext *avctx = inlink->dst;
73 VAAPIVPPContext *ctx = avctx->priv;
74
75 if (ctx->pipeline_uninit)
76 ctx->pipeline_uninit(avctx);
77
78 if (!inlink->hw_frames_ctx) {
79 av_log(avctx, AV_LOG_ERROR, "A hardware frames reference is "
80 "required to associate the processing device.\n");
81 return AVERROR(EINVAL);
82 }
83
84 ctx->input_frames_ref = av_buffer_ref(inlink->hw_frames_ctx);
85 if (!ctx->input_frames_ref) {
86 av_log(avctx, AV_LOG_ERROR, "A input frames reference create "
87 "failed.\n");
88 return AVERROR(ENOMEM);
89 }
90 ctx->input_frames = (AVHWFramesContext*)ctx->input_frames_ref->data;
91
92 return 0;
93 }
94
ff_vaapi_vpp_config_output(AVFilterLink * outlink)95 int ff_vaapi_vpp_config_output(AVFilterLink *outlink)
96 {
97 AVFilterContext *avctx = outlink->src;
98 VAAPIVPPContext *ctx = avctx->priv;
99 AVVAAPIHWConfig *hwconfig = NULL;
100 AVHWFramesConstraints *constraints = NULL;
101 AVHWFramesContext *output_frames;
102 AVVAAPIFramesContext *va_frames;
103 VAStatus vas;
104 int err, i;
105
106 if (ctx->pipeline_uninit)
107 ctx->pipeline_uninit(avctx);
108
109 if (!ctx->output_width)
110 ctx->output_width = avctx->inputs[0]->w;
111 if (!ctx->output_height)
112 ctx->output_height = avctx->inputs[0]->h;
113
114 av_assert0(ctx->input_frames);
115 ctx->device_ref = av_buffer_ref(ctx->input_frames->device_ref);
116 if (!ctx->device_ref) {
117 av_log(avctx, AV_LOG_ERROR, "A device reference create "
118 "failed.\n");
119 return AVERROR(ENOMEM);
120 }
121 ctx->hwctx = ((AVHWDeviceContext*)ctx->device_ref->data)->hwctx;
122
123 av_assert0(ctx->va_config == VA_INVALID_ID);
124 vas = vaCreateConfig(ctx->hwctx->display, VAProfileNone,
125 VAEntrypointVideoProc, NULL, 0, &ctx->va_config);
126 if (vas != VA_STATUS_SUCCESS) {
127 av_log(avctx, AV_LOG_ERROR, "Failed to create processing pipeline "
128 "config: %d (%s).\n", vas, vaErrorStr(vas));
129 err = AVERROR(EIO);
130 goto fail;
131 }
132
133 hwconfig = av_hwdevice_hwconfig_alloc(ctx->device_ref);
134 if (!hwconfig) {
135 err = AVERROR(ENOMEM);
136 goto fail;
137 }
138 hwconfig->config_id = ctx->va_config;
139
140 constraints = av_hwdevice_get_hwframe_constraints(ctx->device_ref,
141 hwconfig);
142 if (!constraints) {
143 err = AVERROR(ENOMEM);
144 goto fail;
145 }
146
147 if (ctx->output_format == AV_PIX_FMT_NONE)
148 ctx->output_format = ctx->input_frames->sw_format;
149 if (constraints->valid_sw_formats) {
150 for (i = 0; constraints->valid_sw_formats[i] != AV_PIX_FMT_NONE; i++) {
151 if (ctx->output_format == constraints->valid_sw_formats[i])
152 break;
153 }
154 if (constraints->valid_sw_formats[i] == AV_PIX_FMT_NONE) {
155 av_log(avctx, AV_LOG_ERROR, "Hardware does not support output "
156 "format %s.\n", av_get_pix_fmt_name(ctx->output_format));
157 err = AVERROR(EINVAL);
158 goto fail;
159 }
160 }
161
162 if (ctx->output_width < constraints->min_width ||
163 ctx->output_height < constraints->min_height ||
164 ctx->output_width > constraints->max_width ||
165 ctx->output_height > constraints->max_height) {
166 av_log(avctx, AV_LOG_ERROR, "Hardware does not support scaling to "
167 "size %dx%d (constraints: width %d-%d height %d-%d).\n",
168 ctx->output_width, ctx->output_height,
169 constraints->min_width, constraints->max_width,
170 constraints->min_height, constraints->max_height);
171 err = AVERROR(EINVAL);
172 goto fail;
173 }
174
175 outlink->hw_frames_ctx = av_hwframe_ctx_alloc(ctx->device_ref);
176 if (!outlink->hw_frames_ctx) {
177 av_log(avctx, AV_LOG_ERROR, "Failed to create HW frame context "
178 "for output.\n");
179 err = AVERROR(ENOMEM);
180 goto fail;
181 }
182
183 output_frames = (AVHWFramesContext*)outlink->hw_frames_ctx->data;
184
185 output_frames->format = AV_PIX_FMT_VAAPI;
186 output_frames->sw_format = ctx->output_format;
187 output_frames->width = ctx->output_width;
188 output_frames->height = ctx->output_height;
189
190 output_frames->initial_pool_size = 4;
191
192 err = ff_filter_init_hw_frames(avctx, outlink, 10);
193 if (err < 0)
194 goto fail;
195
196 err = av_hwframe_ctx_init(outlink->hw_frames_ctx);
197 if (err < 0) {
198 av_log(avctx, AV_LOG_ERROR, "Failed to initialise VAAPI frame "
199 "context for output: %d\n", err);
200 goto fail;
201 }
202
203 va_frames = output_frames->hwctx;
204
205 av_assert0(ctx->va_context == VA_INVALID_ID);
206 vas = vaCreateContext(ctx->hwctx->display, ctx->va_config,
207 ctx->output_width, ctx->output_height,
208 VA_PROGRESSIVE,
209 va_frames->surface_ids, va_frames->nb_surfaces,
210 &ctx->va_context);
211 if (vas != VA_STATUS_SUCCESS) {
212 av_log(avctx, AV_LOG_ERROR, "Failed to create processing pipeline "
213 "context: %d (%s).\n", vas, vaErrorStr(vas));
214 return AVERROR(EIO);
215 }
216
217 outlink->w = ctx->output_width;
218 outlink->h = ctx->output_height;
219
220 if (ctx->build_filter_params) {
221 err = ctx->build_filter_params(avctx);
222 if (err < 0)
223 goto fail;
224 }
225
226 av_freep(&hwconfig);
227 av_hwframe_constraints_free(&constraints);
228 return 0;
229
230 fail:
231 av_buffer_unref(&outlink->hw_frames_ctx);
232 av_freep(&hwconfig);
233 av_hwframe_constraints_free(&constraints);
234 return err;
235 }
236
237 typedef struct VAAPIColourProperties {
238 VAProcColorStandardType va_color_standard;
239
240 enum AVColorPrimaries color_primaries;
241 enum AVColorTransferCharacteristic color_trc;
242 enum AVColorSpace colorspace;
243
244 uint8_t va_chroma_sample_location;
245 uint8_t va_color_range;
246
247 enum AVColorRange color_range;
248 enum AVChromaLocation chroma_sample_location;
249 } VAAPIColourProperties;
250
251 static const VAAPIColourProperties vaapi_colour_standard_map[] = {
252 { VAProcColorStandardBT601, 5, 6, 5 },
253 { VAProcColorStandardBT601, 6, 6, 6 },
254 { VAProcColorStandardBT709, 1, 1, 1 },
255 { VAProcColorStandardBT470M, 4, 4, 4 },
256 { VAProcColorStandardBT470BG, 5, 5, 5 },
257 { VAProcColorStandardSMPTE170M, 6, 6, 6 },
258 { VAProcColorStandardSMPTE240M, 7, 7, 7 },
259 { VAProcColorStandardGenericFilm, 8, 1, 1 },
260 #if VA_CHECK_VERSION(1, 1, 0)
261 { VAProcColorStandardSRGB, 1, 13, 0 },
262 { VAProcColorStandardXVYCC601, 1, 11, 5 },
263 { VAProcColorStandardXVYCC709, 1, 11, 1 },
264 { VAProcColorStandardBT2020, 9, 14, 9 },
265 #endif
266 };
267
vaapi_vpp_fill_colour_standard(VAAPIColourProperties * props,VAProcColorStandardType * vacs,int nb_vacs)268 static void vaapi_vpp_fill_colour_standard(VAAPIColourProperties *props,
269 VAProcColorStandardType *vacs,
270 int nb_vacs)
271 {
272 const VAAPIColourProperties *t;
273 int i, j, score, best_score, worst_score;
274 VAProcColorStandardType best_standard;
275
276 #if VA_CHECK_VERSION(1, 3, 0)
277 // If the driver supports explicit use of the standard values then just
278 // use them and avoid doing any mapping. (The driver may not support
279 // some particular code point, but it still has enough information to
280 // make a better fallback choice than we do in that case.)
281 for (i = 0; i < nb_vacs; i++) {
282 if (vacs[i] == VAProcColorStandardExplicit) {
283 props->va_color_standard = VAProcColorStandardExplicit;
284 return;
285 }
286 }
287 #endif
288
289 // Give scores to the possible options and choose the lowest one.
290 // An exact match will score zero and therefore always be chosen, as
291 // will a partial match where all unmatched elements are explicitly
292 // unspecified. If no options match at all then just pass "none" to
293 // the driver and let it make its own choice.
294 best_standard = VAProcColorStandardNone;
295 best_score = -1;
296 worst_score = 4 * (props->colorspace != AVCOL_SPC_UNSPECIFIED &&
297 props->colorspace != AVCOL_SPC_RGB) +
298 2 * (props->color_trc != AVCOL_TRC_UNSPECIFIED) +
299 (props->color_primaries != AVCOL_PRI_UNSPECIFIED);
300
301 if (worst_score == 0) {
302 // No properties are specified, so we aren't going to be able to
303 // make a useful choice.
304 props->va_color_standard = VAProcColorStandardNone;
305 return;
306 }
307
308 for (i = 0; i < nb_vacs; i++) {
309 for (j = 0; j < FF_ARRAY_ELEMS(vaapi_colour_standard_map); j++) {
310 t = &vaapi_colour_standard_map[j];
311 if (t->va_color_standard != vacs[i])
312 continue;
313
314 score = 0;
315 if (props->colorspace != AVCOL_SPC_UNSPECIFIED &&
316 props->colorspace != AVCOL_SPC_RGB)
317 score += 4 * (props->colorspace != t->colorspace);
318 if (props->color_trc != AVCOL_TRC_UNSPECIFIED)
319 score += 2 * (props->color_trc != t->color_trc);
320 if (props->color_primaries != AVCOL_PRI_UNSPECIFIED)
321 score += (props->color_primaries != t->color_primaries);
322
323 // Only include choices which matched something.
324 if (score < worst_score &&
325 (best_score == -1 || score < best_score)) {
326 best_score = score;
327 best_standard = t->va_color_standard;
328 }
329 }
330 }
331 props->va_color_standard = best_standard;
332 }
333
vaapi_vpp_fill_chroma_sample_location(VAAPIColourProperties * props)334 static void vaapi_vpp_fill_chroma_sample_location(VAAPIColourProperties *props)
335 {
336 #if VA_CHECK_VERSION(1, 1, 0)
337 static const struct {
338 enum AVChromaLocation av;
339 uint8_t va;
340 } csl_map[] = {
341 { AVCHROMA_LOC_UNSPECIFIED, VA_CHROMA_SITING_UNKNOWN },
342 { AVCHROMA_LOC_LEFT, VA_CHROMA_SITING_VERTICAL_CENTER |
343 VA_CHROMA_SITING_HORIZONTAL_LEFT },
344 { AVCHROMA_LOC_CENTER, VA_CHROMA_SITING_VERTICAL_CENTER |
345 VA_CHROMA_SITING_HORIZONTAL_CENTER },
346 { AVCHROMA_LOC_TOPLEFT, VA_CHROMA_SITING_VERTICAL_TOP |
347 VA_CHROMA_SITING_HORIZONTAL_LEFT },
348 { AVCHROMA_LOC_TOP, VA_CHROMA_SITING_VERTICAL_TOP |
349 VA_CHROMA_SITING_HORIZONTAL_CENTER },
350 { AVCHROMA_LOC_BOTTOMLEFT, VA_CHROMA_SITING_VERTICAL_BOTTOM |
351 VA_CHROMA_SITING_HORIZONTAL_LEFT },
352 { AVCHROMA_LOC_BOTTOM, VA_CHROMA_SITING_VERTICAL_BOTTOM |
353 VA_CHROMA_SITING_HORIZONTAL_CENTER },
354 };
355 int i;
356
357 for (i = 0; i < FF_ARRAY_ELEMS(csl_map); i++) {
358 if (props->chroma_sample_location == csl_map[i].av) {
359 props->va_chroma_sample_location = csl_map[i].va;
360 return;
361 }
362 }
363 props->va_chroma_sample_location = VA_CHROMA_SITING_UNKNOWN;
364 #else
365 props->va_chroma_sample_location = 0;
366 #endif
367 }
368
vaapi_vpp_fill_colour_range(VAAPIColourProperties * props)369 static void vaapi_vpp_fill_colour_range(VAAPIColourProperties *props)
370 {
371 #if VA_CHECK_VERSION(1, 1, 0)
372 switch (props->color_range) {
373 case AVCOL_RANGE_MPEG:
374 props->va_color_range = VA_SOURCE_RANGE_REDUCED;
375 break;
376 case AVCOL_RANGE_JPEG:
377 props->va_color_range = VA_SOURCE_RANGE_FULL;
378 break;
379 case AVCOL_RANGE_UNSPECIFIED:
380 default:
381 props->va_color_range = VA_SOURCE_RANGE_UNKNOWN;
382 }
383 #else
384 props->va_color_range = 0;
385 #endif
386 }
387
vaapi_vpp_fill_colour_properties(AVFilterContext * avctx,VAAPIColourProperties * props,VAProcColorStandardType * vacs,int nb_vacs)388 static void vaapi_vpp_fill_colour_properties(AVFilterContext *avctx,
389 VAAPIColourProperties *props,
390 VAProcColorStandardType *vacs,
391 int nb_vacs)
392 {
393 vaapi_vpp_fill_colour_standard(props, vacs, nb_vacs);
394 vaapi_vpp_fill_chroma_sample_location(props);
395 vaapi_vpp_fill_colour_range(props);
396
397 av_log(avctx, AV_LOG_DEBUG, "Mapped colour properties %s %s/%s/%s %s "
398 "to VA standard %d chroma siting %#x range %#x.\n",
399 av_color_range_name(props->color_range),
400 av_color_space_name(props->colorspace),
401 av_color_primaries_name(props->color_primaries),
402 av_color_transfer_name(props->color_trc),
403 av_chroma_location_name(props->chroma_sample_location),
404 props->va_color_standard,
405 props->va_chroma_sample_location, props->va_color_range);
406 }
407
vaapi_vpp_frame_is_rgb(const AVFrame * frame)408 static int vaapi_vpp_frame_is_rgb(const AVFrame *frame)
409 {
410 const AVHWFramesContext *hwfc;
411 const AVPixFmtDescriptor *desc;
412 av_assert0(frame->format == AV_PIX_FMT_VAAPI &&
413 frame->hw_frames_ctx);
414 hwfc = (const AVHWFramesContext*)frame->hw_frames_ctx->data;
415 desc = av_pix_fmt_desc_get(hwfc->sw_format);
416 av_assert0(desc);
417 return !!(desc->flags & AV_PIX_FMT_FLAG_RGB);
418 }
419
vaapi_vpp_colour_properties(AVFilterContext * avctx,VAProcPipelineParameterBuffer * params,const AVFrame * input_frame,AVFrame * output_frame)420 static int vaapi_vpp_colour_properties(AVFilterContext *avctx,
421 VAProcPipelineParameterBuffer *params,
422 const AVFrame *input_frame,
423 AVFrame *output_frame)
424 {
425 VAAPIVPPContext *ctx = avctx->priv;
426 VAAPIColourProperties input_props, output_props;
427 VAProcPipelineCaps caps;
428 VAStatus vas;
429
430 vas = vaQueryVideoProcPipelineCaps(ctx->hwctx->display, ctx->va_context,
431 ctx->filter_buffers, ctx->nb_filter_buffers,
432 &caps);
433 if (vas != VA_STATUS_SUCCESS) {
434 av_log(avctx, AV_LOG_ERROR, "Failed to query capabilities for "
435 "colour standard support: %d (%s).\n", vas, vaErrorStr(vas));
436 return AVERROR_EXTERNAL;
437 }
438
439 input_props = (VAAPIColourProperties) {
440 .colorspace = vaapi_vpp_frame_is_rgb(input_frame)
441 ? AVCOL_SPC_RGB : input_frame->colorspace,
442 .color_primaries = input_frame->color_primaries,
443 .color_trc = input_frame->color_trc,
444 .color_range = input_frame->color_range,
445 .chroma_sample_location = input_frame->chroma_location,
446 };
447
448 vaapi_vpp_fill_colour_properties(avctx, &input_props,
449 caps.input_color_standards,
450 caps.num_input_color_standards);
451
452 output_props = (VAAPIColourProperties) {
453 .colorspace = vaapi_vpp_frame_is_rgb(output_frame)
454 ? AVCOL_SPC_RGB : output_frame->colorspace,
455 .color_primaries = output_frame->color_primaries,
456 .color_trc = output_frame->color_trc,
457 .color_range = output_frame->color_range,
458 .chroma_sample_location = output_frame->chroma_location,
459 };
460 vaapi_vpp_fill_colour_properties(avctx, &output_props,
461 caps.output_color_standards,
462 caps.num_output_color_standards);
463
464 // If the properties weren't filled completely in the output frame and
465 // we chose a fixed standard then fill the known values in here.
466 #if VA_CHECK_VERSION(1, 3, 0)
467 if (output_props.va_color_standard != VAProcColorStandardExplicit)
468 #endif
469 {
470 const VAAPIColourProperties *output_standard = NULL;
471 int i;
472
473 for (i = 0; i < FF_ARRAY_ELEMS(vaapi_colour_standard_map); i++) {
474 if (output_props.va_color_standard ==
475 vaapi_colour_standard_map[i].va_color_standard) {
476 output_standard = &vaapi_colour_standard_map[i];
477 break;
478 }
479 }
480 if (output_standard) {
481 output_frame->colorspace = vaapi_vpp_frame_is_rgb(output_frame)
482 ? AVCOL_SPC_RGB : output_standard->colorspace;
483 output_frame->color_primaries = output_standard->color_primaries;
484 output_frame->color_trc = output_standard->color_trc;
485 }
486 }
487
488 params->surface_color_standard = input_props.va_color_standard;
489 params->output_color_standard = output_props.va_color_standard;
490
491 #if VA_CHECK_VERSION(1, 1, 0)
492 params->input_color_properties = (VAProcColorProperties) {
493 .chroma_sample_location = input_props.va_chroma_sample_location,
494 .color_range = input_props.va_color_range,
495 #if VA_CHECK_VERSION(1, 3, 0)
496 .colour_primaries = input_props.color_primaries,
497 .transfer_characteristics = input_props.color_trc,
498 .matrix_coefficients = input_props.colorspace,
499 #endif
500 };
501 params->output_color_properties = (VAProcColorProperties) {
502 .chroma_sample_location = output_props.va_chroma_sample_location,
503 .color_range = output_props.va_color_range,
504 #if VA_CHECK_VERSION(1, 3, 0)
505 .colour_primaries = output_props.color_primaries,
506 .transfer_characteristics = output_props.color_trc,
507 .matrix_coefficients = output_props.colorspace,
508 #endif
509 };
510 #endif
511
512 return 0;
513 }
514
ff_vaapi_vpp_init_params(AVFilterContext * avctx,VAProcPipelineParameterBuffer * params,const AVFrame * input_frame,AVFrame * output_frame)515 int ff_vaapi_vpp_init_params(AVFilterContext *avctx,
516 VAProcPipelineParameterBuffer *params,
517 const AVFrame *input_frame,
518 AVFrame *output_frame)
519 {
520 VAAPIVPPContext *ctx = avctx->priv;
521 VASurfaceID input_surface;
522 int err;
523
524 ctx->input_region = (VARectangle) {
525 .x = input_frame->crop_left,
526 .y = input_frame->crop_top,
527 .width = input_frame->width -
528 (input_frame->crop_left + input_frame->crop_right),
529 .height = input_frame->height -
530 (input_frame->crop_top + input_frame->crop_bottom),
531 };
532 output_frame->crop_top = 0;
533 output_frame->crop_bottom = 0;
534 output_frame->crop_left = 0;
535 output_frame->crop_right = 0;
536
537 input_surface = (VASurfaceID)(uintptr_t)input_frame->data[3],
538
539 *params = (VAProcPipelineParameterBuffer) {
540 .surface = input_surface,
541 .surface_region = &ctx->input_region,
542 .output_region = NULL,
543 .output_background_color = VAAPI_VPP_BACKGROUND_BLACK,
544 .pipeline_flags = 0,
545 .filter_flags = VA_FRAME_PICTURE,
546
547 // Filter and reference data filled by the filter itself.
548
549 #if VA_CHECK_VERSION(1, 1, 0)
550 .rotation_state = VA_ROTATION_NONE,
551 .mirror_state = VA_MIRROR_NONE,
552 #endif
553 };
554
555 err = vaapi_vpp_colour_properties(avctx, params,
556 input_frame, output_frame);
557 if (err < 0)
558 return err;
559
560 return 0;
561 }
562
ff_vaapi_vpp_make_param_buffers(AVFilterContext * avctx,int type,const void * data,size_t size,int count)563 int ff_vaapi_vpp_make_param_buffers(AVFilterContext *avctx,
564 int type,
565 const void *data,
566 size_t size,
567 int count)
568 {
569 VAStatus vas;
570 VABufferID buffer;
571 VAAPIVPPContext *ctx = avctx->priv;
572
573 av_assert0(ctx->nb_filter_buffers + 1 <= VAProcFilterCount);
574
575 vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context,
576 type, size, count, (void*)data, &buffer);
577 if (vas != VA_STATUS_SUCCESS) {
578 av_log(avctx, AV_LOG_ERROR, "Failed to create parameter "
579 "buffer (type %d): %d (%s).\n",
580 type, vas, vaErrorStr(vas));
581 return AVERROR(EIO);
582 }
583
584 ctx->filter_buffers[ctx->nb_filter_buffers++] = buffer;
585
586 av_log(avctx, AV_LOG_DEBUG, "Param buffer (type %d, %zu bytes, count %d) "
587 "is %#x.\n", type, size, count, buffer);
588 return 0;
589 }
590
591
ff_vaapi_vpp_render_picture(AVFilterContext * avctx,VAProcPipelineParameterBuffer * params,AVFrame * output_frame)592 int ff_vaapi_vpp_render_picture(AVFilterContext *avctx,
593 VAProcPipelineParameterBuffer *params,
594 AVFrame *output_frame)
595 {
596 VAAPIVPPContext *ctx = avctx->priv;
597 VASurfaceID output_surface;
598 VABufferID params_id;
599 VAStatus vas;
600 int err;
601
602 output_surface = (VASurfaceID)(uintptr_t)output_frame->data[3];
603
604 vas = vaBeginPicture(ctx->hwctx->display,
605 ctx->va_context, output_surface);
606 if (vas != VA_STATUS_SUCCESS) {
607 av_log(avctx, AV_LOG_ERROR, "Failed to attach new picture: "
608 "%d (%s).\n", vas, vaErrorStr(vas));
609 err = AVERROR(EIO);
610 goto fail;
611 }
612
613 vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context,
614 VAProcPipelineParameterBufferType,
615 sizeof(*params), 1, params, ¶ms_id);
616 if (vas != VA_STATUS_SUCCESS) {
617 av_log(avctx, AV_LOG_ERROR, "Failed to create parameter buffer: "
618 "%d (%s).\n", vas, vaErrorStr(vas));
619 err = AVERROR(EIO);
620 goto fail_after_begin;
621 }
622 av_log(avctx, AV_LOG_DEBUG, "Pipeline parameter buffer is %#x.\n",
623 params_id);
624
625 vas = vaRenderPicture(ctx->hwctx->display, ctx->va_context,
626 ¶ms_id, 1);
627 if (vas != VA_STATUS_SUCCESS) {
628 av_log(avctx, AV_LOG_ERROR, "Failed to render parameter buffer: "
629 "%d (%s).\n", vas, vaErrorStr(vas));
630 err = AVERROR(EIO);
631 goto fail_after_begin;
632 }
633
634 vas = vaEndPicture(ctx->hwctx->display, ctx->va_context);
635 if (vas != VA_STATUS_SUCCESS) {
636 av_log(avctx, AV_LOG_ERROR, "Failed to start picture processing: "
637 "%d (%s).\n", vas, vaErrorStr(vas));
638 err = AVERROR(EIO);
639 goto fail_after_render;
640 }
641
642 if (CONFIG_VAAPI_1 || ctx->hwctx->driver_quirks &
643 AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS) {
644 vas = vaDestroyBuffer(ctx->hwctx->display, params_id);
645 if (vas != VA_STATUS_SUCCESS) {
646 av_log(avctx, AV_LOG_ERROR, "Failed to free parameter buffer: "
647 "%d (%s).\n", vas, vaErrorStr(vas));
648 // And ignore.
649 }
650 }
651
652 return 0;
653
654 // We want to make sure that if vaBeginPicture has been called, we also
655 // call vaRenderPicture and vaEndPicture. These calls may well fail or
656 // do something else nasty, but once we're in this failure case there
657 // isn't much else we can do.
658 fail_after_begin:
659 vaRenderPicture(ctx->hwctx->display, ctx->va_context, ¶ms_id, 1);
660 fail_after_render:
661 vaEndPicture(ctx->hwctx->display, ctx->va_context);
662 fail:
663 return err;
664 }
665
ff_vaapi_vpp_ctx_init(AVFilterContext * avctx)666 void ff_vaapi_vpp_ctx_init(AVFilterContext *avctx)
667 {
668 int i;
669 VAAPIVPPContext *ctx = avctx->priv;
670
671 ctx->va_config = VA_INVALID_ID;
672 ctx->va_context = VA_INVALID_ID;
673 ctx->valid_ids = 1;
674
675 for (i = 0; i < VAProcFilterCount; i++)
676 ctx->filter_buffers[i] = VA_INVALID_ID;
677 ctx->nb_filter_buffers = 0;
678 }
679
ff_vaapi_vpp_ctx_uninit(AVFilterContext * avctx)680 void ff_vaapi_vpp_ctx_uninit(AVFilterContext *avctx)
681 {
682 VAAPIVPPContext *ctx = avctx->priv;
683 if (ctx->valid_ids && ctx->pipeline_uninit)
684 ctx->pipeline_uninit(avctx);
685
686 av_buffer_unref(&ctx->input_frames_ref);
687 av_buffer_unref(&ctx->device_ref);
688 }
689