AAC音频基础知识及码流解析

AAC音频基础知识及码流解析


目录

  1. AAC简介
  2. AAC规格简介
  3. AAC特点
  4. AAC音频文件格式及代码解析
  5. AAC元素信息
  6. AAC文件处理流程
  7. AAC解码流程
  8. 技术解析

1. AAC简介

  1. AAC是高级音频编码(Advanced Audio Coding) 的缩写,出现于1997年,最初是基于MPEG-2的音频编码技术。由Fraunhofer IIS、Dolby Laboratories、AT&T、Sony等公司共同开发,目的是取代MP3格式。2000年,MPEG-4标准出现后,AAC重新集成了其特性,加入了SBR技术和PS技术,为了区别于传统的MPEG-2 AAC又称为MPEG-4 AAC。

  2. AAC是新一代的音频有损压缩技术,它通过一些附加的编码技术(比如PS,SBR等),衍生出了LC-AAC,HE-AAC,HE-AACv2三 种主要的编码,LC-AAC就是比较传统的AAC,相对而言,主要用于中高码率(>=80Kbps),HE-AAC(相当于AAC+SBR)主要用于中低码(<=80Kbps),而新近推出的HE-AACv2(相当于AAC+SBR+PS)主要用于低码率(<=48Kbps),事实上大部分编码器设成<=48Kbps自动启用PS技术,而>48Kbps就不加PS,就相当于普通的HE-AAC。

  3. 音频码流在视频播放器中的位置如下所示。
    在这里插入图片描述


2. AAC规格简介

  1. AAC共有9种规格,以适应不同的场合的需要,目前使用最多的是LC和HE(适合低码率)。

    1. MPEG-4 AAC LC低复杂度规格(Low Complexity)------现在的手机比较常见的MP4文件中。
    2. MPEG-4 AAC HE 高效率规格(High Efficiency)-----这种规格适合用于低码率编码,有Nero ACC 编码器支持
  2. 流行的Nero AAC编码程序只支持LC,HE,HEv2这三种规格,编码后的AAC音频,规格显示都是LC。HE其实就是AAC(LC)+SBR技术,HEv2就是AAC(LC)+SBR+PS技术;
    3.

  3. HE:“High Efficiency”(高效性)。HE-AAC v1(又称AACPlusV1,SBR),用容器的方法实现了AAC(LC)+SBR技术。SBR其实代表的是Spectral Band Replication(光谱带复制)。简要叙述一下,音乐的主要频谱集中在低频段,高频段幅度很小,但很重要,决定了音质。如果对整个频段编码,若是为了保护高频就会造成低频段编码过细以致文件巨大;若是保存了低频的主要成分而失去高频成分就会丧失音质。SBR把频谱切割开来,低频单独编码保存主要成分,高频单独放大编码保存音质,“统筹兼顾”了,在减少文件大小的情况下还保存了音质,完美的化解这一矛盾。

  4. HEv2:用容器的方法包含了HE-AAC v1和PS技术。PS指“parametric stereo”(参数立体声)。原来的立体声文件文件大小是一个声道的两倍。但是两个声道的声音存在某种相似性,根据香农信息熵编码定理,相关性应该被去掉才能减小文件大小。所以PS技术存储了一个声道的全部信息,然后,花很少的字节用参数描述另一个声道和它不同的地方。


3. AAC特点

  1. AAC是一种高压缩比的音频压缩算法,但它的压缩比要远超过较老的音频压缩算法, 如AC-3、MP3等。并且其质量可以同未压缩的CD音质相媲美。

  2. 同其他类似的音频编码算法一样,AAC也是采用了变换编码算法,但AAC使用了分辨率更高的滤波器组,因此它可以达到更高的压缩比。

  3. AAC使用了临时噪声重整、后向自适应线性预测、联合立体声技术和量化哈夫曼编码等最新技术,这些新技术的使用都使压缩比得到进一步的提高。

  4. AAC支持更多种采样率和比特率、支持1个到48个音轨、支持多达15个低频音轨、具有多种语言的兼容能力、还有多达15个内嵌数据流。

  5. AAC支持更宽的声音频率范围,最高可达到96kHz,最低可达8KHz,远宽于MP3的16KHz-48kHz的范围。

  6. 不同于MP3及WMA,AAC几乎不损失声音频率中的甚高、甚低频率成分,并且比WMA在频谱结构上更接近于原始音频,因而声音的保真度更好。专业评测中表明,AAC比WMA声音更清晰,而且更接近原音。

  7. AAC采用优化的算法达到了更高的解码效率,解码时只需较少的处理能力。


4. AAC音频文件格式

1. AAC的音频文件格式有ADIF & ADTS:
  1. ADIF:Audio Data Interchange Format 音频数据交换格式。这种格式的特征是可以确定的找到这个音频数据的开始,不需进行在音频数据流中间开始的解码,即它的解码必须在明确定义的开始处进行。故这种格式常用在磁盘文件中。
  2. AAC的ADIF格式见下图:
    在这里插入图片描述
  3. **ADTS:Audio Data Transport Stream 音频数据传输流。**这种格式的特征是它是一个有同步字的比特流,解码可以在这个流中任何位置开始。它的特征类似于mp3数据流格式。
  4. 简单说,ADTS可以在任意帧解码,也就是说它每一帧都有头信息。ADIF只有一个统一的头,所以必须得到所有的数据后解码。且这两种的header的格式也是不同的,目前一般编码后的和抽取出的都是ADTS格式的音频流。
  5. 有的时候当你编码AAC裸流的时候,会遇到写出来的AAC⽂件并不能在PC和⼿机上播放,很⼤的可能就是AAC⽂件的每⼀帧⾥缺少ADTS头信息⽂件的包装拼接,只需要加⼊头⽂件ADTS即可。
  6. ⼀个AAC原始数据块⻓度是可变的,对原始帧加上ADTS头进⾏ADTS的封装,就形成了ADTS帧。
  7. AAC的ADTS的一般格式见下图:
    在这里插入图片描述
  8. 图中表示出了ADTS一帧的简明结构,其两边的紫色矩形表示一帧前后的数据。
2. ADIF和ADTS的header
1. ADIF 的头信息:

在这里插入图片描述

  1. ADIF头信息位于AAC文件的起始处,接下来就是连续的 raw data blocks。
  2. 组成ADIF头信息的各个域如下所示:
    在这里插入图片描述
2. AAC⾳频⽂件的每⼀帧由ADTS Header和AAC Audio Data组成。结构体如下:

在这里插入图片描述

  1. 每⼀帧的ADTS的头⽂件都包含了⾳频的采样率,声道,帧⻓度等信息,这样解码器才能解析读取。
  2. ⼀般情况下ADTS的头信息都是7个字节,分为2部分:
    1. adts_fixed_header();
    2. adts_variable_header();
  3. 其⼀为固定头信息,紧接着是可变头信息。固定头信息中的数据每⼀帧都相同,⽽可变头信息则在帧与帧之间可变
1. ADTS 的固定头信息:

在这里插入图片描述

  1. syncword :同步头 总是0xFFF, all bits must be 1,代表着⼀个ADTS帧的开始
  2. ID:MPEG标识符,0标识MPEG-4,1标识MPEG-2
  3. Layer:always: ‘00’
  4. protection_absent:表示是否误码校验。Warning, set to 1 if there is noCRC and 0 if there is CRC
  5. profile:表示使⽤哪个级别的AAC,如01 Low Complexity(LC)— AAC LC。有些芯⽚只⽀持AAC LC
  6. 在MPEG-2 AAC中定义了3种在这里插入图片描述
  7. profile的值等于 Audio Object Type的值减1,profile = MPEG-4 Audio Object Type - 1
    在这里插入图片描述
  8. sampling_frequency_index:表示使⽤的采样率下标,通过这个下标在Sampling Frequencies[ ]数组中查找得知采样率的值。
    在这里插入图片描述
  9. channel_configuration: 表示声道数,⽐如2表示⽴体声双声道
    在这里插入图片描述
0: Defined in AOT Specifc Config
1: 1 channel: front-center
2: 2 channels: front-left, front-right
3: 3 channels: front-center, front-left, front-right
4: 4 channels: front-center, front-left, front-right, back-center
5: 5 channels: front-center, front-left, front-right, back-left, backright
6: 6 channels: front-center, front-left, front-right, back-left, backright, LFE-channel
7: 8 channels: front-center, front-left, front-right, side-left, side-right,back-left, back-right, LFE-channel
8-15: Reserved
2. ADTS的可变头信息:

6.

  1. frame_length : ⼀个ADTS帧的⻓度包括ADTS头和AAC原始流.

frame length, this value must include 7 or 9 bytes of header length:
aac_frame_length = (protection_absent == 1 ? 7 : 9) + size(AACFrame)
protection_absent=0时, header length=9bytes
protection_absent=1时, header length=7bytes

  1. adts_buffer_fullness:0x7FF 说明是码率可变的码流。

  2. number_of_raw_data_blocks_in_frame:表示ADTS帧中有number_of_raw_data_blocks_in_frame + 1个AAC原始帧,所以number_of_raw_data_blocks_in_frame == 0 表示说ADTS帧中有⼀个AAC数据块。

  3. 下⾯是ADTS的AAC⽂件部分:
    在这里插入图片描述

  4. 第⼀帧的帧头7个字节为:0xFF 0xF1 0x4C 0x40 0x20 0xFF 0xFC 分析各个关键数值:
    在这里插入图片描述

  5. 计算帧⻓度:将⼆进制 0000100000111 转换成⼗进制为263。观察第⼀帧的⻓度确实为263个字节。计算⽅法:(帧⻓度为13位,使⽤unsigned int来存储帧⻓数值)

unsigned int getFrameLength(unsigned char* str)
{
	if ( !str )
	{
		return 0;
	}
	unsigned int len = 0;
	int f_bit = str[3];
	int m_bit = str[4];
	int b_bit = str[5];
	len += (b_bit>>5);
	len += (m_bit<<3);
	len += ((f_bit&3)<<11);
	return len;
}
  1. 帧同步目的在于找出帧头在比特流中的位置,13818-7规定,aac ADTS格式的帧头同步字为12比特的“1111 1111 1111”.

  2. ADTS的头信息为两部分组成,其一为固定头信息,紧接着是可变头信息。固定头信息中的数据每一帧都相同,而可变头信息则在帧与帧之间可变。

  3. 代码解析

#include <stdio.h>
#include <libavutil/log.h>
#include <libavformat/avio.h>
#include <libavformat/avformat.h>

#define ADTS_HEADER_LEN  7;

const int sampling_frequencies[] = {
        96000,  // 0x0
        88200,  // 0x1
        64000,  // 0x2
        48000,  // 0x3
        44100,  // 0x4
        32000,  // 0x5
        24000,  // 0x6
        22050,  // 0x7
        16000,  // 0x8
        12000,  // 0x9
        11025,  // 0xa
        8000   // 0xb
        // 0xc d e f是保留的
};

int adts_header(char *const p_adts_header, const int data_length,
                const int profile, const int samplerate,
                const int channels) {

    int sampling_frequency_index = 3; // 默认使用48000hz
    int adtsLen = data_length + 7;

    int frequencies_size = sizeof(sampling_frequencies) / sizeof(sampling_frequencies[0]);
    int i = 0;
    for (i = 0; i < frequencies_size; i++) {
        if (sampling_frequencies[i] == samplerate) {
            sampling_frequency_index = i;
            break;
        }
    }
    if (i >= frequencies_size) {
        printf("unsupport samplerate:%d\n", samplerate);
        return -1;
    }

    p_adts_header[0] = 0xff;         //syncword:0xfff                          高8bits
    p_adts_header[1] = 0xf0;         //syncword:0xfff                          低4bits
    p_adts_header[1] |= (0 << 3);    //MPEG Version:0 for MPEG-4,1 for MPEG-2  1bit
    p_adts_header[1] |= (0 << 1);    //Layer:0                                 2bits
    p_adts_header[1] |= 1;           //protection absent:1                     1bit

    p_adts_header[2] = (profile) << 6;            //profile:profile               2bits
    p_adts_header[2] |=
            (sampling_frequency_index & 0x0f) << 2; //sampling frequency index:sampling_frequency_index  4bits
    p_adts_header[2] |= (0 << 1);             //private bit:0                   1bit
    p_adts_header[2] |= (channels & 0x04) >> 2; //channel configuration:channels  高1bit

    p_adts_header[3] = (channels & 0x03) << 6; //channel configuration:channels 低2bits
    p_adts_header[3] |= (0 << 5);               //original:0                1bit
    p_adts_header[3] |= (0 << 4);               //home:0                    1bit
    p_adts_header[3] |= (0 << 3);               //copyright id bit:0        1bit
    p_adts_header[3] |= (0 << 2);               //copyright id start:0      1bit
    p_adts_header[3] |= ((adtsLen & 0x1800) >> 11);           //frame length:value   高2bits

    p_adts_header[4] = (uint8_t) ((adtsLen & 0x7f8) >> 3);     //frame length:value    中间8bits
    p_adts_header[5] = (uint8_t) ((adtsLen & 0x7) << 5);       //frame length:value    低3bits
    p_adts_header[5] |= 0x1f;                                 //buffer fullness:0x7ff 高5bits
    p_adts_header[6] = 0xfc;      //‭11111100‬       //buffer fullness:0x7ff 低6bits
    // number_of_raw_data_blocks_in_frame:
    //    表示ADTS帧中有number_of_raw_data_blocks_in_frame + 1个AAC原始帧。

    return 0;
}

int main(int argc, char *argv[]) {
    int ret = -1;
    char errors[1024];

    char *in_filename = "/Users/lijinwang/Downloads/course/study/believe.mp4";
    char *aac_filename = "/Users/lijinwang/Downloads/course/study/believe.aac";

    FILE *aac_fd = NULL;

    int audio_index = -1;
    int len = 0;


    AVFormatContext *ifmt_ctx = NULL;
    AVPacket pkt;

    // 设置打印级别
    av_log_set_level(AV_LOG_DEBUG);

    /*if (argc < 3) {
        av_log(NULL, AV_LOG_DEBUG, "the count of parameters should be more than three!\n");
        return -1;
    }

    in_filename = argv[1];      // 输入文件
    aac_filename = argv[2];     // 输出文件

    if (in_filename == NULL || aac_filename == NULL) {
        av_log(NULL, AV_LOG_DEBUG, "src or dts file is null, plz check them!\n");
        return -1;
    }*/

    aac_fd = fopen(aac_filename, "wb");
    if (!aac_fd) {
        av_log(NULL, AV_LOG_DEBUG, "Could not open destination file %s\n", aac_filename);
        return -1;
    }

    // 打开输入文件
    if ((ret = avformat_open_input(&ifmt_ctx, in_filename, NULL, NULL)) < 0) {
        av_strerror(ret, errors, 1024);
        av_log(NULL, AV_LOG_DEBUG, "Could not open source file: %s, %d(%s)\n",
               in_filename,
               ret,
               errors);
        return -1;
    }

    // 获取解码器信息
    if ((ret = avformat_find_stream_info(ifmt_ctx, NULL)) < 0) {
        av_strerror(ret, errors, 1024);
        av_log(NULL, AV_LOG_DEBUG, "failed to find stream information: %s, %d(%s)\n",
               in_filename,
               ret,
               errors);
        return -1;
    }

    // dump媒体信息
    av_dump_format(ifmt_ctx, 0, in_filename, 0);

    // 初始化packet
    av_init_packet(&pkt);

    // 查找audio对应的steam index
    audio_index = av_find_best_stream(ifmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);
    if (audio_index < 0) {
        av_log(NULL, AV_LOG_DEBUG, "Could not find %s stream in input file %s\n",
               av_get_media_type_string(AVMEDIA_TYPE_AUDIO),
               in_filename);
        return AVERROR(EINVAL);
    }

    // 打印AAC级别
    printf("audio profile:%d, FF_PROFILE_AAC_LOW:%d\n",
           ifmt_ctx->streams[audio_index]->codecpar->profile,
           FF_PROFILE_AAC_LOW);

    if (ifmt_ctx->streams[audio_index]->codecpar->codec_id != AV_CODEC_ID_AAC) {
        printf("the media file no contain AAC stream, it's codec_id is %d\n",
               ifmt_ctx->streams[audio_index]->codecpar->codec_id);
        goto failed;
    }
    // 读取媒体文件,并把aac数据帧写入到本地文件
    while (av_read_frame(ifmt_ctx, &pkt) >= 0) {
        if (pkt.stream_index == audio_index) {
            char adts_header_buf[7] = {0};
            adts_header(adts_header_buf, pkt.size,
                        ifmt_ctx->streams[audio_index]->codecpar->profile,
                        ifmt_ctx->streams[audio_index]->codecpar->sample_rate,
                        ifmt_ctx->streams[audio_index]->codecpar->channels);
            fwrite(adts_header_buf, 1, 7, aac_fd);  // 写adts header , ts流不适用,ts流分离出来的packet带了adts header
            len = fwrite(pkt.data, 1, pkt.size, aac_fd);   // 写adts data
            if (len != pkt.size) {
                av_log(NULL, AV_LOG_DEBUG, "warning, length of writed data isn't equal pkt.size(%d, %d)\n",
                       len,
                       pkt.size);
            }
        }
        av_packet_unref(&pkt);
    }

    failed:
    // 关闭输入文件
    if (ifmt_ctx) {
        avformat_close_input(&ifmt_ctx);
    }
    if (aac_fd) {
        fclose(aac_fd);
    }

    return 0;
}


  1. 结果
    在这里插入图片描述

5. AAC元素信息

1. 在AAC中,原始数据块的组成可能有七种不同的元素:
  1. SCE: Single Channel Element单通道元素。单通道元素基本上只由一个ICS组成。一个原始数据块最可能由16个SCE组成。

  2. CPE: Channel Pair Element 双通道元素,由两个可能共享边信息的ICS和一些联合立体声编码信息组成。

  3. CCE: Coupling Channel Element 藕合通道元素。代表一个块的多通道联合立体声信息或者多语种程序的对话信息。

  4. LFE: Low Frequency Element 低频元素。包含了一个加强低采样频率的通道。

  5. DSE: Data Stream Element 数据流元素,包含了一些并不属于音频的附加信息。

  6. PCE: Program Config Element 程序配置元素。包含了声道的配置信息。它可能出现在ADIF 头部信息中。

  7. FIL: Fill Element 填充元素。包含了一些扩展信息。如SBR,动态范围控制信息等。


6. AAC文件处理流程

  1. 判断文件格式,确定为ADIF或ADTS

  2. 若为ADIF,解ADIF头信息,跳至第6步。

  3. 若为ADTS,寻找同步头。

  4. 解ADTS帧头信息。

  5. 若有错误检测,进行错误检测。

  6. 解块信息。

  7. 解元素信息。


7. AAC解码流程

在这里插入图片描述

  1. 在主控模块开始运行后,主控模块将AAC比特流的一部分放入输入缓冲区,通过查找同步字 得到一帧的起始,找到后,根据ISO/IEC 13818-7所述的语法开始进行Noisless Decoding(无噪解码),无噪解码实际上就是哈夫曼解码,通过反量化(Dequantize)、联合立体声(Joint Stereo),知觉噪声替换(PNS),瞬时噪声整形(TNS),反离散余弦变换(IMDCT),频段复制(SBR)这几个模块之后,得出左右声道的PCM码流,再由主控模块将其放入输出缓冲区输出到声音播放设备。

8. 技术解析

1. 主控模块:
  1. 所谓的主控模块,它的主要任务是操作输入输出缓冲区,调用其它各模块协同工作。
  2. 其中,输入输出缓冲区均由DSP控制模块提供接口。
  3. 输出缓冲区中将存放的数据为解码出来的PCM数据,代表了声音的振幅。它由一块固定长度的缓冲区构成,通过调用DSP控制模块的接口函数,得到头指针,在完成输出缓冲区的填充后,调用中断处理输出至I2S接口所连接的音频ADC芯片(立体声音频DAC和DirectDrive耳机放大器)输出模拟声音。
2. Noisless Decoding(无噪解码):
  1. 无噪编码就是哈夫曼编码,它的作用在于进一步减少尺度因子和量化后频谱的冗余,即将尺度因子和量化后的频谱信息进行哈夫曼编码。
  2. 全局增益编码成一个8位的无符号整数,第一个尺度因子与全局增益值进行差分编码后再使用尺度因子编码表进行哈夫曼编码。
  3. 后续的各尺度因子都与前一个尺度因子进行差分编码。
  4. 量化频谱的无噪编码有两个频谱系数的划分。
  5. 其一为4元组和2元组的划分,另一个为节划分。对前一个划分来说,确定了一次哈夫曼表查找出的数值是4个还是2个。对后一个划分来说,确定了应该用哪一个哈夫曼表,一节中含有若干的尺度因子带并且每节只用一个哈夫曼表。
2.1 分段
  1. 无噪声编码将输入的1024个量化频谱系数分为几个段(section),段内的各点均使用同一个哈夫曼表,考虑到编码效率,每一段的边界最好同尺度因子带的边界重合。所以每一段必需段传送信息应该有:段长度,所在的尺度因子带,使用的哈夫曼表。
2.2 分组和交替
  1. 分组是指忽略频谱系数所在窗,将连续的,具有相同尺度因子带的频谱系数分为一组放在一起,共享一个尺度因子从而得到更好的编码效率。
  2. 这样做必然会引起交替,即本来是以c[组][窗][尺度因子带][ 系数索引] 为顺序的系数排列,变为将尺度因子相同的系数放在一起: c[组][尺度因子带][窗][ 系数索引] 这样就引起了相同窗的系数的交替。
2.3 大量化值的处理
  1. 大量化值在AAC中有两种处理方法:在哈夫曼编码表中使用escape标志或使用脉冲escape方法。
  2. 前者跟mp3编码方法相似,在许多大量化值出现时采用专门的哈夫曼表,这个表暗示了它的使用将会在哈夫曼编码后面跟跟一对escape值及对值的符号。
  3. 在用脉冲escape方法时,大数值被减去一个差值变为小数值,然后使用哈夫曼表编码,后面会跟一个脉冲结构来帮助差值的还原.
3. 尺度因子解码及逆量化
  1. 在AAC编码中,逆量化频谱系数是由一个非均匀量化器来实现的,在解码中需进行其逆运算。 即保持符号并进行4/3次幂运算。

  2. 在频域调整量化噪声的基本方法就是用尺度因子来进行噪声整形。尺度因子就是一个用来改变在一个尺度因子带的所有的频谱系数的振幅增益值。使用尺度因子这种机制是为了使用非均匀量化器在频域中改变量化噪声的比特分配。

3.1 尺度因子带(scalefactor-band)
  1. 频率线根据人耳的听觉特性被分成多个组,每个组对应若干个尺度因子,这些组就叫做尺度因子带。为了减少信息含有短窗的边信息,连续的短窗可能会被分为一组,即将若干个短窗当成一个窗口一起传送,然后尺度因子将会作用到所有分组后的窗口去。
4. 联合立体声(Joint Stereo)
  1. 联合立体声的是对原来的取样进行的一定的渲染工作,使声音更”好听”些。
5. 知觉噪声替换(PNS)
  1. 知觉噪声替换模块是一种以参数编码的方式模拟噪声的模块。在判别出音频值中的噪声后,将那些噪声不进行量化编码,而是采用一些参数告诉解码器端这是某种噪声,然后解码器端将会对这些噪声用一些随机的编码来制造出这一类型的噪声。

  2. 在具体操作上,PNS模块对每个尺度因子带侦测频率4kHz以下的信号成分。如果这个信号既不是音调,在时间上也无强烈的能量变动,就被认为是噪声信号。其信号的音调及能量变化都在心理声学模型中算出。

  3. 在解码中,如果发现使用了哈夫曼表13(NOISE_HCB),则表明使用了PNS。由于M/S立体声解码与PNS解码互斥,故可以用参数ms_used来表明是否两个声道都用同样的PNS。如果ms_used参数为1,则两个声道会用同样的随机向量来生成噪声信号。PNS的能量信号用noise_nrg来表示,如果使用了PNS,则能量信号将会代替各自的尺度因子来传送。噪声能量编码同尺度因子一样,采用差分编码的方式。第一个值同样为全局增益值。它同强度立体声位置值及尺度因子交替地放在一起,但对差分解码来说又彼此忽略。即下一个噪声能量值以上一个噪声能量值而不是强度立体声位置或尺度因子为标准差分解码。随机能量将会在一个尺度 因子带内产生noise_nrg所计算出的平均能量分布。此项技术只有在MPEG-4 AAC中才会使用。

6. 瞬时噪声整形(TNS)
  1. 这项神奇的技术可以通过在频率域上的预测,来修整时域上的量化噪音的分布。在一些特殊的语音和剧烈变化信号的量化上,TNS技术对音质的提高贡献巨大!

  2. TNS瞬态噪声整形用于控制一个转换窗口内的瞬时噪声形态。它是用一个对单个通道的滤波过程来实现的。传统的变换编码方案常常遇到信号在时域变化非常剧烈的问题,特别是语音信号,这个问题是因为量化后的噪声分布虽然在频率域上得到控制,但在时域上却以一个常数分布在一个转换块内。如果这种块中信号变化得很剧烈却又不转向一个短块去,那这个常数分布的噪声将会被听到。

  3. TNS的原理利用了时域和频域的二元性和LPC(线性预测编码)的时频对称性,即在其中的任意一个域上做编码与在另一域上做预测编码等效,也就是说,在一个域内做预测编码可以在另一域内增加其解析度。量化噪声产生是在频域产生的,降低了时域的解析度,故在这里是在频域上做预测编码。在AACplus中,由于基于AAC profile LC,故TNS的滤波器阶数被限制在 12阶以内。

7. 反离散余弦变换(IMDCT)
  1. 将音频数据从频域转换到时域的过程主要是由将频域数据填入一组IMDCT滤波器来实现的。在进行IMDCT变换后,输出数值经过加窗,叠加,最后得到时域数值。
8. 频段复制(SBR)
  1. 简要叙述,音乐的主要频谱集中在低频段,高频段幅度很小,但很重要,决定了音质。
  2. 如果对整个频段编码,若是为了保护高频就会造成低频段编码过细以致文件巨大;若是保存了低频的主要成分而失去高频成分就会丧失音质。
  3. SBR把频谱切割开来,低频单独编码保存主要成分,高频单独放大编码保存音质,“统筹兼顾”了,在减少文件大小的情况下还保存了音质,完美的化解这一矛盾。
9. 参数立体声(PS)
  1. 对于之前的立体声文件来说,其文件大小是单声道的两倍,但是两个声道的声音存在某种相似性,根据香农信息熵编码定理,相关性应该被去掉才能减小文件大小。所以PS技术存储了一个声道的全部信息,之后,用很少的字节当作参数来描述另一个声道和它不同的地方。

在这里插入图片描述


参考博客:AAC文件格式解析

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值