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
也就是是说有3个时间轴,音频时间轴,视频时间轴,ntp时间轴。
音视频的时间轴的单位都是各自的采样率,需要除以采样率才能取得单位为秒的时间单位。
有两个rtcp流,分别为音/视频的,其中有一个当前的音频的timestamp和一个ntp的timestamp。这两个值是在不同轴上的相同时间点,即音/视频轴和ntp轴的重合点。使用这个值可以使音视频轴同步。
当拿到音频NTP时间(Tan),音频RTP时间(Tar),视频NTP时间(Tvn),视频RTP时间(Tvr),就可以计算音视频时间轴的差距D:
假设使用音频为主轴,视频向音频对齐。D = (Tar-Tvr) - (Tan - Tvn);
新的视频时间戳为Tar = Tar + D;
在rtcp的sr单元中有32位的MSW和32位的LSW。MSW的单位为妙,而LSW的单位为232 picoseconds。1皮秒为1/10^12秒。LSW转为us的公式为(LSW*10^12/2^32)/1000000;
time_t lt;
lt = MSW;
lt -= JAN_1970;(0x83aa7e80 )
char* tmpTimeString = ctime(<);
记得两年前刚开始做RTP/RTCP的时候碰到一个问题,是关于如何计算RTCP中的NTP时间戳,最近又有人问这个问题,于是就想把它贴出来,让大家参考,提提建议,交流促进进步。
记得当时有个客户说用openRTSP(open source ,you can get it from
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就可以了:
uint64_t NTPtime64 (void)
{
#if defined (CLOCK_REALTIME)
#else
#endif
// ntp的低32位, 单位为u = 10^12 / (2^32) 皮秒
// 假设其低32位为x, 在这个x表示的时间为 x * u 皮秒
// 那么对于t纳秒, 我们有
// t * (10^3) = x * u
// => x = t * (10^3) / u = t * (2 ^ 32) / (10^9)
// 即上面的计算。
}