楊明極,畢 晶
(哈爾濱理工大學(xué)測(cè)控技術(shù)與通信工程學(xué)院,黑龍江 哈爾濱 150080)
隨著21世紀(jì)的到來,全球快速的進(jìn)入信息時(shí)代,移動(dòng)通信系統(tǒng)由于綜合利用了有線和無線的傳輸方式,解決了人們?cè)诨顒?dòng)中與固定終端或其他移動(dòng)載體上的對(duì)象進(jìn)行通信聯(lián)系的要求,移動(dòng)通信給社會(huì)帶來了深刻的信息化變革,已成為最受青睞的通信手段。如今,以嵌入式技術(shù)為依托,以網(wǎng)絡(luò)、通信技術(shù)為平臺(tái)的網(wǎng)絡(luò)視頻監(jiān)控,已經(jīng)越來越成熟,應(yīng)用范圍越來越廣闊。網(wǎng)絡(luò)視頻監(jiān)控突破了地域的限制,實(shí)現(xiàn)了遠(yuǎn)程監(jiān)控,可是,隨著“Any Time,Any Where,Any Device”(任何時(shí)間、任何地點(diǎn)、任何設(shè)備)等概念的提出,普通的網(wǎng)絡(luò)視頻監(jiān)控已經(jīng)不能滿足用戶日益增長的多元化需求?!笆謾C(jī)視頻監(jiān)控”使這個(gè)問題有了答案,這項(xiàng)應(yīng)用將在安防行業(yè)中得到迅速推廣和普及,同時(shí),它也會(huì)逐漸走入人們的家庭生活中,比如在工作中的白領(lǐng)人員可以在工作中用手機(jī)實(shí)時(shí)監(jiān)看家里無人照看的老人或幼兒園里孩子的情況,企業(yè)人員可以用手機(jī)隨時(shí)隨地監(jiān)看自己的店鋪、超市、公司的運(yùn)營情況等。
本文主要是對(duì)基于Android平臺(tái)視頻客戶端進(jìn)行設(shè)計(jì),最后實(shí)現(xiàn)其播放的核心功能以及實(shí)時(shí)監(jiān)視等多項(xiàng)基本功能。
2007年11月5日,Google與其他33家手機(jī)制造商(包括摩托羅拉、宏達(dá)電、三星、LG)、手機(jī)芯片供應(yīng)商、軟硬件供應(yīng)商、電信業(yè)者所聯(lián)合組成的開放手機(jī)聯(lián)盟(Open Handset Alliance,OHA),發(fā)布了名為Android的開放手機(jī)軟硬件平臺(tái)。
Android是基于Linux內(nèi)核的軟件平臺(tái)和操作系統(tǒng)。框架結(jié)構(gòu)由5個(gè)部分組成,其核心為Linux內(nèi)核,逐次向上是Android開發(fā)的Libraries(函數(shù)庫)和Android Runtime(運(yùn)行環(huán)境),以及搭配Application Framework(應(yīng)用程序框架)來開發(fā)各種不同的應(yīng)用程序[1]。
對(duì)于硬件開發(fā)商來說,Android是開放的平臺(tái),只要廠商有實(shí)力和能力就可以在此平臺(tái)上自由添加特有的設(shè)備或功能,不受到手機(jī)操作系統(tǒng)的限制;對(duì)于手機(jī)開發(fā)者而言,Android是先進(jìn)的平臺(tái),平臺(tái)上的應(yīng)用程序可兼容于各種型號(hào)的Android手機(jī),免除為各種不同手機(jī)機(jī)型開發(fā)的困擾。Android平臺(tái)支持各種先進(jìn)的網(wǎng)絡(luò)、繪圖、3D處理能力,可以用來提供更好的用戶體驗(yàn)。通過Android Market將自己的應(yīng)用程序銷售給世界各地用戶;對(duì)于用戶來說,Android是一個(gè)用于手機(jī)的操作系統(tǒng)。只要用戶申請(qǐng)了Google帳戶,當(dāng)想換手機(jī)時(shí),可以在不同的廠牌同樣使用Android操作系統(tǒng)平臺(tái)的手機(jī)之間選擇,并且很容易將比如通訊薄等個(gè)人資料轉(zhuǎn)換到新手機(jī)上。
目前,遠(yuǎn)程實(shí)時(shí)視頻監(jiān)視技術(shù)主要趨向以下幾個(gè)方向:首先,支持多樣化格式。Xmms,Xmovie,QuickTime是主要針對(duì)固定的媒體格式類型或傳輸協(xié)議,具有一定的專用性,因此難以滿足廣大消費(fèi)者的的需求,如今的音頻、視頻格式越來越多,如常見的音頻WMA、MP3以及視頻的RM、AVI等。如何能播放所有格式,是現(xiàn)今研究的方向。其次,可擴(kuò)展性也是一個(gè)必要的趨勢(shì),如今的播放器功能越來越強(qiáng)大,如何在現(xiàn)有的基礎(chǔ)上使功能更全面,也是人們接受的一個(gè)因素。這就是本設(shè)計(jì)選用開放式Android平臺(tái)的一個(gè)原因,代碼完全公開,為其功能擴(kuò)展提供方便的條件。
遠(yuǎn)程視頻監(jiān)視系統(tǒng)無論播放本地文件還是網(wǎng)絡(luò)流媒體文件,都需要經(jīng)歷3個(gè)處理階段,分別是獲取媒體數(shù)據(jù)、對(duì)音視頻媒體流解碼以及將解碼后的媒體數(shù)據(jù)給用戶顯示[2],本設(shè)計(jì)依據(jù)這3個(gè)處理階段將遠(yuǎn)程視頻實(shí)時(shí)監(jiān)視在整體結(jié)構(gòu)上進(jìn)行分層設(shè)計(jì)。
由于本地文件和網(wǎng)絡(luò)流媒體文件的數(shù)據(jù)獲取方式是相異的,若保證上層解碼的一致性,就要對(duì)本地文件和網(wǎng)絡(luò)流媒體文件進(jìn)行預(yù)處理,使它們的數(shù)據(jù)格式相同以供上層解碼。因此,本設(shè)計(jì)結(jié)合以上特點(diǎn)以及文件的解碼流程對(duì)遠(yuǎn)程視頻實(shí)時(shí)監(jiān)視的整體結(jié)構(gòu)采用分層設(shè)計(jì)方案,每一層獨(dú)立完成工作,不但能夠降低系統(tǒng)的耦合度,而且各層的獨(dú)立擴(kuò)展不干擾上下層的應(yīng)用。整體結(jié)構(gòu)層從上到下分別設(shè)計(jì)為用戶界面、音視頻解碼層、數(shù)據(jù)預(yù)處理層、數(shù)據(jù)提取層。整體結(jié)構(gòu)如圖1所示。
圖1 遠(yuǎn)程實(shí)時(shí)視頻監(jiān)視的整體結(jié)構(gòu)圖
遠(yuǎn)程視頻實(shí)時(shí)監(jiān)視的用戶界面主要由Android的GUI系統(tǒng)實(shí)現(xiàn),負(fù)責(zé)提供播放器和用戶之間的交互接口,例如播放時(shí)的快進(jìn)、后退、暫停等功能。GUI系統(tǒng)由Java語言框架和C語言框架組成,對(duì)于下層,GUI系統(tǒng)通過調(diào)用顯示輸入、輸出設(shè)備的驅(qū)動(dòng)將Android的軟件系統(tǒng)和底層的硬件聯(lián)系起來;對(duì)于上層,GUI系統(tǒng)提供了Java層次的繪圖接口,Android的Java框架層調(diào)用這些繪圖接口來構(gòu)建各種UI元素。此外,Java應(yīng)用程序?qū)右部梢哉{(diào)用這些繪圖接口。
音視頻解碼層包括解碼選擇組件、多樣主流音視頻格式的解碼器以及多路媒體流之間的同步的功能。解碼選擇組件先從本地文件或者流媒體文件中獲取媒體解碼格式的相關(guān)信息,通過獲取的信息來匹配出對(duì)應(yīng)的解碼器對(duì)媒體流解碼,此部分通過解碼算法的移植、修剪及優(yōu)化后完成。
數(shù)據(jù)預(yù)處理層對(duì)于媒體流文件來說,先要將RTP的包頭信息去除,再對(duì)RTP中的音視頻信息進(jìn)行組幀,同時(shí)將全部的數(shù)據(jù)幀傳遞到上層待解碼緩沖區(qū);而對(duì)于本地文件,則需要按照相對(duì)應(yīng)的媒體格式進(jìn)行解封裝,再將獲取文件的音視頻等信息按幀放入對(duì)應(yīng)的上層待解碼緩沖區(qū)。
數(shù)據(jù)獲取層的功能主要是對(duì)本地或流媒體文件的獲取。對(duì)本地文件信息獲取需要讀取本地文件即可,而對(duì)于流媒體信息文件的獲取,則需要從流媒體服務(wù)器上獲取數(shù)據(jù)信息,獲取信息期間包括前期會(huì)話協(xié)商、數(shù)據(jù)緩沖、數(shù)據(jù)發(fā)送等部分。此外,媒體協(xié)商部分中協(xié)商媒體流的常規(guī)信息,例如音視頻媒體類型、傳輸協(xié)議以及媒體傳輸端口等信息,這些都需用到RTSP協(xié)議[3]。
用戶界面是基于Android的GUI系統(tǒng)實(shí)現(xiàn)的[4],由類Video Monitor來具體實(shí)現(xiàn),其類圖如圖2所示。
圖2 Video Monitor類圖
登錄界面效果如圖3所示。
圖3 登錄界面效果
本設(shè)計(jì)的核心只需要利用解碼算法對(duì)視頻文件解封裝以及對(duì)音視頻解碼,因?yàn)槿魧⒄麄€(gè)遠(yuǎn)程視頻實(shí)時(shí)監(jiān)視的系統(tǒng)全部移植到Android平臺(tái)上,可能會(huì)造成大批量代碼冗余。同時(shí),整個(gè)項(xiàng)目的開發(fā)是基于Linux操作系統(tǒng),忽視了手機(jī)平臺(tái)能源不足、處理能力不夠大等限制因素的問題,所以面對(duì)客戶端手機(jī)的功能需求來說,將解碼算法進(jìn)行移植、修剪和優(yōu)化是很重要的。
3.2.1 解碼算法的移植
NDK的makefile文件是由Google發(fā)布,實(shí)質(zhì)是Android.mk文件,其語法和一般的makefile文件有很多相異點(diǎn)。因?yàn)樵械膍akefile文件在跨平臺(tái)編譯時(shí)不能被使用,所以將解碼算法里的makefile文件全部替換成NDK中的Android.mk文件是解碼算法移植的必要條件。通過對(duì)解碼層結(jié)構(gòu)的分析可以看出,最基礎(chǔ)模塊是avutil,基于已經(jīng)編譯好的avutil模塊之上的是avcodec模塊,基于avutil和avcodec兩者模塊之上的是avformat模塊。依據(jù)這種結(jié)構(gòu),本設(shè)計(jì)將編譯移植的順序由下到上設(shè)計(jì)為avutil,avcoedec,avformat,編譯的步驟如下說明:
1)說明config.h和config.mak文件
config.h和config.mak文件非常重要,因?yàn)楹芏嗖煌奈募紩?huì)用到include config.h,編譯器也會(huì)依據(jù)它而優(yōu)先選擇對(duì)代碼編譯。此外,解碼器自帶的makefile框架通過configure命令之后將產(chǎn)生1個(gè)config.h文件和1個(gè)config.mak文件,2個(gè)文件加起來共有600~700個(gè)宏定義,這些宏定義主要用于描述編譯后代碼各部分的參數(shù)設(shè)置,包括體系架構(gòu)、編譯器、版本、頭文件、編解碼器等設(shè)置。與此同時(shí),有關(guān)平臺(tái)差異方面的定義在此部分需要重新修改,例如把體系架構(gòu)改成Android平臺(tái)下的ARMv5TE,只有這樣編譯時(shí)的指令集才不會(huì)選擇X86的指令集而是ARM的指令集。
2)編譯libavutil.a
首先,在libavutil里創(chuàng)建一個(gè)Android.mk文件,然后在libavutil里的makefile文件調(diào)用subdir.mak就實(shí)現(xiàn)了真正的編譯,需要注意的是在Android.mk下書寫make文件可以在此省略,只要直接把對(duì)應(yīng)的源文件引入即可;標(biāo)準(zhǔn)的makefile是指定.o目標(biāo)文件,但是在Android.mk中需要直接指定.c源文件,Android.mk文件如下所示:
其中,在編譯時(shí)出現(xiàn)的錯(cuò)誤大部分來自于頭文件沒有引入,例如不識(shí)別某些文件的size_t關(guān)鍵字在該文件include stdio.h后就不報(bào)錯(cuò)等類似問題,修改時(shí)只需要把對(duì)應(yīng)的頭文件引入即可。其他層也可以按照以上相同的方法書寫Android.mk文件,并移植到Android平臺(tái)。
3.2.2 解碼算法的修剪及優(yōu)化
在Linux下編譯運(yùn)行解碼代碼時(shí),要經(jīng)過三步才能將解碼算法正確的編譯到Linux系統(tǒng)中,即configure,make,make install。第一步configure過程中將生成1個(gè)configure.h和1個(gè)make文件,作用是查找此次編譯了何種文件。經(jīng)過操作和嘗試發(fā)現(xiàn)可以在configure源代碼中添加多種配置參數(shù),這些參數(shù)包括基本選項(xiàng)參數(shù)、高級(jí)選項(xiàng)參數(shù)以及專門提供的優(yōu)化參數(shù),而優(yōu)化參數(shù)就是用于配置編譯過程中用到的編譯內(nèi)容。因此本設(shè)計(jì)也利用這些優(yōu)化參數(shù),擇優(yōu)選擇出合適的方法查詢出遠(yuǎn)程視頻實(shí)時(shí)監(jiān)視需要的文件,而解碼算法的修剪即將其中不需要的文件進(jìn)行刪除。編譯時(shí)設(shè)置的參數(shù)如下所示:
其中,參數(shù)配置在編譯源文件過程中,整個(gè)項(xiàng)目只有一部分編譯到鏈接庫,分別是H.264、amr_nb的編碼方法、3gp的文件封裝格式、解封裝文件的源代碼以及全部的解碼格式。而鏈接庫里已被編譯的源代碼的集合就是本設(shè)計(jì)所需要的源代碼的有效集,可以通過configure.h和make文件中的后綴名為.o文件來進(jìn)行查找,編譯.c代碼時(shí)生成的目標(biāo)文件其后綴名為.o的文件,因?yàn)槿魏我粋€(gè)被編譯的.c文件都能生成.o文件,所以可以利用查找后綴名為.o文件的方法來判斷配置參數(shù)下有哪些文件被編譯,哪些沒有被編譯,最后便可以得出本設(shè)計(jì)所需要的已編譯的源文件的最小集合。
開源代碼目前能夠跨平臺(tái)編譯運(yùn)行,但是由于手機(jī)的CPU處理能力、能源、內(nèi)存等各方面的限制資源都與PC機(jī)存在很大的不同,因此,本設(shè)計(jì)針對(duì)客戶端手機(jī)的特性來對(duì)代碼進(jìn)行優(yōu)化,具體有以下幾點(diǎn):
1)去除冗余代碼以及調(diào)試過程中的打印語句,減少if-else的判斷及不必要的代碼冗余,對(duì)局部和全局變量進(jìn)行調(diào)整,對(duì)程序結(jié)構(gòu)進(jìn)行規(guī)范,使用寄存器變量代替局部變量。
2)由于邏輯移位指令的執(zhí)行時(shí)間遠(yuǎn)遠(yuǎn)小于乘除運(yùn)算指令,因此乘除操作可以用邏輯移位運(yùn)算來代替,特別是除法指令,被代替后能夠縮短指令運(yùn)行的時(shí)間。
3)在編寫代碼過程中,盡量避免多重循環(huán)函數(shù)的調(diào)用以及盡量降低上下次循環(huán)的相關(guān)性,這樣做可大大減少?zèng)]必要的計(jì)算量。
4)設(shè)置合理的緩存,設(shè)置適合解碼算法移植的目標(biāo)平臺(tái)Android平臺(tái)的緩存大小。
本層針對(duì)本地文件的預(yù)處理可以依賴于解碼算法解封裝功能,但是對(duì)流媒體文件的預(yù)處理需要將一個(gè)或多個(gè)RTP數(shù)據(jù)包整合在一起,其中傳輸階段主要任務(wù)是為解碼模塊提供RTP數(shù)據(jù)包[5]。
RTP實(shí)現(xiàn)流程如圖4所示。
圖4 RTP實(shí)現(xiàn)流程
1)函數(shù)RTP_Create(context*the_context)用于完成RTP會(huì)話的初始化和為其上下分配內(nèi)存,函數(shù)先調(diào)用ITP Context_Create(the_context),然后再調(diào)用RTP_Session_Save_Cxinfo(*the_context,conx_cc),從而完成 RTP 會(huì)話初始化后上下文信息的創(chuàng)建和保存。
2)創(chuàng)建RTP結(jié)構(gòu),此部分由函數(shù)Create_Socket()完成,先調(diào)用 sockfd=socket(AF_INET,SOCK_DGRAM,0)來創(chuàng)建套接字,若創(chuàng)建成功,則可調(diào)用bind(sockfd,(struct sockaddr*)&local,sizeof(local)綁定套接字。
3)獲取且保存本地IP地址,隨機(jī)產(chǎn)生同步源標(biāo)志、創(chuàng)建新的同步源和設(shè)置規(guī)范名。關(guān)鍵代碼如下:
4)判斷會(huì)話是否結(jié)束。若是,結(jié)束網(wǎng)絡(luò)數(shù)據(jù)接收線程;若不是,進(jìn)入步驟5)。
5)接收RTP包,該部分由函數(shù)RTP_Receive(context cid,int fd,char*payload,int*len,struct sockaddr*sin)完成。
6)更新新包號(hào)的順序,設(shè)置序列號(hào)和信息時(shí)間標(biāo)簽。
7)將步驟5)中接收到的RTP數(shù)據(jù)包加入視頻幀緩沖區(qū)中,為解碼使用做準(zhǔn)備。
8)回到步驟4)繼續(xù)執(zhí)行。
該層完成主要功能是與流媒體服務(wù)器端協(xié)商媒體信息細(xì)節(jié),并根據(jù)協(xié)商結(jié)果從服務(wù)器端獲取流媒體數(shù)據(jù),將流媒體數(shù)據(jù)存入緩沖區(qū),按照本設(shè)計(jì)緩沖方案將數(shù)據(jù)包發(fā)送給數(shù)據(jù)預(yù)處理層,其結(jié)構(gòu)圖如圖5所示。
圖5 數(shù)據(jù)獲取模塊結(jié)構(gòu)圖
該層一共啟動(dòng)5個(gè)線程,其中1個(gè)線程中啟動(dòng)TCP連接,用于RTSP會(huì)話協(xié)商并且在RTP數(shù)據(jù)傳輸期間,該TCP連接必須一直保留。2個(gè)線程分別為接收音頻和視頻RTP數(shù)據(jù)的線程,另外2個(gè)線程分別為接收以及發(fā)送音頻和視頻的RTCP數(shù)據(jù)包[6]。
首先在PC機(jī)進(jìn)行模擬測(cè)試,即在Android編譯環(huán)境eclipse中將程序運(yùn)行,通過模擬器測(cè)試成功。然后將程序移植到具備Android操作系統(tǒng)的手機(jī)里,利用WiFi無線網(wǎng)絡(luò)連接服務(wù)器并且通過了權(quán)限訪問,測(cè)試結(jié)果驗(yàn)證了此視頻客戶端軟件在功能上滿足設(shè)計(jì)的基本需求。其效果如圖6所示。
本文實(shí)現(xiàn)了客戶端基于Android平臺(tái)的遠(yuǎn)程視頻實(shí)時(shí)監(jiān)視功能,能夠播放本地及流媒體視頻文件。遠(yuǎn)程視頻實(shí)時(shí)監(jiān)視系統(tǒng)整體采用分層的設(shè)計(jì)理念,本文分析了各層的結(jié)構(gòu)特點(diǎn)和關(guān)鍵技術(shù),并對(duì)解碼層的源代碼進(jìn)行了修剪和優(yōu)化。通過對(duì)各層的設(shè)計(jì),還實(shí)現(xiàn)了訪問權(quán)限的設(shè)置、播放、暫停等功能。本文移植的程序代碼目前能夠穩(wěn)定的在手機(jī)上運(yùn)行。該設(shè)計(jì)具有一定的通用性和開放性,可以被應(yīng)用到其他的客戶終端,對(duì)Android開發(fā)人員有一定的借鑒意義。
[1]Code Home.Android-An Open Handset Alliance Project[EB/OL].[2011-04-15].http://code.Google.com/android/what is android.Html.
[2]趙亮,張維.基于Android技術(shù)的界面設(shè)計(jì)與研究[J].電腦知識(shí)與技術(shù),2009,29(5):8183-8185.
[3]陳瑕,陳平華,李文亮.Android內(nèi)核分析[J].現(xiàn)代計(jì)算機(jī),2009(11):112-115.
[4]余志龍.Google Android SDK開發(fā)范例大全[M].北京:人民郵電出版社,2009.
[5]魏聰穎.基于實(shí)時(shí)流媒體傳輸系統(tǒng)的H.264組包算法研究[J].計(jì)算機(jī)科學(xué),2007(34):41-44.
[6]西剎子.安防天下——智能網(wǎng)絡(luò)視頻監(jiān)控技術(shù)詳解與實(shí)踐[M].北京:清華大學(xué)出版社,2010:3-10.