Android: Update tests to use new SurfaceTextureHelper interface

Bug: webrtc:9412
Change-Id: I17d2f2cb4e1271d07958c6b7f2db47960e4b39ee
Reviewed-on: https://webrtc-review.googlesource.com/87260
Reviewed-by: Sami Kalliomäki <sakal@webrtc.org>
Commit-Queue: Magnus Jedvert <magjed@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#23877}
This commit is contained in:
Magnus Jedvert
2018-07-06 11:23:37 +02:00
committed by Commit Bot
parent 5e898d612e
commit bf7463b88f
3 changed files with 68 additions and 77 deletions

View File

@ -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();

View File

@ -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();

View File

@ -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();