1935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org/* 2935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org * libjingle 3935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org * Copyright 2014, Google Inc. 4935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org * 5935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org * Redistribution and use in source and binary forms, with or without 6935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org * modification, are permitted provided that the following conditions are met: 7935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org * 8935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org * 1. Redistributions of source code must retain the above copyright notice, 9935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org * this list of conditions and the following disclaimer. 10935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org * 2. Redistributions in binary form must reproduce the above copyright notice, 11935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org * this list of conditions and the following disclaimer in the documentation 12935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org * and/or other materials provided with the distribution. 13935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org * 3. The name of the author may not be used to endorse or promote products 14935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org * derived from this software without specific prior written permission. 15935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org * 16935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org */ 27935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org 28935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org#if !defined(__has_feature) || !__has_feature(objc_arc) 29935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org#error "This file requires ARC support." 30935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org#endif 31935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org 32935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org#import "RTCEAGLVideoView+Internal.h" 33935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org 34935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org#import <GLKit/GLKit.h> 35935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org 3652348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org#import "RTCOpenGLVideoRenderer.h" 37935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org#import "RTCVideoRenderer.h" 38935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org#import "RTCVideoTrack.h" 39935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org 405eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org// RTCDisplayLinkTimer wraps a CADisplayLink and is set to fire every two screen 415eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org// refreshes, which should be 30fps. We wrap the display link in order to avoid 425eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org// a retain cycle since CADisplayLink takes a strong reference onto its target. 435eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org// The timer is paused by default. 445eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org@interface RTCDisplayLinkTimer : NSObject 455eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org 465eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org@property(nonatomic) BOOL isPaused; 475eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org 485eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org- (instancetype)initWithTimerHandler:(void (^)(void))timerHandler; 495eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org- (void)invalidate; 505eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org 515eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org@end 525eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org 535eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org@implementation RTCDisplayLinkTimer { 545eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org CADisplayLink* _displayLink; 555eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org void (^_timerHandler)(void); 565eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org} 575eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org 585eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org- (instancetype)initWithTimerHandler:(void (^)(void))timerHandler { 595eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org NSParameterAssert(timerHandler); 605eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org if (self = [super init]) { 615eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org _timerHandler = timerHandler; 625eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org _displayLink = 635eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org [CADisplayLink displayLinkWithTarget:self 645eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org selector:@selector(displayLinkDidFire:)]; 655eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org _displayLink.paused = YES; 665eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org // Set to half of screen refresh, which should be 30fps. 675eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org [_displayLink setFrameInterval:2]; 685eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org [_displayLink addToRunLoop:[NSRunLoop currentRunLoop] 695eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org forMode:NSRunLoopCommonModes]; 705eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org } 715eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org return self; 725eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org} 735eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org 745eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org- (void)dealloc { 755eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org [self invalidate]; 765eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org} 775eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org 785eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org- (BOOL)isPaused { 795eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org return _displayLink.paused; 805eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org} 815eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org 825eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org- (void)setIsPaused:(BOOL)isPaused { 835eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org _displayLink.paused = isPaused; 845eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org} 855eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org 865eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org- (void)invalidate { 875eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org [_displayLink invalidate]; 885eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org} 895eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org 905eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org- (void)displayLinkDidFire:(CADisplayLink*)displayLink { 915eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org _timerHandler(); 925eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org} 935eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org 945eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org@end 955eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org 96935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org@interface RTCEAGLVideoView () <GLKViewDelegate> 9752348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org// |i420Frame| is set when we receive a frame from a worker thread and is read 9852348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org// from the display link callback so atomicity is required. 99935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org@property(atomic, strong) RTCI420Frame* i420Frame; 1005eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org@property(nonatomic, readonly) GLKView* glkView; 1015eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org@property(nonatomic, readonly) RTCOpenGLVideoRenderer* glRenderer; 102935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org@end 103935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org 104935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org@implementation RTCEAGLVideoView { 1055eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org RTCDisplayLinkTimer* _timer; 106935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org GLKView* _glkView; 10752348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org RTCOpenGLVideoRenderer* _glRenderer; 108935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org RTCVideoRenderer* _videoRenderer; 109935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org} 110935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org 111935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org- (instancetype)initWithFrame:(CGRect)frame { 112935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org if (self = [super initWithFrame:frame]) { 113935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org EAGLContext* glContext = 114935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; 11552348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org _glRenderer = [[RTCOpenGLVideoRenderer alloc] initWithContext:glContext]; 116935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org 117935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org // GLKView manages a framebuffer for us. 118935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org _glkView = [[GLKView alloc] initWithFrame:CGRectZero 119935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org context:glContext]; 120935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org _glkView.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888; 121935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org _glkView.drawableDepthFormat = GLKViewDrawableDepthFormatNone; 122935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org _glkView.drawableStencilFormat = GLKViewDrawableStencilFormatNone; 123935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org _glkView.drawableMultisample = GLKViewDrawableMultisampleNone; 124935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org _glkView.delegate = self; 125935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org _glkView.layer.masksToBounds = YES; 126935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org [self addSubview:_glkView]; 127935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org 128935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org // Listen to application state in order to clean up OpenGL before app goes 129935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org // away. 130935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org NSNotificationCenter* notificationCenter = 131935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org [NSNotificationCenter defaultCenter]; 132935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org [notificationCenter addObserver:self 133935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org selector:@selector(willResignActive) 134935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org name:UIApplicationWillResignActiveNotification 135935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org object:nil]; 136935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org [notificationCenter addObserver:self 137935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org selector:@selector(didBecomeActive) 138935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org name:UIApplicationDidBecomeActiveNotification 139935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org object:nil]; 1405eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org 1415eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org // Frames are received on a separate thread, so we poll for current frame 1425eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org // using a refresh rate proportional to screen refresh frequency. This 1435eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org // occurs on the main thread. 1445eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org __weak RTCEAGLVideoView* weakSelf = self; 1455eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org _timer = [[RTCDisplayLinkTimer alloc] initWithTimerHandler:^{ 1465eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org RTCEAGLVideoView* strongSelf = weakSelf; 1475eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org // Don't render if frame hasn't changed. 1485eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org if (strongSelf.glRenderer.lastDrawnFrame == strongSelf.i420Frame) { 1495eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org return; 1505eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org } 1515eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org // This tells the GLKView that it's dirty, which will then call the 1525eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org // GLKViewDelegate method implemented below. 1535eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org [strongSelf.glkView setNeedsDisplay]; 1545eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org }]; 155935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org _videoRenderer = [[RTCVideoRenderer alloc] initWithDelegate:self]; 156935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org [self setupGL]; 157935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org } 158935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org return self; 159935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org} 160935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org 161935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org- (void)dealloc { 162935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org [[NSNotificationCenter defaultCenter] removeObserver:self]; 163935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org UIApplicationState appState = 164935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org [UIApplication sharedApplication].applicationState; 165935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org if (appState == UIApplicationStateActive) { 166935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org [self teardownGL]; 167935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org } 1685eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org [_timer invalidate]; 169935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org} 170935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org 171935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org- (void)setVideoTrack:(RTCVideoTrack*)videoTrack { 172935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org if (_videoTrack == videoTrack) { 173935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org return; 174935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org } 175935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org [_videoTrack removeRenderer:_videoRenderer]; 176fdfa16850f56fffaf3bfd26ed132bdec1fa99d32tkchin@webrtc.org self.i420Frame = nil; 177935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org _videoTrack = videoTrack; 178935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org [_videoTrack addRenderer:_videoRenderer]; 179935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org // TODO(tkchin): potentially handle changes in track state - e.g. render 180935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org // black if track fails. 181935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org} 182935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org 183935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org#pragma mark - UIView 184935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org 185935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org- (void)layoutSubviews { 186935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org [super layoutSubviews]; 187935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org _glkView.frame = self.bounds; 188935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org} 189935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org 190935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org#pragma mark - GLKViewDelegate 191935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org 192935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org// This method is called when the GLKView's content is dirty and needs to be 193935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org// redrawn. This occurs on main thread. 194935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org- (void)glkView:(GLKView*)view drawInRect:(CGRect)rect { 195fdfa16850f56fffaf3bfd26ed132bdec1fa99d32tkchin@webrtc.org // The renderer will draw the frame to the framebuffer corresponding to the 196fdfa16850f56fffaf3bfd26ed132bdec1fa99d32tkchin@webrtc.org // one used by |view|. 197fdfa16850f56fffaf3bfd26ed132bdec1fa99d32tkchin@webrtc.org [_glRenderer drawFrame:self.i420Frame]; 198935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org} 199935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org 200935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org#pragma mark - Private 201935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org 202935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org- (void)setupGL { 203935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org [_glRenderer setupGL]; 2045eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org _timer.isPaused = NO; 205935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org} 206935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org 207935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org- (void)teardownGL { 2085eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org _timer.isPaused = YES; 209935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org [_glkView deleteDrawable]; 210935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org [_glRenderer teardownGL]; 211935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org} 212935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org 213935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org- (void)didBecomeActive { 214935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org [self setupGL]; 215935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org} 216935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org 217935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org- (void)willResignActive { 218935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org [self teardownGL]; 219935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org} 220935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org 221935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org@end 222935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org 223935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org@implementation RTCEAGLVideoView (Internal) 224935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org 225935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org#pragma mark - RTCVideoRendererDelegate 226935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org 227935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org// These methods are called when the video track has frame information to 228935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org// provide. This occurs on non-main thread. 229935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org- (void)renderer:(RTCVideoRenderer*)renderer 230935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org didSetSize:(CGSize)size { 2315eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org __weak RTCEAGLVideoView* weakSelf = self; 23252348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org dispatch_async(dispatch_get_main_queue(), ^{ 2335eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org RTCEAGLVideoView* strongSelf = weakSelf; 2345eb79e17e8d4d6df3791c863e5266ea906a7a37btkchin@webrtc.org [strongSelf.delegate videoView:strongSelf didChangeVideoSize:size]; 23552348f6729702ec8888955b7aa5d6b47a4727e6atkchin@webrtc.org }); 236935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org} 237935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org 238935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org- (void)renderer:(RTCVideoRenderer*)renderer 239935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org didReceiveFrame:(RTCI420Frame*)frame { 240935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org self.i420Frame = frame; 241935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org} 242935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org 243935b8f2c093115e48d105962c5f403a5c8e76f7etkchin@webrtc.org@end 244