FFmpeg中sendcmd适配drawtext,为何无法兼容scale、rotate等滤镜?
Great question! Let’s break this down clearly, like we’re troubleshooting together:
1. How sendcmd actually works
The sendcmd filter’s whole job is to send control commands to filters that come after it at specific timestamps. But here’s the critical catch: the target filter has to explicitly support the command you’re sending. It can’t magically modify any filter’s parameters out of the box.
2. Why drawtext plays nice with sendcmd
The drawtext filter was built to handle runtime parameter changes—it implements a reinit command that lets you reinitialize its settings (like text content, font size, or position) while the video is processing.
Your working example uses exactly this functionality:
ffmpeg -i testIN.mp4 -filter_complex "[0:v]sendcmd=f=testTXT.cmd,drawtext=fontfile=PF.ttf:text='': fontcolor=white:fontsize=150" testOUT.mp4
And your testTXT.cmd sends valid reinit commands that drawtext understands perfectly:
0 drawtext reinit 'text=111'; 1 drawtext reinit 'text=222'; 2 drawtext reinit 'text=333';
When sendcmd fires these commands, drawtext knows exactly how to respond by updating its text parameter on the fly.
3. Why scale/rotate don’t work by default
Filters like scale and rotate don’t have the same built-in command interface as drawtext. Their core parameters (like w/h for scale, angle for rotate) are usually locked in when the filter initializes, and there’s no native reinit or similar command to modify them mid-processing.
If you tried sending a command like scale reinit 'w=640:h=360', the scale filter would have no idea what to do with that input—it would just ignore it entirely.
4. Workaround: Use variables with expression-supporting filters
Luckily, many FFmpeg filters (including scale and rotate) support expression-based parameters. You can combine this with sendcmd’s setvar command to dynamically update parameters at runtime.
Example: Dynamic scaling
First, create a scale.cmd file:
0 setvar target_w 640; setvar target_h 360; 2 setvar target_w 1280; setvar target_h 720; 4 setvar target_w 320; setvar target_h 180;
Then run FFmpeg with this filter chain:
ffmpeg -i testIN.mp4 -filter_complex "[0:v]sendcmd=f=scale.cmd,scale=w='${target_w}':h='${target_h}'" testOUT.mp4
Here, scale uses the ${target_w} and ${target_h} variables, and sendcmd updates those variables at the specified timestamps to resize the video dynamically.
Example: Dynamic rotation
Create a rotate.cmd file:
0 setvar rot_angle 0; 1 setvar rot_angle PI/4; # 45 degrees 2 setvar rot_angle PI/2; # 90 degrees
Then run:
ffmpeg -i testIN.mp4 -filter_complex "[0:v]sendcmd=f=rotate.cmd,rotate=angle='${rot_angle}':ow='hypot(iw,ih)':oh='ow'" testOUT.mp4
The rotate filter uses the ${rot_angle} variable, and sendcmd adjusts it over time. The ow/oh parameters ensure the output frame size accommodates the rotated video without cropping.
5. What if the filter doesn’t support expressions?
For filters that don’t accept expression parameters, you’ll need a more complex filtergraph:
- Split the video stream into multiple branches, each with a different filter configuration
- Use the
selectfilter to switch between branches at specific timestamps - Merge the branches back together
This is less clean than the variable approach, but it works for cases where expressions aren’t supported.
内容的提问来源于stack exchange,提问作者Makes

