X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavfilter%2Fvf_hqdn3d.c;h=be6b7616b6b49a8ccee6abda992109660f1dad75;hb=2572d07c1f0abd9e2bf3ed20dbe35c58f1dd6ac4;hp=78a7bf71c7a124a7697b7ca0c873bbd75921df3c;hpb=a4dc7aa5b5f2b8d1a2993b9887c0428e6b01677f;p=ffmpeg diff --git a/libavfilter/vf_hqdn3d.c b/libavfilter/vf_hqdn3d.c index 78a7bf71c7a..be6b7616b6b 100644 --- a/libavfilter/vf_hqdn3d.c +++ b/libavfilter/vf_hqdn3d.c @@ -1,21 +1,22 @@ /* * Copyright (c) 2003 Daniel Moreno * Copyright (c) 2010 Baptiste Coudurier + * Copyright (c) 2012 Loren Merritt * - * This file is part of FFmpeg, ported from MPlayer. + * This file is part of Libav, ported from MPlayer. * - * FFmpeg is free software; you can redistribute it and/or modify + * Libav is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * - * FFmpeg is distributed in the hope that it will be useful, + * Libav is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along - * with FFmpeg; if not, write to the Free Software Foundation, Inc., + * with Libav; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ @@ -25,321 +26,339 @@ * libmpcodecs/vf_hqdn3d.c. */ -#include "libavutil/pixdesc.h" -#include "avfilter.h" +#include -typedef struct { - int Coefs[4][512*16]; - unsigned int *Line; - unsigned short *Frame[3]; - int hsub, vsub; -} HQDN3DContext; +#include "config.h" +#include "libavutil/attributes.h" +#include "libavutil/common.h" +#include "libavutil/pixdesc.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/opt.h" -static inline unsigned int LowPassMul(unsigned int PrevMul, unsigned int CurrMul, int *Coef) +#include "avfilter.h" +#include "formats.h" +#include "internal.h" +#include "video.h" +#include "vf_hqdn3d.h" + +#define LUT_BITS (depth==16 ? 8 : 4) +#define LOAD(x) (((depth == 8 ? src[x] : AV_RN16A(src + (x) * 2)) << (16 - depth))\ + + (((1 << (16 - depth)) - 1) >> 1)) +#define STORE(x,val) (depth == 8 ? dst[x] = (val) >> (16 - depth) : \ + AV_WN16A(dst + (x) * 2, (val) >> (16 - depth))) + +av_always_inline +static uint32_t lowpass(int prev, int cur, int16_t *coef, int depth) { - // int dMul= (PrevMul&0xFFFFFF)-(CurrMul&0xFFFFFF); - int dMul= PrevMul-CurrMul; - unsigned int d=((dMul+0x10007FF)>>12); - return CurrMul + Coef[d]; + int d = (prev - cur) >> (8 - LUT_BITS); + return cur + coef[d]; } -static void deNoiseTemporal(unsigned char *FrameSrc, - unsigned char *FrameDest, - unsigned short *FrameAnt, - int W, int H, int sStride, int dStride, - int *Temporal) +av_always_inline +static void denoise_temporal(uint8_t *src, uint8_t *dst, + uint16_t *frame_ant, + int w, int h, int sstride, int dstride, + int16_t *temporal, int depth) { - long X, Y; - unsigned int PixelDst; - - for (Y = 0; Y < H; Y++) { - for (X = 0; X < W; X++) { - PixelDst = LowPassMul(FrameAnt[X]<<8, FrameSrc[X]<<16, Temporal); - FrameAnt[X] = ((PixelDst+0x1000007F)>>8); - FrameDest[X]= ((PixelDst+0x10007FFF)>>16); - } - FrameSrc += sStride; - FrameDest += dStride; - FrameAnt += W; - } -} + long x, y; + uint32_t tmp; -static void deNoiseSpacial(unsigned char *Frame, - unsigned char *FrameDest, - unsigned int *LineAnt, - int W, int H, int sStride, int dStride, - int *Horizontal, int *Vertical) -{ - long X, Y; - long sLineOffs = 0, dLineOffs = 0; - unsigned int PixelAnt; - unsigned int PixelDst; - - /* First pixel has no left nor top neighbor. */ - PixelDst = LineAnt[0] = PixelAnt = Frame[0]<<16; - FrameDest[0]= ((PixelDst+0x10007FFF)>>16); - - /* First line has no top neighbor, only left. */ - for (X = 1; X < W; X++) { - PixelDst = LineAnt[X] = LowPassMul(PixelAnt, Frame[X]<<16, Horizontal); - FrameDest[X]= ((PixelDst+0x10007FFF)>>16); - } + temporal += 256 << LUT_BITS; - for (Y = 1; Y < H; Y++) { - unsigned int PixelAnt; - sLineOffs += sStride, dLineOffs += dStride; - /* First pixel on each line doesn't have previous pixel */ - PixelAnt = Frame[sLineOffs]<<16; - PixelDst = LineAnt[0] = LowPassMul(LineAnt[0], PixelAnt, Vertical); - FrameDest[dLineOffs]= ((PixelDst+0x10007FFF)>>16); - - for (X = 1; X < W; X++) { - unsigned int PixelDst; - /* The rest are normal */ - PixelAnt = LowPassMul(PixelAnt, Frame[sLineOffs+X]<<16, Horizontal); - PixelDst = LineAnt[X] = LowPassMul(LineAnt[X], PixelAnt, Vertical); - FrameDest[dLineOffs+X]= ((PixelDst+0x10007FFF)>>16); + for (y = 0; y < h; y++) { + for (x = 0; x < w; x++) { + frame_ant[x] = tmp = lowpass(frame_ant[x], LOAD(x), temporal, depth); + STORE(x, tmp); } + src += sstride; + dst += dstride; + frame_ant += w; } } -static void deNoise(unsigned char *Frame, - unsigned char *FrameDest, - unsigned int *LineAnt, - unsigned short **FrameAntPtr, - int W, int H, int sStride, int dStride, - int *Horizontal, int *Vertical, int *Temporal) +av_always_inline +static void denoise_spatial(HQDN3DContext *s, + uint8_t *src, uint8_t *dst, + uint16_t *line_ant, uint16_t *frame_ant, + int w, int h, int sstride, int dstride, + int16_t *spatial, int16_t *temporal, int depth) { - long X, Y; - long sLineOffs = 0, dLineOffs = 0; - unsigned int PixelAnt; - unsigned int PixelDst; - unsigned short* FrameAnt=(*FrameAntPtr); - - if (!FrameAnt) { - (*FrameAntPtr) = FrameAnt = av_malloc(W*H*sizeof(unsigned short)); - for (Y = 0; Y < H; Y++) { - unsigned short* dst=&FrameAnt[Y*W]; - unsigned char* src=Frame+Y*sStride; - for (X = 0; X < W; X++) dst[X]=src[X]<<8; - } - } - - if (!Horizontal[0] && !Vertical[0]) { - deNoiseTemporal(Frame, FrameDest, FrameAnt, - W, H, sStride, dStride, Temporal); - return; - } - if (!Temporal[0]) { - deNoiseSpacial(Frame, FrameDest, LineAnt, - W, H, sStride, dStride, Horizontal, Vertical); - return; - } + long x, y; + uint32_t pixel_ant; + uint32_t tmp; - /* First pixel has no left nor top neighbor. Only previous frame */ - LineAnt[0] = PixelAnt = Frame[0]<<16; - PixelDst = LowPassMul(FrameAnt[0]<<8, PixelAnt, Temporal); - FrameAnt[0] = ((PixelDst+0x1000007F)>>8); - FrameDest[0]= ((PixelDst+0x10007FFF)>>16); + spatial += 256 << LUT_BITS; + temporal += 256 << LUT_BITS; - /* First line has no top neighbor. Only left one for each pixel and + /* First line has no top neighbor. Only left one for each tmp and * last frame */ - for (X = 1; X < W; X++) { - LineAnt[X] = PixelAnt = LowPassMul(PixelAnt, Frame[X]<<16, Horizontal); - PixelDst = LowPassMul(FrameAnt[X]<<8, PixelAnt, Temporal); - FrameAnt[X] = ((PixelDst+0x1000007F)>>8); - FrameDest[X]= ((PixelDst+0x10007FFF)>>16); + pixel_ant = LOAD(0); + for (x = 0; x < w; x++) { + line_ant[x] = tmp = pixel_ant = lowpass(pixel_ant, LOAD(x), spatial, depth); + frame_ant[x] = tmp = lowpass(frame_ant[x], tmp, temporal, depth); + STORE(x, tmp); } - for (Y = 1; Y < H; Y++) { - unsigned int PixelAnt; - unsigned short* LinePrev=&FrameAnt[Y*W]; - sLineOffs += sStride, dLineOffs += dStride; - /* First pixel on each line doesn't have previous pixel */ - PixelAnt = Frame[sLineOffs]<<16; - LineAnt[0] = LowPassMul(LineAnt[0], PixelAnt, Vertical); - PixelDst = LowPassMul(LinePrev[0]<<8, LineAnt[0], Temporal); - LinePrev[0] = ((PixelDst+0x1000007F)>>8); - FrameDest[dLineOffs]= ((PixelDst+0x10007FFF)>>16); - - for (X = 1; X < W; X++) { - unsigned int PixelDst; - /* The rest are normal */ - PixelAnt = LowPassMul(PixelAnt, Frame[sLineOffs+X]<<16, Horizontal); - LineAnt[X] = LowPassMul(LineAnt[X], PixelAnt, Vertical); - PixelDst = LowPassMul(LinePrev[X]<<8, LineAnt[X], Temporal); - LinePrev[X] = ((PixelDst+0x1000007F)>>8); - FrameDest[dLineOffs+X]= ((PixelDst+0x10007FFF)>>16); + for (y = 1; y < h; y++) { + src += sstride; + dst += dstride; + frame_ant += w; + if (s->denoise_row[depth]) { + s->denoise_row[depth](src, dst, line_ant, frame_ant, w, spatial, temporal); + continue; + } + pixel_ant = LOAD(0); + for (x = 0; x < w-1; x++) { + line_ant[x] = tmp = lowpass(line_ant[x], pixel_ant, spatial, depth); + pixel_ant = lowpass(pixel_ant, LOAD(x+1), spatial, depth); + frame_ant[x] = tmp = lowpass(frame_ant[x], tmp, temporal, depth); + STORE(x, tmp); } + line_ant[x] = tmp = lowpass(line_ant[x], pixel_ant, spatial, depth); + frame_ant[x] = tmp = lowpass(frame_ant[x], tmp, temporal, depth); + STORE(x, tmp); } } -static void PrecalcCoefs(int *Ct, double Dist25) +av_always_inline +static void denoise_depth(HQDN3DContext *s, + uint8_t *src, uint8_t *dst, + uint16_t *line_ant, uint16_t **frame_ant_ptr, + int w, int h, int sstride, int dstride, + int16_t *spatial, int16_t *temporal, int depth) { - int i; - double Gamma, Simil, C; + // FIXME: For 16bit depth, frame_ant could be a pointer to the previous + // filtered frame rather than a separate buffer. + long x, y; + uint16_t *frame_ant = *frame_ant_ptr; + if (!frame_ant) { + uint8_t *frame_src = src; + *frame_ant_ptr = frame_ant = av_malloc(w*h*sizeof(uint16_t)); + for (y = 0; y < h; y++, src += sstride, frame_ant += w) + for (x = 0; x < w; x++) + frame_ant[x] = LOAD(x); + src = frame_src; + frame_ant = *frame_ant_ptr; + } + + if (spatial[0]) + denoise_spatial(s, src, dst, line_ant, frame_ant, + w, h, sstride, dstride, spatial, temporal, depth); + else + denoise_temporal(src, dst, frame_ant, + w, h, sstride, dstride, temporal, depth); + emms_c(); +} - Gamma = log(0.25) / log(1.0 - Dist25/255.0 - 0.00001); +#define denoise(...) \ + switch (s->depth) {\ + case 8: denoise_depth(__VA_ARGS__, 8); break;\ + case 9: denoise_depth(__VA_ARGS__, 9); break;\ + case 10: denoise_depth(__VA_ARGS__, 10); break;\ + case 16: denoise_depth(__VA_ARGS__, 16); break;\ + } - for (i = -255*16; i <= 255*16; i++) { - Simil = 1.0 - FFABS(i) / (16*255.0); - C = pow(Simil, Gamma) * 65536.0 * i / 16.0; - Ct[16*256+i] = lrint(C); +static int16_t *precalc_coefs(double dist25, int depth) +{ + int i; + double gamma, simil, C; + int16_t *ct = av_malloc((512<priv; - double LumSpac, LumTmp, ChromSpac, ChromTmp; - double Param1, Param2, Param3, Param4; - - LumSpac = PARAM1_DEFAULT; - ChromSpac = PARAM2_DEFAULT; - LumTmp = PARAM3_DEFAULT; - ChromTmp = LumTmp * ChromSpac / LumSpac; - - if (args) { - switch (sscanf(args, "%lf:%lf:%lf:%lf", - &Param1, &Param2, &Param3, &Param4)) { - case 1: - LumSpac = Param1; - ChromSpac = PARAM2_DEFAULT * Param1 / PARAM1_DEFAULT; - LumTmp = PARAM3_DEFAULT * Param1 / PARAM1_DEFAULT; - ChromTmp = LumTmp * ChromSpac / LumSpac; - break; - case 2: - LumSpac = Param1; - ChromSpac = Param2; - LumTmp = PARAM3_DEFAULT * Param1 / PARAM1_DEFAULT; - ChromTmp = LumTmp * ChromSpac / LumSpac; - break; - case 3: - LumSpac = Param1; - ChromSpac = Param2; - LumTmp = Param3; - ChromTmp = LumTmp * ChromSpac / LumSpac; - break; - case 4: - LumSpac = Param1; - ChromSpac = Param2; - LumTmp = Param3; - ChromTmp = Param4; - break; - } - } + HQDN3DContext *s = ctx->priv; - av_log(ctx, AV_LOG_INFO, "ls:%lf cs:%lf lt:%lf ct:%lf\n", - LumSpac, ChromSpac, LumTmp, ChromTmp); - if (LumSpac < 0 || ChromSpac < 0 || isnan(ChromTmp)) { - av_log(ctx, AV_LOG_ERROR, - "Invalid negative value for luma or chroma spatial strength, " - "or resulting value for chroma temporal strength is nan.\n"); - return AVERROR(EINVAL); - } + if (!s->strength[LUMA_SPATIAL]) + s->strength[LUMA_SPATIAL] = PARAM1_DEFAULT; + if (!s->strength[CHROMA_SPATIAL]) + s->strength[CHROMA_SPATIAL] = PARAM2_DEFAULT * s->strength[LUMA_SPATIAL] / PARAM1_DEFAULT; + if (!s->strength[LUMA_TMP]) + s->strength[LUMA_TMP] = PARAM3_DEFAULT * s->strength[LUMA_SPATIAL] / PARAM1_DEFAULT; + if (!s->strength[CHROMA_TMP]) + s->strength[CHROMA_TMP] = s->strength[LUMA_TMP] * s->strength[CHROMA_SPATIAL] / s->strength[LUMA_SPATIAL]; - PrecalcCoefs(hqdn3d->Coefs[0], LumSpac); - PrecalcCoefs(hqdn3d->Coefs[1], LumTmp); - PrecalcCoefs(hqdn3d->Coefs[2], ChromSpac); - PrecalcCoefs(hqdn3d->Coefs[3], ChromTmp); + av_log(ctx, AV_LOG_VERBOSE, "ls:%f cs:%f lt:%f ct:%f\n", + s->strength[LUMA_SPATIAL], s->strength[CHROMA_SPATIAL], + s->strength[LUMA_TMP], s->strength[CHROMA_TMP]); return 0; } -static void uninit(AVFilterContext *ctx) +static av_cold void uninit(AVFilterContext *ctx) { - HQDN3DContext *hqdn3d = ctx->priv; - - av_freep(&hqdn3d->Line); - av_freep(&hqdn3d->Frame[0]); - av_freep(&hqdn3d->Frame[1]); - av_freep(&hqdn3d->Frame[2]); + HQDN3DContext *s = ctx->priv; + + av_freep(&s->coefs[0]); + av_freep(&s->coefs[1]); + av_freep(&s->coefs[2]); + av_freep(&s->coefs[3]); + av_freep(&s->line); + av_freep(&s->frame_prev[0]); + av_freep(&s->frame_prev[1]); + av_freep(&s->frame_prev[2]); } static int query_formats(AVFilterContext *ctx) { - static const enum PixelFormat pix_fmts[] = { - PIX_FMT_YUV420P, PIX_FMT_YUV422P, PIX_FMT_YUV411P, PIX_FMT_NONE + static const enum AVPixelFormat pix_fmts[] = { + AV_PIX_FMT_YUV420P, + AV_PIX_FMT_YUV422P, + AV_PIX_FMT_YUV444P, + AV_PIX_FMT_YUV410P, + AV_PIX_FMT_YUV411P, + AV_PIX_FMT_YUV440P, + AV_PIX_FMT_YUVJ420P, + AV_PIX_FMT_YUVJ422P, + AV_PIX_FMT_YUVJ444P, + AV_PIX_FMT_YUVJ440P, + AV_NE( AV_PIX_FMT_YUV420P9BE, AV_PIX_FMT_YUV420P9LE ), + AV_NE( AV_PIX_FMT_YUV422P9BE, AV_PIX_FMT_YUV422P9LE ), + AV_NE( AV_PIX_FMT_YUV444P9BE, AV_PIX_FMT_YUV444P9LE ), + AV_NE( AV_PIX_FMT_YUV420P10BE, AV_PIX_FMT_YUV420P10LE ), + AV_NE( AV_PIX_FMT_YUV422P10BE, AV_PIX_FMT_YUV422P10LE ), + AV_NE( AV_PIX_FMT_YUV444P10BE, AV_PIX_FMT_YUV444P10LE ), + AV_NE( AV_PIX_FMT_YUV420P16BE, AV_PIX_FMT_YUV420P16LE ), + AV_NE( AV_PIX_FMT_YUV422P16BE, AV_PIX_FMT_YUV422P16LE ), + AV_NE( AV_PIX_FMT_YUV444P16BE, AV_PIX_FMT_YUV444P16LE ), + AV_PIX_FMT_NONE }; - avfilter_set_common_formats(ctx, avfilter_make_format_list(pix_fmts)); + ff_set_common_formats(ctx, ff_make_format_list(pix_fmts)); return 0; } static int config_input(AVFilterLink *inlink) { - HQDN3DContext *hqdn3d = inlink->dst->priv; + HQDN3DContext *s = inlink->dst->priv; + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); + int i; - hqdn3d->hsub = av_pix_fmt_descriptors[inlink->format].log2_chroma_w; - hqdn3d->vsub = av_pix_fmt_descriptors[inlink->format].log2_chroma_h; + uninit(inlink->dst); - hqdn3d->Line = av_malloc(inlink->w * sizeof(*hqdn3d->Line)); - if (!hqdn3d->Line) + s->hsub = desc->log2_chroma_w; + s->vsub = desc->log2_chroma_h; + s->depth = desc->comp[0].depth_minus1+1; + + s->line = av_malloc(inlink->w * sizeof(*s->line)); + if (!s->line) return AVERROR(ENOMEM); + for (i = 0; i < 4; i++) { + s->coefs[i] = precalc_coefs(s->strength[i], s->depth); + if (!s->coefs[i]) + return AVERROR(ENOMEM); + } + + if (ARCH_X86) + ff_hqdn3d_init_x86(s); + return 0; } -static void null_draw_slice(AVFilterLink *link, int y, int h, int slice_dir) { } - -static void end_frame(AVFilterLink *inlink) +static int filter_frame(AVFilterLink *inlink, AVFrame *in) { - HQDN3DContext *hqdn3d = inlink->dst->priv; + HQDN3DContext *s = inlink->dst->priv; AVFilterLink *outlink = inlink->dst->outputs[0]; - AVFilterBufferRef *inpic = inlink ->cur_buf; - AVFilterBufferRef *outpic = outlink->out_buf; - int cw = inpic->video->w >> hqdn3d->hsub; - int ch = inpic->video->h >> hqdn3d->vsub; - - deNoise(inpic->data[0], outpic->data[0], - hqdn3d->Line, &hqdn3d->Frame[0], inpic->video->w, inpic->video->h, - inpic->linesize[0], outpic->linesize[0], - hqdn3d->Coefs[0], - hqdn3d->Coefs[0], - hqdn3d->Coefs[1]); - deNoise(inpic->data[1], outpic->data[1], - hqdn3d->Line, &hqdn3d->Frame[1], cw, ch, - inpic->linesize[1], outpic->linesize[1], - hqdn3d->Coefs[2], - hqdn3d->Coefs[2], - hqdn3d->Coefs[3]); - deNoise(inpic->data[2], outpic->data[2], - hqdn3d->Line, &hqdn3d->Frame[2], cw, ch, - inpic->linesize[2], outpic->linesize[2], - hqdn3d->Coefs[2], - hqdn3d->Coefs[2], - hqdn3d->Coefs[3]); - - avfilter_draw_slice(outlink, 0, inpic->video->h, 1); - avfilter_end_frame(outlink); - avfilter_unref_buffer(inpic); - avfilter_unref_buffer(outpic); + AVFrame *out; + int direct, c; + + if (av_frame_is_writable(in)) { + direct = 1; + out = in; + } else { + direct = 0; + out = ff_get_video_buffer(outlink, outlink->w, outlink->h); + if (!out) { + av_frame_free(&in); + return AVERROR(ENOMEM); + } + + av_frame_copy_props(out, in); + out->width = outlink->w; + out->height = outlink->h; + } + + for (c = 0; c < 3; c++) { + denoise(s, in->data[c], out->data[c], + s->line, &s->frame_prev[c], + in->width >> (!!c * s->hsub), + in->height >> (!!c * s->vsub), + in->linesize[c], out->linesize[c], + s->coefs[c?2:0], s->coefs[c?3:1]); + } + + if (!direct) + av_frame_free(&in); + + return ff_filter_frame(outlink, out); } -AVFilter avfilter_vf_hqdn3d = { +#define OFFSET(x) offsetof(HQDN3DContext, x) +#define FLAGS AV_OPT_FLAG_VIDEO_PARAM +static const AVOption options[] = { + { "luma_spatial", "spatial luma strength", OFFSET(strength[LUMA_SPATIAL]), AV_OPT_TYPE_DOUBLE, { .dbl = 0.0 }, 0, DBL_MAX, FLAGS }, + { "chroma_spatial", "spatial chroma strength", OFFSET(strength[CHROMA_SPATIAL]), AV_OPT_TYPE_DOUBLE, { .dbl = 0.0 }, 0, DBL_MAX, FLAGS }, + { "luma_tmp", "temporal luma strength", OFFSET(strength[LUMA_TMP]), AV_OPT_TYPE_DOUBLE, { .dbl = 0.0 }, 0, DBL_MAX, FLAGS }, + { "chroma_tmp", "temporal chroma strength", OFFSET(strength[CHROMA_TMP]), AV_OPT_TYPE_DOUBLE, { .dbl = 0.0 }, 0, DBL_MAX, FLAGS }, + { NULL }, +}; + +static const AVClass hqdn3d_class = { + .class_name = "hqdn3d", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +static const AVFilterPad avfilter_vf_hqdn3d_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = config_input, + .filter_frame = filter_frame, + }, + { NULL } +}; + +static const AVFilterPad avfilter_vf_hqdn3d_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO + }, + { NULL } +}; + +AVFilter ff_vf_hqdn3d = { .name = "hqdn3d", .description = NULL_IF_CONFIG_SMALL("Apply a High Quality 3D Denoiser."), .priv_size = sizeof(HQDN3DContext), + .priv_class = &hqdn3d_class, .init = init, .uninit = uninit, .query_formats = query_formats, - .inputs = (AVFilterPad[]) {{ .name = "default", - .type = AVMEDIA_TYPE_VIDEO, - .draw_slice = null_draw_slice, - .config_props = config_input, - .end_frame = end_frame }, - { .name = NULL}}, + .inputs = avfilter_vf_hqdn3d_inputs, - .outputs = (AVFilterPad[]) {{ .name = "default", - .type = AVMEDIA_TYPE_VIDEO }, - { .name = NULL}}, + .outputs = avfilter_vf_hqdn3d_outputs, };