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.
... | ... |
@@ -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" |
... | ... |
@@ -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 |
+}; |