FLV 文件 = File Header(FLV 文件头)+ File Body(FLV 文件体)。其中文件体又由一系列的 Tag 和 Tag Size 组成。
使用16进制查看器打开一个FLV文件,查看数据的格式
FLV File Header
字段 | 字节 | 描述 |
---|---|---|
signature | 3 | 文件格式标识。('F‘ : 0x46,'L' : 0x4C,'V' : 0x56) |
version | 1 | 版本号。(0x01:版本号为1) |
type flags | 1 | 类型标识。 前5个bit是类型标志预留字段,必须是0; 第6个bit音频类型标志(TypeFlagsAudio); 第7个bit是类型标志预留字段,必须是0; 第8个bit视频类型标志(TypeFlagsVideo)。(0x05,也就是 00000101,表示既有音频也有视频) |
data offset | 4 | 文件头的长度。(对于版本号为1的FLV文件来说,文件头长度固定是9,大于9表示下面还有扩展信息) |
FLV File Body
Body部分是由一系列的 PreviousTagSize + Tag 构成。
PreviousTagSize 固定为4字节,表示前一个Tag的size
Tag分为3种类型:Script(脚本)、Video(视频)、Audio(音频)
FLV Tag
FLV中的Tag又分为 tag header(tag头部分)和 tag data(tag数据部分)。
FLV Tag Header(Tag头1+3+3+1+3=11个字节)
字段 | 字节 | 描述 |
---|---|---|
TagType | 1 | 当前tag的类型,值有: 0x08:audio 0x09:video 0x12:script 其他:未使用的预留值 |
DataSize | 3 | 数据部分的数据长度(Data字段的数据长度)。 |
Timestamp | 3 | 当前帧的时间戳,单位是毫秒。相对于第一个TAG的时间戳(第一个的时间戳总是0) |
TimestampExtended | 1 | 时间戳扩展字段。 如果时间戳大于0xFFFFFF,将会使用这个字节。这个字节是时间戳的高8位,上面的三个字节是低24位。 |
StreamID | 3 | 流ID,总是0 |
Data | n | 数据部分 |
00 01 6A代表数据长度有362个字节,所以蓝色区域都是data数据区域。
FLV Script Tag
Script Tag一般只有一个,且是FLV中第一个Tag,用来存放一些描述信息,如:duration、width、height等。Script Tag 中Data部分的数据都是以 【数据类型 + 数据长度 + 数据】的格式出现的。一般来说,该Tag Data结构包含两个AMF包。AMF(Action Message Format)是Adobe设计的一种通用数据封装格式,在Adobe的很多产品中应用,简单来说,AMF将不同类型的数据用统一的格式来描述。第一个AMF包封装字符串类型数据,用来装入一个“onMetaData”标志,这个标志与Adobe的一些API调用有关。第二个AMF包封装一个数组类型,这个数组中包含了音视频信息项的名称和值。
类型值意义
值 | 类型 | 说明 |
---|---|---|
0 | Number type | double类型,后8字节为数据长度 |
1 | Boolean type | bool类型,后1字节为数据长度 |
2 | String type | string类型,后两字节为数据长度 |
3 | Object type | |
4 | MovieClip type | |
5 | Null type | |
6 | Undefined type | |
7 | Reference type | |
8 | ECMA array type | 数组类型(类似Map),后4字节为数组长度。(key:前两字节为长度;value部分第1字节为类型) |
10 | Strict array type | |
11 | Date type | |
12 | Long string type | |
第一个AMF(1+2+10=13个字节)
02:String类型
0A:String长度为10
后面10字节为数据的值
第二个AMF包(头5个字节)
08:数组
00 00 00 10 :数组长度为16
数组中元素封装形式为:前两个字节为元素名称的长度,后面跟着长度为L的字符串。紧跟着的一个字节表示元素值的类型,后面跟着是对应值,占用的字节数取决于值的类型。
元素“duration”(19字节)
00 08 代表后面8个字节长度为元素名称
名称:duration
00 代表double类型,后8字节为数据长度
元素“width”(16个字节)
00 05 长度
元素名称:width
00:代表double类型,后8字节为数据长度
元素"height"(17个字节)
00 06
68 65 69 67 68 74 height
00 代表double类型,后8字节为数据长度
元素“videodatarate”(24个字节)
00 0D :长度
76 69 64 65 6F 64 61 74 61 72 61 74 65 字符串“videodatarate”
00 :代表double类型,后8字节为数据长度
元素“framerate”(20个字节)
00 09 长度
66 72 61 6D 65 72 61 74 65:字符串“framerate”
00 代表double类型,后8字节为数据长度
元素“videocodecid”(23个字符)
00 0c :长度
76 69 64 65 6F 63 6F 64 65 63 69 64 字符串videocodecid
00 代表double类型,后8字节为数据长度
以下就不再截图了,对比数据自己慢慢往下找
元素“audiodatarate”(24个字节)
00 0D:长度
元素“audiosamplerate”(26个字节)
00 0F:长度
元素“audiosamplesize”(26个字节)
00 0F
元素“stereo”(10个字节)
00 06 长度
73 74 65 72 65 6F 字符串“stereo”
01:bool类型,后1字节为数据长度
元素“audiocodecid”(23个字节)
00 0C:长度
元素“major_brand”(20个字节)
00 0B :长度
02:看上面的类型文档,string,,后两个字节代表长度
00 04 :长度为4
元素“minor_version”(19个字节)
00 0D:长度为13
02:string 后两位表示长度
00 01 长度为1
元素“compatible_brands”(30个字节)
00 11 :长度为17
02 :string 后两位代表长度
00 08 长度为8
元素“encoder”(字节数25)
00 07 :长度为7
02 :string
00 0D:长度为13
元素“filesize”(22个字节)
00 08 长度为8
00:后8位表示长度
00 00 :空字符串
09 :结束标志
16个元素长度相加19+16+17+24+20+23+...+22 = 344
第一个AMF包(13)+第二个AMF包头(5)+16个元素数组数据长度(344)=362个字节。
至此,,362个data数据全部分析完毕。
那么下一个PreviousTagSize就是362+tag头(11)=373个字节
PreviousTagSize是固定长度4
00 00 01 75 = 373
上面分析的是Script Tag,一般都是flv文件的开头才有一个,中间是一个TagSize,再接下来就是第一个VideoTag,TagHaeder(11个字节)
Tag头分析,按照上面的文档一个个对照
09:video
00 00 2E :data 长度
00 00 00 00 时间戳
00 00 00 流id
接下来分析VideoTagBody
1700000000这五个字节为VideoTag数据部分的固定头五个字节
字段 | 比特位 | 描述 |
---|---|---|
FrameType | 高四位 | 帧类型。 1: keyframe(for AVC, a seekable frame) 2: inter frame(for AVC, a non-seekable frame) 3: disposable inter frame(H.263 only) 4: generated keyframe(reserved for server use only) 5: video info/command frame |
CodecId | 低四位 | 编码类型。 1: JPEG(目前未用到) 2: Sorenson H.263 3: Screen video 4: On2 VP6 5: On2 VP6 with alpha channel 6: Screen video version 2 7: AVC(高级视频编码) |
比如上面的17就代表着是keyframe关键帧,并且是AVC(高级视频编码)
字段 | 字节数 | 描述 |
---|---|---|
AVCPacketType | 1 | 0:AVC sequence header 1:AVC NALU 2:AVC end of sequence |
CompositionTime | 3 | 合成时间。 AVCPacketType==1,表示 合成时间(单位毫秒); 否则为0 |
比如上面的00 00 00 00 就表示AVC sequence header和合成时间为0
Data数据
字段 | 字节 | 描述 |
---|---|---|
data | n | 如果AVCPacketType==0,数据部分为AVCDecoderConfigurationRecord; 如果AVCPacketType==1,数据部分为1个或多个NALU; 如果AVCPacketType==2,数据部分为空 |
AVCDecoderConfigurationRecord
AVCDecoderConfigurationRecord 包含了H.264解码相关比较重要的SPS和PPS信息,再给AVC解码器送数据流之前一定要把SPS和PPS信息送出,否则的话解码器不能正常解码。而且在解码器stop之后再次start之前,如seek、快进快退状态切换等,都需要重新送一遍SPS和PPS的信息。AVCDecoderConfigurationRecord在FLV文件中一般情况也是出现1次,也就是第一个video tag。
字段 | 字节 | 描述 |
---|---|---|
版本 | 1 | 0x01,版本号为1 |
编码规格 | 3 | sps[1]+sps[2]+sps[3] |
NALU 的长度 | 1 | 0xFF,包长为 (0xFF& 3) + 1,也就是4字节表示 |
SPS个数 | 1 | 0xE1,个数为0xE1 & 0x1F 也就是1 |
SPS长度 | 2 | 整个sps长度 |
SPS的内容 | n | 整个sps |
PPS个数 | 1 | 0x01,1个 |
PPS长度 | 2 | 整个pps长度 |
PPS内容 | n | 整个pps内容 |
00 19 :sps长度为25
00 05 :pps长度为5
上面的头数据(11)+(固定长度17 00 00 00 00)5+(1+3+1+1+2)+25(sps长度)+(1+2)+5(pps长度)= 57
所以下一个PreviousTagSize为0x39
第一个VideoTag过了之后,接下来是第一个AudioTag(Tag头11个字节)
AudioTagBody与VideoTag类似
字段 | 比特位 | 描述 |
---|---|---|
SoundFormat | 4 | 音频数据格式。值: 0 = Linear PCM, platform endian 1 = ADPCM 2 = MP3 3 = Linear PCM, little endian 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 11 = Speex 14 = MP3 8-kHz 15 = Device-specific sound (7,8,14,15是内部预留) |
SoundRate | 2 | 音频采样率。值: 0 = 5.5-kHz 1 = 11-kHz 2 = 22-kHz 3 = 44-kHz (对于AAC来说,该字段总是3) |
SoundSize | 1 | 采样长度。值: 0 = snd9Bit 1 = snd16Bit (对于压缩过的音频来说,一般都是16bit) |
SoundType | 1 | 音频类型(单声道还是双声道)。值: 0 = sndMono 1 = sndStereo (对于AAC,总是1) |
SoundData | n | 音频数据部分(AAC则需要参考下面AACAUDIODATA部分) |
AACAUDIODATA
字段 | 字节 | 描述 |
---|---|---|
AACPacketType | 1 | 0:AAC 序列头 1:AAC 数据 |
Data | n | 如果AACPacketType==0,参考下面的 AudioSpecificConfig 如果AACPacketType==1,即AAC原始音频数据 |
AudioSpecificConfig(5个字节)
字段 | 占位 |
---|---|
audioObjectType | 5 |
samplingFrequencyIndex | 4 |
channelConfiguration | 4 |
frameLengthFlag | 1 |
dependsOnCoreCoder | 1 |
extensionFlag | 1 |
Sync Extension Type() | 11 |
Extension Audio Object Type | 5 |
SBR Present Flag | 1 |
audioObjectType:2-AAC-LC,5-SBR,29-PS
samplingFrequencyIndex:0-96000,1-88200,3-64000,4-44100,5-32000,6-24000,7-22050,8-16000
channelConfiguration:1-单声道,2-双声道,依次类推....
Frame Length Flag:0-1024 samples
dependsOnCoreCoder:0-不依赖 1-依赖
extensionFlag:0-Is not extention 1-Is extention
Sync Extension Type():0x2b7表示HE-AAC的扩展
Extension Audio Object Type:
SBR Present Flag:
AF:10101111 1010代表AAC 11代表44khz 1代表16Bit 1代表Stereo
00:序列头
12-10-56-E5-00:00010010-00010000-01010110-11100101-00000000
00010:表示2-AAC-LC
0100:表示4—44100
0010:表示2-双声道
0:表示0-1024samples
0:表示不依赖
0:表示is not extention
01010110111:表示0x2b7-HE-AAC的扩展
00101:表示5
0:SBR Present Flag为0
后面不足的地方全部补0
所以当前Audio Tag的body Sized为2+5=7;整个Tag的size为body+header = 7+11=18
Previous Tag Size(4个字节)
接下来就是一个个普通的VideoTag和Audio Tag按照时间戳交替存放。记住每个Tag之后都有4个字节的Previous Tag Size.下面只列出一个Video Tag和一个Audio Tag的格式,其他的类似
BodySize = 5+4+NALU_LENGTH;
VideoTag数据部分固定的头5个字节,4个字节表示NALU长度,最后就是NALU数据部分
BodySize = AAC_Data_Length+2
到此为止已经介绍完FLV文件格式,flv格式还是比较简单的,header部分很简洁,body部分都是由一个个tag组成,tag的话也就三种,脚本tag一般只有一个。