Flash Video 简称FLV,目前国内大部分视频分析网站都是采用这种格式。
它的主要是由 File Header
+ File Body
构成。 如下图所示
FLV Header 构成
字段 | 字节数 | 描述 |
---|---|---|
Signature | 3 | 固定字节 0X46 4c 56 对应ASCII 的FLV |
Version | 1 | 版本号 |
TypeFlags | 1 | 类型标识。 前5个bit是类型标志预留字段,必须是0; 第6个bit音频类型标志(TypeFlagsAudio); 第7个bit是类型标志预留字段,必须是0; 第8个bit视频类型标志(TypeFlagsVideo)。(0x05,也就是 00000101,表示既有音频也有视频。0x01 只有视频) |
data offset | 4 | 版本号为1,值固定为9 |
FLV Body 构成
FLV body 由PreviousTagSize + Tag 构成,而tag 又分为 3种类型,分别是
Script(脚本)、Video(视频)、Audio(音频)
PreviousTagSize 解析
PreviousTagSize
为固定的4个字节,表示前面一个tag 的值
FLV Tag 解析
FLV tag 由 TagHeader + tag Data 构成
Tag Header
Tag Header
为固定的11 个字节,其内部由以下几个字段构成
字段 | 字节数 | 描述 |
---|---|---|
TagType | 1 | 0x12 : Scipt 0x09 :视频 0x08:音频 |
DataSize | 3 | 数据长度 |
TimeStamp | 3 | 相对于第一帧的时间戳,单位为毫秒,第一帧总为0 |
TimeStampExtender | 1 | 时间戳的补充字段 |
StreamID | 3 | 0 |
所以后面的一个 PreviousTagSize
= 前一个dataSize + 11;
Tag Data
Script data
Script Tag,一般都是flv文件的开头才有一个。它包含两个AMF(Action Message Format)包,第一个AMF包封装了" onMetaData ",第二个AMF包封装了诸如视频图像长宽,文件长度,视频帧率,音频比特率,位深等等。
上图中0x08 字节,表示 Value 字段是数组类型
Video Data
Tag Data 是由 FrameType
和CodecID
以及VideoData
或者AVCVIDEOPACKET
构成,AVCVIDEOPACKET
只存在第一个video tag 中。
下图是视频的首个 Tag,它一定是由 11个字节的Header + frameType(0x17,0x27)+AVCVIDEOPACKET 组成
下面是Tag Data
3个字段的描述:
0x17 : 1个byte 对应8 bits, 0x17 转为0001 0111 ,分别对应的是截图中的frameType
和 CodecID
.
FrameType
数值对应的值意味着 (0001 = 1)
1– keyframe
2 – inner frame
3 – disposable inner frame (h.263 only)
4 – generated keyframe
CodecID
数值对应的值意味着 (0111 = 7)
2 – seronson h.263
3 – screen video
4 – On2 VP6
5 – On2 VP6 with alpha channel
6 – Screen video version 2
7 – AVC (h.264)
所以我们可以判断在传输非关键帧的时候 FrameType
+ CodeCID
组成的值为0x27
AVCVIDEOPACKET 解析
字段 | 字节 | 描述 |
---|---|---|
AVCPACKETType | 1 | 0:AVC sequence header 1:AVC NALU 2:AVC end of sequence |
Composition Offset | 3 | 合成时间。 AVCPacketType==1,表示 合成时间(单位毫秒); 否则为0 |
VideoData | 2 | 如果AVCPacketType=0数据部分为AVCDecoderConfigurationRecord; 如果AVCPacketType=1,数据部分为1个或多个NALU; 如果AVCPacketType==2,数据部分为空 |
关键的AVCDecoderConfigurationRecord
数据构成
字段 | 字节 | 描述 |
---|---|---|
版本 | 1 | 0x01版本号为1 |
编码规格 | 3 | sps[1]+sps[2]+sps[3] |
NALU 的长度 | 1 | 0xff |
SPS个数 | 1 | 0xE1 |
SPS长度 | 2 | 整个sps长度 |
SPS的内容 | n | 整个sps |
PPS个数 | 1 | 0x01 |
PPS长度 | 2 | 整个pps长度 |
PPS内容 | n | 整个pps内容 |
组装的相关代码见下:
const char *sps = videoFrame.sps.bytes;const char *pps = videoFrame.pps.bytes;NSInteger sps_len = videoFrame.sps.length;NSInteger pps_len = videoFrame.pps.length;body = (unsigned char *)malloc(rtmpLength);memset(body, 0, rtmpLength);body[iIndex++] = 0x17;body[iIndex++] = 0x00;body[iIndex++] = 0x00;body[iIndex++] = 0x00;body[iIndex++] = 0x00;body[iIndex++] = 0x01;body[iIndex++] = sps[1];body[iIndex++] = sps[2];body[iIndex++] = sps[3];body[iIndex++] = 0xff;/*sps*/body[iIndex++] = 0xe1;body[iIndex++] = (sps_len >> 8) & 0xff;body[iIndex++] = sps_len & 0xff;memcpy(&body[iIndex], sps, sps_len);iIndex += sps_len;/*pps*/body[iIndex++] = 0x01;body[iIndex++] = (pps_len >> 8) & 0xff;body[iIndex++] = (pps_len) & 0xff;memcpy(&body[iIndex], pps, pps_len);iIndex += pps_len;
普通Video Data 解析
讲完第一个特殊的VideoData, 其他所有的VideoData
都是由AVPACKETTYPE
+ CompsitionTime offset
+ Data(去除startCode 的有效图像数据)
构成。
具体的iOS 侧代码组装可见:LFLIiveKit
FLV 分析工具需要使用Windows 下的 FLV Analyzer