摘 要: 以視頻監(jiān)控系統(tǒng)在物聯(lián)網(wǎng)中的應(yīng)用為背景,,介紹了如何在Android平臺(tái)上進(jìn)行實(shí)時(shí)的視頻監(jiān)控系統(tǒng)的開(kāi)發(fā),。在對(duì)Android操作系統(tǒng)進(jìn)行深入分析的基礎(chǔ)之上,提出了一個(gè)基于Android的流媒體監(jiān)控方案,,此方案通過(guò)移植X264開(kāi)源庫(kù),,實(shí)現(xiàn)了Android視頻的H.264編碼,并通過(guò)雙緩沖文件搭建流媒體服務(wù)器對(duì)實(shí)時(shí)視頻流進(jìn)行發(fā)布,。通過(guò)對(duì)系統(tǒng)的測(cè)試,,指出了值得改進(jìn)的方向,為今后的研究工作提供參考,。
關(guān)鍵詞: Android,;視頻監(jiān)控;H.264,;雙緩沖技術(shù),;流媒體服務(wù)器
終端平臺(tái)的智能化和3G網(wǎng)絡(luò)的覆蓋帶來(lái)了移動(dòng)互聯(lián)網(wǎng)時(shí)代,,這對(duì)當(dāng)今不斷壯大的物聯(lián)網(wǎng)帶來(lái)了很多的便利。比如對(duì)物流車(chē)輛進(jìn)行隨時(shí),、隨地,、隨身的視頻監(jiān)控,相比傳統(tǒng)的PC機(jī)監(jiān)控更加方便和高效,。在移動(dòng)終端上進(jìn)行視頻監(jiān)控系統(tǒng)的開(kāi)發(fā),,由于其硬件資源和網(wǎng)絡(luò)環(huán)境的限制,開(kāi)發(fā)難度遠(yuǎn)大于PC機(jī),,并且對(duì)移動(dòng)終端和網(wǎng)絡(luò)都有很高的要求,。本文通過(guò)分析流媒體服務(wù)器的特點(diǎn),在服務(wù)器上實(shí)現(xiàn)了一個(gè)雙緩沖機(jī)制來(lái)達(dá)到實(shí)時(shí)發(fā)布流媒體的要求,,通過(guò)服務(wù)器多線(xiàn)程的方式實(shí)現(xiàn)邊采集邊傳輸并實(shí)時(shí)的發(fā)布,。
本文采用Android操作系統(tǒng)作為終端視頻采集的平臺(tái),借助Android系統(tǒng)平臺(tái)開(kāi)發(fā)的優(yōu)點(diǎn),,可以很好地進(jìn)行推廣及后期應(yīng)用,。此外,為了保證數(shù)據(jù)傳輸?shù)馁|(zhì)量,,本文通過(guò)在Android中移植X264開(kāi)源庫(kù)來(lái)實(shí)現(xiàn)流媒體視頻的編碼,,并通過(guò)雙緩沖文件優(yōu)化流媒體傳輸機(jī)制以實(shí)現(xiàn)實(shí)時(shí)視頻和移動(dòng)監(jiān)控的融合。
1 系統(tǒng)分析與設(shè)計(jì)
1.1 系統(tǒng)總體架構(gòu)設(shè)計(jì)
系統(tǒng)由視頻移動(dòng)終端,、流媒體服務(wù)器,、視頻監(jiān)控端3部分組成,系統(tǒng)組成框圖如圖1所示,。
其中,,視頻移動(dòng)終端通過(guò)Anrdoid平臺(tái)提供的api實(shí)時(shí)獲取攝像頭捕獲的視頻流,并通過(guò)JNI的方式調(diào)用底層的native代碼以完成H.264的編碼工作,,之后通過(guò)socket傳輸?shù)揭曨l監(jiān)控服務(wù)器,。
視頻監(jiān)控服務(wù)器包括應(yīng)用服務(wù)器和流媒體服務(wù)器兩部分。其中應(yīng)用服務(wù)器作為整個(gè)系統(tǒng)的服務(wù)端,,用于處理視頻監(jiān)控端的視頻請(qǐng)求以及接收視頻移動(dòng)終端發(fā)來(lái)的實(shí)時(shí)視頻流數(shù)據(jù),。流媒體服務(wù)器則用于將應(yīng)用服務(wù)器接收的視頻流數(shù)據(jù)封裝成流媒體格式并實(shí)時(shí)發(fā)布。
視頻監(jiān)控端采用Android平臺(tái)構(gòu)建,,可以通過(guò)RTSP和HTTP兩種協(xié)議訪(fǎng)問(wèn)流媒體服務(wù)器以獲得觀看實(shí)時(shí)視頻的效果,。
1.2 視頻采集和編碼
本系統(tǒng)采集的實(shí)時(shí)視頻來(lái)源于Android系統(tǒng)支持的攝像頭??紤]到無(wú)線(xiàn)網(wǎng)絡(luò)帶寬的限制,,本系統(tǒng)采用H.264標(biāo)準(zhǔn)進(jìn)行壓縮編碼。由于H.264編碼對(duì)硬件要求較高,,編碼的速度會(huì)受到一定的影響,,這樣采集到的視頻可能不夠連貫,。本系統(tǒng)采用多線(xiàn)程加緩沖隊(duì)列的方法進(jìn)行采集和編碼。視頻采集線(xiàn)程將捕獲的每一幀數(shù)據(jù)放入一個(gè)緩沖隊(duì)列中,,視頻編碼線(xiàn)程從隊(duì)列中獲取視頻幀集合來(lái)完成編碼和傳輸?shù)墓ぷ?。具體流程圖如圖2所示。
其中視頻采集線(xiàn)程的偽代碼如下:
Begin:
//初始化攝像頭,,設(shè)置視頻采集參數(shù),;
While(視頻采集處于激活狀態(tài)){
從攝像頭獲取一幀數(shù)據(jù);
while(緩沖隊(duì)列已滿(mǎn))
wait,;//將線(xiàn)程掛起以等待隊(duì)列可寫(xiě)
將一幀數(shù)據(jù)壓入幀緩沖隊(duì)列,;
Notify;//通知編碼線(xiàn)程隊(duì)列可讀
}
End
視頻編碼線(xiàn)程的偽代碼如下:
Begin:
//設(shè)置編碼參數(shù)(H.264),,初始化編碼對(duì)象,;
While(編碼標(biāo)志位為真){
While(緩沖隊(duì)列為空)
wait;//將線(xiàn)程掛起以等待隊(duì)列可讀
從緩沖隊(duì)列取一幀數(shù)據(jù),;
Notify,;//通知采集線(xiàn)程隊(duì)列可寫(xiě)
JNI調(diào)用native代碼對(duì)數(shù)據(jù)幀進(jìn)行編碼;
If(編碼成功){
調(diào)用RTP組件對(duì)數(shù)據(jù)打包,;
通過(guò)UDP傳輸RTP包,;
}
}
End
1.3 H.264視頻流傳輸控制模型
H.264的定義由視頻編碼層(VCL)和網(wǎng)絡(luò)提取層(NAL)兩部分組成。其中VCL作為H.264的核心算法引擎對(duì)視頻數(shù)據(jù)進(jìn)行壓縮編碼和解碼,;NAL層則根據(jù)不同的網(wǎng)絡(luò)把數(shù)據(jù)打包成相應(yīng)的格式并通過(guò)網(wǎng)絡(luò)傳送出去,。為了保證較低的延時(shí),需要將H.264視頻流數(shù)據(jù)打包成RTP包,,并加上時(shí)間戳和序列號(hào)等信息,,然后通過(guò)UDP傳輸?shù)椒?wù)器。RTP的打包模式有3種:?jiǎn)蜰AL單元模式,、非交錯(cuò)模式和交錯(cuò)模式,。本文根據(jù)系統(tǒng)的要求,采用非交錯(cuò)模式按照編碼的視頻流順序進(jìn)行組包,,適用于延時(shí)較低的實(shí)時(shí)系統(tǒng)。
由于H.264編碼對(duì)CPU消耗較大,,如果放在java層則會(huì)大幅度影響系統(tǒng)性能,。本系統(tǒng)將H.264編碼模塊放在native層,用C/C++實(shí)現(xiàn),,通過(guò)jni調(diào)用編碼接口,,然后通過(guò)RTP傳輸。
1.4 服務(wù)器設(shè)計(jì)
服務(wù)器端采用雙緩沖文件實(shí)現(xiàn)流媒體的生成和發(fā)布,。傳統(tǒng)的實(shí)時(shí)視頻監(jiān)控一般采用socket連接實(shí)現(xiàn)邊傳輸邊播放視頻,,視頻數(shù)據(jù)并不會(huì)被緩存,,并且如果要有新的客戶(hù)端加入監(jiān)控,則必須要新建一個(gè)socket連接,。本系統(tǒng)通過(guò)加入流媒體服務(wù)器作為視頻中轉(zhuǎn),,很好地解決了這一問(wèn)題。由于流媒體服務(wù)器發(fā)布實(shí)時(shí)流媒體需要實(shí)時(shí)的視頻源,,本系統(tǒng)的應(yīng)用服務(wù)器將接收的實(shí)時(shí)視頻流數(shù)據(jù)寫(xiě)入一個(gè)緩沖文件作為流媒體服務(wù)器的視頻源,,此緩沖文件通過(guò)linux命名管道實(shí)現(xiàn)。此外,,流媒體服務(wù)器發(fā)布流媒體也需要一個(gè)緩沖文件,,用于存放被編碼成流媒體格式后的視頻流數(shù)據(jù),以供客戶(hù)端調(diào)用,。服務(wù)器的工作流程圖如圖3所示,。
2 系統(tǒng)實(shí)現(xiàn)
2.1 Android Camera視頻采集
為了實(shí)時(shí)捕獲Android攝像頭的畫(huà)面,需要用到Android Camera,。Android Camera包含取景和拍照兩個(gè)功能,,它實(shí)際上是建立在C/S架構(gòu)上的。Camera運(yùn)行的時(shí)候,,可以大致分成服務(wù)器和客戶(hù)端兩個(gè)部分,,他們分別運(yùn)行在兩個(gè)不同的進(jìn)程中,通過(guò)Binder機(jī)制來(lái)完成進(jìn)程間通信,。這種Android特有的Binder機(jī)制可以保證客戶(hù)端和服務(wù)器獨(dú)立的變化,,客戶(hù)端調(diào)用接口AIDL定義的接口,功能則在服務(wù)器中實(shí)現(xiàn),,并且進(jìn)程間通信的部分對(duì)上層程序不可見(jiàn),。
具體實(shí)現(xiàn)中,通過(guò)Android Framework提供的android.hardware.Camera類(lèi)來(lái)完成和Camera Service服務(wù)端通信,。由于需要對(duì)采集到的每一幀畫(huà)面進(jìn)行壓縮編碼處理,,可以通過(guò)調(diào)用Camera對(duì)象的setPreviewCallback函數(shù)來(lái)設(shè)置一個(gè)回調(diào)對(duì)象,此回調(diào)對(duì)象中的onPreviewFrame函數(shù)可用于完成對(duì)當(dāng)前幀的捕獲,,這樣就可以在此函數(shù)中對(duì)采集到的視頻進(jìn)行編碼的處理了,。
2.2 JNI調(diào)用X264庫(kù)
考慮到無(wú)線(xiàn)網(wǎng)絡(luò)環(huán)境的不穩(wěn)定性和帶寬有限的問(wèn)題。本文對(duì)采集到的視頻進(jìn)行H.264標(biāo)準(zhǔn)的高效壓縮編碼,。H.264是目前一個(gè)廣泛使用的具有高壓縮比的視頻編碼格式,,具有較高的視頻壓縮性能,適合用窄帶傳輸,,適用于移動(dòng)互聯(lián)網(wǎng)和流媒體播放,。本文采用X264開(kāi)源庫(kù)來(lái)對(duì)實(shí)時(shí)視頻進(jìn)行壓縮編碼。首先需要在Android操作系統(tǒng)上移植X264庫(kù),。
由于X264是用C語(yǔ)言寫(xiě)的一個(gè)開(kāi)源庫(kù),,為了能夠被Android平臺(tái)使用,,需要用到NDK工具對(duì)其進(jìn)行編譯。NDK是用來(lái)編譯本地代碼的工具,,作為Android SDK的一個(gè)補(bǔ)充,,用于將原生的C/C++代碼集成到應(yīng)用中,并通過(guò)JNI的方式被上層java程序調(diào)用,。本文采用JNI方式調(diào)用X264庫(kù)的步驟如下所示,。
(1)JNI接口設(shè)計(jì)
設(shè)計(jì)調(diào)用本地代碼的函數(shù)接口,。本文需要對(duì)采集的視頻進(jìn)行H.264編碼,,編碼部分需要定義3個(gè)接口。分別如下:
private native long CompressBegin(int width,,int height),;
private native int CompressBuffer(long encoder,int type,,byte[] in,,int insize,byte[]out),;
private native int CompressEnd(long encoder),;
其中native關(guān)鍵表明這3個(gè)函數(shù)來(lái)自于native代碼。CompressBegin接口是編碼初始化接口,,通過(guò)傳遞視頻畫(huà)面的寬和高來(lái)對(duì)H.264編碼器進(jìn)行初始化設(shè)定,;CompressBuffer接口是編碼接口,通過(guò)傳遞encoder編碼器結(jié)構(gòu)和視頻流字節(jié)數(shù)組來(lái)對(duì)當(dāng)前幀的視頻流數(shù)據(jù)進(jìn)行H.264編碼,,編碼后的結(jié)果存儲(chǔ)在out數(shù)組中,;CompressEnd接口用于釋放編碼資源。
?。?)實(shí)現(xiàn)本地方法
JNI接口設(shè)計(jì)完畢之后,,需要用C語(yǔ)言實(shí)現(xiàn)接口。創(chuàng)建一個(gè)H264Android.c的文件,,用來(lái)實(shí)現(xiàn)第一步中定義的3個(gè)接口,。
(3)生成動(dòng)態(tài)鏈接庫(kù)
實(shí)現(xiàn)JNI接口之后,,需要生成.so的動(dòng)態(tài)鏈接庫(kù)以供java程序調(diào)用,。為了生成動(dòng)態(tài)鏈接庫(kù),需要編寫(xiě)Android.mk文件并通過(guò)NDK工具對(duì)本地代碼進(jìn)行交叉編譯,。交叉編譯時(shí)需要針對(duì)X264庫(kù)編寫(xiě)相應(yīng)的Android.mk文件,核心內(nèi)容如下所示:
include $(CLEAR_VARS)
LOCAL_C_INCLUDES+=libx264/include
LOCAL_MODULE:=H264Android
LOCAL_SRC_FILES:=H264Android.c
LOCAL_LDFLAGS+=$(LOCAL_PATH)/libx264/lib/libx264.a
LOCAL_LDLIBS:=-L$(SYSROOT)/usr/lib-lgcc
include$(BUILD_SHARED_LIBRARY)
其中,,LOCAL_C_INCLUDES標(biāo)明了編譯需要的外部頭文件路徑,;LOCAL_MODULE標(biāo)明了當(dāng)前生成模塊名稱(chēng),;LOCAL_SRC_FILES標(biāo)明了編譯需要用到的源文件;LOCAL_LDFLAGS標(biāo)明了編譯需要用到的外部靜態(tài)庫(kù),;LOCAL_LDLIBS標(biāo)明了引用的外部庫(kù)文件,。
通過(guò)引用X264的靜態(tài)庫(kù),即可將X264編譯到native代碼中,,并被上層java程序調(diào)用,。編譯成功之后,會(huì)在Android項(xiàng)目的根目錄下的libs文件夾中形成一個(gè)libH264Android.so的動(dòng)態(tài)鏈接庫(kù),,編譯完成,。
(4)Java程序調(diào)用本地代碼
Android中的Java程序可以通過(guò)System.loadLibrary("H264Android")函數(shù)調(diào)用第3步中生成libH264Android.so動(dòng)態(tài)鏈接庫(kù),。并使用聲明的native方法來(lái)完成視頻編碼的功能,。
2.3 視頻傳輸?shù)膶?shí)現(xiàn)
視頻傳輸通過(guò)TCP和UDP兩種方式配合實(shí)現(xiàn)。為了保證視頻采集終端和服務(wù)器之間有可靠的通信機(jī)制,,采用TCP連接來(lái)進(jìn)行控制信息的傳輸,,當(dāng)視頻終端收到有效的傳輸視頻的控制信息之后,采用UDP連接發(fā)送實(shí)時(shí)的視頻流到服務(wù)器,。服務(wù)器視頻接收線(xiàn)程會(huì)將收到的有效視頻數(shù)據(jù)寫(xiě)入到一個(gè)緩沖文件Camera.h264中,,此文件被作為流媒體服務(wù)器的視頻源。
2.4 FFmpeg流媒體服務(wù)器架設(shè)
服務(wù)器端采用FFmpeg作為流媒體服務(wù)器,。FFmpeg是一個(gè)開(kāi)源免費(fèi)跨平臺(tái)的視頻和音頻流方案,,屬于自由軟件,采用LGPL或GPL許可證,。FFmpeg既可以對(duì)視頻進(jìn)行編解碼,,也可以搭建基于http和rtsp協(xié)議的流媒體服務(wù)器。
本系統(tǒng)服務(wù)器利用Camera.h264緩沖文件作為FFmpeg的視頻源進(jìn)行流媒體的發(fā)布,。由于ffmpeg發(fā)布流媒體需要用到其中的FFserver組件,,ffserver組件的啟動(dòng)需要編寫(xiě)相應(yīng)的ffserver.conf配置文件,主要配置如下所示:
Port 8090//配置RTSP端口號(hào)
BindAddress 0.0.0.0//綁定本地IP地址
MaxClients 1000//配置最大連接數(shù)
<Feed feed1.ffm>//配置流媒體緩沖文件
File/tmp/feed1.ffm
FileMaxSize 200 KB//緩沖文件大小為200 KB
</Feed>
<Stream camera.asf>//配置發(fā)布的流媒體格式
Feed feed1.ffm
Format asf
VideoFrameRate 15
VideoSize 352x240
</Stream>
其中,,Port指定了流媒體服務(wù)器綁定的端口,。<Feed feed1.ffm>標(biāo)簽定義了流媒體服務(wù)器運(yùn)行所需要的一個(gè)緩沖文件,大小為200 KB,。<Stream camera.asf>標(biāo)簽定義了流媒體服務(wù)器輸出的視頻格式以及視頻相關(guān)的參數(shù),。如本系統(tǒng)輸出的流媒體格式為.asf格式。
在ffserver啟動(dòng)時(shí),,會(huì)根據(jù)ffserver.conf文件中的配置新建一個(gè)feed1.ffm緩沖文件,。此緩沖文件用于存放來(lái)自視頻源文件的實(shí)時(shí)視頻流。FFmpeg會(huì)根據(jù)配置文件中的視頻輸出格式將視頻源中的文件進(jìn)行轉(zhuǎn)換,轉(zhuǎn)換之后的數(shù)據(jù)會(huì)寫(xiě)入feed1.ffm文件中,。本系統(tǒng)中,,feed1.ffm文件大小被限制在200 KB,當(dāng)200 KB的空間被用完后,,新數(shù)據(jù)會(huì)從文件的開(kāi)頭進(jìn)行寫(xiě)入,。這樣可以保證當(dāng)有新的客戶(hù)端加入監(jiān)控時(shí),觀看到的是最新的視頻,。
3 系統(tǒng)測(cè)試
為了驗(yàn)證H.264視頻在無(wú)線(xiàn)網(wǎng)絡(luò)中的傳輸性能,,本系統(tǒng)選取了2臺(tái)Android 2.3系統(tǒng)的手機(jī)進(jìn)行測(cè)試。測(cè)試環(huán)境如下:
視頻終端:Google Nexus S
CPU主頻:1 GHz
內(nèi)存:512 MB
操作系統(tǒng):Android 2.3
服務(wù)器采用Ubuntu10.04搭建,。
表1對(duì)雙緩沖和無(wú)緩沖的流媒體傳輸機(jī)制進(jìn)行了測(cè)試和對(duì)比,,顯示了隨著分辨率和每秒傳輸幀數(shù)/(F/S)的變化導(dǎo)致的丟包率和延時(shí)的變化。
經(jīng)過(guò)測(cè)試,,在采用了雙緩沖機(jī)制發(fā)布流媒體之后,,客戶(hù)端能夠以更小的延時(shí)播放流媒體服務(wù)器發(fā)布的H.264視頻流。由于丟包率主要取決于傳輸帶寬,,改變傳輸模式對(duì)丟包率的提升并不是很大,。
在高速移動(dòng)互聯(lián)網(wǎng)的環(huán)境下進(jìn)行視頻監(jiān)控成為了物聯(lián)網(wǎng)行業(yè)一個(gè)比較熱門(mén)的應(yīng)用。本文在流媒體服務(wù)器的搭建上采用雙緩沖文件技術(shù),,有效地保證了視頻源的實(shí)時(shí)性,,降低了網(wǎng)絡(luò)傳輸?shù)难訒r(shí)。此外,,考慮到無(wú)線(xiàn)網(wǎng)絡(luò)環(huán)境中視頻數(shù)據(jù)傳輸?shù)睦щy,,本文采用H.264標(biāo)準(zhǔn)對(duì)實(shí)時(shí)視頻進(jìn)行壓縮編碼,有效地提高了帶寬利用率,。由于本文傳輸視頻數(shù)據(jù)采用的RTP組包模式[5]并沒(méi)有考慮到實(shí)際的應(yīng)用背景,,會(huì)產(chǎn)生一定程度的數(shù)據(jù)丟包,因此只是和應(yīng)用與對(duì)實(shí)時(shí)畫(huà)面要求不高的場(chǎng)景,,比如物聯(lián)網(wǎng)物流行業(yè)等,,如果要實(shí)時(shí)傳輸更清晰的視頻數(shù)據(jù),則需要采用良好的失序和擁塞處理技術(shù),,并重寫(xiě)RTP的組包算法,,這樣可以保證視頻數(shù)據(jù)的穩(wěn)定性和完整性,這也是今后要研究和改進(jìn)的方向,。
參考文獻(xiàn)
[1] SCHULZRINNE H,, CASNER S. RTP: A Transport Protocol for Real-Time Application[M]. RFC3550, 2003.
[2] WENGER S,, HANNUKSEL M M. RTP Payload Format for H.264 Video[M]. RFC3984,, 2005.
[3] 王立青.基于X264和流媒體的嵌入式視頻監(jiān)控系統(tǒng)[J].計(jì)算機(jī)安全,2010(7):13-15.
[4] 任嚴(yán).基于FFMPEG的視頻轉(zhuǎn)換與發(fā)布系統(tǒng)[J].計(jì)算機(jī)工程與設(shè)計(jì),2007,,28(20):4962-4967.
[5] 魏聰穎.基于實(shí)時(shí)流媒體傳輸系統(tǒng)的H.264組包算法研究[J].計(jì)算機(jī)科學(xué),,2007,34(8):41-44.