LCOV - code coverage report
Current view: top level - libavfilter - vf_gradfun.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 96 107 89.7 %
Date: 2017-12-10 21:22:29 Functions: 8 8 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2010 Nolan Lum <nol888@gmail.com>
       3             :  * Copyright (c) 2009 Loren Merritt <lorenm@u.washington.edu>
       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             : /**
      23             :  * @file
      24             :  * gradfun debanding filter, ported from MPlayer
      25             :  * libmpcodecs/vf_gradfun.c
      26             :  *
      27             :  * Apply a boxblur debanding algorithm (based on the gradfun2db
      28             :  * AviSynth filter by prunedtree).
      29             :  * For each pixel, if it is within the threshold of the blurred value, make it
      30             :  * closer. So now we have a smoothed and higher bitdepth version of all the
      31             :  * shallow gradients, while leaving detailed areas untouched.
      32             :  * Dither it back to 8bit.
      33             :  */
      34             : 
      35             : #include "libavutil/imgutils.h"
      36             : #include "libavutil/common.h"
      37             : #include "libavutil/cpu.h"
      38             : #include "libavutil/opt.h"
      39             : #include "libavutil/pixdesc.h"
      40             : #include "avfilter.h"
      41             : #include "formats.h"
      42             : #include "gradfun.h"
      43             : #include "internal.h"
      44             : #include "video.h"
      45             : 
      46             : DECLARE_ALIGNED(16, static const uint16_t, dither)[8][8] = {
      47             :     {0x00,0x60,0x18,0x78,0x06,0x66,0x1E,0x7E},
      48             :     {0x40,0x20,0x58,0x38,0x46,0x26,0x5E,0x3E},
      49             :     {0x10,0x70,0x08,0x68,0x16,0x76,0x0E,0x6E},
      50             :     {0x50,0x30,0x48,0x28,0x56,0x36,0x4E,0x2E},
      51             :     {0x04,0x64,0x1C,0x7C,0x02,0x62,0x1A,0x7A},
      52             :     {0x44,0x24,0x5C,0x3C,0x42,0x22,0x5A,0x3A},
      53             :     {0x14,0x74,0x0C,0x6C,0x12,0x72,0x0A,0x6A},
      54             :     {0x54,0x34,0x4C,0x2C,0x52,0x32,0x4A,0x2A},
      55             : };
      56             : 
      57       32160 : void ff_gradfun_filter_line_c(uint8_t *dst, const uint8_t *src, const uint16_t *dc, int width, int thresh, const uint16_t *dithers)
      58             : {
      59             :     int x;
      60     8710560 :     for (x = 0; x < width; dc += x & 1, x++) {
      61     8678400 :         int pix = src[x] << 7;
      62     8678400 :         int delta = dc[0] - pix;
      63     8678400 :         int m = abs(delta) * thresh >> 16;
      64     8678400 :         m = FFMAX(0, 127 - m);
      65     8678400 :         m = m * m * delta >> 14;
      66     8678400 :         pix += m + dithers[x & 7];
      67     8678400 :         dst[x] = av_clip_uint8(pix >> 7);
      68             :     }
      69       32160 : }
      70             : 
      71       16080 : void ff_gradfun_blur_line_c(uint16_t *dc, uint16_t *buf, const uint16_t *buf1, const uint8_t *src, int src_linesize, int width)
      72             : {
      73             :     int x, v, old;
      74     2185680 :     for (x = 0; x < width; x++) {
      75     2169600 :         v = buf1[x] + src[2 * x] + src[2 * x + 1] + src[2 * x + src_linesize] + src[2 * x + 1 + src_linesize];
      76     2169600 :         old = buf[x];
      77     2169600 :         buf[x] = v;
      78     2169600 :         dc[x] = v - old;
      79             :     }
      80       16080 : }
      81             : 
      82         164 : static void filter(GradFunContext *ctx, uint8_t *dst, const uint8_t *src, int width, int height, int dst_linesize, int src_linesize, int r)
      83             : {
      84         164 :     int bstride = FFALIGN(width, 16) / 2;
      85             :     int y;
      86         164 :     uint32_t dc_factor = (1 << 21) / (r * r);
      87         164 :     uint16_t *dc = ctx->buf + 16;
      88         164 :     uint16_t *buf = ctx->buf + bstride + 32;
      89         164 :     int thresh = ctx->thresh;
      90             : 
      91         164 :     memset(dc, 0, (bstride + 16) * sizeof(*buf));
      92        1876 :     for (y = 0; y < r; y++)
      93        1712 :         ctx->blur_line(dc, buf + y * bstride, buf + (y - 1) * bstride, src + 2 * y * src_linesize, src_linesize, width / 2);
      94             :     for (;;) {
      95       30284 :         if (y < height - r) {
      96       14368 :             int mod = ((y + r) / 2) % r;
      97       14368 :             uint16_t *buf0 = buf + mod * bstride;
      98       14368 :             uint16_t *buf1 = buf + (mod ? mod - 1 : r - 1) * bstride;
      99             :             int x, v;
     100       14368 :             ctx->blur_line(dc, buf0, buf1, src + (y + r) * src_linesize, src_linesize, width / 2);
     101      180512 :             for (x = v = 0; x < r; x++)
     102      166144 :                 v += dc[x];
     103     1788704 :             for (; x < width / 2; x++) {
     104     1774336 :                 v += dc[x] - dc[x-r];
     105     1774336 :                 dc[x-r] = v * dc_factor >> 16;
     106             :             }
     107       97440 :             for (; x < (width + r + 1) / 2; x++)
     108       83072 :                 dc[x-r] = v * dc_factor >> 16;
     109       97440 :             for (x = -r / 2; x < 0; x++)
     110       83072 :                 dc[x] = dc[0];
     111             :         }
     112       15224 :         if (y == r) {
     113        1876 :             for (y = 0; y < r; y++)
     114        1712 :                 ctx->filter_line(dst + y * dst_linesize, src + y * src_linesize, dc - r / 2, width, thresh, dither[y & 7]);
     115             :         }
     116       15224 :         ctx->filter_line(dst + y * dst_linesize, src + y * src_linesize, dc - r / 2, width, thresh, dither[y & 7]);
     117       15224 :         if (++y >= height) break;
     118       15224 :         ctx->filter_line(dst + y * dst_linesize, src + y * src_linesize, dc - r / 2, width, thresh, dither[y & 7]);
     119       15224 :         if (++y >= height) break;
     120             :     }
     121         164 :     emms_c();
     122         164 : }
     123             : 
     124           2 : static av_cold int init(AVFilterContext *ctx)
     125             : {
     126           2 :     GradFunContext *s = ctx->priv;
     127             : 
     128           2 :     s->thresh  = (1 << 15) / s->strength;
     129           2 :     s->radius  = av_clip((s->radius + 1) & ~1, 4, 32);
     130             : 
     131           2 :     s->blur_line   = ff_gradfun_blur_line_c;
     132           2 :     s->filter_line = ff_gradfun_filter_line_c;
     133             : 
     134             :     if (ARCH_X86)
     135           2 :         ff_gradfun_init_x86(s);
     136             : 
     137           2 :     av_log(ctx, AV_LOG_VERBOSE, "threshold:%.2f radius:%d\n", s->strength, s->radius);
     138             : 
     139           2 :     return 0;
     140             : }
     141             : 
     142           2 : static av_cold void uninit(AVFilterContext *ctx)
     143             : {
     144           2 :     GradFunContext *s = ctx->priv;
     145           2 :     av_freep(&s->buf);
     146           2 : }
     147             : 
     148           2 : static int query_formats(AVFilterContext *ctx)
     149             : {
     150             :     static const enum AVPixelFormat pix_fmts[] = {
     151             :         AV_PIX_FMT_YUV410P,            AV_PIX_FMT_YUV420P,
     152             :         AV_PIX_FMT_GRAY8,              AV_PIX_FMT_YUV444P,
     153             :         AV_PIX_FMT_YUV422P,            AV_PIX_FMT_YUV411P,
     154             :         AV_PIX_FMT_YUV440P,
     155             :         AV_PIX_FMT_GBRP,
     156             :         AV_PIX_FMT_NONE
     157             :     };
     158           2 :     AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
     159           2 :     if (!fmts_list)
     160           0 :         return AVERROR(ENOMEM);
     161           2 :     return ff_set_common_formats(ctx, fmts_list);
     162             : }
     163             : 
     164           2 : static int config_input(AVFilterLink *inlink)
     165             : {
     166           2 :     GradFunContext *s = inlink->dst->priv;
     167           2 :     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
     168           2 :     int hsub = desc->log2_chroma_w;
     169           2 :     int vsub = desc->log2_chroma_h;
     170             : 
     171           2 :     av_freep(&s->buf);
     172           2 :     s->buf = av_calloc((FFALIGN(inlink->w, 16) * (s->radius + 1) / 2 + 32), sizeof(*s->buf));
     173           2 :     if (!s->buf)
     174           0 :         return AVERROR(ENOMEM);
     175             : 
     176           2 :     s->chroma_w = AV_CEIL_RSHIFT(inlink->w, hsub);
     177           2 :     s->chroma_h = AV_CEIL_RSHIFT(inlink->h, vsub);
     178           2 :     s->chroma_r = av_clip(((((s->radius >> hsub) + (s->radius >> vsub)) / 2 ) + 1) & ~1, 4, 32);
     179             : 
     180           2 :     return 0;
     181             : }
     182             : 
     183          64 : static int filter_frame(AVFilterLink *inlink, AVFrame *in)
     184             : {
     185          64 :     GradFunContext *s = inlink->dst->priv;
     186          64 :     AVFilterLink *outlink = inlink->dst->outputs[0];
     187             :     AVFrame *out;
     188             :     int p, direct;
     189             : 
     190          64 :     if (av_frame_is_writable(in)) {
     191          64 :         direct = 1;
     192          64 :         out = in;
     193             :     } else {
     194           0 :         direct = 0;
     195           0 :         out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
     196           0 :         if (!out) {
     197           0 :             av_frame_free(&in);
     198           0 :             return AVERROR(ENOMEM);
     199             :         }
     200           0 :         av_frame_copy_props(out, in);
     201             :     }
     202             : 
     203         228 :     for (p = 0; p < 4 && in->data[p] && in->linesize[p]; p++) {
     204         164 :         int w = inlink->w;
     205         164 :         int h = inlink->h;
     206         164 :         int r = s->radius;
     207         164 :         if (p) {
     208         100 :             w = s->chroma_w;
     209         100 :             h = s->chroma_h;
     210         100 :             r = s->chroma_r;
     211             :         }
     212             : 
     213         164 :         if (FFMIN(w, h) > 2 * r)
     214         164 :             filter(s, out->data[p], in->data[p], w, h, out->linesize[p], in->linesize[p], r);
     215           0 :         else if (out->data[p] != in->data[p])
     216           0 :             av_image_copy_plane(out->data[p], out->linesize[p], in->data[p], in->linesize[p], w, h);
     217             :     }
     218             : 
     219          64 :     if (!direct)
     220           0 :         av_frame_free(&in);
     221             : 
     222          64 :     return ff_filter_frame(outlink, out);
     223             : }
     224             : 
     225             : #define OFFSET(x) offsetof(GradFunContext, x)
     226             : #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
     227             : 
     228             : static const AVOption gradfun_options[] = {
     229             :     { "strength", "The maximum amount by which the filter will change any one pixel.", OFFSET(strength), AV_OPT_TYPE_FLOAT, { .dbl = 1.2 }, 0.51, 64, FLAGS },
     230             :     { "radius",   "The neighborhood to fit the gradient to.",                          OFFSET(radius),   AV_OPT_TYPE_INT,   { .i64 = 16  }, 4,    32, FLAGS },
     231             :     { NULL }
     232             : };
     233             : 
     234             : AVFILTER_DEFINE_CLASS(gradfun);
     235             : 
     236             : static const AVFilterPad avfilter_vf_gradfun_inputs[] = {
     237             :     {
     238             :         .name         = "default",
     239             :         .type         = AVMEDIA_TYPE_VIDEO,
     240             :         .config_props = config_input,
     241             :         .filter_frame = filter_frame,
     242             :     },
     243             :     { NULL }
     244             : };
     245             : 
     246             : static const AVFilterPad avfilter_vf_gradfun_outputs[] = {
     247             :     {
     248             :         .name = "default",
     249             :         .type = AVMEDIA_TYPE_VIDEO,
     250             :     },
     251             :     { NULL }
     252             : };
     253             : 
     254             : AVFilter ff_vf_gradfun = {
     255             :     .name          = "gradfun",
     256             :     .description   = NULL_IF_CONFIG_SMALL("Debands video quickly using gradients."),
     257             :     .priv_size     = sizeof(GradFunContext),
     258             :     .priv_class    = &gradfun_class,
     259             :     .init          = init,
     260             :     .uninit        = uninit,
     261             :     .query_formats = query_formats,
     262             :     .inputs        = avfilter_vf_gradfun_inputs,
     263             :     .outputs       = avfilter_vf_gradfun_outputs,
     264             :     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
     265             : };

Generated by: LCOV version 1.13