ffmpeg-filter-complex-patterns

v2026.09.24

Complete guide to FFmpeg filter_complex syntax, multi-input/output pipelines, and composition patterns. PROACTIVELY activate for: (1) filter_complex syntax questions, (2) Multi-input video composition (PiP, grids, overlays), (3) Video transitions (xfade, fades, wipes), (4) Audio mixing (amix, amerge), (5) Stream splitting and routing, (6) Named stream labels, (7) Complex filtergraphs, (8) GPU + CPU hybrid filter chains, (9) ABR encoding ladders, (10) Text and watermark overlays. Provides: Syntax reference, composition patterns, audio mixing examples, transition effects, GPU-accelerated filtergraphs, debugging tips.

GitHub
Install command
npx skhub add josiahsiegel/ffmpeg-filter-complex-patterns
Markdown
SKILL.md

CRITICAL GUIDELINES

Windows File Path Requirements

MANDATORY: Always Use Backslashes on Windows for File Paths

When using Edit or Write tools on Windows, you MUST use backslashes (\) in file paths, NOT forward slashes (/).


Quick Reference

TaskCommand Pattern
Basic filter_complex-filter_complex "[0:v][1:v]overlay"
Named labels[input]filter[output]
Chain filtersfilter1,filter2,filter3
Separate chainschain1;chain2
Map output-map "[label]"

When to Use This Skill

Use for complex filtergraph operations:

  • Multi-input compositions (PiP, grids, overlays)
  • Video transitions and effects
  • Audio mixing and routing
  • Stream splitting for multiple outputs
  • GPU + CPU hybrid processing

For basic filters: use ffmpeg-fundamentals-2025 For hardware acceleration: use ffmpeg-hardware-acceleration


FFmpeg filter_complex Reference (2025)

Comprehensive guide to complex filtergraphs, multi-input compositions, and advanced filter chains.

filter_complex Syntax

Basic Structure

-filter_complex "filterchain1;filterchain2;..."

Each filterchain consists of:

  • Input labels: [input_label]
  • Filter(s): filter1,filter2,... (comma-separated)
  • Output labels: [output_label]

Complete Syntax

[input_label1][input_label2]filter=param1=value1:param2=value2[output_label]

Syntax Components

ComponentDescriptionExample
[0:v]Video stream from input 0First input video
[0:a]Audio stream from input 0First input audio
[1:v]Video stream from input 1Second input video
[label]Custom named labelUser-defined
,Chain filters sequentiallyscale,fps
;Separate independent chainschain1;chain2
=Parameter assignmentscale=1280:720
:Parameter separatorw=1280:h=720

Stream References

ReferenceMeaning
[0]First input (all streams)
[0:v]First input, video stream
[0:a]First input, audio stream
[0:s]First input, subtitle stream
[0:v:0]First input, first video stream
[1:a:1]Second input, second audio stream

Default Labels

  • Unlabeled first filter input uses in
  • Unlabeled last filter output uses out
  • Unlabeled pads connect sequentially

Escaping Rules

# Wrap filtergraph in double quotes
ffmpeg -i input.mp4 \
  -filter_complex "[0:v]drawtext=text='Hello World':fontsize=24[out]" \
  -map "[out]" output.mp4

# Using shell variables
text="Dynamic Text"
ffmpeg -i input.mp4 \
  -filter_complex "[0:v]drawtext=text='$text':fontsize=24[out]" \
  -map "[out]" output.mp4

# Escaping special characters (colons in timestamps)
ffmpeg -i input.mp4 \
  -filter_complex "[0:v]drawtext=text='Time\: %{pts\:hms}':fontsize=24[out]" \
  -map "[out]" output.mp4

Common Composition Patterns

1. Picture-in-Picture (PiP)

# Basic PiP - small video in bottom-right corner
ffmpeg -i main.mp4 -i pip.mp4 \
  -filter_complex "\
    [1:v]scale=320:240[pip];\
    [0:v][pip]overlay=W-w-10:H-h-10" \
  -c:v libx264 -c:a copy output.mp4

# PiP with border
ffmpeg -i main.mp4 -i pip.mp4 \
  -filter_complex "\
    [1:v]scale=320:240,drawbox=x=0:y=0:w=iw:h=ih:c=white:t=3[pip];\
    [0:v][pip]overlay=W-w-10:H-h-10" \
  output.mp4

# Animated PiP (moving)
ffmpeg -i main.mp4 -i pip.mp4 \
  -filter_complex "\
    [1:v]scale=320:240[pip];\
    [0:v][pip]overlay='W-w-10-sin(t)*20':'H-h-10-cos(t)*20'" \
  output.mp4

# PiP with fade-in
ffmpeg -i main.mp4 -i pip.mp4 \
  -filter_complex "\
    [1:v]scale=320:240,fade=in:st=2:d=1[pip];\
    [0:v][pip]overlay=W-w-10:H-h-10:enable='gte(t,2)'" \
  output.mp4

2. Video Grid Layouts

Using hstack/vstack (fast, simple):

# 2x2 Grid
ffmpeg -i 1.mp4 -i 2.mp4 -i 3.mp4 -i 4.mp4 \
  -filter_complex "\
    [0:v]scale=640:360[v0];\
    [1:v]scale=640:360[v1];\
    [2:v]scale=640:360[v2];\
    [3:v]scale=640:360[v3];\
    [v0][v1]hstack=inputs=2[top];\
    [v2][v3]hstack=inputs=2[bottom];\
    [top][bottom]vstack=inputs=2[out]" \
  -map "[out]" output.mp4

# 3x2 Grid
ffmpeg -i 1.mp4 -i 2.mp4 -i 3.mp4 -i 4.mp4 -i 5.mp4 -i 6.mp4 \
  -filter_complex "\
    [0:v]scale=426:240[v0];\
    [1:v]scale=426:240[v1];\
    [2:v]scale=426:240[v2];\
    [3:v]scale=426:240[v3];\
    [4:v]scale=426:240[v4];\
    [5:v]scale=426:240[v5];\
    [v0][v1][v2]hstack=inputs=3[top];\
    [v3][v4][v5]hstack=inputs=3[bottom];\
    [top][bottom]vstack=inputs=2[out]" \
  -map "[out]" output.mp4

Using xstack (more flexible positioning):

# 2x2 Grid with xstack
ffmpeg -i 1.mp4 -i 2.mp4 -i 3.mp4 -i 4.mp4 \
  -filter_complex "\
    [0:v]scale=640:360[v0];\
    [1:v]scale=640:360[v1];\
    [2:v]scale=640:360[v2];\
    [3:v]scale=640:360[v3];\
    [v0][v1][v2][v3]xstack=inputs=4:layout=0_0|640_0|0_360|640_360[out]" \
  -map "[out]" output.mp4

# L-shaped layout
ffmpeg -i main.mp4 -i side1.mp4 -i side2.mp4 \
  -filter_complex "\
    [0:v]scale=960:720[main];\
    [1:v]scale=320:360[s1];\
    [2:v]scale=320:360[s2];\
    [main][s1][s2]xstack=inputs=3:layout=0_0|960_0|960_360[out]" \
  -map "[out]" output.mp4

3. Video Transitions (xfade)

# Simple fade transition
ffmpeg -i first.mp4 -i second.mp4 \
  -filter_complex "\
    [0:v][1:v]xfade=transition=fade:duration=1:offset=4[v];\
    [0:a][1:a]acrossfade=d=1[a]" \
  -map "[v]" -map "[a]" output.mp4

# Dissolve transition
ffmpeg -i first.mp4 -i second.mp4 \
  -filter_complex "\
    [0:v][1:v]xfade=transition=dissolve:duration=2:offset=3[v]" \
  -map "[v]" output.mp4

# Wipe transitions
ffmpeg -i first.mp4 -i second.mp4 \
  -filter_complex "[0:v][1:v]xfade=transition=wipeleft:duration=1:offset=4[v]" \
  -map "[v]" output.mp4

# Multiple transitions (3+ clips)
ffmpeg -i 1.mp4 -i 2.mp4 -i 3.mp4 \
  -filter_complex "\
    [0:v]settb=AVTB,fps=30[v0];\
    [1:v]settb=AVTB,fps=30[v1];\
    [2:v]settb=AVTB,fps=30[v2];\
    [v0][v1]xfade=transition=fade:duration=1:offset=4[xf1];\
    [xf1][v2]xfade=transition=dissolve:duration=1:offset=8[out]" \
  -map "[out]" output.mp4

Available xfade transitions:

  • fade, fadeblack, fadewhite
  • wipeleft, wiperight, wipeup, wipedown
  • slideleft, slideright, slideup, slidedown
  • circlecrop, rectcrop, distance
  • radial, smoothleft, smoothright
  • dissolve, pixelize, diagtl, diagtr, diagbl, diagbr
  • hlslice, hrslice, vuslice, vdslice
  • hblur, fadegrays, squeezev, squeezeh

4. Audio Mixing

# Mix two audio tracks
ffmpeg -i video.mp4 -i music.mp3 \
  -filter_complex "\
    [0:a][1:a]amix=inputs=2:duration=first:dropout_transition=2[aout]" \
  -map 0:v -map "[aout]" output.mp4

# Mix with volume control
ffmpeg -i vocals.mp4 -i music.mp3 \
  -filter_complex "\
    [0:a]volume=1.0[v0];\
    [1:a]volume=0.3[v1];\
    [v0][v1]amix=inputs=2:duration=first[aout]" \
  -map 0:v -map "[aout]" output.mp4

# Audio with delay (ducking)
ffmpeg -i main.mp4 -i effect.mp3 \
  -filter_complex "\
    [1:a]adelay=2000|2000[delayed];\
    [0:a][delayed]amix=inputs=2:duration=first[aout]" \
  -map 0:v -map "[aout]" output.mp4

# Merge channels (stereo from two mono)
ffmpeg -i left.wav -i right.wav \
  -filter_complex "[0:a][1:a]amerge=inputs=2[aout]" \
  -map "[aout]" stereo.wav

# Audio crossfade between tracks
ffmpeg -i track1.mp3 -i track2.mp3 \
  -filter_complex "[0:a][1:a]acrossfade=d=3:c1=tri:c2=tri[out]" \
  -map "[out]" mixed.mp3

5. Text and Watermark Overlays

# Static text overlay
ffmpeg -i input.mp4 \
  -filter_complex "\
    [0:v]drawtext=text='Watermark':\
    fontsize=48:fontcolor=white@0.8:\
    x=10:y=H-th-10[out]" \
  -map "[out]" output.mp4

# Fade-in text
ffmpeg -i input.mp4 \
  -filter_complex "\
    [0:v]drawtext=text='Hello':\
    fontsize=64:fontcolor=white:\
    x=(w-text_w)/2:y=(h-text_h)/2:\
    alpha='if(lt(t,1),t,1)'[out]" \
  -map "[out]" output.mp4

# Scrolling credits
ffmpeg -i input.mp4 \
  -filter_complex "\
    [0:v]drawtext=textfile=credits.txt:\
    fontsize=32:fontcolor=white:\
    x=(w-text_w)/2:y=h-t*50[out]" \
  -map "[out]" output.mp4

# Timed text (appear/disappear)
ffmpeg -i input.mp4 \
  -filter_complex "\
    [0:v]drawtext=text='Show at 2s':\
    fontsize=48:fontcolor=yellow:\
    x=100:y=100:\
    enable='between(t,2,5)'[out]" \
  -map "[out]" output.mp4

# Logo/image watermark
ffmpeg -i video.mp4 -i logo.png \
  -filter_complex "\
    [1:v]scale=150:-1[logo];\
    [0:v][logo]overlay=W-w-20:20[out]" \
  -map "[out]" -map 0:a output.mp4

6. Stream Splitting and Multiple Outputs

# Split for multiple resolutions
ffmpeg -i input.mp4 \
  -filter_complex "\
    [0:v]split=3[v1][v2][v3];\
    [v1]scale=1920:1080[hd];\
    [v2]scale=1280:720[sd];\
    [v3]scale=640:360[mobile]" \
  -map "[hd]" hd.mp4 \
  -map "[sd]" sd.mp4 \
  -map "[mobile]" mobile.mp4

# Split video and audio separately
ffmpeg -i input.mp4 \
  -filter_complex "\
    [0:v]split=2[v1][v2];\
    [0:a]asplit=2[a1][a2];\
    [v1]scale=1280:720[vout1];\
    [v2]scale=640:360[vout2]" \
  -map "[vout1]" -map "[a1]" output1.mp4 \
  -map "[vout2]" -map "[a2]" output2.mp4

7. Video Concatenation with Filters

# Concatenate with format normalization
ffmpeg -i 1.mp4 -i 2.mp4 -i 3.mp4 \
  -filter_complex "\
    [0:v]scale=1920:1080,fps=30,setpts=PTS-STARTPTS[v0];\
    [1:v]scale=1920:1080,fps=30,setpts=PTS-STARTPTS[v1];\
    [2:v]scale=1920:1080,fps=30,setpts=PTS-STARTPTS[v2];\
    [0:a]aformat=sample_rates=48000:channel_layouts=stereo[a0];\
    [1:a]aformat=sample_rates=48000:channel_layouts=stereo[a1];\
    [2:a]aformat=sample_rates=48000:channel_layouts=stereo[a2];\
    [v0][a0][v1][a1][v2][a2]concat=n=3:v=1:a=1[outv][outa]" \
  -map "[outv]" -map "[outa]" output.mp4

GPU-Accelerated Filtergraphs

Full CUDA Pipeline

# GPU decode -> GPU filter -> GPU encode
ffmpeg -hwaccel cuda -hwaccel_output_format cuda -i main.mp4 \
  -hwaccel cuda -hwaccel_output_format cuda -i overlay.mp4 \
  -filter_complex "\
    [0:v]scale_cuda=1920:1080[main];\
    [1:v]scale_cuda=320:180[pip];\
    [main][pip]overlay_cuda=W-w-10:H-h-10[out]" \
  -map "[out]" -map 0:a \
  -c:v h264_nvenc -preset p4 output.mp4

Hybrid GPU + CPU Pipeline

When you need CPU-only filters (drawtext, subtitles), use hwdownload/hwupload:

# GPU scale -> CPU text -> GPU encode
ffmpeg -hwaccel cuda -hwaccel_output_format cuda -i input.mp4 \
  -filter_complex "\
    [0:v]scale_cuda=1920:1080[scaled];\
    [scaled]hwdownload,format=nv12[cpu];\
    [cpu]drawtext=text='Watermark':fontsize=48:x=10:y=10[text];\
    [text]hwupload_cuda[out]" \
  -map "[out]" \
  -c:v h264_nvenc output.mp4

ABR Ladder with GPU

# Generate multiple resolutions on GPU
ffmpeg -y -vsync 0 \
  -hwaccel cuda \
  -hwaccel_output_format cuda \
  -i input.mp4 \
  -filter_complex "[0:v]split=3[v1][v2][v3];\
    [v1]scale_cuda=1920:1080[hd];\
    [v2]scale_cuda=1280:720[sd];\
    [v3]scale_cuda=640:360[mobile]" \
  -map "[hd]" -c:v h264_nvenc -b:v 5M output_1080p.mp4 \
  -map "[sd]" -c:v h264_nvenc -b:v 2M output_720p.mp4 \
  -map "[mobile]" -c:v h264_nvenc -b:v 500k output_360p.mp4

Advanced Patterns

Multi-Layer Composition

# Video with lower third, logo, and timecode
ffmpeg -i main.mp4 -i logo.png -i lower_third.png \
  -filter_complex "\
    [1:v]scale=150:-1[logo];\
    [2:v]scale=400:-1[third];\
    [0:v][logo]overlay=W-w-20:20[step1];\
    [step1][third]overlay=50:H-h-80:enable='between(t,5,55)'[step2];\
    [step2]drawtext=text='%{pts\\:hms}':\
      fontsize=32:fontcolor=white:\
      x=W-tw-20:y=H-th-20[out]" \
  -map "[out]" -map 0:a output.mp4

Audio Visualization Overlay

# Waveform overlay on video
ffmpeg -i video.mp4 -i audio.mp3 \
  -filter_complex "\
    [1:a]showwaves=s=1920x200:mode=cline:colors=white@0.8[wave];\
    [0:v][wave]overlay=0:H-h-50[out]" \
  -map "[out]" -map 1:a output.mp4

# Spectrum analyzer
ffmpeg -i video.mp4 \
  -filter_complex "\
    [0:a]showspectrum=s=1920x200:legend=0:color=rainbow[spec];\
    [0:v][spec]overlay=0:H-h[out]" \
  -map "[out]" -map 0:a output.mp4

Time-Based Effects

# Different effects at different times
ffmpeg -i input.mp4 \
  -filter_complex "\
    [0:v]split=3[v1][v2][v3];\
    [v1]trim=0:5,setpts=PTS-STARTPTS[part1];\
    [v2]trim=5:10,setpts=PTS-STARTPTS,eq=brightness=0.2:saturation=2.0[part2];\
    [v3]trim=10,setpts=PTS-STARTPTS[part3];\
    [part1][part2][part3]concat=n=3:v=1:a=0[out]" \
  -map "[out]" -map 0:a output.mp4

Debugging Filtergraphs

Verbose Logging

# Enable debug logging
ffmpeg -loglevel debug -i input.mp4 -filter_complex "..." output.mp4

# Show filter graph info
ffmpeg -filter_complex_script script.txt -lavfi "..." 2>&1 | grep -i filter

Validate Filtergraph

# Test filtergraph without encoding (null output)
ffmpeg -i input.mp4 -filter_complex "..." -f null -

# Check specific filter options
ffmpeg -h filter=overlay
ffmpeg -h filter=xfade
ffmpeg -h filter=amix

Common Errors

ErrorCauseSolution
"Input pad not connected"Missing input labelAdd [0:v] or correct label
"Output pad not connected"Unused filter outputAdd -map or connect to next filter
"Stream specifier not found"Invalid stream referenceCheck input has that stream type
"Filter not found"Missing filter in FFmpeg buildCheck ffmpeg -filters
"Discarding frame"Timestamp discontinuityAdd setpts=PTS-STARTPTS

Performance Tips

  1. Order matters - Put expensive filters later in the chain
  2. Use GPU filters when available (scale_cuda, overlay_cuda)
  3. Avoid unnecessary format conversions - Keep same pixel format
  4. Split before filters if creating multiple outputs
  5. Use -threads 0 to auto-detect optimal thread count

Best Practices

  1. Use meaningful labels - [scaled] not [v1] for clarity
  2. Test on short clips - Use -t 5 to test first 5 seconds
  3. Check all streams - Verify audio mapping with -map
  4. Normalize inputs - Match fps, resolution before concat/transitions
  5. Quote the filtergraph - Use double quotes around entire -filter_complex
  6. Handle audio separately - Video and audio often need different processing

This guide covers filter_complex patterns for 2025. For hardware acceleration details, see ffmpeg-hardware-acceleration. For basic filter syntax, see ffmpeg-fundamentals-2025.

Discovery
Tags

No tags published for this skill.

Version
Latest version metadata

Version

v2026.09.24

Published

Sep 24, 2026

Category

Uncategorized

License

MIT

Source path

plugins/ffmpeg-core/skills/ffmpeg-filter-complex-patterns

Default branch

main

Latest commit

5a1b112

Tree SHA

376c8e0