如何使用 ffmpeg 在即時視訊上繪製十字線?

如何使用 ffmpeg 在即時視訊上繪製十字線?

我正在嘗試為即時視訊來源添加十字線,並且需要十字線能夠根據一些外部資料移動。

我可以用 ffmpeg 在影片上畫一個框:

ffmpeg -i input.mpg -vf drawbox=x=100:y=100:w=20:h=20:c=red output.mpg

(請注意,目前我只是使用視訊檔案進行測試,因為這使得它的某些部分變得更簡單。)

但是,一旦命令啟動,似乎沒有辦法在外部調整x和值。y如果有一種方法可以輕鬆地從 stdin 或 讀取它們,那麼這將是理想的/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 demuxer 的循環選項在每一幀上讀取 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) 並將其覆蓋到主視訊上。

相關內容