我正在尝试向实时视频源添加标线,并且需要标线能够根据某些外部数据移动。
我可以用 ffmpeg 在视频上画一个框:
ffmpeg -i input.mpg -vf drawbox=x=100:y=100:w=20:h=20:c=red output.mpg
(请注意,目前我只是使用视频文件进行测试,因为这样可以使其中的某些部分变得更简单。)
但是,命令启动后,似乎没有办法从外部调整x
和值。如果有办法轻松地从 stdin 或 读取它们,那就太理想了,但我找不到这样做的方法。y
/dev/shm/reticle-pos.txt
我尝试过的另一种选择是使用 imagemagick 在外部绘制标线,然后使用 ffmpeg 将其覆盖:
while true; do
for x in {100..500..1}; do
convert -size 1080x720 xc:none -fill none -stroke red -strokewidth 2 \
-draw "ellipse $x,100 10,10 0,360" -scale 1080x720 /dev/shm/newreticle.png
cp /dev/shm/newreticle.png /dev/shm/reticle.png
sleep 0.001
done
done &
ffmpeg -i input.mpg -i /dev/shm/reticle.png -filter_complex overlay output.mpg
然而,这不起作用,因为 ffmpeg 似乎只读取图像文件一次,而不是每一帧都读取。
我怎样才能在视频上方绘制标线,以便控制标线的位置?
答案1
使用循环选项:
ffmpeg -i input.mpg -loop 1 -f image2 -i /dev/shm/reticle.png -filter_complex overlay output.mpg
- ffmpeg 使用 image2 解复用器的循环选项在每一帧上读取 reticle.png。
- 通过首先将新的标线写入临时文件然后重命名为 rectile.png 来原子地更新 rectile.png。
- 详细信息:https://ffmpeg.org/ffmpeg-formats.html#image2-1
答案2
我想出了一个办法。这可能不是最好的办法,但它确实有效:
reticle(){
convert -size 1080x720 xc:none \
-fill none -stroke red -strokewidth 2 -draw "ellipse $1,$2 10,10 0,360" \
-size 1080x720 -depth 8 rgba:-
}
export -f reticle
parallel -k reticle {} 100 ::: {100..500} \
| ffmpeg \
-i input.mpg \
-f rawvideo -pixel_format bgr32 -video_size 1080x720 -framerate 30 -i pipe:0 \
-filter_complex overlay \
-y -c libx264 output.mpg
这是通过让 imagemagick 输出原始像素数据 ( -size 1080x720 -depth 8 rgba:-
) 来实现的。每帧的像素数据与其余数据连接在一起形成单个原始视频流。然后 ffmpeg 能够读取该原始视频流 ( -f rawvideo -pixel_format bgr32 -video_size 1080x720 -framerate 30 -i pipe:0
) 并将其叠加到主视频上。