Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(107)

Side by Side Diff: webrtc/sdk/objc/Framework/Classes/RTCEAGLVideoView.m

Issue 2812613003: ObjC: Remove RTCOpenGLVideoRenderer (Closed)
Patch Set: Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright 2015 The WebRTC project authors. All Rights Reserved. 2 * Copyright 2015 The WebRTC project authors. All Rights Reserved.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license 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 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 6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may 7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree. 8 * be found in the AUTHORS file in the root of the source tree.
9 */ 9 */
10 10
11 #import "WebRTC/RTCEAGLVideoView.h" 11 #import "WebRTC/RTCEAGLVideoView.h"
12 12
13 #import <GLKit/GLKit.h> 13 #import <GLKit/GLKit.h>
14 14
15 #import "RTCOpenGLVideoRenderer.h" 15 #import "RTCShader+Private.h"
16 #import "WebRTC/RTCVideoFrame.h" 16 #import "WebRTC/RTCVideoFrame.h"
17 17
18 // RTCDisplayLinkTimer wraps a CADisplayLink and is set to fire every two screen 18 // RTCDisplayLinkTimer wraps a CADisplayLink and is set to fire every two screen
19 // refreshes, which should be 30fps. We wrap the display link in order to avoid 19 // refreshes, which should be 30fps. We wrap the display link in order to avoid
20 // a retain cycle since CADisplayLink takes a strong reference onto its target. 20 // a retain cycle since CADisplayLink takes a strong reference onto its target.
21 // The timer is paused by default. 21 // The timer is paused by default.
22 @interface RTCDisplayLinkTimer : NSObject 22 @interface RTCDisplayLinkTimer : NSObject
23 23
24 @property(nonatomic) BOOL isPaused; 24 @property(nonatomic) BOOL isPaused;
25 25
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
81 // the method that will trigger the binding of the render 81 // the method that will trigger the binding of the render
82 // buffer. Because the standard behaviour of -[UIView setNeedsDisplay] 82 // buffer. Because the standard behaviour of -[UIView setNeedsDisplay]
83 // is disabled for the reasons above, the RTCEAGLVideoView maintains 83 // is disabled for the reasons above, the RTCEAGLVideoView maintains
84 // its own |isDirty| flag. 84 // its own |isDirty| flag.
85 85
86 @interface RTCEAGLVideoView () <GLKViewDelegate> 86 @interface RTCEAGLVideoView () <GLKViewDelegate>
87 // |videoFrame| is set when we receive a frame from a worker thread and is read 87 // |videoFrame| is set when we receive a frame from a worker thread and is read
88 // from the display link callback so atomicity is required. 88 // from the display link callback so atomicity is required.
89 @property(atomic, strong) RTCVideoFrame *videoFrame; 89 @property(atomic, strong) RTCVideoFrame *videoFrame;
90 @property(nonatomic, readonly) GLKView *glkView; 90 @property(nonatomic, readonly) GLKView *glkView;
91 @property(nonatomic, readonly) RTCOpenGLVideoRenderer *glRenderer;
92 @end 91 @end
93 92
94 @implementation RTCEAGLVideoView { 93 @implementation RTCEAGLVideoView {
95 RTCDisplayLinkTimer *_timer; 94 RTCDisplayLinkTimer *_timer;
96 EAGLContext *_glContext; 95 EAGLContext *_glContext;
97 // This flag should only be set and read on the main thread (e.g. by 96 // This flag should only be set and read on the main thread (e.g. by
98 // setNeedsDisplay) 97 // setNeedsDisplay)
99 BOOL _isDirty; 98 BOOL _isDirty;
99
100 BOOL _isInitialized;
sakal 2017/04/11 11:00:21 Why is this only needed on iOS and not on Mac?
magjed_webrtc 2017/04/11 12:05:43 It was obvious from the code that it wasn't necess
101 id<RTCShader> _i420Shader;
102 id<RTCShader> _nv12Shader;
103 RTCVideoFrame *_lastDrawnFrame;
100 } 104 }
101 105
102 @synthesize delegate = _delegate; 106 @synthesize delegate = _delegate;
103 @synthesize videoFrame = _videoFrame; 107 @synthesize videoFrame = _videoFrame;
104 @synthesize glkView = _glkView; 108 @synthesize glkView = _glkView;
105 @synthesize glRenderer = _glRenderer;
106 109
107 - (instancetype)initWithFrame:(CGRect)frame { 110 - (instancetype)initWithFrame:(CGRect)frame {
108 if (self = [super initWithFrame:frame]) { 111 if (self = [super initWithFrame:frame]) {
109 [self configure]; 112 [self configure];
110 } 113 }
111 return self; 114 return self;
112 } 115 }
113 116
114 - (instancetype)initWithCoder:(NSCoder *)aDecoder { 117 - (instancetype)initWithCoder:(NSCoder *)aDecoder {
115 if (self = [super initWithCoder:aDecoder]) { 118 if (self = [super initWithCoder:aDecoder]) {
116 [self configure]; 119 [self configure];
117 } 120 }
118 return self; 121 return self;
119 } 122 }
120 123
121 - (void)configure { 124 - (void)configure {
122 EAGLContext *glContext = 125 EAGLContext *glContext =
123 [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3]; 126 [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
124 if (!glContext) { 127 if (!glContext) {
125 glContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; 128 glContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
126 } 129 }
127 _glContext = glContext; 130 _glContext = glContext;
128 _glRenderer = [[RTCOpenGLVideoRenderer alloc] initWithContext:_glContext];
129 131
130 // GLKView manages a framebuffer for us. 132 // GLKView manages a framebuffer for us.
131 _glkView = [[GLKView alloc] initWithFrame:CGRectZero 133 _glkView = [[GLKView alloc] initWithFrame:CGRectZero
132 context:_glContext]; 134 context:_glContext];
133 _glkView.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888; 135 _glkView.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;
134 _glkView.drawableDepthFormat = GLKViewDrawableDepthFormatNone; 136 _glkView.drawableDepthFormat = GLKViewDrawableDepthFormatNone;
135 _glkView.drawableStencilFormat = GLKViewDrawableStencilFormatNone; 137 _glkView.drawableStencilFormat = GLKViewDrawableStencilFormatNone;
136 _glkView.drawableMultisample = GLKViewDrawableMultisampleNone; 138 _glkView.drawableMultisample = GLKViewDrawableMultisampleNone;
137 _glkView.delegate = self; 139 _glkView.delegate = self;
138 _glkView.layer.masksToBounds = YES; 140 _glkView.layer.masksToBounds = YES;
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
193 _glkView.frame = self.bounds; 195 _glkView.frame = self.bounds;
194 } 196 }
195 197
196 #pragma mark - GLKViewDelegate 198 #pragma mark - GLKViewDelegate
197 199
198 // This method is called when the GLKView's content is dirty and needs to be 200 // This method is called when the GLKView's content is dirty and needs to be
199 // redrawn. This occurs on main thread. 201 // redrawn. This occurs on main thread.
200 - (void)glkView:(GLKView *)view drawInRect:(CGRect)rect { 202 - (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
201 // The renderer will draw the frame to the framebuffer corresponding to the 203 // The renderer will draw the frame to the framebuffer corresponding to the
202 // one used by |view|. 204 // one used by |view|.
203 [_glRenderer drawFrame:self.videoFrame]; 205 RTCVideoFrame *frame = self.videoFrame;
206 if (!_isInitialized || !frame || frame == _lastDrawnFrame) {
sakal 2017/04/11 11:00:21 Is this something we expect to happen or should we
magjed_webrtc 2017/04/11 12:05:43 Yes, it can happen that we try to render the same
207 return;
208 }
209 [self ensureGLContext];
210 glClear(GL_COLOR_BUFFER_BIT);
211 id<RTCShader> shader = nil;
212 if (frame.nativeHandle) {
213 if (!_nv12Shader) {
214 _nv12Shader = [[RTCNativeNV12Shader alloc] initWithContext:_glContext];
215 }
216 shader = _nv12Shader;
217 } else {
218 if (!_i420Shader) {
219 _i420Shader = [[RTCI420Shader alloc] initWithContext:_glContext];
220 }
221 shader = _i420Shader;
222 }
223 if (shader && [shader drawFrame:frame]) {
sakal 2017/04/11 11:00:21 Log on failure?
magjed_webrtc 2017/04/11 12:05:43 We didn't do it previously, but I guess we can add
224 _lastDrawnFrame = frame;
225 }
204 } 226 }
205 227
206 #pragma mark - RTCVideoRenderer 228 #pragma mark - RTCVideoRenderer
207 229
208 // These methods may be called on non-main thread. 230 // These methods may be called on non-main thread.
209 - (void)setSize:(CGSize)size { 231 - (void)setSize:(CGSize)size {
210 __weak RTCEAGLVideoView *weakSelf = self; 232 __weak RTCEAGLVideoView *weakSelf = self;
211 dispatch_async(dispatch_get_main_queue(), ^{ 233 dispatch_async(dispatch_get_main_queue(), ^{
212 RTCEAGLVideoView *strongSelf = weakSelf; 234 RTCEAGLVideoView *strongSelf = weakSelf;
213 [strongSelf.delegate videoView:strongSelf didChangeVideoSize:size]; 235 [strongSelf.delegate videoView:strongSelf didChangeVideoSize:size];
214 }); 236 });
215 } 237 }
216 238
217 - (void)renderFrame:(RTCVideoFrame *)frame { 239 - (void)renderFrame:(RTCVideoFrame *)frame {
218 self.videoFrame = frame; 240 self.videoFrame = frame;
219 } 241 }
220 242
221 #pragma mark - Private 243 #pragma mark - Private
222 244
223 - (void)displayLinkTimerDidFire { 245 - (void)displayLinkTimerDidFire {
224 // Don't render unless video frame have changed or the view content 246 // Don't render unless video frame have changed or the view content
225 // has explicitly been marked dirty. 247 // has explicitly been marked dirty.
226 if (!_isDirty && _glRenderer.lastDrawnFrame == self.videoFrame) { 248 if (!_isDirty && _lastDrawnFrame == self.videoFrame) {
227 return; 249 return;
228 } 250 }
229 251
230 // Always reset isDirty at this point, even if -[GLKView display] 252 // Always reset isDirty at this point, even if -[GLKView display]
231 // won't be called in the case the drawable size is empty. 253 // won't be called in the case the drawable size is empty.
232 _isDirty = NO; 254 _isDirty = NO;
233 255
234 // Only call -[GLKView display] if the drawable size is 256 // Only call -[GLKView display] if the drawable size is
235 // non-empty. Calling display will make the GLKView setup its 257 // non-empty. Calling display will make the GLKView setup its
236 // render buffer if necessary, but that will fail with error 258 // render buffer if necessary, but that will fail with error
237 // GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT if size is empty. 259 // GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT if size is empty.
238 if (self.bounds.size.width > 0 && self.bounds.size.height > 0) { 260 if (self.bounds.size.width > 0 && self.bounds.size.height > 0) {
239 [_glkView display]; 261 [_glkView display];
240 } 262 }
241 } 263 }
242 264
243 - (void)setupGL { 265 - (void)setupGL {
244 self.videoFrame = nil; 266 self.videoFrame = nil;
245 [_glRenderer setupGL]; 267 if (!_isInitialized) {
sakal 2017/04/11 11:00:21 I don't like the way isInitialized is used. It see
magjed_webrtc 2017/04/11 12:05:43 It looks like we don't need it at all.
268 [self ensureGLContext];
269 _isInitialized = YES;
270 }
246 _timer.isPaused = NO; 271 _timer.isPaused = NO;
247 } 272 }
248 273
249 - (void)teardownGL { 274 - (void)teardownGL {
250 self.videoFrame = nil; 275 self.videoFrame = nil;
251 _timer.isPaused = YES; 276 _timer.isPaused = YES;
252 [_glkView deleteDrawable]; 277 [_glkView deleteDrawable];
253 [_glRenderer teardownGL]; 278 if (_isInitialized) {
279 [self ensureGLContext];
280 _i420Shader = nil;
281 _nv12Shader = nil;
282 _isInitialized = NO;
283 }
254 } 284 }
255 285
256 - (void)didBecomeActive { 286 - (void)didBecomeActive {
257 [self setupGL]; 287 [self setupGL];
258 } 288 }
259 289
260 - (void)willResignActive { 290 - (void)willResignActive {
261 [self teardownGL]; 291 [self teardownGL];
262 } 292 }
263 293
294 - (void)ensureGLContext {
295 NSAssert(_glContext, @"context shouldn't be nil");
296 if ([EAGLContext currentContext] != _glContext) {
297 [EAGLContext setCurrentContext:_glContext];
298 }
299 }
300
264 @end 301 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698