'Controlling buffer size for webcam video capture to file using ffmpeg
In a Python script I want to capture a webcam stream and save it to a video file on local harddisk, but I want to script to determine lifecycle of the video. For this I am using python-ffmpeg library which is essentially a simple Python SDK around ffmpeg in a subprocess.
This is my snipped currently:
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()
This works fine. However, the process.terminate() is quite abrupt, since it essentially just kills the subprocess immediately. I've seen that this tends to cut off a few seconds of the video stream. I assume it is being written continuously and when killed whatever is already written remains.
Right now I have no control over the duration (of the.. buffer?). I'm just guessing it's around 3 seconds, hence my sleep call. Is there a way to configure this to ffmpeg?
Solution 1:[1]
Instead of trying to control the buffer size, we have to close FFmpeg gracefully.
For closing FFmpeg gracefully, we may write 'q' to stdin pipe, as described in this post.
When we start recording, the following message appears: Press [q] to stop, [?] for help.
Writing 'q' to stdin simulates pressing the q key.
Open FFmpeg sub-process with
pipe_stdin=True:process = ffmpeg.run_async(stream, cmd=APPLICATION, pipe_stdin=True, overwrite_output=True, quiet=True)Write
'q'letter (withencode("GBK")) tostdinpipe, and "communicate()":process.stdin.write('q'.encode("GBK")) process.communicate()Wait for FFmpeg sub-process to end:
process.wait()
Code sample:
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()
When I used sleep(10) instead of _ = input, the recorded video duration was about 9 seconds.
I think it records 9 seconds and not 10 seconds because it takes FFmpeg about one second to be loaded and start execution.
Setting real-time buffer to 100M, and fflags="nobuffer" had no effect.
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")
It looks like FFmpeg flushes the buffers when we write 'q', there is no data loss and the buffer size has no effect.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Mark Setchell |
