前言
RTP timestamp是用时钟频率(clock rate)计算而来表示时间的。
RTP timestamp表示每帧的时间,由于一个帧(如I帧)可能被分成多个RTP包,所以多个相同帧的RTP timestamp相等。(可以通过每帧最后一个RTP的marker标志区别帧,但最可靠的方法是查看相同RTP timestamp包为同一帧。)
RTP包头的第2个32Bit即为RTP包的时间戳,Time Stamp ,占32位。
时间戳反映了RTP分组中的数据的第一个字节的采样时刻。在一次会话开始时的时间戳初值也是随机选择的。即使是没有信号发送时,时间戳的数值也要随时间不断的增加。接收端使用时间戳可准确知道应当在什么时间还原哪一个数据块,从而消除传输中的抖动。时间戳还可用来使视频应用中声音和图像同步。
在RTP协议中并没有规定时间戳的粒度,这取决于有效载荷的类型。因此RTP的时间戳又称为媒体时间戳,以强调这种时间戳的粒度取决于信号的类型。例如,对于8kHz采样的话音信号,若每隔20ms构成一个数据块,则一个数据块中包含有160个样本(0.02×8000=160)。因此每发送一个RTP分组,其时间戳的值就增加160。
概念分析
采样率
采样率就是每秒钟抽取图像或声波幅度样本的次数。比如音频采样率8k,表示1秒有8000次采样,视频很少提及采样率这个概念。
帧率
帧率就是每秒显示帧数。比如30fps标识1秒显示30帧图像,音频没有帧率但可以算出帧率:采样率/1024。
时间戳单位
时间戳计算的单位不为秒之类的单位,而是由采样频率所代替的单位,这样做的目的就是为了是时间戳单位更为精准。比如说一个音频的采样频率为8000HZ,那么我们可以把时间戳单位设为1/8000。
时间戳增量
相邻两个RTP包之间的时间差(以时间戳单位为基准)。
视频时间戳分析
视频帧率是25(FPS),采样率是90KHZ(视频很少使用采样率这个概念每秒钟抽取图像样本的次数)。
两视频帧的间隔为:1 秒/ 25帧 = 0.04(帧/秒) = 40(毫帧/秒)
时间戳增量单位:1/90000(秒/个) ,特别注意RTP时间戳是有单位的
每帧对应的采样: 90000 / 25 = 3600 (个/帧)
对应关系如下:
时间 | 符号 | 个数 |
---|---|---|
1(秒) | 等于 | 90000(个) |
40(毫秒) | 等于 | 3600(个) |
1(毫秒) | 等于 | 90(个) |
视频时间戳计算公式:时间戳增量 = 两个RTP包时间差(毫秒)* 90000(采样率) / 1000
- 采样率和帧率不是相等的概念
- 一帧应该是对应多少次的采集;比如视频25帧,采样率是90KHZ,那么1帧就3600次的采集(90000 / 25 = 3600 (个/帧))
相邻帧间RTP timestamp增量值
两帧之间RTP timestamp的增量 = 时钟频率 / 帧率。
前一帧的timestamp加上固定的timestamp的增量就是下一帧。
举例:
其中时钟频率可从SDP中获取,如:
m=video 2834 RTP/AVP 96
a=rtpmap:96 H264/90000
其时钟频率为90000(通常视频的时钟频率),若视频帧率为25fps,则相邻帧间RTP timestamp增量值 = 90000/25 = 3600。
原文链接:https://blog.csdn.net/qq_28258885/article/details/119675555
音频时间戳分析
采样率是48K为例子,
时间戳增量单位:1/48000(秒/个) ,特别注意RTP时间戳是有单位的
对应关系如下:
时间 | 符号 | 个数 |
---|---|---|
1(秒) | 等于 | 48000(个) |
1(毫秒) | 等于 | 48(个) |
音频时间戳计算公式:时间戳增量 = 两个RTP包时间差(毫秒)* 48000(采样率) / 1000
音频时间戳的单位就是采样率的倒数,例如采样率48000,那么1秒就有48000个采样,每个采样1/48ms,每个采样对应一个时间戳。RTP音频包一般打包20ms的数据,对应的采样数为 48000 * 20 / 1000 = 960,也就是说每个音频包里携带960个音频采样,因为1个采样对应1个时间戳,那么相邻两个音频RTP包的时间戳之差就是960。
时间戳增量伪代码
//视频时间戳增量
private uint GetVideoTimestamp(MediaFrame mediaFrame)
{
if (视频时间戳== 0)
{
视频时间戳 = mediaFrame.采集时间戳;
return 0;
}
else
{
var step = mediaFrame.采集时间戳 - 视频时间戳;
视频时间戳 = mediaFrame.采集时间戳;
return step * 90000 / 1000;
}
}
//音频时间戳增量
private uint GetAudioTimestamp(MediaFrame mediaFrame)
{
if (音频时间戳== 0)
{
_timestampAudio = mediaFrame.采集时间戳;
return 0;
}
else
{
var step = mediaFrame.采集时间戳 - 音频时间戳;
音频时间戳 = mediaFrame.采集时间戳;
return step * 采样率 / 1000; //采样率可以从ADTS Header中算出来
}
}