| Index: webrtc/sdk/objc/Framework/Classes/RTCEAGLVideoView.m
|
| diff --git a/webrtc/sdk/objc/Framework/Classes/RTCEAGLVideoView.m b/webrtc/sdk/objc/Framework/Classes/RTCEAGLVideoView.m
|
| deleted file mode 100644
|
| index 1fb03bc909e27305eee7eb41bd9f6066983f7e3e..0000000000000000000000000000000000000000
|
| --- a/webrtc/sdk/objc/Framework/Classes/RTCEAGLVideoView.m
|
| +++ /dev/null
|
| @@ -1,297 +0,0 @@
|
| -/*
|
| - * Copyright 2015 The WebRTC project authors. All Rights Reserved.
|
| - *
|
| - * Use of this source code is governed by a BSD-style license
|
| - * that can be found in the LICENSE file in the root of the source
|
| - * tree. An additional intellectual property rights grant can be found
|
| - * in the file PATENTS. All contributing project authors may
|
| - * be found in the AUTHORS file in the root of the source tree.
|
| - */
|
| -
|
| -#import "WebRTC/RTCEAGLVideoView.h"
|
| -
|
| -#import <GLKit/GLKit.h>
|
| -
|
| -#import "RTCShader+Private.h"
|
| -#import "WebRTC/RTCLogging.h"
|
| -#import "WebRTC/RTCVideoFrame.h"
|
| -
|
| -// RTCDisplayLinkTimer wraps a CADisplayLink and is set to fire every two screen
|
| -// refreshes, which should be 30fps. We wrap the display link in order to avoid
|
| -// a retain cycle since CADisplayLink takes a strong reference onto its target.
|
| -// The timer is paused by default.
|
| -@interface RTCDisplayLinkTimer : NSObject
|
| -
|
| -@property(nonatomic) BOOL isPaused;
|
| -
|
| -- (instancetype)initWithTimerHandler:(void (^)(void))timerHandler;
|
| -- (void)invalidate;
|
| -
|
| -@end
|
| -
|
| -@implementation RTCDisplayLinkTimer {
|
| - CADisplayLink *_displayLink;
|
| - void (^_timerHandler)(void);
|
| -}
|
| -
|
| -- (instancetype)initWithTimerHandler:(void (^)(void))timerHandler {
|
| - NSParameterAssert(timerHandler);
|
| - if (self = [super init]) {
|
| - _timerHandler = timerHandler;
|
| - _displayLink =
|
| - [CADisplayLink displayLinkWithTarget:self
|
| - selector:@selector(displayLinkDidFire:)];
|
| - _displayLink.paused = YES;
|
| - // Set to half of screen refresh, which should be 30fps.
|
| - [_displayLink setFrameInterval:2];
|
| - [_displayLink addToRunLoop:[NSRunLoop currentRunLoop]
|
| - forMode:NSRunLoopCommonModes];
|
| - }
|
| - return self;
|
| -}
|
| -
|
| -- (void)dealloc {
|
| - [self invalidate];
|
| -}
|
| -
|
| -- (BOOL)isPaused {
|
| - return _displayLink.paused;
|
| -}
|
| -
|
| -- (void)setIsPaused:(BOOL)isPaused {
|
| - _displayLink.paused = isPaused;
|
| -}
|
| -
|
| -- (void)invalidate {
|
| - [_displayLink invalidate];
|
| -}
|
| -
|
| -- (void)displayLinkDidFire:(CADisplayLink *)displayLink {
|
| - _timerHandler();
|
| -}
|
| -
|
| -@end
|
| -
|
| -// RTCEAGLVideoView wraps a GLKView which is setup with
|
| -// enableSetNeedsDisplay = NO for the purpose of gaining control of
|
| -// exactly when to call -[GLKView display]. This need for extra
|
| -// control is required to avoid triggering method calls on GLKView
|
| -// that results in attempting to bind the underlying render buffer
|
| -// when the drawable size would be empty which would result in the
|
| -// error GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT. -[GLKView display] is
|
| -// the method that will trigger the binding of the render
|
| -// buffer. Because the standard behaviour of -[UIView setNeedsDisplay]
|
| -// is disabled for the reasons above, the RTCEAGLVideoView maintains
|
| -// its own |isDirty| flag.
|
| -
|
| -@interface RTCEAGLVideoView () <GLKViewDelegate>
|
| -// |videoFrame| is set when we receive a frame from a worker thread and is read
|
| -// from the display link callback so atomicity is required.
|
| -@property(atomic, strong) RTCVideoFrame *videoFrame;
|
| -@property(nonatomic, readonly) GLKView *glkView;
|
| -@end
|
| -
|
| -@implementation RTCEAGLVideoView {
|
| - RTCDisplayLinkTimer *_timer;
|
| - EAGLContext *_glContext;
|
| - // This flag should only be set and read on the main thread (e.g. by
|
| - // setNeedsDisplay)
|
| - BOOL _isDirty;
|
| - id<RTCShader> _i420Shader;
|
| - id<RTCShader> _nv12Shader;
|
| - RTCVideoFrame *_lastDrawnFrame;
|
| -}
|
| -
|
| -@synthesize delegate = _delegate;
|
| -@synthesize videoFrame = _videoFrame;
|
| -@synthesize glkView = _glkView;
|
| -
|
| -- (instancetype)initWithFrame:(CGRect)frame {
|
| - if (self = [super initWithFrame:frame]) {
|
| - [self configure];
|
| - }
|
| - return self;
|
| -}
|
| -
|
| -- (instancetype)initWithCoder:(NSCoder *)aDecoder {
|
| - if (self = [super initWithCoder:aDecoder]) {
|
| - [self configure];
|
| - }
|
| - return self;
|
| -}
|
| -
|
| -- (void)configure {
|
| - EAGLContext *glContext =
|
| - [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
|
| - if (!glContext) {
|
| - glContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
|
| - }
|
| - _glContext = glContext;
|
| -
|
| - // GLKView manages a framebuffer for us.
|
| - _glkView = [[GLKView alloc] initWithFrame:CGRectZero
|
| - context:_glContext];
|
| - _glkView.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;
|
| - _glkView.drawableDepthFormat = GLKViewDrawableDepthFormatNone;
|
| - _glkView.drawableStencilFormat = GLKViewDrawableStencilFormatNone;
|
| - _glkView.drawableMultisample = GLKViewDrawableMultisampleNone;
|
| - _glkView.delegate = self;
|
| - _glkView.layer.masksToBounds = YES;
|
| - _glkView.enableSetNeedsDisplay = NO;
|
| - [self addSubview:_glkView];
|
| -
|
| - // Listen to application state in order to clean up OpenGL before app goes
|
| - // away.
|
| - NSNotificationCenter *notificationCenter =
|
| - [NSNotificationCenter defaultCenter];
|
| - [notificationCenter addObserver:self
|
| - selector:@selector(willResignActive)
|
| - name:UIApplicationWillResignActiveNotification
|
| - object:nil];
|
| - [notificationCenter addObserver:self
|
| - selector:@selector(didBecomeActive)
|
| - name:UIApplicationDidBecomeActiveNotification
|
| - object:nil];
|
| -
|
| - // Frames are received on a separate thread, so we poll for current frame
|
| - // using a refresh rate proportional to screen refresh frequency. This
|
| - // occurs on the main thread.
|
| - __weak RTCEAGLVideoView *weakSelf = self;
|
| - _timer = [[RTCDisplayLinkTimer alloc] initWithTimerHandler:^{
|
| - RTCEAGLVideoView *strongSelf = weakSelf;
|
| - [strongSelf displayLinkTimerDidFire];
|
| - }];
|
| - [self setupGL];
|
| -}
|
| -
|
| -- (void)dealloc {
|
| - [[NSNotificationCenter defaultCenter] removeObserver:self];
|
| - UIApplicationState appState =
|
| - [UIApplication sharedApplication].applicationState;
|
| - if (appState == UIApplicationStateActive) {
|
| - [self teardownGL];
|
| - }
|
| - [_timer invalidate];
|
| - if (_glContext && [EAGLContext currentContext] == _glContext) {
|
| - [EAGLContext setCurrentContext:nil];
|
| - }
|
| -}
|
| -
|
| -#pragma mark - UIView
|
| -
|
| -- (void)setNeedsDisplay {
|
| - [super setNeedsDisplay];
|
| - _isDirty = YES;
|
| -}
|
| -
|
| -- (void)setNeedsDisplayInRect:(CGRect)rect {
|
| - [super setNeedsDisplayInRect:rect];
|
| - _isDirty = YES;
|
| -}
|
| -
|
| -- (void)layoutSubviews {
|
| - [super layoutSubviews];
|
| - _glkView.frame = self.bounds;
|
| -}
|
| -
|
| -#pragma mark - GLKViewDelegate
|
| -
|
| -// This method is called when the GLKView's content is dirty and needs to be
|
| -// redrawn. This occurs on main thread.
|
| -- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
|
| - // The renderer will draw the frame to the framebuffer corresponding to the
|
| - // one used by |view|.
|
| - RTCVideoFrame *frame = self.videoFrame;
|
| - if (!frame || frame == _lastDrawnFrame) {
|
| - return;
|
| - }
|
| - [self ensureGLContext];
|
| - glClear(GL_COLOR_BUFFER_BIT);
|
| - id<RTCShader> shader = nil;
|
| - if (frame.nativeHandle) {
|
| - if (!_nv12Shader) {
|
| - _nv12Shader = [[RTCNativeNV12Shader alloc] initWithContext:_glContext];
|
| - }
|
| - shader = _nv12Shader;
|
| - } else {
|
| - if (!_i420Shader) {
|
| - _i420Shader = [[RTCI420Shader alloc] initWithContext:_glContext];
|
| - }
|
| - shader = _i420Shader;
|
| - }
|
| - if (shader && [shader drawFrame:frame]) {
|
| - _lastDrawnFrame = frame;
|
| - } else {
|
| - RTCLog(@"Failed to draw frame.");
|
| - }
|
| -}
|
| -
|
| -#pragma mark - RTCVideoRenderer
|
| -
|
| -// These methods may be called on non-main thread.
|
| -- (void)setSize:(CGSize)size {
|
| - __weak RTCEAGLVideoView *weakSelf = self;
|
| - dispatch_async(dispatch_get_main_queue(), ^{
|
| - RTCEAGLVideoView *strongSelf = weakSelf;
|
| - [strongSelf.delegate videoView:strongSelf didChangeVideoSize:size];
|
| - });
|
| -}
|
| -
|
| -- (void)renderFrame:(RTCVideoFrame *)frame {
|
| - self.videoFrame = frame;
|
| -}
|
| -
|
| -#pragma mark - Private
|
| -
|
| -- (void)displayLinkTimerDidFire {
|
| - // Don't render unless video frame have changed or the view content
|
| - // has explicitly been marked dirty.
|
| - if (!_isDirty && _lastDrawnFrame == self.videoFrame) {
|
| - return;
|
| - }
|
| -
|
| - // Always reset isDirty at this point, even if -[GLKView display]
|
| - // won't be called in the case the drawable size is empty.
|
| - _isDirty = NO;
|
| -
|
| - // Only call -[GLKView display] if the drawable size is
|
| - // non-empty. Calling display will make the GLKView setup its
|
| - // render buffer if necessary, but that will fail with error
|
| - // GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT if size is empty.
|
| - if (self.bounds.size.width > 0 && self.bounds.size.height > 0) {
|
| - [_glkView display];
|
| - }
|
| -}
|
| -
|
| -- (void)setupGL {
|
| - self.videoFrame = nil;
|
| - [self ensureGLContext];
|
| - glDisable(GL_DITHER);
|
| - _timer.isPaused = NO;
|
| -}
|
| -
|
| -- (void)teardownGL {
|
| - self.videoFrame = nil;
|
| - _timer.isPaused = YES;
|
| - [_glkView deleteDrawable];
|
| - [self ensureGLContext];
|
| - _i420Shader = nil;
|
| - _nv12Shader = nil;
|
| -}
|
| -
|
| -- (void)didBecomeActive {
|
| - [self setupGL];
|
| -}
|
| -
|
| -- (void)willResignActive {
|
| - [self teardownGL];
|
| -}
|
| -
|
| -- (void)ensureGLContext {
|
| - NSAssert(_glContext, @"context shouldn't be nil");
|
| - if ([EAGLContext currentContext] != _glContext) {
|
| - [EAGLContext setCurrentContext:_glContext];
|
| - }
|
| -}
|
| -
|
| -@end
|
|
|