RTP 之 AAC 封包和解包
根据课程视频整理:
161--5 RTP之AAC封包和解包1-软件框架分析.mp4162--5 RTP之AAC封包和解包2-原理和源码解析.mp4目标:讲清楚 AAC/ADTS、RTP payload、AU Header、时间戳计算、软件框架以及打包/解包流程。
1. 基础概念
AAC 是音频编码格式。开发中常见的 AAC 文件通常带 ADTS 头,每个 ADTS frame 由:
ADTS Header + AAC Raw Data
组成。
RTP 发送 AAC 时,通常不把 ADTS Header 原封不动地塞进 RTP payload,而是提取 AAC raw data,并按 RFC 3640 的方式添加 AU Header 信息。AU 是 Access Unit,可以理解为一个音频访问单元,通常对应一帧 AAC 音频数据。

2. 软件框架
课程的 AAC 部分先从软件框架入手,整体路径可以概括为:
读取 AAC 文件
解析 ADTS Header
拿到一帧 AAC raw data
调用 RTP AAC 打包函数
构造 RTP header
构造 AU headers
拷贝 AAC raw data
通过 socket 发送
接收端解析 RTP payload
恢复 AAC frame

代码里通常会拆成几类函数:
- 文件读取:负责从
.aac文件读取 ADTS frame。 - ADTS 解析:负责得到 profile、sample rate、channel、frame length。
- RTP 打包:负责生成 RTP header 和 AAC payload。
- RTP 发送:负责 UDP socket 发送。
- RTP 解包:负责从 payload 中取出 AU Header 和 AAC raw data。

3. ADTS Header
ADTS Header 里保存了 AAC 帧的描述信息,常见字段包括:
| 字段 | 含义 |
|---|---|
| syncword | 同步头,通常是 0xFFF |
| profile | AAC profile,例如 AAC LC |
| sampling_frequency_index | 采样率索引 |
| channel_configuration | 声道配置 |
| aac_frame_length | ADTS header + AAC raw data 的总长度 |
读取 AAC 文件时,先通过 ADTS Header 得到当前帧长度,然后读出完整 frame。RTP 打包时通常要跳过 ADTS Header,只发送 AAC raw data。
aac_raw_len = aac_frame_length - adts_header_len
4. AAC RTP Payload 格式
常见 AAC over RTP payload 可以分成三段:
RTP Header | AU-headers-length | AU-header | AAC Raw Data
其中 RTP Header 是标准 RTP 头;AU-headers-length 和 AU-header 用来描述后面 AAC raw data 的长度等信息。

课程重点讲的字段:
AU-headers-length:2 字节,单位是 bit
AU-header:通常 2 字节,其中 13 bit 表示 AU-size
AAC Raw Data:真正的 AAC 音频负载
如果一个 RTP 包只承载一个 AAC AU,常见做法是:
AU-headers-length = 16
AU-header = 当前 AAC raw data 长度 << 3
因为 AU-header 长度是 16 bit,其中高 13 bit 是 AU-size,低 3 bit 可理解为 AU-Index 或相关索引位。

5. AU Header 构造
假设 AAC raw data 长度是 len,AU Header 常见构造方式:
payload[0] = 0x00;
payload[1] = 0x10; // AU-headers-length = 16 bits
payload[2] = (len & 0x1fe0) >> 5;
payload[3] = (len & 0x1f) << 3;
memcpy(payload + 4, aac_raw_data, len);
对应结构:
payload[0..1] AU-headers-length
payload[2..3] AU-header
payload[4..] AAC raw data

这里最容易混淆的是单位:AU-headers-length 的单位是 bit,不是字节。一个 AU-header 如果占 2 字节,也就是 16 bit,所以值写 0x0010。
6. Timestamp 计算
AAC RTP timestamp 使用音频采样率作为时钟。例如采样率是 44100Hz,一个 AAC LC frame 通常包含 1024 个采样点,那么每发送一帧 AAC,timestamp 增量通常是:
1024
这和 H.264 视频常用 90000Hz 时钟不同。视频 timestamp 常按帧率计算,而 AAC timestamp 通常按每帧采样点数推进。

常见例子:
sample rate = 44100
one AAC frame = 1024 samples
RTP timestamp increment = 1024
如果音频是 48000Hz,timestamp 时钟就是 48000Hz,但 AAC LC 一帧仍通常推进 1024 个采样点。

7. AAC RTP 发送流程
发送端可以按这个流程写:
打开 AAC 文件
while 读取一帧 ADTS:
解析 ADTS Header
计算 AAC raw data 偏移和长度
填 RTP Header
填 AU-headers-length
填 AU-header
拷贝 AAC raw data
发送 RTP 包
sequence number += 1
timestamp += 1024

RTP Header 里需要关注:
| 字段 | AAC 中的用法 |
|---|---|
| Payload Type | 动态类型常见为 96,也要和 SDP 对上 |
| Sequence Number | 每发送一个 RTP 包加 1 |
| Timestamp | 每个 AAC frame 按采样点推进,常见加 1024 |
| SSRC | 同一路音频流保持一致 |
| Marker | 音频里通常不像视频那样强依赖一帧结束标记 |
8. AAC RTP 解包流程
接收端解析 RTP payload:
跳过 RTP Header
读取 AU-headers-length
根据 AU-headers-length 计算 AU-header 字节数
读取 AU-header,得到 AU-size
按 AU-size 取出 AAC raw data
需要写回 .aac 文件时,重新补 ADTS Header
交给解码器时,按解码器要求决定是否补 ADTS Header

如果要把 RTP 解出的数据保存成可播放的 .aac 文件,一般要重新写 ADTS Header:
ADTS Header | AAC Raw Data
ADTS Header | AAC Raw Data
ADTS Header | AAC Raw Data
...
如果直接送给某些解码器,则可能只需要 raw data,具体取决于解码器输入格式。
9. SDP 中的 AAC 配置
RTSP 的 DESCRIBE 响应里,SDP 会告诉客户端音频流的参数。AAC 常见字段包括:
m=audio ... RTP/AVP 96
a=rtpmap:96 MPEG4-GENERIC/44100/2
a=fmtp:96 ...
其中:
MPEG4-GENERIC表示 AAC 这类 MPEG-4 音频通用 RTP payload。44100是采样率。2是声道数。fmtp中会出现 profile、mode、config、sizeLength、indexLength 等参数。

客户端必须让 SDP 参数和实际 RTP payload 对上,否则可能出现能收到包但无法解码的问题。
10. 调试要点
调试 AAC over RTP 时按下面检查:
- ADTS frame length 是否解析正确。
- RTP payload 里是否跳过了 ADTS Header。
AU-headers-length是否为 bit 单位。- AU-size 是否等于 AAC raw data 长度。
- RTP timestamp 是否每帧加 1024。
- RTP payload type 是否和 SDP 中
rtpmap/fmtp一致。 - sample rate、channel、profile 是否和 ADTS/SDP 一致。
- 解包保存
.aac文件时是否重新补了 ADTS Header。
最后可以这样记:
AAC over RTP:ADTS 负责文件帧描述,RTP 发送 raw data;payload 前面加 AU Header 说明 raw data 长度。
评论
...正在读取评论。