libswresample: swr_convert() не производит достаточного количества образцов

Я пытаюсь использовать ffmpeg/libswresample для передискретизации потокового аудио в моем приложении С++. Изменение ширины семпла работает хорошо, и результат звучит так, как и следовало ожидать; однако при изменении частоты дискретизации результат несколько трескается. Я не уверен, связано ли это с неправильным использованием библиотеки libswresample или я неправильно понимаю теорию повторной выборки.

Вот мой процесс повторной выборки, упрощенный для демонстрации:

//Externally supplied data
const uint8_t* in_samples //contains the audio data to be resampled
int in_num_samples = 256

//Set up resampling context
SwrContext *swr = swr_alloc();
av_opt_set_channel_layout(swr, "in_channel_layout", AV_CH_LAYOUT_STEREO, 0);
av_opt_set_channel_layout(swr, "out_channel_layout", AV_CH_LAYOUT_STEREO, 0);
av_opt_set_int(swr, "in_sample_rate", 44100, 0);
av_opt_set_int(swr, "out_sample_rate", 22050, 0);
av_opt_set_sample_fmt(swr, "in_sample_fmt", AV_SAMPLE_FMT_FLT, 0);
av_opt_set_sample_fmt(swr, "out_sample_fmt", AV_SAMPLE_FMT_FLT, 0);
swr_init(swr);

//Perform the resampe
uint8_t* out_samples;
int out_num_samples = av_rescale_rnd(swr_get_delay(swr, in_samplerate) + in_num_samples, out_samplerate, in_samplerate, AV_ROUND_UP);
av_samples_alloc(&out_samples, NULL, out_num_channels, out_num_samples, AV_SAMPLE_FMT_FLT, 0);
out_num_samples = swr_convert(swr, &out_samples, out_num_samples, &in_samples, in_num_samples);
av_freep(&out_samples);
swr_free(&swr);

Я подозреваю, что причина того, что звук передискретизированного звука звучит неправильно, заключается в том, что swr_convert() возвращает 112, тогда как я ожидаю, что он вернет 128 (количество выборок звука передискретизации): дают 128 образцов, а swr_convert() производит 112 образцов. Когда это выражается в терминах продолжительности звука, это также вызывает недоумение. 256 выборок на 44 100 = 5,8 мс, но 112 выборок на 22 050 = 5,07 мс. Разве процесс понижения частоты дискретизации не должен изменять продолжительность передискретизированного звука?

Я также рассмотрел пример с ffmpeg, в котором swr_convert() также возвращает меньшее число, чем я ожидал. Итак, я подозреваю, что проблема связана не с ошибкой в ​​libswresample, а скорее с моим собственным непониманием.


person Tsherr    schedule 20.09.2016    source источник
comment
Попробуйте это с массивом out_samples большего размера, я подозреваю, что что-то не так с вашим расчетом.   -  person Steve M    schedule 20.09.2016


Ответы (1)


Причина, по которой количество выборок уменьшается, заключается в том, что повторная выборка фильтрует несколько смежных во времени выборок. Представьте, что мы передискретизируем с использованием фильтра с 32 отводами, образец 127 требует ввода от 127-16 до 127+16 (или сопоставимые позиции, скорректированные для корректировки частоты дискретизации). Поскольку у вас есть только 128 входных сэмплов, вы можете вывести только до 112 в этом примере. Остальное сохраняется во внутренней очереди до тех пор, пока не будет доступен следующий ввод.

Чтобы получить окончательные (завершающие) выборки (когда ввод завершен), введите NULL в качестве ввода, что очистит внутреннюю очередь.

person Ronald S. Bultje    schedule 20.09.2016
comment
Это помогло, спасибо за оперативный ответ! Таким образом, при использовании в контексте реального времени при следующем вызове swr_convert() его входные образцы должны начинаться с нескольких последних, которые были пропущены в предыдущем вызове. Это правильно? - person Tsherr; 21.09.2016
comment
Нет, swr_convert() кэширует входные образцы для вас. Просто не ожидайте, что все сэмплы будут отправлены одновременно с их вводом, то есть ожидайте, что swr_convert() внесет небольшую задержку. - person Ronald S. Bultje; 21.09.2016
comment
Ясно, теперь имеет смысл. Спасибо еще раз! - person Tsherr; 28.09.2016