Кодирование AAC с помощью ffmpeg (c ++)

Я работаю над кодированием видео, которое будет использоваться в плагине Unity. Я сделал кодировку изображений, но теперь я в аудио. Таким образом, пытаясь только с аудио в файл mp4 с кодировкой AAC. И я застрял. Полученный файл не содержит ничего. Кроме того, насколько я понимаю, AAC в ffmpeg поддерживает только AV_SAMPLE_FMT_FLTP, поэтому я использую его. Вот мой код:

Настроить:

int initialize_encoding_audio(const char *filename)
{
int ret;
AVCodecID aud_codec_id = AV_CODEC_ID_AAC;
AVSampleFormat sample_fmt = AV_SAMPLE_FMT_FLTP;

avcodec_register_all();
av_register_all();

aud_codec = avcodec_find_encoder(aud_codec_id);
avcodec_register(aud_codec);

if (!aud_codec)
return COULD_NOT_FIND_AUD_CODEC;

aud_codec_context = avcodec_alloc_context3(aud_codec);
if (!aud_codec_context)
return CONTEXT_CREATION_ERROR;

aud_codec_context->bit_rate = 192000;
aud_codec_context->sample_rate = select_sample_rate(aud_codec);
aud_codec_context->sample_fmt = sample_fmt;
aud_codec_context->channel_layout = AV_CH_LAYOUT_STEREO;
aud_codec_context->channels = av_get_channel_layout_nb_channels(aud_codec_context->channel_layout);

aud_codec_context->codec = aud_codec;
aud_codec_context->codec_id = aud_codec_id;

ret = avcodec_open2(aud_codec_context, aud_codec, NULL);

if (ret < 0)
return COULD_NOT_OPEN_AUD_CODEC;

outctx = avformat_alloc_context();
ret = avformat_alloc_output_context2(&outctx, NULL, "mp4", filename);

outctx->audio_codec = aud_codec;
outctx->audio_codec_id = aud_codec_id;

audio_st = avformat_new_stream(outctx, aud_codec);

audio_st->codecpar->bit_rate = aud_codec_context->bit_rate;
audio_st->codecpar->sample_rate = aud_codec_context->sample_rate;
audio_st->codecpar->channels = aud_codec_context->channels;
audio_st->codecpar->channel_layout = aud_codec_context->channel_layout;
audio_st->codecpar->codec_id = aud_codec_id;
audio_st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
audio_st->codecpar->format = sample_fmt;
audio_st->codecpar->frame_size = aud_codec_context->frame_size;
audio_st->codecpar->block_align = aud_codec_context->block_align;
audio_st->codecpar->initial_padding = aud_codec_context->initial_padding;

outctx->streams = new AVStream*[1];
outctx->streams[0] = audio_st;

av_dump_format(outctx, 0, filename, 1);

if (!(outctx->oformat->flags & AVFMT_NOFILE))
{
if (avio_open(&outctx->pb, filename, AVIO_FLAG_WRITE) < 0)
return COULD_NOT_OPEN_FILE;
}

ret = avformat_write_header(outctx, NULL);

aud_frame = av_frame_alloc();
aud_frame->nb_samples = aud_codec_context->frame_size;
aud_frame->format = aud_codec_context->sample_fmt;
aud_frame->channel_layout = aud_codec_context->channel_layout;

int buffer_size = av_samples_get_buffer_size(NULL, aud_codec_context->channels, aud_codec_context->frame_size,
aud_codec_context->sample_fmt, 0);

av_frame_get_buffer(aud_frame, buffer_size / aud_codec_context->channels);

if (!aud_frame)
return COULD_NOT_ALLOCATE_FRAME;

aud_frame_counter = 0;

return 0;
}

Кодирование:

int encode_audio_samples(uint8_t **aud_samples)
{
int ret;

int buffer_size = av_samples_get_buffer_size(NULL, aud_codec_context->channels, aud_codec_context->frame_size,
aud_codec_context->sample_fmt, 0);

for (size_t i = 0; i < buffer_size / aud_codec_context->channels; i++)
{
aud_frame->data[0][i] = aud_samples[0][i];
aud_frame->data[1][i] = aud_samples[1][i];
}

aud_frame->pts = aud_frame_counter++;

ret = avcodec_send_frame(aud_codec_context, aud_frame);
if (ret < 0)
return ERROR_ENCODING_SAMPLES_SEND;

AVPacket pkt;
av_init_packet(&pkt);
pkt.data = NULL;
pkt.size = 0;

fflush(stdout);

while (true)
{
ret = avcodec_receive_packet(aud_codec_context, &pkt);
if (!ret)
{
av_packet_rescale_ts(&pkt, aud_codec_context->time_base, audio_st->time_base);

pkt.stream_index = audio_st->index;
av_write_frame(outctx, &pkt);
av_packet_unref(&pkt);
}
if (ret == AVERROR(EAGAIN))
break;
else if (ret < 0)
return ERROR_ENCODING_SAMPLES_RECEIVE;
else
break;
}

return 0;
}

Завершить кодирование:

int finish_audio_encoding()
{
AVPacket pkt;
av_init_packet(&pkt);
pkt.data = NULL;
pkt.size = 0;

fflush(stdout);

int ret = avcodec_send_frame(aud_codec_context, NULL);
if (ret < 0)
return ERROR_ENCODING_FRAME_SEND;

while (true)
{
ret = avcodec_receive_packet(aud_codec_context, &pkt);
if (!ret)
{
if (pkt.pts != AV_NOPTS_VALUE)
pkt.pts = av_rescale_q(pkt.pts, aud_codec_context->time_base, audio_st->time_base);
if (pkt.dts != AV_NOPTS_VALUE)
pkt.dts = av_rescale_q(pkt.dts, aud_codec_context->time_base, audio_st->time_base);

av_write_frame(outctx, &pkt);
av_packet_unref(&pkt);
}
if (ret == -AVERROR(AVERROR_EOF))
break;
else if (ret < 0)
return ERROR_ENCODING_FRAME_RECEIVE;
}

av_write_trailer(outctx);
}

Главный:

void get_audio_frame(float_t *left_samples, float_t *right_samples, int frame_size, float* t, float* tincr, float* tincr2)
{
int j, i;
float v;
for (j = 0; j < frame_size; j++)
{
v = sin(*t);
*left_samples = v;
*right_samples = v;

left_samples++;
right_samples++;

*t += *tincr;
*tincr += *tincr2;
}
}

int main()
{
int frame_rate = 30;  // this should be like 96000 / 1024 or somthing i guess?
float t, tincr, tincr2;

initialize_encoding_audio("audio.mp4");

int sec = 50;

float_t** aud_samples;
int src_samples_linesize;
int src_nb_samples = 1024;
int src_channels = 2;

int ret = av_samples_alloc_array_and_samples((uint8_t***)&aud_samples, &src_samples_linesize, src_channels,
src_nb_samples, AV_SAMPLE_FMT_FLTP, 0);t = 0;
tincr = 0;
tincr2 = 0;

for (size_t i = 0; i < frame_rate * sec; i++)
{
get_audio_frame(aud_samples[0], aud_samples[1], src_nb_samples, &t, &tincr, &tincr2);

encode_audio_samples((uint8_t **)aud_samples);

}

finish_audio_encoding();
//cleanup();

return 0;
}

Я думаю, первое, что я хотел бы убедиться в том, что я правильно понял, — это синтезированное звучание и как я перенесу его в AVFrame. Верны ли мои конверсии? Но не стесняйтесь указывать на все, что может быть неправильно.

Заранее спасибо!

Редактировать: весь источник: http://pastebin.com/jYtmkhek

Edit2: добавлена ​​инициализация tincr & tincr2

7

Решение

Если я не пропустил что-то из пастбина, вы забыли инициализировать несколько переменных. Вы используете мусор для генерации ваших образцов.

float t, tincr, tincr2;
[...]
get_audio_frame(aud_samples[0], aud_samples[1], src_nb_samples, &t, &tincr, &tincr2);

Вы, вероятно, хотите начать с t=0 и увеличить на 2 * PI * frequency / sample rate для синусоиды.

Также, avformat_new_stream() создает поток для вас, не делайте этого с new,

Обновить:

Я удалил все c++ вещи, чтобы проверить это. Вот код, который работает: Pastebin

И вот результирующий файл: audio.mp4

ffmpeg -i audio.mp4 -filter_complex "showwaves=s=640x120:mode=line:colors=white" -frames:v 1 wave.jpg

введите описание изображения здесь

Diff:

1,6d0
< #include "encoder.h"< #include <algorithm>
< #include <iterator>
<
< extern "C"< {
14a9
> #include <math.h>
40,41c35,36
<   SwsContext *sws_ctx;
<   SwrContext *swr_ctx = NULL;
---
> struct SwsContext *sws_ctx;
> struct SwrContext *swr_ctx = NULL;
76,77c71,72
<       AVCodecID aud_codec_id = AV_CODEC_ID_AAC;
<       AVSampleFormat sample_fmt = AV_SAMPLE_FMT_FLTP;
---
>   enum AVCodecID aud_codec_id = AV_CODEC_ID_AAC;
>   enum AVSampleFormat sample_fmt = AV_SAMPLE_FMT_FLTP;
125,126c120,121
<       outctx->streams = new AVStream*[1];
<       outctx->streams[0] = audio_st;
---
>   //outctx->streams = new AVStream*[1];
>   //outctx->streams[0] = audio_st;
182c177
<       while (true)
---
>   while (1)
216c211
<       while (true)
---
>   while (1)
291c286
<       float t, tincr, tincr2;
---
>   float t = 0, tincr = 2 * M_PI * 440.0 / 96000, tincr2 = 0;
317d311
<   }
2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]