FFmpeg Single vs Multiple Filtergraph Performance

When designing video processing pipelines in FFmpeg, choosing between a single complex filtergraph and multiple simple filtergraphs significantly affects processing speed, hardware utilization, and memory consumption. A single large filtergraph processes frames entirely in memory to avoid intermediate disk I/O and redundant re-encoding, but it can introduce threading bottlenecks and high RAM usage. Conversely, splitting processing into multiple simpler stages offers better modularity and thread isolation, but typically introduces severe disk I/O, context switching, or generational compression overhead.

Encode and Decode Overhead

The most substantial performance difference lies in how pixel data is passed between operations:

  • Single Filtergraph: Raw, uncompressed video frames (AVFrame) pass directly from one filter to the next within memory buffers. Encoding occurs only once at the end of the graph, maximizing processor efficiency by eliminating unnecessary decompression and compression cycles.
  • Multiple Filtergraphs (File-based): Each separate step requires decoding the input, applying the filter, encoding the output to an intermediate file, and writing to disk. Even with fast, intermediate codecs like ProRes or DNxHD, the CPU and GPU spend massive amounts of cycles repeatedly compressing and decompressing the same stream.
  • Multiple Filtergraphs (Piped): Using standard OS pipes (|) or named pipes between separate FFmpeg instances eliminates disk writes, but it still requires serializing raw video frames (like yuv4mpegpipe or rawvideo) between processes. This incurs significant operating system context switching and inter-process communication (IPC) overhead.

Threading and Pipeline Bottlenecks

FFmpeg handles threading differently within a single execution compared to multiple distinct operating system processes:

  • Thread Synchronization Bottlenecks: In a massive filtergraph using complex branching (split, overlay, concat), the entire pipeline moves at the speed of the slowest filter. If one branch contains a single-threaded filter (or a filter with poor thread scalability), that filter throttles upstream inputs and downstream outputs. FFmpeg’s internal frame-threading can stall waiting for sync points, causing CPU core utilization to drop.
  • Process-Level Concurrency: Running multiple simple filtergraphs across distinct FFmpeg processes allows the operating system kernel to schedule each task across all available CPU cores independently. If you have distinct stages that are CPU-bound and do not rely on immediate sequential dependencies, parallel process execution can achieve higher aggregate CPU utilization than a single tangled graph.

Memory Footprint and Buffer Management

Memory usage scales radically depending on how filters buffer frames:

  • Single Graph Buffering: Complex topologies that branch and recombine frames—such as delaying a stream to overlay it later, or running multi-pass spatial filters—must hold uncompressed frames in memory queues until all target nodes consume them. Because uncompressed 4K or 10-bit HDR frames consume vast amounts of RAM (approximately 25–50 MB per single frame), large filtergraphs with long delays can quickly lead to out-of-memory errors.
  • Simple Graph Isolation: Simple, linear filtergraphs require minimal internal buffering. The memory footprint remains predictably low because frames are processed and discarded almost immediately.

Error Handling and Crash Resilience

Beyond raw throughput, system-level performance includes processing resilience:

  • All-or-Nothing Execution: A single large filtergraph fails completely if an unexpected error occurs at any point in the pipeline. If a filter fails two hours into a complex render, the entire process must be restarted from the beginning.
  • Checkpointing Capability: Segmenting operations into simpler, discrete filtergraphs allows for caching intermediate results. If a downstream stage fails, processing can resume from the latest intermediate state without re-running the earlier filters.

Performance Summary

Use a single large filtergraph when maximum throughput and zero generation loss are required, provided the processing stages are linear or have synchronized branches with minimal frame queuing. Opt for multiple simpler filtergraphs only when memory constraints are critical, when intermediate caching is required for unstable workflows, or when distinct tasks must be distributed across multiple physical machines or nodes.