http://www.rosoo.net/a/201101/10776.html
http://hi.baidu.com/fairygardenjoy/blog/item/e56c5cca95829e37b600c88e.html
H264關于RTP協議的實現:http://www.rosoo.net/a/201108/14896.html
RTP協議包頭的格式:
10~16 Bit為PT域,指的就是負載類型(PayLoad),負載類型定義了RTP負載的格式,協議原文說該域由具體應用決定其解釋。
目前,負載類型主要用來告訴接收端(或者播放器)傳輸的是哪種類型的媒體(例如G.729,H.264,MPEG-4等),這樣接收端(或者播放器)才知道了數據流的格式,才會調用適當的編解碼器去解碼或者播放,這就是負載類型的主要作用。
就ORTP庫而言,負載類型定義如下:
?
每一種負載類型都有著其獨特的參數,這里基本上涵蓋了當前主流的一些媒體類型,例如pcmu 、g.729、h.263(很奇怪,竟然沒有定義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。
在Jrtplib中好像不需要自己管理時間戳的遞增,由庫內部管理。但在ORTP中每次數據的發送都需要自己傳入時間戳的值,即自己需要每次發完一個RTP包后,累加時間戳增量,不是很方便,這就需要自己對RTP的時間戳有比較深刻地理解,我剛開始就是因為沒搞清楚,隨時設置時間戳增量導致傳輸一直有問題,困擾我好久。
?
===========================================================================
?
在使用JRTPLIB的發送數據的時候需要設置時間戳單位(timestamp)和時間戳增量(timestampincrement)。看了網上一些文章,細細想來現在才想通這個問題。???
????????? RFC3550對時間戳的描述是:
??????? 時間戳(timestamp) 32比特 時間戳反映了RTP數據包中第一個字節的采樣時間。(采樣時鐘必須來源于一個及時的單調、線性遞增時鐘,以便允許同步和去除網絡引起的數據包抖動(見章節6.4.1)。該時鐘的分辨率必須滿足理想的同步精度和測量數據包到來時的抖動的需要(一種典型的時鐘分辨率不滿足情況是每個視頻幀僅一個時鐘周期)時鐘頻率依賴于負載數據的格式,并在描述文件(profile)中或者是在負載格式描述中(payload format speci_cation)進行靜態描述。也可以通過非RTP方法(non-RTP means)對負載格式動態描述。
?????? 如果RTP包是周期性產生的,那么將使用由采樣時鐘決定的名義上的采樣時刻,而不是讀取系統時間。例如,對一個固定速率的音頻,采樣時鐘(時間戳時鐘)將在每個周期內增加1。如果一個音頻從輸入設備中讀取含有160個采樣周期的塊,那么對每個塊,時間戳的值增加160,而不考慮該塊是否用一個包傳遞或是被丟棄。
??????? 時間戳的初始值應當是隨機的,就像序號一樣。幾個連續的RTP包如果(邏輯上)是同時產生的,如:屬于同一個視頻幀的RTP包,將有相同的序列號。如果數據并不是以它采樣的順序進行傳輸,那么連續的RTP包可以包含不是單調遞增(或遞減)的時間戳(RTP包的序列號仍然是單調變化的)。
??
根據一些文章我自己推敲了一下幾個概念如下:???
?????? 時間戳單位:時間戳計算的單位不為秒之類的單位,而是由采樣頻率所代替的單位,這樣做的目的就是為了是時間戳單位更為精準。比如說一個音頻的采樣頻率為8000HZ,那么我們可以把時間戳單位設為1/8000。
?????? 時間戳增量:相鄰兩個RTP包之間的時間差(以時間戳單位為基準)。
?????? 如何設定時間戳之間的增量呢?
?????? 按照剛才時間戳單位來看,1秒鐘按照時間戳單位就是8000,那么一秒鐘如果可以播放20幀,也就是發送30幀(幀率),那么可以求出相鄰兩幀之間的時間差,也就是時間戳增量,那么顯而易見是用8000/20,那么這個時間戳增量就為400.
?????? 網上大多數列舉的一個例子是:例如MPEG,每幀20ms,采樣頻率8000Hz,設定時間戳單位1/8000,而每個包之間就是160的增量
????這里又該如何理解呢?可以輕易地看出增量是直接8000與20ms相乘的結果,我們可以知道這里兩幀之間的時間為20ms,也就是0.02s,這個單位是以秒來衡量的,那么我們要用時間戳單位來表示那么就是8000*0.02=160.所以時間戳增量為160.
??????? 還有一點為什么一般都用90000作為視頻采樣頻率呢?
??????? 90k是用于視頻同步的時間尺度(TimeScale),就是每秒90k個時鐘tick。為什么采用90k呢?目前視頻的幀速率主要有25fps、29.97fps、30fps等,而90k剛好是它們的倍數,所以就采用了90k。