diff options
Diffstat (limited to 'talk/app/webrtc/androidtests/src/org/webrtc/VideoCapturerAndroidTestFixtures.java')
-rw-r--r-- | talk/app/webrtc/androidtests/src/org/webrtc/VideoCapturerAndroidTestFixtures.java | 214 |
1 files changed, 193 insertions, 21 deletions
diff --git a/talk/app/webrtc/androidtests/src/org/webrtc/VideoCapturerAndroidTestFixtures.java b/talk/app/webrtc/androidtests/src/org/webrtc/VideoCapturerAndroidTestFixtures.java index 11b3ce98a0..0b42e33785 100644 --- a/talk/app/webrtc/androidtests/src/org/webrtc/VideoCapturerAndroidTestFixtures.java +++ b/talk/app/webrtc/androidtests/src/org/webrtc/VideoCapturerAndroidTestFixtures.java @@ -29,6 +29,7 @@ package org.webrtc; import android.content.Context; import android.hardware.Camera; +import org.webrtc.VideoCapturerAndroidTestFixtures; import org.webrtc.CameraEnumerationAndroid.CaptureFormat; import org.webrtc.VideoRenderer.I420Frame; @@ -42,16 +43,32 @@ public class VideoCapturerAndroidTestFixtures { static class RendererCallbacks implements VideoRenderer.Callbacks { private int framesRendered = 0; private Object frameLock = 0; + private int width = 0; + private int height = 0; @Override public void renderFrame(I420Frame frame) { synchronized (frameLock) { ++framesRendered; + width = frame.rotatedWidth(); + height = frame.rotatedHeight(); frameLock.notify(); } VideoRenderer.renderFrameDone(frame); } + public int frameWidth() { + synchronized (frameLock) { + return width; + } + } + + public int frameHeight() { + synchronized (frameLock) { + return height; + } + } + public int WaitForNextFrameToRender() throws InterruptedException { synchronized (frameLock) { frameLock.wait(); @@ -102,11 +119,11 @@ public class VideoCapturerAndroidTestFixtures { } @Override - public void onByteBufferFrameCaptured(byte[] frame, int length, int width, int height, - int rotation, long timeStamp) { + public void onByteBufferFrameCaptured(byte[] frame, int width, int height, int rotation, + long timeStamp) { synchronized (frameLock) { ++framesCaptured; - frameSize = length; + frameSize = frame.length; frameWidth = width; frameHeight = height; timestamps.add(timeStamp); @@ -115,7 +132,8 @@ public class VideoCapturerAndroidTestFixtures { } @Override public void onTextureFrameCaptured( - int width, int height, int oesTextureId, float[] transformMatrix, long timeStamp) { + int width, int height, int oesTextureId, float[] transformMatrix, int rotation, + long timeStamp) { synchronized (frameLock) { ++framesCaptured; frameWidth = width; @@ -174,9 +192,20 @@ public class VideoCapturerAndroidTestFixtures { VideoCapturerAndroid.CameraEventsHandler { public boolean onCameraOpeningCalled; public boolean onFirstFrameAvailableCalled; + public final Object onCameraFreezedLock = new Object(); + private String onCameraFreezedDescription; @Override - public void onCameraError(String errorDescription) { } + public void onCameraError(String errorDescription) { + } + + @Override + public void onCameraFreezed(String errorDescription) { + synchronized (onCameraFreezedLock) { + onCameraFreezedDescription = errorDescription; + onCameraFreezedLock.notifyAll(); + } + } @Override public void onCameraOpening(int cameraId) { @@ -190,6 +219,13 @@ public class VideoCapturerAndroidTestFixtures { @Override public void onCameraClosed() { } + + public String WaitForCameraFreezed() throws InterruptedException { + synchronized (onCameraFreezedLock) { + onCameraFreezedLock.wait(); + return onCameraFreezedDescription; + } + } } static public CameraEvents createCameraEvents() { @@ -275,8 +311,8 @@ public class VideoCapturerAndroidTestFixtures { assertTrue(observer.WaitForCapturerToStart()); observer.WaitForNextCapturedFrame(); capturer.stopCapture(); - for (long timeStamp : observer.getCopyAndResetListOftimeStamps()) { - capturer.returnBuffer(timeStamp); + if (capturer.isCapturingToTexture()) { + capturer.surfaceHelper.returnTextureFrame(); } capturer.dispose(); @@ -296,9 +332,10 @@ public class VideoCapturerAndroidTestFixtures { // Make sure camera is started and then stop it. assertTrue(observer.WaitForCapturerToStart()); capturer.stopCapture(); - for (long timeStamp : observer.getCopyAndResetListOftimeStamps()) { - capturer.returnBuffer(timeStamp); + if (capturer.isCapturingToTexture()) { + capturer.surfaceHelper.returnTextureFrame(); } + // We can't change |capturer| at this point, but we should not crash. capturer.switchCamera(null); capturer.onOutputFormatRequest(640, 480, 15); @@ -357,17 +394,90 @@ public class VideoCapturerAndroidTestFixtures { if (capturer.isCapturingToTexture()) { assertEquals(0, observer.frameSize()); } else { - assertEquals(format.frameSize(), observer.frameSize()); + assertTrue(format.frameSize() <= observer.frameSize()); } capturer.stopCapture(); - for (long timestamp : observer.getCopyAndResetListOftimeStamps()) { - capturer.returnBuffer(timestamp); + if (capturer.isCapturingToTexture()) { + capturer.surfaceHelper.returnTextureFrame(); } } capturer.dispose(); assertTrue(capturer.isReleased()); } + static void waitUntilIdle(VideoCapturerAndroid capturer) throws InterruptedException { + final CountDownLatch barrier = new CountDownLatch(1); + capturer.getCameraThreadHandler().post(new Runnable() { + @Override public void run() { + barrier.countDown(); + } + }); + barrier.await(); + } + + static public void startWhileCameraIsAlreadyOpen( + VideoCapturerAndroid capturer, Context appContext) throws InterruptedException { + Camera camera = Camera.open(capturer.getCurrentCameraId()); + + final List<CaptureFormat> formats = capturer.getSupportedFormats(); + final CameraEnumerationAndroid.CaptureFormat format = formats.get(0); + + final FakeCapturerObserver observer = new FakeCapturerObserver(); + capturer.startCapture(format.width, format.height, format.maxFramerate, + appContext, observer); + + if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.LOLLIPOP_MR1) { + // The first opened camera client will be evicted. + assertTrue(observer.WaitForCapturerToStart()); + capturer.stopCapture(); + } else { + assertFalse(observer.WaitForCapturerToStart()); + } + + capturer.dispose(); + camera.release(); + } + + static public void startWhileCameraIsAlreadyOpenAndCloseCamera( + VideoCapturerAndroid capturer, Context appContext) throws InterruptedException { + Camera camera = Camera.open(capturer.getCurrentCameraId()); + + final List<CaptureFormat> formats = capturer.getSupportedFormats(); + final CameraEnumerationAndroid.CaptureFormat format = formats.get(0); + + final FakeCapturerObserver observer = new FakeCapturerObserver(); + capturer.startCapture(format.width, format.height, format.maxFramerate, + appContext, observer); + waitUntilIdle(capturer); + + camera.release(); + + // Make sure camera is started and first frame is received and then stop it. + assertTrue(observer.WaitForCapturerToStart()); + observer.WaitForNextCapturedFrame(); + capturer.stopCapture(); + if (capturer.isCapturingToTexture()) { + capturer.surfaceHelper.returnTextureFrame(); + } + capturer.dispose(); + assertTrue(capturer.isReleased()); + } + + static public void startWhileCameraIsAlreadyOpenAndStop( + VideoCapturerAndroid capturer, Context appContext) throws InterruptedException { + Camera camera = Camera.open(capturer.getCurrentCameraId()); + final List<CaptureFormat> formats = capturer.getSupportedFormats(); + final CameraEnumerationAndroid.CaptureFormat format = formats.get(0); + + final FakeCapturerObserver observer = new FakeCapturerObserver(); + capturer.startCapture(format.width, format.height, format.maxFramerate, + appContext, observer); + capturer.stopCapture(); + capturer.dispose(); + assertTrue(capturer.isReleased()); + camera.release(); + } + static public void returnBufferLate(VideoCapturerAndroid capturer, Context appContext) throws InterruptedException { FakeCapturerObserver observer = new FakeCapturerObserver(); @@ -387,9 +497,8 @@ public class VideoCapturerAndroidTestFixtures { capturer.startCapture(format.width, format.height, format.maxFramerate, appContext, observer); observer.WaitForCapturerToStart(); - - for (Long timeStamp : listOftimestamps) { - capturer.returnBuffer(timeStamp); + if (capturer.isCapturingToTexture()) { + capturer.surfaceHelper.returnTextureFrame(); } observer.WaitForNextCapturedFrame(); @@ -397,9 +506,10 @@ public class VideoCapturerAndroidTestFixtures { listOftimestamps = observer.getCopyAndResetListOftimeStamps(); assertTrue(listOftimestamps.size() >= 1); - for (Long timeStamp : listOftimestamps) { - capturer.returnBuffer(timeStamp); + if (capturer.isCapturingToTexture()) { + capturer.surfaceHelper.returnTextureFrame(); } + capturer.dispose(); assertTrue(capturer.isReleased()); } @@ -410,6 +520,7 @@ public class VideoCapturerAndroidTestFixtures { final VideoSource source = factory.createVideoSource(capturer, new MediaConstraints()); final VideoTrack track = factory.createVideoTrack("dummy", source); final FakeAsyncRenderer renderer = new FakeAsyncRenderer(); + track.addRenderer(new VideoRenderer(renderer)); // Wait for at least one frame that has not been returned. assertFalse(renderer.waitForPendingFrames().isEmpty()); @@ -420,9 +531,7 @@ public class VideoCapturerAndroidTestFixtures { track.dispose(); source.dispose(); factory.dispose(); - - // The pending frames should keep the JNI parts and |capturer| alive. - assertFalse(capturer.isReleased()); + assertTrue(capturer.isReleased()); // Return the frame(s), on a different thread out of spite. final List<I420Frame> pendingFrames = renderer.waitForPendingFrames(); @@ -436,8 +545,71 @@ public class VideoCapturerAndroidTestFixtures { }); returnThread.start(); returnThread.join(); + } + + static public void cameraFreezedEventOnBufferStarvationUsingTextures( + VideoCapturerAndroid capturer, + CameraEvents events, Context appContext) throws InterruptedException { + assertTrue("Not capturing to textures.", capturer.isCapturingToTexture()); - // Check that frames have successfully returned. This will cause |capturer| to be released. + final List<CaptureFormat> formats = capturer.getSupportedFormats(); + final CameraEnumerationAndroid.CaptureFormat format = formats.get(0); + + final FakeCapturerObserver observer = new FakeCapturerObserver(); + capturer.startCapture(format.width, format.height, format.maxFramerate, + appContext, observer); + // Make sure camera is started. + assertTrue(observer.WaitForCapturerToStart()); + // Since we don't return the buffer, we should get a starvation message if we are + // capturing to a texture. + assertEquals("Camera failure. Client must return video buffers.", + events.WaitForCameraFreezed()); + + capturer.stopCapture(); + if (capturer.isCapturingToTexture()) { + capturer.surfaceHelper.returnTextureFrame(); + } + + capturer.dispose(); assertTrue(capturer.isReleased()); } + + static public void scaleCameraOutput(VideoCapturerAndroid capturer) throws InterruptedException { + PeerConnectionFactory factory = new PeerConnectionFactory(); + VideoSource source = + factory.createVideoSource(capturer, new MediaConstraints()); + VideoTrack track = factory.createVideoTrack("dummy", source); + RendererCallbacks renderer = new RendererCallbacks(); + track.addRenderer(new VideoRenderer(renderer)); + assertTrue(renderer.WaitForNextFrameToRender() > 0); + + final int startWidth = renderer.frameWidth(); + final int startHeight = renderer.frameHeight(); + final int frameRate = 30; + final int scaledWidth = startWidth / 2; + final int scaledHeight = startHeight / 2; + + // Request the captured frames to be scaled. + capturer.onOutputFormatRequest(scaledWidth, scaledHeight, frameRate); + + boolean gotExpectedResolution = false; + int numberOfInspectedFrames = 0; + + do { + renderer.WaitForNextFrameToRender(); + ++numberOfInspectedFrames; + + gotExpectedResolution = (renderer.frameWidth() == scaledWidth + && renderer.frameHeight() == scaledHeight); + } while (!gotExpectedResolution && numberOfInspectedFrames < 30); + + source.stop(); + track.dispose(); + source.dispose(); + factory.dispose(); + assertTrue(capturer.isReleased()); + + assertTrue(gotExpectedResolution); + } + } |