Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4349 Serge 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
};