Browse code

lavfi: rename decimate to mpdecimate.

The next commit will introduce a proper decimation filter to be used
along with the field matching filter. To avoid confusion with this
filter which has currently a very limited usage (and will not work
properly with the fieldmatching filter), the new decimation filter will
take the decimate name, and this filter is renamed to mpdecimate.

Clément Bœsch authored on 2013/03/23 06:58:36
Showing 7 changed files
... ...
@@ -2118,7 +2118,6 @@ blackframe_filter_deps="gpl"
2118 2118
 boxblur_filter_deps="gpl"
2119 2119
 colormatrix_filter_deps="gpl"
2120 2120
 cropdetect_filter_deps="gpl"
2121
-decimate_filter_deps="gpl avcodec"
2122 2121
 delogo_filter_deps="gpl"
2123 2122
 deshake_filter_deps="avcodec"
2124 2123
 deshake_filter_select="dsputil"
... ...
@@ -2137,6 +2136,7 @@ interlace_filter_deps="gpl"
2137 2137
 kerndeint_filter_deps="gpl"
2138 2138
 movie_filter_deps="avcodec avformat"
2139 2139
 mp_filter_deps="gpl avcodec swscale inline_asm"
2140
+mpdecimate_filter_deps="gpl avcodec"
2140 2141
 mptestsrc_filter_deps="gpl"
2141 2142
 negate_filter_deps="lut_filter"
2142 2143
 noise_filter_deps="gpl"
... ...
@@ -2383,7 +2383,7 @@ curves=vintage
2383 2383
 @end example
2384 2384
 @end itemize
2385 2385
 
2386
-@section decimate
2386
+@section mpdecimate
2387 2387
 
2388 2388
 Drop frames that do not differ greatly from the previous frame in
2389 2389
 order to reduce frame rate.
... ...
@@ -109,7 +109,6 @@ OBJS-$(CONFIG_COPY_FILTER)                   += vf_copy.o
109 109
 OBJS-$(CONFIG_CROP_FILTER)                   += vf_crop.o
110 110
 OBJS-$(CONFIG_CROPDETECT_FILTER)             += vf_cropdetect.o
111 111
 OBJS-$(CONFIG_CURVES_FILTER)                 += vf_curves.o
112
-OBJS-$(CONFIG_DECIMATE_FILTER)               += vf_decimate.o
113 112
 OBJS-$(CONFIG_DELOGO_FILTER)                 += vf_delogo.o
114 113
 OBJS-$(CONFIG_DESHAKE_FILTER)                += vf_deshake.o
115 114
 OBJS-$(CONFIG_DRAWBOX_FILTER)                += vf_drawbox.o
... ...
@@ -137,6 +136,7 @@ OBJS-$(CONFIG_LUT_FILTER)                    += vf_lut.o
137 137
 OBJS-$(CONFIG_LUTRGB_FILTER)                 += vf_lut.o
138 138
 OBJS-$(CONFIG_LUTYUV_FILTER)                 += vf_lut.o
139 139
 OBJS-$(CONFIG_MP_FILTER)                     += vf_mp.o
140
+OBJS-$(CONFIG_MPDECIMATE_FILTER)             += vf_mpdecimate.o
140 141
 OBJS-$(CONFIG_NEGATE_FILTER)                 += vf_lut.o
141 142
 OBJS-$(CONFIG_NOFORMAT_FILTER)               += vf_format.o
142 143
 OBJS-$(CONFIG_NOISE_FILTER)                  += vf_noise.o
... ...
@@ -107,7 +107,6 @@ void avfilter_register_all(void)
107 107
     REGISTER_FILTER(CROP,           crop,           vf);
108 108
     REGISTER_FILTER(CROPDETECT,     cropdetect,     vf);
109 109
     REGISTER_FILTER(CURVES,         curves,         vf);
110
-    REGISTER_FILTER(DECIMATE,       decimate,       vf);
111 110
     REGISTER_FILTER(DELOGO,         delogo,         vf);
112 111
     REGISTER_FILTER(DESHAKE,        deshake,        vf);
113 112
     REGISTER_FILTER(DRAWBOX,        drawbox,        vf);
... ...
@@ -135,6 +134,7 @@ void avfilter_register_all(void)
135 135
     REGISTER_FILTER(LUTRGB,         lutrgb,         vf);
136 136
     REGISTER_FILTER(LUTYUV,         lutyuv,         vf);
137 137
     REGISTER_FILTER(MP,             mp,             vf);
138
+    REGISTER_FILTER(MPDECIMATE,     mpdecimate,     vf);
138 139
     REGISTER_FILTER(NEGATE,         negate,         vf);
139 140
     REGISTER_FILTER(NOFORMAT,       noformat,       vf);
140 141
     REGISTER_FILTER(NOISE,          noise,          vf);
... ...
@@ -29,7 +29,7 @@
29 29
 #include "libavutil/avutil.h"
30 30
 
31 31
 #define LIBAVFILTER_VERSION_MAJOR  3
32
-#define LIBAVFILTER_VERSION_MINOR  54
32
+#define LIBAVFILTER_VERSION_MINOR  55
33 33
 #define LIBAVFILTER_VERSION_MICRO 100
34 34
 
35 35
 #define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
36 36
deleted file mode 100644
... ...
@@ -1,258 +0,0 @@
1
-/*
2
- * Copyright (c) 2003 Rich Felker
3
- * Copyright (c) 2012 Stefano Sabatini
4
- *
5
- * This file is part of FFmpeg.
6
- *
7
- * FFmpeg is free software; you can redistribute it and/or modify
8
- * it under the terms of the GNU General Public License as published by
9
- * the Free Software Foundation; either version 2 of the License, or
10
- * (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
15
- * GNU General Public License for more details.
16
- *
17
- * You should have received a copy of the GNU General Public License along
18
- * with FFmpeg; if not, write to the Free Software Foundation, Inc.,
19
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
- */
21
-
22
-/**
23
- * @file decimate filter, ported from libmpcodecs/vf_decimate.c by
24
- * Rich Felker.
25
- */
26
-
27
-#include "libavutil/opt.h"
28
-#include "libavutil/pixdesc.h"
29
-#include "libavutil/timestamp.h"
30
-#include "libavcodec/dsputil.h"
31
-#include "avfilter.h"
32
-#include "internal.h"
33
-#include "formats.h"
34
-#include "video.h"
35
-
36
-typedef struct {
37
-    const AVClass *class;
38
-    int lo, hi;                    ///< lower and higher threshold number of differences
39
-                                   ///< values for 8x8 blocks
40
-
41
-    float frac;                    ///< threshold of changed pixels over the total fraction
42
-
43
-    int max_drop_count;            ///< if positive: maximum number of sequential frames to drop
44
-                                   ///< if negative: minimum number of frames between two drops
45
-
46
-    int drop_count;                ///< if positive: number of frames sequentially dropped
47
-                                   ///< if negative: number of sequential frames which were not dropped
48
-
49
-    int hsub, vsub;                ///< chroma subsampling values
50
-    AVFrame *ref;                  ///< reference picture
51
-    DSPContext dspctx;             ///< context providing optimized diff routines
52
-    AVCodecContext *avctx;         ///< codec context required for the DSPContext
53
-} DecimateContext;
54
-
55
-#define OFFSET(x) offsetof(DecimateContext, x)
56
-#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
57
-
58
-static const AVOption decimate_options[] = {
59
-    { "max",  "set the maximum number of consecutive dropped frames (positive), or the minimum interval between dropped frames (negative)",
60
-      OFFSET(max_drop_count), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX, FLAGS },
61
-    { "hi",   "set high dropping threshold", OFFSET(hi), AV_OPT_TYPE_INT, {.i64=64*12}, INT_MIN, INT_MAX, FLAGS },
62
-    { "lo",   "set low dropping threshold", OFFSET(lo), AV_OPT_TYPE_INT, {.i64=64*5}, INT_MIN, INT_MAX, FLAGS },
63
-    { "frac", "set fraction dropping threshold",  OFFSET(frac), AV_OPT_TYPE_FLOAT, {.dbl=0.33}, 0, 1, FLAGS },
64
-    { NULL }
65
-};
66
-
67
-AVFILTER_DEFINE_CLASS(decimate);
68
-
69
-/**
70
- * Return 1 if the two planes are different, 0 otherwise.
71
- */
72
-static int diff_planes(AVFilterContext *ctx,
73
-                       uint8_t *cur, uint8_t *ref, int linesize,
74
-                       int w, int h)
75
-{
76
-    DecimateContext *decimate = ctx->priv;
77
-    DSPContext *dspctx = &decimate->dspctx;
78
-
79
-    int x, y;
80
-    int d, c = 0;
81
-    int t = (w/16)*(h/16)*decimate->frac;
82
-    int16_t block[8*8];
83
-
84
-    /* compute difference for blocks of 8x8 bytes */
85
-    for (y = 0; y < h-7; y += 4) {
86
-        for (x = 8; x < w-7; x += 4) {
87
-            dspctx->diff_pixels(block,
88
-                                cur+x+y*linesize,
89
-                                ref+x+y*linesize, linesize);
90
-            d = dspctx->sum_abs_dctelem(block);
91
-            if (d > decimate->hi)
92
-                return 1;
93
-            if (d > decimate->lo) {
94
-                c++;
95
-                if (c > t)
96
-                    return 1;
97
-            }
98
-        }
99
-    }
100
-    return 0;
101
-}
102
-
103
-/**
104
- * Tell if the frame should be decimated, for example if it is no much
105
- * different with respect to the reference frame ref.
106
- */
107
-static int decimate_frame(AVFilterContext *ctx,
108
-                          AVFrame *cur, AVFrame *ref)
109
-{
110
-    DecimateContext *decimate = ctx->priv;
111
-    int plane;
112
-
113
-    if (decimate->max_drop_count > 0 &&
114
-        decimate->drop_count >= decimate->max_drop_count)
115
-        return 0;
116
-    if (decimate->max_drop_count < 0 &&
117
-        (decimate->drop_count-1) > decimate->max_drop_count)
118
-        return 0;
119
-
120
-    for (plane = 0; ref->data[plane] && ref->linesize[plane]; plane++) {
121
-        int vsub = plane == 1 || plane == 2 ? decimate->vsub : 0;
122
-        int hsub = plane == 1 || plane == 2 ? decimate->hsub : 0;
123
-        if (diff_planes(ctx,
124
-                        cur->data[plane], ref->data[plane], ref->linesize[plane],
125
-                        ref->width>>hsub, ref->height>>vsub))
126
-            return 0;
127
-    }
128
-
129
-    return 1;
130
-}
131
-
132
-static av_cold int init(AVFilterContext *ctx)
133
-{
134
-    DecimateContext *decimate = ctx->priv;
135
-
136
-    av_log(ctx, AV_LOG_VERBOSE, "max_drop_count:%d hi:%d lo:%d frac:%f\n",
137
-           decimate->max_drop_count, decimate->hi, decimate->lo, decimate->frac);
138
-
139
-    decimate->avctx = avcodec_alloc_context3(NULL);
140
-    if (!decimate->avctx)
141
-        return AVERROR(ENOMEM);
142
-    dsputil_init(&decimate->dspctx, decimate->avctx);
143
-
144
-    return 0;
145
-}
146
-
147
-static av_cold void uninit(AVFilterContext *ctx)
148
-{
149
-    DecimateContext *decimate = ctx->priv;
150
-    av_frame_free(&decimate->ref);
151
-    if (decimate->avctx) {
152
-        avcodec_close(decimate->avctx);
153
-        av_freep(&decimate->avctx);
154
-    }
155
-}
156
-
157
-static int query_formats(AVFilterContext *ctx)
158
-{
159
-    static const enum AVPixelFormat pix_fmts[] = {
160
-        AV_PIX_FMT_YUV444P,      AV_PIX_FMT_YUV422P,
161
-        AV_PIX_FMT_YUV420P,      AV_PIX_FMT_YUV411P,
162
-        AV_PIX_FMT_YUV410P,      AV_PIX_FMT_YUV440P,
163
-        AV_PIX_FMT_YUVJ444P,     AV_PIX_FMT_YUVJ422P,
164
-        AV_PIX_FMT_YUVJ420P,     AV_PIX_FMT_YUVJ440P,
165
-        AV_PIX_FMT_YUVA420P,
166
-        AV_PIX_FMT_NONE
167
-    };
168
-
169
-    ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
170
-
171
-    return 0;
172
-}
173
-
174
-static int config_input(AVFilterLink *inlink)
175
-{
176
-    AVFilterContext *ctx = inlink->dst;
177
-    DecimateContext *decimate = ctx->priv;
178
-    const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(inlink->format);
179
-    decimate->hsub = pix_desc->log2_chroma_w;
180
-    decimate->vsub = pix_desc->log2_chroma_h;
181
-
182
-    return 0;
183
-}
184
-
185
-static int filter_frame(AVFilterLink *inlink, AVFrame *cur)
186
-{
187
-    DecimateContext *decimate = inlink->dst->priv;
188
-    AVFilterLink *outlink = inlink->dst->outputs[0];
189
-    int ret;
190
-
191
-    if (decimate->ref && decimate_frame(inlink->dst, cur, decimate->ref)) {
192
-        decimate->drop_count = FFMAX(1, decimate->drop_count+1);
193
-    } else {
194
-        av_frame_free(&decimate->ref);
195
-        decimate->ref = cur;
196
-        decimate->drop_count = FFMIN(-1, decimate->drop_count-1);
197
-
198
-        if (ret = ff_filter_frame(outlink, av_frame_clone(cur)) < 0)
199
-            return ret;
200
-    }
201
-
202
-    av_log(inlink->dst, AV_LOG_DEBUG,
203
-           "%s pts:%s pts_time:%s drop_count:%d\n",
204
-           decimate->drop_count > 0 ? "drop" : "keep",
205
-           av_ts2str(cur->pts), av_ts2timestr(cur->pts, &inlink->time_base),
206
-           decimate->drop_count);
207
-
208
-    if (decimate->drop_count > 0)
209
-        av_frame_free(&cur);
210
-
211
-    return 0;
212
-}
213
-
214
-static int request_frame(AVFilterLink *outlink)
215
-{
216
-    DecimateContext *decimate = outlink->src->priv;
217
-    AVFilterLink *inlink = outlink->src->inputs[0];
218
-    int ret;
219
-
220
-    do {
221
-        ret = ff_request_frame(inlink);
222
-    } while (decimate->drop_count > 0 && ret >= 0);
223
-
224
-    return ret;
225
-}
226
-
227
-static const AVFilterPad decimate_inputs[] = {
228
-    {
229
-        .name             = "default",
230
-        .type             = AVMEDIA_TYPE_VIDEO,
231
-        .get_video_buffer = ff_null_get_video_buffer,
232
-        .config_props     = config_input,
233
-        .filter_frame     = filter_frame,
234
-    },
235
-    { NULL }
236
-};
237
-
238
-static const AVFilterPad decimate_outputs[] = {
239
-    {
240
-        .name          = "default",
241
-        .type          = AVMEDIA_TYPE_VIDEO,
242
-        .request_frame = request_frame,
243
-    },
244
-    { NULL }
245
-};
246
-
247
-AVFilter avfilter_vf_decimate = {
248
-    .name        = "decimate",
249
-    .description = NULL_IF_CONFIG_SMALL("Remove near-duplicate frames."),
250
-    .init        = init,
251
-    .uninit      = uninit,
252
-
253
-    .priv_size = sizeof(DecimateContext),
254
-    .query_formats = query_formats,
255
-    .inputs        = decimate_inputs,
256
-    .outputs       = decimate_outputs,
257
-    .priv_class    = &decimate_class,
258
-};
259 1
new file mode 100644
... ...
@@ -0,0 +1,258 @@
0
+/*
1
+ * Copyright (c) 2003 Rich Felker
2
+ * Copyright (c) 2012 Stefano Sabatini
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 mpdecimate filter, ported from libmpcodecs/vf_decimate.c by
23
+ * Rich Felker.
24
+ */
25
+
26
+#include "libavutil/opt.h"
27
+#include "libavutil/pixdesc.h"
28
+#include "libavutil/timestamp.h"
29
+#include "libavcodec/dsputil.h"
30
+#include "avfilter.h"
31
+#include "internal.h"
32
+#include "formats.h"
33
+#include "video.h"
34
+
35
+typedef struct {
36
+    const AVClass *class;
37
+    int lo, hi;                    ///< lower and higher threshold number of differences
38
+                                   ///< values for 8x8 blocks
39
+
40
+    float frac;                    ///< threshold of changed pixels over the total fraction
41
+
42
+    int max_drop_count;            ///< if positive: maximum number of sequential frames to drop
43
+                                   ///< if negative: minimum number of frames between two drops
44
+
45
+    int drop_count;                ///< if positive: number of frames sequentially dropped
46
+                                   ///< if negative: number of sequential frames which were not dropped
47
+
48
+    int hsub, vsub;                ///< chroma subsampling values
49
+    AVFrame *ref;                  ///< reference picture
50
+    DSPContext dspctx;             ///< context providing optimized diff routines
51
+    AVCodecContext *avctx;         ///< codec context required for the DSPContext
52
+} DecimateContext;
53
+
54
+#define OFFSET(x) offsetof(DecimateContext, x)
55
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
56
+
57
+static const AVOption mpdecimate_options[] = {
58
+    { "max",  "set the maximum number of consecutive dropped frames (positive), or the minimum interval between dropped frames (negative)",
59
+      OFFSET(max_drop_count), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX, FLAGS },
60
+    { "hi",   "set high dropping threshold", OFFSET(hi), AV_OPT_TYPE_INT, {.i64=64*12}, INT_MIN, INT_MAX, FLAGS },
61
+    { "lo",   "set low dropping threshold", OFFSET(lo), AV_OPT_TYPE_INT, {.i64=64*5}, INT_MIN, INT_MAX, FLAGS },
62
+    { "frac", "set fraction dropping threshold",  OFFSET(frac), AV_OPT_TYPE_FLOAT, {.dbl=0.33}, 0, 1, FLAGS },
63
+    { NULL }
64
+};
65
+
66
+AVFILTER_DEFINE_CLASS(mpdecimate);
67
+
68
+/**
69
+ * Return 1 if the two planes are different, 0 otherwise.
70
+ */
71
+static int diff_planes(AVFilterContext *ctx,
72
+                       uint8_t *cur, uint8_t *ref, int linesize,
73
+                       int w, int h)
74
+{
75
+    DecimateContext *decimate = ctx->priv;
76
+    DSPContext *dspctx = &decimate->dspctx;
77
+
78
+    int x, y;
79
+    int d, c = 0;
80
+    int t = (w/16)*(h/16)*decimate->frac;
81
+    int16_t block[8*8];
82
+
83
+    /* compute difference for blocks of 8x8 bytes */
84
+    for (y = 0; y < h-7; y += 4) {
85
+        for (x = 8; x < w-7; x += 4) {
86
+            dspctx->diff_pixels(block,
87
+                                cur+x+y*linesize,
88
+                                ref+x+y*linesize, linesize);
89
+            d = dspctx->sum_abs_dctelem(block);
90
+            if (d > decimate->hi)
91
+                return 1;
92
+            if (d > decimate->lo) {
93
+                c++;
94
+                if (c > t)
95
+                    return 1;
96
+            }
97
+        }
98
+    }
99
+    return 0;
100
+}
101
+
102
+/**
103
+ * Tell if the frame should be decimated, for example if it is no much
104
+ * different with respect to the reference frame ref.
105
+ */
106
+static int decimate_frame(AVFilterContext *ctx,
107
+                          AVFrame *cur, AVFrame *ref)
108
+{
109
+    DecimateContext *decimate = ctx->priv;
110
+    int plane;
111
+
112
+    if (decimate->max_drop_count > 0 &&
113
+        decimate->drop_count >= decimate->max_drop_count)
114
+        return 0;
115
+    if (decimate->max_drop_count < 0 &&
116
+        (decimate->drop_count-1) > decimate->max_drop_count)
117
+        return 0;
118
+
119
+    for (plane = 0; ref->data[plane] && ref->linesize[plane]; plane++) {
120
+        int vsub = plane == 1 || plane == 2 ? decimate->vsub : 0;
121
+        int hsub = plane == 1 || plane == 2 ? decimate->hsub : 0;
122
+        if (diff_planes(ctx,
123
+                        cur->data[plane], ref->data[plane], ref->linesize[plane],
124
+                        ref->width>>hsub, ref->height>>vsub))
125
+            return 0;
126
+    }
127
+
128
+    return 1;
129
+}
130
+
131
+static av_cold int init(AVFilterContext *ctx)
132
+{
133
+    DecimateContext *decimate = ctx->priv;
134
+
135
+    av_log(ctx, AV_LOG_VERBOSE, "max_drop_count:%d hi:%d lo:%d frac:%f\n",
136
+           decimate->max_drop_count, decimate->hi, decimate->lo, decimate->frac);
137
+
138
+    decimate->avctx = avcodec_alloc_context3(NULL);
139
+    if (!decimate->avctx)
140
+        return AVERROR(ENOMEM);
141
+    dsputil_init(&decimate->dspctx, decimate->avctx);
142
+
143
+    return 0;
144
+}
145
+
146
+static av_cold void uninit(AVFilterContext *ctx)
147
+{
148
+    DecimateContext *decimate = ctx->priv;
149
+    av_frame_free(&decimate->ref);
150
+    if (decimate->avctx) {
151
+        avcodec_close(decimate->avctx);
152
+        av_freep(&decimate->avctx);
153
+    }
154
+}
155
+
156
+static int query_formats(AVFilterContext *ctx)
157
+{
158
+    static const enum AVPixelFormat pix_fmts[] = {
159
+        AV_PIX_FMT_YUV444P,      AV_PIX_FMT_YUV422P,
160
+        AV_PIX_FMT_YUV420P,      AV_PIX_FMT_YUV411P,
161
+        AV_PIX_FMT_YUV410P,      AV_PIX_FMT_YUV440P,
162
+        AV_PIX_FMT_YUVJ444P,     AV_PIX_FMT_YUVJ422P,
163
+        AV_PIX_FMT_YUVJ420P,     AV_PIX_FMT_YUVJ440P,
164
+        AV_PIX_FMT_YUVA420P,
165
+        AV_PIX_FMT_NONE
166
+    };
167
+
168
+    ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
169
+
170
+    return 0;
171
+}
172
+
173
+static int config_input(AVFilterLink *inlink)
174
+{
175
+    AVFilterContext *ctx = inlink->dst;
176
+    DecimateContext *decimate = ctx->priv;
177
+    const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(inlink->format);
178
+    decimate->hsub = pix_desc->log2_chroma_w;
179
+    decimate->vsub = pix_desc->log2_chroma_h;
180
+
181
+    return 0;
182
+}
183
+
184
+static int filter_frame(AVFilterLink *inlink, AVFrame *cur)
185
+{
186
+    DecimateContext *decimate = inlink->dst->priv;
187
+    AVFilterLink *outlink = inlink->dst->outputs[0];
188
+    int ret;
189
+
190
+    if (decimate->ref && decimate_frame(inlink->dst, cur, decimate->ref)) {
191
+        decimate->drop_count = FFMAX(1, decimate->drop_count+1);
192
+    } else {
193
+        av_frame_free(&decimate->ref);
194
+        decimate->ref = cur;
195
+        decimate->drop_count = FFMIN(-1, decimate->drop_count-1);
196
+
197
+        if (ret = ff_filter_frame(outlink, av_frame_clone(cur)) < 0)
198
+            return ret;
199
+    }
200
+
201
+    av_log(inlink->dst, AV_LOG_DEBUG,
202
+           "%s pts:%s pts_time:%s drop_count:%d\n",
203
+           decimate->drop_count > 0 ? "drop" : "keep",
204
+           av_ts2str(cur->pts), av_ts2timestr(cur->pts, &inlink->time_base),
205
+           decimate->drop_count);
206
+
207
+    if (decimate->drop_count > 0)
208
+        av_frame_free(&cur);
209
+
210
+    return 0;
211
+}
212
+
213
+static int request_frame(AVFilterLink *outlink)
214
+{
215
+    DecimateContext *decimate = outlink->src->priv;
216
+    AVFilterLink *inlink = outlink->src->inputs[0];
217
+    int ret;
218
+
219
+    do {
220
+        ret = ff_request_frame(inlink);
221
+    } while (decimate->drop_count > 0 && ret >= 0);
222
+
223
+    return ret;
224
+}
225
+
226
+static const AVFilterPad mpdecimate_inputs[] = {
227
+    {
228
+        .name             = "default",
229
+        .type             = AVMEDIA_TYPE_VIDEO,
230
+        .get_video_buffer = ff_null_get_video_buffer,
231
+        .config_props     = config_input,
232
+        .filter_frame     = filter_frame,
233
+    },
234
+    { NULL }
235
+};
236
+
237
+static const AVFilterPad mpdecimate_outputs[] = {
238
+    {
239
+        .name          = "default",
240
+        .type          = AVMEDIA_TYPE_VIDEO,
241
+        .request_frame = request_frame,
242
+    },
243
+    { NULL }
244
+};
245
+
246
+AVFilter avfilter_vf_mpdecimate = {
247
+    .name        = "mpdecimate",
248
+    .description = NULL_IF_CONFIG_SMALL("Remove near-duplicate frames."),
249
+    .init        = init,
250
+    .uninit      = uninit,
251
+
252
+    .priv_size = sizeof(DecimateContext),
253
+    .query_formats = query_formats,
254
+    .inputs        = mpdecimate_inputs,
255
+    .outputs       = mpdecimate_outputs,
256
+    .priv_class    = &mpdecimate_class,
257
+};