LCOV - code coverage report
Current view: top level - libavfilter - vf_colorkey.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 41 45 91.1 %
Date: 2017-12-18 06:23:41 Functions: 5 5 100.0 %

          Line data    Source code
       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       65536 : static uint8_t do_colorkey_pixel(ColorkeyContext *ctx, uint8_t r, uint8_t g, uint8_t b)
      40             : {
      41       65536 :     int dr = (int)r - ctx->colorkey_rgba[0];
      42       65536 :     int dg = (int)g - ctx->colorkey_rgba[1];
      43       65536 :     int db = (int)b - ctx->colorkey_rgba[2];
      44             : 
      45       65536 :     double diff = sqrt((dr * dr + dg * dg + db * db) / (255.0 * 255.0));
      46             : 
      47       65536 :     if (ctx->blend > 0.0001) {
      48       65536 :         return av_clipd((diff - ctx->similarity) / ctx->blend, 0.0, 1.0) * 255.0;
      49             :     } else {
      50           0 :         return (diff > ctx->similarity) ? 255 : 0;
      51             :     }
      52             : }
      53             : 
      54           9 : static int do_colorkey_slice(AVFilterContext *avctx, void *arg, int jobnr, int nb_jobs)
      55             : {
      56           9 :     AVFrame *frame = arg;
      57             : 
      58           9 :     const int slice_start = (frame->height * jobnr) / nb_jobs;
      59           9 :     const int slice_end = (frame->height * (jobnr + 1)) / nb_jobs;
      60             : 
      61           9 :     ColorkeyContext *ctx = avctx->priv;
      62             : 
      63             :     int o, x, y;
      64             : 
      65         265 :     for (y = slice_start; y < slice_end; ++y) {
      66       65792 :         for (x = 0; x < frame->width; ++x) {
      67       65536 :             o = frame->linesize[0] * y + x * 4;
      68             : 
      69      131072 :             frame->data[0][o + ctx->co[3]] =
      70      262144 :                 do_colorkey_pixel(ctx,
      71       65536 :                                   frame->data[0][o + ctx->co[0]],
      72       65536 :                                   frame->data[0][o + ctx->co[1]],
      73       65536 :                                   frame->data[0][o + ctx->co[2]]);
      74             :         }
      75             :     }
      76             : 
      77           9 :     return 0;
      78             : }
      79             : 
      80           1 : static int filter_frame(AVFilterLink *link, AVFrame *frame)
      81             : {
      82           1 :     AVFilterContext *avctx = link->dst;
      83             :     int res;
      84             : 
      85           1 :     if (res = av_frame_make_writable(frame))
      86           0 :         return res;
      87             : 
      88           1 :     if (res = avctx->internal->execute(avctx, do_colorkey_slice, frame, NULL, FFMIN(frame->height, ff_filter_get_nb_threads(avctx))))
      89           0 :         return res;
      90             : 
      91           1 :     return ff_filter_frame(avctx->outputs[0], frame);
      92             : }
      93             : 
      94           1 : static av_cold int config_output(AVFilterLink *outlink)
      95             : {
      96           1 :     AVFilterContext *avctx = outlink->src;
      97           1 :     ColorkeyContext *ctx = avctx->priv;
      98           1 :     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(outlink->format);
      99             :     int i;
     100             : 
     101           1 :     outlink->w = avctx->inputs[0]->w;
     102           1 :     outlink->h = avctx->inputs[0]->h;
     103           1 :     outlink->time_base = avctx->inputs[0]->time_base;
     104             : 
     105           5 :     for (i = 0; i < 4; ++i)
     106           4 :         ctx->co[i] = desc->comp[i].offset;
     107             : 
     108           1 :     return 0;
     109             : }
     110             : 
     111           1 : 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           1 :     AVFilterFormats *formats = NULL;
     122             : 
     123           1 :     formats = ff_make_format_list(pixel_fmts);
     124           1 :     if (!formats)
     125           0 :         return AVERROR(ENOMEM);
     126             : 
     127           1 :     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("Turns a certain color into transparency. Operates on RGB colors."),
     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             : };

Generated by: LCOV version 1.13