多媒體開發之rtp打包---打包中的FU-A分包方式說明

繼上篇rtp中的時間戳和負載類型以後,升入到了nalu的分片打包問題,這裏作下筆記html

(1)fu-a的打包格式java

1.基於RTP協議的打包及解包
(1)單個NAL打包
H.264NALU單元常由[start code][NALU header][NALU payload]三部分組成,其中start code 用於標誌一個NALU單元的開始,必須是「00000001」或者是「000001」,打包時去掉開始碼,把其餘數據打包到RTP包就能夠了。
(2)分片打包
因爲1500個字節是IP數據報的長度的上限,去除20個字節的數據報首部,1480字節是用來存放UDP數據報的。因此當一幀中的字節數超過這個數值時,咱們必須將其分片打包。並且UDP在傳輸的過程當中也要由包頭開銷,因此將RTP包的最大字節數定位1400字節。
須要分片的包格式有所區別,首先說明下分片的格式:
FU指示字節有如下格式:
+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|F|NRI| Type |
+---------------+
FU指示字節的類型28,29表示FU-A和FU-B。NRI域的值必須根據要分片的NAL單元NRI的值設置。
FU頭的格式以下:
+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|S|E|R| Type |
+---------------+
S:開始位(1bit),當設置爲1,開始位指示分片NAL單元的開始。第一個分片包設爲1,其餘的分片設置爲0。
E:結束位(1bit),當設置爲1,結束位指示分片NAL單元的結束,即,FU荷載是最後分片時設置爲1,其餘時候設置爲0。
R:保留位(1bit),必須設置爲0。
Type:5bit
(3)打包和解包的流程分析:
打包:
分片時詳細說明:
①第一個FU-A包的FU indicator 是這麼設置的:F=NALU頭中的F,NRI=NALU頭中的NRI,Type=28 FU header: S=1,E=0,R=0,Type=NALU頭中的Type;
②中間的FU-A包的FU indicator是這麼設置的:F=NALU頭中的F,NRI=NALU頭中的NRI,Type=28 FU header: S=0,E=0,R=0,Type=NALU頭中的Type;
③尾FU-A包的FU indicator是這麼設置的:F=NALU頭中的F,NRI=NALU頭中的NRI,Type=28 FU header: S=0,E=1,R=0,Type=NALU頭中的Type。
 
解包:
下面咱們針對RTP解包時對待分片進行分類的代碼實現作分析:
byte startBit=(byte)(recbuf[13]&0x80); byte endBit=(byte)(recbuf[13]&0x40);
①若是,startBit==-128,這包是分片的首包。
NalBuf[4]=(byte) ((recbuf[12]&0xE0)+(recbuf[13]&0x1F)); 這句用於重建組合NAL單元類型
②若是(startBit==0)&&(endBit==0),這包是分片的中間部分。
③若是 endBit==64 ,這包是分片尾部。
當分類清楚,就能夠對各部分作相應的處理,如圖中分析的那樣。
2.碼流管理機制
(1) 碼流的接收。在發送端碼流發送很快的狀況下,因爲接收端不只要接收碼流,還要進行分析,解碼,這個處理須要一個較長的過程,若是接收端順序執行這個過程的話,會致使沒法完整接收發送端的包、出現丟包,由此而帶來的是解碼錯誤、沒法正常播放視頻、甚至程序奔潰等嚴重錯誤。針對這個問題咱們採起併發的處理機制予以解決。線程併發存在的一個意義就是爲了提升運行在單處理器上的速度。在java中咱們採用java.util.concurrent包中的執行器(Executor)來管理線程Thread對象。咱們建立20個線程,也就是向SingleThreadExecutor提交了20個任務,這些任務將排好隊,每一個任務會在下一個任務開始以前運行結束,每一個任務都是按照他們被提交的順序,在下一個任務開始以前完成。這樣不只實現了快速的接收並且還保證了接收到的包順序是正確的。經過這樣的處理後,接收和分析解碼能夠被分紅兩個部分,咱們能夠把接收到的數據暫時存放在緩衝區,而後就能夠接着去接收下一包數據,不用等着分析、解碼完成後纔去接收下一包數據。這樣作大大提升了接收效率,同時避免了丟包問題。
(2) 視頻數據解析和解碼。因爲採用了併發的機制,接收到的數據不止一包,因此對接收到的數據應該作怎樣合理的處理,成爲咱們接下來的難點。咱們須要保證的仍然是數據包的順序,還且每次只能處理一包,這裏涉及到一個線程之間的協做問題。咱們採用消費者生產者這種線程協做模式來作處理。咱們將從存放數據的緩衝區中按順序取到的包通過分析後放入另一個緩衝區,通知解碼程序能夠進行今後緩衝區中得到數據解碼,而後分析視頻數據的程序進入等待。解碼完成後,通知分析視頻數據的程序繼續進行視頻數據分析,同時解碼程序又進入等待。兩個程序在執行和等待中交替進行。
(3) 多級緩衝機制。上面咱們也提到了幾個緩衝,總結以下。
①接收後存放數據的緩衝,因爲服務器端源源不斷的實時碼流,和採用了併發機制後帶來更大量的數據,咱們不可能立刻處理完,因此必須設置一個緩衝區。
②接收端和處理端之間的緩衝,因爲網絡不穩定,接收到的數據可能會有時快有時慢,這直接會形成解碼的不穩定和視頻播放的不連續,因此在此設置一個緩衝,起到一個平滑,過渡的做用,這個緩衝區既要存放接收到大量的碼流還要爲視頻數據分析提供數據,有個寫讀入和讀出的過程,因此咱們使用先入先出的隊列Queue容器來作緩衝區。
③解析和解碼過程之間的緩衝,因爲在此過程當中的數據量相較而言不是很大,而這個獲取數據的速度直接影響了解碼的速度,因此咱們要用一個高效的緩衝區來擔當此時的緩衝做用,因爲stack是由系統自動分配,因此速度比較快,因此咱們就在棧上分配一個數組用於存儲便可。
④解碼後到播放之間的緩衝,這個緩衝區一樣除了起到使播放視頻連續穩定的做用外,主要就是用來顯示圖像,還能夠對視頻圖像進行一些處理工做,平滑,濾波等。
3.解碼和播放的實現
H.264解碼是移植了ffmpeg 中的H.264解碼部分到Android,而且了深度刪減優化。界面部分,文件接收處理以及視頻顯示都是用java作的,底層的視頻解碼部分則使用C來作從而知足速度的要求。H.264碼流分割NAl(接受到視頻數據的復原工做)是在java層作而沒有分裝到c中,是由於每次送的數據會受到限制,若是送的數據量大,底層可能會一次解碼好幾幀視頻,可是到界面層只能顯示一幀,形成丟幀。若是每次送的數據量較少,就會使得屢次底層調用但並無進行實質解碼的現象發生,因此儘管這樣作耦合度差些,速度慢些,可是綜合考慮仍是將數據分析工做放在java層完成。

咱們將解碼後的視頻數據用bitmap顯示,draw到surfaceView的方法顯示到手機屏上,因爲有些手機不支持rgb24但幾乎全部手機都支持rgb565,因此解碼後返回的是rgb565數據。
4.程序流程功能架構
 
3、結束語
    本文完整的設計並實現了從pc端到android手機端的H.264視頻傳輸與解碼播放功能。詳細的分析了實現中的技術要點和難點,詳細分析了rtp打包,解包的流程,針對發送數據快而處理速度慢的問題,採用多線程併發機制予以解決,面對大量,並且不穩定的數據包,針對各個環節的特色,設置了多級緩衝。使得視頻播放更加流暢、平穩。對於分析和解碼的前後次序問題,採用線程協做的思想,利用消費者,生產者模式,保證了視頻數據的時序性。另外對於解碼部分,則利用現有解碼方法進行平臺移植,合理處理c層和java層的分工,並以實現了這個完整的功能。在網絡情況好的狀況下,android手機端視頻播放延時短,播放流暢,平穩。本文技術研究能夠運用到視頻播放的各個應用中,有着很強的實用價值。
http://blog.csdn.net/jwybobo2007/article/details/7235942
http://blog.sina.com.cn/s/blog_4ad7c2540101lep1.html
http://www.360doc.com/content/11/1018/13/1016783_157130105.shtml
http://blog.csdn.net/zjf82031913/article/details/7210106 講的很深刻!!!

(2)android

(3)數組

相關文章
相關標籤/搜索