lavfi: cosmetics: fix vertical alignment for pads in some filters
[ffmpeg.git] / libavfilter / vf_colorchannelmixer.c
1 /*
2  * Copyright (c) 2013 Paul B Mahol
3  *
4  * This file is part of FFmpeg.
5  *
6  * FFmpeg is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * FFmpeg is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with FFmpeg; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20
21 #include "libavutil/opt.h"
22 #include "avfilter.h"
23 #include "drawutils.h"
24 #include "formats.h"
25 #include "internal.h"
26 #include "video.h"
27
28 #define R 0
29 #define G 1
30 #define B 2
31 #define A 3
32
33 typedef struct {
34     const AVClass *class;
35     double rr, rg, rb, ra;
36     double gr, gg, gb, ga;
37     double br, bg, bb, ba;
38     double ar, ag, ab, aa;
39
40     int *lut[4][4];
41
42     int *buffer;
43
44     uint8_t rgba_map[4];
45 } ColorChannelMixerContext;
46
47 #define OFFSET(x) offsetof(ColorChannelMixerContext, x)
48 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
49 static const AVOption colorchannelmixer_options[] = {
50     { "rr", "set the red gain for the red channel",     OFFSET(rr), AV_OPT_TYPE_DOUBLE, {.dbl=1}, -2, 2, FLAGS },
51     { "rg", "set the green gain for the red channel",   OFFSET(rg), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -2, 2, FLAGS },
52     { "rb", "set the blue gain for the red channel",    OFFSET(rb), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -2, 2, FLAGS },
53     { "ra", "set the alpha gain for the red channel",   OFFSET(ra), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -2, 2, FLAGS },
54     { "gr", "set the red gain for the green channel",   OFFSET(gr), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -2, 2, FLAGS },
55     { "gg", "set the green gain for the green channel", OFFSET(gg), AV_OPT_TYPE_DOUBLE, {.dbl=1}, -2, 2, FLAGS },
56     { "gb", "set the blue gain for the green channel",  OFFSET(gb), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -2, 2, FLAGS },
57     { "ga", "set the alpha gain for the green channel", OFFSET(ga), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -2, 2, FLAGS },
58     { "br", "set the red gain for the blue channel",    OFFSET(br), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -2, 2, FLAGS },
59     { "bg", "set the green gain for the blue channel",  OFFSET(bg), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -2, 2, FLAGS },
60     { "bb", "set the blue gain for the blue channel",   OFFSET(bb), AV_OPT_TYPE_DOUBLE, {.dbl=1}, -2, 2, FLAGS },
61     { "ba", "set the alpha gain for the blue channel",  OFFSET(ba), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -2, 2, FLAGS },
62     { "ar", "set the red gain for the alpha channel",   OFFSET(ar), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -2, 2, FLAGS },
63     { "ag", "set the green gain for the alpha channel", OFFSET(ag), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -2, 2, FLAGS },
64     { "ab", "set the blue gain for the alpha channel",  OFFSET(ab), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -2, 2, FLAGS },
65     { "aa", "set the alpha gain for the alpha channel", OFFSET(aa), AV_OPT_TYPE_DOUBLE, {.dbl=1}, -2, 2, FLAGS },
66     { NULL }
67 };
68
69 AVFILTER_DEFINE_CLASS(colorchannelmixer);
70
71 static int query_formats(AVFilterContext *ctx)
72 {
73     static const enum AVPixelFormat pix_fmts[] = {
74         AV_PIX_FMT_RGB24,  AV_PIX_FMT_BGR24,
75         AV_PIX_FMT_RGBA,   AV_PIX_FMT_BGRA,
76         AV_PIX_FMT_ARGB,   AV_PIX_FMT_ABGR,
77         AV_PIX_FMT_0RGB,   AV_PIX_FMT_0BGR,
78         AV_PIX_FMT_RGB0,   AV_PIX_FMT_BGR0,
79         AV_PIX_FMT_RGB48,  AV_PIX_FMT_BGR48,
80         AV_PIX_FMT_RGBA64, AV_PIX_FMT_BGRA64,
81         AV_PIX_FMT_NONE
82     };
83
84     ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
85     return 0;
86 }
87
88 static int config_output(AVFilterLink *outlink)
89 {
90     AVFilterContext *ctx = outlink->src;
91     ColorChannelMixerContext *cm = ctx->priv;
92     int i, j, size, *buffer;
93
94     ff_fill_rgba_map(cm->rgba_map, outlink->format);
95
96     switch (outlink->format) {
97     case AV_PIX_FMT_RGB48:
98     case AV_PIX_FMT_BGR48:
99     case AV_PIX_FMT_RGBA64:
100     case AV_PIX_FMT_BGRA64:
101         size = 65536;
102         break;
103     default:
104         size = 256;
105     }
106
107     cm->buffer = buffer = av_malloc(16 * size * sizeof(*cm->buffer));
108     if (!cm->buffer)
109         return AVERROR(ENOMEM);
110
111     for (i = 0; i < 4; i++)
112         for (j = 0; j < 4; j++, buffer += size)
113             cm->lut[i][j] = buffer;
114
115     for (i = 0; i < size; i++) {
116         cm->lut[R][R][i] = round(i * cm->rr);
117         cm->lut[R][G][i] = round(i * cm->rg);
118         cm->lut[R][B][i] = round(i * cm->rb);
119         cm->lut[R][A][i] = round(i * cm->ra);
120
121         cm->lut[G][R][i] = round(i * cm->gr);
122         cm->lut[G][G][i] = round(i * cm->gg);
123         cm->lut[G][B][i] = round(i * cm->gb);
124         cm->lut[G][A][i] = round(i * cm->ga);
125
126         cm->lut[B][R][i] = round(i * cm->br);
127         cm->lut[B][G][i] = round(i * cm->bg);
128         cm->lut[B][B][i] = round(i * cm->bb);
129         cm->lut[B][A][i] = round(i * cm->ba);
130
131         cm->lut[A][R][i] = round(i * cm->ar);
132         cm->lut[A][G][i] = round(i * cm->ag);
133         cm->lut[A][B][i] = round(i * cm->ab);
134         cm->lut[A][A][i] = round(i * cm->aa);
135     }
136
137     return 0;
138 }
139
140 static int filter_frame(AVFilterLink *inlink, AVFrame *in)
141 {
142     AVFilterContext *ctx = inlink->dst;
143     ColorChannelMixerContext *cm = ctx->priv;
144     AVFilterLink *outlink = ctx->outputs[0];
145     const uint8_t roffset = cm->rgba_map[R];
146     const uint8_t goffset = cm->rgba_map[G];
147     const uint8_t boffset = cm->rgba_map[B];
148     const uint8_t aoffset = cm->rgba_map[A];
149     const uint8_t *srcrow = in->data[0];
150     uint8_t *dstrow;
151     AVFrame *out;
152     int i, j;
153
154     if (av_frame_is_writable(in)) {
155         out = in;
156     } else {
157         out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
158         if (!out) {
159             av_frame_free(&in);
160             return AVERROR(ENOMEM);
161         }
162         av_frame_copy_props(out, in);
163     }
164
165     dstrow = out->data[0];
166     switch (outlink->format) {
167     case AV_PIX_FMT_BGR24:
168     case AV_PIX_FMT_RGB24:
169         for (i = 0; i < outlink->h; i++) {
170             const uint8_t *src = srcrow;
171             uint8_t *dst = dstrow;
172
173             for (j = 0; j < outlink->w * 3; j += 3) {
174                 const uint8_t rin = src[j + roffset];
175                 const uint8_t gin = src[j + goffset];
176                 const uint8_t bin = src[j + boffset];
177
178                 dst[j + roffset] = av_clip_uint8(cm->lut[R][R][rin] +
179                                                  cm->lut[R][G][gin] +
180                                                  cm->lut[R][B][bin]);
181                 dst[j + goffset] = av_clip_uint8(cm->lut[G][R][rin] +
182                                                  cm->lut[G][G][gin] +
183                                                  cm->lut[G][B][bin]);
184                 dst[j + boffset] = av_clip_uint8(cm->lut[B][R][rin] +
185                                                  cm->lut[B][G][gin] +
186                                                  cm->lut[B][B][bin]);
187             }
188
189             srcrow += in->linesize[0];
190             dstrow += out->linesize[0];
191         }
192         break;
193     case AV_PIX_FMT_0BGR:
194     case AV_PIX_FMT_0RGB:
195     case AV_PIX_FMT_BGR0:
196     case AV_PIX_FMT_RGB0:
197         for (i = 0; i < outlink->h; i++) {
198             const uint8_t *src = srcrow;
199             uint8_t *dst = dstrow;
200
201             for (j = 0; j < outlink->w * 4; j += 4) {
202                 const uint8_t rin = src[j + roffset];
203                 const uint8_t gin = src[j + goffset];
204                 const uint8_t bin = src[j + boffset];
205
206                 dst[j + roffset] = av_clip_uint8(cm->lut[R][R][rin] +
207                                                  cm->lut[R][G][gin] +
208                                                  cm->lut[R][B][bin]);
209                 dst[j + goffset] = av_clip_uint8(cm->lut[G][R][rin] +
210                                                  cm->lut[G][G][gin] +
211                                                  cm->lut[G][B][bin]);
212                 dst[j + boffset] = av_clip_uint8(cm->lut[B][R][rin] +
213                                                  cm->lut[B][G][gin] +
214                                                  cm->lut[B][B][bin]);
215                 if (in != out)
216                     dst[j + aoffset] = 0;
217             }
218
219             srcrow += in->linesize[0];
220             dstrow += out->linesize[0];
221         }
222         break;
223     case AV_PIX_FMT_ABGR:
224     case AV_PIX_FMT_ARGB:
225     case AV_PIX_FMT_BGRA:
226     case AV_PIX_FMT_RGBA:
227         for (i = 0; i < outlink->h; i++) {
228             const uint8_t *src = srcrow;
229             uint8_t *dst = dstrow;
230
231             for (j = 0; j < outlink->w * 4; j += 4) {
232                 const uint8_t rin = src[j + roffset];
233                 const uint8_t gin = src[j + goffset];
234                 const uint8_t bin = src[j + boffset];
235                 const uint8_t ain = src[j + aoffset];
236
237                 dst[j + roffset] = av_clip_uint8(cm->lut[R][R][rin] +
238                                                  cm->lut[R][G][gin] +
239                                                  cm->lut[R][B][bin] +
240                                                  cm->lut[R][A][ain]);
241                 dst[j + goffset] = av_clip_uint8(cm->lut[G][R][rin] +
242                                                  cm->lut[G][G][gin] +
243                                                  cm->lut[G][B][bin] +
244                                                  cm->lut[G][A][ain]);
245                 dst[j + boffset] = av_clip_uint8(cm->lut[B][R][rin] +
246                                                  cm->lut[B][G][gin] +
247                                                  cm->lut[B][B][bin] +
248                                                  cm->lut[B][A][ain]);
249                 dst[j + aoffset] = av_clip_uint8(cm->lut[A][R][rin] +
250                                                  cm->lut[A][G][gin] +
251                                                  cm->lut[A][B][bin] +
252                                                  cm->lut[A][A][ain]);
253             }
254
255             srcrow += in->linesize[0];
256             dstrow += out->linesize[0];
257         }
258         break;
259     case AV_PIX_FMT_BGR48:
260     case AV_PIX_FMT_RGB48:
261         for (i = 0; i < outlink->h; i++) {
262             const uint16_t *src = (const uint16_t *)srcrow;
263             uint16_t *dst = (uint16_t *)dstrow;
264
265             for (j = 0; j < outlink->w * 3; j += 3) {
266                 const uint16_t rin = src[j + roffset];
267                 const uint16_t gin = src[j + goffset];
268                 const uint16_t bin = src[j + boffset];
269
270                 dst[j + roffset] = av_clip_uint16(cm->lut[R][R][rin] +
271                                                   cm->lut[R][G][gin] +
272                                                   cm->lut[R][B][bin]);
273                 dst[j + goffset] = av_clip_uint16(cm->lut[G][R][rin] +
274                                                   cm->lut[G][G][gin] +
275                                                   cm->lut[G][B][bin]);
276                 dst[j + boffset] = av_clip_uint16(cm->lut[B][R][rin] +
277                                                   cm->lut[B][G][gin] +
278                                                   cm->lut[B][B][bin]);
279             }
280
281             srcrow += in->linesize[0];
282             dstrow += out->linesize[0];
283         }
284         break;
285     case AV_PIX_FMT_BGRA64:
286     case AV_PIX_FMT_RGBA64:
287         for (i = 0; i < outlink->h; i++) {
288             const uint16_t *src = (const uint16_t *)srcrow;
289             uint16_t *dst = (uint16_t *)dstrow;
290
291             for (j = 0; j < outlink->w * 4; j += 4) {
292                 const uint16_t rin = src[j + roffset];
293                 const uint16_t gin = src[j + goffset];
294                 const uint16_t bin = src[j + boffset];
295                 const uint16_t ain = src[j + aoffset];
296
297                 dst[j + roffset] = av_clip_uint16(cm->lut[R][R][rin] +
298                                                   cm->lut[R][G][gin] +
299                                                   cm->lut[R][B][bin] +
300                                                   cm->lut[R][A][ain]);
301                 dst[j + goffset] = av_clip_uint16(cm->lut[G][R][rin] +
302                                                   cm->lut[G][G][gin] +
303                                                   cm->lut[G][B][bin] +
304                                                   cm->lut[G][A][ain]);
305                 dst[j + boffset] = av_clip_uint16(cm->lut[B][R][rin] +
306                                                   cm->lut[B][G][gin] +
307                                                   cm->lut[B][B][bin] +
308                                                   cm->lut[B][A][ain]);
309                 dst[j + aoffset] = av_clip_uint16(cm->lut[A][R][rin] +
310                                                   cm->lut[A][G][gin] +
311                                                   cm->lut[A][B][bin] +
312                                                   cm->lut[A][A][ain]);
313             }
314
315             srcrow += in->linesize[0];
316             dstrow += out->linesize[0];
317         }
318     }
319
320     if (in != out)
321         av_frame_free(&in);
322     return ff_filter_frame(ctx->outputs[0], out);
323 }
324
325 static av_cold void uninit(AVFilterContext *ctx)
326 {
327     ColorChannelMixerContext *cm = ctx->priv;
328
329     av_freep(&cm->buffer);
330 }
331
332 static const AVFilterPad colorchannelmixer_inputs[] = {
333     {
334         .name         = "default",
335         .type         = AVMEDIA_TYPE_VIDEO,
336         .filter_frame = filter_frame,
337     },
338     { NULL }
339 };
340
341 static const AVFilterPad colorchannelmixer_outputs[] = {
342     {
343         .name         = "default",
344         .type         = AVMEDIA_TYPE_VIDEO,
345         .config_props = config_output,
346     },
347     { NULL }
348 };
349
350 AVFilter avfilter_vf_colorchannelmixer = {
351     .name          = "colorchannelmixer",
352     .description   = NULL_IF_CONFIG_SMALL("Adjust colors by mixing color channels."),
353     .priv_size     = sizeof(ColorChannelMixerContext),
354     .priv_class    = &colorchannelmixer_class,
355     .uninit        = uninit,
356     .query_formats = query_formats,
357     .inputs        = colorchannelmixer_inputs,
358     .outputs       = colorchannelmixer_outputs,
359     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
360 };