NTP和RTP时间戳

来源:互联网 发布:电子商城源码 编辑:程序博客网 时间:2024/05/16 23:49

时间戳

关于时间戳的解释来自wiki:时间戳(英语:Timestamp)是指字符串或编码信息用于辨识记录下来的时间日期
它并没有规定时间戳的单位,所以我们在讨论时间戳的时候要记得把单位加上,要不别人并不知道你说什么。在音视频领域常用的时间戳单位有毫秒(Milliseconds)/微秒(Microseconds)/纳秒(Nanoseconds)。

  • 时间单位之间的关系
static const int64_t kNumMillisecsPerSec = INT64_C(1000);static const int64_t kNumMicrosecsPerSec = INT64_C(1000000);static const int64_t kNumNanosecsPerSec  = INT64_C(1000000000);
  • 获取时间的函数
函数 说明 返回 time time 函数获得从 1970 年 1 月 1 日 0 点到当前的秒数(time_t) tv_sec(秒) gettimeofday gettimeofday 函数返回从 1970 年 1 月 1 日 0 点以来,到现在的时间(timeval) tv_sec(秒)和tv_usec(微秒) clock_gettime clock_gettime 函数返回从 1970 年 1 月 1 日 0 点以来,到现在的时间(timespec) tv_sec(秒)和tv_nsec(纳秒)

几个函数的区别在于获取时间的精度不同

  • clock id
id 说明 CLOCK_REALTIME 墙上真实时间(系统显示时间),用户可以任意修改 CLOCK_MONOTONIC 单调递增的时间,不受墙上时间影响

clock_gettime可以指定获取的时间类型(id),gettimeofday获取的是墙上时间(CLOCK_REALTIME)。

RTP时间戳

所谓的RTP时间戳就是RTP包头中存放的那个时间戳,单位是毫秒。RTP时间戳必须是一个单调递增的时间戳,因为它用于表示数据的采集时间,所以不能受系统时间的影响。在WebRTC中采集和编码使用的时间戳单位都是毫秒,并且只取低32位。

  • WebRTC中RTP时间戳的获取
    主要提供了TimeInMillisecondsTimeInMicroseconds两个函数获取毫秒和微妙时间戳,通过代码可以知道它是获取当前一个单调递增的时间。
int64_t TimeInMilliseconds() const override {    return rtc::TimeMillis();}int64_t TimeInMicroseconds() const override {    return rtc::TimeMicros();}int64_t TimeMillis() {    return TimeNanos() / kNumNanosecsPerMillisec;}int64_t TimeMicros() {    return TimeNanos() / kNumNanosecsPerMicrosec;}int64_t TimeNanos() {    if (g_clock) {        return g_clock->TimeNanos();    }    return SystemTimeNanos();}int64_t SystemTimeNanos() {    int64_t ticks;    struct timespec ts;    clock_gettime(CLOCK_MONOTONIC, &ts);    ticks = kNumNanosecsPerSec * static_cast<int64_t>(ts.tv_sec) +        static_cast<int64_t>(ts.tv_nsec);    return ticks;}

NTP时间戳

NTP是Network Time Protocol的简称,在rfc3550#section-4中有详细的解释。它用于表示从格林时间(UTC)1900年1月1日以来的秒数。通常它用一个uint64_t表示(SR包中的SenderInfo部分的NTP时间戳就是用64位表示),分为整数部分(前32位表示妙)和小数部分(后32位表示1/0x100000000秒{=(0x1 << 32)=(2^32)})。在一些更紧凑的领域(SR和RR中的ReportBlobck中的LSR和DLSR就是使用32位表示)使用32位表示NTP时间戳,前16位表示整数部分,后16位表示小数部分。WebRTC中RTT的计算方式就是用当前接收时刻的NTP时间戳 - 上一次发送的NTP时间戳 - 处理时间戳,这部分可以看HandleReportBlock函数。

  • NtpTime
    NtpTime是WebRTC中一个用来表示NTP时间戳的类,从构造函数可以知道NTP时间戳的组成和上面的说法是吻合的。ToMs是一个NTP时间戳转换为普通时间戳(单位是毫秒)的方式。
static constexpr uint64_t kFractionsPerSecond = 0x100000000;NtpTime(uint32_t seconds, uint32_t fractions)    : value_(seconds * kFractionsPerSecond + fractions) {}int64_t ToMs() const {    static constexpr double kNtpFracPerMs = 4.294967296E6;  // 2^32 / 1000.    const double frac_ms = static_cast<double>(fractions()) / kNtpFracPerMs;    return 1000 * static_cast<int64_t>(seconds()) +        static_cast<int64_t>(frac_ms + 0.5);}
  • WebRTC中NTP时间戳的获取
    1. 获取当前时间戳,这个是系统相关的,posix的通过gettimeofday获取
    2. 把获取后的时间戳加上1970到1900之间间隔的时间(kNtpJan1970),再转换为NTP的格式(前32位表示秒,后32位表示1/2^32秒);kNtpJan1970的值等于(1900到1970经过的秒数);kMagicNtpFractionalUnit等于2^32
// January 1970, in NTP seconds.const uint32_t kNtpJan1970 = 2208988800UL;// Magic NTP fractional unit.const double kMagicNtpFractionalUnit = 4.294967296E+9;NtpTime CurrentNtpTime() const override {    timeval tv = CurrentTimeVal();    double microseconds_in_seconds;    uint32_t seconds;    Adjust(tv, &seconds, &microseconds_in_seconds);    uint32_t fractions = static_cast<uint32_t>(            microseconds_in_seconds * kMagicNtpFractionalUnit + 0.5);    return NtpTime(seconds, fractions);}timeval CurrentTimeVal() const override {    struct timeval tv;    struct timezone tz;    tz.tz_minuteswest = 0;    tz.tz_dsttime = 0;    gettimeofday(&tv, &tz);    return tv;}static void Adjust(const timeval& tv, uint32_t* adjusted_s,        double* adjusted_us_in_s) {    *adjusted_s = tv.tv_sec + kNtpJan1970;    *adjusted_us_in_s = tv.tv_usec / 1e6;    if (*adjusted_us_in_s >= 1) {        *adjusted_us_in_s -= 1;        ++*adjusted_s;    } else if (*adjusted_us_in_s < -1) {        *adjusted_us_in_s += 1;        --*adjusted_s;    }}
  • NTP转RTP
    以下是WebRTC中NTP时间戳转RTP时间戳的函数,函数很容易看懂,但是我并没有找到转换的依据(算法的依据)。传入的参数有ntp和freq,其中ntp在前面有介绍,freq的值是根据编码类型而定的,一般来说视频都是90kHz,详情可以看RTP Payload Format media types
// Converts NTP timestamp to RTP timestamp.inline uint32_t NtpToRtp(NtpTime ntp, uint32_t freq) {  uint32_t tmp = (static_cast<uint64_t>(ntp.fractions()) * freq) >> 32;  return ntp.seconds() * freq + tmp;}
  • RTP扩展中的绝对发送时间(abs-send-time)
    WebRTC官网有介绍abs-send-time,它的计算方式是abs_send_time_24 = (ntp_timestamp_64 » 14) & 0x00ffffff,关于它的格式如下:
//  0                   1                   2                   3//  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+// |  ID   | len=2 |              absolute send time               |// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
原创粉丝点击