diff --git a/talk/base/timeutils.cc b/talk/base/timeutils.cc index fee85aa642..c4e84cc20d 100644 --- a/talk/base/timeutils.cc +++ b/talk/base/timeutils.cc @@ -203,4 +203,18 @@ int32 TimeDiff(uint32 later, uint32 earlier) { #endif } +TimestampWrapAroundHandler::TimestampWrapAroundHandler() + : last_ts_(0), num_wrap_(0) {} + +int64 TimestampWrapAroundHandler::Unwrap(uint32 ts) { + if (ts < last_ts_) { + if (last_ts_ > 0xf0000000 && ts < 0x0fffffff) { + ++num_wrap_; + } + } + last_ts_ = ts; + int64_t unwrapped_ts = ts + (num_wrap_ << 32); + return unwrapped_ts; +} + } // namespace talk_base diff --git a/talk/base/timeutils.h b/talk/base/timeutils.h index f13c3f2ef2..6de9df6714 100644 --- a/talk/base/timeutils.h +++ b/talk/base/timeutils.h @@ -97,6 +97,17 @@ inline int64 UnixTimestampNanosecsToNtpMillisecs(int64 unix_ts_ns) { return unix_ts_ns / kNumNanosecsPerMillisec + kJan1970AsNtpMillisecs; } +class TimestampWrapAroundHandler { + public: + TimestampWrapAroundHandler(); + + int64 Unwrap(uint32 ts); + + private: + uint32 last_ts_; + int64 num_wrap_; +}; + } // namespace talk_base #endif // TALK_BASE_TIMEUTILS_H_ diff --git a/talk/base/timeutils_unittest.cc b/talk/base/timeutils_unittest.cc index 0fc5eb19c8..a078abee2c 100644 --- a/talk/base/timeutils_unittest.cc +++ b/talk/base/timeutils_unittest.cc @@ -160,4 +160,27 @@ TEST(TimeTest, DISABLED_CurrentTmTime) { EXPECT_TRUE(0 <= microseconds && microseconds < 1000000); } +class TimestampWrapAroundHandlerTest : public testing::Test { + public: + TimestampWrapAroundHandlerTest() {} + + protected: + TimestampWrapAroundHandler wraparound_handler_; +}; + +TEST_F(TimestampWrapAroundHandlerTest, Unwrap) { + uint32 ts = 0xfffffff2; + int64 unwrapped_ts = ts; + EXPECT_EQ(ts, wraparound_handler_.Unwrap(ts)); + ts = 2; + unwrapped_ts += 0x10; + EXPECT_EQ(unwrapped_ts, wraparound_handler_.Unwrap(ts)); + ts = 0xfffffff2; + unwrapped_ts += 0xfffffff0; + EXPECT_EQ(unwrapped_ts, wraparound_handler_.Unwrap(ts)); + ts = 0; + unwrapped_ts += 0xe; + EXPECT_EQ(unwrapped_ts, wraparound_handler_.Unwrap(ts)); +} + } // namespace talk_base diff --git a/talk/media/webrtc/webrtcvideoengine.cc b/talk/media/webrtc/webrtcvideoengine.cc index d09edb57f0..0283f575da 100644 --- a/talk/media/webrtc/webrtcvideoengine.cc +++ b/talk/media/webrtc/webrtcvideoengine.cc @@ -180,8 +180,7 @@ class WebRtcRenderAdapter : public webrtc::ExternalRenderer { channel_id_(channel_id), width_(0), height_(0), - first_frame_arrived_(false), - capture_start_rtp_time_stamp_(0), + capture_start_rtp_time_stamp_(-1), capture_start_ntp_time_ms_(0) { } @@ -233,8 +232,7 @@ class WebRtcRenderAdapter : public webrtc::ExternalRenderer { int64_t render_time, void* handle) { talk_base::CritScope cs(&crit_); - if (!first_frame_arrived_) { - first_frame_arrived_ = true; + if (capture_start_rtp_time_stamp_ < 0) { capture_start_rtp_time_stamp_ = rtp_time_stamp; } @@ -242,9 +240,9 @@ class WebRtcRenderAdapter : public webrtc::ExternalRenderer { #ifdef USE_WEBRTC_DEV_BRANCH if (ntp_time_ms > 0) { - uint32 elapsed_time_ms = - (rtp_time_stamp - capture_start_rtp_time_stamp_) / - kVideoCodecClockratekHz; + int64 elapsed_time_ms = + (rtp_ts_wraparound_handler_.Unwrap(rtp_time_stamp) - + capture_start_rtp_time_stamp_) / kVideoCodecClockratekHz; capture_start_ntp_time_ms_ = ntp_time_ms - elapsed_time_ms; } #endif @@ -329,8 +327,8 @@ class WebRtcRenderAdapter : public webrtc::ExternalRenderer { unsigned int width_; unsigned int height_; talk_base::RateTracker frame_rate_tracker_; - bool first_frame_arrived_; - uint32 capture_start_rtp_time_stamp_; + talk_base::TimestampWrapAroundHandler rtp_ts_wraparound_handler_; + int64 capture_start_rtp_time_stamp_; int64 capture_start_ntp_time_ms_; };