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 16 matching lines...) Expand all Loading... | |
27 private static final String TAG = "CameraCapturer"; | 27 private static final String TAG = "CameraCapturer"; |
28 private final static int MAX_OPEN_CAMERA_ATTEMPTS = 3; | 28 private final static int MAX_OPEN_CAMERA_ATTEMPTS = 3; |
29 private final static int OPEN_CAMERA_DELAY_MS = 500; | 29 private final static int OPEN_CAMERA_DELAY_MS = 500; |
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() { |
magjed_webrtc
2016/09/16 09:00:37
It would be nice with checkIsOnCameraThread for on
sakal
2016/09/16 12:38:58
Done.
| |
38 @Override | 38 @Override |
39 public void onDone(CameraSession session) { | 39 public void onDone(CameraSession session) { |
40 Logging.d(TAG, "Create session done"); | 40 Logging.d(TAG, "Create session done"); |
41 uiThreadHandler.removeCallbacks(openCameraTimeoutRunnable); | 41 uiThreadHandler.removeCallbacks(openCameraTimeoutRunnable); |
42 capturerObserver.onCapturerStarted(true /* success */); | |
42 synchronized (stateLock) { | 43 synchronized (stateLock) { |
43 sessionOpening = false; | 44 sessionOpening = false; |
44 currentSession = session; | 45 currentSession = session; |
45 stateLock.notifyAll(); | 46 stateLock.notifyAll(); |
46 | 47 |
47 if (switchState == SwitchState.IN_PROGRESS) { | 48 if (switchState == SwitchState.IN_PROGRESS) { |
48 if (switchEventsHandler != null) { | 49 if (switchEventsHandler != null) { |
49 switchEventsHandler.onCameraSwitchDone( | 50 switchEventsHandler.onCameraSwitchDone( |
50 cameraEnumerator.isFrontFacing(cameraName)); | 51 cameraEnumerator.isFrontFacing(cameraName)); |
51 switchEventsHandler = null; | 52 switchEventsHandler = null; |
52 } | 53 } |
53 switchState = SwitchState.IDLE; | 54 switchState = SwitchState.IDLE; |
54 } else if (switchState == SwitchState.PENDING) { | 55 } else if (switchState == SwitchState.PENDING) { |
55 switchState = SwitchState.IDLE; | 56 switchState = SwitchState.IDLE; |
56 switchCameraInternal(switchEventsHandler); | 57 switchCameraInternal(switchEventsHandler); |
57 } | 58 } |
59 | |
60 cameraStatistics = new CameraStatistics(surfaceHelper, eventsHandler ); | |
61 firstFrameObserved = false; | |
58 } | 62 } |
59 } | 63 } |
60 | 64 |
61 @Override | 65 @Override |
62 public void onFailure(String error) { | 66 public void onFailure(String error) { |
63 uiThreadHandler.removeCallbacks(openCameraTimeoutRunnable); | 67 uiThreadHandler.removeCallbacks(openCameraTimeoutRunnable); |
68 capturerObserver.onCapturerStarted(false /* success */); | |
64 synchronized (stateLock) { | 69 synchronized (stateLock) { |
65 openAttemptsRemaining--; | 70 openAttemptsRemaining--; |
66 | 71 |
67 if (openAttemptsRemaining <= 0) { | 72 if (openAttemptsRemaining <= 0) { |
68 Logging.w(TAG, "Opening camera failed, passing: " + error); | 73 Logging.w(TAG, "Opening camera failed, passing: " + error); |
69 sessionOpening = false; | 74 sessionOpening = false; |
70 stateLock.notifyAll(); | 75 stateLock.notifyAll(); |
71 | 76 |
72 if (switchState != SwitchState.IDLE) { | 77 if (switchState != SwitchState.IDLE) { |
73 if (switchEventsHandler != null) { | 78 if (switchEventsHandler != null) { |
74 switchEventsHandler.onCameraSwitchError(error); | 79 switchEventsHandler.onCameraSwitchError(error); |
75 switchEventsHandler = null; | 80 switchEventsHandler = null; |
76 } | 81 } |
77 switchState = SwitchState.IDLE; | 82 switchState = SwitchState.IDLE; |
78 } | 83 } |
79 | 84 |
80 eventsHandler.onCameraError(error); | 85 eventsHandler.onCameraError(error); |
81 } else { | 86 } else { |
82 Logging.w(TAG, "Opening camera failed, retry: " + error); | 87 Logging.w(TAG, "Opening camera failed, retry: " + error); |
83 | 88 |
84 createSessionInternal(OPEN_CAMERA_DELAY_MS); | 89 createSessionInternal(OPEN_CAMERA_DELAY_MS); |
85 } | 90 } |
86 } | 91 } |
87 } | 92 } |
88 }; | 93 }; |
89 | 94 |
95 private final CameraSession.Events cameraSessionEventsHandler = | |
96 new CameraSession.Events() { | |
magjed_webrtc
2016/09/16 09:00:37
nit: Can you move 'new CameraSession.Events() {' u
sakal
2016/09/16 12:38:58
Done.
| |
97 public void onCameraError(CameraSession session, String error) { | |
magjed_webrtc
2016/09/16 09:00:37
It would be nice with checkIsOnCameraThread checks
sakal
2016/09/16 12:38:59
Done.
| |
98 synchronized (stateLock) { | |
99 if (session != currentSession) { | |
100 Logging.w(TAG, "onCameraError from another session: " + error); | |
101 return; | |
102 } | |
103 eventsHandler.onCameraError(error); | |
104 stopCapture(); | |
105 } | |
106 } | |
107 | |
108 public void onCameraOpening(CameraSession session) { | |
109 synchronized (stateLock) { | |
110 if (currentSession != null) { | |
111 Logging.w(TAG, "onCameraOpening while session was open."); | |
112 return; | |
113 } | |
114 eventsHandler.onCameraOpening(cameraName); | |
115 } | |
116 } | |
117 | |
118 public void onCameraClosed(CameraSession session) { | |
119 synchronized (stateLock) { | |
120 if (session != currentSession && currentSession != null) { | |
121 Logging.d(TAG, "onCameraClosed from another session."); | |
122 return; | |
123 } | |
124 eventsHandler.onCameraClosed(); | |
magjed_webrtc
2016/09/15 14:58:06
Now we hold stateLock while making the callbacks.
sakal
2016/09/15 15:08:18
If the callbacks invoke method on other threads, d
| |
125 } | |
126 } | |
127 | |
128 public void onByteBufferFrameCaptured( | |
129 CameraSession session, byte[] data, int width, int height, int rotat ion, | |
130 long timestamp) { | |
131 synchronized (stateLock) { | |
132 if (session != currentSession) { | |
magjed_webrtc
2016/09/15 14:58:06
Can we drop frames if we are in an incorrect state
sakal
2016/09/15 15:08:18
I am not sure what you mean. The stopping state is
magjed_webrtc
2016/09/16 09:00:37
I was thinking if the frame dropping in the sessio
sakal
2016/09/16 12:38:58
It is already redundant since we don't keep closed
magjed_webrtc
2016/09/16 12:59:19
Good, no keep it.
| |
133 Logging.w(TAG, "onByteBufferFrameCaptured from another session."); | |
134 return; | |
135 } | |
136 if (!firstFrameObserved) { | |
137 eventsHandler.onFirstFrameAvailable(); | |
138 firstFrameObserved = true; | |
139 } | |
140 cameraStatistics.addFrame(); | |
141 capturerObserver.onByteBufferFrameCaptured(data, width, height, rota tion, timestamp); | |
142 } | |
143 } | |
144 | |
145 public void onTextureFrameCaptured( | |
146 CameraSession session, int width, int height, int oesTextureId, floa t[] transformMatrix, | |
147 int rotation, long timestamp) { | |
148 synchronized (stateLock) { | |
149 if (session != currentSession) { | |
150 Logging.w(TAG, "onTextureFrameCaptured from another session."); | |
151 return; | |
152 } | |
153 if (!firstFrameObserved) { | |
154 eventsHandler.onFirstFrameAvailable(); | |
155 firstFrameObserved = true; | |
156 } | |
157 cameraStatistics.addFrame(); | |
158 capturerObserver.onTextureFrameCaptured( | |
159 width, height, oesTextureId, transformMatrix, rotation, timestam p); | |
160 } | |
161 } | |
162 }; | |
163 | |
90 private final Runnable openCameraTimeoutRunnable = new Runnable() { | 164 private final Runnable openCameraTimeoutRunnable = new Runnable() { |
91 @Override | 165 @Override |
92 public void run() { | 166 public void run() { |
93 eventsHandler.onCameraError("Camera failed to start within timeout."); | 167 eventsHandler.onCameraError("Camera failed to start within timeout."); |
94 } | 168 } |
95 }; | 169 }; |
96 | 170 |
97 // Initialized on initialize | 171 // Initialized on initialize |
98 // ------------------------- | 172 // ------------------------- |
99 private Handler cameraThreadHandler; | 173 private Handler cameraThreadHandler; |
100 private Context applicationContext; | 174 private Context applicationContext; |
101 private CapturerObserver capturerObserver; | 175 private CapturerObserver capturerObserver; |
102 private SurfaceTextureHelper surfaceHelper; | 176 private SurfaceTextureHelper surfaceHelper; |
103 | 177 |
104 private final Object stateLock = new Object(); | 178 private final Object stateLock = new Object(); |
105 private boolean sessionOpening; /* guarded by stateLock */ | 179 private boolean sessionOpening; /* guarded by stateLock */ |
106 private CameraSession currentSession; /* guarded by stateLock */ | 180 private CameraSession currentSession; /* guarded by stateLock */ |
107 private String cameraName; /* guarded by stateLock */ | 181 private String cameraName; /* guarded by stateLock */ |
108 private int width; /* guarded by stateLock */ | 182 private int width; /* guarded by stateLock */ |
109 private int height; /* guarded by stateLock */ | 183 private int height; /* guarded by stateLock */ |
110 private int framerate; /* guarded by stateLock */ | 184 private int framerate; /* guarded by stateLock */ |
111 private int openAttemptsRemaining; /* guarded by stateLock */ | 185 private int openAttemptsRemaining; /* guarded by stateLock */ |
112 private SwitchState switchState = SwitchState.IDLE; /* guarded by stateLock */ | 186 private SwitchState switchState = SwitchState.IDLE; /* guarded by stateLock */ |
113 private CameraSwitchHandler switchEventsHandler; /* guarded by stateLock */ | 187 private CameraSwitchHandler switchEventsHandler; /* guarded by stateLock */ |
188 // Valid from onDone call until stopCapture, otherwise null. | |
189 private CameraStatistics cameraStatistics; /* guarded by stateLock */ | |
190 private boolean firstFrameObserved; /* guarded by stateLock */ | |
114 | 191 |
115 public CameraCapturer( | 192 public CameraCapturer( |
116 String cameraName, CameraEventsHandler eventsHandler, CameraEnumerator cam eraEnumerator) { | 193 String cameraName, CameraEventsHandler eventsHandler, CameraEnumerator cam eraEnumerator) { |
117 if (eventsHandler == null) { | 194 if (eventsHandler == null) { |
118 eventsHandler = new CameraEventsHandler() { | 195 eventsHandler = new CameraEventsHandler() { |
119 @Override | 196 @Override |
120 public void onCameraError(String errorDescription) {} | 197 public void onCameraError(String errorDescription) {} |
121 @Override | 198 @Override |
122 public void onCameraFreezed(String errorDescription) {} | 199 public void onCameraFreezed(String errorDescription) {} |
123 @Override | 200 @Override |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
174 createSessionInternal(0); | 251 createSessionInternal(0); |
175 } | 252 } |
176 } | 253 } |
177 | 254 |
178 private void createSessionInternal(int delayMs) { | 255 private void createSessionInternal(int delayMs) { |
179 uiThreadHandler.postDelayed(openCameraTimeoutRunnable, delayMs + OPEN_CAMERA _TIMEOUT); | 256 uiThreadHandler.postDelayed(openCameraTimeoutRunnable, delayMs + OPEN_CAMERA _TIMEOUT); |
180 cameraThreadHandler.postDelayed(new Runnable() { | 257 cameraThreadHandler.postDelayed(new Runnable() { |
181 @Override | 258 @Override |
182 public void run() { | 259 public void run() { |
183 createCameraSession( | 260 createCameraSession( |
184 createSessionCallback, | 261 createSessionCallback, cameraSessionEventsHandler, applicationContex t, surfaceHelper, |
185 eventsHandler, applicationContext, capturerObserver, surfaceHelper, | |
186 cameraName, width, height, framerate); | 262 cameraName, width, height, framerate); |
187 } | 263 } |
188 }, delayMs); | 264 }, delayMs); |
189 } | 265 } |
190 | 266 |
191 @Override | 267 @Override |
192 public void stopCapture() { | 268 public void stopCapture() { |
193 Logging.d(TAG, "Stop capture"); | 269 Logging.d(TAG, "Stop capture"); |
194 | 270 |
195 synchronized (stateLock) { | 271 synchronized (stateLock) { |
196 while (sessionOpening) { | 272 while (sessionOpening) { |
197 Logging.d(TAG, "Stop capture: Waiting for session to open"); | 273 Logging.d(TAG, "Stop capture: Waiting for session to open"); |
198 ThreadUtils.waitUninterruptibly(stateLock); | 274 ThreadUtils.waitUninterruptibly(stateLock); |
199 } | 275 } |
200 | 276 |
201 if (currentSession != null) { | 277 if (currentSession != null) { |
202 Logging.d(TAG, "Stop capture: Stopping session"); | 278 cameraStatistics.release(); |
279 cameraStatistics = null; | |
203 currentSession.stop(); | 280 currentSession.stop(); |
204 currentSession = null; | 281 currentSession = null; |
282 capturerObserver.onCapturerStopped(); | |
205 } else { | 283 } else { |
206 Logging.d(TAG, "Stop capture: No session open"); | 284 Logging.d(TAG, "Stop capture: No session open"); |
207 } | 285 } |
208 } | 286 } |
209 | 287 |
210 Logging.d(TAG, "Stop capture done"); | 288 Logging.d(TAG, "Stop capture done"); |
211 } | 289 } |
212 | 290 |
213 @Override | 291 @Override |
214 public void onOutputFormatRequest(final int width, final int height, final int framerate) { | 292 public void onOutputFormatRequest(final int width, final int height, final int framerate) { |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
319 Logging.d(TAG, "switchCamera done"); | 397 Logging.d(TAG, "switchCamera done"); |
320 } | 398 } |
321 | 399 |
322 protected String getCameraName() { | 400 protected String getCameraName() { |
323 synchronized (stateLock) { | 401 synchronized (stateLock) { |
324 return cameraName; | 402 return cameraName; |
325 } | 403 } |
326 } | 404 } |
327 | 405 |
328 abstract protected void createCameraSession( | 406 abstract protected void createCameraSession( |
329 CameraSession.CreateSessionCallback createSessionCallback, | 407 CameraSession.CreateSessionCallback createSessionCallback, CameraSession.E vents events, |
330 CameraEventsHandler eventsHandler, Context applicationContext, | 408 Context applicationContext, SurfaceTextureHelper surfaceTextureHelper, |
331 CameraVideoCapturer.CapturerObserver capturerObserver, | |
332 SurfaceTextureHelper surfaceTextureHelper, | |
333 String cameraName, int width, int height, int framerate); | 409 String cameraName, int width, int height, int framerate); |
334 } | 410 } |
OLD | NEW |