RTP支持傳送不同codec的steaming,不同codec的clock rate的也不一樣,不同的media之間需要依靠RTCP進行同步。這裏簡單介紹一下他們的機制。
在每個RTCP SR包中對應有一個RTP時間和一個NTP時間,它表達的意思很明確,那就是這個RTP時間對應的絕對時間, 不同media的RTP時間儘管不同,但可以通過NTP時間映射到同一個時間軸上,從而實現同步。
如下圖所示,RTP session 1 send H264 使用90,000HZ,而RTP session 2 send G.711 使用8,000HZ:
記得兩年前剛開始做RTP/RTCP的時候碰到一個問題,是關於如何計算RTCP中的NTP時間戳,最近又有人問這個問題,於是就想把它貼出來,讓大家參考,提提建議,交流促進進步。
記得當時有個客戶說用openRTSP(open source ,you can get it from www.live555.com)無法錄製我們送出去的RTP流,於是我也去下了一個,試了發現果然不行,於是就把openRTSP的source code撈出來看看,最後發現它必須要收到RTCP包後纔開始錄製視頻,於是我就加了RTCP,結果發現視頻錄製是沒問題,但用VLC播放的時候老是抖動,於是回後去找原因,一個排下來,最後focus到NTP時間戳上來了。
NTP的時間戳有MSW和LSW組成, MSW好算,以秒爲單位,LSW就頭痛了,查了RTP的文檔,講得很模糊,NTP(RFC1305)中只講單位大約是200 picoseconds,但我試了用200 picoseconds爲單位不行,還是閃。
沒辦法了,之後去研究Darwin Streaming Server,看看人家是怎麼做了,抓了包,找了好幾個RTCP的點,畫了個數軸,因爲抓包工具wireshark會顯示NTP時間(如下圖),於是我就倒過去算,最後算出來單位大約是232 picoseconds, 把這個值代入到我的source code中,果然不閃了。
問題雖然解決了,但心裏一直有個結,就是一直不知道232這個值是怎麼來的,糾結啊。 只好回去再看RFC1305, 它只說單位大約是200 picoseconds, 而1 second = 1,000,000,000,000 picoseconds, 這個值貌似有點大啊,而232=4294967296,很明顯用32bits無法精確到1 picoseconds, 於是我就想到不能精確到1 picoseconds, 那也應該盡力而爲之吧,於是自然就有了把1,000,000,000,000 picoseconds劈成232份:
1,000,000,000,000/4294967296 = 232.83064365386962890625
That's it!!
現在想想其實有更快捷的方法,直接看VLC的source code就可以了:
/**
* @return NTP 64-bits timestamp in host byte order.
*/
uint64_t NTPtime64 (void)
{
struct timespec ts;
#if defined (CLOCK_REALTIME)
clock_gettime (CLOCK_REALTIME, &ts);
#else
{
struct timeval tv;
gettimeofday (&tv, NULL);
ts.tv_sec = tv.tv_sec;
ts.tv_nsec = tv.tv_usec * 1000;
}
#endif
/* Convert nanoseconds to 32-bits fraction (232 picosecond units) */
uint64_t t = (uint64_t)(ts.tv_nsec) << 32;
t /= 1000000000;
/* There is 70 years (incl. 17 leap ones) offset to the Unix Epoch.
* No leap seconds during that period since they were not invented yet.
*/
assert (t < 0x100000000);
t |= ((70LL * 365 + 17) * 24 * 60 * 60 + ts.tv_sec) << 32;
return t;
}