Skip to content

Commit 6739467

Browse files
ruiling-songlizhong1008
authored andcommitted
lavf: make overlay_qsv work based on framesync.
the previous version which was cherry-picked does not work with FFmpeg framework, because ff_request_frame() was totally different between Libav and FFmpeg. So, I make it work through using framesync. There are still some issues to be fixed in later patch. v2: add .preinit field to initilize framesync options. export more options like vf_overlay.c Signed-off-by: Ruiling Song <ruiling.song@intel.com>
1 parent c49ac0b commit 6739467

2 files changed

Lines changed: 78 additions & 139 deletions

File tree

libavfilter/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ OBJS-$(CONFIG_OCV_FILTER) += vf_libopencv.o
252252
OBJS-$(CONFIG_OPENCL) += deshake_opencl.o unsharp_opencl.o
253253
OBJS-$(CONFIG_OSCILLOSCOPE_FILTER) += vf_datascope.o
254254
OBJS-$(CONFIG_OVERLAY_FILTER) += vf_overlay.o framesync.o
255-
OBJS-$(CONFIG_OVERLAY_QSV_FILTER) += vf_overlay_qsv.o
255+
OBJS-$(CONFIG_OVERLAY_QSV_FILTER) += vf_overlay_qsv.o framesync.o
256256
OBJS-$(CONFIG_OWDENOISE_FILTER) += vf_owdenoise.o
257257
OBJS-$(CONFIG_PAD_FILTER) += vf_pad.o
258258
OBJS-$(CONFIG_PALETTEGEN_FILTER) += vf_palettegen.o

libavfilter/vf_overlay_qsv.c

Lines changed: 77 additions & 138 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include "formats.h"
3737
#include "video.h"
3838

39+
#include "framesync.h"
3940
#include "qsvvpp.h"
4041

4142
#define MAIN 0
@@ -56,14 +57,10 @@ enum var_name {
5657
VAR_VARS_NB
5758
};
5859

59-
enum EOFAction {
60-
EOF_ACTION_REPEAT,
61-
EOF_ACTION_ENDALL
62-
};
63-
6460
typedef struct QSVOverlayContext {
6561
const AVClass *class;
6662

63+
FFFrameSync fs;
6764
QSVVPPContext *qsv;
6865
QSVVPPParam qsv_param;
6966
mfxExtVPPComposite comp_conf;
@@ -72,10 +69,6 @@ typedef struct QSVOverlayContext {
7269
char *overlay_ox, *overlay_oy, *overlay_ow, *overlay_oh;
7370
uint16_t overlay_alpha, overlay_pixel_alpha;
7471

75-
enum EOFAction eof_action; /* action to take on EOF from source */
76-
77-
AVFrame *main;
78-
AVFrame *over_prev, *over_next;
7972
} QSVOverlayContext;
8073

8174
static const char *const var_names[] = {
@@ -90,20 +83,25 @@ static const char *const var_names[] = {
9083
NULL
9184
};
9285

93-
static const AVOption options[] = {
86+
static const AVOption overlay_qsv_options[] = {
9487
{ "x", "Overlay x position", OFFSET(overlay_ox), AV_OPT_TYPE_STRING, { .str="0"}, 0, 255, .flags = FLAGS},
9588
{ "y", "Overlay y position", OFFSET(overlay_oy), AV_OPT_TYPE_STRING, { .str="0"}, 0, 255, .flags = FLAGS},
9689
{ "w", "Overlay width", OFFSET(overlay_ow), AV_OPT_TYPE_STRING, { .str="overlay_iw"}, 0, 255, .flags = FLAGS},
9790
{ "h", "Overlay height", OFFSET(overlay_oh), AV_OPT_TYPE_STRING, { .str="overlay_ih*w/overlay_iw"}, 0, 255, .flags = FLAGS},
9891
{ "alpha", "Overlay global alpha", OFFSET(overlay_alpha), AV_OPT_TYPE_INT, { .i64 = 255}, 0, 255, .flags = FLAGS},
9992
{ "eof_action", "Action to take when encountering EOF from secondary input ",
100-
OFFSET(eof_action), AV_OPT_TYPE_INT, { .i64 = EOF_ACTION_REPEAT },
101-
EOF_ACTION_REPEAT, EOF_ACTION_ENDALL, .flags = FLAGS, "eof_action" },
102-
{ "repeat", "Repeat the previous frame.", 0, AV_OPT_TYPE_CONST, { .i64 = EOF_ACTION_REPEAT }, .flags = FLAGS, "eof_action" },
103-
{ "endall", "End both streams.", 0, AV_OPT_TYPE_CONST, { .i64 = EOF_ACTION_ENDALL }, .flags = FLAGS, "eof_action" },
93+
OFFSET(fs.opt_eof_action), AV_OPT_TYPE_INT, { .i64 = EOF_ACTION_REPEAT },
94+
EOF_ACTION_REPEAT, EOF_ACTION_PASS, .flags = FLAGS, "eof_action" },
95+
{ "repeat", "Repeat the previous frame.", 0, AV_OPT_TYPE_CONST, { .i64 = EOF_ACTION_REPEAT }, .flags = FLAGS, "eof_action" },
96+
{ "endall", "End both streams.", 0, AV_OPT_TYPE_CONST, { .i64 = EOF_ACTION_ENDALL }, .flags = FLAGS, "eof_action" },
97+
{ "pass", "Pass through the main input.", 0, AV_OPT_TYPE_CONST, { .i64 = EOF_ACTION_PASS }, .flags = FLAGS, "eof_action" },
98+
{ "shortest", "force termination when the shortest input terminates", OFFSET(fs.opt_shortest), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS },
99+
{ "repeatlast", "repeat overlay of the last overlay frame", OFFSET(fs.opt_repeatlast), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGS },
104100
{ NULL }
105101
};
106102

103+
FRAMESYNC_DEFINE_CLASS(overlay_qsv, QSVOverlayContext, fs);
104+
107105
static int eval_expr(AVFilterContext *ctx)
108106
{
109107
QSVOverlayContext *vpp = ctx->priv;
@@ -230,12 +228,53 @@ static int config_overlay_input(AVFilterLink *inlink)
230228
return 0;
231229
}
232230

231+
static int process_frame(FFFrameSync *fs)
232+
{
233+
AVFilterContext *ctx = fs->parent;
234+
QSVOverlayContext *s = fs->opaque;
235+
AVFrame *frame = NULL;
236+
int ret = 0, i;
237+
238+
for (i = 0; i < ctx->nb_inputs; i++) {
239+
ret = ff_framesync_get_frame(fs, i, &frame, 0);
240+
if (ret == 0)
241+
ret = ff_qsvvpp_filter_frame(s->qsv, ctx->inputs[i], frame);
242+
if (ret < 0)
243+
break;
244+
}
245+
246+
return ret;
247+
}
248+
249+
static int init_framesync(AVFilterContext *ctx)
250+
{
251+
QSVOverlayContext *s = ctx->priv;
252+
int ret, i;
253+
254+
s->fs.on_event = process_frame;
255+
s->fs.opaque = s;
256+
ret = ff_framesync_init(&s->fs, ctx, ctx->nb_inputs);
257+
if (ret < 0)
258+
return ret;
259+
260+
for (i = 0; i < ctx->nb_inputs; i++) {
261+
FFFrameSyncIn *in = &s->fs.in[i];
262+
in->before = EXT_STOP;
263+
in->after = EXT_INFINITY;
264+
in->sync = i ? 1 : 2;
265+
in->time_base = ctx->inputs[i]->time_base;
266+
}
267+
268+
return ff_framesync_configure(&s->fs);
269+
}
270+
233271
static int config_output(AVFilterLink *outlink)
234272
{
235273
AVFilterContext *ctx = outlink->src;
236274
QSVOverlayContext *vpp = ctx->priv;
237275
AVFilterLink *in0 = ctx->inputs[0];
238276
AVFilterLink *in1 = ctx->inputs[1];
277+
int ret;
239278

240279
av_log(ctx, AV_LOG_DEBUG, "Output is of %s.\n", av_get_pix_fmt_name(outlink->format));
241280
if ((in0->format == AV_PIX_FMT_QSV && in1->format != AV_PIX_FMT_QSV) ||
@@ -257,121 +296,27 @@ static int config_output(AVFilterLink *outlink)
257296
outlink->frame_rate = in0->frame_rate;
258297
outlink->time_base = av_inv_q(outlink->frame_rate);
259298

260-
return ff_qsvvpp_create(ctx, &vpp->qsv, &vpp->qsv_param);
261-
}
262-
263-
static int blend_frame(AVFilterContext *ctx, AVFrame *mpic, AVFrame *opic)
264-
{
265-
int ret = 0;
266-
QSVOverlayContext *vpp = ctx->priv;
267-
AVFrame *opic_copy = NULL;
268-
269-
ret = ff_qsvvpp_filter_frame(vpp->qsv, ctx->inputs[0], mpic);
270-
if (ret == 0 || ret == AVERROR(EAGAIN)) {
271-
/* Reference the overlay frame. Because:
272-
* 1. ff_qsvvpp_filter_frame will take control of the given frame
273-
* 2. We need to repeat the overlay frame when 2nd input goes into EOF
274-
*/
275-
opic_copy = av_frame_clone(opic);
276-
if (!opic_copy)
277-
return AVERROR(ENOMEM);
278-
279-
ret = ff_qsvvpp_filter_frame(vpp->qsv, ctx->inputs[1], opic_copy);
280-
}
281-
282-
return ret;
283-
}
284-
285-
static int handle_overlay_eof(AVFilterContext *ctx)
286-
{
287-
int ret = 0;
288-
QSVOverlayContext *s = ctx->priv;
289-
/* Repeat previous frame on secondary input */
290-
if (s->over_prev && s->eof_action == EOF_ACTION_REPEAT)
291-
ret = blend_frame(ctx, s->main, s->over_prev);
292-
/* End both streams */
293-
else if (s->eof_action == EOF_ACTION_ENDALL)
294-
return AVERROR_EOF;
295-
296-
s->main = NULL;
299+
ret = init_framesync(ctx);
300+
if (ret < 0)
301+
return ret;
297302

298-
return ret;
303+
return ff_qsvvpp_create(ctx, &vpp->qsv, &vpp->qsv_param);
299304
}
300305

301-
static int request_frame(AVFilterLink *outlink)
302-
{
303-
AVFilterContext *ctx = outlink->src;
304-
QSVOverlayContext *s = ctx->priv;
305-
AVRational tb_main = ctx->inputs[MAIN]->time_base;
306-
AVRational tb_over = ctx->inputs[OVERLAY]->time_base;
307-
int ret = 0;
308-
309-
/* get a frame on the main input */
310-
if (!s->main) {
311-
ret = ff_request_frame(ctx->inputs[MAIN]);
312-
if (ret < 0)
313-
return ret;
314-
}
315-
316-
/* get a new frame on the overlay input, on EOF check setting 'eof_action' */
317-
if (!s->over_next) {
318-
ret = ff_request_frame(ctx->inputs[OVERLAY]);
319-
if (ret == AVERROR_EOF)
320-
return handle_overlay_eof(ctx);
321-
else if (ret < 0)
322-
return ret;
323-
}
324-
325-
while (s->main->pts != AV_NOPTS_VALUE &&
326-
s->over_next->pts != AV_NOPTS_VALUE &&
327-
av_compare_ts(s->over_next->pts, tb_over, s->main->pts, tb_main) < 0) {
328-
av_frame_free(&s->over_prev);
329-
FFSWAP(AVFrame*, s->over_prev, s->over_next);
330-
331-
ret = ff_request_frame(ctx->inputs[OVERLAY]);
332-
if (ret == AVERROR_EOF)
333-
return handle_overlay_eof(ctx);
334-
else if (ret < 0)
335-
return ret;
336-
}
337-
338-
if (s->main->pts == AV_NOPTS_VALUE ||
339-
s->over_next->pts == AV_NOPTS_VALUE ||
340-
!av_compare_ts(s->over_next->pts, tb_over, s->main->pts, tb_main)) {
341-
ret = blend_frame(ctx, s->main, s->over_next);
342-
av_frame_free(&s->over_prev);
343-
FFSWAP(AVFrame*, s->over_prev, s->over_next);
344-
} else if (s->over_prev) {
345-
ret = blend_frame(ctx, s->main, s->over_prev);
346-
} else {
347-
av_frame_free(&s->main);
348-
ret = AVERROR(EAGAIN);
349-
}
350-
351-
s->main = NULL;
352-
353-
return ret;
354-
}
306+
/*
307+
* Callback for qsvvpp
308+
* @Note: qsvvpp composition does not generate PTS for result frame.
309+
* so we assign the PTS from framesync to the output frame.
310+
*/
355311

356-
static int filter_frame_main(AVFilterLink *inlink, AVFrame *frame)
312+
static int filter_callback(AVFilterLink *outlink, AVFrame *frame)
357313
{
358-
QSVOverlayContext *s = inlink->dst->priv;
359-
360-
av_assert0(!s->main);
361-
s->main = frame;
362-
363-
return 0;
314+
QSVOverlayContext *s = outlink->src->priv;
315+
frame->pts = av_rescale_q(s->fs.pts,
316+
s->fs.time_base, outlink->time_base);
317+
return ff_filter_frame(outlink, frame);
364318
}
365319

366-
static int filter_frame_overlay(AVFilterLink *inlink, AVFrame *frame)
367-
{
368-
QSVOverlayContext *s = inlink->dst->priv;
369-
370-
av_assert0(!s->over_next);
371-
s->over_next = frame;
372-
373-
return 0;
374-
}
375320

376321
static int overlay_qsv_init(AVFilterContext *ctx)
377322
{
@@ -387,7 +332,7 @@ static int overlay_qsv_init(AVFilterContext *ctx)
387332
return AVERROR(ENOMEM);
388333

389334
/* initialize QSVVPP params */
390-
vpp->qsv_param.filter_frame = NULL;
335+
vpp->qsv_param.filter_frame = filter_callback;
391336
vpp->qsv_param.ext_buf = av_mallocz(sizeof(*vpp->qsv_param.ext_buf));
392337
if (!vpp->qsv_param.ext_buf)
393338
return AVERROR(ENOMEM);
@@ -404,14 +349,18 @@ static void overlay_qsv_uninit(AVFilterContext *ctx)
404349
{
405350
QSVOverlayContext *vpp = ctx->priv;
406351

407-
av_frame_free(&vpp->main);
408-
av_frame_free(&vpp->over_prev);
409-
av_frame_free(&vpp->over_next);
410352
ff_qsvvpp_free(&vpp->qsv);
353+
ff_framesync_uninit(&vpp->fs);
411354
av_freep(&vpp->comp_conf.InputStream);
412355
av_freep(&vpp->qsv_param.ext_buf);
413356
}
414357

358+
static int activate(AVFilterContext *ctx)
359+
{
360+
QSVOverlayContext *s = ctx->priv;
361+
return ff_framesync_activate(&s->fs);
362+
}
363+
415364
static int overlay_qsv_query_formats(AVFilterContext *ctx)
416365
{
417366
int i;
@@ -444,27 +393,16 @@ static int overlay_qsv_query_formats(AVFilterContext *ctx)
444393
return 0;
445394
}
446395

447-
static const AVClass overlay_qsv_class = {
448-
.class_name = "overlay_qsv",
449-
.item_name = av_default_item_name,
450-
.option = options,
451-
.version = LIBAVUTIL_VERSION_INT,
452-
};
453-
454396
static const AVFilterPad overlay_qsv_inputs[] = {
455397
{
456398
.name = "main",
457399
.type = AVMEDIA_TYPE_VIDEO,
458-
.filter_frame = filter_frame_main,
459400
.config_props = config_main_input,
460-
.needs_fifo = 1,
461401
},
462402
{
463403
.name = "overlay",
464404
.type = AVMEDIA_TYPE_VIDEO,
465-
.filter_frame = filter_frame_overlay,
466405
.config_props = config_overlay_input,
467-
.needs_fifo = 1,
468406
},
469407
{ NULL }
470408
};
@@ -474,7 +412,6 @@ static const AVFilterPad overlay_qsv_outputs[] = {
474412
.name = "default",
475413
.type = AVMEDIA_TYPE_VIDEO,
476414
.config_props = config_output,
477-
.request_frame = request_frame,
478415
},
479416
{ NULL }
480417
};
@@ -484,8 +421,10 @@ AVFilter ff_vf_overlay_qsv = {
484421
.description = NULL_IF_CONFIG_SMALL("Quick Sync Video overlay."),
485422
.priv_size = sizeof(QSVOverlayContext),
486423
.query_formats = overlay_qsv_query_formats,
424+
.preinit = overlay_qsv_framesync_preinit,
487425
.init = overlay_qsv_init,
488426
.uninit = overlay_qsv_uninit,
427+
.activate = activate,
489428
.inputs = overlay_qsv_inputs,
490429
.outputs = overlay_qsv_outputs,
491430
.priv_class = &overlay_qsv_class,

0 commit comments

Comments
 (0)