'Best audio codec for FFMPEG RTMP

I want to use the best audio AVCodecID with rtmp in ffmpeg: in order to get stereo sound and a decent quality.

I have tried to use AV_CODEC_ID_AAC which works, but only for mono for now. I was thinking of using AV_CODEC_ID_MP3 maybe?

When using AV_CODEC_ID_MP3, i am faced with an issue: my AVFrame's nb_samples has to be set manually:


#define FRAME_SIZE 1024
 int fmt_size = (codec_ctx->frame_size != 0) ? codec_ctx->frame_size : FRAME_SIZE;
 frame->nb_samples = fmt_size;

As the AVCodec I'm using for my AVCodecContext has the flag AV_CODEC_CAP_VARIABLE_FRAME_SIZE.

When trying to send the AVFrame by doing:


        ret = avcodec_send_frame(codec_ctx, frame);

i get an error:

[mp3_mf @ 00000252ABEEF140] nb_samples (1024) != frame_size (0)

Any ideas?

Here is the relevant code :


AVFormatContext *av_fmt_ctx = nullptr;


const char* fmt_name = "flv";
std::string rtmp_output = "rtmp://x.rtmp.youtube.com/live2/KEY-KEY-KEY-KEY";
const int bit_rate = 2000000;
const int smaple_rate = 48000;
const int nb_channels = 2;

// init FFmpeg
AVFormatContext* av_fmt_ctx = nullptr;
AVStream* stream = nullptr;
AVCodec* codec = nullptr;
AVCodecContext* codec_ctx = nullptr;
AVFrame* frame = nullptr;

int initialise_audio(AVCodecID codec_id, int sample_rate, int nb_channels, int bit_rate) {

    int ret = 0;

    codec = avcodec_find_encoder(codec_id);

    if (!codec)
    {
        std::cout << "could not find the audio encoder" << std::endl;
        return -1;
    }

    if ((codec->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE))
    {
        std::cout << "audio codec has variable frame size" << std::endl;
    }

    av_fmt_ctx->audio_codec = codec;
    av_fmt_ctx->audio_codec_id = codec->id;

    stream = avformat_new_stream(av_fmt_ctx, codec);

    if (!stream)
    {
        std::cout << "audio stream not initialised"<<std::endl;
        return -1;
    }


    codec_ctx = avcodec_alloc_context3(codec);
    codec_ctx->bit_rate = bit_rate;
    codec_ctx->sample_fmt = codec->sample_fmts[0];


    codec_ctx->sample_rate = sample_rate;
    //select_sample_rate(a_codec);
    codec_ctx->channels = nb_channels;
    codec_ctx->channel_layout = AV_CH_LAYOUT_STEREO;
        //av_get_default_channel_layout(nb_channels);

    ret = avcodec_open2(codec_ctx, codec, NULL);

    if (ret < 0)
    {
        std::cout << "can't open the audio AVCodecContext with current options / codec"<<std::endl;
        return ret;
    }

    stream->codecpar->extradata = codec_ctx->extradata;
    stream->codecpar->extradata_size = codec_ctx->extradata_size;
    stream->time_base = AVRational{ 1, codec_ctx->sample_rate };


    ret = avcodec_parameters_from_context(stream->codecpar, codec_ctx);
    if (ret < 0)
    {
        std::cout << "can't copy the audio parameter from the AVCodecContext to the AVStream"<<std::endl;
        return ret;
    }


    frame = av_frame_alloc();
    if (!frame)
    {
        std::cout << "can't allocate the audio frame"<<std::endl;
        return -1;
    }

    frame->sample_rate = codec_ctx->sample_rate;
    int fmt_size = (codec_ctx->frame_size != 0) ? codec_ctx->frame_size : FRAME_SIZE;
    frame->nb_samples = fmt_size;
    frame->format = codec_ctx->sample_fmt;
    frame->channel_layout = codec_ctx->channel_layout;
    frame->pts = 0;

    const int audio_buffer_size = av_samples_get_buffer_size(NULL,
        codec_ctx->channels,
        codec_ctx->frame_size,
        codec_ctx->sample_fmt,
        0);

    ret = av_frame_get_buffer(frame, 0);

    if (ret < 0)
    {
        std::cout << "can't allocate the audio frame"<<std::endl;
        return ret;
    }

    return ret;
}



int update_audio(int index_frame) {
    int ret = 0;

    ret = av_frame_make_writable(frame);
    if (ret < 0) {
        std::cout << "can't make frame wirtable"<<std::endl;
        return ret;
    }


    frame->pts = av_rescale_q(index_frame * frame->nb_samples, AVRational{ 1, codec_ctx->sample_rate }, codec_ctx->time_base);

    ret = avcodec_send_frame(codec_ctx, frame);
    if (ret < 0) {
        std::cout << "couldn't send the audio frame"<<std::endl;
        return ret;
    }


    index_frame++;

    AVPacket pkt = { 0 };
    av_new_packet(&pkt, 0);

    while (ret >= 0) {
        ret = avcodec_receive_packet(codec_ctx, &pkt);
        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
            break;
        }
        else if (ret < 0) {
            LOG("error receiving the packet");
            return ret;
        }

        av_packet_rescale_ts(&pkt, codec_ctx->time_base, stream->time_base);
        pkt.stream_index = stream->index;

        ret = av_interleaved_write_frame(av_fmt_ctx, &pkt);
        if (ret < 0) {
            std::cout << "error writing the audio frame"<<std::endl;
            return ret;
        }


        av_packet_unref(&pkt);



    }


    return ret;
}



int main(int argc, char* argv[]){

 



    // format context init
    int ret = 0;
    ret = avformat_alloc_output_context2(&av_fmt_ctx, nullptr, fmt_name, nullptr);
    if (ret < 0)
    {
        std::cout << "Could not allocate output format (flv) context!"<<std::endl;
        return ret;
    }

    if (!(av_fmt_ctx->oformat->flags & AVFMT_NOFILE))
    {
        ret = avio_open2(&(av_fmt_ctx->pb), rtmp_output.c_str(), AVIO_FLAG_WRITE, nullptr, nullptr);
        if (ret < 0)
        {
            std::cout << "Could not open output IO context " << std::endl;
            return ret;

        }
    }
    
    if(initialise_audio() < 0)return 0;

    int index = 0;
    bool stream = true;
    while(stream){

        if(update_audio(index) <0)return 0;

        index++;
    }


    return 0;
}

Best,

P



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source