This is a follow-up to the my previous message: https://ffmpeg.org/pipermail/ffmpeg-devel/2025-March/340895.html
On 3/13/25 13:18, Leandro Santiago wrote: > This is a POC/prototype that aims to enable out of tree filters on > FFmpeg. > > Here I name them "extra filters". > > It introduces the program `jq` as a new build dependency. > > To test it, create a directory, for instance, /tmp/my-shiny-filter/ and > inside it, create the following files: > > `filter.json`, with the content: > > ``` > { > "check": "require_pkg_config json json-c json-c/json.h json_c_version_num", > "symbols": ["ff_vf_foo", "ff_vf_bar"] > } > ``` > > `filter.mak`, with the content: > > ``` > OBJS += vf_shiny.o > LIBOBJS += vf_shiny.o > > libavfilter/vf_shiny.o: > $(CC) $(EXTRA_FILTER_FLAGS) -c -o $@ > $(EXTRA_FILTER_FOO_LOCATION)/vf_shiny.c > ``` > > `vf_shiny.c` file, with the content: > > > ``` > #include "libavutil/internal.h" > > #include "avfilter.h" > > #include "filters.h" > > #include "video.h" > > const FFFilter ff_vf_bar = { > .p.name = "bar", > .p.description = NULL_IF_CONFIG_SMALL("Example filter Baz"), > .p.flags = AVFILTER_FLAG_METADATA_ONLY, > FILTER_INPUTS(ff_video_default_filterpad), > FILTER_OUTPUTS(ff_video_default_filterpad), > }; > > const FFFilter ff_vf_foo = { > .p.name = "foo", > .p.description = NULL_IF_CONFIG_SMALL("Another foo filter"), > .p.flags = AVFILTER_FLAG_METADATA_ONLY, > FILTER_INPUTS(ff_video_default_filterpad), > FILTER_OUTPUTS(ff_video_default_filterpad), > }; > ``` > > Then, from the ffmpeg source tree, run configure specifying where the > extra filter is located: > > ``` > ./configure --extra-filter=/tmp/my-shiny-filter > make ffplay > ``` > > Now you can use the filters: > > ``` > ./ffplay /path/to/file.webm -vf 'foo,baz' > ``` > > What works: > > - Building C based filters with no extra dependencies. > - Multiple filters in the same object file. > > What does not work: > > - The extra filters will not use the same CC flags used to build the > built-in filters as I could get it to work yet. > - Due to the above limitation, you cannot include headers of extra > dependencies, for instance, `json.h` in the example. > - You can pass arbitrary CFLAGS or LDFLAGS in the filter.json file, > but they should be passed only then building/linking `libavfilter`, > instead of other libraries. > > What was not implemented: > > - I believe it would be useful to check if the license of the filter is > compatible with the license used to build FFmpeg. > - Only extra filters written in C (maybe C++?) are supported for now. > One of my goals is to enable Rust as well. > > Signed-off-by: Leandro Santiago <leandrosansi...@gmail.com> > --- > .gitignore | 3 ++ > configure | 61 ++++++++++++++++++++++++++++++++++++++++ > libavfilter/Makefile | 4 +++ > libavfilter/allfilters.c | 1 + > 4 files changed, 69 insertions(+) > > diff --git a/.gitignore b/.gitignore > index 9cfc78b414..4963e90191 100644 > --- a/.gitignore > +++ b/.gitignore > @@ -43,3 +43,6 @@ > /tools/python/__pycache__/ > /libavcodec/vulkan/*.c > /libavfilter/vulkan/*.c > +/ffbuild/extra-filters.txt > +/ffbuild/extra-filters.mak > +/libavfilter/extra_filters_extern.h > diff --git a/configure b/configure > index 750c99e3b9..6a2adc6c05 100755 > --- a/configure > +++ b/configure > @@ -179,6 +179,7 @@ Individual component options: > --enable-filter=NAME enable filter NAME > --disable-filter=NAME disable filter NAME > --disable-filters disable all filters > + --extra-filter=/foo/bar add extra filter from directory. This option can > be used multiple times > > External library support: > > @@ -1798,6 +1799,7 @@ AVDEVICE_COMPONENTS=" > > AVFILTER_COMPONENTS=" > filters > + extra_filters > " > > AVFORMAT_COMPONENTS=" > @@ -4382,6 +4384,8 @@ do_random(){ > $action $(rand_list "$@" | awk "BEGIN { srand($random_seed) } \$1 == > \"prob\" { prob = \$2; next } rand() < prob { print }") > } > > +rm -f ffbuild/extra-filters.txt > + > # deprecated components (disabled by default) > disable sonic_encoder sonic_ls_encoder > > @@ -4457,6 +4461,10 @@ for opt do > die_unknown $opt > fi > ;; > + --extra-filter=*) > + filter_path="${opt#--extra-filter=}" > + echo "$filter_path" >> ffbuild/extra-filters.txt > + ;; > --list-*) > NAME="${opt#--list-}" > is_in $NAME $COMPONENT_LIST || die_unknown $opt > @@ -4487,6 +4495,36 @@ for opt do > esac > done > > +find_extra_filters_extern() { > + # TODO: handle invalid filter > + while read f; do > + jq -r '.symbols[]' < "$f/filter.json" | sed > 's/^ff_[avfsinkrc]\{2,5\}_\([[:alnum:]_]\{1,\}\)/\1_filter/' > + done < ffbuild/extra-filters.txt > +} > + > +EXTRA_FILTER_LIST=$(find_extra_filters_extern) > + > +for n in extra_filters; do > + v=$(toupper ${n%s})_LIST > + eval enable \$$v > + eval ${n}_if_any="\$$v" > +done > + > +FILTER_LIST=" > + $FILTER_LIST > + $EXTRA_FILTER_LIST > +" > + > +AVFILTER_COMPONENTS_LIST=" > + $AVFILTER_COMPONENTS_LIST > + $EXTRA_FILTER_LIST > +" > + > +ALL_COMPONENTS=" > + $ALL_COMPONENTS > + $EXTRA_FILTER_LIST > +" > + > for e in $env; do > eval "export $e" > done > @@ -7165,6 +7203,10 @@ enabled rkmpp && { require_pkg_config > rkmpp rockchip_mpp rockchip/r > } > enabled vapoursynth && require_headers "vapoursynth/VSScript4.h > vapoursynth/VapourSynth4.h" > > +while read f; do > + # NOTE: this eval is dangerous, as it allows arbitrary code execution! > + eval $(jq -r '.check // true' < "$f/filter.json") > +done < ffbuild/extra-filters.txt > > if enabled gcrypt; then > GCRYPT_CONFIG="${cross_prefix}libgcrypt-config" > @@ -8243,6 +8285,12 @@ for entry in $LIBRARY_LIST $PROGRAM_LIST > $EXTRALIBS_LIST; do > eval echo "EXTRALIBS-${entry}=\$${entry}_extralibs" >> ffbuild/config.mak > done > > +echo "" > ffbuild/extra-filters.mak > + > +while read f; do > + echo "include $f/filter.mak" >> ffbuild/extra-filters.mak > +done < ffbuild/extra-filters.txt > + > cat > $TMPH <<EOF > /* Automatically generated by configure - do not modify! */ > #ifndef FFMPEG_CONFIG_H > @@ -8330,6 +8378,19 @@ cp_if_changed $TMPH libavutil/avconfig.h > # ... > eval "$(sed -n "s/^extern const FFFilter > ff_\([avfsinkrc]\{2,5\}\)_\(.*\);/full_filter_name_\2=\1_\2/p" > $source_path/libavfilter/allfilters.c)" > > +rm -f libavfilter/extra_filters_extern.h > + > +# Handle extra filters > +while read f; do > + eval "$(jq -r '.symbols[]' < "$f/filter.json" | sed > 's/^ff_\([avfsinkrc]\{2,5\}\)_\([[:alnum:]]\{1,\}\)$/full_filter_name_\2=\1_\2/')" > + jq -r '.symbols[]' < "$f/filter.json" | while read symbol; do > + echo "extern const FFFilter $symbol;" >> > libavfilter/extra_filters_extern.h > + echo "EXTRA_FILTER_$(echo $symbol | sed > 's/^ff_[avfsinkrc]\{2,5\}_\([[:alnum:]]\{1,\}\)$/\1/' | tr a-z A-Z)_LOCATION > = $f" >> ffbuild/extra-filters.mak > + echo "LDFLAGS += $(jq -r '.ldflags // ""' < "$f/filter.json")" >> > ffbuild/extra-filters.mak > + echo "CFLAGS += $(jq -r '.cflags // ""' < "$f/filter.json")" >> > ffbuild/extra-filters.mak > + done > +done < ffbuild/extra-filters.txt > + > # generate the lists of enabled components > print_enabled_components(){ > file=$1 > diff --git a/libavfilter/Makefile b/libavfilter/Makefile > index 7c0d879ec9..9b22aece3a 100644 > --- a/libavfilter/Makefile > +++ b/libavfilter/Makefile > @@ -27,6 +27,10 @@ OBJS = allfilters.o > \ > include $(SRC_PATH)/libavfilter/dnn/Makefile > include $(SRC_PATH)/libavfilter/vulkan/Makefile > > +# extra filters handling > +include $(SRC_PATH)/ffbuild/extra-filters.mak > +EXTRA_FILTER_FLAGS = -I$(PWD) -I$(PWD)/libavfilter $(CPPFLAGS) $(CC_DEPFLAGS) > + > OBJS-$(HAVE_LIBC_MSVCRT) += file_open.o > OBJS-$(HAVE_THREADS) += pthread.o > > diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c > index 740d9ab265..e8565de5b0 100644 > --- a/libavfilter/allfilters.c > +++ b/libavfilter/allfilters.c > @@ -621,6 +621,7 @@ extern const FFFilter ff_vsrc_buffer; > extern const FFFilter ff_asink_abuffer; > extern const FFFilter ff_vsink_buffer; > > +#include "libavfilter/extra_filters_extern.h" > #include "libavfilter/filter_list.c" > > _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".