LCOV - code coverage report
Current view: top level - libavfilter - vf_colorchannelmixer.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 93 311 29.9 %
Date: 2018-05-20 11:54:08 Functions: 6 23 26.1 %

          Line data    Source code
       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             : 
      49             :     uint8_t rgba_map[4];
      50             : 
      51             :     int (*filter_slice)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs);
      52             : } ColorChannelMixerContext;
      53             : 
      54             : #define OFFSET(x) offsetof(ColorChannelMixerContext, x)
      55             : #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
      56             : static const AVOption colorchannelmixer_options[] = {
      57             :     { "rr", "set the red gain for the red channel",     OFFSET(rr), AV_OPT_TYPE_DOUBLE, {.dbl=1}, -2, 2, FLAGS },
      58             :     { "rg", "set the green gain for the red channel",   OFFSET(rg), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -2, 2, FLAGS },
      59             :     { "rb", "set the blue gain for the red channel",    OFFSET(rb), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -2, 2, FLAGS },
      60             :     { "ra", "set the alpha gain for the red channel",   OFFSET(ra), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -2, 2, FLAGS },
      61             :     { "gr", "set the red gain for the green channel",   OFFSET(gr), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -2, 2, FLAGS },
      62             :     { "gg", "set the green gain for the green channel", OFFSET(gg), AV_OPT_TYPE_DOUBLE, {.dbl=1}, -2, 2, FLAGS },
      63             :     { "gb", "set the blue gain for the green channel",  OFFSET(gb), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -2, 2, FLAGS },
      64             :     { "ga", "set the alpha gain for the green channel", OFFSET(ga), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -2, 2, FLAGS },
      65             :     { "br", "set the red gain for the blue channel",    OFFSET(br), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -2, 2, FLAGS },
      66             :     { "bg", "set the green gain for the blue channel",  OFFSET(bg), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -2, 2, FLAGS },
      67             :     { "bb", "set the blue gain for the blue channel",   OFFSET(bb), AV_OPT_TYPE_DOUBLE, {.dbl=1}, -2, 2, FLAGS },
      68             :     { "ba", "set the alpha gain for the blue channel",  OFFSET(ba), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -2, 2, FLAGS },
      69             :     { "ar", "set the red gain for the alpha channel",   OFFSET(ar), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -2, 2, FLAGS },
      70             :     { "ag", "set the green gain for the alpha channel", OFFSET(ag), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -2, 2, FLAGS },
      71             :     { "ab", "set the blue gain for the alpha channel",  OFFSET(ab), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -2, 2, FLAGS },
      72             :     { "aa", "set the alpha gain for the alpha channel", OFFSET(aa), AV_OPT_TYPE_DOUBLE, {.dbl=1}, -2, 2, FLAGS },
      73             :     { NULL }
      74             : };
      75             : 
      76             : AVFILTER_DEFINE_CLASS(colorchannelmixer);
      77             : 
      78           1 : static int query_formats(AVFilterContext *ctx)
      79             : {
      80             :     static const enum AVPixelFormat pix_fmts[] = {
      81             :         AV_PIX_FMT_RGB24,  AV_PIX_FMT_BGR24,
      82             :         AV_PIX_FMT_RGBA,   AV_PIX_FMT_BGRA,
      83             :         AV_PIX_FMT_ARGB,   AV_PIX_FMT_ABGR,
      84             :         AV_PIX_FMT_0RGB,   AV_PIX_FMT_0BGR,
      85             :         AV_PIX_FMT_RGB0,   AV_PIX_FMT_BGR0,
      86             :         AV_PIX_FMT_RGB48,  AV_PIX_FMT_BGR48,
      87             :         AV_PIX_FMT_RGBA64, AV_PIX_FMT_BGRA64,
      88             :         AV_PIX_FMT_GBRP,   AV_PIX_FMT_GBRAP,
      89             :         AV_PIX_FMT_GBRP9,
      90             :         AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRAP10,
      91             :         AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRAP12,
      92             :         AV_PIX_FMT_GBRP14,
      93             :         AV_PIX_FMT_GBRP16, AV_PIX_FMT_GBRAP16,
      94             :         AV_PIX_FMT_NONE
      95             :     };
      96             : 
      97           1 :     AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
      98           1 :     if (!fmts_list)
      99           0 :         return AVERROR(ENOMEM);
     100           1 :     return ff_set_common_formats(ctx, fmts_list);
     101             : }
     102             : 
     103           0 : static av_always_inline int filter_slice_rgba_planar(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs,
     104             :                                                      int have_alpha)
     105             : {
     106           0 :     ColorChannelMixerContext *s = ctx->priv;
     107           0 :     ThreadData *td = arg;
     108           0 :     AVFrame *in = td->in;
     109           0 :     AVFrame *out = td->out;
     110           0 :     const int slice_start = (out->height * jobnr) / nb_jobs;
     111           0 :     const int slice_end = (out->height * (jobnr+1)) / nb_jobs;
     112           0 :     const uint8_t *srcg = in->data[0] + slice_start * in->linesize[0];
     113           0 :     const uint8_t *srcb = in->data[1] + slice_start * in->linesize[1];
     114           0 :     const uint8_t *srcr = in->data[2] + slice_start * in->linesize[2];
     115           0 :     const uint8_t *srca = in->data[3] + slice_start * in->linesize[3];
     116           0 :     uint8_t *dstg = out->data[0] + slice_start * out->linesize[0];
     117           0 :     uint8_t *dstb = out->data[1] + slice_start * out->linesize[1];
     118           0 :     uint8_t *dstr = out->data[2] + slice_start * out->linesize[2];
     119           0 :     uint8_t *dsta = out->data[3] + slice_start * out->linesize[3];
     120             :     int i, j;
     121             : 
     122           0 :     for (i = slice_start; i < slice_end; i++) {
     123           0 :         for (j = 0; j < out->width; j++) {
     124           0 :             const uint8_t rin = srcr[j];
     125           0 :             const uint8_t gin = srcg[j];
     126           0 :             const uint8_t bin = srcb[j];
     127           0 :             const uint8_t ain = srca[j];
     128             : 
     129           0 :             dstr[j] = av_clip_uint8(s->lut[R][R][rin] +
     130           0 :                                     s->lut[R][G][gin] +
     131           0 :                                     s->lut[R][B][bin] +
     132           0 :                                     (have_alpha == 1 ? s->lut[R][A][ain] : 0));
     133           0 :             dstg[j] = av_clip_uint8(s->lut[G][R][rin] +
     134           0 :                                     s->lut[G][G][gin] +
     135           0 :                                     s->lut[G][B][bin] +
     136           0 :                                     (have_alpha == 1 ? s->lut[G][A][ain] : 0));
     137           0 :             dstb[j] = av_clip_uint8(s->lut[B][R][rin] +
     138           0 :                                     s->lut[B][G][gin] +
     139           0 :                                     s->lut[B][B][bin] +
     140           0 :                                     (have_alpha == 1 ? s->lut[B][A][ain] : 0));
     141           0 :             if (have_alpha == 1) {
     142           0 :                 dsta[j] = av_clip_uint8(s->lut[A][R][rin] +
     143           0 :                                         s->lut[A][G][gin] +
     144           0 :                                         s->lut[A][B][bin] +
     145           0 :                                         s->lut[A][A][ain]);
     146             :             }
     147             :         }
     148             : 
     149           0 :         srcg += in->linesize[0];
     150           0 :         srcb += in->linesize[1];
     151           0 :         srcr += in->linesize[2];
     152           0 :         srca += in->linesize[3];
     153           0 :         dstg += out->linesize[0];
     154           0 :         dstb += out->linesize[1];
     155           0 :         dstr += out->linesize[2];
     156           0 :         dsta += out->linesize[3];
     157             :     }
     158             : 
     159           0 :     return 0;
     160             : }
     161             : 
     162           0 : static av_always_inline int filter_slice_rgba16_planar(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs,
     163             :                                                        int have_alpha, int depth)
     164             : {
     165           0 :     ColorChannelMixerContext *s = ctx->priv;
     166           0 :     ThreadData *td = arg;
     167           0 :     AVFrame *in = td->in;
     168           0 :     AVFrame *out = td->out;
     169           0 :     const int slice_start = (out->height * jobnr) / nb_jobs;
     170           0 :     const int slice_end = (out->height * (jobnr+1)) / nb_jobs;
     171           0 :     const uint16_t *srcg = (const uint16_t *)(in->data[0] + slice_start * in->linesize[0]);
     172           0 :     const uint16_t *srcb = (const uint16_t *)(in->data[1] + slice_start * in->linesize[1]);
     173           0 :     const uint16_t *srcr = (const uint16_t *)(in->data[2] + slice_start * in->linesize[2]);
     174           0 :     const uint16_t *srca = (const uint16_t *)(in->data[3] + slice_start * in->linesize[3]);
     175           0 :     uint16_t *dstg = (uint16_t *)(out->data[0] + slice_start * out->linesize[0]);
     176           0 :     uint16_t *dstb = (uint16_t *)(out->data[1] + slice_start * out->linesize[1]);
     177           0 :     uint16_t *dstr = (uint16_t *)(out->data[2] + slice_start * out->linesize[2]);
     178           0 :     uint16_t *dsta = (uint16_t *)(out->data[3] + slice_start * out->linesize[3]);
     179             :     int i, j;
     180             : 
     181           0 :     for (i = slice_start; i < slice_end; i++) {
     182           0 :         for (j = 0; j < out->width; j++) {
     183           0 :             const uint16_t rin = srcr[j];
     184           0 :             const uint16_t gin = srcg[j];
     185           0 :             const uint16_t bin = srcb[j];
     186           0 :             const uint16_t ain = srca[j];
     187             : 
     188           0 :             dstr[j] = av_clip_uintp2(s->lut[R][R][rin] +
     189           0 :                                      s->lut[R][G][gin] +
     190           0 :                                      s->lut[R][B][bin] +
     191           0 :                                      (have_alpha == 1 ? s->lut[R][A][ain] : 0), depth);
     192           0 :             dstg[j] = av_clip_uintp2(s->lut[G][R][rin] +
     193           0 :                                      s->lut[G][G][gin] +
     194           0 :                                      s->lut[G][B][bin] +
     195           0 :                                      (have_alpha == 1 ? s->lut[G][A][ain] : 0), depth);
     196           0 :             dstb[j] = av_clip_uintp2(s->lut[B][R][rin] +
     197           0 :                                      s->lut[B][G][gin] +
     198           0 :                                      s->lut[B][B][bin] +
     199           0 :                                      (have_alpha == 1 ? s->lut[B][A][ain] : 0), depth);
     200           0 :             if (have_alpha == 1) {
     201           0 :                 dsta[j] = av_clip_uintp2(s->lut[A][R][rin] +
     202           0 :                                          s->lut[A][G][gin] +
     203           0 :                                          s->lut[A][B][bin] +
     204           0 :                                          s->lut[A][A][ain], depth);
     205             :             }
     206             :         }
     207             : 
     208           0 :         srcg += in->linesize[0] / 2;
     209           0 :         srcb += in->linesize[1] / 2;
     210           0 :         srcr += in->linesize[2] / 2;
     211           0 :         srca += in->linesize[3] / 2;
     212           0 :         dstg += out->linesize[0] / 2;
     213           0 :         dstb += out->linesize[1] / 2;
     214           0 :         dstr += out->linesize[2] / 2;
     215           0 :         dsta += out->linesize[3] / 2;
     216             :     }
     217             : 
     218           0 :     return 0;
     219             : }
     220             : 
     221           0 : static int filter_slice_gbrp(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
     222             : {
     223           0 :     return filter_slice_rgba_planar(ctx, arg, jobnr, nb_jobs, 0);
     224             : }
     225             : 
     226           0 : static int filter_slice_gbrap(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
     227             : {
     228           0 :     return filter_slice_rgba_planar(ctx, arg, jobnr, nb_jobs, 1);
     229             : }
     230             : 
     231           0 : static int filter_slice_gbrp9(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
     232             : {
     233           0 :     return filter_slice_rgba16_planar(ctx, arg, jobnr, nb_jobs, 0, 9);
     234             : }
     235             : 
     236           0 : static int filter_slice_gbrp10(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
     237             : {
     238           0 :     return filter_slice_rgba16_planar(ctx, arg, jobnr, nb_jobs, 0, 10);
     239             : }
     240             : 
     241           0 : static int filter_slice_gbrap10(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
     242             : {
     243           0 :     return filter_slice_rgba16_planar(ctx, arg, jobnr, nb_jobs, 1, 10);
     244             : }
     245             : 
     246           0 : static int filter_slice_gbrp12(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
     247             : {
     248           0 :     return filter_slice_rgba16_planar(ctx, arg, jobnr, nb_jobs, 0, 12);
     249             : }
     250             : 
     251           0 : static int filter_slice_gbrap12(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
     252             : {
     253           0 :     return filter_slice_rgba16_planar(ctx, arg, jobnr, nb_jobs, 1, 12);
     254             : }
     255             : 
     256           0 : static int filter_slice_gbrp14(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
     257             : {
     258           0 :     return filter_slice_rgba16_planar(ctx, arg, jobnr, nb_jobs, 0, 14);
     259             : }
     260             : 
     261           0 : static int filter_slice_gbrp16(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
     262             : {
     263           0 :     return filter_slice_rgba16_planar(ctx, arg, jobnr, nb_jobs, 0, 16);
     264             : }
     265             : 
     266           0 : static int filter_slice_gbrap16(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
     267             : {
     268           0 :     return filter_slice_rgba16_planar(ctx, arg, jobnr, nb_jobs, 1, 16);
     269             : }
     270             : 
     271         450 : static av_always_inline int filter_slice_rgba_packed(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs,
     272             :                                                      int have_alpha, int step)
     273             : {
     274         450 :     ColorChannelMixerContext *s = ctx->priv;
     275         450 :     ThreadData *td = arg;
     276         450 :     AVFrame *in = td->in;
     277         450 :     AVFrame *out = td->out;
     278         450 :     const int slice_start = (out->height * jobnr) / nb_jobs;
     279         450 :     const int slice_end = (out->height * (jobnr+1)) / nb_jobs;
     280         450 :     const uint8_t roffset = s->rgba_map[R];
     281         450 :     const uint8_t goffset = s->rgba_map[G];
     282         450 :     const uint8_t boffset = s->rgba_map[B];
     283         450 :     const uint8_t aoffset = s->rgba_map[A];
     284         450 :     const uint8_t *srcrow = in->data[0] + slice_start * in->linesize[0];
     285         450 :     uint8_t *dstrow = out->data[0] + slice_start * out->linesize[0];
     286             :     int i, j;
     287             : 
     288       14850 :     for (i = slice_start; i < slice_end; i++) {
     289       14400 :         const uint8_t *src = srcrow;
     290       14400 :         uint8_t *dst = dstrow;
     291             : 
     292     5083200 :         for (j = 0; j < out->width * step; j += step) {
     293     5068800 :             const uint8_t rin = src[j + roffset];
     294     5068800 :             const uint8_t gin = src[j + goffset];
     295     5068800 :             const uint8_t bin = src[j + boffset];
     296     5068800 :             const uint8_t ain = src[j + aoffset];
     297             : 
     298    15206400 :             dst[j + roffset] = av_clip_uint8(s->lut[R][R][rin] +
     299    10137600 :                                              s->lut[R][G][gin] +
     300     5068800 :                                              s->lut[R][B][bin] +
     301     5068800 :                                              (have_alpha == 1 ? s->lut[R][A][ain] : 0));
     302    15206400 :             dst[j + goffset] = av_clip_uint8(s->lut[G][R][rin] +
     303    10137600 :                                              s->lut[G][G][gin] +
     304     5068800 :                                              s->lut[G][B][bin] +
     305     5068800 :                                              (have_alpha == 1 ? s->lut[G][A][ain] : 0));
     306    15206400 :             dst[j + boffset] = av_clip_uint8(s->lut[B][R][rin] +
     307    10137600 :                                              s->lut[B][G][gin] +
     308     5068800 :                                              s->lut[B][B][bin] +
     309     5068800 :                                              (have_alpha == 1 ? s->lut[B][A][ain] : 0));
     310     5068800 :             if (have_alpha == 1) {
     311           0 :                 dst[j + aoffset] = av_clip_uint8(s->lut[A][R][rin] +
     312           0 :                                                  s->lut[A][G][gin] +
     313           0 :                                                  s->lut[A][B][bin] +
     314           0 :                                                  s->lut[A][A][ain]);
     315     5068800 :             } else if (have_alpha == -1 && in != out)
     316           0 :                 dst[j + aoffset] = 0;
     317             :         }
     318             : 
     319       14400 :         srcrow += in->linesize[0];
     320       14400 :         dstrow += out->linesize[0];
     321             :     }
     322             : 
     323         450 :     return 0;
     324             : }
     325             : 
     326           0 : static av_always_inline int filter_slice_rgba16_packed(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs,
     327             :                                                        int have_alpha, int step)
     328             : {
     329           0 :     ColorChannelMixerContext *s = ctx->priv;
     330           0 :     ThreadData *td = arg;
     331           0 :     AVFrame *in = td->in;
     332           0 :     AVFrame *out = td->out;
     333           0 :     const int slice_start = (out->height * jobnr) / nb_jobs;
     334           0 :     const int slice_end = (out->height * (jobnr+1)) / nb_jobs;
     335           0 :     const uint8_t roffset = s->rgba_map[R];
     336           0 :     const uint8_t goffset = s->rgba_map[G];
     337           0 :     const uint8_t boffset = s->rgba_map[B];
     338           0 :     const uint8_t aoffset = s->rgba_map[A];
     339           0 :     const uint8_t *srcrow = in->data[0] + slice_start * in->linesize[0];
     340           0 :     uint8_t *dstrow = out->data[0] + slice_start * out->linesize[0];
     341             :     int i, j;
     342             : 
     343           0 :     for (i = slice_start; i < slice_end; i++) {
     344           0 :         const uint16_t *src = (const uint16_t *)srcrow;
     345           0 :         uint16_t *dst = (uint16_t *)dstrow;
     346             : 
     347           0 :         for (j = 0; j < out->width * step; j += step) {
     348           0 :             const uint16_t rin = src[j + roffset];
     349           0 :             const uint16_t gin = src[j + goffset];
     350           0 :             const uint16_t bin = src[j + boffset];
     351           0 :             const uint16_t ain = src[j + aoffset];
     352             : 
     353           0 :             dst[j + roffset] = av_clip_uint16(s->lut[R][R][rin] +
     354           0 :                                               s->lut[R][G][gin] +
     355           0 :                                               s->lut[R][B][bin] +
     356           0 :                                               (have_alpha == 1 ? s->lut[R][A][ain] : 0));
     357           0 :             dst[j + goffset] = av_clip_uint16(s->lut[G][R][rin] +
     358           0 :                                               s->lut[G][G][gin] +
     359           0 :                                               s->lut[G][B][bin] +
     360           0 :                                               (have_alpha == 1 ? s->lut[G][A][ain] : 0));
     361           0 :             dst[j + boffset] = av_clip_uint16(s->lut[B][R][rin] +
     362           0 :                                               s->lut[B][G][gin] +
     363           0 :                                               s->lut[B][B][bin] +
     364           0 :                                               (have_alpha == 1 ? s->lut[B][A][ain] : 0));
     365           0 :             if (have_alpha == 1) {
     366           0 :                 dst[j + aoffset] = av_clip_uint16(s->lut[A][R][rin] +
     367           0 :                                                   s->lut[A][G][gin] +
     368           0 :                                                   s->lut[A][B][bin] +
     369           0 :                                                   s->lut[A][A][ain]);
     370             :             }
     371             :         }
     372             : 
     373           0 :         srcrow += in->linesize[0];
     374           0 :         dstrow += out->linesize[0];
     375             :     }
     376             : 
     377           0 :     return 0;
     378             : }
     379             : 
     380           0 : static int filter_slice_rgba64(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
     381             : {
     382           0 :     return filter_slice_rgba16_packed(ctx, arg, jobnr, nb_jobs, 1, 4);
     383             : }
     384             : 
     385           0 : static int filter_slice_rgb48(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
     386             : {
     387           0 :     return filter_slice_rgba16_packed(ctx, arg, jobnr, nb_jobs, 0, 3);
     388             : }
     389             : 
     390           0 : static int filter_slice_rgba(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
     391             : {
     392           0 :     return filter_slice_rgba_packed(ctx, arg, jobnr, nb_jobs, 1, 4);
     393             : }
     394             : 
     395         450 : static int filter_slice_rgb24(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
     396             : {
     397         450 :     return filter_slice_rgba_packed(ctx, arg, jobnr, nb_jobs, 0, 3);
     398             : }
     399             : 
     400           0 : static int filter_slice_rgb0(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
     401             : {
     402           0 :     return filter_slice_rgba_packed(ctx, arg, jobnr, nb_jobs, -1, 4);
     403             : }
     404             : 
     405           1 : static int config_output(AVFilterLink *outlink)
     406             : {
     407           1 :     AVFilterContext *ctx = outlink->src;
     408           1 :     ColorChannelMixerContext *s = ctx->priv;
     409           1 :     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(outlink->format);
     410           1 :     const int depth = desc->comp[0].depth;
     411             :     int i, j, size, *buffer;
     412             : 
     413           1 :     ff_fill_rgba_map(s->rgba_map, outlink->format);
     414             : 
     415           1 :     size = 1 << depth;
     416           1 :     s->buffer = buffer = av_malloc(16 * size * sizeof(*s->buffer));
     417           1 :     if (!s->buffer)
     418           0 :         return AVERROR(ENOMEM);
     419             : 
     420           5 :     for (i = 0; i < 4; i++)
     421          20 :         for (j = 0; j < 4; j++, buffer += size)
     422          16 :             s->lut[i][j] = buffer;
     423             : 
     424         257 :     for (i = 0; i < size; i++) {
     425         256 :         s->lut[R][R][i] = lrint(i * s->rr);
     426         256 :         s->lut[R][G][i] = lrint(i * s->rg);
     427         256 :         s->lut[R][B][i] = lrint(i * s->rb);
     428         256 :         s->lut[R][A][i] = lrint(i * s->ra);
     429             : 
     430         256 :         s->lut[G][R][i] = lrint(i * s->gr);
     431         256 :         s->lut[G][G][i] = lrint(i * s->gg);
     432         256 :         s->lut[G][B][i] = lrint(i * s->gb);
     433         256 :         s->lut[G][A][i] = lrint(i * s->ga);
     434             : 
     435         256 :         s->lut[B][R][i] = lrint(i * s->br);
     436         256 :         s->lut[B][G][i] = lrint(i * s->bg);
     437         256 :         s->lut[B][B][i] = lrint(i * s->bb);
     438         256 :         s->lut[B][A][i] = lrint(i * s->ba);
     439             : 
     440         256 :         s->lut[A][R][i] = lrint(i * s->ar);
     441         256 :         s->lut[A][G][i] = lrint(i * s->ag);
     442         256 :         s->lut[A][B][i] = lrint(i * s->ab);
     443         256 :         s->lut[A][A][i] = lrint(i * s->aa);
     444             :     }
     445             : 
     446           1 :     switch (outlink->format) {
     447           1 :     case AV_PIX_FMT_BGR24:
     448             :     case AV_PIX_FMT_RGB24:
     449           1 :         s->filter_slice = filter_slice_rgb24;
     450           1 :         break;
     451           0 :     case AV_PIX_FMT_0BGR:
     452             :     case AV_PIX_FMT_0RGB:
     453             :     case AV_PIX_FMT_BGR0:
     454             :     case AV_PIX_FMT_RGB0:
     455           0 :         s->filter_slice = filter_slice_rgb0;
     456           0 :         break;
     457           0 :     case AV_PIX_FMT_ABGR:
     458             :     case AV_PIX_FMT_ARGB:
     459             :     case AV_PIX_FMT_BGRA:
     460             :     case AV_PIX_FMT_RGBA:
     461           0 :         s->filter_slice = filter_slice_rgba;
     462           0 :         break;
     463           0 :     case AV_PIX_FMT_BGR48:
     464             :     case AV_PIX_FMT_RGB48:
     465           0 :         s->filter_slice = filter_slice_rgb48;
     466           0 :         break;
     467           0 :     case AV_PIX_FMT_BGRA64:
     468             :     case AV_PIX_FMT_RGBA64:
     469           0 :         s->filter_slice = filter_slice_rgba64;
     470           0 :         break;
     471           0 :     case AV_PIX_FMT_GBRP:
     472           0 :         s->filter_slice = filter_slice_gbrp;
     473           0 :         break;
     474           0 :     case AV_PIX_FMT_GBRAP:
     475           0 :         s->filter_slice = filter_slice_gbrap;
     476           0 :         break;
     477           0 :     case AV_PIX_FMT_GBRP9:
     478           0 :         s->filter_slice = filter_slice_gbrp9;
     479           0 :         break;
     480           0 :     case AV_PIX_FMT_GBRP10:
     481           0 :         s->filter_slice = filter_slice_gbrp10;
     482           0 :         break;
     483           0 :     case AV_PIX_FMT_GBRAP10:
     484           0 :         s->filter_slice = filter_slice_gbrap10;
     485           0 :         break;
     486           0 :     case AV_PIX_FMT_GBRP12:
     487           0 :         s->filter_slice = filter_slice_gbrp12;
     488           0 :         break;
     489           0 :     case AV_PIX_FMT_GBRAP12:
     490           0 :         s->filter_slice = filter_slice_gbrap12;
     491           0 :         break;
     492           0 :     case AV_PIX_FMT_GBRP14:
     493           0 :         s->filter_slice = filter_slice_gbrp14;
     494           0 :         break;
     495           0 :     case AV_PIX_FMT_GBRP16:
     496           0 :         s->filter_slice = filter_slice_gbrp16;
     497           0 :         break;
     498           0 :     case AV_PIX_FMT_GBRAP16:
     499           0 :         s->filter_slice = filter_slice_gbrap16;
     500           0 :         break;
     501             :     }
     502             : 
     503           1 :     return 0;
     504             : }
     505             : 
     506          50 : static int filter_frame(AVFilterLink *inlink, AVFrame *in)
     507             : {
     508          50 :     AVFilterContext *ctx = inlink->dst;
     509          50 :     ColorChannelMixerContext *s = ctx->priv;
     510          50 :     AVFilterLink *outlink = ctx->outputs[0];
     511             :     ThreadData td;
     512             :     AVFrame *out;
     513             : 
     514          50 :     if (av_frame_is_writable(in)) {
     515          50 :         out = in;
     516             :     } else {
     517           0 :         out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
     518           0 :         if (!out) {
     519           0 :             av_frame_free(&in);
     520           0 :             return AVERROR(ENOMEM);
     521             :         }
     522           0 :         av_frame_copy_props(out, in);
     523             :     }
     524             : 
     525          50 :     td.in = in;
     526          50 :     td.out = out;
     527          50 :     ctx->internal->execute(ctx, s->filter_slice, &td, NULL, FFMIN(outlink->h, ff_filter_get_nb_threads(ctx)));
     528             : 
     529          50 :     if (in != out)
     530           0 :         av_frame_free(&in);
     531          50 :     return ff_filter_frame(outlink, out);
     532             : }
     533             : 
     534           1 : static av_cold void uninit(AVFilterContext *ctx)
     535             : {
     536           1 :     ColorChannelMixerContext *s = ctx->priv;
     537             : 
     538           1 :     av_freep(&s->buffer);
     539           1 : }
     540             : 
     541             : static const AVFilterPad colorchannelmixer_inputs[] = {
     542             :     {
     543             :         .name         = "default",
     544             :         .type         = AVMEDIA_TYPE_VIDEO,
     545             :         .filter_frame = filter_frame,
     546             :     },
     547             :     { NULL }
     548             : };
     549             : 
     550             : static const AVFilterPad colorchannelmixer_outputs[] = {
     551             :     {
     552             :         .name         = "default",
     553             :         .type         = AVMEDIA_TYPE_VIDEO,
     554             :         .config_props = config_output,
     555             :     },
     556             :     { NULL }
     557             : };
     558             : 
     559             : AVFilter ff_vf_colorchannelmixer = {
     560             :     .name          = "colorchannelmixer",
     561             :     .description   = NULL_IF_CONFIG_SMALL("Adjust colors by mixing color channels."),
     562             :     .priv_size     = sizeof(ColorChannelMixerContext),
     563             :     .priv_class    = &colorchannelmixer_class,
     564             :     .uninit        = uninit,
     565             :     .query_formats = query_formats,
     566             :     .inputs        = colorchannelmixer_inputs,
     567             :     .outputs       = colorchannelmixer_outputs,
     568             :     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
     569             : };

Generated by: LCOV version 1.13