| 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 227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 238 | 238 |
| 239 private final Object mCameraStateLock = new Object(); | 239 private final Object mCameraStateLock = new Object(); |
| 240 | 240 |
| 241 private CameraDevice mCameraDevice; | 241 private CameraDevice mCameraDevice; |
| 242 private CameraCaptureSession mPreviewSession; | 242 private CameraCaptureSession mPreviewSession; |
| 243 private CaptureRequest mPreviewRequest; | 243 private CaptureRequest mPreviewRequest; |
| 244 | 244 |
| 245 private CameraState mCameraState = CameraState.STOPPED; | 245 private CameraState mCameraState = CameraState.STOPPED; |
| 246 private final float mMaxZoom; | 246 private final float mMaxZoom; |
| 247 private Rect mCropRect = new Rect(); | 247 private Rect mCropRect = new Rect(); |
| 248 private int mFocusMode = AndroidFocusMode.CONTINUOUS; |
| 249 private int mPhotoWidth = 0; |
| 250 private int mPhotoHeight = 0; |
| 248 | 251 |
| 249 // Service function to grab CameraCharacteristics and handle exceptions. | 252 // Service function to grab CameraCharacteristics and handle exceptions. |
| 250 private static CameraCharacteristics getCameraCharacteristics(Context appCon
text, int id) { | 253 private static CameraCharacteristics getCameraCharacteristics(Context appCon
text, int id) { |
| 251 final CameraManager manager = | 254 final CameraManager manager = |
| 252 (CameraManager) appContext.getSystemService(Context.CAMERA_SERVI
CE); | 255 (CameraManager) appContext.getSystemService(Context.CAMERA_SERVI
CE); |
| 253 try { | 256 try { |
| 254 return manager.getCameraCharacteristics(Integer.toString(id)); | 257 return manager.getCameraCharacteristics(Integer.toString(id)); |
| 255 } catch (CameraAccessException ex) { | 258 } catch (CameraAccessException ex) { |
| 256 Log.e(TAG, "getCameraCharacteristics: ", ex); | 259 Log.e(TAG, "getCameraCharacteristics: ", ex); |
| 257 } | 260 } |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 295 // Construct an ImageReader Surface and plug it into our CaptureRequest.
Builder. | 298 // Construct an ImageReader Surface and plug it into our CaptureRequest.
Builder. |
| 296 previewRequestBuilder.addTarget(imageReader.getSurface()); | 299 previewRequestBuilder.addTarget(imageReader.getSurface()); |
| 297 | 300 |
| 298 // A series of configuration options in the PreviewBuilder | 301 // A series of configuration options in the PreviewBuilder |
| 299 previewRequestBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CO
NTROL_MODE_AUTO); | 302 previewRequestBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CO
NTROL_MODE_AUTO); |
| 300 previewRequestBuilder.set( | 303 previewRequestBuilder.set( |
| 301 CaptureRequest.NOISE_REDUCTION_MODE, CameraMetadata.NOISE_REDUCT
ION_MODE_FAST); | 304 CaptureRequest.NOISE_REDUCTION_MODE, CameraMetadata.NOISE_REDUCT
ION_MODE_FAST); |
| 302 previewRequestBuilder.set(CaptureRequest.EDGE_MODE, CameraMetadata.EDGE_
MODE_FAST); | 305 previewRequestBuilder.set(CaptureRequest.EDGE_MODE, CameraMetadata.EDGE_
MODE_FAST); |
| 303 previewRequestBuilder.set(CaptureRequest.CONTROL_VIDEO_STABILIZATION_MOD
E, | 306 previewRequestBuilder.set(CaptureRequest.CONTROL_VIDEO_STABILIZATION_MOD
E, |
| 304 CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_ON); | 307 CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_ON); |
| 308 if (mFocusMode == AndroidFocusMode.CONTINUOUS) { |
| 309 Log.d(TAG, "Focus: CONTROL_AF_MODE_CONTINUOUS_PICTURE"); |
| 310 previewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, |
| 311 CameraMetadata.CONTROL_AF_MODE_CONTINUOUS_PICTURE); |
| 312 } else if (mFocusMode == AndroidFocusMode.SINGLE_SHOT) { |
| 313 Log.d(TAG, "Focus: triggering a single shot"); |
| 314 previewRequestBuilder.set( |
| 315 CaptureRequest.CONTROL_AF_MODE, CameraMetadata.CONTROL_AF_MO
DE_AUTO); |
| 316 previewRequestBuilder.set( |
| 317 CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF
_TRIGGER_START); |
| 318 } |
| 319 |
| 305 // SENSOR_EXPOSURE_TIME ? | 320 // SENSOR_EXPOSURE_TIME ? |
| 306 if (!mCropRect.isEmpty()) { | 321 if (!mCropRect.isEmpty()) { |
| 307 previewRequestBuilder.set(CaptureRequest.SCALER_CROP_REGION, mCropRe
ct); | 322 previewRequestBuilder.set(CaptureRequest.SCALER_CROP_REGION, mCropRe
ct); |
| 308 } | 323 } |
| 309 | 324 |
| 310 List<Surface> surfaceList = new ArrayList<Surface>(1); | 325 List<Surface> surfaceList = new ArrayList<Surface>(1); |
| 311 surfaceList.add(imageReader.getSurface()); | 326 surfaceList.add(imageReader.getSurface()); |
| 312 | 327 |
| 313 mPreviewRequest = previewRequestBuilder.build(); | 328 mPreviewRequest = previewRequestBuilder.build(); |
| 314 final CrPreviewSessionListener captureSessionListener = | 329 final CrPreviewSessionListener captureSessionListener = |
| (...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 556 int minWidth = Integer.MAX_VALUE; | 571 int minWidth = Integer.MAX_VALUE; |
| 557 int minHeight = Integer.MAX_VALUE; | 572 int minHeight = Integer.MAX_VALUE; |
| 558 int maxWidth = 0; | 573 int maxWidth = 0; |
| 559 int maxHeight = 0; | 574 int maxHeight = 0; |
| 560 for (Size size : supportedSizes) { | 575 for (Size size : supportedSizes) { |
| 561 if (size.getWidth() < minWidth) minWidth = size.getWidth(); | 576 if (size.getWidth() < minWidth) minWidth = size.getWidth(); |
| 562 if (size.getHeight() < minHeight) minHeight = size.getHeight(); | 577 if (size.getHeight() < minHeight) minHeight = size.getHeight(); |
| 563 if (size.getWidth() > maxWidth) maxWidth = size.getWidth(); | 578 if (size.getWidth() > maxWidth) maxWidth = size.getWidth(); |
| 564 if (size.getHeight() > maxHeight) maxHeight = size.getHeight(); | 579 if (size.getHeight() > maxHeight) maxHeight = size.getHeight(); |
| 565 } | 580 } |
| 566 final int currentHeight = mCaptureFormat.getHeight(); | 581 final int currentHeight = (mPhotoHeight > 0) ? mPhotoHeight : mCaptureFo
rmat.getHeight(); |
| 567 final int currentWidth = mCaptureFormat.getWidth(); | 582 final int currentWidth = (mPhotoWidth > 0) ? mPhotoWidth : mCaptureForma
t.getWidth(); |
| 568 | 583 |
| 569 // The Min and Max zoom are returned as x100 by the API to avoid using f
loating point. There | 584 // The Min and Max zoom are returned as x100 by the API to avoid using f
loating point. There |
| 570 // is no min-zoom per se, so clamp it to always 100 (TODO(mcasas): make
const member). | 585 // is no min-zoom per se, so clamp it to always 100 (TODO(mcasas): make
const member). |
| 571 final int minZoom = 100; | 586 final int minZoom = 100; |
| 572 final int maxZoom = Math.round(mMaxZoom * 100); | 587 final int maxZoom = Math.round(mMaxZoom * 100); |
| 573 // Width Ratio x100 is used as measure of current zoom. | 588 // Width Ratio x100 is used as measure of current zoom. |
| 574 final int currentZoom = 100 * mPreviewRequest.get(CaptureRequest.SCALER_
CROP_REGION).width() | 589 final int currentZoom = 100 |
| 575 / cameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_AC
TIVE_ARRAY_SIZE) | 590 * cameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_AC
TIVE_ARRAY_SIZE) |
| 576 .width(); | 591 .width() |
| 592 / mPreviewRequest.get(CaptureRequest.SCALER_CROP_REGION).width()
; |
| 577 | 593 |
| 578 final int focusMode = mPreviewRequest.get(CaptureRequest.CONTROL_AF_MODE
); | 594 final int focusMode = mPreviewRequest.get(CaptureRequest.CONTROL_AF_MODE
); |
| 579 Log.d(TAG, "focusMode " + focusMode); | 595 Log.d(TAG, "focusMode: %s", focusMode); |
| 580 final boolean isFocusManual = (focusMode == CameraMetadata.CONTROL_AF_MO
DE_OFF) | 596 // Classify the Focus capabilities. In CONTINUOUS and SINGLE_SHOT, we ca
n call |
| 581 || (focusMode == CameraMetadata.CONTROL_AF_MODE_EDOF); | 597 // autoFocus(AutoFocusCallback) to configure region(s) to focus onto. |
| 598 int jniFocusMode = AndroidFocusMode.UNAVAILABLE; |
| 599 if (focusMode == CameraMetadata.CONTROL_AF_MODE_CONTINUOUS_VIDEO |
| 600 || focusMode == CameraMetadata.CONTROL_AF_MODE_CONTINUOUS_PICTUR
E) { |
| 601 jniFocusMode = AndroidFocusMode.CONTINUOUS; |
| 602 } else if (focusMode == CameraMetadata.CONTROL_AF_MODE_AUTO |
| 603 || focusMode == CameraMetadata.CONTROL_AF_MODE_MACRO) { |
| 604 jniFocusMode = AndroidFocusMode.SINGLE_SHOT; |
| 605 } else if (focusMode == CameraMetadata.CONTROL_AF_MODE_OFF) { |
| 606 jniFocusMode = AndroidFocusMode.FIXED; |
| 607 } else { |
| 608 assert jniFocusMode == CameraMetadata.CONTROL_AF_MODE_EDOF; |
| 609 } |
| 582 | 610 |
| 583 return new PhotoCapabilities(minIso, maxIso, currentIso, maxHeight, minH
eight, | 611 return new PhotoCapabilities(minIso, maxIso, currentIso, maxHeight, minH
eight, |
| 584 currentHeight, maxWidth, minWidth, currentWidth, maxZoom, minZoo
m, currentZoom, | 612 currentHeight, maxWidth, minWidth, currentWidth, maxZoom, minZoo
m, currentZoom, |
| 585 !isFocusManual); | 613 jniFocusMode); |
| 586 } | 614 } |
| 587 | 615 |
| 588 @Override | 616 @Override |
| 589 public void setZoom(int zoom) { | 617 public void setPhotoOptions(int zoom, int focusMode, int width, int height)
{ |
| 590 final CameraCharacteristics cameraCharacteristics = getCameraCharacteris
tics(mContext, mId); | 618 final CameraCharacteristics cameraCharacteristics = getCameraCharacteris
tics(mContext, mId); |
| 591 final Rect canvas = | 619 final Rect canvas = |
| 592 cameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_ACTI
VE_ARRAY_SIZE); | 620 cameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_ACTI
VE_ARRAY_SIZE); |
| 593 | 621 |
| 594 final float normalizedZoom = Math.max(100, Math.min(zoom, mMaxZoom * 100
)) / 100; | 622 if (zoom != 0) { |
| 595 final float cropFactor = (normalizedZoom - 1) / (2 * normalizedZoom); | 623 final float normalizedZoom = Math.max(100, Math.min(zoom, mMaxZoom *
100)) / 100; |
| 624 final float cropFactor = (normalizedZoom - 1) / (2 * normalizedZoom)
; |
| 596 | 625 |
| 597 mCropRect = new Rect(Math.round(canvas.width() * cropFactor), | 626 mCropRect = new Rect(Math.round(canvas.width() * cropFactor), |
| 598 Math.round(canvas.height() * cropFactor), | 627 Math.round(canvas.height() * cropFactor), |
| 599 Math.round(canvas.width() * (1 - cropFactor)), | 628 Math.round(canvas.width() * (1 - cropFactor)), |
| 600 Math.round(canvas.height() * (1 - cropFactor))); | 629 Math.round(canvas.height() * (1 - cropFactor))); |
| 601 Log.d(TAG, "zoom level " + normalizedZoom + ", rectangle: " + mCropRect.
toString()); | 630 Log.d(TAG, "zoom level %f, rectangle: %s", normalizedZoom, mCropRect
.toString()); |
| 631 } |
| 632 |
| 633 mFocusMode = focusMode; |
| 634 |
| 635 if (width > 0) mPhotoWidth = width; |
| 636 if (height > 0) mPhotoHeight = height; |
| 602 | 637 |
| 603 final Handler mainHandler = new Handler(mContext.getMainLooper()); | 638 final Handler mainHandler = new Handler(mContext.getMainLooper()); |
| 604 mainHandler.removeCallbacks(mRestartCapture); | 639 mainHandler.removeCallbacks(mRestartCapture); |
| 605 mainHandler.post(mRestartCapture); | 640 mainHandler.post(mRestartCapture); |
| 606 } | 641 } |
| 607 | 642 |
| 608 @Override | 643 @Override |
| 609 public boolean takePhoto(final long callbackId, int width, int height) { | 644 public boolean takePhoto(final long callbackId) { |
| 610 Log.d(TAG, "takePhoto " + callbackId); | 645 Log.d(TAG, "takePhoto " + callbackId); |
| 611 if (mCameraDevice == null || mCameraState != CameraState.STARTED) return
false; | 646 if (mCameraDevice == null || mCameraState != CameraState.STARTED) return
false; |
| 612 | 647 |
| 613 final CameraCharacteristics cameraCharacteristics = getCameraCharacteris
tics(mContext, mId); | 648 final CameraCharacteristics cameraCharacteristics = getCameraCharacteris
tics(mContext, mId); |
| 614 final StreamConfigurationMap streamMap = | 649 final StreamConfigurationMap streamMap = |
| 615 cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CO
NFIGURATION_MAP); | 650 cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CO
NFIGURATION_MAP); |
| 616 final Size[] supportedSizes = streamMap.getOutputSizes(ImageFormat.JPEG)
; | 651 final Size[] supportedSizes = streamMap.getOutputSizes(ImageFormat.JPEG)
; |
| 617 final Size closestSize = findClosestSizeInArray(supportedSizes, width, h
eight); | 652 final Size closestSize = findClosestSizeInArray(supportedSizes, mPhotoWi
dth, mPhotoHeight); |
| 618 | 653 |
| 619 Log.d(TAG, "requested resolution: (%dx%d)", width, height); | 654 Log.d(TAG, "requested resolution: (%dx%d)", mPhotoWidth, mPhotoHeight); |
| 620 if (closestSize != null) { | 655 if (closestSize != null) { |
| 621 Log.d(TAG, " matched (%dx%d)", closestSize.getWidth(), closestSize.g
etHeight()); | 656 Log.d(TAG, " matched (%dx%d)", closestSize.getWidth(), closestSize.g
etHeight()); |
| 622 } | 657 } |
| 623 final ImageReader imageReader = ImageReader.newInstance( | 658 final ImageReader imageReader = ImageReader.newInstance( |
| 624 (closestSize != null) ? closestSize.getWidth() : mCaptureFormat.
getWidth(), | 659 (closestSize != null) ? closestSize.getWidth() : mCaptureFormat.
getWidth(), |
| 625 (closestSize != null) ? closestSize.getHeight() : mCaptureFormat
.getHeight(), | 660 (closestSize != null) ? closestSize.getHeight() : mCaptureFormat
.getHeight(), |
| 626 ImageFormat.JPEG, 1 /* maxImages */); | 661 ImageFormat.JPEG, 1 /* maxImages */); |
| 627 | 662 |
| 628 HandlerThread thread = new HandlerThread("CameraPicture"); | 663 HandlerThread thread = new HandlerThread("CameraPicture"); |
| 629 thread.start(); | 664 thread.start(); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 646 if (photoRequestBuilder == null) { | 681 if (photoRequestBuilder == null) { |
| 647 Log.e(TAG, "photoRequestBuilder error"); | 682 Log.e(TAG, "photoRequestBuilder error"); |
| 648 return false; | 683 return false; |
| 649 } | 684 } |
| 650 photoRequestBuilder.addTarget(imageReader.getSurface()); | 685 photoRequestBuilder.addTarget(imageReader.getSurface()); |
| 651 photoRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, getCameraRotati
on()); | 686 photoRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, getCameraRotati
on()); |
| 652 if (!mCropRect.isEmpty()) { | 687 if (!mCropRect.isEmpty()) { |
| 653 photoRequestBuilder.set(CaptureRequest.SCALER_CROP_REGION, mCropRect
); | 688 photoRequestBuilder.set(CaptureRequest.SCALER_CROP_REGION, mCropRect
); |
| 654 } | 689 } |
| 655 | 690 |
| 691 if (mFocusMode == AndroidFocusMode.CONTINUOUS) { |
| 692 photoRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, |
| 693 CameraMetadata.CONTROL_AF_MODE_CONTINUOUS_PICTURE); |
| 694 } else if (mFocusMode == AndroidFocusMode.SINGLE_SHOT) { |
| 695 Log.d(TAG, "triggering auto focus (maybe?)"); |
| 696 photoRequestBuilder.set( |
| 697 CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF
_TRIGGER_START); |
| 698 } |
| 699 |
| 656 final CaptureRequest photoRequest = photoRequestBuilder.build(); | 700 final CaptureRequest photoRequest = photoRequestBuilder.build(); |
| 657 final CrPhotoSessionListener sessionListener = | 701 final CrPhotoSessionListener sessionListener = |
| 658 new CrPhotoSessionListener(photoRequest, callbackId); | 702 new CrPhotoSessionListener(photoRequest, callbackId); |
| 659 try { | 703 try { |
| 660 mCameraDevice.createCaptureSession(surfaceList, sessionListener, bac
kgroundHandler); | 704 mCameraDevice.createCaptureSession(surfaceList, sessionListener, bac
kgroundHandler); |
| 661 } catch (CameraAccessException | IllegalArgumentException | SecurityExce
ption ex) { | 705 } catch (CameraAccessException | IllegalArgumentException | SecurityExce
ption ex) { |
| 662 Log.e(TAG, "createCaptureSession: " + ex); | 706 Log.e(TAG, "createCaptureSession: " + ex); |
| 663 return false; | 707 return false; |
| 664 } | 708 } |
| 665 return true; | 709 return true; |
| 666 } | 710 } |
| 667 | 711 |
| 668 @Override | 712 @Override |
| 669 public void deallocate() { | 713 public void deallocate() { |
| 670 Log.d(TAG, "deallocate"); | 714 Log.d(TAG, "deallocate"); |
| 671 } | 715 } |
| 672 } | 716 } |
| OLD | NEW |