1 /* 2 * libjingle 3 * Copyright 2004 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/webrtc/webrtcpassthroughrender.h" 29 30 #include "talk/base/common.h" 31 #include "talk/base/logging.h" 32 33 namespace cricket { 34 35 #define LOG_FIND_STREAM_ERROR(func, id) LOG(LS_ERROR) \ 36 << "" << func << " - Failed to find stream: " << id 37 38 class PassthroughStream: public webrtc::VideoRenderCallback { 39 public: 40 explicit PassthroughStream(const uint32_t stream_id) 41 : stream_id_(stream_id), 42 running_(false) { 43 } 44 virtual ~PassthroughStream() { 45 } 46 virtual int32_t RenderFrame(const uint32_t stream_id, 47 webrtc::I420VideoFrame& videoFrame) { 48 talk_base::CritScope cs(&stream_critical_); 49 // Send frame for rendering directly 50 if (running_ && renderer_) { 51 renderer_->RenderFrame(stream_id, videoFrame); 52 } 53 return 0; 54 } 55 int32_t SetRenderer(VideoRenderCallback* renderer) { 56 talk_base::CritScope cs(&stream_critical_); 57 renderer_ = renderer; 58 return 0; 59 } 60 61 int32_t StartRender() { 62 talk_base::CritScope cs(&stream_critical_); 63 running_ = true; 64 return 0; 65 } 66 67 int32_t StopRender() { 68 talk_base::CritScope cs(&stream_critical_); 69 running_ = false; 70 return 0; 71 } 72 73 private: 74 uint32_t stream_id_; 75 VideoRenderCallback* renderer_; 76 talk_base::CriticalSection stream_critical_; 77 bool running_; 78 }; 79 80 WebRtcPassthroughRender::WebRtcPassthroughRender() 81 : window_(NULL) { 82 } 83 84 WebRtcPassthroughRender::~WebRtcPassthroughRender() { 85 while (!stream_render_map_.empty()) { 86 PassthroughStream* stream = stream_render_map_.begin()->second; 87 stream_render_map_.erase(stream_render_map_.begin()); 88 delete stream; 89 } 90 } 91 92 webrtc::VideoRenderCallback* WebRtcPassthroughRender::AddIncomingRenderStream( 93 const uint32_t stream_id, 94 const uint32_t zOrder, 95 const float left, const float top, 96 const float right, const float bottom) { 97 talk_base::CritScope cs(&render_critical_); 98 // Stream already exist. 99 if (FindStream(stream_id) != NULL) { 100 LOG(LS_ERROR) << "AddIncomingRenderStream - Stream already exists: " 101 << stream_id; 102 return NULL; 103 } 104 105 PassthroughStream* stream = new PassthroughStream(stream_id); 106 // Store the stream 107 stream_render_map_[stream_id] = stream; 108 return stream; 109 } 110 111 int32_t WebRtcPassthroughRender::DeleteIncomingRenderStream( 112 const uint32_t stream_id) { 113 talk_base::CritScope cs(&render_critical_); 114 PassthroughStream* stream = FindStream(stream_id); 115 if (stream == NULL) { 116 LOG_FIND_STREAM_ERROR("DeleteIncomingRenderStream", stream_id); 117 return -1; 118 } 119 delete stream; 120 stream_render_map_.erase(stream_id); 121 return 0; 122 } 123 124 int32_t WebRtcPassthroughRender::AddExternalRenderCallback( 125 const uint32_t stream_id, 126 webrtc::VideoRenderCallback* render_object) { 127 talk_base::CritScope cs(&render_critical_); 128 PassthroughStream* stream = FindStream(stream_id); 129 if (stream == NULL) { 130 LOG_FIND_STREAM_ERROR("AddExternalRenderCallback", stream_id); 131 return -1; 132 } 133 return stream->SetRenderer(render_object); 134 } 135 136 bool WebRtcPassthroughRender::HasIncomingRenderStream( 137 const uint32_t stream_id) const { 138 return (FindStream(stream_id) != NULL); 139 } 140 141 webrtc::RawVideoType WebRtcPassthroughRender::PreferredVideoType() const { 142 return webrtc::kVideoI420; 143 } 144 145 int32_t WebRtcPassthroughRender::StartRender(const uint32_t stream_id) { 146 talk_base::CritScope cs(&render_critical_); 147 PassthroughStream* stream = FindStream(stream_id); 148 if (stream == NULL) { 149 LOG_FIND_STREAM_ERROR("StartRender", stream_id); 150 return -1; 151 } 152 return stream->StartRender(); 153 } 154 155 int32_t WebRtcPassthroughRender::StopRender(const uint32_t stream_id) { 156 talk_base::CritScope cs(&render_critical_); 157 PassthroughStream* stream = FindStream(stream_id); 158 if (stream == NULL) { 159 LOG_FIND_STREAM_ERROR("StopRender", stream_id); 160 return -1; 161 } 162 return stream->StopRender(); 163 } 164 165 // TODO(ronghuawu): Is it ok to return non-const pointer to PassthroughStream 166 // from this const function FindStream. 167 PassthroughStream* WebRtcPassthroughRender::FindStream( 168 const uint32_t stream_id) const { 169 StreamMap::const_iterator it = stream_render_map_.find(stream_id); 170 if (it == stream_render_map_.end()) { 171 return NULL; 172 } 173 return it->second; 174 } 175 176 } // namespace cricket 177