/* * libjingle * Copyright 2012, Google Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "talk/media/base/capturerenderadapter.h" #include "talk/media/base/videocapturer.h" #include "talk/media/base/videoprocessor.h" #include "talk/media/base/videorenderer.h" #include "webrtc/base/logging.h" namespace cricket { CaptureRenderAdapter::CaptureRenderAdapter(VideoCapturer* video_capturer) : video_capturer_(video_capturer) { } CaptureRenderAdapter::~CaptureRenderAdapter() { // Since the signal we're connecting to is multi-threaded, // disconnect_all() will block until all calls are serviced, meaning any // outstanding calls to OnVideoFrame will be done when this is done, and no // more calls will be serviced by this. // We do this explicitly instead of just letting the has_slots<> destructor // take care of it because we need to do this *before* video_renderers_ is // cleared by the destructor; otherwise we could mess with it while // OnVideoFrame is running. // We *don't* take capture_crit_ here since it could deadlock with the lock // taken by the video frame signal. disconnect_all(); } CaptureRenderAdapter* CaptureRenderAdapter::Create( VideoCapturer* video_capturer) { if (!video_capturer) { return NULL; } CaptureRenderAdapter* return_value = new CaptureRenderAdapter(video_capturer); return_value->Init(); // Can't fail. return return_value; } bool CaptureRenderAdapter::AddRenderer(VideoRenderer* video_renderer) { if (!video_renderer) { return false; } rtc::CritScope cs(&capture_crit_); if (IsRendererRegistered(*video_renderer)) { return false; } video_renderers_.push_back(VideoRendererInfo(video_renderer)); return true; } bool CaptureRenderAdapter::RemoveRenderer(VideoRenderer* video_renderer) { if (!video_renderer) { return false; } rtc::CritScope cs(&capture_crit_); for (VideoRenderers::iterator iter = video_renderers_.begin(); iter != video_renderers_.end(); ++iter) { if (video_renderer == iter->renderer) { video_renderers_.erase(iter); return true; } } return false; } void CaptureRenderAdapter::Init() { video_capturer_->SignalVideoFrame.connect( this, &CaptureRenderAdapter::OnVideoFrame); } void CaptureRenderAdapter::OnVideoFrame(VideoCapturer* capturer, const VideoFrame* video_frame) { rtc::CritScope cs(&capture_crit_); if (video_renderers_.empty()) { return; } MaybeSetRenderingSize(video_frame); for (VideoRenderers::iterator iter = video_renderers_.begin(); iter != video_renderers_.end(); ++iter) { VideoRenderer* video_renderer = iter->renderer; video_renderer->RenderFrame(video_frame); } } // The renderer_crit_ lock needs to be taken when calling this function. void CaptureRenderAdapter::MaybeSetRenderingSize(const VideoFrame* frame) { for (VideoRenderers::iterator iter = video_renderers_.begin(); iter != video_renderers_.end(); ++iter) { const bool new_resolution = iter->render_width != frame->GetWidth() || iter->render_height != frame->GetHeight(); if (new_resolution) { if (iter->renderer->SetSize(static_cast(frame->GetWidth()), static_cast(frame->GetHeight()), 0)) { iter->render_width = frame->GetWidth(); iter->render_height = frame->GetHeight(); } else { LOG(LS_ERROR) << "Captured frame size not supported by renderer: " << frame->GetWidth() << " x " << frame->GetHeight(); } } } } // The renderer_crit_ lock needs to be taken when calling this function. bool CaptureRenderAdapter::IsRendererRegistered( const VideoRenderer& video_renderer) const { for (VideoRenderers::const_iterator iter = video_renderers_.begin(); iter != video_renderers_.end(); ++iter) { if (&video_renderer == iter->renderer) { return true; } } return false; } } // namespace cricket