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