Fix video renderer slowdown by wrong RenderTime

This commit fixes the issue of video playback in slow motion caused by VCMTiming being unable to provide the correct rendering time in
 scenarios of continuous network packet loss

WANT_LGTM=mbonadei

Bug: webrtc:376183208
Change-Id: I63617068506e536c4b812215ea084eec18e8ee06
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/367000
Reviewed-by: Rasmus Brandt <brandtr@webrtc.org>
Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org>
Commit-Queue: Ilya Nikolaevskiy <ilnik@webrtc.org>
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#43392}
diff --git a/AUTHORS b/AUTHORS
index 716a9c3..9424a61 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -125,6 +125,7 @@
 Shaofan Qi <vshaqi@gmail.com>
 Shigemasa Watanabe <shigemasa7watanabe@gmail.com>
 Shuhai Peng <shuhai.peng@intel.com>
+Shunbo Li <lishunbo@agora.io>
 Shunbo Li <lishunbo@shengwang.cn>
 Seija <doremylover123@gmail.com>
 Silviu Caragea <silviu.cpp@gmail.com>
diff --git a/modules/video_coding/timing/timing.cc b/modules/video_coding/timing/timing.cc
index e791612..1dbf5bb 100644
--- a/modules/video_coding/timing/timing.cc
+++ b/modules/video_coding/timing/timing.cc
@@ -201,8 +201,12 @@
   }
   // Note that TimestampExtrapolator::ExtrapolateLocalTime is not a const
   // method; it mutates the object's wraparound state.
-  Timestamp estimated_complete_time =
-      ts_extrapolator_->ExtrapolateLocalTime(frame_timestamp).value_or(now);
+  std::optional<Timestamp> local_time =
+      ts_extrapolator_->ExtrapolateLocalTime(frame_timestamp);
+  if (!local_time.has_value()) {
+    return now;
+  }
+  Timestamp estimated_complete_time = *local_time;
 
   // Make sure the actual delay stays in the range of `min_playout_delay_`
   // and `max_playout_delay_`.
diff --git a/modules/video_coding/timing/timing_unittest.cc b/modules/video_coding/timing/timing_unittest.cc
index ffb831b..8e49426 100644
--- a/modules/video_coding/timing/timing_unittest.cc
+++ b/modules/video_coding/timing/timing_unittest.cc
@@ -449,4 +449,46 @@
   EXPECT_THAT(timings, HasConsistentVideoDelayTimings());
 }
 
+TEST(VCMTimingTest, GetTimingsBeforeAndAfterValidRtpTimestamp) {
+  SimulatedClock clock(33);
+  test::ScopedKeyValueConfig field_trials;
+  VCMTiming timing(&clock, field_trials);
+
+  // Setup.
+  TimeDelta min_playout_delay = TimeDelta::Millis(50);
+  timing.set_min_playout_delay(min_playout_delay);
+  timing.set_max_playout_delay(TimeDelta::Millis(500));
+
+  // On decodable frames before valid rtp timestamp.
+  constexpr int decodeable_frame_cnt = 10;
+  constexpr uint32_t any_time_elapsed = 17;
+  constexpr uint32_t rtp_ts_base = 3000;
+  constexpr uint32_t rtp_ts_delta_10fps = 9000;
+  constexpr uint32_t frame_ts_delta_10fps = 100;
+  uint32_t rtp_ts = rtp_ts_base;
+
+  for (int i = 0; i < decodeable_frame_cnt; i++) {
+    clock.AdvanceTimeMilliseconds(any_time_elapsed);
+    rtp_ts += rtp_ts_delta_10fps;
+
+    Timestamp render_time = timing.RenderTime(rtp_ts, clock.CurrentTime());
+    // Render time should be CurrentTime, because timing.IncomingTimestamp has
+    // not been called yet.
+    EXPECT_EQ(render_time, clock.CurrentTime());
+  }
+
+  // On frame complete, which one not 'metadata.delayed_by_retransmission'
+  Timestamp valid_frame_ts = clock.CurrentTime();
+  timing.IncomingTimestamp(rtp_ts, valid_frame_ts);
+
+  clock.AdvanceTimeMilliseconds(any_time_elapsed);
+  rtp_ts += rtp_ts_delta_10fps;
+
+  Timestamp render_time = timing.RenderTime(rtp_ts, clock.CurrentTime());
+  // Render time should be relative to the latest valid frame timestamp.
+  EXPECT_EQ(render_time, valid_frame_ts +
+                             TimeDelta::Millis(frame_ts_delta_10fps) +
+                             min_playout_delay);
+}
+
 }  // namespace webrtc