... | ... |
@@ -2634,13 +2634,17 @@ The threshold below which a pixel value is considered black; it defaults to |
2634 | 2634 |
|
2635 | 2635 |
@end table |
2636 | 2636 |
|
2637 |
-@section blend |
|
2637 |
+@section blend, tblend |
|
2638 | 2638 |
|
2639 | 2639 |
Blend two video frames into each other. |
2640 | 2640 |
|
2641 |
-It takes two input streams and outputs one stream, the first input is the |
|
2642 |
-"top" layer and second input is "bottom" layer. |
|
2643 |
-Output terminates when shortest input terminates. |
|
2641 |
+The @code{blend} filter takes two input streams and outputs one |
|
2642 |
+stream, the first input is the "top" layer and second input is |
|
2643 |
+"bottom" layer. Output terminates when shortest input terminates. |
|
2644 |
+ |
|
2645 |
+The @code{tblend} (time blend) filter takes two consecutive frames |
|
2646 |
+from one single stream, and outputs the result obtained by blending |
|
2647 |
+the new frame on top of the old frame. |
|
2644 | 2648 |
|
2645 | 2649 |
A description of the accepted options follows. |
2646 | 2650 |
|
... | ... |
@@ -2730,11 +2734,13 @@ Value of pixel component at current location for second video frame (bottom laye |
2730 | 2730 |
@end table |
2731 | 2731 |
|
2732 | 2732 |
@item shortest |
2733 |
-Force termination when the shortest input terminates. Default is @code{0}. |
|
2733 |
+Force termination when the shortest input terminates. Default is |
|
2734 |
+@code{0}. This option is only defined for the @code{blend} filter. |
|
2735 |
+ |
|
2734 | 2736 |
@item repeatlast |
2735 | 2737 |
Continue applying the last bottom frame after the end of the stream. A value of |
2736 | 2738 |
@code{0} disable the filter after the last frame of the bottom layer is reached. |
2737 |
-Default is @code{1}. |
|
2739 |
+Default is @code{1}. This option is only defined for the @code{blend} filter. |
|
2738 | 2740 |
@end table |
2739 | 2741 |
|
2740 | 2742 |
@subsection Examples |
... | ... |
@@ -2769,6 +2775,12 @@ Apply uncover up-left effect: |
2769 | 2769 |
@example |
2770 | 2770 |
blend=all_expr='if(gte(T*SH*40+Y,H)*gte((T*40*SW+X)*W/H,W),A,B)' |
2771 | 2771 |
@end example |
2772 |
+ |
|
2773 |
+@item |
|
2774 |
+Display differences between the current and the previous frame: |
|
2775 |
+@example |
|
2776 |
+tblend=all_mode=difference128 |
|
2777 |
+@end example |
|
2772 | 2778 |
@end itemize |
2773 | 2779 |
|
2774 | 2780 |
@section boxblur |
... | ... |
@@ -188,6 +188,7 @@ OBJS-$(CONFIG_STEREO3D_FILTER) += vf_stereo3d.o |
188 | 188 |
OBJS-$(CONFIG_SUBTITLES_FILTER) += vf_subtitles.o |
189 | 189 |
OBJS-$(CONFIG_SUPER2XSAI_FILTER) += vf_super2xsai.o |
190 | 190 |
OBJS-$(CONFIG_SWAPUV_FILTER) += vf_swapuv.o |
191 |
+OBJS-$(CONFIG_TBLEND_FILTER) += vf_blend.o |
|
191 | 192 |
OBJS-$(CONFIG_TELECINE_FILTER) += vf_telecine.o |
192 | 193 |
OBJS-$(CONFIG_THUMBNAIL_FILTER) += vf_thumbnail.o |
193 | 194 |
OBJS-$(CONFIG_TILE_FILTER) += vf_tile.o |
... | ... |
@@ -203,6 +203,7 @@ void avfilter_register_all(void) |
203 | 203 |
REGISTER_FILTER(SUBTITLES, subtitles, vf); |
204 | 204 |
REGISTER_FILTER(SUPER2XSAI, super2xsai, vf); |
205 | 205 |
REGISTER_FILTER(SWAPUV, swapuv, vf); |
206 |
+ REGISTER_FILTER(TBLEND, tblend, vf); |
|
206 | 207 |
REGISTER_FILTER(TELECINE, telecine, vf); |
207 | 208 |
REGISTER_FILTER(THUMBNAIL, thumbnail, vf); |
208 | 209 |
REGISTER_FILTER(TILE, tile, vf); |
... | ... |
@@ -30,8 +30,8 @@ |
30 | 30 |
#include "libavutil/version.h" |
31 | 31 |
|
32 | 32 |
#define LIBAVFILTER_VERSION_MAJOR 5 |
33 |
-#define LIBAVFILTER_VERSION_MINOR 5 |
|
34 |
-#define LIBAVFILTER_VERSION_MICRO 102 |
|
33 |
+#define LIBAVFILTER_VERSION_MINOR 6 |
|
34 |
+#define LIBAVFILTER_VERSION_MICRO 100 |
|
35 | 35 |
|
36 | 36 |
#define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \ |
37 | 37 |
LIBAVFILTER_VERSION_MINOR, \ |
... | ... |
@@ -96,52 +96,57 @@ typedef struct { |
96 | 96 |
double all_opacity; |
97 | 97 |
|
98 | 98 |
FilterParams params[4]; |
99 |
+ int tblend; |
|
100 |
+ AVFrame *prev_frame; /* only used with tblend */ |
|
99 | 101 |
} BlendContext; |
100 | 102 |
|
103 |
+#define COMMON_OPTIONS \ |
|
104 |
+ { "c0_mode", "set component #0 blend mode", OFFSET(params[0].mode), AV_OPT_TYPE_INT, {.i64=0}, 0, BLEND_NB-1, FLAGS, "mode"},\ |
|
105 |
+ { "c1_mode", "set component #1 blend mode", OFFSET(params[1].mode), AV_OPT_TYPE_INT, {.i64=0}, 0, BLEND_NB-1, FLAGS, "mode"},\ |
|
106 |
+ { "c2_mode", "set component #2 blend mode", OFFSET(params[2].mode), AV_OPT_TYPE_INT, {.i64=0}, 0, BLEND_NB-1, FLAGS, "mode"},\ |
|
107 |
+ { "c3_mode", "set component #3 blend mode", OFFSET(params[3].mode), AV_OPT_TYPE_INT, {.i64=0}, 0, BLEND_NB-1, FLAGS, "mode"},\ |
|
108 |
+ { "all_mode", "set blend mode for all components", OFFSET(all_mode), AV_OPT_TYPE_INT, {.i64=-1},-1, BLEND_NB-1, FLAGS, "mode"},\ |
|
109 |
+ { "addition", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_ADDITION}, 0, 0, FLAGS, "mode" },\ |
|
110 |
+ { "and", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_AND}, 0, 0, FLAGS, "mode" },\ |
|
111 |
+ { "average", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_AVERAGE}, 0, 0, FLAGS, "mode" },\ |
|
112 |
+ { "burn", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_BURN}, 0, 0, FLAGS, "mode" },\ |
|
113 |
+ { "darken", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_DARKEN}, 0, 0, FLAGS, "mode" },\ |
|
114 |
+ { "difference", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_DIFFERENCE}, 0, 0, FLAGS, "mode" },\ |
|
115 |
+ { "difference128", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_DIFFERENCE128}, 0, 0, FLAGS, "mode" },\ |
|
116 |
+ { "divide", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_DIVIDE}, 0, 0, FLAGS, "mode" },\ |
|
117 |
+ { "dodge", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_DODGE}, 0, 0, FLAGS, "mode" },\ |
|
118 |
+ { "exclusion", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_EXCLUSION}, 0, 0, FLAGS, "mode" },\ |
|
119 |
+ { "hardlight", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_HARDLIGHT}, 0, 0, FLAGS, "mode" },\ |
|
120 |
+ { "lighten", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_LIGHTEN}, 0, 0, FLAGS, "mode" },\ |
|
121 |
+ { "multiply", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_MULTIPLY}, 0, 0, FLAGS, "mode" },\ |
|
122 |
+ { "negation", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_NEGATION}, 0, 0, FLAGS, "mode" },\ |
|
123 |
+ { "normal", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_NORMAL}, 0, 0, FLAGS, "mode" },\ |
|
124 |
+ { "or", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_OR}, 0, 0, FLAGS, "mode" },\ |
|
125 |
+ { "overlay", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_OVERLAY}, 0, 0, FLAGS, "mode" },\ |
|
126 |
+ { "phoenix", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_PHOENIX}, 0, 0, FLAGS, "mode" },\ |
|
127 |
+ { "pinlight", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_PINLIGHT}, 0, 0, FLAGS, "mode" },\ |
|
128 |
+ { "reflect", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_REFLECT}, 0, 0, FLAGS, "mode" },\ |
|
129 |
+ { "screen", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_SCREEN}, 0, 0, FLAGS, "mode" },\ |
|
130 |
+ { "softlight", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_SOFTLIGHT}, 0, 0, FLAGS, "mode" },\ |
|
131 |
+ { "subtract", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_SUBTRACT}, 0, 0, FLAGS, "mode" },\ |
|
132 |
+ { "vividlight", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_VIVIDLIGHT}, 0, 0, FLAGS, "mode" },\ |
|
133 |
+ { "xor", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_XOR}, 0, 0, FLAGS, "mode" },\ |
|
134 |
+ { "c0_expr", "set color component #0 expression", OFFSET(params[0].expr_str), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },\ |
|
135 |
+ { "c1_expr", "set color component #1 expression", OFFSET(params[1].expr_str), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },\ |
|
136 |
+ { "c2_expr", "set color component #2 expression", OFFSET(params[2].expr_str), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },\ |
|
137 |
+ { "c3_expr", "set color component #3 expression", OFFSET(params[3].expr_str), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },\ |
|
138 |
+ { "all_expr", "set expression for all color components", OFFSET(all_expr), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },\ |
|
139 |
+ { "c0_opacity", "set color component #0 opacity", OFFSET(params[0].opacity), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS },\ |
|
140 |
+ { "c1_opacity", "set color component #1 opacity", OFFSET(params[1].opacity), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS },\ |
|
141 |
+ { "c2_opacity", "set color component #2 opacity", OFFSET(params[2].opacity), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS },\ |
|
142 |
+ { "c3_opacity", "set color component #3 opacity", OFFSET(params[3].opacity), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS },\ |
|
143 |
+ { "all_opacity", "set opacity for all color components", OFFSET(all_opacity), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS} |
|
144 |
+ |
|
101 | 145 |
#define OFFSET(x) offsetof(BlendContext, x) |
102 | 146 |
#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM |
103 | 147 |
|
104 | 148 |
static const AVOption blend_options[] = { |
105 |
- { "c0_mode", "set component #0 blend mode", OFFSET(params[0].mode), AV_OPT_TYPE_INT, {.i64=0}, 0, BLEND_NB-1, FLAGS, "mode"}, |
|
106 |
- { "c1_mode", "set component #1 blend mode", OFFSET(params[1].mode), AV_OPT_TYPE_INT, {.i64=0}, 0, BLEND_NB-1, FLAGS, "mode"}, |
|
107 |
- { "c2_mode", "set component #2 blend mode", OFFSET(params[2].mode), AV_OPT_TYPE_INT, {.i64=0}, 0, BLEND_NB-1, FLAGS, "mode"}, |
|
108 |
- { "c3_mode", "set component #3 blend mode", OFFSET(params[3].mode), AV_OPT_TYPE_INT, {.i64=0}, 0, BLEND_NB-1, FLAGS, "mode"}, |
|
109 |
- { "all_mode", "set blend mode for all components", OFFSET(all_mode), AV_OPT_TYPE_INT, {.i64=-1},-1, BLEND_NB-1, FLAGS, "mode"}, |
|
110 |
- { "addition", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_ADDITION}, 0, 0, FLAGS, "mode" }, |
|
111 |
- { "and", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_AND}, 0, 0, FLAGS, "mode" }, |
|
112 |
- { "average", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_AVERAGE}, 0, 0, FLAGS, "mode" }, |
|
113 |
- { "burn", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_BURN}, 0, 0, FLAGS, "mode" }, |
|
114 |
- { "darken", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_DARKEN}, 0, 0, FLAGS, "mode" }, |
|
115 |
- { "difference", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_DIFFERENCE}, 0, 0, FLAGS, "mode" }, |
|
116 |
- { "difference128", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_DIFFERENCE128}, 0, 0, FLAGS, "mode" }, |
|
117 |
- { "divide", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_DIVIDE}, 0, 0, FLAGS, "mode" }, |
|
118 |
- { "dodge", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_DODGE}, 0, 0, FLAGS, "mode" }, |
|
119 |
- { "exclusion", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_EXCLUSION}, 0, 0, FLAGS, "mode" }, |
|
120 |
- { "hardlight", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_HARDLIGHT}, 0, 0, FLAGS, "mode" }, |
|
121 |
- { "lighten", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_LIGHTEN}, 0, 0, FLAGS, "mode" }, |
|
122 |
- { "multiply", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_MULTIPLY}, 0, 0, FLAGS, "mode" }, |
|
123 |
- { "negation", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_NEGATION}, 0, 0, FLAGS, "mode" }, |
|
124 |
- { "normal", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_NORMAL}, 0, 0, FLAGS, "mode" }, |
|
125 |
- { "or", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_OR}, 0, 0, FLAGS, "mode" }, |
|
126 |
- { "overlay", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_OVERLAY}, 0, 0, FLAGS, "mode" }, |
|
127 |
- { "phoenix", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_PHOENIX}, 0, 0, FLAGS, "mode" }, |
|
128 |
- { "pinlight", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_PINLIGHT}, 0, 0, FLAGS, "mode" }, |
|
129 |
- { "reflect", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_REFLECT}, 0, 0, FLAGS, "mode" }, |
|
130 |
- { "screen", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_SCREEN}, 0, 0, FLAGS, "mode" }, |
|
131 |
- { "softlight", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_SOFTLIGHT}, 0, 0, FLAGS, "mode" }, |
|
132 |
- { "subtract", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_SUBTRACT}, 0, 0, FLAGS, "mode" }, |
|
133 |
- { "vividlight", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_VIVIDLIGHT}, 0, 0, FLAGS, "mode" }, |
|
134 |
- { "xor", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_XOR}, 0, 0, FLAGS, "mode" }, |
|
135 |
- { "c0_expr", "set color component #0 expression", OFFSET(params[0].expr_str), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS }, |
|
136 |
- { "c1_expr", "set color component #1 expression", OFFSET(params[1].expr_str), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS }, |
|
137 |
- { "c2_expr", "set color component #2 expression", OFFSET(params[2].expr_str), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS }, |
|
138 |
- { "c3_expr", "set color component #3 expression", OFFSET(params[3].expr_str), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS }, |
|
139 |
- { "all_expr", "set expression for all color components", OFFSET(all_expr), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS }, |
|
140 |
- { "c0_opacity", "set color component #0 opacity", OFFSET(params[0].opacity), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS }, |
|
141 |
- { "c1_opacity", "set color component #1 opacity", OFFSET(params[1].opacity), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS }, |
|
142 |
- { "c2_opacity", "set color component #2 opacity", OFFSET(params[2].opacity), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS }, |
|
143 |
- { "c3_opacity", "set color component #3 opacity", OFFSET(params[3].opacity), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS }, |
|
144 |
- { "all_opacity", "set opacity for all color components", OFFSET(all_opacity), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS}, |
|
149 |
+ COMMON_OPTIONS, |
|
145 | 150 |
{ "shortest", "force termination when the shortest input terminates", OFFSET(dinput.shortest), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS }, |
146 | 151 |
{ "repeatlast", "repeat last bottom frame", OFFSET(dinput.repeatlast), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, FLAGS }, |
147 | 152 |
{ NULL } |
... | ... |
@@ -288,7 +293,8 @@ static AVFrame *blend_frame(AVFilterContext *ctx, AVFrame *top_buf, |
288 | 288 |
ctx->internal->execute(ctx, filter_slice, &td, NULL, FFMIN(outh, ctx->graph->nb_threads)); |
289 | 289 |
} |
290 | 290 |
|
291 |
- av_frame_free(&top_buf); |
|
291 |
+ if (!b->tblend) |
|
292 |
+ av_frame_free(&top_buf); |
|
292 | 293 |
|
293 | 294 |
return dst_buf; |
294 | 295 |
} |
... | ... |
@@ -298,6 +304,8 @@ static av_cold int init(AVFilterContext *ctx) |
298 | 298 |
BlendContext *b = ctx->priv; |
299 | 299 |
int ret, plane; |
300 | 300 |
|
301 |
+ b->tblend = !strcmp(ctx->filter->name, "tblend"); |
|
302 |
+ |
|
301 | 303 |
for (plane = 0; plane < FF_ARRAY_ELEMS(b->params); plane++) { |
302 | 304 |
FilterParams *param = &b->params[plane]; |
303 | 305 |
|
... | ... |
@@ -416,6 +424,8 @@ static av_cold void uninit(AVFilterContext *ctx) |
416 | 416 |
int i; |
417 | 417 |
|
418 | 418 |
ff_dualinput_uninit(&b->dinput); |
419 |
+ av_freep(&b->prev_frame); |
|
420 |
+ |
|
419 | 421 |
for (i = 0; i < FF_ARRAY_ELEMS(b->params); i++) |
420 | 422 |
av_expr_free(b->params[i].e); |
421 | 423 |
} |
... | ... |
@@ -467,3 +477,71 @@ AVFilter ff_vf_blend = { |
467 | 467 |
.priv_class = &blend_class, |
468 | 468 |
.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | AVFILTER_FLAG_SLICE_THREADS, |
469 | 469 |
}; |
470 |
+ |
|
471 |
+static int tblend_config_output(AVFilterLink *outlink) |
|
472 |
+{ |
|
473 |
+ AVFilterContext *ctx = outlink->src; |
|
474 |
+ AVFilterLink *inlink = ctx->inputs[0]; |
|
475 |
+ BlendContext *b = ctx->priv; |
|
476 |
+ const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(inlink->format); |
|
477 |
+ |
|
478 |
+ b->hsub = pix_desc->log2_chroma_w; |
|
479 |
+ b->vsub = pix_desc->log2_chroma_h; |
|
480 |
+ b->nb_planes = av_pix_fmt_count_planes(inlink->format); |
|
481 |
+ outlink->flags |= FF_LINK_FLAG_REQUEST_LOOP; |
|
482 |
+ |
|
483 |
+ return 0; |
|
484 |
+} |
|
485 |
+ |
|
486 |
+static int tblend_filter_frame(AVFilterLink *inlink, AVFrame *frame) |
|
487 |
+{ |
|
488 |
+ BlendContext *b = inlink->dst->priv; |
|
489 |
+ AVFilterLink *outlink = inlink->dst->outputs[0]; |
|
490 |
+ |
|
491 |
+ if (b->prev_frame) { |
|
492 |
+ AVFrame *out = blend_frame(inlink->dst, frame, b->prev_frame); |
|
493 |
+ av_frame_free(&b->prev_frame); |
|
494 |
+ b->prev_frame = frame; |
|
495 |
+ return ff_filter_frame(outlink, out); |
|
496 |
+ } |
|
497 |
+ b->prev_frame = frame; |
|
498 |
+ return 0; |
|
499 |
+} |
|
500 |
+ |
|
501 |
+static const AVOption tblend_options[] = { |
|
502 |
+ COMMON_OPTIONS, |
|
503 |
+ { NULL } |
|
504 |
+}; |
|
505 |
+ |
|
506 |
+AVFILTER_DEFINE_CLASS(tblend); |
|
507 |
+ |
|
508 |
+static const AVFilterPad tblend_inputs[] = { |
|
509 |
+ { |
|
510 |
+ .name = "default", |
|
511 |
+ .type = AVMEDIA_TYPE_VIDEO, |
|
512 |
+ .filter_frame = tblend_filter_frame, |
|
513 |
+ }, |
|
514 |
+ { NULL } |
|
515 |
+}; |
|
516 |
+ |
|
517 |
+static const AVFilterPad tblend_outputs[] = { |
|
518 |
+ { |
|
519 |
+ .name = "default", |
|
520 |
+ .type = AVMEDIA_TYPE_VIDEO, |
|
521 |
+ .config_props = tblend_config_output, |
|
522 |
+ }, |
|
523 |
+ { NULL } |
|
524 |
+}; |
|
525 |
+ |
|
526 |
+AVFilter ff_vf_tblend = { |
|
527 |
+ .name = "tblend", |
|
528 |
+ .description = NULL_IF_CONFIG_SMALL("Blend successive frames."), |
|
529 |
+ .priv_size = sizeof(BlendContext), |
|
530 |
+ .priv_class = &blend_class, |
|
531 |
+ .query_formats = query_formats, |
|
532 |
+ .init = init, |
|
533 |
+ .uninit = uninit, |
|
534 |
+ .inputs = tblend_inputs, |
|
535 |
+ .outputs = tblend_outputs, |
|
536 |
+ .flags = AVFILTER_FLAG_SLICE_THREADS, |
|
537 |
+}; |