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 "webrtc/base/common.h"
31 #include "webrtc/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:
PassthroughStream(const uint32_t stream_id)40 explicit PassthroughStream(const uint32_t stream_id)
41 : stream_id_(stream_id),
42 running_(false) {
43 }
~PassthroughStream()44 virtual ~PassthroughStream() {
45 }
RenderFrame(const uint32_t stream_id,webrtc::I420VideoFrame & videoFrame)46 virtual int32_t RenderFrame(const uint32_t stream_id,
47 webrtc::I420VideoFrame& videoFrame) {
48 rtc::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 }
SetRenderer(VideoRenderCallback * renderer)55 int32_t SetRenderer(VideoRenderCallback* renderer) {
56 rtc::CritScope cs(&stream_critical_);
57 renderer_ = renderer;
58 return 0;
59 }
60
StartRender()61 int32_t StartRender() {
62 rtc::CritScope cs(&stream_critical_);
63 running_ = true;
64 return 0;
65 }
66
StopRender()67 int32_t StopRender() {
68 rtc::CritScope cs(&stream_critical_);
69 running_ = false;
70 return 0;
71 }
72
73 private:
74 uint32_t stream_id_;
75 VideoRenderCallback* renderer_;
76 rtc::CriticalSection stream_critical_;
77 bool running_;
78 };
79
WebRtcPassthroughRender()80 WebRtcPassthroughRender::WebRtcPassthroughRender()
81 : window_(NULL) {
82 }
83
~WebRtcPassthroughRender()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
AddIncomingRenderStream(const uint32_t stream_id,const uint32_t zOrder,const float left,const float top,const float right,const float bottom)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 rtc::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
DeleteIncomingRenderStream(const uint32_t stream_id)111 int32_t WebRtcPassthroughRender::DeleteIncomingRenderStream(
112 const uint32_t stream_id) {
113 rtc::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
AddExternalRenderCallback(const uint32_t stream_id,webrtc::VideoRenderCallback * render_object)124 int32_t WebRtcPassthroughRender::AddExternalRenderCallback(
125 const uint32_t stream_id,
126 webrtc::VideoRenderCallback* render_object) {
127 rtc::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
HasIncomingRenderStream(const uint32_t stream_id) const136 bool WebRtcPassthroughRender::HasIncomingRenderStream(
137 const uint32_t stream_id) const {
138 return (FindStream(stream_id) != NULL);
139 }
140
PreferredVideoType() const141 webrtc::RawVideoType WebRtcPassthroughRender::PreferredVideoType() const {
142 return webrtc::kVideoI420;
143 }
144
StartRender(const uint32_t stream_id)145 int32_t WebRtcPassthroughRender::StartRender(const uint32_t stream_id) {
146 rtc::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
StopRender(const uint32_t stream_id)155 int32_t WebRtcPassthroughRender::StopRender(const uint32_t stream_id) {
156 rtc::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.
FindStream(const uint32_t stream_id) const167 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