林海東,余 強
(西華大學數學與計算機學院,四川 成都 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.