diff options
author | Paul B Mahol <onemda@gmail.com> | 2021-09-27 20:38:26 +0200 |
---|---|---|
committer | Paul B Mahol <onemda@gmail.com> | 2021-09-28 00:14:19 +0200 |
commit | dd190195007093da57959c68c740e729e1048c24 (patch) | |
tree | 83fff085b837d6449df8db41129d733a5be3c900 /libavfilter/blend_modes.c | |
parent | 524407af0c3993a36fb8399e5ba7fa07b731b57c (diff) | |
download | ffmpeg-dd190195007093da57959c68c740e729e1048c24.tar.gz |
avfilter/vf_blend: refactor blend modes
Diffstat (limited to 'libavfilter/blend_modes.c')
-rw-r--r-- | libavfilter/blend_modes.c | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/libavfilter/blend_modes.c b/libavfilter/blend_modes.c new file mode 100644 index 0000000000..d75560185c --- /dev/null +++ b/libavfilter/blend_modes.c @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2013 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/common.h" +#include "libavutil/intfloat.h" +#include "avfilter.h" +#include "formats.h" +#include "internal.h" +#include "video.h" +#include "blend.h" + +#undef PIXEL +#undef MAX +#undef HALF +#undef CLIP + +#if DEPTH == 8 +#define PIXEL uint8_t +#define MAX 255 +#define HALF 128 +#define CLIP(x) (av_clip_uint8(x)) +#elif DEPTH == 32 +#define PIXEL float +#define MAX 1.f +#define HALF 0.5f +#define CLIP(x) (x) +#else +#define PIXEL uint16_t +#define MAX ((1 << DEPTH) - 1) +#define HALF (1 << (DEPTH - 1)) +#define CLIP(x) ((int)av_clip_uintp2(x, DEPTH)) +#endif + +#undef MULTIPLY +#undef SCREEN +#undef BURN +#undef DODGE +#undef INT2FLOAT +#undef FLOAT2INT +#undef MDIV + +#if DEPTH < 32 +#define MULTIPLY(x, a, b) ((x) * (((a) * (b)) / MAX)) +#define SCREEN(x, a, b) (MAX - (x) * ((MAX - (a)) * (MAX - (b)) / MAX)) +#define BURN(a, b) (((a) == 0) ? (a) : FFMAX(0, MAX - ((MAX - (b)) << DEPTH) / (a))) +#define DODGE(a, b) (((a) == MAX) ? (a) : FFMIN(MAX, (((b) << DEPTH) / (MAX - (a))))) +#define INT2FLOAT(x) (x) +#define FLOAT2INT(x) (x) +#define MDIV (0.125f * (1 << DEPTH)) +#else +#define MULTIPLY(x, a, b) ((x) * (((a) * (b)) / 1.0)) +#define SCREEN(x, a, b) (1.0 - (x) * ((1.0 - (a)) * (1.0 - (b)) / 1.0)) +#define BURN(a, b) (((a) <= 0.0) ? (a) : FFMAX(0.0, 1.0 - (1.0 - (b)) / (a))) +#define DODGE(a, b) (((a) >= 1.0) ? (a) : FFMIN(1.0, ((b) / (1.0 - (a))))) +#define INT2FLOAT(x) av_int2float(x) +#define FLOAT2INT(x) av_float2int(x) +#define MDIV 0.125f +#endif + +#define A top[j] +#define B bottom[j] + +#define fn2(a, b) blend_##a##_##b##bit +#define fn1(name, depth) fn2(name, depth) +#define fn0(name) fn1(name, DEPTH) + +#define fn(NAME, EXPR) \ +static void fn0(NAME)(const uint8_t *_top, ptrdiff_t top_linesize, \ + const uint8_t *_bottom, ptrdiff_t bottom_linesize, \ + uint8_t *_dst, ptrdiff_t dst_linesize, \ + ptrdiff_t width, ptrdiff_t height, \ + FilterParams *param, double *values, int starty) \ +{ \ + const PIXEL *top = (PIXEL *)_top; \ + const PIXEL *bottom = (PIXEL *)_bottom; \ + PIXEL *dst = (PIXEL *)_dst; \ + const float opacity = param->opacity; \ + \ + dst_linesize /= sizeof(PIXEL); \ + top_linesize /= sizeof(PIXEL); \ + bottom_linesize /= sizeof(PIXEL); \ + \ + for (int i = 0; i < height; i++) { \ + for (int j = 0; j < width; j++) { \ + dst[j] = top[j] + ((EXPR)-top[j]) * opacity; \ + } \ + dst += dst_linesize; \ + top += top_linesize; \ + bottom += bottom_linesize; \ + } \ +} + +fn(addition, FFMIN(MAX, A + B)) +fn(grainmerge, CLIP(A + B - HALF)) +fn(average, (A + B) / 2) +fn(subtract, FFMAX(0, A - B)) +fn(multiply, MULTIPLY(1, A, B)) +fn(multiply128,CLIP((A - HALF) * B / MDIV + HALF)) +fn(negation, MAX - FFABS(MAX - A - B)) +fn(extremity, FFABS(MAX - A - B)) +fn(difference, FFABS(A - B)) +fn(grainextract, CLIP(HALF + A - B)) +fn(screen, SCREEN(1, A, B)) +fn(overlay, (A < HALF) ? MULTIPLY(2, A, B) : SCREEN(2, A, B)) +fn(hardlight, (B < HALF) ? MULTIPLY(2, B, A) : SCREEN(2, B, A)) +fn(hardmix, (A < (MAX - B)) ? 0: MAX) +fn(heat, (A == 0) ? 0 : MAX - FFMIN(((MAX - B) * (MAX - B)) / A, MAX)) +fn(freeze, (B == 0) ? 0 : MAX - FFMIN(((MAX - A) * (MAX - A)) / B, MAX)) +fn(darken, FFMIN(A, B)) +fn(lighten, FFMAX(A, B)) +fn(divide, CLIP(B == 0 ? MAX : MAX * A / B)) +fn(dodge, DODGE(A, B)) +fn(burn, BURN(A, B)) +fn(softlight, CLIP(A * A / MAX + (2 * (B * ((A * (MAX - A)) / MAX) / MAX)))) +fn(exclusion, A + B - 2 * A * B / MAX) +fn(pinlight, (B < HALF) ? FFMIN(A, 2 * B) : FFMAX(A, 2 * (B - HALF))) +fn(phoenix, FFMIN(A, B) - FFMAX(A, B) + MAX) +fn(reflect, (B == MAX) ? B : FFMIN(MAX, (A * A / (MAX - B)))) +fn(glow, (A == MAX) ? A : FFMIN(MAX, (B * B / (MAX - A)))) +fn(and, INT2FLOAT(FLOAT2INT(A) & FLOAT2INT(B))) +fn(or, INT2FLOAT(FLOAT2INT(A) | FLOAT2INT(B))) +fn(xor, INT2FLOAT(FLOAT2INT(A) ^ FLOAT2INT(B))) +fn(vividlight, (A < HALF) ? BURN(2 * A, B) : DODGE(2 * (A - HALF), B)) +fn(linearlight,CLIP((B < HALF) ? B + 2 * A - MAX : B + 2 * (A - HALF))) +fn(softdifference,CLIP((A > B) ? (B == MAX) ? 0 : (A - B) * MAX / (MAX - B) : (B == 0) ? 0 : (B - A) * MAX / B)) |