| Index: talk/app/webrtc/androidtests/src/org/webrtc/SurfaceTextureHelperTest.java
|
| diff --git a/talk/app/webrtc/androidtests/src/org/webrtc/SurfaceTextureHelperTest.java b/talk/app/webrtc/androidtests/src/org/webrtc/SurfaceTextureHelperTest.java
|
| deleted file mode 100644
|
| index 9e0164d4b836891382729af8e6d81a8e662341e4..0000000000000000000000000000000000000000
|
| --- a/talk/app/webrtc/androidtests/src/org/webrtc/SurfaceTextureHelperTest.java
|
| +++ /dev/null
|
| @@ -1,439 +0,0 @@
|
| -/*
|
| - * libjingle
|
| - * Copyright 2015 Google Inc.
|
| - *
|
| - * Redistribution and use in source and binary forms, with or without
|
| - * modification, are permitted provided that the following conditions are met:
|
| - *
|
| - * 1. Redistributions of source code must retain the above copyright notice,
|
| - * this list of conditions and the following disclaimer.
|
| - * 2. Redistributions in binary form must reproduce the above copyright notice,
|
| - * this list of conditions and the following disclaimer in the documentation
|
| - * and/or other materials provided with the distribution.
|
| - * 3. The name of the author may not be used to endorse or promote products
|
| - * derived from this software without specific prior written permission.
|
| - *
|
| - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
| - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
| - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
| - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
| - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
| - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
| - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
| - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
| - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
| - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| - */
|
| -package org.webrtc;
|
| -
|
| -import android.graphics.SurfaceTexture;
|
| -import android.opengl.GLES20;
|
| -import android.os.Handler;
|
| -import android.os.HandlerThread;
|
| -import android.os.SystemClock;
|
| -import android.test.ActivityTestCase;
|
| -import android.test.suitebuilder.annotation.MediumTest;
|
| -import android.test.suitebuilder.annotation.SmallTest;
|
| -
|
| -import java.nio.ByteBuffer;
|
| -
|
| -public final class SurfaceTextureHelperTest extends ActivityTestCase {
|
| - /**
|
| - * Mock texture listener with blocking wait functionality.
|
| - */
|
| - public static final class MockTextureListener
|
| - implements SurfaceTextureHelper.OnTextureFrameAvailableListener {
|
| - public int oesTextureId;
|
| - public float[] transformMatrix;
|
| - private boolean hasNewFrame = false;
|
| - // Thread where frames are expected to be received on.
|
| - private final Thread expectedThread;
|
| -
|
| - MockTextureListener() {
|
| - this.expectedThread = null;
|
| - }
|
| -
|
| - MockTextureListener(Thread expectedThread) {
|
| - this.expectedThread = expectedThread;
|
| - }
|
| -
|
| - @Override
|
| - public synchronized void onTextureFrameAvailable(
|
| - int oesTextureId, float[] transformMatrix, long timestampNs) {
|
| - if (expectedThread != null && Thread.currentThread() != expectedThread) {
|
| - throw new IllegalStateException("onTextureFrameAvailable called on wrong thread.");
|
| - }
|
| - this.oesTextureId = oesTextureId;
|
| - this.transformMatrix = transformMatrix;
|
| - hasNewFrame = true;
|
| - notifyAll();
|
| - }
|
| -
|
| - /**
|
| - * Wait indefinitely for a new frame.
|
| - */
|
| - public synchronized void waitForNewFrame() throws InterruptedException {
|
| - while (!hasNewFrame) {
|
| - wait();
|
| - }
|
| - hasNewFrame = false;
|
| - }
|
| -
|
| - /**
|
| - * Wait for a new frame, or until the specified timeout elapses. Returns true if a new frame was
|
| - * received before the timeout.
|
| - */
|
| - public synchronized boolean waitForNewFrame(final long timeoutMs) throws InterruptedException {
|
| - final long startTimeMs = SystemClock.elapsedRealtime();
|
| - long timeRemainingMs = timeoutMs;
|
| - while (!hasNewFrame && timeRemainingMs > 0) {
|
| - wait(timeRemainingMs);
|
| - final long elapsedTimeMs = SystemClock.elapsedRealtime() - startTimeMs;
|
| - timeRemainingMs = timeoutMs - elapsedTimeMs;
|
| - }
|
| - final boolean didReceiveFrame = hasNewFrame;
|
| - hasNewFrame = false;
|
| - return didReceiveFrame;
|
| - }
|
| - }
|
| -
|
| - /** Assert that two integers are close, with difference at most
|
| - * {@code threshold}. */
|
| - public static void assertClose(int threshold, int expected, int actual) {
|
| - if (Math.abs(expected - actual) <= threshold)
|
| - return;
|
| - failNotEquals("Not close enough, threshold " + threshold, expected, actual);
|
| - }
|
| -
|
| - /**
|
| - * Test normal use by receiving three uniform texture frames. Texture frames are returned as early
|
| - * as possible. The texture pixel values are inspected by drawing the texture frame to a pixel
|
| - * buffer and reading it back with glReadPixels().
|
| - */
|
| - @MediumTest
|
| - public static void testThreeConstantColorFrames() throws InterruptedException {
|
| - final int width = 16;
|
| - final int height = 16;
|
| - // Create EGL base with a pixel buffer as display output.
|
| - final EglBase eglBase = EglBase.create(null, EglBase.CONFIG_PIXEL_BUFFER);
|
| - eglBase.createPbufferSurface(width, height);
|
| - final GlRectDrawer drawer = new GlRectDrawer();
|
| -
|
| - // Create SurfaceTextureHelper and listener.
|
| - final SurfaceTextureHelper surfaceTextureHelper =
|
| - SurfaceTextureHelper.create(eglBase.getEglBaseContext());
|
| - final MockTextureListener listener = new MockTextureListener();
|
| - surfaceTextureHelper.setListener(listener);
|
| - surfaceTextureHelper.getSurfaceTexture().setDefaultBufferSize(width, height);
|
| -
|
| - // Create resources for stubbing an OES texture producer. |eglOesBase| has the SurfaceTexture in
|
| - // |surfaceTextureHelper| as the target EGLSurface.
|
| - final EglBase eglOesBase =
|
| - EglBase.create(eglBase.getEglBaseContext(), EglBase.CONFIG_PLAIN);
|
| - eglOesBase.createSurface(surfaceTextureHelper.getSurfaceTexture());
|
| - assertEquals(eglOesBase.surfaceWidth(), width);
|
| - assertEquals(eglOesBase.surfaceHeight(), height);
|
| -
|
| - final int red[] = new int[] {79, 144, 185};
|
| - final int green[] = new int[] {66, 210, 162};
|
| - final int blue[] = new int[] {161, 117, 158};
|
| - // Draw three frames.
|
| - for (int i = 0; i < 3; ++i) {
|
| - // Draw a constant color frame onto the SurfaceTexture.
|
| - eglOesBase.makeCurrent();
|
| - GLES20.glClearColor(red[i] / 255.0f, green[i] / 255.0f, blue[i] / 255.0f, 1.0f);
|
| - GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
|
| - // swapBuffers() will ultimately trigger onTextureFrameAvailable().
|
| - eglOesBase.swapBuffers();
|
| -
|
| - // Wait for an OES texture to arrive and draw it onto the pixel buffer.
|
| - listener.waitForNewFrame();
|
| - eglBase.makeCurrent();
|
| - drawer.drawOes(listener.oesTextureId, listener.transformMatrix, 0, 0, width, height);
|
| -
|
| - surfaceTextureHelper.returnTextureFrame();
|
| -
|
| - // Download the pixels in the pixel buffer as RGBA. Not all platforms support RGB, e.g.
|
| - // Nexus 9.
|
| - final ByteBuffer rgbaData = ByteBuffer.allocateDirect(width * height * 4);
|
| - GLES20.glReadPixels(0, 0, width, height, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, rgbaData);
|
| - GlUtil.checkNoGLES2Error("glReadPixels");
|
| -
|
| - // Assert rendered image is expected constant color.
|
| - while (rgbaData.hasRemaining()) {
|
| - assertEquals(rgbaData.get() & 0xFF, red[i]);
|
| - assertEquals(rgbaData.get() & 0xFF, green[i]);
|
| - assertEquals(rgbaData.get() & 0xFF, blue[i]);
|
| - assertEquals(rgbaData.get() & 0xFF, 255);
|
| - }
|
| - }
|
| -
|
| - drawer.release();
|
| - surfaceTextureHelper.disconnect();
|
| - eglBase.release();
|
| - }
|
| -
|
| - /**
|
| - * Test disconnecting the SurfaceTextureHelper while holding a pending texture frame. The pending
|
| - * texture frame should still be valid, and this is tested by drawing the texture frame to a pixel
|
| - * buffer and reading it back with glReadPixels().
|
| - */
|
| - @MediumTest
|
| - public static void testLateReturnFrame() throws InterruptedException {
|
| - final int width = 16;
|
| - final int height = 16;
|
| - // Create EGL base with a pixel buffer as display output.
|
| - final EglBase eglBase = EglBase.create(null, EglBase.CONFIG_PIXEL_BUFFER);
|
| - eglBase.createPbufferSurface(width, height);
|
| -
|
| - // Create SurfaceTextureHelper and listener.
|
| - final SurfaceTextureHelper surfaceTextureHelper =
|
| - SurfaceTextureHelper.create(eglBase.getEglBaseContext());
|
| - final MockTextureListener listener = new MockTextureListener();
|
| - surfaceTextureHelper.setListener(listener);
|
| - surfaceTextureHelper.getSurfaceTexture().setDefaultBufferSize(width, height);
|
| -
|
| - // Create resources for stubbing an OES texture producer. |eglOesBase| has the SurfaceTexture in
|
| - // |surfaceTextureHelper| as the target EGLSurface.
|
| - final EglBase eglOesBase =
|
| - EglBase.create(eglBase.getEglBaseContext(), EglBase.CONFIG_PLAIN);
|
| - eglOesBase.createSurface(surfaceTextureHelper.getSurfaceTexture());
|
| - assertEquals(eglOesBase.surfaceWidth(), width);
|
| - assertEquals(eglOesBase.surfaceHeight(), height);
|
| -
|
| - final int red = 79;
|
| - final int green = 66;
|
| - final int blue = 161;
|
| - // Draw a constant color frame onto the SurfaceTexture.
|
| - eglOesBase.makeCurrent();
|
| - GLES20.glClearColor(red / 255.0f, green / 255.0f, blue / 255.0f, 1.0f);
|
| - GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
|
| - // swapBuffers() will ultimately trigger onTextureFrameAvailable().
|
| - eglOesBase.swapBuffers();
|
| - eglOesBase.release();
|
| -
|
| - // Wait for OES texture frame.
|
| - listener.waitForNewFrame();
|
| - // Diconnect while holding the frame.
|
| - surfaceTextureHelper.disconnect();
|
| -
|
| - // Draw the pending texture frame onto the pixel buffer.
|
| - eglBase.makeCurrent();
|
| - final GlRectDrawer drawer = new GlRectDrawer();
|
| - drawer.drawOes(listener.oesTextureId, listener.transformMatrix, 0, 0, width, height);
|
| - drawer.release();
|
| -
|
| - // Download the pixels in the pixel buffer as RGBA. Not all platforms support RGB, e.g. Nexus 9.
|
| - final ByteBuffer rgbaData = ByteBuffer.allocateDirect(width * height * 4);
|
| - GLES20.glReadPixels(0, 0, width, height, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, rgbaData);
|
| - GlUtil.checkNoGLES2Error("glReadPixels");
|
| - eglBase.release();
|
| -
|
| - // Assert rendered image is expected constant color.
|
| - while (rgbaData.hasRemaining()) {
|
| - assertEquals(rgbaData.get() & 0xFF, red);
|
| - assertEquals(rgbaData.get() & 0xFF, green);
|
| - assertEquals(rgbaData.get() & 0xFF, blue);
|
| - assertEquals(rgbaData.get() & 0xFF, 255);
|
| - }
|
| - // Late frame return after everything has been disconnected and released.
|
| - surfaceTextureHelper.returnTextureFrame();
|
| - }
|
| -
|
| - /**
|
| - * Test disconnecting the SurfaceTextureHelper, but keep trying to produce more texture frames. No
|
| - * frames should be delivered to the listener.
|
| - */
|
| - @MediumTest
|
| - public static void testDisconnect() throws InterruptedException {
|
| - // Create SurfaceTextureHelper and listener.
|
| - final SurfaceTextureHelper surfaceTextureHelper =
|
| - SurfaceTextureHelper.create(null);
|
| - final MockTextureListener listener = new MockTextureListener();
|
| - surfaceTextureHelper.setListener(listener);
|
| - // Create EglBase with the SurfaceTexture as target EGLSurface.
|
| - final EglBase eglBase = EglBase.create(null, EglBase.CONFIG_PLAIN);
|
| - eglBase.createSurface(surfaceTextureHelper.getSurfaceTexture());
|
| - eglBase.makeCurrent();
|
| - // Assert no frame has been received yet.
|
| - assertFalse(listener.waitForNewFrame(1));
|
| - // Draw and wait for one frame.
|
| - GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
|
| - // swapBuffers() will ultimately trigger onTextureFrameAvailable().
|
| - eglBase.swapBuffers();
|
| - listener.waitForNewFrame();
|
| - surfaceTextureHelper.returnTextureFrame();
|
| -
|
| - // Disconnect - we should not receive any textures after this.
|
| - surfaceTextureHelper.disconnect();
|
| -
|
| - // Draw one frame.
|
| - GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
|
| - eglBase.swapBuffers();
|
| - // swapBuffers() should not trigger onTextureFrameAvailable() because we are disconnected.
|
| - // Assert that no OES texture was delivered.
|
| - assertFalse(listener.waitForNewFrame(500));
|
| -
|
| - eglBase.release();
|
| - }
|
| -
|
| - /**
|
| - * Test disconnecting the SurfaceTextureHelper immediately after is has been setup to use a
|
| - * shared context. No frames should be delivered to the listener.
|
| - */
|
| - @SmallTest
|
| - public static void testDisconnectImmediately() {
|
| - final SurfaceTextureHelper surfaceTextureHelper =
|
| - SurfaceTextureHelper.create(null);
|
| - surfaceTextureHelper.disconnect();
|
| - }
|
| -
|
| - /**
|
| - * Test use SurfaceTextureHelper on a separate thread. A uniform texture frame is created and
|
| - * received on a thread separate from the test thread.
|
| - */
|
| - @MediumTest
|
| - public static void testFrameOnSeparateThread() throws InterruptedException {
|
| - final HandlerThread thread = new HandlerThread("SurfaceTextureHelperTestThread");
|
| - thread.start();
|
| - final Handler handler = new Handler(thread.getLooper());
|
| -
|
| - // Create SurfaceTextureHelper and listener.
|
| - final SurfaceTextureHelper surfaceTextureHelper =
|
| - SurfaceTextureHelper.create(null, handler);
|
| - // Create a mock listener and expect frames to be delivered on |thread|.
|
| - final MockTextureListener listener = new MockTextureListener(thread);
|
| - surfaceTextureHelper.setListener(listener);
|
| -
|
| - // Create resources for stubbing an OES texture producer. |eglOesBase| has the
|
| - // SurfaceTexture in |surfaceTextureHelper| as the target EGLSurface.
|
| - final EglBase eglOesBase = EglBase.create(null, EglBase.CONFIG_PLAIN);
|
| - eglOesBase.createSurface(surfaceTextureHelper.getSurfaceTexture());
|
| - eglOesBase.makeCurrent();
|
| - // Draw a frame onto the SurfaceTexture.
|
| - GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
|
| - // swapBuffers() will ultimately trigger onTextureFrameAvailable().
|
| - eglOesBase.swapBuffers();
|
| - eglOesBase.release();
|
| -
|
| - // Wait for an OES texture to arrive.
|
| - listener.waitForNewFrame();
|
| -
|
| - // Return the frame from this thread.
|
| - surfaceTextureHelper.returnTextureFrame();
|
| - surfaceTextureHelper.disconnect(handler);
|
| - }
|
| -
|
| - /**
|
| - * Test use SurfaceTextureHelper on a separate thread. A uniform texture frame is created and
|
| - * received on a thread separate from the test thread and returned after disconnect.
|
| - */
|
| - @MediumTest
|
| - public static void testLateReturnFrameOnSeparateThread() throws InterruptedException {
|
| - final HandlerThread thread = new HandlerThread("SurfaceTextureHelperTestThread");
|
| - thread.start();
|
| - final Handler handler = new Handler(thread.getLooper());
|
| -
|
| - // Create SurfaceTextureHelper and listener.
|
| - final SurfaceTextureHelper surfaceTextureHelper =
|
| - SurfaceTextureHelper.create(null, handler);
|
| - // Create a mock listener and expect frames to be delivered on |thread|.
|
| - final MockTextureListener listener = new MockTextureListener(thread);
|
| - surfaceTextureHelper.setListener(listener);
|
| -
|
| - // Create resources for stubbing an OES texture producer. |eglOesBase| has the
|
| - // SurfaceTexture in |surfaceTextureHelper| as the target EGLSurface.
|
| - final EglBase eglOesBase = EglBase.create(null, EglBase.CONFIG_PLAIN);
|
| - eglOesBase.createSurface(surfaceTextureHelper.getSurfaceTexture());
|
| - eglOesBase.makeCurrent();
|
| - // Draw a frame onto the SurfaceTexture.
|
| - GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
|
| - // swapBuffers() will ultimately trigger onTextureFrameAvailable().
|
| - eglOesBase.swapBuffers();
|
| - eglOesBase.release();
|
| -
|
| - // Wait for an OES texture to arrive.
|
| - listener.waitForNewFrame();
|
| -
|
| - surfaceTextureHelper.disconnect(handler);
|
| -
|
| - surfaceTextureHelper.returnTextureFrame();
|
| - }
|
| -
|
| - @MediumTest
|
| - public static void testTexturetoYUV() throws InterruptedException {
|
| - final int width = 16;
|
| - final int height = 16;
|
| -
|
| - final EglBase eglBase = EglBase.create(null, EglBase.CONFIG_PLAIN);
|
| -
|
| - // Create SurfaceTextureHelper and listener.
|
| - final SurfaceTextureHelper surfaceTextureHelper =
|
| - SurfaceTextureHelper.create(eglBase.getEglBaseContext());
|
| - final MockTextureListener listener = new MockTextureListener();
|
| - surfaceTextureHelper.setListener(listener);
|
| - surfaceTextureHelper.getSurfaceTexture().setDefaultBufferSize(width, height);
|
| -
|
| - // Create resources for stubbing an OES texture producer. |eglBase| has the SurfaceTexture in
|
| - // |surfaceTextureHelper| as the target EGLSurface.
|
| -
|
| - eglBase.createSurface(surfaceTextureHelper.getSurfaceTexture());
|
| - assertEquals(eglBase.surfaceWidth(), width);
|
| - assertEquals(eglBase.surfaceHeight(), height);
|
| -
|
| - final int red[] = new int[] {79, 144, 185};
|
| - final int green[] = new int[] {66, 210, 162};
|
| - final int blue[] = new int[] {161, 117, 158};
|
| -
|
| - final int ref_y[] = new int[] {81, 180, 168};
|
| - final int ref_u[] = new int[] {173, 93, 122};
|
| - final int ref_v[] = new int[] {127, 103, 140};
|
| -
|
| - // Draw three frames.
|
| - for (int i = 0; i < 3; ++i) {
|
| - // Draw a constant color frame onto the SurfaceTexture.
|
| - eglBase.makeCurrent();
|
| - GLES20.glClearColor(red[i] / 255.0f, green[i] / 255.0f, blue[i] / 255.0f, 1.0f);
|
| - GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
|
| - // swapBuffers() will ultimately trigger onTextureFrameAvailable().
|
| - eglBase.swapBuffers();
|
| -
|
| - // Wait for an OES texture to arrive.
|
| - listener.waitForNewFrame();
|
| -
|
| - // Memory layout: Lines are 16 bytes. First 16 lines are
|
| - // the Y data. These are followed by 8 lines with 8 bytes of U
|
| - // data on the left and 8 bytes of V data on the right.
|
| - //
|
| - // Offset
|
| - // 0 YYYYYYYY YYYYYYYY
|
| - // 16 YYYYYYYY YYYYYYYY
|
| - // ...
|
| - // 240 YYYYYYYY YYYYYYYY
|
| - // 256 UUUUUUUU VVVVVVVV
|
| - // 272 UUUUUUUU VVVVVVVV
|
| - // ...
|
| - // 368 UUUUUUUU VVVVVVVV
|
| - // 384 buffer end
|
| - ByteBuffer buffer = ByteBuffer.allocateDirect(width * height * 3 / 2);
|
| - surfaceTextureHelper.textureToYUV(buffer, width, height, width,
|
| - listener.oesTextureId, listener.transformMatrix);
|
| -
|
| - surfaceTextureHelper.returnTextureFrame();
|
| -
|
| - // Allow off-by-one differences due to different rounding.
|
| - while (buffer.position() < width*height) {
|
| - assertClose(1, buffer.get() & 0xff, ref_y[i]);
|
| - }
|
| - while (buffer.hasRemaining()) {
|
| - if (buffer.position() % width < width/2)
|
| - assertClose(1, buffer.get() & 0xff, ref_u[i]);
|
| - else
|
| - assertClose(1, buffer.get() & 0xff, ref_v[i]);
|
| - }
|
| - }
|
| -
|
| - surfaceTextureHelper.disconnect();
|
| - eglBase.release();
|
| - }
|
| -}
|
|
|