ffmpeg конвертирует AV_SAMPLE_FMT_S16 в AV_SAMPLE_FMT_FLTP в c ++ - PullRequest
2 голосов
/ 07 апреля 2020

Я хочу кодировать и декодировать звук из моего приложения Android в формат Opus с помощью FFmpeg 4.2.2.

Проблема заключается в том, что мое приложение Android обеспечивает необработанный звук PCM в AV_SAMPLE_FMT_S16 формат, но кодер FFmpeg opus требует только AV_SAMPLE_FMT_FLTP. Итак, я решил пересчитать звук с помощью функции FFmpeg swr_convert(), но он вылетает с ошибкой SIGSEGV, и я не могу понять, почему.

Мой код выглядит так:

swrContext = swr_alloc();

av_opt_set_int(swrContext, "in_channel_layout", (int64_t) codecContext->channel_layouts, 0);
av_opt_set_int(swrContext, "out_channel_layout", (int64_t) codecContext->channel_layouts,  0);
av_opt_set_int(swrContext, "in_sample_rate", 8000, 0);
av_opt_set_int(swrContext, "out_sample_rate", 48000, 0);

av_opt_set_sample_fmt(swrContext, "in_sample_fmt", AV_SAMPLE_FMT_S16, 0);
av_opt_set_sample_fmt(swrContext, "out_sample_fmt", AV_SAMPLE_FMT_FLTP,  0);

swr_init(swrContext);

memcpy(frame->data[0], data, dataSize); 

uint8_t *outBuffer = (uint8_t *) malloc(sizeof(uint8_t) * frame->nb_samples);

swr_convert(swrContext, &outBuffer, frame->nb_samples, (const uint8_t **)frame->data, frame->nb_samples);

Я новичок в C ++, поэтому извините за некоторые ошибки, если я их сделал.

1 Ответ

1 голос
/ 12 апреля 2020

Вот несколько вещей, о которых вам нужно позаботиться:

Убедитесь, что frame->data[0] содержит достаточно памяти (по крайней мере, равно dataSize) для копирования data из в этом вызове:

memcpy( frame->data[0], data, dataSize );

Также вам необходимо установить frame->nb_samples соответственно. Возможно, у вас уже есть, но в коде, который вы опубликовали, нет никаких указаний.

Вам также нужно выделить буфер сэмплов, используя av_samples_alloc, и освободить его, включая всю остальную выделенную память после использования, чтобы победить ' Не должно быть утечек памяти.

Вот пример (добавьте значение для out_num_channels):

const int in_sample_rate = 8000;
const int out_sample_rate = 48000;

swrContext = swr_alloc();
av_opt_set_int(swrContext, "in_channel_layout", (int64_t) codecContext->channel_layouts, 0);
av_opt_set_int(swrContext, "out_channel_layout", (int64_t) codecContext->channel_layouts,  0);
av_opt_set_int(swrContext, "in_sample_rate", in_sample_rate, 0);
av_opt_set_int(swrContext, "out_sample_rate", out_sample_rate, 0);
av_opt_set_sample_fmt(swrContext, "in_sample_fmt", AV_SAMPLE_FMT_S16, 0);
av_opt_set_sample_fmt(swrContext, "out_sample_fmt", AV_SAMPLE_FMT_FLTP,  0);
swr_init(swrContext);

memcpy(frame->data[0], data, dataSize); // frame->nb_samples ???

const int out_num_samples = av_rescale_rnd(swr_get_delay(swrContext, in_sample_rate) + frame->nb_samples, out_sample_rate, in_sample_rate, AV_ROUND_UP);

uint8_t* out_samples = NULL;
av_samples_alloc(&out_samples, NULL, out_num_channels, out_num_samples, AV_SAMPLE_FMT_FLTP, 0);

out_num_samples = swr_convert(swrContext, &out_samples, out_num_samples, &frame->data[0], frame->nb_samples);

av_freep(&out_samples);    // free after use
swr_free(&swrContext);     // free after use

Возможно, вы захотите повозиться out_sample_rate в соответствии с вашими требованиями. Я бы предложил преобразовать ваш файл в командной строке с помощью команды ffmpeg и использовать параметры, которые работали в вашем коде позже. Итерации кода будут меньше, и вы будете более гибко работать с командной строкой. См. this и this thread при использовании утилиты командной строки ffmpeg.

Надеюсь, это поможет!

...