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

Side by Side Diff: webrtc/api/android/java/src/org/webrtc/Camera1Session.java

Issue 2187293002: Session based capturing for Camera1Capturer. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@camera2session
Patch Set: Add missing setPictureSize. Created 4 years, 3 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
« no previous file with comments | « webrtc/api/android/java/src/org/webrtc/Camera1Capturer.java ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 org.webrtc.CameraEnumerationAndroid.CaptureFormat;
14 import org.webrtc.Metrics.Histogram;
15
16 import android.content.Context;
17 import android.os.Handler;
18 import android.os.SystemClock;
19 import android.view.Surface;
20 import android.view.WindowManager;
21
22 import java.io.IOException;
23 import java.nio.ByteBuffer;
24 import java.util.List;
25 import java.util.concurrent.CountDownLatch;
26 import java.util.concurrent.TimeUnit;
27
28 @SuppressWarnings("deprecation")
29 public class Camera1Session implements CameraSession {
30 private static final String TAG = "Camera1Session";
31 private static final int NUMBER_OF_CAPTURE_BUFFERS = 3;
32
33 private static final Histogram camera1StartTimeMsHistogram =
34 Histogram.createCounts("WebRTC.Android.Camera1.StartTimeMs", 1, 10000, 50) ;
35 private static final Histogram camera1StopTimeMsHistogram =
36 Histogram.createCounts("WebRTC.Android.Camera1.StopTimeMs", 1, 10000, 50);
37
38 private static enum SessionState { RUNNING, STOPPED };
39
40 private final Handler cameraThreadHandler;
41 private final Events events;
42 private final boolean captureToTexture;
43 private final Context applicationContext;
44 private final SurfaceTextureHelper surfaceTextureHelper;
45 private final int cameraId;
46 private final int width;
47 private final int height;
48 private final int framerate;
49 private final android.hardware.Camera camera;
50 private final android.hardware.Camera.CameraInfo info;
51 private final CaptureFormat captureFormat;
52 // Used only for stats. Only used on the camera thread.
53 private final long constructionTimeNs; // Construction time of this class.
54
55 private SessionState state;
56 private boolean firstFrameReported = false;
57
58 public static void create(
59 final CreateSessionCallback callback, final Events events,
60 final boolean captureToTexture, final Context applicationContext,
61 final SurfaceTextureHelper surfaceTextureHelper,
62 final int cameraId, final int width, final int height, final int framerate ) {
63 final long constructionTimeNs = System.nanoTime();
64 Logging.d(TAG, "Open camera " + cameraId);
65 events.onCameraOpening();
66
67 final android.hardware.Camera camera;
68 try {
69 camera = android.hardware.Camera.open(cameraId);
70 } catch (RuntimeException e) {
71 callback.onFailure(e.getMessage());
72 return;
73 }
74
75 try {
76 camera.setPreviewTexture(surfaceTextureHelper.getSurfaceTexture());
77 } catch (IOException e) {
78 camera.release();
79 callback.onFailure(e.getMessage());
80 return;
81 }
82
83 final android.hardware.Camera.CameraInfo info = new android.hardware.Camera. CameraInfo();
84 android.hardware.Camera.getCameraInfo(cameraId, info);
85
86 final android.hardware.Camera.Parameters parameters = camera.getParameters() ;
87 final CaptureFormat captureFormat = findClosestCaptureFormat(
88 parameters, width, height, framerate);
89 final Size pictureSize = findClosestPictureSize(parameters, width, height);
90
91 updateCameraParameters(camera, parameters, captureFormat, pictureSize, captu reToTexture);
92
93 // Initialize the capture buffers.
94 if (!captureToTexture) {
95 final int frameSize = captureFormat.frameSize();
96 for (int i = 0; i < NUMBER_OF_CAPTURE_BUFFERS; ++i) {
97 final ByteBuffer buffer = ByteBuffer.allocateDirect(frameSize);
98 camera.addCallbackBuffer(buffer.array());
99 }
100 }
101
102 // Calculate orientation manually and send it as CVO insted.
103 camera.setDisplayOrientation(0 /* degrees */);
104
105 callback.onDone(new Camera1Session(
106 events, captureToTexture, applicationContext, surfaceTextureHelper,
107 cameraId, width, height, framerate,
108 camera, info, captureFormat, constructionTimeNs));
109 }
110
111 private static void updateCameraParameters(android.hardware.Camera camera,
112 android.hardware.Camera.Parameters parameters, CaptureFormat captureFormat , Size pictureSize,
113 boolean captureToTexture) {
114 final List<String> focusModes = parameters.getSupportedFocusModes();
115
116 parameters.setPreviewFpsRange(captureFormat.framerate.min, captureFormat.fra merate.max);
117 parameters.setPreviewSize(captureFormat.width, captureFormat.height);
118 parameters.setPictureSize(pictureSize.width, pictureSize.height);
119 if (!captureToTexture) {
120 parameters.setPreviewFormat(captureFormat.imageFormat);
121 }
122
123 if (parameters.isVideoStabilizationSupported()) {
124 parameters.setVideoStabilization(true);
125 }
126 if (focusModes.contains(android.hardware.Camera.Parameters.FOCUS_MODE_CONTIN UOUS_VIDEO)) {
127 parameters.setFocusMode(android.hardware.Camera.Parameters.FOCUS_MODE_CONT INUOUS_VIDEO);
128 }
129 camera.setParameters(parameters);
130 }
131
132 private static CaptureFormat findClosestCaptureFormat(
133 android.hardware.Camera.Parameters parameters, int width, int height, int framerate) {
134 // Find closest supported format for |width| x |height| @ |framerate|.
135 final List<CaptureFormat.FramerateRange> supportedFramerates =
136 Camera1Enumerator.convertFramerates(parameters.getSupportedPreviewFpsRan ge());
137 Logging.d(TAG, "Available fps ranges: " + supportedFramerates);
138
139 final CaptureFormat.FramerateRange fpsRange =
140 CameraEnumerationAndroid.getClosestSupportedFramerateRange(
141 supportedFramerates, framerate);
142
143 final Size previewSize = CameraEnumerationAndroid.getClosestSupportedSize(
144 Camera1Enumerator.convertSizes(parameters.getSupportedPreviewSizes()),
145 width, height);
146
147 return new CaptureFormat(previewSize.width, previewSize.height, fpsRange);
148 }
149
150 private static Size findClosestPictureSize(android.hardware.Camera.Parameters parameters,
151 int width, int height) {
152 return CameraEnumerationAndroid.getClosestSupportedSize(
153 Camera1Enumerator.convertSizes(parameters.getSupportedPictureSizes()),
154 width, height);
155 }
156
157 private Camera1Session(
158 Events events, boolean captureToTexture,
159 Context applicationContext, SurfaceTextureHelper surfaceTextureHelper,
160 int cameraId, int width, int height, int framerate,
161 android.hardware.Camera camera, android.hardware.Camera.CameraInfo info,
162 CaptureFormat captureFormat, long constructionTimeNs) {
163 Logging.d(TAG, "Create new camera1 session on camera " + cameraId);
164
165 this.cameraThreadHandler = new Handler();
166 this.events = events;
167 this.captureToTexture = captureToTexture;
168 this.applicationContext = applicationContext;
169 this.surfaceTextureHelper = surfaceTextureHelper;
170 this.cameraId = cameraId;
171 this.width = width;
172 this.height = height;
173 this.framerate = framerate;
174 this.camera = camera;
175 this.info = info;
176 this.captureFormat = captureFormat;
177 this.constructionTimeNs = constructionTimeNs;
178
179 startCapturing();
180 }
181
182 @Override
183 public void stop() {
184 final long stopStartTime = System.nanoTime();
185 Logging.d(TAG, "Stop camera1 session on camera " + cameraId);
186 if (Thread.currentThread() == cameraThreadHandler.getLooper().getThread()) {
187 if (state != SessionState.STOPPED) {
188 state = SessionState.STOPPED;
189 // Post the stopInternal to return earlier.
190 cameraThreadHandler.post(new Runnable() {
191 @Override
192 public void run() {
193 stopInternal();
194 final int stopTimeMs =
195 (int) TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - stopStar tTime);
196 camera1StopTimeMsHistogram.addSample(stopTimeMs);
197 }
198 });
199 }
200 } else {
201 final CountDownLatch stopLatch = new CountDownLatch(1);
202
203 cameraThreadHandler.post(new Runnable() {
204 @Override
205 public void run() {
206 if (state != SessionState.STOPPED) {
207 state = SessionState.STOPPED;
208 stopLatch.countDown();
209 stopInternal();
210 final int stopTimeMs =
211 (int) TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - stopStar tTime);
212 camera1StopTimeMsHistogram.addSample(stopTimeMs);
213 }
214 }
215 });
216
217 ThreadUtils.awaitUninterruptibly(stopLatch);
218 }
219 }
220
221 private void startCapturing() {
222 Logging.d(TAG, "Start capturing");
223 checkIsOnCameraThread();
224
225 state = SessionState.RUNNING;
226
227 camera.setErrorCallback(new android.hardware.Camera.ErrorCallback() {
228 @Override
229 public void onError(int error, android.hardware.Camera camera) {
230 String errorMessage;
231 if (error == android.hardware.Camera.CAMERA_ERROR_SERVER_DIED) {
232 errorMessage = "Camera server died!";
233 } else {
234 errorMessage = "Camera error: " + error;
235 }
236 Logging.e(TAG, errorMessage);
237 state = SessionState.STOPPED;
238 stopInternal();
239 events.onCameraError(Camera1Session.this, errorMessage);
240 }
241 });
242
243 if (captureToTexture) {
244 listenForTextureFrames();
245 } else {
246 listenForBytebufferFrames();
247 }
248 try {
249 camera.startPreview();
250 } catch (RuntimeException e) {
251 state = SessionState.STOPPED;
252 stopInternal();
253 events.onCameraError(this, e.getMessage());
254 }
255 }
256
257 private void stopInternal() {
258 Logging.d(TAG, "Stop internal");
259 checkIsOnCameraThread();
260
261 surfaceTextureHelper.stopListening();
262
263 // Note: stopPreview or other driver code might deadlock. Deadlock in
264 // android.hardware.Camera._stopPreview(Native Method) has been observed on
265 // Nexus 5 (hammerhead), OS version LMY48I.
266 camera.stopPreview();
267 camera.release();
268 events.onCameraClosed(this);
269
270 Logging.d(TAG, "Stop done");
271 }
272
273 private void listenForTextureFrames() {
274 surfaceTextureHelper.startListening(new SurfaceTextureHelper.OnTextureFrameA vailableListener() {
275 @Override
276 public void onTextureFrameAvailable(
277 int oesTextureId, float[] transformMatrix, long timestampNs) {
278 checkIsOnCameraThread();
279
280 if (state != SessionState.RUNNING) {
281 Logging.d(TAG, "Texture frame captured but camera is no longer running .");
282 surfaceTextureHelper.returnTextureFrame();
283 return;
284 }
285
286 if (!firstFrameReported) {
287 final int startTimeMs =
288 (int) TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - constructi onTimeNs);
289 camera1StartTimeMsHistogram.addSample(startTimeMs);
290 firstFrameReported = true;
291 }
292
293 int rotation = getFrameOrientation();
294 if (info.facing == android.hardware.Camera.CameraInfo.CAMERA_FACING_FRON T) {
295 // Undo the mirror that the OS "helps" us with.
296 // http://developer.android.com/reference/android/hardware/Camera.html #setDisplayOrientation(int)
297 transformMatrix = RendererCommon.multiplyMatrices(
298 transformMatrix, RendererCommon.horizontalFlipMatrix());
299 }
300 events.onTextureFrameCaptured(Camera1Session.this, captureFormat.width,
301 captureFormat.height, oesTextureId, transformMatrix, rotation, times tampNs);
302 }
303 });
304 }
305
306 private void listenForBytebufferFrames() {
307 camera.setPreviewCallbackWithBuffer(new android.hardware.Camera.PreviewCallb ack() {
308 @Override
309 public void onPreviewFrame(byte[] data, android.hardware.Camera callbackCa mera) {
310 checkIsOnCameraThread();
311
312 if (callbackCamera != camera) {
313 Logging.e(TAG, "Callback from a different camera. This should never ha ppen.");
314 return;
315 }
316
317 if (state != SessionState.RUNNING) {
318 Logging.d(TAG, "Bytebuffer frame captured but camera is no longer runn ing.");
319 return;
320 }
321
322 final long captureTimeNs = TimeUnit.MILLISECONDS.toNanos(SystemClock.ela psedRealtime());
323
324 if (!firstFrameReported) {
325 final int startTimeMs =
326 (int) TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - constructi onTimeNs);
327 camera1StartTimeMsHistogram.addSample(startTimeMs);
328 firstFrameReported = true;
329 }
330
331 events.onByteBufferFrameCaptured(Camera1Session.this, data, captureForma t.width,
332 captureFormat.height, getFrameOrientation(), captureTimeNs);
333 camera.addCallbackBuffer(data);
334 }
335 });
336 }
337
338 private int getDeviceOrientation() {
339 int orientation = 0;
340
341 WindowManager wm = (WindowManager) applicationContext.getSystemService(
342 Context.WINDOW_SERVICE);
343 switch(wm.getDefaultDisplay().getRotation()) {
344 case Surface.ROTATION_90:
345 orientation = 90;
346 break;
347 case Surface.ROTATION_180:
348 orientation = 180;
349 break;
350 case Surface.ROTATION_270:
351 orientation = 270;
352 break;
353 case Surface.ROTATION_0:
354 default:
355 orientation = 0;
356 break;
357 }
358 return orientation;
359 }
360
361 private int getFrameOrientation() {
362 int rotation = getDeviceOrientation();
363 if (info.facing == android.hardware.Camera.CameraInfo.CAMERA_FACING_BACK) {
364 rotation = 360 - rotation;
365 }
366 return (info.orientation + rotation) % 360;
367 }
368
369 private void checkIsOnCameraThread() {
370 if (Thread.currentThread() != cameraThreadHandler.getLooper().getThread()) {
371 throw new IllegalStateException("Wrong thread");
372 }
373 }
374 }
OLDNEW
« no previous file with comments | « webrtc/api/android/java/src/org/webrtc/Camera1Capturer.java ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698