Browse code

avfilter/vf_colorkey: Add colorkey video filter

Signed-off-by: Michael Niedermayer <michaelni@gmx.at>

Timo Rothenpieler authored on 2015/06/13 22:09:07
Showing 6 changed files
... ...
@@ -2,6 +2,7 @@ Entries are sorted chronologically from oldest to youngest within each release,
2 2
 releases are sorted from youngest to oldest.
3 3
 
4 4
 version <next>:
5
+- colorkey video filter
5 6
 
6 7
 
7 8
 version 2.7:
... ...
@@ -352,6 +352,7 @@ Filters:
352 352
   avf_showcqt.c                         Muhammad Faiz
353 353
   vf_blend.c                            Paul B Mahol
354 354
   vf_colorbalance.c                     Paul B Mahol
355
+  vf_colorkey.c                         Timo Rothenpieler
355 356
   vf_dejudder.c                         Nicholas Robbins
356 357
   vf_delogo.c                           Jean Delvare (CC <khali@linux-fr.org>)
357 358
   vf_drawbox.c/drawgrid                 Andrey Utkin
... ...
@@ -3029,6 +3029,45 @@ colorbalance=rs=.3
3029 3029
 @end example
3030 3030
 @end itemize
3031 3031
 
3032
+@section colorkey
3033
+RGB colorspace color keying.
3034
+
3035
+The filter accepts the following options:
3036
+
3037
+@table @option
3038
+@item color
3039
+The color which will be replaced with transparency.
3040
+
3041
+@item similarity
3042
+Similarity percentage with the key color.
3043
+
3044
+0.01 matches only the exact key color, while 1.0 matches everything.
3045
+
3046
+@item blend
3047
+Blend percentage.
3048
+
3049
+0.0 makes pixels either fully transparent, or not transparent at all.
3050
+
3051
+Higher values result in semi-transparent pixels, with a higher transparency
3052
+the more similar the pixels color is to the key color.
3053
+@end table
3054
+
3055
+@subsection Examples
3056
+
3057
+@itemize
3058
+@item
3059
+Make every green pixel in the input image transparent:
3060
+@example
3061
+ffmpeg -i input.png -vf colorkey=green out.png
3062
+@end example
3063
+
3064
+@item
3065
+Overlay a greenscreen-video on top of a static background image.
3066
+@example
3067
+ffmpeg -i background.png -i video.mp4 -filter_complex "[1:v]colorkey=0x3BBD1E:0.3:0.2[ckout];[0:v][ckout]overlay[out]" -map "[out]" output.flv
3068
+@end example
3069
+@end itemize
3070
+
3032 3071
 @section colorlevels
3033 3072
 
3034 3073
 Adjust video input frames using levels.
... ...
@@ -102,6 +102,7 @@ OBJS-$(CONFIG_BOXBLUR_FILTER)                += vf_boxblur.o
102 102
 OBJS-$(CONFIG_CODECVIEW_FILTER)              += vf_codecview.o
103 103
 OBJS-$(CONFIG_COLORBALANCE_FILTER)           += vf_colorbalance.o
104 104
 OBJS-$(CONFIG_COLORCHANNELMIXER_FILTER)      += vf_colorchannelmixer.o
105
+OBJS-$(CONFIG_COLORKEY_FILTER)               += vf_colorkey.o
105 106
 OBJS-$(CONFIG_COLORLEVELS_FILTER)            += vf_colorlevels.o
106 107
 OBJS-$(CONFIG_COLORMATRIX_FILTER)            += vf_colormatrix.o
107 108
 OBJS-$(CONFIG_COPY_FILTER)                   += vf_copy.o
... ...
@@ -118,6 +118,7 @@ void avfilter_register_all(void)
118 118
     REGISTER_FILTER(CODECVIEW,      codecview,      vf);
119 119
     REGISTER_FILTER(COLORBALANCE,   colorbalance,   vf);
120 120
     REGISTER_FILTER(COLORCHANNELMIXER, colorchannelmixer, vf);
121
+    REGISTER_FILTER(COLORKEY,       colorkey,       vf);
121 122
     REGISTER_FILTER(COLORLEVELS,    colorlevels,    vf);
122 123
     REGISTER_FILTER(COLORMATRIX,    colormatrix,    vf);
123 124
     REGISTER_FILTER(COPY,           copy,           vf);
124 125
new file mode 100644
... ...
@@ -0,0 +1,169 @@
0
+/*
1
+ * Copyright (c) 2015 Timo Rothenpieler <timo@rothenpieler.org>
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 ColorkeyContext {
28
+    const AVClass *class;
29
+
30
+    /* color offsets rgba */
31
+    int co[4];
32
+
33
+    uint8_t colorkey_rgba[4];
34
+    float similarity;
35
+    float blend;
36
+} ColorkeyContext;
37
+
38
+static uint8_t do_colorkey_pixel(ColorkeyContext *ctx, uint8_t r, uint8_t g, uint8_t b)
39
+{
40
+    int dr = (int)r - ctx->colorkey_rgba[0];
41
+    int dg = (int)g - ctx->colorkey_rgba[1];
42
+    int db = (int)b - ctx->colorkey_rgba[2];
43
+
44
+    double diff = sqrt((dr * dr + dg * dg + db * db) / (255.0 * 255.0));
45
+
46
+    if (ctx->blend > 0.0001) {
47
+        return av_clipd((diff - ctx->similarity) / ctx->blend, 0.0, 1.0) * 255.0;
48
+    } else {
49
+        return (diff > ctx->similarity) ? 255 : 0;
50
+    }
51
+}
52
+
53
+static int do_colorkey_slice(AVFilterContext *avctx, void *arg, int jobnr, int nb_jobs)
54
+{
55
+    AVFrame *frame = arg;
56
+
57
+    const int slice_start = (frame->height * jobnr) / nb_jobs;
58
+    const int slice_end = (frame->height * (jobnr + 1)) / nb_jobs;
59
+
60
+    ColorkeyContext *ctx = avctx->priv;
61
+
62
+    int o, x, y;
63
+
64
+    for (y = slice_start; y < slice_end; ++y) {
65
+        for (x = 0; x < frame->width; ++x) {
66
+            o = frame->linesize[0] * y + x * 4;
67
+
68
+            frame->data[0][o + ctx->co[3]] =
69
+                do_colorkey_pixel(ctx,
70
+                                  frame->data[0][o + ctx->co[0]],
71
+                                  frame->data[0][o + ctx->co[1]],
72
+                                  frame->data[0][o + ctx->co[2]]);
73
+        }
74
+    }
75
+
76
+    return 0;
77
+}
78
+
79
+static int filter_frame(AVFilterLink *link, AVFrame *frame)
80
+{
81
+    AVFilterContext *avctx = link->dst;
82
+    int res;
83
+
84
+    if (res = av_frame_make_writable(frame))
85
+        return res;
86
+
87
+    if (res = avctx->internal->execute(avctx, do_colorkey_slice, frame, NULL, FFMIN(frame->height, avctx->graph->nb_threads)))
88
+        return res;
89
+
90
+    return ff_filter_frame(avctx->outputs[0], frame);
91
+}
92
+
93
+static av_cold int config_output(AVFilterLink *outlink)
94
+{
95
+    AVFilterContext *avctx = outlink->src;
96
+    ColorkeyContext *ctx = avctx->priv;
97
+    const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(outlink->format);
98
+    int i;
99
+
100
+    outlink->w = avctx->inputs[0]->w;
101
+    outlink->h = avctx->inputs[0]->h;
102
+    outlink->time_base = avctx->inputs[0]->time_base;
103
+
104
+    for (i = 0; i < 4; ++i)
105
+        ctx->co[i] = desc->comp[i].offset_plus1 - 1;
106
+
107
+    return 0;
108
+}
109
+
110
+static av_cold int query_formats(AVFilterContext *avctx)
111
+{
112
+    static const enum AVPixelFormat pixel_fmts[] = {
113
+        AV_PIX_FMT_ARGB,
114
+        AV_PIX_FMT_RGBA,
115
+        AV_PIX_FMT_ABGR,
116
+        AV_PIX_FMT_BGRA,
117
+        AV_PIX_FMT_NONE
118
+    };
119
+
120
+    AVFilterFormats *formats = NULL;
121
+
122
+    formats = ff_make_format_list(pixel_fmts);
123
+    if (!formats)
124
+        return AVERROR(ENOMEM);
125
+
126
+    return ff_set_common_formats(avctx, formats);
127
+}
128
+
129
+static const AVFilterPad colorkey_inputs[] = {
130
+    {
131
+        .name = "default",
132
+        .type = AVMEDIA_TYPE_VIDEO,
133
+        .filter_frame = filter_frame,
134
+    },
135
+    { NULL }
136
+};
137
+
138
+static const AVFilterPad colorkey_outputs[] = {
139
+    {
140
+        .name = "default",
141
+        .type = AVMEDIA_TYPE_VIDEO,
142
+        .config_props  = config_output,
143
+    },
144
+    { NULL }
145
+};
146
+
147
+#define OFFSET(x) offsetof(ColorkeyContext, x)
148
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
149
+
150
+static const AVOption colorkey_options[] = {
151
+    { "color", "set the colorkey key color", OFFSET(colorkey_rgba), AV_OPT_TYPE_COLOR, { .str = "black" }, CHAR_MIN, CHAR_MAX, FLAGS },
152
+    { "similarity", "set the colorkey similarity value", OFFSET(similarity), AV_OPT_TYPE_FLOAT, { .dbl = 0.01 }, 0.01, 1.0, FLAGS },
153
+    { "blend", "set the colorkey key blend value", OFFSET(blend), AV_OPT_TYPE_FLOAT, { .dbl = 0.0 }, 0.0, 1.0, FLAGS },
154
+    { NULL }
155
+};
156
+
157
+AVFILTER_DEFINE_CLASS(colorkey);
158
+
159
+AVFilter ff_vf_colorkey = {
160
+    .name          = "colorkey",
161
+    .description   = NULL_IF_CONFIG_SMALL("colorkey filter"),
162
+    .priv_size     = sizeof(ColorkeyContext),
163
+    .priv_class    = &colorkey_class,
164
+    .query_formats = query_formats,
165
+    .inputs        = colorkey_inputs,
166
+    .outputs       = colorkey_outputs,
167
+    .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
168
+};