FFmpeg Interactive Commands via Local Socket

This article explains how to dynamically control FFmpeg filters during runtime using interactive commands sent through a local Unix socket. You will learn how to configure FFmpeg with the ZeroMQ (zmq) filter, set up a local IPC socket, and send real-time commands to modify video and audio filter parameters on the fly without restarting your processing pipeline.


Prerequisites

To send interactive commands to FFmpeg via a local socket, your FFmpeg build must be compiled with ZeroMQ support. You can verify this by running the following command in your terminal:

ffmpeg -filters | grep zmq

If you see zmq (video) and azmq (audio) in the output, your installation is ready.


Step 1: Start FFmpeg with the ZMQ Filter

The zmq filter acts as a local socket server inside FFmpeg. It listens for incoming commands and dispatches them to target filters in your filtergraph.

To bind FFmpeg to a local Unix domain socket (IPC), use the following syntax:

ffmpeg -i input.mp4 -vf "zmq=bind_address='ipc:///tmp/ffmpeg.sock',drawtext=fontfile=Arial.ttf:text='Initial Text':x=10:y=10" output.mp4

In this command: * zmq=bind_address='ipc:///tmp/ffmpeg.sock' creates a local socket file at /tmp/ffmpeg.sock. * drawtext is the target filter we want to control interactively. By default, FFmpeg assigns it the identifier Parsed_drawtext_1.


Step 2: Write a Client to Send Interactive Commands

Because the zmq filter utilizes ZeroMQ’s REP (Reply) socket pattern, you cannot use standard utility tools like netcat (nc) to write raw text directly to the socket. Instead, you must use a ZeroMQ-compatible client.

Below is a simple Python script using the pyzmq library to send interactive commands to the FFmpeg local socket.

Install the Dependency

pip install pyzmq

The Python Command Sender Script (send_command.py)

import zmq
import sys

# Define the local socket address
socket_address = "ipc:///tmp/ffmpeg.sock"

# Initialize ZeroMQ context and REQ (Request) socket
context = zmq.Context()
socket = context.socket(zmq.REQ)
socket.connect(socket_address)

# Command format: [Target Filter] [Command] [Arguments]
# Example: Parsed_drawtext_1 reinit text='Dynamic Text Update'
command = "Parsed_drawtext_1 reinit text='Dynamic Text Update'"

print(f"Sending command: {command}")
socket.send_string(command)

# Wait for FFmpeg's response
reply = socket.recv_string()
print(f"FFmpeg Reply: {reply}")

Run this script while FFmpeg is running, and the text overlay on your output video will instantly change to “Dynamic Text Update”.


Step 3: Using the sendcmd Filter via Socket

If you prefer to use the sendcmd (or asendcmd) filter to queue up multiple timed commands interactively, you can target the sendcmd filter directly through the ZMQ socket.

Run FFmpeg with sendcmd and zmq:

ffmpeg -i input.mp4 -vf "zmq=bind_address='ipc:///tmp/ffmpeg.sock',sendcmd=f=NULL,drawtext=text='Static'" output.mp4

Send Commands to sendcmd:

The sendcmd filter accepts a reinit command followed by a timeline-based command string. You can send this block over the ZMQ socket using your Python script:

command = "Parsed_sendcmd_0 reinit 2.0 drawtext reinit text='Updated after 2 seconds'"

When FFmpeg receives this command via the local socket, it passes the instruction to sendcmd, which schedules the text change to execute exactly at the 2.0-second mark of the video playback timeline.