Commit | Line | Data |
---|---|---|
2ba45a60 DM |
1 | /* |
2 | * Copyright (c) 2010 Stefano Sabatini | |
3 | * Copyright (c) 2010 Baptiste Coudurier | |
4 | * Copyright (c) 2007 Bobby Bingham | |
5 | * | |
6 | * This file is part of FFmpeg. | |
7 | * | |
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. | |
12 | * | |
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. | |
17 | * | |
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 | |
21 | */ | |
22 | ||
23 | /** | |
24 | * @file | |
25 | * overlay one video on top of another | |
26 | */ | |
27 | ||
28 | #include "avfilter.h" | |
29 | #include "formats.h" | |
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" | |
38 | #include "internal.h" | |
39 | #include "dualinput.h" | |
40 | #include "drawutils.h" | |
41 | #include "video.h" | |
42 | ||
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 | |
48 | "hsub", | |
49 | "vsub", | |
50 | "x", | |
51 | "y", | |
52 | "n", ///< number of frame | |
53 | "pos", ///< position in the file | |
54 | "t", ///< timestamp expressed in seconds | |
55 | NULL | |
56 | }; | |
57 | ||
58 | enum var_name { | |
59 | VAR_MAIN_W, VAR_MW, | |
60 | VAR_MAIN_H, VAR_MH, | |
61 | VAR_OVERLAY_W, VAR_OW, | |
62 | VAR_OVERLAY_H, VAR_OH, | |
63 | VAR_HSUB, | |
64 | VAR_VSUB, | |
65 | VAR_X, | |
66 | VAR_Y, | |
67 | VAR_N, | |
68 | VAR_POS, | |
69 | VAR_T, | |
70 | VAR_VARS_NB | |
71 | }; | |
72 | ||
73 | enum EOFAction { | |
74 | EOF_ACTION_REPEAT, | |
75 | EOF_ACTION_ENDALL, | |
76 | EOF_ACTION_PASS | |
77 | }; | |
78 | ||
79 | static const char * const eof_action_str[] = { | |
80 | "repeat", "endall", "pass" | |
81 | }; | |
82 | ||
83 | #define MAIN 0 | |
84 | #define OVERLAY 1 | |
85 | ||
86 | #define R 0 | |
87 | #define G 1 | |
88 | #define B 2 | |
89 | #define A 3 | |
90 | ||
91 | #define Y 0 | |
92 | #define U 1 | |
93 | #define V 2 | |
94 | ||
95 | typedef struct OverlayContext { | |
96 | const AVClass *class; | |
97 | int x, y; ///< position of overlayed picture | |
98 | ||
99 | int allow_packed_rgb; | |
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; | |
108 | ||
109 | FFDualInputContext dinput; | |
110 | ||
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 | |
114 | ||
115 | double var_values[VAR_VARS_NB]; | |
116 | char *x_expr, *y_expr; | |
117 | ||
118 | enum EOFAction eof_action; ///< action to take on EOF from source | |
119 | ||
120 | AVExpr *x_pexpr, *y_pexpr; | |
121 | } OverlayContext; | |
122 | ||
123 | static av_cold void uninit(AVFilterContext *ctx) | |
124 | { | |
125 | OverlayContext *s = ctx->priv; | |
126 | ||
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; | |
130 | } | |
131 | ||
132 | static inline int normalize_xy(double d, int chroma_sub) | |
133 | { | |
134 | if (isnan(d)) | |
135 | return INT_MAX; | |
136 | return (int)d & ~((1 << chroma_sub) - 1); | |
137 | } | |
138 | ||
139 | static void eval_expr(AVFilterContext *ctx) | |
140 | { | |
141 | OverlayContext *s = ctx->priv; | |
142 | ||
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); | |
148 | } | |
149 | ||
150 | static int set_expr(AVExpr **pexpr, const char *expr, const char *option, void *log_ctx) | |
151 | { | |
152 | int ret; | |
153 | AVExpr *old = NULL; | |
154 | ||
155 | if (*pexpr) | |
156 | old = *pexpr; | |
157 | ret = av_expr_parse(pexpr, expr, var_names, | |
158 | NULL, NULL, NULL, NULL, 0, log_ctx); | |
159 | if (ret < 0) { | |
160 | av_log(log_ctx, AV_LOG_ERROR, | |
161 | "Error when evaluating the expression '%s' for %s\n", | |
162 | expr, option); | |
163 | *pexpr = old; | |
164 | return ret; | |
165 | } | |
166 | ||
167 | av_expr_free(old); | |
168 | return 0; | |
169 | } | |
170 | ||
171 | static int process_command(AVFilterContext *ctx, const char *cmd, const char *args, | |
172 | char *res, int res_len, int flags) | |
173 | { | |
174 | OverlayContext *s = ctx->priv; | |
175 | int ret; | |
176 | ||
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); | |
181 | else | |
182 | ret = AVERROR(ENOSYS); | |
183 | ||
184 | if (ret < 0) | |
185 | return ret; | |
186 | ||
187 | if (s->eval_mode == EVAL_MODE_INIT) { | |
188 | eval_expr(ctx); | |
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); | |
192 | } | |
193 | return ret; | |
194 | } | |
195 | ||
196 | static int query_formats(AVFilterContext *ctx) | |
197 | { | |
198 | OverlayContext *s = ctx->priv; | |
199 | ||
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 | |
203 | }; | |
204 | static const enum AVPixelFormat overlay_pix_fmts_yuv420[] = { | |
205 | AV_PIX_FMT_YUVA420P, AV_PIX_FMT_NONE | |
206 | }; | |
207 | ||
208 | static const enum AVPixelFormat main_pix_fmts_yuv422[] = { | |
209 | AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_NONE | |
210 | }; | |
211 | static const enum AVPixelFormat overlay_pix_fmts_yuv422[] = { | |
212 | AV_PIX_FMT_YUVA422P, AV_PIX_FMT_NONE | |
213 | }; | |
214 | ||
215 | static const enum AVPixelFormat main_pix_fmts_yuv444[] = { | |
216 | AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVA444P, AV_PIX_FMT_NONE | |
217 | }; | |
218 | static const enum AVPixelFormat overlay_pix_fmts_yuv444[] = { | |
219 | AV_PIX_FMT_YUVA444P, AV_PIX_FMT_NONE | |
220 | }; | |
221 | ||
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, | |
226 | AV_PIX_FMT_NONE | |
227 | }; | |
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, | |
231 | AV_PIX_FMT_NONE | |
232 | }; | |
233 | ||
234 | AVFilterFormats *main_formats; | |
235 | AVFilterFormats *overlay_formats; | |
236 | ||
237 | switch (s->format) { | |
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); | |
241 | break; | |
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); | |
245 | break; | |
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); | |
249 | break; | |
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); | |
253 | break; | |
254 | default: | |
255 | av_assert0(0); | |
256 | } | |
257 | ||
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 ); | |
261 | ||
262 | return 0; | |
263 | } | |
264 | ||
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 | |
269 | }; | |
270 | ||
271 | static int config_input_main(AVFilterLink *inlink) | |
272 | { | |
273 | OverlayContext *s = inlink->dst->priv; | |
274 | const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(inlink->format); | |
275 | ||
276 | av_image_fill_max_pixsteps(s->main_pix_step, NULL, pix_desc); | |
277 | ||
278 | s->hsub = pix_desc->log2_chroma_w; | |
279 | s->vsub = pix_desc->log2_chroma_h; | |
280 | ||
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); | |
284 | return 0; | |
285 | } | |
286 | ||
287 | static int config_input_overlay(AVFilterLink *inlink) | |
288 | { | |
289 | AVFilterContext *ctx = inlink->dst; | |
290 | OverlayContext *s = inlink->dst->priv; | |
291 | int ret; | |
292 | const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(inlink->format); | |
293 | ||
294 | av_image_fill_max_pixsteps(s->overlay_pix_step, NULL, pix_desc); | |
295 | ||
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; | |
309 | ||
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) | |
312 | return ret; | |
313 | ||
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); | |
317 | ||
318 | if (s->eval_mode == EVAL_MODE_INIT) { | |
319 | eval_expr(ctx); | |
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); | |
323 | } | |
324 | ||
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]); | |
332 | return 0; | |
333 | } | |
334 | ||
335 | static int config_output(AVFilterLink *outlink) | |
336 | { | |
337 | AVFilterContext *ctx = outlink->src; | |
338 | OverlayContext *s = ctx->priv; | |
339 | int ret; | |
340 | ||
341 | if ((ret = ff_dualinput_init(ctx, &s->dinput)) < 0) | |
342 | return ret; | |
343 | ||
344 | outlink->w = ctx->inputs[MAIN]->w; | |
345 | outlink->h = ctx->inputs[MAIN]->h; | |
346 | outlink->time_base = ctx->inputs[MAIN]->time_base; | |
347 | ||
348 | return 0; | |
349 | } | |
350 | ||
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) | |
354 | ||
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))) | |
360 | ||
361 | /** | |
362 | * Blend image in src to destination buffer dst at position (x, y). | |
363 | */ | |
364 | static void blend_image(AVFilterContext *ctx, | |
365 | AVFrame *dst, const AVFrame *src, | |
366 | int x, int y) | |
367 | { | |
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; | |
374 | ||
375 | if (x >= dst_w || x+src_w < 0 || | |
376 | y >= dst_h || y+src_h < 0) | |
377 | return; /* no intersection */ | |
378 | ||
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; | |
393 | ||
394 | i = FFMAX(-y, 0); | |
395 | sp = src->data[0] + i * src->linesize[0]; | |
396 | dp = dst->data[0] + (y+i) * dst->linesize[0]; | |
397 | ||
398 | for (imax = FFMIN(-y + dst_h, src_h); i < imax; i++) { | |
399 | j = FFMAX(-x, 0); | |
400 | s = sp + j * sstep; | |
401 | d = dp + (x+j) * dstep; | |
402 | ||
403 | for (jmax = FFMIN(-x + dst_w, src_w); j < jmax; j++) { | |
404 | alpha = s[sa]; | |
405 | ||
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); | |
411 | } | |
412 | ||
413 | switch (alpha) { | |
414 | case 0: | |
415 | break; | |
416 | case 255: | |
417 | d[dr] = s[sr]; | |
418 | d[dg] = s[sg]; | |
419 | d[db] = s[sb]; | |
420 | break; | |
421 | default: | |
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); | |
427 | } | |
428 | if (main_has_alpha) { | |
429 | switch (alpha) { | |
430 | case 0: | |
431 | break; | |
432 | case 255: | |
433 | d[da] = s[sa]; | |
434 | break; | |
435 | default: | |
436 | // apply alpha compositing: main_alpha += (1-main_alpha) * overlay_alpha | |
437 | d[da] += FAST_DIV255((255 - d[da]) * s[sa]); | |
438 | } | |
439 | } | |
440 | d += dstep; | |
441 | s += sstep; | |
442 | } | |
443 | dp += dst->linesize[0]; | |
444 | sp += src->linesize[0]; | |
445 | } | |
446 | } else { | |
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; | |
451 | ||
452 | i = FFMAX(-y, 0); | |
453 | sa = src->data[3] + i * src->linesize[3]; | |
454 | da = dst->data[3] + (y+i) * dst->linesize[3]; | |
455 | ||
456 | for (imax = FFMIN(-y + dst_h, src_h); i < imax; i++) { | |
457 | j = FFMAX(-x, 0); | |
458 | s = sa + j; | |
459 | d = da + x+j; | |
460 | ||
461 | for (jmax = FFMIN(-x + dst_w, src_w); j < jmax; j++) { | |
462 | alpha = *s; | |
463 | if (alpha != 0 && alpha != 255) { | |
464 | uint8_t alpha_d = *d; | |
465 | alpha = UNPREMULTIPLY_ALPHA(alpha, alpha_d); | |
466 | } | |
467 | switch (alpha) { | |
468 | case 0: | |
469 | break; | |
470 | case 255: | |
471 | *d = *s; | |
472 | break; | |
473 | default: | |
474 | // apply alpha compositing: main_alpha += (1-main_alpha) * overlay_alpha | |
475 | *d += FAST_DIV255((255 - *d) * *s); | |
476 | } | |
477 | d += 1; | |
478 | s += 1; | |
479 | } | |
480 | da += dst->linesize[3]; | |
481 | sa += src->linesize[3]; | |
482 | } | |
483 | } | |
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); | |
491 | int yp = y>>vsub; | |
492 | int xp = x>>hsub; | |
493 | uint8_t *s, *sp, *d, *dp, *a, *ap; | |
494 | ||
495 | j = FFMAX(-yp, 0); | |
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]; | |
499 | ||
500 | for (jmax = FFMIN(-yp + dst_hp, src_hp); j < jmax; j++) { | |
501 | k = FFMAX(-xp, 0); | |
502 | d = dp + xp+k; | |
503 | s = sp + k; | |
504 | a = ap + (k<<hsub); | |
505 | ||
506 | for (kmax = FFMIN(-xp + dst_wp, src_wp); k < kmax; k++) { | |
507 | int alpha_v, alpha_h, alpha; | |
508 | ||
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; | |
519 | } else | |
520 | alpha = a[0]; | |
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 | |
525 | uint8_t alpha_d; | |
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; | |
535 | } else | |
536 | alpha_d = d[0]; | |
537 | alpha = UNPREMULTIPLY_ALPHA(alpha, alpha_d); | |
538 | } | |
539 | *d = FAST_DIV255(*d * (255 - alpha) + *s * alpha); | |
540 | s++; | |
541 | d++; | |
542 | a += 1 << hsub; | |
543 | } | |
544 | dp += dst->linesize[i]; | |
545 | sp += src->linesize[i]; | |
546 | ap += (1 << vsub) * src->linesize[3]; | |
547 | } | |
548 | } | |
549 | } | |
550 | } | |
551 | ||
552 | static AVFrame *do_blend(AVFilterContext *ctx, AVFrame *mainpic, | |
553 | const AVFrame *second) | |
554 | { | |
555 | OverlayContext *s = ctx->priv; | |
556 | AVFilterLink *inlink = ctx->inputs[0]; | |
557 | ||
558 | if (s->eval_mode == EVAL_MODE_FRAME) { | |
559 | int64_t pos = av_frame_get_pkt_pos(mainpic); | |
560 | ||
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; | |
565 | ||
566 | eval_expr(ctx); | |
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); | |
571 | } | |
572 | ||
573 | blend_image(ctx, mainpic, second, s->x, s->y); | |
574 | return mainpic; | |
575 | } | |
576 | ||
577 | static int filter_frame(AVFilterLink *inlink, AVFrame *inpicref) | |
578 | { | |
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); | |
582 | } | |
583 | ||
584 | static int request_frame(AVFilterLink *outlink) | |
585 | { | |
586 | OverlayContext *s = outlink->src->priv; | |
587 | return ff_dualinput_request_frame(&s->dinput, outlink); | |
588 | } | |
589 | ||
590 | static av_cold int init(AVFilterContext *ctx) | |
591 | { | |
592 | OverlayContext *s = ctx->priv; | |
593 | ||
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; | |
598 | } | |
599 | if (!s->dinput.repeatlast || s->eof_action == EOF_ACTION_PASS) { | |
600 | s->dinput.repeatlast = 0; | |
601 | s->eof_action = EOF_ACTION_PASS; | |
602 | } | |
603 | if (s->dinput.shortest || s->eof_action == EOF_ACTION_ENDALL) { | |
604 | s->dinput.shortest = 1; | |
605 | s->eof_action = EOF_ACTION_ENDALL; | |
606 | } | |
607 | ||
608 | s->dinput.process = do_blend; | |
609 | return 0; | |
610 | } | |
611 | ||
612 | #define OFFSET(x) offsetof(OverlayContext, x) | |
613 | #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM | |
614 | ||
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 }, | |
635 | { NULL } | |
636 | }; | |
637 | ||
638 | AVFILTER_DEFINE_CLASS(overlay); | |
639 | ||
640 | static const AVFilterPad avfilter_vf_overlay_inputs[] = { | |
641 | { | |
642 | .name = "main", | |
643 | .type = AVMEDIA_TYPE_VIDEO, | |
644 | .config_props = config_input_main, | |
645 | .filter_frame = filter_frame, | |
646 | .needs_writable = 1, | |
647 | }, | |
648 | { | |
649 | .name = "overlay", | |
650 | .type = AVMEDIA_TYPE_VIDEO, | |
651 | .config_props = config_input_overlay, | |
652 | .filter_frame = filter_frame, | |
653 | }, | |
654 | { NULL } | |
655 | }; | |
656 | ||
657 | static const AVFilterPad avfilter_vf_overlay_outputs[] = { | |
658 | { | |
659 | .name = "default", | |
660 | .type = AVMEDIA_TYPE_VIDEO, | |
661 | .config_props = config_output, | |
662 | .request_frame = request_frame, | |
663 | }, | |
664 | { NULL } | |
665 | }; | |
666 | ||
667 | AVFilter ff_vf_overlay = { | |
668 | .name = "overlay", | |
669 | .description = NULL_IF_CONFIG_SMALL("Overlay a video source on top of the input."), | |
670 | .init = init, | |
671 | .uninit = uninit, | |
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, | |
679 | }; |