Subversion Repositories Kolibri OS

Rev

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

  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. };
  361.