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

Side by Side Diff: talk/app/webrtc/objc/RTCEAGLVideoView.m

Issue 2296613002: Delete talk directory, and references from build_ios_libs.sh. (Closed)
Patch Set: Update filenames for c -> c++ conversion. Created 4 years, 3 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
« no previous file with comments | « talk/app/webrtc/objc/RTCDataChannel+Internal.h ('k') | talk/app/webrtc/objc/RTCEnumConverter.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * libjingle
3 * Copyright 2014 Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #if !defined(__has_feature) || !__has_feature(objc_arc)
29 #error "This file requires ARC support."
30 #endif
31
32 #import "RTCEAGLVideoView.h"
33
34 #import <GLKit/GLKit.h>
35
36 #import "RTCI420Frame.h"
37 #import "RTCOpenGLVideoRenderer.h"
38
39 // RTCDisplayLinkTimer wraps a CADisplayLink and is set to fire every two screen
40 // refreshes, which should be 30fps. We wrap the display link in order to avoid
41 // a retain cycle since CADisplayLink takes a strong reference onto its target.
42 // The timer is paused by default.
43 @interface RTCDisplayLinkTimer : NSObject
44
45 @property(nonatomic) BOOL isPaused;
46
47 - (instancetype)initWithTimerHandler:(void (^)(void))timerHandler;
48 - (void)invalidate;
49
50 @end
51
52 @implementation RTCDisplayLinkTimer {
53 CADisplayLink* _displayLink;
54 void (^_timerHandler)(void);
55 }
56
57 - (instancetype)initWithTimerHandler:(void (^)(void))timerHandler {
58 NSParameterAssert(timerHandler);
59 if (self = [super init]) {
60 _timerHandler = timerHandler;
61 _displayLink =
62 [CADisplayLink displayLinkWithTarget:self
63 selector:@selector(displayLinkDidFire:)];
64 _displayLink.paused = YES;
65 // Set to half of screen refresh, which should be 30fps.
66 [_displayLink setFrameInterval:2];
67 [_displayLink addToRunLoop:[NSRunLoop currentRunLoop]
68 forMode:NSRunLoopCommonModes];
69 }
70 return self;
71 }
72
73 - (void)dealloc {
74 [self invalidate];
75 }
76
77 - (BOOL)isPaused {
78 return _displayLink.paused;
79 }
80
81 - (void)setIsPaused:(BOOL)isPaused {
82 _displayLink.paused = isPaused;
83 }
84
85 - (void)invalidate {
86 [_displayLink invalidate];
87 }
88
89 - (void)displayLinkDidFire:(CADisplayLink*)displayLink {
90 _timerHandler();
91 }
92
93 @end
94
95 // RTCEAGLVideoView wraps a GLKView which is setup with
96 // enableSetNeedsDisplay = NO for the purpose of gaining control of
97 // exactly when to call -[GLKView display]. This need for extra
98 // control is required to avoid triggering method calls on GLKView
99 // that results in attempting to bind the underlying render buffer
100 // when the drawable size would be empty which would result in the
101 // error GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT. -[GLKView display] is
102 // the method that will trigger the binding of the render
103 // buffer. Because the standard behaviour of -[UIView setNeedsDisplay]
104 // is disabled for the reasons above, the RTCEAGLVideoView maintains
105 // its own |isDirty| flag.
106
107 @interface RTCEAGLVideoView () <GLKViewDelegate>
108 // |i420Frame| is set when we receive a frame from a worker thread and is read
109 // from the display link callback so atomicity is required.
110 @property(atomic, strong) RTCI420Frame* i420Frame;
111 @property(nonatomic, readonly) GLKView* glkView;
112 @property(nonatomic, readonly) RTCOpenGLVideoRenderer* glRenderer;
113 @end
114
115 @implementation RTCEAGLVideoView {
116 RTCDisplayLinkTimer* _timer;
117 GLKView* _glkView;
118 RTCOpenGLVideoRenderer* _glRenderer;
119 // This flag should only be set and read on the main thread (e.g. by
120 // setNeedsDisplay)
121 BOOL _isDirty;
122 }
123
124 - (instancetype)initWithFrame:(CGRect)frame {
125 if (self = [super initWithFrame:frame]) {
126 [self configure];
127 }
128 return self;
129 }
130
131 - (instancetype)initWithCoder:(NSCoder *)aDecoder {
132 if (self = [super initWithCoder:aDecoder]) {
133 [self configure];
134 }
135 return self;
136 }
137
138 - (void)configure {
139 EAGLContext* glContext =
140 [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
141 if (!glContext) {
142 glContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
143 }
144 _glRenderer = [[RTCOpenGLVideoRenderer alloc] initWithContext:glContext];
145
146 // GLKView manages a framebuffer for us.
147 _glkView = [[GLKView alloc] initWithFrame:CGRectZero
148 context:glContext];
149 _glkView.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;
150 _glkView.drawableDepthFormat = GLKViewDrawableDepthFormatNone;
151 _glkView.drawableStencilFormat = GLKViewDrawableStencilFormatNone;
152 _glkView.drawableMultisample = GLKViewDrawableMultisampleNone;
153 _glkView.delegate = self;
154 _glkView.layer.masksToBounds = YES;
155 _glkView.enableSetNeedsDisplay = NO;
156 [self addSubview:_glkView];
157
158 // Listen to application state in order to clean up OpenGL before app goes
159 // away.
160 NSNotificationCenter* notificationCenter =
161 [NSNotificationCenter defaultCenter];
162 [notificationCenter addObserver:self
163 selector:@selector(willResignActive)
164 name:UIApplicationWillResignActiveNotification
165 object:nil];
166 [notificationCenter addObserver:self
167 selector:@selector(didBecomeActive)
168 name:UIApplicationDidBecomeActiveNotification
169 object:nil];
170
171 // Frames are received on a separate thread, so we poll for current frame
172 // using a refresh rate proportional to screen refresh frequency. This
173 // occurs on the main thread.
174 __weak RTCEAGLVideoView* weakSelf = self;
175 _timer = [[RTCDisplayLinkTimer alloc] initWithTimerHandler:^{
176 RTCEAGLVideoView* strongSelf = weakSelf;
177 [strongSelf displayLinkTimerDidFire];
178 }];
179 [self setupGL];
180 }
181
182 - (void)dealloc {
183 [[NSNotificationCenter defaultCenter] removeObserver:self];
184 UIApplicationState appState =
185 [UIApplication sharedApplication].applicationState;
186 if (appState == UIApplicationStateActive) {
187 [self teardownGL];
188 }
189 [_timer invalidate];
190 }
191
192 #pragma mark - UIView
193
194 - (void)setNeedsDisplay {
195 [super setNeedsDisplay];
196 _isDirty = YES;
197 }
198
199 - (void)setNeedsDisplayInRect:(CGRect)rect {
200 [super setNeedsDisplayInRect:rect];
201 _isDirty = YES;
202 }
203
204 - (void)layoutSubviews {
205 [super layoutSubviews];
206 _glkView.frame = self.bounds;
207 }
208
209 #pragma mark - GLKViewDelegate
210
211 // This method is called when the GLKView's content is dirty and needs to be
212 // redrawn. This occurs on main thread.
213 - (void)glkView:(GLKView*)view drawInRect:(CGRect)rect {
214 // The renderer will draw the frame to the framebuffer corresponding to the
215 // one used by |view|.
216 [_glRenderer drawFrame:self.i420Frame];
217 }
218
219 #pragma mark - RTCVideoRenderer
220
221 // These methods may be called on non-main thread.
222 - (void)setSize:(CGSize)size {
223 __weak RTCEAGLVideoView* weakSelf = self;
224 dispatch_async(dispatch_get_main_queue(), ^{
225 RTCEAGLVideoView* strongSelf = weakSelf;
226 [strongSelf.delegate videoView:strongSelf didChangeVideoSize:size];
227 });
228 }
229
230 - (void)renderFrame:(RTCI420Frame*)frame {
231 self.i420Frame = frame;
232 }
233
234 #pragma mark - Private
235
236 - (void)displayLinkTimerDidFire {
237 // Don't render unless video frame have changed or the view content
238 // has explicitly been marked dirty.
239 if (!_isDirty && _glRenderer.lastDrawnFrame == self.i420Frame) {
240 return;
241 }
242
243 // Always reset isDirty at this point, even if -[GLKView display]
244 // won't be called in the case the drawable size is empty.
245 _isDirty = NO;
246
247 // Only call -[GLKView display] if the drawable size is
248 // non-empty. Calling display will make the GLKView setup its
249 // render buffer if necessary, but that will fail with error
250 // GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT if size is empty.
251 if (self.bounds.size.width > 0 && self.bounds.size.height > 0) {
252 [_glkView display];
253 }
254 }
255
256 - (void)setupGL {
257 self.i420Frame = nil;
258 [_glRenderer setupGL];
259 _timer.isPaused = NO;
260 }
261
262 - (void)teardownGL {
263 self.i420Frame = nil;
264 _timer.isPaused = YES;
265 [_glkView deleteDrawable];
266 [_glRenderer teardownGL];
267 }
268
269 - (void)didBecomeActive {
270 [self setupGL];
271 }
272
273 - (void)willResignActive {
274 [self teardownGL];
275 }
276
277 @end
OLDNEW
« no previous file with comments | « talk/app/webrtc/objc/RTCDataChannel+Internal.h ('k') | talk/app/webrtc/objc/RTCEnumConverter.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698