From eb7b7bce3d9cdd473bca1d5073602b5617ae0d2d Mon Sep 17 00:00:00 2001 From: "pbos@webrtc.org" Date: Mon, 16 Dec 2013 18:24:37 +0000 Subject: [PATCH] Modify video_render/ to allow a single old frame. This stabilizes tests as a single frame reaches end-to-end, as well as allowing slow or heavily-loaded systems to see any video updates even if the frame takes more than 500ms in the pipeline. R=mflodman@webrtc.org, stefan@webrtc.org BUG=2724 Review URL: https://webrtc-codereview.appspot.com/5949004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@5303 4adac7df-926f-26a2-2b94-8c16560cd09d --- .../video_render/video_render_frames.cc | 13 +++- webrtc/video/call_tests.cc | 73 +++++++++++++++++++ 2 files changed, 83 insertions(+), 3 deletions(-) diff --git a/webrtc/modules/video_render/video_render_frames.cc b/webrtc/modules/video_render/video_render_frames.cc index be5cac9aaa..bedb8be95d 100644 --- a/webrtc/modules/video_render/video_render_frames.cc +++ b/webrtc/modules/video_render/video_render_frames.cc @@ -35,12 +35,19 @@ VideoRenderFrames::~VideoRenderFrames() { int32_t VideoRenderFrames::AddFrame(I420VideoFrame* new_frame) { const int64_t time_now = TickTime::MillisecondTimestamp(); - if (new_frame->render_time_ms() + KOldRenderTimestampMS < time_now) { - WEBRTC_TRACE(kTraceWarning, kTraceVideoRenderer, -1, + // Drop old frames only when there are other frames in the queue, otherwise, a + // really slow system never renders any frames. + if (!incoming_frames_.Empty() && + new_frame->render_time_ms() + KOldRenderTimestampMS < time_now) { + WEBRTC_TRACE(kTraceWarning, + kTraceVideoRenderer, + -1, "%s: too old frame, timestamp=%u.", - __FUNCTION__, new_frame->timestamp()); + __FUNCTION__, + new_frame->timestamp()); return -1; } + if (new_frame->render_time_ms() > time_now + KFutureRenderTimestampMS) { WEBRTC_TRACE(kTraceWarning, kTraceVideoRenderer, -1, "%s: frame too long into the future, timestamp=%u.", diff --git a/webrtc/video/call_tests.cc b/webrtc/video/call_tests.cc index 1b0c874879..f511a7ba2c 100644 --- a/webrtc/video/call_tests.cc +++ b/webrtc/video/call_tests.cc @@ -23,6 +23,7 @@ #include "webrtc/system_wrappers/interface/critical_section_wrapper.h" #include "webrtc/system_wrappers/interface/event_wrapper.h" #include "webrtc/system_wrappers/interface/scoped_ptr.h" +#include "webrtc/system_wrappers/interface/sleep.h" #include "webrtc/test/direct_transport.h" #include "webrtc/test/fake_audio_device.h" #include "webrtc/test/fake_decoder.h" @@ -298,6 +299,78 @@ TEST_F(CallTest, UsesTraceCallback) { receiver_call_.reset(); } +TEST_F(CallTest, RendersSingleDelayedFrame) { + static const int kWidth = 320; + static const int kHeight = 240; + // This constant is chosen to be higher than the timeout in the video_render + // module. This makes sure that frames aren't dropped if there are no other + // frames in the queue. + static const int kDelayRenderCallbackMs = 1000; + + class Renderer : public VideoRenderer { + public: + Renderer() : event_(EventWrapper::Create()) {} + + virtual void RenderFrame(const I420VideoFrame& video_frame, + int /*time_to_render_ms*/) OVERRIDE { + event_->Set(); + } + + EventTypeWrapper Wait() { return event_->Wait(kDefaultTimeoutMs); } + + scoped_ptr event_; + } renderer; + + class TestFrameCallback : public I420FrameCallback { + public: + TestFrameCallback() : event_(EventWrapper::Create()) {} + + EventTypeWrapper Wait() { return event_->Wait(kDefaultTimeoutMs); } + + private: + virtual void FrameCallback(I420VideoFrame* frame) { + SleepMs(kDelayRenderCallbackMs); + event_->Set(); + } + + scoped_ptr event_; + }; + + test::DirectTransport sender_transport, receiver_transport; + + CreateCalls(Call::Config(&sender_transport), + Call::Config(&receiver_transport)); + + sender_transport.SetReceiver(receiver_call_->Receiver()); + receiver_transport.SetReceiver(sender_call_->Receiver()); + + CreateTestConfigs(); + + TestFrameCallback pre_render_callback; + receive_config_.pre_render_callback = &pre_render_callback; + receive_config_.renderer = &renderer; + + CreateStreams(); + StartSending(); + + // Create frames that are smaller than the send width/height, this is done to + // check that the callbacks are done after processing video. + scoped_ptr frame_generator( + test::FrameGenerator::Create(kWidth, kHeight)); + send_stream_->Input()->SwapFrame(frame_generator->NextFrame()); + EXPECT_EQ(kEventSignaled, pre_render_callback.Wait()) + << "Timed out while waiting for pre-render callback."; + EXPECT_EQ(kEventSignaled, renderer.Wait()) + << "Timed out while waiting for the frame to render."; + + StopSending(); + + sender_transport.StopSending(); + receiver_transport.StopSending(); + + DestroyStreams(); +} + TEST_F(CallTest, TransmitsFirstFrame) { class Renderer : public VideoRenderer { public: