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