FLV文件结构解析

1. FLV文件格式相对于MP4,简单很多。
   FLV Header(9Bytes) + FLV Body
   
                    a比特: 1:有音频; 0:无音频
                    v比特: 1:有视频; 0:无视频   如果音视频都有这个字节为0x05
   'F'|'L'|'V'|0x01|0b00000a0v| 0x00 00 00 09|
                    |                                         |
         版本字节一般为0x01      头长度 固定为9
 
    FLV Body由一系列的Tag组成,每个tag的结构如下:
    { 0x00000000| tag_header0| tag_data0 } | {tag_size0| tag_header1 | tag_data1 } | {tag_size1| tag_header2 | tag_data2 } |...
       tag_size(n) = tag_data_size(n-1) + 11
       解析完一个tag后,读取下4个字节,可以比较下看是不是前帧完全解码完毕。

       除了可以验证码流外,还有什么样的好处促使FLV格式采用这种方式呢?不太清楚。

        0x00000000| { tag_header0| tag_data0  | tag_size0} | { tag_header1 | tag_data1 | tag_size1} |...

       Tag body也可以这样看,编码时按照: 数据头 数据体 数据大小 三部分来划分,更适合一些。下面各个tag都是按照这个结构来写的。 


    Tag header 11Bytes

    |1Byte Tag类型                                |  只支持3类, 0x08音频; 0x09视频;0x12脚本
    |3Byte data_size数据区长度         |  纯数据长度,不包括头信息的15字节
    |3Byte timestamp 时间戳               |  最终的时间戳 = (timestamp_ex<< 24) | timestamp   
    |1Byte timestamp_ex扩展时间戳 |  最终时间戳的高8位。不知道为什么定义成这样,可能是因为标准扩展
    |3Byte StreamID                             |  总为0

    Tag Data data_size字节
    |Tag数据段,长度为data_size...  |  音视频或者脚本数据。
    |4Byte PreviousTagSize               |  是前一个Tag数据长度,第一个Tag此数据段为0.

2. 视频Tag
   视频数据的第一个字节定义视频信息:
   高4比特定义帧格式:1 关键帧; 2 内部帧(非IDR帧);3可丢弃内部帧(仅对H.263有用)
   低4比特定义编码器:2:H.263, 4: VP6, 7:H264; ...
   对于264的视频FLV,这个字节一般为 0x17或者0x27.
   
3. 音频tag
   音频数据的第一个字节定义视频信息:
   高4比特定义音频编码格式:0 Linear PCM, 1: ADPCM, 2: MP3, 10:AAC ..
   第4,3两比特定义采样率: 0 5.5KHz, 1 11KHz, 2 22KHz, 3 44KHz. 对于AAC该值总为3
   第2比特定义采样大小: 0 8比特,1 16比特
   第1比特定义声道数: 0 单声道,1 立体声

4. 脚本tag
   理论上不需要解析脚本Tag就可以解码FLV文件,它只是提供了一些信息记录。
   脚本Tag里面的类型比较多,格式也不一样。
   Number 类,记录一个8字节double数据。|0x00|8字节data|.
   Boolean类,记录一个1字节布尔型数据。|0x01|1字节data|.
   String类,记录一个变长字符串数据。  |0x02|2字节 字符串长度 N| N字节字符串内容|.
             注意读取完字符串后加一个'\0'字符串结束符号。因此字符串申请的时候,长度为N+1.

   ECMA array type, 记录一些数据对。

        |0x08| 4字节 数组长度 N|2字节 字符串长度 m1 | m1字节字符串内容|1字节 data1 type | X字节 data1 | ...

                                               |2字节 字符串长度 Nm| Nm字节字符串内容|1字节 dataN type| X字节 dataN|           
                      有N个数据对                  元素名    (长度|数据)                               元素值(类型|数据)

                一般用这个记录一些音视频信息,例如:

                                                                0x0008                         "duration"                   0x00      8字节double
                                                                0x0005                            "width"                     0x00      8字节double
                                                                0x0006                           "stereo"                    0x01      1字节boolean型  

   Strict array type类,记录一组数据。
                               |0x0A|4字节 数组长度 N| 1字节 data1 type| X字节 data1 | ...
                                                                    |1字节 dataN type| X字节 dataN|
                                                 有N个数据,      每个数据的类型    数据值                                   
                     一般会用这个类记录关键帧的偏移地址和对应的pts值。类型都是 Number类,即X=8字节double型
   Object type, 记录对象数据。一般用它来做keyframes的数据存储起始。

5.keyframes字段
   FLV没有像mp4一样定义stbl,FLV文件如果做快进,seek等操作会比较麻烦。

   业内通用做法是在脚本Tag里面增加keyfrmes object类。一般定义为:

   |00 09| 9字节 "keyframes"|00 0D| 13字节 "filepositions"|0A| 4字节关键字数目 N|00|8字节 关键帧1偏移地址| ...
                                                                                                                               |00|8字节 关键帧N偏移地址|

                                                 |00 05| 5字节 "times"               |0A| 4字节关键字数目 N|00|8字节 关键帧1时间| ...
                                                                                                                               |00|8字节 关键帧N时间|          
  有了各个关键帧的偏移地址和时间,做Seek操作的时候就方便的多。
 
6. 读取8字节double型,这个牵扯浮点型的存储结构问题,蛮罗嗦,没看明白,但找到下面一段代码可以实现转换。
    uint64_t v = get_8bytes();
    if(v+v > 0xFFEULL<<52) return 0.0/0.0;
    double x = ldexp(((v&((1LL<<52)-1)) + (1LL<<52)) * (v>>63|1), (v>>52&0x7FF)-1075);

7. FLV结构里面,数据长度有3字节和4字节限制,不会像Mp4一样出现8字节长度。
   3字节最大表示16M数据,4字节最大是4G数据。
   一个Video Tag里面的NALU长度不能超过16M字节。
   
发布了40 篇原创文章 · 获赞 7 · 访问量 11万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章