Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(40)

Unified Diff: webrtc/modules/video_render/mac/video_render_agl.cc

Issue 1923613003: Revert of Delete video_render module. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: webrtc/modules/video_render/mac/video_render_agl.cc
diff --git a/webrtc/modules/video_render/mac/video_render_agl.cc b/webrtc/modules/video_render/mac/video_render_agl.cc
new file mode 100644
index 0000000000000000000000000000000000000000..3243563b2bf901e1e268637273247fa0e72ba3f2
--- /dev/null
+++ b/webrtc/modules/video_render/mac/video_render_agl.cc
@@ -0,0 +1,1987 @@
+/*
+ * Copyright (c) 2012 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.
+ */
+
+#include "webrtc/engine_configurations.h"
+
+#if defined(CARBON_RENDERING)
+
+#include "webrtc/modules/video_render/mac/video_render_agl.h"
+
+// includes
+#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
+#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
+#include "webrtc/system_wrappers/include/event_wrapper.h"
+#include "webrtc/system_wrappers/include/trace.h"
+
+namespace webrtc {
+
+/*
+ *
+ * VideoChannelAGL
+ *
+ */
+
+#pragma mark VideoChannelAGL constructor
+
+VideoChannelAGL::VideoChannelAGL(AGLContext& aglContext, int iId, VideoRenderAGL* owner) :
+ _aglContext( aglContext),
+ _id( iId),
+ _owner( owner),
+ _width( 0),
+ _height( 0),
+ _stretchedWidth( 0),
+ _stretchedHeight( 0),
+ _startWidth( 0.0f),
+ _startHeight( 0.0f),
+ _stopWidth( 0.0f),
+ _stopHeight( 0.0f),
+ _xOldWidth( 0),
+ _yOldHeight( 0),
+ _oldStretchedHeight(0),
+ _oldStretchedWidth( 0),
+ _buffer( 0),
+ _bufferSize( 0),
+ _incomingBufferSize(0),
+ _bufferIsUpdated( false),
+ _sizeInitialized( false),
+ _numberOfStreams( 0),
+ _bVideoSizeStartedChanging(false),
+ _pixelFormat( GL_RGBA),
+ _pixelDataType( GL_UNSIGNED_INT_8_8_8_8),
+ _texture( 0)
+
+{
+ //WEBRTC_TRACE(kTraceInfo, kTraceVideoRenderer, _id, "%s:%d Constructor", __FUNCTION__, __LINE__);
+}
+
+VideoChannelAGL::~VideoChannelAGL()
+{
+ //WEBRTC_TRACE(kTraceInfo, kTraceVideoRenderer, _id, "%s:%d Destructor", __FUNCTION__, __LINE__);
+ if (_buffer)
+ {
+ delete [] _buffer;
+ _buffer = NULL;
+ }
+
+ aglSetCurrentContext(_aglContext);
+
+ if (_texture != 0)
+ {
+ glDeleteTextures(1, (const GLuint*) &_texture);
+ _texture = 0;
+ }
+}
+
+int32_t VideoChannelAGL::RenderFrame(const uint32_t streamId,
+ VideoFrame& videoFrame) {
+ _owner->LockAGLCntx();
+ if (_width != videoFrame.width() ||
+ _height != videoFrame.height()) {
+ if (FrameSizeChange(videoFrame.width(), videoFrame.height(), 1) == -1) {
+ WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id, "%s:%d FrameSize
+ Change returned an error", __FUNCTION__, __LINE__);
+ _owner->UnlockAGLCntx();
+ return -1;
+ }
+ }
+
+ _owner->UnlockAGLCntx();
+ return DeliverFrame(videoFrame);
+}
+
+int VideoChannelAGL::UpdateSize(int /*width*/, int /*height*/)
+{
+ _owner->LockAGLCntx();
+ _owner->UnlockAGLCntx();
+ return 0;
+}
+
+int VideoChannelAGL::UpdateStretchSize(int stretchHeight, int stretchWidth)
+{
+
+ _owner->LockAGLCntx();
+ _stretchedHeight = stretchHeight;
+ _stretchedWidth = stretchWidth;
+ _owner->UnlockAGLCntx();
+ return 0;
+}
+
+int VideoChannelAGL::FrameSizeChange(int width, int height, int numberOfStreams)
+{
+ // We'll get a new frame size from VideoAPI, prepare the buffer
+
+ _owner->LockAGLCntx();
+
+ if (width == _width && _height == height)
+ {
+ // We already have a correct buffer size
+ _numberOfStreams = numberOfStreams;
+ _owner->UnlockAGLCntx();
+ return 0;
+ }
+
+ _width = width;
+ _height = height;
+
+ // Delete the old buffer, create a new one with correct size.
+ if (_buffer)
+ {
+ delete [] _buffer;
+ _bufferSize = 0;
+ }
+
+ _incomingBufferSize = CalcBufferSize(kI420, _width, _height);
+ _bufferSize = CalcBufferSize(kARGB, _width, _height);//_width * _height * bytesPerPixel;
+ _buffer = new unsigned char [_bufferSize];
+ memset(_buffer, 0, _bufferSize * sizeof(unsigned char));
+
+ if (aglSetCurrentContext(_aglContext) == false)
+ {
+ _owner->UnlockAGLCntx();
+ return -1;
+ }
+
+ // Delete a possible old texture
+ if (_texture != 0)
+ {
+ glDeleteTextures(1, (const GLuint*) &_texture);
+ _texture = 0;
+ }
+
+ // Create a new texture
+ glGenTextures(1, (GLuint *) &_texture);
+
+ GLenum glErr = glGetError();
+
+ if (glErr != GL_NO_ERROR)
+ {
+ }
+
+ // Do the setup for both textures
+ // Note: we setup two textures even if we're not running full screen
+ glBindTexture(GL_TEXTURE_RECTANGLE_EXT, _texture);
+
+ // Set texture parameters
+ glTexParameterf(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_PRIORITY, 1.0);
+
+ glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ //glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ //glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+
+ glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+ glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_STORAGE_HINT_APPLE, GL_STORAGE_SHARED_APPLE);
+
+ // Maximum width/height for a texture
+ GLint texSize;
+ glGetIntegerv(GL_MAX_TEXTURE_SIZE, &texSize);
+
+ if (texSize < _width || texSize < _height)
+ {
+ // Image too big for memory
+ _owner->UnlockAGLCntx();
+ return -1;
+ }
+
+ // Set up th texture type and size
+ glTexImage2D(GL_TEXTURE_RECTANGLE_EXT, // target
+ 0, // level
+ GL_RGBA, // internal format
+ _width, // width
+ _height, // height
+ 0, // border 0/1 = off/on
+ _pixelFormat, // format, GL_BGRA
+ _pixelDataType, // data type, GL_UNSIGNED_INT_8_8_8_8
+ _buffer); // pixel data
+
+ glErr = glGetError();
+ if (glErr != GL_NO_ERROR)
+ {
+ _owner->UnlockAGLCntx();
+ return -1;
+ }
+
+ _owner->UnlockAGLCntx();
+ return 0;
+}
+
+// Called from video engine when a new frame should be rendered.
+int VideoChannelAGL::DeliverFrame(const VideoFrame& videoFrame) {
+ _owner->LockAGLCntx();
+
+ if (_texture == 0) {
+ _owner->UnlockAGLCntx();
+ return 0;
+ }
+
+ if (CalcBufferSize(kI420, videoFrame.width(), videoFrame.height()) !=
+ _incomingBufferSize) {
+ _owner->UnlockAGLCntx();
+ return -1;
+ }
+
+ // Setting stride = width.
+ int rgbret = ConvertFromYV12(videoFrame, kBGRA, 0, _buffer);
+ if (rgbret < 0) {
+ _owner->UnlockAGLCntx();
+ return -1;
+ }
+
+ aglSetCurrentContext(_aglContext);
+
+ // Put the new frame into the graphic card texture.
+ // Make sure this texture is the active one
+ glBindTexture(GL_TEXTURE_RECTANGLE_EXT, _texture);
+ GLenum glErr = glGetError();
+ if (glErr != GL_NO_ERROR) {
+ _owner->UnlockAGLCntx();
+ return -1;
+ }
+
+ // Copy buffer to texture
+ glTexSubImage2D(GL_TEXTURE_RECTANGLE_EXT,
+ 0, // Level, not use
+ 0, // start point x, (low left of pic)
+ 0, // start point y,
+ _width, // width
+ _height, // height
+ _pixelFormat, // pictue format for _buffer
+ _pixelDataType, // data type of _buffer
+ (const GLvoid*) _buffer); // the pixel data
+
+ if (glGetError() != GL_NO_ERROR) {
+ _owner->UnlockAGLCntx();
+ return -1;
+ }
+
+ _bufferIsUpdated = true;
+ _owner->UnlockAGLCntx();
+
+ return 0;
+}
+
+int VideoChannelAGL::RenderOffScreenBuffer()
+{
+
+ _owner->LockAGLCntx();
+
+ if (_texture == 0)
+ {
+ _owner->UnlockAGLCntx();
+ return 0;
+ }
+
+ GLfloat xStart = 2.0f * _startWidth - 1.0f;
+ GLfloat xStop = 2.0f * _stopWidth - 1.0f;
+ GLfloat yStart = 1.0f - 2.0f * _stopHeight;
+ GLfloat yStop = 1.0f - 2.0f * _startHeight;
+
+ aglSetCurrentContext(_aglContext);
+ glBindTexture(GL_TEXTURE_RECTANGLE_EXT, _texture);
+
+ if(_stretchedWidth != _oldStretchedWidth || _stretchedHeight != _oldStretchedHeight)
+ {
+ glViewport(0, 0, _stretchedWidth, _stretchedHeight);
+ }
+ _oldStretchedHeight = _stretchedHeight;
+ _oldStretchedWidth = _stretchedWidth;
+
+ // Now really put the texture into the framebuffer
+ glLoadIdentity();
+
+ glEnable(GL_TEXTURE_RECTANGLE_EXT);
+
+ glBegin(GL_POLYGON);
+ {
+ glTexCoord2f(0.0, 0.0); glVertex2f(xStart, yStop);
+ glTexCoord2f(_width, 0.0); glVertex2f(xStop, yStop);
+ glTexCoord2f(_width, _height); glVertex2f(xStop, yStart);
+ glTexCoord2f(0.0, _height); glVertex2f(xStart, yStart);
+ }
+ glEnd();
+
+ glDisable(GL_TEXTURE_RECTANGLE_EXT);
+
+ _bufferIsUpdated = false;
+
+ _owner->UnlockAGLCntx();
+ return 0;
+}
+
+int VideoChannelAGL::IsUpdated(bool& isUpdated)
+{
+ _owner->LockAGLCntx();
+ isUpdated = _bufferIsUpdated;
+ _owner->UnlockAGLCntx();
+
+ return 0;
+}
+
+int VideoChannelAGL::SetStreamSettings(int /*streamId*/, float startWidth, float startHeight, float stopWidth, float stopHeight)
+{
+
+ _owner->LockAGLCntx();
+
+ _startWidth = startWidth;
+ _stopWidth = stopWidth;
+ _startHeight = startHeight;
+ _stopHeight = stopHeight;
+
+ int oldWidth = _width;
+ int oldHeight = _height;
+ int oldNumberOfStreams = _numberOfStreams;
+
+ _width = 0;
+ _height = 0;
+
+ int retVal = FrameSizeChange(oldWidth, oldHeight, oldNumberOfStreams);
+
+ _owner->UnlockAGLCntx();
+
+ return retVal;
+}
+
+int VideoChannelAGL::SetStreamCropSettings(int /*streamId*/, float /*startWidth*/, float /*startHeight*/, float /*stopWidth*/, float /*stopHeight*/)
+{
+ return -1;
+}
+
+#pragma mark VideoRenderAGL WindowRef constructor
+
+VideoRenderAGL::VideoRenderAGL(WindowRef windowRef, bool fullscreen, int iId) :
+_hiviewRef( 0),
+_windowRef( windowRef),
+_fullScreen( fullscreen),
+_id( iId),
+_renderCritSec(*CriticalSectionWrapper::CreateCriticalSection()),
+_screenUpdateEvent( 0),
+_isHIViewRef( false),
+_aglContext( 0),
+_windowWidth( 0),
+_windowHeight( 0),
+_lastWindowWidth( -1),
+_lastWindowHeight( -1),
+_lastHiViewWidth( -1),
+_lastHiViewHeight( -1),
+_currentParentWindowHeight( 0),
+_currentParentWindowWidth( 0),
+_currentParentWindowBounds( ),
+_windowHasResized( false),
+_lastParentWindowBounds( ),
+_currentHIViewBounds( ),
+_lastHIViewBounds( ),
+_windowRect( ),
+_aglChannels( ),
+_zOrderToChannel( ),
+_hiviewEventHandlerRef( NULL),
+_windowEventHandlerRef( NULL),
+_currentViewBounds( ),
+_lastViewBounds( ),
+_renderingIsPaused( false),
+
+{
+ //WEBRTC_TRACE(kTraceInfo, kTraceVideoRenderer, _id, "%s");
+
+ _screenUpdateThread.reset(
+ new rtc::PlatformThread(ScreenUpdateThreadProc, this, "ScreenUpdate"));
+ _screenUpdateEvent = EventWrapper::Create();
+
+ if(!IsValidWindowPtr(_windowRef))
+ {
+ //WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id, "%s:%d Invalid WindowRef:0x%x", __FUNCTION__, __LINE__, _windowRef);
+ }
+ else
+ {
+ //WEBRTC_TRACE(kTraceDebug, kTraceVideoRenderer, _id, "%s:%d WindowRef 0x%x is valid", __FUNCTION__, __LINE__, _windowRef);
+ }
+
+ GetWindowRect(_windowRect);
+
+ _lastViewBounds.origin.x = 0;
+ _lastViewBounds.origin.y = 0;
+ _lastViewBounds.size.width = 0;
+ _lastViewBounds.size.height = 0;
+
+}
+
+// this is a static function. It has been registered (in class constructor) to be called on various window redrawing or resizing.
+// Since it is a static method, I have passed in "this" as the userData (one and only allowed) parameter, then calling member methods on it.
+#pragma mark WindowRef Event Handler
+pascal OSStatus VideoRenderAGL::sHandleWindowResized (EventHandlerCallRef /*nextHandler*/,
+ EventRef theEvent,
+ void* userData)
+{
+ WindowRef windowRef = NULL;
+
+ int eventType = GetEventKind(theEvent);
+
+ // see https://dcs.sourcerepo.com/dcs/tox_view/trunk/tox/libraries/i686-win32/include/quicktime/CarbonEvents.h for a list of codes
+ GetEventParameter (theEvent,
+ kEventParamDirectObject,
+ typeWindowRef,
+ NULL,
+ sizeof (WindowRef),
+ NULL,
+ &windowRef);
+
+ VideoRenderAGL* obj = (VideoRenderAGL*)(userData);
+
+ bool updateUI = true;
+ if(kEventWindowBoundsChanged == eventType)
+ {
+ }
+ else if(kEventWindowBoundsChanging == eventType)
+ {
+ }
+ else if(kEventWindowZoomed == eventType)
+ {
+ }
+ else if(kEventWindowExpanding == eventType)
+ {
+ }
+ else if(kEventWindowExpanded == eventType)
+ {
+ }
+ else if(kEventWindowClickResizeRgn == eventType)
+ {
+ }
+ else if(kEventWindowClickDragRgn == eventType)
+ {
+ }
+ else
+ {
+ updateUI = false;
+ }
+
+ if(true == updateUI)
+ {
+ obj->ParentWindowResized(windowRef);
+ obj->UpdateClipping();
+ obj->RenderOffScreenBuffers();
+ }
+
+ return noErr;
+}
+
+#pragma mark VideoRenderAGL HIViewRef constructor
+
+VideoRenderAGL::VideoRenderAGL(HIViewRef windowRef, bool fullscreen, int iId) :
+_hiviewRef( windowRef),
+_windowRef( 0),
+_fullScreen( fullscreen),
+_id( iId),
+_renderCritSec(*CriticalSectionWrapper::CreateCriticalSection()),
+_screenUpdateEvent( 0),
+_isHIViewRef( false),
+_aglContext( 0),
+_windowWidth( 0),
+_windowHeight( 0),
+_lastWindowWidth( -1),
+_lastWindowHeight( -1),
+_lastHiViewWidth( -1),
+_lastHiViewHeight( -1),
+_currentParentWindowHeight( 0),
+_currentParentWindowWidth( 0),
+_currentParentWindowBounds( ),
+_windowHasResized( false),
+_lastParentWindowBounds( ),
+_currentHIViewBounds( ),
+_lastHIViewBounds( ),
+_windowRect( ),
+_aglChannels( ),
+_zOrderToChannel( ),
+_hiviewEventHandlerRef( NULL),
+_windowEventHandlerRef( NULL),
+_currentViewBounds( ),
+_lastViewBounds( ),
+_renderingIsPaused( false),
+{
+ //WEBRTC_TRACE(kTraceDebug, "%s:%d Constructor", __FUNCTION__, __LINE__);
+ // _renderCritSec = CriticalSectionWrapper::CreateCriticalSection();
+
+ _screenUpdateThread.reset(new rtc::PlatformThread(
+ ScreenUpdateThreadProc, this, "ScreenUpdateThread"));
+ _screenUpdateEvent = EventWrapper::Create();
+
+ GetWindowRect(_windowRect);
+
+ _lastViewBounds.origin.x = 0;
+ _lastViewBounds.origin.y = 0;
+ _lastViewBounds.size.width = 0;
+ _lastViewBounds.size.height = 0;
+
+#ifdef NEW_HIVIEW_PARENT_EVENT_HANDLER
+ // This gets the parent window of the HIViewRef that's passed in and installs a WindowRef event handler on it
+ // The event handler looks for window resize events and adjusts the offset of the controls.
+
+ //WEBRTC_TRACE(kTraceDebug, "%s:%d Installing Eventhandler for hiviewRef's parent window", __FUNCTION__, __LINE__);
+
+
+ static const EventTypeSpec windowEventTypes[] =
+ {
+ kEventClassWindow, kEventWindowBoundsChanged,
+ kEventClassWindow, kEventWindowBoundsChanging,
+ kEventClassWindow, kEventWindowZoomed,
+ kEventClassWindow, kEventWindowExpanded,
+ kEventClassWindow, kEventWindowClickResizeRgn,
+ kEventClassWindow, kEventWindowClickDragRgn
+ };
+
+ WindowRef parentWindow = HIViewGetWindow(windowRef);
+
+ InstallWindowEventHandler (parentWindow,
+ NewEventHandlerUPP (sHandleWindowResized),
+ GetEventTypeCount(windowEventTypes),
+ windowEventTypes,
+ (void *) this, // this is an arbitrary parameter that will be passed on to your event handler when it is called later
+ &_windowEventHandlerRef);
+
+#endif
+
+#ifdef NEW_HIVIEW_EVENT_HANDLER
+ //WEBRTC_TRACE(kTraceDebug, "%s:%d Installing Eventhandler for hiviewRef", __FUNCTION__, __LINE__);
+
+ static const EventTypeSpec hiviewEventTypes[] =
+ {
+ kEventClassControl, kEventControlBoundsChanged,
+ kEventClassControl, kEventControlDraw
+ // kEventControlDragLeave
+ // kEventControlDragReceive
+ // kEventControlGetFocusPart
+ // kEventControlApplyBackground
+ // kEventControlDraw
+ // kEventControlHit
+
+ };
+
+ HIViewInstallEventHandler(_hiviewRef,
+ NewEventHandlerUPP(sHandleHiViewResized),
+ GetEventTypeCount(hiviewEventTypes),
+ hiviewEventTypes,
+ (void *) this,
+ &_hiviewEventHandlerRef);
+
+#endif
+}
+
+// this is a static function. It has been registered (in constructor) to be called on various window redrawing or resizing.
+// Since it is a static method, I have passed in "this" as the userData (one and only allowed) parameter, then calling member methods on it.
+#pragma mark HIViewRef Event Handler
+pascal OSStatus VideoRenderAGL::sHandleHiViewResized (EventHandlerCallRef nextHandler, EventRef theEvent, void* userData)
+{
+ //static int callbackCounter = 1;
+ HIViewRef hiviewRef = NULL;
+
+ // see https://dcs.sourcerepo.com/dcs/tox_view/trunk/tox/libraries/i686-win32/include/quicktime/CarbonEvents.h for a list of codes
+ int eventType = GetEventKind(theEvent);
+ OSStatus status = noErr;
+ status = GetEventParameter (theEvent,
+ kEventParamDirectObject,
+ typeControlRef,
+ NULL,
+ sizeof (ControlRef),
+ NULL,
+ &hiviewRef);
+
+ VideoRenderAGL* obj = (VideoRenderAGL*)(userData);
+ WindowRef parentWindow = HIViewGetWindow(hiviewRef);
+ bool updateUI = true;
+
+ if(kEventControlBoundsChanged == eventType)
+ {
+ }
+ else if(kEventControlDraw == eventType)
+ {
+ }
+ else
+ {
+ updateUI = false;
+ }
+
+ if(true == updateUI)
+ {
+ obj->ParentWindowResized(parentWindow);
+ obj->UpdateClipping();
+ obj->RenderOffScreenBuffers();
+ }
+
+ return status;
+}
+
+VideoRenderAGL::~VideoRenderAGL()
+{
+
+ //WEBRTC_TRACE(kTraceDebug, "%s:%d Destructor", __FUNCTION__, __LINE__);
+
+
+#ifdef USE_EVENT_HANDLERS
+ // remove event handlers
+ OSStatus status;
+ if(_isHIViewRef)
+ {
+ status = RemoveEventHandler(_hiviewEventHandlerRef);
+ }
+ else
+ {
+ status = RemoveEventHandler(_windowEventHandlerRef);
+ }
+ if(noErr != status)
+ {
+ if(_isHIViewRef)
+ {
+
+ //WEBRTC_TRACE(kTraceDebug, "%s:%d Failed to remove hiview event handler: %d", __FUNCTION__, __LINE__, (int)_hiviewEventHandlerRef);
+ }
+ else
+ {
+ //WEBRTC_TRACE(kTraceDebug, "%s:%d Failed to remove window event handler %d", __FUNCTION__, __LINE__, (int)_windowEventHandlerRef);
+ }
+ }
+
+#endif
+
+ OSStatus status;
+#ifdef NEW_HIVIEW_PARENT_EVENT_HANDLER
+ if(_windowEventHandlerRef)
+ {
+ status = RemoveEventHandler(_windowEventHandlerRef);
+ if(status != noErr)
+ {
+ //WEBRTC_TRACE(kTraceDebug, "%s:%d failed to remove window event handler %d", __FUNCTION__, __LINE__, (int)_windowEventHandlerRef);
+ }
+ }
+#endif
+
+#ifdef NEW_HIVIEW_EVENT_HANDLER
+ if(_hiviewEventHandlerRef)
+ {
+ status = RemoveEventHandler(_hiviewEventHandlerRef);
+ if(status != noErr)
+ {
+ //WEBRTC_TRACE(kTraceDebug, "%s:%d Failed to remove hiview event handler: %d", __FUNCTION__, __LINE__, (int)_hiviewEventHandlerRef);
+ }
+ }
+#endif
+
+ // Signal event to exit thread, then delete it
+ rtc::PlatformThread* tmpPtr = _screenUpdateThread.release();
+
+ if (tmpPtr)
+ {
+ _screenUpdateEvent->Set();
+ _screenUpdateEvent->StopTimer();
+
+ tmpPtr->Stop();
+ delete tmpPtr;
+ delete _screenUpdateEvent;
+ _screenUpdateEvent = NULL;
+ }
+
+ if (_aglContext != 0)
+ {
+ aglSetCurrentContext(_aglContext);
+ aglDestroyContext(_aglContext);
+ _aglContext = 0;
+ }
+
+ // Delete all channels
+ std::map<int, VideoChannelAGL*>::iterator it = _aglChannels.begin();
+ while (it!= _aglChannels.end())
+ {
+ delete it->second;
+ _aglChannels.erase(it);
+ it = _aglChannels.begin();
+ }
+ _aglChannels.clear();
+
+ // Clean the zOrder map
+ std::multimap<int, int>::iterator zIt = _zOrderToChannel.begin();
+ while(zIt != _zOrderToChannel.end())
+ {
+ _zOrderToChannel.erase(zIt);
+ zIt = _zOrderToChannel.begin();
+ }
+ _zOrderToChannel.clear();
+
+ //delete _renderCritSec;
+
+
+}
+
+int VideoRenderAGL::GetOpenGLVersion(int& aglMajor, int& aglMinor)
+{
+ aglGetVersion((GLint *) &aglMajor, (GLint *) &aglMinor);
+ return 0;
+}
+
+int VideoRenderAGL::Init()
+{
+ LockAGLCntx();
+
+ // Start rendering thread...
+ if (!_screenUpdateThread)
+ {
+ UnlockAGLCntx();
+ //WEBRTC_TRACE(kTraceError, "%s:%d Thread not created", __FUNCTION__, __LINE__);
+ return -1;
+ }
+ _screenUpdateThread->Start();
+ _screenUpdateThread->SetPriority(rtc::kRealtimePriority);
+
+ // Start the event triggering the render process
+ unsigned int monitorFreq = 60;
+ _screenUpdateEvent->StartTimer(true, 1000/monitorFreq);
+
+ // Create mixing textures
+ if (CreateMixingContext() == -1)
+ {
+ //WEBRTC_TRACE(kTraceError, "%s:%d Could not create a mixing context", __FUNCTION__, __LINE__);
+ UnlockAGLCntx();
+ return -1;
+ }
+
+ UnlockAGLCntx();
+ return 0;
+}
+
+VideoChannelAGL* VideoRenderAGL::CreateAGLChannel(int channel, int zOrder, float startWidth, float startHeight, float stopWidth, float stopHeight)
+{
+
+ LockAGLCntx();
+
+ //WEBRTC_TRACE(kTraceInfo, "%s:%d Creating AGL channel: %d", __FUNCTION__, __LINE__, channel);
+
+ if (HasChannel(channel))
+ {
+ //WEBRTC_TRACE(kTraceError, "%s:%d Channel already exists", __FUNCTION__, __LINE__);
+ UnlockAGLCntx();k
+ return NULL;
+ }
+
+ if (_zOrderToChannel.find(zOrder) != _zOrderToChannel.end())
+ {
+ // There are already one channel using this zOrder
+ // TODO: Allow multiple channels with same zOrder
+ }
+
+ VideoChannelAGL* newAGLChannel = new VideoChannelAGL(_aglContext, _id, this);
+
+ if (newAGLChannel->SetStreamSettings(0, startWidth, startHeight, stopWidth, stopHeight) == -1)
+ {
+ if (newAGLChannel)
+ {
+ delete newAGLChannel;
+ newAGLChannel = NULL;
+ }
+ //WEBRTC_LOG(kTraceError, "Could not create AGL channel");
+ //WEBRTC_TRACE(kTraceError, "%s:%d Could not create AGL channel", __FUNCTION__, __LINE__);
+ UnlockAGLCntx();
+ return NULL;
+ }
+k
+ _aglChannels[channel] = newAGLChannel;
+ _zOrderToChannel.insert(std::pair<int, int>(zOrder, channel));
+
+ UnlockAGLCntx();
+ return newAGLChannel;
+}
+
+int VideoRenderAGL::DeleteAllAGLChannels()
+{
+ CriticalSectionScoped cs(&_renderCritSec);
+
+ //WEBRTC_TRACE(kTraceInfo, "%s:%d Deleting all AGL channels", __FUNCTION__, __LINE__);
+ //int i = 0 ;
+ std::map<int, VideoChannelAGL*>::iterator it;
+ it = _aglChannels.begin();
+
+ while (it != _aglChannels.end())
+ {
+ VideoChannelAGL* channel = it->second;
+ if (channel)
+ delete channel;
+
+ _aglChannels.erase(it);
+ it = _aglChannels.begin();
+ }
+ _aglChannels.clear();
+ return 0;
+}
+
+int VideoRenderAGL::DeleteAGLChannel(int channel)
+{
+ CriticalSectionScoped cs(&_renderCritSec);
+ //WEBRTC_TRACE(kTraceDebug, "%s:%d Deleting AGL channel %d", __FUNCTION__, __LINE__, channel);
+
+ std::map<int, VideoChannelAGL*>::iterator it;
+ it = _aglChannels.find(channel);
+ if (it != _aglChannels.end())
+ {
+ delete it->second;
+ _aglChannels.erase(it);
+ }
+ else
+ {
+ //WEBRTC_TRACE(kTraceWarning, "%s:%d Channel not found", __FUNCTION__, __LINE__);
+ return -1;
+ }
+
+ std::multimap<int, int>::iterator zIt = _zOrderToChannel.begin();
+ while( zIt != _zOrderToChannel.end())
+ {
+ if (zIt->second == channel)
+ {
+ _zOrderToChannel.erase(zIt);
+ break;
+ }
+ zIt++;// = _zOrderToChannel.begin();
+ }
+
+ return 0;
+}
+
+int VideoRenderAGL::StopThread()
+{
+ CriticalSectionScoped cs(&_renderCritSec);
+ rtc::PlatformThread* tmpPtr = _screenUpdateThread.release();
+
+ if (tmpPtr)
+ {
+ _screenUpdateEvent->Set();
+ _renderCritSec.Leave();
+ tmpPtr->Stop();
+ delete tmpPtr;
+ _renderCritSec.Enter();
+ }
+
+ delete _screenUpdateEvent;
+ _screenUpdateEvent = NULL;
+
+ return 0;
+}
+
+bool VideoRenderAGL::IsFullScreen()
+{
+ CriticalSectionScoped cs(&_renderCritSec);
+ return _fullScreen;
+}
+
+bool VideoRenderAGL::HasChannels()
+{
+
+ CriticalSectionScoped cs(&_renderCritSec);
+
+ if (_aglChannels.begin() != _aglChannels.end())
+ {
+ return true;
+ }
+
+ return false;
+}
+
+bool VideoRenderAGL::HasChannel(int channel)
+{
+ CriticalSectionScoped cs(&_renderCritSec);
+
+ std::map<int, VideoChannelAGL*>::iterator it = _aglChannels.find(channel);
+ if (it != _aglChannels.end())
+ {
+ return true;
+ }
+
+ return false;
+}
+
+int VideoRenderAGL::GetChannels(std::list<int>& channelList)
+{
+
+ CriticalSectionScoped cs(&_renderCritSec);
+ std::map<int, VideoChannelAGL*>::iterator it = _aglChannels.begin();
+
+ while (it != _aglChannels.end())
+ {
+ channelList.push_back(it->first);
+ it++;
+ }
+
+ return 0;
+}
+
+VideoChannelAGL* VideoRenderAGL::ConfigureAGLChannel(int channel, int zOrder, float startWidth, float startHeight, float stopWidth, float stopHeight)
+{
+
+ CriticalSectionScoped cs(&_renderCritSec);
+
+ std::map<int, VideoChannelAGL*>::iterator it = _aglChannels.find(channel);
+
+ if (it != _aglChannels.end())
+ {
+ VideoChannelAGL* aglChannel = it->second;
+ if (aglChannel->SetStreamSettings(0, startWidth, startHeight, stopWidth, stopHeight) == -1)
+ {
+ return NULL;
+ }
+
+ std::multimap<int, int>::iterator it = _zOrderToChannel.begin();
+ while(it != _zOrderToChannel.end())
+ {
+ if (it->second == channel)
+ {
+ if (it->first != zOrder)
+ {
+ _zOrderToChannel.erase(it);
+ _zOrderToChannel.insert(std::pair<int, int>(zOrder, channel));
+ }
+ break;
+ }
+ it++;
+ }
+ return aglChannel;
+ }
+
+ return NULL;
+}
+
+bool VideoRenderAGL::ScreenUpdateThreadProc(void* obj)
+{
+ return static_cast<VideoRenderAGL*>(obj)->ScreenUpdateProcess();
+}
+
+bool VideoRenderAGL::ScreenUpdateProcess()
+{
+ _screenUpdateEvent->Wait(100);
+
+ LockAGLCntx();
+
+ if (!_screenUpdateThread)
+ {
+ UnlockAGLCntx();
+ return false;
+ }
+
+ if (aglSetCurrentContext(_aglContext) == GL_FALSE)
+ {
+ UnlockAGLCntx();
+ return true;
+ }
+
+ if (GetWindowRect(_windowRect) == -1)
+ {
+ UnlockAGLCntx();
+ return true;
+ }
+
+ if (_windowWidth != (_windowRect.right - _windowRect.left)
+ || _windowHeight != (_windowRect.bottom - _windowRect.top))
+ {
+ // We have a new window size, update the context.
+ if (aglUpdateContext(_aglContext) == GL_FALSE)
+ {
+ UnlockAGLCntx();
+ return true;
+ }
+ _windowWidth = _windowRect.right - _windowRect.left;
+ _windowHeight = _windowRect.bottom - _windowRect.top;
+ }
+
+ // this section will poll to see if the window size has changed
+ // this is causing problem w/invalid windowRef
+ // this code has been modified and exists now in the window event handler
+#ifndef NEW_HIVIEW_PARENT_EVENT_HANDLER
+ if (_isHIViewRef)
+ {
+
+ if(FALSE == HIViewIsValid(_hiviewRef))
+ {
+
+ //WEBRTC_TRACE(kTraceDebug, "%s:%d Invalid windowRef", __FUNCTION__, __LINE__);
+ UnlockAGLCntx();
+ return true;
+ }
+ WindowRef window = HIViewGetWindow(_hiviewRef);
+
+ if(FALSE == IsValidWindowPtr(window))
+ {
+ //WEBRTC_TRACE(kTraceDebug, "%s:%d Invalide hiviewRef", __FUNCTION__, __LINE__);
+ UnlockAGLCntx();
+ return true;
+ }
+ if (window == NULL)
+ {
+ //WEBRTC_TRACE(kTraceDebug, "%s:%d WindowRef = NULL", __FUNCTION__, __LINE__);
+ UnlockAGLCntx();
+ return true;
+ }
+
+ if(FALSE == MacIsWindowVisible(window))
+ {
+ //WEBRTC_TRACE(kTraceDebug, "%s:%d MacIsWindowVisible == FALSE. Returning early", __FUNCTION__, __LINE__);
+ UnlockAGLCntx();
+ return true;
+ }
+
+ HIRect viewBounds; // Placement and size for HIView
+ int windowWidth = 0; // Parent window width
+ int windowHeight = 0; // Parent window height
+
+ // NOTE: Calling GetWindowBounds with kWindowStructureRgn will crash intermittentaly if the OS decides it needs to push it into the back for a moment.
+ // To counter this, we get the titlebar height on class construction and then add it to the content region here. Content regions seems not to crash
+ Rect contentBounds =
+ { 0, 0, 0, 0}; // The bounds for the parent window
+
+#if defined(USE_CONTENT_RGN)
+ GetWindowBounds(window, kWindowContentRgn, &contentBounds);
+#elif defined(USE_STRUCT_RGN)
+ GetWindowBounds(window, kWindowStructureRgn, &contentBounds);
+#endif
+
+ Rect globalBounds =
+ { 0, 0, 0, 0}; // The bounds for the parent window
+ globalBounds.top = contentBounds.top;
+ globalBounds.right = contentBounds.right;
+ globalBounds.bottom = contentBounds.bottom;
+ globalBounds.left = contentBounds.left;
+
+ windowHeight = globalBounds.bottom - globalBounds.top;
+ windowWidth = globalBounds.right - globalBounds.left;
+
+ // Get the size of the HIViewRef
+ HIViewGetBounds(_hiviewRef, &viewBounds);
+ HIViewConvertRect(&viewBounds, _hiviewRef, NULL);
+
+ // Check if this is the first call..
+ if (_lastWindowHeight == -1 &&
+ _lastWindowWidth == -1)
+ {
+ _lastWindowWidth = windowWidth;
+ _lastWindowHeight = windowHeight;
+
+ _lastViewBounds.origin.x = viewBounds.origin.x;
+ _lastViewBounds.origin.y = viewBounds.origin.y;
+ _lastViewBounds.size.width = viewBounds.size.width;
+ _lastViewBounds.size.height = viewBounds.size.height;
+ }
+ sfasdfasdf
+
+ bool resized = false;
+
+ // Check if parent window size has changed
+ if (windowHeight != _lastWindowHeight ||
+ windowWidth != _lastWindowWidth)
+ {
+ resized = true;
+ }
+
+ // Check if the HIView has new size or is moved in the parent window
+ if (_lastViewBounds.origin.x != viewBounds.origin.x ||
+ _lastViewBounds.origin.y != viewBounds.origin.y ||
+ _lastViewBounds.size.width != viewBounds.size.width ||
+ _lastViewBounds.size.height != viewBounds.size.height)
+ {
+ // The HiView is resized or has moved.
+ resized = true;
+ }
+
+ if (resized)
+ {
+
+ //WEBRTC_TRACE(kTraceDebug, "%s:%d Window has resized", __FUNCTION__, __LINE__);
+
+ // Calculate offset between the windows
+ // {x, y, widht, height}, x,y = lower left corner
+ const GLint offs[4] =
+ { (int)(0.5f + viewBounds.origin.x),
+ (int)(0.5f + windowHeight - (viewBounds.origin.y + viewBounds.size.height)),
+ viewBounds.size.width, viewBounds.size.height};
+
+ //WEBRTC_TRACE(kTraceDebug, "%s:%d contentBounds t:%d r:%d b:%d l:%d", __FUNCTION__, __LINE__,
+ contentBounds.top, contentBounds.right, contentBounds.bottom, contentBounds.left);
+ //WEBRTC_TRACE(kTraceDebug, "%s:%d windowHeight=%d", __FUNCTION__, __LINE__, windowHeight);
+ //WEBRTC_TRACE(kTraceDebug, "%s:%d offs[4] = %d, %d, %d, %d", __FUNCTION__, __LINE__, offs[0], offs[1], offs[2], offs[3]);
+
+ aglSetDrawable (_aglContext, GetWindowPort(window));
+ aglSetInteger(_aglContext, AGL_BUFFER_RECT, offs);
+ aglEnable(_aglContext, AGL_BUFFER_RECT);
+
+ // We need to change the viewport too if the HIView size has changed
+ glViewport(0.0f, 0.0f, (GLsizei) viewBounds.size.width, (GLsizei) viewBounds.size.height);
+
+ }
+ _lastWindowWidth = windowWidth;
+ _lastWindowHeight = windowHeight;
+
+ _lastViewBounds.origin.x = viewBounds.origin.x;
+ _lastViewBounds.origin.y = viewBounds.origin.y;
+ _lastViewBounds.size.width = viewBounds.size.width;
+ _lastViewBounds.size.height = viewBounds.size.height;
+
+ }
+#endif
+ if (_fullScreen)
+ {
+ // TODO
+ // We use double buffers, must always update
+ //RenderOffScreenBuffersToBackBuffer();
+ }
+ else
+ {
+ // Check if there are any updated buffers
+ bool updated = false;
+
+ // TODO: check if window size is updated!
+ // TODO Improvement: Walk through the zOrder Map to only render the ones in need of update
+ std::map<int, VideoChannelAGL*>::iterator it = _aglChannels.begin();
+ while (it != _aglChannels.end())
+ {
+
+ VideoChannelAGL* aglChannel = it->second;
+ aglChannel->UpdateStretchSize(_windowHeight, _windowWidth);
+ aglChannel->IsUpdated(updated);
+ if (updated)
+ {
+ break;
+ }
+ it++;
+ }
+
+ if (updated)
+ {
+ // At least on buffers is updated, we need to repaint the texture
+ if (RenderOffScreenBuffers() != -1)
+ {
+ // MF
+ //SwapAndDisplayBuffers();
+ }
+ else
+ {
+ // Error updating the mixing texture, don't swap.
+ }
+ }
+ }
+
+ UnlockAGLCntx();
+
+ //WEBRTC_LOG(kTraceDebug, "Leaving ScreenUpdateProcess()");
+ return true;
+}
+
+void VideoRenderAGL::ParentWindowResized(WindowRef window)
+{
+ //WEBRTC_LOG(kTraceDebug, "%s HIViewRef:%d owner window has resized", __FUNCTION__, (int)_hiviewRef);
+
+ LockAGLCntx();
+k
+ // set flag
+ _windowHasResized = false;
+
+ if(FALSE == HIViewIsValid(_hiviewRef))
+ {
+ //WEBRTC_LOG(kTraceDebug, "invalid windowRef");
+ UnlockAGLCntx();
+ return;
+ }
+
+ if(FALSE == IsValidWindowPtr(window))
+ {
+ //WEBRTC_LOG(kTraceError, "invalid windowRef");
+ UnlockAGLCntx();
+ return;
+ }
+
+ if (window == NULL)
+ {
+ //WEBRTC_LOG(kTraceError, "windowRef = NULL");
+ UnlockAGLCntx();
+ return;
+ }
+
+ if(FALSE == MacIsWindowVisible(window))
+ {
+ //WEBRTC_LOG(kTraceDebug, "MacIsWindowVisible = FALSE. Returning early.");
+ UnlockAGLCntx();
+ return;
+ }
+
+ Rect contentBounds =
+ { 0, 0, 0, 0};
+
+#if defined(USE_CONTENT_RGN)
+ GetWindowBounds(window, kWindowContentRgn, &contentBounds);
+#elif defined(USE_STRUCT_RGN)
+ GetWindowBounds(window, kWindowStructureRgn, &contentBounds);
+#endif
+
+ //WEBRTC_LOG(kTraceDebug, "%s contentBounds t:%d r:%d b:%d l:%d", __FUNCTION__, contentBounds.top, contentBounds.right, contentBounds.bottom, contentBounds.left);
+
+ // update global vars
+ _currentParentWindowBounds.top = contentBounds.top;
+ _currentParentWindowBounds.left = contentBounds.left;
+ _currentParentWindowBounds.bottom = contentBounds.bottom;
+ _currentParentWindowBounds.right = contentBounds.right;
+
+ _currentParentWindowWidth = _currentParentWindowBounds.right - _currentParentWindowBounds.left;
+ _currentParentWindowHeight = _currentParentWindowBounds.bottom - _currentParentWindowBounds.top;
+
+ _windowHasResized = true;
+
+ // ********* update AGL offsets
+ HIRect viewBounds;
+ HIViewGetBounds(_hiviewRef, &viewBounds);
+ HIViewConvertRect(&viewBounds, _hiviewRef, NULL);
+
+ const GLint offs[4] =
+ { (int)(0.5f + viewBounds.origin.x),
+ (int)(0.5f + _currentParentWindowHeight - (viewBounds.origin.y + viewBounds.size.height)),
+ viewBounds.size.width, viewBounds.size.height};
+ //WEBRTC_LOG(kTraceDebug, "%s _currentParentWindowHeight=%d", __FUNCTION__, _currentParentWindowHeight);
+ //WEBRTC_LOG(kTraceDebug, "%s offs[4] = %d, %d, %d, %d", __FUNCTION__, offs[0], offs[1], offs[2], offs[3]);
+
+ aglSetCurrentContext(_aglContext);
+ aglSetDrawable (_aglContext, GetWindowPort(window));
+ aglSetInteger(_aglContext, AGL_BUFFER_RECT, offs);
+ aglEnable(_aglContext, AGL_BUFFER_RECT);
+
+ // We need to change the viewport too if the HIView size has changed
+ glViewport(0.0f, 0.0f, (GLsizei) viewBounds.size.width, (GLsizei) viewBounds.size.height);
+
+ UnlockAGLCntx();
+
+ return;
+}
+
+int VideoRenderAGL::CreateMixingContext()
+{
+
+ LockAGLCntx();
+
+ //WEBRTC_LOG(kTraceDebug, "Entering CreateMixingContext()");
+
+ // Use both AGL_ACCELERATED and AGL_NO_RECOVERY to make sure
+ // a hardware renderer is used and not a software renderer.
+
+ GLint attributes[] =
+ {
+ AGL_DOUBLEBUFFER,
+ AGL_WINDOW,
+ AGL_RGBA,
+ AGL_NO_RECOVERY,
+ AGL_ACCELERATED,
+ AGL_RED_SIZE, 8,
+ AGL_GREEN_SIZE, 8,
+ AGL_BLUE_SIZE, 8,
+ AGL_ALPHA_SIZE, 8,
+ AGL_DEPTH_SIZE, 24,
+ AGL_NONE,
+ };
+
+ AGLPixelFormat aglPixelFormat;
+
+ // ***** Set up the OpenGL Context *****
+
+ // Get a pixel format for the attributes above
+ aglPixelFormat = aglChoosePixelFormat(NULL, 0, attributes);
+ if (NULL == aglPixelFormat)
+ {
+ //WEBRTC_LOG(kTraceError, "Could not create pixel format");
+ UnlockAGLCntx();
+ return -1;
+ }
+
+ // Create an AGL context
+ _aglContext = aglCreateContext(aglPixelFormat, NULL);
+ if (_aglContext == NULL)
+ {
+ //WEBRTC_LOG(kTraceError, "Could no create AGL context");
+ UnlockAGLCntx();
+ return -1;
+ }
+
+ // Release the pixel format memory
+ aglDestroyPixelFormat(aglPixelFormat);
+
+ // Set the current AGL context for the rest of the settings
+ if (aglSetCurrentContext(_aglContext) == false)
+ {
+ //WEBRTC_LOG(kTraceError, "Could not set current context: %d", aglGetError());
+ UnlockAGLCntx();
+ return -1;
+ }
+
+ if (_isHIViewRef)
+ {
+ //---------------------------
+ // BEGIN: new test code
+#if 0
+ // Don't use this one!
+ // There seems to be an OS X bug that can't handle
+ // movements and resizing of the parent window
+ // and or the HIView
+ if (aglSetHIViewRef(_aglContext,_hiviewRef) == false)
+ {
+ //WEBRTC_LOG(kTraceError, "Could not set WindowRef: %d", aglGetError());
+ UnlockAGLCntx();
+ return -1;
+ }
+#else
+
+ // Get the parent window for this control
+ WindowRef window = GetControlOwner(_hiviewRef);
+
+ Rect globalBounds =
+ { 0,0,0,0}; // The bounds for the parent window
+ HIRect viewBounds; // Placemnt in the parent window and size.
+ int windowHeight = 0;
+
+ // Rect titleBounds = {0,0,0,0};
+ // GetWindowBounds(window, kWindowTitleBarRgn, &titleBounds);
+ // _titleBarHeight = titleBounds.top - titleBounds.bottom;
+ // if(0 == _titleBarHeight)
+ // {
+ // //WEBRTC_LOG(kTraceError, "Titlebar height = 0");
+ // //return -1;
+ // }
+
+
+ // Get the bounds for the parent window
+#if defined(USE_CONTENT_RGN)
+ GetWindowBounds(window, kWindowContentRgn, &globalBounds);
+#elif defined(USE_STRUCT_RGN)
+ GetWindowBounds(window, kWindowStructureRgn, &globalBounds);
+#endif
+ windowHeight = globalBounds.bottom - globalBounds.top;
+
+ // Get the bounds for the HIView
+ HIViewGetBounds(_hiviewRef, &viewBounds);
+
+ HIViewConvertRect(&viewBounds, _hiviewRef, NULL);
+
+ const GLint offs[4] =
+ { (int)(0.5f + viewBounds.origin.x),
+ (int)(0.5f + windowHeight - (viewBounds.origin.y + viewBounds.size.height)),
+ viewBounds.size.width, viewBounds.size.height};
+
+ //WEBRTC_LOG(kTraceDebug, "%s offs[4] = %d, %d, %d, %d", __FUNCTION__, offs[0], offs[1], offs[2], offs[3]);
+
+
+ aglSetDrawable (_aglContext, GetWindowPort(window));
+ aglSetInteger(_aglContext, AGL_BUFFER_RECT, offs);
+ aglEnable(_aglContext, AGL_BUFFER_RECT);
+
+ GLint surfaceOrder = 1; // 1: above window, -1 below.
+ //OSStatus status = aglSetInteger(_aglContext, AGL_SURFACE_ORDER, &surfaceOrder);
+ aglSetInteger(_aglContext, AGL_SURFACE_ORDER, &surfaceOrder);
+
+ glViewport(0.0f, 0.0f, (GLsizei) viewBounds.size.width, (GLsizei) viewBounds.size.height);
+#endif
+
+ }
+ else
+ {
+ if(GL_FALSE == aglSetDrawable (_aglContext, GetWindowPort(_windowRef)))
+ {
+ //WEBRTC_LOG(kTraceError, "Could not set WindowRef: %d", aglGetError());
+ UnlockAGLCntx();
+ return -1;
+ }
+ }
+
+ _windowWidth = _windowRect.right - _windowRect.left;
+ _windowHeight = _windowRect.bottom - _windowRect.top;
+
+ // opaque surface
+ int surfaceOpacity = 1;
+ if (aglSetInteger(_aglContext, AGL_SURFACE_OPACITY, (const GLint *) &surfaceOpacity) == false)
+ {
+ //WEBRTC_LOG(kTraceError, "Could not set surface opacity: %d", aglGetError());
+ UnlockAGLCntx();
+ return -1;
+ }
+
+ // 1 -> sync to screen rat, slow...
+ //int swapInterval = 0; // 0 don't sync with vertical trace
+ int swapInterval = 0; // 1 sync with vertical trace
+ if (aglSetInteger(_aglContext, AGL_SWAP_INTERVAL, (const GLint *) &swapInterval) == false)
+ {
+ //WEBRTC_LOG(kTraceError, "Could not set swap interval: %d", aglGetError());
+ UnlockAGLCntx();
+ return -1;
+ }
+
+ // Update the rect with the current size
+ if (GetWindowRect(_windowRect) == -1)
+ {
+ //WEBRTC_LOG(kTraceError, "Could not get window size");
+ UnlockAGLCntx();
+ return -1;
+ }
+
+ // Disable not needed functionality to increase performance
+ glDisable(GL_DITHER);
+ glDisable(GL_ALPHA_TEST);
+ glDisable(GL_STENCIL_TEST);
+ glDisable(GL_FOG);
+ glDisable(GL_TEXTURE_2D);
+ glPixelZoom(1.0, 1.0);
+
+ glDisable(GL_BLEND);
+ glDisable(GL_DEPTH_TEST);
+ glDepthMask(GL_FALSE);
+ glDisable(GL_CULL_FACE);
+
+ glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ GLenum glErr = glGetError();
+
+ if (glErr)
+ {
+ }
+
+ UpdateClipping();
+
+ //WEBRTC_LOG(kTraceDebug, "Leaving CreateMixingContext()");
+
+ UnlockAGLCntx();
+ return 0;
+}
+
+int VideoRenderAGL::RenderOffScreenBuffers()
+{
+ LockAGLCntx();
+
+ // Get the current window size, it might have changed since last render.
+ if (GetWindowRect(_windowRect) == -1)
+ {
+ //WEBRTC_LOG(kTraceError, "Could not get window rect");
+ UnlockAGLCntx();
+ return -1;
+ }
+
+ if (aglSetCurrentContext(_aglContext) == false)
+ {
+ //WEBRTC_LOG(kTraceError, "Could not set current context for rendering");
+ UnlockAGLCntx();
+ return -1;
+ }
+
+ // HERE - onl if updated!
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ // Loop through all channels starting highest zOrder ending with lowest.
+ for (std::multimap<int, int>::reverse_iterator rIt = _zOrderToChannel.rbegin();
+ rIt != _zOrderToChannel.rend();
+ rIt++)
+ {
+ int channelId = rIt->second;
+ std::map<int, VideoChannelAGL*>::iterator it = _aglChannels.find(channelId);
+
+ VideoChannelAGL* aglChannel = it->second;
+
+ aglChannel->RenderOffScreenBuffer();
+ }
+
+ SwapAndDisplayBuffers();
+
+ UnlockAGLCntx();
+ return 0;
+}
+
+int VideoRenderAGL::SwapAndDisplayBuffers()
+{
+
+ LockAGLCntx();
+ if (_fullScreen)
+ {
+ // TODO:
+ // Swap front and back buffers, rendering taking care of in the same call
+ //aglSwapBuffers(_aglContext);
+ // Update buffer index to the idx for the next rendering!
+ //_textureIdx = (_textureIdx + 1) & 1;
+ }
+ else
+ {
+ // Single buffer rendering, only update context.
+ glFlush();
+ aglSwapBuffers(_aglContext);
+ HIViewSetNeedsDisplay(_hiviewRef, true);
+ }
+
+ UnlockAGLCntx();
+ return 0;
+}
+
+int VideoRenderAGL::GetWindowRect(Rect& rect)
+{
+
+ LockAGLCntx();
+
+ if (_isHIViewRef)
+ {
+ if (_hiviewRef)
+ {
+ HIRect HIViewRect1;
+ if(FALSE == HIViewIsValid(_hiviewRef))
+ {
+ rect.top = 0;
+ rect.left = 0;
+ rect.right = 0;
+ rect.bottom = 0;
+ //WEBRTC_LOG(kTraceError,"GetWindowRect() HIViewIsValid() returned false");
+ UnlockAGLCntx();
+ }
+ HIViewGetBounds(_hiviewRef,&HIViewRect1);
+ HIRectConvert(&HIViewRect1, 1, NULL, 2, NULL);
+ if(HIViewRect1.origin.x < 0)
+ {
+ rect.top = 0;
+ //WEBRTC_LOG(kTraceDebug, "GetWindowRect() rect.top = 0");
+ }
+ else
+ {
+ rect.top = HIViewRect1.origin.x;
+ }
+
+ if(HIViewRect1.origin.y < 0)
+ {
+ rect.left = 0;
+ //WEBRTC_LOG(kTraceDebug, "GetWindowRect() rect.left = 0");
+ }
+ else
+ {
+ rect.left = HIViewRect1.origin.y;
+ }
+
+ if(HIViewRect1.size.width < 0)
+ {
+ rect.right = 0;
+ //WEBRTC_LOG(kTraceDebug, "GetWindowRect() rect.right = 0");
+ }
+ else
+ {
+ rect.right = HIViewRect1.size.width;
+ }
+
+ if(HIViewRect1.size.height < 0)
+ {
+ rect.bottom = 0;
+ //WEBRTC_LOG(kTraceDebug, "GetWindowRect() rect.bottom = 0");
+ }
+ else
+ {
+ rect.bottom = HIViewRect1.size.height;
+ }
+
+ ////WEBRTC_LOG(kTraceDebug,"GetWindowRect() HIViewRef: rect.top = %d, rect.left = %d, rect.right = %d, rect.bottom =%d in GetWindowRect", rect.top,rect.left,rect.right,rect.bottom);
+ UnlockAGLCntx();
+ }
+ else
+ {
+ //WEBRTC_LOG(kTraceError, "invalid HIViewRef");
+ UnlockAGLCntx();
+ }
+ }
+ else
+ {
+ if (_windowRef)
+ {
+ GetWindowBounds(_windowRef, kWindowContentRgn, &rect);
+ UnlockAGLCntx();
+ }
+ else
+ {
+ //WEBRTC_LOG(kTraceError, "No WindowRef");
+ UnlockAGLCntx();
+ }
+ }
+}
+
+int VideoRenderAGL::UpdateClipping()
+{
+ //WEBRTC_LOG(kTraceDebug, "Entering UpdateClipping()");
+ LockAGLCntx();
+
+ if(_isHIViewRef)
+ {
+ if(FALSE == HIViewIsValid(_hiviewRef))
+ {
+ //WEBRTC_LOG(kTraceError, "UpdateClipping() _isHIViewRef is invalid. Returning -1");
+ UnlockAGLCntx();
+ return -1;
+ }
+
+ RgnHandle visibleRgn = NewRgn();
+ SetEmptyRgn (visibleRgn);
+
+ if(-1 == CalculateVisibleRegion((ControlRef)_hiviewRef, visibleRgn, true))
+ {
+ }
+
+ if(GL_FALSE == aglSetCurrentContext(_aglContext))
+ {
+ GLenum glErr = aglGetError();
+ //WEBRTC_LOG(kTraceError, "aglSetCurrentContext returned FALSE with error code %d at line %d", glErr, __LINE__);
+ }
+
+ if(GL_FALSE == aglEnable(_aglContext, AGL_CLIP_REGION))
+ {
+ GLenum glErr = aglGetError();
+ //WEBRTC_LOG(kTraceError, "aglEnable returned FALSE with error code %d at line %d\n", glErr, __LINE__);
+ }
+
+ if(GL_FALSE == aglSetInteger(_aglContext, AGL_CLIP_REGION, (const GLint*)visibleRgn))
+ {
+ GLenum glErr = aglGetError();
+ //WEBRTC_LOG(kTraceError, "aglSetInteger returned FALSE with error code %d at line %d\n", glErr, __LINE__);
+ }
+
+ DisposeRgn(visibleRgn);
+ }
+ else
+ {
+ //WEBRTC_LOG(kTraceDebug, "Not using a hiviewref!\n");
+ }
+
+ //WEBRTC_LOG(kTraceDebug, "Leaving UpdateClipping()");
+ UnlockAGLCntx();
+ return true;
+}
+
+int VideoRenderAGL::CalculateVisibleRegion(ControlRef control, RgnHandle &visibleRgn, bool clipChildren)
+{
+
+ // LockAGLCntx();
+
+ //WEBRTC_LOG(kTraceDebug, "Entering CalculateVisibleRegion()");
+ OSStatus osStatus = 0;
+ OSErr osErr = 0;
+
+ RgnHandle tempRgn = NewRgn();
+ if (IsControlVisible(control))
+ {
+ RgnHandle childRgn = NewRgn();
+ WindowRef window = GetControlOwner(control);
+ ControlRef rootControl;
+ GetRootControl(window, &rootControl); // 'wvnc'
+ ControlRef masterControl;
+ osStatus = GetSuperControl(rootControl, &masterControl);
+ // //WEBRTC_LOG(kTraceDebug, "IBM GetSuperControl=%d", osStatus);
+
+ if (masterControl != NULL)
+ {
+ CheckValidRegion(visibleRgn);
+ // init visibleRgn with region of 'wvnc'
+ osStatus = GetControlRegion(rootControl, kControlStructureMetaPart, visibleRgn);
+ // //WEBRTC_LOG(kTraceDebug, "IBM GetControlRegion=%d : %d", osStatus, __LINE__);
+ //GetSuperControl(rootControl, &rootControl);
+ ControlRef tempControl = control, lastControl = 0;
+ while (tempControl != masterControl) // current control != master
+
+ {
+ CheckValidRegion(tempRgn);
+
+ // //WEBRTC_LOG(kTraceDebug, "IBM tempControl=%d masterControl=%d", tempControl, masterControl);
+ ControlRef subControl;
+
+ osStatus = GetControlRegion(tempControl, kControlStructureMetaPart, tempRgn); // intersect the region of the current control with visibleRgn
+ // //WEBRTC_LOG(kTraceDebug, "IBM GetControlRegion=%d : %d", osStatus, __LINE__);
+ CheckValidRegion(tempRgn);
+
+ osErr = HIViewConvertRegion(tempRgn, tempControl, rootControl);
+ // //WEBRTC_LOG(kTraceDebug, "IBM HIViewConvertRegion=%d : %d", osErr, __LINE__);
+ CheckValidRegion(tempRgn);
+
+ SectRgn(tempRgn, visibleRgn, visibleRgn);
+ CheckValidRegion(tempRgn);
+ CheckValidRegion(visibleRgn);
+ if (EmptyRgn(visibleRgn)) // if the region is empty, bail
+ break;
+
+ if (clipChildren || tempControl != control) // clip children if true, cut out the tempControl if it's not one passed to this function
+
+ {
+ UInt16 numChildren;
+ osStatus = CountSubControls(tempControl, &numChildren); // count the subcontrols
+ // //WEBRTC_LOG(kTraceDebug, "IBM CountSubControls=%d : %d", osStatus, __LINE__);
+
+ // //WEBRTC_LOG(kTraceDebug, "IBM numChildren=%d", numChildren);
+ for (int i = 0; i < numChildren; i++)
+ {
+ osErr = GetIndexedSubControl(tempControl, numChildren - i, &subControl); // retrieve the subcontrol in order by zorder
+ // //WEBRTC_LOG(kTraceDebug, "IBM GetIndexedSubControls=%d : %d", osErr, __LINE__);
+ if ( subControl == lastControl ) // break because of zorder
+
+ {
+ // //WEBRTC_LOG(kTraceDebug, "IBM breaking because of zorder %d", __LINE__);
+ break;
+ }
+
+ if (!IsControlVisible(subControl)) // dont' clip invisible controls
+
+ {
+ // //WEBRTC_LOG(kTraceDebug, "IBM continue. Control is not visible %d", __LINE__);
+ continue;
+ }
+
+ if(!subControl) continue;
+
+ osStatus = GetControlRegion(subControl, kControlStructureMetaPart, tempRgn); //get the region of the current control and union to childrg
+ // //WEBRTC_LOG(kTraceDebug, "IBM GetControlRegion=%d %d", osStatus, __LINE__);
+ CheckValidRegion(tempRgn);
+ if(osStatus != 0)
+ {
+ // //WEBRTC_LOG(kTraceDebug, "IBM ERROR! osStatus=%d. Continuing. %d", osStatus, __LINE__);
+ continue;
+ }
+ if(!tempRgn)
+ {
+ // //WEBRTC_LOG(kTraceDebug, "IBM ERROR! !tempRgn %d", osStatus, __LINE__);
+ continue;
+ }
+
+ osStatus = HIViewConvertRegion(tempRgn, subControl, rootControl);
+ CheckValidRegion(tempRgn);
+ // //WEBRTC_LOG(kTraceDebug, "IBM HIViewConvertRegion=%d %d", osStatus, __LINE__);
+ if(osStatus != 0)
+ {
+ // //WEBRTC_LOG(kTraceDebug, "IBM ERROR! osStatus=%d. Continuing. %d", osStatus, __LINE__);
+ continue;
+ }
+ if(!rootControl)
+ {
+ // //WEBRTC_LOG(kTraceDebug, "IBM ERROR! !rootControl %d", osStatus, __LINE__);
+ continue;
+ }
+
+ UnionRgn(tempRgn, childRgn, childRgn);
+ CheckValidRegion(tempRgn);
+ CheckValidRegion(childRgn);
+ CheckValidRegion(visibleRgn);
+ if(!childRgn)
+ {
+ // //WEBRTC_LOG(kTraceDebug, "IBM ERROR! !childRgn %d", osStatus, __LINE__);
+ continue;
+ }
+
+ } // next child control
+ }
+ lastControl = tempControl;
+ GetSuperControl(tempControl, &subControl);
+ tempControl = subControl;
+ }
+
+ DiffRgn(visibleRgn, childRgn, visibleRgn);
+ CheckValidRegion(visibleRgn);
+ CheckValidRegion(childRgn);
+ DisposeRgn(childRgn);
+ }
+ else
+ {
+ CopyRgn(tempRgn, visibleRgn);
+ CheckValidRegion(tempRgn);
+ CheckValidRegion(visibleRgn);
+ }
+ DisposeRgn(tempRgn);
+ }
+
+ //WEBRTC_LOG(kTraceDebug, "Leaving CalculateVisibleRegion()");
+ //_aglCritPtr->Leave();
+ return 0;
+}
+
+bool VideoRenderAGL::CheckValidRegion(RgnHandle rHandle)
+{
+
+ Handle hndSize = (Handle)rHandle;
+ long size = GetHandleSize(hndSize);
+ if(0 == size)
+ {
+
+ OSErr memErr = MemError();
+ if(noErr != memErr)
+ {
+ // //WEBRTC_LOG(kTraceError, "IBM ERROR Could not get size of handle. MemError() returned %d", memErr);
+ }
+ else
+ {
+ // //WEBRTC_LOG(kTraceError, "IBM ERROR Could not get size of handle yet MemError() returned noErr");
+ }
+
+ }
+ else
+ {
+ // //WEBRTC_LOG(kTraceDebug, "IBM handleSize = %d", size);
+ }
+
+ if(false == IsValidRgnHandle(rHandle))
+ {
+ // //WEBRTC_LOG(kTraceError, "IBM ERROR Invalid Region found : $%d", rHandle);
+ assert(false);
+ }
+
+ int err = QDError();
+ switch(err)
+ {
+ case 0:
+ break;
+ case -147:
+ //WEBRTC_LOG(kTraceError, "ERROR region too big");
+ assert(false);
+ break;
+
+ case -149:
+ //WEBRTC_LOG(kTraceError, "ERROR not enough stack");
+ assert(false);
+ break;
+
+ default:
+ //WEBRTC_LOG(kTraceError, "ERROR Unknown QDError %d", err);
+ assert(false);
+ break;
+ }
+
+ return true;
+}
+
+int VideoRenderAGL::ChangeWindow(void* newWindowRef)
+{
+
+ LockAGLCntx();
+
+ UnlockAGLCntx();
+ return -1;
+}
+
+int32_t VideoRenderAGL::StartRender()
+{
+
+ LockAGLCntx();
+ const unsigned int MONITOR_FREQ = 60;
+ if(TRUE == _renderingIsPaused)
+ {
+ //WEBRTC_TRACE(kTraceInfo, kTraceVideoRenderer, _id, "%s:%d Rendering is paused. Restarting now", __FUNCTION__, __LINE__);
+
+ // we already have the thread. Most likely StopRender() was called and they were paused
+ if(FALSE == _screenUpdateThread->Start())
+ {
+ //WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id, "%s:%d Failed to start screenUpdateThread", __FUNCTION__, __LINE__);
+ UnlockAGLCntx();
+ return -1;
+ }
+ _screenUpdateThread->SetPriority(rtc::kRealtimePriority);
+ if(FALSE == _screenUpdateEvent->StartTimer(true, 1000/MONITOR_FREQ))
+ {
+ //WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id, "%s:%d Failed to start screenUpdateEvent", __FUNCTION__, __LINE__);
+ UnlockAGLCntx();
+ return -1;
+ }
+
+ return 0;
+ }
+
+ _screenUpdateThread.reset(
+ new rtc::PlatformThread(ScreenUpdateThreadProc, this, "ScreenUpdate"));
+ _screenUpdateEvent = EventWrapper::Create();
+
+ if (!_screenUpdateThread)
+ {
+ //WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id, "%s:%d Failed to start screenUpdateThread", __FUNCTION__, __LINE__);
+ UnlockAGLCntx();
+ return -1;
+ }
+
+ _screenUpdateThread->Start();
+ _screenUpdateThread->SetPriority(rtc::kRealtimePriority);
+ _screenUpdateEvent->StartTimer(true, 1000/MONITOR_FREQ);
+
+ //WEBRTC_TRACE(kTraceInfo, kTraceVideoRenderer, _id, "%s:%d Started screenUpdateThread", __FUNCTION__, __LINE__);
+
+ UnlockAGLCntx();
+ return 0;
+}
+
+int32_t VideoRenderAGL::StopRender()
+{
+ LockAGLCntx();
+
+ if(!_screenUpdateThread || !_screenUpdateEvent)
+ {
+ _renderingIsPaused = TRUE;
+ UnlockAGLCntx();
+ return 0;
+ }
+
+ if(FALSE == _screenUpdateThread->Stop() || FALSE == _screenUpdateEvent->StopTimer())
+ {
+ _renderingIsPaused = FALSE;
+ //WEBRTC_TRACE(kTraceInfo, kTraceVideoRenderer, _id, "%s:%d Could not stop either: screenUpdateThread or screenUpdateEvent", __FUNCTION__, __LINE__);
+ UnlockAGLCntx();
+ return -1;
+ }
+
+ _renderingIsPaused = TRUE;
+
+ //WEBRTC_TRACE(kTraceInfo, kTraceVideoRenderer, _id, "%s:%d Stopped screenUpdateThread", __FUNCTION__, __LINE__);
+ UnlockAGLCntx();
+ return 0;
+}
+
+int32_t VideoRenderAGL::DeleteAGLChannel(const uint32_t streamID)
+{
+
+ LockAGLCntx();
+
+ std::map<int, VideoChannelAGL*>::iterator it;
+ it = _aglChannels.begin();
+
+ while (it != _aglChannels.end())
+ {
+ VideoChannelAGL* channel = it->second;
+ //WEBRTC_TRACE(kTraceInfo, kTraceVideoRenderer, _id, "%s:%d Deleting channel %d", __FUNCTION__, __LINE__, streamID);
+ delete channel;
+ it++;
+ }
+ _aglChannels.clear();
+
+ UnlockAGLCntx();
+ return 0;
+}
+
+int32_t VideoRenderAGL::GetChannelProperties(const uint16_t streamId,
+ uint32_t& zOrder,
+ float& left,
+ float& top,
+ float& right,
+ float& bottom)
+{
+
+ LockAGLCntx();
+ UnlockAGLCntx();
+ return -1;
+
+}
+
+void VideoRenderAGL::LockAGLCntx()
+{
+ _renderCritSec.Enter();
+}
+void VideoRenderAGL::UnlockAGLCntx()
+{
+ _renderCritSec.Leave();
+}
+
+} // namespace webrtc
+
+#endif // CARBON_RENDERING
« no previous file with comments | « webrtc/modules/video_render/mac/video_render_agl.h ('k') | webrtc/modules/video_render/mac/video_render_mac_carbon_impl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698