2

I'm updating my code from the older version of ffmpeg (53) to the newer (54/55). Code that did work has now been deprecated or removed so i'm having problems updating it.

Previously I could create a stereo MP3 file using a sample format called:

SAMPLE_FMT_S16

That matched up perfectly with my source stream. This has now been replace with

AV_SAMPLE_FMT_S16

Which works fine for mono recordings but when I try to create a stereo MP3 file it bugs out at avcodec_open2 with:

"Specified sample_fmt is not supported."

Through trial and error I've found that using

AV_SAMPLE_FMT_S16P

...is accepted by avcodec_open2 but when I get through and create the MP3 file the sound is very distorted - it sounds about 2 octaves lower than usual with a massive hum in the background - here's an example recording:

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

I've been told by the ffmpeg guys that this is because I now need to manually deinterleave my byte stream before calling:

avcodec_fill_audio_frame

How do I do that? I've tried using the swrescale library without success and i've tried manually feeding in L/R data into avcodec_fill_audio_frame but the results i'm getting are sounding exactly the same as without interleaving.

Here is my code for encoding:

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; 

}

Would love to hear any ideas - I've been trying to get this working for 3 days now :(

Sean
  • 2,033
  • 2
  • 23
  • 28

2 Answers2

0

you don't want to increase pSoundBuffer if a frame hasn't been fully encoded (e.g. got_packet isn't set to true) as no memory has been written yet. Also, you are allocating a frame during each loop: there's no need for that, you can re-use the same AVFrame over an over. Your code is also leaking as you never free the AVFrame.

I wrote a code as part of MythTV that encode audio to AC3. This also do what you were looking for: deinterleave the content. https://github.com/MythTV/mythtv/blob/476b2a826d43fca5e658ebe787c3cb1ec2334f98/mythtv/libs/libmyth/audio/audiooutputdigitalencoder.cpp#L178

jyavenard
  • 2,142
  • 1
  • 26
  • 35
0

I know this question is old, but for posterity: I'm working on some audio resampling code, and after I arrived at an audio sounding very similar to the mp3 the author linked, I identified the cause as being a mismatch in audio sampling rate between the input the resampler expects and the actual data.

idevelop
  • 199
  • 2
  • 10