Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Copyright (c) 2015 Timo Rothenpieler <timo@rothenpieler.org>
  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/imgutils.h"
  23. #include "avfilter.h"
  24. #include "formats.h"
  25. #include "internal.h"
  26. #include "video.h"
  27.  
  28. typedef struct ColorkeyContext {
  29.     const AVClass *class;
  30.  
  31.     /* color offsets rgba */
  32.     int co[4];
  33.  
  34.     uint8_t colorkey_rgba[4];
  35.     float similarity;
  36.     float blend;
  37. } ColorkeyContext;
  38.  
  39. static uint8_t do_colorkey_pixel(ColorkeyContext *ctx, uint8_t r, uint8_t g, uint8_t b)
  40. {
  41.     int dr = (int)r - ctx->colorkey_rgba[0];
  42.     int dg = (int)g - ctx->colorkey_rgba[1];
  43.     int db = (int)b - ctx->colorkey_rgba[2];
  44.  
  45.     double diff = sqrt((dr * dr + dg * dg + db * db) / (255.0 * 255.0));
  46.  
  47.     if (ctx->blend > 0.0001) {
  48.         return av_clipd((diff - ctx->similarity) / ctx->blend, 0.0, 1.0) * 255.0;
  49.     } else {
  50.         return (diff > ctx->similarity) ? 255 : 0;
  51.     }
  52. }
  53.  
  54. static int do_colorkey_slice(AVFilterContext *avctx, void *arg, int jobnr, int nb_jobs)
  55. {
  56.     AVFrame *frame = arg;
  57.  
  58.     const int slice_start = (frame->height * jobnr) / nb_jobs;
  59.     const int slice_end = (frame->height * (jobnr + 1)) / nb_jobs;
  60.  
  61.     ColorkeyContext *ctx = avctx->priv;
  62.  
  63.     int o, x, y;
  64.  
  65.     for (y = slice_start; y < slice_end; ++y) {
  66.         for (x = 0; x < frame->width; ++x) {
  67.             o = frame->linesize[0] * y + x * 4;
  68.  
  69.             frame->data[0][o + ctx->co[3]] =
  70.                 do_colorkey_pixel(ctx,
  71.                                   frame->data[0][o + ctx->co[0]],
  72.                                   frame->data[0][o + ctx->co[1]],
  73.                                   frame->data[0][o + ctx->co[2]]);
  74.         }
  75.     }
  76.  
  77.     return 0;
  78. }
  79.  
  80. static int filter_frame(AVFilterLink *link, AVFrame *frame)
  81. {
  82.     AVFilterContext *avctx = link->dst;
  83.     int res;
  84.  
  85.     if (res = av_frame_make_writable(frame))
  86.         return res;
  87.  
  88.     if (res = avctx->internal->execute(avctx, do_colorkey_slice, frame, NULL, FFMIN(frame->height, avctx->graph->nb_threads)))
  89.         return res;
  90.  
  91.     return ff_filter_frame(avctx->outputs[0], frame);
  92. }
  93.  
  94. static av_cold int config_output(AVFilterLink *outlink)
  95. {
  96.     AVFilterContext *avctx = outlink->src;
  97.     ColorkeyContext *ctx = avctx->priv;
  98.     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(outlink->format);
  99.     int i;
  100.  
  101.     outlink->w = avctx->inputs[0]->w;
  102.     outlink->h = avctx->inputs[0]->h;
  103.     outlink->time_base = avctx->inputs[0]->time_base;
  104.  
  105.     for (i = 0; i < 4; ++i)
  106.         ctx->co[i] = desc->comp[i].offset_plus1 - 1;
  107.  
  108.     return 0;
  109. }
  110.  
  111. static av_cold int query_formats(AVFilterContext *avctx)
  112. {
  113.     static const enum AVPixelFormat pixel_fmts[] = {
  114.         AV_PIX_FMT_ARGB,
  115.         AV_PIX_FMT_RGBA,
  116.         AV_PIX_FMT_ABGR,
  117.         AV_PIX_FMT_BGRA,
  118.         AV_PIX_FMT_NONE
  119.     };
  120.  
  121.     AVFilterFormats *formats = NULL;
  122.  
  123.     formats = ff_make_format_list(pixel_fmts);
  124.     if (!formats)
  125.         return AVERROR(ENOMEM);
  126.  
  127.     return ff_set_common_formats(avctx, formats);
  128. }
  129.  
  130. static const AVFilterPad colorkey_inputs[] = {
  131.     {
  132.         .name = "default",
  133.         .type = AVMEDIA_TYPE_VIDEO,
  134.         .filter_frame = filter_frame,
  135.     },
  136.     { NULL }
  137. };
  138.  
  139. static const AVFilterPad colorkey_outputs[] = {
  140.     {
  141.         .name = "default",
  142.         .type = AVMEDIA_TYPE_VIDEO,
  143.         .config_props  = config_output,
  144.     },
  145.     { NULL }
  146. };
  147.  
  148. #define OFFSET(x) offsetof(ColorkeyContext, x)
  149. #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
  150.  
  151. static const AVOption colorkey_options[] = {
  152.     { "color", "set the colorkey key color", OFFSET(colorkey_rgba), AV_OPT_TYPE_COLOR, { .str = "black" }, CHAR_MIN, CHAR_MAX, FLAGS },
  153.     { "similarity", "set the colorkey similarity value", OFFSET(similarity), AV_OPT_TYPE_FLOAT, { .dbl = 0.01 }, 0.01, 1.0, FLAGS },
  154.     { "blend", "set the colorkey key blend value", OFFSET(blend), AV_OPT_TYPE_FLOAT, { .dbl = 0.0 }, 0.0, 1.0, FLAGS },
  155.     { NULL }
  156. };
  157.  
  158. AVFILTER_DEFINE_CLASS(colorkey);
  159.  
  160. AVFilter ff_vf_colorkey = {
  161.     .name          = "colorkey",
  162.     .description   = NULL_IF_CONFIG_SMALL("colorkey filter"),
  163.     .priv_size     = sizeof(ColorkeyContext),
  164.     .priv_class    = &colorkey_class,
  165.     .query_formats = query_formats,
  166.     .inputs        = colorkey_inputs,
  167.     .outputs       = colorkey_outputs,
  168.     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
  169. };
  170.