1 /* 2 * libjingle 3 * Copyright 2012, Google Inc. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include "talk/media/base/capturerenderadapter.h" 29 30 #include "talk/base/logging.h" 31 #include "talk/media/base/videocapturer.h" 32 #include "talk/media/base/videoprocessor.h" 33 #include "talk/media/base/videorenderer.h" 34 35 namespace cricket { 36 37 CaptureRenderAdapter::CaptureRenderAdapter(VideoCapturer* video_capturer) 38 : video_capturer_(video_capturer) { 39 } 40 41 CaptureRenderAdapter::~CaptureRenderAdapter() { 42 // Since the signal we're connecting to is multi-threaded, 43 // disconnect_all() will block until all calls are serviced, meaning any 44 // outstanding calls to OnVideoFrame will be done when this is done, and no 45 // more calls will be serviced by this. 46 // We do this explicitly instead of just letting the has_slots<> destructor 47 // take care of it because we need to do this *before* video_renderers_ is 48 // cleared by the destructor; otherwise we could mess with it while 49 // OnVideoFrame is running. 50 // We *don't* take capture_crit_ here since it could deadlock with the lock 51 // taken by the video frame signal. 52 disconnect_all(); 53 } 54 55 CaptureRenderAdapter* CaptureRenderAdapter::Create( 56 VideoCapturer* video_capturer) { 57 if (!video_capturer) { 58 return NULL; 59 } 60 CaptureRenderAdapter* return_value = new CaptureRenderAdapter(video_capturer); 61 return_value->Init(); // Can't fail. 62 return return_value; 63 } 64 65 bool CaptureRenderAdapter::AddRenderer(VideoRenderer* video_renderer) { 66 if (!video_renderer) { 67 return false; 68 } 69 talk_base::CritScope cs(&capture_crit_); 70 if (IsRendererRegistered(*video_renderer)) { 71 return false; 72 } 73 video_renderers_.push_back(VideoRendererInfo(video_renderer)); 74 return true; 75 } 76 77 bool CaptureRenderAdapter::RemoveRenderer(VideoRenderer* video_renderer) { 78 if (!video_renderer) { 79 return false; 80 } 81 talk_base::CritScope cs(&capture_crit_); 82 for (VideoRenderers::iterator iter = video_renderers_.begin(); 83 iter != video_renderers_.end(); ++iter) { 84 if (video_renderer == iter->renderer) { 85 video_renderers_.erase(iter); 86 return true; 87 } 88 } 89 return false; 90 } 91 92 void CaptureRenderAdapter::Init() { 93 video_capturer_->SignalVideoFrame.connect( 94 this, 95 &CaptureRenderAdapter::OnVideoFrame); 96 } 97 98 void CaptureRenderAdapter::OnVideoFrame(VideoCapturer* capturer, 99 const VideoFrame* video_frame) { 100 talk_base::CritScope cs(&capture_crit_); 101 if (video_renderers_.empty()) { 102 return; 103 } 104 MaybeSetRenderingSize(video_frame); 105 106 for (VideoRenderers::iterator iter = video_renderers_.begin(); 107 iter != video_renderers_.end(); ++iter) { 108 VideoRenderer* video_renderer = iter->renderer; 109 video_renderer->RenderFrame(video_frame); 110 } 111 } 112 113 // The renderer_crit_ lock needs to be taken when calling this function. 114 void CaptureRenderAdapter::MaybeSetRenderingSize(const VideoFrame* frame) { 115 for (VideoRenderers::iterator iter = video_renderers_.begin(); 116 iter != video_renderers_.end(); ++iter) { 117 const bool new_resolution = iter->render_width != frame->GetWidth() || 118 iter->render_height != frame->GetHeight(); 119 if (new_resolution) { 120 if (iter->renderer->SetSize(static_cast<int>(frame->GetWidth()), 121 static_cast<int>(frame->GetHeight()), 0)) { 122 iter->render_width = frame->GetWidth(); 123 iter->render_height = frame->GetHeight(); 124 } else { 125 LOG(LS_ERROR) << "Captured frame size not supported by renderer: " << 126 frame->GetWidth() << " x " << frame->GetHeight(); 127 } 128 } 129 } 130 } 131 132 // The renderer_crit_ lock needs to be taken when calling this function. 133 bool CaptureRenderAdapter::IsRendererRegistered( 134 const VideoRenderer& video_renderer) const { 135 for (VideoRenderers::const_iterator iter = video_renderers_.begin(); 136 iter != video_renderers_.end(); ++iter) { 137 if (&video_renderer == iter->renderer) { 138 return true; 139 } 140 } 141 return false; 142 } 143 144 } // namespace cricket 145