其他分享
首页 > 其他分享> > 封装格式 -- FLV

封装格式 -- FLV

作者:互联网

FLV


内部结构

FLV(Flash Video)是Adobe公司推出的一种媒体封装格式,适合流媒体传输。优点是封装简单,文件体积小。后缀为.flv。总体上看,FLV包括文件头(File Header)和文件体(File Body)两部分,其中文件体由一系列的Tag及Tag Size对组成。
FLV结构图

1. FLV Header

– 内部结构图

在这里插入图片描述

– 关键栏位

2. FLV file body


FLV tag

1. 类型

FLV tag分为3种类型:

2. FLV tag header

对于FLV版本1,tag header固定为11字节。

– 内部结构图

在这里插入图片描述

– 关键栏位

3. Audio Tag Body

音频tag第一个字节包含音频数据的参数信息(固定的),从第二个字节开始为音频流数据。

– 内部结构图

在这里插入图片描述

– 关键栏位

– Audio config tag

即AACPacketType为0,Tag body第1个字节为简略的参数信息,第2个字节为AAC packet type,从第3个字节开始为audio specific config data。相比于tag body第一个字节中的参数信息,AudioSpecificConfig提供了更加详细的音频信息,它的定义在ISO14496-3中1.6.2.1。
一般的AudioSpecificConfig有2字节定义如下:

|AAC Profile 5bits | 采样率 4bits | 声道数 4bits | 其他 3bits |

对于AAC audio tag,FLV文件中第一个audio tag是audio config tag。
如下图为一个audio config tag的例子:
在这里插入图片描述
audio config tag结构图如下:
在这里插入图片描述

– Audio raw data tag

即AACPacketType为1的case,Tag body第1个字节为简略的参数信息,第2个字节为AAC packet type,从第3个字节开始为AAC raw data,如下图:
在这里插入图片描述

4. Video Tag Body

视频tag body第一个字节包含视频数据的参数信息(固定),从第二个字节开始为视频数据。

– 内部结构图

在这里插入图片描述

– 关键栏位

– Video config tag

即AVCPacketType为0的case,Tag body第一个字节固定为0x17(key frame,AVC),packet data里面是该视频的SPS和PPS。
下图为实例:
在这里插入图片描述

– Video raw data tag

即AVCPacketType为1的case,Packet data里面是NALU。
下图是实例:
在这里插入图片描述

– video tag例子

在这里插入图片描述

– 关于CompositionTime(cts)

CompositionTime表示pts相对于该帧dts的差值,CompositionTime= (pts – dts) ms
当B帧存在时,视频帧的pts和dts可能不同,dts在flv中是指tag header中的timestamp。
所以视频帧的pts = CompositionTime + timestamp。
如果B帧不存在,则CTS固定为0,也就是CompositionTime这个栏位0,
即pts = timestamp。

5.Script Tag Body


实际应用遇到的问题

  1. 如何probe一个数据流为FLV类型?
    满足以下三个条件:

    i. "FLV"。
    	数据流开头前3个字节是'F', 'L', 'V' --> FLV Header前3个字节固定是'F', 'L', 'V'
    ii. 保留位。
    	数据流第5个字节 & 0xf2的值为0  --> FLV Header前5个字节的高5位和第7位为保留位,固定为0
    iii. 大小。
    	数据流第6个字节到第9个字节固定为 0x 00 00 00 09  --> FLV Header的长度固定为9个字节,记录与FLV Header最后4个字节。
    
  2. 如何获得FLV文件的duration?
    首先,从Script tag中的duration metadata中获取duration。
    然后,拿到第一个video tag的timestamp 和 最后一个video tag的timestamp,两者的差值就是duration(单位ms)

  3. 如何识别一个tag,并且一个一个tag的读取数据?
    识别方法是:先找到一个字节为0x08、0x09或者0x12,如果是tag的话,那么后面三个字节为datasize,在往后跳(datasize + 11 + 4)bytes,如果第一个字节还是0x08、0x09或者0x12,再往后跳(datasize + 11 + 4)bytes,如此循环判断五次,每次都找到0x08、0x09和0x12的话,那说明第一个找到的字节为一个tag的开始。如果有一个找不到的话,那就寻找下一个字节为0x08、0x09或者0x12,按照上述方式再进行判断。

  4. 如何seek?
    ▪ FLV官方标准对seek的支持不好,每次seek都必须从当前位置加载tag数据,直到目标位置,从而导致缓冲时间长,效果极差。
    ▪ 而较为常用但非官方的做法是在Script Tag中加入keyframe字段,用来建立关键帧时间点和文件位置的映射表。
    ▪ keyframe字段包含file positions和times两个数组,times为关键帧时间点数组,filepositions数组为关键帧在文件中偏移量数组。两个数组的长度相同,类型为double类型,且fileposition和time一一对应。借助keyframe字段,seek过程是:

    i. 根据用户想要seek的时间点,在times数组中比对最接近值,拿到该值对应数组索引,记为KeyframeIndex
    ii. 根据keyframeIndex,在fileposition数组中取得对应的偏移量,记为keyframeOffset
    iii. 从该偏移量开始读取数据即可完成seek播放。
    

标签:封装,字节,--,tag,FLV,header,Tag
来源: https://blog.csdn.net/Ritchie_Lin/article/details/121730749