天天看點

(轉)談談RTP傳輸中的負載類型和時間戳

原創作品,允許轉載,轉載時請務必以超連結形式标明文章  原始出處  、作者資訊和本聲明。否則将追究法律責任。 http://ticktick.blog.51cto.com/823160/350142

    最近被RTP的負載類型和時間戳搞郁悶了,一個問題調試了近一周,終于圓滿解決,回頭看看,發現其實主要原因還是自己沒有真正地搞清楚RTP協定中負載類型和時間戳的含義。雖然做RTP傳輸,有着Jrtplib和Ortp這兩個強大的庫支援,一個是c++接口,一個是c語言接口,各有各的特點,各有各的應用環境,但是僅僅有庫就能解決一切問題嗎?可能仿照着一些例子程式,你能夠完成主要的功能,但一旦問題發生了,不清楚原理你是很難定位和解決問題的,是以在此,用我的經驗勸勸大家,磨刀不誤砍柴工,做應用還是先把原理搞清楚再動手吧……

    看這篇文章之前,首先你應該知道什麼是RTP協定,可以去看RTP協定原文(RFC3550協定),也可以看一些網友對RTP協定的講解的文章,很多,這裡我提供一篇我個人覺得寫得還不錯的:http://blog.csdn.net/bripengandre/archive/2008/04/01/2238818.aspx 。

   好,下面言歸正傳,首先談談RTP傳輸中的負載類型吧。

    首先,看RTP協定標頭的格式:

(轉)談談RTP傳輸中的負載類型和時間戳

    10~16 Bit為PT域,指的就是負載類型(PayLoad),負載類型定義了RTP負載的格式,協定原文說該域由具體應用決定其解釋。

    目前,負載類型主要用來告訴接收端(或者播放器)傳輸的是哪種類型的媒體(例如G.729,H.264,MPEG-4等),這樣接收端(或者播放器)才知道了資料流的格式,才會調用适當的編解碼器去解碼或者播放,這就是負載類型的主要作用。

    就ORTP庫(本文用的是ortp-0.9.1)而言,負載類型定義如下:

(轉)談談RTP傳輸中的負載類型和時間戳

    每一種負載類型都有着其獨特的參數,這裡基本上涵蓋了目前主流的一些媒體類型,例如pcmu 、g.729、h.263(很奇怪,竟然沒有定義h.264,注:新版本已經添加了對h.264的支援)、mpeg-4等等。Jrtplib庫應該也有相類似的定義,你可以去找找源碼,在此我就不再贅述了。

    在ORTP庫和JRTplib庫中,都提供了設定RTP負載類型的函數,千萬要記得根據實際的應用進行設定,我就是當時沒有注意,使用ORTP預設的pcmu音頻的負載類型,傳輸H.264編碼的視訊資料,結果傳輸中一直有問題,困擾我好久好久。

    好了,再說說RTP的時間戳吧。

    首先,了解幾個基本概念:

    時間戳機關:時間戳計算的機關不是秒之類的機關,而是由采樣頻率所代替的機關,這樣做的目的就是為了是時間戳機關更為精準。比如說一個音頻的采樣頻率為8000Hz,那麼我們可以把時間戳機關設為1 / 8000。

    時間戳增量:相鄰兩個RTP包之間的時間差(以時間戳機關為基準)。

    采樣頻率:  每秒鐘抽取樣本的次數,例如音頻的采樣率一般為8000Hz

    幀率:      每秒傳輸或者顯示幀數,例如25f/s

    再看看RTP時間戳課本中的定義:

    RTP標頭的第2個32Bit即為RTP包的時間戳,Time Stamp ,占32位。

    時間戳反映了RTP分組中的資料的第一個位元組的采樣時刻。在一次會話開始時的時間戳初值也是随機選擇的。即使是沒有信号發送時,時間戳的數值也要随時間不斷的增加。接收端使用時間戳可準确知道應當在什麼時間還原哪一個資料塊,進而消除傳輸中的抖動。時間戳還可用來使視訊應用中聲音和圖像同步。

    在RTP協定中并沒有規定時間戳的粒度,這取決于有效載荷的類型。是以RTP的時間戳又稱為媒體時間戳,以強調這種時間戳的粒度取決于信号的類型。例如,對于8kHz采樣的話音信号,若每隔20ms構成一個資料塊,則一個資料塊中包含有160個樣本(0.02×8000=160)。是以每發送一個RTP分組,其時間戳的值就增加160。

    官方的解釋看懂沒?沒看懂?沒關系,我剛開始也沒看懂,那就聽我的解釋吧。

    首先,時間戳就是一個值,用來反映某個資料塊的産生(采集)時間點的,後采集的資料塊的時間戳肯定是大于先采集的資料塊的。有了這樣一個時間戳,就可以标記資料塊的先後順序。

    第二,在實時流傳輸中,資料采集後立刻傳遞到RTP子產品進行發送,那麼,其實,資料塊的采集時間戳就直接作為RTP包的時間戳。

    第三,如果用RTP來傳輸固定的檔案,則這個時間戳就是讀檔案的時間點,依次遞增。這個不再我們目前的讨論範圍内,暫時不考慮。

    第四,時間戳的機關采用的是采樣頻率的倒數,例如采樣頻率為8000Hz時,時間戳的機關為1 / 8000 ,在Jrtplib庫中,有設定時間戳機關的函數接口,而ORTP庫中根據負載類型直接給定了時間戳的機關(音頻負載1/8000,視訊負載1/90000)

    第五,時間戳增量是指兩個RTP包之間的時間間隔,詳細點說,就是發送第二個RTP包相距發送第一個RTP包時的時間間隔(機關是時間戳機關)。

    如果采樣頻率為90000Hz,則由上面讨論可知,時間戳機關為1/90000,我們就假設1s鐘被劃分了90000個時間塊,那麼,如果每秒發送25幀,那麼,每一個幀的發送占多少個時間塊呢?當然是 90000/25 = 3600。是以,我們根據定義“時間戳增量是發送第二個RTP包相距發送第一個RTP包時的時間間隔”,故時間戳增量應該為3600。

      【補充】:最近思考了一下,又有了新的體會和解釋,可能對大家更容易地去了解這個時間戳增量會有所幫助,補充在下面吧:

       其實,網絡發送重點關注的是流量的平衡,即均勻地利用網絡帶寬,為了實作這一點,需要滿足:資料采集的速率與資料網絡傳輸的速率盡量保持一緻。時間戳增量的設定影響的是RTP包的網絡傳輸的速率,時間戳增量越小,發送速度越快。

      下面再進一步解釋一下時間戳增量是怎麼計算出來的:

      對于PAL制式的視訊而言,每秒攝像頭會采集 25 幀 資料,那麼,每采集到 1幀 耗時 1/25 s ,如果我們設計為1個RTP包隻包含1幀資料,并且一次發送1幀,那麼,要想網絡流量均勻,則時間戳增量應該設計為 1/25 s .  而在一般的RTP協定的實作中,時間戳機關不是 秒(s),而約定為采樣頻率的倒數,由于一般視訊的采樣頻率是 90000,故時間戳機關為 1/90000 s,是以,實際的時間戳增量 = 時間戳增量 ( 1/25 s ) / 時間戳機關(1/90000 s) = 3600  

    在Jrtplib中好像不需要自己管理時間戳的遞增,由庫内部管理。但在ORTP中每次資料的發送都需要自己傳入時間戳的值,即自己需要每次發完一個RTP包後,累加時間戳增量,不是很友善,這就需要自己對RTP的時間戳有比較深刻地了解,我剛開始就是因為沒搞清楚,随時設定時間戳增量導緻傳輸一直有問題,困擾我好久。

    好了,關于RTP的負載類型和時間戳的介紹就到這裡了,這次通過解決RTP傳輸中的問題學到了不少知識,在此分享希望對大家有用。有說得不正确的地方歡迎高手指教,也可以來信交流:[email protected]