History

avfilter: add threshold filter

Paul B Mahol committed 10 years ago

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

Showing the changes to libavfilter (4 of 6 files). Show all

Unified · Split

4 files
  1. libavfilter/Makefile +1 −0
  2. libavfilter/allfilters.c +1 −0
  3. libavfilter/version.h +1 −1
  4. libavfilter/vf_threshold.c +349 −0
libavfilter/Makefile+1−0
@@ -289,6 +289,7 @@ OBJS-$(CONFIG_SWAPRECT_FILTER) += vf_swaprect.o · 288 unmodified lines
289289 OBJS-$(CONFIG_SWAPUV_FILTER) += vf_swapuv.o
290290 OBJS-$(CONFIG_TBLEND_FILTER) += vf_blend.o dualinput.o framesync.o
291291 OBJS-$(CONFIG_TELECINE_FILTER) += vf_telecine.o
292+OBJS-$(CONFIG_THRESHOLD_FILTER) += vf_threshold.o
292293 OBJS-$(CONFIG_THUMBNAIL_FILTER) += vf_thumbnail.o
293294 OBJS-$(CONFIG_TILE_FILTER) += vf_tile.o
294295 OBJS-$(CONFIG_TINTERLACE_FILTER) += vf_tinterlace.o
libavfilter/allfilters.c+1−0
@@ -304,6 +304,7 @@ void avfilter_register_all(void) · 303 unmodified lines
304304 REGISTER_FILTER(SWAPUV, swapuv, vf);
305305 REGISTER_FILTER(TBLEND, tblend, vf);
306306 REGISTER_FILTER(TELECINE, telecine, vf);
307+ REGISTER_FILTER(THRESHOLD, threshold, vf);
307308 REGISTER_FILTER(THUMBNAIL, thumbnail, vf);
308309 REGISTER_FILTER(TILE, tile, vf);
309310 REGISTER_FILTER(TINTERLACE, tinterlace, vf);
libavfilter/version.h+1−1
@@ -30,7 +30,7 @@ · 29 unmodified lines
3030 #include "libavutil/version.h"
3131
3232 #define LIBAVFILTER_VERSION_MAJOR 6
33−#define LIBAVFILTER_VERSION_MINOR 71
33+#define LIBAVFILTER_VERSION_MINOR 72
3434 #define LIBAVFILTER_VERSION_MICRO 100
3535
3636 #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+
35+typedef 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+
59+static 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+
64+AVFILTER_DEFINE_CLASS(threshold);
65+
66+static 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+
91+static 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+
140+static 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+
163+static 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+
191+static 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+
218+static 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+
285+static 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+
291+static int request_frame(AVFilterLink *outlink)
292+{
293+ ThresholdContext *s = outlink->src->priv;
294+ return ff_framesync_request_frame(&s->fs, outlink);
295+}
296+
297+static av_cold void uninit(AVFilterContext *ctx)
298+{
299+ ThresholdContext *s = ctx->priv;
300+
301+ ff_framesync_uninit(&s->fs);
302+}
303+
304+static 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+
329+static 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+
339+AVFilter 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