【问题标题】:Python : PortAudio + Opus encoding/decodingPython : PortAudio + Opus 编码/解码
【发布时间】:2015-02-19 12:08:51
【问题描述】:

我正在使用 Pyaudio 从我的麦克风中捕获音频,并尝试使用 opus 编解码器对其进行编码/解码。我正在使用 SvartalF (https://github.com/svartalf/python-opus) 对 libopus 的绑定。

这是我的代码:

import pyaudio
from opus import encoder, decoder

def streaming(p):
    chunk = 960
    FORMAT = pyaudio.paInt16
    CHANNELS = 1
    RATE = 48000
    streamin = p.open(format = FORMAT,
            channels = CHANNELS, 
            rate = RATE, 
            input = True,
            input_device_index = 7,
            frames_per_buffer = chunk)
    streamout = p.open(format = FORMAT,
            channels = CHANNELS, 
            rate = 48000, 
            output = True,
            output_device_index = p.get_default_input_device_info()["index"],
            frames_per_buffer = chunk)
    enc = encoder.Encoder(RATE,CHANNELS,'voip')
    dec = decoder.Decoder(RATE,CHANNELS)
    data = []
    for i in xrange(100):
        data.append(streamin.read(chunk*2))
    streamout.write(''.join(data))
    encdata = []
    for x in data:
        encdata.append(enc.encode(x,chunk))
    print "DATA LENGTH :", len(''.join(data))
    print "ENCDATA LENGTH :", len(''.join(encdata))
    decdata = ''
    for x in encdata:
        decdata += dec.decode(x,chunk)
    print "DECDATA LENGTH :", len(decdata)
    streamout.write(decdata)
    streamin.close()
    streamout.close()


p = pyaudio.PyAudio()
streaming(p)
p.terminate()

我必须在data.append(streamin.read(chunk*2))DECDATA LENGTH == DATA LENGTH*2 中输入chunk*2 而不是chunk,我不知道为什么。

输出:

DATA LENGTH :    384000  
ENCDATA LENGTH : 12865  
DECDATA LENGTH : 384000

没有编码/解码,第一个streamout.write(''.join(data)) 完美运行。通过编码/解码,streamout.write(decdata) 有点工作,但混合了很多噼啪声。

我在这里做错了什么?

【问题讨论】:

  • 您好!我现在没有时间支持 python-opus,但你可以分叉并贡献,所以我可以用固定版本更新 PyPI 存储库。

标签: python portaudio pyaudio opus


【解决方案1】:

这似乎是由解码方法中的 python-opus 中的错误引起的。

根据Opus APIopus_decode返回解码的样本数。 python 绑定假定它将完全填充它传入的结果缓冲区,因此每组解码样本都会附加一个静默。这种静默会导致低帧大小的破裂和较高帧大小的卡顿。虽然文档没有说明任何内容,但返回的数字似乎是每个频道的。

150 of opus/api/decoder.py 更改为以下为我修复它:

    return array.array('h', pcm[:result*channels]).tostring()

如果您需要使用 decode_float 方法,可能需要进行相同的更改。

【讨论】:

    【解决方案2】:

    只需将输出减半并获取第一部分。 通过反复试验,我发现这个解决方案令人满意。

    from opus import decoder as opus_decoder
    from opus import encoder as opus_encoder
    
    class OpusCodec():
        def __init__(self, *args, **kwargs):
            self.chunk = 960
            self.channels = 1
            self.rate = 48000
            self.encoder = opus_encoder.Encoder(
                self.rate, 
                self.channels,
                opus_encoder.APPLICATION_TYPES_MAP['voip']
            )
            self.decoder = opus_decoder.Decoder(
                self.rate, 
                self.channels, 
            )
    
        def encode(self, data, **kwargs):
            if not 'frame_size' in kwargs:
                kwargs['frame_size'] = self.chunk
            out = self.encoder.encode(data, frame_size=self.chunk)
            return out
    
        def decode(self, data, **kwargs):
            if not 'frame_size' in kwargs:
                kwargs['frame_size'] = self.chunk
            out = self.decoder.decode(data, **kwargs)
            return out[0:int(len(out)/2)] # hackety hack :D
    

    【讨论】:

    • 所以你要把输出减半?怀疑这是个好主意。
    猜你喜欢
    • 2012-11-19
    • 1970-01-01
    • 2020-06-20
    • 2014-10-17
    • 2020-05-12
    • 2016-10-30
    • 2016-02-08
    • 1970-01-01
    • 2020-08-14
    相关资源
    最近更新 更多