2 * This file is part of FFmpeg.
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.
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.
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
21 #include "libavutil/avassert.h"
22 #include "libavutil/mem.h"
23 #include "libavutil/pixdesc.h"
27 #include "vaapi_vpp.h"
29 int ff_vaapi_vpp_query_formats(const AVFilterContext
*avctx
,
30 AVFilterFormatsConfig
**cfg_in
,
31 AVFilterFormatsConfig
**cfg_out
)
33 static const enum AVPixelFormat pix_fmts
[] = {
34 AV_PIX_FMT_VAAPI
, AV_PIX_FMT_NONE
,
38 err
= ff_set_common_formats_from_list2(avctx
, cfg_in
, cfg_out
, pix_fmts
);
45 void ff_vaapi_vpp_pipeline_uninit(AVFilterContext
*avctx
)
47 VAAPIVPPContext
*ctx
= avctx
->priv
;
49 for (i
= 0; i
< ctx
->nb_filter_buffers
; i
++) {
50 if (ctx
->filter_buffers
[i
] != VA_INVALID_ID
) {
51 vaDestroyBuffer(ctx
->hwctx
->display
, ctx
->filter_buffers
[i
]);
52 ctx
->filter_buffers
[i
] = VA_INVALID_ID
;
55 ctx
->nb_filter_buffers
= 0;
57 if (ctx
->va_context
!= VA_INVALID_ID
) {
58 vaDestroyContext(ctx
->hwctx
->display
, ctx
->va_context
);
59 ctx
->va_context
= VA_INVALID_ID
;
62 if (ctx
->va_config
!= VA_INVALID_ID
) {
63 vaDestroyConfig(ctx
->hwctx
->display
, ctx
->va_config
);
64 ctx
->va_config
= VA_INVALID_ID
;
67 av_buffer_unref(&ctx
->device_ref
);
71 int ff_vaapi_vpp_config_input(AVFilterLink
*inlink
)
73 FilterLink
*l
= ff_filter_link(inlink
);
74 AVFilterContext
*avctx
= inlink
->dst
;
75 VAAPIVPPContext
*ctx
= avctx
->priv
;
77 if (ctx
->pipeline_uninit
)
78 ctx
->pipeline_uninit(avctx
);
80 if (!l
->hw_frames_ctx
) {
81 av_log(avctx
, AV_LOG_ERROR
, "A hardware frames reference is "
82 "required to associate the processing device.\n");
83 return AVERROR(EINVAL
);
86 ctx
->input_frames_ref
= av_buffer_ref(l
->hw_frames_ctx
);
87 if (!ctx
->input_frames_ref
) {
88 av_log(avctx
, AV_LOG_ERROR
, "A input frames reference create "
90 return AVERROR(ENOMEM
);
92 ctx
->input_frames
= (AVHWFramesContext
*)ctx
->input_frames_ref
->data
;
97 int ff_vaapi_vpp_config_output(AVFilterLink
*outlink
)
99 FilterLink
*outl
= ff_filter_link(outlink
);
100 AVFilterContext
*avctx
= outlink
->src
;
101 AVFilterLink
*inlink
= avctx
->inputs
[0];
102 FilterLink
*inl
= ff_filter_link(inlink
);
103 VAAPIVPPContext
*ctx
= avctx
->priv
;
104 AVVAAPIHWConfig
*hwconfig
= NULL
;
105 AVHWFramesConstraints
*constraints
= NULL
;
106 AVHWFramesContext
*output_frames
;
107 AVVAAPIFramesContext
*va_frames
;
111 if (ctx
->pipeline_uninit
)
112 ctx
->pipeline_uninit(avctx
);
114 if (!ctx
->output_width
)
115 ctx
->output_width
= avctx
->inputs
[0]->w
;
116 if (!ctx
->output_height
)
117 ctx
->output_height
= avctx
->inputs
[0]->h
;
119 outlink
->w
= ctx
->output_width
;
120 outlink
->h
= ctx
->output_height
;
122 if (ctx
->passthrough
) {
123 if (inl
->hw_frames_ctx
)
124 outl
->hw_frames_ctx
= av_buffer_ref(inl
->hw_frames_ctx
);
125 av_log(ctx
, AV_LOG_VERBOSE
, "Using VAAPI filter passthrough mode.\n");
130 av_assert0(ctx
->input_frames
);
131 ctx
->device_ref
= av_buffer_ref(ctx
->input_frames
->device_ref
);
132 if (!ctx
->device_ref
) {
133 av_log(avctx
, AV_LOG_ERROR
, "A device reference create "
135 return AVERROR(ENOMEM
);
137 ctx
->hwctx
= ((AVHWDeviceContext
*)ctx
->device_ref
->data
)->hwctx
;
139 av_assert0(ctx
->va_config
== VA_INVALID_ID
);
140 vas
= vaCreateConfig(ctx
->hwctx
->display
, VAProfileNone
,
141 VAEntrypointVideoProc
, NULL
, 0, &ctx
->va_config
);
142 if (vas
!= VA_STATUS_SUCCESS
) {
143 av_log(avctx
, AV_LOG_ERROR
, "Failed to create processing pipeline "
144 "config: %d (%s).\n", vas
, vaErrorStr(vas
));
149 hwconfig
= av_hwdevice_hwconfig_alloc(ctx
->device_ref
);
151 err
= AVERROR(ENOMEM
);
154 hwconfig
->config_id
= ctx
->va_config
;
156 constraints
= av_hwdevice_get_hwframe_constraints(ctx
->device_ref
,
159 err
= AVERROR(ENOMEM
);
163 if (ctx
->output_format
== AV_PIX_FMT_NONE
)
164 ctx
->output_format
= ctx
->input_frames
->sw_format
;
165 if (constraints
->valid_sw_formats
) {
166 for (i
= 0; constraints
->valid_sw_formats
[i
] != AV_PIX_FMT_NONE
; i
++) {
167 if (ctx
->output_format
== constraints
->valid_sw_formats
[i
])
170 if (constraints
->valid_sw_formats
[i
] == AV_PIX_FMT_NONE
) {
171 av_log(avctx
, AV_LOG_ERROR
, "Hardware does not support output "
172 "format %s.\n", av_get_pix_fmt_name(ctx
->output_format
));
173 err
= AVERROR(EINVAL
);
178 if (ctx
->output_width
< constraints
->min_width
||
179 ctx
->output_height
< constraints
->min_height
||
180 ctx
->output_width
> constraints
->max_width
||
181 ctx
->output_height
> constraints
->max_height
) {
182 av_log(avctx
, AV_LOG_ERROR
, "Hardware does not support scaling to "
183 "size %dx%d (constraints: width %d-%d height %d-%d).\n",
184 ctx
->output_width
, ctx
->output_height
,
185 constraints
->min_width
, constraints
->max_width
,
186 constraints
->min_height
, constraints
->max_height
);
187 err
= AVERROR(EINVAL
);
191 outl
->hw_frames_ctx
= av_hwframe_ctx_alloc(ctx
->device_ref
);
192 if (!outl
->hw_frames_ctx
) {
193 av_log(avctx
, AV_LOG_ERROR
, "Failed to create HW frame context "
195 err
= AVERROR(ENOMEM
);
199 output_frames
= (AVHWFramesContext
*)outl
->hw_frames_ctx
->data
;
201 output_frames
->format
= AV_PIX_FMT_VAAPI
;
202 output_frames
->sw_format
= ctx
->output_format
;
203 output_frames
->width
= ctx
->output_width
;
204 output_frames
->height
= ctx
->output_height
;
207 output_frames
->initial_pool_size
= 0;
209 output_frames
->initial_pool_size
= 4;
211 err
= ff_filter_init_hw_frames(avctx
, outlink
, 10);
215 err
= av_hwframe_ctx_init(outl
->hw_frames_ctx
);
217 av_log(avctx
, AV_LOG_ERROR
, "Failed to initialise VAAPI frame "
218 "context for output: %d\n", err
);
222 va_frames
= output_frames
->hwctx
;
224 av_assert0(ctx
->va_context
== VA_INVALID_ID
);
225 av_assert0(output_frames
->initial_pool_size
||
226 (va_frames
->surface_ids
== NULL
&& va_frames
->nb_surfaces
== 0));
227 vas
= vaCreateContext(ctx
->hwctx
->display
, ctx
->va_config
,
228 ctx
->output_width
, ctx
->output_height
,
230 va_frames
->surface_ids
, va_frames
->nb_surfaces
,
232 if (vas
!= VA_STATUS_SUCCESS
) {
233 av_log(avctx
, AV_LOG_ERROR
, "Failed to create processing pipeline "
234 "context: %d (%s).\n", vas
, vaErrorStr(vas
));
238 if (ctx
->build_filter_params
) {
239 err
= ctx
->build_filter_params(avctx
);
245 av_hwframe_constraints_free(&constraints
);
249 av_buffer_unref(&outl
->hw_frames_ctx
);
251 av_hwframe_constraints_free(&constraints
);
255 typedef struct VAAPIColourProperties
{
256 VAProcColorStandardType va_color_standard
;
258 enum AVColorPrimaries color_primaries
;
259 enum AVColorTransferCharacteristic color_trc
;
260 enum AVColorSpace colorspace
;
262 uint8_t va_chroma_sample_location
;
263 uint8_t va_color_range
;
265 enum AVColorRange color_range
;
266 enum AVChromaLocation chroma_sample_location
;
267 } VAAPIColourProperties
;
269 static const VAAPIColourProperties vaapi_colour_standard_map
[] = {
270 { VAProcColorStandardBT601
, 5, 6, 5 },
271 { VAProcColorStandardBT601
, 6, 6, 6 },
272 { VAProcColorStandardBT709
, 1, 1, 1 },
273 { VAProcColorStandardBT470M
, 4, 4, 4 },
274 { VAProcColorStandardBT470BG
, 5, 5, 5 },
275 { VAProcColorStandardSMPTE170M
, 6, 6, 6 },
276 { VAProcColorStandardSMPTE240M
, 7, 7, 7 },
277 { VAProcColorStandardGenericFilm
, 8, 1, 1 },
278 #if VA_CHECK_VERSION(1, 1, 0)
279 { VAProcColorStandardSRGB
, 1, 13, 0 },
280 { VAProcColorStandardXVYCC601
, 1, 11, 5 },
281 { VAProcColorStandardXVYCC709
, 1, 11, 1 },
282 { VAProcColorStandardBT2020
, 9, 14, 9 },
286 static void vaapi_vpp_fill_colour_standard(VAAPIColourProperties
*props
,
287 VAProcColorStandardType
*vacs
,
290 const VAAPIColourProperties
*t
;
291 int i
, j
, score
, best_score
, worst_score
;
292 VAProcColorStandardType best_standard
;
294 #if VA_CHECK_VERSION(1, 3, 0)
295 // If the driver supports explicit use of the standard values then just
296 // use them and avoid doing any mapping. (The driver may not support
297 // some particular code point, but it still has enough information to
298 // make a better fallback choice than we do in that case.)
299 for (i
= 0; i
< nb_vacs
; i
++) {
300 if (vacs
[i
] == VAProcColorStandardExplicit
) {
301 props
->va_color_standard
= VAProcColorStandardExplicit
;
307 // Give scores to the possible options and choose the lowest one.
308 // An exact match will score zero and therefore always be chosen, as
309 // will a partial match where all unmatched elements are explicitly
310 // unspecified. If no options match at all then just pass "none" to
311 // the driver and let it make its own choice.
312 best_standard
= VAProcColorStandardNone
;
314 worst_score
= 4 * (props
->colorspace
!= AVCOL_SPC_UNSPECIFIED
&&
315 props
->colorspace
!= AVCOL_SPC_RGB
) +
316 2 * (props
->color_trc
!= AVCOL_TRC_UNSPECIFIED
) +
317 (props
->color_primaries
!= AVCOL_PRI_UNSPECIFIED
);
319 if (worst_score
== 0) {
320 // No properties are specified, so we aren't going to be able to
321 // make a useful choice.
322 props
->va_color_standard
= VAProcColorStandardNone
;
326 for (i
= 0; i
< nb_vacs
; i
++) {
327 for (j
= 0; j
< FF_ARRAY_ELEMS(vaapi_colour_standard_map
); j
++) {
328 t
= &vaapi_colour_standard_map
[j
];
329 if (t
->va_color_standard
!= vacs
[i
])
333 if (props
->colorspace
!= AVCOL_SPC_UNSPECIFIED
&&
334 props
->colorspace
!= AVCOL_SPC_RGB
)
335 score
+= 4 * (props
->colorspace
!= t
->colorspace
);
336 if (props
->color_trc
!= AVCOL_TRC_UNSPECIFIED
)
337 score
+= 2 * (props
->color_trc
!= t
->color_trc
);
338 if (props
->color_primaries
!= AVCOL_PRI_UNSPECIFIED
)
339 score
+= (props
->color_primaries
!= t
->color_primaries
);
341 // Only include choices which matched something.
342 if (score
< worst_score
&&
343 (best_score
== -1 || score
< best_score
)) {
345 best_standard
= t
->va_color_standard
;
349 props
->va_color_standard
= best_standard
;
352 static void vaapi_vpp_fill_chroma_sample_location(VAAPIColourProperties
*props
)
354 #if VA_CHECK_VERSION(1, 1, 0)
355 static const struct {
356 enum AVChromaLocation av
;
359 { AVCHROMA_LOC_UNSPECIFIED
, VA_CHROMA_SITING_UNKNOWN
},
360 { AVCHROMA_LOC_LEFT
, VA_CHROMA_SITING_VERTICAL_CENTER
|
361 VA_CHROMA_SITING_HORIZONTAL_LEFT
},
362 { AVCHROMA_LOC_CENTER
, VA_CHROMA_SITING_VERTICAL_CENTER
|
363 VA_CHROMA_SITING_HORIZONTAL_CENTER
},
364 { AVCHROMA_LOC_TOPLEFT
, VA_CHROMA_SITING_VERTICAL_TOP
|
365 VA_CHROMA_SITING_HORIZONTAL_LEFT
},
366 { AVCHROMA_LOC_TOP
, VA_CHROMA_SITING_VERTICAL_TOP
|
367 VA_CHROMA_SITING_HORIZONTAL_CENTER
},
368 { AVCHROMA_LOC_BOTTOMLEFT
, VA_CHROMA_SITING_VERTICAL_BOTTOM
|
369 VA_CHROMA_SITING_HORIZONTAL_LEFT
},
370 { AVCHROMA_LOC_BOTTOM
, VA_CHROMA_SITING_VERTICAL_BOTTOM
|
371 VA_CHROMA_SITING_HORIZONTAL_CENTER
},
375 for (i
= 0; i
< FF_ARRAY_ELEMS(csl_map
); i
++) {
376 if (props
->chroma_sample_location
== csl_map
[i
].av
) {
377 props
->va_chroma_sample_location
= csl_map
[i
].va
;
381 props
->va_chroma_sample_location
= VA_CHROMA_SITING_UNKNOWN
;
383 props
->va_chroma_sample_location
= 0;
387 static void vaapi_vpp_fill_colour_range(VAAPIColourProperties
*props
)
389 #if VA_CHECK_VERSION(1, 1, 0)
390 switch (props
->color_range
) {
391 case AVCOL_RANGE_MPEG
:
392 props
->va_color_range
= VA_SOURCE_RANGE_REDUCED
;
394 case AVCOL_RANGE_JPEG
:
395 props
->va_color_range
= VA_SOURCE_RANGE_FULL
;
397 case AVCOL_RANGE_UNSPECIFIED
:
399 props
->va_color_range
= VA_SOURCE_RANGE_UNKNOWN
;
402 props
->va_color_range
= 0;
406 static void vaapi_vpp_fill_colour_properties(AVFilterContext
*avctx
,
407 VAAPIColourProperties
*props
,
408 VAProcColorStandardType
*vacs
,
411 vaapi_vpp_fill_colour_standard(props
, vacs
, nb_vacs
);
412 vaapi_vpp_fill_chroma_sample_location(props
);
413 vaapi_vpp_fill_colour_range(props
);
415 av_log(avctx
, AV_LOG_DEBUG
, "Mapped colour properties %s %s/%s/%s %s "
416 "to VA standard %d chroma siting %#x range %#x.\n",
417 av_color_range_name(props
->color_range
),
418 av_color_space_name(props
->colorspace
),
419 av_color_primaries_name(props
->color_primaries
),
420 av_color_transfer_name(props
->color_trc
),
421 av_chroma_location_name(props
->chroma_sample_location
),
422 props
->va_color_standard
,
423 props
->va_chroma_sample_location
, props
->va_color_range
);
426 static int vaapi_vpp_frame_is_rgb(const AVFrame
*frame
)
428 const AVHWFramesContext
*hwfc
;
429 const AVPixFmtDescriptor
*desc
;
430 av_assert0(frame
->format
== AV_PIX_FMT_VAAPI
&&
431 frame
->hw_frames_ctx
);
432 hwfc
= (const AVHWFramesContext
*)frame
->hw_frames_ctx
->data
;
433 desc
= av_pix_fmt_desc_get(hwfc
->sw_format
);
435 return !!(desc
->flags
& AV_PIX_FMT_FLAG_RGB
);
438 static int vaapi_vpp_colour_properties(AVFilterContext
*avctx
,
439 VAProcPipelineParameterBuffer
*params
,
440 const AVFrame
*input_frame
,
441 AVFrame
*output_frame
)
443 VAAPIVPPContext
*ctx
= avctx
->priv
;
444 VAAPIColourProperties input_props
, output_props
;
445 VAProcPipelineCaps caps
;
448 vas
= vaQueryVideoProcPipelineCaps(ctx
->hwctx
->display
, ctx
->va_context
,
449 ctx
->filter_buffers
, ctx
->nb_filter_buffers
,
451 if (vas
!= VA_STATUS_SUCCESS
) {
452 av_log(avctx
, AV_LOG_ERROR
, "Failed to query capabilities for "
453 "colour standard support: %d (%s).\n", vas
, vaErrorStr(vas
));
454 return AVERROR_EXTERNAL
;
457 input_props
= (VAAPIColourProperties
) {
458 .colorspace
= vaapi_vpp_frame_is_rgb(input_frame
)
459 ? AVCOL_SPC_RGB
: input_frame
->colorspace
,
460 .color_primaries
= input_frame
->color_primaries
,
461 .color_trc
= input_frame
->color_trc
,
462 .color_range
= input_frame
->color_range
,
463 .chroma_sample_location
= input_frame
->chroma_location
,
466 vaapi_vpp_fill_colour_properties(avctx
, &input_props
,
467 caps
.input_color_standards
,
468 caps
.num_input_color_standards
);
470 output_props
= (VAAPIColourProperties
) {
471 .colorspace
= vaapi_vpp_frame_is_rgb(output_frame
)
472 ? AVCOL_SPC_RGB
: output_frame
->colorspace
,
473 .color_primaries
= output_frame
->color_primaries
,
474 .color_trc
= output_frame
->color_trc
,
475 .color_range
= output_frame
->color_range
,
476 .chroma_sample_location
= output_frame
->chroma_location
,
478 vaapi_vpp_fill_colour_properties(avctx
, &output_props
,
479 caps
.output_color_standards
,
480 caps
.num_output_color_standards
);
482 // If the properties weren't filled completely in the output frame and
483 // we chose a fixed standard then fill the known values in here.
484 #if VA_CHECK_VERSION(1, 3, 0)
485 if (output_props
.va_color_standard
!= VAProcColorStandardExplicit
)
488 const VAAPIColourProperties
*output_standard
= NULL
;
491 for (i
= 0; i
< FF_ARRAY_ELEMS(vaapi_colour_standard_map
); i
++) {
492 if (output_props
.va_color_standard
==
493 vaapi_colour_standard_map
[i
].va_color_standard
) {
494 output_standard
= &vaapi_colour_standard_map
[i
];
498 if (output_standard
) {
499 output_frame
->colorspace
= vaapi_vpp_frame_is_rgb(output_frame
)
500 ? AVCOL_SPC_RGB
: output_standard
->colorspace
;
501 output_frame
->color_primaries
= output_standard
->color_primaries
;
502 output_frame
->color_trc
= output_standard
->color_trc
;
506 params
->surface_color_standard
= input_props
.va_color_standard
;
507 params
->output_color_standard
= output_props
.va_color_standard
;
509 #if VA_CHECK_VERSION(1, 1, 0)
510 params
->input_color_properties
= (VAProcColorProperties
) {
511 .chroma_sample_location
= input_props
.va_chroma_sample_location
,
512 .color_range
= input_props
.va_color_range
,
513 #if VA_CHECK_VERSION(1, 3, 0)
514 .colour_primaries
= input_props
.color_primaries
,
515 .transfer_characteristics
= input_props
.color_trc
,
516 .matrix_coefficients
= input_props
.colorspace
,
519 params
->output_color_properties
= (VAProcColorProperties
) {
520 .chroma_sample_location
= output_props
.va_chroma_sample_location
,
521 .color_range
= output_props
.va_color_range
,
522 #if VA_CHECK_VERSION(1, 3, 0)
523 .colour_primaries
= output_props
.color_primaries
,
524 .transfer_characteristics
= output_props
.color_trc
,
525 .matrix_coefficients
= output_props
.colorspace
,
533 int ff_vaapi_vpp_init_params(AVFilterContext
*avctx
,
534 VAProcPipelineParameterBuffer
*params
,
535 const AVFrame
*input_frame
,
536 AVFrame
*output_frame
)
538 VAAPIVPPContext
*ctx
= avctx
->priv
;
541 ctx
->input_region
= (VARectangle
) {
542 .x
= input_frame
->crop_left
,
543 .y
= input_frame
->crop_top
,
544 .width
= input_frame
->width
-
545 (input_frame
->crop_left
+ input_frame
->crop_right
),
546 .height
= input_frame
->height
-
547 (input_frame
->crop_top
+ input_frame
->crop_bottom
),
549 output_frame
->crop_top
= 0;
550 output_frame
->crop_bottom
= 0;
551 output_frame
->crop_left
= 0;
552 output_frame
->crop_right
= 0;
554 *params
= (VAProcPipelineParameterBuffer
) {
555 .surface
= ff_vaapi_vpp_get_surface_id(input_frame
),
556 .surface_region
= &ctx
->input_region
,
557 .output_region
= NULL
,
558 .output_background_color
= VAAPI_VPP_BACKGROUND_BLACK
,
560 .filter_flags
= VA_FRAME_PICTURE
,
562 // Filter and reference data filled by the filter itself.
564 #if VA_CHECK_VERSION(1, 1, 0)
565 .rotation_state
= VA_ROTATION_NONE
,
566 .mirror_state
= VA_MIRROR_NONE
,
570 err
= vaapi_vpp_colour_properties(avctx
, params
,
571 input_frame
, output_frame
);
575 av_log(avctx
, AV_LOG_DEBUG
, "Filter frame from surface %#x to %#x.\n",
576 ff_vaapi_vpp_get_surface_id(input_frame
),
577 ff_vaapi_vpp_get_surface_id(output_frame
));
582 int ff_vaapi_vpp_make_param_buffers(AVFilterContext
*avctx
,
590 VAAPIVPPContext
*ctx
= avctx
->priv
;
592 av_assert0(ctx
->nb_filter_buffers
+ 1 <= VAProcFilterCount
);
594 vas
= vaCreateBuffer(ctx
->hwctx
->display
, ctx
->va_context
,
595 type
, size
, count
, (void*)data
, &buffer
);
596 if (vas
!= VA_STATUS_SUCCESS
) {
597 av_log(avctx
, AV_LOG_ERROR
, "Failed to create parameter "
598 "buffer (type %d): %d (%s).\n",
599 type
, vas
, vaErrorStr(vas
));
603 ctx
->filter_buffers
[ctx
->nb_filter_buffers
++] = buffer
;
605 av_log(avctx
, AV_LOG_DEBUG
, "Param buffer (type %d, %zu bytes, count %d) "
606 "is %#x.\n", type
, size
, count
, buffer
);
610 static int vaapi_vpp_render_single_pipeline_buffer(AVFilterContext
*avctx
,
611 VAProcPipelineParameterBuffer
*params
,
612 VABufferID
*params_id
)
614 VAAPIVPPContext
*ctx
= avctx
->priv
;
617 vas
= vaCreateBuffer(ctx
->hwctx
->display
, ctx
->va_context
,
618 VAProcPipelineParameterBufferType
,
619 sizeof(*params
), 1, params
, params_id
);
620 if (vas
!= VA_STATUS_SUCCESS
) {
621 av_log(avctx
, AV_LOG_ERROR
, "Failed to create parameter buffer: "
622 "%d (%s).\n", vas
, vaErrorStr(vas
));
623 *params_id
= VA_INVALID_ID
;
627 av_log(avctx
, AV_LOG_DEBUG
, "Pipeline parameter buffer is %#x.\n", *params_id
);
629 vas
= vaRenderPicture(ctx
->hwctx
->display
, ctx
->va_context
, params_id
, 1);
630 if (vas
!= VA_STATUS_SUCCESS
) {
631 av_log(avctx
, AV_LOG_ERROR
, "Failed to render parameter buffer: "
632 "%d (%s).\n", vas
, vaErrorStr(vas
));
639 int ff_vaapi_vpp_render_pictures(AVFilterContext
*avctx
,
640 VAProcPipelineParameterBuffer
*params_list
,
642 AVFrame
*output_frame
)
644 VAAPIVPPContext
*ctx
= avctx
->priv
;
645 VABufferID
*params_ids
;
649 params_ids
= (VABufferID
*)av_malloc_array(cout
, sizeof(VABufferID
));
651 return AVERROR(ENOMEM
);
653 for (int i
= 0; i
< cout
; i
++)
654 params_ids
[i
] = VA_INVALID_ID
;
656 vas
= vaBeginPicture(ctx
->hwctx
->display
,
657 ctx
->va_context
, ff_vaapi_vpp_get_surface_id(output_frame
));
658 if (vas
!= VA_STATUS_SUCCESS
) {
659 av_log(avctx
, AV_LOG_ERROR
, "Failed to attach new picture: "
660 "%d (%s).\n", vas
, vaErrorStr(vas
));
665 for (int i
= 0; i
< cout
; i
++) {
666 err
= vaapi_vpp_render_single_pipeline_buffer(avctx
, ¶ms_list
[i
], ¶ms_ids
[i
]);
668 goto fail_after_begin
;
671 vas
= vaEndPicture(ctx
->hwctx
->display
, ctx
->va_context
);
672 if (vas
!= VA_STATUS_SUCCESS
) {
673 av_log(avctx
, AV_LOG_ERROR
, "Failed to start picture processing: "
674 "%d (%s).\n", vas
, vaErrorStr(vas
));
676 goto fail_after_render
;
679 if (CONFIG_VAAPI_1
|| ctx
->hwctx
->driver_quirks
&
680 AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS
) {
681 for (int i
= 0; i
< cout
&& params_ids
[i
] != VA_INVALID_ID
; i
++) {
682 vas
= vaDestroyBuffer(ctx
->hwctx
->display
, params_ids
[i
]);
683 if (vas
!= VA_STATUS_SUCCESS
) {
684 av_log(avctx
, AV_LOG_ERROR
, "Failed to free parameter buffer: "
685 "%d (%s).\n", vas
, vaErrorStr(vas
));
691 av_freep(¶ms_ids
);
694 // We want to make sure that if vaBeginPicture has been called, we also
695 // call vaRenderPicture and vaEndPicture. These calls may well fail or
696 // do something else nasty, but once we're in this failure case there
697 // isn't much else we can do.
699 vaRenderPicture(ctx
->hwctx
->display
, ctx
->va_context
, ¶ms_ids
[0], 1);
701 vaEndPicture(ctx
->hwctx
->display
, ctx
->va_context
);
703 av_freep(¶ms_ids
);
707 int ff_vaapi_vpp_render_picture(AVFilterContext
*avctx
,
708 VAProcPipelineParameterBuffer
*params
,
709 AVFrame
*output_frame
)
711 return ff_vaapi_vpp_render_pictures(avctx
, params
, 1, output_frame
);
714 void ff_vaapi_vpp_ctx_init(AVFilterContext
*avctx
)
717 VAAPIVPPContext
*ctx
= avctx
->priv
;
719 ctx
->va_config
= VA_INVALID_ID
;
720 ctx
->va_context
= VA_INVALID_ID
;
723 for (i
= 0; i
< VAProcFilterCount
; i
++)
724 ctx
->filter_buffers
[i
] = VA_INVALID_ID
;
725 ctx
->nb_filter_buffers
= 0;
728 void ff_vaapi_vpp_ctx_uninit(AVFilterContext
*avctx
)
730 VAAPIVPPContext
*ctx
= avctx
->priv
;
731 if (ctx
->valid_ids
&& ctx
->pipeline_uninit
)
732 ctx
->pipeline_uninit(avctx
);
734 av_buffer_unref(&ctx
->input_frames_ref
);
735 av_buffer_unref(&ctx
->device_ref
);