1/* 2 * Copyright 2015 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#import "RTCNSGLVideoView.h" 12 13#import <CoreVideo/CVDisplayLink.h> 14#import <OpenGL/gl3.h> 15#import "RTCVideoFrame.h" 16#import "RTCOpenGLVideoRenderer.h" 17 18@interface RTCNSGLVideoView () 19// |videoFrame| is set when we receive a frame from a worker thread and is read 20// from the display link callback so atomicity is required. 21@property(atomic, strong) RTCVideoFrame *videoFrame; 22@property(atomic, strong) RTCOpenGLVideoRenderer *glRenderer; 23- (void)drawFrame; 24@end 25 26static CVReturn OnDisplayLinkFired(CVDisplayLinkRef displayLink, 27 const CVTimeStamp *now, 28 const CVTimeStamp *outputTime, 29 CVOptionFlags flagsIn, 30 CVOptionFlags *flagsOut, 31 void *displayLinkContext) { 32 RTCNSGLVideoView *view = (__bridge RTCNSGLVideoView *)displayLinkContext; 33 [view drawFrame]; 34 return kCVReturnSuccess; 35} 36 37@implementation RTCNSGLVideoView { 38 CVDisplayLinkRef _displayLink; 39} 40 41@synthesize delegate = _delegate; 42@synthesize videoFrame = _videoFrame; 43@synthesize glRenderer = _glRenderer; 44 45- (void)dealloc { 46 [self teardownDisplayLink]; 47} 48 49- (void)drawRect:(NSRect)rect { 50 [self drawFrame]; 51} 52 53- (void)reshape { 54 [super reshape]; 55 NSRect frame = [self frame]; 56 CGLLockContext([[self openGLContext] CGLContextObj]); 57 glViewport(0, 0, frame.size.width, frame.size.height); 58 CGLUnlockContext([[self openGLContext] CGLContextObj]); 59} 60 61- (void)lockFocus { 62 NSOpenGLContext *context = [self openGLContext]; 63 [super lockFocus]; 64 if ([context view] != self) { 65 [context setView:self]; 66 } 67 [context makeCurrentContext]; 68} 69 70- (void)prepareOpenGL { 71 [super prepareOpenGL]; 72 if (!self.glRenderer) { 73 self.glRenderer = 74 [[RTCOpenGLVideoRenderer alloc] initWithContext:[self openGLContext]]; 75 } 76 [self.glRenderer setupGL]; 77 [self setupDisplayLink]; 78} 79 80- (void)clearGLContext { 81 [self.glRenderer teardownGL]; 82 self.glRenderer = nil; 83 [super clearGLContext]; 84} 85 86#pragma mark - RTCVideoRenderer 87 88// These methods may be called on non-main thread. 89- (void)setSize:(CGSize)size { 90 dispatch_async(dispatch_get_main_queue(), ^{ 91 [self.delegate videoView:self didChangeVideoSize:size]; 92 }); 93} 94 95- (void)renderFrame:(RTCVideoFrame *)frame { 96 self.videoFrame = frame; 97} 98 99#pragma mark - Private 100 101- (void)drawFrame { 102 RTCVideoFrame *videoFrame = self.videoFrame; 103 if (self.glRenderer.lastDrawnFrame != videoFrame) { 104 // This method may be called from CVDisplayLink callback which isn't on the 105 // main thread so we have to lock the GL context before drawing. 106 CGLLockContext([[self openGLContext] CGLContextObj]); 107 [self.glRenderer drawFrame:videoFrame]; 108 CGLUnlockContext([[self openGLContext] CGLContextObj]); 109 } 110} 111 112- (void)setupDisplayLink { 113 if (_displayLink) { 114 return; 115 } 116 // Synchronize buffer swaps with vertical refresh rate. 117 GLint swapInt = 1; 118 [[self openGLContext] setValues:&swapInt forParameter:NSOpenGLCPSwapInterval]; 119 120 // Create display link. 121 CVDisplayLinkCreateWithActiveCGDisplays(&_displayLink); 122 CVDisplayLinkSetOutputCallback(_displayLink, 123 &OnDisplayLinkFired, 124 (__bridge void *)self); 125 // Set the display link for the current renderer. 126 CGLContextObj cglContext = [[self openGLContext] CGLContextObj]; 127 CGLPixelFormatObj cglPixelFormat = [[self pixelFormat] CGLPixelFormatObj]; 128 CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext( 129 _displayLink, cglContext, cglPixelFormat); 130 CVDisplayLinkStart(_displayLink); 131} 132 133- (void)teardownDisplayLink { 134 if (!_displayLink) { 135 return; 136 } 137 CVDisplayLinkRelease(_displayLink); 138 _displayLink = NULL; 139} 140 141@end 142