您的位置:首页 > 其它

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

2016-10-26 15:56 246 查看
https://my.oschina.net/jerikc/blog/497102

Jerikc

 

发表于 1年前 
阅读 578 
收藏 14 
点赞 1 
评论 0

一、flv 格式

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

flv 文件的格式其实网上资料还是不少,但是怎么封装成 flv 却不多。看了不少资料,找到了一个觉得还比较靠谱的:

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

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

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。



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

tag data 如果是音频数据,第一个 byte 记录 audio 信息:

前 4 bits 表示音频格式(全部格式请看官方文档):

·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 

二、开始动手

前面写了 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。

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

每一个结构怎么封都说清楚了,安上面的步骤一个一个NALU封就行了。
 
封包的时候要特别注意一下包头里面的时间戳,因为这个控制着播放的速度,如果不填,全是 0 的话,播放会相当快,一般按视频帧率来设置。我这个 h264 流是 8 帧的,所以我每个 tag 的时间间隔是 125ms 左右。

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

原文地址:http://blog.csdn.net/yeyumin89/article/details/7932368

分类:流媒体 
字数:2728
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: