Ticket #4910: 0001-Added-nl_means-from-https-github.com-farindk-ffmpeg.patch

File 0001-Added-nl_means-from-https-github.com-farindk-ffmpeg.patch, 26.1 KB (added by dakooga, 10 years ago)

Patch file for anyone wanting to try it out...

  • configure

    From 96d4bea2bfde52bbabfded3a6400842628888850 Mon Sep 17 00:00:00 2001
    From: Steph <steph@mobilenations.com>
    Date: Sat, 19 Dec 2015 10:44:14 +0000
    Subject: [PATCH] Added nl_means from https://github.com/farindk/ffmpeg
     modified avfilter_nlmeans -> ff_vf_nlmeans
    
    ---
     configure                    |   1 +
     libavfilter/Makefile         |   1 +
     libavfilter/allfilters.c     |   1 +
     libavfilter/vf_nlmeans.c     | 572 +++++++++++++++++++++++++++++++++++++++++++
     libavfilter/vf_nlmeans.h     |  38 +++
     libavfilter/x86/Makefile     |   1 +
     libavfilter/x86/vf_nlmeans.c | 167 +++++++++++++
     7 files changed, 781 insertions(+)
     create mode 100644 libavfilter/vf_nlmeans.c
     create mode 100644 libavfilter/vf_nlmeans.h
     create mode 100644 libavfilter/x86/vf_nlmeans.c
    
    diff --git a/configure b/configure
    index dc1d2eb..91c10d5 100755
    a b fspp_filter_deps="gpl"  
    28642864geq_filter_deps="gpl"
    28652865histeq_filter_deps="gpl"
    28662866hqdn3d_filter_deps="gpl"
     2867nlmeans_filter_deps="gpl"
    28672868interlace_filter_deps="gpl"
    28682869kerndeint_filter_deps="gpl"
    28692870ladspa_filter_deps="ladspa dlopen"
  • libavfilter/Makefile

    diff --git a/libavfilter/Makefile b/libavfilter/Makefile
    index dea012a..5abfcd3 100644
    a b OBJS-$(CONFIG_HFLIP_FILTER) += vf_hflip.o  
    165165OBJS-$(CONFIG_HISTEQ_FILTER)                 += vf_histeq.o
    166166OBJS-$(CONFIG_HISTOGRAM_FILTER)              += vf_histogram.o
    167167OBJS-$(CONFIG_HQDN3D_FILTER)                 += vf_hqdn3d.o
     168OBJS-$(CONFIG_NLMEANS_FILTER)                += vf_nlmeans.o
    168169OBJS-$(CONFIG_HQX_FILTER)                    += vf_hqx.o
    169170OBJS-$(CONFIG_HSTACK_FILTER)                 += vf_stack.o framesync.o
    170171OBJS-$(CONFIG_HUE_FILTER)                    += vf_hue.o
  • libavfilter/allfilters.c

    diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
    index 131e067..7d97708 100644
    a b void avfilter_register_all(void)  
    186186    REGISTER_FILTER(HISTEQ,         histeq,         vf);
    187187    REGISTER_FILTER(HISTOGRAM,      histogram,      vf);
    188188    REGISTER_FILTER(HQDN3D,         hqdn3d,         vf);
     189    REGISTER_FILTER(NLMEANS,        nlmeans,        vf);   
    189190    REGISTER_FILTER(HQX,            hqx,            vf);
    190191    REGISTER_FILTER(HSTACK,         hstack,         vf);
    191192    REGISTER_FILTER(HUE,            hue,            vf);
  • new file libavfilter/vf_nlmeans.c

    diff --git a/libavfilter/vf_nlmeans.c b/libavfilter/vf_nlmeans.c
    new file mode 100644
    index 0000000..1658b8e
    - +  
     1/*
     2 * Copyright (c) 2013 Dirk Farin <dirk.farin@gmail.com>
     3 *
     4 * This file is part of FFmpeg.
     5 *
     6 * FFmpeg is free software; you can redistribute it and/or modify
     7 * it under the terms of the GNU General Public License as published by
     8 * the Free Software Foundation; either version 2 of the License, or
     9 * (at your option) any later version.
     10 *
     11 * FFmpeg is distributed in the hope that it will be useful,
     12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14 * GNU General Public License for more details.
     15 *
     16 * You should have received a copy of the GNU General Public License along
     17 * with FFmpeg; if not, write to the Free Software Foundation, Inc.,
     18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
     19 */
     20
     21/**
     22 * @file
     23 * Non-Local Means noise reduction filter.
     24 *
     25 * This implementation is an implementation of the paper below with
     26 * an extension to use several frames. The computation is slightly
     27 * simplified to reduce computation complexity.
     28 *
     29 * A. Buades, B. Coll, J.-M. Morel:
     30 * "A non-local algorithm for image denoising",
     31 * IEEE Computer Vision and Pattern Recognition 2005, Vol 2, pp: 60-65, 2005.
     32 */
     33
     34#include <float.h>
     35#include <stdint.h>
     36#include <string.h>
     37#include <stdlib.h>
     38#include <stddef.h>
     39#include <math.h>
     40#include <assert.h>
     41
     42#include <stdio.h>
     43
     44#include "config.h"
     45#include "libavutil/pixdesc.h"
     46
     47#include "avfilter.h"
     48#include "formats.h"
     49#include "internal.h"
     50#include "video.h"
     51#include "libavutil/opt.h"
     52
     53#include "libavfilter/vf_nlmeans.h"
     54
     55
     56
     57typedef struct
     58{
     59    uint8_t* img; // point to logical origin (0;0)
     60    int stride;
     61
     62    int w,h;
     63    int border; // extra border on all four sides
     64
     65    uint8_t* mem_start; // start of allocated memory
     66} MonoImage;
     67
     68
     69typedef enum {
     70    ImageFormat_Mono,
     71    ImageFormat_YUV420,
     72    ImageFormat_YUV422,
     73    ImageFormat_YUV444,
     74    ImageFormat_RGB
     75} ImageFormat;
     76
     77
     78typedef struct
     79{
     80    MonoImage   plane[3];
     81    ImageFormat format;
     82} ColorImage;
     83
     84
     85static void alloc_and_copy_image_with_border(MonoImage* out_img,
     86                                             const uint8_t* input_image, int input_stride,
     87                                             int w,int h, int req_border)
     88{
     89    const int border = (req_border+15)/16*16;
     90    const int out_stride = (w+2*border);
     91    const int out_total_height = (h+2*border);
     92
     93    uint8_t* const memory_ptr   = (uint8_t*)malloc(out_stride*out_total_height);
     94    uint8_t* const output_image = memory_ptr + border + border*out_stride; // logical output image origin (0,0)
     95
     96
     97    // copy main image content
     98
     99    for (int y=0;y<h;y++) {
     100        memcpy(output_image + y*out_stride, input_image+y*input_stride, w);
     101    }
     102
     103    // top/bottom borders
     104
     105    for (int k=0;k<border;k++) {
     106        memcpy(output_image-(k+1)*out_stride, input_image, w);
     107        memcpy(output_image+(h+k)*out_stride, input_image+(h-1)*input_stride, w);
     108    }
     109
     110    // left/right borders
     111
     112    for (int k=0;k<border;k++) {
     113        for (int y=-border;y<h+border;y++)
     114        {
     115            *(output_image  -k-1+y*out_stride) = output_image[y*out_stride];
     116            *(output_image+w+k  +y*out_stride) = output_image[y*out_stride+w-1];
     117        }
     118    }
     119
     120    out_img->img = output_image;
     121    out_img->mem_start = memory_ptr;
     122    out_img->stride = out_stride;
     123    out_img->w = w;
     124    out_img->h = h;
     125    out_img->border = border;
     126}
     127
     128
     129static void free_mono_image(MonoImage* img)
     130{
     131    if (img->mem_start) {
     132        free(img->mem_start);
     133        img->mem_start=NULL;
     134        img->img=NULL;
     135    }
     136}
     137
     138static void free_color_image(ColorImage* img)
     139{
     140    for (int c=0;c<3;c++) {
     141        free_mono_image(&(img->plane[c]));
     142    }
     143}
     144
     145
     146
     147
     148
     149typedef struct
     150{
     151    double h_param;
     152    int    patch_size;
     153    int    range;      // search range (must be odd number)
     154    int    n_frames;   // temporal search depth
     155} NLMeansParams;
     156
     157
     158#define MAX_NLMeansImages 32
     159
     160typedef struct {
     161    const AVClass *class;
     162
     163    int hsub,vsub;
     164
     165    NLMeansParams param;
     166
     167    ColorImage images[MAX_NLMeansImages];
     168    int        image_available[MAX_NLMeansImages];
     169
     170    NLMeansFunctions func;
     171
     172} NLMContext;
     173
     174
     175
     176static void buildIntegralImage_scalar(uint32_t* integral_image,   int integral_stride,
     177                                      const uint8_t* current_image, int current_image_stride,
     178                                      const uint8_t* compare_image, int compare_image_stride,
     179                                      int  w,int  h,
     180                                      int dx,int dy)
     181{
     182    memset(integral_image -1 -integral_stride, 0, (w+1)*sizeof(uint32_t));
     183
     184    for (int y=0;y<h;y++) {
     185        const uint8_t* p1 = current_image +  y    *current_image_stride;
     186        const uint8_t* p2 = compare_image + (y+dy)*compare_image_stride + dx;
     187        uint32_t* out = integral_image + y*integral_stride -1;
     188
     189        *out++ = 0;
     190
     191        for (int x=0;x<w;x++)
     192        {
     193            int diff = *p1++ - *p2++;
     194            *out = *(out-1) + diff * diff;
     195            out++;
     196        }
     197
     198        if (y>0) {
     199            out = integral_image + y*integral_stride;
     200
     201            for (int x=0;x<w;x++) {
     202                *out += *(out - integral_stride);
     203                out++;
     204            }
     205        }
     206    }
     207}
     208
     209
     210
     211struct PixelSum
     212{
     213    float weight_sum;
     214    float pixel_sum;
     215};
     216
     217
     218
     219static void NLMeans_mono_multi(uint8_t* out, int out_stride,
     220                               const MonoImage*const* images, int n_images,
     221                               const NLMContext* ctx)
     222{
     223    const int w = images[0]->w;
     224    const int h = images[0]->h;
     225
     226    const int n = (ctx->param.patch_size|1);
     227    const int r = (ctx->param.range     |1);
     228
     229    const int n_half = (n-1)/2;
     230    const int r_half = (r-1)/2;
     231
     232
     233    // alloc memory for temporary pixel sums
     234
     235    struct PixelSum* const tmp_data = (struct PixelSum*)calloc(w*h,sizeof(struct PixelSum));
     236
     237
     238    // allocate integral image
     239
     240    const int integral_stride = w+2*16;
     241    uint32_t* const integral_mem = (uint32_t*)malloc( integral_stride*(h+1)*sizeof(uint32_t) );
     242    uint32_t* const integral = integral_mem + integral_stride + 16;
     243
     244
     245    // precompute exponential table
     246
     247    const float weight_factor = 1.0/n/n / (ctx->param.h_param * ctx->param.h_param);
     248
     249#define EXP_TABSIZE 128
     250
     251    const int table_size=EXP_TABSIZE;
     252    const float min_weight_in_table = 0.0005;
     253
     254    float exptable[EXP_TABSIZE];
     255
     256    const float stretch = table_size/ (-log(min_weight_in_table));
     257    const float weight_fact_table = weight_factor*stretch;
     258    const int diff_max = table_size/weight_fact_table;
     259
     260    for (int i=0;i<table_size;i++) {
     261        exptable[i] = exp(-i/stretch);
     262    }
     263    exptable[table_size-1]=0;
     264
     265
     266
     267    for (int image_idx=0; image_idx<n_images; image_idx++)
     268    {
     269        // copy input image
     270
     271        const uint8_t* current_image = images[0]->img;
     272        int current_image_stride = images[0]->stride;
     273
     274        const uint8_t* compare_image = images[image_idx]->img;
     275        int compare_image_stride = images[image_idx]->stride;
     276
     277
     278        // --- iterate through all displacements ---
     279
     280        for (int dy=-r_half ; dy<=r_half ; dy++)
     281            for (int dx=-r_half ; dx<=r_half ; dx++)
     282            {
     283                // special, simple implementation for no shift (no difference -> weight 1)
     284
     285                if (dx==0 && dy==0 && image_idx==0) {
     286#pragma omp parallel for
     287                    for (int y=n_half;y<h-n+n_half;y++) {
     288                        for (int x=n_half;x<w-n+n_half;x++) {
     289                            tmp_data[y*w+x].weight_sum += 1;
     290                            tmp_data[y*w+x].pixel_sum  += current_image[y*current_image_stride+x];
     291                        }
     292                    }
     293
     294                    continue;
     295                }
     296
     297
     298                // --- regular case ---
     299
     300                ctx->func.buildIntegralImage(integral,integral_stride,
     301                                             current_image, current_image_stride,
     302                                             compare_image, compare_image_stride,
     303                                             w,h, dx,dy);
     304
     305#pragma omp parallel for
     306                for (int y=0;y<=h-n;y++) {
     307                    const uint32_t* integral_ptr1 = integral+(y  -1)*integral_stride-1;
     308                    const uint32_t* integral_ptr2 = integral+(y+n-1)*integral_stride-1;
     309
     310                    for (int x=0;x<=w-n;x++) {
     311                        const int xc = x+n_half;
     312                        const int yc = y+n_half;
     313
     314                        // patch difference
     315
     316                        int diff = (uint32_t)(integral_ptr2[n] - integral_ptr2[0] - integral_ptr1[n] + integral_ptr1[0]);
     317
     318
     319                        // sum pixel with weight
     320
     321                        if (diff<diff_max) {
     322                            int diffidx = diff*weight_fact_table;
     323
     324                            //float weight = exp(-diff*weightFact);
     325                            float weight = exptable[diffidx];
     326
     327                            tmp_data[yc*w+xc].weight_sum += weight;
     328                            tmp_data[yc*w+xc].pixel_sum  += weight * compare_image[(yc+dy)*compare_image_stride+xc+dx];
     329                        }
     330
     331                        integral_ptr1++;
     332                        integral_ptr2++;
     333                    }
     334                }
     335            }
     336    }
     337
     338
     339
     340    // --- fill output image ---
     341
     342    // copy border area
     343
     344    {
     345        const uint8_t* in  = images[0]->img;
     346        int orig_in_stride = images[0]->stride;
     347
     348        for (int y=0;       y<n_half  ;y++) { memcpy(out+y*out_stride, in+y*orig_in_stride, w); }
     349        for (int y=h-n_half;y<h       ;y++) { memcpy(out+y*out_stride, in+y*orig_in_stride, w); }
     350        for (int y=n_half  ;y<h-n_half;y++) {
     351            memcpy(out+y*out_stride,          in+y*orig_in_stride,          n_half);
     352            memcpy(out+y*out_stride+w-n_half, in+y*orig_in_stride+w-n_half, n_half);
     353        }
     354    }
     355
     356    // output main image
     357
     358    for (int y=n_half;y<h-n_half;y++) {
     359        for (int x=n_half;x<w-n_half;x++) {
     360            *(out+y*out_stride+x) = tmp_data[y*w+x].pixel_sum / tmp_data[y*w+x].weight_sum;
     361        }
     362    }
     363
     364    free(tmp_data);
     365    free(integral_mem);
     366}
     367
     368
     369static void NLMeans_color_auto(uint8_t** out, int* out_stride,
     370                               const ColorImage* img, // function takes ownership
     371                               NLMContext* ctx)
     372{
     373    assert(ctx->param.n_frames >= 1);
     374    assert(ctx->param.n_frames <= MAX_NLMeansImages);
     375
     376    // free oldest image
     377
     378    free_color_image(&ctx->images[ctx->param.n_frames-1]);
     379
     380    // shift old images one down and put new image into entry [0]
     381
     382    for (int i=ctx->param.n_frames-1; i>0; i--) {
     383        ctx->images[i] = ctx->images[i-1];
     384        ctx->image_available[i] = ctx->image_available[i-1];
     385    }
     386
     387    ctx->images[0] = *img;
     388    ctx->image_available[0] = 1;
     389
     390
     391    // process color planes separately
     392
     393    for (int c=0;c<3;c++)
     394        if (ctx->images[0].plane[c].img != NULL)
     395        {
     396            const MonoImage* images[MAX_NLMeansImages];
     397            int i;
     398            for (i=0; ctx->image_available[i]; i++) {
     399                images[i] = &ctx->images[i].plane[c];
     400            }
     401
     402            NLMeans_mono_multi(out[c], out_stride[c],
     403                               images, i, ctx);
     404        }
     405}
     406
     407
     408
     409static av_cold int init(AVFilterContext *ctx)
     410{
     411    NLMContext *nlm = ctx->priv;
     412
     413    for (int i=0;i<MAX_NLMeansImages;i++) {
     414        nlm->image_available[i] = 0;
     415    }
     416
     417
     418    nlm->func.buildIntegralImage = buildIntegralImage_scalar;
     419
     420    if (ARCH_X86) {
     421        ff_nlmeans_init_x86(&nlm->func);
     422    }
     423
     424    return 0;
     425}
     426
     427static av_cold void uninit(AVFilterContext *ctx)
     428{
     429    NLMContext *nlm = ctx->priv;
     430
     431    for (int i=0;i<MAX_NLMeansImages;i++) {
     432        if (nlm->image_available[i]) {
     433            free_color_image(&(nlm->images[i]));
     434
     435            nlm->image_available[i] = 0;
     436        }
     437    }
     438}
     439
     440static int query_formats(AVFilterContext *ctx)
     441{
     442    static const enum AVPixelFormat pix_fmts[] = {
     443        AV_PIX_FMT_YUV420P,
     444        AV_PIX_FMT_YUV422P,
     445        AV_PIX_FMT_YUV444P,
     446        AV_PIX_FMT_YUV410P,
     447        AV_PIX_FMT_YUV411P,
     448        AV_PIX_FMT_YUV440P,
     449
     450        AV_PIX_FMT_YUVJ420P,
     451        AV_PIX_FMT_YUVJ422P,
     452        AV_PIX_FMT_YUVJ444P,
     453        AV_PIX_FMT_YUVJ440P,
     454
     455        AV_PIX_FMT_NONE
     456    };
     457
     458    ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
     459
     460    return 0;
     461}
     462
     463static int config_input(AVFilterLink *inlink)
     464{
     465    NLMContext *nlm = inlink->dst->priv;
     466    const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
     467
     468    nlm->hsub  = desc->log2_chroma_w;
     469    nlm->vsub  = desc->log2_chroma_h;
     470
     471    return 0;
     472}
     473
     474static int filter_frame(AVFilterLink *inlink, AVFrame *in)
     475{
     476    NLMContext *nlm = inlink->dst->priv;
     477    AVFilterLink *outlink = inlink->dst->outputs[0];
     478
     479    ColorImage bordered_image;
     480
     481    AVFrame *out;
     482    int direct, c;
     483
     484    if (av_frame_is_writable(in)) {
     485        direct = 1;
     486        out = in;
     487    } else {
     488        direct = 0;
     489        out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
     490        if (!out) {
     491            av_frame_free(&in);
     492            return AVERROR(ENOMEM);
     493        }
     494
     495        av_frame_copy_props(out, in);
     496    }
     497
     498
     499    // extend image with border
     500
     501    for (c = 0; c < 3; c++) {
     502        int w = FF_CEIL_RSHIFT(in->width,  (!!c * nlm->hsub));
     503        int h = FF_CEIL_RSHIFT(in->height, (!!c * nlm->vsub));
     504        int border = nlm->param.range/2;
     505
     506        alloc_and_copy_image_with_border(&bordered_image.plane[c],
     507                                         in->data[c], in->linesize[c],
     508                                         w,h,border);
     509    }
     510
     511    NLMeans_color_auto(out->data, out->linesize,
     512                       &bordered_image,
     513                       nlm);
     514
     515
     516    if (!direct)
     517        av_frame_free(&in);
     518
     519    return ff_filter_frame(outlink, out);
     520}
     521
     522#define OFFSET(x) offsetof(NLMContext, x)
     523#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM
     524static const AVOption options[] = {
     525    { "h",           "averaging weight decay parameter", OFFSET(param.h_param),    AV_OPT_TYPE_DOUBLE, { .dbl = 8.0 }, 0.1, 100.0, FLAGS },
     526    { "patchsize",   "patch width/height",               OFFSET(param.patch_size), AV_OPT_TYPE_INT,    { .i64 = 7   },   3, 255,   FLAGS },
     527    { "range",       "search range",                     OFFSET(param.range),      AV_OPT_TYPE_INT,    { .i64 = 3   },   1, 255,   FLAGS },
     528    { "temporal",    "temporal search range",            OFFSET(param.n_frames),   AV_OPT_TYPE_INT,    { .i64 = 2   },   1, MAX_NLMeansImages,   FLAGS },
     529    { NULL },
     530};
     531
     532
     533static const AVClass nlm_class = {
     534    .class_name = "nlm",
     535    .item_name  = av_default_item_name,
     536    .option     = options,
     537    .version    = LIBAVUTIL_VERSION_INT,
     538};
     539
     540
     541static const AVFilterPad avfilter_vf_nlm_inputs[] = {
     542    {
     543        .name         = "default",
     544        .type         = AVMEDIA_TYPE_VIDEO,
     545        .config_props = config_input,
     546        .filter_frame = filter_frame,
     547    },
     548    { NULL }
     549};
     550
     551
     552static const AVFilterPad avfilter_vf_nlm_outputs[] = {
     553    {
     554        .name = "default",
     555        .type = AVMEDIA_TYPE_VIDEO
     556    },
     557    { NULL }
     558};
     559
     560AVFilter ff_vf_nlmeans = {
     561    .name          = "nlmeans",
     562    .description   = NULL_IF_CONFIG_SMALL("Apply a Non-Local Means filter."),
     563
     564    .priv_size     = sizeof(NLMContext),
     565    .priv_class    = &nlm_class,
     566    .init          = init,
     567    .uninit        = uninit,
     568    .query_formats = query_formats,
     569
     570    .inputs    = avfilter_vf_nlm_inputs,
     571    .outputs   = avfilter_vf_nlm_outputs,
     572};
  • new file libavfilter/vf_nlmeans.h

    diff --git a/libavfilter/vf_nlmeans.h b/libavfilter/vf_nlmeans.h
    new file mode 100644
    index 0000000..1e864b7
    - +  
     1/*
     2 * Copyright (c) 2013 Dirk Farin <dirk.farin@gmail.com>
     3 *
     4 * This file is part of FFmpeg.
     5 *
     6 * FFmpeg is free software; you can redistribute it and/or modify
     7 * it under the terms of the GNU General Public License as published by
     8 * the Free Software Foundation; either version 2 of the License, or
     9 * (at your option) any later version.
     10 *
     11 * FFmpeg is distributed in the hope that it will be useful,
     12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14 * GNU General Public License for more details.
     15 *
     16 * You should have received a copy of the GNU General Public License along
     17 * with FFmpeg; if not, write to the Free Software Foundation, Inc.,
     18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
     19 */
     20
     21#ifndef AVFILTER_VF_NLMEANS_H
     22#define AVFILTER_VF_NLMEANS_H
     23
     24#include <stdint.h>
     25
     26
     27typedef struct
     28{
     29    void (*buildIntegralImage)(uint32_t* integral,   int integral_stride32,
     30                               const uint8_t* currimage, int currstride,
     31                               const uint8_t* image, int stride,
     32                               int  w,int  h,
     33                               int dx,int dy);
     34} NLMeansFunctions;
     35
     36av_cold void ff_nlmeans_init_x86(NLMeansFunctions*);
     37
     38#endif /* AVFILTER_VF_NLMEANS_H */
  • libavfilter/x86/Makefile

    diff --git a/libavfilter/x86/Makefile b/libavfilter/x86/Makefile
    index 33de380..d17f380 100644
    a b OBJS-$(CONFIG_EQ_FILTER) += x86/vf_eq.o  
    33OBJS-$(CONFIG_FSPP_FILTER)                   += x86/vf_fspp_init.o
    44OBJS-$(CONFIG_GRADFUN_FILTER)                += x86/vf_gradfun_init.o
    55OBJS-$(CONFIG_HQDN3D_FILTER)                 += x86/vf_hqdn3d_init.o
     6OBJS-$(CONFIG_NLMEANS_FILTER)                += x86/vf_nlmeans.o
    67OBJS-$(CONFIG_IDET_FILTER)                   += x86/vf_idet_init.o
    78OBJS-$(CONFIG_INTERLACE_FILTER)              += x86/vf_interlace_init.o
    89OBJS-$(CONFIG_MASKEDMERGE_FILTER)            += x86/vf_maskedmerge_init.o
  • new file libavfilter/x86/vf_nlmeans.c

    diff --git a/libavfilter/x86/vf_nlmeans.c b/libavfilter/x86/vf_nlmeans.c
    new file mode 100644
    index 0000000..095d530
    - +  
     1/*
     2 * Copyright (c) 2013 Dirk Farin <dirk.farin@gmail.com>
     3 *
     4 * This file is part of FFmpeg.
     5 *
     6 * FFmpeg is free software; you can redistribute it and/or modify
     7 * it under the terms of the GNU General Public License as published by
     8 * the Free Software Foundation; either version 2 of the License, or
     9 * (at your option) any later version.
     10 *
     11 * FFmpeg is distributed in the hope that it will be useful,
     12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14 * GNU General Public License for more details.
     15 *
     16 * You should have received a copy of the GNU General Public License along
     17 * with FFmpeg; if not, write to the Free Software Foundation, Inc.,
     18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
     19 */
     20
     21
     22#include "libavutil/cpu.h"
     23#include "libavutil/x86/cpu.h"
     24#include "libavfilter/vf_nlmeans.h"
     25
     26#include <emmintrin.h>
     27#include <string.h>
     28
     29
     30/* Input image must be large enough to have valid pixels for the offset (dx,dy).
     31   I.e., with (dx,dy)=(-10,8), x-value up to -10 and y-values up to (h-1)+8 will be accessed.
     32   The integral image will be access with (x,y) in [-1,w)x[-1,h).
     33
     34   Note also that we use 32bit for the integral image even though the values may overflow
     35   that range. However, the modulo-arithmetic used when computing the block sums later
     36   will be still correct when the block size is not too large.
     37 */
     38static void buildIntegralImage_SSE(uint32_t* integral_image, int integral_stride,
     39                                   const uint8_t* current_image, int current_image_stride,
     40                                   const uint8_t* compare_image, int compare_image_stride,
     41                                   int  w,int  h,
     42                                   int dx,int dy)
     43{
     44    const __m128i zero = _mm_set1_epi8(0);
     45
     46
     47    memset(integral_image -1 -integral_stride, 0, (w+1)*sizeof(uint32_t));
     48
     49    for (int y=0;y<h;y++) {
     50        const uint8_t* p1 = current_image +  y    *current_image_stride;
     51        const uint8_t* p2 = compare_image + (y+dy)*compare_image_stride + dx;
     52
     53        uint32_t* out = integral_image + y*integral_stride-1;
     54
     55        __m128i prevadd = _mm_set1_epi32(0);
     56        const int pixels_step = 16;
     57
     58        *out++ = 0;
     59
     60        for (int x=0 ; x<w ; x+=pixels_step)
     61        {
     62            __m128i pa, pb;
     63            __m128i pla, plb;
     64            __m128i ldiff, lldiff, lhdiff;
     65            __m128i ltmp,htmp;
     66            __m128i ladd,hadd;
     67            __m128i pha,phb;
     68            __m128i hdiff,hldiff,hhdiff;
     69            __m128i l2tmp,h2tmp;
     70
     71
     72
     73            pa = _mm_loadu_si128((__m128i*)p1);
     74            pb = _mm_loadu_si128((__m128i*)p2);
     75
     76            pla = _mm_unpacklo_epi8(pa,zero);
     77            plb = _mm_unpacklo_epi8(pb,zero);
     78
     79            ldiff = _mm_sub_epi16(pla,plb);
     80            ldiff = _mm_mullo_epi16(ldiff,ldiff);
     81
     82            lldiff = _mm_unpacklo_epi16(ldiff,zero);
     83            lhdiff = _mm_unpackhi_epi16(ldiff,zero);
     84
     85            ltmp = _mm_slli_si128(lldiff, 4);
     86            lldiff = _mm_add_epi32(lldiff, ltmp);
     87            ltmp = _mm_slli_si128(lldiff, 8);
     88            lldiff = _mm_add_epi32(lldiff, ltmp);
     89            lldiff = _mm_add_epi32(lldiff, prevadd);
     90
     91            ladd = _mm_shuffle_epi32(lldiff, 0xff);
     92
     93            htmp = _mm_slli_si128(lhdiff, 4);
     94            lhdiff = _mm_add_epi32(lhdiff, htmp);
     95            htmp = _mm_slli_si128(lhdiff, 8);
     96            lhdiff = _mm_add_epi32(lhdiff, htmp);
     97            lhdiff = _mm_add_epi32(lhdiff, ladd);
     98
     99            prevadd = _mm_shuffle_epi32(lhdiff, 0xff);
     100
     101            _mm_store_si128((__m128i*)(out),  lldiff);
     102            _mm_store_si128((__m128i*)(out+4),lhdiff);
     103
     104
     105
     106            pha = _mm_unpackhi_epi8(pa,zero);
     107            phb = _mm_unpackhi_epi8(pb,zero);
     108            hdiff = _mm_sub_epi16(pha,phb);
     109
     110            hdiff = _mm_mullo_epi16(hdiff,hdiff);
     111
     112            hldiff = _mm_unpacklo_epi16(hdiff,zero);
     113            hhdiff = _mm_unpackhi_epi16(hdiff,zero);
     114            l2tmp = _mm_slli_si128(hldiff, 4);
     115            hldiff = _mm_add_epi32(hldiff, l2tmp);
     116            l2tmp = _mm_slli_si128(hldiff, 8);
     117            hldiff = _mm_add_epi32(hldiff, l2tmp);
     118            hldiff = _mm_add_epi32(hldiff, prevadd);
     119            hadd = _mm_shuffle_epi32(hldiff, 0xff);
     120            h2tmp = _mm_slli_si128(hhdiff, 4);
     121            hhdiff = _mm_add_epi32(hhdiff, h2tmp);
     122            h2tmp = _mm_slli_si128(hhdiff, 8);
     123            hhdiff = _mm_add_epi32(hhdiff, h2tmp);
     124            hhdiff = _mm_add_epi32(hhdiff, hadd);
     125
     126            prevadd = _mm_shuffle_epi32(hhdiff, 0xff);
     127
     128            _mm_store_si128((__m128i*)(out+8), hldiff);
     129            _mm_store_si128((__m128i*)(out+12),hhdiff);
     130
     131
     132            out+=pixels_step;
     133            p1 +=pixels_step;
     134            p2 +=pixels_step;
     135        }
     136
     137        if (y>0) {
     138            out = integral_image + y*integral_stride;
     139
     140            for (int x=0 ; x<w ; x+=pixels_step) {
     141                *((__m128i*)out) = _mm_add_epi32(*(__m128i*)(out-integral_stride),
     142                                                 *(__m128i*)(out));
     143
     144                *((__m128i*)(out+4)) = _mm_add_epi32(*(__m128i*)(out+4-integral_stride),
     145                                                     *(__m128i*)(out+4));
     146
     147                *((__m128i*)(out+8)) = _mm_add_epi32(*(__m128i*)(out+8-integral_stride),
     148                                                     *(__m128i*)(out+8));
     149
     150                *((__m128i*)(out+12)) = _mm_add_epi32(*(__m128i*)(out+12-integral_stride),
     151                                                      *(__m128i*)(out+12));
     152
     153                out += 4*4;
     154            }
     155        }
     156    }
     157}
     158
     159
     160av_cold void ff_nlmeans_init_x86(NLMeansFunctions* func)
     161{
     162  int cpu_flags = av_get_cpu_flags();
     163
     164  if (EXTERNAL_SSE2(cpu_flags)) {
     165    func->buildIntegralImage = buildIntegralImage_SSE;
     166  }
     167}