多媒体封装格式学习: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(二)

之前也看过很多人写的博客或者是技术贴,基本上都忽略了一些问题,也就是一个Tag中应该封装H264码流文件中多少码流呢,是一个Nalu单元还是几个?经过多次的研究和试验,我发现大部分的Tag中可以只存放...

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载

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

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

ios实现H264裸流封装为FLV格式

公司最近想承接一个通过智能手机实现视频双向通讯的功能。我们提前开始了技术预研究。为保证较小的延迟,和优质的视频功能,我们绝对手机采集的音频和视频都利用手机硬件提供的硬编码功能直接实现H264+AAC编...
  • tiberx
  • tiberx
  • 2014年12月19日 11:28
  • 2413

ios实现H264裸流封装为FLV格式

http://blog.csdn.net/tiberx/article/details/42025907 公司最近想承接一个通过智能手机实现视频双向通讯的功能。提前开始了技术...

将h.264视频流封装成flv格式文件(一.flv格式)

flv文件的格式其实网上资料还是不少,但是怎么封装成flv却不多。看了不少资料,找到了一个觉得还比较靠谱的:http://www.cnblogs.com/chef/archive/2012/07/18...

将h.264视频流封装成flv格式文件(一.flv格式)

flv文件的格式其实网上资料还是不少,但是怎么封装成flv却不多。看了不少资料,找到了一个觉得还比较靠谱的:http://www.cnblogs.com/chef/archive/2012/07/18...

打包H264码流到FLV文件

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

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载

将h.264视频流封装成flv格式文件(一.flv格式)

原帖地址:http://blog.csdn.net/yeyumin89/article/details/7932368 原帖虽然贵为好贴,看感觉看起来有点乱,没有层次感,贴过来,修改下格式,阅读起...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:多媒体封装格式学习:H264封装成FLV(一)
举报原因:
原因补充:

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