Python:mp3 到 alsaaudio 通过 ffmpeg 管道和 wave.open(f ,'r')

标签 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() 重定向到 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/

相关文章:

Android AudioRecord 配置与录制的音频不匹配

ffmpeg - 如何将 ffplay 作为无窗口进程运行?

python - 写入 wav 文件会发出咔嗒声

python - 使用 Python 根据第一列将 xlsx 文件拆分为其他 xlsx 文件

c# - 计算与源文件相比的wav文件中的噪声量

java - 如何播放给定绝对文件名的 mp3 文件?

video - FFMPEG - 在不丢失分辨率的情况下转换视频

ffmpeg:从视频中提取图像及其帧号?

python kill script.py 名称不是 PID

python - 与 web.py 匹配的 URL