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-
6460typedef 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
8174static 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+
107105static 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+
233271static 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
376321static 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+
415364static 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-
454396static 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