LCOV - code coverage report
Current view: top level - libavfilter - vf_avgblur.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 56 68 82.4 %
Date: 2017-12-13 10:57:33 Functions: 7 9 77.8 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2016 Paul B Mahol
       3             :  *
       4             :  * Permission is hereby granted, free of charge, to any person obtaining a copy
       5             :  * of this software and associated documentation files (the "Software"), to deal
       6             :  * in the Software without restriction, including without limitation the rights
       7             :  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       8             :  * copies of the Software, and to permit persons to whom the Software is
       9             :  * furnished to do so, subject to the following conditions:
      10             :  *
      11             :  * The above copyright notice and this permission notice shall be included in
      12             :  * all copies or substantial portions of the Software.
      13             :  *
      14             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      15             :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      16             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      17             :  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      18             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      19             :  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
      20             :  * SOFTWARE.
      21             :  */
      22             : 
      23             : #include "libavutil/imgutils.h"
      24             : #include "libavutil/opt.h"
      25             : #include "libavutil/pixdesc.h"
      26             : #include "avfilter.h"
      27             : #include "formats.h"
      28             : #include "internal.h"
      29             : #include "video.h"
      30             : 
      31             : typedef struct AverageBlurContext {
      32             :     const AVClass *class;
      33             : 
      34             :     int radius;
      35             :     int radiusV;
      36             :     int planes;
      37             : 
      38             :     int depth;
      39             :     int planewidth[4];
      40             :     int planeheight[4];
      41             :     float *buffer;
      42             :     int nb_planes;
      43             : 
      44             :     int (*filter_horizontally)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs);
      45             :     int (*filter_vertically)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs);
      46             : } AverageBlurContext;
      47             : 
      48             : #define OFFSET(x) offsetof(AverageBlurContext, x)
      49             : #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
      50             : 
      51             : static const AVOption avgblur_options[] = {
      52             :     { "sizeX",  "set horizontal size",  OFFSET(radius),  AV_OPT_TYPE_INT, {.i64=1},   1, 1024, FLAGS },
      53             :     { "planes", "set planes to filter", OFFSET(planes),  AV_OPT_TYPE_INT, {.i64=0xF}, 0,  0xF, FLAGS },
      54             :     { "sizeY",  "set vertical size",    OFFSET(radiusV), AV_OPT_TYPE_INT, {.i64=0},   0, 1024, FLAGS },
      55             :     { NULL }
      56             : };
      57             : 
      58             : AVFILTER_DEFINE_CLASS(avgblur);
      59             : 
      60             : typedef struct ThreadData {
      61             :     int height;
      62             :     int width;
      63             :     uint8_t *ptr;
      64             :     int linesize;
      65             : } ThreadData;
      66             : 
      67             : #define HORIZONTAL_FILTER(name, type)                                                         \
      68             : static int filter_horizontally_##name(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)\
      69             : {                                                                                             \
      70             :     AverageBlurContext *s = ctx->priv;                                                        \
      71             :     ThreadData *td = arg;                                                                     \
      72             :     const int height = td->height;                                                            \
      73             :     const int width = td->width;                                                              \
      74             :     const int slice_start = (height *  jobnr   ) / nb_jobs;                                   \
      75             :     const int slice_end   = (height * (jobnr+1)) / nb_jobs;                                   \
      76             :     const int radius = FFMIN(s->radius, width / 2);                                           \
      77             :     const int linesize = td->linesize / sizeof(type);                                         \
      78             :     float *buffer = s->buffer;                                                                \
      79             :     const type *src;                                                                          \
      80             :     float *ptr;                                                                               \
      81             :     int y, x;                                                                                 \
      82             :                                                                                               \
      83             :     /* Filter horizontally along each row */                                                  \
      84             :     for (y = slice_start; y < slice_end; y++) {                                               \
      85             :         float acc = 0;                                                                        \
      86             :         int count = 0;                                                                        \
      87             :                                                                                               \
      88             :         src = (const type *)td->ptr + linesize * y;                                           \
      89             :         ptr = buffer + width * y;                                                             \
      90             :                                                                                               \
      91             :         for (x = 0; x < radius; x++) {                                                        \
      92             :             acc += src[x];                                                                    \
      93             :         }                                                                                     \
      94             :         count += radius;                                                                      \
      95             :                                                                                               \
      96             :         for (x = 0; x <= radius; x++) {                                                       \
      97             :             acc += src[x + radius];                                                           \
      98             :             count++;                                                                          \
      99             :             ptr[x] = acc / count;                                                             \
     100             :         }                                                                                     \
     101             :                                                                                               \
     102             :         for (; x < width - radius; x++) {                                                     \
     103             :             acc += src[x + radius] - src[x - radius - 1];                                     \
     104             :             ptr[x] = acc / count;                                                             \
     105             :         }                                                                                     \
     106             :                                                                                               \
     107             :         for (; x < width; x++) {                                                              \
     108             :             acc -= src[x - radius];                                                           \
     109             :             count--;                                                                          \
     110             :             ptr[x] = acc / count;                                                             \
     111             :         }                                                                                     \
     112             :     }                                                                                         \
     113             :                                                                                               \
     114             :     return 0;                                                                                 \
     115             : }
     116             : 
     117         540 : HORIZONTAL_FILTER(8, uint8_t)
     118           0 : HORIZONTAL_FILTER(16, uint16_t)
     119             : 
     120             : #define VERTICAL_FILTER(name, type)                                                           \
     121             : static int filter_vertically_##name(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)  \
     122             : {                                                                                             \
     123             :     AverageBlurContext *s = ctx->priv;                                                        \
     124             :     ThreadData *td = arg;                                                                     \
     125             :     const int height = td->height;                                                            \
     126             :     const int width = td->width;                                                              \
     127             :     const int slice_start = (width *  jobnr   ) / nb_jobs;                                    \
     128             :     const int slice_end   = (width * (jobnr+1)) / nb_jobs;                                    \
     129             :     const int radius = FFMIN(s->radiusV, height / 2);                                         \
     130             :     const int linesize = td->linesize / sizeof(type);                                         \
     131             :     type *buffer = (type *)td->ptr;                                                           \
     132             :     const float *src;                                                                         \
     133             :     type *ptr;                                                                                \
     134             :     int i, x;                                                                                 \
     135             :                                                                                               \
     136             :     /* Filter vertically along each column */                                                 \
     137             :     for (x = slice_start; x < slice_end; x++) {                                               \
     138             :         float acc = 0;                                                                        \
     139             :         int count = 0;                                                                        \
     140             :                                                                                               \
     141             :         ptr = buffer + x;                                                                     \
     142             :         src = s->buffer + x;                                                                  \
     143             :                                                                                               \
     144             :         for (i = 0; i < radius; i++) {                                                        \
     145             :             acc += src[0];                                                                    \
     146             :             src += width;                                                                     \
     147             :         }                                                                                     \
     148             :         count += radius;                                                                      \
     149             :                                                                                               \
     150             :         src = s->buffer + x;                                                                  \
     151             :         ptr = buffer + x;                                                                     \
     152             :         for (i = 0; i <= radius; i++) {                                                       \
     153             :             acc += src[(i + radius) * width];                                                 \
     154             :             count++;                                                                          \
     155             :             ptr[i * linesize] = acc / count;                                                  \
     156             :         }                                                                                     \
     157             :                                                                                               \
     158             :         for (; i < height - radius; i++) {                                                    \
     159             :             acc += src[(i + radius) * width] - src[(i - radius - 1) * width];                 \
     160             :             ptr[i * linesize] = acc / count;                                                  \
     161             :         }                                                                                     \
     162             :                                                                                               \
     163             :         for (; i < height; i++) {                                                             \
     164             :             acc -= src[(i - radius) * width];                                                 \
     165             :             count--;                                                                          \
     166             :             ptr[i * linesize] = acc / count;                                                  \
     167             :         }                                                                                     \
     168             :     }                                                                                         \
     169             :                                                                                               \
     170             :     return 0;                                                                                 \
     171             : }
     172             : 
     173         540 : VERTICAL_FILTER(8, uint8_t)
     174           0 : VERTICAL_FILTER(16, uint16_t)
     175             : 
     176           4 : static int config_input(AVFilterLink *inlink)
     177             : {
     178           4 :     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
     179           4 :     AverageBlurContext *s = inlink->dst->priv;
     180             : 
     181           4 :     s->depth = desc->comp[0].depth;
     182           4 :     s->planewidth[1] = s->planewidth[2] = AV_CEIL_RSHIFT(inlink->w, desc->log2_chroma_w);
     183           4 :     s->planewidth[0] = s->planewidth[3] = inlink->w;
     184           4 :     s->planeheight[1] = s->planeheight[2] = AV_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h);
     185           4 :     s->planeheight[0] = s->planeheight[3] = inlink->h;
     186             : 
     187           4 :     s->nb_planes = av_pix_fmt_count_planes(inlink->format);
     188             : 
     189           4 :     s->buffer = av_malloc_array(inlink->w, inlink->h * sizeof(*s->buffer));
     190           4 :     if (!s->buffer)
     191           0 :         return AVERROR(ENOMEM);
     192             : 
     193           4 :     if (s->radiusV <= 0) {
     194           4 :         s->radiusV = s->radius;
     195             :     }
     196             : 
     197           4 :     if (s->depth == 8) {
     198           4 :         s->filter_horizontally = filter_horizontally_8;
     199           4 :         s->filter_vertically = filter_vertically_8;
     200             :     } else {
     201           0 :         s->filter_horizontally = filter_horizontally_16;
     202           0 :         s->filter_vertically = filter_vertically_16;
     203             :     }
     204             : 
     205           4 :     return 0;
     206             : }
     207             : 
     208          60 : static void averageiir2d(AVFilterContext *ctx, AVFrame *in, AVFrame *out, int plane)
     209             : {
     210          60 :     AverageBlurContext *s = ctx->priv;
     211          60 :     const int width = s->planewidth[plane];
     212          60 :     const int height = s->planeheight[plane];
     213          60 :     const int nb_threads = ff_filter_get_nb_threads(ctx);
     214             :     ThreadData td;
     215             : 
     216          60 :     td.width = width;
     217          60 :     td.height = height;
     218          60 :     td.ptr = in->data[plane];
     219          60 :     td.linesize = in->linesize[plane];
     220          60 :     ctx->internal->execute(ctx, s->filter_horizontally, &td, NULL, FFMIN(height, nb_threads));
     221          60 :     td.ptr = out->data[plane];
     222          60 :     td.linesize = out->linesize[plane];
     223          60 :     ctx->internal->execute(ctx, s->filter_vertically, &td, NULL, FFMIN(width, nb_threads));
     224          60 : }
     225             : 
     226           4 : static int query_formats(AVFilterContext *ctx)
     227             : {
     228             :     static const enum AVPixelFormat pix_fmts[] = {
     229             :         AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV440P,
     230             :         AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P,
     231             :         AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUV420P,
     232             :         AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ420P,
     233             :         AV_PIX_FMT_YUVJ411P, AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P,
     234             :         AV_PIX_FMT_YUV420P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV444P9,
     235             :         AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10,
     236             :         AV_PIX_FMT_YUV420P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV440P12,
     237             :         AV_PIX_FMT_YUV420P14, AV_PIX_FMT_YUV422P14, AV_PIX_FMT_YUV444P14,
     238             :         AV_PIX_FMT_YUV420P16, AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV444P16,
     239             :         AV_PIX_FMT_YUVA420P9, AV_PIX_FMT_YUVA422P9, AV_PIX_FMT_YUVA444P9,
     240             :         AV_PIX_FMT_YUVA420P10, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA444P10,
     241             :         AV_PIX_FMT_YUVA420P16, AV_PIX_FMT_YUVA422P16, AV_PIX_FMT_YUVA444P16,
     242             :         AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10,
     243             :         AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16,
     244             :         AV_PIX_FMT_GBRAP, AV_PIX_FMT_GBRAP10, AV_PIX_FMT_GBRAP12, AV_PIX_FMT_GBRAP16,
     245             :         AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY16,
     246             :         AV_PIX_FMT_NONE
     247             :     };
     248             : 
     249           4 :     return ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
     250             : }
     251             : 
     252          20 : static int filter_frame(AVFilterLink *inlink, AVFrame *in)
     253             : {
     254          20 :     AVFilterContext *ctx = inlink->dst;
     255          20 :     AverageBlurContext *s = ctx->priv;
     256          20 :     AVFilterLink *outlink = ctx->outputs[0];
     257             :     AVFrame *out;
     258             :     int plane;
     259             : 
     260          20 :     if (av_frame_is_writable(in)) {
     261          10 :         out = in;
     262             :     } else {
     263          10 :         out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
     264          10 :         if (!out) {
     265           0 :             av_frame_free(&in);
     266           0 :             return AVERROR(ENOMEM);
     267             :         }
     268          10 :         av_frame_copy_props(out, in);
     269             :     }
     270             : 
     271          80 :     for (plane = 0; plane < s->nb_planes; plane++) {
     272          60 :         const int height = s->planeheight[plane];
     273          60 :         const int width = s->planewidth[plane];
     274             : 
     275          60 :         if (!(s->planes & (1 << plane))) {
     276           0 :             if (out != in)
     277           0 :                 av_image_copy_plane(out->data[plane], out->linesize[plane],
     278           0 :                                     in->data[plane], in->linesize[plane],
     279           0 :                                     width * ((s->depth + 7) / 8), height);
     280           0 :             continue;
     281             :         }
     282             : 
     283          60 :         averageiir2d(ctx, in, out, plane);
     284             :     }
     285             : 
     286          20 :     if (out != in)
     287          10 :         av_frame_free(&in);
     288          20 :     return ff_filter_frame(outlink, out);
     289             : }
     290             : 
     291           8 : static av_cold void uninit(AVFilterContext *ctx)
     292             : {
     293           8 :     AverageBlurContext *s = ctx->priv;
     294             : 
     295           8 :     av_freep(&s->buffer);
     296           8 : }
     297             : 
     298             : static const AVFilterPad avgblur_inputs[] = {
     299             :     {
     300             :         .name         = "default",
     301             :         .type         = AVMEDIA_TYPE_VIDEO,
     302             :         .config_props = config_input,
     303             :         .filter_frame = filter_frame,
     304             :     },
     305             :     { NULL }
     306             : };
     307             : 
     308             : static const AVFilterPad avgblur_outputs[] = {
     309             :     {
     310             :         .name = "default",
     311             :         .type = AVMEDIA_TYPE_VIDEO,
     312             :     },
     313             :     { NULL }
     314             : };
     315             : 
     316             : AVFilter ff_vf_avgblur = {
     317             :     .name          = "avgblur",
     318             :     .description   = NULL_IF_CONFIG_SMALL("Apply Average Blur filter."),
     319             :     .priv_size     = sizeof(AverageBlurContext),
     320             :     .priv_class    = &avgblur_class,
     321             :     .uninit        = uninit,
     322             :     .query_formats = query_formats,
     323             :     .inputs        = avgblur_inputs,
     324             :     .outputs       = avgblur_outputs,
     325             :     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
     326             : };

Generated by: LCOV version 1.13