将H.264封装为FLV格式

本文将介绍如何将H.264封装成flv格式。

在看本文之间,建议先看一看下面两篇文章:

H.264码流结构

FLV格式详解

首先说一说构建一个FLV文件需要什么?

FLV Header + FLv script tag + FLV Video tag + FLV Audio tag

由于这里只是封装H.264,所以不包括Audio tag。

下面将通过分析示例来说明FLV Header + FLv script tag + FLV Video tag这三部分如何构建。

1、FLV Header

通过阅读上面的文章《FLV格式详解》应该就很清楚FLV Header的内容了。

下面来分析一个实例:

将H.264封装为FLV格式

Signature:0x46('F')
Signature:0x4c('L')
Signature:0x56('V')
Version:01
Flags:01
    TypeFlagsReserved [Bit 3-7]:0
    TypeFlagsAudio [Bit 2]:0
    TypeFlagsReserved [Bit 1]:0
    TypeFlagsVideo [Bit 0]:1
DataOffset:00 00 00 09
preTagSize:00 00 00 00 // 第一个tag默认为0

2、FLv script tag

又称Metadata Tag,位于flv header后的第一个tag

下面来分析一个实例

将H.264封装为FLV格式

Tag Header:

TagType:12(表示这是一个script tag)
Datasize:00 00 9f(Tag Data 部分的大小)
Timestamp:00 00 00(该Tag的时间戳)
Timestamp_ex:00(时间戳的扩展部分)
StreamID::00 00 00(总是0)

Tag data:

因为TagType为0x12,所以这部分的数据为两个AMF包

第一个AMF包:

type:02(表示字符串)
stringLen:00 0a(字符串长度为10)
string:6f 6e 4d 65 74 61 44 61 74 61(onMetaData)

第二个AMF包:

type:08(表示数组)
arrayNum:00 00 00 07(数组元素个数)
stringLen:00 08(第一个数组元素字符串长度)
string:64 75 72 61 74 69 6f 6e(duration)
valType:00(数据类型,double型)
val:40 03 70 a3 d7 0a 3d 71(double型)
stringLen:00 05
string:77 69 64 74 68(width)
...
end:00 00 09
preTagSize:00 00 00 aa

3、FLV Video Tag

这部分封装着图像数据,也就是H.264的数据封装在这里。

H.264是由一个一个NALU组成,NALU的类型有(SPS、PPS、I帧的SLICE、非I帧的SLICE)

封装H.264就是将这些NALU一个一个取出来,然后封装成Tag。

需要注意的是,SPS与PPS必须封装在一个Tag中。

下面分别通过实例来分析各种NALU(SPS、PPS、I帧的SLICE、SEI、非I帧的SLICE)是怎么封装的。

1、SPS与PPS

将H.264封装为FLV格式

Tag Header:

TagType:09(Tag的类型,包括音频(0x08)、视频(0x09)、script data(0x12))
Datasize:00 00 2e(Tag Data 部分的大小)
Timestamp:00 00 00(时间戳,19ms)
Timestamp_ex:00(时间戳的扩展部分)
StreamID:00 00 00(总是0)

Tag data:

FrameType | CodecID:17(keyframe | AVC)(视频tag的参数)

AVCVideoPaket:(因为CodecID==7,所以VideoData为AVCVideoPaket)

AVCPaketType:00(ACVPacket的类型,0: AVC sequence header;1: AVC NALU;2: AVC end of sequence)
CompositionTime:00 00 00

(因为ACVPaketType==0,所以Data=AVCDecoderConfigurationRecord)
AVCDecoderConfigurationRecord:

configurationVersion:01
AVCProfileIndication:64
profile_compatibility:00
AVCLevelIndication:1e
lengthSi*usOne:ff 
numOfSequenceParameterSets:e1(低五位为SPS的个数,计算方法为:numOfSequenceParameterSets & 0x1F=1)
sequenceParameterSetLength:00 18(SPS的长度,24)
sequenceParameterSetNALUnits:67 64 00 1e ac d9 40 a0 33 b0 11 00 00 03 02 47 00 00 6d 34 0f 16 2d 96(SPS)
numOfPictureParameterSets:01(PPS的个数)
pictureParameterSetLength:00 06(PPS的长度)
pictureParameterSetNALUnits:68 eb e3 cb 22 c0(PPS)
previousTagSize:00 00 00 39

2、I帧的SLICE

将H.264封装为FLV格式

Tag Header:

TagType:09(Tag的类型,包括音频(0x08)、视频(0x09)、script data(0x12))
Datasize:00 35 78(Tag Data 部分的大小)
Timestamp:00 00 0a(时间戳,19ms)
Timestamp_ex:00(时间戳的扩展部分)
StreamID:00 00 00(总是0)

Tag data:

FrameType | CodecID:17(key frame | AVC)(视频tag的参数)

因为CodecID==7,所以VideoData为AVCVideoPaket

AVCVideoPaket:

AVCPaketType:01(ACVPacket的类型,0: AVC sequence header;1: AVC NALU;2: AVC end of sequence)
CompositionTime:00 00 0a
NaluLen:00 00 35 6f
NaluData:...
preTagSize:00 00 35 83

对于SEI的封装跟I帧是一样的。

3、非I帧的SLICE

非I帧的封装格式和I帧的封装格式基本一样,唯一不同的是FrameType | CodecID:部分,应该设置为:

FrameType | CodecID:27(inter frame | AVC)(视频tag的参数)

总结:以上通过实例讲解了FLV的头部信息,script tag,以及H.264不同类型的NALU如何封装成tag,下面放出源码。

GitHub:https://github.com/ImSjt/H.264toFLV

CSDN下载:https://download.csdn.net/download/weixin_42462202/11037715