diff --git a/talk/media/base/fakevideocapturer.h b/talk/media/base/fakevideocapturer.h index ef6288ac39..0909f842b8 100644 --- a/talk/media/base/fakevideocapturer.h +++ b/talk/media/base/fakevideocapturer.h @@ -133,6 +133,10 @@ class FakeVideoCapturer : public cricket::VideoCapturer { return true; } + void SignalCapturedFrame(cricket::CapturedFrame* frame) { + SignalFrameCaptured(this, frame); + } + sigslot::signal1 SignalDestroyed; virtual cricket::CaptureState Start(const cricket::VideoFormat& format) { diff --git a/talk/media/webrtc/webrtcvideoengine2.cc b/talk/media/webrtc/webrtcvideoengine2.cc index e94c0b1794..917efc8c50 100644 --- a/talk/media/webrtc/webrtcvideoengine2.cc +++ b/talk/media/webrtc/webrtcvideoengine2.cc @@ -1881,6 +1881,10 @@ bool WebRtcVideoChannel2::WebRtcVideoSendStream::SetCapturer( { 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 71581de2e3..52acec4082 100644 --- a/talk/media/webrtc/webrtcvideoengine2_unittest.cc +++ b/talk/media/webrtc/webrtcvideoengine2_unittest.cc @@ -440,18 +440,14 @@ TEST_F(WebRtcVideoEngine2Test, PropagatesInputFrameTimestamp) { cricket::FOURCC_I420)); channel->SetSend(true); - FakeCall* call = factory.GetCall(); - std::vector 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 @@ TEST_F(WebRtcVideoEngine2Test, PropagatesInputFrameTimestamp) { 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 @@ TEST_F(WebRtcVideoEngine2Test, PropagatesInputFrameTimestamp) { EXPECT_TRUE(channel->RemoveSendStream(kSsrc)); } +TEST_F(WebRtcVideoEngine2Test, + ProducesIncreasingTimestampsWithResetInputSources) { + cricket::FakeWebRtcVideoEncoderFactory encoder_factory; + encoder_factory.AddSupportedVideoCodecType(webrtc::kVideoCodecVP8, "VP8"); + std::vector codecs; + codecs.push_back(kVp8Codec); + + FakeCallFactory factory; + engine_.SetCallFactory(&factory); + rtc::scoped_ptr 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( + cricket::VideoFrame::SizeOf(frame.width, frame.height)); + rtc::scoped_ptr 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& codecs) {