FLV 封装格式详解
FLV 封装格式详解
简介
FLV(Flash Video)是 Adobe 公司设计开发的一种流行的流媒体格式,由于其视频文件体积轻巧、封装简单等特点,使其很适合在互联网上进行应用。此外,FLV可以使用 Flash Player 进行播放,而 Flash Player 插件已经安装在全世界绝大部分浏览器上,这使得通过网页播放 FLV 视频十分容易。目前主流的视频网站如优酷网,土豆网,乐视网等网站无一例外地使用了 FLV 格式。FLV 封装格式的文件后缀通常为“.flv”。直播场景下拉流比较常见的是 http-flv 直播流,具有延时低,易传输等特点。
FLV 格式
总体上看,FLV 由文件头(file header)和(file body)组成,其中 FLV body 由一对对的 Tag 和 Previous Tag Size 组成。
其中,Previous Tag Size 占用4个字节,记录前一个 Tag 的大小,用于逆向读取处理。
FLV header 后的第一个 Previous Tag Size 为 0。
Tag 由 Tag Header 和 Tag Body 组成。Tag Header 占 11 字节。
而 Tag Body 一般分为三种类型:脚本(Script)数据、视频数据、音频数据。其中 Video Tag 和 Audio Tag 由 Tag header 和 Tag Data 组成;Script Tag 只有 Tag Data。
FLV 数据以大端序进行存储,在解析时需要注意。
FLV 文件的详细内容结构如下:
FLV header
从上图中可以看到,FLV 头占用 9 个字节,用来标识文件类型为 FLV 类型,以及后续的音视频标识。一个 FLV 文件,每种类型的 tag 都属于一个流,也就是一个 flv 文件最多只有一个音频流,一个视频流,不存在多个独立的音视频流在一个文件的情况。FLV 头的结构如下:
上面的 UI 表示无符号整型,后面跟着的数字代表其长度是多少位;UB 表示位域,表示一个字节的多少位。可以参考C语言中的结构体位域。
所有 FLV 格式文件都以 FLV Header 开头。FLV Header 类型是 FLVHEADER,FLVHEADER 定义如下:
typedef struct {
UI8 Signature; // 'F' (0x46)
UI8 Signature; // 'L' (0x4C)
UI8 Signature; // 'V' (0x56)
UI8 Version; // FLV 版本。例如,0x01 表示 FLV 版本 1
UI8 TypeFlags; // b0 是否存在视频流,b2 是否存在音频流,其他字段保留,值为 0
UI32 DataOffset; // FLV Header 长度,单位:字节
} FLVHEADER;
在 FLV 版本 1 中,“数据偏移”字段值为 9。在 FLV 未来版本中,此字段可兼容更大尺寸的 FLV Header。
FLV body
FLV Header之后,就是 FLV File Body。FLV File Body 是由一连串的 back-pointers + tags 构成。
FLV Body 类型是 FLVBODY,FLVBODY 定义如下:
typedef struct {
UI32 PreviousTagSize0;
FLVTAG Tag1;
UI32 PreviousTagSize1;
FLVTAG Tag2;
...
UI32 PreviousTagSizeN-1;
FLVTAG TagN;
UI32 PreviousTagSizeN;
} FLVBODY;
back-pointer
back-pointer 表示 Previous Tag Size(前一个 tag 的字节数据长度),占4个字节,第一个 back-pointer 数据为 0。
FLV tag
tag 表示音视频数据,每一个 tag 由两部分组成:tag header 和 tag data。
FLV Tag 类型是 FLVTAG,FLVTAG 定义如下:
typedef struct {
UB[2] Reserved; // 用于 FMS 的保留字段, 值为 0
UB[1] Filter; // 指示 packet 是否需要预处理。0 = 不需要预处理。1 = packet 在渲染前需要预处理。未加密文件中此值为0,加密文件中此值为1。
UB[5] TagType; // 8 = 音频,9 = 视频,18 = 脚本数据
UI24 DataSize; // tag data 的长度。等于 tag 总长度 – 11
UI24 Timestamp; // 当前tag的解码时间戳 (DTS),单位是ms。第一个tag的DTS总是0
UI8 TimestampExtended; // 和Timestamp字段一起构成一个32位值, 此字段为高8位。单位是ms
UI24 StreamID; // 总为 0
IF TagType == 8
AudioTagHeader Header;
IF TagType == 9
VideoTagHeader Header;
IF TagType == 8
AUDIODATA Data;
IF TagType == 9
VIDEODATA Data;
IF TagType == 18
SCRIPTDATA Data;
} FLVTAG;
上面 Timestamp 和 TimestampExtended 两个字段拼成一个 32 位的时间戳,是当前 Tag 的解码时间戳 (DTS)。对于音频帧来说,PTS 和 DTS 相同。对于视频帧来说,若含 B 帧,则 PTS 和 DTS 不同,H264 视频帧 PTS = DTS + CTS,CTS 就是 CompositionTime 字段,表示 PTS 与 DTS 的时间偏移值,单位 ms。
FLV tag header
存放当前 tag 的类型、数据区长度、时间戳等信息。tag header 一般占 11 个字节。
FLV tag 的类型可以是视频、音频和 Script(脚本类型)。
FLV tag data:audio tag
audio tag 包含 audio tag header 和 audio tag body 两部分。
其中,audio tag header 占 1 字节,包含了音频数据的参数信息,从第 2 个字节开始为音频流数据。
前 4bit 表示音频格式;第 5、6bit 表示采样率;第 7bit 表示采样精度;第 8bit 表示音频声道。
这里着重强调一下格式10格式:AAC。声音类型应为 1 (立体声) 且采样率应为 3 (44 kHz)。这并不表示 FLV 中的 AAC 音频总是立体声、44 kHz的数据。实际上,Flash 播放器会忽略这两个值,而从已编码的 AAC 位流中提取出声道数和采样率信息。
第二个字节开始为音频数据:
如果音频格式为 10,即是 AAC 格式。AudioTagHeader 中会多出一个字节 AACPacketType,这个字段来表示 AACAUDIODATA 的类型:0 = AAC sequence header,1 = AAC raw。
- AAC sequence header 也就是包含了 AudioSpecificConfig,里面有一些更加详细音频的信息。
- AAC raw 这种包含的就是音频 ES 流了,也就是音频负载(audio payload)。
AudioTagHeader 定义如下:
typedef struct {
UB [4] SoundFormat;
UB [2] SoundRate;
UB [1] SoundSize;
UB [1] SoundType;
IF SoundFormat == 10
UI8 AACPacketType;
} AudioTagHeader;
AudioTagBody/AUDIODATA 定义如下:
typedef struct {
IF Encrypted
EncryptedBody Body
else
AudioTagBody Body;
} AudioTagBody;
AUDIODATA 包含 Body 字段。如果采用了加密,Body 的类型是 EncryptedBody,可参考规范文档“附件 F. FLV 加密”章节获得详细信息,此处略。如果未采用加密,则 Body 的类型是 AudioTagBody,下面详述。
AudioTagBody 定义如下:
typedef struct {
IF SoundFormat == 10
AACAUDIODATA SoundData;
ELSE
Varies by format
} AudioTagBody;
Flash 播放器 9.0.115.0 及以上版本支持 AAC 格式。AACAUDIODATA 定义如下:
typedef struct {
IF AACPacketType == 0
AudioSpecificConfig;
ELSE IF AACPacketType == 1
Raw AAC frame data in UI8;
} AACAUDIODATA;
FLV tag data:video tag
video tag 包含 video tag header 和 video tag body 两部分。video tag data 开始的第一个字节包含视频数据的参数信息,从第二个字节开始为视频流数据。结构如下:
第一个字节包含视频信息:前4位表示帧类型;后4位表示编码类型。
第 2 个字节开始为视频数据。
如果 CodecID = 7,视频的格式是 AVC(H.264)的话,VideoTagHeader 会多出 4 个字节的信息,AVCPacketType(1 字节) 和 CompositionTime(3 字节),所以是 H.264 编码的情况下 VideoHeader 长度是 5 个字节。
AVC VIDEO PACKET 结构如下:
VideoTagBody/VIDEODATA 定义如下:
typedef struct {
IF Encrypted
EncryptedBody Body
else
VideoTagBody Body;
} VIDEODATA;
VIDEODATA 包含 Body 字段。如果采用了加密,Body 的类型是 EncryptedBody,可参考规范文档“附件 F. FLV 加密”章节获得详细信息,此处略。如果未采用加密,则 Body 的类型是 VideoTagBody,下面详述。
VideoTagBody 包含视频帧净荷数据。VideoTagBody 定义如下:
typedef struct {
IF FrameType == 5
UI8 VideoData;
ELSE (
IF CodecID == 2
H263VIDEOPACKET VideoData;
IF CodecID == 3
SCREENVIDEOPACKET VideoData;
IF CodecID == 4
VP6FLVVIDEOPACKET VideoData;
IF CodecID == 5
VP6FLVALPHAVIDEOPACKET VideoData;
IF CodecID == 6
SCREENV2VIDEOPACKET VideoData;
IF CodecID == 7
AVCVIDEOPACKET VideoData;
)
} VideoTagBody;
AVCVIDEOPACKET 包含 AVC(H264)视频净荷数据。AVCVIDEOPACKET 定义如下:
typedef struct {
IF AVCPacketType == 0
AVCDecoderConfigurationRecord Data;
IF AVCPacketType == 1
One or more NALUs
} AVCVIDEOPACKET;
AVCDecoderConfigurationRecord 包含着 H.264 解码相关比较重要的 sps 和 pps 信息,再给 AVC 解码器送数据流之前一定要把 sps 和 pps 信息送出,否则的话解码器不能正常解码。而且在解码器 stop 之后再次 start 之前,如 seek、快进快退状态切换等,都需要重新送一遍 sps 和 pps 的信息。
AVCDecoderConfigurationRecord 在 FLV 文件中一般情况也是出现 1 次,也就是第一个 video tag。
FLV tag data:script tag
script tag 又通常被称为 metadata tag,会放一些关于FLV视频和音频的元数据信息如:duration、width、height等。通常该类型 tag 会跟在 FLV header 后面作为第一个 tag 出现,而且只有一个。
script tag 没有 script tag header,只有script tag body。一般来说,script tag 包含两个 AMF 包。结构如下所示:
第一个 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 类型值,表示数组元素的个数。
后面即为各数组元素的封装,数组元素为元素名称和值组成的对。表示方法如下:第 1-2 个字节表示元素名称的长度,假设为 L。后面跟着为长度为 L 的字符串。第 L+3 个字节表示元素值的类型。后面跟着为对应值,占用字节数取决于值的类型。
常见的数组元素表示如下表:
标签:Tag,封装,字节,FLV,header,tag,类型,详解 From: https://blog.csdn.net/ProgramNovice/article/details/137468819AMF:Action Message Format,是 Adobe 设计的一种通用数据封装格式,在 Adobe 的很多产品中应用,简单来说,AMF 将不同类型的数据用统一的格式来描述。