如何通过传递文件对象(而不是磁盘上文件的位置)将 ffmpeg 与 Python 一起使用
Posted
技术标签:
【中文标题】如何通过传递文件对象(而不是磁盘上文件的位置)将 ffmpeg 与 Python 一起使用【英文标题】:How do I use ffmpeg with Python by passing File Objects (instead of locations to files on disk) 【发布时间】:2012-05-11 03:34:03 【问题描述】:我正在尝试将 ffmpeg 与 Python 的 subprocess 模块一起使用来转换一些音频文件。我从 URL 中获取音频文件,并且希望能够将 Python 文件对象传递给 ffmpeg,而不是先将它们保存到磁盘。如果我可以只取回文件流而不是让 ffmpeg 将输出保存到文件中,那也很好。
作为参考,这是我现在正在做的:
tmp = "/dev/shm"
audio_wav_file = requests.get(audio_url)
## ## ##
## This is what I don't want to have to do ##
wavfile = open(tmp+filename, 'wrb')
wavfile.write(audio_wav_file.content)
wavfile.close()
## ## ##
conversion = subprocess.Popen('ffmpeg -i "'+tmp+filename+'" -y "'+tmp+filename_noext+'.flac" 2>&1', shell = True, stdout = subprocess.PIPE).stdout.read()
有人知道怎么做吗?
谢谢!
【问题讨论】:
【参考方案1】:使用 ffmpeg,您可以使用-
作为输入/输出文件名来指示它应该从标准输入读取数据/写入标准输出。
然后您可以使用Popen
的stdin
/stdout
参数来读取/写入您的数据。
一个例子:
from subprocess import Popen, PIPE
with open("test.avi", "rb") as infile:
p=Popen(["ffmpeg", "-i", "-", "-f", "matroska", "-vcodec", "mpeg4",
"-acodec", "aac", "-strict", "experimental", "-"],
stdin=infile, stdout=PIPE)
while True:
data = p.stdout.read(1024)
if len(data) == 0:
break
# do something with data...
print(data)
print p.wait() # should have finisted anyway
您也可以使用 PIPE
并直接写入进程输入流 (p.stdin
),而不是为 stdin
提供文件。或者在您的情况下,您只需使用 wavfile ...
请注意,您必须明确指定输出格式和编解码器,因为 ffmpeg 无法像通常那样从文件扩展名中猜出它们。 它只适用于不需要可搜索输出流的多路复用器,但 flac 应该可以工作......
【讨论】:
【参考方案2】:对于仍在阅读本文的任何人:
这可以通过使用FFMPEG's pipe protocol 代替子进程来完成。
如果使用包ffmpeg-python
调用FFMPEG,则可以将FFMPEG 命令的stdout, stderr
输出输入到Python 变量中,如here 所示:
out, err = inpstream.output('pipe:', ... ).run(capture_stdout=True)
【讨论】:
【参考方案3】:由于您使用的是 Unix('ffmpeg' 末尾没有 .exe),我建议使用命名管道,也就是 fifo:
mkfifo multimedia-pipe
让 Python 脚本将音频数据写入“多媒体文件”并要求 FFmpeg 从同一文件中读取。我已使用此模式将多媒体文件解码为巨大的原始表示形式以进行验证,而无需占用磁盘空间。
或者,尝试将 'http://...' URL 直接传递给 FFmpeg 的输入选项。
【讨论】:
以上是关于如何通过传递文件对象(而不是磁盘上文件的位置)将 ffmpeg 与 Python 一起使用的主要内容,如果未能解决你的问题,请参考以下文章