Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  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 "libavutil/x86/asm.h"
  33. #include "avfilter.h"
  34. #include "formats.h"
  35. #include "internal.h"
  36. #include "video.h"
  37.  
  38. #define MAX_NOISE 5120
  39. #define MAX_SHIFT 1024
  40. #define MAX_RES (MAX_NOISE-MAX_SHIFT)
  41.  
  42. #define NOISE_UNIFORM  1
  43. #define NOISE_TEMPORAL 2
  44. #define NOISE_AVERAGED 8
  45. #define NOISE_PATTERN  16
  46.  
  47. typedef struct {
  48.     int strength;
  49.     unsigned flags;
  50.     AVLFG lfg;
  51.     int seed;
  52.     int8_t *noise;
  53.     int8_t *prev_shift[MAX_RES][3];
  54. } FilterParams;
  55.  
  56. typedef struct {
  57.     const AVClass *class;
  58.     int nb_planes;
  59.     int bytewidth[4];
  60.     int height[4];
  61.     FilterParams all;
  62.     FilterParams param[4];
  63.     int rand_shift[MAX_RES];
  64.     int rand_shift_init;
  65.     void (*line_noise)(uint8_t *dst, const uint8_t *src, int8_t *noise, int len, int shift);
  66.     void (*line_noise_avg)(uint8_t *dst, const uint8_t *src, int len, int8_t **shift);
  67. } NoiseContext;
  68.  
  69. typedef struct ThreadData {
  70.     AVFrame *in, *out;
  71. } ThreadData;
  72.  
  73. #define OFFSET(x) offsetof(NoiseContext, x)
  74. #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
  75.  
  76. #define NOISE_PARAMS(name, x, param)                                                                                             \
  77.     {#name"_seed", "set component #"#x" noise seed", OFFSET(param.seed), AV_OPT_TYPE_INT, {.i64=-1}, -1, INT_MAX, FLAGS},        \
  78.     {#name"_strength", "set component #"#x" strength", OFFSET(param.strength), AV_OPT_TYPE_INT, {.i64=0}, 0, 100, FLAGS},        \
  79.     {#name"s",         "set component #"#x" strength", OFFSET(param.strength), AV_OPT_TYPE_INT, {.i64=0}, 0, 100, FLAGS},        \
  80.     {#name"_flags", "set component #"#x" flags", OFFSET(param.flags), AV_OPT_TYPE_FLAGS, {.i64=0}, 0, 31, FLAGS, #name"_flags"}, \
  81.     {#name"f", "set component #"#x" flags", OFFSET(param.flags), AV_OPT_TYPE_FLAGS, {.i64=0}, 0, 31, FLAGS, #name"_flags"},      \
  82.     {"a", "averaged noise", 0, AV_OPT_TYPE_CONST, {.i64=NOISE_AVERAGED}, 0, 0, FLAGS, #name"_flags"},                            \
  83.     {"p", "(semi)regular pattern", 0, AV_OPT_TYPE_CONST, {.i64=NOISE_PATTERN},  0, 0, FLAGS, #name"_flags"},                     \
  84.     {"t", "temporal noise", 0, AV_OPT_TYPE_CONST, {.i64=NOISE_TEMPORAL}, 0, 0, FLAGS, #name"_flags"},                            \
  85.     {"u", "uniform noise",  0, AV_OPT_TYPE_CONST, {.i64=NOISE_UNIFORM},  0, 0, FLAGS, #name"_flags"},
  86.  
  87. static const AVOption noise_options[] = {
  88.     NOISE_PARAMS(all, 0, all)
  89.     NOISE_PARAMS(c0,  0, param[0])
  90.     NOISE_PARAMS(c1,  1, param[1])
  91.     NOISE_PARAMS(c2,  2, param[2])
  92.     NOISE_PARAMS(c3,  3, param[3])
  93.     {NULL}
  94. };
  95.  
  96. AVFILTER_DEFINE_CLASS(noise);
  97.  
  98. static const int8_t patt[4] = { -1, 0, 1, 0 };
  99.  
  100. #define RAND_N(range) ((int) ((double) range * av_lfg_get(lfg) / (UINT_MAX + 1.0)))
  101. static av_cold int init_noise(NoiseContext *n, int comp)
  102. {
  103.     int8_t *noise = av_malloc(MAX_NOISE * sizeof(int8_t));
  104.     FilterParams *fp = &n->param[comp];
  105.     AVLFG *lfg = &n->param[comp].lfg;
  106.     int strength = fp->strength;
  107.     int flags = fp->flags;
  108.     int i, j;
  109.  
  110.     if (!noise)
  111.         return AVERROR(ENOMEM);
  112.  
  113.     av_lfg_init(&fp->lfg, fp->seed);
  114.  
  115.     for (i = 0, j = 0; i < MAX_NOISE; i++, j++) {
  116.         if (flags & NOISE_UNIFORM) {
  117.             if (flags & NOISE_AVERAGED) {
  118.                 if (flags & NOISE_PATTERN) {
  119.                     noise[i] = (RAND_N(strength) - strength / 2) / 6
  120.                         + patt[j % 4] * strength * 0.25 / 3;
  121.                 } else {
  122.                     noise[i] = (RAND_N(strength) - strength / 2) / 3;
  123.                 }
  124.             } else {
  125.                 if (flags & NOISE_PATTERN) {
  126.                     noise[i] = (RAND_N(strength) - strength / 2) / 2
  127.                         + patt[j % 4] * strength * 0.25;
  128.                 } else {
  129.                     noise[i] = RAND_N(strength) - strength / 2;
  130.                 }
  131.             }
  132.         } else {
  133.             double x1, x2, w, y1;
  134.             do {
  135.                 x1 = 2.0 * av_lfg_get(lfg) / (float)UINT_MAX - 1.0;
  136.                 x2 = 2.0 * av_lfg_get(lfg) / (float)UINT_MAX - 1.0;
  137.                 w = x1 * x1 + x2 * x2;
  138.             } while (w >= 1.0);
  139.  
  140.             w   = sqrt((-2.0 * log(w)) / w);
  141.             y1  = x1 * w;
  142.             y1 *= strength / sqrt(3.0);
  143.             if (flags & NOISE_PATTERN) {
  144.                 y1 /= 2;
  145.                 y1 += patt[j % 4] * strength * 0.35;
  146.             }
  147.             y1 = av_clipf(y1, -128, 127);
  148.             if (flags & NOISE_AVERAGED)
  149.                 y1 /= 3.0;
  150.             noise[i] = (int)y1;
  151.         }
  152.         if (RAND_N(6) == 0)
  153.             j--;
  154.     }
  155.  
  156.     for (i = 0; i < MAX_RES; i++)
  157.         for (j = 0; j < 3; j++)
  158.             fp->prev_shift[i][j] = noise + (av_lfg_get(lfg) & (MAX_SHIFT - 1));
  159.  
  160.     if (!n->rand_shift_init) {
  161.         for (i = 0; i < MAX_RES; i++)
  162.             n->rand_shift[i] = av_lfg_get(lfg) & (MAX_SHIFT - 1);
  163.         n->rand_shift_init = 1;
  164.     }
  165.  
  166.     fp->noise = noise;
  167.     return 0;
  168. }
  169.  
  170. static int query_formats(AVFilterContext *ctx)
  171. {
  172.     AVFilterFormats *formats = NULL;
  173.     int fmt;
  174.  
  175.     for (fmt = 0; fmt < AV_PIX_FMT_NB; fmt++) {
  176.         const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt);
  177.         if (desc->flags & AV_PIX_FMT_FLAG_PLANAR && !((desc->comp[0].depth_minus1 + 1) & 7))
  178.             ff_add_format(&formats, fmt);
  179.     }
  180.  
  181.     ff_set_common_formats(ctx, formats);
  182.     return 0;
  183. }
  184.  
  185. static int config_input(AVFilterLink *inlink)
  186. {
  187.     NoiseContext *n = inlink->dst->priv;
  188.     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
  189.     int ret;
  190.  
  191.     n->nb_planes = av_pix_fmt_count_planes(inlink->format);
  192.  
  193.     if ((ret = av_image_fill_linesizes(n->bytewidth, inlink->format, inlink->w)) < 0)
  194.         return ret;
  195.  
  196.     n->height[1] = n->height[2] = FF_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h);
  197.     n->height[0] = n->height[3] = inlink->h;
  198.  
  199.     return 0;
  200. }
  201.  
  202. static inline void line_noise_c(uint8_t *dst, const uint8_t *src, int8_t *noise,
  203.                        int len, int shift)
  204. {
  205.     int i;
  206.  
  207.     noise += shift;
  208.     for (i = 0; i < len; i++) {
  209.         int v = src[i] + noise[i];
  210.  
  211.         dst[i] = av_clip_uint8(v);
  212.     }
  213. }
  214.  
  215. #define ASMALIGN(ZEROBITS) ".p2align " #ZEROBITS "\n\t"
  216.  
  217. static void line_noise_mmx(uint8_t *dst, const uint8_t *src,
  218.                            int8_t *noise, int len, int shift)
  219. {
  220. #if HAVE_MMX_INLINE
  221.     x86_reg mmx_len= len&(~7);
  222.     noise+=shift;
  223.  
  224.     __asm__ volatile(
  225.             "mov %3, %%"REG_a"               \n\t"
  226.             "pcmpeqb %%mm7, %%mm7            \n\t"
  227.             "psllw $15, %%mm7                \n\t"
  228.             "packsswb %%mm7, %%mm7           \n\t"
  229.             ASMALIGN(4)
  230.             "1:                              \n\t"
  231.             "movq (%0, %%"REG_a"), %%mm0     \n\t"
  232.             "movq (%1, %%"REG_a"), %%mm1     \n\t"
  233.             "pxor %%mm7, %%mm0               \n\t"
  234.             "paddsb %%mm1, %%mm0             \n\t"
  235.             "pxor %%mm7, %%mm0               \n\t"
  236.             "movq %%mm0, (%2, %%"REG_a")     \n\t"
  237.             "add $8, %%"REG_a"               \n\t"
  238.             " js 1b                          \n\t"
  239.             :: "r" (src+mmx_len), "r" (noise+mmx_len), "r" (dst+mmx_len), "g" (-mmx_len)
  240.             : "%"REG_a
  241.     );
  242.     if (mmx_len!=len)
  243.         line_noise_c(dst+mmx_len, src+mmx_len, noise+mmx_len, len-mmx_len, 0);
  244. #endif
  245. }
  246.  
  247. static void line_noise_mmxext(uint8_t *dst, const uint8_t *src,
  248.                               int8_t *noise, int len, int shift)
  249. {
  250. #if HAVE_MMXEXT_INLINE
  251.     x86_reg mmx_len= len&(~7);
  252.     noise+=shift;
  253.  
  254.     __asm__ volatile(
  255.             "mov %3, %%"REG_a"                \n\t"
  256.             "pcmpeqb %%mm7, %%mm7             \n\t"
  257.             "psllw $15, %%mm7                 \n\t"
  258.             "packsswb %%mm7, %%mm7            \n\t"
  259.             ASMALIGN(4)
  260.             "1:                               \n\t"
  261.             "movq (%0, %%"REG_a"), %%mm0      \n\t"
  262.             "movq (%1, %%"REG_a"), %%mm1      \n\t"
  263.             "pxor %%mm7, %%mm0                \n\t"
  264.             "paddsb %%mm1, %%mm0              \n\t"
  265.             "pxor %%mm7, %%mm0                \n\t"
  266.             "movntq %%mm0, (%2, %%"REG_a")    \n\t"
  267.             "add $8, %%"REG_a"                \n\t"
  268.             " js 1b                           \n\t"
  269.             :: "r" (src+mmx_len), "r" (noise+mmx_len), "r" (dst+mmx_len), "g" (-mmx_len)
  270.             : "%"REG_a
  271.             );
  272.     if (mmx_len != len)
  273.         line_noise_c(dst+mmx_len, src+mmx_len, noise+mmx_len, len-mmx_len, 0);
  274. #endif
  275. }
  276.  
  277. static inline void line_noise_avg_c(uint8_t *dst, const uint8_t *src,
  278.                            int len, int8_t **shift)
  279. {
  280.     int i;
  281.     int8_t *src2 = (int8_t*)src;
  282.  
  283.     for (i = 0; i < len; i++) {
  284.         const int n = shift[0][i] + shift[1][i] + shift[2][i];
  285.         dst[i] = src2[i] + ((n * src2[i]) >> 7);
  286.     }
  287. }
  288.  
  289. static inline void line_noise_avg_mmx(uint8_t *dst, const uint8_t *src,
  290.                                       int len, int8_t **shift)
  291. {
  292. #if HAVE_MMX_INLINE
  293.     x86_reg mmx_len= len&(~7);
  294.  
  295.     __asm__ volatile(
  296.             "mov %5, %%"REG_a"              \n\t"
  297.             ASMALIGN(4)
  298.             "1:                             \n\t"
  299.             "movq (%1, %%"REG_a"), %%mm1    \n\t"
  300.             "movq (%0, %%"REG_a"), %%mm0    \n\t"
  301.             "paddb (%2, %%"REG_a"), %%mm1   \n\t"
  302.             "paddb (%3, %%"REG_a"), %%mm1   \n\t"
  303.             "movq %%mm0, %%mm2              \n\t"
  304.             "movq %%mm1, %%mm3              \n\t"
  305.             "punpcklbw %%mm0, %%mm0         \n\t"
  306.             "punpckhbw %%mm2, %%mm2         \n\t"
  307.             "punpcklbw %%mm1, %%mm1         \n\t"
  308.             "punpckhbw %%mm3, %%mm3         \n\t"
  309.             "pmulhw %%mm0, %%mm1            \n\t"
  310.             "pmulhw %%mm2, %%mm3            \n\t"
  311.             "paddw %%mm1, %%mm1             \n\t"
  312.             "paddw %%mm3, %%mm3             \n\t"
  313.             "paddw %%mm0, %%mm1             \n\t"
  314.             "paddw %%mm2, %%mm3             \n\t"
  315.             "psrlw $8, %%mm1                \n\t"
  316.             "psrlw $8, %%mm3                \n\t"
  317.             "packuswb %%mm3, %%mm1          \n\t"
  318.             "movq %%mm1, (%4, %%"REG_a")    \n\t"
  319.             "add $8, %%"REG_a"              \n\t"
  320.             " js 1b                         \n\t"
  321.             :: "r" (src+mmx_len), "r" (shift[0]+mmx_len), "r" (shift[1]+mmx_len), "r" (shift[2]+mmx_len),
  322.                "r" (dst+mmx_len), "g" (-mmx_len)
  323.             : "%"REG_a
  324.         );
  325.  
  326.     if (mmx_len != len){
  327.         int8_t *shift2[3]={shift[0]+mmx_len, shift[1]+mmx_len, shift[2]+mmx_len};
  328.         line_noise_avg_c(dst+mmx_len, src+mmx_len, len-mmx_len, shift2);
  329.     }
  330. #endif
  331. }
  332.  
  333. static void noise(uint8_t *dst, const uint8_t *src,
  334.                   int dst_linesize, int src_linesize,
  335.                   int width, int start, int end, NoiseContext *n, int comp)
  336. {
  337.     FilterParams *p = &n->param[comp];
  338.     int8_t *noise = p->noise;
  339.     const int flags = p->flags;
  340.     AVLFG *lfg = &p->lfg;
  341.     int shift, y;
  342.  
  343.     if (!noise) {
  344.         if (dst != src)
  345.             av_image_copy_plane(dst, dst_linesize, src, src_linesize, width, end - start);
  346.         return;
  347.     }
  348.  
  349.     for (y = start; y < end; y++) {
  350.         const int ix = y & (MAX_RES - 1);
  351.         if (flags & NOISE_TEMPORAL)
  352.             shift = av_lfg_get(lfg) & (MAX_SHIFT - 1);
  353.         else
  354.             shift = n->rand_shift[ix];
  355.  
  356.         if (flags & NOISE_AVERAGED) {
  357.             n->line_noise_avg(dst, src, width, p->prev_shift[ix]);
  358.             p->prev_shift[ix][shift & 3] = noise + shift;
  359.         } else {
  360.             n->line_noise(dst, src, noise, width, shift);
  361.         }
  362.         dst += dst_linesize;
  363.         src += src_linesize;
  364.     }
  365. }
  366.  
  367. static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
  368. {
  369.     NoiseContext *s = ctx->priv;
  370.     ThreadData *td = arg;
  371.     int plane;
  372.  
  373.     for (plane = 0; plane < s->nb_planes; plane++) {
  374.         const int height = s->height[plane];
  375.         const int start  = (height *  jobnr   ) / nb_jobs;
  376.         const int end    = (height * (jobnr+1)) / nb_jobs;
  377.         noise(td->out->data[plane] + start * td->out->linesize[plane],
  378.               td->in->data[plane]  + start * td->in->linesize[plane],
  379.               td->out->linesize[plane], td->in->linesize[plane],
  380.               s->bytewidth[plane], start, end, s, plane);
  381.     }
  382.     return 0;
  383. }
  384.  
  385. static int filter_frame(AVFilterLink *inlink, AVFrame *inpicref)
  386. {
  387.     AVFilterContext *ctx = inlink->dst;
  388.     AVFilterLink *outlink = ctx->outputs[0];
  389.     NoiseContext *n = ctx->priv;
  390.     ThreadData td;
  391.     AVFrame *out;
  392.  
  393.     if (av_frame_is_writable(inpicref)) {
  394.         out = inpicref;
  395.     } else {
  396.         out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
  397.         if (!out) {
  398.             av_frame_free(&inpicref);
  399.             return AVERROR(ENOMEM);
  400.         }
  401.         av_frame_copy_props(out, inpicref);
  402.     }
  403.  
  404.     td.in = inpicref; td.out = out;
  405.     ctx->internal->execute(ctx, filter_slice, &td, NULL, FFMIN(n->height[0], ctx->graph->nb_threads));
  406.     emms_c();
  407.  
  408.     if (inpicref != out)
  409.         av_frame_free(&inpicref);
  410.     return ff_filter_frame(outlink, out);
  411. }
  412.  
  413. static av_cold int init(AVFilterContext *ctx)
  414. {
  415.     NoiseContext *n = ctx->priv;
  416.     int ret, i;
  417.     int cpu_flags = av_get_cpu_flags();
  418.  
  419.     for (i = 0; i < 4; i++) {
  420.         if (n->all.seed >= 0)
  421.             n->param[i].seed = n->all.seed;
  422.         else
  423.             n->param[i].seed = 123457;
  424.         if (n->all.strength)
  425.             n->param[i].strength = n->all.strength;
  426.         if (n->all.flags)
  427.             n->param[i].flags = n->all.flags;
  428.     }
  429.  
  430.     for (i = 0; i < 4; i++) {
  431.         if (n->param[i].strength && ((ret = init_noise(n, i)) < 0))
  432.             return ret;
  433.     }
  434.  
  435.     n->line_noise     = line_noise_c;
  436.     n->line_noise_avg = line_noise_avg_c;
  437.  
  438.     if (HAVE_MMX_INLINE &&
  439.         cpu_flags & AV_CPU_FLAG_MMX) {
  440.         n->line_noise = line_noise_mmx;
  441.         n->line_noise_avg = line_noise_avg_mmx;
  442.     }
  443.     if (HAVE_MMXEXT_INLINE &&
  444.         cpu_flags & AV_CPU_FLAG_MMXEXT)
  445.         n->line_noise = line_noise_mmxext;
  446.  
  447.     return 0;
  448. }
  449.  
  450. static av_cold void uninit(AVFilterContext *ctx)
  451. {
  452.     NoiseContext *n = ctx->priv;
  453.     int i;
  454.  
  455.     for (i = 0; i < 4; i++)
  456.         av_freep(&n->param[i].noise);
  457. }
  458.  
  459. static const AVFilterPad noise_inputs[] = {
  460.     {
  461.         .name         = "default",
  462.         .type         = AVMEDIA_TYPE_VIDEO,
  463.         .filter_frame = filter_frame,
  464.         .config_props = config_input,
  465.     },
  466.     { NULL }
  467. };
  468.  
  469. static const AVFilterPad noise_outputs[] = {
  470.     {
  471.         .name = "default",
  472.         .type = AVMEDIA_TYPE_VIDEO,
  473.     },
  474.     { NULL }
  475. };
  476.  
  477. AVFilter avfilter_vf_noise = {
  478.     .name          = "noise",
  479.     .description   = NULL_IF_CONFIG_SMALL("Add noise."),
  480.     .priv_size     = sizeof(NoiseContext),
  481.     .init          = init,
  482.     .uninit        = uninit,
  483.     .query_formats = query_formats,
  484.     .inputs        = noise_inputs,
  485.     .outputs       = noise_outputs,
  486.     .priv_class    = &noise_class,
  487.     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
  488. };
  489.