Allow TimestampAligner to translate timestamp without new observation of system clock.

Bug: chromium:1054403
Change-Id: I32c622851fc0bed2c47ae142c743399acb91ae84
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/169924
Commit-Queue: Minyue Li <minyue@webrtc.org>
Reviewed-by: Karl Wiberg <kwiberg@webrtc.org>
Reviewed-by: Niels Moller <nisse@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#30744}
diff --git a/rtc_base/timestamp_aligner.cc b/rtc_base/timestamp_aligner.cc
index 8bbcdb5..c9f8f9d 100644
--- a/rtc_base/timestamp_aligner.cc
+++ b/rtc_base/timestamp_aligner.cc
@@ -23,15 +23,22 @@
     : frames_seen_(0),
       offset_us_(0),
       clip_bias_us_(0),
-      prev_translated_time_us_(std::numeric_limits<int64_t>::min()) {}
+      prev_translated_time_us_(std::numeric_limits<int64_t>::min()),
+      prev_time_offset_us_(0) {}
 
 TimestampAligner::~TimestampAligner() {}
 
 int64_t TimestampAligner::TranslateTimestamp(int64_t capturer_time_us,
                                              int64_t system_time_us) {
-  return ClipTimestamp(
+  const int64_t translated_timestamp = ClipTimestamp(
       capturer_time_us + UpdateOffset(capturer_time_us, system_time_us),
       system_time_us);
+  prev_time_offset_us_ = translated_timestamp - capturer_time_us;
+  return translated_timestamp;
+}
+
+int64_t TimestampAligner::TranslateTimestamp(int64_t capturer_time_us) const {
+  return capturer_time_us + prev_time_offset_us_;
 }
 
 int64_t TimestampAligner::UpdateOffset(int64_t capturer_time_us,
diff --git a/rtc_base/timestamp_aligner.h b/rtc_base/timestamp_aligner.h
index 48023ab..da45aa6 100644
--- a/rtc_base/timestamp_aligner.h
+++ b/rtc_base/timestamp_aligner.h
@@ -45,6 +45,11 @@
   // translated timestamp.
   int64_t TranslateTimestamp(int64_t capturer_time_us, int64_t system_time_us);
 
+  // Returns the translated timestamp without updating the states. This is to
+  // allow TimestampAligner to translate capturer time into system clock based
+  // on earlier observations. It won't guarantee monotonicity.
+  int64_t TranslateTimestamp(int64_t capturer_time_us) const;
+
  protected:
   // Update the estimated offset between capturer's time and system monotonic
   // time.
@@ -69,6 +74,9 @@
   int64_t clip_bias_us_;
   // Used to ensure that translated timestamps are monotonous.
   int64_t prev_translated_time_us_;
+  // Offset between |prev_translated_time_us_| and the corresponding capturer
+  // time.
+  int64_t prev_time_offset_us_;
   RTC_DISALLOW_COPY_AND_ASSIGN(TimestampAligner);
 };
 
diff --git a/rtc_base/timestamp_aligner_unittest.cc b/rtc_base/timestamp_aligner_unittest.cc
index 17d9e06..df6207a 100644
--- a/rtc_base/timestamp_aligner_unittest.cc
+++ b/rtc_base/timestamp_aligner_unittest.cc
@@ -152,27 +152,27 @@
   // {0, c1, c1 + c2}, we exhibit non-monotonous behaviour if and only
   // if c1 > s1 + 2 s2 + 4 c2.
   const int kNumSamples = 3;
-  const int64_t camera_time_us[kNumSamples] = {0, 80000, 90001};
-  const int64_t system_time_us[kNumSamples] = {0, 10000, 20000};
+  const int64_t kCaptureTimeUs[kNumSamples] = {0, 80000, 90001};
+  const int64_t kSystemTimeUs[kNumSamples] = {0, 10000, 20000};
   const int64_t expected_offset_us[kNumSamples] = {0, -35000, -46667};
 
   // Non-monotonic translated timestamps can happen when only for
   // translated timestamps in the future. Which is tolerated if
   // |timestamp_aligner.clip_bias_us| is large enough. Instead of
   // changing that private member for this test, just add the bias to
-  // |system_time_us| when calling ClipTimestamp.
+  // |kSystemTimeUs| when calling ClipTimestamp.
   const int64_t kClipBiasUs = 100000;
 
   bool did_clip = false;
   int64_t prev_timestamp_us = std::numeric_limits<int64_t>::min();
   for (int i = 0; i < kNumSamples; i++) {
     int64_t offset_us =
-        timestamp_aligner.UpdateOffset(camera_time_us[i], system_time_us[i]);
+        timestamp_aligner.UpdateOffset(kCaptureTimeUs[i], kSystemTimeUs[i]);
     EXPECT_EQ(offset_us, expected_offset_us[i]);
 
-    int64_t translated_timestamp_us = camera_time_us[i] + offset_us;
+    int64_t translated_timestamp_us = kCaptureTimeUs[i] + offset_us;
     int64_t clip_timestamp_us = timestamp_aligner.ClipTimestamp(
-        translated_timestamp_us, system_time_us[i] + kClipBiasUs);
+        translated_timestamp_us, kSystemTimeUs[i] + kClipBiasUs);
     if (translated_timestamp_us <= prev_timestamp_us) {
       did_clip = true;
       EXPECT_EQ(clip_timestamp_us,
@@ -186,4 +186,22 @@
   EXPECT_TRUE(did_clip);
 }
 
+TEST(TimestampAlignerTest, TranslateTimestampWithoutStateUpdate) {
+  TimestampAligner timestamp_aligner;
+
+  constexpr int kNumSamples = 4;
+  constexpr int64_t kCaptureTimeUs[kNumSamples] = {0, 80000, 90001, 100000};
+  constexpr int64_t kSystemTimeUs[kNumSamples] = {0, 10000, 20000, 30000};
+  constexpr int64_t kQueryCaptureTimeOffsetUs[kNumSamples] = {0, 123, -321,
+                                                              345};
+
+  for (int i = 0; i < kNumSamples; i++) {
+    int64_t reference_timestamp = timestamp_aligner.TranslateTimestamp(
+        kCaptureTimeUs[i], kSystemTimeUs[i]);
+    EXPECT_EQ(reference_timestamp - kQueryCaptureTimeOffsetUs[i],
+              timestamp_aligner.TranslateTimestamp(
+                  kCaptureTimeUs[i] - kQueryCaptureTimeOffsetUs[i]));
+  }
+}
+
 }  // namespace rtc