1/*
2 *  Copyright (c) 2013 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#if !defined(__has_feature) || !__has_feature(objc_arc)
12#error "This file requires ARC support."
13#endif
14
15#include "webrtc/modules/video_render/ios/video_render_ios_view.h"
16#include "webrtc/system_wrappers/include/trace.h"
17
18using namespace webrtc;
19
20@implementation VideoRenderIosView {
21  EAGLContext* _context;
22  rtc::scoped_ptr<webrtc::OpenGles20> _gles_renderer20;
23  int _frameBufferWidth;
24  int _frameBufferHeight;
25  unsigned int _defaultFrameBuffer;
26  unsigned int _colorRenderBuffer;
27}
28
29@synthesize context = context_;
30
31+ (Class)layerClass {
32  return [CAEAGLLayer class];
33}
34
35- (id)initWithCoder:(NSCoder*)coder {
36  // init super class
37  self = [super initWithCoder:coder];
38  if (self) {
39    _gles_renderer20.reset(new OpenGles20());
40  }
41  return self;
42}
43
44- (id)init {
45  // init super class
46  self = [super init];
47  if (self) {
48    _gles_renderer20.reset(new OpenGles20());
49  }
50  return self;
51}
52
53- (id)initWithFrame:(CGRect)frame {
54  // init super class
55  self = [super initWithFrame:frame];
56  if (self) {
57    _gles_renderer20.reset(new OpenGles20());
58  }
59  return self;
60}
61
62- (void)dealloc {
63  if (_defaultFrameBuffer) {
64    glDeleteFramebuffers(1, &_defaultFrameBuffer);
65    _defaultFrameBuffer = 0;
66  }
67
68  if (_colorRenderBuffer) {
69    glDeleteRenderbuffers(1, &_colorRenderBuffer);
70    _colorRenderBuffer = 0;
71  }
72
73  [EAGLContext setCurrentContext:nil];
74}
75
76- (NSString*)description {
77  return [NSString stringWithFormat:
78          @"A WebRTC implemented subclass of UIView."
79          "+Class method is overwritten, along with custom methods"];
80}
81
82- (BOOL)createContext {
83  // create OpenGLES context from self layer class
84  CAEAGLLayer* eagl_layer = (CAEAGLLayer*)self.layer;
85  eagl_layer.opaque = YES;
86  eagl_layer.drawableProperties =
87      [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:NO],
88          kEAGLDrawablePropertyRetainedBacking,
89          kEAGLColorFormatRGBA8,
90          kEAGLDrawablePropertyColorFormat,
91          nil];
92  _context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
93
94  if (!_context) {
95    return NO;
96  }
97
98  if (![EAGLContext setCurrentContext:_context]) {
99    return NO;
100  }
101
102  // generates and binds the OpenGLES buffers
103  glGenFramebuffers(1, &_defaultFrameBuffer);
104  glBindFramebuffer(GL_FRAMEBUFFER, _defaultFrameBuffer);
105
106  // Create color render buffer and allocate backing store.
107  glGenRenderbuffers(1, &_colorRenderBuffer);
108  glBindRenderbuffer(GL_RENDERBUFFER, _colorRenderBuffer);
109  [_context renderbufferStorage:GL_RENDERBUFFER
110                   fromDrawable:(CAEAGLLayer*)self.layer];
111  glGetRenderbufferParameteriv(
112      GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &_frameBufferWidth);
113  glGetRenderbufferParameteriv(
114      GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &_frameBufferHeight);
115  glFramebufferRenderbuffer(GL_FRAMEBUFFER,
116                            GL_COLOR_ATTACHMENT0,
117                            GL_RENDERBUFFER,
118                            _colorRenderBuffer);
119
120  if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
121    return NO;
122  }
123
124  // set the frame buffer
125  glBindFramebuffer(GL_FRAMEBUFFER, _defaultFrameBuffer);
126  glViewport(0, 0, self.frame.size.width, self.frame.size.height);
127
128  return _gles_renderer20->Setup([self bounds].size.width,
129                                 [self bounds].size.height);
130}
131
132- (BOOL)presentFramebuffer {
133  if (![_context presentRenderbuffer:GL_RENDERBUFFER]) {
134    WEBRTC_TRACE(kTraceWarning,
135                 kTraceVideoRenderer,
136                 0,
137                 "%s:%d [context present_renderbuffer] "
138                 "returned false",
139                 __FUNCTION__,
140                 __LINE__);
141  }
142  return YES;
143}
144
145- (BOOL)renderFrame:(VideoFrame*)frameToRender {
146  if (![EAGLContext setCurrentContext:_context]) {
147    return NO;
148  }
149
150  return _gles_renderer20->Render(*frameToRender);
151}
152
153- (BOOL)setCoordinatesForZOrder:(const float)zOrder
154                           Left:(const float)left
155                            Top:(const float)top
156                          Right:(const float)right
157                         Bottom:(const float)bottom {
158  return _gles_renderer20->SetCoordinates(zOrder, left, top, right, bottom);
159}
160
161@end
162