FLV封装格式分析

FLV封装格式分析

原文:https://www.cnblogs.com/leisure_chn/p/10662941.html
FLV 封装的媒体文件具有体积轻巧、封装播放简单等特点,很适合网络应用。
FLV 封装格式的文件扩展名为 .flv。FLV 文件主要由一个 Header 加上由多个 Tag 组成的 Body 构成。
FLV Header
http-flv
首先一个get请求
然后一个200的回复

然后数据包就可以看到FLV的header,以FLV三个字母开头
在这里插入图片描述
flv header 的定义如下

字段类型说明
SignatureUI8‘F’ (0x46)
SignatureUI8‘L’ (0x4C)
SignatureUI8‘V’ (0x56)
VersionUI8FLV 版本。例如,0x01 表示 FLV 版本 1
TypeFlagsUI8b[0] 是否存在视频流;b[2] 是否存在音频流;其他字段保留,值为0
DataOffsetUI32FLV Header 长度(字节)
typedef struct {
    UI8 Signature;
    UI8 Signature;
    UI8 Signature;
    UI8 Version;
    UI8 TypeFlags;
    UI32 DataOffset;
}   FLVHEADER;

FLV body
一个 FLV 文件,除开头的 FLV Header 外,剩余部分就是 FLV Body。FLV Body 由一系列 back-pointer 和 tag 交织构成。back-pointer 表示前一 tag 大小。FLV Body 类型是 FLVBODY,FLVBODY 定义如下:

字段类型说明
PreviousTagSize0UI32值总为 0
Tag1FLVTAG第一个 Tag
PreviousTagSize1UI32前一 Tag 大小,单位字节。FLV 版本 1 中, 此值等于前一 Tag 的 DataSize + 11
Tag2FLVTAG第二个 Tag
PreviousTagSizeN-1UI32倒数第二个 Tag 大小,单位字节
TagNFLVTAG最后一个 Tag
PreviousTagSizeNUI32最后一个 Tag 的大小,单位字节
typedef struct {
    UI32 PreviousTagSize0;
    FLVTAG Tag1;
    UI32 PreviousTagSize1;
    FLVTAG Tag2;
    ...
    UI32 PreviousTagSizeN-1;
    FLVTAG TagN;
    UI32 PreviousTagSizeN;
}   FLVBODY;

FLV tag
FLV Tag 包含音频、视频或脚本元数据、可选的加密元数据和 payload。FLV Tag 类型是 FLVTAG,FLVTAG 定义如下:

字段类型说明
ReservedUB [2]用于 FMS 的保留字段, 值为 0
FilterUB [1]指示 packet 是否需要预处理。0 = 不需要预处理。1 = packet 在渲染前需要预处理(例如解密)。未加密文件中此值为0,加密文件中此值为1。
TagTypeUB [5]8 = 音频9 = 视频18 = 脚本数据
DataSizeUI24Tag 中除通用头外的长度,即 Header + Data 字段的长度 (等于 Tag 总长度 – 11)
TimestampUI24当前 Tag 的解码时间戳 (DTS),单位是毫秒。FLV 文件中第一个 Tag 的 DTS 总为 0
TimestampExtendedUI8和 Timestamp 字段一起构成一个 32 位值, 此字段为高 8 位。单位毫秒
StreamIDUI24总为 0
HeaderIF TagType == 8 AudioTagHeaderIF TagType == 9 VideoTagHeader音频或视频 TagHeader,注意脚本没有 TagHeader
DataIF TagType == 8 AUDIODATAIF TagType == 9 VIDEODATAIF TagType == 18 SCRIPTDATA音频、视频或脚本 TagBody
typedef struct {
    UB[2] Reserved;
    UB[1] Filter;
    UB[5] TagType;
    UI24 DataSize;
    UI24 Timestamp;
    UI8 TimestampExtended;
    UI24 StreamID;
  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;

一个 FLVTAG 中,前 11 个字节是通用 TagHeader,后面紧跟跟着音频 Tag、视频 Tag 或脚本 Tag,其中音频 Tag 和视频 Tag 都包含 TagHeader 和 TagBody 两部分,脚本 Tag 只有 TagBody 部分。

上面 Timestamp 和 TimestampExtended 两个字段拼成一个 32 位的时间戳,是当前 Tag 的解码时间戳 (DTS)。对于音频帧来说,PTS 和 DTS 相同。对于视频帧来说,若含 B 帧,则 PTS 和 DTS 不同,H264 视频帧 PTS = DTS + CTS,CTS 就是 CompositionTime 字段,参考 3.2.1 节 CompositionTime 字段的定义。

3.1 Audio Tag
Audio Tag 包括 AudioTagHeader 和 AudioTagBody 两部分。
3.1.1 AudioTagHeader
AudioTagHeader 定义如下:

字段类型说明
SoundFormatUB [4]声音格式:0 = Linear PCM, platform endian1 = ADPCM2 = MP33 = Linear PCM, little endian4 = Nellymoser 16-kHz mono5 = Nellymoser 8-kHz mono6 = Nellymoser7 = G.711 A-law logarithmic PCM8 = G.711 mu-law logarithmic PCM 9 = reserved10 = AAC11 = Speex14 = MP3 8-Khz15 = Device-specific sound
SoundRateUB [2]采样率:AAC: 总为30 = 5.5 kHz1 = 11 kHz2 = 22 kHz3 = 44 kHz
SoundSizeUB [1]采样位深。此参数仅适用未压缩格式,压缩格式总在内部被解码为16位。0 = 8位1 = 16位
SoundTypeUB [1]0 = 单声道1 = 立体声
IF SoundFormat == 10 AACPacketTypeUI8AAC帧类型。仅当声音格式为 10 时,存在此字段0 = AAC sequence header1 = AAC raw

格式 3,linear PCM,存储原始 PCM 采样点。如果采样位深为 8,采样点数据为无符号型。如果采样位深为 16,采样点数据为小端存储的带符号型。如果是立体声,左右声道采样点交织存放:左-右-左-右-…

格式 0 与格式 3 的不同之处只有一点:格式 0 存储 16 位采样数据,采用的大小端顺序是创建 FLV 文件的平台所使用的大小端顺序。因此,不应使用格式 0,而应使用格式 3。

格式 4 (Nellymoser 16-kHz mono) 和格式 5 (Nellymoser 8 kHz mono),是两种特殊情况, 因为采样率字段无法表示 8 kHz 和 16 kHz。当采样格式是格式 4 或格式 5 时,Flash 播放器会忽略采样率和声音类型两个字段。对于其他采样率的 Nellymoser 格式, 即格式 6,则正常使用采样率和声音类型两个字段。

格式 10,AAC,声音类型应为 1 (立体声) 且采样率应为 3 (44 kHz)。这并不表示 FLV 中的 AAC 音频总是立体声、44 kHz的数据。实际上,Flash 播放器会忽略这两个值,而从已编码的 AAC 位流中提取出声道数和采样率信息。

格式 11,Speex,音频以 16 kHz采样率压缩为单声道,采样率字段值应为 0,采样位深字段值应为 1,声音类型字段值应为 0。

格式 7,8,14 和 15 保留。

typedef struct {
    UB [4] SoundFormat;
    UB [2] SoundRate;
    UB [1] SoundSize;
    UB [1] SoundType;
  IF SoundFormat == 10
    UI8 AACPacketType;
}

3.1.2 AudioTagBody/AUDIODATA
AUDIODATA 定义如下:
字段:Body

类型:IF Encrypted EncryptedBodyELSE AudioTagBody
说明:类型分加密与非加密两种

typedef struct {
  IF SoundFormat == 10
    AACAUDIODATA SoundData;
  ELSE
    Varies by format
}   AudioTagBody;

3.1.3 AACAUDIODATA
Flash 播放器 9.0.115.0 及以上版本支持 AAC 格式。AACAUDIODATA 定义如下:

字段 Data

类型 IF AACPacketType == 0 AudioSpecificConfigELSE IF AACPacketType == 1 Raw AAC frame data in UI8 []

说明 AudioSpecificConfig 在 ISO 14496-3 中定义

3.2 Video Tag
Video Tag 包含 VideoTagHeader 和 VideoTagBody 两部分。

3.2.1 VideoTagHeader

在这里插入图片描述
H.264 的命名遵循了 ITU-T 的命名约定,它是 VCEG 视频编码标准 H.26x 线中的一员;MPEG-4 AVC 的命名来自 ISO/IEC MPEG 的命名约定,它是 ISO/IEC 14496 的第 10 部分,该协议族被称为 MPEG-4

3.2.2 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;

3.2.3 AVCVIDEOPACKET
AVCVIDEOPACKET 包含 AVC(H264) 视频净荷数据。AVCVIDEOPACKET 定义如下:
在这里插入图片描述

typedef struct {
  IF AVCPacketType == 0
    AVCDecoderConfigurationRecord Data;
  IF AVCPacketType == 1
    One or more NALUs
}   AVCVIDEOPACKET;

3.3 Data Tag
数据 Tag 封装了单一方法,此方法通常在 Flash 播放器中的网络流对象上被调用。数据 Tag 包含方法名和一组参数。

在这里插入图片描述

typedef struct {
  IF Encrypted
    EncryptedBody Body
  else
    ScriptTagBody Body;
}   SCRIPTDATA;

CRIPTDATA 包含 Body 字段。如果采用了加密,Body 的类型是 EncryptedBody,可参考规范文档“附件 F. FLV 加密”章节获得详细信息,此处略。如果未采用加密,则 Body 的类型是 ScriptTagBody,下面详述。

ScriptTagBody 包含以 AMF(Action Message Format) 编码的 SCRIPTDATA。AMF 是一种紧凑二进制格式,用于序列化 ActionScript 对象图。ScriptTagBody 定义如下:

在这里插入图片描述
这里的 Name 就是上面提到的数据 Tag 中的方法名,Value 是此方法的一组参数。

typedef struct {
    SCRIPTDATAVALUE Name;
    SCRIPTDATAVALUE Value;
}   ScriptTagBody;

3.3.2 SCRIPTDATAVALUE
一个 SCRIPTDATAVALUE 记录包含一个特定类型的 ActionScript 值。

SCRIPTDATAVALUE 定义如下:

在这里插入图片描述
SCRIPTDATAVALUE 的两个字段,Type 是类型,ScriptDataValue 是值。Type 的值确定 ScriptDataValue 的类型。因为 ScriptDataValue 的类型是动态的,由运行时解析得到的 Type 的值确定,所以这里类型和值用了两个字段。如果是静态类型,显然只用一个字段就可以了。

typedef struct {
    UI8 Type;
  IF Type == 0
    DOUBLE ScriptDataValue;
  IF Type == 1
    UI8 ScriptDataValue;
  IF Type == 2
    SCRIPTDATASTRING ScriptDataValue;
  IF Type == 3
    SCRIPTDATAOBJECT ScriptDataValue;
  IF Type == 7
    UI16 ScriptDataValue;
  IF Type == 8
    SCRIPTDATAECMAARRAY ScriptDataValue;
  IF Type == 10
    SCRIPTDATASTRICTARRAY ScriptDataValue;
  IF Type == 11
    SCRIPTDATADATE ScriptDataValue;
  IF Type == 12
    SCRIPTDATALONGSTRING ScriptDataValue;
}   SCRIPTDATAVALUE;

3.3.1 节中 Name 字段和 Value 字段的类型都是SCRIPTDATAVALUE。Name 表示方法名,实际类型通常是SCRIPTDATASTRING。Value 字段表示方法的一组参数,实际类型通常是SCRIPTDATAECMAARRAY。后文将介绍 SCRIPTDATASTRING 和 SCRIPTDATAECMAARRAY 两种类型。其他类型略,详情可参考 FLV 规范文档。

3.3.5 实例:onMetaData 对象
FLV 元数据对象应在名为 onMetadata 的 SCRIPTDATA 标签中携带。各种属性对通过 NetStream.onMetaData 属性运行的 ActionScript 程序有效。可用的属性根据创建 FLV 文件的软件而有所不同。典型属性包括:

在这里插入图片描述

onMetaData 标签通常会成为 FLV Body 中的第一个标签,紧跟在 FLV Header 之后。onMetaData 标签中存储的是一些视频、音频及文件相关的元数据信息:如视频帧率,音频采样率、文件长度等。

结合 3.3.1 节,onMetaData 标签的 Name 字段主要就是存储 “onMetaData” 字符串。具体为:第 1 个字节值是 0x02,表示 Name 字段是字符串类型。第 2-3 个字节为 UI16 类型值,标识字符串的长度,值为 0x000A (“onMetaData” 这个字符串的长度)。后面跟着的数据为具体的字符串,值为 “onMetaData”。

onMetaData 标签的 Value 字段存储上表所示的各属性键值对。具体为:第 1 个字节值是 0x08,表示 Value 字段是数组类型。第 2-5 个字节为UI32类型值,表示数组元素个数。后面紧跟着数组,数组元素为属性名称和值组成的对(键值对)。最后是数组的结束符。

ScriptTagBody onMetaData;

onMetaData.Name.Type == 0x02
onMetaData.Name.ScriptDataValue.StringLength == 0x000A
onMetaData.Name.ScriptDataValue.StringData == "onMetaData"

onMetaData.Value.Type == 0x08
onMetaData.Value.ScriptDataValue.ECMAArrayLength == 
onMetaData.Value.ScriptDataValue.Variables[0].PropertyName == {0x0005, "width"}   // SCRIPTDATASTRING 类型
onMetaData.Value.ScriptDataValue.Variables[0].PropertyData == {0x00, 1280.0}      // SCRIPTDATAVALUE 类型
onMetaData.Value.ScriptDataValue.Variables[1].PropertyName == {0x0005, "height"}  // SCRIPTDATASTRING 类型
onMetaData.Value.ScriptDataValue.Variables[1].PropertyData == {0x00, 720.0}       // SCRIPTDATAVALUE 类型
...

总结
FLV 结构如下图所示:
在这里插入图片描述
在 C 语言中定义 FLV 文件结构,一目了然:

/*
 * @brief flv file header 9 bytes
 */
typedef struct flv_header {
    uint8_t signature[3];
    uint8_t version;
    uint8_t type_flags;
    uint32_t data_offset; // header size, always 9
} __attribute__((__packed__)) flv_header_t;

/*
 * @brief flv tag general header 11 bytes
 */
typedef struct flv_tag {
    uint8_t tag_type;
    uint32_t data_size;
    uint32_t timestamp;
    uint8_t timestamp_ext;
    uint32_t stream_id;
    void *data; // will point to an audio_tag or video_tag
}   flv_tag_t;

typedef struct audio_tag {
    uint8_t sound_format; // 0 - raw, 1 - ADPCM, 2 - MP3, 4 - Nellymoser 16 KHz mono, 5 - Nellymoser 8 KHz mono, 10 - AAC, 11 - Speex
    uint8_t sound_rate; // 0 - 5.5 KHz, 1 - 11 KHz, 2 - 22 KHz, 3 - 44 KHz
    uint8_t sound_size; // 0 - 8 bit, 1 - 16 bit
    uint8_t sound_type; // 0 - mono, 1 - stereo
    void *data;
}   audio_tag_t;

typedef struct video_tag {
    uint8_t frame_type;
    uint8_t codec_id;
    void *data;
}   video_tag_t;

typedef struct avc_video_tag {
    uint8_t avc_packet_type; // 0x00 - AVC sequence header, 0x01 - AVC NALU
    uint32_t composition_time;
    uint32_t nalu_len;
    void *data;
}   avc_video_tag_t;
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值