[英]python - subprocess.Popen fails to correctly pipe urllib3 Response
我想通过网络打开文件,然后使用subprocess.Popen将其直接传输到ffmpeg。 目标是将音频文件数据直接流式传输到ffmpeg。 这是代码:
# test.py
import subprocess, sys, urllib3, time
http = urllib3.PoolManager()
r = http.urlopen('GET', sys.argv[1], preload_content=False)
args = 'ffmpeg -i - -y audio.mp3'.split(' ')
subprocess.Popen(args, stdin=r)
r.close()
如果我运行本地HTTP服务器并为程序提供url,则它可以成功运行,并且ffmpeg对其进行处理。
$ python3 test.py http://192.168.1.200/original.webm
但是,如果我尝试从远程服务器(如下面的服务器)中检索,则ffmpeg失败。
$ python3 test.py https://cdn.discordapp.com/attachments/304959901376053248/412003156638040084/original.webm
具有以下输出
pipe:: Invalid data found when processing input
我希望这段代码产生与运行此终端命令相同的结果。 对于不一致的CDN URL和本地HTTP服务器URL,此命令均成功。
$ curl [file url] | ffmpeg -i - -y audio.mp3
我在Linux和ffmpeg 3.4.1上使用python 3.5。
编辑1
我现在倾向于认为这不是ffmpeg的错,更多地是关于Popen如何读取/编写对进程stdin的urllib响应的。 通过运行本地netcat服务器并将输出发送到文件( $ nc -l 1234 > nc_output.webm
)并按以下方式调整脚本:
import subprocess, sys, urllib3, time
http = urllib3.PoolManager()
r = http.urlopen('GET', sys.argv[1], preload_content=False)
args = 'nc 192.168.1.200 1234'.split(' ')
subprocess.run(args, stdin=r)
r.close()
然后以$ python3 test.py https://cdn.discordapp.com/attachments/304959901376053248/412003156638040084/original.webm
运行
通过将nc_output.webm与原始.webm文件进行比较,我可以立即看到nc_output.webm稍大一些(4017585字节,而4008589字节)。 尝试播放nc_output.webm(mpv,vlc,ffprobe)也失败,这说明了ffmpeg抱怨的原因。 Popen对流的字节所做的任何事情都足以使输出文件无用。
但是,如果URL指向本地HTTP服务器,例如从python -m SimpleHTTPServer
运行的URL,该问题仍然不会继续发生,这使我认为这与与从远程源读取有关的延迟有关。
urllib3
实现使用Python代码从打开的连接中获取内容。 这在Python客户端上很棒,但是无法跨子进程边界工作。
您正在使用subprocess.Popen()
,它实际上使您可以相对轻松地解决此问题。 您正在子ffmpeg
中启动ffmpeg
,但是控制返回到您的Python代码,而子进程仍在后台,等待您将其输入标准输入数据。
r = http.urlopen('GET', sys.argv[1], preload_content=False)
# Manually split the command, just for aesthetics
s = subprocess.Popen(['ffmpeg', '-i', '-', '-y', 'audio.mp3'], stdin=subprocess.PIPE)
while True:
b = r.read(8192)
if b == '':
break
s.communicate(b)
r.close()
s.close()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.