董 杰,辛吉濤,連 捷
(大連理工大學 電子信息與電氣工程學部,遼寧 大連 116023)
基于Android系統(tǒng)的H.264視頻直播技術(shù)研究
董 杰,辛吉濤,連 捷
(大連理工大學 電子信息與電氣工程學部,遼寧 大連 116023)
隨著智能移動設(shè)備的不斷普及以及流媒體技術(shù)的不斷發(fā)展,手機視頻監(jiān)控系統(tǒng)的應用日趨廣泛。而Android手機又以其平臺開放、種類繁多、用戶體驗良好等優(yōu)點而被大多數(shù)人所選擇。結(jié)合實際項目需求,提出一種基于Android系統(tǒng)的視頻直播解決方案。首先基于RTP協(xié)議將H.264碼流拆包,然后通過DatagramSocket(UDP協(xié)議的Socket)進行傳輸,最后在Windows環(huán)境下利用Cygwin將FFmpeg源解碼庫生成.so格式的目標庫,并在Android系統(tǒng)中調(diào)用生成的動態(tài)代碼庫進行解碼。重點分析了H.264碼流的傳輸以及解碼過程。實驗證明該方案能很好地實現(xiàn)視頻的實時播放,滿足實際項目需求。
Android;H.264;DatagramSocket;視頻解碼;FFmpeg
隨著多媒體技術(shù)、視頻壓縮技術(shù)以及網(wǎng)絡傳輸技術(shù)的發(fā)展,視頻監(jiān)控正朝著數(shù)字化、網(wǎng)絡化、智能化方向持續(xù)發(fā)展,并越來越廣泛地滲透到政府、教育、娛樂、醫(yī)療等領(lǐng)域[1]。傳統(tǒng)的視頻監(jiān)控系統(tǒng)一般采用臺式機作為監(jiān)控終端,需要在指定的地點并且有專用網(wǎng)絡設(shè)備支持的情況下才能對目標現(xiàn)場進行監(jiān)控,大大限制了監(jiān)控系統(tǒng)的應用范圍和靈活性[2]。而與傳統(tǒng)的PC機監(jiān)控終端相比,智能移動監(jiān)控終端以其輕便、隨機、靈活等優(yōu)點能夠滿足用戶隨時隨地獲取監(jiān)控信息的需求,因而顯示出極大的優(yōu)勢。而Android手機又以其平臺開放、價格低廉、種類繁多、用戶體驗良好等優(yōu)點成為智能移動終端的主體。
但是由于Android智能移動終端的網(wǎng)絡傳輸速度較慢以及內(nèi)存較小等限制,通常服務端對視頻數(shù)據(jù)按照H.264[3-4]標準進行編碼后傳輸。這就需要Android終端對接收到的數(shù)據(jù)進行解碼處理之后才能進行播放。本文提出一種基于An?droid系統(tǒng)的H.264視頻直播解決方案,實踐表明該方案實現(xiàn)的視頻播放能夠滿足實際項目需求,具有較好的用戶體驗。
系統(tǒng)設(shè)計原理如圖1所示。首先,視頻采集裝置進行視頻數(shù)據(jù)采集,并將采集到的視頻數(shù)據(jù)傳送到視頻編碼設(shè)備;然后視頻編碼設(shè)備對接收到的視頻數(shù)據(jù)進行H.264編碼,并將編碼后的數(shù)據(jù)傳輸至服務器;服務器和手機端通過Data?gramSocket(UDP協(xié)議的Socket)進行通信。當服務器接收到手機端發(fā)送的請求后,對H.264編碼進行拆包并向手機端傳送視頻數(shù)據(jù);最后Android手機端將接收到的數(shù)據(jù)組包后,調(diào)用解碼模塊進行解碼,最終向用戶展示解碼后的視頻信息。
圖1 系統(tǒng)設(shè)計原理圖
本系統(tǒng)通過視頻采集、編碼、拆包、傳輸、組包、解碼、播放的流程實現(xiàn)實時視頻監(jiān)控。具體流程如圖2所示。
圖2 系統(tǒng)流程圖
2.1 視頻采集及編碼
視頻采集裝置實時進行數(shù)據(jù)采集,并將采集到的數(shù)據(jù)信息傳輸至H.264編碼器進行編碼。
H.264是一種新的視頻編解碼標準,它在保留原有視頻編碼優(yōu)點的基礎(chǔ)上,提出了以往視頻編解碼技術(shù)無法比擬的一些優(yōu)點,如低碼率、網(wǎng)絡適應能力強、容錯能力強等[5]。H.264充分地利用了各種冗余來達到高效的數(shù)據(jù)壓縮比率,同時還具備高質(zhì)量流通的圖形,采用高度負責的算法,使其成為當前在低碼率下壓縮比率最高的視頻編碼標準[6]。基于以上優(yōu)點,本系統(tǒng)采用H.264編碼機制對視頻文件進行編碼傳輸。
2.2 視頻傳輸
TCP[7]協(xié)議是面向連接的傳輸協(xié)議,由于通信前需要建立連接,因而傳輸時延較大;TCP協(xié)議的流量控制機制以及確認和重發(fā)機制能夠保證數(shù)據(jù)傳輸?shù)目煽啃?,但是處理復雜,傳輸效率不高。而UDP[7]協(xié)議由于是無連接的傳輸層協(xié)議,通信前不建立連接,直接向接收方發(fā)送數(shù)據(jù),因而節(jié)省了大量的網(wǎng)絡狀態(tài)確認和數(shù)據(jù)確認的系統(tǒng)資源消耗,大大提高UDP協(xié)議的傳輸效率,傳輸速度快。
視頻圖像傳輸需滿足以下3點:
1)要求傳輸延時小,實時性高;
2)傳輸流量大,要求傳輸效率高;
3)在一定程序上允許傳輸錯誤或數(shù)據(jù)丟失。
根據(jù)以上特點可知,使用UDP協(xié)議來傳輸視頻相對TCP協(xié)議更理想。
傳輸規(guī)則定義如下:
本協(xié)議以1開始定義參數(shù)類型,如通道號以1開始。
本協(xié)議采用大端模式的網(wǎng)絡字節(jié)序傳輸字和雙字。約定如下:
1)字節(jié)(byte,int8)按照字節(jié)流的順序傳輸;
2)字(word,int16)先傳輸高8位,再傳輸?shù)?位;
3)雙字(dword,int32)先傳輸高8位,然后傳輸?shù)?位,再傳輸?shù)?6位,最后傳輸?shù)?4位。
自定義通用消息頭結(jié)構(gòu)如表1所示。
表1 通用消息頭結(jié)構(gòu)
2.2.1 拆包
在網(wǎng)絡傳輸中如果傳輸?shù)腎P報文大小超過最大傳輸單元(Maximum Transmission Unit,MTU)時就會產(chǎn)生IP分片情況。在以太網(wǎng)環(huán)境中可傳輸?shù)淖畲驣P報文(MTU)的大小為1 500 byte。除去IP頭20 byte,UDP頭8 byte,RTP頭12 byte,RTP的最大傳輸量為1 460 byte。如果發(fā)送的IP數(shù)據(jù)包大于MTU,數(shù)據(jù)包就會被拆開來傳送,因而產(chǎn)生數(shù)據(jù)包碎片,降低網(wǎng)絡速度,增加丟包率。對于視頻傳輸而言,若RTP包大于MTU而由底層協(xié)議任意拆包,可能會導致接收端播放器的延時播放,甚至無法正常播放。因此對于大于MTU的NALU單元,必須進行拆包處理。
RFC3984給出3種不同的RTP拆包方案:
1)Single NALU Packet(單一NAL單元模式);
2)Aggregation Packet(組合封包模式);
3)Fragmentation Unit(分片封包模式FU)。
具體拆包方法在此不再贅述。
2.2.2 傳輸
本系統(tǒng)采用DatagramSocket(UDP協(xié)議的Socket)進行數(shù)據(jù)的接收和發(fā)送。Java使用DatagramPacket來代表數(shù)據(jù)報,DatagramSocket接收和發(fā)送的數(shù)據(jù)都是通過DatagramPacket對象完成的。具體步驟如下:
1)創(chuàng)建DatagramSocket實例
m_sock=new DatagramSocket();
2)使用DatagramSocket類的send()和receive()方法發(fā)送和接收DatagramPacket實例
m_recvPack=new DatagramPacket
(m_byRecvbuf,m_byRecvbuf.length);
m_sock.setSoTimeout(50);
m_sock.receive(m_recvPack);
3)使用DatagramSocket類的close()方法銷毀該套接字m_sock.close();
2.2.3 組包
系統(tǒng)根據(jù)表2定義的視頻傳輸通用頭結(jié)構(gòu)進行組包,如果組包過程中出現(xiàn)丟包現(xiàn)象或者接收完當前幀所有包但不包含關(guān)鍵幀,則放棄當前已接收的所有數(shù)據(jù)繼續(xù)接收下一幀,否則調(diào)用解碼程序進行解碼。具體解碼流程如圖3所示。
2.3 視頻解碼
由于Android端從服務端獲得的是H.264編碼數(shù)據(jù),這就需要Android終端對接收到的數(shù)據(jù)進行解碼處理之后才能進行播放。因此首先搭建Cygwin環(huán)境,然后在Windows環(huán)境下利用Cygwin把FFmpeg源解碼庫生成.so格式的目標庫,最后在Android系統(tǒng)中利用JNI技術(shù)調(diào)用生成的動態(tài)代碼庫對視頻數(shù)據(jù)流進行解碼。
2.3.1 FFmpeg編譯
表2 視頻傳輸通用頭結(jié)構(gòu)
圖3 組包流程圖
首先在D盤下新建FFmpeg-1.10.7文件夾,在該文件夾下新建jni文件夾,把下載的源代碼解壓到該文件夾下。每次編譯之前需要對參數(shù)進行配置。在jni文件夾下新建config.sh配置文件。然后打開cmd,輸入bash--login-i,執(zhí)行命令./ config.sh,如果配置正確的話,顯示出如下兩行內(nèi)容:
License:nonfree and unredistributable
Creating config.mak and config.h...
進入jni目錄,在剛剛生成的config.h中找到#define re?strict restrict。因為Android的gcc并不認得restrict這個關(guān)鍵字,所以把它改寫成#define restrict。
將/libavutil/libm.h中所有的static函數(shù)全部注釋掉。分別修改libavcodec,libavfilter,libavformat,libavutil,libpostproc和libswscale目錄下的Makefile文件,將下面內(nèi)容注釋掉:
include$(SUBDIR)../config.mak
在jni目錄下建立一個腳本文件av.mk并進行配置。
在jni目錄下及其下面的jni/libavformat目錄、jni/libavco?dec目錄和其他libavfilter,libavutil,libpostproc和libswscale目錄下都分別新建相應的Android.mk文件。
在jni目錄下新建jni目錄,并把C語言驅(qū)動程序com_act1_H264.c,com_act1_H264.h(見3.3.2JNI調(diào)用動態(tài)代碼庫)和Android.mk放到該目錄中。在cygwin命令行窗口中,到d:ffmpeg-0.10.7目錄下,執(zhí)行ndk-build即可生成需要的動態(tài)鏈接庫libmylibffmepg.so。
2.3.2 JNI調(diào)用動態(tài)代碼庫
JNI是Java Native Interface的縮寫,中文為Java本地調(diào)用。從Java1.1開始,JNI標準成為Java平臺的一部分,它允許Java代碼和其他語言寫的代碼進行交互。JNI一開始是為了本地已編譯語言,尤其是C和C++而設(shè)計的,但是它并不妨礙使用其他語言,只要調(diào)用約定受支持即可[8]。具體實現(xiàn)方法如下:
1)創(chuàng)建JNI接口類H.264
private native int InitCodec();
private native void DeleteCodec(int index);
private native byte[]FFInputFrame
(byte[]data,int iLen,int index);
private native byte[]GetBMPHeade(int index);
2)編譯H.264文件,生成com_act1_H264.h文件。
3)編寫com_act1_H264.c文件。
4)根據(jù)3.3.1介紹的編譯方法生成.so文件。
5)調(diào)用生成的動態(tài)庫
static{
System.loadLibrary("mylibffmepg");
}
mylibffmepg是要調(diào)用的庫的名稱。編譯器會自動在前面加上lib,在后面加上.so。
2.3.3 解碼
在程序中通過調(diào)用類H.264中的函數(shù)完成解碼過程,解碼詳細過程見圖4。
圖4 解碼詳細過程
2.4 Android端顯示
首先進入DetailActivity選擇通道,如果選擇了一個通道,則處理通道信息并執(zhí)行start SingleDeviceActivity,進行單通道視頻播放;如果選擇了多個通道,則存儲信息后并start VideoGridListActivity,進行多通道視頻播放。視頻播放詳細界面如圖5所示。
圖5 單通道及多通道圖像顯示界面
通過實驗驗證,該方案能夠適應不同網(wǎng)絡環(huán)境下視頻的接收和播放。其中WiFi和3G環(huán)境下視頻播放流暢,丟包率較低,2G條件下也能滿足基本的視頻播放,但相對WiFi和3G環(huán)境下視頻丟包率較高。不同網(wǎng)絡條件下播放情況及丟包率比較如表3所示。
表3 不同網(wǎng)絡條件下效果比較
2.5 網(wǎng)絡異常條件下的丟包以及包的亂序處理
當網(wǎng)絡傳輸不穩(wěn)定時易出現(xiàn)丟包或包的傳輸亂序等情況。若不對丟包進行處理則播放畫面將出現(xiàn)花屏現(xiàn)象。在組包處理時對于丟包的幀整體刪除,不予播放。這就避免了由于丟包引起的花屏現(xiàn)象,用戶體驗較好。但是有時會出現(xiàn)當前幀的某些包在接收完下一幀的部分包之后才被傳輸過來的現(xiàn)象。此時若不做任何處理就把前一幀刪除,將會浪費一幀,影響整體播放效果。筆者在處理時創(chuàng)建一個緩沖區(qū),若換幀但當前幀的包沒有接收完,則將前一幀放入緩沖區(qū)內(nèi)等待,若組包成功則解碼播放;否則若在第3幀到來時仍未組包成功,此時再刪除第一幀。這樣就在一定程度上避免了因包的亂序傳輸引起的人為丟包現(xiàn)象。
整個程序中對FFmpeg的編譯和動態(tài)鏈接庫的使用是解碼器設(shè)計的關(guān)鍵,在設(shè)計解碼器之前,先進行了FFmpeg的編譯工作。在對FFmpeg源代碼編譯生成ffmpeg.so之后,還要對用C語言寫成的驅(qū)動程序進行二次編譯生成libffmepg.so。這樣在最終程序中就需要裝載兩個動態(tài)庫,由于兩個庫中相關(guān)函數(shù)的沖突,導致本地視頻播放時出現(xiàn)崩潰。由于動態(tài)庫中函數(shù)很多,排查起來工作量很大,所以需要排查函數(shù)之外的解決方案。
解決方法是把兩個動態(tài)庫合成一個動態(tài)庫。筆者在編譯過程中基于JNI機制的原理,嘗試在ffmpeg目錄下新建文件夾jni,把自己編寫的C程序復制到該文件夾中,并修改設(shè)置使該jni目錄與同層的libavcodec等目錄一起被編譯成為libffmepg.so的一部分,這樣實現(xiàn)了把ffmpeg.so和libffmepg.so兩個動態(tài)庫合成一個動態(tài)庫libffmepg.so。
通過以上的合并方法簡化了編譯工作,通過運行程序驗證該方法是可行的。
[1]曹曉芳,王超,李杰.一種基于Android智能手機的遠程視頻監(jiān)控的設(shè)計[J].電子器件,2011(6):709-712.
[2]李佳毅,徐曉輝,蘇彥莽,等.基于Android平臺的智能溫室視頻無線監(jiān)控系統(tǒng)[J].農(nóng)機化研究,2013(8):188-191.
[3] ITU2T Reeonunendation.H.263,Video Coding for low bit rate communieation[S].2000.
[4] 王嵩,薛全,張穎,等.H.264視頻編碼新標準及性能分析[J].電視技術(shù),2003(6):25-27.
[5] SRINIVASAN K S.The effects of priority levels and buffering on the statistical multiplexing of single-layer H.264/AVC and SVC en?coded video streams[J].IEEE Trans.Broadcasting,2010,56(3):281-286.
[6] 羅歡,謝云,李丕杉.基于Android智能電視的視頻監(jiān)控的設(shè)計[J].電視技術(shù),2013,37(22):85-87.
[7]沈蘭蓀,卓力.小波編碼與網(wǎng)絡視頻傳輸[M].北京:科學出版社,2005.
[8] 農(nóng)麗萍,王力虎,黃一平.Android在嵌入式車載導航系統(tǒng)的應用研究[J].計算機工程與設(shè)計,2010(11):2473-2476.
Study on H.264 Live Video Technology with Andriod System
DONG Jie,XIN Jitao,LIAN Jie
(School of Control Science and Engineering,Dalian University of Technology,Liaoning Dalian 116023,China)
With the popularity of smart mobile devices and the development of streaming media technology,the mobile video surveillance system is more and more popular.The Android mobile phone has been widely used because of open platforms,wide variety,good user experience,etc.In this paper,a solution for live video based on Android system is proposed.First,H.264 stream is unpacked based on the RTP protocol.Second,the generated package is transmitted via DatagramSocket(Socket of UDP protocols).Finally,dynamic library(.so)is generated from FFmpeg library by using Cygwin in the Windows system,and uses dynamic library to decode in the Android system.This paper focuses on the transmission and the decoding process of H.264 stream.The experimental results show the validity and practicability of the proposed solution and met the demand of the program.
Android;H.264;DatagramSocket;video decoding;FFmpeg
TP277
A
10.16280/j.videoe.2015.04.004
2014-08-22
【本文獻信息】董杰,辛吉濤,連捷.基于Android系統(tǒng)的H.264視頻直播技術(shù)研究[J].電視技術(shù),2015,39(4).
國家自然科學基金項目(61374070)
董 杰(1981—),博士,碩士研究生導師,講師,主要研究領(lǐng)域為智能信息處理;辛吉濤(1989—),碩士研究生,主要研究領(lǐng)域為智能信息處理;
連 捷(1980—),女,博士,博士生導師,副教授,主要研究領(lǐng)域為切換系統(tǒng)穩(wěn)定性分析和設(shè)計。
責任編輯:許 盈