Я записываю звук и кодирую в mp3 с помощью ffmpeg lib. затем сразу же декодируйте данные в формате mp3, воспроизводите данные декодирования, но они звучат с такой задержкой.
вот коды:
первый параметр функции encode принимает необработанные данные pcm, len = 44100.
закодировать параметры:
cntx_->channels = 1;
cntx_->sample_rate = 44100;
cntx_->sample_fmt = 6;
cntx_->channel_layout = AV_CH_LAYOUT_MONO;
cntx_->bit_rate = 8000;
err_ = avcodec_open2(cntx_, codec_, NULL);
vector<unsigned char> encode(unsigned char* encode_data, unsigned int len)
{
vector<unsigned char> ret;
AVPacket avpkt;
av_init_packet(&avpkt);
unsigned int len_encoded = 0;
int data_left = len / 2;
int miss_c = 0, i = 0;
while (data_left > 0)
{
int sz = data_left > cntx_->frame_size ? cntx_->frame_size : data_left;
mp3_frame_->nb_samples = sz;
mp3_frame_->format = cntx_->sample_fmt;
mp3_frame_->channel_layout = cntx_->channel_layout;
int needed_size = av_samples_get_buffer_size(NULL, 1,
mp3_frame_->nb_samples, cntx_->sample_fmt, 1);
int r = avcodec_fill_audio_frame(mp3_frame_, 1, cntx_->sample_fmt, encode_data + len_encoded, needed_size, 0);
int gotted = -1;
r = avcodec_encode_audio2(cntx_, &avpkt, mp3_frame_, &gotted);
if (gotted){
i++;
ret.insert(ret.end(), avpkt.data, avpkt.data + avpkt.size);
}
else if (gotted == 0){
miss_c++;
}
len_encoded += needed_size;
data_left -= sz;
av_free_packet(&avpkt);
}
return ret;
}
std::vector<unsigned char> decode(unsigned char* data, unsigned int len)
{
std::vector<unsigned char> ret;
AVPacket avpkt;
av_init_packet(&avpkt);
avpkt.data = data;
avpkt.size = len;
AVFrame* pframe = av_frame_alloc();
while (avpkt.size > 0){
int goted = -1;av_frame_unref(pframe);
int used = avcodec_decode_audio4(cntx_, pframe, &goted, &avpkt);
if (goted){
ret.insert(ret.end(), pframe->data[0], pframe->data[0] + pframe->linesize[0]);
avpkt.data += used;
avpkt.size -= used;
avpkt.dts = avpkt.pts = AV_NOPTS_VALUE;
}
else if (goted == 0){
avpkt.data += used;
avpkt.size -= used;
avpkt.dts = avpkt.pts = AV_NOPTS_VALUE;
}
else if(goted < 0){
break;
}
}
av_frame_free(&pframe);
return ret;
}
Предположим, что это 100-й вызов для кодирования (data, len), этот «кадр» появится в 150-м или позже при вызове декодирования, задержка не является приемлемой. Кажется, кодировщик mp3lame сохранит образцы данных для последующего использования, но это не мое желание.
Я не знаю, что происходит не так. Спасибо за любую информацию.
сегодня я снова отлаживаю код и публикую некоторые детали:
кодировать: каждый кадр сэмпла pcm len = 23040, что в 10 раз превышает размер фрейма mp3, каждый раз, когда вызов кодирует только выходные 9 кадров, этот выход вызывает декодирование, выводит 20736 сэмплов, 1 кадр (2304 байта) теряется, и звук шумит ,
если кодирование mp3 или mp2 не подходит для передачи голоса в реальном времени, какой кодер выбрать?
Предположим, что это 100-й вызов для кодирования (data, len), этот «кадр» появится в 150-м или позже при вызове декодирования, задержка не является приемлемой.
Понять, как работает кодек, и соответственно скорректировать свои ожидания.
MP3 — это кодек с потерями. Он работает путем преобразования данных PCM вашей временной области в частотную область. Это преобразование само по себе требует времени (потому что частотные компоненты не существуют в любой момент времени … они могут существовать только в течение определенного периода времени). На простом уровне он затем использует несколько алгоритмов, чтобы определить, какую спектральную информацию сохранить, а что выбросить. Каждый фрейм MP3 имеет сотни сэмплов, длительный. (576 ниже обычного. Дважды это типичное число.)
Теперь, когда у вас есть минимальное время для создания кадров, MP3 также использует так называемый битовый резервуар. Если сложный проход требует большей пропускной способности, он занимает неиспользуемую пропускную способность у соседних кадров. Чтобы облегчить это, требуется буфер из многих кадров.
Помимо всей работы кодека, FFmpeg имеет буферизацию (для обнаружения ввода, а что нет), и в ваших каналах есть буферы к FFmpeg и от него. Я полагаю, что сам кодек может также использовать общую буферизацию на входе и выходе.
Наконец, вы декодируете поток и воспроизводите его, что означает, что большинство из тех же типов буферов, которые используются при кодировании, теперь используются для декодирования. И мы даже не говорим о задержке в несколько сотен миллисекунд, которая у вас есть для передачи аудиоданных через звуковую карту и выхода из аналогового динамика.
Вы ожидаете нереалистичных ожиданий, и хотя есть возможность настроить некоторые параметры для уменьшения задержки (например, отключение резервуара битов), это приведет к низкокачественному потоку и в любом случае не будет иметь низкую задержку.
Других решений пока нет …