什么是ADTS?
ADTS(Audio Data Transport Stream)是一种用于 AAC(Advanced Audio Coding)音频数据传输 的帧封装格式。它常见于 AAC 裸流(raw AAC) 的存储与传输场景,比如在线广播、流媒体推送和文件存储。
它的特点是:
- 每个 ADTS 帧都包含一个 固定大小的头部(ADTS Header) + AAC 原始数据。
- 支持 流式传输,即使中途加入也可以同步解码。
- 广泛用于 HTTP 直播(HLS)、RTSP、MPEG-TS 封装等场景。
一个 ADTS 帧的基本结构如下:
[ADTS Header][AAC Raw Data]
ADTS的作用
AAC 编码器输出的 原始数据(RAW) 没有时间戳,也无法直接判断每帧边界。ADTS 头部的主要作用:
- 同步标识(Sync Word):用于标记帧的起始位置,方便解码器在任意位置开始解码。
- 音频参数描述:例如采样率、声道数、编码配置等。
- 帧长度信息:指示当前 AAC 数据的字节数,方便提取和播放。
- 错误检测(可选):CRC 校验。
ADTS的帧结构
ADTS 帧由 固定头(Fixed Header) + 可变头(Variable Header) 组成(共 7 或 9 字节,如果有 CRC 校验则为 9 字节)。
结构示意图
ADTS Header (7 or 9 bytes)
┌──────────────┬──────────────────────────────────────────────┐
│ 固定头部 │ syncword、版本、层、保护标志、采样率等 │
├──────────────┼──────────────────────────────────────────────┤
│ 可变头部 │ 帧长度、缓冲区满标志、AAC 原始数据块数等 │
└──────────────┴──────────────────────────────────────────────┘
AAC Raw Data
位分布示意图(无 CRC 时)
|<--- Syncword (0xFFF) --->|
111111111111 ID layer prot_abs profile sfreq priv chcfg orig home
| 12 | 1 | 2 | 1 | 2 | 4 | 1 | 3 | 1 | 1 |
cpy_bit cpy_start frame_length(13) fullness(11) blk(2)
| 1 | 1 | 13 bits | 11 bits | 2 |
二进制布局(无 CRC,7 字节):
位数 | 字段名 | 含义 |
---|---|---|
12 bit | syncword | 同步字 0xFFF ,标识帧起始 |
1 bit | ID | MPEG 版本(0 = MPEG-4,1 = MPEG-2) |
2 bit | layer | 固定为 00 |
1 bit | protection_absent | 1 表示无 CRC 校验 |
2 bit | profile | AAC Profile(0=Main,1=LC,2=SSR,3=保留) |
4 bit | sampling_frequency_index | 采样率索引(如 4 = 44100Hz) |
1 bit | private_bit | 私有标志位 |
3 bit | channel_configuration | 声道数(如 2 = 立体声) |
1 bit | original_copy | 原版/拷贝标志 |
1 bit | home | 主页标志 |
1 bit | copyright_identification_bit | 版权位 |
1 bit | copyright_identification_start | 版权起始位 |
13 bit | frame_length | 整个 ADTS 帧的长度(Header + Data) |
11 bit | adts_buffer_fullness | 缓冲区满度(0x7FF 表示码率可变) |
2 bit | number_of_raw_data_blocks_in_frame | 每帧包含的 AAC 原始块数(一般为 0) |
ADTS字段解析
Syncword(同步字)
- 固定为二进制
111111111111
(0xFFF),保证帧的唯一定位。
Profile
表示 AAC 的编码类型:
- 0:Main
- 1:LC(Low Complexity,常用)
- 2:SSR
- 3:保留
Sampling Frequency Index(采样率索引)
索引 | 采样率 |
---|---|
0 | 96000 |
1 | 88200 |
2 | 64000 |
3 | 48000 |
4 | 44100 |
5 | 32000 |
6 | 24000 |
7 | 22050 |
8 | 16000 |
9 | 12000 |
10 | 11025 |
11 | 8000 |
12 | 7350 |
Frame Length(帧长度)
- 单位:字节
- 计算公式:
frame_length = header_length + AAC_raw_data_length
- 无 CRC 校验时,header_length = 7 字节;有 CRC 校验时,header_length = 9 字节。
AAC解码
总述
输入数据(ADTS/LATM/裸AAC)
↓
[1] 数据解析/同步定位
↓
[2] 解析 AAC 头信息 (采样率、声道数、Profile)
↓
[3] 提取 AAC 码流数据块
↓
[4] 频域解码流程
├── 逆量化 (Inverse Quantization)
├── 频域处理 (TNS, PNS, IS, MS)
├── IMDCT(逆修正离散余弦变换)
└── 短块/长块拼接
↓
[5] 立体声处理 / 混合
↓
[6] PCM 输出(时域信号)
解码流程
步骤 1:数据解析 / 同步定位
- 如果是 ADTS 流:
- 搜索 syncword 0xFFF(12bit)来找到帧头位置
- 读取
aac_frame_length
得到帧大小
- 如果是 LATM/LOAS 流:
- 按 LATM 格式解析 AudioMuxElement
- 如果是裸 AAC(.aac):
- 必须由外部提供配置信息(AudioSpecificConfig)
步骤 2:解析 AAC 头信息
- 从 ADTS 头中提取:
- profile(AAC LC/HE/HEv2 等)
- 采样率(sampling_frequency_index)
- 声道数(channel_configuration)
- 初始化解码器状态:
- 创建滤波器系数
- 分配窗口缓冲
- 初始化 SBR(Spectral Band Replication)、PS(Parametric Stereo)等扩展模块(如果有)
步骤 3:提取 AAC 数据块
- 去掉帧头(ADTS 为 7 或 9 字节)
- 剩余部分是 AAC 原始数据块(Raw Data Block)
- 如果
number_of_raw_data_blocks_in_frame > 0
,则一帧内有多个音频块,要分别解析
步骤 4:频域解码流程(AAC 是基于 MDCT 的频域编码)
- Huffman 解码
- 将压缩的频域系数恢复成量化值
- 逆量化(Inverse Quantization)
- 将量化频谱值恢复到浮点频谱
- 工具处理(Tool Processing)
- TNS(Temporal Noise Shaping):时间域噪声整形
- PNS(Perceptual Noise Substitution):噪声替代
- IS(Intensity Stereo) / MS(Mid/Side Stereo):立体声压缩技术
- IMDCT(Inverse Modified Discrete Cosine Transform)
- 将频域数据转为时域样本
- 窗函数与重叠相加(Overlap-Add)
- AAC 长块为 1024 样本,短块为 128 样本,通过 OLA 合成连续 PCM
步骤 5:立体声处理 / 混合
- 如果是多声道 AAC(例如 5.1):
- 执行声道映射(Channel Mapping)
- 可选:下混(Downmix)到立体声或单声道
- 如果是 HE-AAC:
- SBR 解码:从低采样率重建高频
- PS 解码:从单声道重建立体声
步骤 6:PCM 输出
- 最终得到 16bit、24bit 或 32bit 浮点的 PCM 数据
- 可直接送给音频播放设备(ALSA / WASAPI / OpenSL ES)
- 或存储为 WAV/RAW PCM 文件
示例(C++ 解析 ADTS Header)
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <cstdint>
struct AdtsHeader {
int id; // MPEG 版本(0=MPEG-4, 1=MPEG-2)
int profile; // AAC Profile
int sampling_frequency_index; // 采样率索引
int sampling_frequency; // 实际采样率
int channel_configuration; // 声道数
int frame_length; // 整个ADTS帧长度
bool protection_absent; // 是否有CRC
};
// 采样率索引表
static const int sampling_frequencies[] = {
96000, 88200, 64000, 48000, 44100, 32000,
24000, 22050, 16000, 12000, 11025, 8000, 7350
};
// 解析 ADTS 头
bool parse_adts_header(const uint8_t* data, AdtsHeader& header) {
// 检查同步字 0xFFF
if ((data[0] != 0xFF) || ((data[1] & 0xF0) != 0xF0)) {
return false;
}
header.id = (data[1] & 0x08) >> 3;
header.protection_absent = data[1] & 0x01;
header.profile = ((data[2] & 0xC0) >> 6) + 1; // 加1以符合MPEG定义
header.sampling_frequency_index = (data[2] & 0x3C) >> 2;
if (header.sampling_frequency_index < 13) {
header.sampling_frequency = sampling_frequencies[header.sampling_frequency_index];
} else {
header.sampling_frequency = 0; // 未知采样率
}
header.channel_configuration = ((data[2] & 0x01) << 2) | ((data[3] & 0xC0) >> 6);
header.frame_length = ((data[3] & 0x03) << 11) | (data[4] << 3) | ((data[5] & 0xE0) >> 5);
return true;
}
// 主程序
int main() {
std::string filename = "test.aac"; // ADTS AAC 文件路径
std::ifstream file(filename, std::ios::binary);
if (!file) {
std::cerr << "无法打开文件: " << filename << std::endl;
return 1;
}
while (true) {
uint8_t header_buf[7];
file.read(reinterpret_cast<char*>(header_buf), 7);
if (file.gcount() < 7) break; // 文件结束
AdtsHeader header;
if (!parse_adts_header(header_buf, header)) {
std::cerr << "未找到同步字,可能不是ADTS流" << std::endl;
break;
}
// 输出解析结果
std::cout << "Frame: "
<< " MPEG" << (header.id == 0 ? "4" : "2")
<< " Profile=" << header.profile
<< " Fs=" << header.sampling_frequency << "Hz"
<< " Channels=" << header.channel_configuration
<< " Length=" << header.frame_length
<< " CRC=" << (header.protection_absent ? "No" : "Yes")
<< std::endl;
// 跳过当前帧剩余部分
int data_size = header.frame_length - 7;
file.seekg(data_size, std::ios::cur);
}
file.close();
return 0;
}
总结
- ADTS 是 AAC 裸流 的帧封装格式,适合流式播放。
- 帧头信息提供了解码所需的全部参数。
- 在网络传输中,解码器只需找到同步字并解析帧头,就能从任意位置开始播放。