您的位置:首页 > 其它

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

2014-10-30 15:59 357 查看
前面写了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的低5bits表示着该单元的类型,即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或者***C的话,则有一个音频和视频的配置信息需要写入前两个tag(metadata之后),AAC音频就不说了,在ISO-14496-3 Audio 中有描述,给一张图。




说下***C视频流的configuretion,ISO-14496-15 ***C file format 有详细描述,先给两张图,一张是说明,一张是实际截图。







上面这个图的内容,乍一看起来好像明白,但是如果没有某一个例子对照的话,再仔细看的时候就会一头雾水,那么我们该用哪个例子来和他对照呢??当然是没有例子,因为原来的作者就没有配图,还是我自己配一个图吧,见下图(上图中的01
42 E0 14是原作者的例子的内容,我们这个例子中的内容是01 64 00 28)



看这个这个图,再对照上面的那个说明图,就好理解了,也就是说,在第一个真正的视频帧之前,还是有一个编码说明帧的,这一帧,或者叫这一tag里面的内容,来源于我们的sps和pps两部分的组合。只要有了这个,我们就可以保证保存下来的flv文件的可使用性了。这也是我自己的血的教训啊,保存的flv一直不能播放,郁闷死了。。。

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



现在开始封装h264数据吧,前一章提到了flv关于***C的格式,除开元数据,其他数据是:一个byte的video信息+一个byte的***CPacket type+3个bytes的无用数据(composition time,当***C时无用,全是0)+ 4个bytes的NALU单元长度
+ N个bytes的NALU数据,所以包头数据长度信息是刚才提到的信息的总和长度。要强调下,当音视频配置信息tag的时候,是没有4个bytes的NALU单元长度的。
***C的配置信息时,先上一个图,



17 -- 高4bits:1,keyframe。 低4bits:7,代表***C。 后面一个byte 0x00,***CPacket type,代表***C sequence header。后3个bytes无意义,之后就是decoder configuration
record的内容了。
图中绿底部分后面紧跟的8byte:00 00 00 28就是前面tag的总长度。


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



17 -- 和上面的一样。 01 -- ***C NALU。蓝色框内的4个bytes记录后面NALU数据的长度。65 & 0x1f == 5.


如果NALU第一个byte xx & 0x1f != 5的时候,就不是一个I frame



27 -- 高4bits:2,inter frame ,P frame。 低4bits:7,***C NALU。其他都一样。图中绿底部分后面紧跟的8byte:00 00
00 19就是前面tag的总长度。


整个的flv文件其实是:FLV header + previous tag size0 + tag1 + previous tag size1 + tag2 + previous tag size2 + ... +tagN + previous tag sizeN。
tag1是metadata,记录视频的一些信息;tag2是视频配置信息(***C decoder configuration record),tag3是音频配置信息(如果没有音频则去掉此项),tag4以及之后的tag就是音视频数据了。
每一个结构怎么封都说清楚了,安上面的步骤一个一个NALU封就行了。





封包的时候要特别注意一下包头里面的时间戳,因为这个控制着播放的速度,如果不填,全是0的话,播放会相当快,一般按视频帧率来设置。我这个h264流是8帧的,所以我每个tag的时间间隔是125ms左右。
注意了,flv里面的数据都是大端模式,放数据进去要转换一下,如果你是通常的小端的机器的话。




到这里应该差不多了吧,我是一个NALU单元封装成一个tag,我也是刚接触,不知道上述还有哪些地方不合理,不过测试没有发现问题。我也才接触这东西,如果有知情人,望解释一下为什么有多个PPS SPS,谢谢。



至于rtmp协议发送flv,之后再写吧。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: