I need to enable FFmpeg in my video playback application. However, the FFmpeg application cannot listen to the correct audio stream data. Here is the part of the code that is not working correctly:
if (avformat_open_input(&m_data->formatContext, Filename.c_str(), nullptr, nullptr) != 0)
{
std::cout << "Motion: Failed to open file: '" << Filename << "'" << std::endl;
return false;
}
if (avformat_find_stream_info(m_data->formatContext, nullptr) < 0)
{
std::cout << "Motion: Failed to find stream information" << std::endl;
return false;
}
for (unsigned int i = 0; i < m_data->formatContext->nb_streams; i++)
{
// Получаем параметры кодека для текущего потока
AVCodecParameters *codecParams = m_data->formatContext->streams[i]->codecpar;
switch (codecParams->codec_type)
{
case AVMEDIA_TYPE_AUDIO:
if (m_data->audioStreamID == -1 && EnableAudio)
m_data->audioStreamID = i;
break;
default:
break;
}
}
if (HasAudio())
{
const AVCodec* codec = avcodec_find_decoder(m_data->formatContext->streams[m_data->audioStreamID]->codecpar->codec_id);
std::cout << m_data->formatContext->streams[m_data->audioStreamID]->codecpar->codec_id<< std::endl;
m_data->audioContext = avcodec_alloc_context3(codec);
if (!m_data->audioContext)
{
std::cout << "Motion: Failed to get audio codec context" << std::endl;
m_data->audioStreamID = -1;
}
else
{
m_data->audioCodec = codec;
if (!m_data->audioCodec)
{
std::cout << "Motion: Failed to find audio codec" << std::endl;
m_data->audioStreamID = -1;
}
else
{
if (avcodec_open2(m_data->audioContext, m_data->audioCodec, nullptr) != 0)
{
std::cout << "Motion: Failed to load audio codec" << std::endl;
m_data->audioStreamID = -1;
}
else
{
m_data->audioRawBuffer = av_frame_alloc();
if (!m_data->audioRawBuffer)
{
std::cout << "Motion: Failed to allocate audio buffer" << std::endl;
m_data->audioStreamID = -1;
}
else
{
int buffer_size = av_samples_get_buffer_size(nullptr, m_data->audioContext->channels, MAX_AUDIO_SAMPLES, AV_SAMPLE_FMT_S16, 0);
if (buffer_size < 0) {
char err_buf[AV_ERROR_MAX_STRING_SIZE];
av_strerror(buffer_size, err_buf, sizeof(err_buf));
std::cerr << "Motion: Failed to calculating buffer size: " << err_buf << std::endl;
m_data->audioStreamID = -1;
}
else if (av_samples_alloc(&m_data->audioPCMBuffer, nullptr, m_data->audioContext->channels, av_samples_get_buffer_size(nullptr, m_data->audioContext->channels, MAX_AUDIO_SAMPLES, AV_SAMPLE_FMT_S16, 0), AV_SAMPLE_FMT_S16, 0) < 0)
{
std::cout << "Motion: Failed to create audio samples buffer" << std::endl;
m_data->audioStreamID = -1;
}
else
{
av_frame_unref(m_data->audioRawBuffer);
uint64_t inchanlayout = m_data->audioContext->channel_layout;
uint64_t outchanlayout = inchanlayout;
if (inchanlayout == 0)
inchanlayout = av_get_default_channel_layout(m_data->audioContext->channels);
if (outchanlayout != AV_CH_LAYOUT_MONO)
outchanlayout = AV_CH_LAYOUT_STEREO;
m_data->audioSWContext = swr_alloc();
std::cout << m_data->audioContext->sample_rate << std::endl;
std::cout << m_data->audioContext->sample_fmt << std::endl;
av_opt_set_int(m_data->audioSWContext, "in_channel_layout", inchanlayout, 0);
av_opt_set_int(m_data->audioSWContext, "out_channel_layout", outchanlayout, 0);
av_opt_set_int(m_data->audioSWContext, "in_sample_rate", m_data->audioContext->sample_rate, 0);
av_opt_set_int(m_data->audioSWContext, "out_sample_rate", m_data->audioContext->sample_rate, 0);
av_opt_set_sample_fmt(m_data->audioSWContext, "in_sample_fmt", m_data->audioContext->sample_fmt, 0);
av_opt_set_sample_fmt(m_data->audioSWContext, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0);
swr_init(m_data->audioSWContext);
m_audioChannelCount = av_get_channel_layout_nb_channels(outchanlayout);
}
}
}
}
}
}
The console displays the error "Motion: Failed to calculating buffer size: Invalid argument". This error occurs because avcodec_alloc_context 3(codec)->channels == 0, but this should not be the case.The video file must have a second audio channel
Take a look at the description of the function avcodec_alloc_context3. This function just allocates context and sets its fields to default values. After allocating and before avcodec_open2 you need to copy stream codec parameters using avcodec_parameters_to_context function, or set parameters manually.