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 |