65 static const char *
const var_names[] = {
"X",
"Y",
"W",
"H",
"SW",
"SH",
"T",
"N",
"A",
"B",
"TOP",
"BOTTOM",
NULL };
66 enum {
VAR_X,
VAR_Y,
VAR_W,
VAR_H,
VAR_SW,
VAR_SH,
VAR_T,
VAR_N,
VAR_A,
VAR_B,
VAR_TOP,
VAR_BOTTOM,
VAR_VARS_NB };
74 const uint8_t *bottom,
int bottom_linesize,
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}
145 #define OFFSET(x) offsetof(BlendContext, x)
146 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
150 {
"shortest",
"force termination when the shortest input terminates",
OFFSET(dinput.shortest),
AV_OPT_TYPE_INT, {.i64=0}, 0, 1,
FLAGS },
158 const uint8_t *bottom,
int bottom_linesize,
159 uint8_t *dst,
int dst_linesize,
166 #define DEFINE_BLEND(name, expr) \
167 static void blend_## name(const uint8_t *top, int top_linesize, \
168 const uint8_t *bottom, int bottom_linesize, \
169 uint8_t *dst, int dst_linesize, \
170 int width, int start, int end, \
171 FilterParams *param, double *values) \
173 double opacity = param->opacity; \
176 for (i = start; i < end; i++) { \
177 for (j = 0; j < width; j++) { \
178 dst[j] = top[j] + ((expr) - top[j]) * opacity; \
180 dst += dst_linesize; \
181 top += top_linesize; \
182 bottom += bottom_linesize; \
189 #define MULTIPLY(x, a, b) ((x) * (((a) * (b)) / 255))
190 #define SCREEN(x, a, b) (255 - (x) * ((255 - (a)) * (255 - (b)) / 255))
191 #define BURN(a, b) (((a) == 0) ? (a) : FFMAX(0, 255 - ((255 - (b)) << 8) / (a)))
192 #define DODGE(a, b) (((a) == 255) ? (a) : FFMIN(255, (((b) << 8) / (255 - (a)))))
203 DEFINE_BLEND(hardlight, (
B < 128) ? MULTIPLY(2,
B, A) : SCREEN(2, B, A))
209 DEFINE_BLEND(softlight, (A > 127) ? B + (255 - B) * (A - 127.5) / 127.5 * (0.5 -
FFABS(B - 127.5) / 255): B - B * ((127.5 - A) / 127.5) * (0.5 -
FFABS(B - 127.5)/255))
219 static
void blend_expr(const
uint8_t *top,
int top_linesize,
220 const
uint8_t *bottom,
int bottom_linesize,
221 uint8_t *dst,
int dst_linesize,
228 for (y = start; y <
end; y++) {
230 for (x = 0; x <
width; x++) {
238 bottom += bottom_linesize;
245 int slice_start = (td->
h * jobnr ) / nb_jobs;
246 int slice_end = (td->
h * (jobnr+1)) / nb_jobs;
265 td->
w, slice_start, slice_end, td->
param, &values[0]);
283 for (plane = 0; plane < b->
nb_planes; plane++) {
284 int hsub = plane == 1 || plane == 2 ? b->
hsub : 0;
285 int vsub = plane == 1 || plane == 2 ? b->
vsub : 0;
289 ThreadData td = { .top = top_buf, .bottom = bottom_buf, .dst = dst_buf,
290 .w = outw, .h = outh, .param = param, .plane = plane,
317 switch (param->
mode) {
355 param->
blend = blend_expr;
388 #if CONFIG_BLEND_FILTER
403 if (toplink->
w != bottomlink->
w ||
404 toplink->
h != bottomlink->
h ||
408 "(size %dx%d, SAR %d:%d) do not match the corresponding "
409 "second input link %s parameters (%dx%d, SAR %d:%d)\n",
419 outlink->
w = toplink->
w;
420 outlink->
h = toplink->
h;
479 .priv_class = &blend_class,
485 #if CONFIG_TBLEND_FILTER
517 static const AVOption tblend_options[] = {
528 .filter_frame = tblend_filter_frame,
537 .config_props = tblend_config_output,
546 .priv_class = &tblend_class,