2 * Copyright (c) 2003 Rich Felker
3 * Copyright (c) 2012 Stefano Sabatini
5 * This file is part of FFmpeg.
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.
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.
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.
23 * @file mpdecimate filter, ported from libmpcodecs/vf_decimate.c by
27 #include "libavutil/opt.h"
28 #include "libavutil/pixdesc.h"
29 #include "libavutil/pixelutils.h"
30 #include "libavutil/timestamp.h"
38 int lo
, hi
; ///< lower and higher threshold number of differences
39 ///< values for 8x8 blocks
41 float frac
; ///< threshold of changed pixels over the total fraction
43 int max_drop_count
; ///< if positive: maximum number of sequential frames to drop
44 ///< if negative: minimum number of frames between two drops
46 int drop_count
; ///< if positive: number of frames sequentially dropped
47 ///< if negative: number of sequential frames which were not dropped
49 int hsub
, vsub
; ///< chroma subsampling values
50 AVFrame
*ref
; ///< reference picture
51 av_pixelutils_sad_fn sad
; ///< sum of absolute difference function
54 #define OFFSET(x) offsetof(DecimateContext, x)
55 #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
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
},
66 AVFILTER_DEFINE_CLASS(mpdecimate
);
69 * Return 1 if the two planes are different, 0 otherwise.
71 static int diff_planes(AVFilterContext
*ctx
,
72 uint8_t *cur
, int cur_linesize
,
73 uint8_t *ref
, int ref_linesize
,
76 DecimateContext
*decimate
= ctx
->priv
;
80 int t
= (w
/16)*(h
/16)*decimate
->frac
;
82 /* compute difference for blocks of 8x8 bytes */
83 for (y
= 0; y
< h
-7; y
+= 4) {
84 for (x
= 8; x
< w
-7; x
+= 4) {
85 d
= decimate
->sad(cur
+ y
*cur_linesize
+ x
, cur_linesize
,
86 ref
+ y
*ref_linesize
+ x
, ref_linesize
);
89 if (d
> decimate
->lo
) {
100 * Tell if the frame should be decimated, for example if it is no much
101 * different with respect to the reference frame ref.
103 static int decimate_frame(AVFilterContext
*ctx
,
104 AVFrame
*cur
, AVFrame
*ref
)
106 DecimateContext
*decimate
= ctx
->priv
;
109 if (decimate
->max_drop_count
> 0 &&
110 decimate
->drop_count
>= decimate
->max_drop_count
)
112 if (decimate
->max_drop_count
< 0 &&
113 (decimate
->drop_count
-1) > decimate
->max_drop_count
)
116 for (plane
= 0; ref
->data
[plane
] && ref
->linesize
[plane
]; plane
++) {
117 int vsub
= plane
== 1 || plane
== 2 ? decimate
->vsub
: 0;
118 int hsub
= plane
== 1 || plane
== 2 ? decimate
->hsub
: 0;
120 cur
->data
[plane
], cur
->linesize
[plane
],
121 ref
->data
[plane
], ref
->linesize
[plane
],
122 FF_CEIL_RSHIFT(ref
->width
, hsub
),
123 FF_CEIL_RSHIFT(ref
->height
, vsub
)))
130 static av_cold
int init(AVFilterContext
*ctx
)
132 DecimateContext
*decimate
= ctx
->priv
;
134 decimate
->sad
= av_pixelutils_get_sad_fn(3, 3, 0, decimate
); // 8x8, not aligned on blocksize
136 return AVERROR(EINVAL
);
138 av_log(ctx
, AV_LOG_VERBOSE
, "max_drop_count:%d hi:%d lo:%d frac:%f\n",
139 decimate
->max_drop_count
, decimate
->hi
, decimate
->lo
, decimate
->frac
);
144 static av_cold
void uninit(AVFilterContext
*ctx
)
146 DecimateContext
*decimate
= ctx
->priv
;
147 av_frame_free(&decimate
->ref
);
150 static int query_formats(AVFilterContext
*ctx
)
152 static const enum AVPixelFormat pix_fmts
[] = {
153 AV_PIX_FMT_YUV444P
, AV_PIX_FMT_YUV422P
,
154 AV_PIX_FMT_YUV420P
, AV_PIX_FMT_YUV411P
,
155 AV_PIX_FMT_YUV410P
, AV_PIX_FMT_YUV440P
,
156 AV_PIX_FMT_YUVJ444P
, AV_PIX_FMT_YUVJ422P
,
157 AV_PIX_FMT_YUVJ420P
, AV_PIX_FMT_YUVJ440P
,
162 ff_set_common_formats(ctx
, ff_make_format_list(pix_fmts
));
167 static int config_input(AVFilterLink
*inlink
)
169 AVFilterContext
*ctx
= inlink
->dst
;
170 DecimateContext
*decimate
= ctx
->priv
;
171 const AVPixFmtDescriptor
*pix_desc
= av_pix_fmt_desc_get(inlink
->format
);
172 decimate
->hsub
= pix_desc
->log2_chroma_w
;
173 decimate
->vsub
= pix_desc
->log2_chroma_h
;
178 static int filter_frame(AVFilterLink
*inlink
, AVFrame
*cur
)
180 DecimateContext
*decimate
= inlink
->dst
->priv
;
181 AVFilterLink
*outlink
= inlink
->dst
->outputs
[0];
184 if (decimate
->ref
&& decimate_frame(inlink
->dst
, cur
, decimate
->ref
)) {
185 decimate
->drop_count
= FFMAX(1, decimate
->drop_count
+1);
187 av_frame_free(&decimate
->ref
);
189 decimate
->drop_count
= FFMIN(-1, decimate
->drop_count
-1);
191 if (ret
= ff_filter_frame(outlink
, av_frame_clone(cur
)) < 0)
195 av_log(inlink
->dst
, AV_LOG_DEBUG
,
196 "%s pts:%s pts_time:%s drop_count:%d\n",
197 decimate
->drop_count
> 0 ? "drop" : "keep",
198 av_ts2str(cur
->pts
), av_ts2timestr(cur
->pts
, &inlink
->time_base
),
199 decimate
->drop_count
);
201 if (decimate
->drop_count
> 0)
207 static int request_frame(AVFilterLink
*outlink
)
209 DecimateContext
*decimate
= outlink
->src
->priv
;
210 AVFilterLink
*inlink
= outlink
->src
->inputs
[0];
214 ret
= ff_request_frame(inlink
);
215 } while (decimate
->drop_count
> 0 && ret
>= 0);
220 static const AVFilterPad mpdecimate_inputs
[] = {
223 .type
= AVMEDIA_TYPE_VIDEO
,
224 .config_props
= config_input
,
225 .filter_frame
= filter_frame
,
230 static const AVFilterPad mpdecimate_outputs
[] = {
233 .type
= AVMEDIA_TYPE_VIDEO
,
234 .request_frame
= request_frame
,
239 AVFilter ff_vf_mpdecimate
= {
240 .name
= "mpdecimate",
241 .description
= NULL_IF_CONFIG_SMALL("Remove near-duplicate frames."),
244 .priv_size
= sizeof(DecimateContext
),
245 .priv_class
= &mpdecimate_class
,
246 .query_formats
= query_formats
,
247 .inputs
= mpdecimate_inputs
,
248 .outputs
= mpdecimate_outputs
,