摘 要: 針對(duì)傳統(tǒng)監(jiān)控系統(tǒng)的不足已不能滿足現(xiàn)代人對(duì)監(jiān)控視頻內(nèi)容的要求,提出了一種解決方案并對(duì)其進(jìn)行闡述,說(shuō)明如何在Linux系統(tǒng)下,以IP網(wǎng)絡(luò)攝像頭為數(shù)據(jù)源,結(jié)合開(kāi)源Live555庫(kù)實(shí)現(xiàn)流媒體服務(wù)器的方法,其中涉及了視頻數(shù)據(jù)的獲取、編碼、流化以及傳輸?shù)饶K。流媒體服務(wù)器的實(shí)現(xiàn)解決了多路客戶訪問(wèn)攝像頭的負(fù)載問(wèn)題,同時(shí)若與圖像處理算法結(jié)合可提供特殊的視頻監(jiān)控內(nèi)容以滿足應(yīng)用需求。
關(guān)鍵詞: RTSP;流媒體服務(wù)器;Live555;網(wǎng)絡(luò)監(jiān)控
0 引言
隨著圖像處理的發(fā)展,構(gòu)建一個(gè)良好的視頻圖像處理應(yīng)用平臺(tái)越來(lái)越重要。目前的攝像頭對(duì)多路訪問(wèn)的負(fù)載能力非常有限,并且現(xiàn)在人們對(duì)監(jiān)控內(nèi)容的要求已不僅僅停留在原始視頻上,而大多更希望能夠?qū)崟r(shí)監(jiān)控經(jīng)過(guò)特殊處理的視頻數(shù)據(jù)。為了滿足這一需求,以IP攝像頭作為數(shù)據(jù)源,PC端搭建流媒體服務(wù)器供多路客戶進(jìn)行實(shí)時(shí)監(jiān)控的模式是一個(gè)很好的解決方案,這樣既能減少攝像頭負(fù)載能力的限制,同時(shí)又能滿足圖像處理后的監(jiān)控需求。本文設(shè)計(jì)的流媒體服務(wù)器[1]架設(shè)在Linux操作系統(tǒng)的PC上,采用RTSP協(xié)議[2]進(jìn)行實(shí)時(shí)傳輸以供客戶訪問(wèn)。
服務(wù)器首先登錄訪問(wèn)IP攝像頭,匹配通過(guò)后IP攝像頭返回捕捉的視頻數(shù)據(jù)給服務(wù)器,當(dāng)客戶端通過(guò)鏈接向服務(wù)器發(fā)送訪問(wèn)請(qǐng)求后,服務(wù)器開(kāi)始向客戶端傳送實(shí)時(shí)視頻數(shù)據(jù),供客戶進(jìn)行實(shí)時(shí)監(jiān)控。
1 IPC數(shù)據(jù)獲取及存儲(chǔ)
網(wǎng)絡(luò)攝像機(jī)對(duì)于人們來(lái)說(shuō)較為重要的是如何獲取其視頻源數(shù)據(jù),而??低暤木W(wǎng)絡(luò)攝像機(jī)為人們提供了二次開(kāi)發(fā)的接口以方便對(duì)IPC的功能應(yīng)用進(jìn)行擴(kuò)展。下面對(duì)IPC視頻數(shù)據(jù)獲取流程進(jìn)行介紹。
由于在IPC端已經(jīng)有設(shè)定好的賬戶與密碼,因此用戶在訪問(wèn)此IPC時(shí)就需要通過(guò)NET_DVR_Login_V30函數(shù)來(lái)進(jìn)行注冊(cè):NET_DVR_Login_V30(IP地址,端口,賬號(hào),密碼,&struDeviceInfo),IP攝像頭匹配正確后才有訪問(wèn)權(quán)限。
該流程中,啟動(dòng)數(shù)據(jù)流的接收是通過(guò)調(diào)用NET_DVR_RealPlay_V30來(lái)實(shí)現(xiàn)的。該函數(shù)中有一項(xiàng)參數(shù)可用來(lái)設(shè)置數(shù)據(jù)回調(diào)函數(shù),每當(dāng)有碼流數(shù)據(jù)到達(dá)時(shí),便會(huì)跳轉(zhuǎn)到這個(gè)已設(shè)置的數(shù)據(jù)回調(diào)函數(shù)中,在數(shù)據(jù)回調(diào)函數(shù)中需要對(duì)接收到的數(shù)據(jù)流進(jìn)行判斷,若為系統(tǒng)頭則進(jìn)行一些設(shè)置,若為碼流數(shù)據(jù)則可將其存入緩沖區(qū)內(nèi)。其流程示意圖如圖1所示。
在圖1中,判斷流數(shù)據(jù)為系統(tǒng)頭時(shí)需要進(jìn)行一些設(shè)置,其中就包括了解碼回調(diào)函數(shù)的設(shè)置。解碼回調(diào)函數(shù)的作用是當(dāng)碼流數(shù)據(jù)存入緩沖區(qū)達(dá)一幀時(shí)會(huì)跳轉(zhuǎn)到該函數(shù)中,此時(shí)在解碼回調(diào)函數(shù)內(nèi)部便可對(duì)完整的一幀數(shù)據(jù)進(jìn)行操作。
在解碼回調(diào)函數(shù)內(nèi)獲取到的是YV12格式幀數(shù)據(jù),而由于所選擇的是x264編碼器,其輸入源規(guī)范為YUV格式,因此必須在解碼回調(diào)函數(shù)內(nèi)將其轉(zhuǎn)為YUV格式后才可供x264進(jìn)行編碼,之后就可以將其儲(chǔ)入緩沖區(qū)內(nèi)。本次開(kāi)發(fā)過(guò)程中以循環(huán)緩沖區(qū)和鏈表的方式存取數(shù)據(jù)。
2 圖像編碼模塊
前面提到,H264編碼使用的是x264編碼器,x264提供了一些開(kāi)發(fā)接口,但仍需進(jìn)一步封裝,其設(shè)計(jì)流程如下:
(1)初始化EncoderInit函數(shù):在其內(nèi)部設(shè)置初始化結(jié)構(gòu)體,調(diào)用x264_param_default及x264_encoder_open進(jìn)行編碼器初始化,并開(kāi)辟存放編碼前后圖像存儲(chǔ)空間。
(2)編碼實(shí)現(xiàn)Encode_frame函數(shù):將原始YUV420P格式數(shù)據(jù)傳給x264_encoder_encode函數(shù)進(jìn)行編碼得到nal數(shù)組,其后循環(huán)調(diào)用x264_nal_encode函數(shù)逐一將編碼后nal封裝成NAL單元并寫(xiě)入輸出緩存區(qū)中,完成一幀圖像數(shù)據(jù)的編碼。
3 流媒體服務(wù)器模塊
服務(wù)器結(jié)合開(kāi)源Live555庫(kù)進(jìn)行設(shè)計(jì),提供對(duì)外實(shí)時(shí)播放。Live555是一個(gè)為流媒體提供解決方案的跨平臺(tái)的C++開(kāi)源項(xiàng)目,它包括了四個(gè)基本庫(kù),分別是:UsageEnvironment、BasicUsageEnvironment、Groupsock和LiveMedia[4]。其中LiveMedia庫(kù)是最為核心的,它包含了對(duì)應(yīng)各種不同流媒體類(lèi)型的數(shù)據(jù)源類(lèi)Source、數(shù)據(jù)接收類(lèi)Sink、會(huì)話類(lèi)Session及RTSPServe等。
TaskScheduler實(shí)例是整個(gè)程序的任務(wù)調(diào)度器[5],它通過(guò)doEventLoop()方法實(shí)現(xiàn)程序的循環(huán)結(jié)構(gòu),并在循環(huán)中進(jìn)行任務(wù)調(diào)度。
3.1 服務(wù)器的建立及響應(yīng)
程序流程如下:
?。?)建立任務(wù)調(diào)度器
TaskScheduler*scheduler=BasicTaskScheduler::createNew()
(2)建立程序運(yùn)行環(huán)境
_env=BasicUsageEnvironment::createNew(*scheduler)
?。?)創(chuàng)建RTSP服務(wù)器綁定端口號(hào)
RTSPServer*rtspServer=RTSPServer::createNew(*_env,9554)
?。?)創(chuàng)建服務(wù)器媒體對(duì)象:創(chuàng)建ServerMediaSession實(shí)例。
?。?)進(jìn)入事件循環(huán)
_env->taskScheduler().doEventLoop()
服務(wù)器采用的是事件驅(qū)動(dòng)機(jī)制,在這個(gè)循環(huán)中,doEventLoop()主要負(fù)責(zé)三件事:監(jiān)聽(tīng)客戶端請(qǐng)求并進(jìn)行響應(yīng)、對(duì)事件發(fā)生進(jìn)行處理、對(duì)延時(shí)任務(wù)進(jìn)行調(diào)度。
RTSP協(xié)議應(yīng)用于C/S模式,它本身并不傳輸數(shù)據(jù),而只負(fù)責(zé)實(shí)現(xiàn)連接、播放、停止等操作,數(shù)據(jù)的傳輸則交由RTP協(xié)議來(lái)進(jìn)行[6]。服務(wù)器與客戶端建立連接時(shí)是通過(guò)響應(yīng)客戶端發(fā)送的OPTION、DESCRIBE、SETUP、PLAY、TERADOWN等請(qǐng)求來(lái)進(jìn)行交互連接的[7]。常用的交互方法作用如下:
OPTION:C向S端獲取可提供的交互方法
DESCRIBE:要求得到S端提供的媒體初始化信息(SDP)
SETUP:確定傳輸模式并提醒S端建立會(huì)話
PLAY:C向S發(fā)送播放請(qǐng)求
TERADOWN:C向S發(fā)送關(guān)閉請(qǐng)求
服務(wù)器對(duì)客戶端的具體響應(yīng)情況如下:
(1)服務(wù)器端在收到客戶端發(fā)送的DESCRIBE請(qǐng)求時(shí),相應(yīng)的處理函數(shù)根據(jù)流媒體名查找或創(chuàng)建ServerMediaSession,生成SDP信息作為返回響應(yīng)此請(qǐng)求。
?。?)服務(wù)器端收到SETUP請(qǐng)求時(shí),相應(yīng)處理函數(shù)會(huì)對(duì)SETUP請(qǐng)求的傳輸頭解析,獲取流媒體發(fā)送傳輸參數(shù),將這些參數(shù)組裝成響應(yīng)消息返回給客戶端。期間subsession調(diào)用CreatNew()生成Source數(shù)據(jù)源實(shí)例及RTPSink數(shù)據(jù)接收實(shí)例。
?。?)服務(wù)器端收到PLAY請(qǐng)求時(shí),RTPSink數(shù)據(jù)接收實(shí)例會(huì)開(kāi)始向Source數(shù)據(jù)源索取圖像數(shù)據(jù),并將索取到的數(shù)據(jù)打包成RTP包發(fā)送出去。此時(shí),當(dāng)RTPSink開(kāi)始索取數(shù)據(jù)時(shí),就啟動(dòng)了對(duì)一幀圖像數(shù)據(jù)的流化。
3.2 流化過(guò)程
當(dāng)Sink向Source索取數(shù)據(jù)時(shí)服務(wù)器內(nèi)便啟動(dòng)了流化,數(shù)據(jù)由Source流向Sink,最終再發(fā)送出去。但這一過(guò)程中經(jīng)過(guò)了多個(gè)節(jié)點(diǎn)傳遞才到達(dá)Sink端,這是因?yàn)樽畛醯腟ource視頻數(shù)據(jù)如果直接傳給Sink端,便無(wú)法直接進(jìn)行流式傳輸,因此需要經(jīng)過(guò)中間多個(gè)節(jié)點(diǎn)對(duì)視頻數(shù)據(jù)進(jìn)行“加工”才能滿足流式傳輸?shù)囊?。下面是一個(gè)示例:
′source1′->′source2′(a filter)->′source3′(a filter)->′sink′
filters接收到數(shù)據(jù)后也作為后者的source。對(duì)于本文H264格式的流媒體來(lái)說(shuō),圖像數(shù)據(jù)經(jīng)各節(jié)點(diǎn)傳遞過(guò)程如下:
WebcamFrameSource(自定義節(jié)點(diǎn))->H264VideoStreamParser->H264VideoStreamFramer->H264FUAFragmenter->H264 VideoRTPSink
WebcamFrameSource中H264編碼的視頻數(shù)據(jù)傳給H264VideoStreamParser,并由它分解為多個(gè)NAL單元,然后經(jīng)H264VideoStreamFramer處理后由H264FUAFragmenter進(jìn)行RTP封包,最后H264VideoRTPSink負(fù)責(zé)形成RTP包頭并發(fā)送數(shù)據(jù)。
在這個(gè)過(guò)程中,WebcamFrameSource類(lèi)是創(chuàng)建的,后面的H264VideoStreamFramer類(lèi)、H264FUAFragmenter類(lèi)、H264VideoRTPSink類(lèi)都是由Live555庫(kù)定義好了的,所創(chuàng)建的WebcamFrameSource類(lèi)負(fù)責(zé)將前期的YUV幀數(shù)據(jù)從緩沖區(qū)取出進(jìn)行H264編碼,然后將編碼好的視頻數(shù)據(jù)傳給下一個(gè)節(jié)點(diǎn)即可。
3.3 服務(wù)器內(nèi)數(shù)據(jù)獲取與打包發(fā)送
在Live555中MediaSource類(lèi)是所有Source的基類(lèi),對(duì)各種流媒體格式類(lèi)型及編碼的支持都是通過(guò)這個(gè)類(lèi)的派生類(lèi)來(lái)實(shí)現(xiàn)的,F(xiàn)rameSource派生自MediaSource,并且內(nèi)部定義了一個(gè)虛函數(shù)doGetNextFrame(),用來(lái)讓其子類(lèi)實(shí)現(xiàn)各自媒體格式的幀獲取。若要自定義Source的來(lái)源,則可以通過(guò)自定義一個(gè)派生自FrameSource的類(lèi)來(lái)實(shí)現(xiàn)。前面提到的WebcamFrameSource就是繼承自FrameSource類(lèi)用來(lái)實(shí)現(xiàn)數(shù)據(jù)源獲取的。
doGetNextFrame()是FrameSource的虛函數(shù),Sink實(shí)例在向Source實(shí)例索取數(shù)據(jù)時(shí),會(huì)重復(fù)循環(huán)層層調(diào)用doGetNextFrame()來(lái)獲取實(shí)時(shí)數(shù)據(jù)源,獲取過(guò)程就是將前期的YUV幀數(shù)據(jù)從緩沖區(qū)取出進(jìn)行H264編碼,并將編碼完成的數(shù)據(jù)間接地傳遞給Sink的緩沖區(qū),最后再調(diào)用FramedSource::afterGetting()函數(shù)來(lái)通知Sink端作處理。具體流程如圖2所示。
數(shù)據(jù)獲取后交由PackFrame()等函數(shù)進(jìn)行打包,最后進(jìn)行發(fā)送。若無(wú)數(shù)據(jù),則繼續(xù)向Source數(shù)據(jù)源進(jìn)行索取,循環(huán)之前的步驟。
4 實(shí)驗(yàn)結(jié)果
實(shí)驗(yàn)結(jié)果如圖3所示,左側(cè)PC為基于Linux的RTSP服務(wù)器,負(fù)責(zé)將IPC拍攝到的視頻實(shí)時(shí)傳送;右側(cè)PC以及手機(jī)都作為客戶端,通過(guò)RTSP服務(wù)器提供的URL進(jìn)行鏈接,進(jìn)而實(shí)時(shí)播放。
5 結(jié)論
本文對(duì)IPC數(shù)據(jù)源的獲取方法、編碼流程、服務(wù)器內(nèi)部數(shù)據(jù)流化及數(shù)據(jù)源類(lèi)WebcamFrameSource的設(shè)計(jì)進(jìn)行了說(shuō)明。使用IPC通過(guò)路由器將數(shù)據(jù)傳送至服務(wù)器,服務(wù)器端進(jìn)行實(shí)時(shí)傳送并提供相應(yīng)的URL鏈接供客戶端使用。客戶端可使用VLC等支持RTSP協(xié)議的視頻軟件進(jìn)行實(shí)時(shí)監(jiān)控。
參考文獻(xiàn)
[1] 杜嘩.流媒體技術(shù)的原理和應(yīng)用[J].光盤(pán)技術(shù),2008(7):9-11.
[2] SCHULZRINNE A, RAO R, Columbia University, et al. RFC2326-Real time streaming protocol(RTSP)[S].1998.
[3] 樊珊.基于RTP的H264視頻傳輸技術(shù)的研究[D].濟(jì)南:山東大學(xué),2008.
[4] 樊承澤,陳蜀宇,楊新華.基于網(wǎng)絡(luò)計(jì)算機(jī)的流媒體播放器的研究與實(shí)現(xiàn)[J].計(jì)算機(jī)技術(shù)與發(fā)展,2010,20(4):195-198.
[5] 茅炎菲,忠東.基于RTSP協(xié)議網(wǎng)絡(luò)監(jiān)控系統(tǒng)的研究與實(shí)現(xiàn)[J].計(jì)算機(jī)工程與設(shè)計(jì),2011,32(7):2523-2530.
[6] 王彥麗,陳明,陳華,等.基于RTP/RTCP的數(shù)字視頻監(jiān)控系統(tǒng)的設(shè)計(jì)與實(shí)現(xiàn)[J].計(jì)算機(jī)工程與科學(xué),2009,31(3):58-60.
[7] 王路幫.RTSP協(xié)議及其分布式應(yīng)用框架[J].安徽職業(yè)技術(shù)學(xué)院學(xué)報(bào),2006,5(1):4-6.