avfilter/af_afftdn: add alias for sample_noise end
[ffmpeg.git] / libavfilter / vf_mpdecimate.c
index 2e386f7..c9a9cb3 100644 (file)
 
 #include "libavutil/opt.h"
 #include "libavutil/pixdesc.h"
+#include "libavutil/pixelutils.h"
 #include "libavutil/timestamp.h"
-#include "libavcodec/dsputil.h"
 #include "avfilter.h"
 #include "internal.h"
 #include "formats.h"
 #include "video.h"
 
-typedef struct {
+typedef struct DecimateContext {
     const AVClass *class;
     int lo, hi;                    ///< lower and higher threshold number of differences
                                    ///< values for 8x8 blocks
@@ -48,8 +48,7 @@ typedef struct {
 
     int hsub, vsub;                ///< chroma subsampling values
     AVFrame *ref;                  ///< reference picture
-    DSPContext dspctx;             ///< context providing optimized diff routines
-    AVCodecContext *avctx;         ///< codec context required for the DSPContext
+    av_pixelutils_sad_fn sad;      ///< sum of absolute difference function
 } DecimateContext;
 
 #define OFFSET(x) offsetof(DecimateContext, x)
@@ -70,33 +69,36 @@ AVFILTER_DEFINE_CLASS(mpdecimate);
  * Return 1 if the two planes are different, 0 otherwise.
  */
 static int diff_planes(AVFilterContext *ctx,
-                       uint8_t *cur, uint8_t *ref, int linesize,
+                       uint8_t *cur, int cur_linesize,
+                       uint8_t *ref, int ref_linesize,
                        int w, int h)
 {
     DecimateContext *decimate = ctx->priv;
-    DSPContext *dspctx = &decimate->dspctx;
 
     int x, y;
     int d, c = 0;
     int t = (w/16)*(h/16)*decimate->frac;
-    int16_t block[8*8];
 
     /* compute difference for blocks of 8x8 bytes */
     for (y = 0; y < h-7; y += 4) {
         for (x = 8; x < w-7; x += 4) {
-            dspctx->diff_pixels(block,
-                                cur+x+y*linesize,
-                                ref+x+y*linesize, linesize);
-            d = dspctx->sum_abs_dctelem(block);
-            if (d > decimate->hi)
+            d = decimate->sad(cur + y*cur_linesize + x, cur_linesize,
+                              ref + y*ref_linesize + x, ref_linesize);
+            if (d > decimate->hi) {
+                av_log(ctx, AV_LOG_DEBUG, "%d>=hi ", d);
                 return 1;
+            }
             if (d > decimate->lo) {
                 c++;
-                if (c > t)
+                if (c > t) {
+                    av_log(ctx, AV_LOG_DEBUG, "lo:%d>=%d ", c, t);
                     return 1;
+                }
             }
         }
     }
+
+    av_log(ctx, AV_LOG_DEBUG, "lo:%d<%d ", c, t);
     return 0;
 }
 
@@ -118,14 +120,24 @@ static int decimate_frame(AVFilterContext *ctx,
         return 0;
 
     for (plane = 0; ref->data[plane] && ref->linesize[plane]; plane++) {
+        /* use 8x8 SAD even on subsampled planes.  The blocks won't match up with
+         * luma blocks, but hopefully nobody is depending on this to catch
+         * localized chroma changes that wouldn't exceed the thresholds when
+         * diluted by using what's effectively a larger block size.
+         */
         int vsub = plane == 1 || plane == 2 ? decimate->vsub : 0;
         int hsub = plane == 1 || plane == 2 ? decimate->hsub : 0;
         if (diff_planes(ctx,
-                        cur->data[plane], ref->data[plane], ref->linesize[plane],
-                        ref->width>>hsub, ref->height>>vsub))
+                        cur->data[plane], cur->linesize[plane],
+                        ref->data[plane], ref->linesize[plane],
+                        AV_CEIL_RSHIFT(ref->width,  hsub),
+                        AV_CEIL_RSHIFT(ref->height, vsub))) {
+            emms_c();
             return 0;
+        }
     }
 
+    emms_c();
     return 1;
 }
 
@@ -133,14 +145,13 @@ static av_cold int init(AVFilterContext *ctx)
 {
     DecimateContext *decimate = ctx->priv;
 
+    decimate->sad = av_pixelutils_get_sad_fn(3, 3, 0, ctx); // 8x8, not aligned on blocksize
+    if (!decimate->sad)
+        return AVERROR(EINVAL);
+
     av_log(ctx, AV_LOG_VERBOSE, "max_drop_count:%d hi:%d lo:%d frac:%f\n",
            decimate->max_drop_count, decimate->hi, decimate->lo, decimate->frac);
 
-    decimate->avctx = avcodec_alloc_context3(NULL);
-    if (!decimate->avctx)
-        return AVERROR(ENOMEM);
-    avpriv_dsputil_init(&decimate->dspctx, decimate->avctx);
-
     return 0;
 }
 
@@ -148,10 +159,6 @@ static av_cold void uninit(AVFilterContext *ctx)
 {
     DecimateContext *decimate = ctx->priv;
     av_frame_free(&decimate->ref);
-    if (decimate->avctx) {
-        avcodec_close(decimate->avctx);
-        av_freep(&decimate->avctx);
-    }
 }
 
 static int query_formats(AVFilterContext *ctx)
@@ -163,12 +170,18 @@ static int query_formats(AVFilterContext *ctx)
         AV_PIX_FMT_YUVJ444P,     AV_PIX_FMT_YUVJ422P,
         AV_PIX_FMT_YUVJ420P,     AV_PIX_FMT_YUVJ440P,
         AV_PIX_FMT_YUVA420P,
-        AV_PIX_FMT_NONE
-    };
 
-    ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+        AV_PIX_FMT_GBRP,
 
-    return 0;
+        AV_PIX_FMT_YUVA444P,
+        AV_PIX_FMT_YUVA422P,
+
+        AV_PIX_FMT_NONE
+    };
+    AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+    if (!fmts_list)
+        return AVERROR(ENOMEM);
+    return ff_set_common_formats(ctx, fmts_list);
 }
 
 static int config_input(AVFilterLink *inlink)
@@ -195,7 +208,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *cur)
         decimate->ref = cur;
         decimate->drop_count = FFMIN(-1, decimate->drop_count-1);
 
-        if (ret = ff_filter_frame(outlink, av_frame_clone(cur)) < 0)
+        if ((ret = ff_filter_frame(outlink, av_frame_clone(cur))) < 0)
             return ret;
     }
 
@@ -211,26 +224,12 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *cur)
     return 0;
 }
 
-static int request_frame(AVFilterLink *outlink)
-{
-    DecimateContext *decimate = outlink->src->priv;
-    AVFilterLink *inlink = outlink->src->inputs[0];
-    int ret;
-
-    do {
-        ret = ff_request_frame(inlink);
-    } while (decimate->drop_count > 0 && ret >= 0);
-
-    return ret;
-}
-
 static const AVFilterPad mpdecimate_inputs[] = {
     {
-        .name             = "default",
-        .type             = AVMEDIA_TYPE_VIDEO,
-        .get_video_buffer = ff_null_get_video_buffer,
-        .config_props     = config_input,
-        .filter_frame     = filter_frame,
+        .name         = "default",
+        .type         = AVMEDIA_TYPE_VIDEO,
+        .config_props = config_input,
+        .filter_frame = filter_frame,
     },
     { NULL }
 };
@@ -239,20 +238,18 @@ static const AVFilterPad mpdecimate_outputs[] = {
     {
         .name          = "default",
         .type          = AVMEDIA_TYPE_VIDEO,
-        .request_frame = request_frame,
     },
     { NULL }
 };
 
-AVFilter avfilter_vf_mpdecimate = {
-    .name        = "mpdecimate",
-    .description = NULL_IF_CONFIG_SMALL("Remove near-duplicate frames."),
-    .init        = init,
-    .uninit      = uninit,
-
-    .priv_size = sizeof(DecimateContext),
+AVFilter ff_vf_mpdecimate = {
+    .name          = "mpdecimate",
+    .description   = NULL_IF_CONFIG_SMALL("Remove near-duplicate frames."),
+    .init          = init,
+    .uninit        = uninit,
+    .priv_size     = sizeof(DecimateContext),
+    .priv_class    = &mpdecimate_class,
     .query_formats = query_formats,
     .inputs        = mpdecimate_inputs,
     .outputs       = mpdecimate_outputs,
-    .priv_class    = &mpdecimate_class,
 };