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

音视频学习(五十二):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.lryc.cn/news/616282.html

相关文章:

  • 集成电路学习:什么是Parameter Server参数服务器
  • 比特币现货和比特币合约的区别与联系
  • 联邦学习之------VT合谋
  • 刑法视野下的虚拟财产属性争议:法律风险与市场潜力解析
  • 机器学习——TF-IDF 衡量词语在文档中重要程度
  • MySQL 序列使用详细说明
  • SpringIoc 实践和应用--XML配置
  • PHP版本控制系统:高效文档管理
  • MVC结构变种——第三章核心视图及控制器的整体逻辑
  • 计算机网络---IP(互联网协议)
  • 学习分库分表的前置知识:高可用系统架构理论与实践
  • Android视图回调机制:从post到ViewTreeObserver,从源码分析到最佳实践
  • java组件漏洞
  • 【在线五子棋对战】十二、http请求处理
  • 从 GPT‑2 到 gpt‑oss:解析架构的迭代
  • C++移动语义、完美转发及编译器优化零拷贝
  • win11(RTX5060)下进行nanodetplus训练
  • 2025年全国青少年信息素养大赛Scratch编程践挑战赛-小低组-初赛-模拟题
  • 动态工作流:目标结构源自表
  • 红楼梦文本数据分析
  • SpringBoot实现文件上传
  • CART算法:Gini指数
  • sqli-labs-master/Less-62~Less-65
  • 人工智能正在学习自我提升的方式
  • 《算法导论》第 17 章 - 摊还分析
  • 谷歌DeepMind发布Genie 3:通用型世界模型,可生成前所未有多样化的交互式虚拟环境
  • UE什么贴图要关闭SRGB
  • Virtio 驱动初始化数据收发流程详解
  • 太极行业观察:从传统技艺到数字化转型的演变|创客匠人
  • 【R studio数据分析】准备工作——下载安装