生命不息,编程不止。本章我们继续解析FLV文件中的音频Tag的内容。
Audio Tag Data
在【Go】FLV文件解析(一)中我们讲了FLV Tag的基本结构是Tag Header加Tag Data。显然音频Tag的Tag Data就是音频数据了,其结构如下。
Tag Data的第一个字节被分成了4个部分。前4比特表示音频编码格式,共14种。
值 | 编码格式 | 说明 |
---|---|---|
0 | Linear PCM | 大端小端由编码平台决定 |
1 | ADPCM | |
2 | MP3 | |
3 | Linear PCM | 小端格式 |
4 | Nellymoser 16-kHz mono | |
5 | Nellymoser 8-kHz mono | |
6 | Nellymoser | |
7 | G.711 A-law logarithmic PCM | 保留,内部使用 |
8 | G.711 mu-law logarithmic PCM | 保留,内部使用 |
9 | reserved | |
10 | AAC | Flash Player9,0115,0及以上版本 |
11 | Speex | Flash Player10及以上版本 |
14 | MP3 8-Khz | 保留,内部使用 |
15 | Device-specific sound | 保留,内部使用 |
中间2比特表示采样率,共4种。
值 | 类型 | 说明 |
---|---|---|
0 | 5.5-kHz | |
1 | 11-kHz | |
2 | 22-kHz | |
3 | 44-kHz | AAC总是3 |
第7比特表示采样位宽,0表示8比特宽度,1表示16比特宽度。只针对非压缩编码格式有效,压缩编码格式总是解码成16bit宽度。
模拟音频信号在转换成数字信号之前要经过采样和量化。采样周期,也可以称为采样间隔,是指每隔多长时间从模拟信号采集一次振幅。采样周期的倒数就是采样频率,体现了数字采样的快慢,或称采样的疏密。这里采样频率和采样周期的关系和频率与周期的关系的一样的。比如44KHz的采样频率就表示每隔 1 44000 \frac{1}{44000} 440001秒采集一次振幅。采集到振幅以后需要量化,也就是用二进制来表示,用多少位二进制来表示振幅就是采样位宽,显然16bit能比8bit表示更大范围的振幅变化。
第8比特表示声道信息,0表示单声道,1表示双声道,也就是立体声。对于Nellymoser编码格式,它总是0,对于AAC格式总是1。
Linear PCM(3)存储的是裸PCM采样点(PCM全称Pulse Code Modulation,翻译过来就是脉冲编码调制,也就是模拟信号经过量化编码后得到的数据,属于非压缩编码,是可以直接播放的)。如果采样宽度是8bit,则采样点是无符号整数,如果采样宽度是16bit,则采样点是小端序有符号整数。如果是立体声,则左右声道数据按
左-右-左-右
排列。Linear PCM(0)由于其大端小端取决于编码平台,因此不推荐使用。
Nellymoser有3种格式,Nellymoser 8-kHz和16-kHz会忽略掉上面的采样频率和声道信息,普通的Nellymoser(6)则不会忽略。8kHz和16kHz的采样率其他编码格式也不支持。
如果是AAC编码,音频信息总是设置为1,采样频率总是设置为3,因为Flash Player会忽略这两个值,而是从AAC比特流里解码采样率。
音频数据根据编码格式而不同,对于比较常用的AAC编码,音频数据格式如下。
这里音频配置是一个叫做AudioSpecificConfig的结构,在ISO 14496-3中定义。AudioSpecificConfig共占2个字节,具体结构如下。
audio object type
- 0: Null
- 1: AAC Main
- 2: AAC LC (Low Complexity)
- 3: AAC SSR (Scalable Sample Rate)
- 4: AAC LTP (Long Term Prediction)
- 5: SBR (Spectral Band Replication)
- 6: AAC Scalable
- 7: TwinVQ
- 8: CELP (Code Excited Linear Prediction)
- 9: HXVC (Harmonic Vector eXcitation Coding)
- 10: Reserved
- 11: Reserved
- 12: TTSI (Text-To-Speech Interface)
- 13: Main Synthesis
- 14: Wavetable Synthesis
- 15: General MIDI
- 16: Algorithmic Synthesis and Audio Effects
- 17: ER (Error Resilient) AAC LC
- 18: Reserved
- 19: ER AAC LTP
- 20: ER AAC Scalable
- 21: ER TwinVQ
- 22: ER BSAC (Bit-Sliced Arithmetic Coding)
- 23: ER AAC LD (Low Delay)
- 24: ER CELP
- 25: ER HVXC
- 26: ER HILN (Harmonic and Individual Lines plus Noise)
- 27: ER Parametric
- 28: SSC (SinuSoidal Coding)
- 29: PS (Parametric Stereo)
- 30: MPEG Surround
- 31: (Escape value)
- 32: Layer-1
- 33: Layer-2
- 34: Layer-3
- 35: DST (Direct Stream Transfer)
- 36: ALS (Audio Lossless)
- 37: SLS (Scalable LosslesS)
- 38: SLS non-core
- 39: ER AAC ELD (Enhanced Low Delay)
- 40: SMR (Symbolic Music Representation) Simple
- 41: SMR Main
- 42: USAC (Unified Speech and Audio Coding) (no SBR)
- 43: SAOC (Spatial Audio Object Coding)
- 44: LD MPEG Surround
- 45: USAC
sampling frenquence index
- 0: 96000 Hz
- 1: 88200 Hz
- 2: 64000 Hz
- 3: 48000 Hz
- 4: 44100 Hz
- 5: 32000 Hz
- 6: 24000 Hz
- 7: 22050 Hz
- 8: 16000 Hz
- 9: 12000 Hz
- 10: 11025 Hz
- 11: 8000 Hz
- 12: 7350 Hz
- 13: Reserved
- 14: Reserved
- 15: frequency is written explictly
channel configration
- 0: Defined in AOT Specifc Config
- 1: 1 channel: front-center
- 2: 2 channels: front-left, front-right
- 3: 3 channels: front-center, front-left, front-right
- 4: 4 channels: front-center, front-left, front-right, back-center
- 5: 5 channels: front-center, front-left, front-right, back-left, back-right
- 6: 6 channels: front-center, front-left, front-right, back-left, back-right, LFE-channel
- 7: 8 channels: front-center, front-left, front-right, side-left, side-right, back-left, back-right, LFE-channel
- 8-15: Reserved
实战
第一步还是定义下需要用到的结构,这里我们只以AAC为例。
type FlvAudioTag struct {
Header FlvTagHeader
SoundFmat uint8
SoundRate uint8
SoundSize uint8
SoundType uint8
Data stream.Stream
}
type AACPacket struct {
AACPacketType uint8
Playload []byte
}
type AACAudioSpecificConfig struct {
AudioObjectType uint8
SamplingFrequency uint8
ChannelConfiguration uint8
FrameLengthFlag uint8
DependsOnCoreCoder uint8
ExtensionFlag uint8
}
音频Tag解码过程如下。
// 解码音频Tag
func DecodeFlvAudioTag(tag FlvTag) (a FlvAudioTag, err error) {
a.Header = tag.Header
var b byte
if err = tag.Data.Byte(&b).Error(); err != nil {
return
}
a.SoundFmat = b >> 4
a.SoundRate = b >> 2 & 0x03
a.SoundSize = b >> 1 & 0x01
a.SoundType = b & 0x01
a.Data, err = tag.Data.Produce(tag.Data.Remain())
return
}
AudioSpecificConfig解码过程如下。
// 解码AAC Packet
func DecodeAACPacket(t FlvAudioTag) (p AACPacket, err error) {
if t.SoundFmat != AAC {
err = errors.New("not aac format")
return
}
if err = t.Data.U8(&p.AACPacketType).Error(); err != nil {
return
}
p.Playload = t.Data.ReadAll()
return
}
// 解码AudioSpecificConfig
func DecodeAACAudioSpecificConfig(p AACPacket) (a AACAudioSpecificConfig, err error) {
if len(p.Playload) != 2 {
err = FLV_FMT_ERROR
}
a.AudioObjectType = p.Playload[0] >> 3
a.SamplingFrequency = (p.Playload[0] << 1 & 0x0F) | (p.Playload[1] >> 7)
a.ChannelConfiguration = p.Playload[1] >> 3 & 0x0F
a.FrameLengthFlag = p.Playload[1] >> 2 & 0x01
a.DependsOnCoreCoder = p.Playload[1] >> 1 & 0x01
a.ExtensionFlag = p.Playload[1] & 0x01
return
}
AAC是一种压缩编码,关于AAC的解码,有机会我会出专门的一期来讲。
下一期也是最后一期,我们继续视频Tag的解析。