FFix.Graph (ffix v0.2.0)

Copy Markdown View Source

Parse FFmpeg filtergraphs and reuse named filter pipelines.

Ordinary pipelines can go straight from FFix.Filter to an output. Use a graph when you want to work with existing filtergraph text or package several filter operations behind named inputs and outputs.

Start with an FFmpeg filtergraph

alias FFix.Graph
graph = Graph.parse!("[0:v]scale=w=640:h=-2[preview]")
source = FFix.input("interview.mp4")
bound = Graph.bind(graph, %{0 => source})

FFix.output(bound[:preview], "preview.mp4") |> FFix.command()

Binding associates the graph's input 0 with the input declaration. The name preview comes from the filtergraph's output label. graph[:preview] and graph[0] both retrieve that output as a stream you can filter or map.

Build a reusable template

alias FFix.{Filter, Graph}
picture = Graph.input(:picture, :video)
template = FFix.graph(outputs: [preview: Filter.scale(picture, w: 320, h: -2)])

source = FFix.input("interview.mp4")
instance = Graph.bind(template, picture: FFix.video(source, 0))
flipped = Filter.hflip(instance[:preview])
FFix.output(flipped, "preview.mp4") |> FFix.command()

Each binding creates a separate instance of the template's filters. You can supply input declarations or streams that have already passed through filters. See bind/2 for replacing individual input tracks.

Keep branches connected

Selecting one graph output keeps the other branches of that graph too. Connect every produced stream to another filter or an output. When branching a filtered stream, use FFix.Filter.split/2 or FFix.Filter.asplit/2.

Sinks finish a branch without writing its media to an output. Include them with FFix.graph(terminals: [...]), then pass terminals(graph) to the command's terminals: option. This also supports sink-only graphs.

FFix.graph/1 accepts the graph-level sws_flags setting. Equal settings compose; conflicting values raise an error. General CLI options belong on FFix.command/2 or its inputs and outputs.

Filter composition checks the new operation, not every ancestor in an existing snapshot. After editing graph data directly, use FFix.validate!/1 to check the whole graph. Command construction and graph serialization also validate it.

See FFmpeg filtergraph syntax for labels, chains, and filter arguments.

Summary

Functions

Creates a graph instance by connecting its inputs to declarations or streams.

Returns an output by name or zero-based position, or nil when missing. Also available as graph[key].

Like export/2, raising ArgumentError when the output is missing.

Returns the graph's output streams in declaration order. Each stream retains the whole graph.

Declares a named graph input or a positional FFmpeg input reference.

Builds a graph input from an FFmpeg stream specifier such as "0:v". It supplies one matching stream to a filter.

Parses FFmpeg filtergraph text into a graph with named output streams.

Returns sink references for FFix.command(outputs, terminals: Graph.terminals(graph)).

Validates connections and returns FFmpeg filtergraph text.

Types

input_id()

@type input_id() :: non_neg_integer() | atom() | String.t() | reference()

input_selector()

@type input_selector() ::
  :input
  | FFix.Command.Input.media()
  | :video_only
  | {FFix.Command.Input.media() | :video_only, non_neg_integer()}
  | {:index, non_neg_integer()}
  | {:raw, String.t()}

node_id()

@type node_id() :: reference()

setting()

@type setting() :: {atom() | String.t(), term()}

t()

@type t() :: %FFix.Graph{
  exports: [FFix.Graph.Export.t()],
  id: reference(),
  nodes: %{required(node_id()) => term()},
  order: [node_id()],
  settings: [setting()],
  terminals: [node_id()]
}

Functions

bind(graph, bindings)

@spec bind(t(), map() | list()) :: t()

Creates a graph instance by connecting its inputs to declarations or streams.

Bindings are a map or ordered list of pairs. A key names an input or identifies one exact {input, selector}. An input declaration can supply all tracks of a graph input; a stream replaces one selected track:

graph = FFix.Graph.parse!("[0:v:0]hflip[picture];[0:a:0]volume=0.5[sound]")
source = FFix.input("interview.mp4")
FFix.Graph.bind(graph, %{0 => source})

To replace tracks independently, use keys such as {0, {:video, 0}} and {0, {:audio, 0}}. One stream cannot stand in for several different selectors; bind an input declaration or each exact track instead.

Existing input declarations are retained when omitted. Unbound inputs, unused keys, overlapping bindings, and incompatible media raise ArgumentError. The instance retains supplied streams' other branches, sinks, and settings. Explicit FFmpeg filter instance names are preserved, so choose distinct names yourself when commands refer to particular filter instances.

export(graph, key)

Returns an output by name or zero-based position, or nil when missing. Also available as graph[key].

export!(graph, key)

Like export/2, raising ArgumentError when the output is missing.

exports(graph)

@spec exports(t()) :: [FFix.Graph.StreamRef.t()]

Returns the graph's output streams in declaration order. Each stream retains the whole graph.

input(input, selector)

Declares a named graph input or a positional FFmpeg input reference.

FFix.Graph.input(:picture, :video)
FFix.Graph.input(0, {:audio, 1})

Bind named inputs with bind/2. Positional inputs refer to the command's explicit inputs: order. Graph selectors such as :video supply one matching filter input. For selecting tracks from a declared file, use FFix.video/3 or FFix.audio/3 instead.

input_raw(spec)

@spec input_raw(String.t()) :: FFix.Graph.StreamRef.t()

Builds a graph input from an FFmpeg stream specifier such as "0:v". It supplies one matching stream to a filter.

parse!(source)

@spec parse!(String.t()) :: t()

Parses FFmpeg filtergraph text into a graph with named output streams.

graph = FFix.Graph.parse!("[0:v]scale=w=320:h=-2[preview]")
FFix.to_filtergraph(graph)
#=> "[0:v]scale=w=320:h=-2[preview];"

Filters must be known to the helper catalog and have a resolvable output layout. Declare each labeled producer before the filters that consume it; forward references and cycles raise ArgumentError. The parser supports common FFmpeg syntax, including quoted and escaped option values.

Use FFix.Filter.filter/4 to construct filters with other names or explicit output layouts. Bind parsed inputs with bind/2 before normal command assembly, or provide an explicit inputs: list to FFix.command/2.

terminals(graph)

@spec terminals(t()) :: [FFix.Graph.Terminal.t()]

Returns sink references for FFix.command(outputs, terminals: Graph.terminals(graph)).

to_filtergraph(graph)

@spec to_filtergraph(t()) :: String.t()

Validates connections and returns FFmpeg filtergraph text.

Standalone rendering uses positional input references. For graphs bound to input declarations, use FFix.to_argv/1 on the command so input positions can be resolved. Logical graph names may be escaped or replaced with safe labels in the rendered text.