OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright 2016 The WebRTC project authors. All Rights Reserved. | |
3 * | |
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 | |
6 * tree. An additional intellectual property rights grant can be found | |
7 * in the file PATENTS. All contributing project authors may | |
8 * be found in the AUTHORS file in the root of the source tree. | |
9 */ | |
10 | |
11 package org.webrtc; | |
12 | |
13 import android.content.Context; | |
14 import android.hardware.camera2.CameraAccessException; | |
15 import android.hardware.camera2.CameraDevice; | |
16 import android.hardware.camera2.CameraManager; | |
17 import android.os.Handler; | |
18 import android.os.Looper; | |
19 import android.test.InstrumentationTestCase; | |
20 import android.test.suitebuilder.annotation.LargeTest; | |
21 import android.test.suitebuilder.annotation.MediumTest; | |
22 import android.test.suitebuilder.annotation.SmallTest; | |
23 | |
24 import java.util.concurrent.CountDownLatch; | |
25 | |
26 public class Camera2CapturerTest extends InstrumentationTestCase { | |
27 static final String TAG = "Camera2CapturerTest"; | |
28 | |
29 /** | |
30 * Simple camera2 implementation that only knows how to open the camera and cl
ose it. | |
31 */ | |
32 private class SimpleCamera2 { | |
33 final CameraManager cameraManager; | |
34 final LooperThread looperThread; | |
35 final CountDownLatch openDoneSignal; | |
36 final Object cameraDeviceLock; | |
37 CameraDevice cameraDevice; // Guarded by cameraDeviceLock | |
38 boolean openSucceeded; // Guarded by cameraDeviceLock | |
39 | |
40 private class LooperThread extends Thread { | |
41 final CountDownLatch startedSignal = new CountDownLatch(1); | |
42 private Handler handler; | |
43 | |
44 @Override | |
45 public void run() { | |
46 Looper.prepare(); | |
47 handler = new Handler(); | |
48 startedSignal.countDown(); | |
49 Looper.loop(); | |
50 } | |
51 | |
52 public void waitToStart() { | |
53 ThreadUtils.awaitUninterruptibly(startedSignal); | |
54 } | |
55 | |
56 public void requestStop() { | |
57 handler.getLooper().quit(); | |
58 } | |
59 | |
60 public Handler getHandler() { | |
61 return handler; | |
62 } | |
63 } | |
64 | |
65 private class CameraStateCallback extends CameraDevice.StateCallback { | |
66 @Override | |
67 public void onClosed(CameraDevice cameraDevice) { | |
68 Logging.d(TAG, "Simple camera2 closed."); | |
69 | |
70 synchronized (cameraDeviceLock) { | |
71 SimpleCamera2.this.cameraDevice = null; | |
72 } | |
73 } | |
74 | |
75 @Override | |
76 public void onDisconnected(CameraDevice cameraDevice) { | |
77 Logging.d(TAG, "Simple camera2 disconnected."); | |
78 | |
79 synchronized (cameraDeviceLock) { | |
80 SimpleCamera2.this.cameraDevice = null; | |
81 } | |
82 } | |
83 | |
84 @Override | |
85 public void onError(CameraDevice cameraDevice, int errorCode) { | |
86 Logging.w(TAG, "Simple camera2 error: " + errorCode); | |
87 | |
88 synchronized (cameraDeviceLock) { | |
89 SimpleCamera2.this.cameraDevice = cameraDevice; | |
90 openSucceeded = false; | |
91 } | |
92 | |
93 openDoneSignal.countDown(); | |
94 } | |
95 | |
96 @Override | |
97 public void onOpened(CameraDevice cameraDevice) { | |
98 Logging.d(TAG, "Simple camera2 opened."); | |
99 | |
100 synchronized (cameraDeviceLock) { | |
101 SimpleCamera2.this.cameraDevice = cameraDevice; | |
102 openSucceeded = true; | |
103 } | |
104 | |
105 openDoneSignal.countDown(); | |
106 } | |
107 } | |
108 | |
109 SimpleCamera2(Context context, String deviceName) { | |
110 cameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SE
RVICE); | |
111 looperThread = new LooperThread(); | |
112 looperThread.start(); | |
113 looperThread.waitToStart(); | |
114 cameraDeviceLock = new Object(); | |
115 openDoneSignal = new CountDownLatch(1); | |
116 cameraDevice = null; | |
117 Logging.d(TAG, "Opening simple camera2."); | |
118 try { | |
119 cameraManager.openCamera(deviceName, new CameraStateCallback(), looperTh
read.getHandler()); | |
120 } catch (CameraAccessException e) { | |
121 fail("Simple camera2 CameraAccessException: " + e.getMessage()); | |
122 } | |
123 | |
124 Logging.d(TAG, "Waiting for simple camera2 to open."); | |
125 ThreadUtils.awaitUninterruptibly(openDoneSignal); | |
126 synchronized (cameraDeviceLock) { | |
127 if (!openSucceeded) { | |
128 fail("Opening simple camera2 failed."); | |
129 } | |
130 } | |
131 } | |
132 | |
133 public void close() { | |
134 Logging.d(TAG, "Closing simple camera2."); | |
135 synchronized (cameraDeviceLock) { | |
136 if (cameraDevice != null) { | |
137 cameraDevice.close(); | |
138 } | |
139 } | |
140 | |
141 looperThread.requestStop(); | |
142 ThreadUtils.joinUninterruptibly(looperThread); | |
143 } | |
144 } | |
145 | |
146 private class TestObjectFactory extends CameraVideoCapturerTestFixtures.TestOb
jectFactory { | |
147 @Override | |
148 public CameraEnumerator getCameraEnumerator() { | |
149 return new Camera2Enumerator(getAppContext()); | |
150 } | |
151 | |
152 @Override | |
153 public Context getAppContext() { | |
154 return getInstrumentation().getTargetContext(); | |
155 } | |
156 | |
157 @SuppressWarnings("deprecation") | |
158 @Override | |
159 public Object rawOpenCamera(String cameraName) { | |
160 return new SimpleCamera2(getAppContext(), cameraName); | |
161 } | |
162 | |
163 @SuppressWarnings("deprecation") | |
164 @Override | |
165 public void rawCloseCamera(Object camera) { | |
166 ((SimpleCamera2) camera).close(); | |
167 } | |
168 } | |
169 | |
170 private CameraVideoCapturerTestFixtures fixtures; | |
171 | |
172 @Override | |
173 protected void setUp() { | |
174 fixtures = new CameraVideoCapturerTestFixtures(new TestObjectFactory()); | |
175 } | |
176 | |
177 @Override | |
178 protected void tearDown() { | |
179 fixtures.dispose(); | |
180 } | |
181 | |
182 @SmallTest | |
183 public void testCreateAndDispose() throws InterruptedException { | |
184 fixtures.createCapturerAndDispose(); | |
185 } | |
186 | |
187 @SmallTest | |
188 public void testCreateNonExistingCamera() throws InterruptedException { | |
189 fixtures.createNonExistingCamera(); | |
190 } | |
191 | |
192 // This test that the camera can be started and that the frames are forwarded | |
193 // to a Java video renderer using a "default" capturer. | |
194 // It tests both the Java and the C++ layer. | |
195 @MediumTest | |
196 public void testCreateCapturerAndRender() throws InterruptedException { | |
197 fixtures.createCapturerAndRender(); | |
198 } | |
199 | |
200 // This test that the camera can be started and that the frames are forwarded | |
201 // to a Java video renderer using the front facing video capturer. | |
202 // It tests both the Java and the C++ layer. | |
203 @MediumTest | |
204 public void testStartFrontFacingVideoCapturer() throws InterruptedException { | |
205 fixtures.createFrontFacingCapturerAndRender(); | |
206 } | |
207 | |
208 // This test that the camera can be started and that the frames are forwarded | |
209 // to a Java video renderer using the back facing video capturer. | |
210 // It tests both the Java and the C++ layer. | |
211 @MediumTest | |
212 public void testStartBackFacingVideoCapturer() throws InterruptedException { | |
213 fixtures.createBackFacingCapturerAndRender(); | |
214 } | |
215 | |
216 // This test that the default camera can be started and that the camera can | |
217 // later be switched to another camera. | |
218 // It tests both the Java and the C++ layer. | |
219 @MediumTest | |
220 public void testSwitchVideoCapturer() throws InterruptedException { | |
221 fixtures.switchCamera(); | |
222 } | |
223 | |
224 @MediumTest | |
225 public void testCameraEvents() throws InterruptedException { | |
226 fixtures.cameraEventsInvoked(); | |
227 } | |
228 | |
229 // Test what happens when attempting to call e.g. switchCamera() after camera
has been stopped. | |
230 @MediumTest | |
231 public void testCameraCallsAfterStop() throws InterruptedException { | |
232 fixtures.cameraCallsAfterStop(); | |
233 } | |
234 | |
235 // This test that the VideoSource that the CameraVideoCapturer is connected to
can | |
236 // be stopped and restarted. It tests both the Java and the C++ layer. | |
237 @LargeTest | |
238 public void testStopRestartVideoSource() throws InterruptedException { | |
239 fixtures.stopRestartVideoSource(); | |
240 } | |
241 | |
242 // This test that the camera can be started at different resolutions. | |
243 // It does not test or use the C++ layer. | |
244 @LargeTest | |
245 public void testStartStopWithDifferentResolutions() throws InterruptedExceptio
n { | |
246 fixtures.startStopWithDifferentResolutions(); | |
247 } | |
248 | |
249 // This test what happens if buffers are returned after the capturer have | |
250 // been stopped and restarted. It does not test or use the C++ layer. | |
251 @LargeTest | |
252 public void testReturnBufferLate() throws InterruptedException { | |
253 fixtures.returnBufferLate(); | |
254 } | |
255 | |
256 // This test that we can capture frames, keep the frames in a local renderer,
stop capturing, | |
257 // and then return the frames. The difference between the test testReturnBuffe
rLate() is that we | |
258 // also test the JNI and C++ AndroidVideoCapturer parts. | |
259 @MediumTest | |
260 public void testReturnBufferLateEndToEnd() throws InterruptedException { | |
261 fixtures.returnBufferLateEndToEnd(); | |
262 } | |
263 | |
264 // This test that CameraEventsHandler.onError is triggered if video buffers ar
e not returned to | |
265 // the capturer. | |
266 @LargeTest | |
267 public void testCameraFreezedEventOnBufferStarvation() throws InterruptedExcep
tion { | |
268 fixtures.cameraFreezedEventOnBufferStarvation(); | |
269 } | |
270 | |
271 // This test that frames forwarded to a renderer is scaled if adaptOutputForma
t is | |
272 // called. This test both Java and C++ parts of of the stack. | |
273 @MediumTest | |
274 public void testScaleCameraOutput() throws InterruptedException { | |
275 fixtures.scaleCameraOutput(); | |
276 } | |
277 | |
278 // This test that an error is reported if the camera is already opened | |
279 // when CameraVideoCapturer is started. | |
280 @LargeTest | |
281 public void testStartWhileCameraIsAlreadyOpen() throws InterruptedException { | |
282 fixtures.startWhileCameraIsAlreadyOpen(); | |
283 } | |
284 | |
285 // This test that CameraVideoCapturer can be started, even if the camera is al
ready opened | |
286 // if the camera is closed while CameraVideoCapturer is re-trying to start. | |
287 @LargeTest | |
288 public void testStartWhileCameraIsAlreadyOpenAndCloseCamera() throws Interrupt
edException { | |
289 fixtures.startWhileCameraIsAlreadyOpenAndCloseCamera(); | |
290 } | |
291 | |
292 // This test that CameraVideoCapturer.stop can be called while CameraVideoCapt
urer is | |
293 // re-trying to start. | |
294 @MediumTest | |
295 public void testStartWhileCameraIsAlreadyOpenAndStop() throws InterruptedExcep
tion { | |
296 fixtures.startWhileCameraIsAlreadyOpenAndStop(); | |
297 } | |
298 } | |
OLD | NEW |