android播放rtsp視頻流app, demo app .使用live555+MediaCodec

用libvlc提供的庫播放rtsp,總是延遲比較大(局域網的情況下,存在明顯的畫面延時),netcaching設置爲0還是存在延遲,但是網絡延遲已經比較低了,沒辦法,自己寫了一個APP,現在只測試了接受一個視頻流的rtp流,沒有音頻。延遲較低,總的播放延遲基本在網絡部分。原理:

1.0 解碼播放端:使用android 的MediaCodec 播放h264流,先行使用h264裸流文件模擬網絡流進行了測試,可以達到給一幀就解碼播放一幀,1080p的視頻 60 幀(實際視頻文件是30fps,這裏可以倍速)每秒的輸入速度沒有問題,所以安照網絡視頻流接受的幀率,來一幀解一幀完全沒有問題,延遲應該就只在接受完一幀網絡流,接受端的延遲。

2.0 接受網絡視頻流,從vlc的源碼來看,也是使用live555來拉流,但是vlc來驅動live555拉流的線程(live555是單線程,需要外部驅動),1調用部分是有wait的,拉取到流數據之後送到解碼器解碼,還會有一個緩衝區,2解碼器從緩衝區取數據進行解碼的線程又有一個wait,就是sleep. 待解碼完把數據再放到 顯示緩衝區,3再有顯示線程來獲取數據的時候還是有一個wait. 所以總的流程下來,有多處緩衝和wait等待。  還有一個問題是,vlc從live555接受過來的視頻幀,會對時間戳進行一個簡要的調整,以防止出現網絡視頻流接受端失序,接受到的幀順序和解碼的順序不一致,所以對連續的幾幀會有一個時間戳的矯正,即時間戳可能會被改動。所以解碼線程解碼的時候就會根據這個時間戳來wait休眠。顯示的時候同樣也需要用到這個時間戳來休眠《vlc讀取rtsp流-源碼分析---時間戳dts的計算 》這裏自己寫的app,就不理會這個時間戳,直接網絡受到一幀解一幀,估有可能在使用udp傳輸的時候,受到的幀失序,導致解碼順序不正確,出現花屏。(live555內部還是有一個緩衝區的,默認100ms)

主要的實現:

git下載 https://github.com/Canok7/RTSP_PLAYER_can

說明:1.0 只編譯了arm64 的live555庫,live555相關的庫從vlc源碼編譯中提取出來的,也可以直接使用live555源碼文件使用ndk自己編譯 

2.0 MediaCode 播放h264部分,從網上找的,工程中有自己添加的從h264文件分離出h264NAL 幀的代碼,分別有java 實現的DataProVide_file 類,和c++版本,在jni目錄下的 geth264Frame.cpp ,可以測試MedaiCode

3.0 live555拉流部分,在jni目錄下額live555.cpp,從live555源碼裏面的 testRTSPClient.cpp 修改而來,改這個文件,有幾處要注意的地方:3.1 在shutdownStream()函數裏面,把exit(exit_code) 這一行去掉,改爲 eventLoopWatchVariable = 1。 不改動的話會出現如果rtsp 流打不開情況下,app閃退。 3.2 在afterGettingFrame() 函數裏面取走你要的 h264流數據。3.3 去掉函數continueAfterPLAY()裏面的定時器,這個定時器會自己關掉流。3.3 源文件有一個 #define REQUEST_STREAMING_OVER_TCP False  宏定義,要求服務端使用tcp傳輸的話,把這個宏定義定義爲True, 這樣的話如果你的rtsp服務器支持用tcp傳輸,就會優先用tcp來傳輸rtp流了,如果服務器本身不支持使用tcp傳輸,還是會重新用udp來傳輸的,這裏提醒下 vlc 目前是沒有支持用tcp來推送rtp流的。所以用vlc來推流測試,改爲True,也不頂用。

testRTSPClient.cpp分析 《live555:testRTSPClient.cpp 源碼分析-讀取rtsp流demo》

4.0 從live555拉流出來,爲了保證其及時性,這裏啓了一個線程專門負責拉流,將數據保存到一個緩衝隊列,自己實現的一個環形緩衝隊列,入數據不會阻塞,會覆蓋最老的數據,取數據有兩種方式,阻塞式獲取或者非阻塞式獲取,播放rtsp流這裏解碼器線程用阻塞式獲取數據,只要有數據立馬取出進行解碼播放。

5.0 可能會出現的問題:

5.1 花屏 。無非是丟幀,可以通過在各個環節取流來逐個排查。可能是網絡丟幀(改用rtp-over-tcp吧),這種情況可以通過wireshark或者tcpdump在客戶端抓網絡包,從抓的包中提取h264裸流,也可能是接受端live555處理不過來丟幀(可以通過增加live555接受端socket緩衝區的辦法緩解)。可以將live555獲取到的流數據保存成h264流————在本demo中 從live555庫拉流出來的數據,存放到native層的一個 queue緩衝隊列,app java 層通過jni調用從隊列中取數據,可以將 VideoDecoder.java 中的 bSave2file 設爲true,程序會把live555拉取的碼流數據存儲到/storage/emulated/0/dest.h264  。 再或者,就是mediacode解碼輸入端處理不正確,丟數據。

5.2 卡頓不流暢:這個情況一般在rtp-over-tcp 的情況下出現,ip網絡層丟幀,tcp傳輸層會重發,這樣如果一旦ip層丟幀,就會使得這一個數據包重發出現延時,播放來看就會發現這個畫面卡主。 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章