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 构成
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 的有效图像数据)构成。


版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/34559.html