| 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 |