LCOV - code coverage report
Current view: top level - libavfilter - vf_noise.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 145 0.0 %
Date: 2017-12-16 21:16:39 Functions: 0 10 0.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2002 Michael Niedermayer <michaelni@gmx.at>
       3             :  * Copyright (c) 2013 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             : /**
      23             :  * @file
      24             :  * noise generator
      25             :  */
      26             : 
      27             : #include "libavutil/opt.h"
      28             : #include "libavutil/imgutils.h"
      29             : #include "libavutil/lfg.h"
      30             : #include "libavutil/parseutils.h"
      31             : #include "libavutil/pixdesc.h"
      32             : #include "avfilter.h"
      33             : #include "formats.h"
      34             : #include "internal.h"
      35             : #include "vf_noise.h"
      36             : #include "video.h"
      37             : 
      38             : typedef struct ThreadData {
      39             :     AVFrame *in, *out;
      40             : } ThreadData;
      41             : 
      42             : #define OFFSET(x) offsetof(NoiseContext, x)
      43             : #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
      44             : 
      45             : #define NOISE_PARAMS(name, x, param)                                                                                             \
      46             :     {#name"_seed", "set component #"#x" noise seed", OFFSET(param.seed), AV_OPT_TYPE_INT, {.i64=-1}, -1, INT_MAX, FLAGS},        \
      47             :     {#name"_strength", "set component #"#x" strength", OFFSET(param.strength), AV_OPT_TYPE_INT, {.i64=0}, 0, 100, FLAGS},        \
      48             :     {#name"s",         "set component #"#x" strength", OFFSET(param.strength), AV_OPT_TYPE_INT, {.i64=0}, 0, 100, FLAGS},        \
      49             :     {#name"_flags", "set component #"#x" flags", OFFSET(param.flags), AV_OPT_TYPE_FLAGS, {.i64=0}, 0, 31, FLAGS, #name"_flags"}, \
      50             :     {#name"f", "set component #"#x" flags", OFFSET(param.flags), AV_OPT_TYPE_FLAGS, {.i64=0}, 0, 31, FLAGS, #name"_flags"},      \
      51             :     {"a", "averaged noise", 0, AV_OPT_TYPE_CONST, {.i64=NOISE_AVERAGED}, 0, 0, FLAGS, #name"_flags"},                            \
      52             :     {"p", "(semi)regular pattern", 0, AV_OPT_TYPE_CONST, {.i64=NOISE_PATTERN},  0, 0, FLAGS, #name"_flags"},                     \
      53             :     {"t", "temporal noise", 0, AV_OPT_TYPE_CONST, {.i64=NOISE_TEMPORAL}, 0, 0, FLAGS, #name"_flags"},                            \
      54             :     {"u", "uniform noise",  0, AV_OPT_TYPE_CONST, {.i64=NOISE_UNIFORM},  0, 0, FLAGS, #name"_flags"},
      55             : 
      56             : static const AVOption noise_options[] = {
      57             :     NOISE_PARAMS(all, 0, all)
      58             :     NOISE_PARAMS(c0,  0, param[0])
      59             :     NOISE_PARAMS(c1,  1, param[1])
      60             :     NOISE_PARAMS(c2,  2, param[2])
      61             :     NOISE_PARAMS(c3,  3, param[3])
      62             :     {NULL}
      63             : };
      64             : 
      65             : AVFILTER_DEFINE_CLASS(noise);
      66             : 
      67             : static const int8_t patt[4] = { -1, 0, 1, 0 };
      68             : 
      69             : #define RAND_N(range) ((int) ((double) range * av_lfg_get(lfg) / (UINT_MAX + 1.0)))
      70           0 : static av_cold int init_noise(NoiseContext *n, int comp)
      71             : {
      72           0 :     int8_t *noise = av_malloc(MAX_NOISE * sizeof(int8_t));
      73           0 :     FilterParams *fp = &n->param[comp];
      74           0 :     AVLFG *lfg = &n->param[comp].lfg;
      75           0 :     int strength = fp->strength;
      76           0 :     int flags = fp->flags;
      77             :     int i, j;
      78             : 
      79           0 :     if (!noise)
      80           0 :         return AVERROR(ENOMEM);
      81             : 
      82           0 :     av_lfg_init(&fp->lfg, fp->seed + comp*31415U);
      83             : 
      84           0 :     for (i = 0, j = 0; i < MAX_NOISE; i++, j++) {
      85           0 :         if (flags & NOISE_UNIFORM) {
      86           0 :             if (flags & NOISE_AVERAGED) {
      87           0 :                 if (flags & NOISE_PATTERN) {
      88           0 :                     noise[i] = (RAND_N(strength) - strength / 2) / 6
      89           0 :                         + patt[j % 4] * strength * 0.25 / 3;
      90             :                 } else {
      91           0 :                     noise[i] = (RAND_N(strength) - strength / 2) / 3;
      92             :                 }
      93             :             } else {
      94           0 :                 if (flags & NOISE_PATTERN) {
      95           0 :                     noise[i] = (RAND_N(strength) - strength / 2) / 2
      96           0 :                         + patt[j % 4] * strength * 0.25;
      97             :                 } else {
      98           0 :                     noise[i] = RAND_N(strength) - strength / 2;
      99             :                 }
     100             :             }
     101             :         } else {
     102             :             double x1, x2, w, y1;
     103             :             do {
     104           0 :                 x1 = 2.0 * av_lfg_get(lfg) / (float)UINT_MAX - 1.0;
     105           0 :                 x2 = 2.0 * av_lfg_get(lfg) / (float)UINT_MAX - 1.0;
     106           0 :                 w = x1 * x1 + x2 * x2;
     107           0 :             } while (w >= 1.0);
     108             : 
     109           0 :             w   = sqrt((-2.0 * log(w)) / w);
     110           0 :             y1  = x1 * w;
     111           0 :             y1 *= strength / sqrt(3.0);
     112           0 :             if (flags & NOISE_PATTERN) {
     113           0 :                 y1 /= 2;
     114           0 :                 y1 += patt[j % 4] * strength * 0.35;
     115             :             }
     116           0 :             y1 = av_clipf(y1, -128, 127);
     117           0 :             if (flags & NOISE_AVERAGED)
     118           0 :                 y1 /= 3.0;
     119           0 :             noise[i] = (int)y1;
     120             :         }
     121           0 :         if (RAND_N(6) == 0)
     122           0 :             j--;
     123             :     }
     124             : 
     125           0 :     for (i = 0; i < MAX_RES; i++)
     126           0 :         for (j = 0; j < 3; j++)
     127           0 :             fp->prev_shift[i][j] = noise + (av_lfg_get(lfg) & (MAX_SHIFT - 1));
     128             : 
     129           0 :     fp->noise = noise;
     130           0 :     return 0;
     131             : }
     132             : 
     133           0 : static int query_formats(AVFilterContext *ctx)
     134             : {
     135           0 :     AVFilterFormats *formats = NULL;
     136             :     int fmt, ret;
     137             : 
     138           0 :     for (fmt = 0; av_pix_fmt_desc_get(fmt); fmt++) {
     139           0 :         const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt);
     140           0 :         if (desc->flags & AV_PIX_FMT_FLAG_PLANAR && !(desc->comp[0].depth & 7)
     141           0 :             && (ret = ff_add_format(&formats, fmt)) < 0)
     142           0 :                 return ret;
     143             :     }
     144             : 
     145           0 :     return ff_set_common_formats(ctx, formats);
     146             : }
     147             : 
     148           0 : static int config_input(AVFilterLink *inlink)
     149             : {
     150           0 :     NoiseContext *n = inlink->dst->priv;
     151           0 :     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
     152             :     int ret;
     153             : 
     154           0 :     n->nb_planes = av_pix_fmt_count_planes(inlink->format);
     155             : 
     156           0 :     if ((ret = av_image_fill_linesizes(n->bytewidth, inlink->format, inlink->w)) < 0)
     157           0 :         return ret;
     158             : 
     159           0 :     n->height[1] = n->height[2] = AV_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h);
     160           0 :     n->height[0] = n->height[3] = inlink->h;
     161             : 
     162           0 :     return 0;
     163             : }
     164             : 
     165           0 : void ff_line_noise_c(uint8_t *dst, const uint8_t *src, const int8_t *noise,
     166             :                      int len, int shift)
     167             : {
     168             :     int i;
     169             : 
     170           0 :     noise += shift;
     171           0 :     for (i = 0; i < len; i++) {
     172           0 :         int v = src[i] + noise[i];
     173             : 
     174           0 :         dst[i] = av_clip_uint8(v);
     175             :     }
     176           0 : }
     177             : 
     178           0 : void ff_line_noise_avg_c(uint8_t *dst, const uint8_t *src,
     179             :                          int len, const int8_t * const *shift)
     180             : {
     181             :     int i;
     182           0 :     const int8_t *src2 = (const int8_t*)src;
     183             : 
     184           0 :     for (i = 0; i < len; i++) {
     185           0 :         const int n = shift[0][i] + shift[1][i] + shift[2][i];
     186           0 :         dst[i] = src2[i] + ((n * src2[i]) >> 7);
     187             :     }
     188           0 : }
     189             : 
     190           0 : static void noise(uint8_t *dst, const uint8_t *src,
     191             :                   int dst_linesize, int src_linesize,
     192             :                   int width, int start, int end, NoiseContext *n, int comp)
     193             : {
     194           0 :     FilterParams *p = &n->param[comp];
     195           0 :     int8_t *noise = p->noise;
     196           0 :     const int flags = p->flags;
     197             :     int y;
     198             : 
     199           0 :     if (!noise) {
     200           0 :         if (dst != src)
     201           0 :             av_image_copy_plane(dst, dst_linesize, src, src_linesize, width, end - start);
     202           0 :         return;
     203             :     }
     204             : 
     205           0 :     for (y = start; y < end; y++) {
     206           0 :         const int ix = y & (MAX_RES - 1);
     207             :         int x;
     208           0 :         for (x=0; x < width; x+= MAX_RES) {
     209           0 :             int w = FFMIN(width - x, MAX_RES);
     210           0 :             int shift = p->rand_shift[ix];
     211             : 
     212           0 :             if (flags & NOISE_AVERAGED) {
     213           0 :                 n->line_noise_avg(dst + x, src + x, w, (const int8_t**)p->prev_shift[ix]);
     214           0 :                 p->prev_shift[ix][shift & 3] = noise + shift;
     215             :             } else {
     216           0 :                 n->line_noise(dst + x, src + x, noise, w, shift);
     217             :             }
     218             :         }
     219           0 :         dst += dst_linesize;
     220           0 :         src += src_linesize;
     221             :     }
     222             : }
     223             : 
     224           0 : static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
     225             : {
     226           0 :     NoiseContext *s = ctx->priv;
     227           0 :     ThreadData *td = arg;
     228             :     int plane;
     229             : 
     230           0 :     for (plane = 0; plane < s->nb_planes; plane++) {
     231           0 :         const int height = s->height[plane];
     232           0 :         const int start  = (height *  jobnr   ) / nb_jobs;
     233           0 :         const int end    = (height * (jobnr+1)) / nb_jobs;
     234           0 :         noise(td->out->data[plane] + start * td->out->linesize[plane],
     235           0 :               td->in->data[plane]  + start * td->in->linesize[plane],
     236           0 :               td->out->linesize[plane], td->in->linesize[plane],
     237             :               s->bytewidth[plane], start, end, s, plane);
     238             :     }
     239           0 :     return 0;
     240             : }
     241             : 
     242           0 : static int filter_frame(AVFilterLink *inlink, AVFrame *inpicref)
     243             : {
     244           0 :     AVFilterContext *ctx = inlink->dst;
     245           0 :     AVFilterLink *outlink = ctx->outputs[0];
     246           0 :     NoiseContext *n = ctx->priv;
     247             :     ThreadData td;
     248             :     AVFrame *out;
     249             :     int comp, i;
     250             : 
     251           0 :     if (av_frame_is_writable(inpicref)) {
     252           0 :         out = inpicref;
     253             :     } else {
     254           0 :         out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
     255           0 :         if (!out) {
     256           0 :             av_frame_free(&inpicref);
     257           0 :             return AVERROR(ENOMEM);
     258             :         }
     259           0 :         av_frame_copy_props(out, inpicref);
     260             :     }
     261             : 
     262           0 :     for (comp = 0; comp < 4; comp++) {
     263           0 :         FilterParams *fp = &n->param[comp];
     264             : 
     265           0 :         if ((!fp->rand_shift_init || (fp->flags & NOISE_TEMPORAL)) && fp->strength) {
     266             : 
     267           0 :             for (i = 0; i < MAX_RES; i++) {
     268           0 :                 fp->rand_shift[i] = av_lfg_get(&fp->lfg) & (MAX_SHIFT - 1);
     269             :             }
     270           0 :             fp->rand_shift_init = 1;
     271             :         }
     272             :     }
     273             : 
     274           0 :     td.in = inpicref; td.out = out;
     275           0 :     ctx->internal->execute(ctx, filter_slice, &td, NULL, FFMIN(n->height[0], ff_filter_get_nb_threads(ctx)));
     276           0 :     emms_c();
     277             : 
     278           0 :     if (inpicref != out)
     279           0 :         av_frame_free(&inpicref);
     280           0 :     return ff_filter_frame(outlink, out);
     281             : }
     282             : 
     283           0 : static av_cold int init(AVFilterContext *ctx)
     284             : {
     285           0 :     NoiseContext *n = ctx->priv;
     286             :     int ret, i;
     287             : 
     288           0 :     for (i = 0; i < 4; i++) {
     289           0 :         if (n->all.seed >= 0)
     290           0 :             n->param[i].seed = n->all.seed;
     291             :         else
     292           0 :             n->param[i].seed = 123457;
     293           0 :         if (n->all.strength)
     294           0 :             n->param[i].strength = n->all.strength;
     295           0 :         if (n->all.flags)
     296           0 :             n->param[i].flags = n->all.flags;
     297             :     }
     298             : 
     299           0 :     for (i = 0; i < 4; i++) {
     300           0 :         if (n->param[i].strength && ((ret = init_noise(n, i)) < 0))
     301           0 :             return ret;
     302             :     }
     303             : 
     304           0 :     n->line_noise     = ff_line_noise_c;
     305           0 :     n->line_noise_avg = ff_line_noise_avg_c;
     306             : 
     307             :     if (ARCH_X86)
     308           0 :         ff_noise_init_x86(n);
     309             : 
     310           0 :     return 0;
     311             : }
     312             : 
     313           0 : static av_cold void uninit(AVFilterContext *ctx)
     314             : {
     315           0 :     NoiseContext *n = ctx->priv;
     316             :     int i;
     317             : 
     318           0 :     for (i = 0; i < 4; i++)
     319           0 :         av_freep(&n->param[i].noise);
     320           0 : }
     321             : 
     322             : static const AVFilterPad noise_inputs[] = {
     323             :     {
     324             :         .name         = "default",
     325             :         .type         = AVMEDIA_TYPE_VIDEO,
     326             :         .filter_frame = filter_frame,
     327             :         .config_props = config_input,
     328             :     },
     329             :     { NULL }
     330             : };
     331             : 
     332             : static const AVFilterPad noise_outputs[] = {
     333             :     {
     334             :         .name = "default",
     335             :         .type = AVMEDIA_TYPE_VIDEO,
     336             :     },
     337             :     { NULL }
     338             : };
     339             : 
     340             : AVFilter ff_vf_noise = {
     341             :     .name          = "noise",
     342             :     .description   = NULL_IF_CONFIG_SMALL("Add noise."),
     343             :     .priv_size     = sizeof(NoiseContext),
     344             :     .init          = init,
     345             :     .uninit        = uninit,
     346             :     .query_formats = query_formats,
     347             :     .inputs        = noise_inputs,
     348             :     .outputs       = noise_outputs,
     349             :     .priv_class    = &noise_class,
     350             :     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
     351             : };

Generated by: LCOV version 1.13