From bf7463b88f7b880a9c9ca33f637e1abc32437f7e Mon Sep 17 00:00:00 2001 From: Magnus Jedvert Date: Fri, 6 Jul 2018 11:23:37 +0200 Subject: [PATCH] Android: Update tests to use new SurfaceTextureHelper interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: webrtc:9412 Change-Id: I17d2f2cb4e1271d07958c6b7f2db47960e4b39ee Reviewed-on: https://webrtc-review.googlesource.com/87260 Reviewed-by: Sami Kalliomäki Commit-Queue: Magnus Jedvert Cr-Commit-Position: refs/heads/master@{#23877} --- .../src/org/webrtc/GlRectDrawerTest.java | 9 +- .../org/webrtc/SurfaceTextureHelperTest.java | 131 ++++++++---------- .../src/org/webrtc/VideoFrameBufferTest.java | 5 +- 3 files changed, 68 insertions(+), 77 deletions(-) diff --git a/sdk/android/instrumentationtests/src/org/webrtc/GlRectDrawerTest.java b/sdk/android/instrumentationtests/src/org/webrtc/GlRectDrawerTest.java index 02be56861a..fecddb34fe 100644 --- a/sdk/android/instrumentationtests/src/org/webrtc/GlRectDrawerTest.java +++ b/sdk/android/instrumentationtests/src/org/webrtc/GlRectDrawerTest.java @@ -293,14 +293,15 @@ public class GlRectDrawerTest { // Draw the frame and block until an OES texture is delivered. oesProducer.draw(rgbPlane); - listener.waitForNewFrame(); + final VideoFrame.TextureBuffer textureBuffer = listener.waitForTextureBuffer(); // Real test starts here. // Draw the OES texture on the pixel buffer. eglBase.makeCurrent(); final GlRectDrawer drawer = new GlRectDrawer(); - drawer.drawOes(listener.oesTextureId, listener.transformMatrix, WIDTH, HEIGHT, - 0 /* viewportX */, 0 /* viewportY */, WIDTH, HEIGHT); + drawer.drawOes(textureBuffer.getTextureId(), + RendererCommon.convertMatrixFromAndroidGraphicsMatrix(textureBuffer.getTransformMatrix()), + WIDTH, HEIGHT, 0 /* viewportX */, 0 /* viewportY */, WIDTH, HEIGHT); // 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); @@ -311,7 +312,7 @@ public class GlRectDrawerTest { assertByteBufferEquals(WIDTH, HEIGHT, stripAlphaChannel(rgbaData), rgbPlane); drawer.release(); - surfaceTextureHelper.returnTextureFrame(); + textureBuffer.release(); oesProducer.release(); surfaceTextureHelper.dispose(); eglBase.release(); diff --git a/sdk/android/instrumentationtests/src/org/webrtc/SurfaceTextureHelperTest.java b/sdk/android/instrumentationtests/src/org/webrtc/SurfaceTextureHelperTest.java index 40bdb21db2..3cd08cc8b6 100644 --- a/sdk/android/instrumentationtests/src/org/webrtc/SurfaceTextureHelperTest.java +++ b/sdk/android/instrumentationtests/src/org/webrtc/SurfaceTextureHelperTest.java @@ -12,6 +12,7 @@ package org.webrtc; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import android.graphics.SurfaceTexture; @@ -32,11 +33,9 @@ public class SurfaceTextureHelperTest { /** * 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; + public static final class MockTextureListener implements VideoSink { + private final Object lock = new Object(); + private @Nullable VideoFrame.TextureBuffer textureBuffer; // Thread where frames are expected to be received on. private final @Nullable Thread expectedThread; @@ -49,48 +48,43 @@ public class SurfaceTextureHelperTest { } @Override - // TODO(bugs.webrtc.org/8491): Remove NoSynchronizedMethodCheck suppression. - @SuppressWarnings("NoSynchronizedMethodCheck") - public synchronized void onTextureFrameAvailable( - int oesTextureId, float[] transformMatrix, long timestampNs) { + public void onFrame(VideoFrame frame) { 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. - */ - // TODO(bugs.webrtc.org/8491): Remove NoSynchronizedMethodCheck suppression. - @SuppressWarnings("NoSynchronizedMethodCheck") - public synchronized void waitForNewFrame() throws InterruptedException { - while (!hasNewFrame) { - wait(); + synchronized (lock) { + this.textureBuffer = (VideoFrame.TextureBuffer) frame.getBuffer(); + textureBuffer.retain(); + lock.notifyAll(); } - hasNewFrame = false; } - /** - * Wait for a new frame, or until the specified timeout elapses. Returns true if a new frame was - * received before the timeout. - */ - // TODO(bugs.webrtc.org/8491): Remove NoSynchronizedMethodCheck suppression. - @SuppressWarnings("NoSynchronizedMethodCheck") - public synchronized boolean waitForNewFrame(final long timeoutMs) throws InterruptedException { + /** Wait indefinitely for a new textureBuffer. */ + public VideoFrame.TextureBuffer waitForTextureBuffer() throws InterruptedException { + synchronized (lock) { + while (true) { + final VideoFrame.TextureBuffer textureBufferToReturn = textureBuffer; + if (textureBufferToReturn != null) { + textureBuffer = null; + return textureBufferToReturn; + } + lock.wait(); + } + } + } + + /** Make sure we get no frame in the specified time period. */ + public void assertNoFrameIsDelivered(final long waitPeriodMs) 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; + long timeRemainingMs = waitPeriodMs; + synchronized (lock) { + while (textureBuffer == null && timeRemainingMs > 0) { + lock.wait(timeRemainingMs); + final long elapsedTimeMs = SystemClock.elapsedRealtime() - startTimeMs; + timeRemainingMs = waitPeriodMs - elapsedTimeMs; + } + assertTrue(textureBuffer == null); } - final boolean didReceiveFrame = hasNewFrame; - hasNewFrame = false; - return didReceiveFrame; } } @@ -151,12 +145,12 @@ public class SurfaceTextureHelperTest { eglOesBase.swapBuffers(); // Wait for an OES texture to arrive and draw it onto the pixel buffer. - listener.waitForNewFrame(); + final VideoFrame.TextureBuffer textureBuffer = listener.waitForTextureBuffer(); eglBase.makeCurrent(); - drawer.drawOes( - listener.oesTextureId, listener.transformMatrix, width, height, 0, 0, width, height); - - surfaceTextureHelper.returnTextureFrame(); + drawer.drawOes(textureBuffer.getTextureId(), + RendererCommon.convertMatrixFromAndroidGraphicsMatrix(textureBuffer.getTransformMatrix()), + width, height, 0, 0, width, height); + textureBuffer.release(); // Download the pixels in the pixel buffer as RGBA. Not all platforms support RGB, e.g. // Nexus 9. @@ -218,15 +212,16 @@ public class SurfaceTextureHelperTest { eglOesBase.release(); // Wait for OES texture frame. - listener.waitForNewFrame(); + final VideoFrame.TextureBuffer textureBuffer = listener.waitForTextureBuffer(); // Diconnect while holding the frame. surfaceTextureHelper.dispose(); // Draw the pending texture frame onto the pixel buffer. eglBase.makeCurrent(); final GlRectDrawer drawer = new GlRectDrawer(); - drawer.drawOes( - listener.oesTextureId, listener.transformMatrix, width, height, 0, 0, width, height); + drawer.drawOes(textureBuffer.getTextureId(), + RendererCommon.convertMatrixFromAndroidGraphicsMatrix(textureBuffer.getTransformMatrix()), + width, height, 0, 0, width, height); drawer.release(); // Download the pixels in the pixel buffer as RGBA. Not all platforms support RGB, e.g. Nexus 9. @@ -243,7 +238,7 @@ public class SurfaceTextureHelperTest { assertEquals(rgbaData.get() & 0xFF, 255); } // Late frame return after everything has been disposed and released. - surfaceTextureHelper.returnTextureFrame(); + textureBuffer.release(); } /** @@ -260,16 +255,16 @@ public class SurfaceTextureHelperTest { surfaceTextureHelper.startListening(listener); // Create EglBase with the SurfaceTexture as target EGLSurface. final EglBase eglBase = EglBase.create(null, EglBase.CONFIG_PLAIN); + surfaceTextureHelper.setTextureSize(/* textureWidth= */ 32, /* textureHeight= */ 32); eglBase.createSurface(surfaceTextureHelper.getSurfaceTexture()); eglBase.makeCurrent(); // Assert no frame has been received yet. - assertFalse(listener.waitForNewFrame(1)); + listener.assertNoFrameIsDelivered(/* waitPeriodMs= */ 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(); + listener.waitForTextureBuffer().release(); // Dispose - we should not receive any textures after this. surfaceTextureHelper.dispose(); @@ -279,7 +274,7 @@ public class SurfaceTextureHelperTest { eglBase.swapBuffers(); // swapBuffers() should not trigger onTextureFrameAvailable() because disposed has been called. // Assert that no OES texture was delivered. - assertFalse(listener.waitForNewFrame(500)); + listener.assertNoFrameIsDelivered(/* waitPeriodMs= */ 500); eglBase.release(); } @@ -306,6 +301,7 @@ public class SurfaceTextureHelperTest { // Create SurfaceTextureHelper and listener. final SurfaceTextureHelper surfaceTextureHelper = SurfaceTextureHelper.create("SurfaceTextureHelper test" /* threadName */, null); + surfaceTextureHelper.setTextureSize(/* textureWidth= */ 32, /* textureHeight= */ 32); final MockTextureListener listener = new MockTextureListener(); surfaceTextureHelper.startListening(listener); // Create EglBase with the SurfaceTexture as target EGLSurface. @@ -313,13 +309,12 @@ public class SurfaceTextureHelperTest { eglBase.createSurface(surfaceTextureHelper.getSurfaceTexture()); eglBase.makeCurrent(); // Assert no frame has been received yet. - assertFalse(listener.waitForNewFrame(1)); + listener.assertNoFrameIsDelivered(/* waitPeriodMs= */ 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(); + listener.waitForTextureBuffer().release(); // Stop listening - we should not receive any textures after this. surfaceTextureHelper.stopListening(); @@ -329,7 +324,7 @@ public class SurfaceTextureHelperTest { eglBase.swapBuffers(); // swapBuffers() should not trigger onTextureFrameAvailable() because disposed has been called. // Assert that no OES texture was delivered. - assertFalse(listener.waitForNewFrame(500)); + listener.assertNoFrameIsDelivered(/* waitPeriodMs= */ 500); surfaceTextureHelper.dispose(); eglBase.release(); @@ -402,6 +397,7 @@ public class SurfaceTextureHelperTest { // Create SurfaceTextureHelper and listener. final SurfaceTextureHelper surfaceTextureHelper = SurfaceTextureHelper.create("SurfaceTextureHelper test" /* threadName */, null); + surfaceTextureHelper.setTextureSize(/* textureWidth= */ 32, /* textureHeight= */ 32); final MockTextureListener listener1 = new MockTextureListener(); surfaceTextureHelper.startListening(listener1); // Create EglBase with the SurfaceTexture as target EGLSurface. @@ -409,13 +405,12 @@ public class SurfaceTextureHelperTest { eglBase.createSurface(surfaceTextureHelper.getSurfaceTexture()); eglBase.makeCurrent(); // Assert no frame has been received yet. - assertFalse(listener1.waitForNewFrame(1)); + listener1.assertNoFrameIsDelivered(/* waitPeriodMs= */ 1); // Draw and wait for one frame. GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); // swapBuffers() will ultimately trigger onTextureFrameAvailable(). eglBase.swapBuffers(); - listener1.waitForNewFrame(); - surfaceTextureHelper.returnTextureFrame(); + listener1.waitForTextureBuffer().release(); // Stop listening - |listener1| should not receive any textures after this. surfaceTextureHelper.stopListening(); @@ -424,17 +419,15 @@ public class SurfaceTextureHelperTest { final MockTextureListener listener2 = new MockTextureListener(); surfaceTextureHelper.startListening(listener2); // Assert no frame has been received yet. - assertFalse(listener2.waitForNewFrame(1)); + listener2.assertNoFrameIsDelivered(/* waitPeriodMs= */ 1); // Draw one frame. GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); eglBase.swapBuffers(); // Check that |listener2| received the frame, and not |listener1|. - listener2.waitForNewFrame(); - assertFalse(listener1.waitForNewFrame(1)); - - surfaceTextureHelper.returnTextureFrame(); + listener2.waitForTextureBuffer().release(); + listener1.assertNoFrameIsDelivered(/* waitPeriodMs= */ 1); surfaceTextureHelper.dispose(); eglBase.release(); @@ -480,7 +473,9 @@ public class SurfaceTextureHelperTest { eglBase.swapBuffers(); // Wait for an OES texture to arrive. - listener.waitForNewFrame(); + final VideoFrame.TextureBuffer textureBuffer = listener.waitForTextureBuffer(); + final VideoFrame.I420Buffer i420 = textureBuffer.toI420(); + textureBuffer.release(); // Memory layout: Lines are 16 bytes. First 16 lines are // the Y data. These are followed by 8 lines with 8 bytes of U @@ -496,11 +491,6 @@ public class SurfaceTextureHelperTest { // ... // 368 UUUUUUUU VVVVVVVV // 384 buffer end - final VideoFrame.I420Buffer i420 = - surfaceTextureHelper.textureToYuv(surfaceTextureHelper.createTextureBuffer(width, height, - RendererCommon.convertMatrixToAndroidGraphicsMatrix(listener.transformMatrix))); - - surfaceTextureHelper.returnTextureFrame(); // Allow off-by-one differences due to different rounding. final ByteBuffer dataY = i420.getDataY(); @@ -524,6 +514,7 @@ public class SurfaceTextureHelperTest { assertClose(1, ref_v[i], dataV.get(y * strideV + x) & 0xFF); } } + i420.release(); } surfaceTextureHelper.dispose(); diff --git a/sdk/android/instrumentationtests/src/org/webrtc/VideoFrameBufferTest.java b/sdk/android/instrumentationtests/src/org/webrtc/VideoFrameBufferTest.java index c36570eae3..539ba3ddf5 100644 --- a/sdk/android/instrumentationtests/src/org/webrtc/VideoFrameBufferTest.java +++ b/sdk/android/instrumentationtests/src/org/webrtc/VideoFrameBufferTest.java @@ -202,12 +202,11 @@ public class VideoFrameBufferTest { // Draw the frame and block until an OES texture is delivered. drawI420Buffer(i420Buffer); eglBase.swapBuffers(); - listener.waitForNewFrame(); + final VideoFrame.TextureBuffer textureBuffer = listener.waitForTextureBuffer(); surfaceTextureHelper.stopListening(); surfaceTextureHelper.dispose(); - return surfaceTextureHelper.createTextureBuffer(width, height, - RendererCommon.convertMatrixToAndroidGraphicsMatrix(listener.transformMatrix)); + return textureBuffer; }); renderThread.quit();