FFmpeg
vf_colorchannelmixer.c
Go to the documentation of this file.
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 "libavutil/pixdesc.h"
23 #include "avfilter.h"
24 #include "drawutils.h"
25 #include "formats.h"
26 #include "internal.h"
27 #include "video.h"
28 
29 #define R 0
30 #define G 1
31 #define B 2
32 #define A 3
33 
34 typedef struct ThreadData {
35  AVFrame *in, *out;
36 } ThreadData;
37 
38 typedef struct ColorChannelMixerContext {
39  const AVClass *class;
40  double rr, rg, rb, ra;
41  double gr, gg, gb, ga;
42  double br, bg, bb, ba;
43  double ar, ag, ab, aa;
44 
45  int *lut[4][4];
46 
47  int *buffer;
48 
50 
51  int (*filter_slice)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs);
53 
54 #define OFFSET(x) offsetof(ColorChannelMixerContext, x)
55 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_RUNTIME_PARAM
56 
58  { "rr", "set the red gain for the red channel", OFFSET(rr), AV_OPT_TYPE_DOUBLE, {.dbl=1}, -2, 2, FLAGS },
59  { "rg", "set the green gain for the red channel", OFFSET(rg), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -2, 2, FLAGS },
60  { "rb", "set the blue gain for the red channel", OFFSET(rb), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -2, 2, FLAGS },
61  { "ra", "set the alpha gain for the red channel", OFFSET(ra), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -2, 2, FLAGS },
62  { "gr", "set the red gain for the green channel", OFFSET(gr), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -2, 2, FLAGS },
63  { "gg", "set the green gain for the green channel", OFFSET(gg), AV_OPT_TYPE_DOUBLE, {.dbl=1}, -2, 2, FLAGS },
64  { "gb", "set the blue gain for the green channel", OFFSET(gb), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -2, 2, FLAGS },
65  { "ga", "set the alpha gain for the green channel", OFFSET(ga), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -2, 2, FLAGS },
66  { "br", "set the red gain for the blue channel", OFFSET(br), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -2, 2, FLAGS },
67  { "bg", "set the green gain for the blue channel", OFFSET(bg), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -2, 2, FLAGS },
68  { "bb", "set the blue gain for the blue channel", OFFSET(bb), AV_OPT_TYPE_DOUBLE, {.dbl=1}, -2, 2, FLAGS },
69  { "ba", "set the alpha gain for the blue channel", OFFSET(ba), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -2, 2, FLAGS },
70  { "ar", "set the red gain for the alpha channel", OFFSET(ar), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -2, 2, FLAGS },
71  { "ag", "set the green gain for the alpha channel", OFFSET(ag), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -2, 2, FLAGS },
72  { "ab", "set the blue gain for the alpha channel", OFFSET(ab), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -2, 2, FLAGS },
73  { "aa", "set the alpha gain for the alpha channel", OFFSET(aa), AV_OPT_TYPE_DOUBLE, {.dbl=1}, -2, 2, FLAGS },
74  { NULL }
75 };
76 
77 AVFILTER_DEFINE_CLASS(colorchannelmixer);
78 
80 {
81  static const enum AVPixelFormat pix_fmts[] = {
96  };
97 
99  if (!fmts_list)
100  return AVERROR(ENOMEM);
101  return ff_set_common_formats(ctx, fmts_list);
102 }
103 
104 static av_always_inline int filter_slice_rgba_planar(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs,
105  int have_alpha)
106 {
107  ColorChannelMixerContext *s = ctx->priv;
108  ThreadData *td = arg;
109  AVFrame *in = td->in;
110  AVFrame *out = td->out;
111  const int slice_start = (out->height * jobnr) / nb_jobs;
112  const int slice_end = (out->height * (jobnr+1)) / nb_jobs;
113  const uint8_t *srcg = in->data[0] + slice_start * in->linesize[0];
114  const uint8_t *srcb = in->data[1] + slice_start * in->linesize[1];
115  const uint8_t *srcr = in->data[2] + slice_start * in->linesize[2];
116  const uint8_t *srca = in->data[3] + slice_start * in->linesize[3];
117  uint8_t *dstg = out->data[0] + slice_start * out->linesize[0];
118  uint8_t *dstb = out->data[1] + slice_start * out->linesize[1];
119  uint8_t *dstr = out->data[2] + slice_start * out->linesize[2];
120  uint8_t *dsta = out->data[3] + slice_start * out->linesize[3];
121  int i, j;
122 
123  for (i = slice_start; i < slice_end; i++) {
124  for (j = 0; j < out->width; j++) {
125  const uint8_t rin = srcr[j];
126  const uint8_t gin = srcg[j];
127  const uint8_t bin = srcb[j];
128  const uint8_t ain = have_alpha ? srca[j] : 0;
129 
130  dstr[j] = av_clip_uint8(s->lut[R][R][rin] +
131  s->lut[R][G][gin] +
132  s->lut[R][B][bin] +
133  (have_alpha == 1 ? s->lut[R][A][ain] : 0));
134  dstg[j] = av_clip_uint8(s->lut[G][R][rin] +
135  s->lut[G][G][gin] +
136  s->lut[G][B][bin] +
137  (have_alpha == 1 ? s->lut[G][A][ain] : 0));
138  dstb[j] = av_clip_uint8(s->lut[B][R][rin] +
139  s->lut[B][G][gin] +
140  s->lut[B][B][bin] +
141  (have_alpha == 1 ? s->lut[B][A][ain] : 0));
142  if (have_alpha == 1) {
143  dsta[j] = av_clip_uint8(s->lut[A][R][rin] +
144  s->lut[A][G][gin] +
145  s->lut[A][B][bin] +
146  s->lut[A][A][ain]);
147  }
148  }
149 
150  srcg += in->linesize[0];
151  srcb += in->linesize[1];
152  srcr += in->linesize[2];
153  srca += in->linesize[3];
154  dstg += out->linesize[0];
155  dstb += out->linesize[1];
156  dstr += out->linesize[2];
157  dsta += out->linesize[3];
158  }
159 
160  return 0;
161 }
162 
163 static av_always_inline int filter_slice_rgba16_planar(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs,
164  int have_alpha, int depth)
165 {
166  ColorChannelMixerContext *s = ctx->priv;
167  ThreadData *td = arg;
168  AVFrame *in = td->in;
169  AVFrame *out = td->out;
170  const int slice_start = (out->height * jobnr) / nb_jobs;
171  const int slice_end = (out->height * (jobnr+1)) / nb_jobs;
172  const uint16_t *srcg = (const uint16_t *)(in->data[0] + slice_start * in->linesize[0]);
173  const uint16_t *srcb = (const uint16_t *)(in->data[1] + slice_start * in->linesize[1]);
174  const uint16_t *srcr = (const uint16_t *)(in->data[2] + slice_start * in->linesize[2]);
175  const uint16_t *srca = (const uint16_t *)(in->data[3] + slice_start * in->linesize[3]);
176  uint16_t *dstg = (uint16_t *)(out->data[0] + slice_start * out->linesize[0]);
177  uint16_t *dstb = (uint16_t *)(out->data[1] + slice_start * out->linesize[1]);
178  uint16_t *dstr = (uint16_t *)(out->data[2] + slice_start * out->linesize[2]);
179  uint16_t *dsta = (uint16_t *)(out->data[3] + slice_start * out->linesize[3]);
180  int i, j;
181 
182  for (i = slice_start; i < slice_end; i++) {
183  for (j = 0; j < out->width; j++) {
184  const uint16_t rin = srcr[j];
185  const uint16_t gin = srcg[j];
186  const uint16_t bin = srcb[j];
187  const uint16_t ain = have_alpha ? srca[j] : 0;
188 
189  dstr[j] = av_clip_uintp2(s->lut[R][R][rin] +
190  s->lut[R][G][gin] +
191  s->lut[R][B][bin] +
192  (have_alpha == 1 ? s->lut[R][A][ain] : 0), depth);
193  dstg[j] = av_clip_uintp2(s->lut[G][R][rin] +
194  s->lut[G][G][gin] +
195  s->lut[G][B][bin] +
196  (have_alpha == 1 ? s->lut[G][A][ain] : 0), depth);
197  dstb[j] = av_clip_uintp2(s->lut[B][R][rin] +
198  s->lut[B][G][gin] +
199  s->lut[B][B][bin] +
200  (have_alpha == 1 ? s->lut[B][A][ain] : 0), depth);
201  if (have_alpha == 1) {
202  dsta[j] = av_clip_uintp2(s->lut[A][R][rin] +
203  s->lut[A][G][gin] +
204  s->lut[A][B][bin] +
205  s->lut[A][A][ain], depth);
206  }
207  }
208 
209  srcg += in->linesize[0] / 2;
210  srcb += in->linesize[1] / 2;
211  srcr += in->linesize[2] / 2;
212  srca += in->linesize[3] / 2;
213  dstg += out->linesize[0] / 2;
214  dstb += out->linesize[1] / 2;
215  dstr += out->linesize[2] / 2;
216  dsta += out->linesize[3] / 2;
217  }
218 
219  return 0;
220 }
221 
222 static int filter_slice_gbrp(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
223 {
224  return filter_slice_rgba_planar(ctx, arg, jobnr, nb_jobs, 0);
225 }
226 
227 static int filter_slice_gbrap(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
228 {
229  return filter_slice_rgba_planar(ctx, arg, jobnr, nb_jobs, 1);
230 }
231 
232 static int filter_slice_gbrp9(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
233 {
234  return filter_slice_rgba16_planar(ctx, arg, jobnr, nb_jobs, 0, 9);
235 }
236 
237 static int filter_slice_gbrp10(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
238 {
239  return filter_slice_rgba16_planar(ctx, arg, jobnr, nb_jobs, 0, 10);
240 }
241 
242 static int filter_slice_gbrap10(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
243 {
244  return filter_slice_rgba16_planar(ctx, arg, jobnr, nb_jobs, 1, 10);
245 }
246 
247 static int filter_slice_gbrp12(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
248 {
249  return filter_slice_rgba16_planar(ctx, arg, jobnr, nb_jobs, 0, 12);
250 }
251 
252 static int filter_slice_gbrap12(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
253 {
254  return filter_slice_rgba16_planar(ctx, arg, jobnr, nb_jobs, 1, 12);
255 }
256 
257 static int filter_slice_gbrp14(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
258 {
259  return filter_slice_rgba16_planar(ctx, arg, jobnr, nb_jobs, 0, 14);
260 }
261 
262 static int filter_slice_gbrp16(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
263 {
264  return filter_slice_rgba16_planar(ctx, arg, jobnr, nb_jobs, 0, 16);
265 }
266 
267 static int filter_slice_gbrap16(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
268 {
269  return filter_slice_rgba16_planar(ctx, arg, jobnr, nb_jobs, 1, 16);
270 }
271 
272 static av_always_inline int filter_slice_rgba_packed(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs,
273  int have_alpha, int step)
274 {
275  ColorChannelMixerContext *s = ctx->priv;
276  ThreadData *td = arg;
277  AVFrame *in = td->in;
278  AVFrame *out = td->out;
279  const int slice_start = (out->height * jobnr) / nb_jobs;
280  const int slice_end = (out->height * (jobnr+1)) / nb_jobs;
281  const uint8_t roffset = s->rgba_map[R];
282  const uint8_t goffset = s->rgba_map[G];
283  const uint8_t boffset = s->rgba_map[B];
284  const uint8_t aoffset = s->rgba_map[A];
285  const uint8_t *srcrow = in->data[0] + slice_start * in->linesize[0];
286  uint8_t *dstrow = out->data[0] + slice_start * out->linesize[0];
287  int i, j;
288 
289  for (i = slice_start; i < slice_end; i++) {
290  const uint8_t *src = srcrow;
291  uint8_t *dst = dstrow;
292 
293  for (j = 0; j < out->width * step; j += step) {
294  const uint8_t rin = src[j + roffset];
295  const uint8_t gin = src[j + goffset];
296  const uint8_t bin = src[j + boffset];
297  const uint8_t ain = src[j + aoffset];
298 
299  dst[j + roffset] = av_clip_uint8(s->lut[R][R][rin] +
300  s->lut[R][G][gin] +
301  s->lut[R][B][bin] +
302  (have_alpha == 1 ? s->lut[R][A][ain] : 0));
303  dst[j + goffset] = av_clip_uint8(s->lut[G][R][rin] +
304  s->lut[G][G][gin] +
305  s->lut[G][B][bin] +
306  (have_alpha == 1 ? s->lut[G][A][ain] : 0));
307  dst[j + boffset] = av_clip_uint8(s->lut[B][R][rin] +
308  s->lut[B][G][gin] +
309  s->lut[B][B][bin] +
310  (have_alpha == 1 ? s->lut[B][A][ain] : 0));
311  if (have_alpha == 1) {
312  dst[j + aoffset] = av_clip_uint8(s->lut[A][R][rin] +
313  s->lut[A][G][gin] +
314  s->lut[A][B][bin] +
315  s->lut[A][A][ain]);
316  } else if (have_alpha == -1 && in != out)
317  dst[j + aoffset] = 0;
318  }
319 
320  srcrow += in->linesize[0];
321  dstrow += out->linesize[0];
322  }
323 
324  return 0;
325 }
326 
327 static av_always_inline int filter_slice_rgba16_packed(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs,
328  int have_alpha, int step)
329 {
330  ColorChannelMixerContext *s = ctx->priv;
331  ThreadData *td = arg;
332  AVFrame *in = td->in;
333  AVFrame *out = td->out;
334  const int slice_start = (out->height * jobnr) / nb_jobs;
335  const int slice_end = (out->height * (jobnr+1)) / nb_jobs;
336  const uint8_t roffset = s->rgba_map[R];
337  const uint8_t goffset = s->rgba_map[G];
338  const uint8_t boffset = s->rgba_map[B];
339  const uint8_t aoffset = s->rgba_map[A];
340  const uint8_t *srcrow = in->data[0] + slice_start * in->linesize[0];
341  uint8_t *dstrow = out->data[0] + slice_start * out->linesize[0];
342  int i, j;
343 
344  for (i = slice_start; i < slice_end; i++) {
345  const uint16_t *src = (const uint16_t *)srcrow;
346  uint16_t *dst = (uint16_t *)dstrow;
347 
348  for (j = 0; j < out->width * step; j += step) {
349  const uint16_t rin = src[j + roffset];
350  const uint16_t gin = src[j + goffset];
351  const uint16_t bin = src[j + boffset];
352  const uint16_t ain = src[j + aoffset];
353 
354  dst[j + roffset] = av_clip_uint16(s->lut[R][R][rin] +
355  s->lut[R][G][gin] +
356  s->lut[R][B][bin] +
357  (have_alpha == 1 ? s->lut[R][A][ain] : 0));
358  dst[j + goffset] = av_clip_uint16(s->lut[G][R][rin] +
359  s->lut[G][G][gin] +
360  s->lut[G][B][bin] +
361  (have_alpha == 1 ? s->lut[G][A][ain] : 0));
362  dst[j + boffset] = av_clip_uint16(s->lut[B][R][rin] +
363  s->lut[B][G][gin] +
364  s->lut[B][B][bin] +
365  (have_alpha == 1 ? s->lut[B][A][ain] : 0));
366  if (have_alpha == 1) {
367  dst[j + aoffset] = av_clip_uint16(s->lut[A][R][rin] +
368  s->lut[A][G][gin] +
369  s->lut[A][B][bin] +
370  s->lut[A][A][ain]);
371  }
372  }
373 
374  srcrow += in->linesize[0];
375  dstrow += out->linesize[0];
376  }
377 
378  return 0;
379 }
380 
381 static int filter_slice_rgba64(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
382 {
383  return filter_slice_rgba16_packed(ctx, arg, jobnr, nb_jobs, 1, 4);
384 }
385 
386 static int filter_slice_rgb48(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
387 {
388  return filter_slice_rgba16_packed(ctx, arg, jobnr, nb_jobs, 0, 3);
389 }
390 
391 static int filter_slice_rgba(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
392 {
393  return filter_slice_rgba_packed(ctx, arg, jobnr, nb_jobs, 1, 4);
394 }
395 
396 static int filter_slice_rgb24(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
397 {
398  return filter_slice_rgba_packed(ctx, arg, jobnr, nb_jobs, 0, 3);
399 }
400 
401 static int filter_slice_rgb0(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
402 {
403  return filter_slice_rgba_packed(ctx, arg, jobnr, nb_jobs, -1, 4);
404 }
405 
406 static int config_output(AVFilterLink *outlink)
407 {
408  AVFilterContext *ctx = outlink->src;
409  ColorChannelMixerContext *s = ctx->priv;
411  const int depth = desc->comp[0].depth;
412  int i, j, size, *buffer = s->buffer;
413 
414  ff_fill_rgba_map(s->rgba_map, outlink->format);
415 
416  size = 1 << depth;
417  if (!s->buffer) {
418  s->buffer = buffer = av_malloc(16 * size * sizeof(*s->buffer));
419  if (!s->buffer)
420  return AVERROR(ENOMEM);
421 
422  for (i = 0; i < 4; i++)
423  for (j = 0; j < 4; j++, buffer += size)
424  s->lut[i][j] = buffer;
425  }
426 
427  for (i = 0; i < size; i++) {
428  s->lut[R][R][i] = lrint(i * s->rr);
429  s->lut[R][G][i] = lrint(i * s->rg);
430  s->lut[R][B][i] = lrint(i * s->rb);
431  s->lut[R][A][i] = lrint(i * s->ra);
432 
433  s->lut[G][R][i] = lrint(i * s->gr);
434  s->lut[G][G][i] = lrint(i * s->gg);
435  s->lut[G][B][i] = lrint(i * s->gb);
436  s->lut[G][A][i] = lrint(i * s->ga);
437 
438  s->lut[B][R][i] = lrint(i * s->br);
439  s->lut[B][G][i] = lrint(i * s->bg);
440  s->lut[B][B][i] = lrint(i * s->bb);
441  s->lut[B][A][i] = lrint(i * s->ba);
442 
443  s->lut[A][R][i] = lrint(i * s->ar);
444  s->lut[A][G][i] = lrint(i * s->ag);
445  s->lut[A][B][i] = lrint(i * s->ab);
446  s->lut[A][A][i] = lrint(i * s->aa);
447  }
448 
449  switch (outlink->format) {
450  case AV_PIX_FMT_BGR24:
451  case AV_PIX_FMT_RGB24:
452  s->filter_slice = filter_slice_rgb24;
453  break;
454  case AV_PIX_FMT_0BGR:
455  case AV_PIX_FMT_0RGB:
456  case AV_PIX_FMT_BGR0:
457  case AV_PIX_FMT_RGB0:
458  s->filter_slice = filter_slice_rgb0;
459  break;
460  case AV_PIX_FMT_ABGR:
461  case AV_PIX_FMT_ARGB:
462  case AV_PIX_FMT_BGRA:
463  case AV_PIX_FMT_RGBA:
464  s->filter_slice = filter_slice_rgba;
465  break;
466  case AV_PIX_FMT_BGR48:
467  case AV_PIX_FMT_RGB48:
468  s->filter_slice = filter_slice_rgb48;
469  break;
470  case AV_PIX_FMT_BGRA64:
471  case AV_PIX_FMT_RGBA64:
472  s->filter_slice = filter_slice_rgba64;
473  break;
474  case AV_PIX_FMT_GBRP:
475  s->filter_slice = filter_slice_gbrp;
476  break;
477  case AV_PIX_FMT_GBRAP:
478  s->filter_slice = filter_slice_gbrap;
479  break;
480  case AV_PIX_FMT_GBRP9:
481  s->filter_slice = filter_slice_gbrp9;
482  break;
483  case AV_PIX_FMT_GBRP10:
484  s->filter_slice = filter_slice_gbrp10;
485  break;
486  case AV_PIX_FMT_GBRAP10:
487  s->filter_slice = filter_slice_gbrap10;
488  break;
489  case AV_PIX_FMT_GBRP12:
490  s->filter_slice = filter_slice_gbrp12;
491  break;
492  case AV_PIX_FMT_GBRAP12:
493  s->filter_slice = filter_slice_gbrap12;
494  break;
495  case AV_PIX_FMT_GBRP14:
496  s->filter_slice = filter_slice_gbrp14;
497  break;
498  case AV_PIX_FMT_GBRP16:
499  s->filter_slice = filter_slice_gbrp16;
500  break;
501  case AV_PIX_FMT_GBRAP16:
502  s->filter_slice = filter_slice_gbrap16;
503  break;
504  }
505 
506  return 0;
507 }
508 
510 {
511  AVFilterContext *ctx = inlink->dst;
512  ColorChannelMixerContext *s = ctx->priv;
513  AVFilterLink *outlink = ctx->outputs[0];
514  ThreadData td;
515  AVFrame *out;
516 
517  if (av_frame_is_writable(in)) {
518  out = in;
519  } else {
520  out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
521  if (!out) {
522  av_frame_free(&in);
523  return AVERROR(ENOMEM);
524  }
526  }
527 
528  td.in = in;
529  td.out = out;
530  ctx->internal->execute(ctx, s->filter_slice, &td, NULL, FFMIN(outlink->h, ff_filter_get_nb_threads(ctx)));
531 
532  if (in != out)
533  av_frame_free(&in);
534  return ff_filter_frame(outlink, out);
535 }
536 
537 static int process_command(AVFilterContext *ctx, const char *cmd, const char *args,
538  char *res, int res_len, int flags)
539 {
540  int ret = ff_filter_process_command(ctx, cmd, args, res, res_len, flags);
541 
542  if (ret < 0)
543  return ret;
544 
545  return config_output(ctx->outputs[0]);
546 }
547 
549 {
550  ColorChannelMixerContext *s = ctx->priv;
551 
552  av_freep(&s->buffer);
553 }
554 
556  {
557  .name = "default",
558  .type = AVMEDIA_TYPE_VIDEO,
559  .filter_frame = filter_frame,
560  },
561  { NULL }
562 };
563 
565  {
566  .name = "default",
567  .type = AVMEDIA_TYPE_VIDEO,
568  .config_props = config_output,
569  },
570  { NULL }
571 };
572 
574  .name = "colorchannelmixer",
575  .description = NULL_IF_CONFIG_SMALL("Adjust colors by mixing color channels."),
576  .priv_size = sizeof(ColorChannelMixerContext),
577  .priv_class = &colorchannelmixer_class,
578  .uninit = uninit,
584 };
ColorChannelMixerContext::gg
double gg
Definition: vf_colorchannelmixer.c:41
filter_slice_rgba64
static int filter_slice_rgba64(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: vf_colorchannelmixer.c:381
ff_get_video_buffer
AVFrame * ff_get_video_buffer(AVFilterLink *link, int w, int h)
Request a picture buffer with a specific set of permissions.
Definition: video.c:99
AV_PIX_FMT_GBRAP16
#define AV_PIX_FMT_GBRAP16
Definition: pixfmt.h:419
td
#define td
Definition: regdef.h:70
AVPixelFormat
AVPixelFormat
Pixel format.
Definition: pixfmt.h:64
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
ColorChannelMixerContext::rg
double rg
Definition: vf_colorchannelmixer.c:40
opt.h
ff_make_format_list
AVFilterFormats * ff_make_format_list(const int *fmts)
Create a list of supported formats.
Definition: formats.c:300
ColorChannelMixerContext::bb
double bb
Definition: vf_colorchannelmixer.c:42
out
FILE * out
Definition: movenc.c:54
ff_vf_colorchannelmixer
AVFilter ff_vf_colorchannelmixer
Definition: vf_colorchannelmixer.c:573
ff_filter_frame
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:1075
av_pix_fmt_desc_get
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:2549
inlink
The exact code depends on how similar the blocks are and how related they are to the and needs to apply these operations to the correct inlink or outlink if there are several Macros are available to factor that when no extra processing is inlink
Definition: filter_design.txt:212
colorchannelmixer_options
static const AVOption colorchannelmixer_options[]
Definition: vf_colorchannelmixer.c:57
av_frame_free
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:203
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:300
pixdesc.h
step
trying all byte sequences megabyte in length and selecting the best looking sequence will yield cases to try But a word about which is also called distortion Distortion can be quantified by almost any quality measurement one chooses the sum of squared differences is used but more complex methods that consider psychovisual effects can be used as well It makes no difference in this discussion First step
Definition: rate_distortion.txt:58
AVOption
AVOption.
Definition: opt.h:246
query_formats
static int query_formats(AVFilterContext *ctx)
Definition: vf_colorchannelmixer.c:79
filter_slice_gbrp14
static int filter_slice_gbrp14(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: vf_colorchannelmixer.c:257
R
#define R
Definition: vf_colorchannelmixer.c:29
A
#define A
Definition: vf_colorchannelmixer.c:32
AV_PIX_FMT_BGR24
@ AV_PIX_FMT_BGR24
packed RGB 8:8:8, 24bpp, BGRBGR...
Definition: pixfmt.h:69
AV_PIX_FMT_BGRA
@ AV_PIX_FMT_BGRA
packed BGRA 8:8:8:8, 32bpp, BGRABGRA...
Definition: pixfmt.h:95
AVFilter::name
const char * name
Filter name.
Definition: avfilter.h:148
filter_slice_rgb0
static int filter_slice_rgb0(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: vf_colorchannelmixer.c:401
G
#define G
Definition: vf_colorchannelmixer.c:30
ThreadData::out
AVFrame * out
Definition: af_adeclick.c:494
ColorChannelMixerContext::ar
double ar
Definition: vf_colorchannelmixer.c:43
ColorChannelMixerContext::buffer
int * buffer
Definition: vf_colorchannelmixer.c:47
video.h
AVFormatContext::internal
AVFormatInternal * internal
An opaque field for libavformat internal usage.
Definition: avformat.h:1788
filter_slice_gbrap
static int filter_slice_gbrap(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: vf_colorchannelmixer.c:227
av_malloc
#define av_malloc(s)
Definition: tableprint_vlc.h:31
ra
#define ra
Definition: regdef.h:57
AVFilterFormats
A list of supported formats for one end of a filter link.
Definition: formats.h:64
formats.h
ColorChannelMixerContext::gr
double gr
Definition: vf_colorchannelmixer.c:41
B
#define B
Definition: vf_colorchannelmixer.c:31
AV_PIX_FMT_GBRP14
#define AV_PIX_FMT_GBRP14
Definition: pixfmt.h:415
AV_PIX_FMT_GBRAP
@ AV_PIX_FMT_GBRAP
planar GBRA 4:4:4:4 32bpp
Definition: pixfmt.h:215
filter_slice_rgba
static int filter_slice_rgba(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: vf_colorchannelmixer.c:391
AV_PIX_FMT_GBRP10
#define AV_PIX_FMT_GBRP10
Definition: pixfmt.h:413
filter_slice_gbrap16
static int filter_slice_gbrap16(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: vf_colorchannelmixer.c:267
AVFilterPad
A filter pad used for either input or output.
Definition: internal.h:54
lrint
#define lrint
Definition: tablegen.h:53
av_cold
#define av_cold
Definition: attributes.h:90
ff_set_common_formats
int ff_set_common_formats(AVFilterContext *ctx, AVFilterFormats *formats)
A helper for query_formats() which sets all links to the same list of formats.
Definition: formats.c:605
ColorChannelMixerContext::rb
double rb
Definition: vf_colorchannelmixer.c:40
AV_PIX_FMT_GBRAP10
#define AV_PIX_FMT_GBRAP10
Definition: pixfmt.h:417
ColorChannelMixerContext::ba
double ba
Definition: vf_colorchannelmixer.c:42
s
#define s(width, name)
Definition: cbs_vp9.c:257
AV_PIX_FMT_GBRAP12
#define AV_PIX_FMT_GBRAP12
Definition: pixfmt.h:418
FLAGS
#define FLAGS
Definition: vf_colorchannelmixer.c:55
filter_slice_rgb48
static int filter_slice_rgb48(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: vf_colorchannelmixer.c:386
AV_OPT_TYPE_DOUBLE
@ AV_OPT_TYPE_DOUBLE
Definition: opt.h:225
slice_end
static int slice_end(AVCodecContext *avctx, AVFrame *pict)
Handle slice ends.
Definition: mpeg12dec.c:2040
filter_slice_rgba16_packed
static av_always_inline int filter_slice_rgba16_packed(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs, int have_alpha, int step)
Definition: vf_colorchannelmixer.c:327
ColorChannelMixerContext::lut
int * lut[4][4]
Definition: vf_colorchannelmixer.c:45
ColorChannelMixerContext::ag
double ag
Definition: vf_colorchannelmixer.c:43
outputs
static const AVFilterPad outputs[]
Definition: af_acontrast.c:203
pix_fmts
static enum AVPixelFormat pix_fmts[]
Definition: libkvazaar.c:275
ctx
AVFormatContext * ctx
Definition: movenc.c:48
ColorChannelMixerContext::bg
double bg
Definition: vf_colorchannelmixer.c:42
AV_PIX_FMT_RGBA
@ AV_PIX_FMT_RGBA
packed RGBA 8:8:8:8, 32bpp, RGBARGBA...
Definition: pixfmt.h:93
ColorChannelMixerContext
Definition: vf_colorchannelmixer.c:38
arg
const char * arg
Definition: jacosubdec.c:66
colorchannelmixer_outputs
static const AVFilterPad colorchannelmixer_outputs[]
Definition: vf_colorchannelmixer.c:564
AV_PIX_FMT_GBRP16
#define AV_PIX_FMT_GBRP16
Definition: pixfmt.h:416
AV_PIX_FMT_RGBA64
#define AV_PIX_FMT_RGBA64
Definition: pixfmt.h:387
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:67
AV_PIX_FMT_BGR48
#define AV_PIX_FMT_BGR48
Definition: pixfmt.h:388
NULL
#define NULL
Definition: coverity.c:32
av_frame_copy_props
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
Definition: frame.c:659
filter_slice_gbrp
static int filter_slice_gbrp(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: vf_colorchannelmixer.c:222
filter_slice_gbrp9
static int filter_slice_gbrp9(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: vf_colorchannelmixer.c:232
filter_slice_rgba16_planar
static av_always_inline int filter_slice_rgba16_planar(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs, int have_alpha, int depth)
Definition: vf_colorchannelmixer.c:163
filter_slice_gbrp10
static int filter_slice_gbrp10(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: vf_colorchannelmixer.c:237
src
#define src
Definition: vp8dsp.c:254
AV_PIX_FMT_BGR0
@ AV_PIX_FMT_BGR0
packed BGR 8:8:8, 32bpp, BGRXBGRX... X=unused/undefined
Definition: pixfmt.h:240
inputs
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several inputs
Definition: filter_design.txt:243
AV_PIX_FMT_GBRP9
#define AV_PIX_FMT_GBRP9
Definition: pixfmt.h:412
AV_PIX_FMT_ABGR
@ AV_PIX_FMT_ABGR
packed ABGR 8:8:8:8, 32bpp, ABGRABGR...
Definition: pixfmt.h:94
AVFILTER_DEFINE_CLASS
AVFILTER_DEFINE_CLASS(colorchannelmixer)
desc
const char * desc
Definition: nvenc.c:79
AV_PIX_FMT_RGB24
@ AV_PIX_FMT_RGB24
packed RGB 8:8:8, 24bpp, RGBRGB...
Definition: pixfmt.h:68
filter_slice_gbrap10
static int filter_slice_gbrap10(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: vf_colorchannelmixer.c:242
NULL_IF_CONFIG_SMALL
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:188
AV_PIX_FMT_RGB48
#define AV_PIX_FMT_RGB48
Definition: pixfmt.h:383
size
int size
Definition: twinvq_data.h:11134
av_frame_is_writable
int av_frame_is_writable(AVFrame *frame)
Check if the frame data is writable.
Definition: frame.c:595
ff_filter_process_command
int ff_filter_process_command(AVFilterContext *ctx, const char *cmd, const char *arg, char *res, int res_len, int flags)
Generic processing of user supplied commands that are set in the same way as the filter options.
Definition: avfilter.c:869
FFMIN
#define FFMIN(a, b)
Definition: common.h:96
ColorChannelMixerContext::filter_slice
int(* filter_slice)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: vf_colorchannelmixer.c:51
AV_PIX_FMT_RGB0
@ AV_PIX_FMT_RGB0
packed RGB 8:8:8, 32bpp, RGBXRGBX... X=unused/undefined
Definition: pixfmt.h:238
internal.h
AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC
#define AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC
Some filters support a generic "enable" expression option that can be used to enable or disable a fil...
Definition: avfilter.h:125
AV_PIX_FMT_ARGB
@ AV_PIX_FMT_ARGB
packed ARGB 8:8:8:8, 32bpp, ARGBARGB...
Definition: pixfmt.h:92
in
uint8_t pi<< 24) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_U8, uint8_t,(*(const uint8_t *) pi - 0x80) *(1.0f/(1<< 7))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_U8, uint8_t,(*(const uint8_t *) pi - 0x80) *(1.0/(1<< 7))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S16, int16_t,(*(const int16_t *) pi >> 8)+0x80) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S16, int16_t, *(const int16_t *) pi *(1.0f/(1<< 15))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S16, int16_t, *(const int16_t *) pi *(1.0/(1<< 15))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S32, int32_t,(*(const int32_t *) pi >> 24)+0x80) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S32, int32_t, *(const int32_t *) pi *(1.0f/(1U<< 31))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S32, int32_t, *(const int32_t *) pi *(1.0/(1U<< 31))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_FLT, float, av_clip_uint8(lrintf(*(const float *) pi *(1<< 7))+0x80)) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_FLT, float, av_clip_int16(lrintf(*(const float *) pi *(1<< 15)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_FLT, float, av_clipl_int32(llrintf(*(const float *) pi *(1U<< 31)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_DBL, double, av_clip_uint8(lrint(*(const double *) pi *(1<< 7))+0x80)) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_DBL, double, av_clip_int16(lrint(*(const double *) pi *(1<< 15)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_DBL, double, av_clipl_int32(llrint(*(const double *) pi *(1U<< 31)))) #define SET_CONV_FUNC_GROUP(ofmt, ifmt) static void set_generic_function(AudioConvert *ac) { } void ff_audio_convert_free(AudioConvert **ac) { if(! *ac) return;ff_dither_free(&(*ac) ->dc);av_freep(ac);} AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr, enum AVSampleFormat out_fmt, enum AVSampleFormat in_fmt, int channels, int sample_rate, int apply_map) { AudioConvert *ac;int in_planar, out_planar;ac=av_mallocz(sizeof(*ac));if(!ac) return NULL;ac->avr=avr;ac->out_fmt=out_fmt;ac->in_fmt=in_fmt;ac->channels=channels;ac->apply_map=apply_map;if(avr->dither_method !=AV_RESAMPLE_DITHER_NONE &&av_get_packed_sample_fmt(out_fmt)==AV_SAMPLE_FMT_S16 &&av_get_bytes_per_sample(in_fmt) > 2) { ac->dc=ff_dither_alloc(avr, out_fmt, in_fmt, channels, sample_rate, apply_map);if(!ac->dc) { av_free(ac);return NULL;} return ac;} in_planar=ff_sample_fmt_is_planar(in_fmt, channels);out_planar=ff_sample_fmt_is_planar(out_fmt, channels);if(in_planar==out_planar) { ac->func_type=CONV_FUNC_TYPE_FLAT;ac->planes=in_planar ? ac->channels :1;} else if(in_planar) ac->func_type=CONV_FUNC_TYPE_INTERLEAVE;else ac->func_type=CONV_FUNC_TYPE_DEINTERLEAVE;set_generic_function(ac);if(ARCH_AARCH64) ff_audio_convert_init_aarch64(ac);if(ARCH_ARM) ff_audio_convert_init_arm(ac);if(ARCH_X86) ff_audio_convert_init_x86(ac);return ac;} int ff_audio_convert(AudioConvert *ac, AudioData *out, AudioData *in) { int use_generic=1;int len=in->nb_samples;int p;if(ac->dc) { av_log(ac->avr, AV_LOG_TRACE, "%d samples - audio_convert: %s to %s (dithered)\n", len, av_get_sample_fmt_name(ac->in_fmt), av_get_sample_fmt_name(ac->out_fmt));return ff_convert_dither(ac-> in
Definition: audio_convert.c:326
AV_PIX_FMT_BGRA64
#define AV_PIX_FMT_BGRA64
Definition: pixfmt.h:392
filter_frame
static int filter_frame(AVFilterLink *inlink, AVFrame *in)
Definition: vf_colorchannelmixer.c:509
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:269
AV_PIX_FMT_GBRP12
#define AV_PIX_FMT_GBRP12
Definition: pixfmt.h:414
ff_filter_get_nb_threads
int ff_filter_get_nb_threads(AVFilterContext *ctx)
Get number of threads for current filter instance.
Definition: avfilter.c:784
ThreadData
Used for passing data between threads.
Definition: dsddec.c:67
av_always_inline
#define av_always_inline
Definition: attributes.h:49
uint8_t
uint8_t
Definition: audio_convert.c:194
AVFilterPad::name
const char * name
Pad name.
Definition: internal.h:60
filter_slice_rgba_planar
static av_always_inline int filter_slice_rgba_planar(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs, int have_alpha)
Definition: vf_colorchannelmixer.c:104
filter_slice_gbrp12
static int filter_slice_gbrp12(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: vf_colorchannelmixer.c:247
AVFilter
Filter definition.
Definition: avfilter.h:144
uninit
static av_cold void uninit(AVFilterContext *ctx)
Definition: vf_colorchannelmixer.c:548
ret
ret
Definition: filter_design.txt:187
filter_slice_rgb24
static int filter_slice_rgb24(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: vf_colorchannelmixer.c:396
AV_PIX_FMT_0BGR
@ AV_PIX_FMT_0BGR
packed BGR 8:8:8, 32bpp, XBGRXBGR... X=unused/undefined
Definition: pixfmt.h:239
ColorChannelMixerContext::ab
double ab
Definition: vf_colorchannelmixer.c:43
ColorChannelMixerContext::rr
double rr
Definition: vf_colorchannelmixer.c:40
ColorChannelMixerContext::ga
double ga
Definition: vf_colorchannelmixer.c:41
buffer
the frame and frame reference mechanism is intended to as much as expensive copies of that data while still allowing the filters to produce correct results The data is stored in buffers represented by AVFrame structures Several references can point to the same frame buffer
Definition: filter_design.txt:49
ColorChannelMixerContext::gb
double gb
Definition: vf_colorchannelmixer.c:41
AV_PIX_FMT_NONE
@ AV_PIX_FMT_NONE
Definition: pixfmt.h:65
avfilter.h
AVFilterContext
An instance of a filter.
Definition: avfilter.h:338
config_output
static int config_output(AVFilterLink *outlink)
Definition: vf_colorchannelmixer.c:406
filter_slice_rgba_packed
static av_always_inline int filter_slice_rgba_packed(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs, int have_alpha, int step)
Definition: vf_colorchannelmixer.c:272
AV_PIX_FMT_GBRP
@ AV_PIX_FMT_GBRP
planar GBR 4:4:4 24bpp
Definition: pixfmt.h:168
AVFILTER_FLAG_SLICE_THREADS
#define AVFILTER_FLAG_SLICE_THREADS
The filter supports multithreading by splitting frames into multiple parts and processing them concur...
Definition: avfilter.h:116
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
filter_slice_gbrap12
static int filter_slice_gbrap12(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: vf_colorchannelmixer.c:252
OFFSET
#define OFFSET(x)
Definition: vf_colorchannelmixer.c:54
ThreadData::in
AVFrame * in
Definition: af_afftdn.c:1083
AVPixFmtDescriptor
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition: pixdesc.h:81
ColorChannelMixerContext::rgba_map
uint8_t rgba_map[4]
Definition: vf_colorchannelmixer.c:49
ColorChannelMixerContext::br
double br
Definition: vf_colorchannelmixer.c:42
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
ff_fill_rgba_map
int ff_fill_rgba_map(uint8_t *rgba_map, enum AVPixelFormat pix_fmt)
Definition: drawutils.c:35
ColorChannelMixerContext::ra
double ra
Definition: vf_colorchannelmixer.c:40
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:565
AV_PIX_FMT_0RGB
@ AV_PIX_FMT_0RGB
packed RGB 8:8:8, 32bpp, XRGBXRGB... X=unused/undefined
Definition: pixfmt.h:237
filter_slice_gbrp16
static int filter_slice_gbrp16(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: vf_colorchannelmixer.c:262
process_command
static int process_command(AVFilterContext *ctx, const char *cmd, const char *args, char *res, int res_len, int flags)
Definition: vf_colorchannelmixer.c:537
drawutils.h
ColorChannelMixerContext::aa
double aa
Definition: vf_colorchannelmixer.c:43
colorchannelmixer_inputs
static const AVFilterPad colorchannelmixer_inputs[]
Definition: vf_colorchannelmixer.c:555
int
int
Definition: ffmpeg_filter.c:192