ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

封装格式 -- FLV

2021-12-05 16:59:33  阅读:168  来源: 互联网

标签:封装 字节 -- tag FLV header Tag


FLV


内部结构

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

1. FLV Header

– 内部结构图

在这里插入图片描述

– 关键栏位

  • SigNature:开头三个字节,固定为 FLV 的ascii码(0x46 0x4c 0x56)
  • Version:表示FLV的版本号,比如FLV版本1,则该栏位是0x01
  • FlagsAudio:1表示有audio tag,0表示没有
  • FlagsVideo:1表示有video tag,0表示没有
  • DataOffset:表示FLV header的大小,单位为字节。对于FLV版本1,固定是9,也就是header总共9字节,有效字节有5个。

2. FLV file body

  • 由一系列tag和previousTagSize组成(如图: FLV结构图);
  • Tag的大小 = 11(tag header) + n(tag body),其中previousTagSize为4字节。
  • PreviousTagSize0总是0;其它PreviousTagSizeN的值表示TagN的大小,用于逆向读取处理(因为flv没有同步字节)。

FLV tag

  • 由tag header 和 tag body组成,tag header固定为11字节。如下图:
    在这里插入图片描述

1. 类型

FLV tag分为3种类型:

  • Video Tag:存放视频相关数据
  • Audio Tag:存放音频相关数据
  • Script Tag:存放音视频元数据(metadata),一般会是第一个tag,紧跟着FLV header,有且只有一个。

2. FLV tag header

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

– 内部结构图

在这里插入图片描述

– 关键栏位

  • TagType:
    tag类型,1字节
    tag类型含义
    0x8该tag为audio tag
    0x9该tag为video tag
    0x12该tag为script tag
    其它保留
  • DataSize:
    tag body的大小,3字节(不包含tag header的11字节),所以整个tag大小 = DataSize + 11。
  • TimeStamp:
    与第一个tag的时间戳差值,单位为毫秒,3字节。对于视频来说,就是DTS,单位为ms。
    第一个audio和video tag的Timestamp分别为0,亦表示解码顺序。
  • TimeStampExtended:
    时间戳的扩展字段,当Timestamp栏位不够用时,会启用这字段,表示最高八位。
  • StreamID:
    总是0。

3. Audio Tag Body

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

– 内部结构图

在这里插入图片描述

– 关键栏位

  • SoundFormat:音频格式。
    IDformat
    0Linear PCM,platform endian
    1ADPCM
    2MP3
    3Linear PCM,little endian
    4Nellymoser 16 kHz mono
    5Nellymoser 8 kHz mono
    6Nellymoser
    7G.711 A-law logarithmic PCM
    8G.711 mu-law logrithmic PCM
    9reserved
    10AAC
    11Speex
    14MP3 8 kHz
    15Device-specific sound
  • SoundRate:采样率。
    ID采样率
    05.5 kHz
    111 kHz
    222 kHz
    344 kHz
  • SoundSize:采样位宽。对于压缩过的音频,一般是16位。
    ID位宽
    08 Bits
    116 Bits
  • SoundType:声道类型。
    ID声道数
    0单声道
    1双声道
  • SoundData:音频数据,
    对于AAC音频,也就是SoundFormat为10的case。
    从Tag的第二个字节起被称为AACAudioData,定义如下:
    字段字段类型字段含义
    AACPacketTypeUI80: AAC sequence header 1: AAC raw data
    DataUI8[n]AACPacketType为0,AudioSpecificConfigAACPacketType为1,AAC帧数据

– 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第一个字节包含视频数据的参数信息(固定),从第二个字节开始为视频数据。

– 内部结构图

在这里插入图片描述

– 关键栏位

  • FrameType:帧类型
    ID帧类型
    1Keyframe;对于H264,IDR帧
    2Inter frame;对于H264,普通I帧
    3Disposable inter frame(H.263 only)
    4generated keyframe
    5video info (如sps、pps);
    command frame,普通的帧
  • Codec ID: 编解码器类型
    ID编解码器类型
    1JPEG
    2Sorenson H.263
    3Screen video
    4On2 VP6
    5On2 VP6 with alpha channel6
    7AVC
  • VideoData:视频数据
    CodecIDVideoDataType
    2H263VideoPacket
    3ScreenVideoPacket
    4VP6FlvVideoPacket
    5VP6FlvAlphaVideoPacket
    6ScreenV2VideoPacket
    7AVCVideoPacket
    其中,AVCVideoPacket的定义如下:
    字段字段类型字段含义
    AVCPacketTypeUI80:AVC sequence header,也就是sps和pps
    1:AVC NALU
    2:AVC end of sequence
    CompositionTimeSI24AVCPacketType == 1,该栏位有效,表示pts与dts的差值,单位ms;
    否则,为0
    DataUI8[n]AVCPacketType:
    0–> AVCDecoderConfigurationRecord
    1–> NALU(一个或多个)
    2–> 空

– 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

  • Script Tag通常用来存放跟FLV中音视频相关的元数据信息(onMetaData),比如时长、分辨率等。
    采用AMF(Action Message Format)封装了一系列数据类型,如字符串,数值,数值等。
  • AMF格式的有一系列Object和SCRIPTDATAOBJECTEND(0x9,表示script data结束),示意图如下:
    在这里插入图片描述
  • 在Script tag中一般包含2个AMF包。
    1> 第一个AMF包,内容固定,分别为:
    		▪ 第1个字节:固定为0x02,表示字符串类型
    		▪ 第2-3个字节:UI16类型,固定为0x000A,表示字符串的长度为10(onMetaData的长度);
    		▪ 第4-13个字节:字符串onMetaData对应的16进制数字(0x6F 0x6E 0x4D 0x65 0x74 0x61 0x44 0x61 0x74 0x61);
    	(这个包与Adobe的一些API调用有关)
    	
    2> 第二个AMF包:
    	▪ 第1个字节:固定为0x08,表示数组类型;
    	▪ 第2-5个字节:UI32类型,表示数组的长度,onMetaData中具体包含哪些属性是不固定的。
    	▪ 第6个字节+:
    	比如该AMF包表示duration,则:
    		○ 第6-9个字节:0x0008,表示长度为8个字节;
    		○ 第10-17个字节:0x64 75 72 61 74 69 6F 6E,表示 duration 这个字符串;
    		○ 第18个字节:固定为0x00,表示为数值类型;
    		○ 第19-26个字节:0x...,表示具体的时长;
    
    解析出来的script tag为:
    在这里插入图片描述
    那说明总共有26组元数据信息,比如duration为391.495s,分辨率为1280X720

实际应用遇到的问题

  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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有