由于上一节使用到了rtmp推流,然后一直推一直出错,用rtmp推流的数据格式是FLV,所以这一节分析一下FLV的格式,补充补充知识。
FLV 是FLASH VIDEO的简称,FLV流媒体格式是随着Flash MX的推出发展而来的视频格式。由于它形成的文件极小、加载速度极快,使得网络观看视频文件成为可能,它的出现有效地解决了视频文件导入Flash后,使导出的SWF文件体积庞大,不能在网络上很好的使用等问题。
FLV包括文件头(File Header)和文件体(File Body)两部分,其中文件体由一系列的Tag及Tag Size对组成。(大端字节序)
heard部分由一下几个部分组成:
Signature(3 Byte)+Version(1 Byte)+Flags(1 Bypte)+DataOffset(4 Byte)
这个是昨天拉流,保存出来的flv视频,通过这个查看这个视屏的二进制格式,我们就能到,上面的描述的对的。
FLV body由⼀对对的(Previous Tag Size字段 + tag)组成。
Previous Tag Size字段 排列在Tag之前,占⽤4个字节。
Previous Tag Size记录了前⾯⼀个Tag的⼤⼩,⽤于逆向读取处理。
FLV header后的第⼀个Pervious Tag Size的值为0。
Tag⼀般可以分为3种类型:脚本(帧)数据类型、⾳频数据类型、视频数据。
tag组成:tag type+tag data size+Timestamp+TimestampExtended+stream id+ tag data
详细见下图:
实例分析一下:
我们来看一下tag1,首先我框起来的是Pervious Tag Size0,因为是第一个,所以填为0;
接下来就到TAG:
type:0x12 是script 数据
data size: 0x00 01 a0 = 0x1a0长度的数据
Timestamp:0x000000
TimestampExtended:0x00
stream id:0x00 00 00
0x00000018地址开始就是tag1 data数据的开始,然后data size=0x01a0,所以计算出下一个tag1结束的地址:0x000001B8,这个地址就很好找,刚好是最后框的地方,这里4个字节正好是Pervious Tag Size1=0x01ab,我们之前得到的data size=0x01a0,tag head刚好=0x0b,所以tag1加起来的大小刚好=0x01ab,所以我们找的位置是正确。
script data脚本数据就是描述视频或者音频的信息数据,如宽度、高度、时间等等,一个文件中通常只有一个script数据。该类型的tag又被称为MeteData Tag。
第⼀个AMF包: 第1个字节表示AMF包类型,⼀般总是0x02,表示字符串。第2-3个字节为UI16类型值,标识字符串的⻓度,⼀般总是0x000A(“onMetaData”⻓度)。后⾯字节为具体的字符串,⼀般总为“onMetaData”(6F,6E,4D,65,74,61,44,61,74,61)。
第⼆个AMF包: 第1个字节表示AMF包类型,⼀般总是0x08,表示数组。第2-5个字节为UI32类型值,表示数组元素的个数。后⾯即为各数组元素的封装,数组元素为元素名称和值组成的对。
具体对二进制我这里就不解析了,看着上面的文字都能解析,我使用了一个工具,可以解析flv的,直接看这个工具的显示就可以了。
是不是很清楚,就是不知道为什么有一个0x03的type,难道是昨天的拉流可能还有问题,先不管。
audio数据又是一个新的tag了,所以简单看一下head:
对号入座吧,我就不用了,直接来结果公布:
audio data:
下面是第一个字节具体分析:
前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 |
接着2位为采样率
值 | 类型 |
---|---|
0 | 5.5-kHz |
1 | 11-kHz |
2 | 22-kHz |
3 | 44-kHz |
AAC 总是3
接着1位为采样的长度
值 | 类型 |
---|---|
0 | snd8Bit |
1 | snd16Bit |
压缩过的音频都是16bit
接着1位为音频类型
值 | 类型 |
---|---|
0 | sndMono |
1 | sndStereo |
AAC 总是1
第⼆个字节开始为⾳频流数据
需要判断该数据是真正的⾳频数据,还是⾳频config信息
如果音频格式=10(AAC类型)第二个数据就是音频config数据。
还是先取得video head数据,现在就不用细说了,都比较熟悉了。
解析结果:
video data数据,跟音频一样
值 | 类型 |
---|---|
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 |
后4位为编码ID (CodecID)
值 | 类型 |
---|---|
1 | JPEG (currently unused) |
2 | Sorenson H.263 |
3 | Screen video |
4 | On2 VP6 |
5 | On2 VP6 with alpha channel |
6 | Screen video version 2 |
7 | AVC |
AVCPacketType 占1个字节
值 | 类型 |
---|---|
0 | AVCDecoderConfigurationRecord(AVC sequence header) |
1 | AVC NALU |
2 | AVC end of sequence (lower level NALU sequence ender is not required or supported) |
AVCDecoderConfigurationRecord.包含着是H.264解码相关比较重要的sps和pps信息,再给AVC解码器送数据流之前一定要把sps和pps信息送出,否则的话解码器不能正常解码。而且在解码器stop之后再次start之前,如seek、快进快退状态切换等,都需要重新送一遍sps和pps的信息.AVCDecoderConfigurationRecord在FLV文件中一般情况也是出现1次,也就是第一个video tag.(这个详情以后看h264部分)
CompositionTime 占3个字节
条件 | 值 |
---|---|
AVCPacketType ==1 | Composition time offset |
AVCPacketType !=1 | 0 |
注意:CompositionTime 单位毫秒。CompositionTime 单位为ms : 显示时间 = 解码时间(tag的第58字节,位置索引[4][7]) +
CompositionTime。
这次就不用对二进制数据了吧,感兴趣自己去分析一下二进制数据。
主要参考博客:flv格式详解+实例剖析