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

1、flv 格式

本文转自:http://blog.csdn.net/yeyumin89/article/details/7932368 对其文章的格式稍作调整,并修改了部分 type error.

flv 文件的格式其实网上资料仍是很多,可是怎么封装成 flv 却很少。看了很多资料,找到了一个以为还比较靠谱的: html

http://www.cnblogs.com/chef/archive/2012/07/18/2597279.html 数组

其实 flv 仍是挺简单的一个视频格式,下面就来先谈一谈 FLV 的格式吧。 ide

FLV 是一个二进制文件,简单来讲,其是由一个文件头(FLV header)和不少 tag 组成(FLV body)。tag 又能够分红三类: audio, video, script,分别表明音频流,视频流,脚本流,而每一个 tag 又由 tag header 和 tag data 组成。 工具

文件头由 9 bytes 组成 学习

 

前3个 bytes 是文件类型,老是“FLV”,也就是(0x46 0x4C 0x56)。第4 btye 是版本号,目前通常是 0x01。第5 byte 是流的信息,倒数第一 bit 是1表示有视频(0x01),倒数第三 bit 是1表示有音频(0x4),有视频又有音频就是 0x01 | 0x04(0x05),其余都应该是 0。最后 4 bytes 表示 FLV 头的长度,3+1+1+4 = 9 测试

FLV header 后面就是 FLV body,FLV body 由若干个 tag 组成。每个 tag 第一部分是 tag header,tag header 长度为 11 bytes,可是每一个 tag header 前面有 4 bytes 记录着上一个 tag 的长度,此待会儿再说。tag header 的第1个 byte 为记录着 tag 的类型,音频(0x8),视频(0x9),脚本(0x12);第2到4 bytes 是数据区的长度,也就是 tag data 的长度;再后面3个 bytes 是时间戳,单位是毫秒,类型为0x12则时间戳为0,时间戳控制着文件播放的速度,能够根据音视频的帧率类设置;时间戳后面一个 byte 是扩展时间戳,时间戳不够长的时候用;最后3 bytes 是 streamID,可是总为0,再后面就是数据区了(tag data),也便是h264的裸流,tag header 长度为1+3+3+1+3=11。 spa

0x12 前面的 00 00 00 00 就是刚刚说的记录着上一个 tag 的长度的4 bytes,这里由于前面没有tag,因此为0。 .net

tag data 若是是音频数据,第一个 byte 记录 audio 信息: 设计

前 4 bits 表示音频格式(所有格式请看官方文档): code

·0 -- 未压缩

·1 -- ADPCM

·2 -- MP3

·4 -- Nellymoser 16-kHz mono

·5 -- Nellymoser 8-kHz mono

·10 -- AAC

下面两个 bits 表示 samplerate:

·0 -- 5.5KHz

·1 -- 11kHz

·2 -- 22kHz

·3 -- 44kHz

下面1 bit 表示采样长度:

·0 -- snd8Bit

·1 -- snd16Bit

下面1 bit 表示类型:

·0 -- sndMomo

·1 -- sndStereo

以后是数据。

若是是视频数据,第一个 byte 记录 video 信息:

前4 bits 表示类型:

·1-- keyframe

·2 -- inner frame

·3 -- disposable inner frame (h.263 only)

·4 -- generated keyframe

后4 bits 表示解码器 ID:

·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)

以后是数据。


若是是 AAC 和 AVC 的音视频,则在放入数据前有一个音频和视频的配置信息须要写入前两个 tag,等会再说。以前说每一个 tag 前面会有一个记录上个 tag 长度的4个bytes(previous tag size),整个的 flv 文件实际上是:FLV header + previous tag size0 + tag1 + previous tag size1 + tag2 + previous tag size2 + ... +tagN + previous tag sizeN。第一个 previous tag size 由于前面没有 tag,因此为0,其余的老是记录着前面一个 tag 长度(tag data size + tag header size)。

 

若是 tag data 是脚本数据,Script Tag Data,该类型 Tag 又一般被称为Metadata(元数据) Tag,会放一些关于 FLV 视频和音频的参数信息,如duration、width、height等。一般该类型 Tag 会跟在 File Header 后面做为第一个 Tag 出现,并且只有一个。通常来讲,该 Tag Data 结构包含两个 AMF 包。AMF(Action Message Format)是 Adobe 设计的一种通用数据封装格式,在Adobe 的不少产品中应用,简单来讲,AMF 将不一样类型的数据用统一的格式来描述。第一个 AMF 包封装字符串类型数据,用来装入一个“onMetaData”标志,这个标志与 Adobe 的一些 API 调用有,在此不细述。第二个 AMF 包封装一个数组类型,这个数组中包含了音视频信息项的名称和值。具体说明以下,你们能够参照图片上的数据进行理解

第一个 AMF 包:

第1个字节表示 AMF 包类型,通常老是0x02,表示字符串,其余值表示意义请查阅文档。

第2-3个字节为 UI16 类型值,表示字符串的长度,通常老是 0x000A(“onMetaData”长度)。

后面字节为字符串数据,通常总为“onMetaData”。

第二个AMF包:

 第1个字节表示 AMF 包类型,通常老是 0x08,表示数组。

 第2-5个字节为 UI32 类型值,表示数组元素的个数。

 后面即为各数组元素的封装,数组元素为元素名称和值组成的对。表示方法以下:

   第1-2个字节表示元素名称的长度,假设为L。

   后面跟着为长度为L的字符串。

   第L+3个字节表示元素值的类型。

  后面跟着为对应值,占用字节数取决于值的类型

 

到此flv格式的解析就差很少了,若有写错的地方请指出。

附上一个网友写的flv的查看工具:
http://download.csdn.net/detail/yeyumin89/4534822 

2、开始动手

前面写了 flv 文件的解析,有 h264 裸流的话就开始封装吧。网上大多数都是用ffmeg 库来作这个工做的,哎,学习资料少学不会,仍是本身动手吧。

封装前要先了解下 h.264 格式,只须要知道一点点就能够了,我看了 h.264 官方文档,我靠,3百多页,还全是中文,什么,是中文?既然是中文的我就勉强看下吧,我靠,看起来还很复杂的,果断不看了,不须要,也没时间,我又不作解码,这东西具体步骤资料又少,基本都是那一两篇转来转去,这还要感谢我上一篇提到的那个链接的兄弟,记录下过程,否则之后就忘干净了。
 
h264 是一个个 NALU 单元组成的,每一个单元以 00 00 01 或者 00 00 00 01分隔开来,每2个 00 00 00 01 之间就是一个 NALU 单元。咱们实际上就是将一个个 NALU 单元封装进 FLV 文件
 

每一个NALU单元开头第一个 byte 的低5 bits 表示着该单元的类型,即  NAL nal_unit_type:
#define NALU_TYPE_SLICE 1
#define NALU_TYPE_DPA 2
#define NALU_TYPE_DPB 3
#define NALU_TYPE_DPC 4
#define NALU_TYPE_IDR 5
#define NALU_TYPE_SEI 6          
#define NALU_TYPE_SPS 7
#define NALU_TYPE_PPS 8
#define NALU_TYPE_AUD 9

#define NALU_TYPE_EOSEQ 10
#define NALU_TYPE_EOSTREAM 11

#define NALU_TYPE_FILL 12


每一个 NALU 第一个 byte & 0x1f  就能够得出它的类型,好比上图第一个 NALU:67 & 0x1f = 7,则此单元是 SPS,第三个:68 & 0x1f = 8,则此单元是 PPS。
 
前一章说到若是数据是 AAC 或者 AVC 的话,则有一个音频和视频的配置信息须要写入前两个 tag(metadata 以后),AAC 音频就不说了,在 ISO-14496-3 Audio 中有描述,给一张图。
 
说下 AVC 视频流的 configuretion,ISO-14496-15 AVC file format 有详细描述,先给两张图,一张是说明,一张是实际截图。
 

这个例子是对应我第一个截图来的,通常 h264 数据最开始的两个 NALU 就是 SPS 和 PPS,可是我如今尚未明白为何个人那个 h264 裸流在开始的时候会有两个 SPS、PPS,并且以后数据还会不时的出现,可是我没有管这个,依然只各弄了一个进去,其余的忽略掉了,反正多余的我都忽略了,也没发现有什么错。反正首先把音视频的配置信息封进 metadata 以后的 tag,而后就能够封数据了。再说下元数据,flv header 以后就是它了,再以后就是音视频配置信息,再后面就是音视频数据,元数据前一章说了是 AMF 格式的,按格式封就好了,测试其实没有元数据视频也能够正常播放,等会再简单说下 AMF吧。

 
 

如今开始封装 h264 数据吧,前一章提到了 flv 关于 AVC 的格式,除开元数据,其余数据是:一个 byte 的 video 信息 + 一个 byte 的 AVCPacket type + 3 个 bytes 的无用数据(composition time,当 AVC 时无用,全是 0)+ 4 个bytes 的 NALU 单元长度 + N 个bytes 的 NALU 数据,因此包头数据长度信息是刚才提到的信息的总和长度。要强调下,当音视频配置信息 tag 的时候,是没有 4 个 bytes 的 NALU 单元长度的


AVC 的配置信息时,先上一个图,


17 -- 高4 bits:1,keyframe。 低4 bits:7,表明 AVC。 后面一个 byte 0x00,AVCPacket type,表明 AVC sequence header。后 3 个 bytes 无心义,以后就是 decoder configuration record 的内容了。 图中绿色后面 00 00 00 28 就是前面 tag 的总长度

 
当 NALU 第一个 byte xx & 0x1f == 5 的时候,说明该单元是一个 I frame,关键帧

17 -- 和上面的同样。 01 -- AVC NALU。蓝色框内的 4 个 bytes 记录后面 NALU 数据的长度。65 & 0x1f == 5.
 
若是 NALU 第一个 byte xx & 0x1f != 5 的时候,就不是一个 I frame

27 -- 高4 bits:2,inter frame ,P frame。 低4 bits:7,AVC NALU。其余都同样。图中绿色后面 00 00 00 28 就是前面 tag 的总长度。
 
 
整个的flv文件实际上是:FLV header + previous tag size0 + tag1 + previous tag size1 + tag2 + previous tag size2 + ... +tagN + previous tag sizeN。

  1. tag1 是 metadata,记录视频的一些信息;
  2. tag2 是视频配置信息(AVC decoder configuration record),
  3. tag3 是音频配置信息(若是没有音频则去掉此项),
  4. tag4以及以后的tag就是音视频数据了。

每个结构怎么封都说清楚了,安上面的步骤一个一个NALU封就好了。
 

封包的时候要特别注意一下包头里面的时间戳,由于这个控制着播放的速度,若是不填,全是 0 的话,播放会至关快,通常按视频帧率来设置。我这个 h264 流是 8 帧的,因此我每一个 tag 的时间间隔是 125ms 左右。


注意了,flv里面的数据都是大端模式,放数据进去要转换一下,若是你是一般的小端的机器的话。
 
 
到这里应该差很少了吧,我是一个 NALU 单元封装成一个 tag,我也是刚接触,不知道上述还有哪些地方不合理,不过测试没有发现问题。我也才接触这东西,若是有知情人,望解释一下为何有多个 PPS SPS,谢谢
相关文章
相关标签/搜索