FFmpeg
Loading...
Searching...
No Matches
vf_deinterlace_vaapi.c
Go to the documentation of this file.
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/common.h"
22#include "libavutil/opt.h"
23#include "libavutil/pixdesc.h"
24
25#include "avfilter.h"
26#include "filters.h"
27#include "video.h"
28#include "vaapi_vpp.h"
29
30#define MAX_REFERENCES 8
31
32typedef struct DeintVAAPIContext {
33 VAAPIVPPContext vpp_ctx; // must be the first field
34
35 int mode;
38
39 VAProcFilterCapDeinterlacing
40 deint_caps[VAProcDeinterlacingCount];
42 VAProcPipelineCaps pipeline_caps;
43
48
49 int eof;
52
53static const char *deint_vaapi_mode_name(int mode)
54{
55 switch (mode) {
56#define D(name) case VAProcDeinterlacing ## name: return #name
57 D(Bob);
58 D(Weave);
59 D(MotionAdaptive);
60 D(MotionCompensated);
61#undef D
62 default:
63 return "Invalid";
64 }
65}
66
68{
69 DeintVAAPIContext *ctx = avctx->priv;
70 int i;
71
72 for (i = 0; i < ctx->queue_count; i++)
73 av_frame_free(&ctx->frame_queue[i]);
74 ctx->queue_count = 0;
75
77}
78
80{
81 VAAPIVPPContext *vpp_ctx = avctx->priv;
82 DeintVAAPIContext *ctx = avctx->priv;
83 VAStatus vas;
84 VAProcFilterParameterBufferDeinterlacing params;
85 int i;
86
87 ctx->nb_deint_caps = VAProcDeinterlacingCount;
88 vas = vaQueryVideoProcFilterCaps(vpp_ctx->hwctx->display,
89 vpp_ctx->va_context,
90 VAProcFilterDeinterlacing,
91 &ctx->deint_caps,
92 &ctx->nb_deint_caps);
93 if (vas != VA_STATUS_SUCCESS) {
94 av_log(avctx, AV_LOG_ERROR, "Failed to query deinterlacing "
95 "caps: %d (%s).\n", vas, vaErrorStr(vas));
96 return AVERROR(EIO);
97 }
98
99 if (ctx->mode == VAProcDeinterlacingNone) {
100 for (i = 0; i < ctx->nb_deint_caps; i++) {
101 if (ctx->deint_caps[i].type > ctx->mode)
102 ctx->mode = ctx->deint_caps[i].type;
103 }
104 av_log(avctx, AV_LOG_VERBOSE, "Picking %d (%s) as default "
105 "deinterlacing mode.\n", ctx->mode,
107 } else {
108 for (i = 0; i < ctx->nb_deint_caps; i++) {
109 if (ctx->deint_caps[i].type == ctx->mode)
110 break;
111 }
112 if (i >= ctx->nb_deint_caps) {
113 av_log(avctx, AV_LOG_ERROR, "Deinterlacing mode %d (%s) is "
114 "not supported.\n", ctx->mode,
116 return AVERROR(EINVAL);
117 }
118 }
119
120 params.type = VAProcFilterDeinterlacing;
121 params.algorithm = ctx->mode;
122 params.flags = 0;
123
125 VAProcFilterParameterBufferType,
126 &params,
127 sizeof(params),
128 1);
129 if (vas)
130 return vas;
131
132 vas = vaQueryVideoProcPipelineCaps(vpp_ctx->hwctx->display,
133 vpp_ctx->va_context,
134 &vpp_ctx->filter_buffers[0], 1,
135 &ctx->pipeline_caps);
136 if (vas != VA_STATUS_SUCCESS) {
137 av_log(avctx, AV_LOG_ERROR, "Failed to query pipeline "
138 "caps: %d (%s).\n", vas, vaErrorStr(vas));
139 return AVERROR(EIO);
140 }
141
142 ctx->extra_delay_for_timestamps = ctx->field_rate == 2 &&
143 ctx->pipeline_caps.num_backward_references == 0;
144
145 ctx->queue_depth = ctx->pipeline_caps.num_backward_references +
146 ctx->pipeline_caps.num_forward_references +
147 ctx->extra_delay_for_timestamps + 1;
148 if (ctx->queue_depth > MAX_REFERENCES) {
149 av_log(avctx, AV_LOG_ERROR, "Pipeline requires too many "
150 "references (%u forward, %u back).\n",
151 ctx->pipeline_caps.num_forward_references,
152 ctx->pipeline_caps.num_backward_references);
153 return AVERROR(ENOSYS);
154 }
155
156 return 0;
157}
158
160{
161 FilterLink *outl = ff_filter_link(outlink);
162 AVFilterLink *inlink = outlink->src->inputs[0];
163 FilterLink *inl = ff_filter_link(inlink);
164 AVFilterContext *avctx = outlink->src;
165 DeintVAAPIContext *ctx = avctx->priv;
166 int err;
167
168 err = ff_vaapi_vpp_config_output(outlink);
169 if (err < 0)
170 return err;
171 outlink->time_base = av_mul_q(inlink->time_base,
172 (AVRational) { 1, ctx->field_rate });
173 outl->frame_rate = av_mul_q(inl->frame_rate,
174 (AVRational) { ctx->field_rate, 1 });
175
176 return 0;
177}
178
179static int deint_vaapi_filter_frame(AVFilterLink *inlink, AVFrame *input_frame)
180{
181 AVFilterContext *avctx = inlink->dst;
182 AVFilterLink *outlink = avctx->outputs[0];
183 VAAPIVPPContext *vpp_ctx = avctx->priv;
184 DeintVAAPIContext *ctx = avctx->priv;
186 VASurfaceID input_surface;
187 VASurfaceID backward_references[MAX_REFERENCES];
188 VASurfaceID forward_references[MAX_REFERENCES];
189 VAProcPipelineParameterBuffer params;
190 VAProcFilterParameterBufferDeinterlacing *filter_params;
191 VAStatus vas;
192 void *filter_params_addr = NULL;
193 int err, i, field, current_frame_index;
194
195 // NULL frame is used to flush the queue in field mode
196 if (input_frame)
197 av_log(avctx, AV_LOG_DEBUG, "Filter input: %s, %ux%u (%"PRId64").\n",
198 av_get_pix_fmt_name(input_frame->format),
199 input_frame->width, input_frame->height, input_frame->pts);
200
201 if (ctx->queue_count < ctx->queue_depth) {
202 ctx->frame_queue[ctx->queue_count++] = input_frame;
203 if (ctx->queue_count < ctx->queue_depth) {
204 // Need more reference surfaces before we can continue.
205 return 0;
206 }
207 } else {
208 av_frame_free(&ctx->frame_queue[0]);
209 for (i = 0; i + 1 < ctx->queue_count; i++)
210 ctx->frame_queue[i] = ctx->frame_queue[i + 1];
211 ctx->frame_queue[i] = input_frame;
212 }
213
214 current_frame_index = ctx->pipeline_caps.num_forward_references;
215
216 input_frame = ctx->frame_queue[current_frame_index];
217 if (!input_frame)
218 return 0;
219
220 input_surface = (VASurfaceID)(uintptr_t)input_frame->data[3];
221 for (i = 0; i < ctx->pipeline_caps.num_forward_references; i++)
222 forward_references[i] = (VASurfaceID)(uintptr_t)
223 ctx->frame_queue[current_frame_index - i - 1]->data[3];
224 for (i = 0; i < ctx->pipeline_caps.num_backward_references; i++)
225 backward_references[i] = (VASurfaceID)(uintptr_t)
226 ctx->frame_queue[current_frame_index + i + 1]->data[3];
227
228 av_log(avctx, AV_LOG_DEBUG, "Using surface %#x for "
229 "deinterlace input.\n", input_surface);
230 av_log(avctx, AV_LOG_DEBUG, "Backward references:");
231 for (i = 0; i < ctx->pipeline_caps.num_backward_references; i++)
232 av_log(avctx, AV_LOG_DEBUG, " %#x", backward_references[i]);
233 av_log(avctx, AV_LOG_DEBUG, "\n");
234 av_log(avctx, AV_LOG_DEBUG, "Forward references:");
235 for (i = 0; i < ctx->pipeline_caps.num_forward_references; i++)
236 av_log(avctx, AV_LOG_DEBUG, " %#x", forward_references[i]);
237 av_log(avctx, AV_LOG_DEBUG, "\n");
238
239 for (field = 0; field < ctx->field_rate; field++) {
241 vpp_ctx->output_height);
242 if (!output_frame) {
243 err = AVERROR(ENOMEM);
244 goto fail;
245 }
246
247 err = av_frame_copy_props(output_frame, input_frame);
248 if (err < 0)
249 goto fail;
250
251 err = ff_vaapi_vpp_init_params(avctx, &params,
252 input_frame, output_frame);
253 if (err < 0)
254 goto fail;
255
256 if (!ctx->auto_enable || (input_frame->flags & AV_FRAME_FLAG_INTERLACED)) {
257 vas = vaMapBuffer(vpp_ctx->hwctx->display, vpp_ctx->filter_buffers[0],
258 &filter_params_addr);
259 if (vas != VA_STATUS_SUCCESS) {
260 av_log(avctx, AV_LOG_ERROR, "Failed to map filter parameter "
261 "buffer: %d (%s).\n", vas, vaErrorStr(vas));
262 err = AVERROR(EIO);
263 goto fail;
264 }
265 filter_params = filter_params_addr;
266 filter_params->flags = 0;
267 if (input_frame->flags & AV_FRAME_FLAG_TOP_FIELD_FIRST) {
268 filter_params->flags |= field ? VA_DEINTERLACING_BOTTOM_FIELD : 0;
269 } else {
270 filter_params->flags |= VA_DEINTERLACING_BOTTOM_FIELD_FIRST;
271 filter_params->flags |= field ? 0 : VA_DEINTERLACING_BOTTOM_FIELD;
272 }
273 filter_params_addr = NULL;
274 vas = vaUnmapBuffer(vpp_ctx->hwctx->display, vpp_ctx->filter_buffers[0]);
275 if (vas != VA_STATUS_SUCCESS)
276 av_log(avctx, AV_LOG_ERROR, "Failed to unmap filter parameter "
277 "buffer: %d (%s).\n", vas, vaErrorStr(vas));
278
279 params.filters = &vpp_ctx->filter_buffers[0];
280 params.num_filters = 1;
281
282 params.forward_references = forward_references;
283 params.num_forward_references =
284 ctx->pipeline_caps.num_forward_references;
285 params.backward_references = backward_references;
286 params.num_backward_references =
287 ctx->pipeline_caps.num_backward_references;
288
289 } else {
290 params.filters = NULL;
291 params.num_filters = 0;
292 }
293
295 if (err < 0)
296 goto fail;
297
298 if (ctx->field_rate == 2) {
299 if (field == 0)
300 output_frame->pts = 2 * input_frame->pts;
301 else if (ctx->eof)
302 output_frame->pts = 3 * input_frame->pts - ctx->prev_pts;
303 else
304 output_frame->pts = input_frame->pts +
305 ctx->frame_queue[current_frame_index + 1]->pts;
306 }
308
309 av_log(avctx, AV_LOG_DEBUG, "Filter output: %s, %ux%u (%"PRId64").\n",
311 output_frame->width, output_frame->height, output_frame->pts);
312
313 err = ff_filter_frame(outlink, output_frame);
314 if (err < 0)
315 break;
316 }
317
318 ctx->prev_pts = input_frame->pts;
319
320 return err;
321
322fail:
323 if (filter_params_addr)
324 vaUnmapBuffer(vpp_ctx->hwctx->display, vpp_ctx->filter_buffers[0]);
326 return err;
327}
328
330{
331 AVFilterContext *avctx = link->src;
332 DeintVAAPIContext *ctx = avctx->priv;
333 int ret;
334
335 if (ctx->eof)
336 return AVERROR_EOF;
337
338 ret = ff_request_frame(link->src->inputs[0]);
339 if (ret == AVERROR_EOF && ctx->extra_delay_for_timestamps) {
340 ctx->eof = 1;
342 } else if (ret < 0)
343 return ret;
344
345 return 0;
346}
347
349{
350 VAAPIVPPContext *vpp_ctx = avctx->priv;
351
356
357 return 0;
358}
359
360#define OFFSET(x) offsetof(DeintVAAPIContext, x)
361#define FLAGS (AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM)
363 { "mode", "Deinterlacing mode",
364 OFFSET(mode), AV_OPT_TYPE_INT, { .i64 = VAProcDeinterlacingNone },
365 VAProcDeinterlacingNone, VAProcDeinterlacingCount - 1, FLAGS, .unit = "mode" },
366 { "default", "Use the highest-numbered (and therefore possibly most advanced) deinterlacing algorithm",
367 0, AV_OPT_TYPE_CONST, { .i64 = VAProcDeinterlacingNone }, 0, 0, FLAGS, .unit = "mode" },
368 { "bob", "Use the bob deinterlacing algorithm",
369 0, AV_OPT_TYPE_CONST, { .i64 = VAProcDeinterlacingBob }, 0, 0, FLAGS, .unit = "mode" },
370 { "weave", "Use the weave deinterlacing algorithm",
371 0, AV_OPT_TYPE_CONST, { .i64 = VAProcDeinterlacingWeave }, 0, 0, FLAGS, .unit = "mode" },
372 { "motion_adaptive", "Use the motion adaptive deinterlacing algorithm",
373 0, AV_OPT_TYPE_CONST, { .i64 = VAProcDeinterlacingMotionAdaptive }, 0, 0, FLAGS, .unit = "mode" },
374 { "motion_compensated", "Use the motion compensated deinterlacing algorithm",
375 0, AV_OPT_TYPE_CONST, { .i64 = VAProcDeinterlacingMotionCompensated }, 0, 0, FLAGS, .unit = "mode" },
376
377 { "rate", "Generate output at frame rate or field rate",
378 OFFSET(field_rate), AV_OPT_TYPE_INT, { .i64 = 1 }, 1, 2, FLAGS, .unit = "rate" },
379 { "frame", "Output at frame rate (one frame of output for each field-pair)",
380 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, 0, 0, FLAGS, .unit = "rate" },
381 { "field", "Output at field rate (one frame of output for each field)",
382 0, AV_OPT_TYPE_CONST, { .i64 = 2 }, 0, 0, FLAGS, .unit = "rate" },
383
384 { "auto", "Only deinterlace fields, passing frames through unchanged",
385 OFFSET(auto_enable), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, FLAGS },
386
387 { NULL },
388};
389
391 .class_name = "deinterlace_vaapi",
392 .item_name = av_default_item_name,
393 .option = deint_vaapi_options,
394 .version = LIBAVUTIL_VERSION_INT,
395};
396
398 {
399 .name = "default",
400 .type = AVMEDIA_TYPE_VIDEO,
401 .filter_frame = &deint_vaapi_filter_frame,
402 .config_props = &ff_vaapi_vpp_config_input,
403 },
404};
405
407 {
408 .name = "default",
409 .type = AVMEDIA_TYPE_VIDEO,
410 .request_frame = &deint_vaapi_request_frame,
411 .config_props = &deint_vaapi_config_output,
412 },
413};
414
416 .p.name = "deinterlace_vaapi",
417 .p.description = NULL_IF_CONFIG_SMALL("Deinterlacing of VAAPI surfaces"),
418 .p.priv_class = &deint_vaapi_class,
419 .priv_size = sizeof(DeintVAAPIContext),
425 .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
426};
SwsAArch64OpImplParams params
Definition ops.c:51
const FFFilter ff_vf_deinterlace_vaapi
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition avfilter.c:1068
int ff_request_frame(AVFilterLink *link)
Request an input frame from the filter at the other end of the link.
Definition avfilter.c:483
Main libavfilter public API header.
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define FLAGS
Definition cmdutils.c:598
common internal and external API header
#define NULL
Definition coverity.c:32
int(* init)(AVBSFContext *ctx)
Definition dts2pts.c:608
#define fail
Definition test.h:479
@ AV_OPT_TYPE_CONST
Special option type for declaring named constants.
Definition opt.h:298
@ AV_OPT_TYPE_INT
Underlying C type is int.
Definition opt.h:258
#define AVERROR_EOF
End of file.
Definition error.h:57
#define AVERROR(e)
Definition error.h:45
#define AV_FRAME_FLAG_INTERLACED
A flag to mark frames whose content is interlaced.
Definition frame.h:695
#define AV_FRAME_FLAG_TOP_FIELD_FIRST
A flag to mark frames where the top field is displayed first if the content is interlaced.
Definition frame.h:700
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition frame.c:64
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
Definition frame.c:599
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition log.h:231
#define AV_LOG_VERBOSE
Detailed information.
Definition log.h:226
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition log.h:210
const char * av_default_item_name(void *ptr)
Return the context name.
Definition log.c:241
AVRational av_mul_q(AVRational b, AVRational c)
Multiply two rationals.
Definition rational.c:80
@ AVMEDIA_TYPE_VIDEO
Definition avutil.h:200
#define LIBAVUTIL_VERSION_INT
Definition version.h:85
static av_cold void uninit(AVBitStreamFilterContext *ctx)
static int output_frame(H264Context *h, AVFrame *dst, H264Picture *srcp)
Definition h264dec.c:860
#define FILTER_INPUTS(array)
Definition filters.h:264
#define FILTER_OUTPUTS(array)
Definition filters.h:265
#define FF_FILTER_FLAG_HWFRAME_AWARE
The filter is aware of hardware frames, and any hardware frame context should not be automatically pr...
Definition filters.h:208
static FilterLink * ff_filter_link(AVFilterLink *link)
Definition filters.h:199
#define FILTER_QUERY_FUNC2(func)
Definition filters.h:241
#define av_cold
Definition attributes.h:117
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition internal.h:88
AVOptions.
const char * av_get_pix_fmt_name(enum AVPixelFormat pix_fmt)
Return the short name for a pixel format, NULL in case pix_fmt is unknown.
Definition pixdesc.c:3380
@ AV_PIX_FMT_NONE
Definition pixfmt.h:72
Describe the class of an AVClass context structure.
Definition log.h:76
An instance of a filter.
Definition avfilter.h:273
AVFilterLink ** inputs
array of pointers to input links
Definition avfilter.h:281
void * priv
private data for use by the filter
Definition avfilter.h:288
AVFilterLink ** outputs
array of pointers to output links
Definition avfilter.h:285
A filter pad used for either input or output.
Definition filters.h:40
This structure describes decoded (raw) audio or video data.
Definition frame.h:472
int64_t pts
Presentation timestamp in time_base units (time when frame should be shown to user).
Definition frame.h:574
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition frame.h:493
int width
Definition frame.h:544
int height
Definition frame.h:544
int flags
Frame flags, a combination of AV_FRAME_FLAGS.
Definition frame.h:716
int format
format of the frame, -1 if unknown or unset Values correspond to enum AVPixelFormat for video frames,...
Definition frame.h:559
AVOption.
Definition opt.h:428
Rational number (pair of numerator and denominator).
Definition rational.h:58
VADisplay display
The VADisplay handle, to be filled by the user.
AVFrame * frame_queue[MAX_REFERENCES]
VAProcFilterCapDeinterlacing deint_caps[VAProcDeinterlacingCount]
VAAPIVPPContext vpp_ctx
VAProcPipelineCaps pipeline_caps
VABufferID filter_buffers[VAProcFilterCount]
Definition vaapi_vpp.h:56
void(* pipeline_uninit)(AVFilterContext *avctx)
Definition vaapi_vpp.h:63
enum AVPixelFormat output_format
Definition vaapi_vpp.h:52
int(* build_filter_params)(AVFilterContext *avctx)
Definition vaapi_vpp.h:61
VAContextID va_context
Definition vaapi_vpp.h:46
AVVAAPIDeviceContext * hwctx
Definition vaapi_vpp.h:41
Definition swscale.c:71
#define av_log(a,...)
static AVFormatContext * ctx
Definition movenc.c:49
int ff_vaapi_vpp_config_output(AVFilterLink *outlink)
Definition vaapi_vpp.c:97
int ff_vaapi_vpp_config_input(AVFilterLink *inlink)
Definition vaapi_vpp.c:71
int ff_vaapi_vpp_query_formats(const AVFilterContext *avctx, AVFilterFormatsConfig **cfg_in, AVFilterFormatsConfig **cfg_out)
Definition vaapi_vpp.c:29
void ff_vaapi_vpp_pipeline_uninit(AVFilterContext *avctx)
Definition vaapi_vpp.c:45
void ff_vaapi_vpp_ctx_init(AVFilterContext *avctx)
Definition vaapi_vpp.c:714
int ff_vaapi_vpp_make_param_buffers(AVFilterContext *avctx, int type, const void *data, size_t size, int count)
Definition vaapi_vpp.c:582
int ff_vaapi_vpp_init_params(AVFilterContext *avctx, VAProcPipelineParameterBuffer *params, const AVFrame *input_frame, AVFrame *output_frame)
Definition vaapi_vpp.c:533
int ff_vaapi_vpp_render_picture(AVFilterContext *avctx, VAProcPipelineParameterBuffer *params, AVFrame *output_frame)
Definition vaapi_vpp.c:707
void ff_vaapi_vpp_ctx_uninit(AVFilterContext *avctx)
Definition vaapi_vpp.c:728
#define MAX_REFERENCES
#define D(name)
static const AVClass deint_vaapi_class
static av_cold int deint_vaapi_init(AVFilterContext *avctx)
#define MAX_REFERENCES
static int deint_vaapi_config_output(AVFilterLink *outlink)
static int deint_vaapi_filter_frame(AVFilterLink *inlink, AVFrame *input_frame)
static const AVOption deint_vaapi_options[]
static void deint_vaapi_pipeline_uninit(AVFilterContext *avctx)
static int deint_vaapi_build_filter_params(AVFilterContext *avctx)
static const char * deint_vaapi_mode_name(int mode)
#define OFFSET(x)
static const AVFilterPad deint_vaapi_outputs[]
static const AVFilterPad deint_vaapi_inputs[]
static int deint_vaapi_request_frame(AVFilterLink *link)
AVFrame * ff_get_video_buffer(AVFilterLink *link, int w, int h)
Request a picture buffer with a specific set of permissions.
Definition video.c:89