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