繁体   English   中英

为什么mp3解码输出听起来如此延迟?(使用ffmpeg mp3lame lib)

[英]why the output of mp3 decode sounds so delayed?(with ffmpeg mp3lame lib)

我正在用ffmpeg lib录制声音并编码为mp3。 然后立即解码mp3数据,播放解码数据,但声音如此延迟。 这是代码:函数编码的第一个参数接受原始pcm数据,len = 44100。

编码参数:

cntx_->channels = 1;
cntx_->sample_rate = 44100;
cntx_->sample_fmt = 6;
cntx_->channel_layout =  AV_CH_LAYOUT_MONO;
cntx_->bit_rate = 8000;
err_ = avcodec_open2(cntx_, codec_, NULL);

vector<unsigned char>       encode(unsigned char* encode_data, unsigned int len)
{
    vector<unsigned char> ret;
    AVPacket avpkt;
    av_init_packet(&avpkt);

    unsigned int len_encoded = 0; 
    int data_left = len / 2;
    int miss_c = 0, i = 0;
    while (data_left > 0)
    {
        int sz = data_left > cntx_->frame_size ? cntx_->frame_size : data_left;
        mp3_frame_->nb_samples = sz;
        mp3_frame_->format = cntx_->sample_fmt;
        mp3_frame_->channel_layout = cntx_->channel_layout;

        int needed_size = av_samples_get_buffer_size(NULL, 1,
            mp3_frame_->nb_samples, cntx_->sample_fmt, 1);

        int r = avcodec_fill_audio_frame(mp3_frame_, 1, cntx_->sample_fmt, encode_data + len_encoded, needed_size, 0);

        int gotted = -1;

        r = avcodec_encode_audio2(cntx_, &avpkt, mp3_frame_, &gotted);
        if (gotted){
            i++;
            ret.insert(ret.end(), avpkt.data, avpkt.data + avpkt.size);
        }
        else if (gotted == 0){
            miss_c++;
        }
        len_encoded += needed_size;
        data_left -= sz;
        av_free_packet(&avpkt);
    }
    return ret;
}

std::vector<unsigned char>  decode(unsigned char* data, unsigned int len)
{
    std::vector<unsigned char> ret;

    AVPacket avpkt;
    av_init_packet(&avpkt);
    avpkt.data = data;
    avpkt.size = len;

    AVFrame* pframe = av_frame_alloc();
    while (avpkt.size > 0){
        int goted = -1;av_frame_unref(pframe);
        int used = avcodec_decode_audio4(cntx_, pframe, &goted, &avpkt);
        if (goted){
            ret.insert(ret.end(), pframe->data[0], pframe->data[0] + pframe->linesize[0]);
            avpkt.data += used;
            avpkt.size -= used;
            avpkt.dts = avpkt.pts = AV_NOPTS_VALUE; 
        }
        else if (goted == 0){
            avpkt.data += used;
            avpkt.size -= used;
            avpkt.dts = avpkt.pts = AV_NOPTS_VALUE; 
        }
        else if(goted < 0){
            break;
        }
    }
    av_frame_free(&pframe);
    return ret;
}

假设它是第100次对encode(data,len)的调用,那么此“帧”将出现在第150个或以后的解码调用中,延迟是不可接受的。 似乎mp3lame编码器会保留示例数据供以后使用,但不是我想要的。 我不知道怎么了。 感谢您提供任何信息。

今天,我再次调试代码并发布一些详细信息:

编码:每个pcm样本帧len = 23040,是mp3帧大小的10倍,每次调用仅编码输出9个帧,此输出导致解码输出20736个样本,丢失1帧(2304字节),并且声音嘈杂。

如果mp3或mp2编码不适合实时语音传输,我应该选择哪种编码器?

假设它是第100次对encode(data,len)的调用,那么此“帧”将出现在第150个或以后的解码调用中,延迟是不可接受的。

了解编解码器的工作原理并相应地调整您的期望。

MP3是有损编解码器。 它通过将时域PCM数据转换为频域来工作。 仅此转换就需要时间(因为频率成分在任何瞬间都不存在...它们只能在一段时间内存在)。 然后,在简单的级别上,它使用少数算法来确定要保留哪些光谱信息以及丢弃哪些光谱信息。 每个MP3帧的持续时间都是数百个样本。 (576通常会达到最低要求。两次是典型的数字。)

现在您已拥有创建帧的最短时间,MP3还将使用所谓的位存储库。 如果复杂的通道需要更多的带宽,它将从相邻帧借用未使用的带宽。 为了促进这一点,需要许多帧的缓冲器。

在所有编解码器工作的基础上,FFmpeg本身具有缓冲(用于检测输入和不输入),并且在往返FFmpeg的管道中有缓冲区。 我可以想象编解码器本身也可以在输入和输出上使用通用缓冲。

最后,您要对流进行解码并进行回放,这意味着编码中使用的大多数相同类型的缓冲区现在都已用于解码。 而且,我们甚至没有在谈论通过声卡获取音频数据并将其输出到扬声器的模拟信号所需要的几百毫秒的延迟。

您有一个不切实际的期望,尽管可以调整一些东西来减少延迟(例如禁用位存储),但它会导致质量差的流,并且总之不会具有低延迟。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM