AAC Audio Codec的Profile及其在不同平台上的支

date
Mar 3, 2022
slug
2022-03-03-aac-audio-profile
status
Published
tags
音视频
AAC
summary
本文总结了AAC audio codec的不同profile类型,以及在各种平台上编程设置aac profile的流程。
type
Post

AAC简介

AAC:Advanced Audio Codec。
AAC实际上是作为MP3音频编解码算法的继任者出现在历史舞台的。与MP3一样,AAC也是一种有损的音频编解码算法。相比于MP3而言,对于相同的音频数据进行处理,AAC编码出来的音频文件更小,而声音的质量还可以做到更高。
1997年,AAC作为一项国际标准由MPEG组织发布,具体的定义包含在MPEG-2的第7部分,和MPEG-4的第3部分。

AAC的不同类型(AAC Profile)

AAC-LC:Advanced Audio Codec-Low Complexity。
AAC-HE:Advanced Audio Codec-High Efficiency。
AAC-LD:Advanced Audio Codec-Low Delay。
 
notion image
可以看到,AAC audio codec按照两条独立的路线进行演进,演进的方向总是采用更复杂的技术,从而达到更好的性能指标:
  • AAC-LC(MPEG2)—>AAC-LC(MPEG4)—>HE-AAC—>HE-AAC v2—>Extended HE-AAC(xHE);
    • HE-AAC在AAC-LC的基础上增加了SBR技术;
    • HE-AAC v2在HE-AAC基础上增加了PS技术;
    • Extended HE-AAC则在HE-AAC v2的基础上增加了USAC技术;
  • AAC-LD—>AAC-ELD—>AAC-ELD v2;
    • AAC-ELD在AAC-LD的基础上增加了SBR技术;
    • AAC-ELD v2则是在AAC-ELD的基础上增加了Low Delay MPS技术。
AAC的不同profile版本可以支持向后兼容。例如,MPEG4 AAC-LC Decoder可以对MPEG2 AAC-LC Encoder编码出来的数据正确解码;而MPEG4 HE-AAC的Decoder可以支持对MPEG2和MPEG4的AAC-LC Encoder编码出来的音频流正确解码。

基于FFmpeg实现AAC编码

常用的AAC的开源编解码库是libfdk_aac,libfaac,libaacplus等
下面以libfdk_aac为例说明如何在ffmpeg中进行aac编码的流程。
--enable-libfdk_aac --enable-nonfree --enable-encoder=libfdk_aac
编译后使用以下命令测试libfdk_aac是否被正确的编译和链接进来:
ffmpeg -i <input file> -vcodec copy -acodec libfdk_aac -profile:a aac_he <output file>
使用以下代码段打开并配置aac codec进行音频编码:
AVCodecContext *encoder_ctx;
encoder_ctx->codec_id           =   AV_CODEC_ID_AAC;
encoder_ctx->sample_fmt         =   AV_SAMPLE_FMT_S16; 
encoder_ctx->profile            =   FF_PROFILE_AAC_HE;//在此处指定aac编码的profile

encoder = avcodec_find_encoder_by_name("libfdk_aac");
// if you still try to open it using avcodec_find_encoder it will open libfaac only.
avcodec_open2(encoder_ctx, encoder, NULL);
参考文档4提供了一份更为详细的基于ffmpeg+libfdk_aac进行aac编码的操作说明。

Android的AAC编解码支持

Android对AAC Codec的支持情况如下图所示:
notion image
Android平台下是使用MediaCodec进行音视频Codec的创建和管理。
参考文档5中包含了一份在Android下进行音频麦克风采集+AAC压缩+ADTS流媒体打包封装+AAC解码的完整流程代码。
其中在对MediaCodec编码器进行设置的时候,就通过选项指定AAC-LC profile:MediaCodecInfo.CodecProfileLevel.AACObjectLC
MediaFormat format = MediaFormat.createAudioFormat(MIMETYPE_AUDIO_AAC, SAMPLE_RATE, CHANNEL_COUNT);
format.setInteger(MediaFormat.KEY_AAC_PROFILE, 
MediaCodecInfo.CodecProfileLevel还能够支持的AAC codec profile包括:
public static final int AACObjectELD=39//AAC-ELD

iOS的AAC编解码支持

在iOS SDK中使用AudioToolbox中的Audio Converter Services来实现对AAC的编解码。
参考文档7介绍了使用Audio Converter Services实现对PCM转码为AAC并保存的完整代码流程。
  • 这篇文档并没有显式设置aac的profile。
在Audio Converter Services框架下,一般使用AudioConverterNew或者AudioConverterNewSpecific接口来创建音频编解码器,这两个接口都需要调用AudioStreamBasicDescription结构体来对音频编解码器的参数进行初始化:
struct AudioStreamBasicDescription {
    Float64 mSampleRate;        // sample frames per second
    UInt32  
当AudioStreamBasicDescription结构体mFormatID设置为kAudioFormatMPEG4AAC表示创建的是一个AAC的编码器,此时就可以使用mFormatFlags来指定这个AAC codec的profile。这种方式下iOS能够支持的AAC profile包括:
MPEG4ObjectID.aac_Main
MPEG4ObjectID.AAC_LC
MPEG4ObjectID.AAC_SSR
MPEG4ObjectID.AAC_LTP
MPEG4ObjectID.AAC_SBR
MPEG4ObjectID.aac_Scalable
MPEG4ObjectID.twinVQ
MPEG4ObjectID.CELP
MPEG4ObjectID.HVXC
此外,也可以在设置AudioStreamBasicDescription结构体的mFormatID的时候,直接把mFormatID初始化为以下列表中的一个aac编码器类型,这样就不需要使用mFormatFlags来指定AAC profile了:
kAudioFormatMPEG4AAC_HE
以下为一段初始化audio codec为AAC并设置aac profile的代码:
func setupAudioConverter() {
        var outputFormat = AudioStreamBasicDescription.init(
            mSampleRate: 44100,
            mFormatID: kAudioFormatLinearPCM,
            mFormatFlags: kLinearPCMFormatFlagIsSignedInteger,
            mBytesPerPacket: 2,
            mFramesPerPacket: 1,
            mBytesPerFrame: 2,
            mChannelsPerFrame: 1,
            mBitsPerChannel: 16,
            mReserved: 0)
        
        var inputFormat = AudioStreamBasicDescription.init(
            mSampleRate: 44100,
            mFormatID: kAudioFormatMPEG4AAC,//此处设置audio codec为aac
            mFormatFlags: UInt32(MPEG4ObjectID.AAC_LC.rawValue),//此处设置aac profile为aac_lc
            mBytesPerPacket: 0,
            mFramesPerPacket: 0,
            mBytesPerFrame: 0,
            mChannelsPerFrame: 1,
            mBitsPerChannel: 0,
            mReserved: 0)
        
        let status: OSStatus =  AudioConverterNew(&inputFormat, &outputFormat, &audioConverter)
        if (status != 0) {
            print("setup converter error, status: \(status)")
        }
    }

参考资料:

  1. Advanced Audio Coding (AAC) – ViaCorp (via-corp.com)
  1. All Tips about AAC (iskysoft.com)
  1. ffmpeg - How to encode audio in AAC-LC, AAC-HE-V1, AAC-HE-V2 using libavcodec? - Stack Overflow
  1. AAC编码实战 - 简书 (jianshu.com)
  1. Android音视频之使用MediaCodec编解码AAC - 简书 (jianshu.com)
  1. MediaCodecInfo.CodecProfileLevel  |  Android Developers
  1. iOS 利用 AudioToolbox 将 PCM 编码为 AAC - 博客 - 但江 (danthought.com)
  1. Audio Data Format Identifiers | Apple Developer Documentation

© Pavel Han 2020 - 2022