| OLD | NEW |
| (Empty) |
| 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 | |
| 26 static 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 | |
| OLD | NEW |