Parse FFmpeg Progress Output via Socket or File
Monitoring the progress of an FFmpeg command is essential for
providing real-time feedback in applications. This article explains how
to direct FFmpeg’s progress metrics to a local file or socket using the
-progress flag, details the structure of the generated
key-value pair output, and demonstrates how to parse this data
efficiently in your code.
Directing FFmpeg Progress Output
FFmpeg provides a built-in -progress option that directs
real-time status information to a specified destination. You can write
this data to a local file or stream it over a network protocol like TCP
or UDP.
To write progress to a local file:
ffmpeg -i input.mp4 -progress progress.txt output.mp4To stream progress to a local TCP socket:
ffmpeg -i input.mp4 -progress tcp://127.0.0.1:5555 output.mp4Using a socket is generally preferred for live applications, as it avoids continuous disk I/O and allows your application to read the stream in real-time.
Understanding the Progress Log Format
FFmpeg outputs progress information as newline-separated
key=value pairs. A single update block consists of several
lines of metrics and always ends with the progress key.
An example of a single progress block looks like this:
frame=143
fps=29.97
stream_0_0_q=28.0
bitrate= 1054.3kbits/s
total_size=1048576
out_time_us=4766667
out_time_ms=4766667
out_time=00:00:04.766667
dup_frames=0
drop_frames=0
speed=1.02x
progress=continue
Key Metrics to Parse:
frame: The total number of frames processed so far.fps: The current processing speed in frames per second.out_time_us: The current playback position of the output file in microseconds. Divide this by1000000to get seconds.speed: The encoding speed relative to realtime (e.g.,2.0xmeans encoding is happening at twice the speed of playback).progress: Indicates the status of the process. This will becontinueduring encoding andendwhen the process completes.
How to Parse the Output
To parse this data, your application needs to read the incoming
stream line-by-line, split each line by the = character,
and store the keys and values. When the parser encounters
progress=continue or progress=end, it
signifies that a complete frame update block has been received and can
be processed.
Here is a practical Python example demonstrating how to start a local TCP server, receive progress from FFmpeg, and parse the data:
import socket
def start_progress_server(host='127.0.0.1', port=5555):
# Create and bind the TCP socket
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind((host, port))
server_socket.listen(1)
print(f"Listening for FFmpeg progress on {host}:{port}...")
conn, addr = server_socket.accept()
print(f"Connected by {addr}")
buffer = ""
current_metrics = {}
try:
while True:
data = conn.recv(1024)
if not data:
break
# Append received bytes decoded to string to the buffer
buffer += data.decode('utf-8')
# Process complete lines
while "\n" in buffer:
line, buffer = buffer.split("\n", 1)
line = line.strip()
if not line:
continue
# Split key and value
if "=" in line:
key, value = line.split("=", 1)
current_metrics[key.strip()] = value.strip()
# When 'progress' is received, the current block is complete
if key.strip() == "progress":
handle_progress_update(current_metrics)
if value.strip() == "end":
return
finally:
conn.close()
server_socket.close()
def handle_progress_update(metrics):
# Extract specific values for display or calculation
fps = metrics.get('fps', 'N/A')
speed = metrics.get('speed', 'N/A')
# out_time_us can be used to calculate percentage if total duration is known
out_time_raw = metrics.get('out_time_us', '0')
seconds = int(out_time_raw) / 1000000 if out_time_raw.isdigit() else 0
print(f"Progress: Time: {seconds:.2f}s | FPS: {fps} | Speed: {speed}")
if __name__ == "__main__":
start_progress_server()Calculating Completion Percentage
The FFmpeg progress stream does not inherently know the total length of the input file, so it cannot output a completion percentage directly. To calculate percentage progress:
Get the total duration of the input file beforehand using
ffprobe:ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 input.mp4Compute the percentage in your parser by comparing the parsed
out_time_us(converted to seconds) against the total duration: \[\text{Percentage} = \left( \frac{\text{Current Seconds}}{\text{Total Duration}} \right) \times 100\]