FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavfilter/vf_bwdif.c
Date: 2022-12-09 07:38:14
Exec Total Coverage
Lines: 0 129 0.0%
Functions: 0 10 0.0%
Branches: 0 104 0.0%

Line Branch Exec Source
1 /*
2 * BobWeaver Deinterlacing Filter
3 * Copyright (C) 2016 Thomas Mundt <loudmax@yahoo.de>
4 *
5 * Based on YADIF (Yet Another Deinterlacing Filter)
6 * Copyright (C) 2006-2011 Michael Niedermayer <michaelni@gmx.at>
7 * 2010 James Darnley <james.darnley@gmail.com>
8 *
9 * With use of Weston 3 Field Deinterlacing Filter algorithm
10 * Copyright (C) 2012 British Broadcasting Corporation, All Rights Reserved
11 * Author of de-interlace algorithm: Jim Easterbrook for BBC R&D
12 * Based on the process described by Martin Weston for BBC R&D
13 *
14 * This file is part of FFmpeg.
15 *
16 * FFmpeg is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU Lesser General Public
18 * License as published by the Free Software Foundation; either
19 * version 2.1 of the License, or (at your option) any later version.
20 *
21 * FFmpeg is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 * Lesser General Public License for more details.
25 *
26 * You should have received a copy of the GNU Lesser General Public
27 * License along with FFmpeg; if not, write to the Free Software
28 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
29 */
30
31 #include "libavutil/common.h"
32 #include "libavutil/opt.h"
33 #include "libavutil/pixdesc.h"
34 #include "libavutil/imgutils.h"
35 #include "avfilter.h"
36 #include "formats.h"
37 #include "internal.h"
38 #include "video.h"
39 #include "bwdif.h"
40
41 /*
42 * Filter coefficients coef_lf and coef_hf taken from BBC PH-2071 (Weston 3 Field Deinterlacer).
43 * Used when there is spatial and temporal interpolation.
44 * Filter coefficients coef_sp are used when there is spatial interpolation only.
45 * Adjusted for matching visual sharpness impression of spatial and temporal interpolation.
46 */
47 static const uint16_t coef_lf[2] = { 4309, 213 };
48 static const uint16_t coef_hf[3] = { 5570, 3801, 1016 };
49 static const uint16_t coef_sp[2] = { 5077, 981 };
50
51 typedef struct ThreadData {
52 AVFrame *frame;
53 int plane;
54 int w, h;
55 int parity;
56 int tff;
57 } ThreadData;
58
59 #define FILTER_INTRA() \
60 for (x = 0; x < w; x++) { \
61 interpol = (coef_sp[0] * (cur[mrefs] + cur[prefs]) - coef_sp[1] * (cur[mrefs3] + cur[prefs3])) >> 13; \
62 dst[0] = av_clip(interpol, 0, clip_max); \
63 \
64 dst++; \
65 cur++; \
66 }
67
68 #define FILTER1() \
69 for (x = 0; x < w; x++) { \
70 int c = cur[mrefs]; \
71 int d = (prev2[0] + next2[0]) >> 1; \
72 int e = cur[prefs]; \
73 int temporal_diff0 = FFABS(prev2[0] - next2[0]); \
74 int temporal_diff1 =(FFABS(prev[mrefs] - c) + FFABS(prev[prefs] - e)) >> 1; \
75 int temporal_diff2 =(FFABS(next[mrefs] - c) + FFABS(next[prefs] - e)) >> 1; \
76 int diff = FFMAX3(temporal_diff0 >> 1, temporal_diff1, temporal_diff2); \
77 \
78 if (!diff) { \
79 dst[0] = d; \
80 } else {
81
82 #define SPAT_CHECK() \
83 int b = ((prev2[mrefs2] + next2[mrefs2]) >> 1) - c; \
84 int f = ((prev2[prefs2] + next2[prefs2]) >> 1) - e; \
85 int dc = d - c; \
86 int de = d - e; \
87 int max = FFMAX3(de, dc, FFMIN(b, f)); \
88 int min = FFMIN3(de, dc, FFMAX(b, f)); \
89 diff = FFMAX3(diff, min, -max);
90
91 #define FILTER_LINE() \
92 SPAT_CHECK() \
93 if (FFABS(c - e) > temporal_diff0) { \
94 interpol = (((coef_hf[0] * (prev2[0] + next2[0]) \
95 - coef_hf[1] * (prev2[mrefs2] + next2[mrefs2] + prev2[prefs2] + next2[prefs2]) \
96 + coef_hf[2] * (prev2[mrefs4] + next2[mrefs4] + prev2[prefs4] + next2[prefs4])) >> 2) \
97 + coef_lf[0] * (c + e) - coef_lf[1] * (cur[mrefs3] + cur[prefs3])) >> 13; \
98 } else { \
99 interpol = (coef_sp[0] * (c + e) - coef_sp[1] * (cur[mrefs3] + cur[prefs3])) >> 13; \
100 }
101
102 #define FILTER_EDGE() \
103 if (spat) { \
104 SPAT_CHECK() \
105 } \
106 interpol = (c + e) >> 1;
107
108 #define FILTER2() \
109 if (interpol > d + diff) \
110 interpol = d + diff; \
111 else if (interpol < d - diff) \
112 interpol = d - diff; \
113 \
114 dst[0] = av_clip(interpol, 0, clip_max); \
115 } \
116 \
117 dst++; \
118 cur++; \
119 prev++; \
120 next++; \
121 prev2++; \
122 next2++; \
123 }
124
125 static void filter_intra(void *dst1, void *cur1, int w, int prefs, int mrefs,
126 int prefs3, int mrefs3, int parity, int clip_max)
127 {
128 uint8_t *dst = dst1;
129 uint8_t *cur = cur1;
130 int interpol, x;
131
132 FILTER_INTRA()
133 }
134
135 static void filter_line_c(void *dst1, void *prev1, void *cur1, void *next1,
136 int w, int prefs, int mrefs, int prefs2, int mrefs2,
137 int prefs3, int mrefs3, int prefs4, int mrefs4,
138 int parity, int clip_max)
139 {
140 uint8_t *dst = dst1;
141 uint8_t *prev = prev1;
142 uint8_t *cur = cur1;
143 uint8_t *next = next1;
144 uint8_t *prev2 = parity ? prev : cur ;
145 uint8_t *next2 = parity ? cur : next;
146 int interpol, x;
147
148 FILTER1()
149 FILTER_LINE()
150 FILTER2()
151 }
152
153 static void filter_edge(void *dst1, void *prev1, void *cur1, void *next1,
154 int w, int prefs, int mrefs, int prefs2, int mrefs2,
155 int parity, int clip_max, int spat)
156 {
157 uint8_t *dst = dst1;
158 uint8_t *prev = prev1;
159 uint8_t *cur = cur1;
160 uint8_t *next = next1;
161 uint8_t *prev2 = parity ? prev : cur ;
162 uint8_t *next2 = parity ? cur : next;
163 int interpol, x;
164
165 FILTER1()
166 FILTER_EDGE()
167 FILTER2()
168 }
169
170 static void filter_intra_16bit(void *dst1, void *cur1, int w, int prefs, int mrefs,
171 int prefs3, int mrefs3, int parity, int clip_max)
172 {
173 uint16_t *dst = dst1;
174 uint16_t *cur = cur1;
175 int interpol, x;
176
177 FILTER_INTRA()
178 }
179
180 static void filter_line_c_16bit(void *dst1, void *prev1, void *cur1, void *next1,
181 int w, int prefs, int mrefs, int prefs2, int mrefs2,
182 int prefs3, int mrefs3, int prefs4, int mrefs4,
183 int parity, int clip_max)
184 {
185 uint16_t *dst = dst1;
186 uint16_t *prev = prev1;
187 uint16_t *cur = cur1;
188 uint16_t *next = next1;
189 uint16_t *prev2 = parity ? prev : cur ;
190 uint16_t *next2 = parity ? cur : next;
191 int interpol, x;
192
193 FILTER1()
194 FILTER_LINE()
195 FILTER2()
196 }
197
198 static void filter_edge_16bit(void *dst1, void *prev1, void *cur1, void *next1,
199 int w, int prefs, int mrefs, int prefs2, int mrefs2,
200 int parity, int clip_max, int spat)
201 {
202 uint16_t *dst = dst1;
203 uint16_t *prev = prev1;
204 uint16_t *cur = cur1;
205 uint16_t *next = next1;
206 uint16_t *prev2 = parity ? prev : cur ;
207 uint16_t *next2 = parity ? cur : next;
208 int interpol, x;
209
210 FILTER1()
211 FILTER_EDGE()
212 FILTER2()
213 }
214
215 static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
216 {
217 BWDIFContext *s = ctx->priv;
218 YADIFContext *yadif = &s->yadif;
219 ThreadData *td = arg;
220 int linesize = yadif->cur->linesize[td->plane];
221 int clip_max = (1 << (yadif->csp->comp[td->plane].depth)) - 1;
222 int df = (yadif->csp->comp[td->plane].depth + 7) / 8;
223 int refs = linesize / df;
224 int slice_start = (td->h * jobnr ) / nb_jobs;
225 int slice_end = (td->h * (jobnr+1)) / nb_jobs;
226 int y;
227
228 for (y = slice_start; y < slice_end; y++) {
229 if ((y ^ td->parity) & 1) {
230 uint8_t *prev = &yadif->prev->data[td->plane][y * linesize];
231 uint8_t *cur = &yadif->cur ->data[td->plane][y * linesize];
232 uint8_t *next = &yadif->next->data[td->plane][y * linesize];
233 uint8_t *dst = &td->frame->data[td->plane][y * td->frame->linesize[td->plane]];
234 if (yadif->current_field == YADIF_FIELD_END) {
235 s->filter_intra(dst, cur, td->w, (y + df) < td->h ? refs : -refs,
236 y > (df - 1) ? -refs : refs,
237 (y + 3*df) < td->h ? 3 * refs : -refs,
238 y > (3*df - 1) ? -3 * refs : refs,
239 td->parity ^ td->tff, clip_max);
240 } else if ((y < 4) || ((y + 5) > td->h)) {
241 s->filter_edge(dst, prev, cur, next, td->w,
242 (y + df) < td->h ? refs : -refs,
243 y > (df - 1) ? -refs : refs,
244 refs << 1, -(refs << 1),
245 td->parity ^ td->tff, clip_max,
246 (y < 2) || ((y + 3) > td->h) ? 0 : 1);
247 } else {
248 s->filter_line(dst, prev, cur, next, td->w,
249 refs, -refs, refs << 1, -(refs << 1),
250 3 * refs, -3 * refs, refs << 2, -(refs << 2),
251 td->parity ^ td->tff, clip_max);
252 }
253 } else {
254 memcpy(&td->frame->data[td->plane][y * td->frame->linesize[td->plane]],
255 &yadif->cur->data[td->plane][y * linesize], td->w * df);
256 }
257 }
258 return 0;
259 }
260
261 static void filter(AVFilterContext *ctx, AVFrame *dstpic,
262 int parity, int tff)
263 {
264 BWDIFContext *bwdif = ctx->priv;
265 YADIFContext *yadif = &bwdif->yadif;
266 ThreadData td = { .frame = dstpic, .parity = parity, .tff = tff };
267 int i;
268
269 for (i = 0; i < yadif->csp->nb_components; i++) {
270 int w = dstpic->width;
271 int h = dstpic->height;
272
273 if (i == 1 || i == 2) {
274 w = AV_CEIL_RSHIFT(w, yadif->csp->log2_chroma_w);
275 h = AV_CEIL_RSHIFT(h, yadif->csp->log2_chroma_h);
276 }
277
278 td.w = w;
279 td.h = h;
280 td.plane = i;
281
282 ff_filter_execute(ctx, filter_slice, &td, NULL,
283 FFMIN(h, ff_filter_get_nb_threads(ctx)));
284 }
285 if (yadif->current_field == YADIF_FIELD_END) {
286 yadif->current_field = YADIF_FIELD_NORMAL;
287 }
288
289 emms_c();
290 }
291
292 static av_cold void uninit(AVFilterContext *ctx)
293 {
294 BWDIFContext *bwdif = ctx->priv;
295 YADIFContext *yadif = &bwdif->yadif;
296
297 av_frame_free(&yadif->prev);
298 av_frame_free(&yadif->cur );
299 av_frame_free(&yadif->next);
300 }
301
302 static const enum AVPixelFormat pix_fmts[] = {
303 AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV420P,
304 AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV444P,
305 AV_PIX_FMT_YUVJ411P, AV_PIX_FMT_YUVJ420P,
306 AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_YUVJ444P,
307 AV_PIX_FMT_YUV420P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV444P9,
308 AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10,
309 AV_PIX_FMT_YUV420P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV444P12,
310 AV_PIX_FMT_YUV420P14, AV_PIX_FMT_YUV422P14, AV_PIX_FMT_YUV444P14,
311 AV_PIX_FMT_YUV420P16, AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV444P16,
312 AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA444P,
313 AV_PIX_FMT_YUVA420P9, AV_PIX_FMT_YUVA422P9, AV_PIX_FMT_YUVA444P9,
314 AV_PIX_FMT_YUVA420P10, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA444P10,
315 AV_PIX_FMT_YUVA420P16, AV_PIX_FMT_YUVA422P16, AV_PIX_FMT_YUVA444P16,
316 AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10,
317 AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16,
318 AV_PIX_FMT_GBRAP, AV_PIX_FMT_GBRAP16,
319 AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY16,
320 AV_PIX_FMT_NONE
321 };
322
323 static int config_props(AVFilterLink *link)
324 {
325 AVFilterContext *ctx = link->src;
326 BWDIFContext *s = link->src->priv;
327 YADIFContext *yadif = &s->yadif;
328
329 link->time_base = av_mul_q(ctx->inputs[0]->time_base, (AVRational){1, 2});
330 link->w = link->src->inputs[0]->w;
331 link->h = link->src->inputs[0]->h;
332
333 if(yadif->mode&1)
334 link->frame_rate = av_mul_q(link->src->inputs[0]->frame_rate, (AVRational){2,1});
335
336 if (link->w < 3 || link->h < 4) {
337 av_log(ctx, AV_LOG_ERROR, "Video of less than 3 columns or 4 lines is not supported\n");
338 return AVERROR(EINVAL);
339 }
340
341 yadif->csp = av_pix_fmt_desc_get(link->format);
342 yadif->filter = filter;
343 if (yadif->csp->comp[0].depth > 8) {
344 s->filter_intra = filter_intra_16bit;
345 s->filter_line = filter_line_c_16bit;
346 s->filter_edge = filter_edge_16bit;
347 } else {
348 s->filter_intra = filter_intra;
349 s->filter_line = filter_line_c;
350 s->filter_edge = filter_edge;
351 }
352
353 #if ARCH_X86
354 ff_bwdif_init_x86(s);
355 #endif
356
357 return 0;
358 }
359
360
361 #define OFFSET(x) offsetof(YADIFContext, x)
362 #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
363
364 #define CONST(name, help, val, unit) { name, help, 0, AV_OPT_TYPE_CONST, {.i64=val}, INT_MIN, INT_MAX, FLAGS, unit }
365
366 static const AVOption bwdif_options[] = {
367 { "mode", "specify the interlacing mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=YADIF_MODE_SEND_FIELD}, 0, 1, FLAGS, "mode"},
368 CONST("send_frame", "send one frame for each frame", YADIF_MODE_SEND_FRAME, "mode"),
369 CONST("send_field", "send one frame for each field", YADIF_MODE_SEND_FIELD, "mode"),
370
371 { "parity", "specify the assumed picture field parity", OFFSET(parity), AV_OPT_TYPE_INT, {.i64=YADIF_PARITY_AUTO}, -1, 1, FLAGS, "parity" },
372 CONST("tff", "assume top field first", YADIF_PARITY_TFF, "parity"),
373 CONST("bff", "assume bottom field first", YADIF_PARITY_BFF, "parity"),
374 CONST("auto", "auto detect parity", YADIF_PARITY_AUTO, "parity"),
375
376 { "deint", "specify which frames to deinterlace", OFFSET(deint), AV_OPT_TYPE_INT, {.i64=YADIF_DEINT_ALL}, 0, 1, FLAGS, "deint" },
377 CONST("all", "deinterlace all frames", YADIF_DEINT_ALL, "deint"),
378 CONST("interlaced", "only deinterlace frames marked as interlaced", YADIF_DEINT_INTERLACED, "deint"),
379
380 { NULL }
381 };
382
383 AVFILTER_DEFINE_CLASS(bwdif);
384
385 static const AVFilterPad avfilter_vf_bwdif_inputs[] = {
386 {
387 .name = "default",
388 .type = AVMEDIA_TYPE_VIDEO,
389 .filter_frame = ff_yadif_filter_frame,
390 },
391 };
392
393 static const AVFilterPad avfilter_vf_bwdif_outputs[] = {
394 {
395 .name = "default",
396 .type = AVMEDIA_TYPE_VIDEO,
397 .request_frame = ff_yadif_request_frame,
398 .config_props = config_props,
399 },
400 };
401
402 const AVFilter ff_vf_bwdif = {
403 .name = "bwdif",
404 .description = NULL_IF_CONFIG_SMALL("Deinterlace the input image."),
405 .priv_size = sizeof(BWDIFContext),
406 .priv_class = &bwdif_class,
407 .uninit = uninit,
408 FILTER_INPUTS(avfilter_vf_bwdif_inputs),
409 FILTER_OUTPUTS(avfilter_vf_bwdif_outputs),
410 FILTER_PIXFMTS_ARRAY(pix_fmts),
411 .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | AVFILTER_FLAG_SLICE_THREADS,
412 };
413