当前位置: 首页 > ds >正文

音视频学习(五十二):ADTS

什么是ADTS?

ADTS(Audio Data Transport Stream)是一种用于 AAC(Advanced Audio Coding)音频数据传输 的帧封装格式。它常见于 AAC 裸流(raw AAC) 的存储与传输场景,比如在线广播、流媒体推送和文件存储。

它的特点是:

  • 每个 ADTS 帧都包含一个 固定大小的头部(ADTS Header) + AAC 原始数据
  • 支持 流式传输,即使中途加入也可以同步解码。
  • 广泛用于 HTTP 直播(HLS)RTSPMPEG-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 bitsyncword同步字 0xFFF,标识帧起始
1 bitIDMPEG 版本(0 = MPEG-4,1 = MPEG-2)
2 bitlayer固定为 00
1 bitprotection_absent1 表示无 CRC 校验
2 bitprofileAAC Profile(0=Main,1=LC,2=SSR,3=保留)
4 bitsampling_frequency_index采样率索引(如 4 = 44100Hz)
1 bitprivate_bit私有标志位
3 bitchannel_configuration声道数(如 2 = 立体声)
1 bitoriginal_copy原版/拷贝标志
1 bithome主页标志
1 bitcopyright_identification_bit版权位
1 bitcopyright_identification_start版权起始位
13 bitframe_length整个 ADTS 帧的长度(Header + Data)
11 bitadts_buffer_fullness缓冲区满度(0x7FF 表示码率可变)
2 bitnumber_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(采样率索引)

索引采样率
096000
188200
264000
348000
444100
532000
624000
722050
816000
912000
1011025
118000
127350

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 的频域编码)

  1. Huffman 解码
    • 将压缩的频域系数恢复成量化值
  2. 逆量化(Inverse Quantization)
    • 将量化频谱值恢复到浮点频谱
  3. 工具处理(Tool Processing)
    • TNS(Temporal Noise Shaping):时间域噪声整形
    • PNS(Perceptual Noise Substitution):噪声替代
    • IS(Intensity Stereo) / MS(Mid/Side Stereo):立体声压缩技术
  4. IMDCT(Inverse Modified Discrete Cosine Transform)
    • 将频域数据转为时域样本
  5. 窗函数与重叠相加(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 Profileint 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) {// 检查同步字 0xFFFif ((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 裸流 的帧封装格式,适合流式播放。
  • 帧头信息提供了解码所需的全部参数。
  • 在网络传输中,解码器只需找到同步字并解析帧头,就能从任意位置开始播放。
http://www.xdnf.cn/news/17686.html

相关文章:

  • Graham 算法求二维凸包
  • Python 2025:最新技术趋势与展望
  • 每日五个pyecharts可视化图表-line:从入门到精通 (2)
  • lesson34:深入理解Python线程:从基础到实战优化
  • jupyter notebook如何打开其他盘目录
  • MCP学习与实践
  • [激光原理与应用-222]:机械 - 3D设计与2D设计的异同比较
  • Linux 虚拟机磁盘空间占满-全面清理方案
  • Cesium1.95中如何高效管理 1500 个高频实体
  • 赋值运算符指南
  • 代码可读性与维护性的实践与原则
  • word中,添加新的参考文献后,其他参考文献的交叉引用不能及时更新的解决办法
  • 《Webpack与Vite热模块替换机制深度剖析与策略抉择》
  • 二维前缀和问题
  • 如何在 Ubuntu 24.04 LTS Linux 上安装 MySQL 服务器
  • 电脑本地摄像头做成rtsp流调用测试windows系统中
  • 【大智慧数据】心智开花的时候
  • AI测试助手如何让Bug无处可藏
  • Dify 从入门到精通(第 26/100 篇):Dify 的知识图谱集成
  • 2025最新免费的大模型和免费的大模型API有哪些?(202508更新)
  • 2025年6月电子学会全国青少年软件编程等级考试(Python二级)真题及答案
  • 【Linux指南】Vim的全面解析与深度应用
  • C语言第八章指针四
  • 【接口自动化】初识pytest,一文讲解pytest的安装,识别规则以及配置文件的使用
  • Jotai:React轻量级状态管理新选择
  • Code Exercising Day 10 of “Code Ideas Record“:StackQueue part02
  • SQL三剑客:DELETE、TRUNCATE、DROP全解析
  • CentOS7.9 离线安装mysql数据库
  • CPP继承
  • Windows执行kubectl提示拒绝访问【Windows安装k8s】