[FFmpeg-cvslog] avfilter/avfilter: Add numbers of (in|out)pads directly to AVFilter

Andreas Rheinhardt git at videolan.org
Fri Aug 20 15:32:54 EEST 2021


ffmpeg | branch: master | Andreas Rheinhardt <andreas.rheinhardt at outlook.com> | Thu Aug 12 13:05:31 2021 +0200| [8be701d9f7f77ff2282cc7fe6e0791ca5419de70] | committer: Andreas Rheinhardt

avfilter/avfilter: Add numbers of (in|out)pads directly to AVFilter

Up until now, an AVFilter's lists of input and output AVFilterPads
were terminated by a sentinel and the only way to get the length
of these lists was by using avfilter_pad_count(). This has two
drawbacks: first, sizeof(AVFilterPad) is not negligible
(i.e. 64B on 64bit systems); second, getting the size involves
a function call instead of just reading the data.

This commit therefore changes this. The sentinels are removed and new
private fields nb_inputs and nb_outputs are added to AVFilter that
contain the number of elements of the respective AVFilterPad array.

Given that AVFilter.(in|out)puts are the only arrays of zero-terminated
AVFilterPads an API user has access to (AVFilterContext.(in|out)put_pads
are not zero-terminated and they already have a size field) the argument
to avfilter_pad_count() is always one of these lists, so it just has to
find the filter the list belongs to and read said number. This is slower
than before, but a replacement function that just reads the internal numbers
that users are expected to switch to will be added soon; and furthermore,
avfilter_pad_count() is probably never called in hot loops anyway.

This saves about 49KiB from the binary; notice that these sentinels are
not in .bss despite being zeroed: they are in .data.rel.ro due to the
non-sentinels.

Reviewed-by: Nicolas George <george at nsup.org>
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt at outlook.com>

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=8be701d9f7f77ff2282cc7fe6e0791ca5419de70
---

 libavfilter/aeval.c                 |  9 +++------
 libavfilter/af_acontrast.c          |  6 ++----
 libavfilter/af_acopy.c              |  6 ++----
 libavfilter/af_acrossover.c         |  3 +--
 libavfilter/af_acrusher.c           |  6 ++----
 libavfilter/af_adeclick.c           | 10 ++++------
 libavfilter/af_adelay.c             |  6 ++----
 libavfilter/af_adenorm.c            |  6 ++----
 libavfilter/af_aderivative.c        | 10 ++++------
 libavfilter/af_aecho.c              |  6 ++----
 libavfilter/af_aemphasis.c          |  6 ++----
 libavfilter/af_aexciter.c           |  6 ++----
 libavfilter/af_afade.c              | 12 ++++--------
 libavfilter/af_afftdn.c             |  6 ++----
 libavfilter/af_afftfilt.c           |  6 ++----
 libavfilter/af_aformat.c            |  6 ++----
 libavfilter/af_afreqshift.c         | 10 ++++------
 libavfilter/af_afwtdn.c             |  6 ++----
 libavfilter/af_agate.c              | 12 ++++--------
 libavfilter/af_aiir.c               |  3 +--
 libavfilter/af_alimiter.c           |  6 ++----
 libavfilter/af_amerge.c             |  3 +--
 libavfilter/af_amix.c               |  3 +--
 libavfilter/af_amultiply.c          |  6 ++----
 libavfilter/af_anequalizer.c        |  3 +--
 libavfilter/af_anlmdn.c             |  6 ++----
 libavfilter/af_anlms.c              |  6 ++----
 libavfilter/af_anull.c              |  6 ++----
 libavfilter/af_apad.c               |  6 ++----
 libavfilter/af_aphaser.c            |  6 ++----
 libavfilter/af_apulsator.c          |  6 ++----
 libavfilter/af_aresample.c          |  6 ++----
 libavfilter/af_arnndn.c             |  6 ++----
 libavfilter/af_asetnsamples.c       |  6 ++----
 libavfilter/af_asetrate.c           |  6 ++----
 libavfilter/af_ashowinfo.c          |  6 ++----
 libavfilter/af_asoftclip.c          |  6 ++----
 libavfilter/af_asr.c                |  6 ++----
 libavfilter/af_astats.c             |  6 ++----
 libavfilter/af_asubboost.c          |  6 ++----
 libavfilter/af_asupercut.c          | 18 ++++++++----------
 libavfilter/af_atempo.c             |  6 ++----
 libavfilter/af_axcorrelate.c        |  6 ++----
 libavfilter/af_biquads.c            |  6 ++----
 libavfilter/af_bs2b.c               |  6 ++----
 libavfilter/af_channelmap.c         |  6 ++----
 libavfilter/af_channelsplit.c       |  3 +--
 libavfilter/af_chorus.c             |  6 ++----
 libavfilter/af_compand.c            |  6 ++----
 libavfilter/af_compensationdelay.c  |  6 ++----
 libavfilter/af_crossfeed.c          |  6 ++----
 libavfilter/af_crystalizer.c        |  6 ++----
 libavfilter/af_dcshift.c            |  6 ++----
 libavfilter/af_deesser.c            |  6 ++----
 libavfilter/af_drmeter.c            |  6 ++----
 libavfilter/af_dynaudnorm.c         |  6 ++----
 libavfilter/af_earwax.c             |  6 ++----
 libavfilter/af_extrastereo.c        |  6 ++----
 libavfilter/af_firequalizer.c       |  6 ++----
 libavfilter/af_flanger.c            |  6 ++----
 libavfilter/af_haas.c               |  6 ++----
 libavfilter/af_hdcd.c               |  6 ++----
 libavfilter/af_headphone.c          |  3 +--
 libavfilter/af_join.c               |  3 +--
 libavfilter/af_ladspa.c             |  3 +--
 libavfilter/af_loudnorm.c           |  6 ++----
 libavfilter/af_lv2.c                |  3 +--
 libavfilter/af_mcompand.c           |  6 ++----
 libavfilter/af_pan.c                |  6 ++----
 libavfilter/af_replaygain.c         |  6 ++----
 libavfilter/af_rubberband.c         |  6 ++----
 libavfilter/af_sidechaincompress.c  | 12 ++++--------
 libavfilter/af_silencedetect.c      |  6 ++----
 libavfilter/af_silenceremove.c      |  6 ++----
 libavfilter/af_sofalizer.c          |  6 ++----
 libavfilter/af_speechnorm.c         |  6 ++----
 libavfilter/af_stereotools.c        |  6 ++----
 libavfilter/af_stereowiden.c        |  6 ++----
 libavfilter/af_superequalizer.c     |  6 ++----
 libavfilter/af_surround.c           |  6 ++----
 libavfilter/af_tremolo.c            |  6 ++----
 libavfilter/af_vibrato.c            |  6 ++----
 libavfilter/af_volume.c             |  6 ++----
 libavfilter/af_volumedetect.c       |  6 ++----
 libavfilter/asink_anullsink.c       |  3 +--
 libavfilter/asrc_afirsrc.c          |  3 +--
 libavfilter/asrc_anoisesrc.c        |  3 +--
 libavfilter/asrc_anullsrc.c         |  3 +--
 libavfilter/asrc_flite.c            |  3 +--
 libavfilter/asrc_hilbert.c          |  3 +--
 libavfilter/asrc_sinc.c             |  3 +--
 libavfilter/asrc_sine.c             |  3 +--
 libavfilter/avf_abitscope.c         |  6 ++----
 libavfilter/avf_ahistogram.c        |  6 ++----
 libavfilter/avf_aphasemeter.c       |  3 +--
 libavfilter/avf_avectorscope.c      |  6 ++----
 libavfilter/avf_showcqt.c           |  6 ++----
 libavfilter/avf_showfreqs.c         |  6 ++----
 libavfilter/avf_showspatial.c       |  6 ++----
 libavfilter/avf_showspectrum.c      | 12 ++++--------
 libavfilter/avf_showvolume.c        |  6 ++----
 libavfilter/avf_showwaves.c         | 12 ++++--------
 libavfilter/avfilter.c              | 18 ++++++++++++------
 libavfilter/avfilter.h              | 18 ++++++++++++++----
 libavfilter/buffersink.c            |  6 ++----
 libavfilter/buffersrc.c             |  6 ++----
 libavfilter/f_bench.c               | 12 ++++--------
 libavfilter/f_cue.c                 | 12 ++++--------
 libavfilter/f_drawgraph.c           | 12 ++++--------
 libavfilter/f_ebur128.c             |  3 +--
 libavfilter/f_graphmonitor.c        | 12 ++++--------
 libavfilter/f_interleave.c          |  6 ++----
 libavfilter/f_loop.c                | 12 ++++--------
 libavfilter/f_metadata.c            | 12 ++++--------
 libavfilter/f_perms.c               | 12 ++++--------
 libavfilter/f_realtime.c            | 12 ++++--------
 libavfilter/f_reverse.c             | 12 ++++--------
 libavfilter/f_segment.c             |  6 ++----
 libavfilter/f_select.c              |  6 ++----
 libavfilter/f_sendcmd.c             | 12 ++++--------
 libavfilter/f_sidedata.c            | 12 ++++--------
 libavfilter/f_zmq.c                 | 12 ++++--------
 libavfilter/fifo.c                  | 12 ++++--------
 libavfilter/internal.h              |  6 ++++++
 libavfilter/setpts.c                | 12 ++++--------
 libavfilter/settb.c                 | 12 ++++--------
 libavfilter/split.c                 |  6 ++----
 libavfilter/trim.c                  | 12 ++++--------
 libavfilter/vaf_spectrumsynth.c     |  6 ++----
 libavfilter/vf_addroi.c             |  6 ++----
 libavfilter/vf_alphamerge.c         |  6 ++----
 libavfilter/vf_amplify.c            |  6 ++----
 libavfilter/vf_aspect.c             | 12 ++++--------
 libavfilter/vf_atadenoise.c         |  6 ++----
 libavfilter/vf_avgblur.c            |  6 ++----
 libavfilter/vf_avgblur_opencl.c     | 10 ++++------
 libavfilter/vf_avgblur_vulkan.c     |  6 ++----
 libavfilter/vf_bbox.c               |  6 ++----
 libavfilter/vf_bilateral.c          |  6 ++----
 libavfilter/vf_bitplanenoise.c      |  6 ++----
 libavfilter/vf_blackdetect.c        |  6 ++----
 libavfilter/vf_blackframe.c         |  6 ++----
 libavfilter/vf_blend.c              | 12 ++++--------
 libavfilter/vf_bm3d.c               |  3 +--
 libavfilter/vf_boxblur.c            |  6 ++----
 libavfilter/vf_bwdif.c              |  6 ++----
 libavfilter/vf_cas.c                |  6 ++----
 libavfilter/vf_chromaber_vulkan.c   |  6 ++----
 libavfilter/vf_chromakey.c          | 12 ++++--------
 libavfilter/vf_chromanr.c           |  6 ++----
 libavfilter/vf_chromashift.c        | 10 ++++------
 libavfilter/vf_ciescope.c           |  6 ++----
 libavfilter/vf_codecview.c          |  6 ++----
 libavfilter/vf_colorbalance.c       |  6 ++----
 libavfilter/vf_colorchannelmixer.c  |  6 ++----
 libavfilter/vf_colorconstancy.c     |  6 ++----
 libavfilter/vf_colorcontrast.c      |  6 ++----
 libavfilter/vf_colorcorrect.c       |  6 ++----
 libavfilter/vf_colorize.c           |  6 ++----
 libavfilter/vf_colorkey.c           | 10 ++++------
 libavfilter/vf_colorkey_opencl.c    |  6 ++----
 libavfilter/vf_colorlevels.c        |  6 ++----
 libavfilter/vf_colormatrix.c        |  6 ++----
 libavfilter/vf_colorspace.c         |  6 ++----
 libavfilter/vf_colortemperature.c   |  6 ++----
 libavfilter/vf_convolution.c        | 22 ++++++++++------------
 libavfilter/vf_convolution_opencl.c | 18 ++++++++----------
 libavfilter/vf_convolve.c           | 10 ++++------
 libavfilter/vf_copy.c               |  6 ++----
 libavfilter/vf_coreimage.m          |  9 +++------
 libavfilter/vf_cover_rect.c         |  6 ++----
 libavfilter/vf_crop.c               |  6 ++----
 libavfilter/vf_cropdetect.c         |  6 ++----
 libavfilter/vf_curves.c             |  6 ++----
 libavfilter/vf_datascope.c          | 18 ++++++------------
 libavfilter/vf_dblur.c              |  6 ++----
 libavfilter/vf_dctdnoiz.c           |  6 ++----
 libavfilter/vf_deband.c             |  6 ++----
 libavfilter/vf_deblock.c            |  6 ++----
 libavfilter/vf_decimate.c           |  3 +--
 libavfilter/vf_dedot.c              |  6 ++----
 libavfilter/vf_deflicker.c          |  6 ++----
 libavfilter/vf_deinterlace_qsv.c    |  6 ++----
 libavfilter/vf_deinterlace_vaapi.c  |  6 ++----
 libavfilter/vf_dejudder.c           |  6 ++----
 libavfilter/vf_delogo.c             |  6 ++----
 libavfilter/vf_derain.c             |  6 ++----
 libavfilter/vf_deshake.c            |  6 ++----
 libavfilter/vf_deshake_opencl.c     |  6 ++----
 libavfilter/vf_despill.c            |  6 ++----
 libavfilter/vf_detelecine.c         |  6 ++----
 libavfilter/vf_displace.c           |  6 ++----
 libavfilter/vf_dnn_classify.c       |  6 ++----
 libavfilter/vf_dnn_detect.c         |  6 ++----
 libavfilter/vf_dnn_processing.c     |  6 ++----
 libavfilter/vf_drawbox.c            | 12 ++++--------
 libavfilter/vf_drawtext.c           |  6 ++----
 libavfilter/vf_edgedetect.c         |  6 ++----
 libavfilter/vf_elbg.c               |  6 ++----
 libavfilter/vf_entropy.c            |  6 ++----
 libavfilter/vf_epx.c                |  6 ++----
 libavfilter/vf_eq.c                 |  6 ++----
 libavfilter/vf_estdif.c             |  6 ++----
 libavfilter/vf_exposure.c           |  6 ++----
 libavfilter/vf_extractplanes.c      |  5 ++---
 libavfilter/vf_fade.c               |  6 ++----
 libavfilter/vf_fftdnoiz.c           |  6 ++----
 libavfilter/vf_fftfilt.c            |  6 ++----
 libavfilter/vf_field.c              |  6 ++----
 libavfilter/vf_fieldhint.c          |  6 ++----
 libavfilter/vf_fieldmatch.c         |  3 +--
 libavfilter/vf_fieldorder.c         |  6 ++----
 libavfilter/vf_fillborders.c        |  6 ++----
 libavfilter/vf_find_rect.c          |  6 ++----
 libavfilter/vf_floodfill.c          |  6 ++----
 libavfilter/vf_format.c             | 12 ++++--------
 libavfilter/vf_fps.c                |  6 ++----
 libavfilter/vf_framepack.c          |  6 ++----
 libavfilter/vf_framerate.c          |  6 ++----
 libavfilter/vf_framestep.c          |  6 ++----
 libavfilter/vf_freezedetect.c       |  6 ++----
 libavfilter/vf_freezeframes.c       |  6 ++----
 libavfilter/vf_frei0r.c             |  9 +++------
 libavfilter/vf_fspp.c               |  6 ++----
 libavfilter/vf_gblur.c              |  6 ++----
 libavfilter/vf_geq.c                |  6 ++----
 libavfilter/vf_gradfun.c            |  6 ++----
 libavfilter/vf_guided.c             |  3 +--
 libavfilter/vf_hflip.c              |  6 ++----
 libavfilter/vf_histeq.c             |  6 ++----
 libavfilter/vf_histogram.c          | 10 ++++------
 libavfilter/vf_hqdn3d.c             |  6 ++----
 libavfilter/vf_hqx.c                |  6 ++----
 libavfilter/vf_hue.c                |  6 ++----
 libavfilter/vf_hwdownload.c         |  6 ++----
 libavfilter/vf_hwmap.c              |  6 ++----
 libavfilter/vf_hwupload.c           |  6 ++----
 libavfilter/vf_hwupload_cuda.c      |  6 ++----
 libavfilter/vf_hysteresis.c         |  6 ++----
 libavfilter/vf_identity.c           | 10 ++++------
 libavfilter/vf_idet.c               |  6 ++----
 libavfilter/vf_il.c                 |  6 ++----
 libavfilter/vf_kerndeint.c          |  6 ++----
 libavfilter/vf_lagfun.c             |  6 ++----
 libavfilter/vf_lenscorrection.c     |  6 ++----
 libavfilter/vf_lensfun.c            |  6 ++----
 libavfilter/vf_libopencv.c          |  6 ++----
 libavfilter/vf_libvmaf.c            |  6 ++----
 libavfilter/vf_limiter.c            |  6 ++----
 libavfilter/vf_lumakey.c            |  6 ++----
 libavfilter/vf_lut.c                |  6 ++----
 libavfilter/vf_lut2.c               | 12 ++++--------
 libavfilter/vf_lut3d.c              | 18 ++++++------------
 libavfilter/vf_maskedclamp.c        |  6 ++----
 libavfilter/vf_maskedmerge.c        |  6 ++----
 libavfilter/vf_maskedminmax.c       | 10 ++++------
 libavfilter/vf_maskedthreshold.c    |  6 ++----
 libavfilter/vf_maskfun.c            |  6 ++----
 libavfilter/vf_mcdeint.c            |  6 ++----
 libavfilter/vf_median.c             |  6 ++----
 libavfilter/vf_mergeplanes.c        |  3 +--
 libavfilter/vf_mestimate.c          |  6 ++----
 libavfilter/vf_midequalizer.c       |  6 ++----
 libavfilter/vf_minterpolate.c       |  6 ++----
 libavfilter/vf_misc_vaapi.c         | 10 ++++------
 libavfilter/vf_mix.c                |  8 +++-----
 libavfilter/vf_monochrome.c         |  6 ++----
 libavfilter/vf_mpdecimate.c         |  6 ++----
 libavfilter/vf_neighbor.c           |  6 ++----
 libavfilter/vf_neighbor_opencl.c    | 10 ++++------
 libavfilter/vf_nlmeans.c            |  6 ++----
 libavfilter/vf_nlmeans_opencl.c     |  6 ++----
 libavfilter/vf_nnedi.c              |  6 ++----
 libavfilter/vf_noise.c              |  6 ++----
 libavfilter/vf_normalize.c          |  6 ++----
 libavfilter/vf_null.c               |  6 ++----
 libavfilter/vf_ocr.c                |  6 ++----
 libavfilter/vf_overlay.c            |  6 ++----
 libavfilter/vf_overlay_cuda.c       |  6 ++----
 libavfilter/vf_overlay_opencl.c     |  6 ++----
 libavfilter/vf_overlay_qsv.c        |  6 ++----
 libavfilter/vf_overlay_vulkan.c     |  6 ++----
 libavfilter/vf_owdenoise.c          |  6 ++----
 libavfilter/vf_pad.c                |  6 ++----
 libavfilter/vf_pad_opencl.c         |  6 ++----
 libavfilter/vf_palettegen.c         |  6 ++----
 libavfilter/vf_paletteuse.c         |  6 ++----
 libavfilter/vf_perspective.c        |  6 ++----
 libavfilter/vf_phase.c              |  6 ++----
 libavfilter/vf_photosensitivity.c   |  6 ++----
 libavfilter/vf_pixdesctest.c        |  6 ++----
 libavfilter/vf_pp.c                 |  6 ++----
 libavfilter/vf_pp7.c                |  6 ++----
 libavfilter/vf_premultiply.c        |  5 ++---
 libavfilter/vf_procamp_vaapi.c      |  6 ++----
 libavfilter/vf_program_opencl.c     |  6 ++----
 libavfilter/vf_pseudocolor.c        |  6 ++----
 libavfilter/vf_psnr.c               |  6 ++----
 libavfilter/vf_pullup.c             |  6 ++----
 libavfilter/vf_qp.c                 |  6 ++----
 libavfilter/vf_random.c             |  6 ++----
 libavfilter/vf_readeia608.c         |  6 ++----
 libavfilter/vf_readvitc.c           |  6 ++----
 libavfilter/vf_remap.c              |  6 ++----
 libavfilter/vf_removegrain.c        |  6 ++----
 libavfilter/vf_removelogo.c         |  6 ++----
 libavfilter/vf_repeatfields.c       |  6 ++----
 libavfilter/vf_rotate.c             |  6 ++----
 libavfilter/vf_sab.c                |  6 ++----
 libavfilter/vf_scale.c              | 12 ++++--------
 libavfilter/vf_scale_cuda.c         |  6 ++----
 libavfilter/vf_scale_npp.c          |  6 ++----
 libavfilter/vf_scale_qsv.c          |  6 ++----
 libavfilter/vf_scale_vaapi.c        |  6 ++----
 libavfilter/vf_scale_vulkan.c       |  6 ++----
 libavfilter/vf_scdet.c              |  6 ++----
 libavfilter/vf_scroll.c             |  6 ++----
 libavfilter/vf_selectivecolor.c     |  6 ++----
 libavfilter/vf_separatefields.c     |  6 ++----
 libavfilter/vf_setparams.c          | 14 ++++++--------
 libavfilter/vf_shear.c              |  6 ++----
 libavfilter/vf_showinfo.c           |  6 ++----
 libavfilter/vf_showpalette.c        |  6 ++----
 libavfilter/vf_shuffleframes.c      |  6 ++----
 libavfilter/vf_shufflepixels.c      |  6 ++----
 libavfilter/vf_shuffleplanes.c      |  6 ++----
 libavfilter/vf_signalstats.c        |  6 ++----
 libavfilter/vf_signature.c          |  3 +--
 libavfilter/vf_smartblur.c          |  6 ++----
 libavfilter/vf_spp.c                |  6 ++----
 libavfilter/vf_sr.c                 |  6 ++----
 libavfilter/vf_ssim.c               |  6 ++----
 libavfilter/vf_stack.c              |  7 +++----
 libavfilter/vf_stereo3d.c           |  6 ++----
 libavfilter/vf_subtitles.c          | 10 ++++------
 libavfilter/vf_super2xsai.c         |  6 ++----
 libavfilter/vf_swaprect.c           |  6 ++----
 libavfilter/vf_swapuv.c             |  6 ++----
 libavfilter/vf_telecine.c           |  6 ++----
 libavfilter/vf_threshold.c          |  6 ++----
 libavfilter/vf_thumbnail.c          |  6 ++----
 libavfilter/vf_thumbnail_cuda.c     |  6 ++----
 libavfilter/vf_tile.c               |  6 ++----
 libavfilter/vf_tinterlace.c         | 10 ++++------
 libavfilter/vf_tmidequalizer.c      |  6 ++----
 libavfilter/vf_tonemap.c            |  6 ++----
 libavfilter/vf_tonemap_opencl.c     |  6 ++----
 libavfilter/vf_tonemap_vaapi.c      |  6 ++----
 libavfilter/vf_tpad.c               |  6 ++----
 libavfilter/vf_transpose.c          |  6 ++----
 libavfilter/vf_transpose_npp.c      |  6 ++----
 libavfilter/vf_transpose_opencl.c   |  6 ++----
 libavfilter/vf_transpose_vaapi.c    |  6 ++----
 libavfilter/vf_unsharp.c            |  6 ++----
 libavfilter/vf_unsharp_opencl.c     |  6 ++----
 libavfilter/vf_untile.c             |  6 ++----
 libavfilter/vf_uspp.c               |  6 ++----
 libavfilter/vf_v360.c               |  6 ++----
 libavfilter/vf_vaguedenoiser.c      |  6 ++----
 libavfilter/vf_vectorscope.c        |  6 ++----
 libavfilter/vf_vflip.c              |  6 ++----
 libavfilter/vf_vfrdet.c             |  6 ++----
 libavfilter/vf_vibrance.c           |  6 ++----
 libavfilter/vf_vidstabdetect.c      |  6 ++----
 libavfilter/vf_vidstabtransform.c   |  6 ++----
 libavfilter/vf_vif.c                |  6 ++----
 libavfilter/vf_vignette.c           |  6 ++----
 libavfilter/vf_vmafmotion.c         |  6 ++----
 libavfilter/vf_vpp_qsv.c            |  6 ++----
 libavfilter/vf_w3fdif.c             |  6 ++----
 libavfilter/vf_waveform.c           |  6 ++----
 libavfilter/vf_weave.c              | 10 ++++------
 libavfilter/vf_xbr.c                |  6 ++----
 libavfilter/vf_xfade.c              |  6 ++----
 libavfilter/vf_xfade_opencl.c       |  6 ++----
 libavfilter/vf_xmedian.c            |  9 +++------
 libavfilter/vf_yadif.c              |  6 ++----
 libavfilter/vf_yadif_cuda.c         |  6 ++----
 libavfilter/vf_yaepblur.c           |  6 ++----
 libavfilter/vf_zoompan.c            |  6 ++----
 libavfilter/vf_zscale.c             |  6 ++----
 libavfilter/vsink_nullsink.c        |  3 +--
 libavfilter/vsrc_cellauto.c         |  3 +--
 libavfilter/vsrc_gradients.c        |  3 +--
 libavfilter/vsrc_life.c             |  3 +--
 libavfilter/vsrc_mandelbrot.c       |  3 +--
 libavfilter/vsrc_mptestsrc.c        |  3 +--
 libavfilter/vsrc_sierpinski.c       |  3 +--
 libavfilter/vsrc_testsrc.c          | 36 +++++++++++++-----------------------
 389 files changed, 906 insertions(+), 1696 deletions(-)

diff --git a/libavfilter/aeval.c b/libavfilter/aeval.c
index 7c891c5ad0..7cb05d206a 100644
--- a/libavfilter/aeval.c
+++ b/libavfilter/aeval.c
@@ -307,7 +307,6 @@ static const AVFilterPad aevalsrc_outputs[] = {
         .config_props  = config_props,
         .request_frame = request_frame,
     },
-    { NULL }
 };
 
 const AVFilter ff_asrc_aevalsrc = {
@@ -318,7 +317,7 @@ const AVFilter ff_asrc_aevalsrc = {
     .uninit        = uninit,
     .priv_size     = sizeof(EvalContext),
     .inputs        = NULL,
-    .outputs       = aevalsrc_outputs,
+    FILTER_OUTPUTS(aevalsrc_outputs),
     .priv_class    = &aevalsrc_class,
 };
 
@@ -445,7 +444,6 @@ static const AVFilterPad aeval_inputs[] = {
         .type           = AVMEDIA_TYPE_AUDIO,
         .filter_frame   = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad aeval_outputs[] = {
@@ -454,7 +452,6 @@ static const AVFilterPad aeval_outputs[] = {
         .type          = AVMEDIA_TYPE_AUDIO,
         .config_props  = aeval_config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_aeval = {
@@ -464,8 +461,8 @@ const AVFilter ff_af_aeval = {
     .init          = init,
     .uninit        = uninit,
     .priv_size     = sizeof(EvalContext),
-    .inputs        = aeval_inputs,
-    .outputs       = aeval_outputs,
+    FILTER_INPUTS(aeval_inputs),
+    FILTER_OUTPUTS(aeval_outputs),
     .priv_class    = &aeval_class,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
 };
diff --git a/libavfilter/af_acontrast.c b/libavfilter/af_acontrast.c
index d4128e7495..b5a5381fba 100644
--- a/libavfilter/af_acontrast.c
+++ b/libavfilter/af_acontrast.c
@@ -187,7 +187,6 @@ static const AVFilterPad inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -195,7 +194,6 @@ static const AVFilterPad outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_acontrast = {
@@ -204,6 +202,6 @@ const AVFilter ff_af_acontrast = {
     .query_formats  = query_formats,
     .priv_size      = sizeof(AudioContrastContext),
     .priv_class     = &acontrast_class,
-    .inputs         = inputs,
-    .outputs        = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
 };
diff --git a/libavfilter/af_acopy.c b/libavfilter/af_acopy.c
index 29551996d9..32455d9186 100644
--- a/libavfilter/af_acopy.c
+++ b/libavfilter/af_acopy.c
@@ -51,7 +51,6 @@ static const AVFilterPad acopy_inputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad acopy_outputs[] = {
@@ -59,12 +58,11 @@ static const AVFilterPad acopy_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_acopy = {
     .name          = "acopy",
     .description   = NULL_IF_CONFIG_SMALL("Copy the input audio unchanged to the output."),
-    .inputs        = acopy_inputs,
-    .outputs       = acopy_outputs,
+    FILTER_INPUTS(acopy_inputs),
+    FILTER_OUTPUTS(acopy_outputs),
 };
diff --git a/libavfilter/af_acrossover.c b/libavfilter/af_acrossover.c
index d57c0406c9..edb257d634 100644
--- a/libavfilter/af_acrossover.c
+++ b/libavfilter/af_acrossover.c
@@ -555,7 +555,6 @@ static const AVFilterPad inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_acrossover = {
@@ -566,7 +565,7 @@ const AVFilter ff_af_acrossover = {
     .init           = init,
     .uninit         = uninit,
     .query_formats  = query_formats,
-    .inputs         = inputs,
+    FILTER_INPUTS(inputs),
     .outputs        = NULL,
     .flags          = AVFILTER_FLAG_DYNAMIC_OUTPUTS |
                       AVFILTER_FLAG_SLICE_THREADS,
diff --git a/libavfilter/af_acrusher.c b/libavfilter/af_acrusher.c
index 447d049062..6130c9f2ec 100644
--- a/libavfilter/af_acrusher.c
+++ b/libavfilter/af_acrusher.c
@@ -342,7 +342,6 @@ static const AVFilterPad avfilter_af_acrusher_inputs[] = {
         .config_props = config_input,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad avfilter_af_acrusher_outputs[] = {
@@ -350,7 +349,6 @@ static const AVFilterPad avfilter_af_acrusher_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_acrusher = {
@@ -360,7 +358,7 @@ const AVFilter ff_af_acrusher = {
     .priv_class    = &acrusher_class,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = avfilter_af_acrusher_inputs,
-    .outputs       = avfilter_af_acrusher_outputs,
+    FILTER_INPUTS(avfilter_af_acrusher_inputs),
+    FILTER_OUTPUTS(avfilter_af_acrusher_outputs),
     .process_command = process_command,
 };
diff --git a/libavfilter/af_adeclick.c b/libavfilter/af_adeclick.c
index c216aaca15..1e30ada03c 100644
--- a/libavfilter/af_adeclick.c
+++ b/libavfilter/af_adeclick.c
@@ -741,7 +741,6 @@ static const AVFilterPad inputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -749,7 +748,6 @@ static const AVFilterPad outputs[] = {
         .name          = "default",
         .type          = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_adeclick = {
@@ -761,8 +759,8 @@ const AVFilter ff_af_adeclick = {
     .init          = init,
     .activate      = activate,
     .uninit        = uninit,
-    .inputs        = inputs,
-    .outputs       = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
     .flags         = AVFILTER_FLAG_SLICE_THREADS | AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
 };
 
@@ -797,7 +795,7 @@ const AVFilter ff_af_adeclip = {
     .init          = init,
     .activate      = activate,
     .uninit        = uninit,
-    .inputs        = inputs,
-    .outputs       = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
     .flags         = AVFILTER_FLAG_SLICE_THREADS | AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
 };
diff --git a/libavfilter/af_adelay.c b/libavfilter/af_adelay.c
index 7640cca357..f9b4acd600 100644
--- a/libavfilter/af_adelay.c
+++ b/libavfilter/af_adelay.c
@@ -326,7 +326,6 @@ static const AVFilterPad adelay_inputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad adelay_outputs[] = {
@@ -334,7 +333,6 @@ static const AVFilterPad adelay_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_adelay = {
@@ -345,7 +343,7 @@ const AVFilter ff_af_adelay = {
     .priv_class    = &adelay_class,
     .activate      = activate,
     .uninit        = uninit,
-    .inputs        = adelay_inputs,
-    .outputs       = adelay_outputs,
+    FILTER_INPUTS(adelay_inputs),
+    FILTER_OUTPUTS(adelay_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
 };
diff --git a/libavfilter/af_adenorm.c b/libavfilter/af_adenorm.c
index f6e120c97c..c48c02fc70 100644
--- a/libavfilter/af_adenorm.c
+++ b/libavfilter/af_adenorm.c
@@ -279,7 +279,6 @@ static const AVFilterPad adenorm_inputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad adenorm_outputs[] = {
@@ -288,7 +287,6 @@ static const AVFilterPad adenorm_outputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .config_props = config_output,
     },
-    { NULL }
 };
 
 #define OFFSET(x) offsetof(ADenormContext, x)
@@ -311,8 +309,8 @@ const AVFilter ff_af_adenorm = {
     .description     = NULL_IF_CONFIG_SMALL("Remedy denormals by adding extremely low-level noise."),
     .query_formats   = query_formats,
     .priv_size       = sizeof(ADenormContext),
-    .inputs          = adenorm_inputs,
-    .outputs         = adenorm_outputs,
+    FILTER_INPUTS(adenorm_inputs),
+    FILTER_OUTPUTS(adenorm_outputs),
     .priv_class      = &adenorm_class,
     .process_command = process_command,
     .flags           = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC |
diff --git a/libavfilter/af_aderivative.c b/libavfilter/af_aderivative.c
index 0933bb22a9..e4b6267a1a 100644
--- a/libavfilter/af_aderivative.c
+++ b/libavfilter/af_aderivative.c
@@ -163,7 +163,6 @@ static const AVFilterPad aderivative_inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad aderivative_outputs[] = {
@@ -171,7 +170,6 @@ static const AVFilterPad aderivative_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_aderivative = {
@@ -180,8 +178,8 @@ const AVFilter ff_af_aderivative = {
     .query_formats = query_formats,
     .priv_size     = sizeof(ADerivativeContext),
     .uninit        = uninit,
-    .inputs        = aderivative_inputs,
-    .outputs       = aderivative_outputs,
+    FILTER_INPUTS(aderivative_inputs),
+    FILTER_OUTPUTS(aderivative_outputs),
 };
 
 const AVFilter ff_af_aintegral = {
@@ -190,6 +188,6 @@ const AVFilter ff_af_aintegral = {
     .query_formats = query_formats,
     .priv_size     = sizeof(ADerivativeContext),
     .uninit        = uninit,
-    .inputs        = aderivative_inputs,
-    .outputs       = aderivative_outputs,
+    FILTER_INPUTS(aderivative_inputs),
+    FILTER_OUTPUTS(aderivative_outputs),
 };
diff --git a/libavfilter/af_aecho.c b/libavfilter/af_aecho.c
index bc040536b0..d533bb610b 100644
--- a/libavfilter/af_aecho.c
+++ b/libavfilter/af_aecho.c
@@ -351,7 +351,6 @@ static const AVFilterPad aecho_inputs[] = {
         .name         = "default",
         .type         = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 static const AVFilterPad aecho_outputs[] = {
@@ -360,7 +359,6 @@ static const AVFilterPad aecho_outputs[] = {
         .config_props  = config_output,
         .type          = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_aecho = {
@@ -372,6 +370,6 @@ const AVFilter ff_af_aecho = {
     .init          = init,
     .activate      = activate,
     .uninit        = uninit,
-    .inputs        = aecho_inputs,
-    .outputs       = aecho_outputs,
+    FILTER_INPUTS(aecho_inputs),
+    FILTER_OUTPUTS(aecho_outputs),
 };
diff --git a/libavfilter/af_aemphasis.c b/libavfilter/af_aemphasis.c
index 4646ac0170..a9c0cf599d 100644
--- a/libavfilter/af_aemphasis.c
+++ b/libavfilter/af_aemphasis.c
@@ -376,7 +376,6 @@ static const AVFilterPad avfilter_af_aemphasis_inputs[] = {
         .config_props = config_input,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad avfilter_af_aemphasis_outputs[] = {
@@ -384,7 +383,6 @@ static const AVFilterPad avfilter_af_aemphasis_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_aemphasis = {
@@ -394,8 +392,8 @@ const AVFilter ff_af_aemphasis = {
     .priv_class    = &aemphasis_class,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = avfilter_af_aemphasis_inputs,
-    .outputs       = avfilter_af_aemphasis_outputs,
+    FILTER_INPUTS(avfilter_af_aemphasis_inputs),
+    FILTER_OUTPUTS(avfilter_af_aemphasis_outputs),
     .process_command = process_command,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC |
                      AVFILTER_FLAG_SLICE_THREADS,
diff --git a/libavfilter/af_aexciter.c b/libavfilter/af_aexciter.c
index 6ebf2828df..f9ece59d93 100644
--- a/libavfilter/af_aexciter.c
+++ b/libavfilter/af_aexciter.c
@@ -279,7 +279,6 @@ static const AVFilterPad avfilter_af_aexciter_inputs[] = {
         .config_props = config_input,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad avfilter_af_aexciter_outputs[] = {
@@ -287,7 +286,6 @@ static const AVFilterPad avfilter_af_aexciter_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_aexciter = {
@@ -297,8 +295,8 @@ const AVFilter ff_af_aexciter = {
     .priv_class    = &aexciter_class,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = avfilter_af_aexciter_inputs,
-    .outputs       = avfilter_af_aexciter_outputs,
+    FILTER_INPUTS(avfilter_af_aexciter_inputs),
+    FILTER_OUTPUTS(avfilter_af_aexciter_outputs),
     .process_command = process_command,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
 };
diff --git a/libavfilter/af_afade.c b/libavfilter/af_afade.c
index f39c0e45b6..a55d5d72c3 100644
--- a/libavfilter/af_afade.c
+++ b/libavfilter/af_afade.c
@@ -340,7 +340,6 @@ static const AVFilterPad avfilter_af_afade_inputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad avfilter_af_afade_outputs[] = {
@@ -349,7 +348,6 @@ static const AVFilterPad avfilter_af_afade_outputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .config_props = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_afade = {
@@ -358,8 +356,8 @@ const AVFilter ff_af_afade = {
     .query_formats = query_formats,
     .priv_size     = sizeof(AudioFadeContext),
     .init          = init,
-    .inputs        = avfilter_af_afade_inputs,
-    .outputs       = avfilter_af_afade_outputs,
+    FILTER_INPUTS(avfilter_af_afade_inputs),
+    FILTER_OUTPUTS(avfilter_af_afade_outputs),
     .priv_class    = &afade_class,
     .process_command = process_command,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
@@ -628,7 +626,6 @@ static const AVFilterPad avfilter_af_acrossfade_inputs[] = {
         .name         = "crossfade1",
         .type         = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 static const AVFilterPad avfilter_af_acrossfade_outputs[] = {
@@ -637,7 +634,6 @@ static const AVFilterPad avfilter_af_acrossfade_outputs[] = {
         .type          = AVMEDIA_TYPE_AUDIO,
         .config_props  = acrossfade_config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_acrossfade = {
@@ -647,8 +643,8 @@ const AVFilter ff_af_acrossfade = {
     .priv_size     = sizeof(AudioFadeContext),
     .activate      = activate,
     .priv_class    = &acrossfade_class,
-    .inputs        = avfilter_af_acrossfade_inputs,
-    .outputs       = avfilter_af_acrossfade_outputs,
+    FILTER_INPUTS(avfilter_af_acrossfade_inputs),
+    FILTER_OUTPUTS(avfilter_af_acrossfade_outputs),
 };
 
 #endif /* CONFIG_ACROSSFADE_FILTER */
diff --git a/libavfilter/af_afftdn.c b/libavfilter/af_afftdn.c
index 6f343e8bd0..aa0dd7ce6c 100644
--- a/libavfilter/af_afftdn.c
+++ b/libavfilter/af_afftdn.c
@@ -1400,7 +1400,6 @@ static const AVFilterPad inputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -1408,7 +1407,6 @@ static const AVFilterPad outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_afftdn = {
@@ -1419,8 +1417,8 @@ const AVFilter ff_af_afftdn = {
     .priv_class      = &afftdn_class,
     .activate        = activate,
     .uninit          = uninit,
-    .inputs          = inputs,
-    .outputs         = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
     .process_command = process_command,
     .flags           = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC |
                        AVFILTER_FLAG_SLICE_THREADS,
diff --git a/libavfilter/af_afftfilt.c b/libavfilter/af_afftfilt.c
index 314585c419..de54c13135 100644
--- a/libavfilter/af_afftfilt.c
+++ b/libavfilter/af_afftfilt.c
@@ -466,7 +466,6 @@ static const AVFilterPad inputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -474,7 +473,6 @@ static const AVFilterPad outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_afftfilt = {
@@ -482,8 +480,8 @@ const AVFilter ff_af_afftfilt = {
     .description     = NULL_IF_CONFIG_SMALL("Apply arbitrary expressions to samples in frequency domain."),
     .priv_size       = sizeof(AFFTFiltContext),
     .priv_class      = &afftfilt_class,
-    .inputs          = inputs,
-    .outputs         = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
     .activate        = activate,
     .query_formats   = query_formats,
     .uninit          = uninit,
diff --git a/libavfilter/af_aformat.c b/libavfilter/af_aformat.c
index e9cc4738fd..1cab148d95 100644
--- a/libavfilter/af_aformat.c
+++ b/libavfilter/af_aformat.c
@@ -146,7 +146,6 @@ static const AVFilterPad avfilter_af_aformat_inputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 static const AVFilterPad avfilter_af_aformat_outputs[] = {
@@ -154,7 +153,6 @@ static const AVFilterPad avfilter_af_aformat_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO
     },
-    { NULL }
 };
 
 const AVFilter ff_af_aformat = {
@@ -165,6 +163,6 @@ const AVFilter ff_af_aformat = {
     .query_formats = query_formats,
     .priv_size     = sizeof(AFormatContext),
     .priv_class    = &aformat_class,
-    .inputs        = avfilter_af_aformat_inputs,
-    .outputs       = avfilter_af_aformat_outputs,
+    FILTER_INPUTS(avfilter_af_aformat_inputs),
+    FILTER_OUTPUTS(avfilter_af_aformat_outputs),
 };
diff --git a/libavfilter/af_afreqshift.c b/libavfilter/af_afreqshift.c
index e864a73574..3be393d9f7 100644
--- a/libavfilter/af_afreqshift.c
+++ b/libavfilter/af_afreqshift.c
@@ -367,7 +367,6 @@ static const AVFilterPad inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -375,7 +374,6 @@ static const AVFilterPad outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_afreqshift = {
@@ -385,8 +383,8 @@ const AVFilter ff_af_afreqshift = {
     .priv_size       = sizeof(AFreqShift),
     .priv_class      = &afreqshift_class,
     .uninit          = uninit,
-    .inputs          = inputs,
-    .outputs         = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
     .process_command = ff_filter_process_command,
     .flags           = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC |
                        AVFILTER_FLAG_SLICE_THREADS,
@@ -407,8 +405,8 @@ const AVFilter ff_af_aphaseshift = {
     .priv_size       = sizeof(AFreqShift),
     .priv_class      = &aphaseshift_class,
     .uninit          = uninit,
-    .inputs          = inputs,
-    .outputs         = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
     .process_command = ff_filter_process_command,
     .flags           = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC |
                        AVFILTER_FLAG_SLICE_THREADS,
diff --git a/libavfilter/af_afwtdn.c b/libavfilter/af_afwtdn.c
index d39d75d405..f7e8211bb4 100644
--- a/libavfilter/af_afwtdn.c
+++ b/libavfilter/af_afwtdn.c
@@ -1311,7 +1311,6 @@ static const AVFilterPad inputs[] = {
         .name         = "default",
         .type         = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -1320,7 +1319,6 @@ static const AVFilterPad outputs[] = {
         .type          = AVMEDIA_TYPE_AUDIO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_afwtdn = {
@@ -1331,8 +1329,8 @@ const AVFilter ff_af_afwtdn = {
     .priv_class      = &afwtdn_class,
     .activate        = activate,
     .uninit          = uninit,
-    .inputs          = inputs,
-    .outputs         = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
     .process_command = process_command,
     .flags           = AVFILTER_FLAG_SLICE_THREADS,
 };
diff --git a/libavfilter/af_agate.c b/libavfilter/af_agate.c
index eb77dfbcc5..0dc28ac080 100644
--- a/libavfilter/af_agate.c
+++ b/libavfilter/af_agate.c
@@ -240,7 +240,6 @@ static const AVFilterPad inputs[] = {
         .filter_frame = filter_frame,
         .config_props = agate_config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -248,7 +247,6 @@ static const AVFilterPad outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_agate = {
@@ -257,8 +255,8 @@ const AVFilter ff_af_agate = {
     .query_formats  = query_formats,
     .priv_size      = sizeof(AudioGateContext),
     .priv_class     = &agate_class,
-    .inputs         = inputs,
-    .outputs        = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
     .process_command = ff_filter_process_command,
     .flags          = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
 };
@@ -413,7 +411,6 @@ static const AVFilterPad sidechaingate_inputs[] = {
         .name           = "sidechain",
         .type           = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 static const AVFilterPad sidechaingate_outputs[] = {
@@ -422,7 +419,6 @@ static const AVFilterPad sidechaingate_outputs[] = {
         .type          = AVMEDIA_TYPE_AUDIO,
         .config_props  = scconfig_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_sidechaingate = {
@@ -433,8 +429,8 @@ const AVFilter ff_af_sidechaingate = {
     .query_formats  = scquery_formats,
     .activate       = activate,
     .uninit         = uninit,
-    .inputs         = sidechaingate_inputs,
-    .outputs        = sidechaingate_outputs,
+    FILTER_INPUTS(sidechaingate_inputs),
+    FILTER_OUTPUTS(sidechaingate_outputs),
     .process_command = ff_filter_process_command,
     .flags          = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
 };
diff --git a/libavfilter/af_aiir.c b/libavfilter/af_aiir.c
index d46fdea3b7..cae2c365bf 100644
--- a/libavfilter/af_aiir.c
+++ b/libavfilter/af_aiir.c
@@ -1518,7 +1518,6 @@ static const AVFilterPad inputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 #define OFFSET(x) offsetof(AudioIIRContext, x)
@@ -1574,7 +1573,7 @@ const AVFilter ff_af_aiir = {
     .init          = init,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = inputs,
+    FILTER_INPUTS(inputs),
     .flags         = AVFILTER_FLAG_DYNAMIC_OUTPUTS |
                      AVFILTER_FLAG_SLICE_THREADS,
 };
diff --git a/libavfilter/af_alimiter.c b/libavfilter/af_alimiter.c
index 8ff64c8a7b..9172f305f0 100644
--- a/libavfilter/af_alimiter.c
+++ b/libavfilter/af_alimiter.c
@@ -337,7 +337,6 @@ static const AVFilterPad alimiter_inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad alimiter_outputs[] = {
@@ -345,7 +344,6 @@ static const AVFilterPad alimiter_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_alimiter = {
@@ -356,6 +354,6 @@ const AVFilter ff_af_alimiter = {
     .init           = init,
     .uninit         = uninit,
     .query_formats  = query_formats,
-    .inputs         = alimiter_inputs,
-    .outputs        = alimiter_outputs,
+    FILTER_INPUTS(alimiter_inputs),
+    FILTER_OUTPUTS(alimiter_outputs),
 };
diff --git a/libavfilter/af_amerge.c b/libavfilter/af_amerge.c
index 37fb359c84..0e8bdea436 100644
--- a/libavfilter/af_amerge.c
+++ b/libavfilter/af_amerge.c
@@ -342,7 +342,6 @@ static const AVFilterPad amerge_outputs[] = {
         .type          = AVMEDIA_TYPE_AUDIO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_amerge = {
@@ -355,7 +354,7 @@ const AVFilter ff_af_amerge = {
     .query_formats = query_formats,
     .activate      = activate,
     .inputs        = NULL,
-    .outputs       = amerge_outputs,
+    FILTER_OUTPUTS(amerge_outputs),
     .priv_class    = &amerge_class,
     .flags         = AVFILTER_FLAG_DYNAMIC_INPUTS,
 };
diff --git a/libavfilter/af_amix.c b/libavfilter/af_amix.c
index 8c1bcb96b6..9625864038 100644
--- a/libavfilter/af_amix.c
+++ b/libavfilter/af_amix.c
@@ -634,7 +634,6 @@ static const AVFilterPad avfilter_af_amix_outputs[] = {
         .type          = AVMEDIA_TYPE_AUDIO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_amix = {
@@ -647,7 +646,7 @@ const AVFilter ff_af_amix = {
     .activate       = activate,
     .query_formats  = query_formats,
     .inputs         = NULL,
-    .outputs        = avfilter_af_amix_outputs,
+    FILTER_OUTPUTS(avfilter_af_amix_outputs),
     .process_command = process_command,
     .flags          = AVFILTER_FLAG_DYNAMIC_INPUTS,
 };
diff --git a/libavfilter/af_amultiply.c b/libavfilter/af_amultiply.c
index f6814a802d..7c44cadb2b 100644
--- a/libavfilter/af_amultiply.c
+++ b/libavfilter/af_amultiply.c
@@ -179,7 +179,6 @@ static const AVFilterPad inputs[] = {
         .name = "multiply1",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -188,7 +187,6 @@ static const AVFilterPad outputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .config_props = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_amultiply = {
@@ -199,6 +197,6 @@ const AVFilter ff_af_amultiply = {
     .uninit         = uninit,
     .activate       = activate,
     .query_formats  = query_formats,
-    .inputs         = inputs,
-    .outputs        = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
 };
diff --git a/libavfilter/af_anequalizer.c b/libavfilter/af_anequalizer.c
index 229e978278..ab1838f990 100644
--- a/libavfilter/af_anequalizer.c
+++ b/libavfilter/af_anequalizer.c
@@ -761,7 +761,6 @@ static const AVFilterPad inputs[] = {
         .config_props   = config_input,
         .filter_frame   = filter_frame,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_anequalizer = {
@@ -772,7 +771,7 @@ const AVFilter ff_af_anequalizer = {
     .init          = init,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = inputs,
+    FILTER_INPUTS(inputs),
     .outputs       = NULL,
     .process_command = process_command,
     .flags         = AVFILTER_FLAG_DYNAMIC_OUTPUTS |
diff --git a/libavfilter/af_anlmdn.c b/libavfilter/af_anlmdn.c
index 408e35fb63..0ba725f59f 100644
--- a/libavfilter/af_anlmdn.c
+++ b/libavfilter/af_anlmdn.c
@@ -388,7 +388,6 @@ static const AVFilterPad inputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -398,7 +397,6 @@ static const AVFilterPad outputs[] = {
         .config_props  = config_output,
         .request_frame = request_frame,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_anlmdn = {
@@ -408,8 +406,8 @@ const AVFilter ff_af_anlmdn = {
     .priv_size     = sizeof(AudioNLMeansContext),
     .priv_class    = &anlmdn_class,
     .uninit        = uninit,
-    .inputs        = inputs,
-    .outputs       = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
     .process_command = process_command,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL |
                      AVFILTER_FLAG_SLICE_THREADS,
diff --git a/libavfilter/af_anlms.c b/libavfilter/af_anlms.c
index 83666ac2e7..75e932ca96 100644
--- a/libavfilter/af_anlms.c
+++ b/libavfilter/af_anlms.c
@@ -288,7 +288,6 @@ static const AVFilterPad inputs[] = {
         .name = "desired",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -297,7 +296,6 @@ static const AVFilterPad outputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .config_props = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_anlms = {
@@ -309,8 +307,8 @@ const AVFilter ff_af_anlms = {
     .uninit         = uninit,
     .activate       = activate,
     .query_formats  = query_formats,
-    .inputs         = inputs,
-    .outputs        = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
     .flags          = AVFILTER_FLAG_SLICE_THREADS,
     .process_command = ff_filter_process_command,
 };
diff --git a/libavfilter/af_anull.c b/libavfilter/af_anull.c
index 74f915778f..065d37e17e 100644
--- a/libavfilter/af_anull.c
+++ b/libavfilter/af_anull.c
@@ -32,7 +32,6 @@ static const AVFilterPad avfilter_af_anull_inputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 static const AVFilterPad avfilter_af_anull_outputs[] = {
@@ -40,12 +39,11 @@ static const AVFilterPad avfilter_af_anull_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_anull = {
     .name          = "anull",
     .description   = NULL_IF_CONFIG_SMALL("Pass the source unchanged to the output."),
-    .inputs        = avfilter_af_anull_inputs,
-    .outputs       = avfilter_af_anull_outputs,
+    FILTER_INPUTS(avfilter_af_anull_inputs),
+    FILTER_OUTPUTS(avfilter_af_anull_outputs),
 };
diff --git a/libavfilter/af_apad.c b/libavfilter/af_apad.c
index 8628c0c2e2..27259a87a3 100644
--- a/libavfilter/af_apad.c
+++ b/libavfilter/af_apad.c
@@ -155,7 +155,6 @@ static const AVFilterPad apad_inputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad apad_outputs[] = {
@@ -165,7 +164,6 @@ static const AVFilterPad apad_outputs[] = {
         .config_props  = config_output,
         .type          = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_apad = {
@@ -173,8 +171,8 @@ const AVFilter ff_af_apad = {
     .description   = NULL_IF_CONFIG_SMALL("Pad audio with silence."),
     .init          = init,
     .priv_size     = sizeof(APadContext),
-    .inputs        = apad_inputs,
-    .outputs       = apad_outputs,
+    FILTER_INPUTS(apad_inputs),
+    FILTER_OUTPUTS(apad_outputs),
     .priv_class    = &apad_class,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
 };
diff --git a/libavfilter/af_aphaser.c b/libavfilter/af_aphaser.c
index 5f3244246f..3a365140db 100644
--- a/libavfilter/af_aphaser.c
+++ b/libavfilter/af_aphaser.c
@@ -265,7 +265,6 @@ static const AVFilterPad aphaser_inputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad aphaser_outputs[] = {
@@ -274,7 +273,6 @@ static const AVFilterPad aphaser_outputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .config_props = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_aphaser = {
@@ -284,7 +282,7 @@ const AVFilter ff_af_aphaser = {
     .priv_size     = sizeof(AudioPhaserContext),
     .init          = init,
     .uninit        = uninit,
-    .inputs        = aphaser_inputs,
-    .outputs       = aphaser_outputs,
+    FILTER_INPUTS(aphaser_inputs),
+    FILTER_OUTPUTS(aphaser_outputs),
     .priv_class    = &aphaser_class,
 };
diff --git a/libavfilter/af_apulsator.c b/libavfilter/af_apulsator.c
index cef49d891f..b9a194eb9d 100644
--- a/libavfilter/af_apulsator.c
+++ b/libavfilter/af_apulsator.c
@@ -235,7 +235,6 @@ static const AVFilterPad inputs[] = {
         .config_props = config_input,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -243,7 +242,6 @@ static const AVFilterPad outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_apulsator = {
@@ -252,6 +250,6 @@ const AVFilter ff_af_apulsator = {
     .priv_size     = sizeof(AudioPulsatorContext),
     .priv_class    = &apulsator_class,
     .query_formats = query_formats,
-    .inputs        = inputs,
-    .outputs       = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
 };
diff --git a/libavfilter/af_aresample.c b/libavfilter/af_aresample.c
index 1127ad2718..e46369b98d 100644
--- a/libavfilter/af_aresample.c
+++ b/libavfilter/af_aresample.c
@@ -329,7 +329,6 @@ static const AVFilterPad aresample_inputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad aresample_outputs[] = {
@@ -339,7 +338,6 @@ static const AVFilterPad aresample_outputs[] = {
         .request_frame = request_frame,
         .type          = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_aresample = {
@@ -350,6 +348,6 @@ const AVFilter ff_af_aresample = {
     .query_formats = query_formats,
     .priv_size     = sizeof(AResampleContext),
     .priv_class    = &aresample_class,
-    .inputs        = aresample_inputs,
-    .outputs       = aresample_outputs,
+    FILTER_INPUTS(aresample_inputs),
+    FILTER_OUTPUTS(aresample_outputs),
 };
diff --git a/libavfilter/af_arnndn.c b/libavfilter/af_arnndn.c
index cec22bbacc..1d48188e84 100644
--- a/libavfilter/af_arnndn.c
+++ b/libavfilter/af_arnndn.c
@@ -1584,7 +1584,6 @@ static const AVFilterPad inputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -1592,7 +1591,6 @@ static const AVFilterPad outputs[] = {
         .name          = "default",
         .type          = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 #define OFFSET(x) offsetof(AudioRNNContext, x)
@@ -1616,8 +1614,8 @@ const AVFilter ff_af_arnndn = {
     .activate      = activate,
     .init          = init,
     .uninit        = uninit,
-    .inputs        = inputs,
-    .outputs       = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL |
                      AVFILTER_FLAG_SLICE_THREADS,
     .process_command = process_command,
diff --git a/libavfilter/af_asetnsamples.c b/libavfilter/af_asetnsamples.c
index 9987eff8a2..71788f2a76 100644
--- a/libavfilter/af_asetnsamples.c
+++ b/libavfilter/af_asetnsamples.c
@@ -106,7 +106,6 @@ static const AVFilterPad asetnsamples_inputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 static const AVFilterPad asetnsamples_outputs[] = {
@@ -114,7 +113,6 @@ static const AVFilterPad asetnsamples_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_asetnsamples = {
@@ -122,7 +120,7 @@ const AVFilter ff_af_asetnsamples = {
     .description = NULL_IF_CONFIG_SMALL("Set the number of samples for each output audio frames."),
     .priv_size   = sizeof(ASNSContext),
     .priv_class  = &asetnsamples_class,
-    .inputs      = asetnsamples_inputs,
-    .outputs     = asetnsamples_outputs,
+    FILTER_INPUTS(asetnsamples_inputs),
+    FILTER_OUTPUTS(asetnsamples_outputs),
     .activate    = activate,
 };
diff --git a/libavfilter/af_asetrate.c b/libavfilter/af_asetrate.c
index f89185d936..920baedad2 100644
--- a/libavfilter/af_asetrate.c
+++ b/libavfilter/af_asetrate.c
@@ -94,7 +94,6 @@ static const AVFilterPad asetrate_inputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad asetrate_outputs[] = {
@@ -103,7 +102,6 @@ static const AVFilterPad asetrate_outputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .config_props = config_props,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_asetrate = {
@@ -112,7 +110,7 @@ const AVFilter ff_af_asetrate = {
                                           "altering the data."),
     .query_formats = query_formats,
     .priv_size     = sizeof(ASetRateContext),
-    .inputs        = asetrate_inputs,
-    .outputs       = asetrate_outputs,
+    FILTER_INPUTS(asetrate_inputs),
+    FILTER_OUTPUTS(asetrate_outputs),
     .priv_class    = &asetrate_class,
 };
diff --git a/libavfilter/af_ashowinfo.c b/libavfilter/af_ashowinfo.c
index 72d795f8ee..b6623fa69d 100644
--- a/libavfilter/af_ashowinfo.c
+++ b/libavfilter/af_ashowinfo.c
@@ -243,7 +243,6 @@ static const AVFilterPad inputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -251,7 +250,6 @@ static const AVFilterPad outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_ashowinfo = {
@@ -259,6 +257,6 @@ const AVFilter ff_af_ashowinfo = {
     .description = NULL_IF_CONFIG_SMALL("Show textual information for each audio frame."),
     .priv_size   = sizeof(AShowInfoContext),
     .uninit      = uninit,
-    .inputs      = inputs,
-    .outputs     = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
 };
diff --git a/libavfilter/af_asoftclip.c b/libavfilter/af_asoftclip.c
index 377666678a..a90a4c7eb5 100644
--- a/libavfilter/af_asoftclip.c
+++ b/libavfilter/af_asoftclip.c
@@ -451,7 +451,6 @@ static const AVFilterPad inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -459,7 +458,6 @@ static const AVFilterPad outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_asoftclip = {
@@ -468,8 +466,8 @@ const AVFilter ff_af_asoftclip = {
     .query_formats  = query_formats,
     .priv_size      = sizeof(ASoftClipContext),
     .priv_class     = &asoftclip_class,
-    .inputs         = inputs,
-    .outputs        = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
     .uninit         = uninit,
     .process_command = ff_filter_process_command,
     .flags          = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC |
diff --git a/libavfilter/af_asr.c b/libavfilter/af_asr.c
index 8dbe67fa5b..c7dc3b2db6 100644
--- a/libavfilter/af_asr.c
+++ b/libavfilter/af_asr.c
@@ -156,7 +156,6 @@ static const AVFilterPad asr_inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad asr_outputs[] = {
@@ -164,7 +163,6 @@ static const AVFilterPad asr_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_asr = {
@@ -175,6 +173,6 @@ const AVFilter ff_af_asr = {
     .init          = asr_init,
     .uninit        = asr_uninit,
     .query_formats = query_formats,
-    .inputs        = asr_inputs,
-    .outputs       = asr_outputs,
+    FILTER_INPUTS(asr_inputs),
+    FILTER_OUTPUTS(asr_outputs),
 };
diff --git a/libavfilter/af_astats.c b/libavfilter/af_astats.c
index d910ca8f23..c8fbe44f69 100644
--- a/libavfilter/af_astats.c
+++ b/libavfilter/af_astats.c
@@ -815,7 +815,6 @@ static const AVFilterPad astats_inputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad astats_outputs[] = {
@@ -824,7 +823,6 @@ static const AVFilterPad astats_outputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .config_props = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_astats = {
@@ -834,7 +832,7 @@ const AVFilter ff_af_astats = {
     .priv_size     = sizeof(AudioStatsContext),
     .priv_class    = &astats_class,
     .uninit        = uninit,
-    .inputs        = astats_inputs,
-    .outputs       = astats_outputs,
+    FILTER_INPUTS(astats_inputs),
+    FILTER_OUTPUTS(astats_outputs),
     .flags         = AVFILTER_FLAG_SLICE_THREADS,
 };
diff --git a/libavfilter/af_asubboost.c b/libavfilter/af_asubboost.c
index aeaac2645f..7543601b8a 100644
--- a/libavfilter/af_asubboost.c
+++ b/libavfilter/af_asubboost.c
@@ -221,7 +221,6 @@ static const AVFilterPad inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -229,7 +228,6 @@ static const AVFilterPad outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_asubboost = {
@@ -239,8 +237,8 @@ const AVFilter ff_af_asubboost = {
     .priv_size      = sizeof(ASubBoostContext),
     .priv_class     = &asubboost_class,
     .uninit         = uninit,
-    .inputs         = inputs,
-    .outputs        = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
     .process_command = process_command,
     .flags           = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL |
                        AVFILTER_FLAG_SLICE_THREADS,
diff --git a/libavfilter/af_asupercut.c b/libavfilter/af_asupercut.c
index b6cf4c13c7..bd8b1cf44a 100644
--- a/libavfilter/af_asupercut.c
+++ b/libavfilter/af_asupercut.c
@@ -345,7 +345,6 @@ static const AVFilterPad inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -353,7 +352,6 @@ static const AVFilterPad outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_asupercut = {
@@ -363,8 +361,8 @@ const AVFilter ff_af_asupercut = {
     .priv_size       = sizeof(ASuperCutContext),
     .priv_class      = &asupercut_class,
     .uninit          = uninit,
-    .inputs          = inputs,
-    .outputs         = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
     .process_command = process_command,
     .flags           = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC |
                        AVFILTER_FLAG_SLICE_THREADS,
@@ -386,8 +384,8 @@ const AVFilter ff_af_asubcut = {
     .priv_size       = sizeof(ASuperCutContext),
     .priv_class      = &asubcut_class,
     .uninit          = uninit,
-    .inputs          = inputs,
-    .outputs         = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
     .process_command = process_command,
     .flags           = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC |
                        AVFILTER_FLAG_SLICE_THREADS,
@@ -411,8 +409,8 @@ const AVFilter ff_af_asuperpass = {
     .priv_size       = sizeof(ASuperCutContext),
     .priv_class      = &asuperpass_class,
     .uninit          = uninit,
-    .inputs          = inputs,
-    .outputs         = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
     .process_command = process_command,
     .flags           = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC |
                        AVFILTER_FLAG_SLICE_THREADS,
@@ -428,8 +426,8 @@ const AVFilter ff_af_asuperstop = {
     .priv_size       = sizeof(ASuperCutContext),
     .priv_class      = &asuperstop_class,
     .uninit          = uninit,
-    .inputs          = inputs,
-    .outputs         = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
     .process_command = process_command,
     .flags           = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC |
                        AVFILTER_FLAG_SLICE_THREADS,
diff --git a/libavfilter/af_atempo.c b/libavfilter/af_atempo.c
index 56f216d832..16fa59701a 100644
--- a/libavfilter/af_atempo.c
+++ b/libavfilter/af_atempo.c
@@ -1173,7 +1173,6 @@ static const AVFilterPad atempo_inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_props,
     },
-    { NULL }
 };
 
 static const AVFilterPad atempo_outputs[] = {
@@ -1182,7 +1181,6 @@ static const AVFilterPad atempo_outputs[] = {
         .request_frame = request_frame,
         .type          = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_atempo = {
@@ -1194,6 +1192,6 @@ const AVFilter ff_af_atempo = {
     .process_command = process_command,
     .priv_size       = sizeof(ATempoContext),
     .priv_class      = &atempo_class,
-    .inputs          = atempo_inputs,
-    .outputs         = atempo_outputs,
+    FILTER_INPUTS(atempo_inputs),
+    FILTER_OUTPUTS(atempo_outputs),
 };
diff --git a/libavfilter/af_axcorrelate.c b/libavfilter/af_axcorrelate.c
index ffb90fce7f..18fc3004b1 100644
--- a/libavfilter/af_axcorrelate.c
+++ b/libavfilter/af_axcorrelate.c
@@ -326,7 +326,6 @@ static const AVFilterPad inputs[] = {
         .name = "axcorrelate1",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -335,7 +334,6 @@ static const AVFilterPad outputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .config_props = config_output,
     },
-    { NULL }
 };
 
 #define AF AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
@@ -359,6 +357,6 @@ const AVFilter ff_af_axcorrelate = {
     .query_formats  = query_formats,
     .activate       = activate,
     .uninit         = uninit,
-    .inputs         = inputs,
-    .outputs        = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
 };
diff --git a/libavfilter/af_biquads.c b/libavfilter/af_biquads.c
index 2495069672..c110734458 100644
--- a/libavfilter/af_biquads.c
+++ b/libavfilter/af_biquads.c
@@ -839,7 +839,6 @@ static const AVFilterPad inputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -848,7 +847,6 @@ static const AVFilterPad outputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .config_props = config_output,
     },
-    { NULL }
 };
 
 #define OFFSET(x) offsetof(BiquadsContext, x)
@@ -871,8 +869,8 @@ const AVFilter ff_af_##name_ = {                               \
     .init          = name_##_init,                       \
     .uninit        = uninit,                             \
     .query_formats = query_formats,                      \
-    .inputs        = inputs,                             \
-    .outputs       = outputs,                            \
+    FILTER_INPUTS(inputs),                               \
+    FILTER_OUTPUTS(outputs),                             \
     .priv_class    = &name_##_class,                     \
     .process_command = process_command,                  \
     .flags         = AVFILTER_FLAG_SLICE_THREADS | AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, \
diff --git a/libavfilter/af_bs2b.c b/libavfilter/af_bs2b.c
index beb1d0f341..55b4d2ac6f 100644
--- a/libavfilter/af_bs2b.c
+++ b/libavfilter/af_bs2b.c
@@ -192,7 +192,6 @@ static const AVFilterPad bs2b_inputs[] = {
         .type           = AVMEDIA_TYPE_AUDIO,
         .filter_frame   = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad bs2b_outputs[] = {
@@ -201,7 +200,6 @@ static const AVFilterPad bs2b_outputs[] = {
         .type           = AVMEDIA_TYPE_AUDIO,
         .config_props   = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_bs2b = {
@@ -212,6 +210,6 @@ const AVFilter ff_af_bs2b = {
     .priv_class     = &bs2b_class,
     .init           = init,
     .uninit         = uninit,
-    .inputs         = bs2b_inputs,
-    .outputs        = bs2b_outputs,
+    FILTER_INPUTS(bs2b_inputs),
+    FILTER_OUTPUTS(bs2b_outputs),
 };
diff --git a/libavfilter/af_channelmap.c b/libavfilter/af_channelmap.c
index 82df3ace15..c1eac79c98 100644
--- a/libavfilter/af_channelmap.c
+++ b/libavfilter/af_channelmap.c
@@ -387,7 +387,6 @@ static const AVFilterPad avfilter_af_channelmap_inputs[] = {
         .filter_frame   = channelmap_filter_frame,
         .config_props   = channelmap_config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad avfilter_af_channelmap_outputs[] = {
@@ -395,7 +394,6 @@ static const AVFilterPad avfilter_af_channelmap_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO
     },
-    { NULL }
 };
 
 const AVFilter ff_af_channelmap = {
@@ -405,6 +403,6 @@ const AVFilter ff_af_channelmap = {
     .query_formats = channelmap_query_formats,
     .priv_size     = sizeof(ChannelMapContext),
     .priv_class    = &channelmap_class,
-    .inputs        = avfilter_af_channelmap_inputs,
-    .outputs       = avfilter_af_channelmap_outputs,
+    FILTER_INPUTS(avfilter_af_channelmap_inputs),
+    FILTER_OUTPUTS(avfilter_af_channelmap_outputs),
 };
diff --git a/libavfilter/af_channelsplit.c b/libavfilter/af_channelsplit.c
index 7857ce0343..2bb34881a6 100644
--- a/libavfilter/af_channelsplit.c
+++ b/libavfilter/af_channelsplit.c
@@ -164,7 +164,6 @@ static const AVFilterPad avfilter_af_channelsplit_inputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_channelsplit = {
@@ -174,7 +173,7 @@ const AVFilter ff_af_channelsplit = {
     .priv_class     = &channelsplit_class,
     .init           = init,
     .query_formats  = query_formats,
-    .inputs         = avfilter_af_channelsplit_inputs,
+    FILTER_INPUTS(avfilter_af_channelsplit_inputs),
     .outputs        = NULL,
     .flags          = AVFILTER_FLAG_DYNAMIC_OUTPUTS,
 };
diff --git a/libavfilter/af_chorus.c b/libavfilter/af_chorus.c
index 000f1d2d07..9c9090e4cc 100644
--- a/libavfilter/af_chorus.c
+++ b/libavfilter/af_chorus.c
@@ -343,7 +343,6 @@ static const AVFilterPad chorus_inputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad chorus_outputs[] = {
@@ -353,7 +352,6 @@ static const AVFilterPad chorus_outputs[] = {
         .request_frame = request_frame,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_chorus = {
@@ -364,6 +362,6 @@ const AVFilter ff_af_chorus = {
     .priv_class    = &chorus_class,
     .init          = init,
     .uninit        = uninit,
-    .inputs        = chorus_inputs,
-    .outputs       = chorus_outputs,
+    FILTER_INPUTS(chorus_inputs),
+    FILTER_OUTPUTS(chorus_outputs),
 };
diff --git a/libavfilter/af_compand.c b/libavfilter/af_compand.c
index 37c1884537..1df28d5590 100644
--- a/libavfilter/af_compand.c
+++ b/libavfilter/af_compand.c
@@ -558,7 +558,6 @@ static const AVFilterPad compand_inputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad compand_outputs[] = {
@@ -568,7 +567,6 @@ static const AVFilterPad compand_outputs[] = {
         .config_props  = config_output,
         .type          = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 
@@ -581,6 +579,6 @@ const AVFilter ff_af_compand = {
     .priv_class     = &compand_class,
     .init           = init,
     .uninit         = uninit,
-    .inputs         = compand_inputs,
-    .outputs        = compand_outputs,
+    FILTER_INPUTS(compand_inputs),
+    FILTER_OUTPUTS(compand_outputs),
 };
diff --git a/libavfilter/af_compensationdelay.c b/libavfilter/af_compensationdelay.c
index 3b91145cd0..1620750760 100644
--- a/libavfilter/af_compensationdelay.c
+++ b/libavfilter/af_compensationdelay.c
@@ -162,7 +162,6 @@ static const AVFilterPad compensationdelay_inputs[] = {
         .config_props = config_input,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad compensationdelay_outputs[] = {
@@ -170,7 +169,6 @@ static const AVFilterPad compensationdelay_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_compensationdelay = {
@@ -180,6 +178,6 @@ const AVFilter ff_af_compensationdelay = {
     .priv_size     = sizeof(CompensationDelayContext),
     .priv_class    = &compensationdelay_class,
     .uninit        = uninit,
-    .inputs        = compensationdelay_inputs,
-    .outputs       = compensationdelay_outputs,
+    FILTER_INPUTS(compensationdelay_inputs),
+    FILTER_OUTPUTS(compensationdelay_outputs),
 };
diff --git a/libavfilter/af_crossfeed.c b/libavfilter/af_crossfeed.c
index 1d0f8a8149..bbab8f423c 100644
--- a/libavfilter/af_crossfeed.c
+++ b/libavfilter/af_crossfeed.c
@@ -164,7 +164,6 @@ static const AVFilterPad inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -172,7 +171,6 @@ static const AVFilterPad outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_crossfeed = {
@@ -181,8 +179,8 @@ const AVFilter ff_af_crossfeed = {
     .query_formats  = query_formats,
     .priv_size      = sizeof(CrossfeedContext),
     .priv_class     = &crossfeed_class,
-    .inputs         = inputs,
-    .outputs        = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
     .flags          = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
     .process_command = process_command,
 };
diff --git a/libavfilter/af_crystalizer.c b/libavfilter/af_crystalizer.c
index 1e7432ffd0..9b65264f94 100644
--- a/libavfilter/af_crystalizer.c
+++ b/libavfilter/af_crystalizer.c
@@ -433,7 +433,6 @@ static const AVFilterPad inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -441,7 +440,6 @@ static const AVFilterPad outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_crystalizer = {
@@ -451,8 +449,8 @@ const AVFilter ff_af_crystalizer = {
     .priv_size      = sizeof(CrystalizerContext),
     .priv_class     = &crystalizer_class,
     .uninit         = uninit,
-    .inputs         = inputs,
-    .outputs        = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
     .process_command = process_command,
     .flags          = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL |
                       AVFILTER_FLAG_SLICE_THREADS,
diff --git a/libavfilter/af_dcshift.c b/libavfilter/af_dcshift.c
index a722928b18..d2751df441 100644
--- a/libavfilter/af_dcshift.c
+++ b/libavfilter/af_dcshift.c
@@ -136,7 +136,6 @@ static const AVFilterPad dcshift_inputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad dcshift_outputs[] = {
@@ -144,7 +143,6 @@ static const AVFilterPad dcshift_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_dcshift = {
@@ -154,7 +152,7 @@ const AVFilter ff_af_dcshift = {
     .priv_size      = sizeof(DCShiftContext),
     .priv_class     = &dcshift_class,
     .init           = init,
-    .inputs         = dcshift_inputs,
-    .outputs        = dcshift_outputs,
+    FILTER_INPUTS(dcshift_inputs),
+    FILTER_OUTPUTS(dcshift_outputs),
     .flags          = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
 };
diff --git a/libavfilter/af_deesser.c b/libavfilter/af_deesser.c
index c1471123c5..defea49e41 100644
--- a/libavfilter/af_deesser.c
+++ b/libavfilter/af_deesser.c
@@ -208,7 +208,6 @@ static const AVFilterPad inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -216,7 +215,6 @@ static const AVFilterPad outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_deesser = {
@@ -226,7 +224,7 @@ const AVFilter ff_af_deesser = {
     .priv_size     = sizeof(DeesserContext),
     .priv_class    = &deesser_class,
     .uninit        = uninit,
-    .inputs        = inputs,
-    .outputs       = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
 };
diff --git a/libavfilter/af_drmeter.c b/libavfilter/af_drmeter.c
index 722881dbc9..338fce3fc9 100644
--- a/libavfilter/af_drmeter.c
+++ b/libavfilter/af_drmeter.c
@@ -201,7 +201,6 @@ static const AVFilterPad drmeter_inputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad drmeter_outputs[] = {
@@ -210,7 +209,6 @@ static const AVFilterPad drmeter_outputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .config_props = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_drmeter = {
@@ -220,6 +218,6 @@ const AVFilter ff_af_drmeter = {
     .priv_size     = sizeof(DRMeterContext),
     .priv_class    = &drmeter_class,
     .uninit        = uninit,
-    .inputs        = drmeter_inputs,
-    .outputs       = drmeter_outputs,
+    FILTER_INPUTS(drmeter_inputs),
+    FILTER_OUTPUTS(drmeter_outputs),
 };
diff --git a/libavfilter/af_dynaudnorm.c b/libavfilter/af_dynaudnorm.c
index a6dbadbdd8..130555d1f0 100644
--- a/libavfilter/af_dynaudnorm.c
+++ b/libavfilter/af_dynaudnorm.c
@@ -844,7 +844,6 @@ static const AVFilterPad avfilter_af_dynaudnorm_inputs[] = {
         .type           = AVMEDIA_TYPE_AUDIO,
         .config_props   = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad avfilter_af_dynaudnorm_outputs[] = {
@@ -852,7 +851,6 @@ static const AVFilterPad avfilter_af_dynaudnorm_outputs[] = {
         .name          = "default",
         .type          = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_dynaudnorm = {
@@ -863,8 +861,8 @@ const AVFilter ff_af_dynaudnorm = {
     .init          = init,
     .uninit        = uninit,
     .activate      = activate,
-    .inputs        = avfilter_af_dynaudnorm_inputs,
-    .outputs       = avfilter_af_dynaudnorm_outputs,
+    FILTER_INPUTS(avfilter_af_dynaudnorm_inputs),
+    FILTER_OUTPUTS(avfilter_af_dynaudnorm_outputs),
     .priv_class    = &dynaudnorm_class,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
     .process_command = process_command,
diff --git a/libavfilter/af_earwax.c b/libavfilter/af_earwax.c
index ddb85705ee..2d219181d4 100644
--- a/libavfilter/af_earwax.c
+++ b/libavfilter/af_earwax.c
@@ -220,7 +220,6 @@ static const AVFilterPad earwax_inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad earwax_outputs[] = {
@@ -228,7 +227,6 @@ static const AVFilterPad earwax_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_earwax = {
@@ -237,6 +235,6 @@ const AVFilter ff_af_earwax = {
     .query_formats  = query_formats,
     .priv_size      = sizeof(EarwaxContext),
     .uninit         = uninit,
-    .inputs         = earwax_inputs,
-    .outputs        = earwax_outputs,
+    FILTER_INPUTS(earwax_inputs),
+    FILTER_OUTPUTS(earwax_outputs),
 };
diff --git a/libavfilter/af_extrastereo.c b/libavfilter/af_extrastereo.c
index 6d4f307384..0fcf840a4a 100644
--- a/libavfilter/af_extrastereo.c
+++ b/libavfilter/af_extrastereo.c
@@ -108,7 +108,6 @@ static const AVFilterPad inputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -116,7 +115,6 @@ static const AVFilterPad outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_extrastereo = {
@@ -125,8 +123,8 @@ const AVFilter ff_af_extrastereo = {
     .query_formats  = query_formats,
     .priv_size      = sizeof(ExtraStereoContext),
     .priv_class     = &extrastereo_class,
-    .inputs         = inputs,
-    .outputs        = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
     .flags          = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
     .process_command = ff_filter_process_command,
 };
diff --git a/libavfilter/af_firequalizer.c b/libavfilter/af_firequalizer.c
index d2114a515a..e147118d08 100644
--- a/libavfilter/af_firequalizer.c
+++ b/libavfilter/af_firequalizer.c
@@ -944,7 +944,6 @@ static const AVFilterPad firequalizer_inputs[] = {
         .filter_frame   = filter_frame,
         .type           = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 static const AVFilterPad firequalizer_outputs[] = {
@@ -953,7 +952,6 @@ static const AVFilterPad firequalizer_outputs[] = {
         .request_frame  = request_frame,
         .type           = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_firequalizer = {
@@ -963,7 +961,7 @@ const AVFilter ff_af_firequalizer = {
     .query_formats      = query_formats,
     .process_command    = process_command,
     .priv_size          = sizeof(FIREqualizerContext),
-    .inputs             = firequalizer_inputs,
-    .outputs            = firequalizer_outputs,
+    FILTER_INPUTS(firequalizer_inputs),
+    FILTER_OUTPUTS(firequalizer_outputs),
     .priv_class         = &firequalizer_class,
 };
diff --git a/libavfilter/af_flanger.c b/libavfilter/af_flanger.c
index 38b1bb562f..b0d765365c 100644
--- a/libavfilter/af_flanger.c
+++ b/libavfilter/af_flanger.c
@@ -209,7 +209,6 @@ static const AVFilterPad flanger_inputs[] = {
         .config_props = config_input,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad flanger_outputs[] = {
@@ -217,7 +216,6 @@ static const AVFilterPad flanger_outputs[] = {
         .name          = "default",
         .type          = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_flanger = {
@@ -228,6 +226,6 @@ const AVFilter ff_af_flanger = {
     .priv_class    = &flanger_class,
     .init          = init,
     .uninit        = uninit,
-    .inputs        = flanger_inputs,
-    .outputs       = flanger_outputs,
+    FILTER_INPUTS(flanger_inputs),
+    FILTER_OUTPUTS(flanger_outputs),
 };
diff --git a/libavfilter/af_haas.c b/libavfilter/af_haas.c
index b180d4c5b0..e162e4b7f0 100644
--- a/libavfilter/af_haas.c
+++ b/libavfilter/af_haas.c
@@ -204,7 +204,6 @@ static const AVFilterPad inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -212,7 +211,6 @@ static const AVFilterPad outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_haas = {
@@ -222,6 +220,6 @@ const AVFilter ff_af_haas = {
     .priv_size      = sizeof(HaasContext),
     .priv_class     = &haas_class,
     .uninit         = uninit,
-    .inputs         = inputs,
-    .outputs        = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
 };
diff --git a/libavfilter/af_hdcd.c b/libavfilter/af_hdcd.c
index 3d180bbbda..94a9c701a5 100644
--- a/libavfilter/af_hdcd.c
+++ b/libavfilter/af_hdcd.c
@@ -1761,7 +1761,6 @@ static const AVFilterPad avfilter_af_hdcd_inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad avfilter_af_hdcd_outputs[] = {
@@ -1769,7 +1768,6 @@ static const AVFilterPad avfilter_af_hdcd_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_hdcd = {
@@ -1780,6 +1778,6 @@ const AVFilter ff_af_hdcd = {
     .init          = init,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = avfilter_af_hdcd_inputs,
-    .outputs       = avfilter_af_hdcd_outputs,
+    FILTER_INPUTS(avfilter_af_hdcd_inputs),
+    FILTER_OUTPUTS(avfilter_af_hdcd_outputs),
 };
diff --git a/libavfilter/af_headphone.c b/libavfilter/af_headphone.c
index d5b0d84052..a2f18417bc 100644
--- a/libavfilter/af_headphone.c
+++ b/libavfilter/af_headphone.c
@@ -759,7 +759,6 @@ static const AVFilterPad outputs[] = {
         .type          = AVMEDIA_TYPE_AUDIO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_headphone = {
@@ -772,6 +771,6 @@ const AVFilter ff_af_headphone = {
     .query_formats = query_formats,
     .activate      = activate,
     .inputs        = NULL,
-    .outputs       = outputs,
+    FILTER_OUTPUTS(outputs),
     .flags         = AVFILTER_FLAG_SLICE_THREADS | AVFILTER_FLAG_DYNAMIC_INPUTS,
 };
diff --git a/libavfilter/af_join.c b/libavfilter/af_join.c
index 939edc4fa6..8e57dfb8b9 100644
--- a/libavfilter/af_join.c
+++ b/libavfilter/af_join.c
@@ -536,7 +536,6 @@ static const AVFilterPad avfilter_af_join_outputs[] = {
         .type          = AVMEDIA_TYPE_AUDIO,
         .config_props  = join_config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_join = {
@@ -550,6 +549,6 @@ const AVFilter ff_af_join = {
     .activate       = activate,
     .query_formats  = join_query_formats,
     .inputs         = NULL,
-    .outputs        = avfilter_af_join_outputs,
+    FILTER_OUTPUTS(avfilter_af_join_outputs),
     .flags          = AVFILTER_FLAG_DYNAMIC_INPUTS,
 };
diff --git a/libavfilter/af_ladspa.c b/libavfilter/af_ladspa.c
index 3cf5f9f22b..9186b75957 100644
--- a/libavfilter/af_ladspa.c
+++ b/libavfilter/af_ladspa.c
@@ -774,7 +774,6 @@ static const AVFilterPad ladspa_outputs[] = {
         .config_props  = config_output,
         .request_frame = request_frame,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_ladspa = {
@@ -787,6 +786,6 @@ const AVFilter ff_af_ladspa = {
     .query_formats = query_formats,
     .process_command = process_command,
     .inputs        = 0,
-    .outputs       = ladspa_outputs,
+    FILTER_OUTPUTS(ladspa_outputs),
     .flags         = AVFILTER_FLAG_DYNAMIC_INPUTS,
 };
diff --git a/libavfilter/af_loudnorm.c b/libavfilter/af_loudnorm.c
index f10429867f..7807ed927a 100644
--- a/libavfilter/af_loudnorm.c
+++ b/libavfilter/af_loudnorm.c
@@ -896,7 +896,6 @@ static const AVFilterPad avfilter_af_loudnorm_inputs[] = {
         .config_props = config_input,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad avfilter_af_loudnorm_outputs[] = {
@@ -905,7 +904,6 @@ static const AVFilterPad avfilter_af_loudnorm_outputs[] = {
         .request_frame = request_frame,
         .type          = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_loudnorm = {
@@ -916,6 +914,6 @@ const AVFilter ff_af_loudnorm = {
     .query_formats = query_formats,
     .init          = init,
     .uninit        = uninit,
-    .inputs        = avfilter_af_loudnorm_inputs,
-    .outputs       = avfilter_af_loudnorm_outputs,
+    FILTER_INPUTS(avfilter_af_loudnorm_inputs),
+    FILTER_OUTPUTS(avfilter_af_loudnorm_outputs),
 };
diff --git a/libavfilter/af_lv2.c b/libavfilter/af_lv2.c
index a7f069206d..76a289434f 100644
--- a/libavfilter/af_lv2.c
+++ b/libavfilter/af_lv2.c
@@ -574,7 +574,6 @@ static const AVFilterPad lv2_outputs[] = {
         .config_props  = config_output,
         .request_frame = request_frame,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_lv2 = {
@@ -586,6 +585,6 @@ const AVFilter ff_af_lv2 = {
     .uninit        = uninit,
     .query_formats = query_formats,
     .inputs        = 0,
-    .outputs       = lv2_outputs,
+    FILTER_OUTPUTS(lv2_outputs),
     .flags         = AVFILTER_FLAG_DYNAMIC_INPUTS,
 };
diff --git a/libavfilter/af_mcompand.c b/libavfilter/af_mcompand.c
index 9bce9ae7a1..0ae84221b6 100644
--- a/libavfilter/af_mcompand.c
+++ b/libavfilter/af_mcompand.c
@@ -638,7 +638,6 @@ static const AVFilterPad mcompand_inputs[] = {
         .type           = AVMEDIA_TYPE_AUDIO,
         .filter_frame   = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad mcompand_outputs[] = {
@@ -648,7 +647,6 @@ static const AVFilterPad mcompand_outputs[] = {
         .request_frame = request_frame,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 
@@ -660,6 +658,6 @@ const AVFilter ff_af_mcompand = {
     .priv_size      = sizeof(MCompandContext),
     .priv_class     = &mcompand_class,
     .uninit         = uninit,
-    .inputs         = mcompand_inputs,
-    .outputs        = mcompand_outputs,
+    FILTER_INPUTS(mcompand_inputs),
+    FILTER_OUTPUTS(mcompand_outputs),
 };
diff --git a/libavfilter/af_pan.c b/libavfilter/af_pan.c
index b699faf75b..d17e45438d 100644
--- a/libavfilter/af_pan.c
+++ b/libavfilter/af_pan.c
@@ -435,7 +435,6 @@ static const AVFilterPad pan_inputs[] = {
         .config_props = config_props,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad pan_outputs[] = {
@@ -443,7 +442,6 @@ static const AVFilterPad pan_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_pan = {
@@ -454,6 +452,6 @@ const AVFilter ff_af_pan = {
     .init          = init,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = pan_inputs,
-    .outputs       = pan_outputs,
+    FILTER_INPUTS(pan_inputs),
+    FILTER_OUTPUTS(pan_outputs),
 };
diff --git a/libavfilter/af_replaygain.c b/libavfilter/af_replaygain.c
index fd642297f8..7db7fe4178 100644
--- a/libavfilter/af_replaygain.c
+++ b/libavfilter/af_replaygain.c
@@ -592,7 +592,6 @@ static const AVFilterPad replaygain_inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad replaygain_outputs[] = {
@@ -600,7 +599,6 @@ static const AVFilterPad replaygain_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_replaygain = {
@@ -609,6 +607,6 @@ const AVFilter ff_af_replaygain = {
     .query_formats = query_formats,
     .uninit        = uninit,
     .priv_size     = sizeof(ReplayGainContext),
-    .inputs        = replaygain_inputs,
-    .outputs       = replaygain_outputs,
+    FILTER_INPUTS(replaygain_inputs),
+    FILTER_OUTPUTS(replaygain_outputs),
 };
diff --git a/libavfilter/af_rubberband.c b/libavfilter/af_rubberband.c
index 351104c768..6a4b71d09d 100644
--- a/libavfilter/af_rubberband.c
+++ b/libavfilter/af_rubberband.c
@@ -210,7 +210,6 @@ static const AVFilterPad rubberband_inputs[] = {
         .type          = AVMEDIA_TYPE_AUDIO,
         .config_props  = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad rubberband_outputs[] = {
@@ -218,7 +217,6 @@ static const AVFilterPad rubberband_outputs[] = {
         .name          = "default",
         .type          = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_rubberband = {
@@ -229,7 +227,7 @@ const AVFilter ff_af_rubberband = {
     .priv_class    = &rubberband_class,
     .uninit        = uninit,
     .activate      = activate,
-    .inputs        = rubberband_inputs,
-    .outputs       = rubberband_outputs,
+    FILTER_INPUTS(rubberband_inputs),
+    FILTER_OUTPUTS(rubberband_outputs),
     .process_command = process_command,
 };
diff --git a/libavfilter/af_sidechaincompress.c b/libavfilter/af_sidechaincompress.c
index 8e8547c3a4..c964e0d27c 100644
--- a/libavfilter/af_sidechaincompress.c
+++ b/libavfilter/af_sidechaincompress.c
@@ -371,7 +371,6 @@ static const AVFilterPad sidechaincompress_inputs[] = {
         .name           = "sidechain",
         .type           = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 static const AVFilterPad sidechaincompress_outputs[] = {
@@ -380,7 +379,6 @@ static const AVFilterPad sidechaincompress_outputs[] = {
         .type          = AVMEDIA_TYPE_AUDIO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_sidechaincompress = {
@@ -391,8 +389,8 @@ const AVFilter ff_af_sidechaincompress = {
     .query_formats  = query_formats,
     .activate       = activate,
     .uninit         = uninit,
-    .inputs         = sidechaincompress_inputs,
-    .outputs        = sidechaincompress_outputs,
+    FILTER_INPUTS(sidechaincompress_inputs),
+    FILTER_OUTPUTS(sidechaincompress_outputs),
     .process_command = process_command,
 };
 #endif  /* CONFIG_SIDECHAINCOMPRESS_FILTER */
@@ -454,7 +452,6 @@ static const AVFilterPad acompressor_inputs[] = {
         .type           = AVMEDIA_TYPE_AUDIO,
         .filter_frame   = acompressor_filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad acompressor_outputs[] = {
@@ -463,7 +460,6 @@ static const AVFilterPad acompressor_outputs[] = {
         .type          = AVMEDIA_TYPE_AUDIO,
         .config_props  = compressor_config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_acompressor = {
@@ -472,8 +468,8 @@ const AVFilter ff_af_acompressor = {
     .priv_size      = sizeof(SidechainCompressContext),
     .priv_class     = &acompressor_class,
     .query_formats  = acompressor_query_formats,
-    .inputs         = acompressor_inputs,
-    .outputs        = acompressor_outputs,
+    FILTER_INPUTS(acompressor_inputs),
+    FILTER_OUTPUTS(acompressor_outputs),
     .process_command = process_command,
 };
 #endif  /* CONFIG_ACOMPRESSOR_FILTER */
diff --git a/libavfilter/af_silencedetect.c b/libavfilter/af_silencedetect.c
index 4342793216..11fbc94225 100644
--- a/libavfilter/af_silencedetect.c
+++ b/libavfilter/af_silencedetect.c
@@ -240,7 +240,6 @@ static const AVFilterPad silencedetect_inputs[] = {
         .config_props = config_input,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad silencedetect_outputs[] = {
@@ -248,7 +247,6 @@ static const AVFilterPad silencedetect_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_silencedetect = {
@@ -257,7 +255,7 @@ const AVFilter ff_af_silencedetect = {
     .priv_size     = sizeof(SilenceDetectContext),
     .query_formats = query_formats,
     .uninit        = uninit,
-    .inputs        = silencedetect_inputs,
-    .outputs       = silencedetect_outputs,
+    FILTER_INPUTS(silencedetect_inputs),
+    FILTER_OUTPUTS(silencedetect_outputs),
     .priv_class    = &silencedetect_class,
 };
diff --git a/libavfilter/af_silenceremove.c b/libavfilter/af_silenceremove.c
index 953dbc526f..e60f0f8d3a 100644
--- a/libavfilter/af_silenceremove.c
+++ b/libavfilter/af_silenceremove.c
@@ -923,7 +923,6 @@ static const AVFilterPad silenceremove_inputs[] = {
         .config_props = config_input,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad silenceremove_outputs[] = {
@@ -932,7 +931,6 @@ static const AVFilterPad silenceremove_outputs[] = {
         .type          = AVMEDIA_TYPE_AUDIO,
         .request_frame = request_frame,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_silenceremove = {
@@ -943,6 +941,6 @@ const AVFilter ff_af_silenceremove = {
     .init          = init,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = silenceremove_inputs,
-    .outputs       = silenceremove_outputs,
+    FILTER_INPUTS(silenceremove_inputs),
+    FILTER_OUTPUTS(silenceremove_outputs),
 };
diff --git a/libavfilter/af_sofalizer.c b/libavfilter/af_sofalizer.c
index 9708aab634..52832e0ee2 100644
--- a/libavfilter/af_sofalizer.c
+++ b/libavfilter/af_sofalizer.c
@@ -1095,7 +1095,6 @@ static const AVFilterPad inputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -1103,7 +1102,6 @@ static const AVFilterPad outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_sofalizer = {
@@ -1115,7 +1113,7 @@ const AVFilter ff_af_sofalizer = {
     .activate      = activate,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = inputs,
-    .outputs       = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
     .flags         = AVFILTER_FLAG_SLICE_THREADS,
 };
diff --git a/libavfilter/af_speechnorm.c b/libavfilter/af_speechnorm.c
index a5f704422c..e94608fb41 100644
--- a/libavfilter/af_speechnorm.c
+++ b/libavfilter/af_speechnorm.c
@@ -542,7 +542,6 @@ static const AVFilterPad inputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -550,7 +549,6 @@ static const AVFilterPad outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_speechnorm = {
@@ -561,7 +559,7 @@ const AVFilter ff_af_speechnorm = {
     .priv_class      = &speechnorm_class,
     .activate        = activate,
     .uninit          = uninit,
-    .inputs          = inputs,
-    .outputs         = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
     .process_command = process_command,
 };
diff --git a/libavfilter/af_stereotools.c b/libavfilter/af_stereotools.c
index 043265f22c..d4aca66a92 100644
--- a/libavfilter/af_stereotools.c
+++ b/libavfilter/af_stereotools.c
@@ -363,7 +363,6 @@ static const AVFilterPad inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -371,7 +370,6 @@ static const AVFilterPad outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_stereotools = {
@@ -381,8 +379,8 @@ const AVFilter ff_af_stereotools = {
     .priv_size      = sizeof(StereoToolsContext),
     .priv_class     = &stereotools_class,
     .uninit         = uninit,
-    .inputs         = inputs,
-    .outputs        = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
     .process_command = process_command,
     .flags          = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
 };
diff --git a/libavfilter/af_stereowiden.c b/libavfilter/af_stereowiden.c
index b004b24399..ce194ec5b4 100644
--- a/libavfilter/af_stereowiden.c
+++ b/libavfilter/af_stereowiden.c
@@ -144,7 +144,6 @@ static const AVFilterPad inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -152,7 +151,6 @@ static const AVFilterPad outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_stereowiden = {
@@ -162,8 +160,8 @@ const AVFilter ff_af_stereowiden = {
     .priv_size      = sizeof(StereoWidenContext),
     .priv_class     = &stereowiden_class,
     .uninit         = uninit,
-    .inputs         = inputs,
-    .outputs        = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
     .flags          = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
     .process_command = ff_filter_process_command,
 };
diff --git a/libavfilter/af_superequalizer.c b/libavfilter/af_superequalizer.c
index f48a38b148..69e03e8820 100644
--- a/libavfilter/af_superequalizer.c
+++ b/libavfilter/af_superequalizer.c
@@ -326,7 +326,6 @@ static const AVFilterPad superequalizer_inputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad superequalizer_outputs[] = {
@@ -335,7 +334,6 @@ static const AVFilterPad superequalizer_outputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .config_props = config_output,
     },
-    { NULL }
 };
 
 #define AF AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
@@ -374,6 +372,6 @@ const AVFilter ff_af_superequalizer = {
     .init          = init,
     .activate      = activate,
     .uninit        = uninit,
-    .inputs        = superequalizer_inputs,
-    .outputs       = superequalizer_outputs,
+    FILTER_INPUTS(superequalizer_inputs),
+    FILTER_OUTPUTS(superequalizer_outputs),
 };
diff --git a/libavfilter/af_surround.c b/libavfilter/af_surround.c
index 06e181c7ad..33190de248 100644
--- a/libavfilter/af_surround.c
+++ b/libavfilter/af_surround.c
@@ -1770,7 +1770,6 @@ static const AVFilterPad inputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -1779,7 +1778,6 @@ static const AVFilterPad outputs[] = {
         .type          = AVMEDIA_TYPE_AUDIO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_surround = {
@@ -1791,7 +1789,7 @@ const AVFilter ff_af_surround = {
     .init           = init,
     .uninit         = uninit,
     .activate       = activate,
-    .inputs         = inputs,
-    .outputs        = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
     .flags          = AVFILTER_FLAG_SLICE_THREADS,
 };
diff --git a/libavfilter/af_tremolo.c b/libavfilter/af_tremolo.c
index c3f8e5620b..1ab7832d47 100644
--- a/libavfilter/af_tremolo.c
+++ b/libavfilter/af_tremolo.c
@@ -136,7 +136,6 @@ static const AVFilterPad avfilter_af_tremolo_inputs[] = {
         .config_props = config_input,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad avfilter_af_tremolo_outputs[] = {
@@ -144,7 +143,6 @@ static const AVFilterPad avfilter_af_tremolo_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_tremolo = {
@@ -154,6 +152,6 @@ const AVFilter ff_af_tremolo = {
     .priv_class    = &tremolo_class,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = avfilter_af_tremolo_inputs,
-    .outputs       = avfilter_af_tremolo_outputs,
+    FILTER_INPUTS(avfilter_af_tremolo_inputs),
+    FILTER_OUTPUTS(avfilter_af_tremolo_outputs),
 };
diff --git a/libavfilter/af_vibrato.c b/libavfilter/af_vibrato.c
index 8455074ef0..ec6f6558b0 100644
--- a/libavfilter/af_vibrato.c
+++ b/libavfilter/af_vibrato.c
@@ -174,7 +174,6 @@ static const AVFilterPad avfilter_af_vibrato_inputs[] = {
         .config_props = config_input,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad avfilter_af_vibrato_outputs[] = {
@@ -182,7 +181,6 @@ static const AVFilterPad avfilter_af_vibrato_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_vibrato = {
@@ -192,6 +190,6 @@ const AVFilter ff_af_vibrato = {
     .priv_class    = &vibrato_class,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = avfilter_af_vibrato_inputs,
-    .outputs       = avfilter_af_vibrato_outputs,
+    FILTER_INPUTS(avfilter_af_vibrato_inputs),
+    FILTER_OUTPUTS(avfilter_af_vibrato_outputs),
 };
diff --git a/libavfilter/af_volume.c b/libavfilter/af_volume.c
index 8feea25103..2d4012bfbf 100644
--- a/libavfilter/af_volume.c
+++ b/libavfilter/af_volume.c
@@ -452,7 +452,6 @@ static const AVFilterPad avfilter_af_volume_inputs[] = {
         .type           = AVMEDIA_TYPE_AUDIO,
         .filter_frame   = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad avfilter_af_volume_outputs[] = {
@@ -461,7 +460,6 @@ static const AVFilterPad avfilter_af_volume_outputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .config_props = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_volume = {
@@ -472,8 +470,8 @@ const AVFilter ff_af_volume = {
     .priv_class     = &volume_class,
     .init           = init,
     .uninit         = uninit,
-    .inputs         = avfilter_af_volume_inputs,
-    .outputs        = avfilter_af_volume_outputs,
+    FILTER_INPUTS(avfilter_af_volume_inputs),
+    FILTER_OUTPUTS(avfilter_af_volume_outputs),
     .flags          = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
     .process_command = process_command,
 };
diff --git a/libavfilter/af_volumedetect.c b/libavfilter/af_volumedetect.c
index 89e1b8584b..412b690302 100644
--- a/libavfilter/af_volumedetect.c
+++ b/libavfilter/af_volumedetect.c
@@ -134,7 +134,6 @@ static const AVFilterPad volumedetect_inputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad volumedetect_outputs[] = {
@@ -142,7 +141,6 @@ static const AVFilterPad volumedetect_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_volumedetect = {
@@ -151,6 +149,6 @@ const AVFilter ff_af_volumedetect = {
     .priv_size     = sizeof(VolDetectContext),
     .query_formats = query_formats,
     .uninit        = uninit,
-    .inputs        = volumedetect_inputs,
-    .outputs       = volumedetect_outputs,
+    FILTER_INPUTS(volumedetect_inputs),
+    FILTER_OUTPUTS(volumedetect_outputs),
 };
diff --git a/libavfilter/asink_anullsink.c b/libavfilter/asink_anullsink.c
index dce0204839..64a733e165 100644
--- a/libavfilter/asink_anullsink.c
+++ b/libavfilter/asink_anullsink.c
@@ -34,13 +34,12 @@ static const AVFilterPad avfilter_asink_anullsink_inputs[] = {
         .type           = AVMEDIA_TYPE_AUDIO,
         .filter_frame   = null_filter_frame,
     },
-    { NULL },
 };
 
 const AVFilter ff_asink_anullsink = {
     .name        = "anullsink",
     .description = NULL_IF_CONFIG_SMALL("Do absolutely nothing with the input audio."),
     .priv_size   = 0,
-    .inputs      = avfilter_asink_anullsink_inputs,
+    FILTER_INPUTS(avfilter_asink_anullsink_inputs),
     .outputs     = NULL,
 };
diff --git a/libavfilter/asrc_afirsrc.c b/libavfilter/asrc_afirsrc.c
index aba15dc5e2..9dd04d9533 100644
--- a/libavfilter/asrc_afirsrc.c
+++ b/libavfilter/asrc_afirsrc.c
@@ -301,7 +301,6 @@ static const AVFilterPad afirsrc_outputs[] = {
         .request_frame = request_frame,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_asrc_afirsrc = {
@@ -312,6 +311,6 @@ const AVFilter ff_asrc_afirsrc = {
     .uninit        = uninit,
     .priv_size     = sizeof(AudioFIRSourceContext),
     .inputs        = NULL,
-    .outputs       = afirsrc_outputs,
+    FILTER_OUTPUTS(afirsrc_outputs),
     .priv_class    = &afirsrc_class,
 };
diff --git a/libavfilter/asrc_anoisesrc.c b/libavfilter/asrc_anoisesrc.c
index c3e6252b3d..ca86658040 100644
--- a/libavfilter/asrc_anoisesrc.c
+++ b/libavfilter/asrc_anoisesrc.c
@@ -230,7 +230,6 @@ static const AVFilterPad anoisesrc_outputs[] = {
         .type          = AVMEDIA_TYPE_AUDIO,
         .config_props  = config_props,
     },
-    { NULL }
 };
 
 const AVFilter ff_asrc_anoisesrc = {
@@ -240,6 +239,6 @@ const AVFilter ff_asrc_anoisesrc = {
     .priv_size     = sizeof(ANoiseSrcContext),
     .inputs        = NULL,
     .activate      = activate,
-    .outputs       = anoisesrc_outputs,
+    FILTER_OUTPUTS(anoisesrc_outputs),
     .priv_class    = &anoisesrc_class,
 };
diff --git a/libavfilter/asrc_anullsrc.c b/libavfilter/asrc_anullsrc.c
index 5d9b16dfce..698102deda 100644
--- a/libavfilter/asrc_anullsrc.c
+++ b/libavfilter/asrc_anullsrc.c
@@ -134,7 +134,6 @@ static const AVFilterPad avfilter_asrc_anullsrc_outputs[] = {
         .type          = AVMEDIA_TYPE_AUDIO,
         .config_props  = config_props,
     },
-    { NULL }
 };
 
 const AVFilter ff_asrc_anullsrc = {
@@ -144,7 +143,7 @@ const AVFilter ff_asrc_anullsrc = {
     .query_formats = query_formats,
     .priv_size     = sizeof(ANullContext),
     .inputs        = NULL,
-    .outputs       = avfilter_asrc_anullsrc_outputs,
+    FILTER_OUTPUTS(avfilter_asrc_anullsrc_outputs),
     .activate      = activate,
     .priv_class    = &anullsrc_class,
 };
diff --git a/libavfilter/asrc_flite.c b/libavfilter/asrc_flite.c
index 1478cc07fa..61c177e0ba 100644
--- a/libavfilter/asrc_flite.c
+++ b/libavfilter/asrc_flite.c
@@ -271,7 +271,6 @@ static const AVFilterPad flite_outputs[] = {
         .config_props  = config_props,
         .request_frame = request_frame,
     },
-    { NULL }
 };
 
 const AVFilter ff_asrc_flite = {
@@ -282,6 +281,6 @@ const AVFilter ff_asrc_flite = {
     .uninit        = uninit,
     .priv_size     = sizeof(FliteContext),
     .inputs        = NULL,
-    .outputs       = flite_outputs,
+    FILTER_OUTPUTS(flite_outputs),
     .priv_class    = &flite_class,
 };
diff --git a/libavfilter/asrc_hilbert.c b/libavfilter/asrc_hilbert.c
index fe0c7c8659..460721d96a 100644
--- a/libavfilter/asrc_hilbert.c
+++ b/libavfilter/asrc_hilbert.c
@@ -171,7 +171,6 @@ static const AVFilterPad hilbert_outputs[] = {
         .request_frame = request_frame,
         .config_props  = config_props,
     },
-    { NULL }
 };
 
 const AVFilter ff_asrc_hilbert = {
@@ -182,6 +181,6 @@ const AVFilter ff_asrc_hilbert = {
     .uninit        = uninit,
     .priv_size     = sizeof(HilbertContext),
     .inputs        = NULL,
-    .outputs       = hilbert_outputs,
+    FILTER_OUTPUTS(hilbert_outputs),
     .priv_class    = &hilbert_class,
 };
diff --git a/libavfilter/asrc_sinc.c b/libavfilter/asrc_sinc.c
index ca8991ac2c..a620e08e44 100644
--- a/libavfilter/asrc_sinc.c
+++ b/libavfilter/asrc_sinc.c
@@ -408,7 +408,6 @@ static const AVFilterPad sinc_outputs[] = {
         .config_props  = config_output,
         .request_frame = request_frame,
     },
-    { NULL }
 };
 
 #define AF AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
@@ -440,5 +439,5 @@ const AVFilter ff_asrc_sinc = {
     .query_formats = query_formats,
     .uninit        = uninit,
     .inputs        = NULL,
-    .outputs       = sinc_outputs,
+    FILTER_OUTPUTS(sinc_outputs),
 };
diff --git a/libavfilter/asrc_sine.c b/libavfilter/asrc_sine.c
index af0329e8c7..68c844c556 100644
--- a/libavfilter/asrc_sine.c
+++ b/libavfilter/asrc_sine.c
@@ -253,7 +253,6 @@ static const AVFilterPad sine_outputs[] = {
         .request_frame = request_frame,
         .config_props  = config_props,
     },
-    { NULL }
 };
 
 const AVFilter ff_asrc_sine = {
@@ -264,6 +263,6 @@ const AVFilter ff_asrc_sine = {
     .uninit        = uninit,
     .priv_size     = sizeof(SineContext),
     .inputs        = NULL,
-    .outputs       = sine_outputs,
+    FILTER_OUTPUTS(sine_outputs),
     .priv_class    = &sine_class,
 };
diff --git a/libavfilter/avf_abitscope.c b/libavfilter/avf_abitscope.c
index 481a218e6e..c394091b7b 100644
--- a/libavfilter/avf_abitscope.c
+++ b/libavfilter/avf_abitscope.c
@@ -248,7 +248,6 @@ static const AVFilterPad inputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -257,7 +256,6 @@ static const AVFilterPad outputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_avf_abitscope = {
@@ -265,8 +263,8 @@ const AVFilter ff_avf_abitscope = {
     .description   = NULL_IF_CONFIG_SMALL("Convert input audio to audio bit scope video output."),
     .query_formats = query_formats,
     .priv_size     = sizeof(AudioBitScopeContext),
-    .inputs        = inputs,
-    .outputs       = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
     .activate      = activate,
     .priv_class    = &abitscope_class,
 };
diff --git a/libavfilter/avf_ahistogram.c b/libavfilter/avf_ahistogram.c
index 864c061c2f..96baf6da83 100644
--- a/libavfilter/avf_ahistogram.c
+++ b/libavfilter/avf_ahistogram.c
@@ -412,7 +412,6 @@ static const AVFilterPad ahistogram_inputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad ahistogram_outputs[] = {
@@ -421,7 +420,6 @@ static const AVFilterPad ahistogram_outputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_avf_ahistogram = {
@@ -431,7 +429,7 @@ const AVFilter ff_avf_ahistogram = {
     .query_formats = query_formats,
     .priv_size     = sizeof(AudioHistogramContext),
     .activate      = activate,
-    .inputs        = ahistogram_inputs,
-    .outputs       = ahistogram_outputs,
+    FILTER_INPUTS(ahistogram_inputs),
+    FILTER_OUTPUTS(ahistogram_outputs),
     .priv_class    = &ahistogram_class,
 };
diff --git a/libavfilter/avf_aphasemeter.c b/libavfilter/avf_aphasemeter.c
index bd3ad1ac61..13035328e9 100644
--- a/libavfilter/avf_aphasemeter.c
+++ b/libavfilter/avf_aphasemeter.c
@@ -380,7 +380,6 @@ static const AVFilterPad inputs[] = {
         .config_props = config_input,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 const AVFilter ff_avf_aphasemeter = {
@@ -390,7 +389,7 @@ const AVFilter ff_avf_aphasemeter = {
     .uninit        = uninit,
     .query_formats = query_formats,
     .priv_size     = sizeof(AudioPhaseMeterContext),
-    .inputs        = inputs,
+    FILTER_INPUTS(inputs),
     .outputs       = NULL,
     .priv_class    = &aphasemeter_class,
     .flags         = AVFILTER_FLAG_DYNAMIC_OUTPUTS,
diff --git a/libavfilter/avf_avectorscope.c b/libavfilter/avf_avectorscope.c
index a0011fe33b..f3001e99a3 100644
--- a/libavfilter/avf_avectorscope.c
+++ b/libavfilter/avf_avectorscope.c
@@ -403,7 +403,6 @@ static const AVFilterPad audiovectorscope_inputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad audiovectorscope_outputs[] = {
@@ -412,7 +411,6 @@ static const AVFilterPad audiovectorscope_outputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_avf_avectorscope = {
@@ -422,7 +420,7 @@ const AVFilter ff_avf_avectorscope = {
     .query_formats = query_formats,
     .priv_size     = sizeof(AudioVectorScopeContext),
     .activate      = activate,
-    .inputs        = audiovectorscope_inputs,
-    .outputs       = audiovectorscope_outputs,
+    FILTER_INPUTS(audiovectorscope_inputs),
+    FILTER_OUTPUTS(audiovectorscope_outputs),
     .priv_class    = &avectorscope_class,
 };
diff --git a/libavfilter/avf_showcqt.c b/libavfilter/avf_showcqt.c
index aa9900ebe0..aab4aa28d6 100644
--- a/libavfilter/avf_showcqt.c
+++ b/libavfilter/avf_showcqt.c
@@ -1577,7 +1577,6 @@ static const AVFilterPad showcqt_inputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad showcqt_outputs[] = {
@@ -1587,7 +1586,6 @@ static const AVFilterPad showcqt_outputs[] = {
         .config_props  = config_output,
         .request_frame = request_frame,
     },
-    { NULL }
 };
 
 const AVFilter ff_avf_showcqt = {
@@ -1597,7 +1595,7 @@ const AVFilter ff_avf_showcqt = {
     .uninit        = uninit,
     .query_formats = query_formats,
     .priv_size     = sizeof(ShowCQTContext),
-    .inputs        = showcqt_inputs,
-    .outputs       = showcqt_outputs,
+    FILTER_INPUTS(showcqt_inputs),
+    FILTER_OUTPUTS(showcqt_outputs),
     .priv_class    = &showcqt_class,
 };
diff --git a/libavfilter/avf_showfreqs.c b/libavfilter/avf_showfreqs.c
index 5dee3445a8..7eff726139 100644
--- a/libavfilter/avf_showfreqs.c
+++ b/libavfilter/avf_showfreqs.c
@@ -552,7 +552,6 @@ static const AVFilterPad showfreqs_inputs[] = {
         .name         = "default",
         .type         = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 static const AVFilterPad showfreqs_outputs[] = {
@@ -561,7 +560,6 @@ static const AVFilterPad showfreqs_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_avf_showfreqs = {
@@ -572,7 +570,7 @@ const AVFilter ff_avf_showfreqs = {
     .query_formats = query_formats,
     .priv_size     = sizeof(ShowFreqsContext),
     .activate      = activate,
-    .inputs        = showfreqs_inputs,
-    .outputs       = showfreqs_outputs,
+    FILTER_INPUTS(showfreqs_inputs),
+    FILTER_OUTPUTS(showfreqs_outputs),
     .priv_class    = &showfreqs_class,
 };
diff --git a/libavfilter/avf_showspatial.c b/libavfilter/avf_showspatial.c
index 3e1d4bd70e..c5af903216 100644
--- a/libavfilter/avf_showspatial.c
+++ b/libavfilter/avf_showspatial.c
@@ -346,7 +346,6 @@ static const AVFilterPad showspatial_inputs[] = {
         .name         = "default",
         .type         = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 static const AVFilterPad showspatial_outputs[] = {
@@ -355,7 +354,6 @@ static const AVFilterPad showspatial_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_avf_showspatial = {
@@ -364,8 +362,8 @@ const AVFilter ff_avf_showspatial = {
     .uninit        = uninit,
     .query_formats = query_formats,
     .priv_size     = sizeof(ShowSpatialContext),
-    .inputs        = showspatial_inputs,
-    .outputs       = showspatial_outputs,
+    FILTER_INPUTS(showspatial_inputs),
+    FILTER_OUTPUTS(showspatial_outputs),
     .activate      = spatial_activate,
     .priv_class    = &showspatial_class,
     .flags         = AVFILTER_FLAG_SLICE_THREADS,
diff --git a/libavfilter/avf_showspectrum.c b/libavfilter/avf_showspectrum.c
index 6ae4c89d77..5b5c4dccc9 100644
--- a/libavfilter/avf_showspectrum.c
+++ b/libavfilter/avf_showspectrum.c
@@ -1654,7 +1654,6 @@ static const AVFilterPad showspectrum_inputs[] = {
         .name         = "default",
         .type         = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 static const AVFilterPad showspectrum_outputs[] = {
@@ -1663,7 +1662,6 @@ static const AVFilterPad showspectrum_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_avf_showspectrum = {
@@ -1672,8 +1670,8 @@ const AVFilter ff_avf_showspectrum = {
     .uninit        = uninit,
     .query_formats = query_formats,
     .priv_size     = sizeof(ShowSpectrumContext),
-    .inputs        = showspectrum_inputs,
-    .outputs       = showspectrum_outputs,
+    FILTER_INPUTS(showspectrum_inputs),
+    FILTER_OUTPUTS(showspectrum_outputs),
     .activate      = activate,
     .priv_class    = &showspectrum_class,
     .flags         = AVFILTER_FLAG_SLICE_THREADS,
@@ -1838,7 +1836,6 @@ static const AVFilterPad showspectrumpic_inputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .filter_frame = showspectrumpic_filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad showspectrumpic_outputs[] = {
@@ -1848,7 +1845,6 @@ static const AVFilterPad showspectrumpic_outputs[] = {
         .config_props  = config_output,
         .request_frame = showspectrumpic_request_frame,
     },
-    { NULL }
 };
 
 const AVFilter ff_avf_showspectrumpic = {
@@ -1857,8 +1853,8 @@ const AVFilter ff_avf_showspectrumpic = {
     .uninit        = uninit,
     .query_formats = query_formats,
     .priv_size     = sizeof(ShowSpectrumContext),
-    .inputs        = showspectrumpic_inputs,
-    .outputs       = showspectrumpic_outputs,
+    FILTER_INPUTS(showspectrumpic_inputs),
+    FILTER_OUTPUTS(showspectrumpic_outputs),
     .priv_class    = &showspectrumpic_class,
     .flags         = AVFILTER_FLAG_SLICE_THREADS,
 };
diff --git a/libavfilter/avf_showvolume.c b/libavfilter/avf_showvolume.c
index d4b8c48297..2fd8298b85 100644
--- a/libavfilter/avf_showvolume.c
+++ b/libavfilter/avf_showvolume.c
@@ -486,7 +486,6 @@ static const AVFilterPad showvolume_inputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad showvolume_outputs[] = {
@@ -495,7 +494,6 @@ static const AVFilterPad showvolume_outputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_avf_showvolume = {
@@ -506,7 +504,7 @@ const AVFilter ff_avf_showvolume = {
     .uninit        = uninit,
     .query_formats = query_formats,
     .priv_size     = sizeof(ShowVolumeContext),
-    .inputs        = showvolume_inputs,
-    .outputs       = showvolume_outputs,
+    FILTER_INPUTS(showvolume_inputs),
+    FILTER_OUTPUTS(showvolume_outputs),
     .priv_class    = &showvolume_class,
 };
diff --git a/libavfilter/avf_showwaves.c b/libavfilter/avf_showwaves.c
index b3639f46a5..3dd381b9fd 100644
--- a/libavfilter/avf_showwaves.c
+++ b/libavfilter/avf_showwaves.c
@@ -763,7 +763,6 @@ static const AVFilterPad showwaves_inputs[] = {
         .name         = "default",
         .type         = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 static const AVFilterPad showwaves_outputs[] = {
@@ -772,7 +771,6 @@ static const AVFilterPad showwaves_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_avf_showwaves = {
@@ -782,9 +780,9 @@ const AVFilter ff_avf_showwaves = {
     .uninit        = uninit,
     .query_formats = query_formats,
     .priv_size     = sizeof(ShowWavesContext),
-    .inputs        = showwaves_inputs,
+    FILTER_INPUTS(showwaves_inputs),
     .activate      = activate,
-    .outputs       = showwaves_outputs,
+    FILTER_OUTPUTS(showwaves_outputs),
     .priv_class    = &showwaves_class,
 };
 
@@ -877,7 +875,6 @@ static const AVFilterPad showwavespic_inputs[] = {
         .config_props = showwavespic_config_input,
         .filter_frame = showwavespic_filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad showwavespic_outputs[] = {
@@ -887,7 +884,6 @@ static const AVFilterPad showwavespic_outputs[] = {
         .config_props  = config_output,
         .request_frame = request_frame,
     },
-    { NULL }
 };
 
 const AVFilter ff_avf_showwavespic = {
@@ -897,8 +893,8 @@ const AVFilter ff_avf_showwavespic = {
     .uninit        = uninit,
     .query_formats = query_formats,
     .priv_size     = sizeof(ShowWavesContext),
-    .inputs        = showwavespic_inputs,
-    .outputs       = showwavespic_outputs,
+    FILTER_INPUTS(showwavespic_inputs),
+    FILTER_OUTPUTS(showwavespic_outputs),
     .priv_class    = &showwavespic_class,
 };
 
diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c
index ea22b247de..a869a76b71 100644
--- a/libavfilter/avfilter.c
+++ b/libavfilter/avfilter.c
@@ -540,14 +540,20 @@ int avfilter_process_command(AVFilterContext *filter, const char *cmd, const cha
 
 int avfilter_pad_count(const AVFilterPad *pads)
 {
-    int count;
+    const AVFilter *filter;
+    void *opaque = NULL;
 
     if (!pads)
         return 0;
 
-    for (count = 0; pads->name; count++)
-        pads++;
-    return count;
+    while (filter = av_filter_iterate(&opaque)) {
+        if (pads == filter->inputs)
+            return filter->nb_inputs;
+        if (pads == filter->outputs)
+            return filter->nb_outputs;
+    }
+
+    av_assert0(!"AVFilterPad list not from a filter");
 }
 
 static const char *default_filter_name(void *filter_ctx)
@@ -650,7 +656,7 @@ AVFilterContext *ff_filter_alloc(const AVFilter *filter, const char *inst_name)
         goto err;
     ret->internal->execute = default_execute;
 
-    ret->nb_inputs = avfilter_pad_count(filter->inputs);
+    ret->nb_inputs  = filter->nb_inputs;
     if (ret->nb_inputs ) {
         ret->input_pads   = av_memdup(filter->inputs,  ret->nb_inputs  * sizeof(*filter->inputs));
         if (!ret->input_pads)
@@ -660,7 +666,7 @@ AVFilterContext *ff_filter_alloc(const AVFilter *filter, const char *inst_name)
             goto err;
     }
 
-    ret->nb_outputs = avfilter_pad_count(filter->outputs);
+    ret->nb_outputs = filter->nb_outputs;
     if (ret->nb_outputs) {
         ret->output_pads  = av_memdup(filter->outputs, ret->nb_outputs * sizeof(*filter->outputs));
         if (!ret->output_pads)
diff --git a/libavfilter/avfilter.h b/libavfilter/avfilter.h
index 5a225ffc44..5025fafdc5 100644
--- a/libavfilter/avfilter.h
+++ b/libavfilter/avfilter.h
@@ -71,8 +71,7 @@ typedef struct AVFilterFormats AVFilterFormats;
 typedef struct AVFilterChannelLayouts AVFilterChannelLayouts;
 
 /**
- * Get the number of elements in a NULL-terminated array of AVFilterPads (e.g.
- * AVFilter.inputs/outputs).
+ * Get the number of elements in an AVFilter's inputs or outputs array.
  */
 int avfilter_pad_count(const AVFilterPad *pads);
 
@@ -156,15 +155,16 @@ typedef struct AVFilter {
     const char *description;
 
     /**
-     * List of inputs, terminated by a zeroed element.
+     * List of static inputs.
      *
      * NULL if there are no (static) inputs. Instances of filters with
      * AVFILTER_FLAG_DYNAMIC_INPUTS set may have more inputs than present in
      * this list.
      */
     const AVFilterPad *inputs;
+
     /**
-     * List of outputs, terminated by a zeroed element.
+     * List of static outputs.
      *
      * NULL if there are no (static) outputs. Instances of filters with
      * AVFILTER_FLAG_DYNAMIC_OUTPUTS set may have more outputs than present in
@@ -195,6 +195,16 @@ typedef struct AVFilter {
      *****************************************************************
      */
 
+    /**
+     * The number of entries in the list of inputs.
+     */
+    uint16_t nb_inputs;
+
+    /**
+     * The number of entries in the list of outputs.
+     */
+    uint16_t nb_outputs;
+
     /**
      * Filter pre-initialization function
      *
diff --git a/libavfilter/buffersink.c b/libavfilter/buffersink.c
index 07c4812f29..8b46dcb15e 100644
--- a/libavfilter/buffersink.c
+++ b/libavfilter/buffersink.c
@@ -331,7 +331,6 @@ static const AVFilterPad avfilter_vsink_buffer_inputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vsink_buffer = {
@@ -342,7 +341,7 @@ const AVFilter ff_vsink_buffer = {
     .init          = common_init,
     .query_formats = vsink_query_formats,
     .activate      = activate,
-    .inputs        = avfilter_vsink_buffer_inputs,
+    FILTER_INPUTS(avfilter_vsink_buffer_inputs),
     .outputs       = NULL,
 };
 
@@ -351,7 +350,6 @@ static const AVFilterPad avfilter_asink_abuffer_inputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_asink_abuffer = {
@@ -362,6 +360,6 @@ const AVFilter ff_asink_abuffer = {
     .init          = common_init,
     .query_formats = asink_query_formats,
     .activate      = activate,
-    .inputs        = avfilter_asink_abuffer_inputs,
+    FILTER_INPUTS(avfilter_asink_abuffer_inputs),
     .outputs       = NULL,
 };
diff --git a/libavfilter/buffersrc.c b/libavfilter/buffersrc.c
index 4d0bb4f91d..632bfc7ad8 100644
--- a/libavfilter/buffersrc.c
+++ b/libavfilter/buffersrc.c
@@ -434,7 +434,6 @@ static const AVFilterPad avfilter_vsrc_buffer_outputs[] = {
         .request_frame = request_frame,
         .config_props  = config_props,
     },
-    { NULL }
 };
 
 const AVFilter ff_vsrc_buffer = {
@@ -447,7 +446,7 @@ const AVFilter ff_vsrc_buffer = {
     .uninit    = uninit,
 
     .inputs    = NULL,
-    .outputs   = avfilter_vsrc_buffer_outputs,
+    FILTER_OUTPUTS(avfilter_vsrc_buffer_outputs),
     .priv_class = &buffer_class,
 };
 
@@ -458,7 +457,6 @@ static const AVFilterPad avfilter_asrc_abuffer_outputs[] = {
         .request_frame = request_frame,
         .config_props  = config_props,
     },
-    { NULL }
 };
 
 const AVFilter ff_asrc_abuffer = {
@@ -471,6 +469,6 @@ const AVFilter ff_asrc_abuffer = {
     .uninit    = uninit,
 
     .inputs    = NULL,
-    .outputs   = avfilter_asrc_abuffer_outputs,
+    FILTER_OUTPUTS(avfilter_asrc_abuffer_outputs),
     .priv_class = &abuffer_class,
 };
diff --git a/libavfilter/f_bench.c b/libavfilter/f_bench.c
index e7d7c5e299..f7098adaf4 100644
--- a/libavfilter/f_bench.c
+++ b/libavfilter/f_bench.c
@@ -96,7 +96,6 @@ static const AVFilterPad bench_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad bench_outputs[] = {
@@ -104,7 +103,6 @@ static const AVFilterPad bench_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_bench = {
@@ -112,8 +110,8 @@ const AVFilter ff_vf_bench = {
     .description   = NULL_IF_CONFIG_SMALL("Benchmark part of a filtergraph."),
     .priv_size     = sizeof(BenchContext),
     .init          = init,
-    .inputs        = bench_inputs,
-    .outputs       = bench_outputs,
+    FILTER_INPUTS(bench_inputs),
+    FILTER_OUTPUTS(bench_outputs),
     .priv_class    = &bench_class,
 };
 #endif /* CONFIG_BENCH_FILTER */
@@ -128,7 +126,6 @@ static const AVFilterPad abench_inputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad abench_outputs[] = {
@@ -136,7 +133,6 @@ static const AVFilterPad abench_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_abench = {
@@ -144,8 +140,8 @@ const AVFilter ff_af_abench = {
     .description   = NULL_IF_CONFIG_SMALL("Benchmark part of a filtergraph."),
     .priv_size     = sizeof(BenchContext),
     .init          = init,
-    .inputs        = abench_inputs,
-    .outputs       = abench_outputs,
+    FILTER_INPUTS(abench_inputs),
+    FILTER_OUTPUTS(abench_outputs),
     .priv_class    = &abench_class,
 };
 #endif /* CONFIG_ABENCH_FILTER */
diff --git a/libavfilter/f_cue.c b/libavfilter/f_cue.c
index 03804f1667..e87b7a67c7 100644
--- a/libavfilter/f_cue.c
+++ b/libavfilter/f_cue.c
@@ -103,7 +103,6 @@ static const AVFilterPad cue_inputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 static const AVFilterPad cue_outputs[] = {
@@ -111,7 +110,6 @@ static const AVFilterPad cue_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_cue = {
@@ -119,8 +117,8 @@ const AVFilter ff_vf_cue = {
     .description = NULL_IF_CONFIG_SMALL("Delay filtering to match a cue."),
     .priv_size   = sizeof(CueContext),
     .priv_class  = &cue_class,
-    .inputs      = cue_inputs,
-    .outputs     = cue_outputs,
+    FILTER_INPUTS(cue_inputs),
+    FILTER_OUTPUTS(cue_outputs),
     .activate    = activate,
 };
 #endif /* CONFIG_CUE_FILTER */
@@ -134,7 +132,6 @@ static const AVFilterPad acue_inputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 static const AVFilterPad acue_outputs[] = {
@@ -142,7 +139,6 @@ static const AVFilterPad acue_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_acue = {
@@ -150,8 +146,8 @@ const AVFilter ff_af_acue = {
     .description = NULL_IF_CONFIG_SMALL("Delay filtering to match a cue."),
     .priv_size   = sizeof(CueContext),
     .priv_class  = &acue_class,
-    .inputs      = acue_inputs,
-    .outputs     = acue_outputs,
+    FILTER_INPUTS(acue_inputs),
+    FILTER_OUTPUTS(acue_outputs),
     .activate    = activate,
 };
 #endif /* CONFIG_ACUE_FILTER */
diff --git a/libavfilter/f_drawgraph.c b/libavfilter/f_drawgraph.c
index 70701e330e..a9b47483ad 100644
--- a/libavfilter/f_drawgraph.c
+++ b/libavfilter/f_drawgraph.c
@@ -458,7 +458,6 @@ static const AVFilterPad drawgraph_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad drawgraph_outputs[] = {
@@ -468,7 +467,6 @@ static const AVFilterPad drawgraph_outputs[] = {
         .config_props = config_output,
         .request_frame = request_frame,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_drawgraph = {
@@ -479,8 +477,8 @@ const AVFilter ff_vf_drawgraph = {
     .query_formats = query_formats,
     .init          = init,
     .uninit        = uninit,
-    .inputs        = drawgraph_inputs,
-    .outputs       = drawgraph_outputs,
+    FILTER_INPUTS(drawgraph_inputs),
+    FILTER_OUTPUTS(drawgraph_outputs),
 };
 
 #endif // CONFIG_DRAWGRAPH_FILTER
@@ -496,7 +494,6 @@ static const AVFilterPad adrawgraph_inputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad adrawgraph_outputs[] = {
@@ -506,7 +503,6 @@ static const AVFilterPad adrawgraph_outputs[] = {
         .config_props = config_output,
         .request_frame = request_frame,
     },
-    { NULL }
 };
 
 const AVFilter ff_avf_adrawgraph = {
@@ -517,7 +513,7 @@ const AVFilter ff_avf_adrawgraph = {
     .query_formats = query_formats,
     .init          = init,
     .uninit        = uninit,
-    .inputs        = adrawgraph_inputs,
-    .outputs       = adrawgraph_outputs,
+    FILTER_INPUTS(adrawgraph_inputs),
+    FILTER_OUTPUTS(adrawgraph_outputs),
 };
 #endif // CONFIG_ADRAWGRAPH_FILTER
diff --git a/libavfilter/f_ebur128.c b/libavfilter/f_ebur128.c
index 938ae60848..2ce8a749cf 100644
--- a/libavfilter/f_ebur128.c
+++ b/libavfilter/f_ebur128.c
@@ -1017,7 +1017,6 @@ static const AVFilterPad ebur128_inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_audio_input,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_ebur128 = {
@@ -1027,7 +1026,7 @@ const AVFilter ff_af_ebur128 = {
     .init          = init,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = ebur128_inputs,
+    FILTER_INPUTS(ebur128_inputs),
     .outputs       = NULL,
     .priv_class    = &ebur128_class,
     .flags         = AVFILTER_FLAG_DYNAMIC_OUTPUTS,
diff --git a/libavfilter/f_graphmonitor.c b/libavfilter/f_graphmonitor.c
index 90e93a4ac3..b712c2fdd6 100644
--- a/libavfilter/f_graphmonitor.c
+++ b/libavfilter/f_graphmonitor.c
@@ -395,7 +395,6 @@ static const AVFilterPad graphmonitor_inputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 static const AVFilterPad graphmonitor_outputs[] = {
@@ -404,7 +403,6 @@ static const AVFilterPad graphmonitor_outputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_graphmonitor = {
@@ -414,8 +412,8 @@ const AVFilter ff_vf_graphmonitor = {
     .priv_class    = &graphmonitor_class,
     .query_formats = query_formats,
     .activate      = activate,
-    .inputs        = graphmonitor_inputs,
-    .outputs       = graphmonitor_outputs,
+    FILTER_INPUTS(graphmonitor_inputs),
+    FILTER_OUTPUTS(graphmonitor_outputs),
 };
 
 #endif // CONFIG_GRAPHMONITOR_FILTER
@@ -430,7 +428,6 @@ static const AVFilterPad agraphmonitor_inputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 static const AVFilterPad agraphmonitor_outputs[] = {
@@ -439,7 +436,6 @@ static const AVFilterPad agraphmonitor_outputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_avf_agraphmonitor = {
@@ -449,7 +445,7 @@ const AVFilter ff_avf_agraphmonitor = {
     .priv_class    = &agraphmonitor_class,
     .query_formats = query_formats,
     .activate      = activate,
-    .inputs        = agraphmonitor_inputs,
-    .outputs       = agraphmonitor_outputs,
+    FILTER_INPUTS(agraphmonitor_inputs),
+    FILTER_OUTPUTS(agraphmonitor_outputs),
 };
 #endif // CONFIG_AGRAPHMONITOR_FILTER
diff --git a/libavfilter/f_interleave.c b/libavfilter/f_interleave.c
index 2845d72b79..d0c94abbce 100644
--- a/libavfilter/f_interleave.c
+++ b/libavfilter/f_interleave.c
@@ -235,7 +235,6 @@ static const AVFilterPad interleave_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_interleave = {
@@ -245,7 +244,7 @@ const AVFilter ff_vf_interleave = {
     .init        = init,
     .uninit      = uninit,
     .activate    = activate,
-    .outputs     = interleave_outputs,
+    FILTER_OUTPUTS(interleave_outputs),
     .priv_class  = &interleave_class,
     .flags       = AVFILTER_FLAG_DYNAMIC_INPUTS,
 };
@@ -263,7 +262,6 @@ static const AVFilterPad ainterleave_outputs[] = {
         .type          = AVMEDIA_TYPE_AUDIO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_ainterleave = {
@@ -273,7 +271,7 @@ const AVFilter ff_af_ainterleave = {
     .init        = init,
     .uninit      = uninit,
     .activate    = activate,
-    .outputs     = ainterleave_outputs,
+    FILTER_OUTPUTS(ainterleave_outputs),
     .priv_class  = &ainterleave_class,
     .flags       = AVFILTER_FLAG_DYNAMIC_INPUTS,
 };
diff --git a/libavfilter/f_loop.c b/libavfilter/f_loop.c
index a06e8172d3..29c9f28afc 100644
--- a/libavfilter/f_loop.c
+++ b/libavfilter/f_loop.c
@@ -269,7 +269,6 @@ static const AVFilterPad ainputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .config_props = aconfig_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad aoutputs[] = {
@@ -277,7 +276,6 @@ static const AVFilterPad aoutputs[] = {
         .name          = "default",
         .type          = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_aloop = {
@@ -287,8 +285,8 @@ const AVFilter ff_af_aloop = {
     .priv_class    = &aloop_class,
     .activate      = aactivate,
     .uninit        = auninit,
-    .inputs        = ainputs,
-    .outputs       = aoutputs,
+    FILTER_INPUTS(ainputs),
+    FILTER_OUTPUTS(aoutputs),
 };
 #endif /* CONFIG_ALOOP_FILTER */
 
@@ -442,7 +440,6 @@ static const AVFilterPad inputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -450,7 +447,6 @@ static const AVFilterPad outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_loop = {
@@ -461,7 +457,7 @@ const AVFilter ff_vf_loop = {
     .init        = init,
     .uninit      = uninit,
     .activate    = activate,
-    .inputs      = inputs,
-    .outputs     = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
 };
 #endif /* CONFIG_LOOP_FILTER */
diff --git a/libavfilter/f_metadata.c b/libavfilter/f_metadata.c
index d0a78b00d0..cecfe62a9c 100644
--- a/libavfilter/f_metadata.c
+++ b/libavfilter/f_metadata.c
@@ -373,7 +373,6 @@ static const AVFilterPad ainputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad aoutputs[] = {
@@ -381,7 +380,6 @@ static const AVFilterPad aoutputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_ametadata = {
@@ -391,8 +389,8 @@ const AVFilter ff_af_ametadata = {
     .priv_class    = &ametadata_class,
     .init          = init,
     .uninit        = uninit,
-    .inputs        = ainputs,
-    .outputs       = aoutputs,
+    FILTER_INPUTS(ainputs),
+    FILTER_OUTPUTS(aoutputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
 };
 #endif /* CONFIG_AMETADATA_FILTER */
@@ -408,7 +406,6 @@ static const AVFilterPad inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -416,7 +413,6 @@ static const AVFilterPad outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_metadata = {
@@ -426,8 +422,8 @@ const AVFilter ff_vf_metadata = {
     .priv_class  = &metadata_class,
     .init        = init,
     .uninit      = uninit,
-    .inputs      = inputs,
-    .outputs     = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
     .flags       = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
 };
 #endif /* CONFIG_METADATA_FILTER */
diff --git a/libavfilter/f_perms.c b/libavfilter/f_perms.c
index 0302ed765b..8c449fbdfc 100644
--- a/libavfilter/f_perms.c
+++ b/libavfilter/f_perms.c
@@ -122,7 +122,6 @@ static const AVFilterPad aperms_inputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad aperms_outputs[] = {
@@ -130,7 +129,6 @@ static const AVFilterPad aperms_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_aperms = {
@@ -138,8 +136,8 @@ const AVFilter ff_af_aperms = {
     .description = NULL_IF_CONFIG_SMALL("Set permissions for the output audio frame."),
     .init        = init,
     .priv_size   = sizeof(PermsContext),
-    .inputs      = aperms_inputs,
-    .outputs     = aperms_outputs,
+    FILTER_INPUTS(aperms_inputs),
+    FILTER_OUTPUTS(aperms_outputs),
     .priv_class  = &aperms_class,
     .flags       = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
 };
@@ -156,7 +154,6 @@ static const AVFilterPad perms_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad perms_outputs[] = {
@@ -164,7 +161,6 @@ static const AVFilterPad perms_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_perms = {
@@ -172,8 +168,8 @@ const AVFilter ff_vf_perms = {
     .description = NULL_IF_CONFIG_SMALL("Set permissions for the output video frame."),
     .init        = init,
     .priv_size   = sizeof(PermsContext),
-    .inputs      = perms_inputs,
-    .outputs     = perms_outputs,
+    FILTER_INPUTS(perms_inputs),
+    FILTER_OUTPUTS(perms_outputs),
     .priv_class  = &perms_class,
     .flags       = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
 };
diff --git a/libavfilter/f_realtime.c b/libavfilter/f_realtime.c
index 332ef21ac5..125bd6131c 100644
--- a/libavfilter/f_realtime.c
+++ b/libavfilter/f_realtime.c
@@ -81,7 +81,6 @@ static const AVFilterPad avfilter_vf_realtime_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad avfilter_vf_realtime_outputs[] = {
@@ -89,7 +88,6 @@ static const AVFilterPad avfilter_vf_realtime_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_realtime = {
@@ -97,8 +95,8 @@ const AVFilter ff_vf_realtime = {
     .description = NULL_IF_CONFIG_SMALL("Slow down filtering to match realtime."),
     .priv_size   = sizeof(RealtimeContext),
     .priv_class  = &realtime_class,
-    .inputs      = avfilter_vf_realtime_inputs,
-    .outputs     = avfilter_vf_realtime_outputs,
+    FILTER_INPUTS(avfilter_vf_realtime_inputs),
+    FILTER_OUTPUTS(avfilter_vf_realtime_outputs),
 };
 #endif /* CONFIG_REALTIME_FILTER */
 
@@ -113,7 +111,6 @@ static const AVFilterPad arealtime_inputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad arealtime_outputs[] = {
@@ -121,7 +118,6 @@ static const AVFilterPad arealtime_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_arealtime = {
@@ -129,7 +125,7 @@ const AVFilter ff_af_arealtime = {
     .description = NULL_IF_CONFIG_SMALL("Slow down filtering to match realtime."),
     .priv_size   = sizeof(RealtimeContext),
     .priv_class  = &arealtime_class,
-    .inputs      = arealtime_inputs,
-    .outputs     = arealtime_outputs,
+    FILTER_INPUTS(arealtime_inputs),
+    FILTER_OUTPUTS(arealtime_outputs),
 };
 #endif /* CONFIG_AREALTIME_FILTER */
diff --git a/libavfilter/f_reverse.c b/libavfilter/f_reverse.c
index 29ba5fe9eb..82f0c705a2 100644
--- a/libavfilter/f_reverse.c
+++ b/libavfilter/f_reverse.c
@@ -121,7 +121,6 @@ static const AVFilterPad reverse_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad reverse_outputs[] = {
@@ -130,7 +129,6 @@ static const AVFilterPad reverse_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .request_frame = request_frame,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_reverse = {
@@ -139,8 +137,8 @@ const AVFilter ff_vf_reverse = {
     .priv_size   = sizeof(ReverseContext),
     .init        = init,
     .uninit      = uninit,
-    .inputs      = reverse_inputs,
-    .outputs     = reverse_outputs,
+    FILTER_INPUTS(reverse_inputs),
+    FILTER_OUTPUTS(reverse_outputs),
 };
 
 #endif /* CONFIG_REVERSE_FILTER */
@@ -272,7 +270,6 @@ static const AVFilterPad areverse_inputs[] = {
         .flags          = AVFILTERPAD_FLAG_NEEDS_WRITABLE,
         .filter_frame   = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad areverse_outputs[] = {
@@ -281,7 +278,6 @@ static const AVFilterPad areverse_outputs[] = {
         .type          = AVMEDIA_TYPE_AUDIO,
         .request_frame = areverse_request_frame,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_areverse = {
@@ -291,8 +287,8 @@ const AVFilter ff_af_areverse = {
     .priv_size     = sizeof(ReverseContext),
     .init          = init,
     .uninit        = uninit,
-    .inputs        = areverse_inputs,
-    .outputs       = areverse_outputs,
+    FILTER_INPUTS(areverse_inputs),
+    FILTER_OUTPUTS(areverse_outputs),
 };
 
 #endif /* CONFIG_AREVERSE_FILTER */
diff --git a/libavfilter/f_segment.c b/libavfilter/f_segment.c
index d2c6d44cbe..f40b18839c 100644
--- a/libavfilter/f_segment.c
+++ b/libavfilter/f_segment.c
@@ -277,7 +277,6 @@ static const AVFilterPad segment_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_segment = {
@@ -288,7 +287,7 @@ const AVFilter ff_vf_segment = {
     .priv_size   = sizeof(SegmentContext),
     .priv_class  = &segment_class,
     .activate    = activate,
-    .inputs      = segment_inputs,
+    FILTER_INPUTS(segment_inputs),
     .outputs     = NULL,
     .flags       = AVFILTER_FLAG_DYNAMIC_OUTPUTS,
 };
@@ -317,7 +316,6 @@ static const AVFilterPad asegment_inputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_asegment = {
@@ -328,7 +326,7 @@ const AVFilter ff_af_asegment = {
     .priv_size   = sizeof(SegmentContext),
     .priv_class  = &asegment_class,
     .activate    = activate,
-    .inputs      = asegment_inputs,
+    FILTER_INPUTS(asegment_inputs),
     .outputs     = NULL,
     .flags       = AVFILTER_FLAG_DYNAMIC_OUTPUTS,
 };
diff --git a/libavfilter/f_select.c b/libavfilter/f_select.c
index 68afafb8b6..fad54ab16a 100644
--- a/libavfilter/f_select.c
+++ b/libavfilter/f_select.c
@@ -473,7 +473,6 @@ static const AVFilterPad avfilter_af_aselect_inputs[] = {
         .config_props = config_input,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_aselect = {
@@ -482,7 +481,7 @@ const AVFilter ff_af_aselect = {
     .init        = aselect_init,
     .uninit      = uninit,
     .priv_size   = sizeof(SelectContext),
-    .inputs      = avfilter_af_aselect_inputs,
+    FILTER_INPUTS(avfilter_af_aselect_inputs),
     .priv_class  = &aselect_class,
     .flags       = AVFILTER_FLAG_DYNAMIC_OUTPUTS,
 };
@@ -529,7 +528,6 @@ static const AVFilterPad avfilter_vf_select_inputs[] = {
         .config_props = config_input,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_select = {
@@ -540,7 +538,7 @@ const AVFilter ff_vf_select = {
     .query_formats = query_formats,
     .priv_size     = sizeof(SelectContext),
     .priv_class    = &select_class,
-    .inputs        = avfilter_vf_select_inputs,
+    FILTER_INPUTS(avfilter_vf_select_inputs),
     .flags         = AVFILTER_FLAG_DYNAMIC_OUTPUTS,
 };
 #endif /* CONFIG_SELECT_FILTER */
diff --git a/libavfilter/f_sendcmd.c b/libavfilter/f_sendcmd.c
index 71b0a5c411..99d8ca939c 100644
--- a/libavfilter/f_sendcmd.c
+++ b/libavfilter/f_sendcmd.c
@@ -583,7 +583,6 @@ static const AVFilterPad sendcmd_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad sendcmd_outputs[] = {
@@ -591,7 +590,6 @@ static const AVFilterPad sendcmd_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_sendcmd = {
@@ -600,8 +598,8 @@ const AVFilter ff_vf_sendcmd = {
     .init        = init,
     .uninit      = uninit,
     .priv_size   = sizeof(SendCmdContext),
-    .inputs      = sendcmd_inputs,
-    .outputs     = sendcmd_outputs,
+    FILTER_INPUTS(sendcmd_inputs),
+    FILTER_OUTPUTS(sendcmd_outputs),
     .priv_class  = &sendcmd_class,
 };
 
@@ -618,7 +616,6 @@ static const AVFilterPad asendcmd_inputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad asendcmd_outputs[] = {
@@ -626,7 +623,6 @@ static const AVFilterPad asendcmd_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_asendcmd = {
@@ -635,8 +631,8 @@ const AVFilter ff_af_asendcmd = {
     .init        = init,
     .uninit      = uninit,
     .priv_size   = sizeof(SendCmdContext),
-    .inputs      = asendcmd_inputs,
-    .outputs     = asendcmd_outputs,
+    FILTER_INPUTS(asendcmd_inputs),
+    FILTER_OUTPUTS(asendcmd_outputs),
     .priv_class  = &asendcmd_class,
 };
 
diff --git a/libavfilter/f_sidedata.c b/libavfilter/f_sidedata.c
index 9133fcb1e3..5c9f905cc2 100644
--- a/libavfilter/f_sidedata.c
+++ b/libavfilter/f_sidedata.c
@@ -130,7 +130,6 @@ static const AVFilterPad ainputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad aoutputs[] = {
@@ -138,7 +137,6 @@ static const AVFilterPad aoutputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_asidedata = {
@@ -147,8 +145,8 @@ const AVFilter ff_af_asidedata = {
     .priv_size     = sizeof(SideDataContext),
     .priv_class    = &asidedata_class,
     .init          = init,
-    .inputs        = ainputs,
-    .outputs       = aoutputs,
+    FILTER_INPUTS(ainputs),
+    FILTER_OUTPUTS(aoutputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
 };
 #endif /* CONFIG_ASIDEDATA_FILTER */
@@ -164,7 +162,6 @@ static const AVFilterPad inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -172,7 +169,6 @@ static const AVFilterPad outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_sidedata = {
@@ -181,8 +177,8 @@ const AVFilter ff_vf_sidedata = {
     .priv_size   = sizeof(SideDataContext),
     .priv_class  = &sidedata_class,
     .init        = init,
-    .inputs      = inputs,
-    .outputs     = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
     .flags       = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
 };
 #endif /* CONFIG_SIDEDATA_FILTER */
diff --git a/libavfilter/f_zmq.c b/libavfilter/f_zmq.c
index 774a890871..5de22e2fbe 100644
--- a/libavfilter/f_zmq.c
+++ b/libavfilter/f_zmq.c
@@ -214,7 +214,6 @@ static const AVFilterPad zmq_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad zmq_outputs[] = {
@@ -222,7 +221,6 @@ static const AVFilterPad zmq_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_zmq = {
@@ -231,8 +229,8 @@ const AVFilter ff_vf_zmq = {
     .init        = init,
     .uninit      = uninit,
     .priv_size   = sizeof(ZMQContext),
-    .inputs      = zmq_inputs,
-    .outputs     = zmq_outputs,
+    FILTER_INPUTS(zmq_inputs),
+    FILTER_OUTPUTS(zmq_outputs),
     .priv_class  = &zmq_class,
 };
 
@@ -249,7 +247,6 @@ static const AVFilterPad azmq_inputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad azmq_outputs[] = {
@@ -257,7 +254,6 @@ static const AVFilterPad azmq_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_azmq = {
@@ -266,8 +262,8 @@ const AVFilter ff_af_azmq = {
     .init        = init,
     .uninit      = uninit,
     .priv_size   = sizeof(ZMQContext),
-    .inputs      = azmq_inputs,
-    .outputs     = azmq_outputs,
+    FILTER_INPUTS(azmq_inputs),
+    FILTER_OUTPUTS(azmq_outputs),
     .priv_class  = &azmq_class,
 };
 
diff --git a/libavfilter/fifo.c b/libavfilter/fifo.c
index e0996ba501..bb7d78f09c 100644
--- a/libavfilter/fifo.c
+++ b/libavfilter/fifo.c
@@ -116,7 +116,6 @@ static const AVFilterPad avfilter_vf_fifo_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = add_to_queue,
     },
-    { NULL }
 };
 
 static const AVFilterPad avfilter_vf_fifo_outputs[] = {
@@ -125,7 +124,6 @@ static const AVFilterPad avfilter_vf_fifo_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .request_frame = request_frame,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_fifo = {
@@ -134,8 +132,8 @@ const AVFilter ff_vf_fifo = {
     .init        = init,
     .uninit      = uninit,
     .priv_size   = sizeof(FifoContext),
-    .inputs      = avfilter_vf_fifo_inputs,
-    .outputs     = avfilter_vf_fifo_outputs,
+    FILTER_INPUTS(avfilter_vf_fifo_inputs),
+    FILTER_OUTPUTS(avfilter_vf_fifo_outputs),
 };
 
 static const AVFilterPad avfilter_af_afifo_inputs[] = {
@@ -144,7 +142,6 @@ static const AVFilterPad avfilter_af_afifo_inputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .filter_frame = add_to_queue,
     },
-    { NULL }
 };
 
 static const AVFilterPad avfilter_af_afifo_outputs[] = {
@@ -153,7 +150,6 @@ static const AVFilterPad avfilter_af_afifo_outputs[] = {
         .type          = AVMEDIA_TYPE_AUDIO,
         .request_frame = request_frame,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_afifo = {
@@ -162,6 +158,6 @@ const AVFilter ff_af_afifo = {
     .init        = init,
     .uninit      = uninit,
     .priv_size   = sizeof(FifoContext),
-    .inputs      = avfilter_af_afifo_inputs,
-    .outputs     = avfilter_af_afifo_outputs,
+    FILTER_INPUTS(avfilter_af_afifo_inputs),
+    FILTER_OUTPUTS(avfilter_af_afifo_outputs),
 };
diff --git a/libavfilter/internal.h b/libavfilter/internal.h
index a0aa32af4d..51b0afa24d 100644
--- a/libavfilter/internal.h
+++ b/libavfilter/internal.h
@@ -141,6 +141,12 @@ static av_always_inline int ff_filter_execute(AVFilterContext *ctx, avfilter_act
     return ctx->internal->execute(ctx, func, arg, ret, nb_jobs);
 }
 
+#define FILTER_INOUTPADS(inout, array) \
+       .inout        = array, \
+       .nb_ ## inout = FF_ARRAY_ELEMS(array)
+#define FILTER_INPUTS(array) FILTER_INOUTPADS(inputs, (array))
+#define FILTER_OUTPUTS(array) FILTER_INOUTPADS(outputs, (array))
+
 /**
  * Tell if an integer is contained in the provided -1-terminated list of integers.
  * This is useful for determining (for instance) if an AVPixelFormat is in an
diff --git a/libavfilter/setpts.c b/libavfilter/setpts.c
index ac98974312..fad92033e4 100644
--- a/libavfilter/setpts.c
+++ b/libavfilter/setpts.c
@@ -279,7 +279,6 @@ static const AVFilterPad avfilter_vf_setpts_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad avfilter_vf_setpts_outputs[] = {
@@ -287,7 +286,6 @@ static const AVFilterPad avfilter_vf_setpts_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_setpts = {
@@ -300,8 +298,8 @@ const AVFilter ff_vf_setpts = {
     .priv_size = sizeof(SetPTSContext),
     .priv_class = &setpts_class,
 
-    .inputs    = avfilter_vf_setpts_inputs,
-    .outputs   = avfilter_vf_setpts_outputs,
+    FILTER_INPUTS(avfilter_vf_setpts_inputs),
+    FILTER_OUTPUTS(avfilter_vf_setpts_outputs),
 };
 #endif /* CONFIG_SETPTS_FILTER */
 
@@ -319,7 +317,6 @@ static const AVFilterPad asetpts_inputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad asetpts_outputs[] = {
@@ -327,7 +324,6 @@ static const AVFilterPad asetpts_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_asetpts = {
@@ -338,7 +334,7 @@ const AVFilter ff_af_asetpts = {
     .uninit      = uninit,
     .priv_size   = sizeof(SetPTSContext),
     .priv_class  = &asetpts_class,
-    .inputs      = asetpts_inputs,
-    .outputs     = asetpts_outputs,
+    FILTER_INPUTS(asetpts_inputs),
+    FILTER_OUTPUTS(asetpts_outputs),
 };
 #endif /* CONFIG_ASETPTS_FILTER */
diff --git a/libavfilter/settb.c b/libavfilter/settb.c
index 2f68e44c5b..ae2cf9b888 100644
--- a/libavfilter/settb.c
+++ b/libavfilter/settb.c
@@ -167,7 +167,6 @@ static const AVFilterPad avfilter_vf_settb_inputs[] = {
         .name         = "default",
         .type         = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 static const AVFilterPad avfilter_vf_settb_outputs[] = {
@@ -176,7 +175,6 @@ static const AVFilterPad avfilter_vf_settb_outputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_output_props,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_settb = {
@@ -184,8 +182,8 @@ const AVFilter ff_vf_settb = {
     .description = NULL_IF_CONFIG_SMALL("Set timebase for the video output link."),
     .priv_size   = sizeof(SetTBContext),
     .priv_class  = &settb_class,
-    .inputs      = avfilter_vf_settb_inputs,
-    .outputs     = avfilter_vf_settb_outputs,
+    FILTER_INPUTS(avfilter_vf_settb_inputs),
+    FILTER_OUTPUTS(avfilter_vf_settb_outputs),
     .activate    = activate,
 };
 #endif /* CONFIG_SETTB_FILTER */
@@ -200,7 +198,6 @@ static const AVFilterPad avfilter_af_asettb_inputs[] = {
         .name         = "default",
         .type         = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 static const AVFilterPad avfilter_af_asettb_outputs[] = {
@@ -209,15 +206,14 @@ static const AVFilterPad avfilter_af_asettb_outputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .config_props = config_output_props,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_asettb = {
     .name        = "asettb",
     .description = NULL_IF_CONFIG_SMALL("Set timebase for the audio output link."),
     .priv_size   = sizeof(SetTBContext),
-    .inputs      = avfilter_af_asettb_inputs,
-    .outputs     = avfilter_af_asettb_outputs,
+    FILTER_INPUTS(avfilter_af_asettb_inputs),
+    FILTER_OUTPUTS(avfilter_af_asettb_outputs),
     .priv_class  = &asettb_class,
     .activate    = activate,
 };
diff --git a/libavfilter/split.c b/libavfilter/split.c
index 56b29e1171..a77ce6f6f1 100644
--- a/libavfilter/split.c
+++ b/libavfilter/split.c
@@ -116,7 +116,6 @@ static const AVFilterPad avfilter_vf_split_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_split = {
@@ -126,7 +125,7 @@ const AVFilter ff_vf_split = {
     .priv_class  = &split_class,
     .init        = split_init,
     .uninit      = split_uninit,
-    .inputs      = avfilter_vf_split_inputs,
+    FILTER_INPUTS(avfilter_vf_split_inputs),
     .outputs     = NULL,
     .flags       = AVFILTER_FLAG_DYNAMIC_OUTPUTS,
 };
@@ -137,7 +136,6 @@ static const AVFilterPad avfilter_af_asplit_inputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_asplit = {
@@ -147,7 +145,7 @@ const AVFilter ff_af_asplit = {
     .priv_class  = &asplit_class,
     .init        = split_init,
     .uninit      = split_uninit,
-    .inputs      = avfilter_af_asplit_inputs,
+    FILTER_INPUTS(avfilter_af_asplit_inputs),
     .outputs     = NULL,
     .flags       = AVFILTER_FLAG_DYNAMIC_OUTPUTS,
 };
diff --git a/libavfilter/trim.c b/libavfilter/trim.c
index 261dacbc5c..c260da3a0b 100644
--- a/libavfilter/trim.c
+++ b/libavfilter/trim.c
@@ -195,7 +195,6 @@ static const AVFilterPad trim_inputs[] = {
         .filter_frame = trim_filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad trim_outputs[] = {
@@ -203,7 +202,6 @@ static const AVFilterPad trim_outputs[] = {
         .name         = "default",
         .type         = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_trim = {
@@ -212,8 +210,8 @@ const AVFilter ff_vf_trim = {
     .init        = init,
     .priv_size   = sizeof(TrimContext),
     .priv_class  = &trim_class,
-    .inputs      = trim_inputs,
-    .outputs     = trim_outputs,
+    FILTER_INPUTS(trim_inputs),
+    FILTER_OUTPUTS(trim_outputs),
 };
 #endif // CONFIG_TRIM_FILTER
 
@@ -350,7 +348,6 @@ static const AVFilterPad atrim_inputs[] = {
         .filter_frame = atrim_filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad atrim_outputs[] = {
@@ -358,7 +355,6 @@ static const AVFilterPad atrim_outputs[] = {
         .name         = "default",
         .type         = AVMEDIA_TYPE_AUDIO,
     },
-    { NULL }
 };
 
 const AVFilter ff_af_atrim = {
@@ -367,7 +363,7 @@ const AVFilter ff_af_atrim = {
     .init        = init,
     .priv_size   = sizeof(TrimContext),
     .priv_class  = &atrim_class,
-    .inputs      = atrim_inputs,
-    .outputs     = atrim_outputs,
+    FILTER_INPUTS(atrim_inputs),
+    FILTER_OUTPUTS(atrim_outputs),
 };
 #endif // CONFIG_ATRIM_FILTER
diff --git a/libavfilter/vaf_spectrumsynth.c b/libavfilter/vaf_spectrumsynth.c
index d44d01cd33..a59170ea02 100644
--- a/libavfilter/vaf_spectrumsynth.c
+++ b/libavfilter/vaf_spectrumsynth.c
@@ -532,7 +532,6 @@ static const AVFilterPad spectrumsynth_inputs[] = {
         .name         = "phase",
         .type         = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 static const AVFilterPad spectrumsynth_outputs[] = {
@@ -541,7 +540,6 @@ static const AVFilterPad spectrumsynth_outputs[] = {
         .type          = AVMEDIA_TYPE_AUDIO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vaf_spectrumsynth = {
@@ -551,7 +549,7 @@ const AVFilter ff_vaf_spectrumsynth = {
     .query_formats = query_formats,
     .activate      = activate,
     .priv_size     = sizeof(SpectrumSynthContext),
-    .inputs        = spectrumsynth_inputs,
-    .outputs       = spectrumsynth_outputs,
+    FILTER_INPUTS(spectrumsynth_inputs),
+    FILTER_OUTPUTS(spectrumsynth_outputs),
     .priv_class    = &spectrumsynth_class,
 };
diff --git a/libavfilter/vf_addroi.c b/libavfilter/vf_addroi.c
index 1d09f31879..5f9ec21754 100644
--- a/libavfilter/vf_addroi.c
+++ b/libavfilter/vf_addroi.c
@@ -244,7 +244,6 @@ static const AVFilterPad addroi_inputs[] = {
         .config_props = addroi_config_input,
         .filter_frame = addroi_filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad addroi_outputs[] = {
@@ -252,7 +251,6 @@ static const AVFilterPad addroi_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_addroi = {
@@ -264,6 +262,6 @@ const AVFilter ff_vf_addroi = {
     .priv_size   = sizeof(AddROIContext),
     .priv_class  = &addroi_class,
 
-    .inputs      = addroi_inputs,
-    .outputs     = addroi_outputs,
+    FILTER_INPUTS(addroi_inputs),
+    FILTER_OUTPUTS(addroi_outputs),
 };
diff --git a/libavfilter/vf_alphamerge.c b/libavfilter/vf_alphamerge.c
index 9b01db6605..8fb601ce06 100644
--- a/libavfilter/vf_alphamerge.c
+++ b/libavfilter/vf_alphamerge.c
@@ -170,7 +170,6 @@ static const AVFilterPad alphamerge_inputs[] = {
         .name             = "alpha",
         .type             = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 static const AVFilterPad alphamerge_outputs[] = {
@@ -179,7 +178,6 @@ static const AVFilterPad alphamerge_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 static const AVOption alphamerge_options[] = {
@@ -197,8 +195,8 @@ const AVFilter ff_vf_alphamerge = {
     .priv_class     = &alphamerge_class,
     .init           = init,
     .query_formats  = query_formats,
-    .inputs         = alphamerge_inputs,
-    .outputs        = alphamerge_outputs,
+    FILTER_INPUTS(alphamerge_inputs),
+    FILTER_OUTPUTS(alphamerge_outputs),
     .uninit         = uninit,
     .activate       = activate,
     .flags          = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
diff --git a/libavfilter/vf_amplify.c b/libavfilter/vf_amplify.c
index c24ce6edc0..713e1560b0 100644
--- a/libavfilter/vf_amplify.c
+++ b/libavfilter/vf_amplify.c
@@ -297,7 +297,6 @@ static const AVFilterPad inputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .filter_frame  = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -306,7 +305,6 @@ static const AVFilterPad outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 AVFILTER_DEFINE_CLASS(amplify);
@@ -317,8 +315,8 @@ const AVFilter ff_vf_amplify = {
     .priv_size     = sizeof(AmplifyContext),
     .priv_class    = &amplify_class,
     .query_formats = query_formats,
-    .outputs       = outputs,
-    .inputs        = inputs,
+    FILTER_OUTPUTS(outputs),
+    FILTER_INPUTS(inputs),
     .init          = init,
     .uninit        = uninit,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | AVFILTER_FLAG_SLICE_THREADS,
diff --git a/libavfilter/vf_aspect.c b/libavfilter/vf_aspect.c
index f0467b5247..995c7f4f14 100644
--- a/libavfilter/vf_aspect.c
+++ b/libavfilter/vf_aspect.c
@@ -173,7 +173,6 @@ static const AVFilterPad avfilter_vf_setdar_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad avfilter_vf_setdar_outputs[] = {
@@ -182,7 +181,6 @@ static const AVFilterPad avfilter_vf_setdar_outputs[] = {
         .type = AVMEDIA_TYPE_VIDEO,
         .config_props = setdar_config_props,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_setdar = {
@@ -190,8 +188,8 @@ const AVFilter ff_vf_setdar = {
     .description = NULL_IF_CONFIG_SMALL("Set the frame display aspect ratio."),
     .priv_size   = sizeof(AspectContext),
     .priv_class  = &setdar_class,
-    .inputs      = avfilter_vf_setdar_inputs,
-    .outputs     = avfilter_vf_setdar_outputs,
+    FILTER_INPUTS(avfilter_vf_setdar_inputs),
+    FILTER_OUTPUTS(avfilter_vf_setdar_outputs),
 };
 
 #endif /* CONFIG_SETDAR_FILTER */
@@ -237,7 +235,6 @@ static const AVFilterPad avfilter_vf_setsar_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad avfilter_vf_setsar_outputs[] = {
@@ -246,7 +243,6 @@ static const AVFilterPad avfilter_vf_setsar_outputs[] = {
         .type = AVMEDIA_TYPE_VIDEO,
         .config_props = setsar_config_props,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_setsar = {
@@ -254,8 +250,8 @@ const AVFilter ff_vf_setsar = {
     .description = NULL_IF_CONFIG_SMALL("Set the pixel sample aspect ratio."),
     .priv_size   = sizeof(AspectContext),
     .priv_class  = &setsar_class,
-    .inputs      = avfilter_vf_setsar_inputs,
-    .outputs     = avfilter_vf_setsar_outputs,
+    FILTER_INPUTS(avfilter_vf_setsar_inputs),
+    FILTER_OUTPUTS(avfilter_vf_setsar_outputs),
 };
 
 #endif /* CONFIG_SETSAR_FILTER */
diff --git a/libavfilter/vf_atadenoise.c b/libavfilter/vf_atadenoise.c
index e39670d982..d21726aa5e 100644
--- a/libavfilter/vf_atadenoise.c
+++ b/libavfilter/vf_atadenoise.c
@@ -557,7 +557,6 @@ static const AVFilterPad inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -566,7 +565,6 @@ static const AVFilterPad outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .request_frame = request_frame,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_atadenoise = {
@@ -577,8 +575,8 @@ const AVFilter ff_vf_atadenoise = {
     .init          = init,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = inputs,
-    .outputs       = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | AVFILTER_FLAG_SLICE_THREADS,
     .process_command = process_command,
 };
diff --git a/libavfilter/vf_avgblur.c b/libavfilter/vf_avgblur.c
index 368452e68f..3e222a43fa 100644
--- a/libavfilter/vf_avgblur.c
+++ b/libavfilter/vf_avgblur.c
@@ -304,7 +304,6 @@ static const AVFilterPad avgblur_inputs[] = {
         .config_props = config_input,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad avgblur_outputs[] = {
@@ -312,7 +311,6 @@ static const AVFilterPad avgblur_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_avgblur = {
@@ -322,8 +320,8 @@ const AVFilter ff_vf_avgblur = {
     .priv_class    = &avgblur_class,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = avgblur_inputs,
-    .outputs       = avgblur_outputs,
+    FILTER_INPUTS(avgblur_inputs),
+    FILTER_OUTPUTS(avgblur_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
     .process_command = ff_filter_process_command,
 };
diff --git a/libavfilter/vf_avgblur_opencl.c b/libavfilter/vf_avgblur_opencl.c
index 3b9e56b879..e9a3bc6100 100644
--- a/libavfilter/vf_avgblur_opencl.c
+++ b/libavfilter/vf_avgblur_opencl.c
@@ -311,7 +311,6 @@ static const AVFilterPad avgblur_opencl_inputs[] = {
         .filter_frame = &avgblur_opencl_filter_frame,
         .config_props = &ff_opencl_filter_config_input,
     },
-    { NULL }
 };
 
 
@@ -321,7 +320,6 @@ static const AVFilterPad avgblur_opencl_outputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = &ff_opencl_filter_config_output,
     },
-    { NULL }
 };
 
 
@@ -348,8 +346,8 @@ const AVFilter ff_vf_avgblur_opencl = {
     .init           = &ff_opencl_filter_init,
     .uninit         = &avgblur_opencl_uninit,
     .query_formats  = &ff_opencl_filter_query_formats,
-    .inputs         = avgblur_opencl_inputs,
-    .outputs        = avgblur_opencl_outputs,
+    FILTER_INPUTS(avgblur_opencl_inputs),
+    FILTER_OUTPUTS(avgblur_opencl_outputs),
     .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
 };
 
@@ -387,8 +385,8 @@ const AVFilter ff_vf_boxblur_opencl = {
     .init           = &ff_opencl_filter_init,
     .uninit         = &avgblur_opencl_uninit,
     .query_formats  = &ff_opencl_filter_query_formats,
-    .inputs         = avgblur_opencl_inputs,
-    .outputs        = avgblur_opencl_outputs,
+    FILTER_INPUTS(avgblur_opencl_inputs),
+    FILTER_OUTPUTS(avgblur_opencl_outputs),
     .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
 };
 
diff --git a/libavfilter/vf_avgblur_vulkan.c b/libavfilter/vf_avgblur_vulkan.c
index 1e485061cd..5ae487fc8c 100644
--- a/libavfilter/vf_avgblur_vulkan.c
+++ b/libavfilter/vf_avgblur_vulkan.c
@@ -386,7 +386,6 @@ static const AVFilterPad avgblur_vulkan_inputs[] = {
         .filter_frame = &avgblur_vulkan_filter_frame,
         .config_props = &ff_vk_filter_config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad avgblur_vulkan_outputs[] = {
@@ -395,7 +394,6 @@ static const AVFilterPad avgblur_vulkan_outputs[] = {
         .type = AVMEDIA_TYPE_VIDEO,
         .config_props = &ff_vk_filter_config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_avgblur_vulkan = {
@@ -405,8 +403,8 @@ const AVFilter ff_vf_avgblur_vulkan = {
     .init           = &ff_vk_filter_init,
     .uninit         = &avgblur_vulkan_uninit,
     .query_formats  = &ff_vk_filter_query_formats,
-    .inputs         = avgblur_vulkan_inputs,
-    .outputs        = avgblur_vulkan_outputs,
+    FILTER_INPUTS(avgblur_vulkan_inputs),
+    FILTER_OUTPUTS(avgblur_vulkan_outputs),
     .priv_class     = &avgblur_vulkan_class,
     .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
 };
diff --git a/libavfilter/vf_bbox.c b/libavfilter/vf_bbox.c
index f6426a5135..9f03db3cfd 100644
--- a/libavfilter/vf_bbox.c
+++ b/libavfilter/vf_bbox.c
@@ -138,7 +138,6 @@ static const AVFilterPad bbox_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad bbox_outputs[] = {
@@ -147,7 +146,6 @@ static const AVFilterPad bbox_outputs[] = {
         .type = AVMEDIA_TYPE_VIDEO,
         .config_props = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_bbox = {
@@ -156,8 +154,8 @@ const AVFilter ff_vf_bbox = {
     .priv_size     = sizeof(BBoxContext),
     .priv_class    = &bbox_class,
     .query_formats = query_formats,
-    .inputs        = bbox_inputs,
-    .outputs       = bbox_outputs,
+    FILTER_INPUTS(bbox_inputs),
+    FILTER_OUTPUTS(bbox_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
     .process_command = ff_filter_process_command,
 };
diff --git a/libavfilter/vf_bilateral.c b/libavfilter/vf_bilateral.c
index 7a160798d4..6d7fa8b30d 100644
--- a/libavfilter/vf_bilateral.c
+++ b/libavfilter/vf_bilateral.c
@@ -368,7 +368,6 @@ static const AVFilterPad bilateral_inputs[] = {
         .config_props = config_input,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad bilateral_outputs[] = {
@@ -376,7 +375,6 @@ static const AVFilterPad bilateral_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_bilateral = {
@@ -386,8 +384,8 @@ const AVFilter ff_vf_bilateral = {
     .priv_class    = &bilateral_class,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = bilateral_inputs,
-    .outputs       = bilateral_outputs,
+    FILTER_INPUTS(bilateral_inputs),
+    FILTER_OUTPUTS(bilateral_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
     .process_command = process_command,
 };
diff --git a/libavfilter/vf_bitplanenoise.c b/libavfilter/vf_bitplanenoise.c
index 71b78f3ea1..d45dd7777f 100644
--- a/libavfilter/vf_bitplanenoise.c
+++ b/libavfilter/vf_bitplanenoise.c
@@ -200,7 +200,6 @@ static const AVFilterPad inputs[] = {
         .filter_frame   = filter_frame,
         .config_props   = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -208,7 +207,6 @@ static const AVFilterPad outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_bitplanenoise = {
@@ -216,8 +214,8 @@ const AVFilter ff_vf_bitplanenoise = {
     .description    = NULL_IF_CONFIG_SMALL("Measure bit plane noise."),
     .priv_size      = sizeof(BPNContext),
     .query_formats  = query_formats,
-    .inputs         = inputs,
-    .outputs        = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
     .priv_class     = &bitplanenoise_class,
     .flags          = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
 };
diff --git a/libavfilter/vf_blackdetect.c b/libavfilter/vf_blackdetect.c
index 99366c669e..b3a03c6e91 100644
--- a/libavfilter/vf_blackdetect.c
+++ b/libavfilter/vf_blackdetect.c
@@ -244,7 +244,6 @@ static const AVFilterPad blackdetect_inputs[] = {
         .config_props  = config_input,
         .filter_frame  = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad blackdetect_outputs[] = {
@@ -252,7 +251,6 @@ static const AVFilterPad blackdetect_outputs[] = {
         .name          = "default",
         .type          = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_blackdetect = {
@@ -260,8 +258,8 @@ const AVFilter ff_vf_blackdetect = {
     .description   = NULL_IF_CONFIG_SMALL("Detect video intervals that are (almost) black."),
     .priv_size     = sizeof(BlackDetectContext),
     .query_formats = query_formats,
-    .inputs        = blackdetect_inputs,
-    .outputs       = blackdetect_outputs,
+    FILTER_INPUTS(blackdetect_inputs),
+    FILTER_OUTPUTS(blackdetect_outputs),
     .uninit        = uninit,
     .priv_class    = &blackdetect_class,
     .flags         = AVFILTER_FLAG_SLICE_THREADS,
diff --git a/libavfilter/vf_blackframe.c b/libavfilter/vf_blackframe.c
index 8856542053..ac7f7347c6 100644
--- a/libavfilter/vf_blackframe.c
+++ b/libavfilter/vf_blackframe.c
@@ -118,7 +118,6 @@ static const AVFilterPad avfilter_vf_blackframe_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad avfilter_vf_blackframe_outputs[] = {
@@ -126,7 +125,6 @@ static const AVFilterPad avfilter_vf_blackframe_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_blackframe = {
@@ -135,6 +133,6 @@ const AVFilter ff_vf_blackframe = {
     .priv_size     = sizeof(BlackFrameContext),
     .priv_class    = &blackframe_class,
     .query_formats = query_formats,
-    .inputs        = avfilter_vf_blackframe_inputs,
-    .outputs       = avfilter_vf_blackframe_outputs,
+    FILTER_INPUTS(avfilter_vf_blackframe_inputs),
+    FILTER_OUTPUTS(avfilter_vf_blackframe_outputs),
 };
diff --git a/libavfilter/vf_blend.c b/libavfilter/vf_blend.c
index 7a64e70862..c968ca8012 100644
--- a/libavfilter/vf_blend.c
+++ b/libavfilter/vf_blend.c
@@ -892,7 +892,6 @@ static const AVFilterPad blend_inputs[] = {
         .name          = "bottom",
         .type          = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 static const AVFilterPad blend_outputs[] = {
@@ -901,7 +900,6 @@ static const AVFilterPad blend_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_blend = {
@@ -913,8 +911,8 @@ const AVFilter ff_vf_blend = {
     .priv_size     = sizeof(BlendContext),
     .query_formats = query_formats,
     .activate      = activate,
-    .inputs        = blend_inputs,
-    .outputs       = blend_outputs,
+    FILTER_INPUTS(blend_inputs),
+    FILTER_OUTPUTS(blend_outputs),
     .priv_class    = &blend_class,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | AVFILTER_FLAG_SLICE_THREADS,
     .process_command = process_command,
@@ -954,7 +952,6 @@ static const AVFilterPad tblend_inputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .filter_frame  = tblend_filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad tblend_outputs[] = {
@@ -963,7 +960,6 @@ static const AVFilterPad tblend_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_tblend = {
@@ -974,8 +970,8 @@ const AVFilter ff_vf_tblend = {
     .query_formats = query_formats,
     .init          = init,
     .uninit        = uninit,
-    .inputs        = tblend_inputs,
-    .outputs       = tblend_outputs,
+    FILTER_INPUTS(tblend_inputs),
+    FILTER_OUTPUTS(tblend_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | AVFILTER_FLAG_SLICE_THREADS,
     .process_command = process_command,
 };
diff --git a/libavfilter/vf_bm3d.c b/libavfilter/vf_bm3d.c
index e07072439a..198fc43268 100644
--- a/libavfilter/vf_bm3d.c
+++ b/libavfilter/vf_bm3d.c
@@ -1048,7 +1048,6 @@ static const AVFilterPad bm3d_outputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_bm3d = {
@@ -1060,7 +1059,7 @@ const AVFilter ff_vf_bm3d = {
     .activate      = activate,
     .query_formats = query_formats,
     .inputs        = NULL,
-    .outputs       = bm3d_outputs,
+    FILTER_OUTPUTS(bm3d_outputs),
     .priv_class    = &bm3d_class,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL |
                      AVFILTER_FLAG_DYNAMIC_INPUTS |
diff --git a/libavfilter/vf_boxblur.c b/libavfilter/vf_boxblur.c
index bebbd4ef08..3ace88e5b6 100644
--- a/libavfilter/vf_boxblur.c
+++ b/libavfilter/vf_boxblur.c
@@ -293,7 +293,6 @@ static const AVFilterPad avfilter_vf_boxblur_inputs[] = {
         .config_props = config_input,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad avfilter_vf_boxblur_outputs[] = {
@@ -301,7 +300,6 @@ static const AVFilterPad avfilter_vf_boxblur_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_boxblur = {
@@ -311,7 +309,7 @@ const AVFilter ff_vf_boxblur = {
     .priv_class    = &boxblur_class,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = avfilter_vf_boxblur_inputs,
-    .outputs       = avfilter_vf_boxblur_outputs,
+    FILTER_INPUTS(avfilter_vf_boxblur_inputs),
+    FILTER_OUTPUTS(avfilter_vf_boxblur_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
 };
diff --git a/libavfilter/vf_bwdif.c b/libavfilter/vf_bwdif.c
index 6b737bba32..7f3fb0034b 100644
--- a/libavfilter/vf_bwdif.c
+++ b/libavfilter/vf_bwdif.c
@@ -392,7 +392,6 @@ static const AVFilterPad avfilter_vf_bwdif_inputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .filter_frame  = ff_yadif_filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad avfilter_vf_bwdif_outputs[] = {
@@ -402,7 +401,6 @@ static const AVFilterPad avfilter_vf_bwdif_outputs[] = {
         .request_frame = ff_yadif_request_frame,
         .config_props  = config_props,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_bwdif = {
@@ -412,7 +410,7 @@ const AVFilter ff_vf_bwdif = {
     .priv_class    = &bwdif_class,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = avfilter_vf_bwdif_inputs,
-    .outputs       = avfilter_vf_bwdif_outputs,
+    FILTER_INPUTS(avfilter_vf_bwdif_inputs),
+    FILTER_OUTPUTS(avfilter_vf_bwdif_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | AVFILTER_FLAG_SLICE_THREADS,
 };
diff --git a/libavfilter/vf_cas.c b/libavfilter/vf_cas.c
index 5424c37bf6..d28932a62b 100644
--- a/libavfilter/vf_cas.c
+++ b/libavfilter/vf_cas.c
@@ -258,7 +258,6 @@ static const AVFilterPad cas_inputs[] = {
         .filter_frame   = filter_frame,
         .config_props   = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad cas_outputs[] = {
@@ -266,7 +265,6 @@ static const AVFilterPad cas_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 #define OFFSET(x) offsetof(CASContext, x)
@@ -286,8 +284,8 @@ const AVFilter ff_vf_cas = {
     .priv_size     = sizeof(CASContext),
     .priv_class    = &cas_class,
     .query_formats = query_formats,
-    .inputs        = cas_inputs,
-    .outputs       = cas_outputs,
+    FILTER_INPUTS(cas_inputs),
+    FILTER_OUTPUTS(cas_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
     .process_command = ff_filter_process_command,
 };
diff --git a/libavfilter/vf_chromaber_vulkan.c b/libavfilter/vf_chromaber_vulkan.c
index 2f5bf7bbb9..96fdd7bd9c 100644
--- a/libavfilter/vf_chromaber_vulkan.c
+++ b/libavfilter/vf_chromaber_vulkan.c
@@ -321,7 +321,6 @@ static const AVFilterPad chromaber_vulkan_inputs[] = {
         .filter_frame = &chromaber_vulkan_filter_frame,
         .config_props = &ff_vk_filter_config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad chromaber_vulkan_outputs[] = {
@@ -330,7 +329,6 @@ static const AVFilterPad chromaber_vulkan_outputs[] = {
         .type = AVMEDIA_TYPE_VIDEO,
         .config_props = &ff_vk_filter_config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_chromaber_vulkan = {
@@ -340,8 +338,8 @@ const AVFilter ff_vf_chromaber_vulkan = {
     .init           = &ff_vk_filter_init,
     .uninit         = &chromaber_vulkan_uninit,
     .query_formats  = &ff_vk_filter_query_formats,
-    .inputs         = chromaber_vulkan_inputs,
-    .outputs        = chromaber_vulkan_outputs,
+    FILTER_INPUTS(chromaber_vulkan_inputs),
+    FILTER_OUTPUTS(chromaber_vulkan_outputs),
     .priv_class     = &chromaber_vulkan_class,
     .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
 };
diff --git a/libavfilter/vf_chromakey.c b/libavfilter/vf_chromakey.c
index 42a494697c..304cb9ee6c 100644
--- a/libavfilter/vf_chromakey.c
+++ b/libavfilter/vf_chromakey.c
@@ -371,7 +371,6 @@ static const AVFilterPad chromakey_inputs[] = {
         .filter_frame   = filter_frame,
         .config_props   = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad chromakey_outputs[] = {
@@ -380,7 +379,6 @@ static const AVFilterPad chromakey_outputs[] = {
         .type           = AVMEDIA_TYPE_VIDEO,
         .config_props   = config_output,
     },
-    { NULL }
 };
 
 #define OFFSET(x) offsetof(ChromakeyContext, x)
@@ -402,8 +400,8 @@ const AVFilter ff_vf_chromakey = {
     .priv_size     = sizeof(ChromakeyContext),
     .priv_class    = &chromakey_class,
     .query_formats = query_formats,
-    .inputs        = chromakey_inputs,
-    .outputs       = chromakey_outputs,
+    FILTER_INPUTS(chromakey_inputs),
+    FILTER_OUTPUTS(chromakey_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
     .process_command = process_command,
 };
@@ -424,7 +422,6 @@ static const AVFilterPad chromahold_inputs[] = {
         .filter_frame   = filter_frame,
         .config_props   = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad chromahold_outputs[] = {
@@ -433,7 +430,6 @@ static const AVFilterPad chromahold_outputs[] = {
         .type           = AVMEDIA_TYPE_VIDEO,
         .config_props   = config_output,
     },
-    { NULL }
 };
 
 AVFILTER_DEFINE_CLASS(chromahold);
@@ -444,8 +440,8 @@ const AVFilter ff_vf_chromahold = {
     .priv_size     = sizeof(ChromakeyContext),
     .priv_class    = &chromahold_class,
     .query_formats = query_formats,
-    .inputs        = chromahold_inputs,
-    .outputs       = chromahold_outputs,
+    FILTER_INPUTS(chromahold_inputs),
+    FILTER_OUTPUTS(chromahold_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
     .process_command = process_command,
 };
diff --git a/libavfilter/vf_chromanr.c b/libavfilter/vf_chromanr.c
index 99d5ed552a..fe9bca1d9d 100644
--- a/libavfilter/vf_chromanr.c
+++ b/libavfilter/vf_chromanr.c
@@ -264,7 +264,6 @@ static const AVFilterPad inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -272,7 +271,6 @@ static const AVFilterPad outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 AVFILTER_DEFINE_CLASS(chromanr);
@@ -283,8 +281,8 @@ const AVFilter ff_vf_chromanr = {
     .priv_size     = sizeof(ChromaNRContext),
     .priv_class    = &chromanr_class,
     .query_formats = query_formats,
-    .outputs       = outputs,
-    .inputs        = inputs,
+    FILTER_OUTPUTS(outputs),
+    FILTER_INPUTS(inputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
     .process_command = ff_filter_process_command,
 };
diff --git a/libavfilter/vf_chromashift.c b/libavfilter/vf_chromashift.c
index b6607a05e4..bcff4144e3 100644
--- a/libavfilter/vf_chromashift.c
+++ b/libavfilter/vf_chromashift.c
@@ -429,7 +429,6 @@ static const AVFilterPad inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -437,7 +436,6 @@ static const AVFilterPad outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 AVFILTER_DEFINE_CLASS(chromashift);
@@ -448,8 +446,8 @@ const AVFilter ff_vf_chromashift = {
     .priv_size     = sizeof(ChromaShiftContext),
     .priv_class    = &chromashift_class,
     .query_formats = query_formats,
-    .outputs       = outputs,
-    .inputs        = inputs,
+    FILTER_OUTPUTS(outputs),
+    FILTER_INPUTS(inputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
     .process_command = process_command,
 };
@@ -477,8 +475,8 @@ const AVFilter ff_vf_rgbashift = {
     .priv_size     = sizeof(ChromaShiftContext),
     .priv_class    = &rgbashift_class,
     .query_formats = query_formats,
-    .outputs       = outputs,
-    .inputs        = inputs,
+    FILTER_OUTPUTS(outputs),
+    FILTER_INPUTS(inputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
     .process_command = process_command,
 };
diff --git a/libavfilter/vf_ciescope.c b/libavfilter/vf_ciescope.c
index cafdb915ea..b09012920c 100644
--- a/libavfilter/vf_ciescope.c
+++ b/libavfilter/vf_ciescope.c
@@ -1492,7 +1492,6 @@ static const AVFilterPad inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -1501,7 +1500,6 @@ static const AVFilterPad outputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_ciescope = {
@@ -1511,6 +1509,6 @@ const AVFilter ff_vf_ciescope = {
     .priv_class    = &ciescope_class,
     .query_formats = query_formats,
     .uninit        = uninit,
-    .inputs        = inputs,
-    .outputs       = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
 };
diff --git a/libavfilter/vf_codecview.c b/libavfilter/vf_codecview.c
index 944d8fb303..dc3d3acd82 100644
--- a/libavfilter/vf_codecview.c
+++ b/libavfilter/vf_codecview.c
@@ -304,7 +304,6 @@ static const AVFilterPad codecview_inputs[] = {
         .filter_frame   = filter_frame,
         .config_props   = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad codecview_outputs[] = {
@@ -312,7 +311,6 @@ static const AVFilterPad codecview_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_codecview = {
@@ -320,8 +318,8 @@ const AVFilter ff_vf_codecview = {
     .description   = NULL_IF_CONFIG_SMALL("Visualize information about some codecs."),
     .priv_size     = sizeof(CodecViewContext),
     .query_formats = query_formats,
-    .inputs        = codecview_inputs,
-    .outputs       = codecview_outputs,
+    FILTER_INPUTS(codecview_inputs),
+    FILTER_OUTPUTS(codecview_outputs),
     .priv_class    = &codecview_class,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
 };
diff --git a/libavfilter/vf_colorbalance.c b/libavfilter/vf_colorbalance.c
index 815cb6e5df..23235347e9 100644
--- a/libavfilter/vf_colorbalance.c
+++ b/libavfilter/vf_colorbalance.c
@@ -425,7 +425,6 @@ static const AVFilterPad colorbalance_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad colorbalance_outputs[] = {
@@ -434,7 +433,6 @@ static const AVFilterPad colorbalance_outputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_colorbalance = {
@@ -443,8 +441,8 @@ const AVFilter ff_vf_colorbalance = {
     .priv_size     = sizeof(ColorBalanceContext),
     .priv_class    = &colorbalance_class,
     .query_formats = query_formats,
-    .inputs        = colorbalance_inputs,
-    .outputs       = colorbalance_outputs,
+    FILTER_INPUTS(colorbalance_inputs),
+    FILTER_OUTPUTS(colorbalance_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
     .process_command = ff_filter_process_command,
 };
diff --git a/libavfilter/vf_colorchannelmixer.c b/libavfilter/vf_colorchannelmixer.c
index fa0609329a..76722523a7 100644
--- a/libavfilter/vf_colorchannelmixer.c
+++ b/libavfilter/vf_colorchannelmixer.c
@@ -785,7 +785,6 @@ static const AVFilterPad colorchannelmixer_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad colorchannelmixer_outputs[] = {
@@ -794,7 +793,6 @@ static const AVFilterPad colorchannelmixer_outputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_colorchannelmixer = {
@@ -804,8 +802,8 @@ const AVFilter ff_vf_colorchannelmixer = {
     .priv_class    = &colorchannelmixer_class,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = colorchannelmixer_inputs,
-    .outputs       = colorchannelmixer_outputs,
+    FILTER_INPUTS(colorchannelmixer_inputs),
+    FILTER_OUTPUTS(colorchannelmixer_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
     .process_command = process_command,
 };
diff --git a/libavfilter/vf_colorconstancy.c b/libavfilter/vf_colorconstancy.c
index eae19c1104..25a17788c3 100644
--- a/libavfilter/vf_colorconstancy.c
+++ b/libavfilter/vf_colorconstancy.c
@@ -726,7 +726,6 @@ static const AVFilterPad colorconstancy_inputs[] = {
         .config_props = config_props,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad colorconstancy_outputs[] = {
@@ -734,7 +733,6 @@ static const AVFilterPad colorconstancy_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 #if CONFIG_GREYEDGE_FILTER
@@ -755,8 +753,8 @@ const AVFilter ff_vf_greyedge = {
     .priv_class    = &greyedge_class,
     .query_formats = query_formats,
     .uninit        = uninit,
-    .inputs        = colorconstancy_inputs,
-    .outputs       = colorconstancy_outputs,
+    FILTER_INPUTS(colorconstancy_inputs),
+    FILTER_OUTPUTS(colorconstancy_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
 };
 
diff --git a/libavfilter/vf_colorcontrast.c b/libavfilter/vf_colorcontrast.c
index 1f4c0db43c..e89b3e7af4 100644
--- a/libavfilter/vf_colorcontrast.c
+++ b/libavfilter/vf_colorcontrast.c
@@ -362,7 +362,6 @@ static const AVFilterPad colorcontrast_inputs[] = {
         .filter_frame   = filter_frame,
         .config_props   = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad colorcontrast_outputs[] = {
@@ -370,7 +369,6 @@ static const AVFilterPad colorcontrast_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 #define OFFSET(x) offsetof(ColorContrastContext, x)
@@ -395,8 +393,8 @@ const AVFilter ff_vf_colorcontrast = {
     .priv_size     = sizeof(ColorContrastContext),
     .priv_class    = &colorcontrast_class,
     .query_formats = query_formats,
-    .inputs        = colorcontrast_inputs,
-    .outputs       = colorcontrast_outputs,
+    FILTER_INPUTS(colorcontrast_inputs),
+    FILTER_OUTPUTS(colorcontrast_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
     .process_command = ff_filter_process_command,
 };
diff --git a/libavfilter/vf_colorcorrect.c b/libavfilter/vf_colorcorrect.c
index e76ed96504..1a8341ebd3 100644
--- a/libavfilter/vf_colorcorrect.c
+++ b/libavfilter/vf_colorcorrect.c
@@ -389,7 +389,6 @@ static const AVFilterPad colorcorrect_inputs[] = {
         .filter_frame   = filter_frame,
         .config_props   = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad colorcorrect_outputs[] = {
@@ -397,7 +396,6 @@ static const AVFilterPad colorcorrect_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 #define OFFSET(x) offsetof(ColorCorrectContext, x)
@@ -425,8 +423,8 @@ const AVFilter ff_vf_colorcorrect = {
     .priv_class    = &colorcorrect_class,
     .query_formats = query_formats,
     .uninit        = uninit,
-    .inputs        = colorcorrect_inputs,
-    .outputs       = colorcorrect_outputs,
+    FILTER_INPUTS(colorcorrect_inputs),
+    FILTER_OUTPUTS(colorcorrect_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
     .process_command = ff_filter_process_command,
 };
diff --git a/libavfilter/vf_colorize.c b/libavfilter/vf_colorize.c
index 14c29d6486..4b57998a22 100644
--- a/libavfilter/vf_colorize.c
+++ b/libavfilter/vf_colorize.c
@@ -263,7 +263,6 @@ static const AVFilterPad colorize_inputs[] = {
         .filter_frame   = filter_frame,
         .config_props   = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad colorize_outputs[] = {
@@ -271,7 +270,6 @@ static const AVFilterPad colorize_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 #define OFFSET(x) offsetof(ColorizeContext, x)
@@ -293,8 +291,8 @@ const AVFilter ff_vf_colorize = {
     .priv_size     = sizeof(ColorizeContext),
     .priv_class    = &colorize_class,
     .query_formats = query_formats,
-    .inputs        = colorize_inputs,
-    .outputs       = colorize_outputs,
+    FILTER_INPUTS(colorize_inputs),
+    FILTER_OUTPUTS(colorize_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
     .process_command = ff_filter_process_command,
 };
diff --git a/libavfilter/vf_colorkey.c b/libavfilter/vf_colorkey.c
index 2ebd470e6e..bef3e37414 100644
--- a/libavfilter/vf_colorkey.c
+++ b/libavfilter/vf_colorkey.c
@@ -179,7 +179,6 @@ static const AVFilterPad colorkey_inputs[] = {
         .flags        = AVFILTERPAD_FLAG_NEEDS_WRITABLE,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad colorkey_outputs[] = {
@@ -188,7 +187,6 @@ static const AVFilterPad colorkey_outputs[] = {
         .type = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 #define OFFSET(x) offsetof(ColorkeyContext, x)
@@ -212,8 +210,8 @@ const AVFilter ff_vf_colorkey = {
     .priv_class    = &colorkey_class,
     .query_formats = query_formats,
     .init          = init_filter,
-    .inputs        = colorkey_inputs,
-    .outputs       = colorkey_outputs,
+    FILTER_INPUTS(colorkey_inputs),
+    FILTER_OUTPUTS(colorkey_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
     .process_command = ff_filter_process_command,
 };
@@ -237,8 +235,8 @@ const AVFilter ff_vf_colorhold = {
     .priv_class    = &colorhold_class,
     .query_formats = query_formats,
     .init          = init_filter,
-    .inputs        = colorkey_inputs,
-    .outputs       = colorkey_outputs,
+    FILTER_INPUTS(colorkey_inputs),
+    FILTER_OUTPUTS(colorkey_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
     .process_command = ff_filter_process_command,
 };
diff --git a/libavfilter/vf_colorkey_opencl.c b/libavfilter/vf_colorkey_opencl.c
index cd312ea53e..f4015cbf21 100644
--- a/libavfilter/vf_colorkey_opencl.c
+++ b/libavfilter/vf_colorkey_opencl.c
@@ -206,7 +206,6 @@ static const AVFilterPad colorkey_opencl_inputs[] = {
         .filter_frame = filter_frame,
         .config_props = &ff_opencl_filter_config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad colorkey_opencl_outputs[] = {
@@ -215,7 +214,6 @@ static const AVFilterPad colorkey_opencl_outputs[] = {
         .type = AVMEDIA_TYPE_VIDEO,
         .config_props = &ff_opencl_filter_config_output,
     },
-    { NULL }
 };
 
 #define OFFSET(x) offsetof(ColorkeyOpenCLContext, x)
@@ -238,7 +236,7 @@ const AVFilter ff_vf_colorkey_opencl = {
     .init           = &ff_opencl_filter_init,
     .uninit         = &colorkey_opencl_uninit,
     .query_formats  = &ff_opencl_filter_query_formats,
-    .inputs         = colorkey_opencl_inputs,
-    .outputs        = colorkey_opencl_outputs,
+    FILTER_INPUTS(colorkey_opencl_inputs),
+    FILTER_OUTPUTS(colorkey_opencl_outputs),
     .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE
 };
diff --git a/libavfilter/vf_colorlevels.c b/libavfilter/vf_colorlevels.c
index 039b79a1a2..418a3037d0 100644
--- a/libavfilter/vf_colorlevels.c
+++ b/libavfilter/vf_colorlevels.c
@@ -301,7 +301,6 @@ static const AVFilterPad colorlevels_inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad colorlevels_outputs[] = {
@@ -309,7 +308,6 @@ static const AVFilterPad colorlevels_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_colorlevels = {
@@ -318,8 +316,8 @@ const AVFilter ff_vf_colorlevels = {
     .priv_size     = sizeof(ColorLevelsContext),
     .priv_class    = &colorlevels_class,
     .query_formats = query_formats,
-    .inputs        = colorlevels_inputs,
-    .outputs       = colorlevels_outputs,
+    FILTER_INPUTS(colorlevels_inputs),
+    FILTER_OUTPUTS(colorlevels_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
     .process_command = ff_filter_process_command,
 };
diff --git a/libavfilter/vf_colormatrix.c b/libavfilter/vf_colormatrix.c
index 8a58c209bb..87bf478398 100644
--- a/libavfilter/vf_colormatrix.c
+++ b/libavfilter/vf_colormatrix.c
@@ -493,7 +493,6 @@ static const AVFilterPad colormatrix_inputs[] = {
         .config_props = config_input,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad colormatrix_outputs[] = {
@@ -501,7 +500,6 @@ static const AVFilterPad colormatrix_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_colormatrix = {
@@ -510,8 +508,8 @@ const AVFilter ff_vf_colormatrix = {
     .priv_size     = sizeof(ColorMatrixContext),
     .init          = init,
     .query_formats = query_formats,
-    .inputs        = colormatrix_inputs,
-    .outputs       = colormatrix_outputs,
+    FILTER_INPUTS(colormatrix_inputs),
+    FILTER_OUTPUTS(colormatrix_outputs),
     .priv_class    = &colormatrix_class,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
 };
diff --git a/libavfilter/vf_colorspace.c b/libavfilter/vf_colorspace.c
index 740e258df0..6b23b27ea5 100644
--- a/libavfilter/vf_colorspace.c
+++ b/libavfilter/vf_colorspace.c
@@ -1057,7 +1057,6 @@ static const AVFilterPad inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -1066,7 +1065,6 @@ static const AVFilterPad outputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_props,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_colorspace = {
@@ -1077,7 +1075,7 @@ const AVFilter ff_vf_colorspace = {
     .query_formats   = query_formats,
     .priv_size       = sizeof(ColorSpaceContext),
     .priv_class      = &colorspace_class,
-    .inputs          = inputs,
-    .outputs         = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
     .flags           = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
 };
diff --git a/libavfilter/vf_colortemperature.c b/libavfilter/vf_colortemperature.c
index 9cf3767925..da2e3bf908 100644
--- a/libavfilter/vf_colortemperature.c
+++ b/libavfilter/vf_colortemperature.c
@@ -328,7 +328,6 @@ static const AVFilterPad inputs[] = {
         .filter_frame   = filter_frame,
         .config_props   = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -336,7 +335,6 @@ static const AVFilterPad outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 #define OFFSET(x) offsetof(ColorTemperatureContext, x)
@@ -357,8 +355,8 @@ const AVFilter ff_vf_colortemperature = {
     .priv_size     = sizeof(ColorTemperatureContext),
     .priv_class    = &colortemperature_class,
     .query_formats = query_formats,
-    .inputs        = inputs,
-    .outputs       = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
     .process_command = ff_filter_process_command,
 };
diff --git a/libavfilter/vf_convolution.c b/libavfilter/vf_convolution.c
index e14dc9990a..5d889affa6 100644
--- a/libavfilter/vf_convolution.c
+++ b/libavfilter/vf_convolution.c
@@ -890,7 +890,6 @@ static const AVFilterPad convolution_inputs[] = {
         .config_props = config_input,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad convolution_outputs[] = {
@@ -898,7 +897,6 @@ static const AVFilterPad convolution_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 #if CONFIG_CONVOLUTION_FILTER
@@ -910,8 +908,8 @@ const AVFilter ff_vf_convolution = {
     .priv_class    = &convolution_class,
     .init          = init,
     .query_formats = query_formats,
-    .inputs        = convolution_inputs,
-    .outputs       = convolution_outputs,
+    FILTER_INPUTS(convolution_inputs),
+    FILTER_OUTPUTS(convolution_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
     .process_command = process_command,
 };
@@ -939,8 +937,8 @@ const AVFilter ff_vf_prewitt = {
     .priv_class    = &prewitt_class,
     .init          = init,
     .query_formats = query_formats,
-    .inputs        = convolution_inputs,
-    .outputs       = convolution_outputs,
+    FILTER_INPUTS(convolution_inputs),
+    FILTER_OUTPUTS(convolution_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
     .process_command = process_command,
 };
@@ -959,8 +957,8 @@ const AVFilter ff_vf_sobel = {
     .priv_class    = &sobel_class,
     .init          = init,
     .query_formats = query_formats,
-    .inputs        = convolution_inputs,
-    .outputs       = convolution_outputs,
+    FILTER_INPUTS(convolution_inputs),
+    FILTER_OUTPUTS(convolution_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
     .process_command = process_command,
 };
@@ -979,8 +977,8 @@ const AVFilter ff_vf_roberts = {
     .priv_class    = &roberts_class,
     .init          = init,
     .query_formats = query_formats,
-    .inputs        = convolution_inputs,
-    .outputs       = convolution_outputs,
+    FILTER_INPUTS(convolution_inputs),
+    FILTER_OUTPUTS(convolution_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
     .process_command = process_command,
 };
@@ -999,8 +997,8 @@ const AVFilter ff_vf_kirsch = {
     .priv_class    = &kirsch_class,
     .init          = init,
     .query_formats = query_formats,
-    .inputs        = convolution_inputs,
-    .outputs       = convolution_outputs,
+    FILTER_INPUTS(convolution_inputs),
+    FILTER_OUTPUTS(convolution_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
     .process_command = process_command,
 };
diff --git a/libavfilter/vf_convolution_opencl.c b/libavfilter/vf_convolution_opencl.c
index c6218d3cd6..6932eff246 100644
--- a/libavfilter/vf_convolution_opencl.c
+++ b/libavfilter/vf_convolution_opencl.c
@@ -327,7 +327,6 @@ static const AVFilterPad convolution_opencl_inputs[] = {
         .filter_frame = &convolution_opencl_filter_frame,
         .config_props = &ff_opencl_filter_config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad convolution_opencl_outputs[] = {
@@ -336,7 +335,6 @@ static const AVFilterPad convolution_opencl_outputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = &ff_opencl_filter_config_output,
     },
-    { NULL }
 };
 
 #define OFFSET(x) offsetof(ConvolutionOpenCLContext, x)
@@ -370,8 +368,8 @@ const AVFilter ff_vf_convolution_opencl = {
     .init           = &ff_opencl_filter_init,
     .uninit         = &convolution_opencl_uninit,
     .query_formats  = &ff_opencl_filter_query_formats,
-    .inputs         = convolution_opencl_inputs,
-    .outputs        = convolution_opencl_outputs,
+    FILTER_INPUTS(convolution_opencl_inputs),
+    FILTER_OUTPUTS(convolution_opencl_outputs),
     .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
 };
 
@@ -396,8 +394,8 @@ const AVFilter ff_vf_sobel_opencl = {
     .init           = &ff_opencl_filter_init,
     .uninit         = &convolution_opencl_uninit,
     .query_formats  = &ff_opencl_filter_query_formats,
-    .inputs         = convolution_opencl_inputs,
-    .outputs        = convolution_opencl_outputs,
+    FILTER_INPUTS(convolution_opencl_inputs),
+    FILTER_OUTPUTS(convolution_opencl_outputs),
     .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
 };
 
@@ -422,8 +420,8 @@ const AVFilter ff_vf_prewitt_opencl = {
     .init           = &ff_opencl_filter_init,
     .uninit         = &convolution_opencl_uninit,
     .query_formats  = &ff_opencl_filter_query_formats,
-    .inputs         = convolution_opencl_inputs,
-    .outputs        = convolution_opencl_outputs,
+    FILTER_INPUTS(convolution_opencl_inputs),
+    FILTER_OUTPUTS(convolution_opencl_outputs),
     .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
 };
 
@@ -448,8 +446,8 @@ const AVFilter ff_vf_roberts_opencl = {
     .init           = &ff_opencl_filter_init,
     .uninit         = &convolution_opencl_uninit,
     .query_formats  = &ff_opencl_filter_query_formats,
-    .inputs         = convolution_opencl_inputs,
-    .outputs        = convolution_opencl_outputs,
+    FILTER_INPUTS(convolution_opencl_inputs),
+    FILTER_OUTPUTS(convolution_opencl_outputs),
     .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
 };
 
diff --git a/libavfilter/vf_convolve.c b/libavfilter/vf_convolve.c
index 4ccffa62cc..ab6d1a271f 100644
--- a/libavfilter/vf_convolve.c
+++ b/libavfilter/vf_convolve.c
@@ -645,7 +645,6 @@ static const AVFilterPad convolve_inputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_input_impulse,
     },
-    { NULL }
 };
 
 static const AVFilterPad convolve_outputs[] = {
@@ -654,7 +653,6 @@ static const AVFilterPad convolve_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 #if CONFIG_CONVOLVE_FILTER
@@ -671,8 +669,8 @@ const AVFilter ff_vf_convolve = {
     .activate      = activate,
     .priv_size     = sizeof(ConvolveContext),
     .priv_class    = &convolve_class,
-    .inputs        = convolve_inputs,
-    .outputs       = convolve_outputs,
+    FILTER_INPUTS(convolve_inputs),
+    FILTER_OUTPUTS(convolve_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | AVFILTER_FLAG_SLICE_THREADS,
 };
 
@@ -701,8 +699,8 @@ const AVFilter ff_vf_deconvolve = {
     .activate      = activate,
     .priv_size     = sizeof(ConvolveContext),
     .priv_class    = &deconvolve_class,
-    .inputs        = convolve_inputs,
-    .outputs       = convolve_outputs,
+    FILTER_INPUTS(convolve_inputs),
+    FILTER_OUTPUTS(convolve_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | AVFILTER_FLAG_SLICE_THREADS,
 };
 
diff --git a/libavfilter/vf_copy.c b/libavfilter/vf_copy.c
index f50ac70c92..16fbe438a1 100644
--- a/libavfilter/vf_copy.c
+++ b/libavfilter/vf_copy.c
@@ -70,7 +70,6 @@ static const AVFilterPad avfilter_vf_copy_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad avfilter_vf_copy_outputs[] = {
@@ -78,13 +77,12 @@ static const AVFilterPad avfilter_vf_copy_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_copy = {
     .name        = "copy",
     .description = NULL_IF_CONFIG_SMALL("Copy the input video unchanged to the output."),
-    .inputs      = avfilter_vf_copy_inputs,
-    .outputs     = avfilter_vf_copy_outputs,
+    FILTER_INPUTS(avfilter_vf_copy_inputs),
+    FILTER_OUTPUTS(avfilter_vf_copy_outputs),
     .query_formats = query_formats,
 };
diff --git a/libavfilter/vf_coreimage.m b/libavfilter/vf_coreimage.m
index 98f6386124..5642d0cd28 100644
--- a/libavfilter/vf_coreimage.m
+++ b/libavfilter/vf_coreimage.m
@@ -608,7 +608,6 @@ static const AVFilterPad vf_coreimage_inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad vf_coreimage_outputs[] = {
@@ -616,7 +615,6 @@ static const AVFilterPad vf_coreimage_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 static const AVFilterPad vsrc_coreimagesrc_outputs[] = {
@@ -626,7 +624,6 @@ static const AVFilterPad vsrc_coreimagesrc_outputs[] = {
         .request_frame = request_frame,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 #define OFFSET(x) offsetof(CoreImageContext, x)
@@ -663,8 +660,8 @@ const AVFilter ff_vf_coreimage = {
     .uninit        = uninit,
     .priv_size     = sizeof(CoreImageContext),
     .priv_class    = &coreimage_class,
-    .inputs        = vf_coreimage_inputs,
-    .outputs       = vf_coreimage_outputs,
+    FILTER_INPUTS(vf_coreimage_inputs),
+    FILTER_OUTPUTS(vf_coreimage_outputs),
     .query_formats = query_formats,
 };
 
@@ -685,6 +682,6 @@ const AVFilter ff_vsrc_coreimagesrc = {
     .priv_size     = sizeof(CoreImageContext),
     .priv_class    = &coreimagesrc_class,
     .inputs        = NULL,
-    .outputs       = vsrc_coreimagesrc_outputs,
+    FILTER_OUTPUTS(vsrc_coreimagesrc_outputs),
     .query_formats = query_formats_src,
 };
diff --git a/libavfilter/vf_cover_rect.c b/libavfilter/vf_cover_rect.c
index a1502073fb..0a8c10e06d 100644
--- a/libavfilter/vf_cover_rect.c
+++ b/libavfilter/vf_cover_rect.c
@@ -236,7 +236,6 @@ static const AVFilterPad cover_rect_inputs[] = {
         .config_props = config_input,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad cover_rect_outputs[] = {
@@ -244,7 +243,6 @@ static const AVFilterPad cover_rect_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_cover_rect = {
@@ -254,7 +252,7 @@ const AVFilter ff_vf_cover_rect = {
     .init            = init,
     .uninit          = uninit,
     .query_formats   = query_formats,
-    .inputs          = cover_rect_inputs,
-    .outputs         = cover_rect_outputs,
+    FILTER_INPUTS(cover_rect_inputs),
+    FILTER_OUTPUTS(cover_rect_outputs),
     .priv_class      = &cover_rect_class,
 };
diff --git a/libavfilter/vf_crop.c b/libavfilter/vf_crop.c
index 9cc9ec2844..76d375cdfc 100644
--- a/libavfilter/vf_crop.c
+++ b/libavfilter/vf_crop.c
@@ -380,7 +380,6 @@ static const AVFilterPad avfilter_vf_crop_inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad avfilter_vf_crop_outputs[] = {
@@ -389,7 +388,6 @@ static const AVFilterPad avfilter_vf_crop_outputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_crop = {
@@ -399,7 +397,7 @@ const AVFilter ff_vf_crop = {
     .priv_class      = &crop_class,
     .query_formats   = query_formats,
     .uninit          = uninit,
-    .inputs          = avfilter_vf_crop_inputs,
-    .outputs         = avfilter_vf_crop_outputs,
+    FILTER_INPUTS(avfilter_vf_crop_inputs),
+    FILTER_OUTPUTS(avfilter_vf_crop_outputs),
     .process_command = process_command,
 };
diff --git a/libavfilter/vf_cropdetect.c b/libavfilter/vf_cropdetect.c
index 97c42a5c35..500ef7fa7f 100644
--- a/libavfilter/vf_cropdetect.c
+++ b/libavfilter/vf_cropdetect.c
@@ -260,7 +260,6 @@ static const AVFilterPad avfilter_vf_cropdetect_inputs[] = {
         .config_props = config_input,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad avfilter_vf_cropdetect_outputs[] = {
@@ -268,7 +267,6 @@ static const AVFilterPad avfilter_vf_cropdetect_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_cropdetect = {
@@ -278,7 +276,7 @@ const AVFilter ff_vf_cropdetect = {
     .priv_class    = &cropdetect_class,
     .init          = init,
     .query_formats = query_formats,
-    .inputs        = avfilter_vf_cropdetect_inputs,
-    .outputs       = avfilter_vf_cropdetect_outputs,
+    FILTER_INPUTS(avfilter_vf_cropdetect_inputs),
+    FILTER_OUTPUTS(avfilter_vf_cropdetect_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
 };
diff --git a/libavfilter/vf_curves.c b/libavfilter/vf_curves.c
index de6f37c73a..570e8bded2 100644
--- a/libavfilter/vf_curves.c
+++ b/libavfilter/vf_curves.c
@@ -800,7 +800,6 @@ static const AVFilterPad curves_inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad curves_outputs[] = {
@@ -808,7 +807,6 @@ static const AVFilterPad curves_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_curves = {
@@ -818,8 +816,8 @@ const AVFilter ff_vf_curves = {
     .init          = curves_init,
     .uninit        = curves_uninit,
     .query_formats = query_formats,
-    .inputs        = curves_inputs,
-    .outputs       = curves_outputs,
+    FILTER_INPUTS(curves_inputs),
+    FILTER_OUTPUTS(curves_outputs),
     .priv_class    = &curves_class,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
     .process_command = process_command,
diff --git a/libavfilter/vf_datascope.c b/libavfilter/vf_datascope.c
index 6a9349d0d8..a60d061d18 100644
--- a/libavfilter/vf_datascope.c
+++ b/libavfilter/vf_datascope.c
@@ -438,7 +438,6 @@ static const AVFilterPad inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -447,7 +446,6 @@ static const AVFilterPad outputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_datascope = {
@@ -456,8 +454,8 @@ const AVFilter ff_vf_datascope = {
     .priv_size     = sizeof(DatascopeContext),
     .priv_class    = &datascope_class,
     .query_formats = query_formats,
-    .inputs        = inputs,
-    .outputs       = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
     .flags         = AVFILTER_FLAG_SLICE_THREADS,
     .process_command = process_command,
 };
@@ -728,7 +726,6 @@ static const AVFilterPad pixscope_inputs[] = {
         .filter_frame   = pixscope_filter_frame,
         .config_props   = pixscope_config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad pixscope_outputs[] = {
@@ -736,7 +733,6 @@ static const AVFilterPad pixscope_outputs[] = {
         .name         = "default",
         .type         = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_pixscope = {
@@ -745,8 +741,8 @@ const AVFilter ff_vf_pixscope = {
     .priv_size     = sizeof(PixscopeContext),
     .priv_class    = &pixscope_class,
     .query_formats = query_formats,
-    .inputs        = pixscope_inputs,
-    .outputs       = pixscope_outputs,
+    FILTER_INPUTS(pixscope_inputs),
+    FILTER_OUTPUTS(pixscope_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
     .process_command = pixscope_process_command,
 };
@@ -1134,7 +1130,6 @@ static const AVFilterPad oscilloscope_inputs[] = {
         .filter_frame   = oscilloscope_filter_frame,
         .config_props   = oscilloscope_config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad oscilloscope_outputs[] = {
@@ -1142,7 +1137,6 @@ static const AVFilterPad oscilloscope_outputs[] = {
         .name         = "default",
         .type         = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_oscilloscope = {
@@ -1152,8 +1146,8 @@ const AVFilter ff_vf_oscilloscope = {
     .priv_class    = &oscilloscope_class,
     .query_formats = query_formats,
     .uninit        = oscilloscope_uninit,
-    .inputs        = oscilloscope_inputs,
-    .outputs       = oscilloscope_outputs,
+    FILTER_INPUTS(oscilloscope_inputs),
+    FILTER_OUTPUTS(oscilloscope_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
     .process_command = oscilloscope_process_command,
 };
diff --git a/libavfilter/vf_dblur.c b/libavfilter/vf_dblur.c
index f3d0ab1141..931c6c689d 100644
--- a/libavfilter/vf_dblur.c
+++ b/libavfilter/vf_dblur.c
@@ -281,7 +281,6 @@ static const AVFilterPad dblur_inputs[] = {
         .config_props = config_input,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad dblur_outputs[] = {
@@ -289,7 +288,6 @@ static const AVFilterPad dblur_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_dblur = {
@@ -299,8 +297,8 @@ const AVFilter ff_vf_dblur = {
     .priv_class    = &dblur_class,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = dblur_inputs,
-    .outputs       = dblur_outputs,
+    FILTER_INPUTS(dblur_inputs),
+    FILTER_OUTPUTS(dblur_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
     .process_command = ff_filter_process_command,
 };
diff --git a/libavfilter/vf_dctdnoiz.c b/libavfilter/vf_dctdnoiz.c
index d1bb7bf96b..3192a2f8ae 100644
--- a/libavfilter/vf_dctdnoiz.c
+++ b/libavfilter/vf_dctdnoiz.c
@@ -811,7 +811,6 @@ static const AVFilterPad dctdnoiz_inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad dctdnoiz_outputs[] = {
@@ -819,7 +818,6 @@ static const AVFilterPad dctdnoiz_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_dctdnoiz = {
@@ -829,8 +827,8 @@ const AVFilter ff_vf_dctdnoiz = {
     .init          = init,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = dctdnoiz_inputs,
-    .outputs       = dctdnoiz_outputs,
+    FILTER_INPUTS(dctdnoiz_inputs),
+    FILTER_OUTPUTS(dctdnoiz_outputs),
     .priv_class    = &dctdnoiz_class,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
 };
diff --git a/libavfilter/vf_deband.c b/libavfilter/vf_deband.c
index d84e41b963..6d9fd2c52b 100644
--- a/libavfilter/vf_deband.c
+++ b/libavfilter/vf_deband.c
@@ -456,7 +456,6 @@ static const AVFilterPad avfilter_vf_deband_inputs[] = {
         .config_props = config_input,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad avfilter_vf_deband_outputs[] = {
@@ -464,7 +463,6 @@ static const AVFilterPad avfilter_vf_deband_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_deband = {
@@ -474,8 +472,8 @@ const AVFilter ff_vf_deband = {
     .priv_class    = &deband_class,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = avfilter_vf_deband_inputs,
-    .outputs       = avfilter_vf_deband_outputs,
+    FILTER_INPUTS(avfilter_vf_deband_inputs),
+    FILTER_OUTPUTS(avfilter_vf_deband_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
     .process_command = process_command,
 };
diff --git a/libavfilter/vf_deblock.c b/libavfilter/vf_deblock.c
index 4069123baf..60f2d206bb 100644
--- a/libavfilter/vf_deblock.c
+++ b/libavfilter/vf_deblock.c
@@ -398,7 +398,6 @@ static const AVFilterPad inputs[] = {
         .type           = AVMEDIA_TYPE_VIDEO,
         .filter_frame   = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -407,7 +406,6 @@ static const AVFilterPad outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 AVFILTER_DEFINE_CLASS(deblock);
@@ -418,8 +416,8 @@ const AVFilter ff_vf_deblock = {
     .priv_size     = sizeof(DeblockContext),
     .priv_class    = &deblock_class,
     .query_formats = query_formats,
-    .inputs        = inputs,
-    .outputs       = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
     .process_command = process_command,
 };
diff --git a/libavfilter/vf_decimate.c b/libavfilter/vf_decimate.c
index f831d9c5a3..cc75aecf81 100644
--- a/libavfilter/vf_decimate.c
+++ b/libavfilter/vf_decimate.c
@@ -428,7 +428,6 @@ static const AVFilterPad decimate_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_decimate = {
@@ -439,7 +438,7 @@ const AVFilter ff_vf_decimate = {
     .uninit        = decimate_uninit,
     .priv_size     = sizeof(DecimateContext),
     .query_formats = query_formats,
-    .outputs       = decimate_outputs,
+    FILTER_OUTPUTS(decimate_outputs),
     .priv_class    = &decimate_class,
     .flags         = AVFILTER_FLAG_DYNAMIC_INPUTS,
 };
diff --git a/libavfilter/vf_dedot.c b/libavfilter/vf_dedot.c
index 8f58c59fe9..a61c08ab02 100644
--- a/libavfilter/vf_dedot.c
+++ b/libavfilter/vf_dedot.c
@@ -384,7 +384,6 @@ static const AVFilterPad inputs[] = {
         .name           = "default",
         .type           = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -393,7 +392,6 @@ static const AVFilterPad outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 AVFILTER_DEFINE_CLASS(dedot);
@@ -406,7 +404,7 @@ const AVFilter ff_vf_dedot = {
     .query_formats = query_formats,
     .activate      = activate,
     .uninit        = uninit,
-    .inputs        = inputs,
-    .outputs       = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | AVFILTER_FLAG_SLICE_THREADS,
 };
diff --git a/libavfilter/vf_deflicker.c b/libavfilter/vf_deflicker.c
index b3a301edaf..c15f8cec33 100644
--- a/libavfilter/vf_deflicker.c
+++ b/libavfilter/vf_deflicker.c
@@ -451,7 +451,6 @@ static const AVFilterPad inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -460,7 +459,6 @@ static const AVFilterPad outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .request_frame = request_frame,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_deflicker = {
@@ -470,6 +468,6 @@ const AVFilter ff_vf_deflicker = {
     .priv_class    = &deflicker_class,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = inputs,
-    .outputs       = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
 };
diff --git a/libavfilter/vf_deinterlace_qsv.c b/libavfilter/vf_deinterlace_qsv.c
index 06c4c5e2df..ea0a9f4345 100644
--- a/libavfilter/vf_deinterlace_qsv.c
+++ b/libavfilter/vf_deinterlace_qsv.c
@@ -576,7 +576,6 @@ static const AVFilterPad qsvdeint_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = qsvdeint_filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad qsvdeint_outputs[] = {
@@ -586,7 +585,6 @@ static const AVFilterPad qsvdeint_outputs[] = {
         .config_props  = qsvdeint_config_props,
         .request_frame = qsvdeint_request_frame,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_deinterlace_qsv = {
@@ -599,8 +597,8 @@ const AVFilter ff_vf_deinterlace_qsv = {
     .priv_size = sizeof(QSVDeintContext),
     .priv_class = &qsvdeint_class,
 
-    .inputs    = qsvdeint_inputs,
-    .outputs   = qsvdeint_outputs,
+    FILTER_INPUTS(qsvdeint_inputs),
+    FILTER_OUTPUTS(qsvdeint_outputs),
 
     .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
 };
diff --git a/libavfilter/vf_deinterlace_vaapi.c b/libavfilter/vf_deinterlace_vaapi.c
index fa71947098..5ec830213e 100644
--- a/libavfilter/vf_deinterlace_vaapi.c
+++ b/libavfilter/vf_deinterlace_vaapi.c
@@ -369,7 +369,6 @@ static const AVFilterPad deint_vaapi_inputs[] = {
         .filter_frame = &deint_vaapi_filter_frame,
         .config_props = &ff_vaapi_vpp_config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad deint_vaapi_outputs[] = {
@@ -378,7 +377,6 @@ static const AVFilterPad deint_vaapi_outputs[] = {
         .type = AVMEDIA_TYPE_VIDEO,
         .config_props = &deint_vaapi_config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_deinterlace_vaapi = {
@@ -388,8 +386,8 @@ const AVFilter ff_vf_deinterlace_vaapi = {
     .init           = &deint_vaapi_init,
     .uninit         = &ff_vaapi_vpp_ctx_uninit,
     .query_formats  = &ff_vaapi_vpp_query_formats,
-    .inputs         = deint_vaapi_inputs,
-    .outputs        = deint_vaapi_outputs,
+    FILTER_INPUTS(deint_vaapi_inputs),
+    FILTER_OUTPUTS(deint_vaapi_outputs),
     .priv_class     = &deint_vaapi_class,
     .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
 };
diff --git a/libavfilter/vf_dejudder.c b/libavfilter/vf_dejudder.c
index 5816f82322..0aa8ab7a1e 100644
--- a/libavfilter/vf_dejudder.c
+++ b/libavfilter/vf_dejudder.c
@@ -163,7 +163,6 @@ static const AVFilterPad dejudder_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad dejudder_outputs[] = {
@@ -172,7 +171,6 @@ static const AVFilterPad dejudder_outputs[] = {
         .type = AVMEDIA_TYPE_VIDEO,
         .config_props = config_out_props,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_dejudder = {
@@ -180,8 +178,8 @@ const AVFilter ff_vf_dejudder = {
     .description = NULL_IF_CONFIG_SMALL("Remove judder produced by pullup."),
     .priv_size   = sizeof(DejudderContext),
     .priv_class  = &dejudder_class,
-    .inputs      = dejudder_inputs,
-    .outputs     = dejudder_outputs,
+    FILTER_INPUTS(dejudder_inputs),
+    FILTER_OUTPUTS(dejudder_outputs),
     .init        = dejudder_init,
     .uninit      = dejudder_uninit,
 };
diff --git a/libavfilter/vf_delogo.c b/libavfilter/vf_delogo.c
index 4d2966e249..f7320aa0fe 100644
--- a/libavfilter/vf_delogo.c
+++ b/libavfilter/vf_delogo.c
@@ -384,7 +384,6 @@ static const AVFilterPad avfilter_vf_delogo_inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad avfilter_vf_delogo_outputs[] = {
@@ -392,7 +391,6 @@ static const AVFilterPad avfilter_vf_delogo_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_delogo = {
@@ -403,7 +401,7 @@ const AVFilter ff_vf_delogo = {
     .init          = init,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = avfilter_vf_delogo_inputs,
-    .outputs       = avfilter_vf_delogo_outputs,
+    FILTER_INPUTS(avfilter_vf_delogo_inputs),
+    FILTER_OUTPUTS(avfilter_vf_delogo_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
 };
diff --git a/libavfilter/vf_derain.c b/libavfilter/vf_derain.c
index a5c003ecdf..720cc70f5c 100644
--- a/libavfilter/vf_derain.c
+++ b/libavfilter/vf_derain.c
@@ -112,7 +112,6 @@ static const AVFilterPad derain_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad derain_outputs[] = {
@@ -120,7 +119,6 @@ static const AVFilterPad derain_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_derain = {
@@ -130,8 +128,8 @@ const AVFilter ff_vf_derain = {
     .init          = init,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = derain_inputs,
-    .outputs       = derain_outputs,
+    FILTER_INPUTS(derain_inputs),
+    FILTER_OUTPUTS(derain_outputs),
     .priv_class    = &derain_class,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
 };
diff --git a/libavfilter/vf_deshake.c b/libavfilter/vf_deshake.c
index 7794eecc8d..4d3d950191 100644
--- a/libavfilter/vf_deshake.c
+++ b/libavfilter/vf_deshake.c
@@ -537,7 +537,6 @@ static const AVFilterPad deshake_inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_props,
     },
-    { NULL }
 };
 
 static const AVFilterPad deshake_outputs[] = {
@@ -545,7 +544,6 @@ static const AVFilterPad deshake_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_deshake = {
@@ -555,7 +553,7 @@ const AVFilter ff_vf_deshake = {
     .init          = init,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = deshake_inputs,
-    .outputs       = deshake_outputs,
+    FILTER_INPUTS(deshake_inputs),
+    FILTER_OUTPUTS(deshake_outputs),
     .priv_class    = &deshake_class,
 };
diff --git a/libavfilter/vf_deshake_opencl.c b/libavfilter/vf_deshake_opencl.c
index 2fd682003f..93c50a410d 100644
--- a/libavfilter/vf_deshake_opencl.c
+++ b/libavfilter/vf_deshake_opencl.c
@@ -2141,7 +2141,6 @@ static const AVFilterPad deshake_opencl_inputs[] = {
         .type = AVMEDIA_TYPE_VIDEO,
         .config_props = &ff_opencl_filter_config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad deshake_opencl_outputs[] = {
@@ -2150,7 +2149,6 @@ static const AVFilterPad deshake_opencl_outputs[] = {
         .type = AVMEDIA_TYPE_VIDEO,
         .config_props = &ff_opencl_filter_config_output,
     },
-    { NULL }
 };
 
 #define OFFSET(x) offsetof(DeshakeOpenCLContext, x)
@@ -2196,7 +2194,7 @@ const AVFilter ff_vf_deshake_opencl = {
     .uninit         = &deshake_opencl_uninit,
     .query_formats  = &ff_opencl_filter_query_formats,
     .activate       = activate,
-    .inputs         = deshake_opencl_inputs,
-    .outputs        = deshake_opencl_outputs,
+    FILTER_INPUTS(deshake_opencl_inputs),
+    FILTER_OUTPUTS(deshake_opencl_outputs),
     .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE
 };
diff --git a/libavfilter/vf_despill.c b/libavfilter/vf_despill.c
index 3d56659149..2c60112b48 100644
--- a/libavfilter/vf_despill.c
+++ b/libavfilter/vf_despill.c
@@ -134,7 +134,6 @@ static const AVFilterPad despill_inputs[] = {
         .flags        = AVFILTERPAD_FLAG_NEEDS_WRITABLE,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad despill_outputs[] = {
@@ -143,7 +142,6 @@ static const AVFilterPad despill_outputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_output,
     },
-    { NULL }
 };
 
 #define OFFSET(x) offsetof(DespillContext, x)
@@ -171,8 +169,8 @@ const AVFilter ff_vf_despill = {
     .priv_size     = sizeof(DespillContext),
     .priv_class    = &despill_class,
     .query_formats = query_formats,
-    .inputs        = despill_inputs,
-    .outputs       = despill_outputs,
+    FILTER_INPUTS(despill_inputs),
+    FILTER_OUTPUTS(despill_outputs),
     .process_command = ff_filter_process_command,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
 };
diff --git a/libavfilter/vf_detelecine.c b/libavfilter/vf_detelecine.c
index e345e3062a..7f34a88217 100644
--- a/libavfilter/vf_detelecine.c
+++ b/libavfilter/vf_detelecine.c
@@ -360,7 +360,6 @@ static const AVFilterPad detelecine_inputs[] = {
         .filter_frame  = filter_frame,
         .config_props  = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad detelecine_outputs[] = {
@@ -369,7 +368,6 @@ static const AVFilterPad detelecine_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_detelecine = {
@@ -380,6 +378,6 @@ const AVFilter ff_vf_detelecine = {
     .init          = init,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = detelecine_inputs,
-    .outputs       = detelecine_outputs,
+    FILTER_INPUTS(detelecine_inputs),
+    FILTER_OUTPUTS(detelecine_outputs),
 };
diff --git a/libavfilter/vf_displace.c b/libavfilter/vf_displace.c
index fcdbadb1c1..0bd35b2516 100644
--- a/libavfilter/vf_displace.c
+++ b/libavfilter/vf_displace.c
@@ -388,7 +388,6 @@ static const AVFilterPad displace_inputs[] = {
         .name         = "ymap",
         .type         = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 static const AVFilterPad displace_outputs[] = {
@@ -397,7 +396,6 @@ static const AVFilterPad displace_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_displace = {
@@ -407,8 +405,8 @@ const AVFilter ff_vf_displace = {
     .uninit        = uninit,
     .query_formats = query_formats,
     .activate      = activate,
-    .inputs        = displace_inputs,
-    .outputs       = displace_outputs,
+    FILTER_INPUTS(displace_inputs),
+    FILTER_OUTPUTS(displace_outputs),
     .priv_class    = &displace_class,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
 };
diff --git a/libavfilter/vf_dnn_classify.c b/libavfilter/vf_dnn_classify.c
index eb8758b265..904067f5f6 100644
--- a/libavfilter/vf_dnn_classify.c
+++ b/libavfilter/vf_dnn_classify.c
@@ -308,7 +308,6 @@ static const AVFilterPad dnn_classify_inputs[] = {
         .name         = "default",
         .type         = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 static const AVFilterPad dnn_classify_outputs[] = {
@@ -316,7 +315,6 @@ static const AVFilterPad dnn_classify_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_dnn_classify = {
@@ -326,8 +324,8 @@ const AVFilter ff_vf_dnn_classify = {
     .init          = dnn_classify_init,
     .uninit        = dnn_classify_uninit,
     .query_formats = dnn_classify_query_formats,
-    .inputs        = dnn_classify_inputs,
-    .outputs       = dnn_classify_outputs,
+    FILTER_INPUTS(dnn_classify_inputs),
+    FILTER_OUTPUTS(dnn_classify_outputs),
     .priv_class    = &dnn_classify_class,
     .activate      = dnn_classify_activate,
 };
diff --git a/libavfilter/vf_dnn_detect.c b/libavfilter/vf_dnn_detect.c
index 629743ae61..200b5897c1 100644
--- a/libavfilter/vf_dnn_detect.c
+++ b/libavfilter/vf_dnn_detect.c
@@ -518,7 +518,6 @@ static const AVFilterPad dnn_detect_inputs[] = {
         .name         = "default",
         .type         = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 static const AVFilterPad dnn_detect_outputs[] = {
@@ -526,7 +525,6 @@ static const AVFilterPad dnn_detect_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_dnn_detect = {
@@ -536,8 +534,8 @@ const AVFilter ff_vf_dnn_detect = {
     .init          = dnn_detect_init,
     .uninit        = dnn_detect_uninit,
     .query_formats = dnn_detect_query_formats,
-    .inputs        = dnn_detect_inputs,
-    .outputs       = dnn_detect_outputs,
+    FILTER_INPUTS(dnn_detect_inputs),
+    FILTER_OUTPUTS(dnn_detect_outputs),
     .priv_class    = &dnn_detect_class,
     .activate      = dnn_detect_activate,
 };
diff --git a/libavfilter/vf_dnn_processing.c b/libavfilter/vf_dnn_processing.c
index 8b7471c8cb..5f24955263 100644
--- a/libavfilter/vf_dnn_processing.c
+++ b/libavfilter/vf_dnn_processing.c
@@ -434,7 +434,6 @@ static const AVFilterPad dnn_processing_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad dnn_processing_outputs[] = {
@@ -443,7 +442,6 @@ static const AVFilterPad dnn_processing_outputs[] = {
         .type = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_dnn_processing = {
@@ -453,8 +451,8 @@ const AVFilter ff_vf_dnn_processing = {
     .init          = init,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = dnn_processing_inputs,
-    .outputs       = dnn_processing_outputs,
+    FILTER_INPUTS(dnn_processing_inputs),
+    FILTER_OUTPUTS(dnn_processing_outputs),
     .priv_class    = &dnn_processing_class,
     .activate      = activate,
 };
diff --git a/libavfilter/vf_drawbox.c b/libavfilter/vf_drawbox.c
index c729ed577a..2d36da89cd 100644
--- a/libavfilter/vf_drawbox.c
+++ b/libavfilter/vf_drawbox.c
@@ -388,7 +388,6 @@ static const AVFilterPad drawbox_inputs[] = {
         .config_props   = config_input,
         .filter_frame   = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad drawbox_outputs[] = {
@@ -396,7 +395,6 @@ static const AVFilterPad drawbox_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_drawbox = {
@@ -406,8 +404,8 @@ const AVFilter ff_vf_drawbox = {
     .priv_class    = &drawbox_class,
     .init          = init,
     .query_formats = query_formats,
-    .inputs        = drawbox_inputs,
-    .outputs       = drawbox_outputs,
+    FILTER_INPUTS(drawbox_inputs),
+    FILTER_OUTPUTS(drawbox_outputs),
     .process_command = process_command,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
 };
@@ -472,7 +470,6 @@ static const AVFilterPad drawgrid_inputs[] = {
         .config_props   = config_input,
         .filter_frame   = drawgrid_filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad drawgrid_outputs[] = {
@@ -480,7 +477,6 @@ static const AVFilterPad drawgrid_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_drawgrid = {
@@ -490,8 +486,8 @@ const AVFilter ff_vf_drawgrid = {
     .priv_class    = &drawgrid_class,
     .init          = init,
     .query_formats = query_formats,
-    .inputs        = drawgrid_inputs,
-    .outputs       = drawgrid_outputs,
+    FILTER_INPUTS(drawgrid_inputs),
+    FILTER_OUTPUTS(drawgrid_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
     .process_command = process_command,
 };
diff --git a/libavfilter/vf_drawtext.c b/libavfilter/vf_drawtext.c
index c274166b9b..b1ea58f30a 100644
--- a/libavfilter/vf_drawtext.c
+++ b/libavfilter/vf_drawtext.c
@@ -1619,7 +1619,6 @@ static const AVFilterPad avfilter_vf_drawtext_inputs[] = {
         .filter_frame   = filter_frame,
         .config_props   = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad avfilter_vf_drawtext_outputs[] = {
@@ -1627,7 +1626,6 @@ static const AVFilterPad avfilter_vf_drawtext_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_drawtext = {
@@ -1638,8 +1636,8 @@ const AVFilter ff_vf_drawtext = {
     .init          = init,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = avfilter_vf_drawtext_inputs,
-    .outputs       = avfilter_vf_drawtext_outputs,
+    FILTER_INPUTS(avfilter_vf_drawtext_inputs),
+    FILTER_OUTPUTS(avfilter_vf_drawtext_outputs),
     .process_command = command,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
 };
diff --git a/libavfilter/vf_edgedetect.c b/libavfilter/vf_edgedetect.c
index e6111b4a27..982ed729cf 100644
--- a/libavfilter/vf_edgedetect.c
+++ b/libavfilter/vf_edgedetect.c
@@ -416,7 +416,6 @@ static const AVFilterPad edgedetect_inputs[] = {
         .config_props = config_props,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad edgedetect_outputs[] = {
@@ -424,7 +423,6 @@ static const AVFilterPad edgedetect_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_edgedetect = {
@@ -434,8 +432,8 @@ const AVFilter ff_vf_edgedetect = {
     .init          = init,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = edgedetect_inputs,
-    .outputs       = edgedetect_outputs,
+    FILTER_INPUTS(edgedetect_inputs),
+    FILTER_OUTPUTS(edgedetect_outputs),
     .priv_class    = &edgedetect_class,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
 };
diff --git a/libavfilter/vf_elbg.c b/libavfilter/vf_elbg.c
index d07b0cf0cb..8f97465f12 100644
--- a/libavfilter/vf_elbg.c
+++ b/libavfilter/vf_elbg.c
@@ -239,7 +239,6 @@ static const AVFilterPad elbg_inputs[] = {
         .config_props   = config_input,
         .filter_frame   = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad elbg_outputs[] = {
@@ -247,7 +246,6 @@ static const AVFilterPad elbg_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_elbg = {
@@ -258,6 +256,6 @@ const AVFilter ff_vf_elbg = {
     .query_formats = query_formats,
     .init          = init,
     .uninit        = uninit,
-    .inputs        = elbg_inputs,
-    .outputs       = elbg_outputs,
+    FILTER_INPUTS(elbg_inputs),
+    FILTER_OUTPUTS(elbg_outputs),
 };
diff --git a/libavfilter/vf_entropy.c b/libavfilter/vf_entropy.c
index 73ece7cbb9..bac962fbd9 100644
--- a/libavfilter/vf_entropy.c
+++ b/libavfilter/vf_entropy.c
@@ -179,7 +179,6 @@ static const AVFilterPad inputs[] = {
         .filter_frame   = filter_frame,
         .config_props   = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -187,7 +186,6 @@ static const AVFilterPad outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_entropy = {
@@ -196,8 +194,8 @@ const AVFilter ff_vf_entropy = {
     .priv_size      = sizeof(EntropyContext),
     .uninit         = uninit,
     .query_formats  = query_formats,
-    .inputs         = inputs,
-    .outputs        = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
     .priv_class     = &entropy_class,
     .flags          = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
 };
diff --git a/libavfilter/vf_epx.c b/libavfilter/vf_epx.c
index 28001fd35d..4adf6d5a32 100644
--- a/libavfilter/vf_epx.c
+++ b/libavfilter/vf_epx.c
@@ -260,7 +260,6 @@ static const AVFilterPad inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -269,14 +268,13 @@ static const AVFilterPad outputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_epx = {
     .name          = "epx",
     .description   = NULL_IF_CONFIG_SMALL("Scale the input using EPX algorithm."),
-    .inputs        = inputs,
-    .outputs       = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
     .query_formats = query_formats,
     .priv_size     = sizeof(EPXContext),
     .priv_class    = &epx_class,
diff --git a/libavfilter/vf_eq.c b/libavfilter/vf_eq.c
index e1953db891..7763601935 100644
--- a/libavfilter/vf_eq.c
+++ b/libavfilter/vf_eq.c
@@ -335,7 +335,6 @@ static const AVFilterPad eq_inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_props,
     },
-    { NULL }
 };
 
 static const AVFilterPad eq_outputs[] = {
@@ -343,7 +342,6 @@ static const AVFilterPad eq_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 #define OFFSET(x) offsetof(EQContext, x)
@@ -379,8 +377,8 @@ const AVFilter ff_vf_eq = {
     .description     = NULL_IF_CONFIG_SMALL("Adjust brightness, contrast, gamma, and saturation."),
     .priv_size       = sizeof(EQContext),
     .priv_class      = &eq_class,
-    .inputs          = eq_inputs,
-    .outputs         = eq_outputs,
+    FILTER_INPUTS(eq_inputs),
+    FILTER_OUTPUTS(eq_outputs),
     .process_command = process_command,
     .query_formats   = query_formats,
     .init            = initialize,
diff --git a/libavfilter/vf_estdif.c b/libavfilter/vf_estdif.c
index a04b4b37db..70e804a3c6 100644
--- a/libavfilter/vf_estdif.c
+++ b/libavfilter/vf_estdif.c
@@ -559,7 +559,6 @@ static const AVFilterPad estdif_inputs[] = {
         .filter_frame  = filter_frame,
         .config_props  = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad estdif_outputs[] = {
@@ -569,7 +568,6 @@ static const AVFilterPad estdif_outputs[] = {
         .config_props  = config_output,
         .request_frame = request_frame,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_estdif = {
@@ -579,8 +577,8 @@ const AVFilter ff_vf_estdif = {
     .priv_class    = &estdif_class,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = estdif_inputs,
-    .outputs       = estdif_outputs,
+    FILTER_INPUTS(estdif_inputs),
+    FILTER_OUTPUTS(estdif_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | AVFILTER_FLAG_SLICE_THREADS,
     .process_command = ff_filter_process_command,
 };
diff --git a/libavfilter/vf_exposure.c b/libavfilter/vf_exposure.c
index b61d90658b..2b6e6f1586 100644
--- a/libavfilter/vf_exposure.c
+++ b/libavfilter/vf_exposure.c
@@ -103,7 +103,6 @@ static const AVFilterPad exposure_inputs[] = {
         .filter_frame   = filter_frame,
         .config_props   = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad exposure_outputs[] = {
@@ -111,7 +110,6 @@ static const AVFilterPad exposure_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 #define OFFSET(x) offsetof(ExposureContext, x)
@@ -131,8 +129,8 @@ const AVFilter ff_vf_exposure = {
     .priv_size     = sizeof(ExposureContext),
     .priv_class    = &exposure_class,
     .query_formats = query_formats,
-    .inputs        = exposure_inputs,
-    .outputs       = exposure_outputs,
+    FILTER_INPUTS(exposure_inputs),
+    FILTER_OUTPUTS(exposure_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
     .process_command = ff_filter_process_command,
 };
diff --git a/libavfilter/vf_extractplanes.c b/libavfilter/vf_extractplanes.c
index fdf525493d..54bfaeae5e 100644
--- a/libavfilter/vf_extractplanes.c
+++ b/libavfilter/vf_extractplanes.c
@@ -376,7 +376,6 @@ static const AVFilterPad extractplanes_inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_extractplanes = {
@@ -387,7 +386,7 @@ const AVFilter ff_vf_extractplanes = {
     .init          = init,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = extractplanes_inputs,
+    FILTER_INPUTS(extractplanes_inputs),
     .outputs       = NULL,
     .flags         = AVFILTER_FLAG_DYNAMIC_OUTPUTS,
 };
@@ -411,7 +410,7 @@ const AVFilter ff_vf_alphaextract = {
     .init           = init_alphaextract,
     .uninit         = uninit,
     .query_formats  = query_formats,
-    .inputs         = extractplanes_inputs,
+    FILTER_INPUTS(extractplanes_inputs),
     .outputs        = NULL,
     .flags          = AVFILTER_FLAG_DYNAMIC_OUTPUTS,
 };
diff --git a/libavfilter/vf_fade.c b/libavfilter/vf_fade.c
index 07bb05478d..71d40c4928 100644
--- a/libavfilter/vf_fade.c
+++ b/libavfilter/vf_fade.c
@@ -555,7 +555,6 @@ static const AVFilterPad avfilter_vf_fade_inputs[] = {
         .config_props   = config_input,
         .filter_frame   = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad avfilter_vf_fade_outputs[] = {
@@ -563,7 +562,6 @@ static const AVFilterPad avfilter_vf_fade_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_fade = {
@@ -573,8 +571,8 @@ const AVFilter ff_vf_fade = {
     .priv_size     = sizeof(FadeContext),
     .priv_class    = &fade_class,
     .query_formats = query_formats,
-    .inputs        = avfilter_vf_fade_inputs,
-    .outputs       = avfilter_vf_fade_outputs,
+    FILTER_INPUTS(avfilter_vf_fade_inputs),
+    FILTER_OUTPUTS(avfilter_vf_fade_outputs),
     .flags         = AVFILTER_FLAG_SLICE_THREADS |
                      AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
 };
diff --git a/libavfilter/vf_fftdnoiz.c b/libavfilter/vf_fftdnoiz.c
index eeb3dd9572..110674d5a1 100644
--- a/libavfilter/vf_fftdnoiz.c
+++ b/libavfilter/vf_fftdnoiz.c
@@ -669,7 +669,6 @@ static const AVFilterPad fftdnoiz_inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad fftdnoiz_outputs[] = {
@@ -678,7 +677,6 @@ static const AVFilterPad fftdnoiz_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .request_frame = request_frame,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_fftdnoiz = {
@@ -688,8 +686,8 @@ const AVFilter ff_vf_fftdnoiz = {
     .init          = init,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = fftdnoiz_inputs,
-    .outputs       = fftdnoiz_outputs,
+    FILTER_INPUTS(fftdnoiz_inputs),
+    FILTER_OUTPUTS(fftdnoiz_outputs),
     .priv_class    = &fftdnoiz_class,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
 };
diff --git a/libavfilter/vf_fftfilt.c b/libavfilter/vf_fftfilt.c
index 541e780ce1..b1b657596d 100644
--- a/libavfilter/vf_fftfilt.c
+++ b/libavfilter/vf_fftfilt.c
@@ -414,7 +414,6 @@ static const AVFilterPad fftfilt_inputs[] = {
         .config_props = config_props,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad fftfilt_outputs[] = {
@@ -422,7 +421,6 @@ static const AVFilterPad fftfilt_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_fftfilt = {
@@ -430,8 +428,8 @@ const AVFilter ff_vf_fftfilt = {
     .description     = NULL_IF_CONFIG_SMALL("Apply arbitrary expressions to pixels in frequency domain."),
     .priv_size       = sizeof(FFTFILTContext),
     .priv_class      = &fftfilt_class,
-    .inputs          = fftfilt_inputs,
-    .outputs         = fftfilt_outputs,
+    FILTER_INPUTS(fftfilt_inputs),
+    FILTER_OUTPUTS(fftfilt_outputs),
     .query_formats   = query_formats,
     .init            = initialize,
     .uninit          = uninit,
diff --git a/libavfilter/vf_field.c b/libavfilter/vf_field.c
index 555e615d2e..8d06ffe663 100644
--- a/libavfilter/vf_field.c
+++ b/libavfilter/vf_field.c
@@ -89,7 +89,6 @@ static const AVFilterPad field_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad field_outputs[] = {
@@ -98,14 +97,13 @@ static const AVFilterPad field_outputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_props_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_field = {
     .name        = "field",
     .description = NULL_IF_CONFIG_SMALL("Extract a field from the input video."),
     .priv_size   = sizeof(FieldContext),
-    .inputs      = field_inputs,
-    .outputs     = field_outputs,
+    FILTER_INPUTS(field_inputs),
+    FILTER_OUTPUTS(field_outputs),
     .priv_class  = &field_class,
 };
diff --git a/libavfilter/vf_fieldhint.c b/libavfilter/vf_fieldhint.c
index a6c0237f02..c6c2a8eebe 100644
--- a/libavfilter/vf_fieldhint.c
+++ b/libavfilter/vf_fieldhint.c
@@ -284,7 +284,6 @@ static const AVFilterPad inputs[] = {
         .config_props = config_input,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -293,7 +292,6 @@ static const AVFilterPad outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .request_frame = request_frame,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_fieldhint = {
@@ -304,6 +302,6 @@ const AVFilter ff_vf_fieldhint = {
     .init          = init,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = inputs,
-    .outputs       = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
 };
diff --git a/libavfilter/vf_fieldmatch.c b/libavfilter/vf_fieldmatch.c
index c2c00fb5b6..ea6e5f3780 100644
--- a/libavfilter/vf_fieldmatch.c
+++ b/libavfilter/vf_fieldmatch.c
@@ -1037,7 +1037,6 @@ static const AVFilterPad fieldmatch_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_fieldmatch = {
@@ -1049,7 +1048,7 @@ const AVFilter ff_vf_fieldmatch = {
     .activate       = activate,
     .uninit         = fieldmatch_uninit,
     .inputs         = NULL,
-    .outputs        = fieldmatch_outputs,
+    FILTER_OUTPUTS(fieldmatch_outputs),
     .priv_class     = &fieldmatch_class,
     .flags          = AVFILTER_FLAG_DYNAMIC_INPUTS,
 };
diff --git a/libavfilter/vf_fieldorder.c b/libavfilter/vf_fieldorder.c
index b521d36f52..d34119c920 100644
--- a/libavfilter/vf_fieldorder.c
+++ b/libavfilter/vf_fieldorder.c
@@ -171,7 +171,6 @@ static const AVFilterPad avfilter_vf_fieldorder_inputs[] = {
         .config_props = config_input,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad avfilter_vf_fieldorder_outputs[] = {
@@ -179,7 +178,6 @@ static const AVFilterPad avfilter_vf_fieldorder_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_fieldorder = {
@@ -188,7 +186,7 @@ const AVFilter ff_vf_fieldorder = {
     .priv_size     = sizeof(FieldOrderContext),
     .priv_class    = &fieldorder_class,
     .query_formats = query_formats,
-    .inputs        = avfilter_vf_fieldorder_inputs,
-    .outputs       = avfilter_vf_fieldorder_outputs,
+    FILTER_INPUTS(avfilter_vf_fieldorder_inputs),
+    FILTER_OUTPUTS(avfilter_vf_fieldorder_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
 };
diff --git a/libavfilter/vf_fillborders.c b/libavfilter/vf_fillborders.c
index 8653611393..4a799422b4 100644
--- a/libavfilter/vf_fillborders.c
+++ b/libavfilter/vf_fillborders.c
@@ -709,7 +709,6 @@ static const AVFilterPad fillborders_inputs[] = {
         .config_props   = config_input,
         .filter_frame   = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad fillborders_outputs[] = {
@@ -717,7 +716,6 @@ static const AVFilterPad fillborders_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_fillborders = {
@@ -726,8 +724,8 @@ const AVFilter ff_vf_fillborders = {
     .priv_size     = sizeof(FillBordersContext),
     .priv_class    = &fillborders_class,
     .query_formats = query_formats,
-    .inputs        = fillborders_inputs,
-    .outputs       = fillborders_outputs,
+    FILTER_INPUTS(fillborders_inputs),
+    FILTER_OUTPUTS(fillborders_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
     .process_command = process_command,
 };
diff --git a/libavfilter/vf_find_rect.c b/libavfilter/vf_find_rect.c
index 5e45d77a03..6c126af721 100644
--- a/libavfilter/vf_find_rect.c
+++ b/libavfilter/vf_find_rect.c
@@ -290,7 +290,6 @@ static const AVFilterPad foc_inputs[] = {
         .config_props = config_input,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad foc_outputs[] = {
@@ -298,7 +297,6 @@ static const AVFilterPad foc_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_find_rect = {
@@ -308,7 +306,7 @@ const AVFilter ff_vf_find_rect = {
     .init            = init,
     .uninit          = uninit,
     .query_formats   = query_formats,
-    .inputs          = foc_inputs,
-    .outputs         = foc_outputs,
+    FILTER_INPUTS(foc_inputs),
+    FILTER_OUTPUTS(foc_outputs),
     .priv_class      = &find_rect_class,
 };
diff --git a/libavfilter/vf_floodfill.c b/libavfilter/vf_floodfill.c
index 28045f1c2e..21741cdb4f 100644
--- a/libavfilter/vf_floodfill.c
+++ b/libavfilter/vf_floodfill.c
@@ -385,7 +385,6 @@ static const AVFilterPad floodfill_inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad floodfill_outputs[] = {
@@ -393,7 +392,6 @@ static const AVFilterPad floodfill_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 #define OFFSET(x) offsetof(FloodfillContext, x)
@@ -422,7 +420,7 @@ const AVFilter ff_vf_floodfill = {
     .priv_class    = &floodfill_class,
     .query_formats = query_formats,
     .uninit        = uninit,
-    .inputs        = floodfill_inputs,
-    .outputs       = floodfill_outputs,
+    FILTER_INPUTS(floodfill_inputs),
+    FILTER_OUTPUTS(floodfill_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
 };
diff --git a/libavfilter/vf_format.c b/libavfilter/vf_format.c
index 0128a94e06..b34675b8e0 100644
--- a/libavfilter/vf_format.c
+++ b/libavfilter/vf_format.c
@@ -151,7 +151,6 @@ static const AVFilterPad avfilter_vf_format_inputs[] = {
         .type             = AVMEDIA_TYPE_VIDEO,
         .get_buffer.video = ff_null_get_video_buffer,
     },
-    { NULL }
 };
 
 static const AVFilterPad avfilter_vf_format_outputs[] = {
@@ -159,7 +158,6 @@ static const AVFilterPad avfilter_vf_format_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_format = {
@@ -174,8 +172,8 @@ const AVFilter ff_vf_format = {
     .priv_size     = sizeof(FormatContext),
     .priv_class    = &format_class,
 
-    .inputs        = avfilter_vf_format_inputs,
-    .outputs       = avfilter_vf_format_outputs,
+    FILTER_INPUTS(avfilter_vf_format_inputs),
+    FILTER_OUTPUTS(avfilter_vf_format_outputs),
 };
 #endif /* CONFIG_FORMAT_FILTER */
 
@@ -190,7 +188,6 @@ static const AVFilterPad avfilter_vf_noformat_inputs[] = {
         .type             = AVMEDIA_TYPE_VIDEO,
         .get_buffer.video = ff_null_get_video_buffer,
     },
-    { NULL }
 };
 
 static const AVFilterPad avfilter_vf_noformat_outputs[] = {
@@ -198,7 +195,6 @@ static const AVFilterPad avfilter_vf_noformat_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_noformat = {
@@ -213,7 +209,7 @@ const AVFilter ff_vf_noformat = {
     .priv_size     = sizeof(FormatContext),
     .priv_class    = &noformat_class,
 
-    .inputs        = avfilter_vf_noformat_inputs,
-    .outputs       = avfilter_vf_noformat_outputs,
+    FILTER_INPUTS(avfilter_vf_noformat_inputs),
+    FILTER_OUTPUTS(avfilter_vf_noformat_outputs),
 };
 #endif /* CONFIG_NOFORMAT_FILTER */
diff --git a/libavfilter/vf_fps.c b/libavfilter/vf_fps.c
index fbc845da1b..b8714727fa 100644
--- a/libavfilter/vf_fps.c
+++ b/libavfilter/vf_fps.c
@@ -370,7 +370,6 @@ static const AVFilterPad avfilter_vf_fps_inputs[] = {
         .name         = "default",
         .type         = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 static const AVFilterPad avfilter_vf_fps_outputs[] = {
@@ -379,7 +378,6 @@ static const AVFilterPad avfilter_vf_fps_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_props,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_fps = {
@@ -390,6 +388,6 @@ const AVFilter ff_vf_fps = {
     .priv_size   = sizeof(FPSContext),
     .priv_class  = &fps_class,
     .activate    = activate,
-    .inputs      = avfilter_vf_fps_inputs,
-    .outputs     = avfilter_vf_fps_outputs,
+    FILTER_INPUTS(avfilter_vf_fps_inputs),
+    FILTER_OUTPUTS(avfilter_vf_fps_outputs),
 };
diff --git a/libavfilter/vf_framepack.c b/libavfilter/vf_framepack.c
index 2bf6ed538a..73c973036a 100644
--- a/libavfilter/vf_framepack.c
+++ b/libavfilter/vf_framepack.c
@@ -454,7 +454,6 @@ static const AVFilterPad framepack_inputs[] = {
         .name         = "right",
         .type         = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 static const AVFilterPad framepack_outputs[] = {
@@ -463,7 +462,6 @@ static const AVFilterPad framepack_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_framepack = {
@@ -472,8 +470,8 @@ const AVFilter ff_vf_framepack = {
     .priv_size     = sizeof(FramepackContext),
     .priv_class    = &framepack_class,
     .query_formats = query_formats,
-    .inputs        = framepack_inputs,
-    .outputs       = framepack_outputs,
+    FILTER_INPUTS(framepack_inputs),
+    FILTER_OUTPUTS(framepack_outputs),
     .activate      = activate,
     .uninit        = framepack_uninit,
 };
diff --git a/libavfilter/vf_framerate.c b/libavfilter/vf_framerate.c
index 440cfecc71..0f9994e1ac 100644
--- a/libavfilter/vf_framerate.c
+++ b/libavfilter/vf_framerate.c
@@ -427,7 +427,6 @@ static const AVFilterPad framerate_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad framerate_outputs[] = {
@@ -436,7 +435,6 @@ static const AVFilterPad framerate_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_framerate = {
@@ -447,8 +445,8 @@ const AVFilter ff_vf_framerate = {
     .init          = init,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = framerate_inputs,
-    .outputs       = framerate_outputs,
+    FILTER_INPUTS(framerate_inputs),
+    FILTER_OUTPUTS(framerate_outputs),
     .flags         = AVFILTER_FLAG_SLICE_THREADS,
     .activate      = activate,
 };
diff --git a/libavfilter/vf_framestep.c b/libavfilter/vf_framestep.c
index d61ce0dc56..5509df53e9 100644
--- a/libavfilter/vf_framestep.c
+++ b/libavfilter/vf_framestep.c
@@ -77,7 +77,6 @@ static const AVFilterPad framestep_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad framestep_outputs[] = {
@@ -86,7 +85,6 @@ static const AVFilterPad framestep_outputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_output_props,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_framestep = {
@@ -94,7 +92,7 @@ const AVFilter ff_vf_framestep = {
     .description = NULL_IF_CONFIG_SMALL("Select one frame every N frames."),
     .priv_size   = sizeof(FrameStepContext),
     .priv_class  = &framestep_class,
-    .inputs      = framestep_inputs,
-    .outputs     = framestep_outputs,
+    FILTER_INPUTS(framestep_inputs),
+    FILTER_OUTPUTS(framestep_outputs),
     .flags       = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
 };
diff --git a/libavfilter/vf_freezedetect.c b/libavfilter/vf_freezedetect.c
index 39d712d21e..152ffdbe30 100644
--- a/libavfilter/vf_freezedetect.c
+++ b/libavfilter/vf_freezedetect.c
@@ -207,7 +207,6 @@ static const AVFilterPad freezedetect_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad freezedetect_outputs[] = {
@@ -215,7 +214,6 @@ static const AVFilterPad freezedetect_outputs[] = {
         .name          = "default",
         .type          = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_freezedetect = {
@@ -225,7 +223,7 @@ const AVFilter ff_vf_freezedetect = {
     .priv_class    = &freezedetect_class,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = freezedetect_inputs,
-    .outputs       = freezedetect_outputs,
+    FILTER_INPUTS(freezedetect_inputs),
+    FILTER_OUTPUTS(freezedetect_outputs),
     .activate      = activate,
 };
diff --git a/libavfilter/vf_freezeframes.c b/libavfilter/vf_freezeframes.c
index e29eb07cec..a272336ff2 100644
--- a/libavfilter/vf_freezeframes.c
+++ b/libavfilter/vf_freezeframes.c
@@ -142,7 +142,6 @@ static const AVFilterPad freezeframes_inputs[] = {
         .name = "replace",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL },
 };
 
 static const AVFilterPad freezeframes_outputs[] = {
@@ -151,7 +150,6 @@ static const AVFilterPad freezeframes_outputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_output,
     },
-    { NULL },
 };
 
 const AVFilter ff_vf_freezeframes = {
@@ -159,8 +157,8 @@ const AVFilter ff_vf_freezeframes = {
     .description   = NULL_IF_CONFIG_SMALL("Freeze video frames."),
     .priv_size     = sizeof(FreezeFramesContext),
     .priv_class    = &freezeframes_class,
-    .inputs        = freezeframes_inputs,
-    .outputs       = freezeframes_outputs,
+    FILTER_INPUTS(freezeframes_inputs),
+    FILTER_OUTPUTS(freezeframes_outputs),
     .activate      = activate,
     .uninit        = uninit,
 };
diff --git a/libavfilter/vf_frei0r.c b/libavfilter/vf_frei0r.c
index 00e5ff2444..65191e1932 100644
--- a/libavfilter/vf_frei0r.c
+++ b/libavfilter/vf_frei0r.c
@@ -402,7 +402,6 @@ static const AVFilterPad avfilter_vf_frei0r_inputs[] = {
         .config_props = config_input_props,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad avfilter_vf_frei0r_outputs[] = {
@@ -410,7 +409,6 @@ static const AVFilterPad avfilter_vf_frei0r_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_frei0r = {
@@ -421,8 +419,8 @@ const AVFilter ff_vf_frei0r = {
     .uninit        = uninit,
     .priv_size     = sizeof(Frei0rContext),
     .priv_class    = &frei0r_class,
-    .inputs        = avfilter_vf_frei0r_inputs,
-    .outputs       = avfilter_vf_frei0r_outputs,
+    FILTER_INPUTS(avfilter_vf_frei0r_inputs),
+    FILTER_OUTPUTS(avfilter_vf_frei0r_outputs),
     .process_command = process_command,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
 };
@@ -498,7 +496,6 @@ static const AVFilterPad avfilter_vsrc_frei0r_src_outputs[] = {
         .request_frame = source_request_frame,
         .config_props  = source_config_props
     },
-    { NULL }
 };
 
 const AVFilter ff_vsrc_frei0r_src = {
@@ -510,5 +507,5 @@ const AVFilter ff_vsrc_frei0r_src = {
     .uninit        = uninit,
     .query_formats = query_formats,
     .inputs        = NULL,
-    .outputs       = avfilter_vsrc_frei0r_src_outputs,
+    FILTER_OUTPUTS(avfilter_vsrc_frei0r_src_outputs),
 };
diff --git a/libavfilter/vf_fspp.c b/libavfilter/vf_fspp.c
index 88b13d638f..238dbcb429 100644
--- a/libavfilter/vf_fspp.c
+++ b/libavfilter/vf_fspp.c
@@ -653,7 +653,6 @@ static const AVFilterPad fspp_inputs[] = {
         .config_props = config_input,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad fspp_outputs[] = {
@@ -661,7 +660,6 @@ static const AVFilterPad fspp_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_fspp = {
@@ -670,8 +668,8 @@ const AVFilter ff_vf_fspp = {
     .priv_size       = sizeof(FSPPContext),
     .uninit          = uninit,
     .query_formats   = query_formats,
-    .inputs          = fspp_inputs,
-    .outputs         = fspp_outputs,
+    FILTER_INPUTS(fspp_inputs),
+    FILTER_OUTPUTS(fspp_outputs),
     .priv_class      = &fspp_class,
     .flags           = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
 };
diff --git a/libavfilter/vf_gblur.c b/libavfilter/vf_gblur.c
index 91b9ea8889..4780bb6204 100644
--- a/libavfilter/vf_gblur.c
+++ b/libavfilter/vf_gblur.c
@@ -385,7 +385,6 @@ static const AVFilterPad gblur_inputs[] = {
         .config_props = config_input,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad gblur_outputs[] = {
@@ -393,7 +392,6 @@ static const AVFilterPad gblur_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_gblur = {
@@ -403,8 +401,8 @@ const AVFilter ff_vf_gblur = {
     .priv_class    = &gblur_class,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = gblur_inputs,
-    .outputs       = gblur_outputs,
+    FILTER_INPUTS(gblur_inputs),
+    FILTER_OUTPUTS(gblur_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
     .process_command = ff_filter_process_command,
 };
diff --git a/libavfilter/vf_geq.c b/libavfilter/vf_geq.c
index 75f374df3d..4a78336540 100644
--- a/libavfilter/vf_geq.c
+++ b/libavfilter/vf_geq.c
@@ -476,7 +476,6 @@ static const AVFilterPad geq_inputs[] = {
         .config_props = geq_config_props,
         .filter_frame = geq_filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad geq_outputs[] = {
@@ -484,7 +483,6 @@ static const AVFilterPad geq_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_geq = {
@@ -494,8 +492,8 @@ const AVFilter ff_vf_geq = {
     .init          = geq_init,
     .uninit        = geq_uninit,
     .query_formats = geq_query_formats,
-    .inputs        = geq_inputs,
-    .outputs       = geq_outputs,
+    FILTER_INPUTS(geq_inputs),
+    FILTER_OUTPUTS(geq_outputs),
     .priv_class    = &geq_class,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
 };
diff --git a/libavfilter/vf_gradfun.c b/libavfilter/vf_gradfun.c
index f1cf9a3a06..6171e75a28 100644
--- a/libavfilter/vf_gradfun.c
+++ b/libavfilter/vf_gradfun.c
@@ -237,7 +237,6 @@ static const AVFilterPad avfilter_vf_gradfun_inputs[] = {
         .config_props = config_input,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad avfilter_vf_gradfun_outputs[] = {
@@ -245,7 +244,6 @@ static const AVFilterPad avfilter_vf_gradfun_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_gradfun = {
@@ -256,7 +254,7 @@ const AVFilter ff_vf_gradfun = {
     .init          = init,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = avfilter_vf_gradfun_inputs,
-    .outputs       = avfilter_vf_gradfun_outputs,
+    FILTER_INPUTS(avfilter_vf_gradfun_inputs),
+    FILTER_OUTPUTS(avfilter_vf_gradfun_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
 };
diff --git a/libavfilter/vf_guided.c b/libavfilter/vf_guided.c
index b96b926e57..f808ba1043 100644
--- a/libavfilter/vf_guided.c
+++ b/libavfilter/vf_guided.c
@@ -486,7 +486,6 @@ static const AVFilterPad guided_outputs[] = {
         .type = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_guided = {
@@ -499,7 +498,7 @@ const AVFilter ff_vf_guided = {
     .priv_class      = &guided_class,
     .activate        = activate,
     .inputs          = NULL,
-    .outputs         = guided_outputs,
+    FILTER_OUTPUTS(guided_outputs),
     .flags           = AVFILTER_FLAG_DYNAMIC_INPUTS | AVFILTER_FLAG_SLICE_THREADS |
                        AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
     .process_command = process_command,
diff --git a/libavfilter/vf_hflip.c b/libavfilter/vf_hflip.c
index 390c3a1553..7b5650a821 100644
--- a/libavfilter/vf_hflip.c
+++ b/libavfilter/vf_hflip.c
@@ -235,7 +235,6 @@ static const AVFilterPad avfilter_vf_hflip_inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_props,
     },
-    { NULL }
 };
 
 static const AVFilterPad avfilter_vf_hflip_outputs[] = {
@@ -243,7 +242,6 @@ static const AVFilterPad avfilter_vf_hflip_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_hflip = {
@@ -252,7 +250,7 @@ const AVFilter ff_vf_hflip = {
     .priv_size     = sizeof(FlipContext),
     .priv_class    = &hflip_class,
     .query_formats = query_formats,
-    .inputs        = avfilter_vf_hflip_inputs,
-    .outputs       = avfilter_vf_hflip_outputs,
+    FILTER_INPUTS(avfilter_vf_hflip_inputs),
+    FILTER_OUTPUTS(avfilter_vf_hflip_outputs),
     .flags         = AVFILTER_FLAG_SLICE_THREADS | AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
 };
diff --git a/libavfilter/vf_histeq.c b/libavfilter/vf_histeq.c
index dc17afe30d..d37dc07389 100644
--- a/libavfilter/vf_histeq.c
+++ b/libavfilter/vf_histeq.c
@@ -256,7 +256,6 @@ static const AVFilterPad histeq_inputs[] = {
         .config_props = config_input,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad histeq_outputs[] = {
@@ -264,7 +263,6 @@ static const AVFilterPad histeq_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_histeq = {
@@ -273,8 +271,8 @@ const AVFilter ff_vf_histeq = {
     .priv_size     = sizeof(HisteqContext),
     .init          = init,
     .query_formats = query_formats,
-    .inputs        = histeq_inputs,
-    .outputs       = histeq_outputs,
+    FILTER_INPUTS(histeq_inputs),
+    FILTER_OUTPUTS(histeq_outputs),
     .priv_class    = &histeq_class,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
 };
diff --git a/libavfilter/vf_histogram.c b/libavfilter/vf_histogram.c
index bd9408c42d..ff79d2130c 100644
--- a/libavfilter/vf_histogram.c
+++ b/libavfilter/vf_histogram.c
@@ -488,7 +488,6 @@ static const AVFilterPad inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -497,7 +496,6 @@ static const AVFilterPad outputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_output,
     },
-    { NULL }
 };
 
 #if CONFIG_HISTOGRAM_FILTER
@@ -507,8 +505,8 @@ const AVFilter ff_vf_histogram = {
     .description   = NULL_IF_CONFIG_SMALL("Compute and draw a histogram."),
     .priv_size     = sizeof(HistogramContext),
     .query_formats = query_formats,
-    .inputs        = inputs,
-    .outputs       = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
     .priv_class    = &histogram_class,
 };
 
@@ -549,8 +547,8 @@ const AVFilter ff_vf_thistogram = {
     .description   = NULL_IF_CONFIG_SMALL("Compute and draw a temporal histogram."),
     .priv_size     = sizeof(HistogramContext),
     .query_formats = query_formats,
-    .inputs        = inputs,
-    .outputs       = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
     .uninit        = uninit,
     .priv_class    = &thistogram_class,
 };
diff --git a/libavfilter/vf_hqdn3d.c b/libavfilter/vf_hqdn3d.c
index 885ae02f74..f11fc46ae5 100644
--- a/libavfilter/vf_hqdn3d.c
+++ b/libavfilter/vf_hqdn3d.c
@@ -383,7 +383,6 @@ static const AVFilterPad avfilter_vf_hqdn3d_inputs[] = {
         .config_props = config_input,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 
@@ -392,7 +391,6 @@ static const AVFilterPad avfilter_vf_hqdn3d_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_hqdn3d = {
@@ -403,8 +401,8 @@ const AVFilter ff_vf_hqdn3d = {
     .init          = init,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = avfilter_vf_hqdn3d_inputs,
-    .outputs       = avfilter_vf_hqdn3d_outputs,
+    FILTER_INPUTS(avfilter_vf_hqdn3d_inputs),
+    FILTER_OUTPUTS(avfilter_vf_hqdn3d_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | AVFILTER_FLAG_SLICE_THREADS,
     .process_command = process_command,
 };
diff --git a/libavfilter/vf_hqx.c b/libavfilter/vf_hqx.c
index 4e7c7c6c05..8adb1524b0 100644
--- a/libavfilter/vf_hqx.c
+++ b/libavfilter/vf_hqx.c
@@ -539,7 +539,6 @@ static const AVFilterPad hqx_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad hqx_outputs[] = {
@@ -548,7 +547,6 @@ static const AVFilterPad hqx_outputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_hqx = {
@@ -557,8 +555,8 @@ const AVFilter ff_vf_hqx = {
     .priv_size     = sizeof(HQXContext),
     .init          = init,
     .query_formats = query_formats,
-    .inputs        = hqx_inputs,
-    .outputs       = hqx_outputs,
+    FILTER_INPUTS(hqx_inputs),
+    FILTER_OUTPUTS(hqx_outputs),
     .priv_class    = &hqx_class,
     .flags         = AVFILTER_FLAG_SLICE_THREADS,
 };
diff --git a/libavfilter/vf_hue.c b/libavfilter/vf_hue.c
index 3df27d985c..c35722eb4b 100644
--- a/libavfilter/vf_hue.c
+++ b/libavfilter/vf_hue.c
@@ -502,7 +502,6 @@ static const AVFilterPad hue_inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_props,
     },
-    { NULL }
 };
 
 static const AVFilterPad hue_outputs[] = {
@@ -510,7 +509,6 @@ static const AVFilterPad hue_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_hue = {
@@ -521,8 +519,8 @@ const AVFilter ff_vf_hue = {
     .uninit          = uninit,
     .query_formats   = query_formats,
     .process_command = process_command,
-    .inputs          = hue_inputs,
-    .outputs         = hue_outputs,
+    FILTER_INPUTS(hue_inputs),
+    FILTER_OUTPUTS(hue_outputs),
     .priv_class      = &hue_class,
     .flags           = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
 };
diff --git a/libavfilter/vf_hwdownload.c b/libavfilter/vf_hwdownload.c
index 4a8fed0688..f00f105f84 100644
--- a/libavfilter/vf_hwdownload.c
+++ b/libavfilter/vf_hwdownload.c
@@ -180,7 +180,6 @@ static const AVFilterPad hwdownload_inputs[] = {
         .config_props = hwdownload_config_input,
         .filter_frame = hwdownload_filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad hwdownload_outputs[] = {
@@ -189,7 +188,6 @@ static const AVFilterPad hwdownload_outputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = hwdownload_config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_hwdownload = {
@@ -199,7 +197,7 @@ const AVFilter ff_vf_hwdownload = {
     .query_formats = hwdownload_query_formats,
     .priv_size     = sizeof(HWDownloadContext),
     .priv_class    = &hwdownload_class,
-    .inputs        = hwdownload_inputs,
-    .outputs       = hwdownload_outputs,
+    FILTER_INPUTS(hwdownload_inputs),
+    FILTER_OUTPUTS(hwdownload_outputs),
     .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
 };
diff --git a/libavfilter/vf_hwmap.c b/libavfilter/vf_hwmap.c
index 2bcce15f6a..be29261223 100644
--- a/libavfilter/vf_hwmap.c
+++ b/libavfilter/vf_hwmap.c
@@ -407,7 +407,6 @@ static const AVFilterPad hwmap_inputs[] = {
         .get_buffer.video = hwmap_get_buffer,
         .filter_frame     = hwmap_filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad hwmap_outputs[] = {
@@ -416,7 +415,6 @@ static const AVFilterPad hwmap_outputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = hwmap_config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_hwmap = {
@@ -426,7 +424,7 @@ const AVFilter ff_vf_hwmap = {
     .priv_size      = sizeof(HWMapContext),
     .priv_class     = &hwmap_class,
     .query_formats  = hwmap_query_formats,
-    .inputs         = hwmap_inputs,
-    .outputs        = hwmap_outputs,
+    FILTER_INPUTS(hwmap_inputs),
+    FILTER_OUTPUTS(hwmap_outputs),
     .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
 };
diff --git a/libavfilter/vf_hwupload.c b/libavfilter/vf_hwupload.c
index 8263829a39..4cbc621af3 100644
--- a/libavfilter/vf_hwupload.c
+++ b/libavfilter/vf_hwupload.c
@@ -238,7 +238,6 @@ static const AVFilterPad hwupload_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = hwupload_filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad hwupload_outputs[] = {
@@ -247,7 +246,6 @@ static const AVFilterPad hwupload_outputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = hwupload_config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_hwupload = {
@@ -257,7 +255,7 @@ const AVFilter ff_vf_hwupload = {
     .query_formats = hwupload_query_formats,
     .priv_size     = sizeof(HWUploadContext),
     .priv_class    = &hwupload_class,
-    .inputs        = hwupload_inputs,
-    .outputs       = hwupload_outputs,
+    FILTER_INPUTS(hwupload_inputs),
+    FILTER_OUTPUTS(hwupload_outputs),
     .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
 };
diff --git a/libavfilter/vf_hwupload_cuda.c b/libavfilter/vf_hwupload_cuda.c
index 138949a5ed..31c1cdbddb 100644
--- a/libavfilter/vf_hwupload_cuda.c
+++ b/libavfilter/vf_hwupload_cuda.c
@@ -171,7 +171,6 @@ static const AVFilterPad cudaupload_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = cudaupload_filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad cudaupload_outputs[] = {
@@ -180,7 +179,6 @@ static const AVFilterPad cudaupload_outputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = cudaupload_config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_hwupload_cuda = {
@@ -195,8 +193,8 @@ const AVFilter ff_vf_hwupload_cuda = {
     .priv_size  = sizeof(CudaUploadContext),
     .priv_class = &cudaupload_class,
 
-    .inputs    = cudaupload_inputs,
-    .outputs   = cudaupload_outputs,
+    FILTER_INPUTS(cudaupload_inputs),
+    FILTER_OUTPUTS(cudaupload_outputs),
 
     .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
 };
diff --git a/libavfilter/vf_hysteresis.c b/libavfilter/vf_hysteresis.c
index 12025f9eb6..cbbee2691b 100644
--- a/libavfilter/vf_hysteresis.c
+++ b/libavfilter/vf_hysteresis.c
@@ -362,7 +362,6 @@ static const AVFilterPad hysteresis_inputs[] = {
         .name         = "alt",
         .type         = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 static const AVFilterPad hysteresis_outputs[] = {
@@ -371,7 +370,6 @@ static const AVFilterPad hysteresis_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_hysteresis = {
@@ -382,8 +380,8 @@ const AVFilter ff_vf_hysteresis = {
     .uninit        = uninit,
     .query_formats = query_formats,
     .activate      = activate,
-    .inputs        = hysteresis_inputs,
-    .outputs       = hysteresis_outputs,
+    FILTER_INPUTS(hysteresis_inputs),
+    FILTER_OUTPUTS(hysteresis_outputs),
     .priv_class    = &hysteresis_class,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
 };
diff --git a/libavfilter/vf_identity.c b/libavfilter/vf_identity.c
index 5481222114..fd72137344 100644
--- a/libavfilter/vf_identity.c
+++ b/libavfilter/vf_identity.c
@@ -390,7 +390,6 @@ static const AVFilterPad identity_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_input_ref,
     },
-    { NULL }
 };
 
 static const AVFilterPad identity_outputs[] = {
@@ -399,7 +398,6 @@ static const AVFilterPad identity_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 static const AVOption options[] = {
@@ -421,8 +419,8 @@ const AVFilter ff_vf_identity = {
     .activate      = activate,
     .priv_size     = sizeof(IdentityContext),
     .priv_class    = &identity_class,
-    .inputs        = identity_inputs,
-    .outputs       = identity_outputs,
+    FILTER_INPUTS(identity_inputs),
+    FILTER_OUTPUTS(identity_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | AVFILTER_FLAG_SLICE_THREADS,
 };
 
@@ -443,8 +441,8 @@ const AVFilter ff_vf_msad = {
     .activate      = activate,
     .priv_size     = sizeof(IdentityContext),
     .priv_class    = &msad_class,
-    .inputs        = identity_inputs,
-    .outputs       = identity_outputs,
+    FILTER_INPUTS(identity_inputs),
+    FILTER_OUTPUTS(identity_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | AVFILTER_FLAG_SLICE_THREADS,
 };
 
diff --git a/libavfilter/vf_idet.c b/libavfilter/vf_idet.c
index 36ec73df46..e006e72da9 100644
--- a/libavfilter/vf_idet.c
+++ b/libavfilter/vf_idet.c
@@ -425,7 +425,6 @@ static const AVFilterPad idet_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad idet_outputs[] = {
@@ -434,7 +433,6 @@ static const AVFilterPad idet_outputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .request_frame = request_frame
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_idet = {
@@ -444,7 +442,7 @@ const AVFilter ff_vf_idet = {
     .init          = init,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = idet_inputs,
-    .outputs       = idet_outputs,
+    FILTER_INPUTS(idet_inputs),
+    FILTER_OUTPUTS(idet_outputs),
     .priv_class    = &idet_class,
 };
diff --git a/libavfilter/vf_il.c b/libavfilter/vf_il.c
index 9b21f2e7a7..8e829b2f69 100644
--- a/libavfilter/vf_il.c
+++ b/libavfilter/vf_il.c
@@ -187,7 +187,6 @@ static const AVFilterPad inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -195,7 +194,6 @@ static const AVFilterPad outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_il = {
@@ -203,8 +201,8 @@ const AVFilter ff_vf_il = {
     .description   = NULL_IF_CONFIG_SMALL("Deinterleave or interleave fields."),
     .priv_size     = sizeof(IlContext),
     .query_formats = query_formats,
-    .inputs        = inputs,
-    .outputs       = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
     .priv_class    = &il_class,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
     .process_command = ff_filter_process_command,
diff --git a/libavfilter/vf_kerndeint.c b/libavfilter/vf_kerndeint.c
index 04c04b7e13..85b426d0b0 100644
--- a/libavfilter/vf_kerndeint.c
+++ b/libavfilter/vf_kerndeint.c
@@ -292,7 +292,6 @@ static const AVFilterPad kerndeint_inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_props,
     },
-    { NULL }
 };
 
 static const AVFilterPad kerndeint_outputs[] = {
@@ -300,7 +299,6 @@ static const AVFilterPad kerndeint_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 
@@ -311,6 +309,6 @@ const AVFilter ff_vf_kerndeint = {
     .priv_class    = &kerndeint_class,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = kerndeint_inputs,
-    .outputs       = kerndeint_outputs,
+    FILTER_INPUTS(kerndeint_inputs),
+    FILTER_OUTPUTS(kerndeint_outputs),
 };
diff --git a/libavfilter/vf_lagfun.c b/libavfilter/vf_lagfun.c
index 3ca9639594..fee371b25f 100644
--- a/libavfilter/vf_lagfun.c
+++ b/libavfilter/vf_lagfun.c
@@ -203,7 +203,6 @@ static const AVFilterPad inputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .filter_frame  = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -212,7 +211,6 @@ static const AVFilterPad outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 AVFILTER_DEFINE_CLASS(lagfun);
@@ -224,8 +222,8 @@ const AVFilter ff_vf_lagfun = {
     .priv_class    = &lagfun_class,
     .query_formats = query_formats,
     .uninit        = uninit,
-    .outputs       = outputs,
-    .inputs        = inputs,
+    FILTER_OUTPUTS(outputs),
+    FILTER_INPUTS(inputs),
     .flags         = AVFILTER_FLAG_SLICE_THREADS | AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
     .process_command = ff_filter_process_command,
 };
diff --git a/libavfilter/vf_lenscorrection.c b/libavfilter/vf_lenscorrection.c
index c9585ceb22..1140e1d484 100644
--- a/libavfilter/vf_lenscorrection.c
+++ b/libavfilter/vf_lenscorrection.c
@@ -343,7 +343,6 @@ static const AVFilterPad lenscorrection_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad lenscorrection_outputs[] = {
@@ -352,7 +351,6 @@ static const AVFilterPad lenscorrection_outputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_lenscorrection = {
@@ -360,8 +358,8 @@ const AVFilter ff_vf_lenscorrection = {
     .description   = NULL_IF_CONFIG_SMALL("Rectify the image by correcting for lens distortion."),
     .priv_size     = sizeof(LenscorrectionCtx),
     .query_formats = query_formats,
-    .inputs        = lenscorrection_inputs,
-    .outputs       = lenscorrection_outputs,
+    FILTER_INPUTS(lenscorrection_inputs),
+    FILTER_OUTPUTS(lenscorrection_outputs),
     .priv_class    = &lenscorrection_class,
     .uninit        = uninit,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
diff --git a/libavfilter/vf_lensfun.c b/libavfilter/vf_lensfun.c
index ea5ef5e3cf..3837500481 100644
--- a/libavfilter/vf_lensfun.c
+++ b/libavfilter/vf_lensfun.c
@@ -519,7 +519,6 @@ static const AVFilterPad lensfun_inputs[] = {
         .config_props = config_props,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad lensfun_outputs[] = {
@@ -527,7 +526,6 @@ static const AVFilterPad lensfun_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_lensfun = {
@@ -537,8 +535,8 @@ const AVFilter ff_vf_lensfun = {
     .init          = init,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = lensfun_inputs,
-    .outputs       = lensfun_outputs,
+    FILTER_INPUTS(lensfun_inputs),
+    FILTER_OUTPUTS(lensfun_outputs),
     .priv_class    = &lensfun_class,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
 };
diff --git a/libavfilter/vf_libopencv.c b/libavfilter/vf_libopencv.c
index 8c65007044..4a5bc06871 100644
--- a/libavfilter/vf_libopencv.c
+++ b/libavfilter/vf_libopencv.c
@@ -413,7 +413,6 @@ static const AVFilterPad avfilter_vf_ocv_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad avfilter_vf_ocv_outputs[] = {
@@ -421,7 +420,6 @@ static const AVFilterPad avfilter_vf_ocv_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_ocv = {
@@ -432,6 +430,6 @@ const AVFilter ff_vf_ocv = {
     .query_formats = query_formats,
     .init          = init,
     .uninit        = uninit,
-    .inputs        = avfilter_vf_ocv_inputs,
-    .outputs       = avfilter_vf_ocv_outputs,
+    FILTER_INPUTS(avfilter_vf_ocv_inputs),
+    FILTER_OUTPUTS(avfilter_vf_ocv_outputs),
 };
diff --git a/libavfilter/vf_libvmaf.c b/libavfilter/vf_libvmaf.c
index fc8a0183be..d3e9f62e33 100644
--- a/libavfilter/vf_libvmaf.c
+++ b/libavfilter/vf_libvmaf.c
@@ -350,7 +350,6 @@ static const AVFilterPad libvmaf_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_input_ref,
     },
-    { NULL }
 };
 
 static const AVFilterPad libvmaf_outputs[] = {
@@ -359,7 +358,6 @@ static const AVFilterPad libvmaf_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_libvmaf = {
@@ -372,6 +370,6 @@ const AVFilter ff_vf_libvmaf = {
     .activate      = activate,
     .priv_size     = sizeof(LIBVMAFContext),
     .priv_class    = &libvmaf_class,
-    .inputs        = libvmaf_inputs,
-    .outputs       = libvmaf_outputs,
+    FILTER_INPUTS(libvmaf_inputs),
+    FILTER_OUTPUTS(libvmaf_outputs),
 };
diff --git a/libavfilter/vf_limiter.c b/libavfilter/vf_limiter.c
index 9d4f573bec..022b9ebf39 100644
--- a/libavfilter/vf_limiter.c
+++ b/libavfilter/vf_limiter.c
@@ -246,7 +246,6 @@ static const AVFilterPad inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -254,7 +253,6 @@ static const AVFilterPad outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_limiter = {
@@ -264,8 +262,8 @@ const AVFilter ff_vf_limiter = {
     .priv_class    = &limiter_class,
     .init          = init,
     .query_formats = query_formats,
-    .inputs        = inputs,
-    .outputs       = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
     .process_command = process_command,
 };
diff --git a/libavfilter/vf_lumakey.c b/libavfilter/vf_lumakey.c
index b556f7ab7a..b3bfb0a278 100644
--- a/libavfilter/vf_lumakey.c
+++ b/libavfilter/vf_lumakey.c
@@ -176,7 +176,6 @@ static const AVFilterPad lumakey_inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad lumakey_outputs[] = {
@@ -184,7 +183,6 @@ static const AVFilterPad lumakey_outputs[] = {
         .name          = "default",
         .type          = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 #define OFFSET(x) offsetof(LumakeyContext, x)
@@ -205,8 +203,8 @@ const AVFilter ff_vf_lumakey = {
     .priv_size     = sizeof(LumakeyContext),
     .priv_class    = &lumakey_class,
     .query_formats = query_formats,
-    .inputs        = lumakey_inputs,
-    .outputs       = lumakey_outputs,
+    FILTER_INPUTS(lumakey_inputs),
+    FILTER_OUTPUTS(lumakey_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
     .process_command = process_command,
 };
diff --git a/libavfilter/vf_lut.c b/libavfilter/vf_lut.c
index 082e0bdb7a..812a5c1ee1 100644
--- a/libavfilter/vf_lut.c
+++ b/libavfilter/vf_lut.c
@@ -580,13 +580,11 @@ static const AVFilterPad inputs[] = {
       .filter_frame = filter_frame,
       .config_props = config_props,
     },
-    { NULL }
 };
 static const AVFilterPad outputs[] = {
     { .name = "default",
       .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 #define DEFINE_LUT_FILTER(name_, description_)                          \
@@ -598,8 +596,8 @@ static const AVFilterPad outputs[] = {
         .init          = name_##_init,                                  \
         .uninit        = uninit,                                        \
         .query_formats = query_formats,                                 \
-        .inputs        = inputs,                                        \
-        .outputs       = outputs,                                       \
+        FILTER_INPUTS(inputs),                                          \
+        FILTER_OUTPUTS(outputs),                                        \
         .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC |       \
                          AVFILTER_FLAG_SLICE_THREADS,                   \
         .process_command = process_command,                             \
diff --git a/libavfilter/vf_lut2.c b/libavfilter/vf_lut2.c
index ba03467331..9fde3a08ee 100644
--- a/libavfilter/vf_lut2.c
+++ b/libavfilter/vf_lut2.c
@@ -534,7 +534,6 @@ static const AVFilterPad inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_inputy,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -543,7 +542,6 @@ static const AVFilterPad outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = lut2_config_output,
     },
-    { NULL }
 };
 
 static int process_command(AVFilterContext *ctx, const char *cmd, const char *args,
@@ -570,8 +568,8 @@ const AVFilter ff_vf_lut2 = {
     .uninit        = uninit,
     .query_formats = query_formats,
     .activate      = activate,
-    .inputs        = inputs,
-    .outputs       = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL |
                      AVFILTER_FLAG_SLICE_THREADS,
     .process_command = process_command,
@@ -642,7 +640,6 @@ static const AVFilterPad tlut2_inputs[] = {
         .filter_frame  = tlut2_filter_frame,
         .config_props  = config_inputx,
     },
-    { NULL }
 };
 
 static const AVFilterPad tlut2_outputs[] = {
@@ -651,7 +648,6 @@ static const AVFilterPad tlut2_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_tlut2 = {
@@ -662,8 +658,8 @@ const AVFilter ff_vf_tlut2 = {
     .query_formats = query_formats,
     .init          = init,
     .uninit        = uninit,
-    .inputs        = tlut2_inputs,
-    .outputs       = tlut2_outputs,
+    FILTER_INPUTS(tlut2_inputs),
+    FILTER_OUTPUTS(tlut2_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL |
                      AVFILTER_FLAG_SLICE_THREADS,
     .process_command = process_command,
diff --git a/libavfilter/vf_lut3d.c b/libavfilter/vf_lut3d.c
index 1246a5cab6..111e624dc3 100644
--- a/libavfilter/vf_lut3d.c
+++ b/libavfilter/vf_lut3d.c
@@ -1340,7 +1340,6 @@ static const AVFilterPad lut3d_inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad lut3d_outputs[] = {
@@ -1348,7 +1347,6 @@ static const AVFilterPad lut3d_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_lut3d = {
@@ -1358,8 +1356,8 @@ const AVFilter ff_vf_lut3d = {
     .init          = lut3d_init,
     .uninit        = lut3d_uninit,
     .query_formats = query_formats,
-    .inputs        = lut3d_inputs,
-    .outputs       = lut3d_outputs,
+    FILTER_INPUTS(lut3d_inputs),
+    FILTER_OUTPUTS(lut3d_outputs),
     .priv_class    = &lut3d_class,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
     .process_command = process_command,
@@ -1606,7 +1604,6 @@ static const AVFilterPad haldclut_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_clut,
     },
-    { NULL }
 };
 
 static const AVFilterPad haldclut_outputs[] = {
@@ -1615,7 +1612,6 @@ static const AVFilterPad haldclut_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_haldclut = {
@@ -1627,8 +1623,8 @@ const AVFilter ff_vf_haldclut = {
     .uninit        = haldclut_uninit,
     .query_formats = query_formats,
     .activate      = activate,
-    .inputs        = haldclut_inputs,
-    .outputs       = haldclut_outputs,
+    FILTER_INPUTS(haldclut_inputs),
+    FILTER_OUTPUTS(haldclut_outputs),
     .priv_class    = &haldclut_class,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | AVFILTER_FLAG_SLICE_THREADS,
     .process_command = process_command,
@@ -2273,7 +2269,6 @@ static const AVFilterPad lut1d_inputs[] = {
         .filter_frame = filter_frame_1d,
         .config_props = config_input_1d,
     },
-    { NULL }
 };
 
 static const AVFilterPad lut1d_outputs[] = {
@@ -2281,7 +2276,6 @@ static const AVFilterPad lut1d_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_lut1d = {
@@ -2290,8 +2284,8 @@ const AVFilter ff_vf_lut1d = {
     .priv_size     = sizeof(LUT1DContext),
     .init          = lut1d_init,
     .query_formats = query_formats,
-    .inputs        = lut1d_inputs,
-    .outputs       = lut1d_outputs,
+    FILTER_INPUTS(lut1d_inputs),
+    FILTER_OUTPUTS(lut1d_outputs),
     .priv_class    = &lut1d_class,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
     .process_command = lut1d_process_command,
diff --git a/libavfilter/vf_maskedclamp.c b/libavfilter/vf_maskedclamp.c
index 0c558d1030..c19bc9d849 100644
--- a/libavfilter/vf_maskedclamp.c
+++ b/libavfilter/vf_maskedclamp.c
@@ -304,7 +304,6 @@ static const AVFilterPad maskedclamp_inputs[] = {
         .name         = "bright",
         .type         = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 static const AVFilterPad maskedclamp_outputs[] = {
@@ -313,7 +312,6 @@ static const AVFilterPad maskedclamp_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_maskedclamp = {
@@ -323,8 +321,8 @@ const AVFilter ff_vf_maskedclamp = {
     .uninit        = uninit,
     .activate      = activate,
     .query_formats = query_formats,
-    .inputs        = maskedclamp_inputs,
-    .outputs       = maskedclamp_outputs,
+    FILTER_INPUTS(maskedclamp_inputs),
+    FILTER_OUTPUTS(maskedclamp_outputs),
     .priv_class    = &maskedclamp_class,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | AVFILTER_FLAG_SLICE_THREADS,
     .process_command = ff_filter_process_command,
diff --git a/libavfilter/vf_maskedmerge.c b/libavfilter/vf_maskedmerge.c
index 37d33f9313..00e9308622 100644
--- a/libavfilter/vf_maskedmerge.c
+++ b/libavfilter/vf_maskedmerge.c
@@ -305,7 +305,6 @@ static const AVFilterPad maskedmerge_inputs[] = {
         .name         = "mask",
         .type         = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 static const AVFilterPad maskedmerge_outputs[] = {
@@ -314,7 +313,6 @@ static const AVFilterPad maskedmerge_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_maskedmerge = {
@@ -324,8 +322,8 @@ const AVFilter ff_vf_maskedmerge = {
     .uninit        = uninit,
     .query_formats = query_formats,
     .activate      = activate,
-    .inputs        = maskedmerge_inputs,
-    .outputs       = maskedmerge_outputs,
+    FILTER_INPUTS(maskedmerge_inputs),
+    FILTER_OUTPUTS(maskedmerge_outputs),
     .priv_class    = &maskedmerge_class,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | AVFILTER_FLAG_SLICE_THREADS,
     .process_command = ff_filter_process_command,
diff --git a/libavfilter/vf_maskedminmax.c b/libavfilter/vf_maskedminmax.c
index 08ff6e852b..afac145e2a 100644
--- a/libavfilter/vf_maskedminmax.c
+++ b/libavfilter/vf_maskedminmax.c
@@ -313,7 +313,6 @@ static const AVFilterPad maskedminmax_inputs[] = {
         .name         = "filter2",
         .type         = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 static const AVFilterPad maskedminmax_outputs[] = {
@@ -322,7 +321,6 @@ static const AVFilterPad maskedminmax_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 #define maskedmin_options maskedminmax_options
@@ -337,8 +335,8 @@ const AVFilter ff_vf_maskedmin = {
     .uninit        = uninit,
     .activate      = activate,
     .query_formats = query_formats,
-    .inputs        = maskedminmax_inputs,
-    .outputs       = maskedminmax_outputs,
+    FILTER_INPUTS(maskedminmax_inputs),
+    FILTER_OUTPUTS(maskedminmax_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | AVFILTER_FLAG_SLICE_THREADS,
     .process_command = ff_filter_process_command,
 };
@@ -355,8 +353,8 @@ const AVFilter ff_vf_maskedmax = {
     .uninit        = uninit,
     .activate      = activate,
     .query_formats = query_formats,
-    .inputs        = maskedminmax_inputs,
-    .outputs       = maskedminmax_outputs,
+    FILTER_INPUTS(maskedminmax_inputs),
+    FILTER_OUTPUTS(maskedminmax_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | AVFILTER_FLAG_SLICE_THREADS,
     .process_command = ff_filter_process_command,
 };
diff --git a/libavfilter/vf_maskedthreshold.c b/libavfilter/vf_maskedthreshold.c
index 1392e09176..4b183eb9fd 100644
--- a/libavfilter/vf_maskedthreshold.c
+++ b/libavfilter/vf_maskedthreshold.c
@@ -270,7 +270,6 @@ static const AVFilterPad maskedthreshold_inputs[] = {
         .name         = "reference",
         .type         = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 static const AVFilterPad maskedthreshold_outputs[] = {
@@ -279,7 +278,6 @@ static const AVFilterPad maskedthreshold_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 AVFILTER_DEFINE_CLASS(maskedthreshold);
@@ -292,8 +290,8 @@ const AVFilter ff_vf_maskedthreshold = {
     .uninit        = uninit,
     .activate      = activate,
     .query_formats = query_formats,
-    .inputs        = maskedthreshold_inputs,
-    .outputs       = maskedthreshold_outputs,
+    FILTER_INPUTS(maskedthreshold_inputs),
+    FILTER_OUTPUTS(maskedthreshold_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | AVFILTER_FLAG_SLICE_THREADS,
     .process_command = ff_filter_process_command,
 };
diff --git a/libavfilter/vf_maskfun.c b/libavfilter/vf_maskfun.c
index da1cfe91cb..5f323385ee 100644
--- a/libavfilter/vf_maskfun.c
+++ b/libavfilter/vf_maskfun.c
@@ -298,7 +298,6 @@ static const AVFilterPad maskfun_inputs[] = {
         .filter_frame   = filter_frame,
         .config_props   = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad maskfun_outputs[] = {
@@ -306,7 +305,6 @@ static const AVFilterPad maskfun_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_maskfun = {
@@ -315,8 +313,8 @@ const AVFilter ff_vf_maskfun = {
     .priv_size     = sizeof(MaskFunContext),
     .query_formats = query_formats,
     .uninit        = uninit,
-    .inputs        = maskfun_inputs,
-    .outputs       = maskfun_outputs,
+    FILTER_INPUTS(maskfun_inputs),
+    FILTER_OUTPUTS(maskfun_outputs),
     .priv_class    = &maskfun_class,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
     .process_command = process_command,
diff --git a/libavfilter/vf_mcdeint.c b/libavfilter/vf_mcdeint.c
index 034e72a487..88c8b25a6d 100644
--- a/libavfilter/vf_mcdeint.c
+++ b/libavfilter/vf_mcdeint.c
@@ -290,7 +290,6 @@ static const AVFilterPad mcdeint_inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_props,
     },
-    { NULL }
 };
 
 static const AVFilterPad mcdeint_outputs[] = {
@@ -298,7 +297,6 @@ static const AVFilterPad mcdeint_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_mcdeint = {
@@ -307,7 +305,7 @@ const AVFilter ff_vf_mcdeint = {
     .priv_size     = sizeof(MCDeintContext),
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = mcdeint_inputs,
-    .outputs       = mcdeint_outputs,
+    FILTER_INPUTS(mcdeint_inputs),
+    FILTER_OUTPUTS(mcdeint_outputs),
     .priv_class    = &mcdeint_class,
 };
diff --git a/libavfilter/vf_median.c b/libavfilter/vf_median.c
index 9d92f1543b..61a2656244 100644
--- a/libavfilter/vf_median.c
+++ b/libavfilter/vf_median.c
@@ -273,7 +273,6 @@ static const AVFilterPad median_inputs[] = {
         .config_props = config_input,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad median_outputs[] = {
@@ -281,7 +280,6 @@ static const AVFilterPad median_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_median = {
@@ -291,8 +289,8 @@ const AVFilter ff_vf_median = {
     .priv_class    = &median_class,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = median_inputs,
-    .outputs       = median_outputs,
+    FILTER_INPUTS(median_inputs),
+    FILTER_OUTPUTS(median_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
     .process_command = process_command,
 };
diff --git a/libavfilter/vf_mergeplanes.c b/libavfilter/vf_mergeplanes.c
index 4a83af7d2b..fe68c5c7e7 100644
--- a/libavfilter/vf_mergeplanes.c
+++ b/libavfilter/vf_mergeplanes.c
@@ -293,7 +293,6 @@ static const AVFilterPad mergeplanes_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_mergeplanes = {
@@ -306,6 +305,6 @@ const AVFilter ff_vf_mergeplanes = {
     .query_formats = query_formats,
     .activate      = activate,
     .inputs        = NULL,
-    .outputs       = mergeplanes_outputs,
+    FILTER_OUTPUTS(mergeplanes_outputs),
     .flags         = AVFILTER_FLAG_DYNAMIC_INPUTS,
 };
diff --git a/libavfilter/vf_mestimate.c b/libavfilter/vf_mestimate.c
index 1b65c738d5..582da48568 100644
--- a/libavfilter/vf_mestimate.c
+++ b/libavfilter/vf_mestimate.c
@@ -353,7 +353,6 @@ static const AVFilterPad mestimate_inputs[] = {
         .filter_frame  = filter_frame,
         .config_props  = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad mestimate_outputs[] = {
@@ -361,7 +360,6 @@ static const AVFilterPad mestimate_outputs[] = {
         .name          = "default",
         .type          = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_mestimate = {
@@ -371,6 +369,6 @@ const AVFilter ff_vf_mestimate = {
     .priv_class    = &mestimate_class,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = mestimate_inputs,
-    .outputs       = mestimate_outputs,
+    FILTER_INPUTS(mestimate_inputs),
+    FILTER_OUTPUTS(mestimate_outputs),
 };
diff --git a/libavfilter/vf_midequalizer.c b/libavfilter/vf_midequalizer.c
index ec1ffe5539..0e87723609 100644
--- a/libavfilter/vf_midequalizer.c
+++ b/libavfilter/vf_midequalizer.c
@@ -363,7 +363,6 @@ static const AVFilterPad midequalizer_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_input1,
     },
-    { NULL }
 };
 
 static const AVFilterPad midequalizer_outputs[] = {
@@ -372,7 +371,6 @@ static const AVFilterPad midequalizer_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_midequalizer = {
@@ -382,8 +380,8 @@ const AVFilter ff_vf_midequalizer = {
     .uninit        = uninit,
     .query_formats = query_formats,
     .activate      = activate,
-    .inputs        = midequalizer_inputs,
-    .outputs       = midequalizer_outputs,
+    FILTER_INPUTS(midequalizer_inputs),
+    FILTER_OUTPUTS(midequalizer_outputs),
     .priv_class    = &midequalizer_class,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
 };
diff --git a/libavfilter/vf_minterpolate.c b/libavfilter/vf_minterpolate.c
index 4b58eb00d8..33a4059042 100644
--- a/libavfilter/vf_minterpolate.c
+++ b/libavfilter/vf_minterpolate.c
@@ -1242,7 +1242,6 @@ static const AVFilterPad minterpolate_inputs[] = {
         .filter_frame  = filter_frame,
         .config_props  = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad minterpolate_outputs[] = {
@@ -1251,7 +1250,6 @@ static const AVFilterPad minterpolate_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_minterpolate = {
@@ -1261,6 +1259,6 @@ const AVFilter ff_vf_minterpolate = {
     .priv_class    = &minterpolate_class,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = minterpolate_inputs,
-    .outputs       = minterpolate_outputs,
+    FILTER_INPUTS(minterpolate_inputs),
+    FILTER_OUTPUTS(minterpolate_outputs),
 };
diff --git a/libavfilter/vf_misc_vaapi.c b/libavfilter/vf_misc_vaapi.c
index ca0d46ff19..83aedcdc31 100644
--- a/libavfilter/vf_misc_vaapi.c
+++ b/libavfilter/vf_misc_vaapi.c
@@ -222,7 +222,6 @@ static const AVFilterPad misc_vaapi_inputs[] = {
         .filter_frame = &misc_vaapi_filter_frame,
         .config_props = &ff_vaapi_vpp_config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad misc_vaapi_outputs[] = {
@@ -231,7 +230,6 @@ static const AVFilterPad misc_vaapi_outputs[] = {
         .type = AVMEDIA_TYPE_VIDEO,
         .config_props = &ff_vaapi_vpp_config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_denoise_vaapi = {
@@ -241,8 +239,8 @@ const AVFilter ff_vf_denoise_vaapi = {
     .init          = &denoise_vaapi_init,
     .uninit        = &ff_vaapi_vpp_ctx_uninit,
     .query_formats = &ff_vaapi_vpp_query_formats,
-    .inputs        = misc_vaapi_inputs,
-    .outputs       = misc_vaapi_outputs,
+    FILTER_INPUTS(misc_vaapi_inputs),
+    FILTER_OUTPUTS(misc_vaapi_outputs),
     .priv_class    = &denoise_vaapi_class,
     .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
 };
@@ -254,8 +252,8 @@ const AVFilter ff_vf_sharpness_vaapi = {
     .init          = &sharpness_vaapi_init,
     .uninit        = &ff_vaapi_vpp_ctx_uninit,
     .query_formats = &ff_vaapi_vpp_query_formats,
-    .inputs        = misc_vaapi_inputs,
-    .outputs       = misc_vaapi_outputs,
+    FILTER_INPUTS(misc_vaapi_inputs),
+    FILTER_OUTPUTS(misc_vaapi_outputs),
     .priv_class    = &sharpness_vaapi_class,
     .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
 };
diff --git a/libavfilter/vf_mix.c b/libavfilter/vf_mix.c
index cbcd82f238..a581dfc8ef 100644
--- a/libavfilter/vf_mix.c
+++ b/libavfilter/vf_mix.c
@@ -353,7 +353,6 @@ static const AVFilterPad outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 #if CONFIG_MIX_FILTER
@@ -365,7 +364,7 @@ const AVFilter ff_vf_mix = {
     .priv_size     = sizeof(MixContext),
     .priv_class    = &mix_class,
     .query_formats = query_formats,
-    .outputs       = outputs,
+    FILTER_OUTPUTS(outputs),
     .init          = init,
     .uninit        = uninit,
     .activate      = activate,
@@ -432,7 +431,6 @@ static const AVFilterPad inputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .filter_frame  = tmix_filter_frame,
     },
-    { NULL }
 };
 
 AVFILTER_DEFINE_CLASS(tmix);
@@ -443,8 +441,8 @@ const AVFilter ff_vf_tmix = {
     .priv_size     = sizeof(MixContext),
     .priv_class    = &tmix_class,
     .query_formats = query_formats,
-    .outputs       = outputs,
-    .inputs        = inputs,
+    FILTER_OUTPUTS(outputs),
+    FILTER_INPUTS(inputs),
     .init          = init,
     .uninit        = uninit,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | AVFILTER_FLAG_SLICE_THREADS,
diff --git a/libavfilter/vf_monochrome.c b/libavfilter/vf_monochrome.c
index 825a869707..5792e27cb9 100644
--- a/libavfilter/vf_monochrome.c
+++ b/libavfilter/vf_monochrome.c
@@ -271,7 +271,6 @@ static const AVFilterPad monochrome_inputs[] = {
         .filter_frame   = filter_frame,
         .config_props   = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad monochrome_outputs[] = {
@@ -279,7 +278,6 @@ static const AVFilterPad monochrome_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 #define OFFSET(x) offsetof(MonochromeContext, x)
@@ -301,8 +299,8 @@ const AVFilter ff_vf_monochrome = {
     .priv_size     = sizeof(MonochromeContext),
     .priv_class    = &monochrome_class,
     .query_formats = query_formats,
-    .inputs        = monochrome_inputs,
-    .outputs       = monochrome_outputs,
+    FILTER_INPUTS(monochrome_inputs),
+    FILTER_OUTPUTS(monochrome_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
     .process_command = ff_filter_process_command,
 };
diff --git a/libavfilter/vf_mpdecimate.c b/libavfilter/vf_mpdecimate.c
index 301475906e..8d515396f3 100644
--- a/libavfilter/vf_mpdecimate.c
+++ b/libavfilter/vf_mpdecimate.c
@@ -228,7 +228,6 @@ static const AVFilterPad mpdecimate_inputs[] = {
         .config_props = config_input,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad mpdecimate_outputs[] = {
@@ -236,7 +235,6 @@ static const AVFilterPad mpdecimate_outputs[] = {
         .name          = "default",
         .type          = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_mpdecimate = {
@@ -247,6 +245,6 @@ const AVFilter ff_vf_mpdecimate = {
     .priv_size     = sizeof(DecimateContext),
     .priv_class    = &mpdecimate_class,
     .query_formats = query_formats,
-    .inputs        = mpdecimate_inputs,
-    .outputs       = mpdecimate_outputs,
+    FILTER_INPUTS(mpdecimate_inputs),
+    FILTER_OUTPUTS(mpdecimate_outputs),
 };
diff --git a/libavfilter/vf_neighbor.c b/libavfilter/vf_neighbor.c
index 2d1c3da898..16a092c761 100644
--- a/libavfilter/vf_neighbor.c
+++ b/libavfilter/vf_neighbor.c
@@ -342,7 +342,6 @@ static const AVFilterPad neighbor_inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad neighbor_outputs[] = {
@@ -350,7 +349,6 @@ static const AVFilterPad neighbor_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 #define OFFSET(x) offsetof(NContext, x)
@@ -365,8 +363,8 @@ const AVFilter ff_vf_##name_ = {                                   \
     .priv_size     = sizeof(NContext),                       \
     .priv_class    = &name_##_class,                         \
     .query_formats = query_formats,                          \
-    .inputs        = neighbor_inputs,                        \
-    .outputs       = neighbor_outputs,                       \
+    FILTER_INPUTS(neighbor_inputs),                          \
+    FILTER_OUTPUTS(neighbor_outputs),                        \
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC| \
                      AVFILTER_FLAG_SLICE_THREADS,            \
     .process_command = ff_filter_process_command,            \
diff --git a/libavfilter/vf_neighbor_opencl.c b/libavfilter/vf_neighbor_opencl.c
index e00245089d..68becfe143 100644
--- a/libavfilter/vf_neighbor_opencl.c
+++ b/libavfilter/vf_neighbor_opencl.c
@@ -245,7 +245,6 @@ static const AVFilterPad neighbor_opencl_inputs[] = {
         .filter_frame = &neighbor_opencl_filter_frame,
         .config_props = &ff_opencl_filter_config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad neighbor_opencl_outputs[] = {
@@ -254,7 +253,6 @@ static const AVFilterPad neighbor_opencl_outputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = &ff_opencl_filter_config_output,
     },
-    { NULL }
 };
 
 #define OFFSET(x) offsetof(NeighborOpenCLContext, x)
@@ -281,8 +279,8 @@ const AVFilter ff_vf_erosion_opencl = {
     .init           = &ff_opencl_filter_init,
     .uninit         = &neighbor_opencl_uninit,
     .query_formats  = &ff_opencl_filter_query_formats,
-    .inputs         = neighbor_opencl_inputs,
-    .outputs        = neighbor_opencl_outputs,
+    FILTER_INPUTS(neighbor_opencl_inputs),
+    FILTER_OUTPUTS(neighbor_opencl_outputs),
     .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
 };
 
@@ -309,8 +307,8 @@ const AVFilter ff_vf_dilation_opencl = {
     .init           = &ff_opencl_filter_init,
     .uninit         = &neighbor_opencl_uninit,
     .query_formats  = &ff_opencl_filter_query_formats,
-    .inputs         = neighbor_opencl_inputs,
-    .outputs        = neighbor_opencl_outputs,
+    FILTER_INPUTS(neighbor_opencl_inputs),
+    FILTER_OUTPUTS(neighbor_opencl_outputs),
     .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
 };
 
diff --git a/libavfilter/vf_nlmeans.c b/libavfilter/vf_nlmeans.c
index 08183fa04f..39ed37368a 100644
--- a/libavfilter/vf_nlmeans.c
+++ b/libavfilter/vf_nlmeans.c
@@ -563,7 +563,6 @@ static const AVFilterPad nlmeans_inputs[] = {
         .config_props = config_input,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad nlmeans_outputs[] = {
@@ -571,7 +570,6 @@ static const AVFilterPad nlmeans_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_nlmeans = {
@@ -581,8 +579,8 @@ const AVFilter ff_vf_nlmeans = {
     .init          = init,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = nlmeans_inputs,
-    .outputs       = nlmeans_outputs,
+    FILTER_INPUTS(nlmeans_inputs),
+    FILTER_OUTPUTS(nlmeans_outputs),
     .priv_class    = &nlmeans_class,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
 };
diff --git a/libavfilter/vf_nlmeans_opencl.c b/libavfilter/vf_nlmeans_opencl.c
index 0f16b2fe49..6e28f4be7a 100644
--- a/libavfilter/vf_nlmeans_opencl.c
+++ b/libavfilter/vf_nlmeans_opencl.c
@@ -417,7 +417,6 @@ static const AVFilterPad nlmeans_opencl_inputs[] = {
         .filter_frame = &nlmeans_opencl_filter_frame,
         .config_props = &ff_opencl_filter_config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad nlmeans_opencl_outputs[] = {
@@ -426,7 +425,6 @@ static const AVFilterPad nlmeans_opencl_outputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = &ff_opencl_filter_config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_nlmeans_opencl = {
@@ -437,7 +435,7 @@ const AVFilter ff_vf_nlmeans_opencl = {
     .init           = &ff_opencl_filter_init,
     .uninit         = &nlmeans_opencl_uninit,
     .query_formats  = &ff_opencl_filter_query_formats,
-    .inputs         = nlmeans_opencl_inputs,
-    .outputs        = nlmeans_opencl_outputs,
+    FILTER_INPUTS(nlmeans_opencl_inputs),
+    FILTER_OUTPUTS(nlmeans_opencl_outputs),
     .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
 };
diff --git a/libavfilter/vf_nnedi.c b/libavfilter/vf_nnedi.c
index a5d5f3b0f4..944736a279 100644
--- a/libavfilter/vf_nnedi.c
+++ b/libavfilter/vf_nnedi.c
@@ -1141,7 +1141,6 @@ static const AVFilterPad inputs[] = {
         .filter_frame  = filter_frame,
         .config_props  = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -1151,7 +1150,6 @@ static const AVFilterPad outputs[] = {
         .config_props  = config_output,
         .request_frame = request_frame,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_nnedi = {
@@ -1162,8 +1160,8 @@ const AVFilter ff_vf_nnedi = {
     .init          = init,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = inputs,
-    .outputs       = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | AVFILTER_FLAG_SLICE_THREADS,
     .process_command = ff_filter_process_command,
 };
diff --git a/libavfilter/vf_noise.c b/libavfilter/vf_noise.c
index 9738a12650..50febf230d 100644
--- a/libavfilter/vf_noise.c
+++ b/libavfilter/vf_noise.c
@@ -327,7 +327,6 @@ static const AVFilterPad noise_inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad noise_outputs[] = {
@@ -335,7 +334,6 @@ static const AVFilterPad noise_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_noise = {
@@ -345,8 +343,8 @@ const AVFilter ff_vf_noise = {
     .init          = init,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = noise_inputs,
-    .outputs       = noise_outputs,
+    FILTER_INPUTS(noise_inputs),
+    FILTER_OUTPUTS(noise_outputs),
     .priv_class    = &noise_class,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
 };
diff --git a/libavfilter/vf_normalize.c b/libavfilter/vf_normalize.c
index a9474056af..26f8e2f426 100644
--- a/libavfilter/vf_normalize.c
+++ b/libavfilter/vf_normalize.c
@@ -516,7 +516,6 @@ static const AVFilterPad inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -524,7 +523,6 @@ static const AVFilterPad outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_normalize = {
@@ -534,8 +532,8 @@ const AVFilter ff_vf_normalize = {
     .priv_class    = &normalize_class,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = inputs,
-    .outputs       = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
     .process_command = ff_filter_process_command,
 };
diff --git a/libavfilter/vf_null.c b/libavfilter/vf_null.c
index 1f0e85e900..33b1185ce0 100644
--- a/libavfilter/vf_null.c
+++ b/libavfilter/vf_null.c
@@ -31,7 +31,6 @@ static const AVFilterPad avfilter_vf_null_inputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 static const AVFilterPad avfilter_vf_null_outputs[] = {
@@ -39,12 +38,11 @@ static const AVFilterPad avfilter_vf_null_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_null = {
     .name        = "null",
     .description = NULL_IF_CONFIG_SMALL("Pass the source unchanged to the output."),
-    .inputs      = avfilter_vf_null_inputs,
-    .outputs     = avfilter_vf_null_outputs,
+    FILTER_INPUTS(avfilter_vf_null_inputs),
+    FILTER_OUTPUTS(avfilter_vf_null_outputs),
 };
diff --git a/libavfilter/vf_ocr.c b/libavfilter/vf_ocr.c
index d33e7222ef..7691f41932 100644
--- a/libavfilter/vf_ocr.c
+++ b/libavfilter/vf_ocr.c
@@ -132,7 +132,6 @@ static const AVFilterPad ocr_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad ocr_outputs[] = {
@@ -140,7 +139,6 @@ static const AVFilterPad ocr_outputs[] = {
         .name         = "default",
         .type         = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_ocr = {
@@ -151,6 +149,6 @@ const AVFilter ff_vf_ocr = {
     .query_formats = query_formats,
     .init          = init,
     .uninit        = uninit,
-    .inputs        = ocr_inputs,
-    .outputs       = ocr_outputs,
+    FILTER_INPUTS(ocr_inputs),
+    FILTER_OUTPUTS(ocr_outputs),
 };
diff --git a/libavfilter/vf_overlay.c b/libavfilter/vf_overlay.c
index eb29e8e8c1..afa694e100 100644
--- a/libavfilter/vf_overlay.c
+++ b/libavfilter/vf_overlay.c
@@ -1094,7 +1094,6 @@ static const AVFilterPad avfilter_vf_overlay_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_input_overlay,
     },
-    { NULL }
 };
 
 static const AVFilterPad avfilter_vf_overlay_outputs[] = {
@@ -1103,7 +1102,6 @@ static const AVFilterPad avfilter_vf_overlay_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_overlay = {
@@ -1117,8 +1115,8 @@ const AVFilter ff_vf_overlay = {
     .query_formats = query_formats,
     .activate      = activate,
     .process_command = process_command,
-    .inputs        = avfilter_vf_overlay_inputs,
-    .outputs       = avfilter_vf_overlay_outputs,
+    FILTER_INPUTS(avfilter_vf_overlay_inputs),
+    FILTER_OUTPUTS(avfilter_vf_overlay_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL |
                      AVFILTER_FLAG_SLICE_THREADS,
 };
diff --git a/libavfilter/vf_overlay_cuda.c b/libavfilter/vf_overlay_cuda.c
index 5bab678b0f..4c0719871b 100644
--- a/libavfilter/vf_overlay_cuda.c
+++ b/libavfilter/vf_overlay_cuda.c
@@ -565,7 +565,6 @@ static const AVFilterPad overlay_cuda_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_input_overlay,
     },
-    { NULL }
 };
 
 static const AVFilterPad overlay_cuda_outputs[] = {
@@ -574,7 +573,6 @@ static const AVFilterPad overlay_cuda_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = &overlay_cuda_config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_overlay_cuda = {
@@ -586,8 +584,8 @@ const AVFilter ff_vf_overlay_cuda = {
     .uninit          = &overlay_cuda_uninit,
     .activate        = &overlay_cuda_activate,
     .query_formats   = &overlay_cuda_query_formats,
-    .inputs          = overlay_cuda_inputs,
-    .outputs         = overlay_cuda_outputs,
+    FILTER_INPUTS(overlay_cuda_inputs),
+    FILTER_OUTPUTS(overlay_cuda_outputs),
     .preinit         = overlay_cuda_framesync_preinit,
     .flags_internal  = FF_FILTER_FLAG_HWFRAME_AWARE,
 };
diff --git a/libavfilter/vf_overlay_opencl.c b/libavfilter/vf_overlay_opencl.c
index 6ba622baaa..4f1d6bbdd2 100644
--- a/libavfilter/vf_overlay_opencl.c
+++ b/libavfilter/vf_overlay_opencl.c
@@ -300,7 +300,6 @@ static const AVFilterPad overlay_opencl_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = &ff_opencl_filter_config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad overlay_opencl_outputs[] = {
@@ -309,7 +308,6 @@ static const AVFilterPad overlay_opencl_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = &overlay_opencl_config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_overlay_opencl = {
@@ -321,7 +319,7 @@ const AVFilter ff_vf_overlay_opencl = {
     .uninit          = &overlay_opencl_uninit,
     .query_formats   = &ff_opencl_filter_query_formats,
     .activate        = &overlay_opencl_activate,
-    .inputs          = overlay_opencl_inputs,
-    .outputs         = overlay_opencl_outputs,
+    FILTER_INPUTS(overlay_opencl_inputs),
+    FILTER_OUTPUTS(overlay_opencl_outputs),
     .flags_internal  = FF_FILTER_FLAG_HWFRAME_AWARE,
 };
diff --git a/libavfilter/vf_overlay_qsv.c b/libavfilter/vf_overlay_qsv.c
index 14c4c37a3c..578ef47e88 100644
--- a/libavfilter/vf_overlay_qsv.c
+++ b/libavfilter/vf_overlay_qsv.c
@@ -403,7 +403,6 @@ static const AVFilterPad overlay_qsv_inputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_overlay_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad overlay_qsv_outputs[] = {
@@ -412,7 +411,6 @@ static const AVFilterPad overlay_qsv_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_overlay_qsv = {
@@ -424,8 +422,8 @@ const AVFilter ff_vf_overlay_qsv = {
     .init           = overlay_qsv_init,
     .uninit         = overlay_qsv_uninit,
     .activate       = activate,
-    .inputs         = overlay_qsv_inputs,
-    .outputs        = overlay_qsv_outputs,
+    FILTER_INPUTS(overlay_qsv_inputs),
+    FILTER_OUTPUTS(overlay_qsv_outputs),
     .priv_class     = &overlay_qsv_class,
     .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
 };
diff --git a/libavfilter/vf_overlay_vulkan.c b/libavfilter/vf_overlay_vulkan.c
index 8dd3bd2092..1815709d82 100644
--- a/libavfilter/vf_overlay_vulkan.c
+++ b/libavfilter/vf_overlay_vulkan.c
@@ -463,7 +463,6 @@ static const AVFilterPad overlay_vulkan_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = &ff_vk_filter_config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad overlay_vulkan_outputs[] = {
@@ -472,7 +471,6 @@ static const AVFilterPad overlay_vulkan_outputs[] = {
         .type = AVMEDIA_TYPE_VIDEO,
         .config_props = &overlay_vulkan_config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_overlay_vulkan = {
@@ -483,8 +481,8 @@ const AVFilter ff_vf_overlay_vulkan = {
     .uninit         = &overlay_vulkan_uninit,
     .query_formats  = &ff_vk_filter_query_formats,
     .activate       = &overlay_vulkan_activate,
-    .inputs         = overlay_vulkan_inputs,
-    .outputs        = overlay_vulkan_outputs,
+    FILTER_INPUTS(overlay_vulkan_inputs),
+    FILTER_OUTPUTS(overlay_vulkan_outputs),
     .priv_class     = &overlay_vulkan_class,
     .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
 };
diff --git a/libavfilter/vf_owdenoise.c b/libavfilter/vf_owdenoise.c
index 6a832b8f3c..80ce3ca654 100644
--- a/libavfilter/vf_owdenoise.c
+++ b/libavfilter/vf_owdenoise.c
@@ -351,7 +351,6 @@ static const AVFilterPad owdenoise_inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad owdenoise_outputs[] = {
@@ -359,7 +358,6 @@ static const AVFilterPad owdenoise_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_owdenoise = {
@@ -368,8 +366,8 @@ const AVFilter ff_vf_owdenoise = {
     .priv_size     = sizeof(OWDenoiseContext),
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = owdenoise_inputs,
-    .outputs       = owdenoise_outputs,
+    FILTER_INPUTS(owdenoise_inputs),
+    FILTER_OUTPUTS(owdenoise_outputs),
     .priv_class    = &owdenoise_class,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
 };
diff --git a/libavfilter/vf_pad.c b/libavfilter/vf_pad.c
index 9e76bed4a1..ba1728f820 100644
--- a/libavfilter/vf_pad.c
+++ b/libavfilter/vf_pad.c
@@ -441,7 +441,6 @@ static const AVFilterPad avfilter_vf_pad_inputs[] = {
         .get_buffer.video = get_video_buffer,
         .filter_frame     = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad avfilter_vf_pad_outputs[] = {
@@ -450,7 +449,6 @@ static const AVFilterPad avfilter_vf_pad_outputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_pad = {
@@ -459,6 +457,6 @@ const AVFilter ff_vf_pad = {
     .priv_size     = sizeof(PadContext),
     .priv_class    = &pad_class,
     .query_formats = query_formats,
-    .inputs        = avfilter_vf_pad_inputs,
-    .outputs       = avfilter_vf_pad_outputs,
+    FILTER_INPUTS(avfilter_vf_pad_inputs),
+    FILTER_OUTPUTS(avfilter_vf_pad_outputs),
 };
diff --git a/libavfilter/vf_pad_opencl.c b/libavfilter/vf_pad_opencl.c
index 8155a96e03..9e6fc94097 100644
--- a/libavfilter/vf_pad_opencl.c
+++ b/libavfilter/vf_pad_opencl.c
@@ -354,7 +354,6 @@ static const AVFilterPad pad_opencl_inputs[] = {
         .filter_frame = filter_frame,
         .config_props = &ff_opencl_filter_config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad pad_opencl_outputs[] = {
@@ -363,7 +362,6 @@ static const AVFilterPad pad_opencl_outputs[] = {
         .type = AVMEDIA_TYPE_VIDEO,
         .config_props = &pad_opencl_config_output,
     },
-    { NULL }
 };
 
 #define OFFSET(x) offsetof(PadOpenCLContext, x)
@@ -391,7 +389,7 @@ const AVFilter ff_vf_pad_opencl = {
     .init           = &ff_opencl_filter_init,
     .uninit         = &pad_opencl_uninit,
     .query_formats  = &ff_opencl_filter_query_formats,
-    .inputs         = pad_opencl_inputs,
-    .outputs        = pad_opencl_outputs,
+    FILTER_INPUTS(pad_opencl_inputs),
+    FILTER_OUTPUTS(pad_opencl_outputs),
     .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE
 };
diff --git a/libavfilter/vf_palettegen.c b/libavfilter/vf_palettegen.c
index 048ef8e994..4c2fbd36d7 100644
--- a/libavfilter/vf_palettegen.c
+++ b/libavfilter/vf_palettegen.c
@@ -557,7 +557,6 @@ static const AVFilterPad palettegen_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad palettegen_outputs[] = {
@@ -567,7 +566,6 @@ static const AVFilterPad palettegen_outputs[] = {
         .config_props  = config_output,
         .request_frame = request_frame,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_palettegen = {
@@ -576,7 +574,7 @@ const AVFilter ff_vf_palettegen = {
     .priv_size     = sizeof(PaletteGenContext),
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = palettegen_inputs,
-    .outputs       = palettegen_outputs,
+    FILTER_INPUTS(palettegen_inputs),
+    FILTER_OUTPUTS(palettegen_outputs),
     .priv_class    = &palettegen_class,
 };
diff --git a/libavfilter/vf_paletteuse.c b/libavfilter/vf_paletteuse.c
index 1de6a67738..f9bc28f7d0 100644
--- a/libavfilter/vf_paletteuse.c
+++ b/libavfilter/vf_paletteuse.c
@@ -1118,7 +1118,6 @@ static const AVFilterPad paletteuse_inputs[] = {
         .type           = AVMEDIA_TYPE_VIDEO,
         .config_props   = config_input_palette,
     },
-    { NULL }
 };
 
 static const AVFilterPad paletteuse_outputs[] = {
@@ -1127,7 +1126,6 @@ static const AVFilterPad paletteuse_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_paletteuse = {
@@ -1138,7 +1136,7 @@ const AVFilter ff_vf_paletteuse = {
     .init          = init,
     .uninit        = uninit,
     .activate      = activate,
-    .inputs        = paletteuse_inputs,
-    .outputs       = paletteuse_outputs,
+    FILTER_INPUTS(paletteuse_inputs),
+    FILTER_OUTPUTS(paletteuse_outputs),
     .priv_class    = &paletteuse_class,
 };
diff --git a/libavfilter/vf_perspective.c b/libavfilter/vf_perspective.c
index acfafe2bb0..5fa661862f 100644
--- a/libavfilter/vf_perspective.c
+++ b/libavfilter/vf_perspective.c
@@ -498,7 +498,6 @@ static const AVFilterPad perspective_inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad perspective_outputs[] = {
@@ -506,7 +505,6 @@ static const AVFilterPad perspective_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_perspective = {
@@ -516,8 +514,8 @@ const AVFilter ff_vf_perspective = {
     .init          = init,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = perspective_inputs,
-    .outputs       = perspective_outputs,
+    FILTER_INPUTS(perspective_inputs),
+    FILTER_OUTPUTS(perspective_outputs),
     .priv_class    = &perspective_class,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
 };
diff --git a/libavfilter/vf_phase.c b/libavfilter/vf_phase.c
index 3262454348..cab6174d72 100644
--- a/libavfilter/vf_phase.c
+++ b/libavfilter/vf_phase.c
@@ -221,7 +221,6 @@ static const AVFilterPad phase_inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad phase_outputs[] = {
@@ -229,7 +228,6 @@ static const AVFilterPad phase_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_phase = {
@@ -239,8 +237,8 @@ const AVFilter ff_vf_phase = {
     .priv_class    = &phase_class,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = phase_inputs,
-    .outputs       = phase_outputs,
+    FILTER_INPUTS(phase_inputs),
+    FILTER_OUTPUTS(phase_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
     .process_command = ff_filter_process_command,
 };
diff --git a/libavfilter/vf_photosensitivity.c b/libavfilter/vf_photosensitivity.c
index 1237330fff..a5a86133f1 100644
--- a/libavfilter/vf_photosensitivity.c
+++ b/libavfilter/vf_photosensitivity.c
@@ -317,7 +317,6 @@ static const AVFilterPad inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -325,7 +324,6 @@ static const AVFilterPad outputs[] = {
         .name          = "default",
         .type          = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_photosensitivity = {
@@ -335,6 +333,6 @@ const AVFilter ff_vf_photosensitivity = {
     .priv_class    = &photosensitivity_class,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = inputs,
-    .outputs       = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
 };
diff --git a/libavfilter/vf_pixdesctest.c b/libavfilter/vf_pixdesctest.c
index b56839d994..12815aea9c 100644
--- a/libavfilter/vf_pixdesctest.c
+++ b/libavfilter/vf_pixdesctest.c
@@ -113,7 +113,6 @@ static const AVFilterPad avfilter_vf_pixdesctest_inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_props,
     },
-    { NULL }
 };
 
 static const AVFilterPad avfilter_vf_pixdesctest_outputs[] = {
@@ -121,7 +120,6 @@ static const AVFilterPad avfilter_vf_pixdesctest_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_pixdesctest = {
@@ -129,6 +127,6 @@ const AVFilter ff_vf_pixdesctest = {
     .description = NULL_IF_CONFIG_SMALL("Test pixel format definitions."),
     .priv_size   = sizeof(PixdescTestContext),
     .uninit      = uninit,
-    .inputs      = avfilter_vf_pixdesctest_inputs,
-    .outputs     = avfilter_vf_pixdesctest_outputs,
+    FILTER_INPUTS(avfilter_vf_pixdesctest_inputs),
+    FILTER_OUTPUTS(avfilter_vf_pixdesctest_outputs),
 };
diff --git a/libavfilter/vf_pp.c b/libavfilter/vf_pp.c
index 3fb1333bd6..c27c2029c0 100644
--- a/libavfilter/vf_pp.c
+++ b/libavfilter/vf_pp.c
@@ -177,7 +177,6 @@ static const AVFilterPad pp_inputs[] = {
         .config_props = pp_config_props,
         .filter_frame = pp_filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad pp_outputs[] = {
@@ -185,7 +184,6 @@ static const AVFilterPad pp_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_pp = {
@@ -195,8 +193,8 @@ const AVFilter ff_vf_pp = {
     .init            = pp_init,
     .uninit          = pp_uninit,
     .query_formats   = pp_query_formats,
-    .inputs          = pp_inputs,
-    .outputs         = pp_outputs,
+    FILTER_INPUTS(pp_inputs),
+    FILTER_OUTPUTS(pp_outputs),
     .process_command = pp_process_command,
     .priv_class      = &pp_class,
     .flags           = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
diff --git a/libavfilter/vf_pp7.c b/libavfilter/vf_pp7.c
index d632d9bea8..74f20365e0 100644
--- a/libavfilter/vf_pp7.c
+++ b/libavfilter/vf_pp7.c
@@ -387,7 +387,6 @@ static const AVFilterPad pp7_inputs[] = {
         .config_props = config_input,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad pp7_outputs[] = {
@@ -395,7 +394,6 @@ static const AVFilterPad pp7_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_pp7 = {
@@ -404,8 +402,8 @@ const AVFilter ff_vf_pp7 = {
     .priv_size       = sizeof(PP7Context),
     .uninit          = uninit,
     .query_formats   = query_formats,
-    .inputs          = pp7_inputs,
-    .outputs         = pp7_outputs,
+    FILTER_INPUTS(pp7_inputs),
+    FILTER_OUTPUTS(pp7_outputs),
     .priv_class      = &pp7_class,
     .flags           = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
 };
diff --git a/libavfilter/vf_premultiply.c b/libavfilter/vf_premultiply.c
index 95eabf3883..70a5bf3b11 100644
--- a/libavfilter/vf_premultiply.c
+++ b/libavfilter/vf_premultiply.c
@@ -819,7 +819,6 @@ static const AVFilterPad premultiply_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 #if CONFIG_PREMULTIPLY_FILTER
@@ -833,7 +832,7 @@ const AVFilter ff_vf_premultiply = {
     .query_formats = query_formats,
     .activate      = activate,
     .inputs        = NULL,
-    .outputs       = premultiply_outputs,
+    FILTER_OUTPUTS(premultiply_outputs),
     .priv_class    = &premultiply_class,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL |
                      AVFILTER_FLAG_DYNAMIC_INPUTS |
@@ -856,7 +855,7 @@ const AVFilter ff_vf_unpremultiply = {
     .query_formats = query_formats,
     .activate      = activate,
     .inputs        = NULL,
-    .outputs       = premultiply_outputs,
+    FILTER_OUTPUTS(premultiply_outputs),
     .priv_class    = &unpremultiply_class,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL |
                      AVFILTER_FLAG_DYNAMIC_INPUTS |
diff --git a/libavfilter/vf_procamp_vaapi.c b/libavfilter/vf_procamp_vaapi.c
index 5527556d09..758546abf9 100644
--- a/libavfilter/vf_procamp_vaapi.c
+++ b/libavfilter/vf_procamp_vaapi.c
@@ -219,7 +219,6 @@ static const AVFilterPad procamp_vaapi_inputs[] = {
         .filter_frame = &procamp_vaapi_filter_frame,
         .config_props = &ff_vaapi_vpp_config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad procamp_vaapi_outputs[] = {
@@ -228,7 +227,6 @@ static const AVFilterPad procamp_vaapi_outputs[] = {
         .type = AVMEDIA_TYPE_VIDEO,
         .config_props = &ff_vaapi_vpp_config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_procamp_vaapi = {
@@ -238,8 +236,8 @@ const AVFilter ff_vf_procamp_vaapi = {
     .init          = &procamp_vaapi_init,
     .uninit        = &ff_vaapi_vpp_ctx_uninit,
     .query_formats = &ff_vaapi_vpp_query_formats,
-    .inputs        = procamp_vaapi_inputs,
-    .outputs       = procamp_vaapi_outputs,
+    FILTER_INPUTS(procamp_vaapi_inputs),
+    FILTER_OUTPUTS(procamp_vaapi_outputs),
     .priv_class    = &procamp_vaapi_class,
     .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
 };
diff --git a/libavfilter/vf_program_opencl.c b/libavfilter/vf_program_opencl.c
index 502d797154..d80aa9be04 100644
--- a/libavfilter/vf_program_opencl.c
+++ b/libavfilter/vf_program_opencl.c
@@ -359,7 +359,6 @@ static const AVFilterPad program_opencl_outputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = &program_opencl_config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_program_opencl = {
@@ -374,7 +373,7 @@ const AVFilter ff_vf_program_opencl = {
     .query_formats  = &ff_opencl_filter_query_formats,
     .activate       = &program_opencl_activate,
     .inputs         = NULL,
-    .outputs        = program_opencl_outputs,
+    FILTER_OUTPUTS(program_opencl_outputs),
     .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
 };
 
@@ -413,7 +412,6 @@ static const AVFilterPad openclsrc_outputs[] = {
         .config_props  = &program_opencl_config_output,
         .request_frame = &program_opencl_request_frame,
     },
-    { NULL }
 };
 
 const AVFilter ff_vsrc_openclsrc = {
@@ -425,7 +423,7 @@ const AVFilter ff_vsrc_openclsrc = {
     .uninit         = &program_opencl_uninit,
     .query_formats  = &ff_opencl_filter_query_formats,
     .inputs         = NULL,
-    .outputs        = openclsrc_outputs,
+    FILTER_OUTPUTS(openclsrc_outputs),
     .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
 };
 
diff --git a/libavfilter/vf_pseudocolor.c b/libavfilter/vf_pseudocolor.c
index d860bc7223..44cb01ef9a 100644
--- a/libavfilter/vf_pseudocolor.c
+++ b/libavfilter/vf_pseudocolor.c
@@ -894,7 +894,6 @@ static const AVFilterPad inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -902,7 +901,6 @@ static const AVFilterPad outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 static av_cold void uninit(AVFilterContext *ctx)
@@ -925,8 +923,8 @@ const AVFilter ff_vf_pseudocolor = {
     .priv_class    = &pseudocolor_class,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = inputs,
-    .outputs       = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
     .process_command = process_command,
 };
diff --git a/libavfilter/vf_psnr.c b/libavfilter/vf_psnr.c
index 5f93fa5fc7..d254d0cb55 100644
--- a/libavfilter/vf_psnr.c
+++ b/libavfilter/vf_psnr.c
@@ -453,7 +453,6 @@ static const AVFilterPad psnr_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_input_ref,
     },
-    { NULL }
 };
 
 static const AVFilterPad psnr_outputs[] = {
@@ -462,7 +461,6 @@ static const AVFilterPad psnr_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_psnr = {
@@ -475,7 +473,7 @@ const AVFilter ff_vf_psnr = {
     .activate      = activate,
     .priv_size     = sizeof(PSNRContext),
     .priv_class    = &psnr_class,
-    .inputs        = psnr_inputs,
-    .outputs       = psnr_outputs,
+    FILTER_INPUTS(psnr_inputs),
+    FILTER_OUTPUTS(psnr_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | AVFILTER_FLAG_SLICE_THREADS,
 };
diff --git a/libavfilter/vf_pullup.c b/libavfilter/vf_pullup.c
index 8be10b4fa4..57e86e9c89 100644
--- a/libavfilter/vf_pullup.c
+++ b/libavfilter/vf_pullup.c
@@ -750,7 +750,6 @@ static const AVFilterPad pullup_inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad pullup_outputs[] = {
@@ -758,7 +757,6 @@ static const AVFilterPad pullup_outputs[] = {
         .name         = "default",
         .type         = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_pullup = {
@@ -768,6 +766,6 @@ const AVFilter ff_vf_pullup = {
     .priv_class    = &pullup_class,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = pullup_inputs,
-    .outputs       = pullup_outputs,
+    FILTER_INPUTS(pullup_inputs),
+    FILTER_OUTPUTS(pullup_outputs),
 };
diff --git a/libavfilter/vf_qp.c b/libavfilter/vf_qp.c
index c932d45a76..d942ba1579 100644
--- a/libavfilter/vf_qp.c
+++ b/libavfilter/vf_qp.c
@@ -182,7 +182,6 @@ static const AVFilterPad qp_inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad qp_outputs[] = {
@@ -190,15 +189,14 @@ static const AVFilterPad qp_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_qp = {
     .name          = "qp",
     .description   = NULL_IF_CONFIG_SMALL("Change video quantization parameters."),
     .priv_size     = sizeof(QPContext),
-    .inputs        = qp_inputs,
-    .outputs       = qp_outputs,
+    FILTER_INPUTS(qp_inputs),
+    FILTER_OUTPUTS(qp_outputs),
     .priv_class    = &qp_class,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
 };
diff --git a/libavfilter/vf_random.c b/libavfilter/vf_random.c
index 5e4c30a3b5..b3acdd1fcf 100644
--- a/libavfilter/vf_random.c
+++ b/libavfilter/vf_random.c
@@ -127,7 +127,6 @@ static const AVFilterPad random_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad random_outputs[] = {
@@ -136,7 +135,6 @@ static const AVFilterPad random_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .request_frame = request_frame,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_random = {
@@ -146,6 +144,6 @@ const AVFilter ff_vf_random = {
     .priv_class  = &random_class,
     .init        = init,
     .uninit      = uninit,
-    .inputs      = random_inputs,
-    .outputs     = random_outputs,
+    FILTER_INPUTS(random_inputs),
+    FILTER_OUTPUTS(random_outputs),
 };
diff --git a/libavfilter/vf_readeia608.c b/libavfilter/vf_readeia608.c
index 49e1c27ce6..2d6d0653a1 100644
--- a/libavfilter/vf_readeia608.c
+++ b/libavfilter/vf_readeia608.c
@@ -542,7 +542,6 @@ static const AVFilterPad readeia608_inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad readeia608_outputs[] = {
@@ -550,7 +549,6 @@ static const AVFilterPad readeia608_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_readeia608 = {
@@ -559,8 +557,8 @@ const AVFilter ff_vf_readeia608 = {
     .priv_size     = sizeof(ReadEIA608Context),
     .priv_class    = &readeia608_class,
     .query_formats = query_formats,
-    .inputs        = readeia608_inputs,
-    .outputs       = readeia608_outputs,
+    FILTER_INPUTS(readeia608_inputs),
+    FILTER_OUTPUTS(readeia608_outputs),
     .uninit        = uninit,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
     .process_command = process_command,
diff --git a/libavfilter/vf_readvitc.c b/libavfilter/vf_readvitc.c
index 8dde55b7da..d117a81284 100644
--- a/libavfilter/vf_readvitc.c
+++ b/libavfilter/vf_readvitc.c
@@ -232,7 +232,6 @@ static const AVFilterPad inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_props,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -240,7 +239,6 @@ static const AVFilterPad outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_readvitc = {
@@ -248,8 +246,8 @@ const AVFilter ff_vf_readvitc = {
     .description   = NULL_IF_CONFIG_SMALL("Read vertical interval timecode and write it to frame metadata."),
     .priv_size     = sizeof(ReadVitcContext),
     .priv_class    = &readvitc_class,
-    .inputs        = inputs,
-    .outputs       = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
     .init          = init,
     .query_formats = query_formats,
 };
diff --git a/libavfilter/vf_remap.c b/libavfilter/vf_remap.c
index 9c6e3c390f..d372ac1d7d 100644
--- a/libavfilter/vf_remap.c
+++ b/libavfilter/vf_remap.c
@@ -387,7 +387,6 @@ static const AVFilterPad remap_inputs[] = {
         .name         = "ymap",
         .type         = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 static const AVFilterPad remap_outputs[] = {
@@ -396,7 +395,6 @@ static const AVFilterPad remap_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_remap = {
@@ -406,8 +404,8 @@ const AVFilter ff_vf_remap = {
     .uninit        = uninit,
     .query_formats = query_formats,
     .activate      = activate,
-    .inputs        = remap_inputs,
-    .outputs       = remap_outputs,
+    FILTER_INPUTS(remap_inputs),
+    FILTER_OUTPUTS(remap_outputs),
     .priv_class    = &remap_class,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
 };
diff --git a/libavfilter/vf_removegrain.c b/libavfilter/vf_removegrain.c
index b3bb51175d..1d1d756057 100644
--- a/libavfilter/vf_removegrain.c
+++ b/libavfilter/vf_removegrain.c
@@ -634,7 +634,6 @@ static const AVFilterPad removegrain_inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad removegrain_outputs[] = {
@@ -642,7 +641,6 @@ static const AVFilterPad removegrain_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_removegrain = {
@@ -650,8 +648,8 @@ const AVFilter ff_vf_removegrain = {
     .description   = NULL_IF_CONFIG_SMALL("Remove grain."),
     .priv_size     = sizeof(RemoveGrainContext),
     .query_formats = query_formats,
-    .inputs        = removegrain_inputs,
-    .outputs       = removegrain_outputs,
+    FILTER_INPUTS(removegrain_inputs),
+    FILTER_OUTPUTS(removegrain_outputs),
     .priv_class    = &removegrain_class,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
 };
diff --git a/libavfilter/vf_removelogo.c b/libavfilter/vf_removelogo.c
index 92eeb2e5f5..acf09960ff 100644
--- a/libavfilter/vf_removelogo.c
+++ b/libavfilter/vf_removelogo.c
@@ -559,7 +559,6 @@ static const AVFilterPad removelogo_inputs[] = {
         .config_props = config_props_input,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad removelogo_outputs[] = {
@@ -567,7 +566,6 @@ static const AVFilterPad removelogo_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_removelogo = {
@@ -577,8 +575,8 @@ const AVFilter ff_vf_removelogo = {
     .init          = init,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = removelogo_inputs,
-    .outputs       = removelogo_outputs,
+    FILTER_INPUTS(removelogo_inputs),
+    FILTER_OUTPUTS(removelogo_outputs),
     .priv_class    = &removelogo_class,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
 };
diff --git a/libavfilter/vf_repeatfields.c b/libavfilter/vf_repeatfields.c
index 75f2fdbfb2..ca4bd97b2f 100644
--- a/libavfilter/vf_repeatfields.c
+++ b/libavfilter/vf_repeatfields.c
@@ -167,7 +167,6 @@ static const AVFilterPad repeatfields_inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad repeatfields_outputs[] = {
@@ -175,7 +174,6 @@ static const AVFilterPad repeatfields_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_repeatfields = {
@@ -183,7 +181,7 @@ const AVFilter ff_vf_repeatfields = {
     .description   = NULL_IF_CONFIG_SMALL("Hard repeat fields based on MPEG repeat field flag."),
     .priv_size     = sizeof(RepeatFieldsContext),
     .uninit        = uninit,
-    .inputs        = repeatfields_inputs,
-    .outputs       = repeatfields_outputs,
+    FILTER_INPUTS(repeatfields_inputs),
+    FILTER_OUTPUTS(repeatfields_outputs),
     .query_formats = query_formats,
 };
diff --git a/libavfilter/vf_rotate.c b/libavfilter/vf_rotate.c
index d7f2cd77c4..c74e1adff9 100644
--- a/libavfilter/vf_rotate.c
+++ b/libavfilter/vf_rotate.c
@@ -585,7 +585,6 @@ static const AVFilterPad rotate_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad rotate_outputs[] = {
@@ -594,7 +593,6 @@ static const AVFilterPad rotate_outputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_props,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_rotate = {
@@ -605,8 +603,8 @@ const AVFilter ff_vf_rotate = {
     .uninit        = uninit,
     .query_formats = query_formats,
     .process_command = process_command,
-    .inputs        = rotate_inputs,
-    .outputs       = rotate_outputs,
+    FILTER_INPUTS(rotate_inputs),
+    FILTER_OUTPUTS(rotate_outputs),
     .priv_class    = &rotate_class,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
 };
diff --git a/libavfilter/vf_sab.c b/libavfilter/vf_sab.c
index b4f8f128b7..bc7e7e30ed 100644
--- a/libavfilter/vf_sab.c
+++ b/libavfilter/vf_sab.c
@@ -309,7 +309,6 @@ static const AVFilterPad sab_inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_props,
     },
-    { NULL }
 };
 
 static const AVFilterPad sab_outputs[] = {
@@ -317,7 +316,6 @@ static const AVFilterPad sab_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_sab = {
@@ -327,8 +325,8 @@ const AVFilter ff_vf_sab = {
     .init          = init,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = sab_inputs,
-    .outputs       = sab_outputs,
+    FILTER_INPUTS(sab_inputs),
+    FILTER_OUTPUTS(sab_outputs),
     .priv_class    = &sab_class,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
 };
diff --git a/libavfilter/vf_scale.c b/libavfilter/vf_scale.c
index 160ad8b584..ce39217515 100644
--- a/libavfilter/vf_scale.c
+++ b/libavfilter/vf_scale.c
@@ -957,7 +957,6 @@ static const AVFilterPad avfilter_vf_scale_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad avfilter_vf_scale_outputs[] = {
@@ -966,7 +965,6 @@ static const AVFilterPad avfilter_vf_scale_outputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_props,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_scale = {
@@ -977,8 +975,8 @@ const AVFilter ff_vf_scale = {
     .query_formats   = query_formats,
     .priv_size       = sizeof(ScaleContext),
     .priv_class      = &scale_class,
-    .inputs          = avfilter_vf_scale_inputs,
-    .outputs         = avfilter_vf_scale_outputs,
+    FILTER_INPUTS(avfilter_vf_scale_inputs),
+    FILTER_OUTPUTS(avfilter_vf_scale_outputs),
     .process_command = process_command,
 };
 
@@ -1002,7 +1000,6 @@ static const AVFilterPad avfilter_vf_scale2ref_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame_ref,
     },
-    { NULL }
 };
 
 static const AVFilterPad avfilter_vf_scale2ref_outputs[] = {
@@ -1018,7 +1015,6 @@ static const AVFilterPad avfilter_vf_scale2ref_outputs[] = {
         .config_props = config_props_ref,
         .request_frame= request_frame_ref,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_scale2ref = {
@@ -1029,7 +1025,7 @@ const AVFilter ff_vf_scale2ref = {
     .query_formats   = query_formats,
     .priv_size       = sizeof(ScaleContext),
     .priv_class      = &scale2ref_class,
-    .inputs          = avfilter_vf_scale2ref_inputs,
-    .outputs         = avfilter_vf_scale2ref_outputs,
+    FILTER_INPUTS(avfilter_vf_scale2ref_inputs),
+    FILTER_OUTPUTS(avfilter_vf_scale2ref_outputs),
     .process_command = process_command,
 };
diff --git a/libavfilter/vf_scale_cuda.c b/libavfilter/vf_scale_cuda.c
index 16f345402d..fa7b799e0e 100644
--- a/libavfilter/vf_scale_cuda.c
+++ b/libavfilter/vf_scale_cuda.c
@@ -625,7 +625,6 @@ static const AVFilterPad cudascale_inputs[] = {
         .filter_frame = cudascale_filter_frame,
         .get_buffer.video = cudascale_get_video_buffer,
     },
-    { NULL }
 };
 
 static const AVFilterPad cudascale_outputs[] = {
@@ -634,7 +633,6 @@ static const AVFilterPad cudascale_outputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = cudascale_config_props,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_scale_cuda = {
@@ -648,8 +646,8 @@ const AVFilter ff_vf_scale_cuda = {
     .priv_size = sizeof(CUDAScaleContext),
     .priv_class = &cudascale_class,
 
-    .inputs    = cudascale_inputs,
-    .outputs   = cudascale_outputs,
+    FILTER_INPUTS(cudascale_inputs),
+    FILTER_OUTPUTS(cudascale_outputs),
 
     .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
 };
diff --git a/libavfilter/vf_scale_npp.c b/libavfilter/vf_scale_npp.c
index 3f5538ad3f..3e25c2c95f 100644
--- a/libavfilter/vf_scale_npp.c
+++ b/libavfilter/vf_scale_npp.c
@@ -577,7 +577,6 @@ static const AVFilterPad nppscale_inputs[] = {
         .type        = AVMEDIA_TYPE_VIDEO,
         .filter_frame = nppscale_filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad nppscale_outputs[] = {
@@ -586,7 +585,6 @@ static const AVFilterPad nppscale_outputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = nppscale_config_props,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_scale_npp = {
@@ -601,8 +599,8 @@ const AVFilter ff_vf_scale_npp = {
     .priv_size = sizeof(NPPScaleContext),
     .priv_class = &nppscale_class,
 
-    .inputs    = nppscale_inputs,
-    .outputs   = nppscale_outputs,
+    FILTER_INPUTS(nppscale_inputs),
+    FILTER_OUTPUTS(nppscale_outputs),
 
     .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
 };
diff --git a/libavfilter/vf_scale_qsv.c b/libavfilter/vf_scale_qsv.c
index 2f3afa6ace..2c9f8e153b 100644
--- a/libavfilter/vf_scale_qsv.c
+++ b/libavfilter/vf_scale_qsv.c
@@ -650,7 +650,6 @@ static const AVFilterPad qsvscale_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = qsvscale_filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad qsvscale_outputs[] = {
@@ -659,7 +658,6 @@ static const AVFilterPad qsvscale_outputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = qsvscale_config_props,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_scale_qsv = {
@@ -673,8 +671,8 @@ const AVFilter ff_vf_scale_qsv = {
     .priv_size = sizeof(QSVScaleContext),
     .priv_class = &qsvscale_class,
 
-    .inputs    = qsvscale_inputs,
-    .outputs   = qsvscale_outputs,
+    FILTER_INPUTS(qsvscale_inputs),
+    FILTER_OUTPUTS(qsvscale_outputs),
 
     .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
 };
diff --git a/libavfilter/vf_scale_vaapi.c b/libavfilter/vf_scale_vaapi.c
index 41ff93156d..554b7bac4f 100644
--- a/libavfilter/vf_scale_vaapi.c
+++ b/libavfilter/vf_scale_vaapi.c
@@ -269,7 +269,6 @@ static const AVFilterPad scale_vaapi_inputs[] = {
         .filter_frame = &scale_vaapi_filter_frame,
         .config_props = &ff_vaapi_vpp_config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad scale_vaapi_outputs[] = {
@@ -278,7 +277,6 @@ static const AVFilterPad scale_vaapi_outputs[] = {
         .type = AVMEDIA_TYPE_VIDEO,
         .config_props = &scale_vaapi_config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_scale_vaapi = {
@@ -288,8 +286,8 @@ const AVFilter ff_vf_scale_vaapi = {
     .init          = &scale_vaapi_init,
     .uninit        = &ff_vaapi_vpp_ctx_uninit,
     .query_formats = &ff_vaapi_vpp_query_formats,
-    .inputs        = scale_vaapi_inputs,
-    .outputs       = scale_vaapi_outputs,
+    FILTER_INPUTS(scale_vaapi_inputs),
+    FILTER_OUTPUTS(scale_vaapi_outputs),
     .priv_class    = &scale_vaapi_class,
     .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
 };
diff --git a/libavfilter/vf_scale_vulkan.c b/libavfilter/vf_scale_vulkan.c
index 95503480ef..4eb4fe5664 100644
--- a/libavfilter/vf_scale_vulkan.c
+++ b/libavfilter/vf_scale_vulkan.c
@@ -512,7 +512,6 @@ static const AVFilterPad scale_vulkan_inputs[] = {
         .filter_frame = &scale_vulkan_filter_frame,
         .config_props = &ff_vk_filter_config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad scale_vulkan_outputs[] = {
@@ -521,7 +520,6 @@ static const AVFilterPad scale_vulkan_outputs[] = {
         .type = AVMEDIA_TYPE_VIDEO,
         .config_props = &scale_vulkan_config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_scale_vulkan = {
@@ -531,8 +529,8 @@ const AVFilter ff_vf_scale_vulkan = {
     .init           = &ff_vk_filter_init,
     .uninit         = &scale_vulkan_uninit,
     .query_formats  = &ff_vk_filter_query_formats,
-    .inputs         = scale_vulkan_inputs,
-    .outputs        = scale_vulkan_outputs,
+    FILTER_INPUTS(scale_vulkan_inputs),
+    FILTER_OUTPUTS(scale_vulkan_outputs),
     .priv_class     = &scale_vulkan_class,
     .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
 };
diff --git a/libavfilter/vf_scdet.c b/libavfilter/vf_scdet.c
index b9ea30d47a..b8017a00e5 100644
--- a/libavfilter/vf_scdet.c
+++ b/libavfilter/vf_scdet.c
@@ -196,7 +196,6 @@ static const AVFilterPad scdet_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad scdet_outputs[] = {
@@ -204,7 +203,6 @@ static const AVFilterPad scdet_outputs[] = {
         .name          = "default",
         .type          = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_scdet = {
@@ -214,7 +212,7 @@ const AVFilter ff_vf_scdet = {
     .priv_class    = &scdet_class,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = scdet_inputs,
-    .outputs       = scdet_outputs,
+    FILTER_INPUTS(scdet_inputs),
+    FILTER_OUTPUTS(scdet_outputs),
     .activate      = activate,
 };
diff --git a/libavfilter/vf_scroll.c b/libavfilter/vf_scroll.c
index 278d38bd1b..5e9cf76095 100644
--- a/libavfilter/vf_scroll.c
+++ b/libavfilter/vf_scroll.c
@@ -197,7 +197,6 @@ static const AVFilterPad scroll_inputs[] = {
         .config_props   = config_input,
         .filter_frame   = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad scroll_outputs[] = {
@@ -205,7 +204,6 @@ static const AVFilterPad scroll_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_scroll = {
@@ -214,8 +212,8 @@ const AVFilter ff_vf_scroll = {
     .priv_size     = sizeof(ScrollContext),
     .priv_class    = &scroll_class,
     .query_formats = query_formats,
-    .inputs        = scroll_inputs,
-    .outputs       = scroll_outputs,
+    FILTER_INPUTS(scroll_inputs),
+    FILTER_OUTPUTS(scroll_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
     .process_command = ff_filter_process_command,
 };
diff --git a/libavfilter/vf_selectivecolor.c b/libavfilter/vf_selectivecolor.c
index 167fc88c86..ebbba9157f 100644
--- a/libavfilter/vf_selectivecolor.c
+++ b/libavfilter/vf_selectivecolor.c
@@ -456,7 +456,6 @@ static const AVFilterPad selectivecolor_inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad selectivecolor_outputs[] = {
@@ -464,7 +463,6 @@ static const AVFilterPad selectivecolor_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_selectivecolor = {
@@ -472,8 +470,8 @@ const AVFilter ff_vf_selectivecolor = {
     .description   = NULL_IF_CONFIG_SMALL("Apply CMYK adjustments to specific color ranges."),
     .priv_size     = sizeof(SelectiveColorContext),
     .query_formats = query_formats,
-    .inputs        = selectivecolor_inputs,
-    .outputs       = selectivecolor_outputs,
+    FILTER_INPUTS(selectivecolor_inputs),
+    FILTER_OUTPUTS(selectivecolor_outputs),
     .priv_class    = &selectivecolor_class,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
 };
diff --git a/libavfilter/vf_separatefields.c b/libavfilter/vf_separatefields.c
index c2c7352ad1..7db64c5479 100644
--- a/libavfilter/vf_separatefields.c
+++ b/libavfilter/vf_separatefields.c
@@ -161,7 +161,6 @@ static const AVFilterPad separatefields_inputs[] = {
         .name         = "default",
         .type         = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 static const AVFilterPad separatefields_outputs[] = {
@@ -170,7 +169,6 @@ static const AVFilterPad separatefields_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_props_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_separatefields = {
@@ -179,6 +177,6 @@ const AVFilter ff_vf_separatefields = {
     .priv_size   = sizeof(SeparateFieldsContext),
     .activate    = activate,
     .uninit      = uninit,
-    .inputs      = separatefields_inputs,
-    .outputs     = separatefields_outputs,
+    FILTER_INPUTS(separatefields_inputs),
+    FILTER_OUTPUTS(separatefields_outputs),
 };
diff --git a/libavfilter/vf_setparams.c b/libavfilter/vf_setparams.c
index 0cb3af33ed..0a79599bab 100644
--- a/libavfilter/vf_setparams.c
+++ b/libavfilter/vf_setparams.c
@@ -151,7 +151,6 @@ static const AVFilterPad inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -159,7 +158,6 @@ static const AVFilterPad outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_setparams = {
@@ -167,8 +165,8 @@ const AVFilter ff_vf_setparams = {
     .description = NULL_IF_CONFIG_SMALL("Force field, or color property for the output video frame."),
     .priv_size   = sizeof(SetParamsContext),
     .priv_class  = &setparams_class,
-    .inputs      = inputs,
-    .outputs     = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
 };
 
 #if CONFIG_SETRANGE_FILTER
@@ -206,8 +204,8 @@ const AVFilter ff_vf_setrange = {
     .priv_size   = sizeof(SetParamsContext),
     .init        = init_setrange,
     .priv_class  = &setrange_class,
-    .inputs      = inputs,
-    .outputs     = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
 };
 #endif /* CONFIG_SETRANGE_FILTER */
 
@@ -240,7 +238,7 @@ const AVFilter ff_vf_setfield = {
     .priv_size   = sizeof(SetParamsContext),
     .init        = init_setfield,
     .priv_class  = &setfield_class,
-    .inputs      = inputs,
-    .outputs     = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
 };
 #endif /* CONFIG_SETFIELD_FILTER */
diff --git a/libavfilter/vf_shear.c b/libavfilter/vf_shear.c
index ed7540c90a..e58084d3cd 100644
--- a/libavfilter/vf_shear.c
+++ b/libavfilter/vf_shear.c
@@ -302,7 +302,6 @@ static const AVFilterPad inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -311,7 +310,6 @@ static const AVFilterPad outputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_shear = {
@@ -320,8 +318,8 @@ const AVFilter ff_vf_shear = {
     .priv_size       = sizeof(ShearContext),
     .init            = init,
     .query_formats   = query_formats,
-    .inputs          = inputs,
-    .outputs         = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
     .priv_class      = &shear_class,
     .flags           = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
     .process_command = process_command,
diff --git a/libavfilter/vf_showinfo.c b/libavfilter/vf_showinfo.c
index dfb7f86359..87c2bed73d 100644
--- a/libavfilter/vf_showinfo.c
+++ b/libavfilter/vf_showinfo.c
@@ -661,7 +661,6 @@ static const AVFilterPad avfilter_vf_showinfo_inputs[] = {
         .filter_frame     = filter_frame,
         .config_props     = config_props_in,
     },
-    { NULL }
 };
 
 static const AVFilterPad avfilter_vf_showinfo_outputs[] = {
@@ -670,14 +669,13 @@ static const AVFilterPad avfilter_vf_showinfo_outputs[] = {
         .type = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_props_out,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_showinfo = {
     .name        = "showinfo",
     .description = NULL_IF_CONFIG_SMALL("Show textual information for each video frame."),
-    .inputs      = avfilter_vf_showinfo_inputs,
-    .outputs     = avfilter_vf_showinfo_outputs,
+    FILTER_INPUTS(avfilter_vf_showinfo_inputs),
+    FILTER_OUTPUTS(avfilter_vf_showinfo_outputs),
     .priv_size   = sizeof(ShowInfoContext),
     .priv_class  = &showinfo_class,
 };
diff --git a/libavfilter/vf_showpalette.c b/libavfilter/vf_showpalette.c
index 2455af687c..569f5040d0 100644
--- a/libavfilter/vf_showpalette.c
+++ b/libavfilter/vf_showpalette.c
@@ -100,7 +100,6 @@ static const AVFilterPad showpalette_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad showpalette_outputs[] = {
@@ -109,7 +108,6 @@ static const AVFilterPad showpalette_outputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_showpalette = {
@@ -117,7 +115,7 @@ const AVFilter ff_vf_showpalette = {
     .description   = NULL_IF_CONFIG_SMALL("Display frame palette."),
     .priv_size     = sizeof(ShowPaletteContext),
     .query_formats = query_formats,
-    .inputs        = showpalette_inputs,
-    .outputs       = showpalette_outputs,
+    FILTER_INPUTS(showpalette_inputs),
+    FILTER_OUTPUTS(showpalette_outputs),
     .priv_class    = &showpalette_class,
 };
diff --git a/libavfilter/vf_shuffleframes.c b/libavfilter/vf_shuffleframes.c
index cdc70f552e..14b90e6446 100644
--- a/libavfilter/vf_shuffleframes.c
+++ b/libavfilter/vf_shuffleframes.c
@@ -144,7 +144,6 @@ static const AVFilterPad shuffleframes_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
     },
-    { NULL },
 };
 
 static const AVFilterPad shuffleframes_outputs[] = {
@@ -152,7 +151,6 @@ static const AVFilterPad shuffleframes_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL },
 };
 
 const AVFilter ff_vf_shuffleframes = {
@@ -162,7 +160,7 @@ const AVFilter ff_vf_shuffleframes = {
     .priv_class    = &shuffleframes_class,
     .init          = init,
     .uninit        = uninit,
-    .inputs        = shuffleframes_inputs,
-    .outputs       = shuffleframes_outputs,
+    FILTER_INPUTS(shuffleframes_inputs),
+    FILTER_OUTPUTS(shuffleframes_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
 };
diff --git a/libavfilter/vf_shufflepixels.c b/libavfilter/vf_shufflepixels.c
index aeb41f7896..aa8c726971 100644
--- a/libavfilter/vf_shufflepixels.c
+++ b/libavfilter/vf_shufflepixels.c
@@ -434,7 +434,6 @@ static const AVFilterPad shufflepixels_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
     },
-    { NULL },
 };
 
 static const AVFilterPad shufflepixels_outputs[] = {
@@ -443,7 +442,6 @@ static const AVFilterPad shufflepixels_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
     },
-    { NULL },
 };
 
 const AVFilter ff_vf_shufflepixels = {
@@ -453,7 +451,7 @@ const AVFilter ff_vf_shufflepixels = {
     .priv_class    = &shufflepixels_class,
     .query_formats = query_formats,
     .uninit        = uninit,
-    .inputs        = shufflepixels_inputs,
-    .outputs       = shufflepixels_outputs,
+    FILTER_INPUTS(shufflepixels_inputs),
+    FILTER_OUTPUTS(shufflepixels_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
 };
diff --git a/libavfilter/vf_shuffleplanes.c b/libavfilter/vf_shuffleplanes.c
index d1e1d11074..3ca4aa976d 100644
--- a/libavfilter/vf_shuffleplanes.c
+++ b/libavfilter/vf_shuffleplanes.c
@@ -151,7 +151,6 @@ static const AVFilterPad shuffleplanes_inputs[] = {
         .config_props     = shuffleplanes_config_input,
         .filter_frame     = shuffleplanes_filter_frame,
     },
-    { NULL },
 };
 
 static const AVFilterPad shuffleplanes_outputs[] = {
@@ -159,7 +158,6 @@ static const AVFilterPad shuffleplanes_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL },
 };
 
 const AVFilter ff_vf_shuffleplanes = {
@@ -168,7 +166,7 @@ const AVFilter ff_vf_shuffleplanes = {
     .priv_size    = sizeof(ShufflePlanesContext),
     .priv_class   = &shuffleplanes_class,
     .query_formats = query_formats,
-    .inputs       = shuffleplanes_inputs,
-    .outputs      = shuffleplanes_outputs,
+    FILTER_INPUTS(shuffleplanes_inputs),
+    FILTER_OUTPUTS(shuffleplanes_outputs),
     .flags        = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
 };
diff --git a/libavfilter/vf_signalstats.c b/libavfilter/vf_signalstats.c
index 6863f16803..1bfa7f158d 100644
--- a/libavfilter/vf_signalstats.c
+++ b/libavfilter/vf_signalstats.c
@@ -997,7 +997,6 @@ static const AVFilterPad signalstats_inputs[] = {
         .type           = AVMEDIA_TYPE_VIDEO,
         .filter_frame   = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad signalstats_outputs[] = {
@@ -1006,7 +1005,6 @@ static const AVFilterPad signalstats_outputs[] = {
         .config_props   = config_output,
         .type           = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_signalstats = {
@@ -1016,8 +1014,8 @@ const AVFilter ff_vf_signalstats = {
     .uninit        = uninit,
     .query_formats = query_formats,
     .priv_size     = sizeof(SignalstatsContext),
-    .inputs        = signalstats_inputs,
-    .outputs       = signalstats_outputs,
+    FILTER_INPUTS(signalstats_inputs),
+    FILTER_OUTPUTS(signalstats_outputs),
     .priv_class    = &signalstats_class,
     .flags         = AVFILTER_FLAG_SLICE_THREADS,
 };
diff --git a/libavfilter/vf_signature.c b/libavfilter/vf_signature.c
index 2e9d6e177a..b8339d7442 100644
--- a/libavfilter/vf_signature.c
+++ b/libavfilter/vf_signature.c
@@ -755,7 +755,6 @@ static const AVFilterPad signature_outputs[] = {
         .request_frame = request_frame,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_signature = {
@@ -766,7 +765,7 @@ const AVFilter ff_vf_signature = {
     .init          = init,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .outputs       = signature_outputs,
+    FILTER_OUTPUTS(signature_outputs),
     .inputs        = NULL,
     .flags         = AVFILTER_FLAG_DYNAMIC_INPUTS,
 };
diff --git a/libavfilter/vf_smartblur.c b/libavfilter/vf_smartblur.c
index 1820bbb265..24aa533fd7 100644
--- a/libavfilter/vf_smartblur.c
+++ b/libavfilter/vf_smartblur.c
@@ -277,7 +277,6 @@ static const AVFilterPad smartblur_inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_props,
     },
-    { NULL }
 };
 
 static const AVFilterPad smartblur_outputs[] = {
@@ -285,7 +284,6 @@ static const AVFilterPad smartblur_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_smartblur = {
@@ -295,8 +293,8 @@ const AVFilter ff_vf_smartblur = {
     .init          = init,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = smartblur_inputs,
-    .outputs       = smartblur_outputs,
+    FILTER_INPUTS(smartblur_inputs),
+    FILTER_OUTPUTS(smartblur_outputs),
     .priv_class    = &smartblur_class,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
 };
diff --git a/libavfilter/vf_spp.c b/libavfilter/vf_spp.c
index 51f3670f4a..b3a52fc99b 100644
--- a/libavfilter/vf_spp.c
+++ b/libavfilter/vf_spp.c
@@ -495,7 +495,6 @@ static const AVFilterPad spp_inputs[] = {
         .config_props = config_input,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad spp_outputs[] = {
@@ -503,7 +502,6 @@ static const AVFilterPad spp_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_spp = {
@@ -513,8 +511,8 @@ const AVFilter ff_vf_spp = {
     .init_dict       = init_dict,
     .uninit          = uninit,
     .query_formats   = query_formats,
-    .inputs          = spp_inputs,
-    .outputs         = spp_outputs,
+    FILTER_INPUTS(spp_inputs),
+    FILTER_OUTPUTS(spp_outputs),
     .process_command = process_command,
     .priv_class      = &spp_class,
     .flags           = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
diff --git a/libavfilter/vf_sr.c b/libavfilter/vf_sr.c
index 4373f749d3..f009a868f8 100644
--- a/libavfilter/vf_sr.c
+++ b/libavfilter/vf_sr.c
@@ -174,7 +174,6 @@ static const AVFilterPad sr_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad sr_outputs[] = {
@@ -183,7 +182,6 @@ static const AVFilterPad sr_outputs[] = {
         .config_props = config_output,
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_sr = {
@@ -193,7 +191,7 @@ const AVFilter ff_vf_sr = {
     .init          = init,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = sr_inputs,
-    .outputs       = sr_outputs,
+    FILTER_INPUTS(sr_inputs),
+    FILTER_OUTPUTS(sr_outputs),
     .priv_class    = &sr_class,
 };
diff --git a/libavfilter/vf_ssim.c b/libavfilter/vf_ssim.c
index 851a684673..41e35ac6ee 100644
--- a/libavfilter/vf_ssim.c
+++ b/libavfilter/vf_ssim.c
@@ -579,7 +579,6 @@ static const AVFilterPad ssim_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_input_ref,
     },
-    { NULL }
 };
 
 static const AVFilterPad ssim_outputs[] = {
@@ -588,7 +587,6 @@ static const AVFilterPad ssim_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_ssim = {
@@ -601,7 +599,7 @@ const AVFilter ff_vf_ssim = {
     .activate      = activate,
     .priv_size     = sizeof(SSIMContext),
     .priv_class    = &ssim_class,
-    .inputs        = ssim_inputs,
-    .outputs       = ssim_outputs,
+    FILTER_INPUTS(ssim_inputs),
+    FILTER_OUTPUTS(ssim_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | AVFILTER_FLAG_SLICE_THREADS,
 };
diff --git a/libavfilter/vf_stack.c b/libavfilter/vf_stack.c
index 48f3e4fbfd..8d3360169d 100644
--- a/libavfilter/vf_stack.c
+++ b/libavfilter/vf_stack.c
@@ -402,7 +402,6 @@ static const AVFilterPad outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 #if CONFIG_HSTACK_FILTER
@@ -416,7 +415,7 @@ const AVFilter ff_vf_hstack = {
     .priv_size     = sizeof(StackContext),
     .priv_class    = &hstack_class,
     .query_formats = query_formats,
-    .outputs       = outputs,
+    FILTER_OUTPUTS(outputs),
     .init          = init,
     .uninit        = uninit,
     .activate      = activate,
@@ -436,7 +435,7 @@ const AVFilter ff_vf_vstack = {
     .priv_size     = sizeof(StackContext),
     .priv_class    = &vstack_class,
     .query_formats = query_formats,
-    .outputs       = outputs,
+    FILTER_OUTPUTS(outputs),
     .init          = init,
     .uninit        = uninit,
     .activate      = activate,
@@ -463,7 +462,7 @@ const AVFilter ff_vf_xstack = {
     .priv_size     = sizeof(StackContext),
     .priv_class    = &xstack_class,
     .query_formats = query_formats,
-    .outputs       = outputs,
+    FILTER_OUTPUTS(outputs),
     .init          = init,
     .uninit        = uninit,
     .activate      = activate,
diff --git a/libavfilter/vf_stereo3d.c b/libavfilter/vf_stereo3d.c
index 56b53c8206..10aade7bd9 100644
--- a/libavfilter/vf_stereo3d.c
+++ b/libavfilter/vf_stereo3d.c
@@ -1096,7 +1096,6 @@ static const AVFilterPad stereo3d_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad stereo3d_outputs[] = {
@@ -1105,7 +1104,6 @@ static const AVFilterPad stereo3d_outputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_stereo3d = {
@@ -1114,8 +1112,8 @@ const AVFilter ff_vf_stereo3d = {
     .priv_size     = sizeof(Stereo3DContext),
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = stereo3d_inputs,
-    .outputs       = stereo3d_outputs,
+    FILTER_INPUTS(stereo3d_inputs),
+    FILTER_OUTPUTS(stereo3d_outputs),
     .priv_class    = &stereo3d_class,
     .flags         = AVFILTER_FLAG_SLICE_THREADS,
 };
diff --git a/libavfilter/vf_subtitles.c b/libavfilter/vf_subtitles.c
index 2f7f927d8d..d0bafcd3cf 100644
--- a/libavfilter/vf_subtitles.c
+++ b/libavfilter/vf_subtitles.c
@@ -202,7 +202,6 @@ static const AVFilterPad ass_inputs[] = {
         .filter_frame     = filter_frame,
         .config_props     = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad ass_outputs[] = {
@@ -210,7 +209,6 @@ static const AVFilterPad ass_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 #if CONFIG_ASS_FILTER
@@ -254,8 +252,8 @@ const AVFilter ff_vf_ass = {
     .init          = init_ass,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = ass_inputs,
-    .outputs       = ass_outputs,
+    FILTER_INPUTS(ass_inputs),
+    FILTER_OUTPUTS(ass_outputs),
     .priv_class    = &ass_class,
 };
 #endif
@@ -488,8 +486,8 @@ const AVFilter ff_vf_subtitles = {
     .init          = init_subtitles,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = ass_inputs,
-    .outputs       = ass_outputs,
+    FILTER_INPUTS(ass_inputs),
+    FILTER_OUTPUTS(ass_outputs),
     .priv_class    = &subtitles_class,
 };
 #endif
diff --git a/libavfilter/vf_super2xsai.c b/libavfilter/vf_super2xsai.c
index 8df9dcc72b..3e99d53cee 100644
--- a/libavfilter/vf_super2xsai.c
+++ b/libavfilter/vf_super2xsai.c
@@ -345,7 +345,6 @@ static const AVFilterPad super2xsai_inputs[] = {
         .config_props = config_input,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad super2xsai_outputs[] = {
@@ -354,7 +353,6 @@ static const AVFilterPad super2xsai_outputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_super2xsai = {
@@ -362,7 +360,7 @@ const AVFilter ff_vf_super2xsai = {
     .description   = NULL_IF_CONFIG_SMALL("Scale the input by 2x using the Super2xSaI pixel art algorithm."),
     .priv_size     = sizeof(Super2xSaIContext),
     .query_formats = query_formats,
-    .inputs        = super2xsai_inputs,
-    .outputs       = super2xsai_outputs,
+    FILTER_INPUTS(super2xsai_inputs),
+    FILTER_OUTPUTS(super2xsai_outputs),
     .flags         = AVFILTER_FLAG_SLICE_THREADS,
 };
diff --git a/libavfilter/vf_swaprect.c b/libavfilter/vf_swaprect.c
index 7829f2f852..4a5f4a12a6 100644
--- a/libavfilter/vf_swaprect.c
+++ b/libavfilter/vf_swaprect.c
@@ -232,7 +232,6 @@ static const AVFilterPad inputs[] = {
         .filter_frame   = filter_frame,
         .config_props   = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -240,7 +239,6 @@ static const AVFilterPad outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_swaprect = {
@@ -250,8 +248,8 @@ const AVFilter ff_vf_swaprect = {
     .priv_class    = &swaprect_class,
     .query_formats = query_formats,
     .uninit        = uninit,
-    .inputs        = inputs,
-    .outputs       = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
     .process_command = ff_filter_process_command,
 };
diff --git a/libavfilter/vf_swapuv.c b/libavfilter/vf_swapuv.c
index d0c869b13c..0c285e547c 100644
--- a/libavfilter/vf_swapuv.c
+++ b/libavfilter/vf_swapuv.c
@@ -100,7 +100,6 @@ static const AVFilterPad swapuv_inputs[] = {
         .get_buffer.video = get_video_buffer,
         .filter_frame     = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad swapuv_outputs[] = {
@@ -108,7 +107,6 @@ static const AVFilterPad swapuv_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_swapuv = {
@@ -117,7 +115,7 @@ const AVFilter ff_vf_swapuv = {
     .query_formats = query_formats,
     .priv_size     = sizeof(SwapUVContext),
     .priv_class    = &swapuv_class,
-    .inputs        = swapuv_inputs,
-    .outputs       = swapuv_outputs,
+    FILTER_INPUTS(swapuv_inputs),
+    FILTER_OUTPUTS(swapuv_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
 };
diff --git a/libavfilter/vf_telecine.c b/libavfilter/vf_telecine.c
index 52a3f2f353..99c6d22b7d 100644
--- a/libavfilter/vf_telecine.c
+++ b/libavfilter/vf_telecine.c
@@ -275,7 +275,6 @@ static const AVFilterPad telecine_inputs[] = {
         .filter_frame  = filter_frame,
         .config_props  = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad telecine_outputs[] = {
@@ -284,7 +283,6 @@ static const AVFilterPad telecine_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_telecine = {
@@ -295,6 +293,6 @@ const AVFilter ff_vf_telecine = {
     .init          = init,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = telecine_inputs,
-    .outputs       = telecine_outputs,
+    FILTER_INPUTS(telecine_inputs),
+    FILTER_OUTPUTS(telecine_outputs),
 };
diff --git a/libavfilter/vf_threshold.c b/libavfilter/vf_threshold.c
index c37d676882..828f7a8746 100644
--- a/libavfilter/vf_threshold.c
+++ b/libavfilter/vf_threshold.c
@@ -342,7 +342,6 @@ static const AVFilterPad inputs[] = {
         .name         = "max",
         .type         = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -351,7 +350,6 @@ static const AVFilterPad outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_threshold = {
@@ -362,8 +360,8 @@ const AVFilter ff_vf_threshold = {
     .uninit        = uninit,
     .query_formats = query_formats,
     .activate      = activate,
-    .inputs        = inputs,
-    .outputs       = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | AVFILTER_FLAG_SLICE_THREADS,
     .process_command = ff_filter_process_command,
 };
diff --git a/libavfilter/vf_thumbnail.c b/libavfilter/vf_thumbnail.c
index d81702b323..acfc0ce481 100644
--- a/libavfilter/vf_thumbnail.c
+++ b/libavfilter/vf_thumbnail.c
@@ -272,7 +272,6 @@ static const AVFilterPad thumbnail_inputs[] = {
         .config_props = config_props,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad thumbnail_outputs[] = {
@@ -281,7 +280,6 @@ static const AVFilterPad thumbnail_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .request_frame = request_frame,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_thumbnail = {
@@ -291,8 +289,8 @@ const AVFilter ff_vf_thumbnail = {
     .init          = init,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = thumbnail_inputs,
-    .outputs       = thumbnail_outputs,
+    FILTER_INPUTS(thumbnail_inputs),
+    FILTER_OUTPUTS(thumbnail_outputs),
     .priv_class    = &thumbnail_class,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
 };
diff --git a/libavfilter/vf_thumbnail_cuda.c b/libavfilter/vf_thumbnail_cuda.c
index d92c613d91..df9bba22e0 100644
--- a/libavfilter/vf_thumbnail_cuda.c
+++ b/libavfilter/vf_thumbnail_cuda.c
@@ -428,7 +428,6 @@ static const AVFilterPad thumbnail_cuda_inputs[] = {
         .config_props = config_props,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad thumbnail_cuda_outputs[] = {
@@ -437,7 +436,6 @@ static const AVFilterPad thumbnail_cuda_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .request_frame = request_frame,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_thumbnail_cuda = {
@@ -447,8 +445,8 @@ const AVFilter ff_vf_thumbnail_cuda = {
     .init          = init,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = thumbnail_cuda_inputs,
-    .outputs       = thumbnail_cuda_outputs,
+    FILTER_INPUTS(thumbnail_cuda_inputs),
+    FILTER_OUTPUTS(thumbnail_cuda_outputs),
     .priv_class    = &thumbnail_cuda_class,
     .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
 };
diff --git a/libavfilter/vf_tile.c b/libavfilter/vf_tile.c
index 11392169e4..13bd53bba6 100644
--- a/libavfilter/vf_tile.c
+++ b/libavfilter/vf_tile.c
@@ -272,7 +272,6 @@ static const AVFilterPad tile_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad tile_outputs[] = {
@@ -282,7 +281,6 @@ static const AVFilterPad tile_outputs[] = {
         .config_props  = config_props,
         .request_frame = request_frame,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_tile = {
@@ -292,7 +290,7 @@ const AVFilter ff_vf_tile = {
     .uninit        = uninit,
     .query_formats = query_formats,
     .priv_size     = sizeof(TileContext),
-    .inputs        = tile_inputs,
-    .outputs       = tile_outputs,
+    FILTER_INPUTS(tile_inputs),
+    FILTER_OUTPUTS(tile_outputs),
     .priv_class    = &tile_class,
 };
diff --git a/libavfilter/vf_tinterlace.c b/libavfilter/vf_tinterlace.c
index 6ab43b527d..7c0f00898b 100644
--- a/libavfilter/vf_tinterlace.c
+++ b/libavfilter/vf_tinterlace.c
@@ -540,7 +540,6 @@ static const AVFilterPad tinterlace_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad tinterlace_outputs[] = {
@@ -549,7 +548,6 @@ static const AVFilterPad tinterlace_outputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_out_props,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_tinterlace = {
@@ -558,8 +556,8 @@ const AVFilter ff_vf_tinterlace = {
     .priv_size     = sizeof(TInterlaceContext),
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = tinterlace_inputs,
-    .outputs       = tinterlace_outputs,
+    FILTER_INPUTS(tinterlace_inputs),
+    FILTER_OUTPUTS(tinterlace_outputs),
     .priv_class    = &tinterlace_class,
 };
 
@@ -571,7 +569,7 @@ const AVFilter ff_vf_interlace = {
     .init          = init_interlace,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = tinterlace_inputs,
-    .outputs       = tinterlace_outputs,
+    FILTER_INPUTS(tinterlace_inputs),
+    FILTER_OUTPUTS(tinterlace_outputs),
     .priv_class    = &interlace_class,
 };
diff --git a/libavfilter/vf_tmidequalizer.c b/libavfilter/vf_tmidequalizer.c
index 3516592ee4..cf9fcf9047 100644
--- a/libavfilter/vf_tmidequalizer.c
+++ b/libavfilter/vf_tmidequalizer.c
@@ -415,7 +415,6 @@ static const AVFilterPad tmidequalizer_inputs[] = {
         .config_props = config_input,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad tmidequalizer_outputs[] = {
@@ -424,7 +423,6 @@ static const AVFilterPad tmidequalizer_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .request_frame = request_frame,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_tmidequalizer = {
@@ -433,8 +431,8 @@ const AVFilter ff_vf_tmidequalizer = {
     .priv_size     = sizeof(TMidEqualizerContext),
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = tmidequalizer_inputs,
-    .outputs       = tmidequalizer_outputs,
+    FILTER_INPUTS(tmidequalizer_inputs),
+    FILTER_OUTPUTS(tmidequalizer_outputs),
     .priv_class    = &tmidequalizer_class,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
 };
diff --git a/libavfilter/vf_tonemap.c b/libavfilter/vf_tonemap.c
index eb99ce77f3..8ea54ecafb 100644
--- a/libavfilter/vf_tonemap.c
+++ b/libavfilter/vf_tonemap.c
@@ -324,7 +324,6 @@ static const AVFilterPad tonemap_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad tonemap_outputs[] = {
@@ -332,7 +331,6 @@ static const AVFilterPad tonemap_outputs[] = {
         .name         = "default",
         .type         = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_tonemap = {
@@ -342,7 +340,7 @@ const AVFilter ff_vf_tonemap = {
     .query_formats   = query_formats,
     .priv_size       = sizeof(TonemapContext),
     .priv_class      = &tonemap_class,
-    .inputs          = tonemap_inputs,
-    .outputs         = tonemap_outputs,
+    FILTER_INPUTS(tonemap_inputs),
+    FILTER_OUTPUTS(tonemap_outputs),
     .flags           = AVFILTER_FLAG_SLICE_THREADS,
 };
diff --git a/libavfilter/vf_tonemap_opencl.c b/libavfilter/vf_tonemap_opencl.c
index 8cf7c099ee..f659669159 100644
--- a/libavfilter/vf_tonemap_opencl.c
+++ b/libavfilter/vf_tonemap_opencl.c
@@ -527,7 +527,6 @@ static const AVFilterPad tonemap_opencl_inputs[] = {
         .filter_frame = &tonemap_opencl_filter_frame,
         .config_props = &ff_opencl_filter_config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad tonemap_opencl_outputs[] = {
@@ -536,7 +535,6 @@ static const AVFilterPad tonemap_opencl_outputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = &tonemap_opencl_config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_tonemap_opencl = {
@@ -547,7 +545,7 @@ const AVFilter ff_vf_tonemap_opencl = {
     .init           = &ff_opencl_filter_init,
     .uninit         = &tonemap_opencl_uninit,
     .query_formats  = &ff_opencl_filter_query_formats,
-    .inputs         = tonemap_opencl_inputs,
-    .outputs        = tonemap_opencl_outputs,
+    FILTER_INPUTS(tonemap_opencl_inputs),
+    FILTER_OUTPUTS(tonemap_opencl_outputs),
     .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
 };
diff --git a/libavfilter/vf_tonemap_vaapi.c b/libavfilter/vf_tonemap_vaapi.c
index d33c4f8f6d..a5cf9b0d8d 100644
--- a/libavfilter/vf_tonemap_vaapi.c
+++ b/libavfilter/vf_tonemap_vaapi.c
@@ -391,7 +391,6 @@ static const AVFilterPad tonemap_vaapi_inputs[] = {
         .filter_frame = &tonemap_vaapi_filter_frame,
         .config_props = &ff_vaapi_vpp_config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad tonemap_vaapi_outputs[] = {
@@ -400,7 +399,6 @@ static const AVFilterPad tonemap_vaapi_outputs[] = {
         .type = AVMEDIA_TYPE_VIDEO,
         .config_props = &ff_vaapi_vpp_config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_tonemap_vaapi = {
@@ -410,8 +408,8 @@ const AVFilter ff_vf_tonemap_vaapi = {
     .init           = &tonemap_vaapi_init,
     .uninit         = &ff_vaapi_vpp_ctx_uninit,
     .query_formats  = &ff_vaapi_vpp_query_formats,
-    .inputs         = tonemap_vaapi_inputs,
-    .outputs        = tonemap_vaapi_outputs,
+    FILTER_INPUTS(tonemap_vaapi_inputs),
+    FILTER_OUTPUTS(tonemap_vaapi_outputs),
     .priv_class     = &tonemap_vaapi_class,
     .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
 };
diff --git a/libavfilter/vf_tpad.c b/libavfilter/vf_tpad.c
index d23869f3e2..badd24fd06 100644
--- a/libavfilter/vf_tpad.c
+++ b/libavfilter/vf_tpad.c
@@ -193,7 +193,6 @@ static const AVFilterPad tpad_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad tpad_outputs[] = {
@@ -201,7 +200,6 @@ static const AVFilterPad tpad_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_tpad = {
@@ -212,6 +210,6 @@ const AVFilter ff_vf_tpad = {
     .query_formats = query_formats,
     .activate      = activate,
     .uninit        = uninit,
-    .inputs        = tpad_inputs,
-    .outputs       = tpad_outputs,
+    FILTER_INPUTS(tpad_inputs),
+    FILTER_OUTPUTS(tpad_outputs),
 };
diff --git a/libavfilter/vf_transpose.c b/libavfilter/vf_transpose.c
index ed4b25cb60..9ed132fc0f 100644
--- a/libavfilter/vf_transpose.c
+++ b/libavfilter/vf_transpose.c
@@ -386,7 +386,6 @@ static const AVFilterPad avfilter_vf_transpose_inputs[] = {
         .get_buffer.video = get_video_buffer,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad avfilter_vf_transpose_outputs[] = {
@@ -395,7 +394,6 @@ static const AVFilterPad avfilter_vf_transpose_outputs[] = {
         .config_props = config_props_output,
         .type         = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_transpose = {
@@ -404,7 +402,7 @@ const AVFilter ff_vf_transpose = {
     .priv_size     = sizeof(TransContext),
     .priv_class    = &transpose_class,
     .query_formats = query_formats,
-    .inputs        = avfilter_vf_transpose_inputs,
-    .outputs       = avfilter_vf_transpose_outputs,
+    FILTER_INPUTS(avfilter_vf_transpose_inputs),
+    FILTER_OUTPUTS(avfilter_vf_transpose_outputs),
     .flags         = AVFILTER_FLAG_SLICE_THREADS,
 };
diff --git a/libavfilter/vf_transpose_npp.c b/libavfilter/vf_transpose_npp.c
index ad79d22f7f..14b9d62488 100644
--- a/libavfilter/vf_transpose_npp.c
+++ b/libavfilter/vf_transpose_npp.c
@@ -460,7 +460,6 @@ static const AVFilterPad npptranspose_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = npptranspose_filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad npptranspose_outputs[] = {
@@ -469,7 +468,6 @@ static const AVFilterPad npptranspose_outputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = npptranspose_config_props,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_transpose_npp = {
@@ -480,7 +478,7 @@ const AVFilter ff_vf_transpose_npp = {
     .query_formats  = npptranspose_query_formats,
     .priv_size      = sizeof(NPPTransposeContext),
     .priv_class     = &npptranspose_class,
-    .inputs         = npptranspose_inputs,
-    .outputs        = npptranspose_outputs,
+    FILTER_INPUTS(npptranspose_inputs),
+    FILTER_OUTPUTS(npptranspose_outputs),
     .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
 };
diff --git a/libavfilter/vf_transpose_opencl.c b/libavfilter/vf_transpose_opencl.c
index 17c237ffd3..05e7aa19e0 100644
--- a/libavfilter/vf_transpose_opencl.c
+++ b/libavfilter/vf_transpose_opencl.c
@@ -260,7 +260,6 @@ static const AVFilterPad transpose_opencl_inputs[] = {
         .filter_frame = &transpose_opencl_filter_frame,
         .config_props = &ff_opencl_filter_config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad transpose_opencl_outputs[] = {
@@ -269,7 +268,6 @@ static const AVFilterPad transpose_opencl_outputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = &transpose_opencl_config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_transpose_opencl = {
@@ -280,7 +278,7 @@ const AVFilter ff_vf_transpose_opencl = {
     .init           = &ff_opencl_filter_init,
     .uninit         = &transpose_opencl_uninit,
     .query_formats  = &ff_opencl_filter_query_formats,
-    .inputs         = transpose_opencl_inputs,
-    .outputs        = transpose_opencl_outputs,
+    FILTER_INPUTS(transpose_opencl_inputs),
+    FILTER_OUTPUTS(transpose_opencl_outputs),
     .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
 };
diff --git a/libavfilter/vf_transpose_vaapi.c b/libavfilter/vf_transpose_vaapi.c
index 0d11c6b674..f0d356da71 100644
--- a/libavfilter/vf_transpose_vaapi.c
+++ b/libavfilter/vf_transpose_vaapi.c
@@ -260,7 +260,6 @@ static const AVFilterPad transpose_vaapi_inputs[] = {
         .get_buffer.video = get_video_buffer,
         .config_props = &ff_vaapi_vpp_config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad transpose_vaapi_outputs[] = {
@@ -269,7 +268,6 @@ static const AVFilterPad transpose_vaapi_outputs[] = {
         .type = AVMEDIA_TYPE_VIDEO,
         .config_props = &transpose_vaapi_vpp_config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_transpose_vaapi = {
@@ -279,8 +277,8 @@ const AVFilter ff_vf_transpose_vaapi = {
     .init           = &transpose_vaapi_init,
     .uninit         = &ff_vaapi_vpp_ctx_uninit,
     .query_formats  = &ff_vaapi_vpp_query_formats,
-    .inputs         = transpose_vaapi_inputs,
-    .outputs        = transpose_vaapi_outputs,
+    FILTER_INPUTS(transpose_vaapi_inputs),
+    FILTER_OUTPUTS(transpose_vaapi_outputs),
     .priv_class     = &transpose_vaapi_class,
     .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
 };
diff --git a/libavfilter/vf_unsharp.c b/libavfilter/vf_unsharp.c
index fad880c73d..98399b804a 100644
--- a/libavfilter/vf_unsharp.c
+++ b/libavfilter/vf_unsharp.c
@@ -343,7 +343,6 @@ static const AVFilterPad avfilter_vf_unsharp_inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad avfilter_vf_unsharp_outputs[] = {
@@ -351,7 +350,6 @@ static const AVFilterPad avfilter_vf_unsharp_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_unsharp = {
@@ -362,7 +360,7 @@ const AVFilter ff_vf_unsharp = {
     .init          = init,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = avfilter_vf_unsharp_inputs,
-    .outputs       = avfilter_vf_unsharp_outputs,
+    FILTER_INPUTS(avfilter_vf_unsharp_inputs),
+    FILTER_OUTPUTS(avfilter_vf_unsharp_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
 };
diff --git a/libavfilter/vf_unsharp_opencl.c b/libavfilter/vf_unsharp_opencl.c
index 200350de9f..129611c70d 100644
--- a/libavfilter/vf_unsharp_opencl.c
+++ b/libavfilter/vf_unsharp_opencl.c
@@ -386,7 +386,6 @@ static const AVFilterPad unsharp_opencl_inputs[] = {
         .filter_frame = &unsharp_opencl_filter_frame,
         .config_props = &ff_opencl_filter_config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad unsharp_opencl_outputs[] = {
@@ -395,7 +394,6 @@ static const AVFilterPad unsharp_opencl_outputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = &ff_opencl_filter_config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_unsharp_opencl = {
@@ -406,7 +404,7 @@ const AVFilter ff_vf_unsharp_opencl = {
     .init           = &ff_opencl_filter_init,
     .uninit         = &unsharp_opencl_uninit,
     .query_formats  = &ff_opencl_filter_query_formats,
-    .inputs         = unsharp_opencl_inputs,
-    .outputs        = unsharp_opencl_outputs,
+    FILTER_INPUTS(unsharp_opencl_inputs),
+    FILTER_OUTPUTS(unsharp_opencl_outputs),
     .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
 };
diff --git a/libavfilter/vf_untile.c b/libavfilter/vf_untile.c
index 9035e819d4..2bf5146591 100644
--- a/libavfilter/vf_untile.c
+++ b/libavfilter/vf_untile.c
@@ -172,7 +172,6 @@ static const AVFilterPad untile_inputs[] = {
         .name         = "default",
         .type         = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 static const AVFilterPad untile_outputs[] = {
@@ -181,7 +180,6 @@ static const AVFilterPad untile_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_untile = {
@@ -192,7 +190,7 @@ const AVFilter ff_vf_untile = {
     .query_formats = query_formats,
     .activate      = activate,
     .priv_size     = sizeof(UntileContext),
-    .inputs        = untile_inputs,
-    .outputs       = untile_outputs,
+    FILTER_INPUTS(untile_inputs),
+    FILTER_OUTPUTS(untile_outputs),
     .priv_class    = &untile_class,
 };
diff --git a/libavfilter/vf_uspp.c b/libavfilter/vf_uspp.c
index 0ed9abe92c..ba6ae816a8 100644
--- a/libavfilter/vf_uspp.c
+++ b/libavfilter/vf_uspp.c
@@ -480,7 +480,6 @@ static const AVFilterPad uspp_inputs[] = {
         .config_props = config_input,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad uspp_outputs[] = {
@@ -488,7 +487,6 @@ static const AVFilterPad uspp_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_uspp = {
@@ -497,8 +495,8 @@ const AVFilter ff_vf_uspp = {
     .priv_size       = sizeof(USPPContext),
     .uninit          = uninit,
     .query_formats   = query_formats,
-    .inputs          = uspp_inputs,
-    .outputs         = uspp_outputs,
+    FILTER_INPUTS(uspp_inputs),
+    FILTER_OUTPUTS(uspp_outputs),
     .priv_class      = &uspp_class,
     .flags           = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
 };
diff --git a/libavfilter/vf_v360.c b/libavfilter/vf_v360.c
index 4bba7140ba..52e75ee7f2 100644
--- a/libavfilter/vf_v360.c
+++ b/libavfilter/vf_v360.c
@@ -4966,7 +4966,6 @@ static const AVFilterPad inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -4975,7 +4974,6 @@ static const AVFilterPad outputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_v360 = {
@@ -4985,8 +4983,8 @@ const AVFilter ff_vf_v360 = {
     .init          = init,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = inputs,
-    .outputs       = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
     .priv_class    = &v360_class,
     .flags         = AVFILTER_FLAG_SLICE_THREADS,
     .process_command = process_command,
diff --git a/libavfilter/vf_vaguedenoiser.c b/libavfilter/vf_vaguedenoiser.c
index b3a800e360..ea23067110 100644
--- a/libavfilter/vf_vaguedenoiser.c
+++ b/libavfilter/vf_vaguedenoiser.c
@@ -595,7 +595,6 @@ static const AVFilterPad vaguedenoiser_inputs[] = {
         .config_props = config_input,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 
@@ -604,7 +603,6 @@ static const AVFilterPad vaguedenoiser_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_vaguedenoiser = {
@@ -615,7 +613,7 @@ const AVFilter ff_vf_vaguedenoiser = {
     .init          = init,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = vaguedenoiser_inputs,
-    .outputs       = vaguedenoiser_outputs,
+    FILTER_INPUTS(vaguedenoiser_inputs),
+    FILTER_OUTPUTS(vaguedenoiser_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
 };
diff --git a/libavfilter/vf_vectorscope.c b/libavfilter/vf_vectorscope.c
index 0669230890..b8b406430c 100644
--- a/libavfilter/vf_vectorscope.c
+++ b/libavfilter/vf_vectorscope.c
@@ -1575,7 +1575,6 @@ static const AVFilterPad inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -1584,7 +1583,6 @@ static const AVFilterPad outputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_vectorscope = {
@@ -1594,6 +1592,6 @@ const AVFilter ff_vf_vectorscope = {
     .priv_class    = &vectorscope_class,
     .query_formats = query_formats,
     .uninit        = uninit,
-    .inputs        = inputs,
-    .outputs       = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
 };
diff --git a/libavfilter/vf_vflip.c b/libavfilter/vf_vflip.c
index c590e84763..0d624512f9 100644
--- a/libavfilter/vf_vflip.c
+++ b/libavfilter/vf_vflip.c
@@ -133,7 +133,6 @@ static const AVFilterPad avfilter_vf_vflip_inputs[] = {
         .filter_frame     = filter_frame,
         .config_props     = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad avfilter_vf_vflip_outputs[] = {
@@ -141,7 +140,6 @@ static const AVFilterPad avfilter_vf_vflip_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_vflip = {
@@ -149,7 +147,7 @@ const AVFilter ff_vf_vflip = {
     .description = NULL_IF_CONFIG_SMALL("Flip the input video vertically."),
     .priv_size   = sizeof(FlipContext),
     .priv_class  = &vflip_class,
-    .inputs      = avfilter_vf_vflip_inputs,
-    .outputs     = avfilter_vf_vflip_outputs,
+    FILTER_INPUTS(avfilter_vf_vflip_inputs),
+    FILTER_OUTPUTS(avfilter_vf_vflip_outputs),
     .flags       = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
 };
diff --git a/libavfilter/vf_vfrdet.c b/libavfilter/vf_vfrdet.c
index 7e37036aef..fda8c2d485 100644
--- a/libavfilter/vf_vfrdet.c
+++ b/libavfilter/vf_vfrdet.c
@@ -93,7 +93,6 @@ static const AVFilterPad vfrdet_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad vfrdet_outputs[] = {
@@ -101,7 +100,6 @@ static const AVFilterPad vfrdet_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_vfrdet = {
@@ -110,6 +108,6 @@ const AVFilter ff_vf_vfrdet = {
     .priv_size   = sizeof(VFRDETContext),
     .init        = init,
     .uninit      = uninit,
-    .inputs      = vfrdet_inputs,
-    .outputs     = vfrdet_outputs,
+    FILTER_INPUTS(vfrdet_inputs),
+    FILTER_OUTPUTS(vfrdet_outputs),
 };
diff --git a/libavfilter/vf_vibrance.c b/libavfilter/vf_vibrance.c
index bc53f47a7b..7253ebd594 100644
--- a/libavfilter/vf_vibrance.c
+++ b/libavfilter/vf_vibrance.c
@@ -344,7 +344,6 @@ static const AVFilterPad vibrance_inputs[] = {
         .filter_frame   = filter_frame,
         .config_props   = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad vibrance_outputs[] = {
@@ -352,7 +351,6 @@ static const AVFilterPad vibrance_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 #define OFFSET(x) offsetof(VibranceContext, x)
@@ -378,8 +376,8 @@ const AVFilter ff_vf_vibrance = {
     .priv_size     = sizeof(VibranceContext),
     .priv_class    = &vibrance_class,
     .query_formats = query_formats,
-    .inputs        = vibrance_inputs,
-    .outputs       = vibrance_outputs,
+    FILTER_INPUTS(vibrance_inputs),
+    FILTER_OUTPUTS(vibrance_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
     .process_command = ff_filter_process_command,
 };
diff --git a/libavfilter/vf_vidstabdetect.c b/libavfilter/vf_vidstabdetect.c
index cde6a5e709..5e12d31d0e 100644
--- a/libavfilter/vf_vidstabdetect.c
+++ b/libavfilter/vf_vidstabdetect.c
@@ -193,7 +193,6 @@ static const AVFilterPad avfilter_vf_vidstabdetect_inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad avfilter_vf_vidstabdetect_outputs[] = {
@@ -201,7 +200,6 @@ static const AVFilterPad avfilter_vf_vidstabdetect_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_vidstabdetect = {
@@ -213,7 +211,7 @@ const AVFilter ff_vf_vidstabdetect = {
     .init          = init,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = avfilter_vf_vidstabdetect_inputs,
-    .outputs       = avfilter_vf_vidstabdetect_outputs,
+    FILTER_INPUTS(avfilter_vf_vidstabdetect_inputs),
+    FILTER_OUTPUTS(avfilter_vf_vidstabdetect_outputs),
     .priv_class    = &vidstabdetect_class,
 };
diff --git a/libavfilter/vf_vidstabtransform.c b/libavfilter/vf_vidstabtransform.c
index 342da0b26b..3499b9afe4 100644
--- a/libavfilter/vf_vidstabtransform.c
+++ b/libavfilter/vf_vidstabtransform.c
@@ -294,7 +294,6 @@ static const AVFilterPad avfilter_vf_vidstabtransform_inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad avfilter_vf_vidstabtransform_outputs[] = {
@@ -302,7 +301,6 @@ static const AVFilterPad avfilter_vf_vidstabtransform_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_vidstabtransform = {
@@ -314,7 +312,7 @@ const AVFilter ff_vf_vidstabtransform = {
     .init          = init,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = avfilter_vf_vidstabtransform_inputs,
-    .outputs       = avfilter_vf_vidstabtransform_outputs,
+    FILTER_INPUTS(avfilter_vf_vidstabtransform_inputs),
+    FILTER_OUTPUTS(avfilter_vf_vidstabtransform_outputs),
     .priv_class    = &vidstabtransform_class,
 };
diff --git a/libavfilter/vf_vif.c b/libavfilter/vf_vif.c
index e1b51aae3f..da3069c1f6 100644
--- a/libavfilter/vf_vif.c
+++ b/libavfilter/vf_vif.c
@@ -627,7 +627,6 @@ static const AVFilterPad vif_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_input_ref,
     },
-    { NULL }
 };
 
 static const AVFilterPad vif_outputs[] = {
@@ -636,7 +635,6 @@ static const AVFilterPad vif_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_vif = {
@@ -647,7 +645,7 @@ const AVFilter ff_vf_vif = {
     .priv_size     = sizeof(VIFContext),
     .priv_class    = &vif_class,
     .activate      = activate,
-    .inputs        = vif_inputs,
-    .outputs       = vif_outputs,
+    FILTER_INPUTS(vif_inputs),
+    FILTER_OUTPUTS(vif_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | AVFILTER_FLAG_SLICE_THREADS,
 };
diff --git a/libavfilter/vf_vignette.c b/libavfilter/vf_vignette.c
index ef67deb278..8e9f196ab9 100644
--- a/libavfilter/vf_vignette.c
+++ b/libavfilter/vf_vignette.c
@@ -327,7 +327,6 @@ static const AVFilterPad vignette_inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_props,
     },
-    { NULL }
 };
 
 static const AVFilterPad vignette_outputs[] = {
@@ -335,7 +334,6 @@ static const AVFilterPad vignette_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_vignette = {
@@ -345,8 +343,8 @@ const AVFilter ff_vf_vignette = {
     .init          = init,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = vignette_inputs,
-    .outputs       = vignette_outputs,
+    FILTER_INPUTS(vignette_inputs),
+    FILTER_OUTPUTS(vignette_outputs),
     .priv_class    = &vignette_class,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
 };
diff --git a/libavfilter/vf_vmafmotion.c b/libavfilter/vf_vmafmotion.c
index 454ebb8afa..67cc012b18 100644
--- a/libavfilter/vf_vmafmotion.c
+++ b/libavfilter/vf_vmafmotion.c
@@ -347,7 +347,6 @@ static const AVFilterPad vmafmotion_inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input_ref,
     },
-    { NULL }
 };
 
 static const AVFilterPad vmafmotion_outputs[] = {
@@ -355,7 +354,6 @@ static const AVFilterPad vmafmotion_outputs[] = {
         .name          = "default",
         .type          = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_vmafmotion = {
@@ -366,6 +364,6 @@ const AVFilter ff_vf_vmafmotion = {
     .query_formats = query_formats,
     .priv_size     = sizeof(VMAFMotionContext),
     .priv_class    = &vmafmotion_class,
-    .inputs        = vmafmotion_inputs,
-    .outputs       = vmafmotion_outputs,
+    FILTER_INPUTS(vmafmotion_inputs),
+    FILTER_OUTPUTS(vmafmotion_outputs),
 };
diff --git a/libavfilter/vf_vpp_qsv.c b/libavfilter/vf_vpp_qsv.c
index ee9317a49e..c268b5dba8 100644
--- a/libavfilter/vf_vpp_qsv.c
+++ b/libavfilter/vf_vpp_qsv.c
@@ -600,7 +600,6 @@ static const AVFilterPad vpp_inputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad vpp_outputs[] = {
@@ -609,7 +608,6 @@ static const AVFilterPad vpp_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_vpp_qsv = {
@@ -619,8 +617,8 @@ const AVFilter ff_vf_vpp_qsv = {
     .query_formats = query_formats,
     .init          = vpp_init,
     .uninit        = vpp_uninit,
-    .inputs        = vpp_inputs,
-    .outputs       = vpp_outputs,
+    FILTER_INPUTS(vpp_inputs),
+    FILTER_OUTPUTS(vpp_outputs),
     .activate      = activate,
     .priv_class    = &vpp_class,
     .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
diff --git a/libavfilter/vf_w3fdif.c b/libavfilter/vf_w3fdif.c
index 25f46558e5..9d073e9c34 100644
--- a/libavfilter/vf_w3fdif.c
+++ b/libavfilter/vf_w3fdif.c
@@ -598,7 +598,6 @@ static const AVFilterPad w3fdif_inputs[] = {
         .filter_frame  = filter_frame,
         .config_props  = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad w3fdif_outputs[] = {
@@ -608,7 +607,6 @@ static const AVFilterPad w3fdif_outputs[] = {
         .config_props  = config_output,
         .request_frame = request_frame,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_w3fdif = {
@@ -618,8 +616,8 @@ const AVFilter ff_vf_w3fdif = {
     .priv_class    = &w3fdif_class,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = w3fdif_inputs,
-    .outputs       = w3fdif_outputs,
+    FILTER_INPUTS(w3fdif_inputs),
+    FILTER_OUTPUTS(w3fdif_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | AVFILTER_FLAG_SLICE_THREADS,
     .process_command = ff_filter_process_command,
 };
diff --git a/libavfilter/vf_waveform.c b/libavfilter/vf_waveform.c
index f3d44a236e..431740705b 100644
--- a/libavfilter/vf_waveform.c
+++ b/libavfilter/vf_waveform.c
@@ -3503,7 +3503,6 @@ static const AVFilterPad inputs[] = {
         .filter_frame = filter_frame,
         .config_props = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -3512,7 +3511,6 @@ static const AVFilterPad outputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_waveform = {
@@ -3522,7 +3520,7 @@ const AVFilter ff_vf_waveform = {
     .priv_class    = &waveform_class,
     .query_formats = query_formats,
     .uninit        = uninit,
-    .inputs        = inputs,
-    .outputs       = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
     .flags         = AVFILTER_FLAG_SLICE_THREADS,
 };
diff --git a/libavfilter/vf_weave.c b/libavfilter/vf_weave.c
index 7fba26088c..5d20f65225 100644
--- a/libavfilter/vf_weave.c
+++ b/libavfilter/vf_weave.c
@@ -178,7 +178,6 @@ static const AVFilterPad weave_inputs[] = {
         .type             = AVMEDIA_TYPE_VIDEO,
         .filter_frame     = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad weave_outputs[] = {
@@ -187,7 +186,6 @@ static const AVFilterPad weave_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_props_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_weave = {
@@ -197,8 +195,8 @@ const AVFilter ff_vf_weave = {
     .priv_class    = &weave_class,
     .query_formats = query_formats,
     .uninit        = uninit,
-    .inputs        = weave_inputs,
-    .outputs       = weave_outputs,
+    FILTER_INPUTS(weave_inputs),
+    FILTER_OUTPUTS(weave_outputs),
     .flags         = AVFILTER_FLAG_SLICE_THREADS,
 };
 
@@ -223,7 +221,7 @@ const AVFilter ff_vf_doubleweave = {
     .query_formats = query_formats,
     .init          = init,
     .uninit        = uninit,
-    .inputs        = weave_inputs,
-    .outputs       = weave_outputs,
+    FILTER_INPUTS(weave_inputs),
+    FILTER_OUTPUTS(weave_outputs),
     .flags         = AVFILTER_FLAG_SLICE_THREADS,
 };
diff --git a/libavfilter/vf_xbr.c b/libavfilter/vf_xbr.c
index d73b2fd4e5..bb7b704abb 100644
--- a/libavfilter/vf_xbr.c
+++ b/libavfilter/vf_xbr.c
@@ -410,7 +410,6 @@ static const AVFilterPad xbr_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad xbr_outputs[] = {
@@ -419,14 +418,13 @@ static const AVFilterPad xbr_outputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_xbr = {
     .name          = "xbr",
     .description   = NULL_IF_CONFIG_SMALL("Scale the input using xBR algorithm."),
-    .inputs        = xbr_inputs,
-    .outputs       = xbr_outputs,
+    FILTER_INPUTS(xbr_inputs),
+    FILTER_OUTPUTS(xbr_outputs),
     .query_formats = query_formats,
     .priv_size     = sizeof(XBRContext),
     .priv_class    = &xbr_class,
diff --git a/libavfilter/vf_xfade.c b/libavfilter/vf_xfade.c
index 268352a53e..6183cde24c 100644
--- a/libavfilter/vf_xfade.c
+++ b/libavfilter/vf_xfade.c
@@ -1942,7 +1942,6 @@ static const AVFilterPad xfade_inputs[] = {
         .name          = "xfade",
         .type          = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 static const AVFilterPad xfade_outputs[] = {
@@ -1951,7 +1950,6 @@ static const AVFilterPad xfade_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_xfade = {
@@ -1962,7 +1960,7 @@ const AVFilter ff_vf_xfade = {
     .query_formats = query_formats,
     .activate      = xfade_activate,
     .uninit        = uninit,
-    .inputs        = xfade_inputs,
-    .outputs       = xfade_outputs,
+    FILTER_INPUTS(xfade_inputs),
+    FILTER_OUTPUTS(xfade_outputs),
     .flags         = AVFILTER_FLAG_SLICE_THREADS,
 };
diff --git a/libavfilter/vf_xfade_opencl.c b/libavfilter/vf_xfade_opencl.c
index 684d067d48..c24528eb89 100644
--- a/libavfilter/vf_xfade_opencl.c
+++ b/libavfilter/vf_xfade_opencl.c
@@ -411,7 +411,6 @@ static const AVFilterPad xfade_opencl_inputs[] = {
         .get_buffer.video = get_video_buffer,
         .config_props     = &ff_opencl_filter_config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad xfade_opencl_outputs[] = {
@@ -420,7 +419,6 @@ static const AVFilterPad xfade_opencl_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = &xfade_opencl_config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_xfade_opencl = {
@@ -432,7 +430,7 @@ const AVFilter ff_vf_xfade_opencl = {
     .uninit          = &xfade_opencl_uninit,
     .query_formats   = &ff_opencl_filter_query_formats,
     .activate        = &xfade_opencl_activate,
-    .inputs          = xfade_opencl_inputs,
-    .outputs         = xfade_opencl_outputs,
+    FILTER_INPUTS(xfade_opencl_inputs),
+    FILTER_OUTPUTS(xfade_opencl_outputs),
     .flags_internal  = FF_FILTER_FLAG_HWFRAME_AWARE,
 };
diff --git a/libavfilter/vf_xmedian.c b/libavfilter/vf_xmedian.c
index ab09161879..f900720012 100644
--- a/libavfilter/vf_xmedian.c
+++ b/libavfilter/vf_xmedian.c
@@ -383,7 +383,6 @@ static const AVFilterPad outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 #if CONFIG_XMEDIAN_FILTER
@@ -395,7 +394,7 @@ const AVFilter ff_vf_xmedian = {
     .priv_size     = sizeof(XMedianContext),
     .priv_class    = &xmedian_class,
     .query_formats = query_formats,
-    .outputs       = outputs,
+    FILTER_OUTPUTS(outputs),
     .preinit       = xmedian_framesync_preinit,
     .init          = init,
     .uninit        = uninit,
@@ -460,7 +459,6 @@ static const AVFilterPad tmedian_inputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .filter_frame  = tmedian_filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad tmedian_outputs[] = {
@@ -469,7 +467,6 @@ static const AVFilterPad tmedian_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 AVFILTER_DEFINE_CLASS(tmedian);
@@ -480,8 +477,8 @@ const AVFilter ff_vf_tmedian = {
     .priv_size     = sizeof(XMedianContext),
     .priv_class    = &tmedian_class,
     .query_formats = query_formats,
-    .inputs        = tmedian_inputs,
-    .outputs       = tmedian_outputs,
+    FILTER_INPUTS(tmedian_inputs),
+    FILTER_OUTPUTS(tmedian_outputs),
     .init          = init,
     .uninit        = uninit,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | AVFILTER_FLAG_SLICE_THREADS,
diff --git a/libavfilter/vf_yadif.c b/libavfilter/vf_yadif.c
index 773ff7bede..8b71e0584d 100644
--- a/libavfilter/vf_yadif.c
+++ b/libavfilter/vf_yadif.c
@@ -337,7 +337,6 @@ static const AVFilterPad avfilter_vf_yadif_inputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .filter_frame  = ff_yadif_filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad avfilter_vf_yadif_outputs[] = {
@@ -347,7 +346,6 @@ static const AVFilterPad avfilter_vf_yadif_outputs[] = {
         .request_frame = ff_yadif_request_frame,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_yadif = {
@@ -357,7 +355,7 @@ const AVFilter ff_vf_yadif = {
     .priv_class    = &yadif_class,
     .uninit        = uninit,
     .query_formats = query_formats,
-    .inputs        = avfilter_vf_yadif_inputs,
-    .outputs       = avfilter_vf_yadif_outputs,
+    FILTER_INPUTS(avfilter_vf_yadif_inputs),
+    FILTER_OUTPUTS(avfilter_vf_yadif_outputs),
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | AVFILTER_FLAG_SLICE_THREADS,
 };
diff --git a/libavfilter/vf_yadif_cuda.c b/libavfilter/vf_yadif_cuda.c
index 95267d6a1c..5ddb9a9324 100644
--- a/libavfilter/vf_yadif_cuda.c
+++ b/libavfilter/vf_yadif_cuda.c
@@ -363,7 +363,6 @@ static const AVFilterPad deint_cuda_inputs[] = {
         .filter_frame  = ff_yadif_filter_frame,
         .config_props  = config_input,
     },
-    { NULL }
 };
 
 static const AVFilterPad deint_cuda_outputs[] = {
@@ -373,7 +372,6 @@ static const AVFilterPad deint_cuda_outputs[] = {
         .request_frame = ff_yadif_request_frame,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_yadif_cuda = {
@@ -383,8 +381,8 @@ const AVFilter ff_vf_yadif_cuda = {
     .priv_class     = &yadif_cuda_class,
     .uninit         = deint_cuda_uninit,
     .query_formats  = deint_cuda_query_formats,
-    .inputs         = deint_cuda_inputs,
-    .outputs        = deint_cuda_outputs,
+    FILTER_INPUTS(deint_cuda_inputs),
+    FILTER_OUTPUTS(deint_cuda_outputs),
     .flags          = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
     .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
 };
diff --git a/libavfilter/vf_yaepblur.c b/libavfilter/vf_yaepblur.c
index 7a289c2f5a..983a2fec4f 100644
--- a/libavfilter/vf_yaepblur.c
+++ b/libavfilter/vf_yaepblur.c
@@ -312,7 +312,6 @@ static const AVFilterPad yaep_inputs[] = {
         .config_props = config_input,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad yaep_outputs[] = {
@@ -320,7 +319,6 @@ static const AVFilterPad yaep_outputs[] = {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 #define OFFSET(x) offsetof(YAEPContext, x)
@@ -345,8 +343,8 @@ const AVFilter ff_vf_yaepblur = {
     .priv_class      = &yaepblur_class,
     .uninit          = uninit,
     .query_formats   = query_formats,
-    .inputs          = yaep_inputs,
-    .outputs         = yaep_outputs,
+    FILTER_INPUTS(yaep_inputs),
+    FILTER_OUTPUTS(yaep_outputs),
     .flags           = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
     .process_command = ff_filter_process_command,
 };
diff --git a/libavfilter/vf_zoompan.c b/libavfilter/vf_zoompan.c
index 8a350aa92a..92769f1fd1 100644
--- a/libavfilter/vf_zoompan.c
+++ b/libavfilter/vf_zoompan.c
@@ -361,7 +361,6 @@ static const AVFilterPad inputs[] = {
         .name         = "default",
         .type         = AVMEDIA_TYPE_VIDEO,
     },
-    { NULL }
 };
 
 static const AVFilterPad outputs[] = {
@@ -370,7 +369,6 @@ static const AVFilterPad outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_zoompan = {
@@ -382,6 +380,6 @@ const AVFilter ff_vf_zoompan = {
     .uninit        = uninit,
     .query_formats = query_formats,
     .activate      = activate,
-    .inputs        = inputs,
-    .outputs       = outputs,
+    FILTER_INPUTS(inputs),
+    FILTER_OUTPUTS(outputs),
 };
diff --git a/libavfilter/vf_zscale.c b/libavfilter/vf_zscale.c
index d21de8d9db..dfea00f9eb 100644
--- a/libavfilter/vf_zscale.c
+++ b/libavfilter/vf_zscale.c
@@ -914,7 +914,6 @@ static const AVFilterPad avfilter_vf_zscale_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
     },
-    { NULL }
 };
 
 static const AVFilterPad avfilter_vf_zscale_outputs[] = {
@@ -923,7 +922,6 @@ static const AVFilterPad avfilter_vf_zscale_outputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_props,
     },
-    { NULL }
 };
 
 const AVFilter ff_vf_zscale = {
@@ -934,7 +932,7 @@ const AVFilter ff_vf_zscale = {
     .priv_size       = sizeof(ZScaleContext),
     .priv_class      = &zscale_class,
     .uninit          = uninit,
-    .inputs          = avfilter_vf_zscale_inputs,
-    .outputs         = avfilter_vf_zscale_outputs,
+    FILTER_INPUTS(avfilter_vf_zscale_inputs),
+    FILTER_OUTPUTS(avfilter_vf_zscale_outputs),
     .process_command = process_command,
 };
diff --git a/libavfilter/vsink_nullsink.c b/libavfilter/vsink_nullsink.c
index 1c796b7cb8..f21299c6f0 100644
--- a/libavfilter/vsink_nullsink.c
+++ b/libavfilter/vsink_nullsink.c
@@ -32,13 +32,12 @@ static const AVFilterPad avfilter_vsink_nullsink_inputs[] = {
         .type        = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
     },
-    { NULL },
 };
 
 const AVFilter ff_vsink_nullsink = {
     .name        = "nullsink",
     .description = NULL_IF_CONFIG_SMALL("Do absolutely nothing with the input video."),
     .priv_size   = 0,
-    .inputs      = avfilter_vsink_nullsink_inputs,
+    FILTER_INPUTS(avfilter_vsink_nullsink_inputs),
     .outputs     = NULL,
 };
diff --git a/libavfilter/vsrc_cellauto.c b/libavfilter/vsrc_cellauto.c
index 0b5b131786..9a62cfedc3 100644
--- a/libavfilter/vsrc_cellauto.c
+++ b/libavfilter/vsrc_cellauto.c
@@ -321,7 +321,6 @@ static const AVFilterPad cellauto_outputs[] = {
         .request_frame = request_frame,
         .config_props  = config_props,
     },
-    { NULL }
 };
 
 const AVFilter ff_vsrc_cellauto = {
@@ -333,5 +332,5 @@ const AVFilter ff_vsrc_cellauto = {
     .uninit        = uninit,
     .query_formats = query_formats,
     .inputs        = NULL,
-    .outputs       = cellauto_outputs,
+    FILTER_OUTPUTS(cellauto_outputs),
 };
diff --git a/libavfilter/vsrc_gradients.c b/libavfilter/vsrc_gradients.c
index 199abab3fa..863cfe9b5e 100644
--- a/libavfilter/vsrc_gradients.c
+++ b/libavfilter/vsrc_gradients.c
@@ -292,7 +292,6 @@ static const AVFilterPad gradients_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vsrc_gradients = {
@@ -302,7 +301,7 @@ const AVFilter ff_vsrc_gradients = {
     .priv_class    = &gradients_class,
     .query_formats = query_formats,
     .inputs        = NULL,
-    .outputs       = gradients_outputs,
+    FILTER_OUTPUTS(gradients_outputs),
     .activate      = activate,
     .flags         = AVFILTER_FLAG_SLICE_THREADS,
 };
diff --git a/libavfilter/vsrc_life.c b/libavfilter/vsrc_life.c
index b954f855c7..2165d1a70f 100644
--- a/libavfilter/vsrc_life.c
+++ b/libavfilter/vsrc_life.c
@@ -436,7 +436,6 @@ static const AVFilterPad life_outputs[] = {
         .request_frame = request_frame,
         .config_props  = config_props,
     },
-    { NULL}
 };
 
 const AVFilter ff_vsrc_life = {
@@ -448,5 +447,5 @@ const AVFilter ff_vsrc_life = {
     .uninit        = uninit,
     .query_formats = query_formats,
     .inputs        = NULL,
-    .outputs       = life_outputs,
+    FILTER_OUTPUTS(life_outputs),
 };
diff --git a/libavfilter/vsrc_mandelbrot.c b/libavfilter/vsrc_mandelbrot.c
index 20ae55835b..df8584b37c 100644
--- a/libavfilter/vsrc_mandelbrot.c
+++ b/libavfilter/vsrc_mandelbrot.c
@@ -413,7 +413,6 @@ static const AVFilterPad mandelbrot_outputs[] = {
         .request_frame = request_frame,
         .config_props  = config_props,
     },
-    { NULL }
 };
 
 const AVFilter ff_vsrc_mandelbrot = {
@@ -425,5 +424,5 @@ const AVFilter ff_vsrc_mandelbrot = {
     .uninit        = uninit,
     .query_formats = query_formats,
     .inputs        = NULL,
-    .outputs       = mandelbrot_outputs,
+    FILTER_OUTPUTS(mandelbrot_outputs),
 };
diff --git a/libavfilter/vsrc_mptestsrc.c b/libavfilter/vsrc_mptestsrc.c
index 0a6f3498b5..f94a78fb84 100644
--- a/libavfilter/vsrc_mptestsrc.c
+++ b/libavfilter/vsrc_mptestsrc.c
@@ -351,7 +351,6 @@ static const AVFilterPad mptestsrc_outputs[] = {
         .request_frame = request_frame,
         .config_props  = config_props,
     },
-    { NULL }
 };
 
 const AVFilter ff_vsrc_mptestsrc = {
@@ -362,5 +361,5 @@ const AVFilter ff_vsrc_mptestsrc = {
     .init          = init,
     .query_formats = query_formats,
     .inputs        = NULL,
-    .outputs       = mptestsrc_outputs,
+    FILTER_OUTPUTS(mptestsrc_outputs),
 };
diff --git a/libavfilter/vsrc_sierpinski.c b/libavfilter/vsrc_sierpinski.c
index 1e331b01fb..d3d136f7ae 100644
--- a/libavfilter/vsrc_sierpinski.c
+++ b/libavfilter/vsrc_sierpinski.c
@@ -218,7 +218,6 @@ static const AVFilterPad sierpinski_outputs[] = {
         .request_frame = sierpinski_request_frame,
         .config_props  = config_output,
     },
-    { NULL }
 };
 
 const AVFilter ff_vsrc_sierpinski = {
@@ -228,6 +227,6 @@ const AVFilter ff_vsrc_sierpinski = {
     .priv_class    = &sierpinski_class,
     .query_formats = query_formats,
     .inputs        = NULL,
-    .outputs       = sierpinski_outputs,
+    FILTER_OUTPUTS(sierpinski_outputs),
     .flags         = AVFILTER_FLAG_SLICE_THREADS,
 };
diff --git a/libavfilter/vsrc_testsrc.c b/libavfilter/vsrc_testsrc.c
index 56b46c6bd8..646e8257aa 100644
--- a/libavfilter/vsrc_testsrc.c
+++ b/libavfilter/vsrc_testsrc.c
@@ -263,7 +263,6 @@ static const AVFilterPad color_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = color_config_props,
     },
-    {  NULL }
 };
 
 const AVFilter ff_vsrc_color = {
@@ -276,7 +275,7 @@ const AVFilter ff_vsrc_color = {
     .activate        = activate,
     .query_formats   = color_query_formats,
     .inputs          = NULL,
-    .outputs         = color_outputs,
+    FILTER_OUTPUTS(color_outputs),
     .process_command = color_process_command,
 };
 
@@ -394,7 +393,6 @@ static const AVFilterPad haldclutsrc_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = haldclutsrc_config_props,
     },
-    {  NULL }
 };
 
 const AVFilter ff_vsrc_haldclutsrc = {
@@ -407,7 +405,7 @@ const AVFilter ff_vsrc_haldclutsrc = {
     .query_formats = haldclutsrc_query_formats,
     .activate      = activate,
     .inputs        = NULL,
-    .outputs       = haldclutsrc_outputs,
+    FILTER_OUTPUTS(haldclutsrc_outputs),
 };
 #endif /* CONFIG_HALDCLUTSRC_FILTER */
 
@@ -432,7 +430,6 @@ static const AVFilterPad nullsrc_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_props,
     },
-    { NULL },
 };
 
 const AVFilter ff_vsrc_nullsrc = {
@@ -444,7 +441,7 @@ const AVFilter ff_vsrc_nullsrc = {
     .priv_size   = sizeof(TestSourceContext),
     .priv_class  = &nullsrc_class,
     .inputs      = NULL,
-    .outputs     = nullsrc_outputs,
+    FILTER_OUTPUTS(nullsrc_outputs),
 };
 
 #endif /* CONFIG_NULLSRC_FILTER */
@@ -665,7 +662,6 @@ static const AVFilterPad avfilter_vsrc_testsrc_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_props,
     },
-    { NULL }
 };
 
 const AVFilter ff_vsrc_testsrc = {
@@ -678,7 +674,7 @@ const AVFilter ff_vsrc_testsrc = {
     .query_formats = test_query_formats,
     .activate      = activate,
     .inputs        = NULL,
-    .outputs       = avfilter_vsrc_testsrc_outputs,
+    FILTER_OUTPUTS(avfilter_vsrc_testsrc_outputs),
 };
 
 #endif /* CONFIG_TESTSRC_FILTER */
@@ -938,7 +934,6 @@ static const AVFilterPad avfilter_vsrc_testsrc2_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = test2_config_props,
     },
-    { NULL }
 };
 
 const AVFilter ff_vsrc_testsrc2 = {
@@ -951,7 +946,7 @@ const AVFilter ff_vsrc_testsrc2 = {
     .query_formats = test2_query_formats,
     .activate      = activate,
     .inputs        = NULL,
-    .outputs       = avfilter_vsrc_testsrc2_outputs,
+    FILTER_OUTPUTS(avfilter_vsrc_testsrc2_outputs),
 };
 
 #endif /* CONFIG_TESTSRC2_FILTER */
@@ -1110,7 +1105,6 @@ static const AVFilterPad avfilter_vsrc_rgbtestsrc_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = rgbtest_config_props,
     },
-    { NULL }
 };
 
 const AVFilter ff_vsrc_rgbtestsrc = {
@@ -1123,7 +1117,7 @@ const AVFilter ff_vsrc_rgbtestsrc = {
     .query_formats = rgbtest_query_formats,
     .activate      = activate,
     .inputs        = NULL,
-    .outputs       = avfilter_vsrc_rgbtestsrc_outputs,
+    FILTER_OUTPUTS(avfilter_vsrc_rgbtestsrc_outputs),
 };
 
 #endif /* CONFIG_RGBTESTSRC_FILTER */
@@ -1283,7 +1277,6 @@ static const AVFilterPad avfilter_vsrc_yuvtestsrc_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = yuvtest_config_props,
     },
-    { NULL }
 };
 
 const AVFilter ff_vsrc_yuvtestsrc = {
@@ -1296,7 +1289,7 @@ const AVFilter ff_vsrc_yuvtestsrc = {
     .query_formats = yuvtest_query_formats,
     .activate      = activate,
     .inputs        = NULL,
-    .outputs       = avfilter_vsrc_yuvtestsrc_outputs,
+    FILTER_OUTPUTS(avfilter_vsrc_yuvtestsrc_outputs),
 };
 
 #endif /* CONFIG_YUVTESTSRC_FILTER */
@@ -1423,7 +1416,6 @@ static const AVFilterPad smptebars_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_props,
     },
-    { NULL }
 };
 
 #if CONFIG_PAL75BARS_FILTER
@@ -1470,7 +1462,7 @@ const AVFilter ff_vsrc_pal75bars = {
     .query_formats = smptebars_query_formats,
     .activate      = activate,
     .inputs        = NULL,
-    .outputs       = smptebars_outputs,
+    FILTER_OUTPUTS(smptebars_outputs),
 };
 
 #endif  /* CONFIG_PAL75BARS_FILTER */
@@ -1517,7 +1509,7 @@ const AVFilter ff_vsrc_pal100bars = {
     .query_formats = smptebars_query_formats,
     .activate      = activate,
     .inputs        = NULL,
-    .outputs       = smptebars_outputs,
+    FILTER_OUTPUTS(smptebars_outputs),
 };
 
 #endif  /* CONFIG_PAL100BARS_FILTER */
@@ -1585,7 +1577,7 @@ const AVFilter ff_vsrc_smptebars = {
     .query_formats = smptebars_query_formats,
     .activate      = activate,
     .inputs        = NULL,
-    .outputs       = smptebars_outputs,
+    FILTER_OUTPUTS(smptebars_outputs),
 };
 
 #endif  /* CONFIG_SMPTEBARS_FILTER */
@@ -1691,7 +1683,7 @@ const AVFilter ff_vsrc_smptehdbars = {
     .query_formats = smptebars_query_formats,
     .activate      = activate,
     .inputs        = NULL,
-    .outputs       = smptebars_outputs,
+    FILTER_OUTPUTS(smptebars_outputs),
 };
 
 #endif  /* CONFIG_SMPTEHDBARS_FILTER */
@@ -1753,7 +1745,6 @@ static const AVFilterPad avfilter_vsrc_allyuv_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = config_props,
     },
-    { NULL }
 };
 
 const AVFilter ff_vsrc_allyuv = {
@@ -1766,7 +1757,7 @@ const AVFilter ff_vsrc_allyuv = {
     .query_formats = allyuv_query_formats,
     .activate      = activate,
     .inputs        = NULL,
-    .outputs       = avfilter_vsrc_allyuv_outputs,
+    FILTER_OUTPUTS(avfilter_vsrc_allyuv_outputs),
 };
 
 #endif /* CONFIG_ALLYUV_FILTER */
@@ -1827,7 +1818,6 @@ static const AVFilterPad avfilter_vsrc_allrgb_outputs[] = {
         .type          = AVMEDIA_TYPE_VIDEO,
         .config_props  = allrgb_config_props,
     },
-    { NULL }
 };
 
 const AVFilter ff_vsrc_allrgb = {
@@ -1840,7 +1830,7 @@ const AVFilter ff_vsrc_allrgb = {
     .query_formats = allrgb_query_formats,
     .activate      = activate,
     .inputs        = NULL,
-    .outputs       = avfilter_vsrc_allrgb_outputs,
+    FILTER_OUTPUTS(avfilter_vsrc_allrgb_outputs),
 };
 
 #endif /* CONFIG_ALLRGB_FILTER */



More information about the ffmpeg-cvslog mailing list