lavfi: add tblend filter
This commit is contained in:
		
							parent
							
								
									05e74ac2f3
								
							
						
					
					
						commit
						d4fd3f24e8
					
				@ -8,6 +8,7 @@ version <next>:
 | 
				
			|||||||
- RIFX format for *.wav files
 | 
					- RIFX format for *.wav files
 | 
				
			||||||
- RTP/mpegts muxer
 | 
					- RTP/mpegts muxer
 | 
				
			||||||
- non continuous cache protocol support
 | 
					- non continuous cache protocol support
 | 
				
			||||||
 | 
					- tblend filter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
version 2.5:
 | 
					version 2.5:
 | 
				
			||||||
 | 
				
			|||||||
@ -2634,13 +2634,17 @@ The threshold below which a pixel value is considered black; it defaults to
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@end table
 | 
					@end table
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@section blend
 | 
					@section blend, tblend
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Blend two video frames into each other.
 | 
					Blend two video frames into each other.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
It takes two input streams and outputs one stream, the first input is the
 | 
					The @code{blend} filter takes two input streams and outputs one
 | 
				
			||||||
"top" layer and second input is "bottom" layer.
 | 
					stream, the first input is the "top" layer and second input is
 | 
				
			||||||
Output terminates when shortest input terminates.
 | 
					"bottom" layer.  Output terminates when shortest input terminates.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The @code{tblend} (time blend) filter takes two consecutive frames
 | 
				
			||||||
 | 
					from one single stream, and outputs the result obtained by blending
 | 
				
			||||||
 | 
					the new frame on top of the old frame.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
A description of the accepted options follows.
 | 
					A description of the accepted options follows.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -2730,11 +2734,13 @@ Value of pixel component at current location for second video frame (bottom laye
 | 
				
			|||||||
@end table
 | 
					@end table
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@item shortest
 | 
					@item shortest
 | 
				
			||||||
Force termination when the shortest input terminates. Default is @code{0}.
 | 
					Force termination when the shortest input terminates. Default is
 | 
				
			||||||
 | 
					@code{0}. This option is only defined for the @code{blend} filter.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@item repeatlast
 | 
					@item repeatlast
 | 
				
			||||||
Continue applying the last bottom frame after the end of the stream. A value of
 | 
					Continue applying the last bottom frame after the end of the stream. A value of
 | 
				
			||||||
@code{0} disable the filter after the last frame of the bottom layer is reached.
 | 
					@code{0} disable the filter after the last frame of the bottom layer is reached.
 | 
				
			||||||
Default is @code{1}.
 | 
					Default is @code{1}. This option is only defined for the @code{blend} filter.
 | 
				
			||||||
@end table
 | 
					@end table
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@subsection Examples
 | 
					@subsection Examples
 | 
				
			||||||
@ -2769,6 +2775,12 @@ Apply uncover up-left effect:
 | 
				
			|||||||
@example
 | 
					@example
 | 
				
			||||||
blend=all_expr='if(gte(T*SH*40+Y,H)*gte((T*40*SW+X)*W/H,W),A,B)'
 | 
					blend=all_expr='if(gte(T*SH*40+Y,H)*gte((T*40*SW+X)*W/H,W),A,B)'
 | 
				
			||||||
@end example
 | 
					@end example
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@item
 | 
				
			||||||
 | 
					Display differences between the current and the previous frame:
 | 
				
			||||||
 | 
					@example
 | 
				
			||||||
 | 
					tblend=all_mode=difference128
 | 
				
			||||||
 | 
					@end example
 | 
				
			||||||
@end itemize
 | 
					@end itemize
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@section boxblur
 | 
					@section boxblur
 | 
				
			||||||
 | 
				
			|||||||
@ -188,6 +188,7 @@ OBJS-$(CONFIG_STEREO3D_FILTER)               += vf_stereo3d.o
 | 
				
			|||||||
OBJS-$(CONFIG_SUBTITLES_FILTER)              += vf_subtitles.o
 | 
					OBJS-$(CONFIG_SUBTITLES_FILTER)              += vf_subtitles.o
 | 
				
			||||||
OBJS-$(CONFIG_SUPER2XSAI_FILTER)             += vf_super2xsai.o
 | 
					OBJS-$(CONFIG_SUPER2XSAI_FILTER)             += vf_super2xsai.o
 | 
				
			||||||
OBJS-$(CONFIG_SWAPUV_FILTER)                 += vf_swapuv.o
 | 
					OBJS-$(CONFIG_SWAPUV_FILTER)                 += vf_swapuv.o
 | 
				
			||||||
 | 
					OBJS-$(CONFIG_TBLEND_FILTER)                 += vf_blend.o
 | 
				
			||||||
OBJS-$(CONFIG_TELECINE_FILTER)               += vf_telecine.o
 | 
					OBJS-$(CONFIG_TELECINE_FILTER)               += vf_telecine.o
 | 
				
			||||||
OBJS-$(CONFIG_THUMBNAIL_FILTER)              += vf_thumbnail.o
 | 
					OBJS-$(CONFIG_THUMBNAIL_FILTER)              += vf_thumbnail.o
 | 
				
			||||||
OBJS-$(CONFIG_TILE_FILTER)                   += vf_tile.o
 | 
					OBJS-$(CONFIG_TILE_FILTER)                   += vf_tile.o
 | 
				
			||||||
 | 
				
			|||||||
@ -203,6 +203,7 @@ void avfilter_register_all(void)
 | 
				
			|||||||
    REGISTER_FILTER(SUBTITLES,      subtitles,      vf);
 | 
					    REGISTER_FILTER(SUBTITLES,      subtitles,      vf);
 | 
				
			||||||
    REGISTER_FILTER(SUPER2XSAI,     super2xsai,     vf);
 | 
					    REGISTER_FILTER(SUPER2XSAI,     super2xsai,     vf);
 | 
				
			||||||
    REGISTER_FILTER(SWAPUV,         swapuv,         vf);
 | 
					    REGISTER_FILTER(SWAPUV,         swapuv,         vf);
 | 
				
			||||||
 | 
					    REGISTER_FILTER(TBLEND,         tblend,         vf);
 | 
				
			||||||
    REGISTER_FILTER(TELECINE,       telecine,       vf);
 | 
					    REGISTER_FILTER(TELECINE,       telecine,       vf);
 | 
				
			||||||
    REGISTER_FILTER(THUMBNAIL,      thumbnail,      vf);
 | 
					    REGISTER_FILTER(THUMBNAIL,      thumbnail,      vf);
 | 
				
			||||||
    REGISTER_FILTER(TILE,           tile,           vf);
 | 
					    REGISTER_FILTER(TILE,           tile,           vf);
 | 
				
			||||||
 | 
				
			|||||||
@ -30,8 +30,8 @@
 | 
				
			|||||||
#include "libavutil/version.h"
 | 
					#include "libavutil/version.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define LIBAVFILTER_VERSION_MAJOR  5
 | 
					#define LIBAVFILTER_VERSION_MAJOR  5
 | 
				
			||||||
#define LIBAVFILTER_VERSION_MINOR  5
 | 
					#define LIBAVFILTER_VERSION_MINOR  6
 | 
				
			||||||
#define LIBAVFILTER_VERSION_MICRO 102
 | 
					#define LIBAVFILTER_VERSION_MICRO 100
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
 | 
					#define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
 | 
				
			||||||
                                               LIBAVFILTER_VERSION_MINOR, \
 | 
					                                               LIBAVFILTER_VERSION_MINOR, \
 | 
				
			||||||
 | 
				
			|||||||
@ -96,52 +96,57 @@ typedef struct {
 | 
				
			|||||||
    double all_opacity;
 | 
					    double all_opacity;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    FilterParams params[4];
 | 
					    FilterParams params[4];
 | 
				
			||||||
 | 
					    int tblend;
 | 
				
			||||||
 | 
					    AVFrame *prev_frame;        /* only used with tblend */
 | 
				
			||||||
} BlendContext;
 | 
					} BlendContext;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define COMMON_OPTIONS \
 | 
				
			||||||
 | 
					    { "c0_mode", "set component #0 blend mode", OFFSET(params[0].mode), AV_OPT_TYPE_INT, {.i64=0}, 0, BLEND_NB-1, FLAGS, "mode"},\
 | 
				
			||||||
 | 
					    { "c1_mode", "set component #1 blend mode", OFFSET(params[1].mode), AV_OPT_TYPE_INT, {.i64=0}, 0, BLEND_NB-1, FLAGS, "mode"},\
 | 
				
			||||||
 | 
					    { "c2_mode", "set component #2 blend mode", OFFSET(params[2].mode), AV_OPT_TYPE_INT, {.i64=0}, 0, BLEND_NB-1, FLAGS, "mode"},\
 | 
				
			||||||
 | 
					    { "c3_mode", "set component #3 blend mode", OFFSET(params[3].mode), AV_OPT_TYPE_INT, {.i64=0}, 0, BLEND_NB-1, FLAGS, "mode"},\
 | 
				
			||||||
 | 
					    { "all_mode", "set blend mode for all components", OFFSET(all_mode), AV_OPT_TYPE_INT, {.i64=-1},-1, BLEND_NB-1, FLAGS, "mode"},\
 | 
				
			||||||
 | 
					    { "addition",   "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_ADDITION},   0, 0, FLAGS, "mode" },\
 | 
				
			||||||
 | 
					    { "and",        "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_AND},        0, 0, FLAGS, "mode" },\
 | 
				
			||||||
 | 
					    { "average",    "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_AVERAGE},    0, 0, FLAGS, "mode" },\
 | 
				
			||||||
 | 
					    { "burn",       "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_BURN},       0, 0, FLAGS, "mode" },\
 | 
				
			||||||
 | 
					    { "darken",     "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_DARKEN},     0, 0, FLAGS, "mode" },\
 | 
				
			||||||
 | 
					    { "difference", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_DIFFERENCE}, 0, 0, FLAGS, "mode" },\
 | 
				
			||||||
 | 
					    { "difference128", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_DIFFERENCE128}, 0, 0, FLAGS, "mode" },\
 | 
				
			||||||
 | 
					    { "divide",     "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_DIVIDE},     0, 0, FLAGS, "mode" },\
 | 
				
			||||||
 | 
					    { "dodge",      "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_DODGE},      0, 0, FLAGS, "mode" },\
 | 
				
			||||||
 | 
					    { "exclusion",  "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_EXCLUSION},  0, 0, FLAGS, "mode" },\
 | 
				
			||||||
 | 
					    { "hardlight",  "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_HARDLIGHT},  0, 0, FLAGS, "mode" },\
 | 
				
			||||||
 | 
					    { "lighten",    "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_LIGHTEN},    0, 0, FLAGS, "mode" },\
 | 
				
			||||||
 | 
					    { "multiply",   "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_MULTIPLY},   0, 0, FLAGS, "mode" },\
 | 
				
			||||||
 | 
					    { "negation",   "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_NEGATION},   0, 0, FLAGS, "mode" },\
 | 
				
			||||||
 | 
					    { "normal",     "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_NORMAL},     0, 0, FLAGS, "mode" },\
 | 
				
			||||||
 | 
					    { "or",         "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_OR},         0, 0, FLAGS, "mode" },\
 | 
				
			||||||
 | 
					    { "overlay",    "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_OVERLAY},    0, 0, FLAGS, "mode" },\
 | 
				
			||||||
 | 
					    { "phoenix",    "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_PHOENIX},    0, 0, FLAGS, "mode" },\
 | 
				
			||||||
 | 
					    { "pinlight",   "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_PINLIGHT},   0, 0, FLAGS, "mode" },\
 | 
				
			||||||
 | 
					    { "reflect",    "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_REFLECT},    0, 0, FLAGS, "mode" },\
 | 
				
			||||||
 | 
					    { "screen",     "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_SCREEN},     0, 0, FLAGS, "mode" },\
 | 
				
			||||||
 | 
					    { "softlight",  "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_SOFTLIGHT},  0, 0, FLAGS, "mode" },\
 | 
				
			||||||
 | 
					    { "subtract",   "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_SUBTRACT},   0, 0, FLAGS, "mode" },\
 | 
				
			||||||
 | 
					    { "vividlight", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_VIVIDLIGHT}, 0, 0, FLAGS, "mode" },\
 | 
				
			||||||
 | 
					    { "xor",        "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_XOR},        0, 0, FLAGS, "mode" },\
 | 
				
			||||||
 | 
					    { "c0_expr",  "set color component #0 expression", OFFSET(params[0].expr_str), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },\
 | 
				
			||||||
 | 
					    { "c1_expr",  "set color component #1 expression", OFFSET(params[1].expr_str), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },\
 | 
				
			||||||
 | 
					    { "c2_expr",  "set color component #2 expression", OFFSET(params[2].expr_str), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },\
 | 
				
			||||||
 | 
					    { "c3_expr",  "set color component #3 expression", OFFSET(params[3].expr_str), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },\
 | 
				
			||||||
 | 
					    { "all_expr", "set expression for all color components", OFFSET(all_expr), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },\
 | 
				
			||||||
 | 
					    { "c0_opacity",  "set color component #0 opacity", OFFSET(params[0].opacity), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS },\
 | 
				
			||||||
 | 
					    { "c1_opacity",  "set color component #1 opacity", OFFSET(params[1].opacity), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS },\
 | 
				
			||||||
 | 
					    { "c2_opacity",  "set color component #2 opacity", OFFSET(params[2].opacity), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS },\
 | 
				
			||||||
 | 
					    { "c3_opacity",  "set color component #3 opacity", OFFSET(params[3].opacity), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS },\
 | 
				
			||||||
 | 
					    { "all_opacity", "set opacity for all color components", OFFSET(all_opacity), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define OFFSET(x) offsetof(BlendContext, x)
 | 
					#define OFFSET(x) offsetof(BlendContext, x)
 | 
				
			||||||
#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
 | 
					#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const AVOption blend_options[] = {
 | 
					static const AVOption blend_options[] = {
 | 
				
			||||||
    { "c0_mode", "set component #0 blend mode", OFFSET(params[0].mode), AV_OPT_TYPE_INT, {.i64=0}, 0, BLEND_NB-1, FLAGS, "mode"},
 | 
					    COMMON_OPTIONS,
 | 
				
			||||||
    { "c1_mode", "set component #1 blend mode", OFFSET(params[1].mode), AV_OPT_TYPE_INT, {.i64=0}, 0, BLEND_NB-1, FLAGS, "mode"},
 | 
					 | 
				
			||||||
    { "c2_mode", "set component #2 blend mode", OFFSET(params[2].mode), AV_OPT_TYPE_INT, {.i64=0}, 0, BLEND_NB-1, FLAGS, "mode"},
 | 
					 | 
				
			||||||
    { "c3_mode", "set component #3 blend mode", OFFSET(params[3].mode), AV_OPT_TYPE_INT, {.i64=0}, 0, BLEND_NB-1, FLAGS, "mode"},
 | 
					 | 
				
			||||||
    { "all_mode", "set blend mode for all components", OFFSET(all_mode), AV_OPT_TYPE_INT, {.i64=-1},-1, BLEND_NB-1, FLAGS, "mode"},
 | 
					 | 
				
			||||||
    { "addition",   "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_ADDITION},   0, 0, FLAGS, "mode" },
 | 
					 | 
				
			||||||
    { "and",        "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_AND},        0, 0, FLAGS, "mode" },
 | 
					 | 
				
			||||||
    { "average",    "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_AVERAGE},    0, 0, FLAGS, "mode" },
 | 
					 | 
				
			||||||
    { "burn",       "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_BURN},       0, 0, FLAGS, "mode" },
 | 
					 | 
				
			||||||
    { "darken",     "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_DARKEN},     0, 0, FLAGS, "mode" },
 | 
					 | 
				
			||||||
    { "difference", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_DIFFERENCE}, 0, 0, FLAGS, "mode" },
 | 
					 | 
				
			||||||
    { "difference128", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_DIFFERENCE128}, 0, 0, FLAGS, "mode" },
 | 
					 | 
				
			||||||
    { "divide",     "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_DIVIDE},     0, 0, FLAGS, "mode" },
 | 
					 | 
				
			||||||
    { "dodge",      "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_DODGE},      0, 0, FLAGS, "mode" },
 | 
					 | 
				
			||||||
    { "exclusion",  "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_EXCLUSION},  0, 0, FLAGS, "mode" },
 | 
					 | 
				
			||||||
    { "hardlight",  "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_HARDLIGHT},  0, 0, FLAGS, "mode" },
 | 
					 | 
				
			||||||
    { "lighten",    "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_LIGHTEN},    0, 0, FLAGS, "mode" },
 | 
					 | 
				
			||||||
    { "multiply",   "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_MULTIPLY},   0, 0, FLAGS, "mode" },
 | 
					 | 
				
			||||||
    { "negation",   "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_NEGATION},   0, 0, FLAGS, "mode" },
 | 
					 | 
				
			||||||
    { "normal",     "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_NORMAL},     0, 0, FLAGS, "mode" },
 | 
					 | 
				
			||||||
    { "or",         "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_OR},         0, 0, FLAGS, "mode" },
 | 
					 | 
				
			||||||
    { "overlay",    "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_OVERLAY},    0, 0, FLAGS, "mode" },
 | 
					 | 
				
			||||||
    { "phoenix",    "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_PHOENIX},    0, 0, FLAGS, "mode" },
 | 
					 | 
				
			||||||
    { "pinlight",   "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_PINLIGHT},   0, 0, FLAGS, "mode" },
 | 
					 | 
				
			||||||
    { "reflect",    "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_REFLECT},    0, 0, FLAGS, "mode" },
 | 
					 | 
				
			||||||
    { "screen",     "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_SCREEN},     0, 0, FLAGS, "mode" },
 | 
					 | 
				
			||||||
    { "softlight",  "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_SOFTLIGHT},  0, 0, FLAGS, "mode" },
 | 
					 | 
				
			||||||
    { "subtract",   "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_SUBTRACT},   0, 0, FLAGS, "mode" },
 | 
					 | 
				
			||||||
    { "vividlight", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_VIVIDLIGHT}, 0, 0, FLAGS, "mode" },
 | 
					 | 
				
			||||||
    { "xor",        "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_XOR},        0, 0, FLAGS, "mode" },
 | 
					 | 
				
			||||||
    { "c0_expr",  "set color component #0 expression", OFFSET(params[0].expr_str), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },
 | 
					 | 
				
			||||||
    { "c1_expr",  "set color component #1 expression", OFFSET(params[1].expr_str), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },
 | 
					 | 
				
			||||||
    { "c2_expr",  "set color component #2 expression", OFFSET(params[2].expr_str), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },
 | 
					 | 
				
			||||||
    { "c3_expr",  "set color component #3 expression", OFFSET(params[3].expr_str), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },
 | 
					 | 
				
			||||||
    { "all_expr", "set expression for all color components", OFFSET(all_expr), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },
 | 
					 | 
				
			||||||
    { "c0_opacity",  "set color component #0 opacity", OFFSET(params[0].opacity), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS },
 | 
					 | 
				
			||||||
    { "c1_opacity",  "set color component #1 opacity", OFFSET(params[1].opacity), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS },
 | 
					 | 
				
			||||||
    { "c2_opacity",  "set color component #2 opacity", OFFSET(params[2].opacity), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS },
 | 
					 | 
				
			||||||
    { "c3_opacity",  "set color component #3 opacity", OFFSET(params[3].opacity), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS },
 | 
					 | 
				
			||||||
    { "all_opacity", "set opacity for all color components", OFFSET(all_opacity), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS},
 | 
					 | 
				
			||||||
    { "shortest",    "force termination when the shortest input terminates", OFFSET(dinput.shortest), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS },
 | 
					    { "shortest",    "force termination when the shortest input terminates", OFFSET(dinput.shortest), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS },
 | 
				
			||||||
    { "repeatlast",  "repeat last bottom frame", OFFSET(dinput.repeatlast), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, FLAGS },
 | 
					    { "repeatlast",  "repeat last bottom frame", OFFSET(dinput.repeatlast), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, FLAGS },
 | 
				
			||||||
    { NULL }
 | 
					    { NULL }
 | 
				
			||||||
@ -288,7 +293,8 @@ static AVFrame *blend_frame(AVFilterContext *ctx, AVFrame *top_buf,
 | 
				
			|||||||
        ctx->internal->execute(ctx, filter_slice, &td, NULL, FFMIN(outh, ctx->graph->nb_threads));
 | 
					        ctx->internal->execute(ctx, filter_slice, &td, NULL, FFMIN(outh, ctx->graph->nb_threads));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    av_frame_free(&top_buf);
 | 
					    if (!b->tblend)
 | 
				
			||||||
 | 
					        av_frame_free(&top_buf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return dst_buf;
 | 
					    return dst_buf;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -298,6 +304,8 @@ static av_cold int init(AVFilterContext *ctx)
 | 
				
			|||||||
    BlendContext *b = ctx->priv;
 | 
					    BlendContext *b = ctx->priv;
 | 
				
			||||||
    int ret, plane;
 | 
					    int ret, plane;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    b->tblend = !strcmp(ctx->filter->name, "tblend");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (plane = 0; plane < FF_ARRAY_ELEMS(b->params); plane++) {
 | 
					    for (plane = 0; plane < FF_ARRAY_ELEMS(b->params); plane++) {
 | 
				
			||||||
        FilterParams *param = &b->params[plane];
 | 
					        FilterParams *param = &b->params[plane];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -416,6 +424,8 @@ static av_cold void uninit(AVFilterContext *ctx)
 | 
				
			|||||||
    int i;
 | 
					    int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ff_dualinput_uninit(&b->dinput);
 | 
					    ff_dualinput_uninit(&b->dinput);
 | 
				
			||||||
 | 
					    av_freep(&b->prev_frame);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (i = 0; i < FF_ARRAY_ELEMS(b->params); i++)
 | 
					    for (i = 0; i < FF_ARRAY_ELEMS(b->params); i++)
 | 
				
			||||||
        av_expr_free(b->params[i].e);
 | 
					        av_expr_free(b->params[i].e);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -467,3 +477,71 @@ AVFilter ff_vf_blend = {
 | 
				
			|||||||
    .priv_class    = &blend_class,
 | 
					    .priv_class    = &blend_class,
 | 
				
			||||||
    .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | AVFILTER_FLAG_SLICE_THREADS,
 | 
					    .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | AVFILTER_FLAG_SLICE_THREADS,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int tblend_config_output(AVFilterLink *outlink)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    AVFilterContext *ctx = outlink->src;
 | 
				
			||||||
 | 
					    AVFilterLink *inlink = ctx->inputs[0];
 | 
				
			||||||
 | 
					    BlendContext *b = ctx->priv;
 | 
				
			||||||
 | 
					    const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(inlink->format);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    b->hsub = pix_desc->log2_chroma_w;
 | 
				
			||||||
 | 
					    b->vsub = pix_desc->log2_chroma_h;
 | 
				
			||||||
 | 
					    b->nb_planes = av_pix_fmt_count_planes(inlink->format);
 | 
				
			||||||
 | 
					    outlink->flags |= FF_LINK_FLAG_REQUEST_LOOP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int tblend_filter_frame(AVFilterLink *inlink, AVFrame *frame)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    BlendContext *b = inlink->dst->priv;
 | 
				
			||||||
 | 
					    AVFilterLink *outlink = inlink->dst->outputs[0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (b->prev_frame) {
 | 
				
			||||||
 | 
					        AVFrame *out = blend_frame(inlink->dst, frame, b->prev_frame);
 | 
				
			||||||
 | 
					        av_frame_free(&b->prev_frame);
 | 
				
			||||||
 | 
					        b->prev_frame = frame;
 | 
				
			||||||
 | 
					        return ff_filter_frame(outlink, out);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    b->prev_frame = frame;
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const AVOption tblend_options[] = {
 | 
				
			||||||
 | 
					    COMMON_OPTIONS,
 | 
				
			||||||
 | 
					    { NULL }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					AVFILTER_DEFINE_CLASS(tblend);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const AVFilterPad tblend_inputs[] = {
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .name          = "default",
 | 
				
			||||||
 | 
					        .type          = AVMEDIA_TYPE_VIDEO,
 | 
				
			||||||
 | 
					        .filter_frame  = tblend_filter_frame,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    { NULL }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const AVFilterPad tblend_outputs[] = {
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .name          = "default",
 | 
				
			||||||
 | 
					        .type          = AVMEDIA_TYPE_VIDEO,
 | 
				
			||||||
 | 
					        .config_props  = tblend_config_output,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    { NULL }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					AVFilter ff_vf_tblend = {
 | 
				
			||||||
 | 
					    .name          = "tblend",
 | 
				
			||||||
 | 
					    .description   = NULL_IF_CONFIG_SMALL("Blend successive frames."),
 | 
				
			||||||
 | 
					    .priv_size     = sizeof(BlendContext),
 | 
				
			||||||
 | 
					    .priv_class    = &blend_class,
 | 
				
			||||||
 | 
					    .query_formats = query_formats,
 | 
				
			||||||
 | 
					    .init          = init,
 | 
				
			||||||
 | 
					    .uninit        = uninit,
 | 
				
			||||||
 | 
					    .inputs        = tblend_inputs,
 | 
				
			||||||
 | 
					    .outputs       = tblend_outputs,
 | 
				
			||||||
 | 
					    .flags         = AVFILTER_FLAG_SLICE_THREADS,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user