OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. | |
3 * | |
4 * Use of this source code is governed by a BSD-style license | |
5 * that can be found in the LICENSE file in the root of the source | |
6 * tree. An additional intellectual property rights grant can be found | |
7 * in the file PATENTS. All contributing project authors may | |
8 * be found in the AUTHORS file in the root of the source tree. | |
9 */ | |
10 | |
11 #if !defined(__has_feature) || !__has_feature(objc_arc) | |
12 #error "This file requires ARC support." | |
13 #endif | |
14 | |
15 #include "webrtc/modules/video_render/ios/video_render_ios_gles20.h" | |
16 #include "webrtc/system_wrappers/include/critical_section_wrapper.h" | |
17 #include "webrtc/system_wrappers/include/event_wrapper.h" | |
18 | |
19 using namespace webrtc; | |
20 | |
21 VideoRenderIosGles20::VideoRenderIosGles20(VideoRenderIosView* view, | |
22 bool full_screen, | |
23 int render_id) | |
24 : gles_crit_sec_(CriticalSectionWrapper::CreateCriticalSection()), | |
25 screen_update_event_(0), | |
26 view_(view), | |
27 window_rect_(), | |
28 window_width_(0), | |
29 window_height_(0), | |
30 is_full_screen_(full_screen), | |
31 agl_channels_(), | |
32 z_order_to_channel_(), | |
33 gles_context_([view context]), | |
34 is_rendering_(true) { | |
35 screen_update_thread_.reset(new rtc::PlatformThread( | |
36 ScreenUpdateThreadProc, this, "ScreenUpdateGles20")); | |
37 screen_update_event_ = EventTimerWrapper::Create(); | |
38 GetWindowRect(window_rect_); | |
39 } | |
40 | |
41 VideoRenderIosGles20::~VideoRenderIosGles20() { | |
42 // Signal event to exit thread, then delete it | |
43 rtc::PlatformThread* thread_wrapper = screen_update_thread_.release(); | |
44 | |
45 if (thread_wrapper) { | |
46 screen_update_event_->Set(); | |
47 screen_update_event_->StopTimer(); | |
48 | |
49 thread_wrapper->Stop(); | |
50 delete thread_wrapper; | |
51 delete screen_update_event_; | |
52 screen_update_event_ = NULL; | |
53 is_rendering_ = FALSE; | |
54 } | |
55 | |
56 // Delete all channels | |
57 std::map<int, VideoRenderIosChannel*>::iterator it = agl_channels_.begin(); | |
58 while (it != agl_channels_.end()) { | |
59 delete it->second; | |
60 agl_channels_.erase(it); | |
61 it = agl_channels_.begin(); | |
62 } | |
63 agl_channels_.clear(); | |
64 | |
65 // Clean the zOrder map | |
66 std::multimap<int, int>::iterator z_it = z_order_to_channel_.begin(); | |
67 while (z_it != z_order_to_channel_.end()) { | |
68 z_order_to_channel_.erase(z_it); | |
69 z_it = z_order_to_channel_.begin(); | |
70 } | |
71 z_order_to_channel_.clear(); | |
72 } | |
73 | |
74 int VideoRenderIosGles20::Init() { | |
75 CriticalSectionScoped cs(gles_crit_sec_.get()); | |
76 | |
77 if (!view_) { | |
78 view_ = [[VideoRenderIosView alloc] init]; | |
79 } | |
80 | |
81 if (![view_ createContext]) { | |
82 return -1; | |
83 } | |
84 | |
85 screen_update_thread_->Start(); | |
86 screen_update_thread_->SetPriority(rtc::kRealtimePriority); | |
87 | |
88 // Start the event triggering the render process | |
89 unsigned int monitor_freq = 60; | |
90 screen_update_event_->StartTimer(true, 1000 / monitor_freq); | |
91 | |
92 window_width_ = window_rect_.right - window_rect_.left; | |
93 window_height_ = window_rect_.bottom - window_rect_.top; | |
94 | |
95 return 0; | |
96 } | |
97 | |
98 VideoRenderIosChannel* VideoRenderIosGles20::CreateEaglChannel(int channel, | |
99 int z_order, | |
100 float left, | |
101 float top, | |
102 float right, | |
103 float bottom) { | |
104 CriticalSectionScoped cs(gles_crit_sec_.get()); | |
105 | |
106 if (HasChannel(channel)) { | |
107 return NULL; | |
108 } | |
109 | |
110 VideoRenderIosChannel* new_eagl_channel = new VideoRenderIosChannel(view_); | |
111 | |
112 if (new_eagl_channel->SetStreamSettings(z_order, left, top, right, bottom) == | |
113 -1) { | |
114 return NULL; | |
115 } | |
116 | |
117 agl_channels_[channel] = new_eagl_channel; | |
118 z_order_to_channel_.insert(std::pair<int, int>(z_order, channel)); | |
119 | |
120 return new_eagl_channel; | |
121 } | |
122 | |
123 int VideoRenderIosGles20::DeleteEaglChannel(int channel) { | |
124 CriticalSectionScoped cs(gles_crit_sec_.get()); | |
125 | |
126 std::map<int, VideoRenderIosChannel*>::iterator it; | |
127 it = agl_channels_.find(channel); | |
128 if (it != agl_channels_.end()) { | |
129 delete it->second; | |
130 agl_channels_.erase(it); | |
131 } else { | |
132 return -1; | |
133 } | |
134 | |
135 std::multimap<int, int>::iterator z_it = z_order_to_channel_.begin(); | |
136 while (z_it != z_order_to_channel_.end()) { | |
137 if (z_it->second == channel) { | |
138 z_order_to_channel_.erase(z_it); | |
139 break; | |
140 } | |
141 z_it++; | |
142 } | |
143 | |
144 return 0; | |
145 } | |
146 | |
147 bool VideoRenderIosGles20::HasChannel(int channel) { | |
148 CriticalSectionScoped cs(gles_crit_sec_.get()); | |
149 | |
150 std::map<int, VideoRenderIosChannel*>::iterator it = | |
151 agl_channels_.find(channel); | |
152 | |
153 if (it != agl_channels_.end()) { | |
154 return true; | |
155 } | |
156 | |
157 return false; | |
158 } | |
159 | |
160 // Rendering process | |
161 bool VideoRenderIosGles20::ScreenUpdateThreadProc(void* obj) { | |
162 return static_cast<VideoRenderIosGles20*>(obj)->ScreenUpdateProcess(); | |
163 } | |
164 | |
165 bool VideoRenderIosGles20::ScreenUpdateProcess() { | |
166 screen_update_event_->Wait(100); | |
167 | |
168 CriticalSectionScoped cs(gles_crit_sec_.get()); | |
169 | |
170 if (!is_rendering_) { | |
171 return false; | |
172 } | |
173 | |
174 if (!screen_update_thread_) { | |
175 return false; | |
176 } | |
177 | |
178 if (GetWindowRect(window_rect_) == -1) { | |
179 return true; | |
180 } | |
181 | |
182 if (window_width_ != (window_rect_.right - window_rect_.left) || | |
183 window_height_ != (window_rect_.bottom - window_rect_.top)) { | |
184 window_width_ = window_rect_.right - window_rect_.left; | |
185 window_height_ = window_rect_.bottom - window_rect_.top; | |
186 } | |
187 | |
188 // Check if there are any updated buffers | |
189 bool updated = false; | |
190 | |
191 std::map<int, VideoRenderIosChannel*>::iterator it = agl_channels_.begin(); | |
192 while (it != agl_channels_.end()) { | |
193 VideoRenderIosChannel* agl_channel = it->second; | |
194 | |
195 updated = agl_channel->IsUpdated(); | |
196 if (updated) { | |
197 break; | |
198 } | |
199 it++; | |
200 } | |
201 | |
202 if (updated) { | |
203 // At least one buffer has been updated, we need to repaint the texture | |
204 // Loop through all channels starting highest zOrder ending with lowest. | |
205 for (std::multimap<int, int>::reverse_iterator r_it = | |
206 z_order_to_channel_.rbegin(); | |
207 r_it != z_order_to_channel_.rend(); | |
208 r_it++) { | |
209 int channel_id = r_it->second; | |
210 std::map<int, VideoRenderIosChannel*>::iterator it = | |
211 agl_channels_.find(channel_id); | |
212 | |
213 VideoRenderIosChannel* agl_channel = it->second; | |
214 | |
215 agl_channel->RenderOffScreenBuffer(); | |
216 } | |
217 | |
218 [view_ presentFramebuffer]; | |
219 } | |
220 | |
221 return true; | |
222 } | |
223 | |
224 int VideoRenderIosGles20::GetWindowRect(Rect& rect) { | |
225 CriticalSectionScoped cs(gles_crit_sec_.get()); | |
226 | |
227 if (!view_) { | |
228 return -1; | |
229 } | |
230 | |
231 CGRect bounds = [view_ bounds]; | |
232 rect.top = bounds.origin.y; | |
233 rect.left = bounds.origin.x; | |
234 rect.bottom = bounds.size.height + bounds.origin.y; | |
235 rect.right = bounds.size.width + bounds.origin.x; | |
236 | |
237 return 0; | |
238 } | |
239 | |
240 int VideoRenderIosGles20::ChangeWindow(void* new_window) { | |
241 CriticalSectionScoped cs(gles_crit_sec_.get()); | |
242 | |
243 view_ = (__bridge VideoRenderIosView*)new_window; | |
244 | |
245 return 0; | |
246 } | |
247 | |
248 int VideoRenderIosGles20::StartRender() { | |
249 is_rendering_ = true; | |
250 return 0; | |
251 } | |
252 | |
253 int VideoRenderIosGles20::StopRender() { | |
254 is_rendering_ = false; | |
255 return 0; | |
256 } | |
257 | |
258 int VideoRenderIosGles20::GetScreenResolution(uint& screen_width, | |
259 uint& screen_height) { | |
260 screen_width = [view_ bounds].size.width; | |
261 screen_height = [view_ bounds].size.height; | |
262 return 0; | |
263 } | |
264 | |
265 int VideoRenderIosGles20::SetStreamCropping(const uint stream_id, | |
266 const float left, | |
267 const float top, | |
268 const float right, | |
269 const float bottom) { | |
270 // Check if there are any updated buffers | |
271 // bool updated = false; | |
272 uint counter = 0; | |
273 | |
274 std::map<int, VideoRenderIosChannel*>::iterator it = agl_channels_.begin(); | |
275 while (it != agl_channels_.end()) { | |
276 if (counter == stream_id) { | |
277 VideoRenderIosChannel* agl_channel = it->second; | |
278 agl_channel->SetStreamSettings(0, left, top, right, bottom); | |
279 } | |
280 counter++; | |
281 it++; | |
282 } | |
283 | |
284 return 0; | |
285 } | |
OLD | NEW |