1/*
2 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 *
4 *  Use of this source code is governed by a BSD-style license
5 *  that can be found in the LICENSE file in the root of the source
6 *  tree. An additional intellectual property rights grant can be found
7 *  in the file PATENTS.  All contributing project authors may
8 *  be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "webrtc/engine_configurations.h"
12
13#if defined(CARBON_RENDERING)
14
15#include "webrtc/modules/video_render/mac/video_render_agl.h"
16
17//  includes
18#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
19#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
20#include "webrtc/system_wrappers/interface/event_wrapper.h"
21#include "webrtc/system_wrappers/interface/thread_wrapper.h"
22#include "webrtc/system_wrappers/interface/trace.h"
23
24namespace webrtc {
25
26/*
27 *
28 *    VideoChannelAGL
29 *
30 */
31
32#pragma mark VideoChannelAGL constructor
33
34VideoChannelAGL::VideoChannelAGL(AGLContext& aglContext, int iId, VideoRenderAGL* owner) :
35    _aglContext( aglContext),
36    _id( iId),
37    _owner( owner),
38    _width( 0),
39    _height( 0),
40    _stretchedWidth( 0),
41    _stretchedHeight( 0),
42    _startWidth( 0.0f),
43    _startHeight( 0.0f),
44    _stopWidth( 0.0f),
45    _stopHeight( 0.0f),
46    _xOldWidth( 0),
47    _yOldHeight( 0),
48    _oldStretchedHeight(0),
49    _oldStretchedWidth( 0),
50    _buffer( 0),
51    _bufferSize( 0),
52    _incommingBufferSize(0),
53    _bufferIsUpdated( false),
54    _sizeInitialized( false),
55    _numberOfStreams( 0),
56    _bVideoSizeStartedChanging(false),
57    _pixelFormat( GL_RGBA),
58    _pixelDataType( GL_UNSIGNED_INT_8_8_8_8),
59    _texture( 0)
60
61{
62    //WEBRTC_TRACE(kTraceInfo, kTraceVideoRenderer, _id, "%s:%d Constructor", __FUNCTION__, __LINE__);
63}
64
65VideoChannelAGL::~VideoChannelAGL()
66{
67    //WEBRTC_TRACE(kTraceInfo, kTraceVideoRenderer, _id, "%s:%d Destructor", __FUNCTION__, __LINE__);
68    if (_buffer)
69    {
70        delete [] _buffer;
71        _buffer = NULL;
72    }
73
74    aglSetCurrentContext(_aglContext);
75
76    if (_texture != 0)
77    {
78        glDeleteTextures(1, (const GLuint*) &_texture);
79        _texture = 0;
80    }
81}
82
83int32_t VideoChannelAGL::RenderFrame(const uint32_t streamId,
84                                     I420VideoFrame& videoFrame) {
85  _owner->LockAGLCntx();
86  if (_width != videoFrame.width() ||
87      _height != videoFrame.height()) {
88    if (FrameSizeChange(videoFrame.width(), videoFrame.height(), 1) == -1) {
89      WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id, "%s:%d FrameSize
90                   Change returned an error", __FUNCTION__, __LINE__);
91      _owner->UnlockAGLCntx();
92      return -1;
93    }
94  }
95
96  _owner->UnlockAGLCntx();
97  return DeliverFrame(videoFrame);
98}
99
100int VideoChannelAGL::UpdateSize(int /*width*/, int /*height*/)
101{
102    _owner->LockAGLCntx();
103    _owner->UnlockAGLCntx();
104    return 0;
105}
106
107int VideoChannelAGL::UpdateStretchSize(int stretchHeight, int stretchWidth)
108{
109
110    _owner->LockAGLCntx();
111    _stretchedHeight = stretchHeight;
112    _stretchedWidth = stretchWidth;
113    _owner->UnlockAGLCntx();
114    return 0;
115}
116
117int VideoChannelAGL::FrameSizeChange(int width, int height, int numberOfStreams)
118{
119    //  We'll get a new frame size from VideoAPI, prepare the buffer
120
121    _owner->LockAGLCntx();
122
123    if (width == _width && _height == height)
124    {
125        // We already have a correct buffer size
126        _numberOfStreams = numberOfStreams;
127        _owner->UnlockAGLCntx();
128        return 0;
129    }
130
131    _width = width;
132    _height = height;
133
134    // Delete the old buffer, create a new one with correct size.
135    if (_buffer)
136    {
137        delete [] _buffer;
138        _bufferSize = 0;
139    }
140
141    _incommingBufferSize = CalcBufferSize(kI420, _width, _height);
142    _bufferSize = CalcBufferSize(kARGB, _width, _height);//_width * _height * bytesPerPixel;
143    _buffer = new unsigned char [_bufferSize];
144    memset(_buffer, 0, _bufferSize * sizeof(unsigned char));
145
146    if (aglSetCurrentContext(_aglContext) == false)
147    {
148        _owner->UnlockAGLCntx();
149        return -1;
150    }
151
152    // Delete a possible old texture
153    if (_texture != 0)
154    {
155        glDeleteTextures(1, (const GLuint*) &_texture);
156        _texture = 0;
157    }
158
159    // Create a new texture
160    glGenTextures(1, (GLuint *) &_texture);
161
162    GLenum glErr = glGetError();
163
164    if (glErr != GL_NO_ERROR)
165    {
166    }
167
168    // Do the setup for both textures
169    // Note: we setup two textures even if we're not running full screen
170    glBindTexture(GL_TEXTURE_RECTANGLE_EXT, _texture);
171
172    // Set texture parameters
173    glTexParameterf(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_PRIORITY, 1.0);
174
175    glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
176    glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
177
178    glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
179    glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
180    //glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
181    //glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
182
183    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
184
185    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
186
187    glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_STORAGE_HINT_APPLE, GL_STORAGE_SHARED_APPLE);
188
189    // Maximum width/height for a texture
190    GLint texSize;
191    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &texSize);
192
193    if (texSize < _width || texSize < _height)
194    {
195        // Image too big for memory
196        _owner->UnlockAGLCntx();
197        return -1;
198    }
199
200    // Set up th texture type and size
201    glTexImage2D(GL_TEXTURE_RECTANGLE_EXT, // target
202            0, // level
203            GL_RGBA, // internal format
204            _width, // width
205            _height, // height
206            0, // border 0/1 = off/on
207            _pixelFormat, // format, GL_BGRA
208            _pixelDataType, // data type, GL_UNSIGNED_INT_8_8_8_8
209            _buffer); // pixel data
210
211    glErr = glGetError();
212    if (glErr != GL_NO_ERROR)
213    {
214        _owner->UnlockAGLCntx();
215        return -1;
216    }
217
218    _owner->UnlockAGLCntx();
219    return 0;
220}
221
222// Called from video engine when a new frame should be rendered.
223int VideoChannelAGL::DeliverFrame(const I420VideoFrame& videoFrame) {
224  _owner->LockAGLCntx();
225
226  if (_texture == 0) {
227    _owner->UnlockAGLCntx();
228    return 0;
229  }
230
231  int length = CalcBufferSize(kI420, videoFrame.width(), videoFrame.height());
232  if (length != _incommingBufferSize) {
233    _owner->UnlockAGLCntx();
234    return -1;
235  }
236
237  // Setting stride = width.
238  int rgbret = ConvertFromYV12(videoFrame, kBGRA, 0, _buffer);
239  if (rgbret < 0) {
240    _owner->UnlockAGLCntx();
241    return -1;
242  }
243
244  aglSetCurrentContext(_aglContext);
245
246  // Put the new frame into the graphic card texture.
247  // Make sure this texture is the active one
248  glBindTexture(GL_TEXTURE_RECTANGLE_EXT, _texture);
249  GLenum glErr = glGetError();
250  if (glErr != GL_NO_ERROR) {
251    _owner->UnlockAGLCntx();
252    return -1;
253  }
254
255  // Copy buffer to texture
256  glTexSubImage2D(GL_TEXTURE_RECTANGLE_EXT,
257                  0, // Level, not use
258                  0, // start point x, (low left of pic)
259                  0, // start point y,
260                  _width, // width
261                  _height, // height
262                  _pixelFormat, // pictue format for _buffer
263                  _pixelDataType, // data type of _buffer
264                  (const GLvoid*) _buffer); // the pixel data
265
266  if (glGetError() != GL_NO_ERROR) {
267    _owner->UnlockAGLCntx();
268    return -1;
269  }
270
271  _bufferIsUpdated = true;
272  _owner->UnlockAGLCntx();
273
274  return 0;
275}
276
277int VideoChannelAGL::RenderOffScreenBuffer()
278{
279
280    _owner->LockAGLCntx();
281
282    if (_texture == 0)
283    {
284        _owner->UnlockAGLCntx();
285        return 0;
286    }
287
288    GLfloat xStart = 2.0f * _startWidth - 1.0f;
289    GLfloat xStop = 2.0f * _stopWidth - 1.0f;
290    GLfloat yStart = 1.0f - 2.0f * _stopHeight;
291    GLfloat yStop = 1.0f - 2.0f * _startHeight;
292
293    aglSetCurrentContext(_aglContext);
294    glBindTexture(GL_TEXTURE_RECTANGLE_EXT, _texture);
295
296    if(_stretchedWidth != _oldStretchedWidth || _stretchedHeight != _oldStretchedHeight)
297    {
298        glViewport(0, 0, _stretchedWidth, _stretchedHeight);
299    }
300    _oldStretchedHeight = _stretchedHeight;
301    _oldStretchedWidth = _stretchedWidth;
302
303    // Now really put the texture into the framebuffer
304    glLoadIdentity();
305
306    glEnable(GL_TEXTURE_RECTANGLE_EXT);
307
308    glBegin(GL_POLYGON);
309    {
310        glTexCoord2f(0.0, 0.0); glVertex2f(xStart, yStop);
311        glTexCoord2f(_width, 0.0); glVertex2f(xStop, yStop);
312        glTexCoord2f(_width, _height); glVertex2f(xStop, yStart);
313        glTexCoord2f(0.0, _height); glVertex2f(xStart, yStart);
314    }
315    glEnd();
316
317    glDisable(GL_TEXTURE_RECTANGLE_EXT);
318
319    _bufferIsUpdated = false;
320
321    _owner->UnlockAGLCntx();
322    return 0;
323}
324
325int VideoChannelAGL::IsUpdated(bool& isUpdated)
326{
327    _owner->LockAGLCntx();
328    isUpdated = _bufferIsUpdated;
329    _owner->UnlockAGLCntx();
330
331    return 0;
332}
333
334int VideoChannelAGL::SetStreamSettings(int /*streamId*/, float startWidth, float startHeight, float stopWidth, float stopHeight)
335{
336
337    _owner->LockAGLCntx();
338
339    _startWidth = startWidth;
340    _stopWidth = stopWidth;
341    _startHeight = startHeight;
342    _stopHeight = stopHeight;
343
344    int oldWidth = _width;
345    int oldHeight = _height;
346    int oldNumberOfStreams = _numberOfStreams;
347
348    _width = 0;
349    _height = 0;
350
351    int retVal = FrameSizeChange(oldWidth, oldHeight, oldNumberOfStreams);
352
353    _owner->UnlockAGLCntx();
354
355    return retVal;
356}
357
358int VideoChannelAGL::SetStreamCropSettings(int /*streamId*/, float /*startWidth*/, float /*startHeight*/, float /*stopWidth*/, float /*stopHeight*/)
359{
360    return -1;
361}
362
363#pragma mark VideoRenderAGL WindowRef constructor
364
365VideoRenderAGL::VideoRenderAGL(WindowRef windowRef, bool fullscreen, int iId) :
366_hiviewRef( 0),
367_windowRef( windowRef),
368_fullScreen( fullscreen),
369_id( iId),
370_renderCritSec(*CriticalSectionWrapper::CreateCriticalSection()),
371_screenUpdateThread( 0),
372_screenUpdateEvent( 0),
373_isHIViewRef( false),
374_aglContext( 0),
375_windowWidth( 0),
376_windowHeight( 0),
377_lastWindowWidth( -1),
378_lastWindowHeight( -1),
379_lastHiViewWidth( -1),
380_lastHiViewHeight( -1),
381_currentParentWindowHeight( 0),
382_currentParentWindowWidth( 0),
383_currentParentWindowBounds( ),
384_windowHasResized( false),
385_lastParentWindowBounds( ),
386_currentHIViewBounds( ),
387_lastHIViewBounds( ),
388_windowRect( ),
389_aglChannels( ),
390_zOrderToChannel( ),
391_hiviewEventHandlerRef( NULL),
392_windowEventHandlerRef( NULL),
393_currentViewBounds( ),
394_lastViewBounds( ),
395_renderingIsPaused( false),
396_threadID( )
397
398{
399    //WEBRTC_TRACE(kTraceInfo, kTraceVideoRenderer, _id, "%s");
400
401    _screenUpdateThread = ThreadWrapper::CreateThread(ScreenUpdateThreadProc, this, kRealtimePriority);
402    _screenUpdateEvent = EventWrapper::Create();
403
404    if(!IsValidWindowPtr(_windowRef))
405    {
406        //WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id, "%s:%d Invalid WindowRef:0x%x", __FUNCTION__, __LINE__, _windowRef);
407    }
408    else
409    {
410        //WEBRTC_TRACE(kTraceDebug, kTraceVideoRenderer, _id, "%s:%d WindowRef 0x%x is valid", __FUNCTION__, __LINE__, _windowRef);
411    }
412
413    GetWindowRect(_windowRect);
414
415    _lastViewBounds.origin.x = 0;
416    _lastViewBounds.origin.y = 0;
417    _lastViewBounds.size.width = 0;
418    _lastViewBounds.size.height = 0;
419
420}
421
422// this is a static function. It has been registered (in class constructor) to be called on various window redrawing or resizing.
423// 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.
424#pragma mark WindowRef Event Handler
425pascal OSStatus VideoRenderAGL::sHandleWindowResized (EventHandlerCallRef /*nextHandler*/,
426        EventRef theEvent,
427        void* userData)
428{
429    WindowRef windowRef = NULL;
430
431    int eventType = GetEventKind(theEvent);
432
433    // see https://dcs.sourcerepo.com/dcs/tox_view/trunk/tox/libraries/i686-win32/include/quicktime/CarbonEvents.h for a list of codes
434    GetEventParameter (theEvent,
435            kEventParamDirectObject,
436            typeWindowRef,
437            NULL,
438            sizeof (WindowRef),
439            NULL,
440            &windowRef);
441
442    VideoRenderAGL* obj = (VideoRenderAGL*)(userData);
443
444    bool updateUI = true;
445    if(kEventWindowBoundsChanged == eventType)
446    {
447    }
448    else if(kEventWindowBoundsChanging == eventType)
449    {
450    }
451    else if(kEventWindowZoomed == eventType)
452    {
453    }
454    else if(kEventWindowExpanding == eventType)
455    {
456    }
457    else if(kEventWindowExpanded == eventType)
458    {
459    }
460    else if(kEventWindowClickResizeRgn == eventType)
461    {
462    }
463    else if(kEventWindowClickDragRgn == eventType)
464    {
465    }
466    else
467    {
468        updateUI = false;
469    }
470
471    if(true == updateUI)
472    {
473        obj->ParentWindowResized(windowRef);
474        obj->UpdateClipping();
475        obj->RenderOffScreenBuffers();
476    }
477
478    return noErr;
479}
480
481#pragma mark VideoRenderAGL HIViewRef constructor
482
483VideoRenderAGL::VideoRenderAGL(HIViewRef windowRef, bool fullscreen, int iId) :
484_hiviewRef( windowRef),
485_windowRef( 0),
486_fullScreen( fullscreen),
487_id( iId),
488_renderCritSec(*CriticalSectionWrapper::CreateCriticalSection()),
489_screenUpdateThread( 0),
490_screenUpdateEvent( 0),
491_isHIViewRef( false),
492_aglContext( 0),
493_windowWidth( 0),
494_windowHeight( 0),
495_lastWindowWidth( -1),
496_lastWindowHeight( -1),
497_lastHiViewWidth( -1),
498_lastHiViewHeight( -1),
499_currentParentWindowHeight( 0),
500_currentParentWindowWidth( 0),
501_currentParentWindowBounds( ),
502_windowHasResized( false),
503_lastParentWindowBounds( ),
504_currentHIViewBounds( ),
505_lastHIViewBounds( ),
506_windowRect( ),
507_aglChannels( ),
508_zOrderToChannel( ),
509_hiviewEventHandlerRef( NULL),
510_windowEventHandlerRef( NULL),
511_currentViewBounds( ),
512_lastViewBounds( ),
513_renderingIsPaused( false),
514_threadID( )
515{
516    //WEBRTC_TRACE(kTraceDebug, "%s:%d Constructor", __FUNCTION__, __LINE__);
517    //    _renderCritSec = CriticalSectionWrapper::CreateCriticalSection();
518
519    _screenUpdateThread = ThreadWrapper::CreateThread(ScreenUpdateThreadProc, this, kRealtimePriority);
520    _screenUpdateEvent = EventWrapper::Create();
521
522    GetWindowRect(_windowRect);
523
524    _lastViewBounds.origin.x = 0;
525    _lastViewBounds.origin.y = 0;
526    _lastViewBounds.size.width = 0;
527    _lastViewBounds.size.height = 0;
528
529#ifdef NEW_HIVIEW_PARENT_EVENT_HANDLER
530    // This gets the parent window of the HIViewRef that's passed in and installs a WindowRef event handler on it
531    // The event handler looks for window resize events and adjusts the offset of the controls.
532
533    //WEBRTC_TRACE(kTraceDebug, "%s:%d Installing Eventhandler for hiviewRef's parent window", __FUNCTION__, __LINE__);
534
535
536    static const EventTypeSpec windowEventTypes[] =
537    {
538        kEventClassWindow, kEventWindowBoundsChanged,
539        kEventClassWindow, kEventWindowBoundsChanging,
540        kEventClassWindow, kEventWindowZoomed,
541        kEventClassWindow, kEventWindowExpanded,
542        kEventClassWindow, kEventWindowClickResizeRgn,
543        kEventClassWindow, kEventWindowClickDragRgn
544    };
545
546    WindowRef parentWindow = HIViewGetWindow(windowRef);
547
548    InstallWindowEventHandler (parentWindow,
549            NewEventHandlerUPP (sHandleWindowResized),
550            GetEventTypeCount(windowEventTypes),
551            windowEventTypes,
552            (void *) this, // this is an arbitrary parameter that will be passed on to your event handler when it is called later
553            &_windowEventHandlerRef);
554
555#endif
556
557#ifdef NEW_HIVIEW_EVENT_HANDLER
558    //WEBRTC_TRACE(kTraceDebug, "%s:%d Installing Eventhandler for hiviewRef", __FUNCTION__, __LINE__);
559
560    static const EventTypeSpec hiviewEventTypes[] =
561    {
562        kEventClassControl, kEventControlBoundsChanged,
563        kEventClassControl, kEventControlDraw
564        //			kEventControlDragLeave
565        //			kEventControlDragReceive
566        //			kEventControlGetFocusPart
567        //			kEventControlApplyBackground
568        //			kEventControlDraw
569        //			kEventControlHit
570
571    };
572
573    HIViewInstallEventHandler(_hiviewRef,
574            NewEventHandlerUPP(sHandleHiViewResized),
575            GetEventTypeCount(hiviewEventTypes),
576            hiviewEventTypes,
577            (void *) this,
578            &_hiviewEventHandlerRef);
579
580#endif
581}
582
583// this is a static function. It has been registered (in constructor) to be called on various window redrawing or resizing.
584// 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.
585#pragma mark HIViewRef Event Handler
586pascal OSStatus VideoRenderAGL::sHandleHiViewResized (EventHandlerCallRef nextHandler, EventRef theEvent, void* userData)
587{
588    //static int      callbackCounter = 1;
589    HIViewRef hiviewRef = NULL;
590
591    // see https://dcs.sourcerepo.com/dcs/tox_view/trunk/tox/libraries/i686-win32/include/quicktime/CarbonEvents.h for a list of codes
592    int eventType = GetEventKind(theEvent);
593    OSStatus status = noErr;
594    status = GetEventParameter (theEvent,
595            kEventParamDirectObject,
596            typeControlRef,
597            NULL,
598            sizeof (ControlRef),
599            NULL,
600            &hiviewRef);
601
602    VideoRenderAGL* obj = (VideoRenderAGL*)(userData);
603    WindowRef parentWindow = HIViewGetWindow(hiviewRef);
604    bool updateUI = true;
605
606    if(kEventControlBoundsChanged == eventType)
607    {
608    }
609    else if(kEventControlDraw == eventType)
610    {
611    }
612    else
613    {
614        updateUI = false;
615    }
616
617    if(true == updateUI)
618    {
619        obj->ParentWindowResized(parentWindow);
620        obj->UpdateClipping();
621        obj->RenderOffScreenBuffers();
622    }
623
624    return status;
625}
626
627VideoRenderAGL::~VideoRenderAGL()
628{
629
630    //WEBRTC_TRACE(kTraceDebug, "%s:%d Destructor", __FUNCTION__, __LINE__);
631
632
633#ifdef USE_EVENT_HANDLERS
634    // remove event handlers
635    OSStatus status;
636    if(_isHIViewRef)
637    {
638        status = RemoveEventHandler(_hiviewEventHandlerRef);
639    }
640    else
641    {
642        status = RemoveEventHandler(_windowEventHandlerRef);
643    }
644    if(noErr != status)
645    {
646        if(_isHIViewRef)
647        {
648
649            //WEBRTC_TRACE(kTraceDebug, "%s:%d Failed to remove hiview event handler: %d", __FUNCTION__, __LINE__, (int)_hiviewEventHandlerRef);
650        }
651        else
652        {
653            //WEBRTC_TRACE(kTraceDebug, "%s:%d Failed to remove window event handler %d", __FUNCTION__, __LINE__, (int)_windowEventHandlerRef);
654        }
655    }
656
657#endif
658
659    OSStatus status;
660#ifdef NEW_HIVIEW_PARENT_EVENT_HANDLER
661    if(_windowEventHandlerRef)
662    {
663        status = RemoveEventHandler(_windowEventHandlerRef);
664        if(status != noErr)
665        {
666            //WEBRTC_TRACE(kTraceDebug, "%s:%d failed to remove window event handler %d", __FUNCTION__, __LINE__, (int)_windowEventHandlerRef);
667        }
668    }
669#endif
670
671#ifdef NEW_HIVIEW_EVENT_HANDLER
672    if(_hiviewEventHandlerRef)
673    {
674        status = RemoveEventHandler(_hiviewEventHandlerRef);
675        if(status != noErr)
676        {
677            //WEBRTC_TRACE(kTraceDebug, "%s:%d Failed to remove hiview event handler: %d", __FUNCTION__, __LINE__, (int)_hiviewEventHandlerRef);
678        }
679    }
680#endif
681
682    // Signal event to exit thread, then delete it
683    ThreadWrapper* tmpPtr = _screenUpdateThread;
684    _screenUpdateThread = NULL;
685
686    if (tmpPtr)
687    {
688        tmpPtr->SetNotAlive();
689        _screenUpdateEvent->Set();
690        _screenUpdateEvent->StopTimer();
691
692        if (tmpPtr->Stop())
693        {
694            delete tmpPtr;
695        }
696        delete _screenUpdateEvent;
697        _screenUpdateEvent = NULL;
698    }
699
700    if (_aglContext != 0)
701    {
702        aglSetCurrentContext(_aglContext);
703        aglDestroyContext(_aglContext);
704        _aglContext = 0;
705    }
706
707    // Delete all channels
708    std::map<int, VideoChannelAGL*>::iterator it = _aglChannels.begin();
709    while (it!= _aglChannels.end())
710    {
711        delete it->second;
712        _aglChannels.erase(it);
713        it = _aglChannels.begin();
714    }
715    _aglChannels.clear();
716
717    // Clean the zOrder map
718    std::multimap<int, int>::iterator zIt = _zOrderToChannel.begin();
719    while(zIt != _zOrderToChannel.end())
720    {
721        _zOrderToChannel.erase(zIt);
722        zIt = _zOrderToChannel.begin();
723    }
724    _zOrderToChannel.clear();
725
726    //delete _renderCritSec;
727
728
729}
730
731int VideoRenderAGL::GetOpenGLVersion(int& aglMajor, int& aglMinor)
732{
733    aglGetVersion((GLint *) &aglMajor, (GLint *) &aglMinor);
734    return 0;
735}
736
737int VideoRenderAGL::Init()
738{
739    LockAGLCntx();
740
741    // Start rendering thread...
742    if (!_screenUpdateThread)
743    {
744        UnlockAGLCntx();
745        //WEBRTC_TRACE(kTraceError, "%s:%d Thread not created", __FUNCTION__, __LINE__);
746        return -1;
747    }
748    unsigned int threadId;
749    _screenUpdateThread->Start(threadId);
750
751    // Start the event triggering the render process
752    unsigned int monitorFreq = 60;
753    _screenUpdateEvent->StartTimer(true, 1000/monitorFreq);
754
755    // Create mixing textures
756    if (CreateMixingContext() == -1)
757    {
758        //WEBRTC_TRACE(kTraceError, "%s:%d Could not create a mixing context", __FUNCTION__, __LINE__);
759        UnlockAGLCntx();
760        return -1;
761    }
762
763    UnlockAGLCntx();
764    return 0;
765}
766
767VideoChannelAGL* VideoRenderAGL::CreateAGLChannel(int channel, int zOrder, float startWidth, float startHeight, float stopWidth, float stopHeight)
768{
769
770    LockAGLCntx();
771
772    //WEBRTC_TRACE(kTraceInfo, "%s:%d Creating AGL channel: %d", __FUNCTION__, __LINE__, channel);
773
774    if (HasChannel(channel))
775    {
776        //WEBRTC_TRACE(kTraceError, "%s:%d Channel already exists", __FUNCTION__, __LINE__);
777        UnlockAGLCntx();k
778        return NULL;
779    }
780
781    if (_zOrderToChannel.find(zOrder) != _zOrderToChannel.end())
782    {
783        // There are already one channel using this zOrder
784        // TODO: Allow multiple channels with same zOrder
785    }
786
787    VideoChannelAGL* newAGLChannel = new VideoChannelAGL(_aglContext, _id, this);
788
789    if (newAGLChannel->SetStreamSettings(0, startWidth, startHeight, stopWidth, stopHeight) == -1)
790    {
791        if (newAGLChannel)
792        {
793            delete newAGLChannel;
794            newAGLChannel = NULL;
795        }
796        //WEBRTC_LOG(kTraceError, "Could not create AGL channel");
797        //WEBRTC_TRACE(kTraceError, "%s:%d Could not create AGL channel", __FUNCTION__, __LINE__);
798        UnlockAGLCntx();
799        return NULL;
800    }
801k
802    _aglChannels[channel] = newAGLChannel;
803    _zOrderToChannel.insert(std::pair<int, int>(zOrder, channel));
804
805    UnlockAGLCntx();
806    return newAGLChannel;
807}
808
809int VideoRenderAGL::DeleteAllAGLChannels()
810{
811    CriticalSectionScoped cs(&_renderCritSec);
812
813    //WEBRTC_TRACE(kTraceInfo, "%s:%d Deleting all AGL channels", __FUNCTION__, __LINE__);
814    //int i = 0 ;
815    std::map<int, VideoChannelAGL*>::iterator it;
816    it = _aglChannels.begin();
817
818    while (it != _aglChannels.end())
819    {
820        VideoChannelAGL* channel = it->second;
821        if (channel)
822        delete channel;
823
824        _aglChannels.erase(it);
825        it = _aglChannels.begin();
826    }
827    _aglChannels.clear();
828    return 0;
829}
830
831int VideoRenderAGL::DeleteAGLChannel(int channel)
832{
833    CriticalSectionScoped cs(&_renderCritSec);
834    //WEBRTC_TRACE(kTraceDebug, "%s:%d Deleting AGL channel %d", __FUNCTION__, __LINE__, channel);
835
836    std::map<int, VideoChannelAGL*>::iterator it;
837    it = _aglChannels.find(channel);
838    if (it != _aglChannels.end())
839    {
840        delete it->second;
841        _aglChannels.erase(it);
842    }
843    else
844    {
845        //WEBRTC_TRACE(kTraceWarning, "%s:%d Channel not found", __FUNCTION__, __LINE__);
846        return -1;
847    }
848
849    std::multimap<int, int>::iterator zIt = _zOrderToChannel.begin();
850    while( zIt != _zOrderToChannel.end())
851    {
852        if (zIt->second == channel)
853        {
854            _zOrderToChannel.erase(zIt);
855            break;
856        }
857        zIt++;// = _zOrderToChannel.begin();
858    }
859
860    return 0;
861}
862
863int VideoRenderAGL::StopThread()
864{
865    CriticalSectionScoped cs(&_renderCritSec);
866    ThreadWrapper* tmpPtr = _screenUpdateThread;
867    //_screenUpdateThread = NULL;
868
869    if (tmpPtr)
870    {
871        tmpPtr->SetNotAlive();
872        _screenUpdateEvent->Set();
873        if (tmpPtr->Stop())
874        {
875            delete tmpPtr;
876        }
877    }
878
879    delete _screenUpdateEvent;
880    _screenUpdateEvent = NULL;
881
882    return 0;
883}
884
885bool VideoRenderAGL::IsFullScreen()
886{
887    CriticalSectionScoped cs(&_renderCritSec);
888    return _fullScreen;
889}
890
891bool VideoRenderAGL::HasChannels()
892{
893
894    CriticalSectionScoped cs(&_renderCritSec);
895
896    if (_aglChannels.begin() != _aglChannels.end())
897    {
898        return true;
899    }
900
901    return false;
902}
903
904bool VideoRenderAGL::HasChannel(int channel)
905{
906    CriticalSectionScoped cs(&_renderCritSec);
907
908    std::map<int, VideoChannelAGL*>::iterator it = _aglChannels.find(channel);
909    if (it != _aglChannels.end())
910    {
911        return true;
912    }
913
914    return false;
915}
916
917int VideoRenderAGL::GetChannels(std::list<int>& channelList)
918{
919
920    CriticalSectionScoped cs(&_renderCritSec);
921    std::map<int, VideoChannelAGL*>::iterator it = _aglChannels.begin();
922
923    while (it != _aglChannels.end())
924    {
925        channelList.push_back(it->first);
926        it++;
927    }
928
929    return 0;
930}
931
932VideoChannelAGL* VideoRenderAGL::ConfigureAGLChannel(int channel, int zOrder, float startWidth, float startHeight, float stopWidth, float stopHeight)
933{
934
935    CriticalSectionScoped cs(&_renderCritSec);
936
937    std::map<int, VideoChannelAGL*>::iterator it = _aglChannels.find(channel);
938
939    if (it != _aglChannels.end())
940    {
941        VideoChannelAGL* aglChannel = it->second;
942        if (aglChannel->SetStreamSettings(0, startWidth, startHeight, stopWidth, stopHeight) == -1)
943        {
944            return NULL;
945        }
946
947        std::multimap<int, int>::iterator it = _zOrderToChannel.begin();
948        while(it != _zOrderToChannel.end())
949        {
950            if (it->second == channel)
951            {
952                if (it->first != zOrder)
953                {
954                    _zOrderToChannel.erase(it);
955                    _zOrderToChannel.insert(std::pair<int, int>(zOrder, channel));
956                }
957                break;
958            }
959            it++;
960        }
961        return aglChannel;
962    }
963
964    return NULL;
965}
966
967bool VideoRenderAGL::ScreenUpdateThreadProc(void* obj)
968{
969    return static_cast<VideoRenderAGL*>(obj)->ScreenUpdateProcess();
970}
971
972bool VideoRenderAGL::ScreenUpdateProcess()
973{
974    _screenUpdateEvent->Wait(100);
975
976    LockAGLCntx();
977
978    if (!_screenUpdateThread)
979    {
980        UnlockAGLCntx();
981        return false;
982    }
983
984    if (aglSetCurrentContext(_aglContext) == GL_FALSE)
985    {
986        UnlockAGLCntx();
987        return true;
988    }
989
990    if (GetWindowRect(_windowRect) == -1)
991    {
992        UnlockAGLCntx();
993        return true;
994    }
995
996    if (_windowWidth != (_windowRect.right - _windowRect.left)
997            || _windowHeight != (_windowRect.bottom - _windowRect.top))
998    {
999        // We have a new window size, update the context.
1000        if (aglUpdateContext(_aglContext) == GL_FALSE)
1001        {
1002            UnlockAGLCntx();
1003            return true;
1004        }
1005        _windowWidth = _windowRect.right - _windowRect.left;
1006        _windowHeight = _windowRect.bottom - _windowRect.top;
1007    }
1008
1009    // this section will poll to see if the window size has changed
1010    // this is causing problem w/invalid windowRef
1011    // this code has been modified and exists now in the window event handler
1012#ifndef NEW_HIVIEW_PARENT_EVENT_HANDLER
1013    if (_isHIViewRef)
1014    {
1015
1016        if(FALSE == HIViewIsValid(_hiviewRef))
1017        {
1018
1019            //WEBRTC_TRACE(kTraceDebug, "%s:%d Invalid windowRef", __FUNCTION__, __LINE__);
1020            UnlockAGLCntx();
1021            return true;
1022        }
1023        WindowRef window = HIViewGetWindow(_hiviewRef);
1024
1025        if(FALSE == IsValidWindowPtr(window))
1026        {
1027            //WEBRTC_TRACE(kTraceDebug, "%s:%d Invalide hiviewRef", __FUNCTION__, __LINE__);
1028            UnlockAGLCntx();
1029            return true;
1030        }
1031        if (window == NULL)
1032        {
1033            //WEBRTC_TRACE(kTraceDebug, "%s:%d WindowRef = NULL", __FUNCTION__, __LINE__);
1034            UnlockAGLCntx();
1035            return true;
1036        }
1037
1038        if(FALSE == MacIsWindowVisible(window))
1039        {
1040            //WEBRTC_TRACE(kTraceDebug, "%s:%d MacIsWindowVisible == FALSE. Returning early", __FUNCTION__, __LINE__);
1041            UnlockAGLCntx();
1042            return true;
1043        }
1044
1045        HIRect viewBounds; // Placement and size for HIView
1046        int windowWidth = 0; // Parent window width
1047        int windowHeight = 0; // Parent window height
1048
1049        // NOTE: Calling GetWindowBounds with kWindowStructureRgn will crash intermittentaly if the OS decides it needs to push it into the back for a moment.
1050        // 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
1051        Rect contentBounds =
1052        {   0, 0, 0, 0}; // The bounds for the parent window
1053
1054#if		defined(USE_CONTENT_RGN)
1055        GetWindowBounds(window, kWindowContentRgn, &contentBounds);
1056#elif	defined(USE_STRUCT_RGN)
1057        GetWindowBounds(window, kWindowStructureRgn, &contentBounds);
1058#endif
1059
1060        Rect globalBounds =
1061        {   0, 0, 0, 0}; // The bounds for the parent window
1062        globalBounds.top = contentBounds.top;
1063        globalBounds.right = contentBounds.right;
1064        globalBounds.bottom = contentBounds.bottom;
1065        globalBounds.left = contentBounds.left;
1066
1067        windowHeight = globalBounds.bottom - globalBounds.top;
1068        windowWidth = globalBounds.right - globalBounds.left;
1069
1070        // Get the size of the HIViewRef
1071        HIViewGetBounds(_hiviewRef, &viewBounds);
1072        HIViewConvertRect(&viewBounds, _hiviewRef, NULL);
1073
1074        // Check if this is the first call..
1075        if (_lastWindowHeight == -1 &&
1076                _lastWindowWidth == -1)
1077        {
1078            _lastWindowWidth = windowWidth;
1079            _lastWindowHeight = windowHeight;
1080
1081            _lastViewBounds.origin.x = viewBounds.origin.x;
1082            _lastViewBounds.origin.y = viewBounds.origin.y;
1083            _lastViewBounds.size.width = viewBounds.size.width;
1084            _lastViewBounds.size.height = viewBounds.size.height;
1085        }
1086        sfasdfasdf
1087
1088        bool resized = false;
1089
1090        // Check if parent window size has changed
1091        if (windowHeight != _lastWindowHeight ||
1092                windowWidth != _lastWindowWidth)
1093        {
1094            resized = true;
1095        }
1096
1097        // Check if the HIView has new size or is moved in the parent window
1098        if (_lastViewBounds.origin.x != viewBounds.origin.x ||
1099                _lastViewBounds.origin.y != viewBounds.origin.y ||
1100                _lastViewBounds.size.width != viewBounds.size.width ||
1101                _lastViewBounds.size.height != viewBounds.size.height)
1102        {
1103            // The HiView is resized or has moved.
1104            resized = true;
1105        }
1106
1107        if (resized)
1108        {
1109
1110            //WEBRTC_TRACE(kTraceDebug, "%s:%d Window has resized", __FUNCTION__, __LINE__);
1111
1112            // Calculate offset between the windows
1113            // {x, y, widht, height}, x,y = lower left corner
1114            const GLint offs[4] =
1115            {   (int)(0.5f + viewBounds.origin.x),
1116                (int)(0.5f + windowHeight - (viewBounds.origin.y + viewBounds.size.height)),
1117                viewBounds.size.width, viewBounds.size.height};
1118
1119            //WEBRTC_TRACE(kTraceDebug, "%s:%d contentBounds	t:%d r:%d b:%d l:%d", __FUNCTION__, __LINE__,
1120            contentBounds.top, contentBounds.right, contentBounds.bottom, contentBounds.left);
1121            //WEBRTC_TRACE(kTraceDebug, "%s:%d windowHeight=%d", __FUNCTION__, __LINE__, windowHeight);
1122            //WEBRTC_TRACE(kTraceDebug, "%s:%d offs[4] = %d, %d, %d, %d", __FUNCTION__, __LINE__, offs[0], offs[1], offs[2], offs[3]);
1123
1124            aglSetDrawable (_aglContext, GetWindowPort(window));
1125            aglSetInteger(_aglContext, AGL_BUFFER_RECT, offs);
1126            aglEnable(_aglContext, AGL_BUFFER_RECT);
1127
1128            // We need to change the viewport too if the HIView size has changed
1129            glViewport(0.0f, 0.0f, (GLsizei) viewBounds.size.width, (GLsizei) viewBounds.size.height);
1130
1131        }
1132        _lastWindowWidth = windowWidth;
1133        _lastWindowHeight = windowHeight;
1134
1135        _lastViewBounds.origin.x = viewBounds.origin.x;
1136        _lastViewBounds.origin.y = viewBounds.origin.y;
1137        _lastViewBounds.size.width = viewBounds.size.width;
1138        _lastViewBounds.size.height = viewBounds.size.height;
1139
1140    }
1141#endif
1142    if (_fullScreen)
1143    {
1144        // TODO
1145        // We use double buffers, must always update
1146        //RenderOffScreenBuffersToBackBuffer();
1147    }
1148    else
1149    {
1150        // Check if there are any updated buffers
1151        bool updated = false;
1152
1153        // TODO: check if window size is updated!
1154        // TODO Improvement: Walk through the zOrder Map to only render the ones in need of update
1155        std::map<int, VideoChannelAGL*>::iterator it = _aglChannels.begin();
1156        while (it != _aglChannels.end())
1157        {
1158
1159            VideoChannelAGL* aglChannel = it->second;
1160            aglChannel->UpdateStretchSize(_windowHeight, _windowWidth);
1161            aglChannel->IsUpdated(updated);
1162            if (updated)
1163            {
1164                break;
1165            }
1166            it++;
1167        }
1168
1169        if (updated)
1170        {
1171            // At least on buffers is updated, we need to repaint the texture
1172            if (RenderOffScreenBuffers() != -1)
1173            {
1174                // MF
1175                //SwapAndDisplayBuffers();
1176            }
1177            else
1178            {
1179                // Error updating the mixing texture, don't swap.
1180            }
1181        }
1182    }
1183
1184    UnlockAGLCntx();
1185
1186    //WEBRTC_LOG(kTraceDebug, "Leaving ScreenUpdateProcess()");
1187    return true;
1188}
1189
1190void VideoRenderAGL::ParentWindowResized(WindowRef window)
1191{
1192    //WEBRTC_LOG(kTraceDebug, "%s HIViewRef:%d owner window has resized", __FUNCTION__, (int)_hiviewRef);
1193
1194    LockAGLCntx();
1195k
1196    // set flag
1197    _windowHasResized = false;
1198
1199    if(FALSE == HIViewIsValid(_hiviewRef))
1200    {
1201        //WEBRTC_LOG(kTraceDebug, "invalid windowRef");
1202        UnlockAGLCntx();
1203        return;
1204    }
1205
1206    if(FALSE == IsValidWindowPtr(window))
1207    {
1208        //WEBRTC_LOG(kTraceError, "invalid windowRef");
1209        UnlockAGLCntx();
1210        return;
1211    }
1212
1213    if (window == NULL)
1214    {
1215        //WEBRTC_LOG(kTraceError, "windowRef = NULL");
1216        UnlockAGLCntx();
1217        return;
1218    }
1219
1220    if(FALSE == MacIsWindowVisible(window))
1221    {
1222        //WEBRTC_LOG(kTraceDebug, "MacIsWindowVisible = FALSE. Returning early.");
1223        UnlockAGLCntx();
1224        return;
1225    }
1226
1227    Rect contentBounds =
1228    {   0, 0, 0, 0};
1229
1230#if		defined(USE_CONTENT_RGN)
1231    GetWindowBounds(window, kWindowContentRgn, &contentBounds);
1232#elif	defined(USE_STRUCT_RGN)
1233    GetWindowBounds(window, kWindowStructureRgn, &contentBounds);
1234#endif
1235
1236    //WEBRTC_LOG(kTraceDebug, "%s contentBounds	t:%d r:%d b:%d l:%d", __FUNCTION__, contentBounds.top, contentBounds.right, contentBounds.bottom, contentBounds.left);
1237
1238    // update global vars
1239    _currentParentWindowBounds.top = contentBounds.top;
1240    _currentParentWindowBounds.left = contentBounds.left;
1241    _currentParentWindowBounds.bottom = contentBounds.bottom;
1242    _currentParentWindowBounds.right = contentBounds.right;
1243
1244    _currentParentWindowWidth = _currentParentWindowBounds.right - _currentParentWindowBounds.left;
1245    _currentParentWindowHeight = _currentParentWindowBounds.bottom - _currentParentWindowBounds.top;
1246
1247    _windowHasResized = true;
1248
1249    // ********* update AGL offsets
1250    HIRect viewBounds;
1251    HIViewGetBounds(_hiviewRef, &viewBounds);
1252    HIViewConvertRect(&viewBounds, _hiviewRef, NULL);
1253
1254    const GLint offs[4] =
1255    {   (int)(0.5f + viewBounds.origin.x),
1256        (int)(0.5f + _currentParentWindowHeight - (viewBounds.origin.y + viewBounds.size.height)),
1257        viewBounds.size.width, viewBounds.size.height};
1258    //WEBRTC_LOG(kTraceDebug, "%s _currentParentWindowHeight=%d", __FUNCTION__, _currentParentWindowHeight);
1259    //WEBRTC_LOG(kTraceDebug, "%s offs[4] = %d, %d, %d, %d", __FUNCTION__, offs[0], offs[1], offs[2], offs[3]);
1260
1261    aglSetCurrentContext(_aglContext);
1262    aglSetDrawable (_aglContext, GetWindowPort(window));
1263    aglSetInteger(_aglContext, AGL_BUFFER_RECT, offs);
1264    aglEnable(_aglContext, AGL_BUFFER_RECT);
1265
1266    // We need to change the viewport too if the HIView size has changed
1267    glViewport(0.0f, 0.0f, (GLsizei) viewBounds.size.width, (GLsizei) viewBounds.size.height);
1268
1269    UnlockAGLCntx();
1270
1271    return;
1272}
1273
1274int VideoRenderAGL::CreateMixingContext()
1275{
1276
1277    LockAGLCntx();
1278
1279    //WEBRTC_LOG(kTraceDebug, "Entering CreateMixingContext()");
1280
1281    // Use both AGL_ACCELERATED and AGL_NO_RECOVERY to make sure
1282    // a hardware renderer is used and not a software renderer.
1283
1284    GLint attributes[] =
1285    {
1286        AGL_DOUBLEBUFFER,
1287        AGL_WINDOW,
1288        AGL_RGBA,
1289        AGL_NO_RECOVERY,
1290        AGL_ACCELERATED,
1291        AGL_RED_SIZE, 8,
1292        AGL_GREEN_SIZE, 8,
1293        AGL_BLUE_SIZE, 8,
1294        AGL_ALPHA_SIZE, 8,
1295        AGL_DEPTH_SIZE, 24,
1296        AGL_NONE,
1297    };
1298
1299    AGLPixelFormat aglPixelFormat;
1300
1301    // ***** Set up the OpenGL Context *****
1302
1303    // Get a pixel format for the attributes above
1304    aglPixelFormat = aglChoosePixelFormat(NULL, 0, attributes);
1305    if (NULL == aglPixelFormat)
1306    {
1307        //WEBRTC_LOG(kTraceError, "Could not create pixel format");
1308        UnlockAGLCntx();
1309        return -1;
1310    }
1311
1312    // Create an AGL context
1313    _aglContext = aglCreateContext(aglPixelFormat, NULL);
1314    if (_aglContext == NULL)
1315    {
1316        //WEBRTC_LOG(kTraceError, "Could no create AGL context");
1317        UnlockAGLCntx();
1318        return -1;
1319    }
1320
1321    // Release the pixel format memory
1322    aglDestroyPixelFormat(aglPixelFormat);
1323
1324    // Set the current AGL context for the rest of the settings
1325    if (aglSetCurrentContext(_aglContext) == false)
1326    {
1327        //WEBRTC_LOG(kTraceError, "Could not set current context: %d", aglGetError());
1328        UnlockAGLCntx();
1329        return -1;
1330    }
1331
1332    if (_isHIViewRef)
1333    {
1334        //---------------------------
1335        // BEGIN: new test code
1336#if 0
1337        // Don't use this one!
1338        // There seems to be an OS X bug that can't handle
1339        // movements and resizing of the parent window
1340        // and or the HIView
1341        if (aglSetHIViewRef(_aglContext,_hiviewRef) == false)
1342        {
1343            //WEBRTC_LOG(kTraceError, "Could not set WindowRef: %d", aglGetError());
1344            UnlockAGLCntx();
1345            return -1;
1346        }
1347#else
1348
1349        // Get the parent window for this control
1350        WindowRef window = GetControlOwner(_hiviewRef);
1351
1352        Rect globalBounds =
1353        {   0,0,0,0}; // The bounds for the parent window
1354        HIRect viewBounds; // Placemnt in the parent window and size.
1355        int windowHeight = 0;
1356
1357        //		Rect titleBounds = {0,0,0,0};
1358        //		GetWindowBounds(window, kWindowTitleBarRgn, &titleBounds);
1359        //		_titleBarHeight = titleBounds.top - titleBounds.bottom;
1360        //		if(0 == _titleBarHeight)
1361        //		{
1362        //            //WEBRTC_LOG(kTraceError, "Titlebar height = 0");
1363        //            //return -1;
1364        //		}
1365
1366
1367        // Get the bounds for the parent window
1368#if		defined(USE_CONTENT_RGN)
1369        GetWindowBounds(window, kWindowContentRgn, &globalBounds);
1370#elif	defined(USE_STRUCT_RGN)
1371        GetWindowBounds(window, kWindowStructureRgn, &globalBounds);
1372#endif
1373        windowHeight = globalBounds.bottom - globalBounds.top;
1374
1375        // Get the bounds for the HIView
1376        HIViewGetBounds(_hiviewRef, &viewBounds);
1377
1378        HIViewConvertRect(&viewBounds, _hiviewRef, NULL);
1379
1380        const GLint offs[4] =
1381        {   (int)(0.5f + viewBounds.origin.x),
1382            (int)(0.5f + windowHeight - (viewBounds.origin.y + viewBounds.size.height)),
1383            viewBounds.size.width, viewBounds.size.height};
1384
1385        //WEBRTC_LOG(kTraceDebug, "%s offs[4] = %d, %d, %d, %d", __FUNCTION__, offs[0], offs[1], offs[2], offs[3]);
1386
1387
1388        aglSetDrawable (_aglContext, GetWindowPort(window));
1389        aglSetInteger(_aglContext, AGL_BUFFER_RECT, offs);
1390        aglEnable(_aglContext, AGL_BUFFER_RECT);
1391
1392        GLint surfaceOrder = 1; // 1: above window, -1 below.
1393        //OSStatus status = aglSetInteger(_aglContext, AGL_SURFACE_ORDER, &surfaceOrder);
1394        aglSetInteger(_aglContext, AGL_SURFACE_ORDER, &surfaceOrder);
1395
1396        glViewport(0.0f, 0.0f, (GLsizei) viewBounds.size.width, (GLsizei) viewBounds.size.height);
1397#endif
1398
1399    }
1400    else
1401    {
1402        if(GL_FALSE == aglSetDrawable (_aglContext, GetWindowPort(_windowRef)))
1403        {
1404            //WEBRTC_LOG(kTraceError, "Could not set WindowRef: %d", aglGetError());
1405            UnlockAGLCntx();
1406            return -1;
1407        }
1408    }
1409
1410    _windowWidth = _windowRect.right - _windowRect.left;
1411    _windowHeight = _windowRect.bottom - _windowRect.top;
1412
1413    // opaque surface
1414    int surfaceOpacity = 1;
1415    if (aglSetInteger(_aglContext, AGL_SURFACE_OPACITY, (const GLint *) &surfaceOpacity) == false)
1416    {
1417        //WEBRTC_LOG(kTraceError, "Could not set surface opacity: %d", aglGetError());
1418        UnlockAGLCntx();
1419        return -1;
1420    }
1421
1422    // 1 -> sync to screen rat, slow...
1423    //int swapInterval = 0;  // 0 don't sync with vertical trace
1424    int swapInterval = 0; // 1 sync with vertical trace
1425    if (aglSetInteger(_aglContext, AGL_SWAP_INTERVAL, (const GLint *) &swapInterval) == false)
1426    {
1427        //WEBRTC_LOG(kTraceError, "Could not set swap interval: %d", aglGetError());
1428        UnlockAGLCntx();
1429        return -1;
1430    }
1431
1432    // Update the rect with the current size
1433    if (GetWindowRect(_windowRect) == -1)
1434    {
1435        //WEBRTC_LOG(kTraceError, "Could not get window size");
1436        UnlockAGLCntx();
1437        return -1;
1438    }
1439
1440    // Disable not needed functionality to increase performance
1441    glDisable(GL_DITHER);
1442    glDisable(GL_ALPHA_TEST);
1443    glDisable(GL_STENCIL_TEST);
1444    glDisable(GL_FOG);
1445    glDisable(GL_TEXTURE_2D);
1446    glPixelZoom(1.0, 1.0);
1447
1448    glDisable(GL_BLEND);
1449    glDisable(GL_DEPTH_TEST);
1450    glDepthMask(GL_FALSE);
1451    glDisable(GL_CULL_FACE);
1452
1453    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
1454    glClear(GL_COLOR_BUFFER_BIT);
1455
1456    GLenum glErr = glGetError();
1457
1458    if (glErr)
1459    {
1460    }
1461
1462    UpdateClipping();
1463
1464    //WEBRTC_LOG(kTraceDebug, "Leaving CreateMixingContext()");
1465
1466    UnlockAGLCntx();
1467    return 0;
1468}
1469
1470int VideoRenderAGL::RenderOffScreenBuffers()
1471{
1472    LockAGLCntx();
1473
1474    // Get the current window size, it might have changed since last render.
1475    if (GetWindowRect(_windowRect) == -1)
1476    {
1477        //WEBRTC_LOG(kTraceError, "Could not get window rect");
1478        UnlockAGLCntx();
1479        return -1;
1480    }
1481
1482    if (aglSetCurrentContext(_aglContext) == false)
1483    {
1484        //WEBRTC_LOG(kTraceError, "Could not set current context for rendering");
1485        UnlockAGLCntx();
1486        return -1;
1487    }
1488
1489    // HERE - onl if updated!
1490    glClear(GL_COLOR_BUFFER_BIT);
1491
1492    // Loop through all channels starting highest zOrder ending with lowest.
1493    for (std::multimap<int, int>::reverse_iterator rIt = _zOrderToChannel.rbegin();
1494    rIt != _zOrderToChannel.rend();
1495    rIt++)
1496    {
1497        int channelId = rIt->second;
1498        std::map<int, VideoChannelAGL*>::iterator it = _aglChannels.find(channelId);
1499
1500        VideoChannelAGL* aglChannel = it->second;
1501
1502        aglChannel->RenderOffScreenBuffer();
1503    }
1504
1505    SwapAndDisplayBuffers();
1506
1507    UnlockAGLCntx();
1508    return 0;
1509}
1510
1511int VideoRenderAGL::SwapAndDisplayBuffers()
1512{
1513
1514    LockAGLCntx();
1515    if (_fullScreen)
1516    {
1517        // TODO:
1518        // Swap front and back buffers, rendering taking care of in the same call
1519        //aglSwapBuffers(_aglContext);
1520        // Update buffer index to the idx for the next rendering!
1521        //_textureIdx = (_textureIdx + 1) & 1;
1522    }
1523    else
1524    {
1525        // Single buffer rendering, only update context.
1526        glFlush();
1527        aglSwapBuffers(_aglContext);
1528        HIViewSetNeedsDisplay(_hiviewRef, true);
1529    }
1530
1531    UnlockAGLCntx();
1532    return 0;
1533}
1534
1535int VideoRenderAGL::GetWindowRect(Rect& rect)
1536{
1537
1538    LockAGLCntx();
1539
1540    if (_isHIViewRef)
1541    {
1542        if (_hiviewRef)
1543        {
1544            HIRect HIViewRect1;
1545            if(FALSE == HIViewIsValid(_hiviewRef))
1546            {
1547                rect.top = 0;
1548                rect.left = 0;
1549                rect.right = 0;
1550                rect.bottom = 0;
1551                //WEBRTC_LOG(kTraceError,"GetWindowRect() HIViewIsValid() returned false");
1552                UnlockAGLCntx();
1553            }
1554            HIViewGetBounds(_hiviewRef,&HIViewRect1);
1555            HIRectConvert(&HIViewRect1, 1, NULL, 2, NULL);
1556            if(HIViewRect1.origin.x < 0)
1557            {
1558                rect.top = 0;
1559                //WEBRTC_LOG(kTraceDebug, "GetWindowRect() rect.top = 0");
1560            }
1561            else
1562            {
1563                rect.top = HIViewRect1.origin.x;
1564            }
1565
1566            if(HIViewRect1.origin.y < 0)
1567            {
1568                rect.left = 0;
1569                //WEBRTC_LOG(kTraceDebug, "GetWindowRect() rect.left = 0");
1570            }
1571            else
1572            {
1573                rect.left = HIViewRect1.origin.y;
1574            }
1575
1576            if(HIViewRect1.size.width < 0)
1577            {
1578                rect.right = 0;
1579                //WEBRTC_LOG(kTraceDebug, "GetWindowRect() rect.right = 0");
1580            }
1581            else
1582            {
1583                rect.right = HIViewRect1.size.width;
1584            }
1585
1586            if(HIViewRect1.size.height < 0)
1587            {
1588                rect.bottom = 0;
1589                //WEBRTC_LOG(kTraceDebug, "GetWindowRect() rect.bottom = 0");
1590            }
1591            else
1592            {
1593                rect.bottom = HIViewRect1.size.height;
1594            }
1595
1596            ////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);
1597            UnlockAGLCntx();
1598        }
1599        else
1600        {
1601            //WEBRTC_LOG(kTraceError, "invalid HIViewRef");
1602            UnlockAGLCntx();
1603        }
1604    }
1605    else
1606    {
1607        if (_windowRef)
1608        {
1609            GetWindowBounds(_windowRef, kWindowContentRgn, &rect);
1610            UnlockAGLCntx();
1611        }
1612        else
1613        {
1614            //WEBRTC_LOG(kTraceError, "No WindowRef");
1615            UnlockAGLCntx();
1616        }
1617    }
1618}
1619
1620int VideoRenderAGL::UpdateClipping()
1621{
1622    //WEBRTC_LOG(kTraceDebug, "Entering UpdateClipping()");
1623    LockAGLCntx();
1624
1625    if(_isHIViewRef)
1626    {
1627        if(FALSE == HIViewIsValid(_hiviewRef))
1628        {
1629            //WEBRTC_LOG(kTraceError, "UpdateClipping() _isHIViewRef is invalid. Returning -1");
1630            UnlockAGLCntx();
1631            return -1;
1632        }
1633
1634        RgnHandle visibleRgn = NewRgn();
1635        SetEmptyRgn (visibleRgn);
1636
1637        if(-1 == CalculateVisibleRegion((ControlRef)_hiviewRef, visibleRgn, true))
1638        {
1639        }
1640
1641        if(GL_FALSE == aglSetCurrentContext(_aglContext))
1642        {
1643            GLenum glErr = aglGetError();
1644            //WEBRTC_LOG(kTraceError, "aglSetCurrentContext returned FALSE with error code %d at line %d", glErr, __LINE__);
1645        }
1646
1647        if(GL_FALSE == aglEnable(_aglContext, AGL_CLIP_REGION))
1648        {
1649            GLenum glErr = aglGetError();
1650            //WEBRTC_LOG(kTraceError, "aglEnable returned FALSE with error code %d at line %d\n", glErr, __LINE__);
1651        }
1652
1653        if(GL_FALSE == aglSetInteger(_aglContext, AGL_CLIP_REGION, (const GLint*)visibleRgn))
1654        {
1655            GLenum glErr = aglGetError();
1656            //WEBRTC_LOG(kTraceError, "aglSetInteger returned FALSE with error code %d at line %d\n", glErr, __LINE__);
1657        }
1658
1659        DisposeRgn(visibleRgn);
1660    }
1661    else
1662    {
1663        //WEBRTC_LOG(kTraceDebug, "Not using a hiviewref!\n");
1664    }
1665
1666    //WEBRTC_LOG(kTraceDebug, "Leaving UpdateClipping()");
1667    UnlockAGLCntx();
1668    return true;
1669}
1670
1671int VideoRenderAGL::CalculateVisibleRegion(ControlRef control, RgnHandle &visibleRgn, bool clipChildren)
1672{
1673
1674    //	LockAGLCntx();
1675
1676    //WEBRTC_LOG(kTraceDebug, "Entering CalculateVisibleRegion()");
1677    OSStatus osStatus = 0;
1678    OSErr osErr = 0;
1679
1680    RgnHandle tempRgn = NewRgn();
1681    if (IsControlVisible(control))
1682    {
1683        RgnHandle childRgn = NewRgn();
1684        WindowRef window = GetControlOwner(control);
1685        ControlRef rootControl;
1686        GetRootControl(window, &rootControl); // 'wvnc'
1687        ControlRef masterControl;
1688        osStatus = GetSuperControl(rootControl, &masterControl);
1689        // //WEBRTC_LOG(kTraceDebug, "IBM GetSuperControl=%d", osStatus);
1690
1691        if (masterControl != NULL)
1692        {
1693            CheckValidRegion(visibleRgn);
1694            // init visibleRgn with region of 'wvnc'
1695            osStatus = GetControlRegion(rootControl, kControlStructureMetaPart, visibleRgn);
1696            // //WEBRTC_LOG(kTraceDebug, "IBM GetControlRegion=%d : %d", osStatus, __LINE__);
1697            //GetSuperControl(rootControl, &rootControl);
1698            ControlRef tempControl = control, lastControl = 0;
1699            while (tempControl != masterControl) // current control != master
1700
1701            {
1702                CheckValidRegion(tempRgn);
1703
1704                // //WEBRTC_LOG(kTraceDebug, "IBM tempControl=%d masterControl=%d", tempControl, masterControl);
1705                ControlRef subControl;
1706
1707                osStatus = GetControlRegion(tempControl, kControlStructureMetaPart, tempRgn); // intersect the region of the current control with visibleRgn
1708                // //WEBRTC_LOG(kTraceDebug, "IBM GetControlRegion=%d : %d", osStatus, __LINE__);
1709                CheckValidRegion(tempRgn);
1710
1711                osErr = HIViewConvertRegion(tempRgn, tempControl, rootControl);
1712                // //WEBRTC_LOG(kTraceDebug, "IBM HIViewConvertRegion=%d : %d", osErr, __LINE__);
1713                CheckValidRegion(tempRgn);
1714
1715                SectRgn(tempRgn, visibleRgn, visibleRgn);
1716                CheckValidRegion(tempRgn);
1717                CheckValidRegion(visibleRgn);
1718                if (EmptyRgn(visibleRgn)) // if the region is empty, bail
1719                break;
1720
1721                if (clipChildren || tempControl != control) // clip children if true, cut out the tempControl if it's not one passed to this function
1722
1723                {
1724                    UInt16 numChildren;
1725                    osStatus = CountSubControls(tempControl, &numChildren); // count the subcontrols
1726                    // //WEBRTC_LOG(kTraceDebug, "IBM CountSubControls=%d : %d", osStatus, __LINE__);
1727
1728                    // //WEBRTC_LOG(kTraceDebug, "IBM numChildren=%d", numChildren);
1729                    for (int i = 0; i < numChildren; i++)
1730                    {
1731                        osErr = GetIndexedSubControl(tempControl, numChildren - i, &subControl); // retrieve the subcontrol in order by zorder
1732                        // //WEBRTC_LOG(kTraceDebug, "IBM GetIndexedSubControls=%d : %d", osErr, __LINE__);
1733                        if ( subControl == lastControl ) // break because of zorder
1734
1735                        {
1736                            // //WEBRTC_LOG(kTraceDebug, "IBM breaking because of zorder %d", __LINE__);
1737                            break;
1738                        }
1739
1740                        if (!IsControlVisible(subControl)) // dont' clip invisible controls
1741
1742                        {
1743                            // //WEBRTC_LOG(kTraceDebug, "IBM continue. Control is not visible %d", __LINE__);
1744                            continue;
1745                        }
1746
1747                        if(!subControl) continue;
1748
1749                        osStatus = GetControlRegion(subControl, kControlStructureMetaPart, tempRgn); //get the region of the current control and union to childrg
1750                        // //WEBRTC_LOG(kTraceDebug, "IBM GetControlRegion=%d %d", osStatus, __LINE__);
1751                        CheckValidRegion(tempRgn);
1752                        if(osStatus != 0)
1753                        {
1754                            // //WEBRTC_LOG(kTraceDebug, "IBM ERROR! osStatus=%d. Continuing. %d", osStatus, __LINE__);
1755                            continue;
1756                        }
1757                        if(!tempRgn)
1758                        {
1759                            // //WEBRTC_LOG(kTraceDebug, "IBM ERROR! !tempRgn %d", osStatus, __LINE__);
1760                            continue;
1761                        }
1762
1763                        osStatus = HIViewConvertRegion(tempRgn, subControl, rootControl);
1764                        CheckValidRegion(tempRgn);
1765                        // //WEBRTC_LOG(kTraceDebug, "IBM HIViewConvertRegion=%d %d", osStatus, __LINE__);
1766                        if(osStatus != 0)
1767                        {
1768                            // //WEBRTC_LOG(kTraceDebug, "IBM ERROR! osStatus=%d. Continuing. %d", osStatus, __LINE__);
1769                            continue;
1770                        }
1771                        if(!rootControl)
1772                        {
1773                            // //WEBRTC_LOG(kTraceDebug, "IBM ERROR! !rootControl %d", osStatus, __LINE__);
1774                            continue;
1775                        }
1776
1777                        UnionRgn(tempRgn, childRgn, childRgn);
1778                        CheckValidRegion(tempRgn);
1779                        CheckValidRegion(childRgn);
1780                        CheckValidRegion(visibleRgn);
1781                        if(!childRgn)
1782                        {
1783                            // //WEBRTC_LOG(kTraceDebug, "IBM ERROR! !childRgn %d", osStatus, __LINE__);
1784                            continue;
1785                        }
1786
1787                    }  // next child control
1788                }
1789                lastControl = tempControl;
1790                GetSuperControl(tempControl, &subControl);
1791                tempControl = subControl;
1792            }
1793
1794            DiffRgn(visibleRgn, childRgn, visibleRgn);
1795            CheckValidRegion(visibleRgn);
1796            CheckValidRegion(childRgn);
1797            DisposeRgn(childRgn);
1798        }
1799        else
1800        {
1801            CopyRgn(tempRgn, visibleRgn);
1802            CheckValidRegion(tempRgn);
1803            CheckValidRegion(visibleRgn);
1804        }
1805        DisposeRgn(tempRgn);
1806    }
1807
1808    //WEBRTC_LOG(kTraceDebug, "Leaving CalculateVisibleRegion()");
1809    //_aglCritPtr->Leave();
1810    return 0;
1811}
1812
1813bool VideoRenderAGL::CheckValidRegion(RgnHandle rHandle)
1814{
1815
1816    Handle hndSize = (Handle)rHandle;
1817    long size = GetHandleSize(hndSize);
1818    if(0 == size)
1819    {
1820
1821        OSErr memErr = MemError();
1822        if(noErr != memErr)
1823        {
1824            // //WEBRTC_LOG(kTraceError, "IBM ERROR Could not get size of handle. MemError() returned %d", memErr);
1825        }
1826        else
1827        {
1828            // //WEBRTC_LOG(kTraceError, "IBM ERROR Could not get size of handle yet MemError() returned noErr");
1829        }
1830
1831    }
1832    else
1833    {
1834        // //WEBRTC_LOG(kTraceDebug, "IBM handleSize = %d", size);
1835    }
1836
1837    if(false == IsValidRgnHandle(rHandle))
1838    {
1839        // //WEBRTC_LOG(kTraceError, "IBM ERROR Invalid Region found : $%d", rHandle);
1840        assert(false);
1841    }
1842
1843    int err = QDError();
1844    switch(err)
1845    {
1846        case 0:
1847        break;
1848        case -147:
1849        //WEBRTC_LOG(kTraceError, "ERROR region too big");
1850        assert(false);
1851        break;
1852
1853        case -149:
1854        //WEBRTC_LOG(kTraceError, "ERROR not enough stack");
1855        assert(false);
1856        break;
1857
1858        default:
1859        //WEBRTC_LOG(kTraceError, "ERROR Unknown QDError %d", err);
1860        assert(false);
1861        break;
1862    }
1863
1864    return true;
1865}
1866
1867int VideoRenderAGL::ChangeWindow(void* newWindowRef)
1868{
1869
1870    LockAGLCntx();
1871
1872    UnlockAGLCntx();
1873    return -1;
1874}
1875int32_t VideoRenderAGL::ChangeUniqueID(int32_t id)
1876{
1877    LockAGLCntx();
1878
1879    UnlockAGLCntx();
1880    return -1;
1881}
1882
1883int32_t VideoRenderAGL::StartRender()
1884{
1885
1886    LockAGLCntx();
1887    const unsigned int MONITOR_FREQ = 60;
1888    if(TRUE == _renderingIsPaused)
1889    {
1890        //WEBRTC_TRACE(kTraceInfo, kTraceVideoRenderer, _id, "%s:%d Rendering is paused. Restarting now", __FUNCTION__, __LINE__);
1891
1892        // we already have the thread. Most likely StopRender() was called and they were paused
1893        if(FALSE == _screenUpdateThread->Start(_threadID))
1894        {
1895            //WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id, "%s:%d Failed to start screenUpdateThread", __FUNCTION__, __LINE__);
1896            UnlockAGLCntx();
1897            return -1;
1898        }
1899        if(FALSE == _screenUpdateEvent->StartTimer(true, 1000/MONITOR_FREQ))
1900        {
1901            //WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id, "%s:%d Failed to start screenUpdateEvent", __FUNCTION__, __LINE__);
1902            UnlockAGLCntx();
1903            return -1;
1904        }
1905
1906        return 0;
1907    }
1908
1909    _screenUpdateThread = ThreadWrapper::CreateThread(ScreenUpdateThreadProc, this, kRealtimePriority);
1910    _screenUpdateEvent = EventWrapper::Create();
1911
1912    if (!_screenUpdateThread)
1913    {
1914        //WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id, "%s:%d Failed to start screenUpdateThread", __FUNCTION__, __LINE__);
1915        UnlockAGLCntx();
1916        return -1;
1917    }
1918
1919    _screenUpdateThread->Start(_threadID);
1920    _screenUpdateEvent->StartTimer(true, 1000/MONITOR_FREQ);
1921
1922    //WEBRTC_TRACE(kTraceInfo, kTraceVideoRenderer, _id, "%s:%d Started screenUpdateThread", __FUNCTION__, __LINE__);
1923
1924    UnlockAGLCntx();
1925    return 0;
1926
1927}
1928
1929int32_t VideoRenderAGL::StopRender()
1930{
1931    LockAGLCntx();
1932
1933    if(!_screenUpdateThread || !_screenUpdateEvent)
1934    {
1935        _renderingIsPaused = TRUE;
1936        UnlockAGLCntx();
1937        return 0;
1938    }
1939
1940    if(FALSE == _screenUpdateThread->Stop() || FALSE == _screenUpdateEvent->StopTimer())
1941    {
1942        _renderingIsPaused = FALSE;
1943        //WEBRTC_TRACE(kTraceInfo, kTraceVideoRenderer, _id, "%s:%d Could not stop either: screenUpdateThread or screenUpdateEvent", __FUNCTION__, __LINE__);
1944        UnlockAGLCntx();
1945        return -1;
1946    }
1947
1948    _renderingIsPaused = TRUE;
1949
1950    //WEBRTC_TRACE(kTraceInfo, kTraceVideoRenderer, _id, "%s:%d Stopped screenUpdateThread", __FUNCTION__, __LINE__);
1951    UnlockAGLCntx();
1952    return 0;
1953}
1954
1955int32_t VideoRenderAGL::DeleteAGLChannel(const uint32_t streamID)
1956{
1957
1958    LockAGLCntx();
1959
1960    std::map<int, VideoChannelAGL*>::iterator it;
1961    it = _aglChannels.begin();
1962
1963    while (it != _aglChannels.end())
1964    {
1965        VideoChannelAGL* channel = it->second;
1966        //WEBRTC_TRACE(kTraceInfo, kTraceVideoRenderer, _id, "%s:%d Deleting channel %d", __FUNCTION__, __LINE__, streamID);
1967        delete channel;
1968        it++;
1969    }
1970    _aglChannels.clear();
1971
1972    UnlockAGLCntx();
1973    return 0;
1974}
1975
1976int32_t VideoRenderAGL::GetChannelProperties(const uint16_t streamId,
1977                                             uint32_t& zOrder,
1978                                             float& left,
1979                                             float& top,
1980                                             float& right,
1981                                             float& bottom)
1982{
1983
1984    LockAGLCntx();
1985    UnlockAGLCntx();
1986    return -1;
1987
1988}
1989
1990void VideoRenderAGL::LockAGLCntx()
1991{
1992    _renderCritSec.Enter();
1993}
1994void VideoRenderAGL::UnlockAGLCntx()
1995{
1996    _renderCritSec.Leave();
1997}
1998
1999}  // namespace webrtc
2000
2001#endif   // CARBON_RENDERING
2002