From f4f2145c6e967ffc01bd27775ae6c09e9f7d86eb Mon Sep 17 00:00:00 2001 From: "mflodman@webrtc.org" Date: Fri, 28 Sep 2012 11:27:35 +0000 Subject: [PATCH] Added API to set expected render delay. BUG=905 TEST=API test added and manual delay tests. Review URL: https://webrtc-codereview.appspot.com/810005 git-svn-id: http://webrtc.googlecode.com/svn/trunk@2841 4adac7df-926f-26a2-2b94-8c16560cd09d --- .../main/interface/video_render.h | 7 +++++ .../main/source/incoming_video_stream.cc | 12 +++++++ .../main/source/incoming_video_stream.h | 2 ++ .../main/source/video_render_frames.cc | 12 ++++++- .../main/source/video_render_impl.cc | 31 +++++++++++++++++++ .../main/source/video_render_impl.h | 3 ++ src/video_engine/include/vie_render.h | 5 +++ .../auto_test/source/vie_autotest_render.cc | 30 ++++++++++++++++-- src/video_engine/vie_render_impl.cc | 21 +++++++++++++ src/video_engine/vie_render_impl.h | 1 + src/video_engine/vie_renderer.cc | 4 +++ src/video_engine/vie_renderer.h | 2 ++ 12 files changed, 126 insertions(+), 4 deletions(-) diff --git a/src/modules/video_render/main/interface/video_render.h b/src/modules/video_render/main/interface/video_render.h index 4fc7f2ca7..9ca133f39 100644 --- a/src/modules/video_render/main/interface/video_render.h +++ b/src/modules/video_render/main/interface/video_render.h @@ -236,6 +236,13 @@ public: /* * re-configure renderer */ + + // Set the expected time needed by the graphics card or external renderer, + // i.e. frames will be released for rendering |delay_ms| before set render + // time in the video frame. + virtual WebRtc_Word32 SetExpectedRenderDelay(WebRtc_UWord32 stream_id, + WebRtc_Word32 delay_ms) = 0; + virtual WebRtc_Word32 ConfigureRenderer(const WebRtc_UWord32 streamId, const unsigned int zOrder, const float left, const float top, diff --git a/src/modules/video_render/main/source/incoming_video_stream.cc b/src/modules/video_render/main/source/incoming_video_stream.cc index 2c9806014..0a29482e4 100644 --- a/src/modules/video_render/main/source/incoming_video_stream.cc +++ b/src/modules/video_render/main/source/incoming_video_stream.cc @@ -175,6 +175,18 @@ WebRtc_Word32 IncomingVideoStream::EnableMirroring(const bool enable, return 0; } +WebRtc_Word32 IncomingVideoStream::SetExpectedRenderDelay( + WebRtc_Word32 delay_ms) { + CriticalSectionScoped csS(&stream_critsect_); + if (running_) { + WEBRTC_TRACE(kTraceInfo, kTraceVideoRenderer, module_id_, + "%s(%d) for stream %d", __FUNCTION__, delay_ms, stream_id_); + return -1; + } + CriticalSectionScoped cs(buffer_critsect_); + return render_buffers_.SetRenderDelay(delay_ms); +} + WebRtc_Word32 IncomingVideoStream::SetExternalCallback( VideoRenderCallback* external_callback) { CriticalSectionScoped cs(&stream_critsect_); diff --git a/src/modules/video_render/main/source/incoming_video_stream.h b/src/modules/video_render/main/source/incoming_video_stream.h index 11bc1156e..a2f28fc76 100644 --- a/src/modules/video_render/main/source/incoming_video_stream.h +++ b/src/modules/video_render/main/source/incoming_video_stream.h @@ -68,6 +68,8 @@ class IncomingVideoStream : public VideoRenderCallback { const bool mirror_xaxis, const bool mirror_yaxis); + WebRtc_Word32 SetExpectedRenderDelay(WebRtc_Word32 delay_ms); + protected: static bool IncomingVideoStreamThreadFun(void* obj); bool IncomingVideoStreamProcess(); diff --git a/src/modules/video_render/main/source/video_render_frames.cc b/src/modules/video_render/main/source/video_render_frames.cc index 259e4edd5..0a4f99bb9 100644 --- a/src/modules/video_render/main/source/video_render_frames.cc +++ b/src/modules/video_render/main/source/video_render_frames.cc @@ -18,7 +18,9 @@ namespace webrtc { -WebRtc_Word32 KEventMaxWaitTimeMs = 200; +const WebRtc_Word32 KEventMaxWaitTimeMs = 200; +const WebRtc_Word32 kMinRenderDelayMs = 10; +const WebRtc_Word32 kMaxRenderDelayMs= 500; VideoRenderFrames::VideoRenderFrames() : incoming_frames_(), @@ -167,6 +169,14 @@ WebRtc_UWord32 VideoRenderFrames::TimeToNextFrameRelease() { WebRtc_Word32 VideoRenderFrames::SetRenderDelay( const WebRtc_UWord32 render_delay) { + if (render_delay < kMinRenderDelayMs || + render_delay > kMaxRenderDelayMs) { + WEBRTC_TRACE(kTraceWarning, kTraceVideoRenderer, + -1, "%s(%d): Invalid argument.", __FUNCTION__, + render_delay); + return -1; + } + render_delay_ms_ = render_delay; return 0; } diff --git a/src/modules/video_render/main/source/video_render_impl.cc b/src/modules/video_render/main/source/video_render_impl.cc index 3b3d4cef3..6c273a805 100644 --- a/src/modules/video_render/main/source/video_render_impl.cc +++ b/src/modules/video_render/main/source/video_render_impl.cc @@ -845,6 +845,37 @@ WebRtc_Word32 ModuleVideoRenderImpl::GetLastRenderedFrame( return incomingStream->GetLastRenderedFrame(frame); } +WebRtc_Word32 ModuleVideoRenderImpl::SetExpectedRenderDelay( + WebRtc_UWord32 stream_id, WebRtc_Word32 delay_ms) { + CriticalSectionScoped cs(_moduleCrit); + + if (!_ptrRenderer) { + WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id, + "%s: No renderer", __FUNCTION__); + return false; + } + + MapItem *item = _streamRenderMap.Find(stream_id); + if (item == NULL) { + // This stream doesn't exist + WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id, + "%s(%u, %d): stream doesn't exist", __FUNCTION__, stream_id, + delay_ms); + return -1; + } + + IncomingVideoStream* incoming_stream = + static_cast (item->GetItem()); + if (incoming_stream == NULL) { + // This should never happen + assert(false); + _streamRenderMap.Erase(item); + return 0; + } + + return incoming_stream->SetExpectedRenderDelay(delay_ms); +} + WebRtc_Word32 ModuleVideoRenderImpl::ConfigureRenderer( const WebRtc_UWord32 streamId, const unsigned int zOrder, diff --git a/src/modules/video_render/main/source/video_render_impl.h b/src/modules/video_render/main/source/video_render_impl.h index ac500922d..2665cfb1b 100644 --- a/src/modules/video_render/main/source/video_render_impl.h +++ b/src/modules/video_render/main/source/video_render_impl.h @@ -119,6 +119,9 @@ public: virtual WebRtc_Word32 GetLastRenderedFrame(const WebRtc_UWord32 streamId, VideoFrame &frame) const; + virtual WebRtc_Word32 SetExpectedRenderDelay(WebRtc_UWord32 stream_id, + WebRtc_Word32 delay_ms); + /************************************************************************** * * Start/Stop diff --git a/src/video_engine/include/vie_render.h b/src/video_engine/include/vie_render.h index 0b8328e25..5eecc72b7 100644 --- a/src/video_engine/include/vie_render.h +++ b/src/video_engine/include/vie_render.h @@ -81,6 +81,11 @@ class WEBRTC_DLLEXPORT ViERender { // Stops rendering a render stream. virtual int StopRender(const int render_id) = 0; + // Set expected render time needed by graphics card or external renderer, i.e. + // the number of ms a frame will be sent to rendering before the actual render + // time. + virtual int SetExpectedRenderDelay(int render_id, int render_delay) = 0; + // Configures an already added render stream. virtual int ConfigureRender(int render_id, const unsigned int z_order, diff --git a/src/video_engine/test/auto_test/source/vie_autotest_render.cc b/src/video_engine/test/auto_test/source/vie_autotest_render.cc index 0c8ca222e..8bfc9db07 100644 --- a/src/video_engine/test/auto_test/source/vie_autotest_render.cc +++ b/src/video_engine/test/auto_test/source/vie_autotest_render.cc @@ -289,7 +289,31 @@ void ViEAutoTest::ViERenderExtendedTest() tbCapture.Disconnect(tbChannel.videoChannel); } -void ViEAutoTest::ViERenderAPITest() -{ - // TODO(unknown): add the real tests cases +void ViEAutoTest::ViERenderAPITest() { + TbInterfaces ViE("ViERenderAPITest"); + + TbVideoChannel tbChannel(ViE, webrtc::kVideoCodecVP8); + TbCaptureDevice tbCapture(ViE); + tbCapture.ConnectTo(tbChannel.videoChannel); + tbChannel.StartReceive(); + tbChannel.StartSend(); + + EXPECT_EQ(0, ViE.render->AddRenderer( + tbCapture.captureId, _window1, 0, 0.0, 0.0, 1.0, 1.0)); + EXPECT_EQ(0, ViE.render->StartRender(tbCapture.captureId)); + EXPECT_EQ(0, ViE.render->AddRenderer( + tbChannel.videoChannel, _window2, 1, 0.0, 0.0, 1.0, 1.0)); + EXPECT_EQ(0, ViE.render->StartRender(tbChannel.videoChannel)); + + // Test setting HW render delay. + // Already started. + EXPECT_EQ(-1, ViE.render->SetExpectedRenderDelay(tbChannel.videoChannel, 50)); + EXPECT_EQ(0, ViE.render->StopRender(tbChannel.videoChannel)); + // Invalid values. + EXPECT_EQ(-1, ViE.render->SetExpectedRenderDelay(tbChannel.videoChannel, 9)); + EXPECT_EQ(-1, ViE.render->SetExpectedRenderDelay(tbChannel.videoChannel, + 501)); + // Valid values. + EXPECT_EQ(0, ViE.render->SetExpectedRenderDelay(tbChannel.videoChannel, 11)); + EXPECT_EQ(0, ViE.render->SetExpectedRenderDelay(tbChannel.videoChannel, 499)); } diff --git a/src/video_engine/vie_render_impl.cc b/src/video_engine/vie_render_impl.cc index c667d4d14..a732ea701 100644 --- a/src/video_engine/vie_render_impl.cc +++ b/src/video_engine/vie_render_impl.cc @@ -262,6 +262,27 @@ int ViERenderImpl::StopRender(const int render_id) { return 0; } +int ViERenderImpl::SetExpectedRenderDelay(int render_id, int render_delay) { + WEBRTC_TRACE(kTraceApiCall, kTraceVideo, + ViEId(shared_data_->instance_id(), render_id), + "%s(channel: %d)", __FUNCTION__, render_id); + ViERenderManagerScoped rs(*(shared_data_->render_manager())); + ViERenderer* renderer = rs.Renderer(render_id); + if (!renderer) { + WEBRTC_TRACE(kTraceError, kTraceVideo, + ViEId(shared_data_->instance_id(), render_id), + "%s: No renderer with render_id %d exist.", __FUNCTION__, + render_id); + shared_data_->SetLastError(kViERenderInvalidRenderId); + return -1; + } + if (renderer->SetExpectedRenderDelay(render_delay) != 0) { + shared_data_->SetLastError(kViERenderUnknownError); + return -1; + } + return 0; +} + int ViERenderImpl::ConfigureRender(int render_id, const unsigned int z_order, const float left, const float top, const float right, const float bottom) { diff --git a/src/video_engine/vie_render_impl.h b/src/video_engine/vie_render_impl.h index c0cf9162d..e59ad503f 100644 --- a/src/video_engine/vie_render_impl.h +++ b/src/video_engine/vie_render_impl.h @@ -36,6 +36,7 @@ class ViERenderImpl virtual int RemoveRenderer(const int render_id); virtual int StartRender(const int render_id); virtual int StopRender(const int render_id); + virtual int SetExpectedRenderDelay(int render_id, int render_delay); virtual int ConfigureRender(int render_id, const unsigned int z_order, const float left, const float top, const float right, const float bottom); diff --git a/src/video_engine/vie_renderer.cc b/src/video_engine/vie_renderer.cc index f1c6f8c21..935926251 100644 --- a/src/video_engine/vie_renderer.cc +++ b/src/video_engine/vie_renderer.cc @@ -55,6 +55,10 @@ WebRtc_Word32 ViERenderer::GetLastRenderedFrame(const WebRtc_Word32 renderID, return render_module_.GetLastRenderedFrame(renderID, video_frame); } +int ViERenderer::SetExpectedRenderDelay(int render_delay) { + return render_module_.SetExpectedRenderDelay(render_id_, render_delay); +} + WebRtc_Word32 ViERenderer::ConfigureRenderer(const unsigned int z_order, const float left, const float top, diff --git a/src/video_engine/vie_renderer.h b/src/video_engine/vie_renderer.h index dd216ea1a..85380f745 100644 --- a/src/video_engine/vie_renderer.h +++ b/src/video_engine/vie_renderer.h @@ -62,6 +62,8 @@ class ViERenderer: public ViEFrameCallback { WebRtc_Word32 GetLastRenderedFrame(const WebRtc_Word32 renderID, VideoFrame& video_frame); + int SetExpectedRenderDelay(int render_delay); + WebRtc_Word32 ConfigureRenderer(const unsigned int z_order, const float left, const float top,