我正在尝试使用 ffmpeg 将 mp3 解码为 wav:
import alsaaudio
import wave
from subprocess import Popen, PIPE
with open('filename.mp3', 'rb') as infile:
p=Popen(['ffmpeg', '-i', '-', '-f', 'wav', '-'], stdin=infile, stdout=PIPE)
...
接下来我想将数据从 p.stdout.read() 重定向到 wave.open(file, r) 以使用 readframes(n) 和其他方法。但我不能,因为 wave.open(file,'r') 中的 'file' 只能是文件名或打开的文件指针。
...
file = wave.open(p.stdout.read(),'r')
card='default'
device=alsaaudio.PCM(card=card)
device.setchannels(file.getnchannels())
device.setrate(file.getframerate())
device.setformat(alsaaudio.PCM_FORMAT_S16_LE)
device.setsetperiodsize(320)
data = file.readframes(320)
while data:
device.write(data)
data = file.readframes(320)
我得到了:
TypeError: file() argument 1 must be encoded string without NULL bytes, not str
那么是否可以通过 wave.open() 处理来自 p.stdout.read() 的数据? 制作临时 .wav 文件不是解决方案。
对不起我的英语。 谢谢。
更新
感谢 PM 2Ring 对 io.BytesIO 的关注。
但是生成的代码不起作用。
import alsaaudio
import wave
from subprocess import Popen, PIPE
with open('sometrack.mp3', 'rb') as infile:
p=Popen(['ffmpeg', '-i', '-', '-f','wav', '-'], stdin=infile , stdout=PIPE , stderr=PIPE)
fobj = io.BytesIO(p.stdout.read())
fwave = wave.open(fobj, 'rb')
跟踪:
File "./script.py", line x, in <module>
fwave = wave.open(fobj, 'rb')
File "/usr/lib/python2.7/wave.py", line x, in open
return Wave_read(f)
File "/usr/lib/python2.7/wave.py", line x, in __init__
self.initfp(f)
File "/usr/lib/python2.7/wave.py", line x, in initfp
raise Error, 'not a WAVE file'
wave.Error: not a WAVE file
来自/usr/lib/python2.7/wave.py:
...
self._file = Chunk(file, bigendian = 0)
if self._file.getname() != 'RIFF':
raise Error, 'file does not start with RIFF id'
if self._file.read(4) != 'WAVE':
raise Error, 'not a WAVE file'
...
由于“错误”的 self._file 对象,检查失败。
在/usr/lib/python2.7/chunk.py 中我发现了问题的根源:
...
try:
self.chunksize = struct.unpack(strflag+'L', file.read(4))[0]
except struct.error:
raise EOFError
...
因为 struct.unpack(strflag+'L', file.read(4))[0] 返回 0。 但是这个功能工作正常。
按规定here :
"5-8 字节 - 文件大小(整数) 整个文件的大小 - 8 字节,以字节为单位(32 位整数)。 通常,您会在创建后填写此内容。” 这就是为什么我的脚本不起作用。 wave.open 和其他函数无法处理我的文件对象,因为 self.chunksize = 0。看起来 ffmpeg 在使用 PIPE 时无法插入文件大小。
解决方案
很简单。 我已经更改了 Chunk 类的初始化函数:
之后:
...
try:
self.chunksize = struct.unpack(strflag+'L', file.read(4))[0]
except struct.error:
raise EOFError
...
之前:
...
try:
self.chunksize = struct.unpack(strflag+'L', file.read(4))[0]
currtell = file.tell()
if self.chunksize == 0:
file.seek(0)
file.read(currtell)
self.chunksize = len(file.read())-4
file.seek(0)
file.read(currtell)
except struct.error:
raise EOFError
...
当然,原始模块的编辑是不好的 idia。因此,我为 Chunk 和 Wave_read 这两个类创建了自定义分支。
您可以找到可用但不稳定的完整代码 here .
对不起我糟糕的英语。
谢谢。
最佳答案
如您所述,wave.open(file,'r')
的 file
arg 只能是文件名或打开的文件指针。但是 p.stdout.read()
是 contents 文件 p.stdout
的一个字符串。但是,您不能只将 p.stdout
文件传递给 wave.open()
,因为 wave.open()
需要一个 seekable 类似文件的对象,您通常不能在管道上使用 seek()
。
但是您可以做的是将您从p.stdout.read()
读取的字节包装在io.BytesIO 中。目的。生成的对象将表现得像一个文件,并且是可搜索的。
FWIW,使用 file
作为变量名不是一个好主意,因为它是 Python 2 中的内置类型的名称;我想可以在 Python 3 中使用它,但我仍然会避免使用它。
警告:未经测试的 Python 2.6+ 代码
fbytes = io.BytesIO(p.stdout.read())
fwave = wave.open(fbytes, 'r')
关于Python:mp3 到 alsaaudio 通过 ffmpeg 管道和 wave.open(f ,'r'),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29493204/