AC3(Audio Coding 3),杜比第三代音频编码格式,也称杜比数字。
- 声道配置:支持单声道、立体声、5.1 环绕声(左 / 右 / 中置 / 左后 / 右后 + 低音炮 LFE)
- 码率范围:32kbit/s ~ 640kbit/s,DVD / 蓝光常用 384k、448k
- 文件后缀:
.ac3原始音频流
EAC3 = Enhanced AC3(DD+ 杜比数字加) AC3 增强升级版,标准 A/52 Annex E,2005 年标准化,裸流后缀 .ec3, EAC3讲另外介绍,本文主要介绍AC3格式。
AC3文件格式:

该图很详细,引用:原创桓泽学音频编解码(2):AC3/Dolby Digital 系统算法分析-CSDN博客
一、SI信息(固定5字节)
cpp
SI 帧头 (5字节)
│
├─► syncword (2字节) ──► 验证帧开始
│
├─► CRC1 (2字节) ──► CRC校验字节
│
├─► buf[4] (1字节) ──┬─► fscod(2位) → 采样率
│ └─► frmsizecod(6位) → 帧大小码
1.1 同步字节
AC-3 帧以固定同步字 0x0B77 开头,这是识别帧边界的关键。
cpp
if ((buf[0] != 0x0b) || (buf[1] != 0x77)) // syncword
return 0;
1.2 CRC1
该 16 位 CRC 用于前 5/8 的同步帧数据段的校验。CRC 校验码采用大端模式传输。
1.3 采样率计算
帧大小计算公式由 AC-3 标准定义,与采样率和比特率相关。
fscode:主要用于采用率的计算;
cpp
位布局: | fscod[1:0] | frmsizecod[5:0] |
7 6 5 4 3 2 1 0
switch (buf[4] & 0xc0) {
case 0: // 48kHz
*sample_rate = 48000 >> half;
return 4 * bitrate;
case 0x40: // 44.1kHz
*sample_rate = 44100 >> half;
return 2 * (320 * bitrate / 147 + (frmsizecod & 1));
case 0x80: // 32kHz
*sample_rate = 32000 >> half;
return 6 * bitrate;
}

1.3 比特率计算
AC-3 支持 19 种标准比特率(32kbps ~ 640kbps),通过 frmsizecod 查表获取。
cpp
位布局: | fscod[1:0] | frmsizecod[5:0] |
7 6 5 4 3 2 1 0
static int rate[] = {32, 40, 48, 56, 64, 80, 96, 112,
128, 160, 192, 224, 256, 320, 384, 448,
512, 576, 640};
frmsizecod = buf[4] & 63;
bitrate = rate[frmsizecod >> 1];
*bit_rate = (bitrate * 1000) >> half;
frmsizecod: 共 6 位,高 5 位用于索引比特率表,最低位用于帧大小计算。在标准文档中有一张表直接映射关系。
二、BSI信息(可变)
cpp
┌───────────────────────────────────────────────────────── BSI 整体 ─────────────────────────────────────────────────┐
│ 固定必读基础段(无条件全部存在) │
│ ├─ bsid 5bit │
│ ├─ bsmod 3bit │
│ ├─ acmod 3bit │
│ │
│ 条件分支1:if ((acmod & 0x1) && acmod != 0x1) 存在三前置LCR声道 │
│ ├─ [cmixlev] 2bit │
│ 条件分支2:if (acmod & 0x4) 存在环绕声道 │
│ ├─ [surmixlev] 2bit │
│ 条件分支3:if (acmod == 0x2) 纯3.0 LCR模式 │
│ ├─ [dsurmod] 2bit │
│ │
│ 继续固定必读段 │
│ ├─ lfeon 1bit │
│ ├─ dialnorm 5bit │
│ ├─ compre 1bit │
│ │ └─ 条件分支4:if(compre=1) │
│ │ └─ [compr] 8bit │
│ ├─ langcode 1bit │
│ │ └─ 条件分支5:if(langcode=1) │
│ │ └─ [langcod] 8bit │
│ ├─ audprodie 1bit │
│ │ └─ 条件分支6:if(audprodie=1) │
│ │ ├─ [mixlevel] 5bit │
│ │ └─ [roomtyp] 2bit │
│ │
│ 条件分支7:if (acmod == 0) 双单声道 1+1 专属段 │
│ ├─ [dialnorm2] 5bit │
│ ├─ [compr2e] 1bit │
│ │ └─ if(compr2e=1) → [compr2] 8bit │
│ ├─ [langcod2e] 1bit │
│ │ └─ if(langcod2e=1) → [langcod2] 8bit │
│ ├─ [audprodi2e] 1bit │
│ │ └─ if(audprodi2e=1) │
│ │ ├─ [mixlevel2] 5bit │
│ │ └─ [roomtyp2] 2bit │
│ │
│ 继续固定必读段 │
│ ├─ copyrightb 1bit │
│ ├─ origbs 1bit │
│ ├─ timecod1e 1bit │
│ │ └─ if(timecod1e=1) → [timecod1] 14bit │
│ ├─ timecod2e 1bit │
│ │ └─ if(timecod2e=1) → [timecod2] 14bit │
│ ├─ addbsie 1bit │
│ │ └─ 条件分支8:if(addbsie=1) │
│ │ ├─ addbsil 6bit │
│ │ └─ addbsi (addbsil+1)×8 bit (动态长度 ?) │
└────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
2.1 比特流版本检查
bsid: buf[5] 的高 5 位是 bsid(比特流识别码),对于AC3,值 >= 12 表示不支持的版本;EAC3支持>=12的值。
除非该码流按照AC3标准任一附录规范构建,否则该比特字段(bsid)取值应为01000(十进制 8)。若读取到bsid 大于 8 ,应静音输出(解码器若额外兼容EAC3除外); 若读取到bsid 小于等于 8,则应对音频进行解码并正常播放。
半采样率处理:
某些 AC-3 流使用半采样率(如 24kHz),需根据 bsid 确定降采样因子。
cpp
static uint8_t halfrate[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3};
half = halfrate[buf[5] >> 3];
bsid 还可以用来区分是AC3还是EAC3,
|----------|------------|-----------|
| bsid | half 值 | 实际采样率 |
| 0-8 | 0 | 标准采样率 |
| 9 | 1 | 标准/2 |
| 10 | 2 | 标准/4 |
| 11 | 3 | 标准/8 |
2.2 比特率模式
cpp
bsmod = buf[5] & 7

2.3 声道配置解
- acmod:声道模式(单声道/立体声/5.1等)
A52_DOLBY:杜比环绕声特殊标识
A52_LFE:是否包含低频效果声道
cpp
acmod = buf[6] >> 5; // 音频模式(前3位)
*flags = ((((buf[6] & 0xf8) == 0x50) ? A52_DOLBY : acmod) |
((buf[6] & lfeon[acmod]) ? A52_LFE : 0));

2.3.1 cmixlev 中置混音增益
当解码器仅输出双声道立体声时,控制中置 (C) 声道混入左右前置声道的衰减幅度,避免人声过重 / 过轻。
| cmixlev 值 | 衰减量 | 用途说明 |
|---|---|---|
| 00 | 0.707 (--3.0 dB) | 中置人声混入立体声音量更大,对白突出 |
| 01 | 0.595 (--4.5 dB) | DVD / 影视通用标准值,均衡自然 |
| 10 | 0.500 (--6.0 dB) | 压低中置人声,前置左右声道为主 |
| 11 | 保留 | 解码器默认按 - 4.5dB 处理 |
2.3.2 surmixlev: Surround Mix Level 环绕混声增益
多声道音轨向下兼容立体声 2.0 输出时,控制环绕声道(LS/RS/S) 混入左右主声道的衰减量,平衡前后声场音量。
2.3.3 dsurmod: Dolby Surround Mode 杜比混声增益
标记当前 2.0 母带立体声是否经过杜比模拟矩阵编码(Dolby Surround / Pro Logic / Pro Logic II),给后端功放 / 解码器提示:是否启用矩阵解码,从双声道分离出中置、后置环绕声道。 AC3 数字解码器本身不依赖此字段运算,主要供 AV 功放、播放设备的环绕扩展逻辑使用。
2.4 lfeon (Low Frequency Effects Channel on)低频效果声道启用标志
- lfeon=1:解码时分配独立低频声道缓冲区,输出信号到低音炮通道;
- lfeon=0:不存在 LFE 数据,解码器不生成低频轨道;
- 若播放设备无低音炮,解码器会把 LFE 低频分量按规则混入左右前置声道。
| acmod | 主声道布局 | lfeon=0 | lfeon=1 |
|---|---|---|---|
| 001(1) | LR 立体声 | 2.0 | 2.1 |
| 010(2) | LCR 三前置 | 3.0 | 3.1 |
| 011(3) | LCR+LS RS | 4.0 | 4.1 |
| 100(4) | LCRS | 4.0 | 4.1 |
| 101(5) | L C R LS RS | 5.0 | 5.1(标准影院配置) |
2.5 dialnorm: Dialogue Normalization,对白归一化
记录影片人声对白的平均响度基准,用于统一不同片源播放音量,解决一部电影音量大、另一部音量小的问题
对白基准响度(单位 dBFS): Dialogue Level=−4−(dialnorm×2)
其它属性,本文章不接着详细介绍,具体可以参考标准文档,
三、audblk: Audio Block
单音频块语法层级结构图, 一帧有固定的6个AudioBlock,需要循环解码
cpp
┌──────────────────────────────────────────────── audblk() 单个AudioBlock ──────────────────────────────────────────────┐
│ 1. 块切换与抖动标志(所有声道必读)
│ ├─ for ch 0~nfchans-1: blksw[ch] 1bit // MDCT长短块切换标志
│ └─ for ch 0~nfchans-1: dithflag[ch] 1bit // 量化抖动开关
│
│ 2. 动态范围控制
│ ├─ dynrnge 1bit
│ │ └─ [dynrnge=1] → dynrng 8bit // 主声道动态压缩参数
│ └─ [acmod == 0 双单声道]
│ ├─ dynrng2e 1bit
│ └─ [dynrng2e=1] → dynrng2 8bit // 第二单声道独立动态参数
│
│ 3. 声道耦合策略(高频多声道合并压缩核心)
│ ├─ cplstre 1bit // 是否存在耦合数据
│ │ └─ [cplstre=1]
│ │ ├─ cplinu 1bit // 本块启用耦合
│ │ │ └─ [cplinu=1]
│ │ │ ├─ for ch 0~nfchans-1: chincpl[ch] 1bit // 该声道参与耦合
│ │ │ ├─ [acmod == 2] → phsflginu 1bit // 相位标志启用
│ │ │ ├─ cplbegf 4bit 耦合起始频带
│ │ │ ├─ cplendf 4bit 耦合结束频带
│ │ │ └─ for bnd 1~ncplsubnd-1: cplbndstrc[bnd] 1bit // 耦合子带结构
│
│ 4. 耦合系数、相位标志(仅开启耦合cplinu=1)
│ └─ [cplinu=1]
│ ├─ 遍历所有声道 ch
│ │ └─ [chincpl[ch]=1 该声道参与耦合]
│ │ ├─ cplcoe[ch] 1bit // 该声道存在耦合系数
│ │ │ └─ [cplcoe[ch]=1]
│ │ │ ├─ mstrcplco[ch] 2bit // 耦合主系数模式
│ │ │ └─ for bnd 0~ncplbnd-1: cplcoexp[ch][bnd]4bit + cplcomant[ch][bnd]4bit
│ └─ [acmod==2 && phsflginu && (cplcoe[0]||cplcoe[1])]
│ └─ for bnd 0~ncplbnd-1: phsflg[bnd] 1bit // 立体声耦合相位标记
│
│ 5. 立体声重矩阵 rematrix(仅acmod=2 三前置LCR声道)
│ └─ [acmod == 2]
│ ├─ rematstr 1bit // 是否开启重矩阵
│ │ └─ [rematstr=1]
│ │ ├─ cplbegf>2 或 cplinu=0 → for rbnd0~3 rematflg[rbnd]1bit
│ │ ├─ 0<cplbegf≤2 && cplinu=1 → for rbnd0~2 rematflg[rbnd]1bit
│ │ └─ cplbegf==0 && cplinu=1 → for rbnd0~1 rematflg[rbnd]1bit
│
│ 6. 指数编码策略(频带幅度粗量化模式)
│ ├─ [cplinu=1] → cplexpstr 2bit // 耦合声道指数策略
│ ├─ for ch 0~nfchans-1: chexpstr[ch] 2bit // 各独立声道指数策略
│ ├─ [lfeon=1] → lfeexpstr 1bit // 低音LFE指数策略
│ └─ 遍历所有声道 ch
│ └─ [chexpstr[ch] != reuse 不复用前块指数]
│ └─ [chincpl[ch]==0 非耦合声道] → chbwcod[ch]6bit // 声道带宽编码
│
│ 7. 指数数据 exponents(频带幅度粗值)
│ ├─ [cplinu=1 耦合声道指数区]
│ │ └─ [cplexpstr != reuse]
│ │ ├─ cplabsexp 4bit
│ │ └─ for grp0~ncplgrps-1: cplexps[grp]7bit
│ ├─ 遍历全频声道 ch
│ │ └─ [chexpstr[ch] != reuse]
│ │ ├─ exps[ch][0] 4bit
│ │ ├─ for grp1~nchgrps[ch]: exps[ch][grp]7bit
│ │ └─ gainrng[ch] 2bit
│ └─ [lfeon=1 LFE低音指数]
│ └─ [lfeexpstr != reuse]
│ ├─ lfeexps[0]4bit
│ └─ for grp1~2: lfeexps[grp]7bit
│
│ 8. 比特分配心理声学参数(bit allocation 核心)
│ ├─ baie 1bit // 是否存在比特分配扩展参数
│ │ └─ [baie=1]
│ │ ├─ sdcycod 2bit, fdcycod 2bit
│ │ ├─ sgaincod 2bit, dbpbcod 2bit, floorcod 3bit
│ ├─ snroffste 1bit // 信噪比偏移启用
│ │ └─ [snroffste=1]
│ │ ├─ csnroffst 6bit
│ │ ├─ [cplinu=1] → cplfsnroffst4bit + cplfgaincod3bit
│ │ ├─ for ch: fsnroffst[ch]4bit, fgaincod[ch]3bit
│ │ └─ [lfeon=1] → lfefsnroffst4bit, lfefgaincod3bit
│ └─ [cplinu=1]
│ ├─ cplleake 1bit
│ └─ [cplleake=1] → cplfleak3bit, cplsleak3bit
│
│ 9. 差分比特分配 delta bit allocation
│ ├─ deltbaie 1bit // 差分分配参数启用
│ │ └─ [deltbaie=1]
│ │ ├─ [cplinu=1] → cpldeltbae 2bit
│ │ ├─ for ch: deltbae[ch] 2bit
│ │ ├─ [cpldeltbae==新分段]
│ │ │ ├─ cpldeltnseg3bit
│ │ │ └─ for seg0~cpldeltnseg: cpldeltoffst5 / cpldeltlen4 / cpldeltba3
│ │ └─ 遍历声道 ch
│ │ └─ [deltbae[ch]==新分段]
│ │ ├─ deltnseg[ch]3bit
│ │ └─ for seg0~deltnseg[ch]: deltoffst5 / deltlen4 / deltba3
│
│ 10. 填充跳过数据 dummy skip 填充位
│ ├─ skiple 1bit
│ │ └─ [skiple=1]
│ │ ├─ skipl 9bit
│ │ └─ skipfld 长度=skipl×8 bit 空白占位比特
│
│ 11. 量化尾数 mantissas 音频原始频域系数(音频核心载荷)
│ ├─ got_cplchan=0 标记位
│ ├─ 遍历所有声道 ch
│ │ ├─ for bin0~nchmant[ch]-1: chmant[ch][bin] 变长0~16bit
│ │ └─ [cplinu && chincpl[ch] && !got_cplchan]
│ │ ├─ for bin0~ncplmant-1: cplmant[bin] 0~16bit
│ │ └─ got_cplchan=1 避免重复读取耦合尾数
│ └─ [lfeon=1 低音声道尾数]
│ └─ for bin0~nlfemant-1: lfemant[bin] 0~16bit
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
注:
数字:字段占用比特
[]:条件分支,判断成立才读取
循环 for():多声道 / 多频带重复读取
变长 (0--16):mantissa 尾数动态比特宽度
nfchans:有效全频声道数量,由 BSI acmod 推导
3.1 块切换与抖动标志(blksw /dithflag)
- blksw(Block Switch)长短 MDCT 切换
- 0:长块(512 点 MDCT),适合平稳人声、背景音乐,频率分辨率高;
- 1:短块(256 点 MDCT),适合冲击音(爆炸、敲击),抑制时域混叠失真。 每个声道可独立选择长短块。
- dithflag 量化抖动开关 1 = 开启抖动,低音量细微信号增加随机噪声,消除量化底噪失真;0 = 关闭,节省码率。
3.2. 动态范围控制(dynrnge /dynrng/dynrng2)
针对单块独立动态范围调节(区别 BSI 全局 compr):
- dynrnge=1 时,8bit dynrng 定义本块强弱音量压缩曲线,爆炸、轰鸣自动压低峰值,小声对白放大;
- acmod=0 双单声道 1+1,左右两路独立音频,dynrng2 给第二声道单独动态参数;
- 仅作用当前 audblk,逐块动态调整,比 BSI 全局压缩更精细。
3.3. 声道耦合策略 cplstre /cplinu/chincpl (AC3 核心码率压缩手段)
人耳对高频方位不敏感,把多个声道高于某频点的高频信号合并为一条公共耦合声道编码,大幅节省比特。
- cplstre:1 = 本块存在耦合相关数据;0 = 无耦合,跳过全部耦合逻辑;
- cplinu:1 = 本块启用声道耦合;
- chincpl ch:标记该声道是否参与高频耦合;
- cplbegf /cplendf:耦合起始、终止频带号,低于 cplbegf 的低频独立编码,高于则合并;
- cplbndstrc:耦合子带划分标记,拆分耦合区间用于量化;
- phsflginu(仅 acmod=2 三声道):立体声耦合相位标志启用开关,用于还原左右声场相位。
3.4 耦合系数与相位标志 cplcoe /mstrcplco/phsflg
- cplcoe:该参与耦合的声道是否需要独立耦合系数;
- mstrcplco:耦合系数计算模式(主声道基准缩放);
- cplcoexp + cplcomant:每个耦合子带的幅度指数、幅度尾数,描述该声道相对于公共耦合声道的增益比例;
- phsflg(仅 acmod=2):耦合高频相位标记,解码时恢复立体声左右分离度,避免高频单声道模糊。
3.5 立体声重矩阵 rematrix(仅 acmod=2 LCR 三前置声道)
rematstr=1 开启重矩阵,rematflg 按频带标记是否启用矩阵解耦: 将混在左右声道里的中置人声、环绕信息重新分离还原,修复声场分离度; 根据耦合起始频带 cplbegf 不同,读取不同数量频带标记。
3,6 指数编码策略 expstr /chbwcod
exponent(指数)代表每个频带信号幅度粗量化值,是频域数据的音量基准。 策略分为 4 种模式:全部复用、分组复用、新指数、差值编码,用来减少指数占用比特。
- cplexpstr:耦合声道指数复用策略;
- chexpstr ch:每个独立全频声道指数策略;
- lfeexpstr:LFE 低音声道指数策略;
- chexpstr != reuse(不复用上一块指数)且声道不参与耦合时,读取 chbwcod 声道带宽编码:定义该声道有效最高频带,高于该频带无音频数据,不用编码,节约码率。
3.7 指数数据 exponents(频带幅度粗值)
耦合声道指数、全频声道指数、LFE 低音指数
指数是频域系数的缩放基准:频域幅值 = mantissa 尾数 × 2^exponent
- cplabsexp:耦合声道首组基准指数;cplexps:各组差分指数;
- exps ch0:独立声道首频带基准指数,后续分组差分存储;gainrng:本声道动态增益范围修正;
- LFE 低音独立一套指数,低频单独量化。 指数只存储粗略音量,精细波形由后续 mantissa 尾数表示。
3.8 心理声学基础比特分配参数 baie /snroffst/cplleak
AC3 心理声学核心模块,决定每个频带分配多少量化比特
3.8.1 baie 基础噪声遮蔽参数(baie=1 才存在)
sdcycod /fdcycod/sgaincod /dbpbcod/floorcod 控制人耳掩蔽曲线、高低频衰减、噪声基底,编码器据此计算每个频带允许的噪声,分配对应比特。
3.8.2 snroffste 信噪比偏移
csnroffst、fsnroffst ch、lfefsnroffst:全局 / 各声道信噪比偏移,微调掩蔽阈值; cplfgaincod/fgaincod:耦合 / 独立声道增益修正。
3.8.3 cplleake 耦合泄漏补偿
耦合高频合并后会有声场泄漏,cplfleak/cplsleak 补偿左右声道串音,恢复声场定位。
3.9 差分比特分配 deltbaie
在基础比特分配之上做频带局部修正:
安静频带减少比特、复杂大动态频带增加比特; 用分段区间记录局部比特增减量,相比全局分配更精细,进一步压缩码率。 耦合声道与各独立声道分别存储差分修正分段。
3.10 填充跳过数据 skiple /skipl/skipfld
本 audblk 内部控制位、指数、比特分配、尾数总比特不足标准块长度时,插入空白占位比特补齐; 仅 skiple=1 存在,解码直接跳过该段,不参与音频计算。
3.11 量化尾数 mantissas 音频核心载荷
整个 audblk 真正承载音频波形的部分。
- 指数给出频带音量基准,mantissa 是该频带精细波形量化值;
- 比特数由前面心理声学 bit allocation 算出,静音频带分配 0bit 直接跳过;
- 读取逻辑:先读所有独立声道尾数,遇到参与耦合声道且未读取耦合尾数时读取公共耦合尾数(got_cplchan 标记避免重复读取);
- lfeon=1 时单独读取低音声道尾数; 解码后:mantissa × 2^exponent 还原完整 MDCT 频域系数,再逆 MDCT 得到时域 PCM 音频。
四,auxdata
该模块主要有两个作用:1,用于对齐帧长, 2,存放私有附加信息。
cpp
┌──────────────────── auxdata() 辅助数据段 ────────────────────┐
│ 1. auxbits :nauxbits 比特长度(动态可变填充位)
│ 2. auxdatae 1bit :辅助扩展数据存在标志
│ └─ [auxdatae == 1]
│ └─ Auxdatal 14bit :辅助扩展数据长度
└─────────────────────────────────────────────────────────────┘
auxbits nauxbits前置所有帧段后剩余空闲比特,用于补齐 AC3 帧固定总长度,无固定比特宽,由帧总长减去前面 SI+BSI+6×audblk 的总比特得到。auxdatae 1bit1 比特标志位,标记是否存在厂商自定义扩展辅助数据。Auxdatal 14bit(条件存在) 仅auxdatae=1时读取,14bit 存储后续自定义 auxdata 字节长度。
五,errorcheck()
校验音频主体数据完整性,
- 解码器解码前重新计算 CRC,与码流内 crc2 比对:
- 匹配:音频数据无损坏,正常解码播放;
- 不匹配:传输 / 文件损坏,丢弃当前整帧,静音并重新搜索同步字。
2,格式介绍
cpp
┌──────────── errorcheck() 帧尾校验区域 ───────────┐
│ crcrsv 1bit 保留校验位(预留未使用)
│ crc2 16bit 整帧音频数据CRC校验码
└──────────────────────────────────────────────────┘
- crcrsv:1bit 保留位,标准预留,无实际校验作用,解码直接跳过;
- crc2:16 位循环冗余校验,覆盖本帧 BSI + 6 个 audblk + auxdata 全部音频载荷,用于检测码流传输损坏。
3,区分两段CRC
- crc1(SI 内):只校验 SI 后半段 + BSI;
- crc2(errorcheck):校验音频主体数据块,双重校验提升容错。