flv格式解析
FLV是一个二进制文件,简单来说,其是由一个文件头(FLV header)和很多tag组成(FLV body)。tag又可以分成三类:audio,video,script,分别代表音频流(0x8),视频流(0x9),脚本流(0x12),而每个tag又由tag header和tag data组成。
分析之前推荐一个flv分析工具:flv分析工具
工具的使用说明和出处:使用说明
以一个具体的flv文件为例具体分析:
文件头由9bytes组成:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kbntqCE6-1580714898238)(https://i.loli.net/2020/01/20/SADYzaEdRkWUGQ9.png)]
前3个bytes是文件类型,总是“FLV”,也就是(0x46 0x4C 0x56)。第4btye是版本号,目前一般是0x01。第5byte是流的信息,倒数第一bit是1表示有视频(0x01),倒数第三bit是1表示有音频(0x4),有视频又有音频就是0x01 | 0x04(0x05),其他都应该是0。最后4bytes表示FLV 头的长度,3+1+1+4 = 9。
FLV header后面就是FLV body,FLV body中包含很多个FLV tag,tag的分类有三种:0x08音频、0x09视频、0x12脚本。
每个tag中包含tag头和tag体。
每个tag前面还有一个previous size包 记录这上一个tag的数据的长度。先简单说一下tag head:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-S3t4X8W4-1580714898253)(https://i.loli.net/2020/01/20/aNEIDfAQyx7vlpH.png)]
1byte Tag类型,3bytes数据长度记录,3bytes时间戳,一个扩展时间戳bype,3bytes StreamID
每一个tag第一部分是tag header,tag header长度为11bytes,但是每个tag header前面有4bytes记录着上一个tag的长度。tag header的第1个byte为记录着tag的类型,音频(0x8),视频(0x9),脚本(0x12);第2到4bytes是数据区的长度,也就是tag data的长度;再后面3个bytes是时间戳,单位是毫秒,类型为0x12则时间戳为0,时间戳控制着文件播放的速度,可以根据音视频的帧率类设置;时间戳后面一个byte是扩展时间戳,时间戳不够长的时候用;最后3bytes是streamID,但是总为0,再后面就是数据区了(tag data),也即是h264的裸流,tag header 长度为1+3+3+1+3=11。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1OjXnzFp-1580714898256)(https://i.loli.net/2020/01/20/ezOrFnGiDTvUWL6.png)]
0x12脚本数据(Script Tag Data)
跟在FLV header后面的第一个tag就是脚本数据,Script Tag Data,该类型Tag又通常被称为Metadata(元数据) Tag,会放一些关于FLV视频和音频的参数信息,如duration、width、height等。通常该类型Tag会跟在File Header后面作为第一个Tag出现,而且只有一个。一般来说,该Tag Data结构包含两个AMF包。AMF(Action Message Format)是Adobe设计的一种通用数据封装格式,在Adobe的很多产品中应用,简单来说,AMF将不同类型的数据用统一的格式来描述。第一个 AMF包封装字符串类型数据,用来装入一个“onMetaData”标志,这个标志与Adobe的一些API调用有,在此不细述。第二个AMF包封装一个数组类型,这个数组中包含了音视频信息项的名称和值。具体说明如下,大家可以参照图片上的数据进行理解。
第一个AMF包:
第1个字节表示AMF包类型,一般总是0x02,表示字符串,其他值表示意义请查阅文档。
第2-3个字节为UI16类型值,表示字符串的长度,一般总是0x000A(“onMetaData”长度)。
后面字节为字符串数据,一般总为“onMetaData”。
第二个AMF包:
第1个字节表示AMF包类型,一般总是0x08,表示数组。
第2-5个字节为UI32类型值,表示数组元素的个数。
后面即为各数组元素的封装,数组元素为元素名称和值组成的对。表示方法如下:
第1-2个字节表示元素名称的长度,假设为L。
后面跟着为长度为L的字符串。
第L+3个字节表示元素值的类型。
后面跟着为对应值,占用字节数取决于值的类型。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fW9E5CBK-1580714898259)(https://i.loli.net/2020/01/20/BeQyOovtshnJ1VY.png)]
0x12前面的00 00 00 00 就是刚刚说的记录着上一个tag的长度的4bytes,这里因为前面没有tag,所以为0。
0x09视频数据
H264 的NALU 封装成FLV有三种不同的形式:
(1)H264 NALU type SPS +PPS;
(2)H264 NALU type SEI;
(3)H264 NALU type Slice 也就是 type值为(1-5);
(1)H264 NALU type SPS +PPS 封装成 FLV video tag:
在H264的码流中 SPS 和 PPS是成对出现的,先是SPS然后是PPS,SPS对于H264来说就是编码后的第一帧、PPS是编码后的第二帧这两针携带的数据主要是编码器的一些属性,比如宽高 profile level deblock滤波器等等。
在封装FLV中这两帧数据被合并到一个video tag中:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-o7OMyGto-1580714898261)(https://i.loli.net/2020/01/20/PutVvc4QxaA5DSs.png)]
FLV tag header Bytes value
1)Tag type // 0 0x09
2)Data Size // 1-3 0x00 0x00 0x24
3)TimeStamp // 4-6 0x00 0x00 0x00 (First frame)
4)TimeStampExtend // 7 0x00
5)StreamID // 8-10 0x00 0x00 0x00 (always zero)
AVC Video tag header
1)FrameType | CodecID //11 0x27
2)AVCPacketType //12 0x01
3)Composition Time //13-15 0x00 0x00 0x00
AVCDecoderConfigurationRecord
1)Configuration VerSion //16 0x01
2)AVC Profile SPS[1] //17 0x42
3)profile_compatibility SPS[2] //18 0x00
4)AVC Level SPS[3] //19 0x2A
5)lengthSi*usOne //20 0xFF
6)numOfSequenceParameterSets //21 0xE1
SPS
1)SPS0 Length //22-23 0x0010
2)SPS0 Data
3)SPS(n) length /btyes 如果存在多个循环存放最多31个SPS
4)SPS(n) Data
PPS
PPS count //1byte 0x01
PPS0 Length //2bytes 0x00 0x04
PPS0 Data
PPS(n) Length
PPS(n) Data
+PreviousTag Size
(2)H264 NALU type Sei 封装成 FLV video tag:
SEI NALU 是没有图像数据的,它的主要作用是对图像数据或者视频流的补充,有些内容可能对解码有帮助。在封装FLV文件中含义SEI的videoTAG其中包含色SEI数据还有SEI帧后紧跟着的一个IDR数据。
FLV tag header Bytes value
1)Tag type // 0 0x09
2)Data Size // 1-3 0x00 0x00 0x24
3)TimeStamp // 4-6 0x00 0x00 0x00 (First frame)
4)TimeStampExtend // 7 0x00
5)StreamID // 8-10 0x00 0x00 0x00 (always zero
AVC Video tag header
1)FrameType | CodecID //11 0x27
2)AVCPacketType //12 0x01
3)Composition Time //13-15 0x00 0x00 0x00
SEI
1)SEI length //16-19 0x00 0x00 0x00 0x05
2)SEI Data // 20-N 0x06 E5 01 81 80
3)IDR NALU Length //4Bytes 0x00 0x00 0x1F 0xF4
4)IDR NALU Data
+PreviousTag Size
(3)H264 NALU type Slice 封装成 FLV video tag:
Slice Type NALU (1-5) 就是H264 中一片一片的数据了,在FLV video tag中封装 如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-E1uHXHQQ-1580714898266)(https://i.loli.net/2020/01/20/O78PMQrRdIwqkXc.png)]
FLV tag header Bytes value
1)Tag type // 0 0x09
2)Data Size // 1-3 0x00 0x95 0xF6
3)TimeStamp // 4-6 0x00 0x00 0x00 (First frame)
4)TimeStampExtend // 7 0x00
5)StreamID // 8-10 0x00 0x00 0x00 (always zero)
AVC Video tag header
1)FrameType | CodecID //11 0x27 or 0x17
2)AVCPacketType //12 0x01
3)Composition Time //13-15 0x00 0x00 0x00
NALU
NALU Length // 4bytes 0x00 0x00 0x95 0xEDNALU data
+PreviousTag Size
另外补充:
VideoHeader第一个字节是video info。前4bit表示视频数据帧的类型,后4bit表示编码器的类型。如果是H264的视频,则VideoHeader还要多4个字节。包含1个字节的
avc_packet_type和3个字节的composition_time。
avc_packet_type:0x0表示avc sequence header,0x01表示NALU。VideoData需要完整的一帧的数据,而在RTP传输中,由于一帧数据太大,不利于传输,在传输时会对一帧进行分片。所以在这里需要将接收到的FU_A的NALU转换成原始的NALU,然后将多个NALU组成完成的一帧视频数据,存入VideoData中。至此VideoTagData就封装完成了。
0x09视频数据
AudioHeader第一个字节是audio info。前4bit是音频格式,第5-6bit是采样率,第7bit是采样精度,第8bit是声道数。如果音频格式是AAC的则还要多一个字节的aac_packt_type。
aac_packt_type:0x0表示AAC Sequence Header,0x01表示AAC Raw。AAC一帧数据通常较小,在RTP传输中,每次都是一个包一帧数据,不像H264视频需要分开。所以取出RTP中的音频数据,加上ADTS头就可以直接放入AudioData。至此AudioTagData就封装完成了。
前4bits表示音频格式(全部格式请看官方文档):
·0 – 未压缩
·1 – ADPCM
·2 – MP3
·4 – Nellymoser 16-kHz mono
·5 – Nellymoser 8-kHz mono
·10 – AAC
下面两个bits表示samplerate:
·0 – 5.5KHz
·1 – 11kHz
·2 – 22kHz
·3 – 44kHz
下面1bit表示采样长度:
·0 – snd8Bit
·1 – snd16Bit
下面1bit表示类型:
·0 – sndMomo
·1 – sndStereo
之后是数据。
更多参考:
【音视频技术】H264流媒体封装FLV文件
打包H264码流到FLV文件
打包AAC码流到FLV文件
https://www.optbbs.com/thread-4712999-1-1.html
https://www.cnblogs.com/chef/archive/2012/07/18/2597279.html
http://www.360doc.com/content/16/1013/17/474846_598171645.shtml
小桥流水人家_ 发布了34 篇原创文章 · 获赞 39 · 访问量 9万+ 私信 关注