AAC文件格式与解码流程(未完待续)

1 文件格式

1.1 概述及分类

AAC“Advanced Audio Coding”的缩写,中文称为“高级音频编码”,被手机界称为“21世纪数据压缩方式”,AAC所采用的运算方式是与MP3的运算有所不同,AAC同时可以支持多达48个音轨,15个低频音轨,更多种取样率和比特率与及有多种言语的兼容能力,更高的译码效率,总括来说,AAC可以在对比MP3文件缩小30%的前题下提供更好的音质。

AAC帧与帧之间编码完全独立,所以其广泛运用于流媒体。

由于对AAC有重要贡献的公司比较多,如Fraunhofer,Dolby, Sony和AT&T,导致AAC子格式多,很容易搞混。他们是共分为9种规格,以适应不同场合的需要:

a) MPEG-2 AAC LC 低复杂度规格 (Low Complexity)

b) MPEG-2 AAC Main 主规格

c) MPEG-2 AAC SSR 可变取样率规格 (Scaleable Sample Rate)

d) MPEG-4 AAC LC 低复杂度规格(Low Complexity),现在的手机比较常见的MP4文件中的音频部份就包括了该规格音频文件

e) MPEG-4 AAC Main 主规格

f) MPEG-4 AAC SSR 可变取样率规格 (Scaleable Sample Rate)

g) MPEG-4 AAC LTP 长时期预测规格(Long Term Predicition)

h) MPEG-4 AAC LD 低延迟规格(Low Delay)

i) MPEG-4 AAC HE 高效率规格(High Efficiency)(即AAC+,含SBR)

上述的规格中,主规格“Main”包含了除增益控制之外的全部功能,其音质是最好,而低复杂度规格则是比较简单,没有了增益控制,但提高了编码效率,至“SSR”对“LC”规格大体是相同,但是多了增益的控制功能,另外,MPEG-  4/AAC/LTP/LD/HE,都是用在低码率下编码,特别是“HE”是有Nero ACC编码器支持,是近来多用的一种编码率种,不过通常来说,Main规格和LC规格的音质相差是不大。

以上规格的划分是比较官方的分发,wiki上也是如此划分。事实上MPEG-4与MPEG-2 AAC流除了在文件头(header)上并没有什么区别。只是一些应用软件象QuickTime并不承认MPEG-2 AAC。Real的解码程序中,并未对这2种进行区分。所以从编解码来看,按如下划分更清晰:

a)LC profile:最简单的profile,苹果iTune使用这种格式(iTune也使用Apple LosslessAAC ,不过似乎没有划分到AAC家族中,一个文件通常上20M)。

b) MAIN profile: LC profile + 后向预测(backwards prediction)

c) SRS: sample-rate scalability,submitted by Sony and reportedly

d) LTP:long term prediction, main profile + forward prediction

e)HE-AAC: high efficiency AAC,又叫aacPlus,使用SBR,可能使用PS.AAC + SBR(Spectral Band Replication)aacPlusv1, AAC + SBR + PS(Parametric Stereo)aacPlus v2.  如图所示:

image

其中,aacPlus v1已被运动图像专家组MPEG指定为其标准MPEG-4 HE AAC.

1.2 AAC的编码器

a) FhG Fraunhofer IIS研发的权威编码器,拥有很好的音质,不对外开放。

b) Nero AAC可能是目前最完美的AAC编码器了,同时支持"LC AAC/HE AAC"规格,Nero AAC编码器提供了品质最好的"VBR LC AAC"格式,同时亦对面"HE AAC"规格保证了在低码率下也有良好的表现,千千静听 + Nero插件,就可以编码AAC文件了,我当初就这么做测试向量的,哈哈。

c) QuickTime/iTune Apple公司的两款

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
要在 MFC 框架下读取 AAC 音频文件并进行解码,可以使用开源的解码库如 FFMPEG 或者 OpenAL,这些库都提供了相应的 API 接口,可以在 MFC 中调用。 以下是一个简单的示例代码,使用 FFMPEG 库实现读取 AAC 音频文件并解码: ```c++ #include <iostream> #include <string> #include <vector> #include <fstream> #include <sstream> // FFmpeg 头文件 extern "C" { #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> #include <libswresample/swresample.h> } int main() { const char* input_filename = "test.aac"; // AAC 音频文件路径 const char* output_filename = "output.pcm"; // 输出解码后的 PCM 数据路径 // 1. 初始化 FFmpeg 库 av_register_all(); avcodec_register_all(); // 2. 打开输入音频文件 AVFormatContext* format_ctx = nullptr; if (avformat_open_input(&format_ctx, input_filename, nullptr, nullptr) != 0) { std::cerr << "Error: could not open input file " << input_filename << std::endl; return -1; } // 3. 获取音频流信息 if (avformat_find_stream_info(format_ctx, nullptr) < 0) { std::cerr << "Error: could not find stream information" << std::endl; avformat_close_input(&format_ctx); return -1; } // 4. 查找音频流 int audio_stream_index = -1; for (unsigned int i = 0; i < format_ctx->nb_streams; i++) { if (format_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { audio_stream_index = i; break; } } if (audio_stream_index == -1) { std::cerr << "Error: could not find audio stream" << std::endl; avformat_close_input(&format_ctx); return -1; } // 5. 获取音频解码器 AVCodecParameters* codecpar = format_ctx->streams[audio_stream_index]->codecpar; AVCodec* codec = avcodec_find_decoder(codecpar->codec_id); if (codec == nullptr) { std::cerr << "Error: could not find decoder for codec ID " << codecpar->codec_id << std::endl; avformat_close_input(&format_ctx); return -1; } // 6. 打开音频解码器 AVCodecContext* codec_ctx = avcodec_alloc_context3(codec); if (avcodec_parameters_to_context(codec_ctx, codecpar) < 0) { std::cerr << "Error: could not copy codec parameters to decoder context" << std::endl; avcodec_free_context(&codec_ctx); avformat_close_input(&format_ctx); return -1; } if (avcodec_open2(codec_ctx, codec, nullptr) < 0) { std::cerr << "Error: could not open decoder" << std::endl; avcodec_free_context(&codec_ctx); avformat_close_input(&format_ctx); return -1; } // 7. 初始化音频重采样器 SwrContext* swr_ctx = swr_alloc_set_opts(nullptr, codec_ctx->channel_layout, AV_SAMPLE_FMT_S16, codec_ctx->sample_rate, codec_ctx->channel_layout, codec_ctx->sample_fmt, codec_ctx->sample_rate, 0, nullptr); if (swr_ctx == nullptr) { std::cerr << "Error: could not allocate resampler context" << std::endl; avcodec_close(codec_ctx); avcodec_free_context(&codec_ctx); avformat_close_input(&format_ctx); return -1; } if (swr_init(swr_ctx) < 0) { std::cerr << "Error: could not initialize resampler context" << std::endl; swr_free(&swr_ctx); avcodec_close(codec_ctx); avcodec_free_context(&codec_ctx); avformat_close_input(&format_ctx); return -1; } // 8. 打开输出文件 std::ofstream output_file(output_filename, std::ios::binary); if (!output_file.is_open()) { std::cerr << "Error: could not open output file " << output_filename << std::endl; swr_free(&swr_ctx); avcodec_close(codec_ctx); avcodec_free_context(&codec_ctx); avformat_close_input(&format_ctx); return -1; } // 9. 解码音频数据 AVPacket packet; av_init_packet(&packet); packet.data = nullptr; packet.size = 0; AVFrame* frame = av_frame_alloc(); while (av_read_frame(format_ctx, &packet) >= 0) { if (packet.stream_index == audio_stream_index) { if (avcodec_send_packet(codec_ctx, &packet) == 0) { while (avcodec_receive_frame(codec_ctx, frame) == 0) { // 重采样音频数据 std::vector<uint8_t> buffer(codec_ctx->channels * frame->nb_samples * av_get_bytes_per_sample(AV_SAMPLE_FMT_S16)); uint8_t* output_data[1] = { buffer.data() }; int output_samples = swr_convert(swr_ctx, output_data, frame->nb_samples, (const uint8_t**)frame->extended_data, frame->nb_samples); if (output_samples > 0) { output_file.write((char*)buffer.data(), output_samples * codec_ctx->channels * av_get_bytes_per_sample(AV_SAMPLE_FMT_S16)); } } } } av_packet_unref(&packet); } // 10. 释放资源 av_frame_free(&frame); swr_free(&swr_ctx); avcodec_close(codec_ctx); avcodec_free_context(&codec_ctx); avformat_close_input(&format_ctx); return 0; } ``` 该示例程序会把读取的 AAC 音频文件解码并重采样成 16 位 PCM 数据,然后保存到输出文件中。你可以根据需要修改代码,以满足你的具体需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值