]> git.sesse.net Git - ffmpeg/blob - libavfilter/vf_fftdnoiz.c
856d716be53160404b26dc4f148c4033149008fb
[ffmpeg] / libavfilter / vf_fftdnoiz.c
1 /*
2  * This file is part of FFmpeg.
3  *
4  * FFmpeg is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * FFmpeg is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with FFmpeg; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18
19 #include <float.h>
20
21 #include "libavutil/avassert.h"
22 #include "libavutil/common.h"
23 #include "libavutil/imgutils.h"
24 #include "libavutil/opt.h"
25 #include "libavutil/pixdesc.h"
26 #include "internal.h"
27 #include "libavcodec/avfft.h"
28
29 enum BufferTypes {
30     CURRENT,
31     PREV,
32     NEXT,
33     BSIZE
34 };
35
36 typedef struct PlaneContext {
37     int planewidth, planeheight;
38     int nox, noy;
39     int b;
40     int o;
41     float n;
42
43     float *buffer[BSIZE];
44     FFTComplex *hdata, *vdata;
45     int data_linesize;
46     int buffer_linesize;
47
48     FFTContext *fft, *ifft;
49 } PlaneContext;
50
51 typedef struct FFTdnoizContext {
52     const AVClass *class;
53
54     float sigma;
55     float amount;
56     int   block_bits;
57     float overlap;
58     int   nb_prev;
59     int   nb_next;
60     int   planesf;
61
62     AVFrame *prev, *cur, *next;
63
64     int depth;
65     int nb_planes;
66     PlaneContext planes[4];
67
68     void (*import_row)(FFTComplex *dst, uint8_t *src, int rw);
69     void (*export_row)(FFTComplex *src, uint8_t *dst, int rw, float scale, int depth);
70 } FFTdnoizContext;
71
72 #define OFFSET(x) offsetof(FFTdnoizContext, x)
73 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
74 static const AVOption fftdnoiz_options[] = {
75     { "sigma",   "set denoise strength",
76         OFFSET(sigma),      AV_OPT_TYPE_FLOAT, {.dbl=1},        0,  30, .flags = FLAGS },
77     { "amount",  "set amount of denoising",
78         OFFSET(amount),     AV_OPT_TYPE_FLOAT, {.dbl=1},     0.01,   1, .flags = FLAGS },
79     { "block",   "set block log2(size)",
80         OFFSET(block_bits), AV_OPT_TYPE_INT,   {.i64=4},        3,   6, .flags = FLAGS },
81     { "overlap", "set block overlap",
82         OFFSET(overlap),    AV_OPT_TYPE_FLOAT, {.dbl=0.5},    0.2, 0.8, .flags = FLAGS },
83     { "prev",    "set number of previous frames for temporal denoising",
84         OFFSET(nb_prev),    AV_OPT_TYPE_INT,   {.i64=0},        0,   1, .flags = FLAGS },
85     { "next",    "set number of next frames for temporal denoising",
86         OFFSET(nb_next),    AV_OPT_TYPE_INT,   {.i64=0},        0,   1, .flags = FLAGS },
87     { "planes",  "set planes to filter",
88         OFFSET(planesf),    AV_OPT_TYPE_INT,   {.i64=7},        0,  15, .flags = FLAGS },
89     { NULL }
90 };
91
92 AVFILTER_DEFINE_CLASS(fftdnoiz);
93
94 static av_cold int init(AVFilterContext *ctx)
95 {
96     FFTdnoizContext *s = ctx->priv;
97     int i;
98
99     for (i = 0; i < 4; i++) {
100         PlaneContext *p = &s->planes[i];
101
102         p->fft  = av_fft_init(s->block_bits, 0);
103         p->ifft = av_fft_init(s->block_bits, 1);
104         if (!p->fft || !p->ifft)
105             return AVERROR(ENOMEM);
106     }
107
108     return 0;
109 }
110
111 static int query_formats(AVFilterContext *ctx)
112 {
113     static const enum AVPixelFormat pix_fmts[] = {
114         AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9,
115         AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12,
116         AV_PIX_FMT_GRAY14, AV_PIX_FMT_GRAY16,
117         AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV411P,
118         AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P,
119         AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV444P,
120         AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P,
121         AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_YUVJ444P,
122         AV_PIX_FMT_YUVJ411P,
123         AV_PIX_FMT_YUV420P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV444P9,
124         AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10,
125         AV_PIX_FMT_YUV440P10,
126         AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV420P12,
127         AV_PIX_FMT_YUV440P12,
128         AV_PIX_FMT_YUV444P14, AV_PIX_FMT_YUV422P14, AV_PIX_FMT_YUV420P14,
129         AV_PIX_FMT_YUV420P16, AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV444P16,
130         AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10,
131         AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16,
132         AV_PIX_FMT_YUVA420P,  AV_PIX_FMT_YUVA422P,   AV_PIX_FMT_YUVA444P,
133         AV_PIX_FMT_YUVA444P9, AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_YUVA444P12, AV_PIX_FMT_YUVA444P16,
134         AV_PIX_FMT_YUVA422P9, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA422P12, AV_PIX_FMT_YUVA422P16,
135         AV_PIX_FMT_YUVA420P9, AV_PIX_FMT_YUVA420P10, AV_PIX_FMT_YUVA420P16,
136         AV_PIX_FMT_GBRAP,     AV_PIX_FMT_GBRAP10,    AV_PIX_FMT_GBRAP12,    AV_PIX_FMT_GBRAP16,
137         AV_PIX_FMT_NONE
138     };
139     AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
140     if (!fmts_list)
141         return AVERROR(ENOMEM);
142     return ff_set_common_formats(ctx, fmts_list);
143 }
144
145 typedef struct ThreadData {
146     float *src, *dst;
147 } ThreadData;
148
149 static void import_row8(FFTComplex *dst, uint8_t *src, int rw)
150 {
151     int j;
152
153     for (j = 0; j < rw; j++) {
154         dst[j].re = src[j];
155         dst[j].im = 0;
156     }
157 }
158
159 static void export_row8(FFTComplex *src, uint8_t *dst, int rw, float scale, int depth)
160 {
161     int j;
162
163     for (j = 0; j < rw; j++)
164         dst[j] = av_clip_uint8(src[j].re * scale + 0.5f);
165 }
166
167 static void import_row16(FFTComplex *dst, uint8_t *srcp, int rw)
168 {
169     uint16_t *src = (uint16_t *)srcp;
170     int j;
171
172     for (j = 0; j < rw; j++) {
173         dst[j].re = src[j];
174         dst[j].im = 0;
175     }
176 }
177
178 static void export_row16(FFTComplex *src, uint8_t *dstp, int rw, float scale, int depth)
179 {
180     uint16_t *dst = (uint16_t *)dstp;
181     int j;
182
183     for (j = 0; j < rw; j++)
184         dst[j] = av_clip_uintp2_c(src[j].re * scale + 0.5f, depth);
185 }
186
187 static int config_input(AVFilterLink *inlink)
188 {
189     AVFilterContext *ctx = inlink->dst;
190     const AVPixFmtDescriptor *desc;
191     FFTdnoizContext *s = ctx->priv;
192     int i;
193
194     desc = av_pix_fmt_desc_get(inlink->format);
195     s->depth = desc->comp[0].depth;
196
197     if (s->depth <= 8) {
198         s->import_row = import_row8;
199         s->export_row = export_row8;
200     } else {
201         s->import_row = import_row16;
202         s->export_row = export_row16;
203         s->sigma *= 1 << (s->depth - 8) * (1 + s->nb_prev + s->nb_next);
204     }
205
206     s->planes[1].planewidth = s->planes[2].planewidth = AV_CEIL_RSHIFT(inlink->w, desc->log2_chroma_w);
207     s->planes[0].planewidth = s->planes[3].planewidth = inlink->w;
208     s->planes[1].planeheight = s->planes[2].planeheight = AV_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h);
209     s->planes[0].planeheight = s->planes[3].planeheight = inlink->h;
210
211     s->nb_planes = av_pix_fmt_count_planes(inlink->format);
212
213     for (i = 0; i < s->nb_planes; i++) {
214         PlaneContext *p = &s->planes[i];
215         int size;
216
217         p->b = 1 << s->block_bits;
218         p->n = 1.f / (p->b * p->b);
219         p->o = p->b * s->overlap;
220         size = p->b - p->o;
221         p->nox = (p->planewidth  + (size - 1)) / size;
222         p->noy = (p->planeheight + (size - 1)) / size;
223
224         av_log(ctx, AV_LOG_DEBUG, "nox:%d noy:%d size:%d\n", p->nox, p->noy, size);
225
226         p->buffer_linesize = p->b * p->nox * sizeof(FFTComplex);
227         p->buffer[CURRENT] = av_calloc(p->b * p->noy, p->buffer_linesize);
228         if (!p->buffer[CURRENT])
229             return AVERROR(ENOMEM);
230         if (s->nb_prev > 0) {
231             p->buffer[PREV] = av_calloc(p->b * p->noy, p->buffer_linesize);
232             if (!p->buffer[PREV])
233                 return AVERROR(ENOMEM);
234         }
235         if (s->nb_next > 0) {
236             p->buffer[NEXT] = av_calloc(p->b * p->noy, p->buffer_linesize);
237             if (!p->buffer[NEXT])
238                 return AVERROR(ENOMEM);
239         }
240         p->data_linesize = 2 * p->b * sizeof(float);
241         p->hdata = av_calloc(p->b, p->data_linesize);
242         p->vdata = av_calloc(p->b, p->data_linesize);
243         if (!p->hdata || !p->vdata)
244             return AVERROR(ENOMEM);
245     }
246
247     return 0;
248 }
249
250 static void import_plane(FFTdnoizContext *s,
251                          uint8_t *srcp, int src_linesize,
252                          float *buffer, int buffer_linesize, int plane)
253 {
254     PlaneContext *p = &s->planes[plane];
255     const int width = p->planewidth;
256     const int height = p->planeheight;
257     const int block = p->b;
258     const int overlap = p->o;
259     const int size = block - overlap;
260     const int nox = p->nox;
261     const int noy = p->noy;
262     const int bpp = (s->depth + 7) / 8;
263     const int data_linesize = p->data_linesize / sizeof(FFTComplex);
264     FFTComplex *hdata = p->hdata;
265     FFTComplex *vdata = p->vdata;
266     int x, y, i, j;
267
268     buffer_linesize /= sizeof(float);
269     for (y = 0; y < noy; y++) {
270         for (x = 0; x < nox; x++) {
271             const int rh = FFMIN(block, height - y * size);
272             const int rw = FFMIN(block, width  - x * size);
273             uint8_t *src = srcp + src_linesize * y * size + x * size * bpp;
274             float *bdst = buffer + buffer_linesize * y * block + x * block * 2;
275             FFTComplex *ssrc, *dst = hdata;
276
277             for (i = 0; i < rh; i++) {
278                 s->import_row(dst, src, rw);
279                 for (j = rw; j < block; j++) {
280                     dst[j].re = dst[block - j - 1].re;
281                     dst[j].im = 0;
282                 }
283                 av_fft_permute(p->fft, dst);
284                 av_fft_calc(p->fft, dst);
285
286                 src += src_linesize;
287                 dst += data_linesize;
288             }
289
290             dst = hdata;
291             for (; i < block; i++) {
292                 for (j = 0; j < block; j++) {
293                     dst[j].re = dst[(block - i - 1) * data_linesize + j].re;
294                     dst[j].im = dst[(block - i - 1) * data_linesize + j].im;
295                 }
296             }
297
298             ssrc = hdata;
299             dst = vdata;
300             for (i = 0; i < block; i++) {
301                 for (j = 0; j < block; j++)
302                     dst[j] = ssrc[j * data_linesize + i];
303                 av_fft_permute(p->fft, dst);
304                 av_fft_calc(p->fft, dst);
305                 memcpy(bdst, dst, block * sizeof(FFTComplex));
306
307                 dst += data_linesize;
308                 bdst += buffer_linesize;
309             }
310         }
311     }
312 }
313
314 static void export_plane(FFTdnoizContext *s,
315                          uint8_t *dstp, int dst_linesize,
316                          float *buffer, int buffer_linesize, int plane)
317 {
318     PlaneContext *p = &s->planes[plane];
319     const int depth = s->depth;
320     const int bpp = (depth + 7) / 8;
321     const int width = p->planewidth;
322     const int height = p->planeheight;
323     const int block = p->b;
324     const int overlap = p->o;
325     const int hoverlap = overlap / 2;
326     const int size = block - overlap;
327     const int nox = p->nox;
328     const int noy = p->noy;
329     const int data_linesize = p->data_linesize / sizeof(FFTComplex);
330     const float scale = 1.f / (block * block);
331     FFTComplex *hdata = p->hdata;
332     FFTComplex *vdata = p->vdata;
333     int x, y, i, j;
334
335     buffer_linesize /= sizeof(float);
336     for (y = 0; y < noy; y++) {
337         for (x = 0; x < nox; x++) {
338             const int woff = x == 0 ? 0 : hoverlap;
339             const int hoff = y == 0 ? 0 : hoverlap;
340             const int rw = x == 0 ? block : FFMIN(size, width  - x * size - woff);
341             const int rh = y == 0 ? block : FFMIN(size, height - y * size - hoff);
342             float *bsrc = buffer + buffer_linesize * y * block + x * block * 2;
343             uint8_t *dst = dstp + dst_linesize * (y * size + hoff) + (x * size + woff) * bpp;
344             FFTComplex *hdst, *ddst = vdata;
345
346             hdst = hdata;
347             for (i = 0; i < block; i++) {
348                 memcpy(ddst, bsrc, block * sizeof(FFTComplex));
349                 av_fft_permute(p->ifft, ddst);
350                 av_fft_calc(p->ifft, ddst);
351                 for (j = 0; j < block; j++) {
352                     hdst[j * data_linesize + i] = ddst[j];
353                 }
354
355                 ddst += data_linesize;
356                 bsrc += buffer_linesize;
357             }
358
359             hdst = hdata + hoff * data_linesize;
360             for (i = 0; i < rh; i++) {
361                 av_fft_permute(p->ifft, hdst);
362                 av_fft_calc(p->ifft, hdst);
363                 s->export_row(hdst + woff, dst, rw, scale, depth);
364
365                 hdst += data_linesize;
366                 dst += dst_linesize;
367             }
368         }
369     }
370 }
371
372 static void filter_plane3d2(FFTdnoizContext *s, int plane, float *pbuffer, float *nbuffer)
373 {
374     PlaneContext *p = &s->planes[plane];
375     const int block = p->b;
376     const int nox = p->nox;
377     const int noy = p->noy;
378     const int buffer_linesize = p->buffer_linesize / sizeof(float);
379     const float sigma = s->sigma * s->sigma * block * block;
380     const float limit = 1.f - s->amount;
381     float *cbuffer = p->buffer[CURRENT];
382     const float cfactor = sqrtf(3.f) * 0.5f;
383     const float scale = 1.f / 3.f;
384     int y, x, i, j;
385
386     for (y = 0; y < noy; y++) {
387         for (x = 0; x < nox; x++) {
388             float *cbuff = cbuffer + buffer_linesize * y * block + x * block * 2;
389             float *pbuff = pbuffer + buffer_linesize * y * block + x * block * 2;
390             float *nbuff = nbuffer + buffer_linesize * y * block + x * block * 2;
391
392             for (i = 0; i < block; i++) {
393                 for (j = 0; j < block; j++) {
394                     float sumr, sumi, difr, difi, mpr, mpi, mnr, mni;
395                     float factor, power, sumpnr, sumpni;
396
397                     sumpnr = pbuff[2 * j    ] + nbuff[2 * j    ];
398                     sumpni = pbuff[2 * j + 1] + nbuff[2 * j + 1];
399                     sumr = cbuff[2 * j    ] + sumpnr;
400                     sumi = cbuff[2 * j + 1] + sumpni;
401                     difr = cfactor * (nbuff[2 * j    ] - pbuff[2 * j    ]);
402                     difi = cfactor * (pbuff[2 * j + 1] - nbuff[2 * j + 1]);
403                     mpr = cbuff[2 * j    ] - 0.5f * sumpnr + difi;
404                     mnr = mpr - difi - difi;
405                     mpi = cbuff[2 * j + 1] - 0.5f * sumpni + difr;
406                     mni = mpi - difr - difr;
407                     power = sumr * sumr + sumi * sumi + 1e-15f;
408                     factor = FFMAX((power - sigma) / power, limit);
409                     sumr *= factor;
410                     sumi *= factor;
411                     power = mpr * mpr + mpi * mpi + 1e-15f;
412                     factor = FFMAX((power - sigma) / power, limit);
413                     mpr *= factor;
414                     mpi *= factor;
415                     power = mnr * mnr + mni * mni + 1e-15f;
416                     factor = FFMAX((power - sigma) / power, limit);
417                     mnr *= factor;
418                     mni *= factor;
419                     cbuff[2 * j    ] = (sumr + mpr + mnr) * scale;
420                     cbuff[2 * j + 1] = (sumi + mpi + mni) * scale;
421
422                 }
423
424                 cbuff += buffer_linesize;
425                 pbuff += buffer_linesize;
426                 nbuff += buffer_linesize;
427             }
428         }
429     }
430 }
431
432 static void filter_plane3d1(FFTdnoizContext *s, int plane, float *pbuffer)
433 {
434     PlaneContext *p = &s->planes[plane];
435     const int block = p->b;
436     const int nox = p->nox;
437     const int noy = p->noy;
438     const int buffer_linesize = p->buffer_linesize / sizeof(float);
439     const float sigma = s->sigma * s->sigma * block * block;
440     const float limit = 1.f - s->amount;
441     float *cbuffer = p->buffer[CURRENT];
442     int y, x, i, j;
443
444     for (y = 0; y < noy; y++) {
445         for (x = 0; x < nox; x++) {
446             float *cbuff = cbuffer + buffer_linesize * y * block + x * block * 2;
447             float *pbuff = pbuffer + buffer_linesize * y * block + x * block * 2;
448
449             for (i = 0; i < block; i++) {
450                 for (j = 0; j < block; j++) {
451                     float factor, power, re, im, pre, pim;
452                     float sumr, sumi, difr, difi;
453
454                     re = cbuff[j * 2    ];
455                     pre = pbuff[j * 2    ];
456                     im = cbuff[j * 2 + 1];
457                     pim = pbuff[j * 2 + 1];
458
459                     sumr = re + pre;
460                     sumi = im + pim;
461                     difr = re - pre;
462                     difi = im - pim;
463
464                     power = sumr * sumr + sumi * sumi + 1e-15f;
465                     factor = FFMAX(limit, (power - sigma) / power);
466                     sumr *= factor;
467                     sumi *= factor;
468                     power = difr * difr + difi * difi + 1e-15f;
469                     factor = FFMAX(limit, (power - sigma) / power);
470                     difr *= factor;
471                     difi *= factor;
472
473                     cbuff[j * 2    ] = (sumr + difr) * 0.5f;
474                     cbuff[j * 2 + 1] = (sumi + difi) * 0.5f;
475                 }
476
477                 cbuff += buffer_linesize;
478                 pbuff += buffer_linesize;
479             }
480         }
481     }
482 }
483
484 static void filter_plane2d(FFTdnoizContext *s, int plane)
485 {
486     PlaneContext *p = &s->planes[plane];
487     const int block = p->b;
488     const int nox = p->nox;
489     const int noy = p->noy;
490     const int buffer_linesize = p->buffer_linesize / 4;
491     const float sigma = s->sigma * s->sigma * block * block;
492     const float limit = 1.f - s->amount;
493     float *buffer = p->buffer[CURRENT];
494     int y, x, i, j;
495
496     for (y = 0; y < noy; y++) {
497         for (x = 0; x < nox; x++) {
498             float *buff = buffer + buffer_linesize * y * block + x * block * 2;
499
500             for (i = 0; i < block; i++) {
501                 for (j = 0; j < block; j++) {
502                     float factor, power, re, im;
503
504                     re = buff[j * 2    ];
505                     im = buff[j * 2 + 1];
506                     power = re * re + im * im + 1e-15f;
507                     factor = FFMAX(limit, (power - sigma) / power);
508                     buff[j * 2    ] *= factor;
509                     buff[j * 2 + 1] *= factor;
510                 }
511
512                 buff += buffer_linesize;
513             }
514         }
515     }
516 }
517
518 static int filter_frame(AVFilterLink *inlink, AVFrame *in)
519 {
520     AVFilterContext *ctx = inlink->dst;
521     FFTdnoizContext *s = ctx->priv;
522     AVFilterLink *outlink = ctx->outputs[0];
523     int direct, plane;
524     AVFrame *out;
525
526     if (s->nb_next > 0 && s->nb_prev > 0) {
527         av_frame_free(&s->prev);
528         s->prev = s->cur;
529         s->cur = s->next;
530         s->next = in;
531
532         if (!s->prev && s->cur) {
533             s->prev = av_frame_clone(s->cur);
534             if (!s->prev)
535                 return AVERROR(ENOMEM);
536         }
537         if (!s->cur)
538             return 0;
539     } else if (s->nb_next > 0) {
540         av_frame_free(&s->cur);
541         s->cur = s->next;
542         s->next = in;
543
544         if (!s->cur)
545             return 0;
546     } else if (s->nb_prev > 0) {
547         av_frame_free(&s->prev);
548         s->prev = s->cur;
549         s->cur = in;
550
551         if (!s->prev)
552             s->prev = av_frame_clone(s->cur);
553         if (!s->prev)
554             return AVERROR(ENOMEM);
555     } else {
556         s->cur = in;
557     }
558
559     if (av_frame_is_writable(in) && s->nb_next == 0 && s->nb_prev == 0) {
560         direct = 1;
561         out = in;
562     } else {
563         direct = 0;
564         out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
565         if (!out)
566             return AVERROR(ENOMEM);
567         av_frame_copy_props(out, s->cur);
568     }
569
570     for (plane = 0; plane < s->nb_planes; plane++) {
571         PlaneContext *p = &s->planes[plane];
572
573         if (!((1 << plane) & s->planesf) || ctx->is_disabled) {
574             if (!direct)
575                 av_image_copy_plane(out->data[plane], out->linesize[plane],
576                                     s->cur->data[plane], s->cur->linesize[plane],
577                                     p->planewidth, p->planeheight);
578             continue;
579         }
580
581         if (s->next) {
582             import_plane(s, s->next->data[plane], s->next->linesize[plane],
583                          p->buffer[NEXT], p->buffer_linesize, plane);
584         }
585
586         if (s->prev) {
587             import_plane(s, s->prev->data[plane], s->prev->linesize[plane],
588                          p->buffer[PREV], p->buffer_linesize, plane);
589         }
590
591         import_plane(s, s->cur->data[plane], s->cur->linesize[plane],
592                      p->buffer[CURRENT], p->buffer_linesize, plane);
593
594         if (s->next && s->prev) {
595             filter_plane3d2(s, plane, p->buffer[PREV], p->buffer[NEXT]);
596         } else if (s->next) {
597             filter_plane3d1(s, plane, p->buffer[NEXT]);
598         } else  if (s->prev) {
599             filter_plane3d1(s, plane, p->buffer[PREV]);
600         } else {
601             filter_plane2d(s, plane);
602         }
603
604         export_plane(s, out->data[plane], out->linesize[plane],
605                      p->buffer[CURRENT], p->buffer_linesize, plane);
606     }
607
608     if (s->nb_next == 0 && s->nb_prev == 0) {
609         if (direct) {
610             s->cur = NULL;
611         } else {
612             av_frame_free(&s->cur);
613         }
614     }
615     return ff_filter_frame(outlink, out);
616 }
617
618 static int request_frame(AVFilterLink *outlink)
619 {
620     AVFilterContext *ctx = outlink->src;
621     FFTdnoizContext *s = ctx->priv;
622     int ret = 0;
623
624     ret = ff_request_frame(ctx->inputs[0]);
625
626     if (ret == AVERROR_EOF && (s->nb_next > 0)) {
627         AVFrame *buf;
628
629         if (s->next && s->nb_next > 0)
630             buf = av_frame_clone(s->next);
631         else if (s->cur)
632             buf = av_frame_clone(s->cur);
633         else
634             buf = av_frame_clone(s->prev);
635         if (!buf)
636             return AVERROR(ENOMEM);
637
638         ret = filter_frame(ctx->inputs[0], buf);
639         if (ret < 0)
640             return ret;
641         ret = AVERROR_EOF;
642     }
643
644     return ret;
645 }
646
647 static av_cold void uninit(AVFilterContext *ctx)
648 {
649     FFTdnoizContext *s = ctx->priv;
650     int i;
651
652     for (i = 0; i < 4; i++) {
653         PlaneContext *p = &s->planes[i];
654
655         av_freep(&p->hdata);
656         av_freep(&p->vdata);
657         av_freep(&p->buffer[PREV]);
658         av_freep(&p->buffer[CURRENT]);
659         av_freep(&p->buffer[NEXT]);
660         av_fft_end(p->fft);
661         av_fft_end(p->ifft);
662     }
663
664     av_frame_free(&s->prev);
665     av_frame_free(&s->cur);
666     av_frame_free(&s->next);
667 }
668
669 static const AVFilterPad fftdnoiz_inputs[] = {
670     {
671         .name         = "default",
672         .type         = AVMEDIA_TYPE_VIDEO,
673         .filter_frame = filter_frame,
674         .config_props = config_input,
675     },
676     { NULL }
677 };
678
679 static const AVFilterPad fftdnoiz_outputs[] = {
680     {
681         .name          = "default",
682         .type          = AVMEDIA_TYPE_VIDEO,
683         .request_frame = request_frame,
684     },
685     { NULL }
686 };
687
688 AVFilter ff_vf_fftdnoiz = {
689     .name          = "fftdnoiz",
690     .description   = NULL_IF_CONFIG_SMALL("Denoise frames using 3D FFT."),
691     .priv_size     = sizeof(FFTdnoizContext),
692     .init          = init,
693     .uninit        = uninit,
694     .query_formats = query_formats,
695     .inputs        = fftdnoiz_inputs,
696     .outputs       = fftdnoiz_outputs,
697     .priv_class    = &fftdnoiz_class,
698     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
699 };