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