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.mp4

To stream progress to a local TCP socket:

ffmpeg -i input.mp4 -progress tcp://127.0.0.1:5555 output.mp4

Using 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:

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:

  1. 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.mp4
  2. Compute 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\]