| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package org.chromium.media; | 5 package org.chromium.media; |
| 6 | 6 |
| 7 import android.annotation.TargetApi; | 7 import android.annotation.TargetApi; |
| 8 import android.content.Context; | 8 import android.content.Context; |
| 9 import android.graphics.ImageFormat; | 9 import android.graphics.ImageFormat; |
| 10 import android.hardware.camera2.CameraAccessException; | 10 import android.hardware.camera2.CameraAccessException; |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 137 private CameraState mCameraState = CameraState.STOPPED; | 137 private CameraState mCameraState = CameraState.STOPPED; |
| 138 private final Object mCameraStateLock = new Object(); | 138 private final Object mCameraStateLock = new Object(); |
| 139 | 139 |
| 140 // Service function to grab CameraCharacteristics and handle exceptions. | 140 // Service function to grab CameraCharacteristics and handle exceptions. |
| 141 private static CameraCharacteristics getCameraCharacteristics(Context appCon
text, int id) { | 141 private static CameraCharacteristics getCameraCharacteristics(Context appCon
text, int id) { |
| 142 final CameraManager manager = | 142 final CameraManager manager = |
| 143 (CameraManager) appContext.getSystemService(Context.CAMERA_SERVI
CE); | 143 (CameraManager) appContext.getSystemService(Context.CAMERA_SERVI
CE); |
| 144 try { | 144 try { |
| 145 return manager.getCameraCharacteristics(Integer.toString(id)); | 145 return manager.getCameraCharacteristics(Integer.toString(id)); |
| 146 } catch (CameraAccessException ex) { | 146 } catch (CameraAccessException ex) { |
| 147 Log.e(TAG, "getNumberOfCameras: getCameraIdList(): " + ex); | 147 Log.e(TAG, "getCameraCharacteristics: " + ex); |
| 148 } | 148 } |
| 149 return null; | 149 return null; |
| 150 } | 150 } |
| 151 | 151 |
| 152 private boolean createCaptureObjects() { | 152 private boolean createCaptureObjects() { |
| 153 Log.d(TAG, "createCaptureObjects"); | 153 Log.d(TAG, "createCaptureObjects"); |
| 154 if (mCameraDevice == null) return false; | 154 if (mCameraDevice == null) return false; |
| 155 | 155 |
| 156 // Create an ImageReader and plug a thread looper into it to have | 156 // Create an ImageReader and plug a thread looper into it to have |
| 157 // readback take place on its own thread. | 157 // readback take place on its own thread. |
| 158 final int maxImages = 2; | 158 final int maxImages = 2; |
| 159 mImageReader = ImageReader.newInstance(mCaptureFormat.getWidth(), | 159 mImageReader = ImageReader.newInstance(mCaptureFormat.getWidth(), |
| 160 mCaptureFormat.getHeight(), mCaptureFormat.getPixelFormat(), max
Images); | 160 mCaptureFormat.getHeight(), mCaptureFormat.getPixelFormat(), max
Images); |
| 161 HandlerThread thread = new HandlerThread("CameraPreview"); | 161 HandlerThread thread = new HandlerThread("CameraPreview"); |
| 162 thread.start(); | 162 thread.start(); |
| 163 final Handler backgroundHandler = new Handler(thread.getLooper()); | 163 final Handler backgroundHandler = new Handler(thread.getLooper()); |
| 164 final CrImageReaderListener imageReaderListener = new CrImageReaderListe
ner(); | 164 final CrImageReaderListener imageReaderListener = new CrImageReaderListe
ner(); |
| 165 mImageReader.setOnImageAvailableListener(imageReaderListener, background
Handler); | 165 mImageReader.setOnImageAvailableListener(imageReaderListener, background
Handler); |
| 166 | 166 |
| 167 // The Preview template specifically means "high frame rate is given | 167 // The Preview template specifically means "high frame rate is given |
| 168 // priority over the highest-quality post-processing". | 168 // priority over the highest-quality post-processing". |
| 169 try { | 169 try { |
| 170 mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TE
MPLATE_PREVIEW); | 170 mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TE
MPLATE_PREVIEW); |
| 171 } catch (CameraAccessException ex) { | 171 } catch (CameraAccessException | IllegalArgumentException | SecurityExce
ption ex) { |
| 172 Log.e(TAG, "createCaptureRequest: " + ex); | |
| 173 return false; | |
| 174 } catch (IllegalArgumentException ex) { | |
| 175 Log.e(TAG, "createCaptureRequest: " + ex); | |
| 176 return false; | |
| 177 } catch (SecurityException ex) { | |
| 178 Log.e(TAG, "createCaptureRequest: " + ex); | 172 Log.e(TAG, "createCaptureRequest: " + ex); |
| 179 return false; | 173 return false; |
| 180 } | 174 } |
| 181 if (mPreviewBuilder == null) { | 175 if (mPreviewBuilder == null) { |
| 182 Log.e(TAG, "mPreviewBuilder error"); | 176 Log.e(TAG, "mPreviewBuilder error"); |
| 183 return false; | 177 return false; |
| 184 } | 178 } |
| 185 // Construct an ImageReader Surface and plug it into our CaptureRequest.
Builder. | 179 // Construct an ImageReader Surface and plug it into our CaptureRequest.
Builder. |
| 186 mPreviewBuilder.addTarget(mImageReader.getSurface()); | 180 mPreviewBuilder.addTarget(mImageReader.getSurface()); |
| 187 | 181 |
| 188 // A series of configuration options in the PreviewBuilder | 182 // A series of configuration options in the PreviewBuilder |
| 189 mPreviewBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_
MODE_AUTO); | 183 mPreviewBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_
MODE_AUTO); |
| 190 mPreviewBuilder.set( | 184 mPreviewBuilder.set( |
| 191 CaptureRequest.NOISE_REDUCTION_MODE, CameraMetadata.NOISE_REDUCT
ION_MODE_FAST); | 185 CaptureRequest.NOISE_REDUCTION_MODE, CameraMetadata.NOISE_REDUCT
ION_MODE_FAST); |
| 192 mPreviewBuilder.set(CaptureRequest.EDGE_MODE, CameraMetadata.EDGE_MODE_F
AST); | 186 mPreviewBuilder.set(CaptureRequest.EDGE_MODE, CameraMetadata.EDGE_MODE_F
AST); |
| 193 mPreviewBuilder.set(CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE, | 187 mPreviewBuilder.set(CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE, |
| 194 CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_ON); | 188 CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_ON); |
| 195 // SENSOR_EXPOSURE_TIME ? | 189 // SENSOR_EXPOSURE_TIME ? |
| 196 | 190 |
| 197 List<Surface> surfaceList = new ArrayList<Surface>(1); | 191 List<Surface> surfaceList = new ArrayList<Surface>(1); |
| 198 surfaceList.add(mImageReader.getSurface()); | 192 surfaceList.add(mImageReader.getSurface()); |
| 199 final CrCaptureSessionListener captureSessionListener = new CrCaptureSes
sionListener(); | 193 final CrCaptureSessionListener captureSessionListener = new CrCaptureSes
sionListener(); |
| 200 try { | 194 try { |
| 201 mCameraDevice.createCaptureSession(surfaceList, captureSessionListen
er, null); | 195 mCameraDevice.createCaptureSession(surfaceList, captureSessionListen
er, null); |
| 202 } catch (CameraAccessException ex) { | 196 } catch (CameraAccessException | IllegalArgumentException | SecurityExce
ption ex) { |
| 203 Log.e(TAG, "createCaptureSession: " + ex); | |
| 204 return false; | |
| 205 } catch (IllegalArgumentException ex) { | |
| 206 Log.e(TAG, "createCaptureSession: " + ex); | |
| 207 return false; | |
| 208 } catch (SecurityException ex) { | |
| 209 Log.e(TAG, "createCaptureSession: " + ex); | 197 Log.e(TAG, "createCaptureSession: " + ex); |
| 210 return false; | 198 return false; |
| 211 } | 199 } |
| 212 // Wait for trigger on CrCaptureSessionListener.onConfigured(); | 200 // Wait for trigger on CrCaptureSessionListener.onConfigured(); |
| 213 return true; | 201 return true; |
| 214 } | 202 } |
| 215 | 203 |
| 216 private boolean createCaptureRequest() { | 204 private boolean createCaptureRequest() { |
| 217 Log.d(TAG, "createCaptureRequest"); | 205 Log.d(TAG, "createCaptureRequest"); |
| 218 try { | 206 try { |
| 219 // This line triggers the capture. No |listener| is registered, so | 207 // This line triggers the capture. No |listener| is registered, so |
| 220 // we will not get notified of capture events, instead, ImageReader | 208 // we will not get notified of capture events, instead, ImageReader |
| 221 // will trigger every time a downloaded image is ready. Since | 209 // will trigger every time a downloaded image is ready. Since |
| 222 //|handler| is null, we'll work on the current Thread Looper. | 210 //|handler| is null, we'll work on the current Thread Looper. |
| 223 mCaptureSession.setRepeatingRequest(mPreviewBuilder.build(), null, n
ull); | 211 mCaptureSession.setRepeatingRequest(mPreviewBuilder.build(), null, n
ull); |
| 224 } catch (CameraAccessException ex) { | 212 } catch (CameraAccessException | IllegalArgumentException | SecurityExce
ption ex) { |
| 225 Log.e(TAG, "setRepeatingRequest: " + ex); | |
| 226 return false; | |
| 227 } catch (IllegalArgumentException ex) { | |
| 228 Log.e(TAG, "setRepeatingRequest: " + ex); | |
| 229 return false; | |
| 230 } catch (SecurityException ex) { | |
| 231 Log.e(TAG, "setRepeatingRequest: " + ex); | 213 Log.e(TAG, "setRepeatingRequest: " + ex); |
| 232 return false; | 214 return false; |
| 233 } | 215 } |
| 234 // Now wait for trigger on CrImageReaderListener.onImageAvailable(); | 216 // Now wait for trigger on CrImageReaderListener.onImageAvailable(); |
| 235 return true; | 217 return true; |
| 236 } | 218 } |
| 237 | 219 |
| 238 private static void readImageIntoBuffer(Image image, byte[] data) { | 220 private static void readImageIntoBuffer(Image image, byte[] data) { |
| 239 final int imageWidth = image.getWidth(); | 221 final int imageWidth = image.getWidth(); |
| 240 final int imageHeight = image.getHeight(); | 222 final int imageHeight = image.getHeight(); |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 288 return cameraCharacteristics != null | 270 return cameraCharacteristics != null |
| 289 && cameraCharacteristics.get(CameraCharacteristics.INFO_SUPPORTE
D_HARDWARE_LEVEL) | 271 && cameraCharacteristics.get(CameraCharacteristics.INFO_SUPPORTE
D_HARDWARE_LEVEL) |
| 290 == CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY; | 272 == CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY; |
| 291 } | 273 } |
| 292 | 274 |
| 293 static int getNumberOfCameras(Context appContext) { | 275 static int getNumberOfCameras(Context appContext) { |
| 294 final CameraManager manager = | 276 final CameraManager manager = |
| 295 (CameraManager) appContext.getSystemService(Context.CAMERA_SERVI
CE); | 277 (CameraManager) appContext.getSystemService(Context.CAMERA_SERVI
CE); |
| 296 try { | 278 try { |
| 297 return manager.getCameraIdList().length; | 279 return manager.getCameraIdList().length; |
| 298 } catch (CameraAccessException ex) { | 280 } catch (CameraAccessException | SecurityException ex) { |
| 281 // SecurityException is an undocumented exception, but has been seen
in |
| 282 // http://crbug/605424. |
| 299 Log.e(TAG, "getNumberOfCameras: getCameraIdList(): " + ex); | 283 Log.e(TAG, "getNumberOfCameras: getCameraIdList(): " + ex); |
| 300 return 0; | 284 return 0; |
| 301 } | 285 } |
| 302 } | 286 } |
| 303 | 287 |
| 304 static int getCaptureApiType(int id, Context appContext) { | 288 static int getCaptureApiType(int id, Context appContext) { |
| 305 final CameraCharacteristics cameraCharacteristics = | 289 final CameraCharacteristics cameraCharacteristics = |
| 306 getCameraCharacteristics(appContext, id); | 290 getCameraCharacteristics(appContext, id); |
| 307 if (cameraCharacteristics == null) { | 291 if (cameraCharacteristics == null) { |
| 308 return CaptureApiType.API_TYPE_UNKNOWN; | 292 return CaptureApiType.API_TYPE_UNKNOWN; |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 430 @Override | 414 @Override |
| 431 public boolean startCapture() { | 415 public boolean startCapture() { |
| 432 Log.d(TAG, "startCapture"); | 416 Log.d(TAG, "startCapture"); |
| 433 changeCameraStateAndNotify(CameraState.OPENING); | 417 changeCameraStateAndNotify(CameraState.OPENING); |
| 434 final CameraManager manager = | 418 final CameraManager manager = |
| 435 (CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE
); | 419 (CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE
); |
| 436 final Handler mainHandler = new Handler(mContext.getMainLooper()); | 420 final Handler mainHandler = new Handler(mContext.getMainLooper()); |
| 437 final CrStateListener stateListener = new CrStateListener(); | 421 final CrStateListener stateListener = new CrStateListener(); |
| 438 try { | 422 try { |
| 439 manager.openCamera(Integer.toString(mId), stateListener, mainHandler
); | 423 manager.openCamera(Integer.toString(mId), stateListener, mainHandler
); |
| 440 } catch (CameraAccessException ex) { | 424 } catch (CameraAccessException | IllegalArgumentException | SecurityExce
ption ex) { |
| 441 Log.e(TAG, "allocate: manager.openCamera: " + ex); | |
| 442 return false; | |
| 443 } catch (IllegalArgumentException ex) { | |
| 444 Log.e(TAG, "allocate: manager.openCamera: " + ex); | |
| 445 return false; | |
| 446 } catch (SecurityException ex) { | |
| 447 Log.e(TAG, "allocate: manager.openCamera: " + ex); | 425 Log.e(TAG, "allocate: manager.openCamera: " + ex); |
| 448 return false; | 426 return false; |
| 449 } | 427 } |
| 450 | 428 |
| 451 return true; | 429 return true; |
| 452 } | 430 } |
| 453 | 431 |
| 454 @Override | 432 @Override |
| 455 public boolean stopCapture() { | 433 public boolean stopCapture() { |
| 456 Log.d(TAG, "stopCapture"); | 434 Log.d(TAG, "stopCapture"); |
| 457 | 435 |
| 458 // With Camera2 API, the capture is started asynchronously, which will c
ause problem if | 436 // With Camera2 API, the capture is started asynchronously, which will c
ause problem if |
| 459 // stopCapture comes too quickly. Without stopping the previous capture
properly, the next | 437 // stopCapture comes too quickly. Without stopping the previous capture
properly, the next |
| 460 // startCapture will fail and make Chrome no-responding. So wait camera
to be STARTED. | 438 // startCapture will fail and make Chrome no-responding. So wait camera
to be STARTED. |
| 461 synchronized (mCameraStateLock) { | 439 synchronized (mCameraStateLock) { |
| 462 while (mCameraState != CameraState.STARTED && mCameraState != Camera
State.STOPPED) { | 440 while (mCameraState != CameraState.STARTED && mCameraState != Camera
State.STOPPED) { |
| 463 try { | 441 try { |
| 464 mCameraStateLock.wait(); | 442 mCameraStateLock.wait(); |
| 465 } catch (InterruptedException ex) { | 443 } catch (InterruptedException ex) { |
| 466 Log.e(TAG, "CaptureStartedEvent: " + ex); | 444 Log.e(TAG, "CaptureStartedEvent: " + ex); |
| 467 } | 445 } |
| 468 } | 446 } |
| 469 if (mCameraState == CameraState.STOPPED) return true; | 447 if (mCameraState == CameraState.STOPPED) return true; |
| 470 } | 448 } |
| 471 | 449 |
| 472 try { | 450 try { |
| 473 mCaptureSession.abortCaptures(); | 451 mCaptureSession.abortCaptures(); |
| 474 } catch (CameraAccessException ex) { | 452 } catch (CameraAccessException | IllegalStateException ex) { |
| 475 Log.e(TAG, "abortCaptures: " + ex); | |
| 476 return false; | |
| 477 } catch (IllegalStateException ex) { | |
| 478 Log.e(TAG, "abortCaptures: " + ex); | 453 Log.e(TAG, "abortCaptures: " + ex); |
| 479 return false; | 454 return false; |
| 480 } | 455 } |
| 481 if (mCameraDevice == null) return false; | 456 if (mCameraDevice == null) return false; |
| 482 mCameraDevice.close(); | 457 mCameraDevice.close(); |
| 483 changeCameraStateAndNotify(CameraState.STOPPED); | 458 changeCameraStateAndNotify(CameraState.STOPPED); |
| 484 return true; | 459 return true; |
| 485 } | 460 } |
| 486 | 461 |
| 487 @Override | 462 @Override |
| 488 public void deallocate() { | 463 public void deallocate() { |
| 489 Log.d(TAG, "deallocate"); | 464 Log.d(TAG, "deallocate"); |
| 490 } | 465 } |
| 491 } | 466 } |
| OLD | NEW |