filter-chain: document ffmpeg plugin

This commit is contained in:
Wim Taymans 2025-06-10 10:34:23 +02:00
parent 8c68537446
commit a78e97a53b
2 changed files with 136 additions and 36 deletions

View file

@ -411,7 +411,7 @@ impl_init(const struct spa_handle_factory *factory,
if (spa_streq(k, "filter.graph.path")) if (spa_streq(k, "filter.graph.path"))
path = s; path = s;
} }
if (path == NULL) if (!spa_streq(path, "filtergraph"))
return -EINVAL; return -EINVAL;
impl->plugin.iface = SPA_INTERFACE_INIT( impl->plugin.iface = SPA_INTERFACE_INIT(

View file

@ -32,8 +32,8 @@ extern struct spa_handle_factory spa_filter_graph_factory;
* \page page_module_filter_chain Filter-Chain * \page page_module_filter_chain Filter-Chain
* *
* The filter-chain allows you to create an arbitrary processing graph * The filter-chain allows you to create an arbitrary processing graph
* from LADSPA, LV2 and builtin filters. This filter can be made into a * from LADSPA, LV2, sofa, ffmpeg and builtin filters. This filter can be
* virtual sink/source or between any 2 nodes in the graph. * made into a virtual sink/source or between any 2 nodes in the graph.
* *
* The filter chain is built with 2 streams, a capture stream providing * The filter chain is built with 2 streams, a capture stream providing
* the input to the filter chain and a playback stream sending out the * the input to the filter chain and a playback stream sending out the
@ -95,7 +95,7 @@ extern struct spa_handle_factory spa_filter_graph_factory;
* Nodes describe the processing filters in the graph. Use a tool like lv2ls * Nodes describe the processing filters in the graph. Use a tool like lv2ls
* or listplugins to get a list of available plugins, labels and the port names. * or listplugins to get a list of available plugins, labels and the port names.
* *
* - `type` is one of `ladspa`, `lv2`, `builtin`, `sofa` or `ebur128`. * - `type` is one of `ladspa`, `lv2`, `builtin`, `sofa`, `ebur128` of `ffmpeg`.
* - `name` is the name for this node, you might need this later to refer to this node * - `name` is the name for this node, you might need this later to refer to this node
* and its ports when setting controls or making links. * and its ports when setting controls or making links.
* - `plugin` is the type specific plugin name. * - `plugin` is the type specific plugin name.
@ -103,10 +103,12 @@ extern struct spa_handle_factory spa_filter_graph_factory;
* name in the LADSPA plugin path. * name in the LADSPA plugin path.
* - For LV2, this is the plugin URI obtained with lv2ls. * - For LV2, this is the plugin URI obtained with lv2ls.
* - For builtin, sofa and ebur128 this is ignored * - For builtin, sofa and ebur128 this is ignored
* - For ffmpeg this should be filtergraph
* - `label` is the type specific filter inside the plugin. * - `label` is the type specific filter inside the plugin.
* - For LADSPA this is the label * - For LADSPA this is the label
* - For LV2 this is unused * - For LV2 this is unused
* - For builtin, sofa and ebur128 this is the name of the filter to use * - For builtin, sofa and ebur128 this is the name of the filter to use
* - For ffmpeg this is an FFMpeg filtergraph description
* *
* - `config` contains a filter specific configuration section. Some plugins need * - `config` contains a filter specific configuration section. Some plugins need
* this. (convolver, sofa, delay, ...) * this. (convolver, sofa, delay, ...)
@ -209,8 +211,8 @@ extern struct spa_handle_factory spa_filter_graph_factory;
* *
* ## Builtin filters * ## Builtin filters
* *
* There are some useful builtin filters available. You select them with the label * There are some useful builtin filters available. The type should be `builtin` and
* of the filter node. * you select the specific builtin filter with the `label` of the filter node.
* *
* ### Mixer * ### Mixer
* *
@ -561,9 +563,52 @@ extern struct spa_handle_factory spa_filter_graph_factory;
* a volume ramp up or down. For more a more coarse volume ramp, the "Current" value * a volume ramp up or down. For more a more coarse volume ramp, the "Current" value
* can be used in the `linear` plugin. * can be used in the `linear` plugin.
* *
* ## SOFA filter * ### Debug
* *
* There is an optional builtin SOFA filter available. * The `debug` plugin can be used to debug the audio and control data of other plugins.
*
* It has an "In" input port and an "Out" output data ports. The data from "In" will
* be copied to "Out" and the data will be dumped into the INFO log.
*
* There is also a "Control" input port and an "Notify" output control ports. The
* control from "Control" will be copied to "Notify" and the control value will be
* dumped into the INFO log.
*
* ### Pipe
*
* The `pipe` plugin can be used to filter the audio with another application using pipes
* for sending and receiving the raw audio.
*
* The application needs to consume raw float32 samples from stdin and produce filtered
* float32 samples on stdout.
*
* It has an "In" input port and an "Out" output data ports.
*
* The node requires a `config` section with extra configuration:
*
*\code{.unparsed}
* filter.graph = {
* nodes = [
* {
* type = builtin
* name = ...
* label = pipe
* config = {
* command = "ffmpeg -f f32le -ac 1 -ar 48000 -blocksize 1024 -fflags nobuffer -i \"pipe:\" \"-filter:a\" \"loudnorm=I=-18:TP=-3:LRA=4\" -f f32le -ac 1 -ar 48000 \"pipe:\""
* }
* ...
* }
* }
* ...
* }
*\endcode
*
* - `command` the command to execute. It should consume samples from stdin and produce
* samples on stdout.
*
* ## SOFA filters
*
* There is an optional `sofa` type available (when compiled with `libmysofa`).
* *
* ### Spatializer * ### Spatializer
* *
@ -616,13 +661,15 @@ extern struct spa_handle_factory spa_filter_graph_factory;
* - `Radius` controls how far away the signal is as a value between 0 and 100. * - `Radius` controls how far away the signal is as a value between 0 and 100.
* default is 1.0. * default is 1.0.
* *
* ## EBUR128 filter * ## EBUR128 filters
* *
* There is an optional EBU R128 filter available. * There is an optional EBU R128 plugin available (when compiled with
* `libebur128`) selected with the `ebur128` type. Filters in the plugin
* can be selected with the `label` field.
* *
* ### ebur128 * ### ebur128
* *
* The ebur128 plugin can be used to measure the loudness of a signal. * The ebur128 filter can be used to measure the loudness of a signal.
* *
* It has 7 input ports "In FL", "In FR", "In FC", "In UNUSED", "In SL", "In SR" * It has 7 input ports "In FL", "In FR", "In FC", "In UNUSED", "In SL", "In SR"
* and "In DUAL MONO", corresponding to the different input channels for EBUR128. * and "In DUAL MONO", corresponding to the different input channels for EBUR128.
@ -686,55 +733,108 @@ extern struct spa_handle_factory spa_filter_graph_factory;
* *
* ### lufs2gain * ### lufs2gain
* *
* The lufs2gain plugin can be used to convert LUFS control values to gain. It needs * The lufs2gain filter can be used to convert LUFS control values to gain. It needs
* a target LUFS control input to drive the conversion. * a target LUFS control input to drive the conversion.
* *
* It has 2 input control ports "LUFS" and "Target LUFS" and will produce 1 output * It has 2 input control ports "LUFS" and "Target LUFS" and will produce 1 output
* control value "Gain". This gain can be used as input for the builtin `linear` * control value "Gain". This gain can be used as input for the builtin `linear`
* node, for example, to adust the gain. * filter, for example, to adust the gain.
* *
* ### debug
* *
* The debug plugin can be used to debug the audio and control data of other plugins. * ## FFmpeg
* *
* It has an "In" input port and an "Out" output data ports. The data from "In" will * There is an optional FFmpeg filter available (when compiled with `libavfilter`)
* be copied to "Out" and the data will be dumped into the INFO log. * that can be selected with the `ffmpeg` type. Use the `plugin` field to select
* the plugin to use.
* *
* There is also a "Control" input port and an "Notify" output control ports. The * ### Filtergraph
* control from "Control" will be copied to "Notify" and the control value will be
* dumped into the INFO log.
* *
* ### pipe * The filtergraph FFmpeg plugin is selected with the `filtergraph` plugin
* field in the node.
* *
* The pipe plugin can be used to filter the audio with another application using pipes * The filtergraph filter allows you to specify an set of audio filters using
* for sending and receiving the raw audio. * the FFmpeg filtergraph syntax (https://ffmpeg.org/ffmpeg-filters.html).
* *
* The application needs to consume raw float32 samples from stdin and produce filtered * The `label` field should be used to describe the filtergraph in use.
* float32 samples on stdout.
* *
* It has an "In" input port and an "Out" output data ports. * FFmpeg filtergraph input and output ports can have multiple channels. The
* filter-chain can split those into individual ports to use as input and output
* ports. For this, the ports in the filtergraph need to have a specific name
* convention, either `<port-name>_<channel-name>` or `<port-name>_<channel-layout>`.
* *
* The node requires a `config` section with extra configuration: * When a single channel is specified, the port can be referenced in inputs and
* outputs sections with `<name>:<port-name>_<channel-name>`. When a channel-layout
* is specified, each port name gets a `_<number>` appended, starting from 0 and
* counting up for each channel in the layout.
*
* The `filtergraph` plugin will automatically add format converters when the input
* port channel-layout, format or graph sample-rates don't match.
*
* Note that the FFmpeg filtergraph is not Real-time safe because it might does
* allocations from the processing thread. It is advised to run the filter-chain
* streams in async mode (`node.async = true`) to avoid interrupting the other
* RT threads.
*
* Some examples:
*
* The stereo ports are split into their channels with the `_0` and `_1` suffixes.
* *
*\code{.unparsed} *\code{.unparsed}
* filter.graph = { * filter.graph = {
* nodes = [ * nodes = [
* { * {
* type = builtin * type = ffmpeg
* name = ... * plugin = filtergraph
* label = pipe * name = filter
* config = { * label = "[in_stereo]loudnorm=I=-18:TP=-3:LRA=4[out_stereo]"
* command = "ffmpeg -f f32le -ac 1 -ar 48000 -blocksize 1024 -fflags nobuffer -i \"pipe:\" \"-filter:a\" \"loudnorm=I=-18:TP=-3:LRA=4\" -f f32le -ac 1 -ar 48000 \"pipe:\""
* }
* ...
* } * }
* } * }
* inputs = [ "filter:in_stereo_0" "filter:in_stereo_1" ]
* outputs = [ "filter:out_stereo_0" "filter:out_stereo_1" ]
* ... * ...
* } * }
*\endcode *\endcode
* *
* - `command` the command to execute. It should consume samples from stdin and produce * It is possible to have multiple input and output ports for the filtergraphs.
* samples on stdout. * In the next example, the ports have a single channel name and so don't have
* the `_0` suffix to identify them. This can be simplified by removing the `amerge`
* and `channelsplit` filters and using the `_stereo` suffix on port names to let
* PipeWire do the splitting and merging more efficiently.
*
*\code{.unparsed}
* filter.graph = {
* nodes = [
* {
* type = ffmpeg
* plugin = filtergraph
* name = filter
* label = "[in_FL][in_FR]amerge,extrastereo,channelsplit[out_FL][out_FR]"
* }
* }
* inputs = [ "filter:in_FL" "filter:in_FR" ]
* outputs = [ "filter:out_FL" "filter:out_FR" ]
* ...
* }
*\endcode
*
* Here is a last example of a surround sound upmixer:
*
*\code{.unparsed}
* filter.graph = {
* nodes = [
* {
* type = ffmpeg
* plugin = filtergraph
* name = filter
* label = "[in_stereo]surround[out_5.1]"
* }
* }
* inputs = [ "filter:in_FL" "filter:in_FR" ]
* outputs = [ "filter:out_5.1_0" "filter:out_5.1_1" "filter:out_5.1_2"
* "filter:out_5.1_3" "filter:out_5.1_4" "filter:out_5.1_5" ]
* ...
* }
*\endcode
* *
* ## General options * ## General options
* *