Make rtc::TimestampWrapAroundHandler handle backwards wrapping

Also fix a timestamp issue in video analyzer test.

BUG=webrtc:5637, webrtc:5537

Review URL: https://codereview.webrtc.org/1779773002

Cr-Commit-Position: refs/heads/master@{#11938}
diff --git a/webrtc/base/timeutils.cc b/webrtc/base/timeutils.cc
index 24b04ee..b7803ae 100644
--- a/webrtc/base/timeutils.cc
+++ b/webrtc/base/timeutils.cc
@@ -193,17 +193,25 @@
 }
 
 TimestampWrapAroundHandler::TimestampWrapAroundHandler()
-    : last_ts_(0), num_wrap_(0) {}
+    : last_ts_(0), num_wrap_(-1) {}
 
 int64_t TimestampWrapAroundHandler::Unwrap(uint32_t ts) {
-  if (ts < last_ts_) {
-    if (last_ts_ > 0xf0000000 && ts < 0x0fffffff) {
-      ++num_wrap_;
-    }
+  if (num_wrap_ == -1) {
+    last_ts_ = ts;
+    num_wrap_ = 0;
+    return ts;
   }
+
+  if (ts < last_ts_) {
+    if (last_ts_ >= 0xf0000000 && ts < 0x0fffffff)
+      ++num_wrap_;
+  } else if ((ts - last_ts_) > 0xf0000000) {
+    // Backwards wrap. Unwrap with last wrap count and don't update last_ts_.
+    return ts + ((num_wrap_ - 1) << 32);
+  }
+
   last_ts_ = ts;
-  int64_t unwrapped_ts = ts + (num_wrap_ << 32);
-  return unwrapped_ts;
+  return ts + (num_wrap_ << 32);
 }
 
 int64_t TmToSeconds(const std::tm& tm) {
diff --git a/webrtc/base/timeutils_unittest.cc b/webrtc/base/timeutils_unittest.cc
index 688658b..7e342d0 100644
--- a/webrtc/base/timeutils_unittest.cc
+++ b/webrtc/base/timeutils_unittest.cc
@@ -153,18 +153,48 @@
 };
 
 TEST_F(TimestampWrapAroundHandlerTest, Unwrap) {
-  uint32_t ts = 0xfffffff2;
-  int64_t unwrapped_ts = ts;
-  EXPECT_EQ(ts, wraparound_handler_.Unwrap(ts));
+  // Start value.
+  int64_t ts = 2;
+  EXPECT_EQ(ts,
+            wraparound_handler_.Unwrap(static_cast<uint32_t>(ts & 0xffffffff)));
+
+  // Wrap backwards.
+  ts = -2;
+  EXPECT_EQ(ts,
+            wraparound_handler_.Unwrap(static_cast<uint32_t>(ts & 0xffffffff)));
+
+  // Forward to 2 again.
   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));
+  EXPECT_EQ(ts,
+            wraparound_handler_.Unwrap(static_cast<uint32_t>(ts & 0xffffffff)));
+
+  // Max positive skip ahead, until max value (0xffffffff).
+  for (uint32_t i = 0; i <= 0xf; ++i) {
+    ts = (i << 28) + 0x0fffffff;
+    EXPECT_EQ(
+        ts, wraparound_handler_.Unwrap(static_cast<uint32_t>(ts & 0xffffffff)));
+  }
+
+  // Wrap around.
+  ts += 2;
+  EXPECT_EQ(ts,
+            wraparound_handler_.Unwrap(static_cast<uint32_t>(ts & 0xffffffff)));
+
+  // Max wrap backward...
+  ts -= 0x0fffffff;
+  EXPECT_EQ(ts,
+            wraparound_handler_.Unwrap(static_cast<uint32_t>(ts & 0xffffffff)));
+
+  // ...and back again.
+  ts += 0x0fffffff;
+  EXPECT_EQ(ts,
+            wraparound_handler_.Unwrap(static_cast<uint32_t>(ts & 0xffffffff)));
+}
+
+TEST_F(TimestampWrapAroundHandlerTest, NoNegativeStart) {
+  int64_t ts = 0xfffffff0;
+  EXPECT_EQ(ts,
+            wraparound_handler_.Unwrap(static_cast<uint32_t>(ts & 0xffffffff)));
 }
 
 class TmToSeconds : public testing::Test {
diff --git a/webrtc/video/video_quality_test.cc b/webrtc/video/video_quality_test.cc
index e43ddb1..c882992 100644
--- a/webrtc/video/video_quality_test.cc
+++ b/webrtc/video/video_quality_test.cc
@@ -161,13 +161,13 @@
     bool result = transport_->SendRtp(packet, length, options);
     {
       rtc::CritScope lock(&crit_);
-      int64_t timestamp = wrap_handler_.Unwrap(header.timestamp);
 
       if (rtp_timestamp_delta_ == 0) {
-        rtp_timestamp_delta_ = timestamp - first_send_frame_.timestamp();
+        rtp_timestamp_delta_ = header.timestamp - first_send_frame_.timestamp();
         first_send_frame_.Reset();
       }
-      timestamp -= rtp_timestamp_delta_;
+      int64_t timestamp =
+          wrap_handler_.Unwrap(header.timestamp - rtp_timestamp_delta_);
       send_times_[timestamp] = current_time;
       if (!transport_->DiscardedLastPacket() &&
           header.ssrc == ssrc_to_analyze_) {