LCOV - code coverage report
Current view: top level - libavfilter - vf_neighbor.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 105 0.0 %
Date: 2017-12-12 03:56:30 Functions: 0 9 0.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2012-2013 Oka Motofumi (chikuzen.mo at gmail dot com)
       3             :  * Copyright (c) 2015 Paul B Mahol
       4             :  *
       5             :  * This file is part of FFmpeg.
       6             :  *
       7             :  * FFmpeg is free software; you can redistribute it and/or
       8             :  * modify it under the terms of the GNU Lesser General Public
       9             :  * License as published by the Free Software Foundation; either
      10             :  * version 2.1 of the License, or (at your option) any later version.
      11             :  *
      12             :  * FFmpeg is distributed in the hope that it will be useful,
      13             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15             :  * Lesser General Public License for more details.
      16             :  *
      17             :  * You should have received a copy of the GNU Lesser General Public
      18             :  * License along with FFmpeg; if not, write to the Free Software
      19             :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
      20             :  */
      21             : 
      22             : #include "libavutil/imgutils.h"
      23             : #include "libavutil/pixdesc.h"
      24             : #include "libavutil/opt.h"
      25             : #include "avfilter.h"
      26             : #include "formats.h"
      27             : #include "internal.h"
      28             : #include "video.h"
      29             : 
      30             : typedef struct NContext {
      31             :     const AVClass *class;
      32             :     int planeheight[4];
      33             :     int planewidth[4];
      34             :     int nb_planes;
      35             :     int threshold[4];
      36             :     int coordinates;
      37             :     uint8_t *buffer;
      38             : 
      39             :     void (*filter)(uint8_t *dst, const uint8_t *p1, int width,
      40             :                    int threshold, const uint8_t *coordinates[], int coord);
      41             : } NContext;
      42             : 
      43           0 : static int query_formats(AVFilterContext *ctx)
      44             : {
      45             :     static const enum AVPixelFormat pix_fmts[] = {
      46             :         AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA420P,
      47             :         AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_YUVJ422P,AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ411P,
      48             :         AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P,
      49             :         AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP, AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE
      50             :     };
      51             : 
      52           0 :     return ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
      53             : }
      54             : 
      55           0 : static av_cold void uninit(AVFilterContext *ctx)
      56             : {
      57           0 :     NContext *s = ctx->priv;
      58             : 
      59           0 :     av_freep(&s->buffer);
      60           0 : }
      61             : 
      62           0 : static inline void line_copy8(uint8_t *line, const uint8_t *srcp, int width, int mergin)
      63             : {
      64             :     int i;
      65             : 
      66           0 :     memcpy(line, srcp, width);
      67             : 
      68           0 :     for (i = mergin; i > 0; i--) {
      69           0 :         line[-i] = line[i];
      70           0 :         line[width - 1 + i] = line[width - 1 - i];
      71             :     }
      72           0 : }
      73             : 
      74           0 : static void erosion(uint8_t *dst, const uint8_t *p1, int width,
      75             :                     int threshold, const uint8_t *coordinates[], int coord)
      76             : {
      77             :     int x, i;
      78             : 
      79           0 :     for (x = 0; x < width; x++) {
      80           0 :         int min = p1[x];
      81           0 :         int limit = FFMAX(min - threshold, 0);
      82             : 
      83           0 :         for (i = 0; i < 8; i++) {
      84           0 :             if (coord & (1 << i)) {
      85           0 :                 min = FFMIN(min, *(coordinates[i] + x));
      86             :             }
      87           0 :             min = FFMAX(min, limit);
      88             :         }
      89             : 
      90           0 :         dst[x] = min;
      91             :     }
      92           0 : }
      93             : 
      94           0 : static void dilation(uint8_t *dst, const uint8_t *p1, int width,
      95             :                      int threshold, const uint8_t *coordinates[], int coord)
      96             : {
      97             :     int x, i;
      98             : 
      99           0 :     for (x = 0; x < width; x++) {
     100           0 :         int max = p1[x];
     101           0 :         int limit = FFMIN(max + threshold, 255);
     102             : 
     103           0 :         for (i = 0; i < 8; i++) {
     104           0 :             if (coord & (1 << i)) {
     105           0 :                 max = FFMAX(max, *(coordinates[i] + x));
     106             :             }
     107           0 :             max = FFMIN(max, limit);
     108             :         }
     109             : 
     110           0 :         dst[x] = max;
     111             :     }
     112           0 : }
     113             : 
     114           0 : static void deflate(uint8_t *dst, const uint8_t *p1, int width,
     115             :                     int threshold, const uint8_t *coordinates[], int coord)
     116             : {
     117             :     int x, i;
     118             : 
     119           0 :     for (x = 0; x < width; x++) {
     120           0 :         int sum = 0;
     121           0 :         int limit = FFMAX(p1[x] - threshold, 0);
     122             : 
     123           0 :         for (i = 0; i < 8; sum += *(coordinates[i++] + x));
     124             : 
     125           0 :         dst[x] = FFMAX(FFMIN(sum / 8, p1[x]), limit);
     126             :     }
     127           0 : }
     128             : 
     129           0 : static void inflate(uint8_t *dst, const uint8_t *p1, int width,
     130             :                     int threshold, const uint8_t *coordinates[], int coord)
     131             : {
     132             :     int x, i;
     133             : 
     134           0 :     for (x = 0; x < width; x++) {
     135           0 :         int sum = 0;
     136           0 :         int limit = FFMIN(p1[x] + threshold, 255);
     137             : 
     138           0 :         for (i = 0; i < 8; sum += *(coordinates[i++] + x));
     139             : 
     140           0 :         dst[x] = FFMIN(FFMAX(sum / 8, p1[x]), limit);
     141             :     }
     142           0 : }
     143             : 
     144           0 : static int config_input(AVFilterLink *inlink)
     145             : {
     146           0 :     AVFilterContext *ctx = inlink->dst;
     147           0 :     NContext *s = ctx->priv;
     148           0 :     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
     149             :     int ret;
     150             : 
     151           0 :     if ((ret = av_image_fill_linesizes(s->planewidth, inlink->format, inlink->w)) < 0)
     152           0 :         return ret;
     153             : 
     154           0 :     s->planeheight[1] = s->planeheight[2] = AV_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h);
     155           0 :     s->planeheight[0] = s->planeheight[3] = inlink->h;
     156             : 
     157           0 :     s->nb_planes = av_pix_fmt_count_planes(inlink->format);
     158           0 :     s->buffer = av_malloc(3 * (s->planewidth[0] + 32));
     159           0 :     if (!s->buffer)
     160           0 :         return AVERROR(ENOMEM);
     161             : 
     162           0 :     if (!strcmp(ctx->filter->name, "erosion"))
     163           0 :         s->filter = erosion;
     164           0 :     else if (!strcmp(ctx->filter->name, "dilation"))
     165           0 :         s->filter = dilation;
     166           0 :     else if (!strcmp(ctx->filter->name, "deflate"))
     167           0 :         s->filter = deflate;
     168           0 :     else if (!strcmp(ctx->filter->name, "inflate"))
     169           0 :         s->filter = inflate;
     170             : 
     171           0 :     return 0;
     172             : }
     173             : 
     174           0 : static int filter_frame(AVFilterLink *inlink, AVFrame *in)
     175             : {
     176           0 :     AVFilterContext *ctx = inlink->dst;
     177           0 :     AVFilterLink *outlink = ctx->outputs[0];
     178           0 :     NContext *s = ctx->priv;
     179             :     AVFrame *out;
     180             :     int plane, y;
     181             : 
     182           0 :     out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
     183           0 :     if (!out) {
     184           0 :         av_frame_free(&in);
     185           0 :         return AVERROR(ENOMEM);
     186             :     }
     187           0 :     av_frame_copy_props(out, in);
     188             : 
     189           0 :     for (plane = 0; plane < s->nb_planes; plane++) {
     190           0 :         const int threshold = s->threshold[plane];
     191             : 
     192           0 :         if (threshold) {
     193           0 :             const uint8_t *src = in->data[plane];
     194           0 :             uint8_t *dst = out->data[plane];
     195           0 :             int stride = in->linesize[plane];
     196           0 :             int height = s->planeheight[plane];
     197           0 :             int width  = s->planewidth[plane];
     198           0 :             uint8_t *p0 = s->buffer + 16;
     199           0 :             uint8_t *p1 = p0 + s->planewidth[0];
     200           0 :             uint8_t *p2 = p1 + s->planewidth[0];
     201           0 :             uint8_t *orig = p0, *end = p2;
     202             : 
     203           0 :             line_copy8(p0, src + stride, width, 1);
     204           0 :             line_copy8(p1, src, width, 1);
     205             : 
     206           0 :             for (y = 0; y < height; y++) {
     207           0 :                 const uint8_t *coordinates[] = { p0 - 1, p0, p0 + 1,
     208           0 :                                                  p1 - 1,     p1 + 1,
     209           0 :                                                  p2 - 1, p2, p2 + 1};
     210           0 :                 src += stride * (y < height - 1 ? 1 : -1);
     211           0 :                 line_copy8(p2, src, width, 1);
     212             : 
     213           0 :                 s->filter(dst, p1, width, threshold, coordinates, s->coordinates);
     214             : 
     215           0 :                 p0 = p1;
     216           0 :                 p1 = p2;
     217           0 :                 p2 = (p2 == end) ? orig: p2 + s->planewidth[0];
     218           0 :                 dst += out->linesize[plane];
     219             :             }
     220             :         } else {
     221           0 :             av_image_copy_plane(out->data[plane], out->linesize[plane],
     222           0 :                                 in->data[plane], in->linesize[plane],
     223             :                                 s->planewidth[plane], s->planeheight[plane]);
     224             :         }
     225             :     }
     226             : 
     227           0 :     av_frame_free(&in);
     228           0 :     return ff_filter_frame(outlink, out);
     229             : }
     230             : 
     231             : static const AVFilterPad neighbor_inputs[] = {
     232             :     {
     233             :         .name         = "default",
     234             :         .type         = AVMEDIA_TYPE_VIDEO,
     235             :         .filter_frame = filter_frame,
     236             :         .config_props = config_input,
     237             :     },
     238             :     { NULL }
     239             : };
     240             : 
     241             : static const AVFilterPad neighbor_outputs[] = {
     242             :     {
     243             :         .name = "default",
     244             :         .type = AVMEDIA_TYPE_VIDEO,
     245             :     },
     246             :     { NULL }
     247             : };
     248             : 
     249             : #define OFFSET(x) offsetof(NContext, x)
     250             : #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
     251             : 
     252             : #define DEFINE_NEIGHBOR_FILTER(name_, description_)          \
     253             : AVFILTER_DEFINE_CLASS(name_);                                \
     254             :                                                              \
     255             : AVFilter ff_vf_##name_ = {                                   \
     256             :     .name          = #name_,                                 \
     257             :     .description   = NULL_IF_CONFIG_SMALL(description_),     \
     258             :     .priv_size     = sizeof(NContext),                       \
     259             :     .priv_class    = &name_##_class,                         \
     260             :     .uninit        = uninit,                                 \
     261             :     .query_formats = query_formats,                          \
     262             :     .inputs        = neighbor_inputs,                        \
     263             :     .outputs       = neighbor_outputs,                       \
     264             :     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, \
     265             : }
     266             : 
     267             : #if CONFIG_EROSION_FILTER
     268             : 
     269             : static const AVOption erosion_options[] = {
     270             :     { "threshold0",  "set threshold for 1st plane",   OFFSET(threshold[0]),   AV_OPT_TYPE_INT, {.i64=65535}, 0, 65535, FLAGS },
     271             :     { "threshold1",  "set threshold for 2nd plane",   OFFSET(threshold[1]),   AV_OPT_TYPE_INT, {.i64=65535}, 0, 65535, FLAGS },
     272             :     { "threshold2",  "set threshold for 3rd plane",   OFFSET(threshold[2]),   AV_OPT_TYPE_INT, {.i64=65535}, 0, 65535, FLAGS },
     273             :     { "threshold3",  "set threshold for 4th plane",   OFFSET(threshold[3]),   AV_OPT_TYPE_INT, {.i64=65535}, 0, 65535, FLAGS },
     274             :     { "coordinates", "set coordinates",               OFFSET(coordinates),    AV_OPT_TYPE_INT, {.i64=255},   0, 255,   FLAGS },
     275             :     { NULL }
     276             : };
     277             : 
     278             : DEFINE_NEIGHBOR_FILTER(erosion, "Apply erosion effect.");
     279             : 
     280             : #endif /* CONFIG_EROSION_FILTER */
     281             : 
     282             : #if CONFIG_DILATION_FILTER
     283             : 
     284             : static const AVOption dilation_options[] = {
     285             :     { "threshold0",  "set threshold for 1st plane",   OFFSET(threshold[0]),   AV_OPT_TYPE_INT, {.i64=65535}, 0, 65535, FLAGS },
     286             :     { "threshold1",  "set threshold for 2nd plane",   OFFSET(threshold[1]),   AV_OPT_TYPE_INT, {.i64=65535}, 0, 65535, FLAGS },
     287             :     { "threshold2",  "set threshold for 3rd plane",   OFFSET(threshold[2]),   AV_OPT_TYPE_INT, {.i64=65535}, 0, 65535, FLAGS },
     288             :     { "threshold3",  "set threshold for 4th plane",   OFFSET(threshold[3]),   AV_OPT_TYPE_INT, {.i64=65535}, 0, 65535, FLAGS },
     289             :     { "coordinates", "set coordinates",               OFFSET(coordinates),    AV_OPT_TYPE_INT, {.i64=255},   0, 255,   FLAGS },
     290             :     { NULL }
     291             : };
     292             : 
     293             : DEFINE_NEIGHBOR_FILTER(dilation, "Apply dilation effect.");
     294             : 
     295             : #endif /* CONFIG_DILATION_FILTER */
     296             : 
     297             : #if CONFIG_DEFLATE_FILTER
     298             : 
     299             : static const AVOption deflate_options[] = {
     300             :     { "threshold0", "set threshold for 1st plane",   OFFSET(threshold[0]),   AV_OPT_TYPE_INT, {.i64=65535}, 0, 65535, FLAGS },
     301             :     { "threshold1", "set threshold for 2nd plane",   OFFSET(threshold[1]),   AV_OPT_TYPE_INT, {.i64=65535}, 0, 65535, FLAGS },
     302             :     { "threshold2", "set threshold for 3rd plane",   OFFSET(threshold[2]),   AV_OPT_TYPE_INT, {.i64=65535}, 0, 65535, FLAGS },
     303             :     { "threshold3", "set threshold for 4th plane",   OFFSET(threshold[3]),   AV_OPT_TYPE_INT, {.i64=65535}, 0, 65535, FLAGS },
     304             :     { NULL }
     305             : };
     306             : 
     307             : DEFINE_NEIGHBOR_FILTER(deflate, "Apply deflate effect.");
     308             : 
     309             : #endif /* CONFIG_DEFLATE_FILTER */
     310             : 
     311             : #if CONFIG_INFLATE_FILTER
     312             : 
     313             : static const AVOption inflate_options[] = {
     314             :     { "threshold0", "set threshold for 1st plane",   OFFSET(threshold[0]),   AV_OPT_TYPE_INT, {.i64=65535}, 0, 65535, FLAGS },
     315             :     { "threshold1", "set threshold for 2nd plane",   OFFSET(threshold[1]),   AV_OPT_TYPE_INT, {.i64=65535}, 0, 65535, FLAGS },
     316             :     { "threshold2", "set threshold for 3rd plane",   OFFSET(threshold[2]),   AV_OPT_TYPE_INT, {.i64=65535}, 0, 65535, FLAGS },
     317             :     { "threshold3", "set threshold for 4th plane",   OFFSET(threshold[3]),   AV_OPT_TYPE_INT, {.i64=65535}, 0, 65535, FLAGS },
     318             :     { NULL }
     319             : };
     320             : 
     321             : DEFINE_NEIGHBOR_FILTER(inflate, "Apply inflate effect.");
     322             : 
     323             : #endif /* CONFIG_INFLATE_FILTER */

Generated by: LCOV version 1.13