Reset frame timestamp epoch for new capturers.

Incoming frames usually have an epoch of time since the capturer was
created or similar, not any fixed-time epoch. As such, setting a new
capturer resulted in delivering frames with older timestamps which
caused these frames to be dropped before encoding.

BUG=webrtc:4994
R=stefan@webrtc.org
TBR=pthatcher@webrtc.org

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

Cr-Commit-Position: refs/heads/master@{#9934}
diff --git a/talk/media/base/fakevideocapturer.h b/talk/media/base/fakevideocapturer.h
index ef6288a..0909f84 100644
--- a/talk/media/base/fakevideocapturer.h
+++ b/talk/media/base/fakevideocapturer.h
@@ -133,6 +133,10 @@
     return true;
   }
 
+  void SignalCapturedFrame(cricket::CapturedFrame* frame) {
+    SignalFrameCaptured(this, frame);
+  }
+
   sigslot::signal1<FakeVideoCapturer*> SignalDestroyed;
 
   virtual cricket::CaptureState Start(const cricket::VideoFormat& format) {
diff --git a/talk/media/webrtc/webrtcvideoengine2.cc b/talk/media/webrtc/webrtcvideoengine2.cc
index e94c0b1..917efc8 100644
--- a/talk/media/webrtc/webrtcvideoengine2.cc
+++ b/talk/media/webrtc/webrtcvideoengine2.cc
@@ -1881,6 +1881,10 @@
   {
     rtc::CritScope cs(&lock_);
 
+    // Reset timestamps to realign new incoming frames to a webrtc timestamp. A
+    // new capturer may have a different timestamp delta than the previous one.
+    first_frame_timestamp_ms_ = 0;
+
     if (capturer == NULL) {
       if (stream_ != NULL) {
         LOG(LS_VERBOSE) << "Disabling capturer, sending black frame.";
diff --git a/talk/media/webrtc/webrtcvideoengine2_unittest.cc b/talk/media/webrtc/webrtcvideoengine2_unittest.cc
index 71581de..52acec4 100644
--- a/talk/media/webrtc/webrtcvideoengine2_unittest.cc
+++ b/talk/media/webrtc/webrtcvideoengine2_unittest.cc
@@ -440,18 +440,14 @@
                                       cricket::FOURCC_I420));
   channel->SetSend(true);
 
-  FakeCall* call = factory.GetCall();
-  std::vector<FakeVideoSendStream*> streams = call->GetVideoSendStreams();
-  FakeVideoSendStream* stream = streams[0];
+  FakeVideoSendStream* stream = factory.GetCall()->GetVideoSendStreams()[0];
 
-  int64_t timestamp;
-  int64_t last_timestamp;
 
   EXPECT_TRUE(capturer.CaptureFrame());
-  last_timestamp = stream->GetLastTimestamp();
+  int64_t last_timestamp = stream->GetLastTimestamp();
   for (int i = 0; i < 10; i++) {
     EXPECT_TRUE(capturer.CaptureFrame());
-    timestamp = stream->GetLastTimestamp();
+    int64_t timestamp = stream->GetLastTimestamp();
     int64_t interval = timestamp - last_timestamp;
 
     // Precision changes from nanosecond to millisecond.
@@ -469,7 +465,7 @@
   last_timestamp = stream->GetLastTimestamp();
   for (int i = 0; i < 10; i++) {
     EXPECT_TRUE(capturer.CaptureFrame());
-    timestamp = stream->GetLastTimestamp();
+    int64_t timestamp = stream->GetLastTimestamp();
     int64_t interval = timestamp - last_timestamp;
 
     // Precision changes from nanosecond to millisecond.
@@ -483,6 +479,64 @@
   EXPECT_TRUE(channel->RemoveSendStream(kSsrc));
 }
 
+TEST_F(WebRtcVideoEngine2Test,
+       ProducesIncreasingTimestampsWithResetInputSources) {
+  cricket::FakeWebRtcVideoEncoderFactory encoder_factory;
+  encoder_factory.AddSupportedVideoCodecType(webrtc::kVideoCodecVP8, "VP8");
+  std::vector<cricket::VideoCodec> codecs;
+  codecs.push_back(kVp8Codec);
+
+  FakeCallFactory factory;
+  engine_.SetCallFactory(&factory);
+  rtc::scoped_ptr<VideoMediaChannel> channel(
+      SetUpForExternalEncoderFactory(&encoder_factory, codecs));
+
+  EXPECT_TRUE(
+      channel->AddSendStream(cricket::StreamParams::CreateLegacy(kSsrc)));
+  channel->SetSend(true);
+  FakeVideoSendStream* stream = factory.GetCall()->GetVideoSendStreams()[0];
+
+  FakeVideoCapturer capturer1;
+  EXPECT_TRUE(channel->SetCapturer(kSsrc, &capturer1));
+
+  cricket::CapturedFrame frame;
+  frame.width = 1280;
+  frame.height = 720;
+  frame.fourcc = cricket::FOURCC_I420;
+  frame.data_size = static_cast<uint32>(
+      cricket::VideoFrame::SizeOf(frame.width, frame.height));
+  rtc::scoped_ptr<char[]> data(new char[frame.data_size]);
+  frame.data = data.get();
+  memset(frame.data, 1, frame.data_size);
+  frame.elapsed_time = 0;
+  const int kInitialTimestamp = 123456;
+  frame.time_stamp = kInitialTimestamp;
+
+  // Deliver initial frame.
+  capturer1.SignalCapturedFrame(&frame);
+  // Deliver next frame 1 second later.
+  frame.time_stamp += rtc::kNumNanosecsPerSec;
+  rtc::Thread::Current()->SleepMs(1000);
+  capturer1.SignalCapturedFrame(&frame);
+
+  int64_t capturer1_last_timestamp = stream->GetLastTimestamp();
+  // Reset input source, should still be continuous even though input-frame
+  // timestamp is less than before.
+  FakeVideoCapturer capturer2;
+  EXPECT_TRUE(channel->SetCapturer(kSsrc, &capturer2));
+
+  rtc::Thread::Current()->SleepMs(1);
+  // Deliver with a timestamp (10 seconds) before the previous initial one,
+  // these should not be related at all anymore and it should still work fine.
+  frame.time_stamp = kInitialTimestamp - 10000;
+  capturer2.SignalCapturedFrame(&frame);
+
+  // New timestamp should be at least 1ms in the future and not old.
+  EXPECT_GT(stream->GetLastTimestamp(), capturer1_last_timestamp);
+
+  EXPECT_TRUE(channel->RemoveSendStream(kSsrc));
+}
+
 VideoMediaChannel* WebRtcVideoEngine2Test::SetUpForExternalEncoderFactory(
     cricket::WebRtcVideoEncoderFactory* encoder_factory,
     const std::vector<VideoCodec>& codecs) {