AAC ADTS 帧结构信息

AAC ADTS(Audio Data Transport Stream)帧格式

ADTS 帧结构图

复制代码
┌─────────────────────────────────────────────────────────┐
│                         ADTS 帧                          │
├─────────┬─────┬─────┬─────┬─────┬─────┬─────┬───────────┤
│         │     │     │     │     │     │     │           │
│同步字   │帧头 │帧头 │帧头 │帧头 │帧头 │帧头 │           │
│(12 bits)│(16  │(16  │(16  │(16  │(16  │(16  │  AAC      │
│         │bits)│bits)│bits)│bits)│bits)│bits)│ 载荷数据  │
│         │     │     │     │     │     │     │           │
├─────────┼─────┴─────┴─────┴─────┴─────┴─────┼───────────┤
│ syncword│ header                            │ raw data  │
│         │ (56 bits)                         │ block     │
└─────────┴───────────────────────────────────┴───────────┘

详细的 ADTS 帧头结构(7字节/56位)

字节布局:

复制代码
字节 0-1: ┌─────────┬─────────┬─────────┬─────────┐
          │ syncword │ MPEG版本│ 层      │ 保护    │
          │ (12 bits)│ (1 bit) │ (2 bits)│ (1 bit) │
          └─────────┴─────────┴─────────┴─────────┘

字节 2:   ┌─────────┬─────────┬─────────┬─────────┐
          │ 配置索引 │ 采样率  │ 私有位  │ 声道数  │
          │ (2 bits)│ (4 bits)│ (1 bit) │ (3 bits)│
          └─────────┴─────────┴─────────┴─────────┘

字节 3-4: ┌─────────┬─────────┬─────────┬─────────┐
          │ 原始度  │ 帧长度  │ 帧长度  │ 帧长度  │
          │ (1 bit) │ (高位)  │ (中位)  │ (低位)  │
          │         │ (2 bits)│ (8 bits)│ (3 bits)│
          └─────────┴─────────┴─────────┴─────────┘

字节 5-6: ┌───────────────────────────────────────┐
          │ 缓冲区满度 (11 bits)                  │
          │   + 帧数 (2 bits)                    │
          │   + CRC校验 (16 bits) [可选]         │
          └───────────────────────────────────────┘

每个字段的详细说明

1. 同步字(Syncword,12位)

  • 固定值:0xFFF (二进制:111111111111)
  • 用于帧同步,标志ADTS帧的开始

2. MPEG版本(1位)

  • 0 = MPEG-4
  • 1 = MPEG-2

3. 层(Layer,2位)

  • 对于AAC:总是 00

4. 保护位(Protection Absent,1位)

  • 1 = 没有CRC校验
  • 0 = 有CRC校验(16位CRC在帧头末尾)

5. 配置索引(Profile,2位)

复制代码
00 = AAC Main
01 = AAC LC (Low Complexity) - 最常用
10 = AAC SSR (Scalable Sample Rate)
11 = AAC LTP (Long Term Prediction)

6. 采样率索引(Sampling Frequency Index,4位)

复制代码
0000 = 96000 Hz     1000 = 8000 Hz
0001 = 88200 Hz     1001 = 7350 Hz
0010 = 64000 Hz     1010 = Reserved
0011 = 48000 Hz     1011 = Reserved
0100 = 44100 Hz     1100 = Reserved
0101 = 32000 Hz     1101 = Reserved
0110 = 24000 Hz     1110 = Reserved
0111 = 22050 Hz     1111 = Escape value

7. 私有位(Private Bit,1位)

  • 私有使用,通常设置为 0

8. 声道配置(Channel Configuration,3位)

复制代码
000 = 未定义/自定义
001 = 1声道:中置
010 = 2声道:左、右
011 = 3声道:左、右、中置
100 = 4声道:左、右、中置、环绕
101 = 5声道:左、右、中置、左环绕、右环绕
110 = 5.1声道:左、右、中置、左环绕、右环绕、LFE
111 = 7.1声道:左、右、中置、左环绕、右环绕、左后环绕、右后环绕、LFE

9. 原始度/版权(Originality/Copyright,1位)

  • 0 = 原始拷贝
  • 1 = 原始内容

10. 帧长度(Frame Length,13位)

  • 表示整个ADTS帧的长度(包括头部)
  • 单位:字节
  • 计算公式:帧长度 = (protection_absent ? 7 : 9) + AAC数据长度

11. 缓冲区满度(Buffer Fullness,11位)

  • 表示编码器缓冲区的满度
  • 值越大表示缓冲区越满
  • 固定比特率(CBR)时通常为 0x7FF

12. 帧数(Number of AAC Frames,2位)

  • 每个ADTS帧中包含的AAC帧数
  • 通常为 0(每ADTS帧包含1个AAC帧)

13. CRC校验(可选,16位)

  • 仅当保护位为 0 时存在
  • 对整个ADTS帧(包括头部)进行CRC校验

C++ 代码实现:ADTS头生成

cpp 复制代码
#include <cstdint>
#include <cstring>

class ADTSHeader {
private:
    uint8_t header[7];
    
public:
    // 生成ADTS头
    void generate(int sample_rate, int channels, int aac_length, int profile = 1) {
        // 默认:AAC LC, 无CRC保护
        
        // 采样率索引
        uint8_t freq_idx = 4; // 默认44100Hz
        switch (sample_rate) {
            case 96000: freq_idx = 0; break;
            case 88200: freq_idx = 1; break;
            case 64000: freq_idx = 2; break;
            case 48000: freq_idx = 3; break;
            case 44100: freq_idx = 4; break;
            case 32000: freq_idx = 5; break;
            case 24000: freq_idx = 6; break;
            case 22050: freq_idx = 7; break;
            case 16000: freq_idx = 8; break;
            case 12000: freq_idx = 9; break;
            case 11025: freq_idx = 10; break;
            case 8000: freq_idx = 11; break;
            case 7350: freq_idx = 12; break;
        }
        
        // 声道配置
        uint8_t chan_config = channels;
        if (channels == 1) chan_config = 1;  // 单声道
        else if (channels >= 2) chan_config = 2; // 立体声
        
        // 计算帧长度(头部7字节 + AAC数据长度)
        uint32_t frame_length = aac_length + 7;
        
        // 构造ADTS头
        // 字节1:同步字高8位 + MPEG版本 + 层 + 保护位
        header[0] = 0xFF;  // 同步字高8位
        
        // 字节2:同步字低4位 + 配置索引 + 采样率索引高1位
        header[1] = 0xF1;  // 同步字低4位(1111) + 保护位(1) + 层(00) + MPEG-4(0)
        header[1] |= ((profile & 0x03) << 6);  // 设置配置索引
        
        // 字节3:采样率索引低3位 + 私有位 + 声道配置高1位
        header[2] = ((freq_idx & 0x0F) << 2);  // 采样率索引
        header[2] |= ((chan_config & 0x07) >> 1);  // 声道配置高1位
        
        // 字节4:声道配置低2位 + 原始度 + 帧长度高2位
        header[3] = ((chan_config & 0x07) << 6);  // 声道配置低2位
        header[3] |= ((frame_length & 0x1800) >> 11);  // 帧长度高2位
        
        // 字节5:帧长度中8位
        header[4] = ((frame_length & 0x07F8) >> 3);  // 帧长度中8位
        
        // 字节6:帧长度低3位 + 缓冲区满度高3位
        header[5] = ((frame_length & 0x0007) << 5);  // 帧长度低3位
        header[5] |= 0x1F;  // 缓冲区满度高3位(设为最大值)
        
        // 字节7:缓冲区满度低8位 + 帧数
        header[6] = 0xFC;  // 缓冲区满度低8位 + 帧数(0)
    }
    
    // 获取ADTS头数据
    const uint8_t* getHeader() const {
        return header;
    }
    
    // 获取ADTS头长度(固定7字节)
    static constexpr int getHeaderSize() {
        return 7;
    }
    
    // 打印ADTS头信息
    void printInfo() const {
        printf("ADTS Header:\n");
        printf("  Syncword: 0xFFF\n");
        printf("  Protection absent: %d\n", (header[1] & 0x01));
        printf("  Profile: %d\n", (header[1] >> 6) & 0x03);
        printf("  Sampling freq index: %d\n", (header[2] >> 2) & 0x0F);
        printf("  Channel config: %d\n", ((header[2] & 0x01) << 2) | ((header[3] >> 6) & 0x03));
        printf("  Frame length: %d\n", 
               ((header[3] & 0x03) << 11) | 
               (header[4] << 3) | 
               ((header[5] >> 5) & 0x07));
    }
};

使用示例

cpp 复制代码
// 在编码AAC时添加ADTS头
void encodeWithADTS(AVCodecContext* ctx, AVPacket* pkt, FILE* output) {
    // 编码得到AAC数据包
    // ...
    
    // 生成ADTS头
    ADTSHeader adts;
    adts.generate(ctx->sample_rate, 
                  ctx->channels,  // 或 ctx->ch_layout.nb_channels (新版本)
                  pkt->size,
                  1);  // AAC LC profile
    
    // 写入ADTS头
    fwrite(adts.getHeader(), 1, ADTSHeader::getHeaderSize(), output);
    
    // 写入AAC数据
    fwrite(pkt->data, 1, pkt->size, output);
}

ADTS与原始AAC的区别

ADTS格式的优点:

  1. 自包含:每个帧都包含解码所需的所有信息
  2. 流式友好:适合网络流媒体传输
  3. 容错性好:通过同步字可以重新同步
  4. 无需全局头:可以在任意位置开始解码

原始AAC格式:

  1. 没有ADTS头,只有纯AAC数据
  2. 需要外部提供配置信息(采样率、声道数等)
  3. 更节省空间(每个帧节省7字节)
  4. 需要容器格式(如MP4、TS)来携带元数据

ADTS在FFmpeg中的使用

cpp 复制代码
// 设置编码器标志
codec_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;

// 在编码时检查是否需要添加ADTS头
void writeAudioFrame(AVCodecContext* ctx, AVPacket* pkt, FILE* output) {
    if (ctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) {
        // 需要手动添加ADTS头
        uint8_t adts_header[7];
        get_adts_header(ctx, adts_header, pkt->size);
        fwrite(adts_header, 1, 7, output);
    }
    
    fwrite(pkt->data, 1, pkt->size, output);
}
相关推荐
星融元asterfusion6 小时前
uCentral Controller:数据中心网络的智能化控制核心
网络·开源软件·ucentral
Zsy_0510037 小时前
【数据结构】二叉树OJ
数据结构
青青草原技术员灰太狼7 小时前
Nginx的https搭建
linux·服务器·网络
xu_yule7 小时前
网络和Linux网络-4(应用层)序列化和反序列化(网络计算器)
linux·网络
柳鲲鹏8 小时前
寻北仪的种类及其原理
网络
寂寞旅行8 小时前
解决摄像头/麦克风 在HTTP环境下的调用问题
网络·网络协议·http
爱学习的程序媛8 小时前
《图解HTTP》核心知识点梳理
网络·网络协议·http·https
oioihoii8 小时前
C++网络编程:从Socket混乱到优雅Reactor的蜕变之路
开发语言·网络·c++
程序员东岸8 小时前
《数据结构——排序(中)》选择与交换的艺术:从直接选择到堆排序的性能跃迁
数据结构·笔记·算法·leetcode·排序算法