Index: webrtc/modules/video_render/ios/video_render_ios_gles20.mm |
diff --git a/webrtc/modules/video_render/ios/video_render_ios_gles20.mm b/webrtc/modules/video_render/ios/video_render_ios_gles20.mm |
new file mode 100644 |
index 0000000000000000000000000000000000000000..6ad5db8b8cbcbc5b64b34b7cf584a7a4b71612c9 |
--- /dev/null |
+++ b/webrtc/modules/video_render/ios/video_render_ios_gles20.mm |
@@ -0,0 +1,285 @@ |
+/* |
+ * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. |
+ * |
+ * Use of this source code is governed by a BSD-style license |
+ * that can be found in the LICENSE file in the root of the source |
+ * tree. An additional intellectual property rights grant can be found |
+ * in the file PATENTS. All contributing project authors may |
+ * be found in the AUTHORS file in the root of the source tree. |
+ */ |
+ |
+#if !defined(__has_feature) || !__has_feature(objc_arc) |
+#error "This file requires ARC support." |
+#endif |
+ |
+#include "webrtc/modules/video_render/ios/video_render_ios_gles20.h" |
+#include "webrtc/system_wrappers/include/critical_section_wrapper.h" |
+#include "webrtc/system_wrappers/include/event_wrapper.h" |
+ |
+using namespace webrtc; |
+ |
+VideoRenderIosGles20::VideoRenderIosGles20(VideoRenderIosView* view, |
+ bool full_screen, |
+ int render_id) |
+ : gles_crit_sec_(CriticalSectionWrapper::CreateCriticalSection()), |
+ screen_update_event_(0), |
+ view_(view), |
+ window_rect_(), |
+ window_width_(0), |
+ window_height_(0), |
+ is_full_screen_(full_screen), |
+ agl_channels_(), |
+ z_order_to_channel_(), |
+ gles_context_([view context]), |
+ is_rendering_(true) { |
+ screen_update_thread_.reset(new rtc::PlatformThread( |
+ ScreenUpdateThreadProc, this, "ScreenUpdateGles20")); |
+ screen_update_event_ = EventTimerWrapper::Create(); |
+ GetWindowRect(window_rect_); |
+} |
+ |
+VideoRenderIosGles20::~VideoRenderIosGles20() { |
+ // Signal event to exit thread, then delete it |
+ rtc::PlatformThread* thread_wrapper = screen_update_thread_.release(); |
+ |
+ if (thread_wrapper) { |
+ screen_update_event_->Set(); |
+ screen_update_event_->StopTimer(); |
+ |
+ thread_wrapper->Stop(); |
+ delete thread_wrapper; |
+ delete screen_update_event_; |
+ screen_update_event_ = NULL; |
+ is_rendering_ = FALSE; |
+ } |
+ |
+ // Delete all channels |
+ std::map<int, VideoRenderIosChannel*>::iterator it = agl_channels_.begin(); |
+ while (it != agl_channels_.end()) { |
+ delete it->second; |
+ agl_channels_.erase(it); |
+ it = agl_channels_.begin(); |
+ } |
+ agl_channels_.clear(); |
+ |
+ // Clean the zOrder map |
+ std::multimap<int, int>::iterator z_it = z_order_to_channel_.begin(); |
+ while (z_it != z_order_to_channel_.end()) { |
+ z_order_to_channel_.erase(z_it); |
+ z_it = z_order_to_channel_.begin(); |
+ } |
+ z_order_to_channel_.clear(); |
+} |
+ |
+int VideoRenderIosGles20::Init() { |
+ CriticalSectionScoped cs(gles_crit_sec_.get()); |
+ |
+ if (!view_) { |
+ view_ = [[VideoRenderIosView alloc] init]; |
+ } |
+ |
+ if (![view_ createContext]) { |
+ return -1; |
+ } |
+ |
+ screen_update_thread_->Start(); |
+ screen_update_thread_->SetPriority(rtc::kRealtimePriority); |
+ |
+ // Start the event triggering the render process |
+ unsigned int monitor_freq = 60; |
+ screen_update_event_->StartTimer(true, 1000 / monitor_freq); |
+ |
+ window_width_ = window_rect_.right - window_rect_.left; |
+ window_height_ = window_rect_.bottom - window_rect_.top; |
+ |
+ return 0; |
+} |
+ |
+VideoRenderIosChannel* VideoRenderIosGles20::CreateEaglChannel(int channel, |
+ int z_order, |
+ float left, |
+ float top, |
+ float right, |
+ float bottom) { |
+ CriticalSectionScoped cs(gles_crit_sec_.get()); |
+ |
+ if (HasChannel(channel)) { |
+ return NULL; |
+ } |
+ |
+ VideoRenderIosChannel* new_eagl_channel = new VideoRenderIosChannel(view_); |
+ |
+ if (new_eagl_channel->SetStreamSettings(z_order, left, top, right, bottom) == |
+ -1) { |
+ return NULL; |
+ } |
+ |
+ agl_channels_[channel] = new_eagl_channel; |
+ z_order_to_channel_.insert(std::pair<int, int>(z_order, channel)); |
+ |
+ return new_eagl_channel; |
+} |
+ |
+int VideoRenderIosGles20::DeleteEaglChannel(int channel) { |
+ CriticalSectionScoped cs(gles_crit_sec_.get()); |
+ |
+ std::map<int, VideoRenderIosChannel*>::iterator it; |
+ it = agl_channels_.find(channel); |
+ if (it != agl_channels_.end()) { |
+ delete it->second; |
+ agl_channels_.erase(it); |
+ } else { |
+ return -1; |
+ } |
+ |
+ std::multimap<int, int>::iterator z_it = z_order_to_channel_.begin(); |
+ while (z_it != z_order_to_channel_.end()) { |
+ if (z_it->second == channel) { |
+ z_order_to_channel_.erase(z_it); |
+ break; |
+ } |
+ z_it++; |
+ } |
+ |
+ return 0; |
+} |
+ |
+bool VideoRenderIosGles20::HasChannel(int channel) { |
+ CriticalSectionScoped cs(gles_crit_sec_.get()); |
+ |
+ std::map<int, VideoRenderIosChannel*>::iterator it = |
+ agl_channels_.find(channel); |
+ |
+ if (it != agl_channels_.end()) { |
+ return true; |
+ } |
+ |
+ return false; |
+} |
+ |
+// Rendering process |
+bool VideoRenderIosGles20::ScreenUpdateThreadProc(void* obj) { |
+ return static_cast<VideoRenderIosGles20*>(obj)->ScreenUpdateProcess(); |
+} |
+ |
+bool VideoRenderIosGles20::ScreenUpdateProcess() { |
+ screen_update_event_->Wait(100); |
+ |
+ CriticalSectionScoped cs(gles_crit_sec_.get()); |
+ |
+ if (!is_rendering_) { |
+ return false; |
+ } |
+ |
+ if (!screen_update_thread_) { |
+ return false; |
+ } |
+ |
+ if (GetWindowRect(window_rect_) == -1) { |
+ return true; |
+ } |
+ |
+ if (window_width_ != (window_rect_.right - window_rect_.left) || |
+ window_height_ != (window_rect_.bottom - window_rect_.top)) { |
+ window_width_ = window_rect_.right - window_rect_.left; |
+ window_height_ = window_rect_.bottom - window_rect_.top; |
+ } |
+ |
+ // Check if there are any updated buffers |
+ bool updated = false; |
+ |
+ std::map<int, VideoRenderIosChannel*>::iterator it = agl_channels_.begin(); |
+ while (it != agl_channels_.end()) { |
+ VideoRenderIosChannel* agl_channel = it->second; |
+ |
+ updated = agl_channel->IsUpdated(); |
+ if (updated) { |
+ break; |
+ } |
+ it++; |
+ } |
+ |
+ if (updated) { |
+ // At least one buffer has been updated, we need to repaint the texture |
+ // Loop through all channels starting highest zOrder ending with lowest. |
+ for (std::multimap<int, int>::reverse_iterator r_it = |
+ z_order_to_channel_.rbegin(); |
+ r_it != z_order_to_channel_.rend(); |
+ r_it++) { |
+ int channel_id = r_it->second; |
+ std::map<int, VideoRenderIosChannel*>::iterator it = |
+ agl_channels_.find(channel_id); |
+ |
+ VideoRenderIosChannel* agl_channel = it->second; |
+ |
+ agl_channel->RenderOffScreenBuffer(); |
+ } |
+ |
+ [view_ presentFramebuffer]; |
+ } |
+ |
+ return true; |
+} |
+ |
+int VideoRenderIosGles20::GetWindowRect(Rect& rect) { |
+ CriticalSectionScoped cs(gles_crit_sec_.get()); |
+ |
+ if (!view_) { |
+ return -1; |
+ } |
+ |
+ CGRect bounds = [view_ bounds]; |
+ rect.top = bounds.origin.y; |
+ rect.left = bounds.origin.x; |
+ rect.bottom = bounds.size.height + bounds.origin.y; |
+ rect.right = bounds.size.width + bounds.origin.x; |
+ |
+ return 0; |
+} |
+ |
+int VideoRenderIosGles20::ChangeWindow(void* new_window) { |
+ CriticalSectionScoped cs(gles_crit_sec_.get()); |
+ |
+ view_ = (__bridge VideoRenderIosView*)new_window; |
+ |
+ return 0; |
+} |
+ |
+int VideoRenderIosGles20::StartRender() { |
+ is_rendering_ = true; |
+ return 0; |
+} |
+ |
+int VideoRenderIosGles20::StopRender() { |
+ is_rendering_ = false; |
+ return 0; |
+} |
+ |
+int VideoRenderIosGles20::GetScreenResolution(uint& screen_width, |
+ uint& screen_height) { |
+ screen_width = [view_ bounds].size.width; |
+ screen_height = [view_ bounds].size.height; |
+ return 0; |
+} |
+ |
+int VideoRenderIosGles20::SetStreamCropping(const uint stream_id, |
+ const float left, |
+ const float top, |
+ const float right, |
+ const float bottom) { |
+ // Check if there are any updated buffers |
+ // bool updated = false; |
+ uint counter = 0; |
+ |
+ std::map<int, VideoRenderIosChannel*>::iterator it = agl_channels_.begin(); |
+ while (it != agl_channels_.end()) { |
+ if (counter == stream_id) { |
+ VideoRenderIosChannel* agl_channel = it->second; |
+ agl_channel->SetStreamSettings(0, left, top, right, bottom); |
+ } |
+ counter++; |
+ it++; |
+ } |
+ |
+ return 0; |
+} |