NTP和RTP时间戳

时间戳

关于时间戳的解释来自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(ts.tv_sec) +
        static_cast(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(seconds()) +
        static_cast(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, µseconds_in_seconds);
    uint32_t fractions = static_cast(
            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(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               |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

你可能感兴趣的:(媒体)