使用 ffmpeg 控制网络摄像头视频捕获到文件的缓冲区大小

Controlling buffer size for webcam video capture to file using ffmpeg

在 Python 脚本中,我想捕获网络摄像头流并将其保存到本地硬盘上的视频文件中,但我想编写脚本来确定视频的生命周期。为此,我使用 python-ffmpeg 库,它本质上是一个简单的 Python SDK,围绕子进程中的 ffmpeg。

这是我目前的截图:

from time import sleep
import ffmpeg


APPLICATION = "ffmpeg.exe"
CAMERA_NAME = "Sandberg USB Webcam Pro"

stream = ffmpeg.input(f"video={CAMERA_NAME}", format="dshow")
stream = ffmpeg.output(stream, "output.mkv", preset="medium", c="copy")

if __name__ == "__main__":
    process = ffmpeg.run_async(stream, cmd=APPLICATION, overwrite_output=True, quiet=True)
    _ = input("Press enter when finished.")
    print("Shutting down in 3 seconds..")
    sleep(3)
    process.terminate()

这很好用。然而, process.terminate() 非常突然,因为它基本上只是立即杀死子进程。我已经看到这往往会切断视频流的几秒钟。我假设它是连续写入的,当被杀死时,已经写入的内容仍然存在。

现在我无法控制(..缓冲区的)持续时间。我只是猜测它大约 3 秒,因此我的睡眠呼叫。有没有办法将其配置为 ffmpeg?

与其尝试控制缓冲区大小,不如优雅地关闭 FFmpeg。

为了正常关闭 FFmpeg,我们可以将 'q' 写入 stdin 管道,如 .

中所述

当我们开始录制时,会出现以下消息:Press [q] to stop, [?] for help
'q' 写入 stdin 模拟按下 q 键。


  • pipe_stdin=True:

    打开 FFmpeg sub-process
     process = ffmpeg.run_async(stream, cmd=APPLICATION, pipe_stdin=True, overwrite_output=True, quiet=True)
    
  • 'q' 字母(带 encode("GBK"))写入 stdin 管道,然后 "communicate()":

     process.stdin.write('q'.encode("GBK"))
     process.communicate()
    
  • 等待FFmpeg sub-process结束:

     process.wait()
    

代码示例:

from time import sleep
import ffmpeg
import signal

APPLICATION = "ffmpeg.exe"
CAMERA_NAME = "Sandberg USB Webcam Pro"

stream = ffmpeg.input(f"video={CAMERA_NAME}", format="dshow")   
stream = ffmpeg.output(stream, "output.mkv", preset="medium", c="copy")

if __name__ == "__main__":   
    process = ffmpeg.run_async(stream, cmd=APPLICATION, pipe_stdin=True, overwrite_output=True, quiet=True)
    _ = input("Press enter when finished.")
    #sleep(10) # Record 10 seconds for testing
    process.stdin.write('q'.encode("GBK"))
    process.communicate()
    process.wait()

当我使用 sleep(10) 而不是 _ = input 时,录制的视频时长约为 9 秒。
我认为它记录了 9 秒而不是 10 秒,因为加载 FFmpeg 并开始执行大约需要一秒钟。


将 real-time 缓冲区设置为 100M,并且 fflags="nobuffer" 无效。

rtbufsize="100M":

stream = ffmpeg.input(f"video={CAMERA_NAME}", rtbufsize="100M", format="dshow")

fflags="nobuffer":

stream = ffmpeg.input(f"video={CAMERA_NAME}", fflags="nobuffer", format="dshow")

当我们写 'q' 时,看起来 FFmpeg 会刷新缓冲区,没有数据丢失,缓冲区大小也没有影响。