| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright 2015 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 package org.webrtc; | |
| 12 | |
| 13 import android.opengl.GLES11Ext; | |
| 14 import android.opengl.GLES20; | |
| 15 | |
| 16 import org.webrtc.GlShader; | |
| 17 import org.webrtc.GlUtil; | |
| 18 | |
| 19 import java.nio.ByteBuffer; | |
| 20 import java.nio.FloatBuffer; | |
| 21 import java.util.Arrays; | |
| 22 import java.util.IdentityHashMap; | |
| 23 import java.util.Map; | |
| 24 | |
| 25 /** | |
| 26 * Helper class to draw an opaque quad on the target viewport location. Rotation
, mirror, and | |
| 27 * cropping is specified using a 4x4 texture coordinate transform matrix. The fr
ame input can either | |
| 28 * be an OES texture or YUV textures in I420 format. The GL state must be preser
ved between draw | |
| 29 * calls, this is intentional to maximize performance. The function release() mu
st be called | |
| 30 * manually to free the resources held by this object. | |
| 31 */ | |
| 32 public class GlRectDrawer implements RendererCommon.GlDrawer { | |
| 33 // Simple vertex shader, used for both YUV and OES. | |
| 34 private static final String VERTEX_SHADER_STRING = | |
| 35 "varying vec2 interp_tc;\n" | |
| 36 + "attribute vec4 in_pos;\n" | |
| 37 + "attribute vec4 in_tc;\n" | |
| 38 + "\n" | |
| 39 + "uniform mat4 texMatrix;\n" | |
| 40 + "\n" | |
| 41 + "void main() {\n" | |
| 42 + " gl_Position = in_pos;\n" | |
| 43 + " interp_tc = (texMatrix * in_tc).xy;\n" | |
| 44 + "}\n"; | |
| 45 | |
| 46 private static final String YUV_FRAGMENT_SHADER_STRING = | |
| 47 "precision mediump float;\n" | |
| 48 + "varying vec2 interp_tc;\n" | |
| 49 + "\n" | |
| 50 + "uniform sampler2D y_tex;\n" | |
| 51 + "uniform sampler2D u_tex;\n" | |
| 52 + "uniform sampler2D v_tex;\n" | |
| 53 + "\n" | |
| 54 + "void main() {\n" | |
| 55 // CSC according to http://www.fourcc.org/fccyvrgb.php | |
| 56 + " float y = texture2D(y_tex, interp_tc).r;\n" | |
| 57 + " float u = texture2D(u_tex, interp_tc).r - 0.5;\n" | |
| 58 + " float v = texture2D(v_tex, interp_tc).r - 0.5;\n" | |
| 59 + " gl_FragColor = vec4(y + 1.403 * v, " | |
| 60 + " y - 0.344 * u - 0.714 * v, " | |
| 61 + " y + 1.77 * u, 1);\n" | |
| 62 + "}\n"; | |
| 63 | |
| 64 private static final String RGB_FRAGMENT_SHADER_STRING = | |
| 65 "precision mediump float;\n" | |
| 66 + "varying vec2 interp_tc;\n" | |
| 67 + "\n" | |
| 68 + "uniform sampler2D rgb_tex;\n" | |
| 69 + "\n" | |
| 70 + "void main() {\n" | |
| 71 + " gl_FragColor = texture2D(rgb_tex, interp_tc);\n" | |
| 72 + "}\n"; | |
| 73 | |
| 74 private static final String OES_FRAGMENT_SHADER_STRING = | |
| 75 "#extension GL_OES_EGL_image_external : require\n" | |
| 76 + "precision mediump float;\n" | |
| 77 + "varying vec2 interp_tc;\n" | |
| 78 + "\n" | |
| 79 + "uniform samplerExternalOES oes_tex;\n" | |
| 80 + "\n" | |
| 81 + "void main() {\n" | |
| 82 + " gl_FragColor = texture2D(oes_tex, interp_tc);\n" | |
| 83 + "}\n"; | |
| 84 | |
| 85 // Vertex coordinates in Normalized Device Coordinates, i.e. (-1, -1) is botto
m-left and (1, 1) is | |
| 86 // top-right. | |
| 87 private static final FloatBuffer FULL_RECTANGLE_BUF = | |
| 88 GlUtil.createFloatBuffer(new float[] { | |
| 89 -1.0f, -1.0f, // Bottom left. | |
| 90 1.0f, -1.0f, // Bottom right. | |
| 91 -1.0f, 1.0f, // Top left. | |
| 92 1.0f, 1.0f, // Top right. | |
| 93 }); | |
| 94 | |
| 95 // Texture coordinates - (0, 0) is bottom-left and (1, 1) is top-right. | |
| 96 private static final FloatBuffer FULL_RECTANGLE_TEX_BUF = | |
| 97 GlUtil.createFloatBuffer(new float[] { | |
| 98 0.0f, 0.0f, // Bottom left. | |
| 99 1.0f, 0.0f, // Bottom right. | |
| 100 0.0f, 1.0f, // Top left. | |
| 101 1.0f, 1.0f // Top right. | |
| 102 }); | |
| 103 | |
| 104 private static class Shader { | |
| 105 public final GlShader glShader; | |
| 106 public final int texMatrixLocation; | |
| 107 | |
| 108 public Shader(String fragmentShader) { | |
| 109 this.glShader = new GlShader(VERTEX_SHADER_STRING, fragmentShader); | |
| 110 this.texMatrixLocation = glShader.getUniformLocation("texMatrix"); | |
| 111 } | |
| 112 } | |
| 113 | |
| 114 // The keys are one of the fragments shaders above. | |
| 115 private final Map<String, Shader> shaders = new IdentityHashMap<String, Shader
>(); | |
| 116 | |
| 117 /** | |
| 118 * Draw an OES texture frame with specified texture transformation matrix. Req
uired resources are | |
| 119 * allocated at the first call to this function. | |
| 120 */ | |
| 121 @Override | |
| 122 public void drawOes(int oesTextureId, float[] texMatrix, int frameWidth, int f
rameHeight, | |
| 123 int viewportX, int viewportY, int viewportWidth, int viewportHeight) { | |
| 124 prepareShader(OES_FRAGMENT_SHADER_STRING, texMatrix); | |
| 125 GLES20.glActiveTexture(GLES20.GL_TEXTURE0); | |
| 126 // updateTexImage() may be called from another thread in another EGL context
, so we need to | |
| 127 // bind/unbind the texture in each draw call so that GLES understads it's a
new texture. | |
| 128 GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, oesTextureId); | |
| 129 drawRectangle(viewportX, viewportY, viewportWidth, viewportHeight); | |
| 130 GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0); | |
| 131 } | |
| 132 | |
| 133 /** | |
| 134 * Draw a RGB(A) texture frame with specified texture transformation matrix. R
equired resources | |
| 135 * are allocated at the first call to this function. | |
| 136 */ | |
| 137 @Override | |
| 138 public void drawRgb(int textureId, float[] texMatrix, int frameWidth, int fram
eHeight, | |
| 139 int viewportX, int viewportY, int viewportWidth, int viewportHeight) { | |
| 140 prepareShader(RGB_FRAGMENT_SHADER_STRING, texMatrix); | |
| 141 GLES20.glActiveTexture(GLES20.GL_TEXTURE0); | |
| 142 GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId); | |
| 143 drawRectangle(viewportX, viewportY, viewportWidth, viewportHeight); | |
| 144 // Unbind the texture as a precaution. | |
| 145 GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0); | |
| 146 } | |
| 147 | |
| 148 /** | |
| 149 * Draw a YUV frame with specified texture transformation matrix. Required res
ources are | |
| 150 * allocated at the first call to this function. | |
| 151 */ | |
| 152 @Override | |
| 153 public void drawYuv(int[] yuvTextures, float[] texMatrix, int frameWidth, int
frameHeight, | |
| 154 int viewportX, int viewportY, int viewportWidth, int viewportHeight) { | |
| 155 prepareShader(YUV_FRAGMENT_SHADER_STRING, texMatrix); | |
| 156 // Bind the textures. | |
| 157 for (int i = 0; i < 3; ++i) { | |
| 158 GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + i); | |
| 159 GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, yuvTextures[i]); | |
| 160 } | |
| 161 drawRectangle(viewportX, viewportY, viewportWidth, viewportHeight); | |
| 162 // Unbind the textures as a precaution.. | |
| 163 for (int i = 0; i < 3; ++i) { | |
| 164 GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + i); | |
| 165 GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0); | |
| 166 } | |
| 167 } | |
| 168 | |
| 169 private void drawRectangle(int x, int y, int width, int height) { | |
| 170 // Draw quad. | |
| 171 GLES20.glViewport(x, y, width, height); | |
| 172 GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); | |
| 173 } | |
| 174 | |
| 175 private void prepareShader(String fragmentShader, float[] texMatrix) { | |
| 176 final Shader shader; | |
| 177 if (shaders.containsKey(fragmentShader)) { | |
| 178 shader = shaders.get(fragmentShader); | |
| 179 } else { | |
| 180 // Lazy allocation. | |
| 181 shader = new Shader(fragmentShader); | |
| 182 shaders.put(fragmentShader, shader); | |
| 183 shader.glShader.useProgram(); | |
| 184 // Initialize fragment shader uniform values. | |
| 185 if (fragmentShader == YUV_FRAGMENT_SHADER_STRING) { | |
| 186 GLES20.glUniform1i(shader.glShader.getUniformLocation("y_tex"), 0); | |
| 187 GLES20.glUniform1i(shader.glShader.getUniformLocation("u_tex"), 1); | |
| 188 GLES20.glUniform1i(shader.glShader.getUniformLocation("v_tex"), 2); | |
| 189 } else if (fragmentShader == RGB_FRAGMENT_SHADER_STRING) { | |
| 190 GLES20.glUniform1i(shader.glShader.getUniformLocation("rgb_tex"), 0); | |
| 191 } else if (fragmentShader == OES_FRAGMENT_SHADER_STRING) { | |
| 192 GLES20.glUniform1i(shader.glShader.getUniformLocation("oes_tex"), 0); | |
| 193 } else { | |
| 194 throw new IllegalStateException("Unknown fragment shader: " + fragmentSh
ader); | |
| 195 } | |
| 196 GlUtil.checkNoGLES2Error("Initialize fragment shader uniform values."); | |
| 197 // Initialize vertex shader attributes. | |
| 198 shader.glShader.setVertexAttribArray("in_pos", 2, FULL_RECTANGLE_BUF); | |
| 199 shader.glShader.setVertexAttribArray("in_tc", 2, FULL_RECTANGLE_TEX_BUF); | |
| 200 } | |
| 201 shader.glShader.useProgram(); | |
| 202 // Copy the texture transformation matrix over. | |
| 203 GLES20.glUniformMatrix4fv(shader.texMatrixLocation, 1, false, texMatrix, 0); | |
| 204 } | |
| 205 | |
| 206 /** | |
| 207 * Release all GLES resources. This needs to be done manually, otherwise the r
esources are leaked. | |
| 208 */ | |
| 209 @Override | |
| 210 public void release() { | |
| 211 for (Shader shader : shaders.values()) { | |
| 212 shader.glShader.release(); | |
| 213 } | |
| 214 shaders.clear(); | |
| 215 } | |
| 216 } | |
| OLD | NEW |