赵宇峰
(郑州威科姆科技股份有限公司,河南 郑州 450001)
责任编辑:任健男
三网融合作为国家级的长期战略,目前已在全国多个省份进行试点,数字机顶盒是三网融合的着力点,随着嵌入式芯片技术的飞速发展,其性能越来越高、功能越来越复杂,所能承载的业务越来越多样化。而且随着视频编码功能开始在嵌入式芯片上逐渐普及,以往只能在PC上实现的实时视频通信业务在机顶盒上实现也成为可能。本文提出一种基于海思HI3716C平台的实时视频通信的实现方法,该方法采用USB摄像头+数字机顶盒+电视机的模式,应用场景示意图如图1所示。USB摄像头实现视频原始数据的采集,机顶盒完成视频数据的发送、接收以及编解码,电视机作为显示终端进行视频图像的显示,管理服务器用来对在线用户进行管理。
图1 实时视频通信应用场景示意图
机顶盒终端以海思HI3716C为主芯片。海思HI3716C芯片采用ARM Cortex A9架构的处理器,频率达到1 GHz,支持 H.264,MPEG-4,H.263 视频编码,最大分辨力可达720×576@25 f/s,视频编码提供动态码率和固定码率模式,支持1路语音编码。终端的硬件总体结构如图2所示。
图2 机顶盒终端硬件总体结构
终端的软件部分使用嵌入式Linux操作系统和yaffs2文件系统,并以此为基础开发了视频点播、网络直播、本地磁盘音视频播放、图片浏览等多种业务,本文实现的实时视频通信是其众多业务中的一种,本文也只对该业务的实现方法做重点描述。图3是实时视频通信业务的软件框架,其中的UI是与用户之间的接口,负责接收用户指令以及呈现给用户指令处理结果;指令处理模块负责处理来自UI的指令和来自网络的消息;网络交互模块用于同其他用户和管理服务器进行交互;采集编码发送模块完成视频数据的采集、编码和发送;接收解码显示模块进行视频数据的接解码及显示。视频实时通信的重点在视频数据的采集、编解码和发送,因此本文也主要围绕这几点进行阐述。
图3 视频实时通信业务软件框架
摄像头设备是视频数据来源,要进行视频通信,首先要使机顶盒能够支持USB摄像头设备。目前主流的USB摄像头一般都符合UVC(USB Video Class)规范,Linux从2.6.26开始将UVC驱动纳入内核原生包,只要在配置内核时选择了UVC选项,嵌入式Linux系统就能很方便地支持符合UVC规范的USB摄像头设备,另外Linux UVC驱动支持V4L2应用编程接口[1]。本文使用的Linux版本为2.6.35,其源码中已经包含的UVC驱动,内核编译完成后,在 linux-2.6.35/drivers/media/video/uvc 目录下,生成的有uvcvideo.ko,在机顶盒启动时加载该驱动,在/dev目录下生成video0设备节点。
在Linux系统进行视频采集基本都是用V4L2编程接口,V4L2(Video for Linux 2)是Linux内核中视频设备统一的驱动接口,它采用流水线的方式,在打开视频设备/dev/video0之后,剩余的操作完全通过ioctl系统调用向驱动发送控制命令的方式来完成[2],所使用到的控制命令按照调用顺序如下:
1)控制命令VIDIOC_QUERYCAP,用于查询视频设备的功能,如本文中使用的USB摄像头设备应该具有V4L2_CAP_VIDEO_CAPTURE功能。
2)控制命令VIDIOC_S_FMT,用来设置视频设备的视频数据格式,如视频图像数据的宽、高和像素格式等。
3)控制命令VIDIOC_REQBUFS,向V4L2驱动请求分配视频缓冲区,申请多个视频缓冲区可以提高捕获图像的效率,一般不超过5个。
4)控制命令VIDIOC_QUERYBUF,用于查询在上一步中分配的视频缓冲区的相关信息,如缓冲区在内核中的偏移地址、长度等信息。因为通过VIDIOC_REQBUFS申请到的缓冲区在内核空间,用户空间不能直接访问,所以一般会在通过VIDIOC_QUERYBUF命令获得缓冲区相关信息后调用mmap内存映射函数将内核空间地址映射为用户空间地址,之后应用程序就可以直接访问用户空间地址来获取捕获到的视频图像。
5)控制命令VIDIOC_QBUF,将一个空闲的缓冲区放入视频缓冲区输入队列中,在启动视频采集后,捕获到的视频数据会被保存到此视频缓冲区,在保存有一帧视频数据后,这个缓冲区会被放入输出队列,在调用后面的VIDIOC_DQBUF命令时就能获取到该缓冲区。
6)控制命令VIDIOC_STREAMON,用于启动视频采集。
7)控制命令VIDIOC_DQBUF,从视频缓冲区的输出队列中取得一个已经保存有一帧视频数据的视频缓冲区,因为之前已经调用mmap进行过地址映射,所以应用程序可以直接从用户空间地址来读取该视频数据,然后对视频数据做进一步的处理。处理完数据之后需要调用VIDIOC_QBUF,将该缓冲区仍旧放入输入队列中,进行下一帧视频数据的获取。
在摄像头捕获到视频数据之后,为便于数据的远程传输,需要对数据进行压缩编码。海思HI3716C平台支持H.264,H.263和MPEG-4编码方式,考虑到后续工作中可能有机顶盒与手机终端视频互同的需求,所以选择在手机终端视频解码支持较好的H.263编码。为便于应用程序的编写,海思平台在应用层中抽象出VI和VENC模块,其中VI模块负责将待编码的视频数据输送给VENC模块,VENC模块负责对输入的视频数据进行压缩编码,在海思SDK中提供的有2个模块的应用层API,这些API在实现视频编码时的调用关系如图4所示。首先要调用相应的接口完成VI模块和VENC通道的创建,在调用HI_UNF_VENC_CreateChn接口时可以指定视频码率,然后调用HI_UNF_VENC_AttachInput接口将VI模块和VENC通道进行绑定,紧接着启动图像采集线程并调用接口HI_UNF_VENC_Start,在图像采集线程中将V4L2输出队列中的一个视频缓冲区内的数据拷贝到VI模块的帧缓冲区,VENC模块对这些数据进行压缩编码后输出已编码数据。
图4 视频编码接口调用关系示意图
经过压缩编码的数据需要通过网络传输给远端用户,视频传输对实时性、同步性要求很高,但是可以容忍数据丢失和出错,因此所使用的传输协议可以是无可靠性保证的,但必须是实时高效的。UDP是面向无连接数据传输协议,由于其不提供数据的可靠性保证,所以传输时延较短,非常符合视频传输的要求。另外家庭用户终端多处于NAT设备之后,使用内网IP地址,这种情况下2个机顶盒进行互联互通需要进行NAT穿透,UDP穿透NAT的技术相对成熟。鉴于以上原因,在此选择UDP协议作为视频传输协议。
因为IP协议最大传输单元(MTU)为1500 byte,如果UDP数据包长度过长,超过了MTU的长度,在IP层就会对其进行重新分组,这样会大大降低传输的效率,而且出错概率大大增加,所以最好将视频数据经过分组打包之后再进行UDP传输,以保证在传输时不会造成IP碎片。本文借鉴RTP协议中RTP分组头的格式[3],使用其中的M(Marker)、PT(Payload Type)和 SN(Sequence Number)字段,其中M字段占用1 bit,用来表示帧结束,PT字段占用7 bit,用来表示数据编码类型(按照RTP协议,H.263对应的类型为34),SN字段占用16 bit,用来计数,每发送1个数据包该字段就加1。M,PT和SN字段的总长度占3 byte,UDP的首部是8 byte,IP协议的首部是20 byte,这样每个UDP数据包中承载的静负荷的最大长度是1469。对于长度大于1469的视频帧数据要被打包成多个分组进行传输。比如一个长度为5000 byte的视频帧就要分为4个分组进行传输,如图5所示。
图5 视频数据分组封装示意图
在接收到远端用户发送过来的视频数据之后,需要对数据进行解码显示。与视频编码相类似,海思平台在应用层抽象出了AVPlay和VO模块,AVPlay模块用于音视频的解码和同步,VO模块负责视频的显示。运用模块的API可以很方便地实现视频解码和显示,调用关系示意图如图6所示。
图6 视频解码接口调用关系示意图
完成了AVPlay模块和VO模块的创建后需要调用HI_UNF_VO_AttachWindow接口将两者绑定,同时要调用HI_UNF_VO_SetWindowEnable接口将VO中创建的窗口使能,否则视频是不会显示的。然后调用HI_UNF_AVPLAY_Start接口并启动数据接收线程,在线程中接收到来自远端用户的视频数据包之后,需要组装成帧放入AVPlay帧缓冲区。此后只要AVPlay缓冲区中有数据就会进行视频数据的解码。
本节以用户A和用户B要进行视频通信为例来描述一下数据的交互过程。
当用户启动机顶盒后,需要向管理服务器发送登录信息,管理服务器对用户信息进行记录,用户信息包括用户名、所使用的本地IP、端口号以及是否接有USB摄像头设备等,同时服务器能获取到它们登录管理服务器所使用的公网IP和端口号,也作为用户信息进行保存。当用户需要查看在线用户信息时,向管理服务器发送获取在线用户信息的请求,服务器将当前在线的所有用户的信息返回给用户。
当用户A希望和用户B进行视频通信时,首先要判断对方是否和自己在同一局域网,如果是在同一局域网,用户A可以直接向用户B的本地IP和端口号发送请求,用户B收到请求后返回给用户A确认信息,同时启动视频编解码,用户A在收到用户B的确认信息后也启动视频编解码,两用户的实时视频通信就此建立。如果用户A和用户B不在同一局域网,则需要进行UDP穿透NAT[4],用户A向管理服务器发送穿透请求,管理服务器收到之后向用户B发送穿透NAT指令,用户B向用户A的公网IP和端口方向随便发送一些数据即完成了NAT穿透,用户A在等待一段时间之后向用户B的公网IP和端口发送视频通信请求,此时该请求会被用户B成功接收,之后两者可以正常进行通信。此时管理服务器起到了辅助UDP穿透的作用。图7所示是用户A和用户B不在同一局域网的情况。
本文在嵌入式Linux机顶盒上实现了实时视频通信功能,在局域网内,能较通畅地进行码率为1 Mbit/s的实时视频通信,在公网上则需要将码率限制在500 kbit/s以下。本文只是在初步实现了实时视频通信,验证了其在嵌入式终端实现的可行性,在后续的工作中仍需要对业务功能进行不断优化,首先要添加对音频的支持,其次要增加根据网络状况进行编码码率动态调整功能的支持,另外还要考虑机顶盒与其他类型终端的实时视频通信。
图7 不同局域网内两终端视频通信建立过程
[1]唐人财,刘连浩.基于嵌入式Linux远程图像监控系统的设计[J].计算机与现代化,2010(11):31-38.
[2]刘升,赵晶晶,范秀丽.基于V4L2的嵌入式视频监控系统[J].微计算机应用,2011,32(1):37-42.
[3]陈庆余,朱光喜.一种MPEG-4 over RTP的实现方法[J].电视技术,2001,25(6):27-29.
[4]刘昊东,陈天煌.基于P2P网络中UDP穿透NAT技术的研究[J].计算机与数字工程,2009,37(12):112-114.