Note: We no longer publish the latest version of our code here. We primarily use a kumc-bmi github organization. The heron ETL repository, in particular, is not public. Peers in the informatics community should see MultiSiteDev for details on requesting access.

source: webrtc/webrtc/modules/video_render/ios/open_gles20.mm @ 0:4bda6873e34c

pub_scrub_3792 tip
Last change on this file since 0:4bda6873e34c was 0:4bda6873e34c, checked in by Michael Prittie <mprittie@…>, 6 years ago

Scrubbed password for publication.

File size: 9.8 KB
Line 
1/*
2 *  Copyright (c) 2012 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// This files is mostly copied from
12// webrtc/modules/video_render/android/video_render_opengles20.h
13
14// TODO(sjlee): unify this copy with the android one.
15#include "webrtc/modules/video_render/ios/open_gles20.h"
16#include "webrtc/system_wrappers/interface/trace.h"
17
18using namespace webrtc;
19
20const char OpenGles20::indices_[] = {0, 3, 2, 0, 2, 1};
21
22const char OpenGles20::vertext_shader_[] = {
23    "attribute vec4 aPosition;\n"
24    "attribute vec2 aTextureCoord;\n"
25    "varying vec2 vTextureCoord;\n"
26    "void main() {\n"
27    "  gl_Position = aPosition;\n"
28    "  vTextureCoord = aTextureCoord;\n"
29    "}\n"};
30
31// The fragment shader.
32// Do YUV to RGB565 conversion.
33const char OpenGles20::fragment_shader_[] = {
34    "precision mediump float;\n"
35    "uniform sampler2D Ytex;\n"
36    "uniform sampler2D Utex,Vtex;\n"
37    "varying vec2 vTextureCoord;\n"
38    "void main(void) {\n"
39    "  float nx,ny,r,g,b,y,u,v;\n"
40    "  mediump vec4 txl,ux,vx;"
41    "  nx=vTextureCoord[0];\n"
42    "  ny=vTextureCoord[1];\n"
43    "  y=texture2D(Ytex,vec2(nx,ny)).r;\n"
44    "  u=texture2D(Utex,vec2(nx,ny)).r;\n"
45    "  v=texture2D(Vtex,vec2(nx,ny)).r;\n"
46    "  y=1.1643*(y-0.0625);\n"
47    "  u=u-0.5;\n"
48    "  v=v-0.5;\n"
49    "  r=y+1.5958*v;\n"
50    "  g=y-0.39173*u-0.81290*v;\n"
51    "  b=y+2.017*u;\n"
52    "  gl_FragColor=vec4(r,g,b,1.0);\n"
53    "}\n"};
54
55OpenGles20::OpenGles20() : texture_width_(-1), texture_height_(-1) {
56  texture_ids_[0] = 0;
57  texture_ids_[1] = 0;
58  texture_ids_[2] = 0;
59
60  program_ = 0;
61
62  const GLfloat vertices[20] = {
63      // X, Y, Z, U, V
64      -1, -1, 0, 0, 1,   // Bottom Left
65      1,  -1, 0, 1, 1,   // Bottom Right
66      1,  1,  0, 1, 0,   // Top Right
67      -1, 1,  0, 0, 0};  // Top Left
68
69  memcpy(vertices_, vertices, sizeof(vertices_));
70}
71
72OpenGles20::~OpenGles20() {
73  if (program_) {
74    glDeleteTextures(3, texture_ids_);
75    glDeleteProgram(program_);
76  }
77}
78
79bool OpenGles20::Setup(int32_t width, int32_t height) {
80  program_ = CreateProgram(vertext_shader_, fragment_shader_);
81  if (!program_) {
82    return false;
83  }
84
85  int position_handle = glGetAttribLocation(program_, "aPosition");
86  int texture_handle = glGetAttribLocation(program_, "aTextureCoord");
87
88  // set the vertices array in the shader
89  // vertices_ contains 4 vertices with 5 coordinates.
90  // 3 for (xyz) for the vertices and 2 for the texture
91  glVertexAttribPointer(
92      position_handle, 3, GL_FLOAT, false, 5 * sizeof(GLfloat), vertices_);
93
94  glEnableVertexAttribArray(position_handle);
95
96  // set the texture coordinate array in the shader
97  // vertices_ contains 4 vertices with 5 coordinates.
98  // 3 for (xyz) for the vertices and 2 for the texture
99  glVertexAttribPointer(
100      texture_handle, 2, GL_FLOAT, false, 5 * sizeof(GLfloat), &vertices_[3]);
101  glEnableVertexAttribArray(texture_handle);
102
103  glUseProgram(program_);
104  int i = glGetUniformLocation(program_, "Ytex");
105  glUniform1i(i, 0); /* Bind Ytex to texture unit 0 */
106
107  i = glGetUniformLocation(program_, "Utex");
108  glUniform1i(i, 1); /* Bind Utex to texture unit 1 */
109
110  i = glGetUniformLocation(program_, "Vtex");
111  glUniform1i(i, 2); /* Bind Vtex to texture unit 2 */
112
113  glViewport(0, 0, width, height);
114  return true;
115}
116
117bool OpenGles20::SetCoordinates(const float z_order,
118                                const float left,
119                                const float top,
120                                const float right,
121                                const float bottom) {
122  if (top > 1 || top < 0 || right > 1 || right < 0 || bottom > 1 ||
123      bottom < 0 || left > 1 || left < 0) {
124    return false;
125  }
126
127  // Bottom Left
128  vertices_[0] = (left * 2) - 1;
129  vertices_[1] = -1 * (2 * bottom) + 1;
130  vertices_[2] = z_order;
131
132  // Bottom Right
133  vertices_[5] = (right * 2) - 1;
134  vertices_[6] = -1 * (2 * bottom) + 1;
135  vertices_[7] = z_order;
136
137  // Top Right
138  vertices_[10] = (right * 2) - 1;
139  vertices_[11] = -1 * (2 * top) + 1;
140  vertices_[12] = z_order;
141
142  // Top Left
143  vertices_[15] = (left * 2) - 1;
144  vertices_[16] = -1 * (2 * top) + 1;
145  vertices_[17] = z_order;
146
147  return true;
148}
149
150bool OpenGles20::Render(const I420VideoFrame& frame) {
151  if (texture_width_ != (GLsizei)frame.width() ||
152      texture_height_ != (GLsizei)frame.height()) {
153    SetupTextures(frame);
154  }
155  UpdateTextures(frame);
156
157  glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, indices_);
158
159  return true;
160}
161
162GLuint OpenGles20::LoadShader(GLenum shader_type, const char* shader_source) {
163  GLuint shader = glCreateShader(shader_type);
164  if (shader) {
165    glShaderSource(shader, 1, &shader_source, NULL);
166    glCompileShader(shader);
167
168    GLint compiled = 0;
169    glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
170    if (!compiled) {
171      GLint info_len = 0;
172      glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &info_len);
173      if (info_len) {
174        char* buf = (char*)malloc(info_len);
175        glGetShaderInfoLog(shader, info_len, NULL, buf);
176        WEBRTC_TRACE(kTraceError,
177                     kTraceVideoRenderer,
178                     0,
179                     "%s: Could not compile shader %d: %s",
180                     __FUNCTION__,
181                     shader_type,
182                     buf);
183        free(buf);
184      }
185      glDeleteShader(shader);
186      shader = 0;
187    }
188  }
189  return shader;
190}
191
192GLuint OpenGles20::CreateProgram(const char* vertex_source,
193                                 const char* fragment_source) {
194  GLuint vertex_shader = LoadShader(GL_VERTEX_SHADER, vertex_source);
195  if (!vertex_shader) {
196    return -1;
197  }
198
199  GLuint fragment_shader = LoadShader(GL_FRAGMENT_SHADER, fragment_source);
200  if (!fragment_shader) {
201    return -1;
202  }
203
204  GLuint program = glCreateProgram();
205  if (program) {
206    glAttachShader(program, vertex_shader);
207    glAttachShader(program, fragment_shader);
208    glLinkProgram(program);
209    GLint link_status = GL_FALSE;
210    glGetProgramiv(program, GL_LINK_STATUS, &link_status);
211    if (link_status != GL_TRUE) {
212      GLint info_len = 0;
213      glGetProgramiv(program, GL_INFO_LOG_LENGTH, &info_len);
214      if (info_len) {
215        char* buf = (char*)malloc(info_len);
216        glGetProgramInfoLog(program, info_len, NULL, buf);
217        WEBRTC_TRACE(kTraceError,
218                     kTraceVideoRenderer,
219                     0,
220                     "%s: Could not link program: %s",
221                     __FUNCTION__,
222                     buf);
223        free(buf);
224      }
225      glDeleteProgram(program);
226      program = 0;
227    }
228  }
229
230  if (vertex_shader) {
231    glDeleteShader(vertex_shader);
232  }
233
234  if (fragment_shader) {
235    glDeleteShader(fragment_shader);
236  }
237
238  return program;
239}
240
241static void InitializeTexture(int name, int id, int width, int height) {
242  glActiveTexture(name);
243  glBindTexture(GL_TEXTURE_2D, id);
244  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
245  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
246  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
247  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
248  glTexImage2D(GL_TEXTURE_2D,
249               0,
250               GL_LUMINANCE,
251               width,
252               height,
253               0,
254               GL_LUMINANCE,
255               GL_UNSIGNED_BYTE,
256               NULL);
257}
258
259void OpenGles20::SetupTextures(const I420VideoFrame& frame) {
260  const GLsizei width = frame.width();
261  const GLsizei height = frame.height();
262
263  if (!texture_ids_[0]) {
264    glGenTextures(3, texture_ids_);  // Generate  the Y, U and V texture
265  }
266
267  InitializeTexture(GL_TEXTURE0, texture_ids_[0], width, height);
268  InitializeTexture(GL_TEXTURE1, texture_ids_[1], width / 2, height / 2);
269  InitializeTexture(GL_TEXTURE2, texture_ids_[2], width / 2, height / 2);
270
271  texture_width_ = width;
272  texture_height_ = height;
273}
274
275// Uploads a plane of pixel data, accounting for stride != width*bpp.
276static void GlTexSubImage2D(GLsizei width,
277                            GLsizei height,
278                            int stride,
279                            const uint8_t* plane) {
280  if (stride == width) {
281    // Yay!  We can upload the entire plane in a single GL call.
282    glTexSubImage2D(GL_TEXTURE_2D,
283                    0,
284                    0,
285                    0,
286                    width,
287                    height,
288                    GL_LUMINANCE,
289                    GL_UNSIGNED_BYTE,
290                    static_cast<const GLvoid*>(plane));
291  } else {
292    // Boo!  Since GLES2 doesn't have GL_UNPACK_ROW_LENGTH and iOS doesn't
293    // have GL_EXT_unpack_subimage we have to upload a row at a time.  Ick.
294    for (int row = 0; row < height; ++row) {
295      glTexSubImage2D(GL_TEXTURE_2D,
296                      0,
297                      0,
298                      row,
299                      width,
300                      1,
301                      GL_LUMINANCE,
302                      GL_UNSIGNED_BYTE,
303                      static_cast<const GLvoid*>(plane + (row * stride)));
304    }
305  }
306}
307
308void OpenGles20::UpdateTextures(const I420VideoFrame& frame) {
309  const GLsizei width = frame.width();
310  const GLsizei height = frame.height();
311
312  glActiveTexture(GL_TEXTURE0);
313  glBindTexture(GL_TEXTURE_2D, texture_ids_[0]);
314  GlTexSubImage2D(width, height, frame.stride(kYPlane), frame.buffer(kYPlane));
315
316  glActiveTexture(GL_TEXTURE1);
317  glBindTexture(GL_TEXTURE_2D, texture_ids_[1]);
318  GlTexSubImage2D(
319      width / 2, height / 2, frame.stride(kUPlane), frame.buffer(kUPlane));
320
321  glActiveTexture(GL_TEXTURE2);
322  glBindTexture(GL_TEXTURE_2D, texture_ids_[2]);
323  GlTexSubImage2D(
324      width / 2, height / 2, frame.stride(kVPlane), frame.buffer(kVPlane));
325}
Note: See TracBrowser for help on using the repository browser.