'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 |
|---|
