繁体   English   中英

python-subprocess.Popen无法正确传递urllib3响应

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM