blob: 713e80b04935dcc19a16c85d09555b484e25faf6
1 | /* |
2 | * Copyright (c) 2015 Niklas Haas |
3 | * Copyright (c) 2015 Paul B Mahol |
4 | * |
5 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
6 | * of this software and associated documentation files (the "Software"), to deal |
7 | * in the Software without restriction, including without limitation the rights |
8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
9 | * copies of the Software, and to permit persons to whom the Software is |
10 | * furnished to do so, subject to the following conditions: |
11 | * |
12 | * The above copyright notice and this permission notice shall be included in |
13 | * all copies or substantial portions of the Software. |
14 | * |
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
21 | * SOFTWARE. |
22 | */ |
23 | |
24 | #include "libavutil/opt.h" |
25 | #include "libavutil/pixdesc.h" |
26 | #include "avfilter.h" |
27 | #include "internal.h" |
28 | #include "video.h" |
29 | |
30 | typedef struct DebandContext { |
31 | const AVClass *class; |
32 | |
33 | int coupling; |
34 | float threshold[4]; |
35 | int range; |
36 | int blur; |
37 | float direction; |
38 | |
39 | int nb_components; |
40 | int planewidth[4]; |
41 | int planeheight[4]; |
42 | int shift[2]; |
43 | int thr[4]; |
44 | |
45 | int *x_pos; |
46 | int *y_pos; |
47 | |
48 | int (*deband)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs); |
49 | } DebandContext; |
50 | |
51 | #define OFFSET(x) offsetof(DebandContext, x) |
52 | #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM |
53 | |
54 | static const AVOption deband_options[] = { |
55 | { "1thr", "set 1st plane threshold", OFFSET(threshold[0]), AV_OPT_TYPE_FLOAT, {.dbl=0.02}, 0.00003, 0.5, FLAGS }, |
56 | { "2thr", "set 2nd plane threshold", OFFSET(threshold[1]), AV_OPT_TYPE_FLOAT, {.dbl=0.02}, 0.00003, 0.5, FLAGS }, |
57 | { "3thr", "set 3rd plane threshold", OFFSET(threshold[2]), AV_OPT_TYPE_FLOAT, {.dbl=0.02}, 0.00003, 0.5, FLAGS }, |
58 | { "4thr", "set 4th plane threshold", OFFSET(threshold[3]), AV_OPT_TYPE_FLOAT, {.dbl=0.02}, 0.00003, 0.5, FLAGS }, |
59 | { "range", "set range", OFFSET(range), AV_OPT_TYPE_INT, {.i64=16}, INT_MIN, INT_MAX, FLAGS }, |
60 | { "r", "set range", OFFSET(range), AV_OPT_TYPE_INT, {.i64=16}, INT_MIN, INT_MAX, FLAGS }, |
61 | { "direction", "set direction", OFFSET(direction), AV_OPT_TYPE_FLOAT, {.dbl=2*M_PI},-2*M_PI, 2*M_PI, FLAGS }, |
62 | { "d", "set direction", OFFSET(direction), AV_OPT_TYPE_FLOAT, {.dbl=2*M_PI},-2*M_PI, 2*M_PI, FLAGS }, |
63 | { "blur", "set blur", OFFSET(blur), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGS }, |
64 | { "b", "set blur", OFFSET(blur), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGS }, |
65 | { "coupling", "set plane coupling", OFFSET(coupling), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS }, |
66 | { "c", "set plane coupling", OFFSET(coupling), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS }, |
67 | { NULL } |
68 | }; |
69 | |
70 | AVFILTER_DEFINE_CLASS(deband); |
71 | |
72 | static int query_formats(AVFilterContext *ctx) |
73 | { |
74 | DebandContext *s = ctx->priv; |
75 | |
76 | static const enum AVPixelFormat pix_fmts[] = { |
77 | AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY16, |
78 | AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV420P, |
79 | AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV440P, |
80 | AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ420P, |
81 | AV_PIX_FMT_YUVJ411P, AV_PIX_FMT_YUVJ440P, |
82 | AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA444P, |
83 | AV_PIX_FMT_YUV420P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV444P9, |
84 | AV_PIX_FMT_YUVA420P9, AV_PIX_FMT_YUVA422P9, AV_PIX_FMT_YUVA444P9, |
85 | AV_PIX_FMT_YUVA420P10, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA444P10, |
86 | AV_PIX_FMT_YUV420P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV444P12, |
87 | AV_PIX_FMT_YUV420P14, AV_PIX_FMT_YUV422P14, AV_PIX_FMT_YUV444P14, |
88 | AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP, |
89 | AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10, |
90 | AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, |
91 | AV_PIX_FMT_GBRP16, AV_PIX_FMT_GBRAP16, |
92 | AV_PIX_FMT_YUV420P16, AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV444P16, |
93 | AV_PIX_FMT_YUVA420P16, AV_PIX_FMT_YUVA422P16, AV_PIX_FMT_YUVA444P16, |
94 | AV_PIX_FMT_NONE |
95 | }; |
96 | |
97 | static const enum AVPixelFormat cpix_fmts[] = { |
98 | AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVJ444P, |
99 | AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUV444P9, |
100 | AV_PIX_FMT_YUVA444P9, AV_PIX_FMT_YUVA444P10, |
101 | AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV444P14, |
102 | AV_PIX_FMT_YUV444P16, AV_PIX_FMT_YUVA444P16, |
103 | AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP, |
104 | AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10, |
105 | AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, |
106 | AV_PIX_FMT_GBRP16, AV_PIX_FMT_GBRAP16, |
107 | AV_PIX_FMT_NONE |
108 | }; |
109 | |
110 | AVFilterFormats *fmts_list = ff_make_format_list(s->coupling ? cpix_fmts : pix_fmts); |
111 | if (!fmts_list) |
112 | return AVERROR(ENOMEM); |
113 | |
114 | return ff_set_common_formats(ctx, fmts_list); |
115 | } |
116 | |
117 | static float frand(int x, int y) |
118 | { |
119 | const float r = sinf(x * 12.9898 + y * 78.233) * 43758.545; |
120 | |
121 | return r - floorf(r); |
122 | } |
123 | |
124 | static int inline get_avg(int ref0, int ref1, int ref2, int ref3) |
125 | { |
126 | return (ref0 + ref1 + ref2 + ref3) / 4; |
127 | } |
128 | |
129 | typedef struct ThreadData { |
130 | AVFrame *in, *out; |
131 | } ThreadData; |
132 | |
133 | static int deband_8_c(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) |
134 | { |
135 | DebandContext *s = ctx->priv; |
136 | ThreadData *td = arg; |
137 | AVFrame *in = td->in; |
138 | AVFrame *out = td->out; |
139 | int x, y, p; |
140 | |
141 | for (p = 0; p < s->nb_components; p++) { |
142 | const uint8_t *src_ptr = (const uint8_t *)in->data[p]; |
143 | uint8_t *dst_ptr = (uint8_t *)out->data[p]; |
144 | const int dst_linesize = out->linesize[p]; |
145 | const int src_linesize = in->linesize[p]; |
146 | const int thr = s->thr[p]; |
147 | const int start = (s->planeheight[p] * jobnr ) / nb_jobs; |
148 | const int end = (s->planeheight[p] * (jobnr+1)) / nb_jobs; |
149 | const int w = s->planewidth[p] - 1; |
150 | const int h = s->planeheight[p] - 1; |
151 | |
152 | for (y = start; y < end; y++) { |
153 | const int pos = y * s->planewidth[0]; |
154 | |
155 | for (x = 0; x < s->planewidth[p]; x++) { |
156 | const int x_pos = s->x_pos[pos + x]; |
157 | const int y_pos = s->y_pos[pos + x]; |
158 | const int ref0 = src_ptr[av_clip(y + y_pos, 0, h) * src_linesize + av_clip(x + x_pos, 0, w)]; |
159 | const int ref1 = src_ptr[av_clip(y + -y_pos, 0, h) * src_linesize + av_clip(x + x_pos, 0, w)]; |
160 | const int ref2 = src_ptr[av_clip(y + -y_pos, 0, h) * src_linesize + av_clip(x + -x_pos, 0, w)]; |
161 | const int ref3 = src_ptr[av_clip(y + y_pos, 0, h) * src_linesize + av_clip(x + -x_pos, 0, w)]; |
162 | const int src0 = src_ptr[y * src_linesize + x]; |
163 | |
164 | if (s->blur) { |
165 | const int avg = get_avg(ref0, ref1, ref2, ref3); |
166 | const int diff = FFABS(src0 - avg); |
167 | |
168 | dst_ptr[y * dst_linesize + x] = diff < thr ? avg : src0; |
169 | } else { |
170 | dst_ptr[y * dst_linesize + x] = (FFABS(src0 - ref0) < thr) && |
171 | (FFABS(src0 - ref1) < thr) && |
172 | (FFABS(src0 - ref2) < thr) && |
173 | (FFABS(src0 - ref3) < thr) ? get_avg(ref0, ref1, ref2, ref3) : src0; |
174 | } |
175 | } |
176 | } |
177 | } |
178 | |
179 | return 0; |
180 | } |
181 | |
182 | static int deband_8_coupling_c(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) |
183 | { |
184 | DebandContext *s = ctx->priv; |
185 | ThreadData *td = arg; |
186 | AVFrame *in = td->in; |
187 | AVFrame *out = td->out; |
188 | const int start = (s->planeheight[0] * jobnr ) / nb_jobs; |
189 | const int end = (s->planeheight[0] * (jobnr+1)) / nb_jobs; |
190 | int x, y, p; |
191 | |
192 | for (y = start; y < end; y++) { |
193 | const int pos = y * s->planewidth[0]; |
194 | |
195 | for (x = 0; x < s->planewidth[0]; x++) { |
196 | const int x_pos = s->x_pos[pos + x]; |
197 | const int y_pos = s->y_pos[pos + x]; |
198 | int avg[4], cmp[4] = { 0 }, src[4]; |
199 | |
200 | for (p = 0; p < s->nb_components; p++) { |
201 | const uint8_t *src_ptr = (const uint8_t *)in->data[p]; |
202 | const int src_linesize = in->linesize[p]; |
203 | const int thr = s->thr[p]; |
204 | const int w = s->planewidth[p] - 1; |
205 | const int h = s->planeheight[p] - 1; |
206 | const int ref0 = src_ptr[av_clip(y + y_pos, 0, h) * src_linesize + av_clip(x + x_pos, 0, w)]; |
207 | const int ref1 = src_ptr[av_clip(y + -y_pos, 0, h) * src_linesize + av_clip(x + x_pos, 0, w)]; |
208 | const int ref2 = src_ptr[av_clip(y + -y_pos, 0, h) * src_linesize + av_clip(x + -x_pos, 0, w)]; |
209 | const int ref3 = src_ptr[av_clip(y + y_pos, 0, h) * src_linesize + av_clip(x + -x_pos, 0, w)]; |
210 | const int src0 = src_ptr[y * src_linesize + x]; |
211 | |
212 | src[p] = src0; |
213 | avg[p] = get_avg(ref0, ref1, ref2, ref3); |
214 | |
215 | if (s->blur) { |
216 | cmp[p] = FFABS(src0 - avg[p]) < thr; |
217 | } else { |
218 | cmp[p] = (FFABS(src0 - ref0) < thr) && |
219 | (FFABS(src0 - ref1) < thr) && |
220 | (FFABS(src0 - ref2) < thr) && |
221 | (FFABS(src0 - ref3) < thr); |
222 | } |
223 | } |
224 | |
225 | for (p = 0; p < s->nb_components; p++) |
226 | if (!cmp[p]) |
227 | break; |
228 | if (p == s->nb_components) { |
229 | for (p = 0; p < s->nb_components; p++) { |
230 | const int dst_linesize = out->linesize[p]; |
231 | |
232 | out->data[p][y * dst_linesize + x] = avg[p]; |
233 | } |
234 | } else { |
235 | for (p = 0; p < s->nb_components; p++) { |
236 | const int dst_linesize = out->linesize[p]; |
237 | |
238 | out->data[p][y * dst_linesize + x] = src[p]; |
239 | } |
240 | } |
241 | } |
242 | } |
243 | |
244 | return 0; |
245 | } |
246 | |
247 | static int deband_16_coupling_c(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) |
248 | { |
249 | DebandContext *s = ctx->priv; |
250 | ThreadData *td = arg; |
251 | AVFrame *in = td->in; |
252 | AVFrame *out = td->out; |
253 | const int start = (s->planeheight[0] * jobnr ) / nb_jobs; |
254 | const int end = (s->planeheight[0] * (jobnr+1)) / nb_jobs; |
255 | int x, y, p, z; |
256 | |
257 | for (y = start; y < end; y++) { |
258 | const int pos = y * s->planewidth[0]; |
259 | |
260 | for (x = 0; x < s->planewidth[0]; x++) { |
261 | const int x_pos = s->x_pos[pos + x]; |
262 | const int y_pos = s->y_pos[pos + x]; |
263 | int avg[4], cmp[4] = { 0 }, src[4]; |
264 | |
265 | for (p = 0; p < s->nb_components; p++) { |
266 | const uint16_t *src_ptr = (const uint16_t *)in->data[p]; |
267 | const int src_linesize = in->linesize[p] / 2; |
268 | const int thr = s->thr[p]; |
269 | const int w = s->planewidth[p] - 1; |
270 | const int h = s->planeheight[p] - 1; |
271 | const int ref0 = src_ptr[av_clip(y + y_pos, 0, h) * src_linesize + av_clip(x + x_pos, 0, w)]; |
272 | const int ref1 = src_ptr[av_clip(y + -y_pos, 0, h) * src_linesize + av_clip(x + x_pos, 0, w)]; |
273 | const int ref2 = src_ptr[av_clip(y + -y_pos, 0, h) * src_linesize + av_clip(x + -x_pos, 0, w)]; |
274 | const int ref3 = src_ptr[av_clip(y + y_pos, 0, h) * src_linesize + av_clip(x + -x_pos, 0, w)]; |
275 | const int src0 = src_ptr[y * src_linesize + x]; |
276 | |
277 | src[p] = src0; |
278 | avg[p] = get_avg(ref0, ref1, ref2, ref3); |
279 | |
280 | if (s->blur) { |
281 | cmp[p] = FFABS(src0 - avg[p]) < thr; |
282 | } else { |
283 | cmp[p] = (FFABS(src0 - ref0) < thr) && |
284 | (FFABS(src0 - ref1) < thr) && |
285 | (FFABS(src0 - ref2) < thr) && |
286 | (FFABS(src0 - ref3) < thr); |
287 | } |
288 | } |
289 | |
290 | for (z = 0; z < s->nb_components; z++) |
291 | if (!cmp[z]) |
292 | break; |
293 | if (z == s->nb_components) { |
294 | for (p = 0; p < s->nb_components; p++) { |
295 | const int dst_linesize = out->linesize[p] / 2; |
296 | uint16_t *dst = (uint16_t *)out->data[p] + y * dst_linesize + x; |
297 | |
298 | dst[0] = avg[p]; |
299 | } |
300 | } else { |
301 | for (p = 0; p < s->nb_components; p++) { |
302 | const int dst_linesize = out->linesize[p] / 2; |
303 | uint16_t *dst = (uint16_t *)out->data[p] + y * dst_linesize + x; |
304 | |
305 | dst[0] = src[p]; |
306 | } |
307 | } |
308 | } |
309 | } |
310 | |
311 | return 0; |
312 | } |
313 | |
314 | static int deband_16_c(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) |
315 | { |
316 | DebandContext *s = ctx->priv; |
317 | ThreadData *td = arg; |
318 | AVFrame *in = td->in; |
319 | AVFrame *out = td->out; |
320 | int x, y, p; |
321 | |
322 | for (p = 0; p < s->nb_components; p++) { |
323 | const uint16_t *src_ptr = (const uint16_t *)in->data[p]; |
324 | uint16_t *dst_ptr = (uint16_t *)out->data[p]; |
325 | const int dst_linesize = out->linesize[p] / 2; |
326 | const int src_linesize = in->linesize[p] / 2; |
327 | const int thr = s->thr[p]; |
328 | const int start = (s->planeheight[p] * jobnr ) / nb_jobs; |
329 | const int end = (s->planeheight[p] * (jobnr+1)) / nb_jobs; |
330 | const int w = s->planewidth[p] - 1; |
331 | const int h = s->planeheight[p] - 1; |
332 | |
333 | for (y = start; y < end; y++) { |
334 | const int pos = y * s->planewidth[0]; |
335 | |
336 | for (x = 0; x < s->planewidth[p]; x++) { |
337 | const int x_pos = s->x_pos[pos + x]; |
338 | const int y_pos = s->y_pos[pos + x]; |
339 | const int ref0 = src_ptr[av_clip(y + y_pos, 0, h) * src_linesize + av_clip(x + x_pos, 0, w)]; |
340 | const int ref1 = src_ptr[av_clip(y + -y_pos, 0, h) * src_linesize + av_clip(x + x_pos, 0, w)]; |
341 | const int ref2 = src_ptr[av_clip(y + -y_pos, 0, h) * src_linesize + av_clip(x + -x_pos, 0, w)]; |
342 | const int ref3 = src_ptr[av_clip(y + y_pos, 0, h) * src_linesize + av_clip(x + -x_pos, 0, w)]; |
343 | const int src0 = src_ptr[y * src_linesize + x]; |
344 | |
345 | if (s->blur) { |
346 | const int avg = get_avg(ref0, ref1, ref2, ref3); |
347 | const int diff = FFABS(src0 - avg); |
348 | |
349 | dst_ptr[y * dst_linesize + x] = diff < thr ? avg : src0; |
350 | } else { |
351 | dst_ptr[y * dst_linesize + x] = (FFABS(src0 - ref0) < thr) && |
352 | (FFABS(src0 - ref1) < thr) && |
353 | (FFABS(src0 - ref2) < thr) && |
354 | (FFABS(src0 - ref3) < thr) ? get_avg(ref0, ref1, ref2, ref3) : src0; |
355 | } |
356 | } |
357 | } |
358 | } |
359 | |
360 | return 0; |
361 | } |
362 | |
363 | static int config_input(AVFilterLink *inlink) |
364 | { |
365 | const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); |
366 | AVFilterContext *ctx = inlink->dst; |
367 | DebandContext *s = ctx->priv; |
368 | const float direction = s->direction; |
369 | const int range = s->range; |
370 | int x, y; |
371 | |
372 | s->nb_components = desc->nb_components; |
373 | |
374 | s->planeheight[1] = s->planeheight[2] = AV_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h); |
375 | s->planeheight[0] = s->planeheight[3] = inlink->h; |
376 | s->planewidth[1] = s->planewidth[2] = AV_CEIL_RSHIFT(inlink->w, desc->log2_chroma_w); |
377 | s->planewidth[0] = s->planewidth[3] = inlink->w; |
378 | s->shift[0] = desc->log2_chroma_w; |
379 | s->shift[1] = desc->log2_chroma_h; |
380 | |
381 | if (s->coupling) |
382 | s->deband = desc->comp[0].depth > 8 ? deband_16_coupling_c : deband_8_coupling_c; |
383 | else |
384 | s->deband = desc->comp[0].depth > 8 ? deband_16_c : deband_8_c; |
385 | |
386 | s->thr[0] = ((1 << desc->comp[0].depth) - 1) * s->threshold[0]; |
387 | s->thr[1] = ((1 << desc->comp[1].depth) - 1) * s->threshold[1]; |
388 | s->thr[2] = ((1 << desc->comp[2].depth) - 1) * s->threshold[2]; |
389 | s->thr[3] = ((1 << desc->comp[3].depth) - 1) * s->threshold[3]; |
390 | |
391 | s->x_pos = av_malloc(s->planewidth[0] * s->planeheight[0] * sizeof(*s->x_pos)); |
392 | s->y_pos = av_malloc(s->planewidth[0] * s->planeheight[0] * sizeof(*s->y_pos)); |
393 | if (!s->x_pos || !s->y_pos) |
394 | return AVERROR(ENOMEM); |
395 | |
396 | for (y = 0; y < s->planeheight[0]; y++) { |
397 | for (x = 0; x < s->planewidth[0]; x++) { |
398 | const float r = frand(x, y); |
399 | const float dir = direction < 0 ? -direction : r * direction; |
400 | const int dist = range < 0 ? -range : r * range; |
401 | |
402 | s->x_pos[y * s->planewidth[0] + x] = cosf(dir) * dist; |
403 | s->y_pos[y * s->planewidth[0] + x] = sinf(dir) * dist; |
404 | } |
405 | } |
406 | |
407 | return 0; |
408 | } |
409 | |
410 | static int filter_frame(AVFilterLink *inlink, AVFrame *in) |
411 | { |
412 | AVFilterContext *ctx = inlink->dst; |
413 | AVFilterLink *outlink = ctx->outputs[0]; |
414 | DebandContext *s = ctx->priv; |
415 | AVFrame *out; |
416 | ThreadData td; |
417 | |
418 | out = ff_get_video_buffer(outlink, outlink->w, outlink->h); |
419 | if (!out) { |
420 | av_frame_free(&in); |
421 | return AVERROR(ENOMEM); |
422 | } |
423 | av_frame_copy_props(out, in); |
424 | |
425 | td.in = in; td.out = out; |
426 | ctx->internal->execute(ctx, s->deband, &td, NULL, FFMIN3(s->planeheight[1], |
427 | s->planeheight[2], |
428 | ff_filter_get_nb_threads(ctx))); |
429 | |
430 | av_frame_free(&in); |
431 | return ff_filter_frame(outlink, out); |
432 | } |
433 | |
434 | static av_cold void uninit(AVFilterContext *ctx) |
435 | { |
436 | DebandContext *s = ctx->priv; |
437 | |
438 | av_freep(&s->x_pos); |
439 | av_freep(&s->y_pos); |
440 | } |
441 | |
442 | static const AVFilterPad avfilter_vf_deband_inputs[] = { |
443 | { |
444 | .name = "default", |
445 | .type = AVMEDIA_TYPE_VIDEO, |
446 | .config_props = config_input, |
447 | .filter_frame = filter_frame, |
448 | }, |
449 | { NULL } |
450 | }; |
451 | |
452 | static const AVFilterPad avfilter_vf_deband_outputs[] = { |
453 | { |
454 | .name = "default", |
455 | .type = AVMEDIA_TYPE_VIDEO, |
456 | }, |
457 | { NULL } |
458 | }; |
459 | |
460 | AVFilter ff_vf_deband = { |
461 | .name = "deband", |
462 | .description = NULL_IF_CONFIG_SMALL("Debands video."), |
463 | .priv_size = sizeof(DebandContext), |
464 | .priv_class = &deband_class, |
465 | .uninit = uninit, |
466 | .query_formats = query_formats, |
467 | .inputs = avfilter_vf_deband_inputs, |
468 | .outputs = avfilter_vf_deband_outputs, |
469 | .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS, |
470 | }; |
471 |