
The Stack of the Week
Welcome to the second edition of VFX Stack! In this newsletter, we'll dive into essential tools and workflows that power modern VFX production pipelines using FFMPEG in their core.
Stack[0]: FFMPEG
FFMPEG is the Swiss Army knife of video processing. A powerful, open-source command-line tool that has become the backbone of countless VFX applications. Whether you realize it or not, FFMPEG is working behind the scenes in many of your favorite DCCs, from Nuke and DaVinci Resolve to custom pipeline tools.
What makes FFMPEG invaluable in VFX pipelines is its versatility: it handles format conversions, colorspace transformations, frame sequence operations, and quality, preserving encoding, all with a single, scriptable command. For pipeline TDs and artists alike, understanding FFMPEG fundamentals means gaining precise control over your media workflows.
Today, we'll explore three essential FFMPEG use cases that every VFX professional should have in their toolkit, along with practical production workflows you can implement in your studio.
Stack[1]: Creating Dailies with Text Overlays
The Problem: You need to generate review-ready dailies from an EXR sequence with shot information burned into the frame (shot name and frame numbers).
ffmpeg -y -i "input_sequence.%04d.exr" \
-vf "[in]drawtext=fontfile=C\:/Windows/fonts/Arial.ttf: \
text='%{frame_num}': start_number=1: x=w-tw-20:y=30: \
fontcolor=black: fontsize=40: box=1: boxcolor=white, \
drawtext=fontfile=C\:/Windows/fonts/Arial.ttf: \
text='SH0020_v001': start_number=1: x=(w-tw)/2:y=h-th-30: \
fontcolor=white: fontsize=40[out]" \
-colorspace bt709 -color_trc srgb \
-vcodec libx264 output_daily.movParameter Breakdown:
-y: Automatically overwrite output files without prompting for confirmation-i "input_sequence.%04d.exr": Input pattern for image sequences (e.g., frame.0001.exr, frame.0002.exr)-vf: Video filter chain—applies multiple filters sequentiallydrawtext: Adds text overlays to video framesfontfile: Path to the font file to usetext='%{frame_num}': Dynamic text showing current frame numberstart_number=1: First frame number to displayx=w-tw-20:y=30: Position (width minus text width minus 20px, y position 30px from top)fontcolor,fontsize: Visual styling for the textbox=1: boxcolor=white: Adds a white background box behind the text for readability
-colorspace bt709: Sets output colorspace to Rec.709 (standard for HD movie video files). Take in consideration that this is not the actual color space from the video, but from the format/container.-color_trc srgb: Sets transfer characteristic to sRGB gamma curve-vcodec libx264: Uses H.264 codec for compression (widely compatible for review)
Production Workflow Integration
In a production environment, dailies creation should be automated and standardized. Here's how you can build a robust dailies system:
Automated Dailies Pipeline:
Template System: Create JSON templates defining overlay positions, fonts, and department-specific information (comp, lighting, FX)
Batch Processing: Build a Python wrapper that reads shot metadata from your production database (Shotgun/ShotGrid, ftrack) and generates FFMPEG commands dynamically
Multi-Department Output: Generate different versions simultaneously—full-res for supervisors, proxy for clients, and watermarked versions for external reviews
Advanced Implementation Example:
# Pseudo-code for automated dailies
def generate_daily(shot_data):
overlay_template = load_template(shot_data['department'])
ffmpeg_cmd = build_command(
input_path=shot_data['render_path'],
overlays=overlay_template,
output_preset='client_review'
)
subprocess.run(ffmpeg_cmd)
upload_to_review_platform(output_path)Stack[2]: Smart Editorial Cut Ingestion
The Problem: You need to extract specific time ranges from a source MOV file to match editorial cuts without re-encoding (maintaining quality).
The Solution:
ffmpeg -ss 00:05:29.720 -to 00:05:33.080 \
-i input_source.mov \
-c copy output_trimmed.movParameter Breakdown:
-ss 00:05:29.720: Start time (seek to this position in the source)Format: HH:MM:SS.milliseconds
Positioned before
-ifor faster seeking
-to 00:05:33.080: End time (stop encoding at this position)-i input_source.mov: Input video file-c copy: Stream copy mode—copies video/audio streams without re-encodingMaintains original quality (lossless)
Extremely fast processing
Can only cut at keyframe boundaries (might not be frame-accurate)
Note: For frame-accurate cuts, omit -c copy and specify codec parameters, but this will re-encode the video.
Production Workflow: Automated Ref Edit Ingestion
The editorial cut ingestion workflow is one of the most time-consuming processes in VFX production. Every time a client delivers a new edit, someone needs to manually cut the reference material and prepare it for artists. Here's how to optimize this:
Two-Step Optimization Strategy:
Instead of converting a full-length movie to image sequences (extremely slow and storage-intensive), use this workflow:
# Step 1: Cut the MOV first (fast, no re-encoding)
ffmpeg -ss 00:05:29.720 -to 00:05:33.080 -i full_edit.mov -c copy shot_020.mov
# Step 2: Convert only the cut section to JPG sequences
ffmpeg -i shot_020.mov -vf "colormatrix=bt709:bt470bg" \
-pix_fmt yuvj422p -q:v 1 -start_number 1001 \
shot_020.%04d.jpgWhy this matters: Converting a 2-hour reference edit directly to JPG sequences might take 30+ minutes and generate hundreds of gigabytes. By cutting first, then converting, you reduce processing time by 90% and only store what you need.
Handling Data Range for Accurate Color Conversion:
When converting MOV files to image sequences, one critical aspect that often gets overlooked is the video data range. Video files can encode pixel values in two different ranges:
Full Range (0-255): Uses the complete 8-bit range. Common in computer graphics, screen recordings, and some camera formats
TV/Limited Range (16-235): Uses a reduced range with 16 as black and 235 as white. Standard for broadcast video and most professional cameras
FFMPEG attempts to auto-detect the input range, but misdetection can result in crushed blacks. If you know your source material's data range, you should specify it explicitly:
# For full range source material (0-255)
ffmpeg -i shot_020.mov -vf "scale=in_range=full,colormatrix=bt709:bt470bg" \
-pix_fmt yuvj422p -q:v 1 -start_number 1001 \
shot_020.%04d.jpg
# For TV/limited range source material (16-235)
ffmpeg -i shot_020.mov -vf "scale=in_range=tv,colormatrix=bt709:bt470bg" \
-pix_fmt yuvj422p -q:v 1 -start_number 1001 \
shot_020.%04d.jpgThis becomes especially important when working with different MOV codecs. ProRes formats typically encode in full range (0-255), while DNxHD/DNxHR can be either full or limited range depending on the export settings used in applications like DaVinci Resolve or Avid. H.264 MOVs from cameras or editorial are usually limited range (16-235), but screen captures or exports from After Effects might be full range. Specifying the correct input range ensures your compositors receive plates with accurate black levels, preventing color mismatches between reference material and final renders.
AI Agent Integration for Modern Pipelines
This is where AI agents become incredibly valuable. Imagine this workflow:
Automated Editorial Sync Agent:
Deploy a simple FastAPI or Flask server that runs locally in your studio. This server integrates with an AI agent (like Claude or a local LLM) to:
Monitor incoming editorial deliveries (watch a specific Dropbox/Google Drive folder where Production/IO/Editorial departments can drop deliveries)
Parse EDL/XML automatically using AI to extract shot information and timecodes or provided a tool/mcp that can do that.
Build the right shot name for each shot to cut. Providing to the MLL a technical requirements document you can specify the right naming and folder structure where the files have to be ingested and with the version system required. The MLL can convert the client naming, that may change constantly to your pipeline naming easily.
Cut each shot and convert it using a FFMPEG mcp/tool. Once the model have prepare the right naming for the shot, can execute a tool to convert it to the right location.
Update shot duration in DB. In the same way, with a tool for you db or production software, the mll can update the shot duration.
Send Slack notifications when ingestion is complete.
Handle edge cases like overlapping timecodes or missing metadata
MVP Implementation:
# Minimal viable product structure
@app.post("/ingest-editorial")
async def ingest_editorial(file: UploadFile):
# AI agent parses the EDL
shots_data = await ai_agent.parse_edl(file)
# Generate processing tasks
for shot in shots_data:
task = create_ingestion_task(shot)
queue.add(task)
return {"status": "processing", "shots": len(shots_data)}This approach eliminates the manual bottleneck of editorial ingestion and allows your pipeline TD to focus on more complex problems. The agent can even learn from your studio's naming conventions and automatically adapt to different client delivery formats. Plus does not require a high cost software licence, only good requirenments and tools like FFMPEG.
Stack[3]: Applying LUTs for Color Transformation
The Problem: You need to convert an ACES color space image sequence to sRGB using a cube LUT for client review.
The Solution:
ffmpeg -y \
-start_number 1001 \
-i "exr_acescc_in.%04d.exr" \
-vf "lut3d=file='acescc_to_srgb.cube'" \
-c:v libx264 \
-crf 18 \
-pix_fmt yuv420p \
output_with_lut.movParameter Breakdown:
-start_number 1001: First frame number in the input sequence (common VFX convention)-i "exr_acescc_in.%04d.exr": Input EXR sequence pattern-vf "lut3d=file='acescc_to_srgb.cube'": Applies a 3D LUT for color transformationSupports
.cubeand.3dlLUT formatsEssential for ACES to display-referred conversions
-c:v libx264: H.264 codec for output-crf 18: Constant Rate Factor quality setting (0-51 scale)Lower values = higher quality (18 is visually lossless for most content)
23 is default, 18 is recommended for high-quality masters
-pix_fmt yuv420p: Pixel format for maximum compatibilityYUV 4:2:0 chroma subsampling
Required for playback on most devices and software
Production Workflow: Color Pipeline Integration
Color management in VFX is critical, and FFMPEG's LUT application capability makes it an essential tool for maintaining color consistency across the pipeline.
It’s important to consider that previous parameters used in other examples like color matrix or color spaces, were not actual color transformations for color spaces of the video, but transformations or specifications for the color tables, matrix or similar features of the codecs, as each container may have different color configurations, but are not intended to be user for color conversions like we do with OCIO and ACES. For that we need to apply luts designed for the conversion we want to make.
Multi-Stage Color Workflow:
In production, you often need to generate multiple render versions of the same content. The most common situation is to render a raw exr and have a mov with cdls and lut applied. In some situations you could try to automatize the mov generation with FFMPEG appliying the lut through it.:
# Client-specific LUT for approval
ffmpeg -y -start_number 1001 -i "shot.%04d.exr" \
-vf "lut3d=file='client_custom_look.cube'" \
-c:v libx264 -crf 15 -pix_fmt yuv420p \
shot_client.movWhile FFMPEG doesn't have native CDL (.cdl or .ccc file) support, you can emulate CDL operations using FFMPEG's built-in color correction filters combined with LUT application.Building a LUT Management System
# Applying CDL-style corrections + LUT in a single command
ffmpeg -y -start_number 1001 -i "shot.%04d.exr" \
-vf "eq=brightness=0.02:contrast=1.15:saturation=1.05,\
curves=r='0/0.02 1/0.98':g='0/0.01 1/0.99':b='0/0 1/1',\
lut3d=file='client_look.cube'" \
-c:v libx264 -crf 15 -pix_fmt yuv420p \
shot_graded.movThis CDL approximation is useful for fast daily reviews that don't require deep color accuracy. For workflows demanding precise color reproduction, such as final client approvals, DI preparation, or color-critical VFX shots, it's better to explore alternative approaches involving OCIO tools (like ociobakelut to pre-convert CDL to cube files) or processing directly in Nuke where CDL implementation is spec-compliant.
Integration with Modern Color Pipelines
OCIO + FFMPEG Hybrid Approach:
While OCIO (OpenColorIO) is the industry standard for color management, FFMPEG's LUT application is perfect for final delivery conversions where speed matters:
Use OCIO in your DCCs for interactive color-accurate work.
Use FFMPEG for batch conversions when generating hundreds of shots for client delivery.
Pre-bake LUTs from your OCIO config using
ociobakelutcommand, then apply with FFMPEG for maximum throughput.
Stack[-1]: Community Stack - FFMPEG Tools
For this week's community stack, we've curated three open-source FFMPEG-based tools that can supercharge your VFX workflows. These projects showcase how FFMPEG's versatility can be harnessed for specific production needs.
Stack[-1][0]: StaX – Shot-Ready Asset Browsing
StaX is a Nuke-focused asset browser that understands image sequences out of the box. It ingests plates, elements, and toolsets into a hierarchical Stack → List → Element model, generates thumbnails, GIFs, and MOV previews automatically, and even exposes a lightweight WebGL viewer for GLB/GTLF assets. Because the database layer supports network file locking and custom Python hooks, you can sync StaX with your facility storage and drop curated stock, shared gizmos, or photogrammetry assets straight into the Nuke DAG via drag and drop.
Stack[-1][1]: Awesome FFmpeg – Curated Knowledge Graph
Need inspiration for your next automation script? Awesome FFmpeg is a living, crowd-sourced index of wrappers, GUI front-ends, optimization tips, command collections, and learning resources. It’s organized by workflow (encoding, streaming, hardware acceleration, and more), so you can quickly jump from a Python binding to a GPU tuning guide or a broadcast-specific streaming recipe. Keep it bookmarked for those moments when you remember the feature but not the exact flag syntax.
Stack[-1][2]: VFXDailies – Multi-Engine Submission Wrapper
VFXDailies wraps FFmpeg, Nuke, and RV into a single UI that turns EXR deliveries into reviewable QuickTimes, JPG sequences, or slateable submissions. Artists can add project metadata, choose codecs or resolution overrides, and then push the rendered output directly into Shotgun, Ftrack, or Kitsu through configurable tracking adapters. If your in-house tools team needs a head start on a dailies app (especially one that supports both video and image-sequence round-trips), this project provides production-ready scaffolding.
Stack[:]
FFMPEG's real power emerges when integrated into automated workflows. The three use cases we've explored (dailies generation, editorial ingestion, and color conversion), plus these community tools, are just the beginning. By combining FFMPEG with modern tools like AI agents and pipeline automation, you can transform hours of manual work into minutes of automated processing. Best of all, it's free, open-source, and runs everywhere. No expensive licenses required; just solid pipeline engineering.
💡 Glossary
ACES (Academy Color Encoding System): Industry-standard color management framework that ensures consistent color across different devices and software.
Codec: Software or hardware that compresses (encodes) and decompresses (decodes) digital video.
Colorspace: Mathematical model defining how colors are represented numerically (e.g., Rec.709, sRGB, ACEScg).
CRF (Constant Rate Factor): Quality-based encoding mode where you specify desired quality rather than bitrate.
DCC (Digital Content Creation): Software applications used for creating digital content (Maya, Nuke, Houdini, etc.).
DCI-P3: Digital Cinema Initiatives color space with wider gamut than Rec.709, used in digital cinema projection.
EDL (Edit Decision List): File format that describes a video editing sequence, including timecodes and transitions.
EXR (OpenEXR): High dynamic range image file format commonly used in VFX for its ability to store extensive color and brightness information.
H.264: Widely-used video compression standard (also known as AVC or MPEG-4 Part 10).
Keyframe: A fully encoded frame in compressed video; other frames reference keyframes for reconstruction.
LUT (Look-Up Table): Pre-calculated transformation that maps input colors to output colors for efficient color grading.
MVP (Minimum Viable Product): Basic version of a product with core features to validate concept before full development.
OCIO (OpenColorIO): Open-source color management system used across the VFX industry for consistent color workflows.
Pixel Format: Defines how pixel color data is stored (RGB, YUV, bit depth, chroma subsampling).
ProRes: Apple's professional video codec family, widely used for high-quality intermediate formats in post-production.
Rec.709: Color space standard for HD television (1920×1080), defining color primaries and transfer characteristics.
Transfer Characteristic (TRC): Mathematical function defining the relationship between scene light and encoded values (gamma curve).
📚 Resources
Here are some valuable resources to deepen your FFMPEG knowledge:
Official FFMPEG Documentation: https://ffmpeg.org/documentation.html
FFMPEG Wiki - H.264 Encoding Guide: https://trac.ffmpeg.org/wiki/Encode/H.264
Color Space Conversions in FFMPEG: https://trac.ffmpeg.org/wiki/colorspace
FFMPEG Filtering Guide: https://ffmpeg.org/ffmpeg-filters.html
ACES Central - LUT Resources: https://acescentral.com
EDL Parser Libraries: https://github.com/szbalint/edl_parser (Python)
