这里仅介绍流媒体服务器端的实现思路,及编码注意问题,不会贴代码的具体实现。直接入正题先介绍一下系统硬件框架:
服务器端连接PC机用VLC播放如下图:
服务器端应用程序可以分为图像采集、视频硬件编码压缩、RTP打包发送,三个部分。采用C++语言编程,引入C、C++语言混合共享库的方式实现。
图像采集模块主要负责视频数据的采集,并将采集到的数据暂存到DDR2内存中,作为硬件编码模块的数据源。Linux3.0.8内核下视频采集是基于V4L2(Video for Linux 2)框架实现的.V4L2是Linux内核中关于视频设备的应用程序接口,它为音视频设备的应用程序编程提供了一套接口规范.完善的摄像头驱动包含了摄像头源数据与处理器硬件模块FIMC0的数据共享,暂存到DDR2中的数据源,会经过FIMC0转码成NV12格式,应用程序中可以通过V4L2提供的应用程序接口来控制FIMC0的转码格式。这样应用程序就完成了指定颜色空间的实时视频采集。过程如图下图所示:
完成原始视频数据采集后,需要将视频硬件编码压缩成H.264,这里选用的H.264,主要因为它编码效率高、能以较低的数据速率传送基于IP(网际协议)的视频流,在视频质量、压缩效率和数据包恢复丢失等方面有较大的优势,能很好适应以太网传输,是目前监控系统最为理想的信源压缩编码标准。
编码过程是通过调用S5PV210处理器的硬件编码单元MFC,对转码得到的NV12格式的数据进行编码压缩处理。由于210的MFC支持H.264、H.263、VC1、MPEG2、MPEG4等多种视频编码标准,而且每种编码格式对应多组参数可供开发人员选择,适应多种不同环境多种要求下的视频编码。为了均衡视频质量和成像速度。在权衡考虑网络传输条件和摄像头成像质量后,需要选择适中的MFC编码器品质因数,这样在保证高品质H.264图像压缩的前提下,降低了客户端的显示延迟。
编码压缩过程完成后,下一步就要进行,视频RTP打包工作了。原始的 H.264 视频编码数据,不能直接用于网络传输,容易造成丢包及传输错误,需要对其进行封装。因此在客户端应用程序中加入了RTP打包子功能。视频数据的整个打包封装过程如下图 所示。另外,在实时性要求较高的应用场合,RTP 是使用UDP 进行数据传输。下面就简单介绍一下RTP+UDP包的结构:
RTP 载荷常用的打包方式有三种:单NAL 单元方式,非交错方式以及交错方式。各种方式有其允许的NAL 单元类型,常用的类型有单个NAL 单元包(NAL unit),聚合包(STAP-A,STAP-B,MTAP),分片单元(FU-A,FU-B)等。其中,NAL unit 包中必须包含一个完整的编码后的NAL 单元,聚合包中包含一个或多个NAL 单元,而分片单元Fus 允许将一个NAL单元分片到几个RTP 包中。根据TI 提供的H.264 压缩算法及其压缩后的NAL 单元数据特点,本文采用NAL unit 和FU-A 两种包类型。其对应的RTP 载荷格式主要是头部不同,描述如下。
NAL unit
头部为一个字节,三个标志的含义如下。
F:1 bit,0 表示NAL 单元类型的八位组和载荷不允许包含比特错误或其它语法错误,1 则相反。H.264规范要求该位为0;
NRI:2 bits,与编码后的网络抽象层NAL 单元中的NAL 单元类型字节里NRI 值保持一致。
Type:5 bits,H.264 规范定义其取值范围为1~23。在该类型包设计时取值同上,即与NAL 单元类型字节里nal_unit_type 相同。程序设计时该字节与NAL 单元第一字节设置为相同即可,对于编码后的NAL 单元,第一字节即是NAL 单元类型字节。
FU-A
头部包含两个字节,第一字节为FU indicator,第二字节为FU header。FU indicator,该字节与NAL unit 头部结构相同。标志F 和NRI 设置方法同上,对于Type 标志,规范中该类型值设置为28。
FU header,各标志含义如下。
S:1 bit,开始标志位。对于NAL 单元第一个分片,设置为1,其它为0。
E:1 bit,结束标志位。对于最后一个分片,设置为1,其它为0
R:1 bit,保留位,设置为0,接收者必须忽略该位。
Type:5 bits,NAL 单元荷载类型,与编码后的网络抽象层NAL 单元中的NAL 单元类型字节nal_unit_type 值保持一致。
对于原始压缩数据,不仅要进行RTP 载荷打包,还需要增加RTP 头来组成完整的RTP 包。我是用的是JRTPLIB 库实现RTP 的自动打包以及传输功能。RTP包头所需的一些参数如:Market,帧间延时时间,时间戳由函数SendPacket 参数传入。
写到这里服务器端功能模块基本介绍完了。再说一下程序设计关键点,如下:
(1)由于MFC驱动中的视频源数据的颜色空间必须为NV12,因此在通过V4L2框架初始化/video0 输出视频格式时,注意要将格式设置为NV12,从而才能正确解码。
(2) 通过MFC硬编码后的一帧视频包含若干个NAL 单元,每个NAL 单元都由一个起始码开头,对于S5PV210的MFC硬件编码H.264 压缩算法起始码由00 00 00 01 四个字节组成。
(3) 由于UDP协议会对大于1500 字节的数据包进行自动拆包,从而导致丢包概率会大大增加。因此需要设置RTP 荷载包的最大长度为1400。在封装荷载头,RTP头,UDP头和IP头后长度依然会小于1500字节,降低丢包概率。
(4) 参数M,PT,timestamp 设置。M,对于NAL_unit 包类型即单个NAL单元长度值小于1400字节,值为1。当单个NAL单元长度大于1400时,需要进行分片处理。FU-A 类型除该NAL 单元的最后一个分片设置为1 外,其它为0;载荷类型PT 根据标准设置为96;时间戳在SendPacket 函数中传入的是其增量timestamp_inc,对于NAL unit,由于视频采用的是PAL 制式,故值设为9000/25。对于同一NAL 单元的所有FU-A 分片包,timestamp 值应相同。因此,除第一个包设置值以外,其它为0。
服务器端程序流程图如下:
领取专属 10元无门槛券
私享最新 技术干货