History

avfilter: add threshold filter

Paul B Mahol committed 10 years ago

Commit acf1dd51 parent ebb83e26 files · +410 −1Browse files

Unified · Split

6 files
  1. Changelog +1 −0
  2. doc/filters.texi +57 −0
  3. libavfilter/Makefile +1 −0
  4. libavfilter/allfilters.c +1 −0
  5. libavfilter/version.h +1 −1
  6. libavfilter/vf_threshold.c +349 −0
Changelog+1−0
@@ -19,6 +19,7 @@ version <next>: · 18 unmodified lines
19- Sample Dump eXchange demuxer19- Sample Dump eXchange demuxer
20- abitscope multimedia filter20- abitscope multimedia filter
21- Scenarist Closed Captions demuxer and muxer21- Scenarist Closed Captions demuxer and muxer
22- threshold filter
22 23
23version 3.2:24version 3.2:
24- libopenmpt demuxer25- libopenmpt demuxer
doc/filters.texi+57−0
@@ -13192,6 +13192,63 @@ PAL output (25i): · 13191 unmodified lines
1319216p: 333333341319216p: 33333334
13193@end example13193@end example
13194 13194
13195@section threshold
13196
13197Apply threshold effect to video stream.
13198
13199This filter needs four video streams to perform thresholding.
13200First stream is stream we are filtering.
13201Second stream is holding threshold values, third stream is holding min values,
13202and last, fourth stream is holding max values.
13203
13204The filter accepts the following option:
13205
13206@table @option
13207@item planes
13208Set which planes will be processed, unprocessed planes will be copied.
13209By default value 0xf, all planes will be processed.
13210@end table
13211
13212For example if first stream pixel's component value is less then threshold value
13213of pixel component from 2nd threshold stream, third stream value will picked,
13214otherwise fourth stream pixel component value will be picked.
13215
13216Using color source filter one can perform various types of thresholding:
13217
13218@subsection Examples
13219
13220@itemize
13221@item
13222Binary threshold, using gray color as threshold:
13223@example
13224ffmpeg -i 320x240.avi -f lavfi -i color=gray -f lavfi -i color=black -f lavfi -i color=white -lavfi threshold output.avi
13225@end example
13226
13227@item
13228Inverted binary threshold, using gray color as threshold:
13229@example
13230ffmpeg -i 320x240.avi -f lavfi -i color=gray -f lavfi -i color=white -f lavfi -i color=black -lavfi threshold output.avi
13231@end example
13232
13233@item
13234Truncate binary threshold, using gray color as threshold:
13235@example
13236ffmpeg -i 320x240.avi -f lavfi -i color=gray -i 320x240.avi -f lavfi -i color=gray -lavfi threshold output.avi
13237@end example
13238
13239@item
13240Threshold to zero, using gray color as threshold:
13241@example
13242ffmpeg -i 320x240.avi -f lavfi -i color=gray -f lavfi -i color=white -i 320x240.avi -lavfi threshold output.avi
13243@end example
13244
13245@item
13246Inverted threshold to zero, using gray color as threshold:
13247@example
13248ffmpeg -i 320x240.avi -f lavfi -i color=gray -i 320x240.avi -f lavfi -i color=white -lavfi threshold output.avi
13249@end example
13250@end itemize
13251
13195@section thumbnail13252@section thumbnail
13196Select the most representative frame in a given sequence of consecutive frames.13253Select the most representative frame in a given sequence of consecutive frames.
13197 13254
libavfilter/Makefile+1−0
@@ -289,6 +289,7 @@ OBJS-$(CONFIG_SWAPRECT_FILTER) += vf_swaprect.o · 288 unmodified lines
289OBJS-$(CONFIG_SWAPUV_FILTER) += vf_swapuv.o289OBJS-$(CONFIG_SWAPUV_FILTER) += vf_swapuv.o
290OBJS-$(CONFIG_TBLEND_FILTER) += vf_blend.o dualinput.o framesync.o290OBJS-$(CONFIG_TBLEND_FILTER) += vf_blend.o dualinput.o framesync.o
291OBJS-$(CONFIG_TELECINE_FILTER) += vf_telecine.o291OBJS-$(CONFIG_TELECINE_FILTER) += vf_telecine.o
292OBJS-$(CONFIG_THRESHOLD_FILTER) += vf_threshold.o
292OBJS-$(CONFIG_THUMBNAIL_FILTER) += vf_thumbnail.o293OBJS-$(CONFIG_THUMBNAIL_FILTER) += vf_thumbnail.o
293OBJS-$(CONFIG_TILE_FILTER) += vf_tile.o294OBJS-$(CONFIG_TILE_FILTER) += vf_tile.o
294OBJS-$(CONFIG_TINTERLACE_FILTER) += vf_tinterlace.o295OBJS-$(CONFIG_TINTERLACE_FILTER) += vf_tinterlace.o
libavfilter/allfilters.c+1−0
@@ -304,6 +304,7 @@ void avfilter_register_all(void) · 303 unmodified lines
304 REGISTER_FILTER(SWAPUV, swapuv, vf);304 REGISTER_FILTER(SWAPUV, swapuv, vf);
305 REGISTER_FILTER(TBLEND, tblend, vf);305 REGISTER_FILTER(TBLEND, tblend, vf);
306 REGISTER_FILTER(TELECINE, telecine, vf);306 REGISTER_FILTER(TELECINE, telecine, vf);
307 REGISTER_FILTER(THRESHOLD, threshold, vf);
307 REGISTER_FILTER(THUMBNAIL, thumbnail, vf);308 REGISTER_FILTER(THUMBNAIL, thumbnail, vf);
308 REGISTER_FILTER(TILE, tile, vf);309 REGISTER_FILTER(TILE, tile, vf);
309 REGISTER_FILTER(TINTERLACE, tinterlace, vf);310 REGISTER_FILTER(TINTERLACE, tinterlace, vf);
libavfilter/version.h+1−1
@@ -30,7 +30,7 @@ · 29 unmodified lines
30#include "libavutil/version.h"30#include "libavutil/version.h"
31 31
32#define LIBAVFILTER_VERSION_MAJOR 632#define LIBAVFILTER_VERSION_MAJOR 6
33#define LIBAVFILTER_VERSION_MINOR 7133#define LIBAVFILTER_VERSION_MINOR 72
34#define LIBAVFILTER_VERSION_MICRO 10034#define LIBAVFILTER_VERSION_MICRO 100
35 35
36#define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \36#define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
libavfilter/vf_threshold.c+349−0
@@ -0,0 +1,349 @@
1/*
2 * Copyright (c) 2016 Paul B Mahol
3 *
4 * This file is part of FFmpeg.
5 *
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (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 GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21/**
22 * @file
23 * threshold video filter
24 */
25
26#include "libavutil/imgutils.h"
27#include "libavutil/internal.h"
28#include "libavutil/opt.h"
29#include "libavutil/pixdesc.h"
30#include "avfilter.h"
31#include "framesync.h"
32#include "internal.h"
33#include "video.h"
34
35typedef struct ThresholdContext {
36 const AVClass *class;
37
38 int planes;
39 int bpc;
40
41 int nb_planes;
42 int width[4], height[4];
43
44 void (*threshold)(const uint8_t *in, const uint8_t *threshold,
45 const uint8_t *min, const uint8_t *max,
46 uint8_t *out,
47 ptrdiff_t ilinesize, ptrdiff_t tlinesize,
48 ptrdiff_t flinesize, ptrdiff_t slinesize,
49 ptrdiff_t olinesize,
50 int w, int h);
51
52 AVFrame *frames[4];
53 FFFrameSync fs;
54} ThresholdContext;
55
56#define OFFSET(x) offsetof(ThresholdContext, x)
57#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
58
59static const AVOption threshold_options[] = {
60 { "planes", "set planes to filter", OFFSET(planes), AV_OPT_TYPE_INT, {.i64=15}, 0, 15, FLAGS},
61 { NULL }
62};
63
64AVFILTER_DEFINE_CLASS(threshold);
65
66static int query_formats(AVFilterContext *ctx)
67{
68 static const enum AVPixelFormat pix_fmts[] = {
69 AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV440P,
70 AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P,
71 AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUV420P,
72 AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ420P,
73 AV_PIX_FMT_YUVJ411P, AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P,
74 AV_PIX_FMT_YUV420P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV444P9,
75 AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10,
76 AV_PIX_FMT_YUV420P16, AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV444P16,
77 AV_PIX_FMT_YUVA420P9, AV_PIX_FMT_YUVA422P9, AV_PIX_FMT_YUVA444P9,
78 AV_PIX_FMT_YUVA420P10, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA444P10,
79 AV_PIX_FMT_YUVA420P16, AV_PIX_FMT_YUVA422P16, AV_PIX_FMT_YUVA444P16,
80 AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10,
81 AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16,
82 AV_PIX_FMT_GBRAP, AV_PIX_FMT_GBRAP16,
83 AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY10,
84 AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY16,
85 AV_PIX_FMT_NONE
86 };
87
88 return ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
89}
90
91static int process_frame(FFFrameSync *fs)
92{
93 AVFilterContext *ctx = fs->parent;
94 ThresholdContext *s = fs->opaque;
95 AVFilterLink *outlink = ctx->outputs[0];
96 AVFrame *out, *in, *threshold, *min, *max;
97 int ret;
98
99 if ((ret = ff_framesync_get_frame(&s->fs, 0, &in, 0)) < 0 ||
100 (ret = ff_framesync_get_frame(&s->fs, 1, &threshold, 0)) < 0 ||
101 (ret = ff_framesync_get_frame(&s->fs, 2, &min, 0)) < 0 ||
102 (ret = ff_framesync_get_frame(&s->fs, 3, &max, 0)) < 0)
103 return ret;
104
105 if (ctx->is_disabled) {
106 out = av_frame_clone(in);
107 if (!out)
108 return AVERROR(ENOMEM);
109 } else {
110 int p;
111
112 out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
113 if (!out)
114 return AVERROR(ENOMEM);
115 av_frame_copy_props(out, in);
116
117 for (p = 0; p < s->nb_planes; p++) {
118 if (!(s->planes & (1 << p))) {
119 av_image_copy_plane(out->data[p], out->linesize[p],
120 in->data[p], in->linesize[p],
121 s->width[p] * s->bpc,
122 s->height[p]);
123 continue;
124 }
125 s->threshold(in->data[p], threshold->data[p],
126 min->data[p], max->data[p],
127 out->data[p],
128 in->linesize[p], threshold->linesize[p],
129 min->linesize[p], max->linesize[p],
130 out->linesize[p],
131 s->width[p], s->height[p]);
132 }
133 }
134
135 out->pts = av_rescale_q(s->fs.pts, s->fs.time_base, outlink->time_base);
136
137 return ff_filter_frame(outlink, out);
138}
139
140static void threshold8(const uint8_t *in, const uint8_t *threshold,
141 const uint8_t *min, const uint8_t *max,
142 uint8_t *out,
143 ptrdiff_t ilinesize, ptrdiff_t tlinesize,
144 ptrdiff_t flinesize, ptrdiff_t slinesize,
145 ptrdiff_t olinesize,
146 int w, int h)
147{
148 int x, y;
149
150 for (y = 0; y < h; y++) {
151 for (x = 0; x < w; x++) {
152 out[x] = in[x] < threshold[x] ? min[x] : max[x];
153 }
154
155 in += ilinesize;
156 threshold += tlinesize;
157 min += flinesize;
158 max += flinesize;
159 out += olinesize;
160 }
161}
162
163static void threshold16(const uint8_t *iin, const uint8_t *tthreshold,
164 const uint8_t *ffirst, const uint8_t *ssecond,
165 uint8_t *oout,
166 ptrdiff_t ilinesize, ptrdiff_t tlinesize,
167 ptrdiff_t flinesize, ptrdiff_t slinesize,
168 ptrdiff_t olinesize,
169 int w, int h)
170{
171 const uint16_t *in = (const uint16_t *)iin;
172 const uint16_t *threshold = (const uint16_t *)tthreshold;
173 const uint16_t *min = (const uint16_t *)ffirst;
174 const uint16_t *max = (const uint16_t *)ssecond;
175 uint16_t *out = (uint16_t *)oout;
176 int x, y;
177
178 for (y = 0; y < h; y++) {
179 for (x = 0; x < w; x++) {
180 out[x] = in[x] < threshold[x] ? min[x] : max[x];
181 }
182
183 in += ilinesize / 2;
184 threshold += tlinesize / 2;
185 min += flinesize / 2;
186 max += flinesize / 2;
187 out += olinesize / 2;
188 }
189}
190
191static int config_input(AVFilterLink *inlink)
192{
193 AVFilterContext *ctx = inlink->dst;
194 ThresholdContext *s = ctx->priv;
195 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
196 int vsub, hsub;
197
198 s->nb_planes = av_pix_fmt_count_planes(inlink->format);
199
200 hsub = desc->log2_chroma_w;
201 vsub = desc->log2_chroma_h;
202 s->height[1] = s->height[2] = AV_CEIL_RSHIFT(inlink->h, vsub);
203 s->height[0] = s->height[3] = inlink->h;
204 s->width[1] = s->width[2] = AV_CEIL_RSHIFT(inlink->w, hsub);
205 s->width[0] = s->width[3] = inlink->w;
206
207 if (desc->comp[0].depth == 8) {
208 s->threshold = threshold8;
209 s->bpc = 1;
210 } else {
211 s->threshold = threshold16;
212 s->bpc = 2;
213 }
214
215 return 0;
216}
217
218static int config_output(AVFilterLink *outlink)
219{
220 AVFilterContext *ctx = outlink->src;
221 ThresholdContext *s = ctx->priv;
222 AVFilterLink *base = ctx->inputs[0];
223 AVFilterLink *threshold = ctx->inputs[1];
224 AVFilterLink *min = ctx->inputs[2];
225 AVFilterLink *max = ctx->inputs[3];
226 FFFrameSyncIn *in;
227 int ret;
228
229 if (base->format != threshold->format ||
230 base->format != min->format ||
231 base->format != max->format) {
232 av_log(ctx, AV_LOG_ERROR, "inputs must be of same pixel format\n");
233 return AVERROR(EINVAL);
234 }
235 if (base->w != threshold->w ||
236 base->h != threshold->h ||
237 base->w != min->w ||
238 base->h != min->h ||
239 base->w != max->w ||
240 base->h != max->h) {
241 av_log(ctx, AV_LOG_ERROR, "First input link %s parameters "
242 "(size %dx%d) do not match the corresponding "
243 "second input link %s parameters (%dx%d) "
244 "and/or third input link %s parameters (%dx%d) "
245 "and/or fourth input link %s parameters (%dx%d)\n",
246 ctx->input_pads[0].name, base->w, base->h,
247 ctx->input_pads[1].name, threshold->w, threshold->h,
248 ctx->input_pads[2].name, min->w, min->h,
249 ctx->input_pads[3].name, max->w, max->h);
250 return AVERROR(EINVAL);
251 }
252
253 outlink->w = base->w;
254 outlink->h = base->h;
255 outlink->time_base = base->time_base;
256 outlink->sample_aspect_ratio = base->sample_aspect_ratio;
257 outlink->frame_rate = base->frame_rate;
258
259 if ((ret = ff_framesync_init(&s->fs, ctx, 4)) < 0)
260 return ret;
261
262 in = s->fs.in;
263 in[0].time_base = base->time_base;
264 in[1].time_base = threshold->time_base;
265 in[2].time_base = min->time_base;
266 in[3].time_base = max->time_base;
267 in[0].sync = 1;
268 in[0].before = EXT_STOP;
269 in[0].after = EXT_STOP;
270 in[1].sync = 1;
271 in[1].before = EXT_STOP;
272 in[1].after = EXT_STOP;
273 in[2].sync = 1;
274 in[2].before = EXT_STOP;
275 in[2].after = EXT_STOP;
276 in[3].sync = 1;
277 in[3].before = EXT_STOP;
278 in[3].after = EXT_STOP;
279 s->fs.opaque = s;
280 s->fs.on_event = process_frame;
281
282 return ff_framesync_configure(&s->fs);
283}
284
285static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
286{
287 ThresholdContext *s = inlink->dst->priv;
288 return ff_framesync_filter_frame(&s->fs, inlink, buf);
289}
290
291static int request_frame(AVFilterLink *outlink)
292{
293 ThresholdContext *s = outlink->src->priv;
294 return ff_framesync_request_frame(&s->fs, outlink);
295}
296
297static av_cold void uninit(AVFilterContext *ctx)
298{
299 ThresholdContext *s = ctx->priv;
300
301 ff_framesync_uninit(&s->fs);
302}
303
304static const AVFilterPad inputs[] = {
305 {
306 .name = "default",
307 .type = AVMEDIA_TYPE_VIDEO,
308 .filter_frame = filter_frame,
309 .config_props = config_input,
310 },
311 {
312 .name = "threshold",
313 .type = AVMEDIA_TYPE_VIDEO,
314 .filter_frame = filter_frame,
315 },
316 {
317 .name = "min",
318 .type = AVMEDIA_TYPE_VIDEO,
319 .filter_frame = filter_frame,
320 },
321 {
322 .name = "max",
323 .type = AVMEDIA_TYPE_VIDEO,
324 .filter_frame = filter_frame,
325 },
326 { NULL }
327};
328
329static const AVFilterPad outputs[] = {
330 {
331 .name = "default",
332 .type = AVMEDIA_TYPE_VIDEO,
333 .config_props = config_output,
334 .request_frame = request_frame,
335 },
336 { NULL }
337};
338
339AVFilter ff_vf_threshold = {
340 .name = "threshold",
341 .description = NULL_IF_CONFIG_SMALL("Threshold first video stream using other video streams."),
342 .priv_size = sizeof(ThresholdContext),
343 .priv_class = &threshold_class,
344 .uninit = uninit,
345 .query_formats = query_formats,
346 .inputs = inputs,
347 .outputs = outputs,
348 .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
349};

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t