如何使用 ffmpeg 在实时视频上绘制标线?

如何使用 ffmpeg 在实时视频上绘制标线?

我正在尝试向实时视频源添加标线,并且需要标线能够根据某些外部数据移动。

我可以用 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) 并将其叠加到主视频上。

相关内容