Chinaunix首页 | 论坛 | 博客
  • 博客访问: 13576
  • 博文数量: 2
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 10
  • 用 户 组: 普通用户
  • 注册时间: 2016-08-12 12:36
文章分类
文章存档

2016年(2)

我的朋友
最近访客

分类: LINUX

2016-10-11 17:55:59

本文转自:http://blog.csdn.net/yeyumin89/article/details/7932431

前面写了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或者AVC的话,则有一个音频和视频的配置信息需要写入前两个tag(metadata之后),AAC音频就不说了,在ISO-14496-3 Audio 中有描述,给一张图。
 
说下AVC视频流的configuretion,ISO-14496-15 AVC file format 有详细描述,先给两张图,一张是说明,一张是实际截图。
 
这个例子是对应我第一个截图来的,一般h264数据最开始的两个NALU就是PSP和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 -- 高4bits:1,keyframe。 低4bits: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 -- 高4bits:2,inter frame ,P frame。 低4bits: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,谢谢可怜
 
至于rtmp协议发送flv,之后再写吧。
阅读(2125) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~