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

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

Issue 2024843002: Refactor VideoCapturerAndroid tests in WebRTC. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Reorder imports to match Java style guide Created 4 years, 6 months 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
1 /* 1 /*
2 * Copyright 2015 The WebRTC project authors. All Rights Reserved. 2 * Copyright 2015 The WebRTC project authors. All Rights Reserved.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license 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 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 6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may 7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree. 8 * be found in the AUTHORS file in the root of the source tree.
9 */ 9 */
10 package org.webrtc; 10 package org.webrtc;
11 11
12 import android.content.Context; 12 import static junit.framework.Assert.*;
13 13
14 import org.webrtc.VideoCapturerAndroidTestFixtures;
15 import org.webrtc.CameraEnumerationAndroid.CaptureFormat; 14 import org.webrtc.CameraEnumerationAndroid.CaptureFormat;
16 import org.webrtc.VideoRenderer.I420Frame; 15 import org.webrtc.VideoRenderer.I420Frame;
17 16
17 import android.content.Context;
18
18 import java.util.ArrayList; 19 import java.util.ArrayList;
19 import java.util.List; 20 import java.util.List;
20 import java.util.concurrent.CountDownLatch; 21 import java.util.concurrent.CountDownLatch;
21 22
22 import static junit.framework.Assert.*; 23 class CameraVideoCapturerTestFixtures {
24 static final String TAG = "CameraVideoCapturerTestFixtures";
23 25
24 @SuppressWarnings("deprecation") 26 static private class RendererCallbacks implements VideoRenderer.Callbacks {
25 public class VideoCapturerAndroidTestFixtures {
26 static class RendererCallbacks implements VideoRenderer.Callbacks {
27 private int framesRendered = 0; 27 private int framesRendered = 0;
28 private Object frameLock = 0; 28 private Object frameLock = 0;
29 private int width = 0; 29 private int width = 0;
30 private int height = 0; 30 private int height = 0;
31 31
32 @Override 32 @Override
33 public void renderFrame(I420Frame frame) { 33 public void renderFrame(I420Frame frame) {
34 synchronized (frameLock) { 34 synchronized (frameLock) {
35 ++framesRendered; 35 ++framesRendered;
36 width = frame.rotatedWidth(); 36 width = frame.rotatedWidth();
37 height = frame.rotatedHeight(); 37 height = frame.rotatedHeight();
38 frameLock.notify(); 38 frameLock.notify();
39 } 39 }
40 VideoRenderer.renderFrameDone(frame); 40 VideoRenderer.renderFrameDone(frame);
41 } 41 }
42 42
43 public int frameWidth() { 43 public int frameWidth() {
44 synchronized (frameLock) { 44 synchronized (frameLock) {
45 return width; 45 return width;
46 } 46 }
47 } 47 }
48 48
49 public int frameHeight() { 49 public int frameHeight() {
50 synchronized (frameLock) { 50 synchronized (frameLock) {
51 return height; 51 return height;
52 } 52 }
53 } 53 }
54 54
55 public int WaitForNextFrameToRender() throws InterruptedException { 55 public int waitForNextFrameToRender() throws InterruptedException {
56 Logging.d(TAG, "Waiting for the next frame to render");
56 synchronized (frameLock) { 57 synchronized (frameLock) {
57 frameLock.wait(); 58 frameLock.wait();
58 return framesRendered; 59 return framesRendered;
59 } 60 }
60 } 61 }
61 } 62 }
62 63
63 static class FakeAsyncRenderer implements VideoRenderer.Callbacks { 64 static private class FakeAsyncRenderer implements VideoRenderer.Callbacks {
64 private final List<I420Frame> pendingFrames = new ArrayList<I420Frame>(); 65 private final List<I420Frame> pendingFrames = new ArrayList<I420Frame>();
65 66
66 @Override 67 @Override
67 public void renderFrame(I420Frame frame) { 68 public void renderFrame(I420Frame frame) {
68 synchronized (pendingFrames) { 69 synchronized (pendingFrames) {
69 pendingFrames.add(frame); 70 pendingFrames.add(frame);
70 pendingFrames.notifyAll(); 71 pendingFrames.notifyAll();
71 } 72 }
72 } 73 }
73 74
74 // Wait until at least one frame have been received, before returning them. 75 // Wait until at least one frame have been received, before returning them.
75 public List<I420Frame> waitForPendingFrames() throws InterruptedException { 76 public List<I420Frame> waitForPendingFrames() throws InterruptedException {
77 Logging.d(TAG, "Waiting for pending frames");
76 synchronized (pendingFrames) { 78 synchronized (pendingFrames) {
77 while (pendingFrames.isEmpty()) { 79 while (pendingFrames.isEmpty()) {
78 pendingFrames.wait(); 80 pendingFrames.wait();
79 } 81 }
80 return new ArrayList<I420Frame>(pendingFrames); 82 return new ArrayList<I420Frame>(pendingFrames);
81 } 83 }
82 } 84 }
83 } 85 }
84 86
85 static class FakeCapturerObserver implements VideoCapturer.CapturerObserver { 87 static private class FakeCapturerObserver implements CameraVideoCapturer.Captu rerObserver {
86 private int framesCaptured = 0; 88 private int framesCaptured = 0;
87 private int frameSize = 0; 89 private int frameSize = 0;
88 private int frameWidth = 0; 90 private int frameWidth = 0;
89 private int frameHeight = 0; 91 private int frameHeight = 0;
90 private Object frameLock = 0; 92 final private Object frameLock = new Object();
91 private Object capturerStartLock = 0; 93 final private Object capturerStartLock = new Object();
92 private boolean captureStartResult = false; 94 private boolean capturerStartResult = false;
93 private List<Long> timestamps = new ArrayList<Long>(); 95 final private List<Long> timestamps = new ArrayList<Long>();
94 96
95 @Override 97 @Override
96 public void onCapturerStarted(boolean success) { 98 public void onCapturerStarted(boolean success) {
99 Logging.d(TAG, "onCapturerStarted: " + success);
100
97 synchronized (capturerStartLock) { 101 synchronized (capturerStartLock) {
98 captureStartResult = success; 102 capturerStartResult = success;
99 capturerStartLock.notify(); 103 capturerStartLock.notifyAll();
100 } 104 }
101 } 105 }
102 106
103 @Override 107 @Override
104 public void onByteBufferFrameCaptured(byte[] frame, int width, int height, i nt rotation, 108 public void onByteBufferFrameCaptured(byte[] frame, int width, int height, i nt rotation,
105 long timeStamp) { 109 long timeStamp) {
106 synchronized (frameLock) { 110 synchronized (frameLock) {
107 ++framesCaptured; 111 ++framesCaptured;
108 frameSize = frame.length; 112 frameSize = frame.length;
109 frameWidth = width; 113 frameWidth = width;
(...skipping 12 matching lines...) Expand all
122 frameHeight = height; 126 frameHeight = height;
123 frameSize = 0; 127 frameSize = 0;
124 timestamps.add(timeStamp); 128 timestamps.add(timeStamp);
125 frameLock.notify(); 129 frameLock.notify();
126 } 130 }
127 } 131 }
128 132
129 @Override 133 @Override
130 public void onOutputFormatRequest(int width, int height, int fps) {} 134 public void onOutputFormatRequest(int width, int height, int fps) {}
131 135
132 public boolean WaitForCapturerToStart() throws InterruptedException { 136 public boolean waitForCapturerToStart() throws InterruptedException {
137 Logging.d(TAG, "Waiting for the capturer to start");
133 synchronized (capturerStartLock) { 138 synchronized (capturerStartLock) {
134 capturerStartLock.wait(); 139 capturerStartLock.wait();
135 return captureStartResult; 140 return capturerStartResult;
136 } 141 }
137 } 142 }
138 143
139 public int WaitForNextCapturedFrame() throws InterruptedException { 144 public int waitForNextCapturedFrame() throws InterruptedException {
145 Logging.d(TAG, "Waiting for the next captured frame");
140 synchronized (frameLock) { 146 synchronized (frameLock) {
141 frameLock.wait(); 147 frameLock.wait();
142 return framesCaptured; 148 return framesCaptured;
143 } 149 }
144 } 150 }
145 151
146 int frameSize() { 152 int frameSize() {
147 synchronized (frameLock) { 153 synchronized (frameLock) {
148 return frameSize; 154 return frameSize;
149 } 155 }
(...skipping 14 matching lines...) Expand all
164 List<Long> getCopyAndResetListOftimeStamps() { 170 List<Long> getCopyAndResetListOftimeStamps() {
165 synchronized (frameLock) { 171 synchronized (frameLock) {
166 ArrayList<Long> list = new ArrayList<Long>(timestamps); 172 ArrayList<Long> list = new ArrayList<Long>(timestamps);
167 timestamps.clear(); 173 timestamps.clear();
168 return list; 174 return list;
169 } 175 }
170 } 176 }
171 } 177 }
172 178
173 static class CameraEvents implements 179 static class CameraEvents implements
174 VideoCapturerAndroid.CameraEventsHandler { 180 CameraVideoCapturer.CameraEventsHandler {
175 public boolean onCameraOpeningCalled; 181 public boolean onCameraOpeningCalled;
176 public boolean onFirstFrameAvailableCalled; 182 public boolean onFirstFrameAvailableCalled;
177 public final Object onCameraFreezedLock = new Object(); 183 public final Object onCameraFreezedLock = new Object();
178 private String onCameraFreezedDescription; 184 private String onCameraFreezedDescription;
179 185
180 @Override 186 @Override
181 public void onCameraError(String errorDescription) { 187 public void onCameraError(String errorDescription) {
182 } 188 }
183 189
184 @Override 190 @Override
(...skipping 10 matching lines...) Expand all
195 } 201 }
196 202
197 @Override 203 @Override
198 public void onFirstFrameAvailable() { 204 public void onFirstFrameAvailable() {
199 onFirstFrameAvailableCalled = true; 205 onFirstFrameAvailableCalled = true;
200 } 206 }
201 207
202 @Override 208 @Override
203 public void onCameraClosed() { } 209 public void onCameraClosed() { }
204 210
205 public String WaitForCameraFreezed() throws InterruptedException { 211 public String waitForCameraFreezed() throws InterruptedException {
212 Logging.d(TAG, "Waiting for the camera to freeze");
206 synchronized (onCameraFreezedLock) { 213 synchronized (onCameraFreezedLock) {
207 onCameraFreezedLock.wait(); 214 onCameraFreezedLock.wait();
208 return onCameraFreezedDescription; 215 return onCameraFreezedDescription;
209 } 216 }
210 } 217 }
211 } 218 }
212 219
213 static public CameraEvents createCameraEvents() { 220 /**
214 return new CameraEvents(); 221 * Class to collect all classes related to single capturer instance.
222 */
223 static private class CapturerInstance {
224 public CameraVideoCapturer capturer;
225 public CameraEvents cameraEvents;
226 public SurfaceTextureHelper surfaceTextureHelper;
227 public FakeCapturerObserver observer;
228 public List<CaptureFormat> supportedFormats;
229 public CaptureFormat format;
215 } 230 }
216 231
217 // Return true if the device under test have at least two cameras. 232 /**
218 @SuppressWarnings("deprecation") 233 * Class used for collecting a VideoSource, a VideoTrack and a renderer. The c lass
219 static public boolean HaveTwoCameras() { 234 * is used for testing local rendering from a capturer.
220 return (android.hardware.Camera.getNumberOfCameras() >= 2); 235 */
236 static private class VideoTrackWithRenderer {
237 public VideoSource source;
238 public VideoTrack track;
239 public RendererCallbacks rendererCallbacks;
240 public FakeAsyncRenderer fakeAsyncRenderer;
221 } 241 }
222 242
223 static public void release(VideoCapturerAndroid capturer) { 243 public interface TestObjectFactory {
224 assertNotNull(capturer); 244 CameraVideoCapturer createCapturer(
225 capturer.dispose(); 245 String name, CameraVideoCapturer.CameraEventsHandler eventsHandler);
246 String getNameOfFrontFacingDevice();
247 String getNameOfBackFacingDevice();
248 boolean haveTwoCameras();
249 boolean isCapturingToTexture();
250 Context getAppContext();
251
252 // CameraVideoCapturer API is too slow for some of our tests where we need t o open a competing
253 // camera. These methods are used instead.
254 Object rawOpenCamera(String cameraName);
255 void rawCloseCamera(Object camera);
226 } 256 }
227 257
228 static public void startCapturerAndRender(VideoCapturerAndroid capturer) 258 private PeerConnectionFactory peerConnectionFactory;
229 throws InterruptedException { 259 private TestObjectFactory testObjectFactory;
230 PeerConnectionFactory factory = new PeerConnectionFactory(null /* options */ ); 260
231 VideoSource source = 261 CameraVideoCapturerTestFixtures(TestObjectFactory testObjectFactory) {
232 factory.createVideoSource(capturer, new MediaConstraints()); 262 PeerConnectionFactory.initializeAndroidGlobals(
233 VideoTrack track = factory.createVideoTrack("dummy", source); 263 testObjectFactory.getAppContext(), true, true, true);
234 RendererCallbacks callbacks = new RendererCallbacks(); 264
235 track.addRenderer(new VideoRenderer(callbacks)); 265 this.peerConnectionFactory = new PeerConnectionFactory(null /* options */);
236 assertTrue(callbacks.WaitForNextFrameToRender() > 0); 266 this.testObjectFactory = testObjectFactory;
237 track.dispose();
238 source.dispose();
239 factory.dispose();
240 } 267 }
241 268
242 static public void switchCamera(VideoCapturerAndroid capturer) throws Interrup tedException { 269 public void dispose() {
243 PeerConnectionFactory factory = new PeerConnectionFactory(null /* options */ ); 270 this.peerConnectionFactory.dispose();
244 VideoSource source = 271 }
245 factory.createVideoSource(capturer, new MediaConstraints()); 272
246 VideoTrack track = factory.createVideoTrack("dummy", source); 273 // Internal helper methods
274 private CapturerInstance createCapturer(String name) {
275 CapturerInstance instance = new CapturerInstance();
276 instance.cameraEvents = new CameraEvents();
277 instance.capturer = testObjectFactory.createCapturer(name, instance.cameraEv ents);
278 instance.surfaceTextureHelper = SurfaceTextureHelper.create(
279 "SurfaceTextureHelper test" /* threadName */, null /* sharedContext */);
280 instance.observer = new FakeCapturerObserver();
281 instance.supportedFormats = instance.capturer.getSupportedFormats();
282 return instance;
283 }
284
285 private CapturerInstance createCapturer() {
286 return createCapturer("");
287 }
288
289 private void startCapture(CapturerInstance instance) {
290 startCapture(instance, 0);
291 }
292
293 private void startCapture(CapturerInstance instance, int formatIndex) {
294 final CameraEnumerationAndroid.CaptureFormat format =
295 instance.supportedFormats.get(formatIndex);
296
297 instance.capturer.startCapture(format.width, format.height, format.framerate .max,
298 instance.surfaceTextureHelper, testObjectFactory.getAppContext(), instan ce.observer);
299 instance.format = format;
300 }
301
302 private void disposeCapturer(CapturerInstance instance) {
303 instance.capturer.dispose();
304 instance.surfaceTextureHelper.returnTextureFrame();
305 instance.surfaceTextureHelper.dispose();
306 }
307
308 private VideoTrackWithRenderer createVideoTrackWithRenderer(CameraVideoCapture r capturer,
309 VideoRenderer.Callbacks rendererCallbacks) {
310 VideoTrackWithRenderer videoTrackWithRenderer = new VideoTrackWithRenderer() ;
311 videoTrackWithRenderer.source =
312 peerConnectionFactory.createVideoSource(capturer, new MediaConstraints() );
313 videoTrackWithRenderer.track =
314 peerConnectionFactory.createVideoTrack("dummy", videoTrackWithRenderer.s ource);
315 videoTrackWithRenderer.track.addRenderer(new VideoRenderer(rendererCallbacks ));
316 return videoTrackWithRenderer;
317 }
318
319 private VideoTrackWithRenderer createVideoTrackWithRenderer(CameraVideoCapture r capturer) {
320 RendererCallbacks rendererCallbacks = new RendererCallbacks();
321 VideoTrackWithRenderer videoTrackWithRenderer =
322 createVideoTrackWithRenderer(capturer, rendererCallbacks);
323 videoTrackWithRenderer.rendererCallbacks = rendererCallbacks;
324 return videoTrackWithRenderer;
325 }
326
327 private VideoTrackWithRenderer createVideoTrackWithFakeAsyncRenderer(
328 CameraVideoCapturer capturer) {
329 FakeAsyncRenderer fakeAsyncRenderer = new FakeAsyncRenderer();
330 VideoTrackWithRenderer videoTrackWithRenderer =
331 createVideoTrackWithRenderer(capturer, fakeAsyncRenderer);
332 videoTrackWithRenderer.fakeAsyncRenderer = fakeAsyncRenderer;
333 return videoTrackWithRenderer;
334 }
335
336 private void disposeVideoTrackWithRenderer(VideoTrackWithRenderer videoTrackWi thRenderer) {
337 videoTrackWithRenderer.track.dispose();
338 videoTrackWithRenderer.source.dispose();
339 }
340
341 private void waitUntilIdle(CapturerInstance capturerInstance) throws Interrupt edException {
342 final CountDownLatch barrier = new CountDownLatch(1);
343 capturerInstance.surfaceTextureHelper.getHandler().post(new Runnable() {
344 @Override public void run() {
345 barrier.countDown();
346 }
347 });
348 barrier.await();
349 }
350
351 private void createCapturerAndRender(String name) throws InterruptedException {
352 if (name == null) {
353 Logging.w(TAG, "Skipping video capturer test because device name is null." );
354 return;
355 }
356
357 final CapturerInstance capturerInstance = createCapturer(name);
358 final VideoTrackWithRenderer videoTrackWithRenderer =
359 createVideoTrackWithRenderer(capturerInstance.capturer);
360 assertTrue(videoTrackWithRenderer.rendererCallbacks.waitForNextFrameToRender () > 0);
361 disposeVideoTrackWithRenderer(videoTrackWithRenderer);
362 disposeCapturer(capturerInstance);
363 }
364
365 // Test methods
366 public void createCapturerAndDispose() {
367 disposeCapturer(createCapturer());
368 }
369
370 public void createNonExistingCamera() {
371 try {
372 disposeCapturer(createCapturer("non-existing camera"));
373 } catch (IllegalArgumentException e) {
374 return;
375 }
376
377 fail("Expected illegal argument exception when creating non-existing camera. ");
378 }
379
380 public void createCapturerAndRender() throws InterruptedException {
381 createCapturerAndRender("");
382 }
383
384 public void createFrontFacingCapturerAndRender() throws InterruptedException {
385 createCapturerAndRender(testObjectFactory.getNameOfFrontFacingDevice());
386 }
387
388 public void createBackFacingCapturerAndRender() throws InterruptedException {
389 createCapturerAndRender(testObjectFactory.getNameOfBackFacingDevice());
390 }
391
392 public void switchCamera() throws InterruptedException {
393 if (!testObjectFactory.haveTwoCameras()) {
394 Logging.w(TAG,
395 "Skipping test switch video capturer because the device doesn't have t wo cameras.");
396 return;
397 }
398
399 final CapturerInstance capturerInstance = createCapturer();
400 final VideoTrackWithRenderer videoTrackWithRenderer =
401 createVideoTrackWithRenderer(capturerInstance.capturer);
247 402
248 // Array with one element to avoid final problem in nested classes. 403 // Array with one element to avoid final problem in nested classes.
249 final boolean[] cameraSwitchSuccessful = new boolean[1]; 404 final boolean[] cameraSwitchSuccessful = new boolean[1];
250 final CountDownLatch barrier = new CountDownLatch(1); 405 final CountDownLatch barrier = new CountDownLatch(1);
251 capturer.switchCamera(new VideoCapturerAndroid.CameraSwitchHandler() { 406 capturerInstance.capturer.switchCamera(new CameraVideoCapturer.CameraSwitchH andler() {
252 @Override 407 @Override
253 public void onCameraSwitchDone(boolean isFrontCamera) { 408 public void onCameraSwitchDone(boolean isFrontCamera) {
254 cameraSwitchSuccessful[0] = true; 409 cameraSwitchSuccessful[0] = true;
255 barrier.countDown(); 410 barrier.countDown();
256 } 411 }
257 @Override 412 @Override
258 public void onCameraSwitchError(String errorDescription) { 413 public void onCameraSwitchError(String errorDescription) {
259 cameraSwitchSuccessful[0] = false; 414 cameraSwitchSuccessful[0] = false;
260 barrier.countDown(); 415 barrier.countDown();
261 } 416 }
262 }); 417 });
263 // Wait until the camera has been switched. 418 // Wait until the camera has been switched.
264 barrier.await(); 419 barrier.await();
265 420
266 // Check result. 421 // Check result.
267 if (HaveTwoCameras()) { 422 assertTrue(cameraSwitchSuccessful[0]);
268 assertTrue(cameraSwitchSuccessful[0]);
269 } else {
270 assertFalse(cameraSwitchSuccessful[0]);
271 }
272 // Ensure that frames are received. 423 // Ensure that frames are received.
273 RendererCallbacks callbacks = new RendererCallbacks(); 424 assertTrue(videoTrackWithRenderer.rendererCallbacks.waitForNextFrameToRender () > 0);
274 track.addRenderer(new VideoRenderer(callbacks)); 425 disposeVideoTrackWithRenderer(videoTrackWithRenderer);
275 assertTrue(callbacks.WaitForNextFrameToRender() > 0); 426 disposeCapturer(capturerInstance);
276 track.dispose();
277 source.dispose();
278 factory.dispose();
279 } 427 }
280 428
281 static public void cameraEventsInvoked(VideoCapturerAndroid capturer, CameraEv ents events, 429 public void cameraEventsInvoked() throws InterruptedException {
282 Context appContext) throws InterruptedException { 430 final CapturerInstance capturerInstance = createCapturer();
283 final List<CaptureFormat> formats = capturer.getSupportedFormats(); 431 startCapture(capturerInstance);
284 final CameraEnumerationAndroid.CaptureFormat format = formats.get(0); 432 // Make sure camera is started and first frame is received and then stop it.
433 assertTrue(capturerInstance.observer.waitForCapturerToStart());
434 capturerInstance.observer.waitForNextCapturedFrame();
435 capturerInstance.capturer.stopCapture();
436 disposeCapturer(capturerInstance);
285 437
286 final SurfaceTextureHelper surfaceTextureHelper = SurfaceTextureHelper.creat e( 438 assertTrue(capturerInstance.cameraEvents.onCameraOpeningCalled);
287 "SurfaceTextureHelper test" /* threadName */, null /* sharedContext */); 439 assertTrue(capturerInstance.cameraEvents.onFirstFrameAvailableCalled);
288 final FakeCapturerObserver observer = new FakeCapturerObserver();
289 capturer.startCapture(format.width, format.height, format.framerate.max,
290 surfaceTextureHelper, appContext, observer);
291 // Make sure camera is started and first frame is received and then stop it.
292 assertTrue(observer.WaitForCapturerToStart());
293 observer.WaitForNextCapturedFrame();
294 capturer.stopCapture();
295 if (capturer.isCapturingToTexture()) {
296 surfaceTextureHelper.returnTextureFrame();
297 }
298 release(capturer);
299 surfaceTextureHelper.dispose();
300
301 assertTrue(events.onCameraOpeningCalled);
302 assertTrue(events.onFirstFrameAvailableCalled);
303 } 440 }
304 441
305 static public void cameraCallsAfterStop( 442 public void cameraCallsAfterStop() throws InterruptedException {
306 VideoCapturerAndroid capturer, Context appContext) throws InterruptedExcep tion { 443 final CapturerInstance capturerInstance = createCapturer();
307 final List<CaptureFormat> formats = capturer.getSupportedFormats(); 444 startCapture(capturerInstance);
308 final CameraEnumerationAndroid.CaptureFormat format = formats.get(0);
309
310 final SurfaceTextureHelper surfaceTextureHelper = SurfaceTextureHelper.creat e(
311 "SurfaceTextureHelper test" /* threadName */, null /* sharedContext */);
312 final FakeCapturerObserver observer = new FakeCapturerObserver();
313 capturer.startCapture(format.width, format.height, format.framerate.max,
314 surfaceTextureHelper, appContext, observer);
315 // Make sure camera is started and then stop it. 445 // Make sure camera is started and then stop it.
316 assertTrue(observer.WaitForCapturerToStart()); 446 assertTrue(capturerInstance.observer.waitForCapturerToStart());
317 capturer.stopCapture(); 447 capturerInstance.capturer.stopCapture();
318 if (capturer.isCapturingToTexture()) { 448 capturerInstance.surfaceTextureHelper.returnTextureFrame();
319 surfaceTextureHelper.returnTextureFrame();
320 }
321 449
322 // We can't change |capturer| at this point, but we should not crash. 450 // We can't change |capturer| at this point, but we should not crash.
323 capturer.switchCamera(null); 451 capturerInstance.capturer.switchCamera(null /* switchEventsHandler */);
324 capturer.onOutputFormatRequest(640, 480, 15); 452 capturerInstance.capturer.onOutputFormatRequest(640, 480, 15);
325 capturer.changeCaptureFormat(640, 480, 15); 453 capturerInstance.capturer.changeCaptureFormat(640, 480, 15);
326 454
327 release(capturer); 455 disposeCapturer(capturerInstance);
328 surfaceTextureHelper.dispose();
329 } 456 }
330 457
331 static public void stopRestartVideoSource(VideoCapturerAndroid capturer) 458 public void stopRestartVideoSource() throws InterruptedException {
332 throws InterruptedException { 459 final CapturerInstance capturerInstance = createCapturer();
333 PeerConnectionFactory factory = new PeerConnectionFactory(null /* options */ ); 460 final VideoTrackWithRenderer videoTrackWithRenderer =
334 VideoSource source = 461 createVideoTrackWithRenderer(capturerInstance.capturer);
335 factory.createVideoSource(capturer, new MediaConstraints());
336 VideoTrack track = factory.createVideoTrack("dummy", source);
337 RendererCallbacks callbacks = new RendererCallbacks();
338 track.addRenderer(new VideoRenderer(callbacks));
339 assertTrue(callbacks.WaitForNextFrameToRender() > 0);
340 assertEquals(MediaSource.State.LIVE, source.state());
341 462
342 source.stop(); 463 assertTrue(videoTrackWithRenderer.rendererCallbacks.waitForNextFrameToRender () > 0);
343 assertEquals(MediaSource.State.ENDED, source.state()); 464 assertEquals(MediaSource.State.LIVE, videoTrackWithRenderer.source.state());
344 465
345 source.restart(); 466 videoTrackWithRenderer.source.stop();
346 assertTrue(callbacks.WaitForNextFrameToRender() > 0); 467 assertEquals(MediaSource.State.ENDED, videoTrackWithRenderer.source.state()) ;
347 assertEquals(MediaSource.State.LIVE, source.state()); 468
348 track.dispose(); 469 videoTrackWithRenderer.source.restart();
349 source.dispose(); 470 assertTrue(videoTrackWithRenderer.rendererCallbacks.waitForNextFrameToRender () > 0);
350 factory.dispose(); 471 assertEquals(MediaSource.State.LIVE, videoTrackWithRenderer.source.state());
472
473 disposeVideoTrackWithRenderer(videoTrackWithRenderer);
474 disposeCapturer(capturerInstance);
351 } 475 }
352 476
353 static public void startStopWithDifferentResolutions(VideoCapturerAndroid capt urer, 477 public void startStopWithDifferentResolutions() throws InterruptedException {
354 Context appContext) throws InterruptedException { 478 final CapturerInstance capturerInstance = createCapturer();
355 final SurfaceTextureHelper surfaceTextureHelper = SurfaceTextureHelper.creat e(
356 "SurfaceTextureHelper test" /* threadName */, null /* sharedContext */);
357 FakeCapturerObserver observer = new FakeCapturerObserver();
358 List<CaptureFormat> formats = capturer.getSupportedFormats();
359 479
360 for(int i = 0; i < 3 ; ++i) { 480 for(int i = 0; i < 3 ; ++i) {
361 CameraEnumerationAndroid.CaptureFormat format = formats.get(i); 481 startCapture(capturerInstance, i);
362 capturer.startCapture(format.width, format.height, format.framerate.max, 482 assertTrue(capturerInstance.observer.waitForCapturerToStart());
363 surfaceTextureHelper, appContext, observer); 483 capturerInstance.observer.waitForNextCapturedFrame();
364 assertTrue(observer.WaitForCapturerToStart());
365 observer.WaitForNextCapturedFrame();
366 484
367 // Check the frame size. The actual width and height depend on how the cap turer is mounted. 485 // Check the frame size. The actual width and height depend on how the cap turer is mounted.
368 final boolean identicalResolution = (observer.frameWidth() == format.width 486 final boolean identicalResolution = (
369 && observer.frameHeight() == format.height); 487 capturerInstance.observer.frameWidth() == capturerInstance.format.widt h
370 final boolean flippedResolution = (observer.frameWidth() == format.height 488 && capturerInstance.observer.frameHeight() == capturerInstance.format .height);
371 && observer.frameHeight() == format.width); 489 final boolean flippedResolution = (
490 capturerInstance.observer.frameWidth() == capturerInstance.format.heig ht
491 && capturerInstance.observer.frameHeight() == capturerInstance.format. width);
372 if (!identicalResolution && !flippedResolution) { 492 if (!identicalResolution && !flippedResolution) {
373 fail("Wrong resolution, got: " + observer.frameWidth() + "x" + observer. frameHeight() 493 fail("Wrong resolution, got: "
374 + " expected: " + format.width + "x" + format.height + " or " + form at.height + "x" 494 + capturerInstance.observer.frameWidth() + "x" + capturerInstance.ob server.frameHeight()
375 + format.width); 495 + " expected: "+ capturerInstance.format.width + "x" + capturerInsta nce.format.height
496 + " or " + capturerInstance.format.height + "x" + capturerInstance.f ormat.width);
376 } 497 }
377 498
378 if (capturer.isCapturingToTexture()) { 499 if (testObjectFactory.isCapturingToTexture()) {
379 assertEquals(0, observer.frameSize()); 500 assertEquals(0, capturerInstance.observer.frameSize());
380 } else { 501 } else {
381 assertTrue(format.frameSize() <= observer.frameSize()); 502 assertTrue(capturerInstance.format.frameSize() <= capturerInstance.obser ver.frameSize());
382 } 503 }
383 capturer.stopCapture(); 504 capturerInstance.capturer.stopCapture();
384 if (capturer.isCapturingToTexture()) { 505 capturerInstance.surfaceTextureHelper.returnTextureFrame();
385 surfaceTextureHelper.returnTextureFrame();
386 }
387 } 506 }
388 release(capturer); 507 disposeCapturer(capturerInstance);
389 surfaceTextureHelper.dispose();
390 } 508 }
391 509
392 static void waitUntilIdle(VideoCapturerAndroid capturer) throws InterruptedExc eption { 510 public void returnBufferLate() throws InterruptedException {
393 final CountDownLatch barrier = new CountDownLatch(1); 511 final CapturerInstance capturerInstance = createCapturer();
394 capturer.getCameraThreadHandler().post(new Runnable() { 512 startCapture(capturerInstance);
395 @Override public void run() { 513 assertTrue(capturerInstance.observer.waitForCapturerToStart());
396 barrier.countDown(); 514
397 } 515 capturerInstance.observer.waitForNextCapturedFrame();
398 }); 516 capturerInstance.capturer.stopCapture();
399 barrier.await(); 517 List<Long> listOftimestamps = capturerInstance.observer.getCopyAndResetListO ftimeStamps();
518 assertTrue(listOftimestamps.size() >= 1);
519
520 startCapture(capturerInstance, 1);
521 capturerInstance.observer.waitForCapturerToStart();
522 capturerInstance.surfaceTextureHelper.returnTextureFrame();
523
524 capturerInstance.observer.waitForNextCapturedFrame();
525 capturerInstance.capturer.stopCapture();
526
527 listOftimestamps = capturerInstance.observer.getCopyAndResetListOftimeStamps ();
528 assertTrue(listOftimestamps.size() >= 1);
529
530 disposeCapturer(capturerInstance);
400 } 531 }
401 532
402 static public void startWhileCameraIsAlreadyOpen( 533 public void returnBufferLateEndToEnd()
403 VideoCapturerAndroid capturer, Context appContext) throws InterruptedExcep tion { 534 throws InterruptedException {
404 final List<CaptureFormat> formats = capturer.getSupportedFormats(); 535 final CapturerInstance capturerInstance = createCapturer();
405 final CameraEnumerationAndroid.CaptureFormat format = formats.get(0); 536 final VideoTrackWithRenderer videoTrackWithRenderer =
406 android.hardware.Camera camera = android.hardware.Camera.open(capturer.getCu rrentCameraId()); 537 createVideoTrackWithFakeAsyncRenderer(capturerInstance.capturer);
538 // Wait for at least one frame that has not been returned.
539 assertFalse(videoTrackWithRenderer.fakeAsyncRenderer.waitForPendingFrames(). isEmpty());
407 540
408 final SurfaceTextureHelper surfaceTextureHelper = SurfaceTextureHelper.creat e( 541 capturerInstance.capturer.stopCapture();
409 "SurfaceTextureHelper test" /* threadName */, null /* sharedContext */);
410 final FakeCapturerObserver observer = new FakeCapturerObserver();
411 capturer.startCapture(format.width, format.height, format.framerate.max,
412 surfaceTextureHelper, appContext, observer);
413
414 if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.LOLLIP OP_MR1) {
415 // The first opened camera client will be evicted.
416 assertTrue(observer.WaitForCapturerToStart());
417 capturer.stopCapture();
418 } else {
419 assertFalse(observer.WaitForCapturerToStart());
420 }
421
422 release(capturer);
423 camera.release();
424 surfaceTextureHelper.dispose();
425 }
426
427 static public void startWhileCameraIsAlreadyOpenAndCloseCamera(
428 VideoCapturerAndroid capturer, Context appContext) throws InterruptedExcep tion {
429 final PeerConnectionFactory factory = new PeerConnectionFactory(null /* opti ons */);
430 final List<CaptureFormat> formats = capturer.getSupportedFormats();
431 final CameraEnumerationAndroid.CaptureFormat format = formats.get(0);
432 android.hardware.Camera camera = android.hardware.Camera.open(capturer.getCu rrentCameraId());
433
434 final SurfaceTextureHelper surfaceTextureHelper = SurfaceTextureHelper.creat e(
435 "SurfaceTextureHelper test" /* threadName */, null /* sharedContext */);
436 final VideoSource source = factory.createVideoSource(capturer, new MediaCons traints());
437 final VideoTrack track = factory.createVideoTrack("dummy", source);
438 final RendererCallbacks callbacks = new RendererCallbacks();
439 track.addRenderer(new VideoRenderer(callbacks));
440 waitUntilIdle(capturer);
441
442 camera.release();
443
444 // Make sure camera is started and first frame is received and then stop it.
445 callbacks.WaitForNextFrameToRender();
446 capturer.stopCapture();
447 release(capturer);
448 surfaceTextureHelper.dispose();
449 }
450
451 static public void startWhileCameraIsAlreadyOpenAndStop(
452 VideoCapturerAndroid capturer, Context appContext) throws InterruptedExcep tion {
453 final List<CaptureFormat> formats = capturer.getSupportedFormats();
454 final CameraEnumerationAndroid.CaptureFormat format = formats.get(0);
455 android.hardware.Camera camera = android.hardware.Camera.open(capturer.getCu rrentCameraId());
456
457 final SurfaceTextureHelper surfaceTextureHelper = SurfaceTextureHelper.creat e(
458 "SurfaceTextureHelper test" /* threadName */, null /* sharedContext */);
459 final FakeCapturerObserver observer = new FakeCapturerObserver();
460 capturer.startCapture(format.width, format.height, format.framerate.max,
461 surfaceTextureHelper, appContext, observer);
462 capturer.stopCapture();
463 release(capturer);
464 camera.release();
465 surfaceTextureHelper.dispose();
466 }
467
468 static public void returnBufferLate(VideoCapturerAndroid capturer,
469 Context appContext) throws InterruptedException {
470 final SurfaceTextureHelper surfaceTextureHelper = SurfaceTextureHelper.creat e(
471 "SurfaceTextureHelper test" /* threadName */, null /* sharedContext */);
472 FakeCapturerObserver observer = new FakeCapturerObserver();
473
474 List<CaptureFormat> formats = capturer.getSupportedFormats();
475 CameraEnumerationAndroid.CaptureFormat format = formats.get(0);
476 capturer.startCapture(format.width, format.height, format.framerate.max,
477 surfaceTextureHelper, appContext, observer);
478 assertTrue(observer.WaitForCapturerToStart());
479
480 observer.WaitForNextCapturedFrame();
481 capturer.stopCapture();
482 List<Long> listOftimestamps = observer.getCopyAndResetListOftimeStamps();
483 assertTrue(listOftimestamps.size() >= 1);
484
485 format = formats.get(1);
486 capturer.startCapture(format.width, format.height, format.framerate.max,
487 surfaceTextureHelper, appContext, observer);
488 observer.WaitForCapturerToStart();
489 if (capturer.isCapturingToTexture()) {
490 surfaceTextureHelper.returnTextureFrame();
491 }
492
493 observer.WaitForNextCapturedFrame();
494 capturer.stopCapture();
495
496 listOftimestamps = observer.getCopyAndResetListOftimeStamps();
497 assertTrue(listOftimestamps.size() >= 1);
498 if (capturer.isCapturingToTexture()) {
499 surfaceTextureHelper.returnTextureFrame();
500 }
501
502 release(capturer);
503 surfaceTextureHelper.dispose();
504 }
505
506 static public void returnBufferLateEndToEnd(VideoCapturerAndroid capturer)
507 throws InterruptedException {
508 final PeerConnectionFactory factory = new PeerConnectionFactory(null /* opti ons */);
509 final VideoSource source = factory.createVideoSource(capturer, new MediaCons traints());
510 final VideoTrack track = factory.createVideoTrack("dummy", source);
511 final FakeAsyncRenderer renderer = new FakeAsyncRenderer();
512
513 track.addRenderer(new VideoRenderer(renderer));
514 // Wait for at least one frame that has not been returned.
515 assertFalse(renderer.waitForPendingFrames().isEmpty());
516
517 capturer.stopCapture();
518 542
519 // Dispose everything. 543 // Dispose everything.
520 track.dispose(); 544 disposeVideoTrackWithRenderer(videoTrackWithRenderer);
521 source.dispose(); 545 disposeCapturer(capturerInstance);
522 factory.dispose();
523 546
524 // Return the frame(s), on a different thread out of spite. 547 // Return the frame(s), on a different thread out of spite.
525 final List<I420Frame> pendingFrames = renderer.waitForPendingFrames(); 548 final List<I420Frame> pendingFrames =
549 videoTrackWithRenderer.fakeAsyncRenderer.waitForPendingFrames();
526 final Thread returnThread = new Thread(new Runnable() { 550 final Thread returnThread = new Thread(new Runnable() {
527 @Override 551 @Override
528 public void run() { 552 public void run() {
529 for (I420Frame frame : pendingFrames) { 553 for (I420Frame frame : pendingFrames) {
530 VideoRenderer.renderFrameDone(frame); 554 VideoRenderer.renderFrameDone(frame);
531 } 555 }
532 } 556 }
533 }); 557 });
534 returnThread.start(); 558 returnThread.start();
535 returnThread.join(); 559 returnThread.join();
536 } 560 }
537 561
538 static public void cameraFreezedEventOnBufferStarvationUsingTextures( 562 public void cameraFreezedEventOnBufferStarvation() throws InterruptedException {
539 VideoCapturerAndroid capturer, 563 final CapturerInstance capturerInstance = createCapturer();
540 CameraEvents events, Context appContext) throws InterruptedException { 564 startCapture(capturerInstance);
541 assertTrue("Not capturing to textures.", capturer.isCapturingToTexture());
542
543 final List<CaptureFormat> formats = capturer.getSupportedFormats();
544 final CameraEnumerationAndroid.CaptureFormat format = formats.get(0);
545
546 final SurfaceTextureHelper surfaceTextureHelper = SurfaceTextureHelper.creat e(
547 "SurfaceTextureHelper test" /* threadName */, null /* sharedContext */);
548 final FakeCapturerObserver observer = new FakeCapturerObserver();
549 capturer.startCapture(format.width, format.height, format.framerate.max,
550 surfaceTextureHelper, appContext, observer);
551 // Make sure camera is started. 565 // Make sure camera is started.
552 assertTrue(observer.WaitForCapturerToStart()); 566 assertTrue(capturerInstance.observer.waitForCapturerToStart());
553 // Since we don't return the buffer, we should get a starvation message if w e are 567 // Since we don't return the buffer, we should get a starvation message if w e are
554 // capturing to a texture. 568 // capturing to a texture.
555 assertEquals("Camera failure. Client must return video buffers.", 569 assertEquals("Camera failure. Client must return video buffers.",
556 events.WaitForCameraFreezed()); 570 capturerInstance.cameraEvents.waitForCameraFreezed());
557 571
558 capturer.stopCapture(); 572 capturerInstance.capturer.stopCapture();
559 if (capturer.isCapturingToTexture()) { 573 disposeCapturer(capturerInstance);
560 surfaceTextureHelper.returnTextureFrame();
561 }
562
563 release(capturer);
564 surfaceTextureHelper.dispose();
565 } 574 }
566 575
567 static public void scaleCameraOutput(VideoCapturerAndroid capturer) throws Int erruptedException { 576 public void scaleCameraOutput() throws InterruptedException {
568 PeerConnectionFactory factory = new PeerConnectionFactory(null /* options */ ); 577 final CapturerInstance capturerInstance = createCapturer();
569 VideoSource source = 578 final VideoTrackWithRenderer videoTrackWithRenderer =
570 factory.createVideoSource(capturer, new MediaConstraints()); 579 createVideoTrackWithRenderer(capturerInstance.capturer);
571 VideoTrack track = factory.createVideoTrack("dummy", source); 580 assertTrue(videoTrackWithRenderer.rendererCallbacks.waitForNextFrameToRender () > 0);
572 RendererCallbacks renderer = new RendererCallbacks();
573 track.addRenderer(new VideoRenderer(renderer));
574 assertTrue(renderer.WaitForNextFrameToRender() > 0);
575 581
576 final int startWidth = renderer.frameWidth(); 582 final int startWidth = videoTrackWithRenderer.rendererCallbacks.frameWidth() ;
577 final int startHeight = renderer.frameHeight(); 583 final int startHeight = videoTrackWithRenderer.rendererCallbacks.frameHeight ();
578 final int frameRate = 30; 584 final int frameRate = 30;
579 final int scaledWidth = startWidth / 2; 585 final int scaledWidth = startWidth / 2;
580 final int scaledHeight = startHeight / 2; 586 final int scaledHeight = startHeight / 2;
581 587
582 // Request the captured frames to be scaled. 588 // Request the captured frames to be scaled.
583 capturer.onOutputFormatRequest(scaledWidth, scaledHeight, frameRate); 589 capturerInstance.capturer.onOutputFormatRequest(scaledWidth, scaledHeight, f rameRate);
584 590
585 boolean gotExpectedResolution = false; 591 boolean gotExpectedResolution = false;
586 int numberOfInspectedFrames = 0; 592 int numberOfInspectedFrames = 0;
587 593
588 do { 594 do {
589 renderer.WaitForNextFrameToRender(); 595 videoTrackWithRenderer.rendererCallbacks.waitForNextFrameToRender();
590 ++numberOfInspectedFrames; 596 ++numberOfInspectedFrames;
591 597
592 gotExpectedResolution = (renderer.frameWidth() == scaledWidth 598 gotExpectedResolution = (videoTrackWithRenderer.rendererCallbacks.frameWid th() == scaledWidth
593 && renderer.frameHeight() == scaledHeight); 599 && videoTrackWithRenderer.rendererCallbacks.frameHeight() == scaledHe ight);
594 } while (!gotExpectedResolution && numberOfInspectedFrames < 30); 600 } while (!gotExpectedResolution && numberOfInspectedFrames < 30);
595 601
596 source.stop(); 602 disposeVideoTrackWithRenderer(videoTrackWithRenderer);
597 track.dispose(); 603 disposeCapturer(capturerInstance);
598 source.dispose();
599 factory.dispose();
600 604
601 assertTrue(gotExpectedResolution); 605 assertTrue(gotExpectedResolution);
602 } 606 }
603 607
608 public void startWhileCameraIsAlreadyOpen() throws InterruptedException {
609 final String cameraName = testObjectFactory.getNameOfBackFacingDevice();
610 // At this point camera is not actually opened.
611 final CapturerInstance capturerInstance = createCapturer(cameraName);
612
613 final Object competingCamera = testObjectFactory.rawOpenCamera(cameraName);
614
615 startCapture(capturerInstance);
616
617 if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.LOLLIP OP_MR1) {
618 // The first opened camera client will be evicted.
619 assertTrue(capturerInstance.observer.waitForCapturerToStart());
620 capturerInstance.capturer.stopCapture();
621 } else {
622 assertFalse(capturerInstance.observer.waitForCapturerToStart());
623 }
624
625 testObjectFactory.rawCloseCamera(competingCamera);
626 disposeCapturer(capturerInstance);
627 }
628
629 public void startWhileCameraIsAlreadyOpenAndCloseCamera() throws InterruptedEx ception {
630 final String cameraName = testObjectFactory.getNameOfBackFacingDevice();
631 // At this point camera is not actually opened.
632 final CapturerInstance capturerInstance = createCapturer(cameraName);
633
634 Logging.d(TAG, "startWhileCameraIsAlreadyOpenAndCloseCamera: Opening competi ng camera.");
635 final Object competingCamera = testObjectFactory.rawOpenCamera(cameraName);
636
637 Logging.d(TAG, "startWhileCameraIsAlreadyOpenAndCloseCamera: Opening camera. ");
638 final VideoTrackWithRenderer videoTrackWithRenderer =
639 createVideoTrackWithRenderer(capturerInstance.capturer);
640 waitUntilIdle(capturerInstance);
641
642 Logging.d(TAG, "startWhileCameraIsAlreadyOpenAndCloseCamera: Closing competi ng camera.");
643 testObjectFactory.rawCloseCamera(competingCamera);
644
645 // Make sure camera is started and first frame is received and then stop it.
646 Logging.d(TAG, "startWhileCameraIsAlreadyOpenAndCloseCamera: Waiting for cap ture to start.");
647 videoTrackWithRenderer.rendererCallbacks.waitForNextFrameToRender();
648 Logging.d(TAG, "startWhileCameraIsAlreadyOpenAndCloseCamera: Stopping captur e.");
649 capturerInstance.capturer.stopCapture();
650 disposeCapturer(capturerInstance);
651 }
652
653 public void startWhileCameraIsAlreadyOpenAndStop() throws InterruptedException {
654 final String cameraName = testObjectFactory.getNameOfBackFacingDevice();
655 // At this point camera is not actually opened.
656 final CapturerInstance capturerInstance = createCapturer(cameraName);
657
658 final Object competingCamera = testObjectFactory.rawOpenCamera(cameraName);
659
660 startCapture(capturerInstance);
661
662 capturerInstance.capturer.stopCapture();
663 disposeCapturer(capturerInstance);
664
665 testObjectFactory.rawCloseCamera(competingCamera);
666 }
604 } 667 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698