In generic encoder ensure capture timestamp is preserved.

Because some hardware encoders may not preserve capture timestamp, use
rtp timestamp as a key to capture time storage and restore corrupted
capture timestamps whenever possible.

Bug: webrtc:8497
Change-Id: Ib3449313c65e864a89cd645a3f5dec99aa9cf8e4
Reviewed-on: https://webrtc-review.googlesource.com/23620
Reviewed-by: Erik Språng <sprang@webrtc.org>
Reviewed-by: Magnus Jedvert <magjed@webrtc.org>
Commit-Queue: Ilya Nikolaevskiy <ilnik@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#20732}
diff --git a/modules/video_coding/generic_encoder_unittest.cc b/modules/video_coding/generic_encoder_unittest.cc
index 48c152f..2b788c5 100644
--- a/modules/video_coding/generic_encoder_unittest.cc
+++ b/modules/video_coding/generic_encoder_unittest.cc
@@ -28,13 +28,16 @@
 class FakeEncodedImageCallback : public EncodedImageCallback {
  public:
   FakeEncodedImageCallback()
-      : last_frame_was_timing_(false), num_frames_dropped_(0) {}
+      : last_frame_was_timing_(false),
+        num_frames_dropped_(0),
+        last_capture_timestamp_(-1) {}
   Result OnEncodedImage(const EncodedImage& encoded_image,
                         const CodecSpecificInfo* codec_specific_info,
                         const RTPFragmentationHeader* fragmentation) override {
     last_frame_was_timing_ =
         encoded_image.timing_.flags != TimingFrameFlags::kInvalid &&
         encoded_image.timing_.flags != TimingFrameFlags::kNotTriggered;
+    last_capture_timestamp_ = encoded_image.capture_time_ms_;
     return Result(Result::OK);
   };
 
@@ -44,9 +47,12 @@
 
   size_t GetNumFramesDropped() { return num_frames_dropped_; }
 
+  int64_t GetLastCaptureTimestamp() { return last_capture_timestamp_; }
+
  private:
   bool last_frame_was_timing_;
   size_t num_frames_dropped_;
+  int64_t last_capture_timestamp_;
 };
 
 enum class FrameType {
@@ -87,9 +93,11 @@
       CodecSpecificInfo codec_specific;
       image._length = FrameSize(min_frame_size, max_frame_size, s, i);
       image.capture_time_ms_ = current_timestamp;
+      image._timeStamp = static_cast<uint32_t>(current_timestamp * 90);
       codec_specific.codecType = kVideoCodecGeneric;
       codec_specific.codecSpecific.generic.simulcast_idx = s;
-      callback.OnEncodeStarted(current_timestamp, s);
+      callback.OnEncodeStarted(static_cast<uint32_t>(current_timestamp * 90),
+                               current_timestamp, s);
       if (dropped) {
         result[s].push_back(FrameType::kDropped);
         continue;
@@ -178,6 +186,7 @@
   int64_t timestamp = 1;
   image._length = 500;
   image.capture_time_ms_ = timestamp;
+  image._timeStamp = static_cast<uint32_t>(timestamp * 90);
   codec_specific.codecType = kVideoCodecGeneric;
   codec_specific.codecSpecific.generic.simulcast_idx = 0;
   FakeEncodedImageCallback sink;
@@ -188,12 +197,13 @@
   callback.OnTargetBitrateChanged(500, 0);
 
   // Verify a single frame works with encode start time set.
-  callback.OnEncodeStarted(timestamp, 0);
+  callback.OnEncodeStarted(static_cast<uint32_t>(timestamp * 90), timestamp, 0);
   callback.OnEncodedImage(image, &codec_specific, nullptr);
   EXPECT_TRUE(sink.WasTimingFrame());
 
   // New frame, now skip OnEncodeStarted. Should not result in timing frame.
   image.capture_time_ms_ = ++timestamp;
+  image._timeStamp = static_cast<uint32_t>(timestamp * 90);
   callback.OnEncodedImage(image, &codec_specific, nullptr);
   EXPECT_FALSE(sink.WasTimingFrame());
 }
@@ -201,33 +211,59 @@
 TEST(TestVCMEncodedFrameCallback, NotifiesAboutDroppedFrames) {
   EncodedImage image;
   CodecSpecificInfo codec_specific;
-  const int64_t timestamp1 = 100;
-  const int64_t timestamp2 = 110;
-  const int64_t timestamp3 = 120;
-  const int64_t timestamp4 = 130;
+  const int64_t kTimestampMs1 = 47721840;
+  const int64_t kTimestampMs2 = 47721850;
+  const int64_t kTimestampMs3 = 47721860;
+  const int64_t kTimestampMs4 = 47721870;
   codec_specific.codecType = kVideoCodecGeneric;
   codec_specific.codecSpecific.generic.simulcast_idx = 0;
   FakeEncodedImageCallback sink;
   VCMEncodedFrameCallback callback(&sink, nullptr);
   // Any non-zero bitrate needed to be set before the first frame.
   callback.OnTargetBitrateChanged(500, 0);
-  callback.OnEncodeStarted(timestamp1, 0);
+  image.capture_time_ms_ = kTimestampMs1;
+  image._timeStamp = static_cast<uint32_t>(image.capture_time_ms_ * 90);
+  callback.OnEncodeStarted(image._timeStamp, image.capture_time_ms_, 0);
   EXPECT_EQ(0u, sink.GetNumFramesDropped());
-  image.capture_time_ms_ = timestamp1;
   callback.OnEncodedImage(image, &codec_specific, nullptr);
-  callback.OnEncodeStarted(timestamp2, 0);
+
+  image.capture_time_ms_ = kTimestampMs2;
+  image._timeStamp = static_cast<uint32_t>(image.capture_time_ms_ * 90);
+  callback.OnEncodeStarted(image._timeStamp, image.capture_time_ms_, 0);
   // No OnEncodedImageCall for timestamp2. Yet, at this moment it's not known
   // that frame with timestamp2 was dropped.
   EXPECT_EQ(0u, sink.GetNumFramesDropped());
-  callback.OnEncodeStarted(timestamp3, 0);
-  image.capture_time_ms_ = timestamp3;
+
+  image.capture_time_ms_ = kTimestampMs3;
+  image._timeStamp = static_cast<uint32_t>(image.capture_time_ms_ * 90);
+  callback.OnEncodeStarted(image._timeStamp, image.capture_time_ms_, 0);
   callback.OnEncodedImage(image, &codec_specific, nullptr);
   EXPECT_EQ(1u, sink.GetNumFramesDropped());
-  callback.OnEncodeStarted(timestamp4, 0);
-  image.capture_time_ms_ = timestamp4;
+
+  image.capture_time_ms_ = kTimestampMs4;
+  image._timeStamp = static_cast<uint32_t>(image.capture_time_ms_ * 90);
+  callback.OnEncodeStarted(image._timeStamp, image.capture_time_ms_, 0);
   callback.OnEncodedImage(image, &codec_specific, nullptr);
   EXPECT_EQ(1u, sink.GetNumFramesDropped());
 }
 
+TEST(TestVCMEncodedFrameCallback, RestoresCaptureTimestamps) {
+  EncodedImage image;
+  CodecSpecificInfo codec_specific;
+  const int64_t kTimestampMs = 123456;
+  codec_specific.codecType = kVideoCodecGeneric;
+  codec_specific.codecSpecific.generic.simulcast_idx = 0;
+  FakeEncodedImageCallback sink;
+  VCMEncodedFrameCallback callback(&sink, nullptr);
+  // Any non-zero bitrate needed to be set before the first frame.
+  callback.OnTargetBitrateChanged(500, 0);
+  image.capture_time_ms_ = kTimestampMs;  // Incorrect timesetamp.
+  image._timeStamp = static_cast<uint32_t>(image.capture_time_ms_ * 90);
+  callback.OnEncodeStarted(image._timeStamp, image.capture_time_ms_, 0);
+  image.capture_time_ms_ = 0;  // Incorrect timesetamp.
+  callback.OnEncodedImage(image, &codec_specific, nullptr);
+  EXPECT_EQ(kTimestampMs, sink.GetLastCaptureTimestamp());
+}
+
 }  // namespace test
 }  // namespace webrtc