如何使用最新版本的ffmpeg创建立体声mp3文件?

时间:2012-10-19 05:09:17

标签: c++ audio ffmpeg mp3

我正在将我的代码从旧版本的ffmpeg(53)更新为更新版本(54/55)。现在已经弃用或删除了有效的代码,因此我在更新时遇到了问题。

以前我可以使用名为

的样本格式创建立体声MP3文件

SAMPLE_FMT_S16

与我的源流完美匹配。现在已经替换为

AV_SAMPLE_FMT_S16

这对于单声道录音效果很好但是当我尝试创建一个立体声MP3文件时,它会在avcodec_open2上发出错误信息:

“不支持指定的sample_fmt。”

通过反复试验,我发现使用

AV_SAMPLE_FMT_S16P

...被avcodec_open2接受,但是当我通过并创建MP3文件时,声音非常失真 - 它听起来比平时低2个八度,后面有一个巨大的嗡嗡声 - 这是一个示例录音:

http://hosting.ispyconnect.com/example.mp3

ffmpeg家伙告诉我这是因为我现在需要在调用之前手动解交织我的字节流:

avcodec_fill_audio_frame

我该怎么做?我尝试过使用swrescale库但没有成功,我尝试将L / R数据手动输入到avcodec_fill_audio_frame中,但我得到的结果与没有交错的情况完全相同。

以下是我的编码代码:

void add_audio_sample( AudioWriterPrivateData^ data, BYTE* soundBuffer, int soundBufferSize)
{
    libffmpeg::AVCodecContext* c = data->AudioStream->codec;
    memcpy(data->AudioBuffer + data->AudioBufferSizeCurrent,  soundBuffer, soundBufferSize);
    data->AudioBufferSizeCurrent += soundBufferSize;
    uint8_t* pSoundBuffer = (uint8_t *)data->AudioBuffer;
    DWORD nCurrentSize    = data->AudioBufferSizeCurrent;

    libffmpeg::AVFrame *frame;

    int got_packet;
    int ret;
    int size = libffmpeg::av_samples_get_buffer_size(NULL, c->channels,
                                              data->AudioInputSampleSize,
                                              c->sample_fmt, 1);

    while( nCurrentSize >= size)    {

        frame=libffmpeg::avcodec_alloc_frame();
        libffmpeg::avcodec_get_frame_defaults(frame);

        frame->nb_samples = data->AudioInputSampleSize;

        ret = libffmpeg::avcodec_fill_audio_frame(frame, c->channels, c->sample_fmt, pSoundBuffer, size, 1);
        if (ret<0)
        {
            throw gcnew System::IO::IOException("error filling audio");
        }
        //audio_pts = (double)audio_st->pts.val * audio_st->time_base.num / audio_st->time_base.den;

        libffmpeg::AVPacket pkt = { 0 };
        libffmpeg::av_init_packet(&pkt);

        ret = libffmpeg::avcodec_encode_audio2(c, &pkt, frame, &got_packet);

        if (ret<0)
                throw gcnew System::IO::IOException("error encoding audio");
        if (got_packet) {
            pkt.stream_index = data->AudioStream->index;

            if (pkt.pts != AV_NOPTS_VALUE)
                pkt.pts = libffmpeg::av_rescale_q(pkt.pts, c->time_base, c->time_base);
            if (pkt.duration > 0)
                pkt.duration = av_rescale_q(pkt.duration, c->time_base, c->time_base);

            pkt.flags |= AV_PKT_FLAG_KEY;

            if (libffmpeg::av_interleaved_write_frame(data->FormatContext, &pkt) != 0)
                    throw gcnew System::IO::IOException("unable to write audio frame.");


        }
        nCurrentSize -= size;  
        pSoundBuffer += size;   
    }
    memcpy(data->AudioBuffer, data->AudioBuffer + data->AudioBufferSizeCurrent - nCurrentSize, nCurrentSize);
    data->AudioBufferSizeCurrent = nCurrentSize; 

}

很想听到任何想法 - 我一直试图让这个工作3天了:(

2 个答案:

答案 0 :(得分:0)

如果帧尚未完全编码(例如,got_packet未设置为true),则不希望增加pSoundBuffer,因为尚未写入任何内存。此外,您在每个循环期间分配一个帧:没有必要,您可以重复使用相同的AVFrame。您的代码也在泄露,因为您永远不会释放AVFrame。

我编写了一个代码作为MythTV的一部分,将音频编码为AC3。 这也可以满足您的需求:对内容进行解交织。 https://github.com/MythTV/mythtv/blob/476b2a826d43fca5e658ebe787c3cb1ec2334f98/mythtv/libs/libmyth/audio/audiooutputdigitalencoder.cpp#L178

答案 1 :(得分:0)

我知道这个问题已经过时了,但对后人来说:我正在研究一些音频重采样代码,在我听到与作者链接的mp3非常相似的音频后,我发现原因是不匹配的。重采样器预期输入与实际数据之间的音频采样率。