Browse code

avfilter: add despill filter

Signed-off-by: Paul B Mahol <onemda@gmail.com>

Paul B Mahol authored on 2017/08/28 21:32:25
Showing 6 changed files
... ...
@@ -42,6 +42,7 @@ version <next>:
42 42
 - FITS muxer and encoder
43 43
 - add --disable-autodetect build switch
44 44
 - drop deprecated qtkit input device (use avfoundation instead)
45
+- despill video filter
45 46
 
46 47
 version 3.3:
47 48
 - CrystalHD decoder moved to new decode API
... ...
@@ -6811,6 +6811,41 @@ FFmpeg was configured with @code{--enable-opencl}. Default value is 0.
6811 6811
 
6812 6812
 @end table
6813 6813
 
6814
+@section despill
6815
+
6816
+Remove unwanted contamination of foreground colors, caused by reflected color of
6817
+greenscreen or bluescreen.
6818
+
6819
+This filter accepts the following options:
6820
+
6821
+@table @option
6822
+@item type
6823
+Set what type of despill to use.
6824
+
6825
+@item mix
6826
+Set how spillmap will be generated.
6827
+
6828
+@item expand
6829
+Set how much to get rid of still remaining spill.
6830
+
6831
+@item red
6832
+Controls ammount of red in spill area.
6833
+
6834
+@item green
6835
+Controls ammount of green in spill area.
6836
+Should be -1 for greenscreen.
6837
+
6838
+@item blue
6839
+Controls ammount of blue in spill area.
6840
+Should be -1 for bluescreen.
6841
+
6842
+@item brightness
6843
+Controls brightness of spill area, preserving colors.
6844
+
6845
+@item alpha
6846
+Modify alpha from generated spillmap.
6847
+@end table
6848
+
6814 6849
 @section detelecine
6815 6850
 
6816 6851
 Apply an exact inverse of the telecine operation. It requires a predefined
... ...
@@ -166,6 +166,7 @@ OBJS-$(CONFIG_DEINTERLACE_VAAPI_FILTER)      += vf_deinterlace_vaapi.o
166 166
 OBJS-$(CONFIG_DEJUDDER_FILTER)               += vf_dejudder.o
167 167
 OBJS-$(CONFIG_DELOGO_FILTER)                 += vf_delogo.o
168 168
 OBJS-$(CONFIG_DESHAKE_FILTER)                += vf_deshake.o
169
+OBJS-$(CONFIG_DESPILL_FILTER)                += vf_despill.o
169 170
 OBJS-$(CONFIG_DETELECINE_FILTER)             += vf_detelecine.o
170 171
 OBJS-$(CONFIG_DILATION_FILTER)               += vf_neighbor.o
171 172
 OBJS-$(CONFIG_DISPLACE_FILTER)               += vf_displace.o framesync2.o
... ...
@@ -178,6 +178,7 @@ static void register_all(void)
178 178
     REGISTER_FILTER(DEJUDDER,       dejudder,       vf);
179 179
     REGISTER_FILTER(DELOGO,         delogo,         vf);
180 180
     REGISTER_FILTER(DESHAKE,        deshake,        vf);
181
+    REGISTER_FILTER(DESPILL,        despill,        vf);
181 182
     REGISTER_FILTER(DETELECINE,     detelecine,     vf);
182 183
     REGISTER_FILTER(DILATION,       dilation,       vf);
183 184
     REGISTER_FILTER(DISPLACE,       displace,       vf);
... ...
@@ -30,7 +30,7 @@
30 30
 #include "libavutil/version.h"
31 31
 
32 32
 #define LIBAVFILTER_VERSION_MAJOR   6
33
-#define LIBAVFILTER_VERSION_MINOR 101
33
+#define LIBAVFILTER_VERSION_MINOR 102
34 34
 #define LIBAVFILTER_VERSION_MICRO 100
35 35
 
36 36
 #define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
37 37
new file mode 100644
... ...
@@ -0,0 +1,183 @@
0
+/*
1
+ * Copyright (c) 2017 Paul B Mahol
2
+ *
3
+ * This file is part of FFmpeg.
4
+ *
5
+ * FFmpeg is free software; you can redistribute it and/or
6
+ * modify it under the terms of the GNU Lesser General Public
7
+ * License as published by the Free Software Foundation; either
8
+ * version 2.1 of the License, or (at your option) any later version.
9
+ *
10
+ * FFmpeg is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
+ * Lesser General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU Lesser General Public
16
+ * License along with FFmpeg; if not, write to the Free Software
17
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
+ */
19
+
20
+#include "libavutil/opt.h"
21
+#include "libavutil/imgutils.h"
22
+#include "avfilter.h"
23
+#include "formats.h"
24
+#include "internal.h"
25
+#include "video.h"
26
+
27
+typedef struct DespillContext {
28
+    const AVClass *class;
29
+
30
+    int co[4]; /* color offsets rgba */
31
+
32
+    int alpha;
33
+    int type;
34
+    float spillmix;
35
+    float spillexpand;
36
+    float redscale;
37
+    float greenscale;
38
+    float bluescale;
39
+    float brightness;
40
+} DespillContext;
41
+
42
+static int do_despill_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
43
+{
44
+    DespillContext *s = ctx->priv;
45
+    AVFrame *frame = arg;
46
+    const int ro = s->co[0], go = s->co[1], bo = s->co[2], ao = s->co[3];
47
+    const int slice_start = (frame->height * jobnr) / nb_jobs;
48
+    const int slice_end = (frame->height * (jobnr + 1)) / nb_jobs;
49
+    const float brightness = s->brightness;
50
+    const float redscale = s->redscale;
51
+    const float greenscale = s->greenscale;
52
+    const float bluescale = s->bluescale;
53
+    const float spillmix = s->spillmix;
54
+    const float factor = (1.f - spillmix) * (1.f - s->spillexpand);
55
+    float red, green, blue;
56
+    int x, y;
57
+
58
+    for (y = slice_start; y < slice_end; y++) {
59
+        uint8_t *dst = frame->data[0] + y * frame->linesize[0];
60
+
61
+        for (x = 0; x < frame->width; x++) {
62
+            float spillmap;
63
+
64
+            red   = dst[x * 4 + ro] / 255.f;
65
+            green = dst[x * 4 + go] / 255.f;
66
+            blue  = dst[x * 4 + bo] / 255.f;
67
+
68
+            if (s->type) {
69
+                spillmap = FFMAX(blue  - (red * spillmix + green * factor), 0.f);
70
+            } else {
71
+                spillmap = FFMAX(green - (red * spillmix + blue  * factor), 0.f);
72
+            }
73
+
74
+            red   = FFMAX(red   + spillmap * redscale   + brightness * spillmap, 0.f);
75
+            green = FFMAX(green + spillmap * greenscale + brightness * spillmap, 0.f);
76
+            blue  = FFMAX(blue  + spillmap * bluescale  + brightness * spillmap, 0.f);
77
+
78
+            dst[x * 4 + ro] = av_clip_uint8(red   * 255);
79
+            dst[x * 4 + go] = av_clip_uint8(green * 255);
80
+            dst[x * 4 + bo] = av_clip_uint8(blue  * 255);
81
+            if (s->alpha) {
82
+                spillmap = 1.f - spillmap;
83
+                dst[x * 4 + ao] = av_clip_uint8(spillmap * 255);
84
+            }
85
+        }
86
+    }
87
+
88
+    return 0;
89
+}
90
+
91
+static int filter_frame(AVFilterLink *link, AVFrame *frame)
92
+{
93
+    AVFilterContext *ctx = link->dst;
94
+    int ret;
95
+
96
+    if (ret = av_frame_make_writable(frame))
97
+        return ret;
98
+
99
+    if (ret = ctx->internal->execute(ctx, do_despill_slice, frame, NULL, FFMIN(frame->height, ff_filter_get_nb_threads(ctx))))
100
+        return ret;
101
+
102
+    return ff_filter_frame(ctx->outputs[0], frame);
103
+}
104
+
105
+static av_cold int config_output(AVFilterLink *outlink)
106
+{
107
+    AVFilterContext *ctx = outlink->src;
108
+    DespillContext *s = ctx->priv;
109
+    const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(outlink->format);
110
+    int i;
111
+
112
+    for (i = 0; i < 4; ++i)
113
+        s->co[i] = desc->comp[i].offset;
114
+
115
+    return 0;
116
+}
117
+
118
+static av_cold int query_formats(AVFilterContext *ctx)
119
+{
120
+    static const enum AVPixelFormat pixel_fmts[] = {
121
+        AV_PIX_FMT_ARGB,
122
+        AV_PIX_FMT_RGBA,
123
+        AV_PIX_FMT_ABGR,
124
+        AV_PIX_FMT_BGRA,
125
+        AV_PIX_FMT_NONE
126
+    };
127
+    AVFilterFormats *formats = NULL;
128
+
129
+    formats = ff_make_format_list(pixel_fmts);
130
+    if (!formats)
131
+        return AVERROR(ENOMEM);
132
+
133
+    return ff_set_common_formats(ctx, formats);
134
+}
135
+
136
+static const AVFilterPad despill_inputs[] = {
137
+    {
138
+        .name         = "default",
139
+        .type         = AVMEDIA_TYPE_VIDEO,
140
+        .filter_frame = filter_frame,
141
+    },
142
+    { NULL }
143
+};
144
+
145
+static const AVFilterPad despill_outputs[] = {
146
+    {
147
+        .name         = "default",
148
+        .type         = AVMEDIA_TYPE_VIDEO,
149
+        .config_props = config_output,
150
+    },
151
+    { NULL }
152
+};
153
+
154
+#define OFFSET(x) offsetof(DespillContext, x)
155
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
156
+
157
+static const AVOption despill_options[] = {
158
+    { "type",       "set the screen type",     OFFSET(type),        AV_OPT_TYPE_INT,     {.i64=0},     0,   1, FLAGS, "type" },
159
+    {   "green",    "greenscreen",             0,                   AV_OPT_TYPE_CONST,   {.i64=0},     0,   0, FLAGS, "type" },
160
+    {   "blue",     "bluescreen",              0,                   AV_OPT_TYPE_CONST,   {.i64=1},     0,   0, FLAGS, "type" },
161
+    { "mix",        "set the spillmap mix",    OFFSET(spillmix),    AV_OPT_TYPE_FLOAT,   {.dbl=0.5},   0,   1, FLAGS },
162
+    { "expand",     "set the spillmap expand", OFFSET(spillexpand), AV_OPT_TYPE_FLOAT,   {.dbl=0},     0,   1, FLAGS },
163
+    { "red",        "set red scale",           OFFSET(bluescale),   AV_OPT_TYPE_FLOAT,   {.dbl=0},  -100, 100, FLAGS },
164
+    { "green",      "set green scale",         OFFSET(greenscale),  AV_OPT_TYPE_FLOAT,   {.dbl=-1}, -100, 100, FLAGS },
165
+    { "blue",       "set blue scale",          OFFSET(bluescale),   AV_OPT_TYPE_FLOAT,   {.dbl=0},  -100, 100, FLAGS },
166
+    { "brightness", "set brightness",          OFFSET(brightness),  AV_OPT_TYPE_FLOAT,   {.dbl=0},   -10,  10, FLAGS },
167
+    { "alpha",      "change alpha component",  OFFSET(alpha),       AV_OPT_TYPE_BOOL,    {.i64=0},     0,   1, FLAGS },
168
+    { NULL }
169
+};
170
+
171
+AVFILTER_DEFINE_CLASS(despill);
172
+
173
+AVFilter ff_vf_despill = {
174
+    .name          = "despill",
175
+    .description   = NULL_IF_CONFIG_SMALL("Despill video."),
176
+    .priv_size     = sizeof(DespillContext),
177
+    .priv_class    = &despill_class,
178
+    .query_formats = query_formats,
179
+    .inputs        = despill_inputs,
180
+    .outputs       = despill_outputs,
181
+    .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
182
+};