OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2016 The WebRTC project authors. All Rights Reserved. | 2 * Copyright 2016 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 | 10 |
(...skipping 19 matching lines...) Expand all Loading... |
30 private final static int OPEN_CAMERA_TIMEOUT = 10000; | 30 private final static int OPEN_CAMERA_TIMEOUT = 10000; |
31 | 31 |
32 private final CameraEnumerator cameraEnumerator; | 32 private final CameraEnumerator cameraEnumerator; |
33 private final CameraEventsHandler eventsHandler; | 33 private final CameraEventsHandler eventsHandler; |
34 private final Handler uiThreadHandler; | 34 private final Handler uiThreadHandler; |
35 | 35 |
36 private final CameraSession.CreateSessionCallback createSessionCallback = | 36 private final CameraSession.CreateSessionCallback createSessionCallback = |
37 new CameraSession.CreateSessionCallback() { | 37 new CameraSession.CreateSessionCallback() { |
38 @Override | 38 @Override |
39 public void onDone(CameraSession session) { | 39 public void onDone(CameraSession session) { |
| 40 checkIsOnCameraThread(); |
40 Logging.d(TAG, "Create session done"); | 41 Logging.d(TAG, "Create session done"); |
41 uiThreadHandler.removeCallbacks(openCameraTimeoutRunnable); | 42 uiThreadHandler.removeCallbacks(openCameraTimeoutRunnable); |
| 43 capturerObserver.onCapturerStarted(true /* success */); |
42 synchronized (stateLock) { | 44 synchronized (stateLock) { |
43 sessionOpening = false; | 45 sessionOpening = false; |
44 currentSession = session; | 46 currentSession = session; |
45 stateLock.notifyAll(); | 47 stateLock.notifyAll(); |
46 | 48 |
47 if (switchState == SwitchState.IN_PROGRESS) { | 49 if (switchState == SwitchState.IN_PROGRESS) { |
48 if (switchEventsHandler != null) { | 50 if (switchEventsHandler != null) { |
49 switchEventsHandler.onCameraSwitchDone( | 51 switchEventsHandler.onCameraSwitchDone( |
50 cameraEnumerator.isFrontFacing(cameraName)); | 52 cameraEnumerator.isFrontFacing(cameraName)); |
51 switchEventsHandler = null; | 53 switchEventsHandler = null; |
52 } | 54 } |
53 switchState = SwitchState.IDLE; | 55 switchState = SwitchState.IDLE; |
54 } else if (switchState == SwitchState.PENDING) { | 56 } else if (switchState == SwitchState.PENDING) { |
55 switchState = SwitchState.IDLE; | 57 switchState = SwitchState.IDLE; |
56 switchCameraInternal(switchEventsHandler); | 58 switchCameraInternal(switchEventsHandler); |
57 } | 59 } |
| 60 |
| 61 cameraStatistics = new CameraStatistics(surfaceHelper, eventsHandler
); |
| 62 firstFrameObserved = false; |
58 } | 63 } |
59 } | 64 } |
60 | 65 |
61 @Override | 66 @Override |
62 public void onFailure(String error) { | 67 public void onFailure(String error) { |
| 68 checkIsOnCameraThread(); |
63 uiThreadHandler.removeCallbacks(openCameraTimeoutRunnable); | 69 uiThreadHandler.removeCallbacks(openCameraTimeoutRunnable); |
| 70 capturerObserver.onCapturerStarted(false /* success */); |
64 synchronized (stateLock) { | 71 synchronized (stateLock) { |
65 openAttemptsRemaining--; | 72 openAttemptsRemaining--; |
66 | 73 |
67 if (openAttemptsRemaining <= 0) { | 74 if (openAttemptsRemaining <= 0) { |
68 Logging.w(TAG, "Opening camera failed, passing: " + error); | 75 Logging.w(TAG, "Opening camera failed, passing: " + error); |
69 sessionOpening = false; | 76 sessionOpening = false; |
70 stateLock.notifyAll(); | 77 stateLock.notifyAll(); |
71 | 78 |
72 if (switchState != SwitchState.IDLE) { | 79 if (switchState != SwitchState.IDLE) { |
73 if (switchEventsHandler != null) { | 80 if (switchEventsHandler != null) { |
74 switchEventsHandler.onCameraSwitchError(error); | 81 switchEventsHandler.onCameraSwitchError(error); |
75 switchEventsHandler = null; | 82 switchEventsHandler = null; |
76 } | 83 } |
77 switchState = SwitchState.IDLE; | 84 switchState = SwitchState.IDLE; |
78 } | 85 } |
79 | 86 |
80 eventsHandler.onCameraError(error); | 87 eventsHandler.onCameraError(error); |
81 } else { | 88 } else { |
82 Logging.w(TAG, "Opening camera failed, retry: " + error); | 89 Logging.w(TAG, "Opening camera failed, retry: " + error); |
83 | 90 |
84 createSessionInternal(OPEN_CAMERA_DELAY_MS); | 91 createSessionInternal(OPEN_CAMERA_DELAY_MS); |
85 } | 92 } |
86 } | 93 } |
87 } | 94 } |
88 }; | 95 }; |
89 | 96 |
| 97 private final CameraSession.Events cameraSessionEventsHandler = new CameraSess
ion.Events() { |
| 98 @Override |
| 99 public void onCameraOpening() { |
| 100 checkIsOnCameraThread(); |
| 101 synchronized (stateLock) { |
| 102 if (currentSession != null) { |
| 103 Logging.w(TAG, "onCameraOpening while session was open."); |
| 104 return; |
| 105 } |
| 106 eventsHandler.onCameraOpening(cameraName); |
| 107 } |
| 108 } |
| 109 |
| 110 @Override |
| 111 public void onCameraError(CameraSession session, String error) { |
| 112 checkIsOnCameraThread(); |
| 113 synchronized (stateLock) { |
| 114 if (session != currentSession) { |
| 115 Logging.w(TAG, "onCameraError from another session: " + error); |
| 116 return; |
| 117 } |
| 118 eventsHandler.onCameraError(error); |
| 119 stopCapture(); |
| 120 } |
| 121 } |
| 122 |
| 123 @Override |
| 124 public void onCameraClosed(CameraSession session) { |
| 125 checkIsOnCameraThread(); |
| 126 synchronized (stateLock) { |
| 127 if (session != currentSession && currentSession != null) { |
| 128 Logging.d(TAG, "onCameraClosed from another session."); |
| 129 return; |
| 130 } |
| 131 eventsHandler.onCameraClosed(); |
| 132 } |
| 133 } |
| 134 |
| 135 @Override |
| 136 public void onByteBufferFrameCaptured( |
| 137 CameraSession session, byte[] data, int width, int height, int rotation, |
| 138 long timestamp) { |
| 139 checkIsOnCameraThread(); |
| 140 synchronized (stateLock) { |
| 141 if (session != currentSession) { |
| 142 Logging.w(TAG, "onByteBufferFrameCaptured from another session."); |
| 143 return; |
| 144 } |
| 145 if (!firstFrameObserved) { |
| 146 eventsHandler.onFirstFrameAvailable(); |
| 147 firstFrameObserved = true; |
| 148 } |
| 149 cameraStatistics.addFrame(); |
| 150 capturerObserver.onByteBufferFrameCaptured(data, width, height, rotation
, timestamp); |
| 151 } |
| 152 } |
| 153 |
| 154 @Override |
| 155 public void onTextureFrameCaptured( |
| 156 CameraSession session, int width, int height, int oesTextureId, float[]
transformMatrix, |
| 157 int rotation, long timestamp) { |
| 158 checkIsOnCameraThread(); |
| 159 synchronized (stateLock) { |
| 160 if (session != currentSession) { |
| 161 Logging.w(TAG, "onTextureFrameCaptured from another session."); |
| 162 return; |
| 163 } |
| 164 if (!firstFrameObserved) { |
| 165 eventsHandler.onFirstFrameAvailable(); |
| 166 firstFrameObserved = true; |
| 167 } |
| 168 cameraStatistics.addFrame(); |
| 169 capturerObserver.onTextureFrameCaptured( |
| 170 width, height, oesTextureId, transformMatrix, rotation, timestamp); |
| 171 } |
| 172 } |
| 173 }; |
| 174 |
90 private final Runnable openCameraTimeoutRunnable = new Runnable() { | 175 private final Runnable openCameraTimeoutRunnable = new Runnable() { |
91 @Override | 176 @Override |
92 public void run() { | 177 public void run() { |
93 eventsHandler.onCameraError("Camera failed to start within timeout."); | 178 eventsHandler.onCameraError("Camera failed to start within timeout."); |
94 } | 179 } |
95 }; | 180 }; |
96 | 181 |
97 // Initialized on initialize | 182 // Initialized on initialize |
98 // ------------------------- | 183 // ------------------------- |
99 private Handler cameraThreadHandler; | 184 private Handler cameraThreadHandler; |
100 private Context applicationContext; | 185 private Context applicationContext; |
101 private CapturerObserver capturerObserver; | 186 private CapturerObserver capturerObserver; |
102 private SurfaceTextureHelper surfaceHelper; | 187 private SurfaceTextureHelper surfaceHelper; |
103 | 188 |
104 private final Object stateLock = new Object(); | 189 private final Object stateLock = new Object(); |
105 private boolean sessionOpening; /* guarded by stateLock */ | 190 private boolean sessionOpening; /* guarded by stateLock */ |
106 private CameraSession currentSession; /* guarded by stateLock */ | 191 private CameraSession currentSession; /* guarded by stateLock */ |
107 private String cameraName; /* guarded by stateLock */ | 192 private String cameraName; /* guarded by stateLock */ |
108 private int width; /* guarded by stateLock */ | 193 private int width; /* guarded by stateLock */ |
109 private int height; /* guarded by stateLock */ | 194 private int height; /* guarded by stateLock */ |
110 private int framerate; /* guarded by stateLock */ | 195 private int framerate; /* guarded by stateLock */ |
111 private int openAttemptsRemaining; /* guarded by stateLock */ | 196 private int openAttemptsRemaining; /* guarded by stateLock */ |
112 private SwitchState switchState = SwitchState.IDLE; /* guarded by stateLock */ | 197 private SwitchState switchState = SwitchState.IDLE; /* guarded by stateLock */ |
113 private CameraSwitchHandler switchEventsHandler; /* guarded by stateLock */ | 198 private CameraSwitchHandler switchEventsHandler; /* guarded by stateLock */ |
| 199 // Valid from onDone call until stopCapture, otherwise null. |
| 200 private CameraStatistics cameraStatistics; /* guarded by stateLock */ |
| 201 private boolean firstFrameObserved; /* guarded by stateLock */ |
114 | 202 |
115 public CameraCapturer( | 203 public CameraCapturer( |
116 String cameraName, CameraEventsHandler eventsHandler, CameraEnumerator cam
eraEnumerator) { | 204 String cameraName, CameraEventsHandler eventsHandler, CameraEnumerator cam
eraEnumerator) { |
117 if (eventsHandler == null) { | 205 if (eventsHandler == null) { |
118 eventsHandler = new CameraEventsHandler() { | 206 eventsHandler = new CameraEventsHandler() { |
119 @Override | 207 @Override |
120 public void onCameraError(String errorDescription) {} | 208 public void onCameraError(String errorDescription) {} |
121 @Override | 209 @Override |
122 public void onCameraFreezed(String errorDescription) {} | 210 public void onCameraFreezed(String errorDescription) {} |
123 @Override | 211 @Override |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
174 createSessionInternal(0); | 262 createSessionInternal(0); |
175 } | 263 } |
176 } | 264 } |
177 | 265 |
178 private void createSessionInternal(int delayMs) { | 266 private void createSessionInternal(int delayMs) { |
179 uiThreadHandler.postDelayed(openCameraTimeoutRunnable, delayMs + OPEN_CAMERA
_TIMEOUT); | 267 uiThreadHandler.postDelayed(openCameraTimeoutRunnable, delayMs + OPEN_CAMERA
_TIMEOUT); |
180 cameraThreadHandler.postDelayed(new Runnable() { | 268 cameraThreadHandler.postDelayed(new Runnable() { |
181 @Override | 269 @Override |
182 public void run() { | 270 public void run() { |
183 createCameraSession( | 271 createCameraSession( |
184 createSessionCallback, | 272 createSessionCallback, cameraSessionEventsHandler, applicationContex
t, surfaceHelper, |
185 eventsHandler, applicationContext, capturerObserver, surfaceHelper, | |
186 cameraName, width, height, framerate); | 273 cameraName, width, height, framerate); |
187 } | 274 } |
188 }, delayMs); | 275 }, delayMs); |
189 } | 276 } |
190 | 277 |
191 @Override | 278 @Override |
192 public void stopCapture() { | 279 public void stopCapture() { |
193 Logging.d(TAG, "Stop capture"); | 280 Logging.d(TAG, "Stop capture"); |
194 | 281 |
195 synchronized (stateLock) { | 282 synchronized (stateLock) { |
196 while (sessionOpening) { | 283 while (sessionOpening) { |
197 Logging.d(TAG, "Stop capture: Waiting for session to open"); | 284 Logging.d(TAG, "Stop capture: Waiting for session to open"); |
198 ThreadUtils.waitUninterruptibly(stateLock); | 285 ThreadUtils.waitUninterruptibly(stateLock); |
199 } | 286 } |
200 | 287 |
201 if (currentSession != null) { | 288 if (currentSession != null) { |
202 Logging.d(TAG, "Stop capture: Stopping session"); | 289 Logging.d(TAG, "Stop capture: Stopping session"); |
| 290 cameraStatistics.release(); |
| 291 cameraStatistics = null; |
203 currentSession.stop(); | 292 currentSession.stop(); |
204 currentSession = null; | 293 currentSession = null; |
| 294 capturerObserver.onCapturerStopped(); |
205 } else { | 295 } else { |
206 Logging.d(TAG, "Stop capture: No session open"); | 296 Logging.d(TAG, "Stop capture: No session open"); |
207 } | 297 } |
208 } | 298 } |
209 | 299 |
210 Logging.d(TAG, "Stop capture done"); | 300 Logging.d(TAG, "Stop capture done"); |
211 } | 301 } |
212 | 302 |
213 @Override | 303 @Override |
214 public void onOutputFormatRequest(final int width, final int height, final int
framerate) { | 304 public void onOutputFormatRequest(final int width, final int height, final int
framerate) { |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
312 int cameraNameIndex = Arrays.asList(deviceNames).indexOf(cameraName); | 402 int cameraNameIndex = Arrays.asList(deviceNames).indexOf(cameraName); |
313 cameraName = deviceNames[(cameraNameIndex + 1) % deviceNames.length]; | 403 cameraName = deviceNames[(cameraNameIndex + 1) % deviceNames.length]; |
314 | 404 |
315 sessionOpening = true; | 405 sessionOpening = true; |
316 openAttemptsRemaining = 1; | 406 openAttemptsRemaining = 1; |
317 createSessionInternal(0); | 407 createSessionInternal(0); |
318 } | 408 } |
319 Logging.d(TAG, "switchCamera done"); | 409 Logging.d(TAG, "switchCamera done"); |
320 } | 410 } |
321 | 411 |
| 412 private void checkIsOnCameraThread() { |
| 413 if (Thread.currentThread() != cameraThreadHandler.getLooper().getThread()) { |
| 414 Logging.e(TAG, "Check is on camera thread failed."); |
| 415 throw new RuntimeException("Not on camera thread."); |
| 416 } |
| 417 } |
| 418 |
322 protected String getCameraName() { | 419 protected String getCameraName() { |
323 synchronized (stateLock) { | 420 synchronized (stateLock) { |
324 return cameraName; | 421 return cameraName; |
325 } | 422 } |
326 } | 423 } |
327 | 424 |
328 abstract protected void createCameraSession( | 425 abstract protected void createCameraSession( |
329 CameraSession.CreateSessionCallback createSessionCallback, | 426 CameraSession.CreateSessionCallback createSessionCallback, CameraSession.E
vents events, |
330 CameraEventsHandler eventsHandler, Context applicationContext, | 427 Context applicationContext, SurfaceTextureHelper surfaceTextureHelper, |
331 CameraVideoCapturer.CapturerObserver capturerObserver, | |
332 SurfaceTextureHelper surfaceTextureHelper, | |
333 String cameraName, int width, int height, int framerate); | 428 String cameraName, int width, int height, int framerate); |
334 } | 429 } |
OLD | NEW |