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.mp43.0and6.0: The timestamps (in seconds) when the text changes.drawtext reinit text=...: Targets thedrawtextfilter and re-initializes it with the new text. Note that spaces in the new text must be escaped or replaced with underscores unless wrapped in proper nested quotes.
Using a Command File
For complex schedules, it is cleaner to define the events in a separate text file.
- Create a file named
commands.txtwith 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';
- Run FFmpeg, pointing the
sendcmdfilter 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.mp4Method
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@livetext: Assigns the identifierlivetextto thedrawtextfilter.zmq=bind_address=tcp\\://127.0.0.1\\:5555: Binds a ZMQ TCP socket to port 5555.
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:5555Using 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}")