Monitor FFmpeg Progress Programmatically
Monitoring long-running FFmpeg tasks is crucial for providing
real-time feedback in applications. This article explains how to use the
FFmpeg -progress option to output real-time status data to
a file, pipe, or network socket, and how to programmatically parse this
data to calculate the exact percentage of completion.
The -progress Option Syntax
The -progress option tells FFmpeg to write
program-readable progress information to a specified URL or stream. The
basic syntax is:
ffmpeg -i input.mp4 -progress [target] output.mp4The [target] can be: * pipe:1 or
pipe:2 to output to standard output (stdout) or standard
error (stderr). * A local file path (e.g., progress.txt). *
A network socket (e.g., tcp://127.0.0.1:5555).
Understanding the Progress Output Format
When FFmpeg runs, it repeatedly writes block of key-value pairs
separated by newlines. Each block ends with a progress key.
A typical block of output looks like this:
frame=124
fps=30.20
stream_0_0_q=28.0
bitrate=1204.5kbits/s
total_size=1024300
out_time_us=5160000
out_time_ms=5160000
out_time=00:00:05.160000
dup_frames=0
drop_frames=0
speed=1.2x
progress=continue
The most important keys for calculating overall progress are: *
out_time_us: The current timestamp of the
processed video in microseconds. *
progress: Indicates whether the process is
ongoing (continue) or finished (end).
Calculating Percentage Programmatically
To calculate the percentage of completion, you must first obtain the
total duration of the input file (usually in seconds or microseconds)
using a tool like ffprobe.
The formula to calculate the progress percentage is:
\[\text{Progress \%} = \left( \frac{\text{out\_time\_us}}{\text{Total Duration in Microseconds}} \right) \times 100\]
Python Implementation Example
Here is a practical Python script that runs an FFmpeg command,
captures the progress output from a pipe, parses the
out_time_us value, and prints the percentage in real
time.
import subprocess
import re
# 1. Define input parameters (manually set or retrieved via ffprobe)
input_duration_seconds = 120.0 # 2 minutes
total_duration_us = int(input_duration_seconds * 1000000)
# 2. Build the FFmpeg command
# We use pipe:1 to output progress to stdout and -nostats to disable default stderr stats
cmd = [
'ffmpeg', '-y',
'-i', 'input.mp4',
'-progress', 'pipe:1',
'-nostats',
'output.mkv'
]
# 3. Start the subprocess
process = subprocess.Popen(
cmd,
stdout=subprocess.PIPE,
stderr=subprocess.DEVNULL, # Suppress standard FFmpeg logs
text=True
)
# 4. Read the stdout stream line by line
try:
for line in process.stdout:
line = line.strip()
if "out_time_us=" in line:
try:
# Extract the microsecond value
out_time_us = int(line.split('=')[1])
# Calculate and display the percentage
percentage = (out_time_us / total_duration_us) * 100
percentage = min(max(percentage, 0.0), 100.0) # Clamp between 0 and 100
print(f"Progress: {percentage:.2f}%")
except ValueError:
pass
if line == "progress=end":
print("Processing complete!")
finally:
process.stdout.close()
process.wait()Best Practices
- Handle Zero Values: During the first few frames of
encoding,
out_time_uscan be negative or zero. Ensure your parser handles these cases without crashing. - Use Microseconds (
out_time_us): Avoid parsing the formattedout_timestring (HH:MM:SS) because parsing integers is computationally cheaper and less prone to formatting errors. - Non-blocking Reads: If integrating this into a GUI or web application, read the stream asynchronously or in a separate thread/worker to prevent blocking the main application interface.