2 * Copyright (c) 2010 Stefano Sabatini
3 * Copyright (c) 2010 Baptiste Coudurier
4 * Copyright (c) 2007 Bobby Bingham
6 * This file is part of FFmpeg.
8 * FFmpeg is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * FFmpeg is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with FFmpeg; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 * overlay one video on top of another
30 #include "libavutil/common.h"
31 #include "libavutil/eval.h"
32 #include "libavutil/avstring.h"
33 #include "libavutil/pixdesc.h"
34 #include "libavutil/imgutils.h"
35 #include "libavutil/mathematics.h"
36 #include "libavutil/opt.h"
37 #include "libavutil/timestamp.h"
39 #include "dualinput.h"
40 #include "drawutils.h"
43 static const char *const var_names
[] = {
44 "main_w", "W", ///< width of the main video
45 "main_h", "H", ///< height of the main video
46 "overlay_w", "w", ///< width of the overlay video
47 "overlay_h", "h", ///< height of the overlay video
52 "n", ///< number of frame
53 "pos", ///< position in the file
54 "t", ///< timestamp expressed in seconds
61 VAR_OVERLAY_W
, VAR_OW
,
62 VAR_OVERLAY_H
, VAR_OH
,
79 static const char * const eof_action_str
[] = {
80 "repeat", "endall", "pass"
95 typedef struct OverlayContext
{
97 int x
, y
; ///< position of overlayed picture
100 uint8_t main_is_packed_rgb
;
101 uint8_t main_rgba_map
[4];
102 uint8_t main_has_alpha
;
103 uint8_t overlay_is_packed_rgb
;
104 uint8_t overlay_rgba_map
[4];
105 uint8_t overlay_has_alpha
;
106 enum OverlayFormat
{ OVERLAY_FORMAT_YUV420
, OVERLAY_FORMAT_YUV422
, OVERLAY_FORMAT_YUV444
, OVERLAY_FORMAT_RGB
, OVERLAY_FORMAT_NB
} format
;
107 enum EvalMode
{ EVAL_MODE_INIT
, EVAL_MODE_FRAME
, EVAL_MODE_NB
} eval_mode
;
109 FFDualInputContext dinput
;
111 int main_pix_step
[4]; ///< steps per pixel for each plane of the main output
112 int overlay_pix_step
[4]; ///< steps per pixel for each plane of the overlay
113 int hsub
, vsub
; ///< chroma subsampling values
115 double var_values
[VAR_VARS_NB
];
116 char *x_expr
, *y_expr
;
118 enum EOFAction eof_action
; ///< action to take on EOF from source
120 AVExpr
*x_pexpr
, *y_pexpr
;
123 static av_cold
void uninit(AVFilterContext
*ctx
)
125 OverlayContext
*s
= ctx
->priv
;
127 ff_dualinput_uninit(&s
->dinput
);
128 av_expr_free(s
->x_pexpr
); s
->x_pexpr
= NULL
;
129 av_expr_free(s
->y_pexpr
); s
->y_pexpr
= NULL
;
132 static inline int normalize_xy(double d
, int chroma_sub
)
136 return (int)d
& ~((1 << chroma_sub
) - 1);
139 static void eval_expr(AVFilterContext
*ctx
)
141 OverlayContext
*s
= ctx
->priv
;
143 s
->var_values
[VAR_X
] = av_expr_eval(s
->x_pexpr
, s
->var_values
, NULL
);
144 s
->var_values
[VAR_Y
] = av_expr_eval(s
->y_pexpr
, s
->var_values
, NULL
);
145 s
->var_values
[VAR_X
] = av_expr_eval(s
->x_pexpr
, s
->var_values
, NULL
);
146 s
->x
= normalize_xy(s
->var_values
[VAR_X
], s
->hsub
);
147 s
->y
= normalize_xy(s
->var_values
[VAR_Y
], s
->vsub
);
150 static int set_expr(AVExpr
**pexpr
, const char *expr
, const char *option
, void *log_ctx
)
157 ret
= av_expr_parse(pexpr
, expr
, var_names
,
158 NULL
, NULL
, NULL
, NULL
, 0, log_ctx
);
160 av_log(log_ctx
, AV_LOG_ERROR
,
161 "Error when evaluating the expression '%s' for %s\n",
171 static int process_command(AVFilterContext
*ctx
, const char *cmd
, const char *args
,
172 char *res
, int res_len
, int flags
)
174 OverlayContext
*s
= ctx
->priv
;
177 if (!strcmp(cmd
, "x"))
178 ret
= set_expr(&s
->x_pexpr
, args
, cmd
, ctx
);
179 else if (!strcmp(cmd
, "y"))
180 ret
= set_expr(&s
->y_pexpr
, args
, cmd
, ctx
);
182 ret
= AVERROR(ENOSYS
);
187 if (s
->eval_mode
== EVAL_MODE_INIT
) {
189 av_log(ctx
, AV_LOG_VERBOSE
, "x:%f xi:%d y:%f yi:%d\n",
190 s
->var_values
[VAR_X
], s
->x
,
191 s
->var_values
[VAR_Y
], s
->y
);
196 static int query_formats(AVFilterContext
*ctx
)
198 OverlayContext
*s
= ctx
->priv
;
200 /* overlay formats contains alpha, for avoiding conversion with alpha information loss */
201 static const enum AVPixelFormat main_pix_fmts_yuv420
[] = {
202 AV_PIX_FMT_YUV420P
, AV_PIX_FMT_YUVA420P
, AV_PIX_FMT_NONE
204 static const enum AVPixelFormat overlay_pix_fmts_yuv420
[] = {
205 AV_PIX_FMT_YUVA420P
, AV_PIX_FMT_NONE
208 static const enum AVPixelFormat main_pix_fmts_yuv422
[] = {
209 AV_PIX_FMT_YUV422P
, AV_PIX_FMT_YUVA422P
, AV_PIX_FMT_NONE
211 static const enum AVPixelFormat overlay_pix_fmts_yuv422
[] = {
212 AV_PIX_FMT_YUVA422P
, AV_PIX_FMT_NONE
215 static const enum AVPixelFormat main_pix_fmts_yuv444
[] = {
216 AV_PIX_FMT_YUV444P
, AV_PIX_FMT_YUVA444P
, AV_PIX_FMT_NONE
218 static const enum AVPixelFormat overlay_pix_fmts_yuv444
[] = {
219 AV_PIX_FMT_YUVA444P
, AV_PIX_FMT_NONE
222 static const enum AVPixelFormat main_pix_fmts_rgb
[] = {
223 AV_PIX_FMT_ARGB
, AV_PIX_FMT_RGBA
,
224 AV_PIX_FMT_ABGR
, AV_PIX_FMT_BGRA
,
225 AV_PIX_FMT_RGB24
, AV_PIX_FMT_BGR24
,
228 static const enum AVPixelFormat overlay_pix_fmts_rgb
[] = {
229 AV_PIX_FMT_ARGB
, AV_PIX_FMT_RGBA
,
230 AV_PIX_FMT_ABGR
, AV_PIX_FMT_BGRA
,
234 AVFilterFormats
*main_formats
;
235 AVFilterFormats
*overlay_formats
;
238 case OVERLAY_FORMAT_YUV420
:
239 main_formats
= ff_make_format_list(main_pix_fmts_yuv420
);
240 overlay_formats
= ff_make_format_list(overlay_pix_fmts_yuv420
);
242 case OVERLAY_FORMAT_YUV422
:
243 main_formats
= ff_make_format_list(main_pix_fmts_yuv422
);
244 overlay_formats
= ff_make_format_list(overlay_pix_fmts_yuv422
);
246 case OVERLAY_FORMAT_YUV444
:
247 main_formats
= ff_make_format_list(main_pix_fmts_yuv444
);
248 overlay_formats
= ff_make_format_list(overlay_pix_fmts_yuv444
);
250 case OVERLAY_FORMAT_RGB
:
251 main_formats
= ff_make_format_list(main_pix_fmts_rgb
);
252 overlay_formats
= ff_make_format_list(overlay_pix_fmts_rgb
);
258 ff_formats_ref(main_formats
, &ctx
->inputs
[MAIN
]->out_formats
);
259 ff_formats_ref(overlay_formats
, &ctx
->inputs
[OVERLAY
]->out_formats
);
260 ff_formats_ref(main_formats
, &ctx
->outputs
[MAIN
]->in_formats
);
265 static const enum AVPixelFormat alpha_pix_fmts
[] = {
266 AV_PIX_FMT_YUVA420P
, AV_PIX_FMT_YUVA444P
,
267 AV_PIX_FMT_ARGB
, AV_PIX_FMT_ABGR
, AV_PIX_FMT_RGBA
,
268 AV_PIX_FMT_BGRA
, AV_PIX_FMT_NONE
271 static int config_input_main(AVFilterLink
*inlink
)
273 OverlayContext
*s
= inlink
->dst
->priv
;
274 const AVPixFmtDescriptor
*pix_desc
= av_pix_fmt_desc_get(inlink
->format
);
276 av_image_fill_max_pixsteps(s
->main_pix_step
, NULL
, pix_desc
);
278 s
->hsub
= pix_desc
->log2_chroma_w
;
279 s
->vsub
= pix_desc
->log2_chroma_h
;
281 s
->main_is_packed_rgb
=
282 ff_fill_rgba_map(s
->main_rgba_map
, inlink
->format
) >= 0;
283 s
->main_has_alpha
= ff_fmt_is_in(inlink
->format
, alpha_pix_fmts
);
287 static int config_input_overlay(AVFilterLink
*inlink
)
289 AVFilterContext
*ctx
= inlink
->dst
;
290 OverlayContext
*s
= inlink
->dst
->priv
;
292 const AVPixFmtDescriptor
*pix_desc
= av_pix_fmt_desc_get(inlink
->format
);
294 av_image_fill_max_pixsteps(s
->overlay_pix_step
, NULL
, pix_desc
);
296 /* Finish the configuration by evaluating the expressions
297 now when both inputs are configured. */
298 s
->var_values
[VAR_MAIN_W
] = s
->var_values
[VAR_MW
] = ctx
->inputs
[MAIN
]->w
;
299 s
->var_values
[VAR_MAIN_H
] = s
->var_values
[VAR_MH
] = ctx
->inputs
[MAIN
]->h
;
300 s
->var_values
[VAR_OVERLAY_W
] = s
->var_values
[VAR_OW
] = ctx
->inputs
[OVERLAY
]->w
;
301 s
->var_values
[VAR_OVERLAY_H
] = s
->var_values
[VAR_OH
] = ctx
->inputs
[OVERLAY
]->h
;
302 s
->var_values
[VAR_HSUB
] = 1<<pix_desc
->log2_chroma_w
;
303 s
->var_values
[VAR_VSUB
] = 1<<pix_desc
->log2_chroma_h
;
304 s
->var_values
[VAR_X
] = NAN
;
305 s
->var_values
[VAR_Y
] = NAN
;
306 s
->var_values
[VAR_N
] = 0;
307 s
->var_values
[VAR_T
] = NAN
;
308 s
->var_values
[VAR_POS
] = NAN
;
310 if ((ret
= set_expr(&s
->x_pexpr
, s
->x_expr
, "x", ctx
)) < 0 ||
311 (ret
= set_expr(&s
->y_pexpr
, s
->y_expr
, "y", ctx
)) < 0)
314 s
->overlay_is_packed_rgb
=
315 ff_fill_rgba_map(s
->overlay_rgba_map
, inlink
->format
) >= 0;
316 s
->overlay_has_alpha
= ff_fmt_is_in(inlink
->format
, alpha_pix_fmts
);
318 if (s
->eval_mode
== EVAL_MODE_INIT
) {
320 av_log(ctx
, AV_LOG_VERBOSE
, "x:%f xi:%d y:%f yi:%d\n",
321 s
->var_values
[VAR_X
], s
->x
,
322 s
->var_values
[VAR_Y
], s
->y
);
325 av_log(ctx
, AV_LOG_VERBOSE
,
326 "main w:%d h:%d fmt:%s overlay w:%d h:%d fmt:%s eof_action:%s\n",
327 ctx
->inputs
[MAIN
]->w
, ctx
->inputs
[MAIN
]->h
,
328 av_get_pix_fmt_name(ctx
->inputs
[MAIN
]->format
),
329 ctx
->inputs
[OVERLAY
]->w
, ctx
->inputs
[OVERLAY
]->h
,
330 av_get_pix_fmt_name(ctx
->inputs
[OVERLAY
]->format
),
331 eof_action_str
[s
->eof_action
]);
335 static int config_output(AVFilterLink
*outlink
)
337 AVFilterContext
*ctx
= outlink
->src
;
338 OverlayContext
*s
= ctx
->priv
;
341 if ((ret
= ff_dualinput_init(ctx
, &s
->dinput
)) < 0)
344 outlink
->w
= ctx
->inputs
[MAIN
]->w
;
345 outlink
->h
= ctx
->inputs
[MAIN
]->h
;
346 outlink
->time_base
= ctx
->inputs
[MAIN
]->time_base
;
351 // divide by 255 and round to nearest
352 // apply a fast variant: (X+127)/255 = ((X+127)*257+257)>>16 = ((X+128)*257)>>16
353 #define FAST_DIV255(x) ((((x) + 128) * 257) >> 16)
355 // calculate the unpremultiplied alpha, applying the general equation:
356 // alpha = alpha_overlay / ( (alpha_main + alpha_overlay) - (alpha_main * alpha_overlay) )
357 // (((x) << 16) - ((x) << 9) + (x)) is a faster version of: 255 * 255 * x
358 // ((((x) + (y)) << 8) - ((x) + (y)) - (y) * (x)) is a faster version of: 255 * (x + y)
359 #define UNPREMULTIPLY_ALPHA(x, y) ((((x) << 16) - ((x) << 9) + (x)) / ((((x) + (y)) << 8) - ((x) + (y)) - (y) * (x)))
362 * Blend image in src to destination buffer dst at position (x, y).
364 static void blend_image(AVFilterContext
*ctx
,
365 AVFrame
*dst
, const AVFrame
*src
,
368 OverlayContext
*s
= ctx
->priv
;
369 int i
, imax
, j
, jmax
, k
, kmax
;
370 const int src_w
= src
->width
;
371 const int src_h
= src
->height
;
372 const int dst_w
= dst
->width
;
373 const int dst_h
= dst
->height
;
375 if (x
>= dst_w
|| x
+src_w
< 0 ||
376 y
>= dst_h
|| y
+src_h
< 0)
377 return; /* no intersection */
379 if (s
->main_is_packed_rgb
) {
380 uint8_t alpha
; ///< the amount of overlay to blend on to main
381 const int dr
= s
->main_rgba_map
[R
];
382 const int dg
= s
->main_rgba_map
[G
];
383 const int db
= s
->main_rgba_map
[B
];
384 const int da
= s
->main_rgba_map
[A
];
385 const int dstep
= s
->main_pix_step
[0];
386 const int sr
= s
->overlay_rgba_map
[R
];
387 const int sg
= s
->overlay_rgba_map
[G
];
388 const int sb
= s
->overlay_rgba_map
[B
];
389 const int sa
= s
->overlay_rgba_map
[A
];
390 const int sstep
= s
->overlay_pix_step
[0];
391 const int main_has_alpha
= s
->main_has_alpha
;
392 uint8_t *s
, *sp
, *d
, *dp
;
395 sp
= src
->data
[0] + i
* src
->linesize
[0];
396 dp
= dst
->data
[0] + (y
+i
) * dst
->linesize
[0];
398 for (imax
= FFMIN(-y
+ dst_h
, src_h
); i
< imax
; i
++) {
401 d
= dp
+ (x
+j
) * dstep
;
403 for (jmax
= FFMIN(-x
+ dst_w
, src_w
); j
< jmax
; j
++) {
406 // if the main channel has an alpha channel, alpha has to be calculated
407 // to create an un-premultiplied (straight) alpha value
408 if (main_has_alpha
&& alpha
!= 0 && alpha
!= 255) {
409 uint8_t alpha_d
= d
[da
];
410 alpha
= UNPREMULTIPLY_ALPHA(alpha
, alpha_d
);
422 // main_value = main_value * (1 - alpha) + overlay_value * alpha
423 // since alpha is in the range 0-255, the result must divided by 255
424 d
[dr
] = FAST_DIV255(d
[dr
] * (255 - alpha
) + s
[sr
] * alpha
);
425 d
[dg
] = FAST_DIV255(d
[dg
] * (255 - alpha
) + s
[sg
] * alpha
);
426 d
[db
] = FAST_DIV255(d
[db
] * (255 - alpha
) + s
[sb
] * alpha
);
428 if (main_has_alpha
) {
436 // apply alpha compositing: main_alpha += (1-main_alpha) * overlay_alpha
437 d
[da
] += FAST_DIV255((255 - d
[da
]) * s
[sa
]);
443 dp
+= dst
->linesize
[0];
444 sp
+= src
->linesize
[0];
447 const int main_has_alpha
= s
->main_has_alpha
;
448 if (main_has_alpha
) {
449 uint8_t alpha
; ///< the amount of overlay to blend on to main
450 uint8_t *s
, *sa
, *d
, *da
;
453 sa
= src
->data
[3] + i
* src
->linesize
[3];
454 da
= dst
->data
[3] + (y
+i
) * dst
->linesize
[3];
456 for (imax
= FFMIN(-y
+ dst_h
, src_h
); i
< imax
; i
++) {
461 for (jmax
= FFMIN(-x
+ dst_w
, src_w
); j
< jmax
; j
++) {
463 if (alpha
!= 0 && alpha
!= 255) {
464 uint8_t alpha_d
= *d
;
465 alpha
= UNPREMULTIPLY_ALPHA(alpha
, alpha_d
);
474 // apply alpha compositing: main_alpha += (1-main_alpha) * overlay_alpha
475 *d
+= FAST_DIV255((255 - *d
) * *s
);
480 da
+= dst
->linesize
[3];
481 sa
+= src
->linesize
[3];
484 for (i
= 0; i
< 3; i
++) {
485 int hsub
= i
? s
->hsub
: 0;
486 int vsub
= i
? s
->vsub
: 0;
487 int src_wp
= FF_CEIL_RSHIFT(src_w
, hsub
);
488 int src_hp
= FF_CEIL_RSHIFT(src_h
, vsub
);
489 int dst_wp
= FF_CEIL_RSHIFT(dst_w
, hsub
);
490 int dst_hp
= FF_CEIL_RSHIFT(dst_h
, vsub
);
493 uint8_t *s
, *sp
, *d
, *dp
, *a
, *ap
;
496 sp
= src
->data
[i
] + j
* src
->linesize
[i
];
497 dp
= dst
->data
[i
] + (yp
+j
) * dst
->linesize
[i
];
498 ap
= src
->data
[3] + (j
<<vsub
) * src
->linesize
[3];
500 for (jmax
= FFMIN(-yp
+ dst_hp
, src_hp
); j
< jmax
; j
++) {
506 for (kmax
= FFMIN(-xp
+ dst_wp
, src_wp
); k
< kmax
; k
++) {
507 int alpha_v
, alpha_h
, alpha
;
509 // average alpha for color components, improve quality
510 if (hsub
&& vsub
&& j
+1 < src_hp
&& k
+1 < src_wp
) {
511 alpha
= (a
[0] + a
[src
->linesize
[3]] +
512 a
[1] + a
[src
->linesize
[3]+1]) >> 2;
513 } else if (hsub
|| vsub
) {
514 alpha_h
= hsub
&& k
+1 < src_wp
?
515 (a
[0] + a
[1]) >> 1 : a
[0];
516 alpha_v
= vsub
&& j
+1 < src_hp
?
517 (a
[0] + a
[src
->linesize
[3]]) >> 1 : a
[0];
518 alpha
= (alpha_v
+ alpha_h
) >> 1;
521 // if the main channel has an alpha channel, alpha has to be calculated
522 // to create an un-premultiplied (straight) alpha value
523 if (main_has_alpha
&& alpha
!= 0 && alpha
!= 255) {
524 // average alpha for color components, improve quality
526 if (hsub
&& vsub
&& j
+1 < src_hp
&& k
+1 < src_wp
) {
527 alpha_d
= (d
[0] + d
[src
->linesize
[3]] +
528 d
[1] + d
[src
->linesize
[3]+1]) >> 2;
529 } else if (hsub
|| vsub
) {
530 alpha_h
= hsub
&& k
+1 < src_wp
?
531 (d
[0] + d
[1]) >> 1 : d
[0];
532 alpha_v
= vsub
&& j
+1 < src_hp
?
533 (d
[0] + d
[src
->linesize
[3]]) >> 1 : d
[0];
534 alpha_d
= (alpha_v
+ alpha_h
) >> 1;
537 alpha
= UNPREMULTIPLY_ALPHA(alpha
, alpha_d
);
539 *d
= FAST_DIV255(*d
* (255 - alpha
) + *s
* alpha
);
544 dp
+= dst
->linesize
[i
];
545 sp
+= src
->linesize
[i
];
546 ap
+= (1 << vsub
) * src
->linesize
[3];
552 static AVFrame
*do_blend(AVFilterContext
*ctx
, AVFrame
*mainpic
,
553 const AVFrame
*second
)
555 OverlayContext
*s
= ctx
->priv
;
556 AVFilterLink
*inlink
= ctx
->inputs
[0];
558 if (s
->eval_mode
== EVAL_MODE_FRAME
) {
559 int64_t pos
= av_frame_get_pkt_pos(mainpic
);
561 s
->var_values
[VAR_N
] = inlink
->frame_count
;
562 s
->var_values
[VAR_T
] = mainpic
->pts
== AV_NOPTS_VALUE
?
563 NAN
: mainpic
->pts
* av_q2d(inlink
->time_base
);
564 s
->var_values
[VAR_POS
] = pos
== -1 ? NAN
: pos
;
567 av_log(ctx
, AV_LOG_DEBUG
, "n:%f t:%f pos:%f x:%f xi:%d y:%f yi:%d\n",
568 s
->var_values
[VAR_N
], s
->var_values
[VAR_T
], s
->var_values
[VAR_POS
],
569 s
->var_values
[VAR_X
], s
->x
,
570 s
->var_values
[VAR_Y
], s
->y
);
573 blend_image(ctx
, mainpic
, second
, s
->x
, s
->y
);
577 static int filter_frame(AVFilterLink
*inlink
, AVFrame
*inpicref
)
579 OverlayContext
*s
= inlink
->dst
->priv
;
580 av_log(inlink
->dst
, AV_LOG_DEBUG
, "Incoming frame (time:%s) from link #%d\n", av_ts2timestr(inpicref
->pts
, &inlink
->time_base
), FF_INLINK_IDX(inlink
));
581 return ff_dualinput_filter_frame(&s
->dinput
, inlink
, inpicref
);
584 static int request_frame(AVFilterLink
*outlink
)
586 OverlayContext
*s
= outlink
->src
->priv
;
587 return ff_dualinput_request_frame(&s
->dinput
, outlink
);
590 static av_cold
int init(AVFilterContext
*ctx
)
592 OverlayContext
*s
= ctx
->priv
;
594 if (s
->allow_packed_rgb
) {
595 av_log(ctx
, AV_LOG_WARNING
,
596 "The rgb option is deprecated and is overriding the format option, use format instead\n");
597 s
->format
= OVERLAY_FORMAT_RGB
;
599 if (!s
->dinput
.repeatlast
|| s
->eof_action
== EOF_ACTION_PASS
) {
600 s
->dinput
.repeatlast
= 0;
601 s
->eof_action
= EOF_ACTION_PASS
;
603 if (s
->dinput
.shortest
|| s
->eof_action
== EOF_ACTION_ENDALL
) {
604 s
->dinput
.shortest
= 1;
605 s
->eof_action
= EOF_ACTION_ENDALL
;
608 s
->dinput
.process
= do_blend
;
612 #define OFFSET(x) offsetof(OverlayContext, x)
613 #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
615 static const AVOption overlay_options
[] = {
616 { "x", "set the x expression", OFFSET(x_expr
), AV_OPT_TYPE_STRING
, {.str
= "0"}, CHAR_MIN
, CHAR_MAX
, FLAGS
},
617 { "y", "set the y expression", OFFSET(y_expr
), AV_OPT_TYPE_STRING
, {.str
= "0"}, CHAR_MIN
, CHAR_MAX
, FLAGS
},
618 { "eof_action", "Action to take when encountering EOF from secondary input ",
619 OFFSET(eof_action
), AV_OPT_TYPE_INT
, { .i64
= EOF_ACTION_REPEAT
},
620 EOF_ACTION_REPEAT
, EOF_ACTION_PASS
, .flags
= FLAGS
, "eof_action" },
621 { "repeat", "Repeat the previous frame.", 0, AV_OPT_TYPE_CONST
, { .i64
= EOF_ACTION_REPEAT
}, .flags
= FLAGS
, "eof_action" },
622 { "endall", "End both streams.", 0, AV_OPT_TYPE_CONST
, { .i64
= EOF_ACTION_ENDALL
}, .flags
= FLAGS
, "eof_action" },
623 { "pass", "Pass through the main input.", 0, AV_OPT_TYPE_CONST
, { .i64
= EOF_ACTION_PASS
}, .flags
= FLAGS
, "eof_action" },
624 { "eval", "specify when to evaluate expressions", OFFSET(eval_mode
), AV_OPT_TYPE_INT
, {.i64
= EVAL_MODE_FRAME
}, 0, EVAL_MODE_NB
-1, FLAGS
, "eval" },
625 { "init", "eval expressions once during initialization", 0, AV_OPT_TYPE_CONST
, {.i64
=EVAL_MODE_INIT
}, .flags
= FLAGS
, .unit
= "eval" },
626 { "frame", "eval expressions per-frame", 0, AV_OPT_TYPE_CONST
, {.i64
=EVAL_MODE_FRAME
}, .flags
= FLAGS
, .unit
= "eval" },
627 { "rgb", "force packed RGB in input and output (deprecated)", OFFSET(allow_packed_rgb
), AV_OPT_TYPE_INT
, {.i64
=0}, 0, 1, FLAGS
},
628 { "shortest", "force termination when the shortest input terminates", OFFSET(dinput
.shortest
), AV_OPT_TYPE_INT
, { .i64
= 0 }, 0, 1, FLAGS
},
629 { "format", "set output format", OFFSET(format
), AV_OPT_TYPE_INT
, {.i64
=OVERLAY_FORMAT_YUV420
}, 0, OVERLAY_FORMAT_NB
-1, FLAGS
, "format" },
630 { "yuv420", "", 0, AV_OPT_TYPE_CONST
, {.i64
=OVERLAY_FORMAT_YUV420
}, .flags
= FLAGS
, .unit
= "format" },
631 { "yuv422", "", 0, AV_OPT_TYPE_CONST
, {.i64
=OVERLAY_FORMAT_YUV422
}, .flags
= FLAGS
, .unit
= "format" },
632 { "yuv444", "", 0, AV_OPT_TYPE_CONST
, {.i64
=OVERLAY_FORMAT_YUV444
}, .flags
= FLAGS
, .unit
= "format" },
633 { "rgb", "", 0, AV_OPT_TYPE_CONST
, {.i64
=OVERLAY_FORMAT_RGB
}, .flags
= FLAGS
, .unit
= "format" },
634 { "repeatlast", "repeat overlay of the last overlay frame", OFFSET(dinput
.repeatlast
), AV_OPT_TYPE_INT
, {.i64
=1}, 0, 1, FLAGS
},
638 AVFILTER_DEFINE_CLASS(overlay
);
640 static const AVFilterPad avfilter_vf_overlay_inputs
[] = {
643 .type
= AVMEDIA_TYPE_VIDEO
,
644 .config_props
= config_input_main
,
645 .filter_frame
= filter_frame
,
650 .type
= AVMEDIA_TYPE_VIDEO
,
651 .config_props
= config_input_overlay
,
652 .filter_frame
= filter_frame
,
657 static const AVFilterPad avfilter_vf_overlay_outputs
[] = {
660 .type
= AVMEDIA_TYPE_VIDEO
,
661 .config_props
= config_output
,
662 .request_frame
= request_frame
,
667 AVFilter ff_vf_overlay
= {
669 .description
= NULL_IF_CONFIG_SMALL("Overlay a video source on top of the input."),
672 .priv_size
= sizeof(OverlayContext
),
673 .priv_class
= &overlay_class
,
674 .query_formats
= query_formats
,
675 .process_command
= process_command
,
676 .inputs
= avfilter_vf_overlay_inputs
,
677 .outputs
= avfilter_vf_overlay_outputs
,
678 .flags
= AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL
,