林海东,余 强
(西华大学数学与计算机学院,四川 成都 610039)
随着计算机信息技术的发展和人们安全意识的增强,视频监控以其直观、准确、及时和信息内容丰富而广泛应用于许多场合,成为社会安全防范系统的重要组成部分。同时,对视频监控的清晰度、网络化、智能化、功耗节能以及传输设备的体积大小等方面提出了更高的要求。本文根据视频监控的发展现状,设计了一种采用新一代H.264视频编码标准的嵌入式Linux的远程视频监控系统。该系统采用模块化思想设计,模块之间高内聚低耦合,便于维护和升级 。
本文提出的视频监控系统整体采用客户机/服务器架构,其设计主要包括2方面。1)服务器设计。服务器端的硬件平台建立在ARMS3C6410为主控芯片的开发板上,主要包括视频采集模块、视频压缩模块、视频传输模块。采集模块通过USB摄像头采集视频图像。视频压缩模块采用新一代H.264视频压缩算法,通过6410内部的MFC(multi format codec)专用编码芯片把视频图像压缩成H264 NALU视频流。H264实时视频的传输协议采用的是RTP/RTCP协议模式。RTP模块主要负责按照RFC 3984协议把NALU封装成RTP数据包发送到客户端,保证流媒体传输的实时性。RTCP 模块主要用于数据分发质量反馈信息,提供流量控制和拥塞控制[1-5]。2)客户端设计。其主要包括视频接收模块、视频解压模块和视频显示模块。视频解压模块主要用FFMPEG实现,显示模块用SDL实现[6-7]。
视频采集程序是基于Video4Linux模块提供的API函数。Video4Linux是Linux内核中提供给用户视频采集的API接口。它支持绝大多数的USB摄像头,对设备的操作简单直观,基本遵循打开视频设备、设置设备属性、设置视频数据格式、设置设备输出方法、循环输出视频信息、关闭设备的顺序。其中,大多数操作都是通过调用ioctl函数实现的。图1是视频采集的流程图。
图1 视频采集流程
1)打开设备。调用open(device_name, flags)函数打开设备,打开模式分为阻塞模式和分阻塞模式。
2)获取设备属性。调用ioctl(fd, VIDIOC_QUERYCAP, struct v4l2_capability *argp)函数将设备性能参数放到v4l2_capability结构体中,获取设备是否具有视频捕获和流式IO性能。
3)设置图片格式。调用ioctl( fd, VIDIOC_S_FMT, struct v4l2_format *argp)设置图像的存储格式、带宽大小、像素等信息。
4)初始化内存映射。调用ioctl(fd, VIDIOC_REQBUFS, struct v4l2_requestbuffers *argp)申请缓存,并通过mmap函数映射到用户地址空间。
5)开始采集视频。调用ioctl(fd, VIDIOC_QBUF, struct v4l2_buffer *argp)函数,将申请到的帧缓冲全部放入V4L2数据缓冲队列,以便存放采集到的数据,并用ioctl(fd, VIDIOC_STREAMON, int *argp)使摄像头开始捕获视频。
6)获取1帧数据。调用ioctl(fd, VIDIOC_DQBUF, struct v4l2_buffer *argp) 从视频缓冲区的输出队列中取得一个已经保存有1帧视频数据的视频缓冲区,从而获得视频信息。
7)停止采集视频。调用ioctl(fd, VIDIOC_STREAMOFF, int *argp)使摄像头停止捕获视频。
8)关闭设备。调用close关闭设备。
视频压缩通过S3C6410内部的MFC模块完成。MFC是一个高能的视频编解码器 IP,由嵌入式位处理器和视频编解码器核心模块组成, 支持H.263P3、MPEG-4 SP、H.264和VC-1的编解码。在Linux内核中加载MFC驱动模块,就可以/dev/s3c-mfc设备文件对其访问,用ioctl函数来实现相应的指令操作。MFC模块的H264编码流程如图2所示,主要用到的函数如下。
1)fd=open(MFC_DEV_NAME, O_RDWR|O_NDELAY)。此函数打开MFC设备,如果打开设备成功,则返回该设备的文件描述符。
2)ioctl(fd, IOCTL_MFC_H264_ENC_INIT, &mfc_args)。此函数初始化MFC,设置视频压缩图像的大小、比特率、帧率等。
3)ioctl(fd n, IOCTL_MFC_GET_FRAM_BUF_ADDR, &mfc_args)。此函数获得MFC设备中用于存放原始YUV420帧格式的FRAM_BUF的存储区的地址,用memcpy函数把原始视频帧放入以这个首地址开始的存储区中就可以对帧进行压缩。
4)ioctl(fd, IOCTL_MFC_H264_ENC_EXE, &mfc_args)。 此函数对放入FRAM_BUF中的视频帧进行压缩。MFC按照H264编码标准的基本档次,把原始视频帧压缩并封装到NALU中,然后把压缩数据存放STRM_BUF的存储区。为减少无用码率,MFC只对第1帧H264码流上添加序列参数集SPS(sequence parameter set)和图像参数集PPS(picture parameter set),这里面包含了如图像的大小、可采用的可选编码模式、宏块到片组的映射等信息,对客户端的解码至关重要。对压缩数据进行发送时,应首先发送第1帧编码的NALU。
5)ioctl(fd, IOCTL_MFC_GET_LINE_BUF_ADDR, &mfc_args)。此函数获得存放MFC压缩视频帧的STRM_BUF的存储区的地址,用memcpy函数获取压缩后的视频数据。MFC首次编码存储区中存储着编码图像NALU 、SPS和PPS 3个NALU ,之后的编码过程中缓冲区只包含一个完整的NALU。
6)close(fd)。关闭设备。
图2 MFC模块的H264编码流程
为保证视频传输的实时性,在视频的传输中采用实时传输协议RTP(real-time transport protocol)。RTP 提供了端到端的网络传输功能,适合于通过多播或单播网络视频服务的实时数据传输应用。RTP的典型应用建立在UDP协议上,本身只保证实时数据的传输,并不能为数据传输提供可靠的传送机制,也不提供流量控制或拥塞控制。它依靠RTCP(RTP control protocol)提供这些服务。RTCP负责管理传输质量在应用进程之间交换控制信息。在RTP会话期间,各参与者周期性地传送RTCP包,包中含有已发送的数据包的数量、丢失的数据包的数量等统计资料,发送端可以利用这些信息动态地改变传输速率。RTP和RTCP配合使用,能以有效的反馈和最小的开销使传输效率最佳化,故特别适合视频数据的实时性传输。RFC3550协议详细描述了RTP和RTCP协议。
本文的视频传输由ORTP提供实现。ORTP是一个支持RFC3550协议的开源库,完全由C语言实现,除了能保证传输的实时性外,还具有跨平台可移植的特点。在ORTP的实现中提供了一个表示RTP会话的结构RtpSession。它定义了RTP会话中所用到的所有信息,所有操作都是围绕它展开的。
发送视频的实现步骤如下。
1)在进行RTP传输前,首先要对ORTP库进行初始化。初始化函数如下:
ortp_init():初始化ORTP库。
ortp_scheduler_init():初始化任务调度。
2)对RTP收发进行初始化。首先通过rtp_session_new创建一个RTP会话实例,并用一个RtpSession结构session表示这个会话;然后通过返回的结构设置任务调度模式、发送模式、目标地址和端口号、负载类型等,如下所示:
rtp_session_set_scheduling_mode(session,1);设置任务调度支持阻塞
rtp_session_set_blocking_mode(session,1);设置发送接收为阻塞模式
rtp_session_set_connected_mode(session,TRUE);设置连接模式
rtp_session_set_remote_addr(session,argv[2],atoi(argv[3]));设置发送地址
rtp_session_set_payload_type(session,0);设置负载类型
3)发送压缩数据。数据的发送主要用到rtp_session_send_with_ts (session, buffer, len, userts)。buf是要发送RTP包的负载部分,在本应用中负载就是NALU的数据部分。len是负载的长度。userts是发送RTP包的时间戳。S3C6410的MFC在对原始帧进行H264编码后,在每一个NAL单元前添加起始码0X00000001,可根据这个找到NALU的起始头部。如果NALU的长度大于1 400,则要按照RFC3984对其分割后再发送,以避免IP层对大分组的分割。由于在ORTP中要自己管理时间戳,因此在对一个NALU分割发送的RTP包应使用相同的时间戳。
4)终止RTP会话。程序如下:
rtp_session_destroy(session);
ortp_exit();
接收视频的实现如下。
初始化和终止的步骤和发送端一样,只是在初始化时要把接收IP设置为“0.0.0.0”,端口和发送端口保持一致。数据的接收使用rtp_session_recv_with_ts(session, buffer,len, ts, have_more)。这个函数将根据时间戳ts接收发送端发送的具有相同时间戳的RTP包,并把负载数据放到buferr里面,如果提供的buferr太小不足以存下所有的数据,have_more将被设置为1。把同一时间戳内接收的数据封装在一起就是发送的NALU单元。特定的时间戳的数据包接收完后,应根据时间戳增量增加时间戳,然后接收下一个NALU。
客户端的任务主要是把接收到的H264视频帧解码成YUV420的图像格式,并把图像转化为需要的格式,并在播放器的窗口里播放。本系统采用的基于开源的FFmpeg进行H264的解码和SDL用于解码后视频的播放。
FFmpeg在Linux平台下开发,是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。它包括了目前领先的音/视频编码库libavcodec。用FFmepeg解码时首先用av_register_all()函数注册所有的编解码器,通过avcodec_find_decoder(AV_CODEC_ID_H264)找到程序所用的H264解码器,并返回H264解码器的句柄pcodec,然后调用avcodec_alloc_context3(pcodec),初始化编码器的一些固定参数,并返回编码上下文句柄pcodecctx。利用上面得到的pcodec和pcodecctx,通过avcodec_open2(pcodecctx, pcodec, NULL)打开H264解码器就可以进行H264解码了。解码时,定义一个AVPacket结构,把接收到的NALU存储的地址和长度传递给AVPacket,利用avcodec_decode_video2(pcodecctx, pFrame, &frameFinished, &avpkt)函数对NALU进行解码,解码得到的YUV420格式的图像数据将会存储在pFrame中。
SDL是一套开放源代码的跨平台多媒体开发库,使用C语言写成。它提供了数种控制图像、声音、输出入的函数,多用于媒体播放器、开发游戏模拟器等多媒体应用领域。SDL的播放流程如图3所示。
图3 SDL播放
本文提出了一套基于H264的远程视频监控系统方案。系统采用Linux2.6.28作为操作系统,以S3C6410作为主控处理器实现了对视频数据的采集、压缩和传输。由于采用了新一代的H.264视频编码标准,因此,在同等质量图像下,其压缩比是传统压缩标准MPEG-2的2倍以上,是MPEG-4的1.5~2倍,提高了系统的数据压缩比。H.264在具有高压缩比的同时还拥有高质量流畅的图像,因此在网络传输过程中所需的带宽更小,极大地提高了数据的处理与传输效率,使整个系统具有良好的实时性。在客户端将图像帧率设置为25(f/s),用局域网模拟公网,前端设备与用户终端设备间的信息延迟大约为2 s。使用openRTSP工具观测系统性能,系统运行2 h,传输速率为156 kb/s,平均丢包率为2.3%,满足国家视频监控的标准。在客户端看到的监控视频画面满足视频监控系统的实时性、流畅性和画面清晰的要求。采集图像,如图4所示。实验结果表明,本系统成本低、功耗小、功能可扩展、运行稳定可靠,可适用于各个领域的视频监控。
图4 远程视频采集图像
[1]李珊珊.王旭国.基于V4l2的远程视频采集系统设计与实现[EB/OL].(2011-11-24).http://www.paper.edu.cn/download/downPaper/201103-1124.
[2]白立朋.李秋林,程磊,等.嵌入式ARM下的USB摄像头监控系统[J] .计算机系统应用,2011,20(6):122-125.
[3]刘健敏.杨斌.嵌入式Linux下基于FFmpeg的视频硬件编解码[J] .单片机与嵌入式系统应用,2011,11(6):28-31.
[4]毕厚杰.新一代视频压缩编码标准:H.264/AVC[M].北京:人民邮电出版社,2009:189-213.
[5]S3C6400/6410 HW Multimedia Codec (MFC) User’s Guide [M]. [S.l.]:Samsung Electronics,2008:2-24.
[6]RFC 1889-RTP A Transport Protocol for Real-Time Applications [EB/OL].(1996-01-25).http://www.packetizer.com/rfc/rfc1889/.
[7]Doxygen,ORTP APT Documentation Rev0.14.2[EB/OL].(2008-02-02).http://www.antisip.com/doc/ortp.