From mboxrd@z Thu Jan  1 00:00:00 1970
Return-Path: <ffmpeg-devel-bounces@ffmpeg.org>
Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100])
	by master.gitmailbox.com (Postfix) with ESMTPS id C494C4E5F0
	for <ffmpegdev@gitmailbox.com>; Thu, 13 Mar 2025 12:19:02 +0000 (UTC)
Received: from [127.0.1.1] (localhost [127.0.0.1])
	by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 249B868E789;
	Thu, 13 Mar 2025 14:18:59 +0200 (EET)
Received: from mail-wr1-f41.google.com (mail-wr1-f41.google.com
 [209.85.221.41])
 by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 1802568C8BB
 for <ffmpeg-devel@ffmpeg.org>; Thu, 13 Mar 2025 14:18:53 +0200 (EET)
Received: by mail-wr1-f41.google.com with SMTP id
 ffacd0b85a97d-3913fdd0120so502042f8f.0
 for <ffmpeg-devel@ffmpeg.org>; Thu, 13 Mar 2025 05:18:53 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=gmail.com; s=20230601; t=1741868332; x=1742473132; darn=ffmpeg.org;
 h=content-transfer-encoding:content-language:to:subject:from
 :user-agent:mime-version:date:message-id:from:to:cc:subject:date
 :message-id:reply-to;
 bh=a9nSAFr+LRlyyioU39NvKlQtAtnlpPcvNdr7XWZXSEY=;
 b=ZlDof47pafkh6PYJ66IjUAB/+kVgX85FWb+eMx6lNEvECYFhBMiKkotd24yuq12WuK
 JLLq/ACdnyKQCC2NCDg9ypVN7vT3WQEosvzI+0jL7hIo1awkEbuxIkVxqFgJe39iGx/s
 7GoNQUeQNUfAJm3/LX5i32Qdrk/MccCdRrfK1PB+hTwdR6DvaD0bf+LXdfxcbNzt5PEZ
 KT8TUw1WGwGev3EfjDmh45sJrBGgExIp57e0VWGrbIffv0G/2bFdbB2o9ICiG+0pdmnp
 hiEf6CivPp6AGOK/hKLqKn8bui5iOFicl+jDcpsVruXfQUWiTTrPBA/pExDd0GEpofJk
 e9pw==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1741868332; x=1742473132;
 h=content-transfer-encoding:content-language:to:subject:from
 :user-agent:mime-version:date:message-id:x-gm-message-state:from:to
 :cc:subject:date:message-id:reply-to;
 bh=a9nSAFr+LRlyyioU39NvKlQtAtnlpPcvNdr7XWZXSEY=;
 b=xHXF5wh4/4dkC078QAYMZYWo+9/0qXlfhuvmxp0gRAyBnv4uenSOb/KoUvD6rA9kQ3
 Rr8oMYxBr3Jf+9g0esqGawOwQznCA0MAEvgawVVrLsL+R8+IYT1fg2ALvz+tkZITvsO3
 xfj6s8iu9gokv3C2Ihkt3+HPGVf46HHQiEUlHN7Hi4P1qnMO5aEpZZvzy/X4kBtpt21O
 7ydktrUEkybRma7b5HTLYKo7X6AiCS9ueStzYEZplGohK5HqPLrNSVrm9ZjqYpis3oGl
 f0xrJF73kTinLzM+zKZ3YQ3wbIwBVI4tDlfOP+6yBwekyHzoBBHqNm1tolfKM5oBMuiG
 AhZA==
X-Gm-Message-State: AOJu0YwJCwCx8R+8Iqyw6FRGe3VyyCJ8GhVl0pBeCkW1aIdgZmSdmecu
 4ei/eMW7p6yiUgJdnEjAzOgMR4juJ2DbZGHGdEew/nFXDYYdXo8oFRiOag==
X-Gm-Gg: ASbGnctXBcS+fg+7NVY1/OZ0GG8JaupI5WKQj+0uAlCwAAve/VKlMro8s7zOZmhTQKj
 OiWQo/8kR1Fgn5gXlfZveCffqSCAz207JEIsK6PC6GsZIy3S8O+UHhfQkKW000TSw+63PUOvn0W
 QwYVcezsKVmD2QHNrOSWh/baQgd91MyA3duZ9AySPdekjoxgv38A4KeoR5D1q5hZIPmfaQitClQ
 8Qb9s/AKAgJWG/VtcfaE77Wt/h3wX1RW6kUgi9fqUo1kQZ8lRs0GAoEusbArxiWU0QBcvS7eJXI
 3JwLHL1v71qIHb9kgSze9GwQHlxI5lwOf5gSwSutHnEY19vNyAumQDOpJCBszKcyp/umCnE4X6n
 EuSqhkn9hddJFj0iPsP6n9Ug=
X-Google-Smtp-Source: AGHT+IE9Wh3p9THu1J/bk0UcrkRc/ZvSS0odSPm2/G5RUQx3Hw1avFp7ADbR3jndQGBKKm0qWEChMg==
X-Received: by 2002:a05:6000:144d:b0:391:2e58:f085 with SMTP id
 ffacd0b85a97d-39132dab192mr20348986f8f.54.1741868332241; 
 Thu, 13 Mar 2025 05:18:52 -0700 (PDT)
Received: from ?IPV6:2001:9e8:1da4:1900:cde4:ff8d:50cc:75e6?
 ([2001:9e8:1da4:1900:cde4:ff8d:50cc:75e6])
 by smtp.gmail.com with ESMTPSA id
 ffacd0b85a97d-395c888117csm1931769f8f.44.2025.03.13.05.18.51
 for <ffmpeg-devel@ffmpeg.org>
 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128);
 Thu, 13 Mar 2025 05:18:51 -0700 (PDT)
Message-ID: <6bef7ee3-6e0b-496a-9018-ce02d5e8cd63@gmail.com>
Date: Thu, 13 Mar 2025 13:18:49 +0100
MIME-Version: 1.0
User-Agent: Mozilla Thunderbird
From: Leandro Santiago <leandrosansilva@gmail.com>
To: ffmpeg-devel@ffmpeg.org
Content-Language: en-US
Subject: [FFmpeg-devel] [PATCH] avfilter: POC: enable out-of-tree filters
X-BeenThere: ffmpeg-devel@ffmpeg.org
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: FFmpeg development discussions and patches <ffmpeg-devel.ffmpeg.org>
List-Unsubscribe: <https://ffmpeg.org/mailman/options/ffmpeg-devel>,
 <mailto:ffmpeg-devel-request@ffmpeg.org?subject=unsubscribe>
List-Archive: <https://ffmpeg.org/pipermail/ffmpeg-devel>
List-Post: <mailto:ffmpeg-devel@ffmpeg.org>
List-Help: <mailto:ffmpeg-devel-request@ffmpeg.org?subject=help>
List-Subscribe: <https://ffmpeg.org/mailman/listinfo/ffmpeg-devel>,
 <mailto:ffmpeg-devel-request@ffmpeg.org?subject=subscribe>
Reply-To: FFmpeg development discussions and patches <ffmpeg-devel@ffmpeg.org>
Content-Type: text/plain; charset="us-ascii"
Content-Transfer-Encoding: 7bit
Errors-To: ffmpeg-devel-bounces@ffmpeg.org
Sender: "ffmpeg-devel" <ffmpeg-devel-bounces@ffmpeg.org>
Archived-At: <https://master.gitmailbox.com/ffmpegdev/6bef7ee3-6e0b-496a-9018-ce02d5e8cd63@gmail.com/>
List-Archive: <https://master.gitmailbox.com/ffmpegdev/>
List-Post: <mailto:ffmpegdev@gitmailbox.com>

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 <leandrosansilva@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"
 
 
-- 
2.48.1

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".