ffmpeg 与 python 子进程 Popen

Eul*_*lar 2 audio video subprocess ffmpeg

我正在尝试使用 ffmpeg 从 python 录制网络摄像头视频。从 cmd 运行时,以下 ffmpeg 可以正常工作

ffmpeg -f dshow -rtbufsize 2000M -i video="HP HD Camera":audio="Headset (realme Buds Wireless 2 Neo Hands-Free AG Audio)" -y -vcodec libx264 -crf 24 output.mp4 
Run Code Online (Sandbox Code Playgroud)

我已经检查了音频和视频输入

ffmpeg -list_devices true -f dshow -i dummy
Run Code Online (Sandbox Code Playgroud)

现在,当我尝试使用子进程调用命令时,会发生问题。我可以像这样传递整个命令

ffmpeg -f dshow -rtbufsize 2000M -i video="HP HD Camera":audio="Headset (realme Buds Wireless 2 Neo Hands-Free AG Audio)" -y -vcodec libx264 -crf 24 output.mp4 
Run Code Online (Sandbox Code Playgroud)

现在,由于这是运行的,因此shell=True不会终止录制,并且我已经检查了不同的解决方案,但它们也不起作用。所以,我选择了shell=False。我尝试过

recorder = subprocess.Popen(['ffmpeg', '-f', 'dshow', '-rtbufsize', '2000M', '-t', '60', '-i', 'video="HP HD Camera":audio="Headset (realme Buds Wireless 2 Neo Hands-Free AG Audio)"', '-y', '-vcodec', 'libx264', '-crf', '24', 'output.mp4'],shell=False)
Run Code Online (Sandbox Code Playgroud)

这会引发错误

[dshow @ 0000024f2becd540] Could not find video device with name ["HP HD Camera"] among source devices of type video.
video="HP HD Camera":audio="Headset (realme Buds Wireless 2 Neo Hands-Free AG Audio)": I/O error
Run Code Online (Sandbox Code Playgroud)

然后,我尝试了

ffmpeg -list_devices true -f dshow -i dummy
Run Code Online (Sandbox Code Playgroud)

这会创建输出,但视频无法播放。
如何解决这个问题?

Rot*_*tem 7

我们可以添加双引号,让 Pythonsubprocess知道该字符串是一个参数,并且我们必须优雅地关闭 FFmpeg。

添加双引号:
将以下部分替换video="HP HD Camera":audio="Headset (realme Buds Wireless 2 Neo Hands-Free AG Audio)"为:需要
"video=""HP HD Camera"":audio=""Headset (realme Buds Wireless 2 Neo Hands-Free AG Audio)"""
加倍引号,因为is 位于引号之间。"""" ... "

""我们也可以在没有:的情况下使用它"video=HP HD Camera:audio=Headset (realme Buds Wireless 2 Neo Hands-Free AG Audio)"


为了获得可播放的文件,我们必须优雅地关闭 FFmpeg 。
为了简单地记录 10 秒,我们可以添加-t 10参数。

为了以编程方式优雅地关闭 FFmpeg,我们可以写入'q'.encode("GBK")FFmpegstdin子进程的管道。
写入q模拟q用户按下该键(停止录制)。

  • 添加stdin=subprocess.PIPE参数到subprocess.Popen.

  • 添加后time.sleep(10)

     recorder.stdin.write('q'.encode("GBK"))  # Simulate user pressing q key
     recorder.communicate()
    
    Run Code Online (Sandbox Code Playgroud)
  • 添加recorder.wait()(而不是recorder.terminate()recorder.kill())。


作为良好的实践,我们还可以添加shlex.split(...)将命令行转换为参数列表的功能。
在 Windows 中它应该可以在没有它的情况下工作,但在 Linux 中则不然。

代码示例:

 recorder.stdin.write('q'.encode("GBK"))  # Simulate user pressing q key
 recorder.communicate()
Run Code Online (Sandbox Code Playgroud)