AAC 编码






3.80/5 (9投票s)
使用 ffmmpeg 库将原始音频数据编码为 AAC 压缩格式。
引言
本文是音频捕获、编码和流媒体的第二篇文章。 它描述了如何将捕获的 PCM 数据编码为 AAC 编码并写入音频文件。
背景。
适用于对音频相关应用感兴趣的软件开发人员。 特别适合有兴趣使用 Windows 平台上的 FFMPEG 库将音频文件编码和解码为 AAC 编码的音频软件开发人员。 不需要了解 AAC 编码和解码的细节,除非有人想手动解码捕获的数据。
整个应用程序是用 "C" 语言编写的,由简单的函数、简单的端口音频库和 ffmpeg 库调用组成。 它大量使用 ffmpeg 库调用,最好具备一些 ffmpeg 知识。
Port-Audio
Port-Audio 是一个免费的、跨平台的、开源的音频 I/O 库。 它允许您用 'C' 或 C++ 编写简单的音频程序,这些程序可以在包括 Windows、Macintosh OS X 和 Unix (OSS/ALSA) 在内的许多平台上编译和运行。 它的目的是促进不同平台上的开发人员之间交换音频软件。 Port Audio 软件有很多有用的例子。
官方网站 http://www.portaudio.com。
FFMPEG
ffmpeg 是一个非常快速的视频和音频转换器,也可以从实时音频/视频源抓取。 它还可以使用高质量的多相滤波器在任意采样率之间转换,并动态调整视频大小。
ffmpeg 从任意数量的输入 "文件"(可以是常规文件、管道、网络流、抓取设备等)读取数据,这些文件由 -i
选项指定,并写入任意数量的输出 "文件",这些文件由一个纯输出文件名指定。 在命令行上找到的任何不能被解释为选项的东西都被认为是输出文件名。
官方 ffmpeg 网站 https://ffmpeg.net.cn/
AAC 音频编码数据流图。
数据流图如下
软件详情
有关端口音频调用的更多详细信息,请参阅端口音频文档,有关 AMR 窄带的信息,请参阅 opencor-amr 文档。
步骤1:初始化端口音频并注册记录回调函数。
初始化端口音频,并使用记录回调函数打开端口音频流,配置如下:8000 采样率,16 位有符号 PCM 数据,帧大小为 80 个样本,意味着一个帧中有 10 毫秒的音频数据。 启动流后,每 10 毫秒调用一次记录回调,并带有一个音频数据帧。
static PaError
yakAudioStreamOpen(paTestData *yakData)
static PaError yakAudioStreamOpen(paTestData *yakData)
{
PaStreamParametersinputParameters;
PaStream*stream;
PaErrorerr = paNoError;
// register signal SIGINT and signal handler
signal(SIGINT, signalHandler);
err = Pa_Initialize();
if( err != paNoError ) goto done;
inputParameters.device = Pa_GetDefaultInputDevice(); /* default input device */
if (inputParameters.device == paNoDevice) {
fprintf(stderr,"Error: No default input device.\n");
goto done;
}
inputParameters.channelCount = NUM_CHANNELS;/* stereo input */
inputParameters.sampleFormat = PA_SAMPLE_TYPE;
inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultLowInputLatency;
inputParameters.hostApiSpecificStreamInfo = NULL;
/* Record some audio. -------------------------------------------- */
err = Pa_OpenStream(
&stream,
&inputParameters,
NULL,/* &outputParameters, */
SAMPLE_RATE,
SAMPLES_PER_FRAME,
paClipOff,/* we won't output out of range samples so don't bother clipping them */
yakAudioRecordCallback,
yakData );
if( err != paNoError ) goto done;
yakData->recordStream = stream;
return paNoError;
done:
Pa_Terminate();
if( err != paNoError )
{
fprintf( stderr, "An error occured while using the portaudio stream\n" );
fprintf( stderr, "Error number: %d\n", err );
fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
err = 1;/* Always return 0 or 1, but no other return codes. */
}
return err;
}
步骤 2:初始化 FFMPEG 库。
使用正确的配置参数初始化 opencore-amr 库,以匹配端口音频捕获配置。
代码片段如下
AVCodecContext*audioCodec;
AVCodec *codec;
avcodec_register_all();
//Set up audio encoder
codec = avcodec_find_encoder(CODEC_ID_AAC);
if (codec == NULL)
{
printf("avcodec_find_encoder: ERROR\n");
return NULL;
}
audioCodec = avcodec_alloc_context();
audioCodec->bit_rate = audioBitrate;
audioCodec->sample_fmt = SAMPLE_FMT_S16;
audioCodec->sample_rate = sampleRate;
audioCodec->channels = channels;
audioCodec->profile = FF_PROFILE_AAC_MAIN;
//audioCodec->time_base = (AVRational){1, sampleRate};
audioCodec->time_base.num= 1;
audioCodec->time_base.den= sampleRate;
audioCodec->codec_type = AVMEDIA_TYPE_AUDIO;
if (avcodec_open(audioCodec, codec) < 0)
{
printf("avcodec_open: ERROR\n");
return NULL;
}
return audioCodec;
}
步骤 3:编码原始音频帧。
当调用 port-audio 记录回调时,原始音频数据存储在输入缓冲区中,将缓冲区和长度传递给 amr 编码器,amr 编码器返回编码后的数据。
static void yakAudioEncode(paTestData *yakData, uint8_t *rawData, int rawDataSize)
{
int frameBytes;
frameBytes = yakData->c->frame_size * yakData->c->channels * sizeof(SAMPLE);
// Note: revisit the while loop
// BUG-1
while (rawDataSize >= frameBytes)
{
int packetSize;
packetSize = avcodec_encode_audio(yakData->c, yakData->encoderOutput,
yakData->allocOutputSize, (short *)rawData);
//printf("EncodePaData (%d-%d-%d)\n",packetSize,audioSize,frameBytes);
yakData->encoderOutputSize+= packetSize;
rawData += frameBytes;
rawDataSize -= frameBytes;
}
}
步骤 4:写入文件。
static void EncodePaData(paTestData *yakData, uint8_t *rawData, int rawDataSize)
{
yakAudioEncode(yakData, rawData, rawDataSize);
fwrite(yakData->encoderOutput, sizeof(uint8_t), yakData->encoderOutputSize,
yakData->recFileStream);
yakData->encoderOutputSize = 0;
}
步骤 6:关闭 ffmpeg 库
关闭与 ffmpeg AvCodecContext 和 AvCodec 库相关的所有资源。
步骤 7:停止、关闭音频流并关闭端口音频。
static PaError yakCloseAudioStream(paTestData *yakData)
{
return Pa_CloseStream( yakData->recordStream);
}
所需软件
需要以下软件才能执行和收听捕获的音频文件。
VC++,portaudio 库/dll,ffmpeg 库/dll 和 ant AAC 音频播放器 (VLC)。
注意
运行此应用程序需要 FFMPEG 开发版本软件。 请下载 ffmpeg 开发版本。 并指定所需的 include 和库路径。