【问题标题】:speex decoding going wrongspeex 解码出错
【发布时间】:2011-05-15 20:31:55
【问题描述】:

我正在使用 speex 对一些音频数据进行编码并通过 UDP 发送,然后在另一端对其进行解码。 我用 speex 进行了一些测试,并注意到如果我在编码后直接解码一个数据包,解码后的数据绝不会接近原始数据。缓冲区开始处的大部分字节为 0。 因此,当我解码通过 UDP 发送的音频时,我得到的只是噪音。 这就是我编码音频的方式:

bool AudioEncoder::encode( float *raw, char *encoded_bits )
{
    for ( size_t i = 0; i < 256; i++ )
        this->_rfdata[i] = raw[i];
    speex_bits_reset(&this->_bits);
    speex_encode(this->_state, this->_rfdata, &this->_bits);
    int bytesWritten = speex_bits_write(&this->_bits, encoded_bits, 512);
    if (bytesWritten)
        return true;
    return false;
}

这就是我解码音频的方式:

float *f = new float[256];
// recvbuf is the buffer I pass to my recv function on the socket
speex_bits_read_from(&this->_bits, recvbuf, 512);
speex_decode(this->state, &this->_bits, f);

我查看了文档,我的大部分代码来自 speex 网站的示例编码/解码示例。 我不确定我在这里缺少什么。

【问题讨论】:

  • speex 是有损编解码器,生成的流将与原始流不同,因为您会丢失信息以实现更好的压缩。
  • @Paulo Scardine 如果我用来自正弦波的值对数组进行编码,则 20~ 第一个浮点数(一旦解码)都等于 0。我知道它是有损的,但我正在丢失大部分数据。我也得到了一些负值,而我有一些正值。
  • 似乎是有符号/无符号数据类型问题。
  • 它与签名/未签名数据有什么关系?

标签: c++ c encoding speex portaudio


【解决方案1】:

实际上讲给音频数据引入了额外的延迟,我通过逆向工程发现:

narrow band : delay = 200 - framesize + lookahead = 200 - 160 +  40 =  80 samples 

wide band   : delay = 400 - framesize + lookahead = 400 - 320 + 143 = 223 samples

uwide band  : delay = 800 - framesize + lookahead = 800 - 640 + 349 = 509 samples

由于前瞻是用零初始化的,因此您观察到前几个样本“接近于零”。

要获得正确的时序,您必须先跳过这些样本,然后才能获得输入编解码器的实际音频数据。为什么会这样,我不知道。 speex 的作者 Probalby 从未关心过这一点,因为 speex 用于流式传输,而不是主要用于存储和恢复音频数据。 另一种解决方法(不浪费空间)是,在输入实际音频数据之前,将(帧大小延迟)零输入编解码器,然后丢弃整个第一个 speex 帧。

我希望这可以澄清一切。如果熟悉 Speex 的人看到这篇文章,如果我错了,请随时纠正我。

编辑:实际上,解码器和编码器都有一个前瞻时间。延迟的实际公式是:

narrow band : delay = decoder_lh + encoder_lh =  40 +  40 =  80 samples 

wide band   : delay = decoder_lh + encoder_lh =  80 + 143 = 223 samples

uwide band  : delay = decoder_lh + encoder_lh = 160 + 349 = 509 samples

【讨论】:

    【解决方案2】:

    我找到了编码数据如此不同的原因。事实上,正如 Paulo Scardine 所说,它是一种有损压缩,而且 speex 仅适用于 160 帧,因此当从 portaudio 获取数据到 speex 时,它需要通过 160 帧的“数据包”。

    【讨论】:

    • 160帧是什么意思?一帧应该包含 160 个短字节或 320 个字节,对吗?
    • Framesize 总是指样本中解码后的数据帧大小。帧大小取决于编码模式窄带 (8kHz):帧大小 = 160 个样本 = 320 字节的 PCM 宽带 (16kHz):帧大小 = 320 个样本 = 640 字节的 PCM 超宽带 (32kHz):帧大小 = 640 个样本 = 1280 字节的 PCM
    【解决方案3】:

    您可能想在这里查看一些简单的编码/解码: http://www.speex.org/docs/manual/speex-manual/node13.html#SECTION001310000000000000000

    由于您使用的是 UDP,您还可以使用抖动缓冲区来重新排序数据包和内容。

    【讨论】:

    • 我已经看到了那个链接,不,还没有使用抖动缓冲区,因为我什至无法正确编码/发送/解码/播放一个数据包。我把头发拉出来了!
    猜你喜欢
    • 1970-01-01
    • 2012-01-15
    • 1970-01-01
    • 2014-05-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-31
    • 1970-01-01
    相关资源
    最近更新 更多