Меня смутил результат передискретизации в новом ffmpeg. Я декодирую аудио AAC в PCM, ffmpeg показывает аудиоинформацию как:
Stream #0:0: Audio: aac, 44100 Hz, stereo, fltp, 122 kb/s
В новом ffmpeg выходные образцы имеют формат fltp, поэтому мне нужно преобразовать его из AV_SAMPLE_FMT_FLTP в AV_SAMPLE_FMT_S16
PS: в старом ffmpeg как libavcodec 54.12.100 это напрямую S16, поэтому не требуется передискретизация и никаких проблем с качеством звука.
Затем я попробовал три способа передискретизации:
используя swr_convert
используя avresample_convert
конвертировать вручную
Но все они дают один и тот же результат, качество звука очень плохое, очень медленное и расстроенное, с небольшим шумом.
Мой код передискретизации выглядит следующим образом:
void resampling(AVFrame* frame_, AVCodecContext* pCodecCtx, int64_t want_sample_rate, uint8_t* outbuf){
SwrContext *swrCtx_ = 0;
AVAudioResampleContext *avr = 0;
// Initializing the sample rate convert. We only really use it to convert float output into int.
int64_t wanted_channel_layout = AV_CH_LAYOUT_STEREO;
#ifdef AV_SAMPLEING
avr = avresample_alloc_context();
av_opt_set_int(avr, "in_channel_layout", frame_->channel_layout, 0);
av_opt_set_int(avr, "out_channel_layout", wanted_channel_layout, 0);
av_opt_set_int(avr, "in_sample_rate", frame_->sample_rate, 0);
av_opt_set_int(avr, "out_sample_rate", 44100, 0);
av_opt_set_int(avr, "in_sample_fmt", pCodecCtx->sample_fmt, 0); //AV_SAMPLE_FMT_FLTP
av_opt_set_int(avr, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0);
av_opt_set_int(avr, "internal_sample_fmt", pCodecCtx->sample_fmt, 0);
avresample_open(avr);
avresample_convert(avr, &outbuf, frame_->linesize[0], frame_->nb_samples, frame_->extended_data, frame_->linesize[0], frame_->nb_samples);
avresample_close(avr);
return;
#endif
#ifdef USER_SAMPLEING
if (pCodecCtx->sample_fmt == AV_SAMPLE_FMT_FLTP)
{
int nb_samples = frame_->nb_samples;
int channels = frame_->channels;
int outputBufferLen = nb_samples & channels * 2;
auto outputBuffer = (int16_t*)outbuf;
for (int i = 0; i < nb_samples; i++)
{
for (int c = 0; c < channels; c++)
{
float* extended_data = (float*)frame_->extended_data[c];
float sample = extended_data[i];
if (sample < -1.0f) sample = -1.0f;
else if (sample > 1.0f) sample = 1.0f;
outputBuffer[i * channels + c] = (int16_t)round(sample * 32767.0f);
}
}
return;
}
#endif
swrCtx_ = swr_alloc_set_opts(
NULL, //swrCtx_,
wanted_channel_layout,
AV_SAMPLE_FMT_S16,
want_sample_rate,
pCodecCtx->channel_layout,
pCodecCtx->sample_fmt,
pCodecCtx->sample_rate,
0,
NULL);
if (!swrCtx_ || swr_init(swrCtx_) < 0) {
printf("swr_init: Failed to initialize the resampling context");
return;
}
// convert audio to AV_SAMPLE_FMT_S16
int swrRet = swr_convert(swrCtx_, &outbuf, frame_->nb_samples, (const uint8_t **)frame_->extended_data, frame_->nb_samples);
if (swrRet < 0) {
printf("swr_convert: Error while converting %d", swrRet);
return;
}
}
Что делать?
PS1: играть с ffplay - это нормально.
PS2: сохраните ресэмпл S16 PCM в файл, и при его воспроизведении будет такая же проблема с качеством звука.
Большое спасибо за вашу помощь и предложения!
Я также заметил, что в старом ffmpeg aac распознается как формат FLT и напрямую декодируется в 16-битный PCM, в то время как в новом ffmpeg aac считается форматом FLTP и выдает 32-битный вывод с плавающей запятой IEEE.
Таким образом, один и тот же код будет давать совершенно разные результаты с разными версиями ffmpeg. Затем, я хотел бы спросить, как правильно преобразовать аудио AAC в 16-битный PCM в новой версии?
Заранее большое спасибо!
s16le
и выходной аудиокодекpcm_s16le
. - person Brad   schedule 03.04.2014