Change FFmpeg drawtext Dynamically with Commands

This article explains how to dynamically update the text displayed by FFmpeg’s drawtext filter during runtime. You will learn how to use the sendcmd filter to schedule text changes at specific timestamps, and how to use the zmq filter to inject text changes in real-time using external scripts.


Method 1: Scheduled Updates using the sendcmd Filter

The sendcmd filter reads a list of commands and sends them to other filters (like drawtext) at specified time intervals.

To change the text, you must target the drawtext filter and use the reinit command to pass a new text parameter.

Using an Inline Command

For simple, pre-planned changes, you can pass the commands directly inside your FFmpeg command line:

ffmpeg -i input.mp4 -filter_complex "sendcmd=c='3.0 drawtext reinit text=First_Change; 6.0 drawtext reinit text=Second_Change',drawtext=text='Original Text':x=50:y=50:fontcolor=white:fontsize=24" -c:a copy output.mp4

Using a Command File

For complex schedules, it is cleaner to define the events in a separate text file.

  1. Create a file named commands.txt with the following content:
2.0 drawtext reinit text='Two Seconds Passed';
5.5 drawtext reinit text='Five Point Five Seconds';
10.0 drawtext reinit text='Ten Seconds';
  1. Run FFmpeg, pointing the sendcmd filter to your file:
ffmpeg -i input.mp4 -filter_complex "sendcmd=f=commands.txt,drawtext=text='Initial Text':x=50:y=50:fontcolor=white:fontsize=24" -c:a copy output.mp4

Method 2: Real-Time Interactive Updates using the zmq Filter

If you need to change the text dynamically on the fly (for example, displaying live data during a stream), you can use the zmq (ZeroMQ) filter. This opens a network port that accepts command strings while FFmpeg is running.

1. Start FFmpeg with ZMQ and a Labeled Filter

You must label your drawtext filter (using @label_name) so the ZMQ filter knows where to route the command.

ffmpeg -i input.mp4 -filter_complex "drawtext=text='Initial Live Text':x=50:y=50:fontcolor=white:fontsize=24@livetext,zmq=bind_address=tcp\\://127.0.0.1\\:5555" -f mpegts udp://127.0.0.1:1234

2. Send Commands to the Port

You can now send commands to port 5555 from another terminal or external script. The message format must target the filter label, specify the reinit command, and provide the new text parameters.

Using the zmq-send utility (often compiled with FFmpeg):

echo "livetext reinit text='This is a live update!'" | zmq-send -b tcp://127.0.0.1:5555

Using a Python script:

import zmq

context = zmq.Context()
socket = context.socket(zmq.REQ)
socket.connect("tcp://127.0.0.1:5555")

# Send the command to the @livetext filter
socket.send_string("livetext reinit text='Updated from Python'")
response = socket.recv_string()
print(f"FFmpeg response: {response}")