| 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.graphics.Rect; | 10 import android.graphics.Rect; |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 120 | 120 |
| 121 if (reader.getWidth() != image.getWidth() | 121 if (reader.getWidth() != image.getWidth() |
| 122 || reader.getHeight() != image.getHeight()) { | 122 || reader.getHeight() != image.getHeight()) { |
| 123 nativeOnError(mNativeVideoCaptureDeviceAndroid, "ImageReader
size (" | 123 nativeOnError(mNativeVideoCaptureDeviceAndroid, "ImageReader
size (" |
| 124 + reader.getWidth() + "x" + reader.getHeight() | 124 + reader.getWidth() + "x" + reader.getHeight() |
| 125 + ") did not match Image size (" + image.getWidth()
+ "x" | 125 + ") did not match Image size (" + image.getWidth()
+ "x" |
| 126 + image.getHeight() + ")"); | 126 + image.getHeight() + ")"); |
| 127 throw new IllegalStateException(); | 127 throw new IllegalStateException(); |
| 128 } | 128 } |
| 129 | 129 |
| 130 readImageIntoBuffer(image, mCapturedData); | 130 nativeOnI420FrameAvailable(mNativeVideoCaptureDeviceAndroid, |
| 131 nativeOnFrameAvailable(mNativeVideoCaptureDeviceAndroid, mCaptur
edData, | 131 image.getPlanes()[0].getBuffer(), image.getPlanes()[0].g
etRowStride(), |
| 132 mCapturedData.length, getCameraRotation()); | 132 image.getPlanes()[1].getBuffer(), image.getPlanes()[2].g
etBuffer(), |
| 133 image.getPlanes()[1].getRowStride(), image.getPlanes()[1
].getPixelStride(), |
| 134 image.getWidth(), image.getHeight(), getCameraRotation()
); |
| 133 } catch (IllegalStateException ex) { | 135 } catch (IllegalStateException ex) { |
| 134 Log.e(TAG, "acquireLatestImage():", ex); | 136 Log.e(TAG, "acquireLatestImage():", ex); |
| 135 } | 137 } |
| 136 } | 138 } |
| 137 }; | 139 }; |
| 138 | 140 |
| 139 // Inner class to extend a Photo Session state change listener. | 141 // Inner class to extend a Photo Session state change listener. |
| 140 // Error paths must signal notifyTakePhotoError(). | 142 // Error paths must signal notifyTakePhotoError(). |
| 141 private class CrPhotoSessionListener extends CameraCaptureSession.StateCallb
ack { | 143 private class CrPhotoSessionListener extends CameraCaptureSession.StateCallb
ack { |
| 142 private final CaptureRequest mPhotoRequest; | 144 private final CaptureRequest mPhotoRequest; |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 218 } | 220 } |
| 219 }; | 221 }; |
| 220 | 222 |
| 221 private static final double kNanoSecondsToFps = 1.0E-9; | 223 private static final double kNanoSecondsToFps = 1.0E-9; |
| 222 private static final String TAG = "VideoCapture"; | 224 private static final String TAG = "VideoCapture"; |
| 223 | 225 |
| 224 private static enum CameraState { OPENING, CONFIGURING, STARTED, STOPPED } | 226 private static enum CameraState { OPENING, CONFIGURING, STARTED, STOPPED } |
| 225 | 227 |
| 226 private final Object mCameraStateLock = new Object(); | 228 private final Object mCameraStateLock = new Object(); |
| 227 | 229 |
| 228 private byte[] mCapturedData; | |
| 229 | |
| 230 private CameraDevice mCameraDevice; | 230 private CameraDevice mCameraDevice; |
| 231 private CameraCaptureSession mPreviewSession; | 231 private CameraCaptureSession mPreviewSession; |
| 232 private CaptureRequest mPreviewRequest; | 232 private CaptureRequest mPreviewRequest; |
| 233 | 233 |
| 234 private CameraState mCameraState = CameraState.STOPPED; | 234 private CameraState mCameraState = CameraState.STOPPED; |
| 235 private final float mMaxZoom; | 235 private final float mMaxZoom; |
| 236 private Rect mCropRect = new Rect(); | 236 private Rect mCropRect = new Rect(); |
| 237 | 237 |
| 238 // Service function to grab CameraCharacteristics and handle exceptions. | 238 // Service function to grab CameraCharacteristics and handle exceptions. |
| 239 private static CameraCharacteristics getCameraCharacteristics(Context appCon
text, int id) { | 239 private static CameraCharacteristics getCameraCharacteristics(Context appCon
text, int id) { |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 305 try { | 305 try { |
| 306 mCameraDevice.createCaptureSession(surfaceList, captureSessionListen
er, null); | 306 mCameraDevice.createCaptureSession(surfaceList, captureSessionListen
er, null); |
| 307 } catch (CameraAccessException | IllegalArgumentException | SecurityExce
ption ex) { | 307 } catch (CameraAccessException | IllegalArgumentException | SecurityExce
ption ex) { |
| 308 Log.e(TAG, "createCaptureSession: ", ex); | 308 Log.e(TAG, "createCaptureSession: ", ex); |
| 309 return false; | 309 return false; |
| 310 } | 310 } |
| 311 // Wait for trigger on CrPreviewSessionListener.onConfigured(); | 311 // Wait for trigger on CrPreviewSessionListener.onConfigured(); |
| 312 return true; | 312 return true; |
| 313 } | 313 } |
| 314 | 314 |
| 315 private static void readImageIntoBuffer(Image image, byte[] data) { | |
| 316 final int imageWidth = image.getWidth(); | |
| 317 final int imageHeight = image.getHeight(); | |
| 318 final Image.Plane[] planes = image.getPlanes(); | |
| 319 | |
| 320 int offset = 0; | |
| 321 for (int plane = 0; plane < planes.length; ++plane) { | |
| 322 final ByteBuffer buffer = planes[plane].getBuffer(); | |
| 323 final int rowStride = planes[plane].getRowStride(); | |
| 324 // Experimentally, U and V planes have |pixelStride| = 2, which | |
| 325 // essentially means they are packed. That's silly, because we are | |
| 326 // forced to unpack here. | |
| 327 final int pixelStride = planes[plane].getPixelStride(); | |
| 328 final int planeWidth = (plane == 0) ? imageWidth : imageWidth / 2; | |
| 329 final int planeHeight = (plane == 0) ? imageHeight : imageHeight / 2
; | |
| 330 | |
| 331 if (pixelStride == 1 && rowStride == planeWidth) { | |
| 332 // Copy whole plane from buffer into |data| at once. | |
| 333 buffer.get(data, offset, planeWidth * planeHeight); | |
| 334 offset += planeWidth * planeHeight; | |
| 335 } else { | |
| 336 // Copy pixels one by one respecting pixelStride and rowStride. | |
| 337 byte[] rowData = new byte[rowStride]; | |
| 338 for (int row = 0; row < planeHeight - 1; ++row) { | |
| 339 buffer.get(rowData, 0, rowStride); | |
| 340 for (int col = 0; col < planeWidth; ++col) { | |
| 341 data[offset++] = rowData[col * pixelStride]; | |
| 342 } | |
| 343 } | |
| 344 | |
| 345 // Last row is special in some devices and may not contain the f
ull | |
| 346 // |rowStride| bytes of data. See http://crbug.com/458701 and | |
| 347 // http://developer.android.com/reference/android/media/Image.Pl
ane.html#getBuffer() | |
| 348 buffer.get(rowData, 0, Math.min(rowStride, buffer.remaining())); | |
| 349 for (int col = 0; col < planeWidth; ++col) { | |
| 350 data[offset++] = rowData[col * pixelStride]; | |
| 351 } | |
| 352 } | |
| 353 } | |
| 354 } | |
| 355 | |
| 356 private void changeCameraStateAndNotify(CameraState state) { | 315 private void changeCameraStateAndNotify(CameraState state) { |
| 357 synchronized (mCameraStateLock) { | 316 synchronized (mCameraStateLock) { |
| 358 mCameraState = state; | 317 mCameraState = state; |
| 359 mCameraStateLock.notifyAll(); | 318 mCameraStateLock.notifyAll(); |
| 360 } | 319 } |
| 361 } | 320 } |
| 362 | 321 |
| 363 static boolean isLegacyDevice(Context appContext, int id) { | 322 static boolean isLegacyDevice(Context appContext, int id) { |
| 364 final CameraCharacteristics cameraCharacteristics = | 323 final CameraCharacteristics cameraCharacteristics = |
| 365 getCameraCharacteristics(appContext, id); | 324 getCameraCharacteristics(appContext, id); |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 490 if (minDiff == Integer.MAX_VALUE) { | 449 if (minDiff == Integer.MAX_VALUE) { |
| 491 Log.e(TAG, "No supported resolutions."); | 450 Log.e(TAG, "No supported resolutions."); |
| 492 return false; | 451 return false; |
| 493 } | 452 } |
| 494 Log.d(TAG, "allocate: matched (%d x %d)", closestSupportedSize.getWidth(
), | 453 Log.d(TAG, "allocate: matched (%d x %d)", closestSupportedSize.getWidth(
), |
| 495 closestSupportedSize.getHeight()); | 454 closestSupportedSize.getHeight()); |
| 496 | 455 |
| 497 // |mCaptureFormat| is also used to configure the ImageReader. | 456 // |mCaptureFormat| is also used to configure the ImageReader. |
| 498 mCaptureFormat = new VideoCaptureFormat(closestSupportedSize.getWidth(), | 457 mCaptureFormat = new VideoCaptureFormat(closestSupportedSize.getWidth(), |
| 499 closestSupportedSize.getHeight(), frameRate, ImageFormat.YUV_420
_888); | 458 closestSupportedSize.getHeight(), frameRate, ImageFormat.YUV_420
_888); |
| 500 int expectedFrameSize = mCaptureFormat.mWidth * mCaptureFormat.mHeight | |
| 501 * ImageFormat.getBitsPerPixel(mCaptureFormat.mPixelFormat) / 8; | |
| 502 mCapturedData = new byte[expectedFrameSize]; | |
| 503 mCameraNativeOrientation = | 459 mCameraNativeOrientation = |
| 504 cameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATI
ON); | 460 cameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATI
ON); |
| 505 // TODO(mcasas): The following line is correct for N5 with prerelease Bu
ild, | 461 // TODO(mcasas): The following line is correct for N5 with prerelease Bu
ild, |
| 506 // but NOT for N7 with a dev Build. Figure out which one to support. | 462 // but NOT for N7 with a dev Build. Figure out which one to support. |
| 507 mInvertDeviceOrientationReadings = | 463 mInvertDeviceOrientationReadings = |
| 508 cameraCharacteristics.get(CameraCharacteristics.LENS_FACING) | 464 cameraCharacteristics.get(CameraCharacteristics.LENS_FACING) |
| 509 == CameraCharacteristics.LENS_FACING_BACK; | 465 == CameraCharacteristics.LENS_FACING_BACK; |
| 510 return true; | 466 return true; |
| 511 } | 467 } |
| 512 | 468 |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 651 return false; | 607 return false; |
| 652 } | 608 } |
| 653 return true; | 609 return true; |
| 654 } | 610 } |
| 655 | 611 |
| 656 @Override | 612 @Override |
| 657 public void deallocate() { | 613 public void deallocate() { |
| 658 Log.d(TAG, "deallocate"); | 614 Log.d(TAG, "deallocate"); |
| 659 } | 615 } |
| 660 } | 616 } |
| OLD | NEW |