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

Side by Side Diff: webrtc/api/androidtests/src/org/webrtc/GlRectDrawerTest.java

Issue 2514883002: Create //webrtc/api:libjingle_peerconnection_api + refactorings. (Closed)
Patch Set: Big move! Created 4 years 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
OLDNEW
(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 package org.webrtc;
11
12 import android.graphics.SurfaceTexture;
13 import android.opengl.GLES20;
14 import android.test.ActivityTestCase;
15 import android.test.suitebuilder.annotation.MediumTest;
16 import android.test.suitebuilder.annotation.SmallTest;
17
18 import java.nio.ByteBuffer;
19 import java.util.Random;
20
21 public final class GlRectDrawerTest extends ActivityTestCase {
22 // Resolution of the test image.
23 private static final int WIDTH = 16;
24 private static final int HEIGHT = 16;
25 // Seed for random pixel creation.
26 private static final int SEED = 42;
27 // When comparing pixels, allow some slack for float arithmetic and integer ro unding.
28 private static final float MAX_DIFF = 1.5f;
29
30 private static float normalizedByte(byte b) {
31 return (b & 0xFF) / 255.0f;
32 }
33
34 private static float saturatedConvert(float c) {
35 return 255.0f * Math.max(0, Math.min(c, 1));
36 }
37
38 // Assert RGB ByteBuffers are pixel perfect identical.
39 private static void assertEquals(int width, int height, ByteBuffer actual, Byt eBuffer expected) {
40 actual.rewind();
41 expected.rewind();
42 assertEquals(actual.remaining(), width * height * 3);
43 assertEquals(expected.remaining(), width * height * 3);
44 for (int y = 0; y < height; ++y) {
45 for (int x = 0; x < width; ++x) {
46 final int actualR = actual.get() & 0xFF;
47 final int actualG = actual.get() & 0xFF;
48 final int actualB = actual.get() & 0xFF;
49 final int expectedR = expected.get() & 0xFF;
50 final int expectedG = expected.get() & 0xFF;
51 final int expectedB = expected.get() & 0xFF;
52 if (actualR != expectedR || actualG != expectedG || actualB != expectedB ) {
53 fail("ByteBuffers of size " + width + "x" + height + " not equal at po sition "
54 + "(" + x + ", " + y + "). Expected color (R,G,B): "
55 + "(" + expectedR + ", " + expectedG + ", " + expectedB + ")"
56 + " but was: "
57 + "(" + actualR + ", " + actualG + ", " + actualB + ").");
58 }
59 }
60 }
61 }
62
63 // Convert RGBA ByteBuffer to RGB ByteBuffer.
64 private static ByteBuffer stripAlphaChannel(ByteBuffer rgbaBuffer) {
65 rgbaBuffer.rewind();
66 assertEquals(rgbaBuffer.remaining() % 4, 0);
67 final int numberOfPixels = rgbaBuffer.remaining() / 4;
68 final ByteBuffer rgbBuffer = ByteBuffer.allocateDirect(numberOfPixels * 3);
69 while (rgbaBuffer.hasRemaining()) {
70 // Copy RGB.
71 for (int channel = 0; channel < 3; ++channel) {
72 rgbBuffer.put(rgbaBuffer.get());
73 }
74 // Drop alpha.
75 rgbaBuffer.get();
76 }
77 return rgbBuffer;
78 }
79
80 @SmallTest
81 public void testRgbRendering() {
82 // Create EGL base with a pixel buffer as display output.
83 final EglBase eglBase = EglBase.create(null, EglBase.CONFIG_PIXEL_BUFFER);
84 eglBase.createPbufferSurface(WIDTH, HEIGHT);
85 eglBase.makeCurrent();
86
87 // Create RGB byte buffer plane with random content.
88 final ByteBuffer rgbPlane = ByteBuffer.allocateDirect(WIDTH * HEIGHT * 3);
89 final Random random = new Random(SEED);
90 random.nextBytes(rgbPlane.array());
91
92 // Upload the RGB byte buffer data as a texture.
93 final int rgbTexture = GlUtil.generateTexture(GLES20.GL_TEXTURE_2D);
94 GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
95 GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, rgbTexture);
96 GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGB, WIDTH, HEIGHT, 0 , GLES20.GL_RGB,
97 GLES20.GL_UNSIGNED_BYTE, rgbPlane);
98 GlUtil.checkNoGLES2Error("glTexImage2D");
99
100 // Draw the RGB frame onto the pixel buffer.
101 final GlRectDrawer drawer = new GlRectDrawer();
102 drawer.drawRgb(rgbTexture, RendererCommon.identityMatrix(), WIDTH, HEIGHT, 0 /* viewportX */,
103 0 /* viewportY */, WIDTH, HEIGHT);
104
105 // Download the pixels in the pixel buffer as RGBA. Not all platforms suppor t RGB, e.g. Nexus 9.
106 final ByteBuffer rgbaData = ByteBuffer.allocateDirect(WIDTH * HEIGHT * 4);
107 GLES20.glReadPixels(0, 0, WIDTH, HEIGHT, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_ BYTE, rgbaData);
108 GlUtil.checkNoGLES2Error("glReadPixels");
109
110 // Assert rendered image is pixel perfect to source RGB.
111 assertEquals(WIDTH, HEIGHT, stripAlphaChannel(rgbaData), rgbPlane);
112
113 drawer.release();
114 GLES20.glDeleteTextures(1, new int[] {rgbTexture}, 0);
115 eglBase.release();
116 }
117
118 @SmallTest
119 public void testYuvRendering() {
120 // Create EGL base with a pixel buffer as display output.
121 EglBase eglBase = EglBase.create(null, EglBase.CONFIG_PIXEL_BUFFER);
122 eglBase.createPbufferSurface(WIDTH, HEIGHT);
123 eglBase.makeCurrent();
124
125 // Create YUV byte buffer planes with random content.
126 final ByteBuffer[] yuvPlanes = new ByteBuffer[3];
127 final Random random = new Random(SEED);
128 for (int i = 0; i < 3; ++i) {
129 yuvPlanes[i] = ByteBuffer.allocateDirect(WIDTH * HEIGHT);
130 random.nextBytes(yuvPlanes[i].array());
131 }
132
133 // Generate 3 texture ids for Y/U/V.
134 final int yuvTextures[] = new int[3];
135 for (int i = 0; i < 3; i++) {
136 yuvTextures[i] = GlUtil.generateTexture(GLES20.GL_TEXTURE_2D);
137 }
138
139 // Upload the YUV byte buffer data as textures.
140 for (int i = 0; i < 3; ++i) {
141 GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + i);
142 GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, yuvTextures[i]);
143 GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE, WIDTH, H EIGHT, 0,
144 GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, yuvPlanes[i]);
145 GlUtil.checkNoGLES2Error("glTexImage2D");
146 }
147
148 // Draw the YUV frame onto the pixel buffer.
149 final GlRectDrawer drawer = new GlRectDrawer();
150 drawer.drawYuv(yuvTextures, RendererCommon.identityMatrix(), WIDTH, HEIGHT, 0 /* viewportX */,
151 0 /* viewportY */, WIDTH, HEIGHT);
152
153 // Download the pixels in the pixel buffer as RGBA. Not all platforms suppor t RGB, e.g. Nexus 9.
154 final ByteBuffer data = ByteBuffer.allocateDirect(WIDTH * HEIGHT * 4);
155 GLES20.glReadPixels(0, 0, WIDTH, HEIGHT, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_ BYTE, data);
156 GlUtil.checkNoGLES2Error("glReadPixels");
157
158 // Compare the YUV data with the RGBA result.
159 for (int y = 0; y < HEIGHT; ++y) {
160 for (int x = 0; x < WIDTH; ++x) {
161 // YUV color space. Y in [0, 1], UV in [-0.5, 0.5]. The constants are ta ken from the YUV
162 // fragment shader code in GlRectDrawer.
163 final float y_luma = normalizedByte(yuvPlanes[0].get());
164 final float u_chroma = normalizedByte(yuvPlanes[1].get()) - 0.5f;
165 final float v_chroma = normalizedByte(yuvPlanes[2].get()) - 0.5f;
166 // Expected color in unrounded RGB [0.0f, 255.0f].
167 final float expectedRed = saturatedConvert(y_luma + 1.403f * v_chroma);
168 final float expectedGreen =
169 saturatedConvert(y_luma - 0.344f * u_chroma - 0.714f * v_chroma);
170 final float expectedBlue = saturatedConvert(y_luma + 1.77f * u_chroma);
171
172 // Actual color in RGB8888.
173 final int actualRed = data.get() & 0xFF;
174 final int actualGreen = data.get() & 0xFF;
175 final int actualBlue = data.get() & 0xFF;
176 final int actualAlpha = data.get() & 0xFF;
177
178 // Assert rendered image is close to pixel perfect from source YUV.
179 assertTrue(Math.abs(actualRed - expectedRed) < MAX_DIFF);
180 assertTrue(Math.abs(actualGreen - expectedGreen) < MAX_DIFF);
181 assertTrue(Math.abs(actualBlue - expectedBlue) < MAX_DIFF);
182 assertEquals(actualAlpha, 255);
183 }
184 }
185
186 drawer.release();
187 GLES20.glDeleteTextures(3, yuvTextures, 0);
188 eglBase.release();
189 }
190
191 /**
192 * The purpose here is to test GlRectDrawer.oesDraw(). Unfortunately, there is no easy way to
193 * create an OES texture, which is needed for input to oesDraw(). Most of the test is concerned
194 * with creating OES textures in the following way:
195 * - Create SurfaceTexture with help from SurfaceTextureHelper.
196 * - Create an EglBase with the SurfaceTexture as EGLSurface.
197 * - Upload RGB texture with known content.
198 * - Draw the RGB texture onto the EglBase with the SurfaceTexture as target.
199 * - Wait for an OES texture to be produced.
200 * The actual oesDraw() test is this:
201 * - Create an EglBase with a pixel buffer as target.
202 * - Render the OES texture onto the pixel buffer.
203 * - Read back the pixel buffer and compare it with the known RGB data.
204 */
205 @MediumTest
206 public void testOesRendering() throws InterruptedException {
207 /**
208 * Stub class to convert RGB ByteBuffers to OES textures by drawing onto a S urfaceTexture.
209 */
210 class StubOesTextureProducer {
211 private final EglBase eglBase;
212 private final GlRectDrawer drawer;
213 private final int rgbTexture;
214
215 public StubOesTextureProducer(
216 EglBase.Context sharedContext, SurfaceTexture surfaceTexture, int widt h, int height) {
217 eglBase = EglBase.create(sharedContext, EglBase.CONFIG_PLAIN);
218 surfaceTexture.setDefaultBufferSize(width, height);
219 eglBase.createSurface(surfaceTexture);
220 assertEquals(eglBase.surfaceWidth(), width);
221 assertEquals(eglBase.surfaceHeight(), height);
222
223 drawer = new GlRectDrawer();
224
225 eglBase.makeCurrent();
226 rgbTexture = GlUtil.generateTexture(GLES20.GL_TEXTURE_2D);
227 }
228
229 public void draw(ByteBuffer rgbPlane) {
230 eglBase.makeCurrent();
231
232 // Upload RGB data to texture.
233 GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
234 GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, rgbTexture);
235 GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGB, WIDTH, HEIGH T, 0, GLES20.GL_RGB,
236 GLES20.GL_UNSIGNED_BYTE, rgbPlane);
237 // Draw the RGB data onto the SurfaceTexture.
238 drawer.drawRgb(rgbTexture, RendererCommon.identityMatrix(), WIDTH, HEIGH T,
239 0 /* viewportX */, 0 /* viewportY */, WIDTH, HEIGHT);
240 eglBase.swapBuffers();
241 }
242
243 public void release() {
244 eglBase.makeCurrent();
245 drawer.release();
246 GLES20.glDeleteTextures(1, new int[] {rgbTexture}, 0);
247 eglBase.release();
248 }
249 }
250
251 // Create EGL base with a pixel buffer as display output.
252 final EglBase eglBase = EglBase.create(null, EglBase.CONFIG_PIXEL_BUFFER);
253 eglBase.createPbufferSurface(WIDTH, HEIGHT);
254
255 // Create resources for generating OES textures.
256 final SurfaceTextureHelper surfaceTextureHelper = SurfaceTextureHelper.creat e(
257 "SurfaceTextureHelper test" /* threadName */, eglBase.getEglBaseContext( ));
258 final StubOesTextureProducer oesProducer = new StubOesTextureProducer(
259 eglBase.getEglBaseContext(), surfaceTextureHelper.getSurfaceTexture(), W IDTH, HEIGHT);
260 final SurfaceTextureHelperTest.MockTextureListener listener =
261 new SurfaceTextureHelperTest.MockTextureListener();
262 surfaceTextureHelper.startListening(listener);
263
264 // Create RGB byte buffer plane with random content.
265 final ByteBuffer rgbPlane = ByteBuffer.allocateDirect(WIDTH * HEIGHT * 3);
266 final Random random = new Random(SEED);
267 random.nextBytes(rgbPlane.array());
268
269 // Draw the frame and block until an OES texture is delivered.
270 oesProducer.draw(rgbPlane);
271 listener.waitForNewFrame();
272
273 // Real test starts here.
274 // Draw the OES texture on the pixel buffer.
275 eglBase.makeCurrent();
276 final GlRectDrawer drawer = new GlRectDrawer();
277 drawer.drawOes(listener.oesTextureId, listener.transformMatrix, WIDTH, HEIGH T,
278 0 /* viewportX */, 0 /* viewportY */, WIDTH, HEIGHT);
279
280 // Download the pixels in the pixel buffer as RGBA. Not all platforms suppor t RGB, e.g. Nexus 9.
281 final ByteBuffer rgbaData = ByteBuffer.allocateDirect(WIDTH * HEIGHT * 4);
282 GLES20.glReadPixels(0, 0, WIDTH, HEIGHT, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_ BYTE, rgbaData);
283 GlUtil.checkNoGLES2Error("glReadPixels");
284
285 // Assert rendered image is pixel perfect to source RGB.
286 assertEquals(WIDTH, HEIGHT, stripAlphaChannel(rgbaData), rgbPlane);
287
288 drawer.release();
289 surfaceTextureHelper.returnTextureFrame();
290 oesProducer.release();
291 surfaceTextureHelper.dispose();
292 eglBase.release();
293 }
294 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698