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 |