Python:mp3通过ffmpeg管道和wave.open(f,';r';)到alsaaudio
我正在尝试使用ffmpeg将mp3解码为wav:Python:mp3通过ffmpeg管道和wave.open(f,';r';)到alsaaudio,python,audio,ffmpeg,Python,Audio,Ffmpeg,我正在尝试使用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()重定
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(文件,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文件不是解决方案
对不起我的英语。
谢谢
更新
多亏了pm2ring对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
由于“错误”的self.\u文件对象,检查失败
在/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。
但是这个函数是正确的
按照规定:
“5-8字节-文件大小(整数)
整个文件的大小—8个字节,以字节(32位整数)为单位。通常,您会在创建后填写此文件。“
这就是为什么我的脚本不起作用。wave.open和其他函数无法处理我的文件对象,因为self.chunksize=0。看起来ffmpeg在使用管道时无法插入文件大小
解决方案
很简单。
我更改了Chunk类的init函数:
之后:
...
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两个类创建了自定义分叉
可以找到工作但不稳定的完整代码
对不起,我的英语糟透了
谢谢。正如您所提到的,wave.open(file,'r')的
文件参数只能是文件名或打开的文件指针。但是p.stdout.read()
是作为字符串的文件p.stdout
的内容。但是,您不能只将p.stdout
文件传递给wave.open()
,因为wave.open()
需要一个可查找的类似文件的对象,并且通常不能在管道上seek()
但您可以做的是将从p.stdout.read()
读取的字节包装到对象中。结果对象的行为将类似于文件,并且它是可查找的
FWIW,使用file
作为变量名不是一个好主意,因为它是Python 2中内置类型的名称;我想使用Python 3是可以的,但我还是会避免使用它
警告:未经测试的Python 2.6+代码
fbytes = io.BytesIO(p.stdout.read())
fwave = wave.open(fbytes, 'r')
如果使用-f s16le
而不是-f wav
将音频文件转换为原始音频而不是wav,则可能不需要wave。完全打开
,就可以直接流式传输到ALSA。我只在PyAudio上试用过,效果很好。很有趣!但是你真的应该把你找到的解决方案作为一个答案,而不是对你的问题的修改。
fbytes = io.BytesIO(p.stdout.read())
fwave = wave.open(fbytes, 'r')