多媒体封装格式学习:H264封装成FLV(一)

原创 2015年11月21日 17:37:43

         搞了好几天的FLV封装,话说封装真是个苦力活,有时候思路不是很清晰的时候,真心有点乱。

         网上关于H264封装成FLV的文档,都分析的很详细了,但是有几个点没有考虑到,一会在下面我会一一跟大家说明。图什么的我就不画了,网上一搜应该有很多,那先看下面一个结构体吧。

typedef struct FLVHeader
{
  unsigned char First;// "F"
  unsigned char Second;//"L"
  unsigned char Last;//"V"
  unsigned char Version; //0x01
  unsigned char Flags;//"前五位保留且为0,第六位表示是否存在音频Tag,第七位保留为0,第八位表示是否有视频Tag"
  unsigned char HeaderLenth[4];//header 长度,一共9bytes
}FLVHeader;

了解过FLV的朋友都应该知道FLV是由FLVHeader和FLVBody两大部分构成的,而FLVBody又可以划分成N个更小的单元:Tag。我们先从简单的看起,上述代码是一个FLVHeader的结构体,其前三个字节分别是F,L,V 第四个字节是Version也就是FLV的版本号,当前为1。第五个字节是一个标志位Flags,代表当前FLV是否包含音频或者视频Tag,此Flags的第六位代表是否含有音频Tag,第八位表示是否含有视频Tag,其他位为0;举个例子,当Flag = 0X01的时候,代表只包含视频Tag,等于0X04的时候代表只含有音频Tag,当Flag等于0X05时,就代表此FLV既包含音频Tag,也包含视频Tag。最后有一个四字节的HeaderLenth,代表着当前Header的长度。大家有没有注意到,我用char[4]来表示这个四字节的变量,而没有用unsigned int类型吗?是有一定道理的,大家可以自己去尝试一下。

下面具体介绍一下FLVBody部分。FLVBody由多个previousdata size + Tag构成,其中Tag的类型多种多样,由于我对音频部分不是很熟悉,我这里就不讨论音频Tag了。而previous data size 用四个字节代表上一个Tag所占字节数,但是FLVBody和第一个Tag之间的previous data size为0.

那么一个Tag是由哪几个部分组成的呢?如果简单分开来:Tag = TagHeader + TagData,如下结构体说明了TagHeader的结构:

typedef struct TagHeader
{
  unsigned char TagType;//tag类型,音频为(0X08),视频(0X09),script data(0x12),其他值保留
  unsigned char DataSize[3];//3字节表示Tagdata的大小
  unsigned char Ts[3]      ;     //3字节,为Tag的时间戳,  
  unsigned char TsEx     ;//时间戳的拓展位,当24位不够用时,此八位作为时间戳最高位,将时间戳变为32位
  unsigned char StreamID[3];//一直为0;
}TagHeader;

Tagheader的第一个字节为TagType,此字节意在说明此Tag的类型,如果是音频,TagType=0X08,视频的话,TagType = 0X09;如果是Script data的话,TagType = 0X12;其他值保留。第2-4字节为DataSize,表示TagHeader后面接着的TagData的数据大小。Ts和TsEx结构地内注释已经很清楚了,就不重复了。StreamID恒定为0.

         对于一个Tag来说,TagHeader的结构都是一样的,而TagData的结构就很复杂了,首先,针对不同的TagType,对应的TagData肯定不一样,分为AudioTagData,VideoTagData,ScriptTagData。AudioTagData在本文中不做分析,因为这并不会影响H264码流的封装。

         当我们向一个FLV文件中写入FLVHeader后,紧接着的肯定是4个字节的previousdata size,且为0。那下一步,我们应该来写我们的Tag了,但是第一个是什么Tag呢,是AudioTag,VideoTag,还是ScriptTag呢。我们第一个应该写入的Tag是ScriptTag,那我们看一下它的结构是如何的:


ypedef struct ScriptTagData
{
  unsigned char MetaDataType;//0x02
  unsigned char StringLenth[2];//一般位10,即0x000A;
  unsigned char MetaString[10];//值为onMetaDat
  unsigned char InfoDataType;//0x08表示数组,也就是第二个AMF包
  unsigned char EnumNum[4];//4bytes有多少个元素//18bytes
  //1
  unsigned char DurationLenth[2];//2bytes,duration的长度
  unsigned char DurationName[8];
  unsigned char DurationType;
  unsigned char DurationData[8];
  //2
  unsigned char WidthLenth[2];//
  unsigned char WidthName[5];
  unsigned char WidthType;
  unsigned char WidthData[8];
  //3
  unsigned char HeightLenth[2];
  unsigned char HeightName[6];
  unsigned char HeightType;
  unsigned char HeightData[8];
  //4
  unsigned char FrameRateLenth[2];
  unsigned char FrameRateName[9];
  unsigned char FrameRateType;
  unsigned char FrameRateData[8];
  //5
  unsigned char FileSizeLenth[2];
  unsigned char FileSizeName[8];
  unsigned char FileSizeType;
  unsigned char FileSizeData[8];
  
  unsigned char End[3];//0x000009
}ScriptTagData;

上面的结构是ScriptTag的TagData,ScriptTag的TagHeader按之前的结构来写。ScriptTagData中的MetaDataType,StringLenth,MetaString,InfoDataType都是恒定不变的固定值,注释里都有他们的值,在这里就不多做解释了。接下来就是EnumNum[4]了,它包含4个字节,它代表ScriptTagData中含有多少个字段,上述结构体中我只定义了五个字段:Duration,width,height,framrate和filesize,所以EnumNum[4] = 0x00 00 00 05,当然也可以定义更多的字段,具体得去查看FLV的封装文档。接下来就是定义的字段了,以durantion为例子,DurationLenth[2]代表duration这个字符串的长度8,不包含’\0’所以DurationLenth[2]=0x00 08;  DurationName[8]代表这个字符串”duration”也不包含’\0’。 DurationType代表着duration这个字段所对应的值DurationData的类型,这里DurationType为0,代表DurationData是Double型的,所以在结构体中我将其定义为了unsigned char DurationData[8],为8个字节的unsignedchar 型,与Double所占字节数一样。其他的几个字段也是一样的,就不累述了。最后当字段定义结束后,需要结束符End[3],为0X00 00 09。

既然SciptTag结束了,那么就轮到VideoTag了,这里确实有点恶心。搞过视频的朋友应该都知道不管是H264还是H265都是以Nalu来封装的吧,每条Nalu都是以0X 00 00 01或者0X 00 00 00 01开头的,在这个头之后的1Byte内,包含了此Nalu的Type,在这个字节的低五位中,具体关于Nalu的请去查看H264或者H265的说明。先写到这里了,明儿接着。


对了,有几个不错的链接,这里给大家发一下:

http://blog.csdn.net/leixiaohua1020/article/details/17934487

http://niulei20012001.blog.163.com/blog/static/751472112012111901130404/




版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

打包H264码流到FLV文件

FLV格式非常简单,头信息数据量很少,适合网络传输,因此被广泛的应用。 1. H264 NALU结构     h264 NALU:  0x00 00 00 01 | nalu_type(1字节)|...

h264_aac合成flv的个人经验之谈

h264_aac合成flv的个人经验之谈,作为自己工作的总结,不当之处,请高手指点。    第一,aac的音频包写成flv时,第一个tag中有一个字段为AudioSpecificConfig,即为Ob...
  • czgwdm
  • czgwdm
  • 2011-04-07 11:22
  • 7754

将h.264视频流封装成flv格式文件(二.开始动手)

前面写了flv文件的解析,有h264裸流的话就开始封装吧。网上大多数都是用ffmeg库来做这个工作的,哎,学习资料少学不会,还是自己动手吧。 封装前要先了解下h.264格式,只需要知道一点点就可...

视音频编解码学习工程:FLV封装格式分析器

本文介绍一个自己的开源小项目:FLV封装格式分析器。FLV全称是Flash Video,是互联网上使用极为广泛的视频封装格式。像Youtube,优酷这类视频网站,都使用FLV封装视频。我这个项目规模不...

rtmp协议简单解析以及用其发送h264的flv文件

 首先说下rtmp协议包的格式。握手之后,rtmp传输一个数据默认的长度是128bytes,这128bytes不包括包头的长度,只是数据的长度,文档上面没有说明,很憋了我一段时间,数据超过这个长...

多媒体封装格式学习:H264封装成FLV(二)

之前也看过很多人写的博客或者是技术贴,基本上都忽略了一些问题,也就是一个Tag中应该封装H264码流文件中多少码流呢,是一个Nalu单元还是几个?经过多次的研究和试验,我发现大部分的Tag中可以只存放...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)