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; |
11 import android.hardware.camera2.CameraAccessException; | 11 import android.hardware.camera2.CameraAccessException; |
12 import android.hardware.camera2.CameraCaptureSession; | 12 import android.hardware.camera2.CameraCaptureSession; |
13 import android.hardware.camera2.CameraCharacteristics; | 13 import android.hardware.camera2.CameraCharacteristics; |
14 import android.hardware.camera2.CameraDevice; | 14 import android.hardware.camera2.CameraDevice; |
15 import android.hardware.camera2.CameraManager; | 15 import android.hardware.camera2.CameraManager; |
16 import android.hardware.camera2.CameraMetadata; | 16 import android.hardware.camera2.CameraMetadata; |
17 import android.hardware.camera2.CaptureRequest; | 17 import android.hardware.camera2.CaptureRequest; |
18 import android.hardware.camera2.params.StreamConfigurationMap; | 18 import android.hardware.camera2.params.StreamConfigurationMap; |
19 import android.media.Image; | 19 import android.media.Image; |
20 import android.media.ImageReader; | 20 import android.media.ImageReader; |
21 import android.os.Build; | 21 import android.os.Build; |
22 import android.os.Handler; | 22 import android.os.Handler; |
23 import android.os.HandlerThread; | 23 import android.os.HandlerThread; |
| 24 import android.util.Range; |
24 import android.util.Size; | 25 import android.util.Size; |
25 import android.view.Surface; | 26 import android.view.Surface; |
26 | 27 |
27 import org.chromium.base.Log; | 28 import org.chromium.base.Log; |
28 import org.chromium.base.annotations.JNINamespace; | 29 import org.chromium.base.annotations.JNINamespace; |
29 | 30 |
30 import java.nio.ByteBuffer; | 31 import java.nio.ByteBuffer; |
31 import java.util.ArrayList; | 32 import java.util.ArrayList; |
32 import java.util.List; | 33 import java.util.List; |
33 | 34 |
(...skipping 319 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
353 } | 354 } |
354 } | 355 } |
355 | 356 |
356 private void changeCameraStateAndNotify(CameraState state) { | 357 private void changeCameraStateAndNotify(CameraState state) { |
357 synchronized (mCameraStateLock) { | 358 synchronized (mCameraStateLock) { |
358 mCameraState = state; | 359 mCameraState = state; |
359 mCameraStateLock.notifyAll(); | 360 mCameraStateLock.notifyAll(); |
360 } | 361 } |
361 } | 362 } |
362 | 363 |
| 364 // Finds the closest Size to (|width|x|height|) in |sizes|, and returns it o
r null. |
| 365 // Ignores |width| or |height| if either is zero (== don't care). |
| 366 private static Size findClosestSizeInArray(Size[] sizes, int width, int heig
ht) { |
| 367 if (sizes == null) return null; |
| 368 Size closestSize = null; |
| 369 int minDiff = Integer.MAX_VALUE; |
| 370 for (Size size : sizes) { |
| 371 final int diff = ((width > 0) ? Math.abs(size.getWidth() - width) :
0) |
| 372 + ((height > 0) ? Math.abs(size.getHeight() - height) : 0); |
| 373 if (diff < minDiff) { |
| 374 minDiff = diff; |
| 375 closestSize = size; |
| 376 } |
| 377 } |
| 378 if (minDiff == Integer.MAX_VALUE) { |
| 379 Log.e(TAG, "Couldn't find resolution close to (%dx%d)", width, heigh
t); |
| 380 return null; |
| 381 } |
| 382 return closestSize; |
| 383 } |
| 384 |
363 static boolean isLegacyDevice(Context appContext, int id) { | 385 static boolean isLegacyDevice(Context appContext, int id) { |
364 final CameraCharacteristics cameraCharacteristics = | 386 final CameraCharacteristics cameraCharacteristics = |
365 getCameraCharacteristics(appContext, id); | 387 getCameraCharacteristics(appContext, id); |
366 return cameraCharacteristics != null | 388 return cameraCharacteristics != null |
367 && cameraCharacteristics.get(CameraCharacteristics.INFO_SUPPORTE
D_HARDWARE_LEVEL) | 389 && cameraCharacteristics.get(CameraCharacteristics.INFO_SUPPORTE
D_HARDWARE_LEVEL) |
368 == CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY; | 390 == CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY; |
369 } | 391 } |
370 | 392 |
371 static int getNumberOfCameras(Context appContext) { | 393 static int getNumberOfCameras(Context appContext) { |
372 final CameraManager manager = | 394 final CameraManager manager = |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
469 Log.e(TAG, "allocate() invoked while Camera is busy opening/conf
iguring."); | 491 Log.e(TAG, "allocate() invoked while Camera is busy opening/conf
iguring."); |
470 return false; | 492 return false; |
471 } | 493 } |
472 } | 494 } |
473 final CameraCharacteristics cameraCharacteristics = getCameraCharacteris
tics(mContext, mId); | 495 final CameraCharacteristics cameraCharacteristics = getCameraCharacteris
tics(mContext, mId); |
474 final StreamConfigurationMap streamMap = | 496 final StreamConfigurationMap streamMap = |
475 cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CO
NFIGURATION_MAP); | 497 cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CO
NFIGURATION_MAP); |
476 | 498 |
477 // Find closest supported size. | 499 // Find closest supported size. |
478 final Size[] supportedSizes = streamMap.getOutputSizes(ImageFormat.YUV_4
20_888); | 500 final Size[] supportedSizes = streamMap.getOutputSizes(ImageFormat.YUV_4
20_888); |
479 if (supportedSizes == null) return false; | 501 final Size closestSupportedSize = findClosestSizeInArray(supportedSizes,
width, height); |
480 Size closestSupportedSize = null; | 502 if (closestSupportedSize == null) { |
481 int minDiff = Integer.MAX_VALUE; | |
482 for (Size size : supportedSizes) { | |
483 final int diff = | |
484 Math.abs(size.getWidth() - width) + Math.abs(size.getHeight(
) - height); | |
485 if (diff < minDiff) { | |
486 minDiff = diff; | |
487 closestSupportedSize = size; | |
488 } | |
489 } | |
490 if (minDiff == Integer.MAX_VALUE) { | |
491 Log.e(TAG, "No supported resolutions."); | 503 Log.e(TAG, "No supported resolutions."); |
492 return false; | 504 return false; |
493 } | 505 } |
494 Log.d(TAG, "allocate: matched (%d x %d)", closestSupportedSize.getWidth(
), | 506 Log.d(TAG, "allocate: matched (%d x %d)", closestSupportedSize.getWidth(
), |
495 closestSupportedSize.getHeight()); | 507 closestSupportedSize.getHeight()); |
496 | 508 |
497 // |mCaptureFormat| is also used to configure the ImageReader. | 509 // |mCaptureFormat| is also used to configure the ImageReader. |
498 mCaptureFormat = new VideoCaptureFormat(closestSupportedSize.getWidth(), | 510 mCaptureFormat = new VideoCaptureFormat(closestSupportedSize.getWidth(), |
499 closestSupportedSize.getHeight(), frameRate, ImageFormat.YUV_420
_888); | 511 closestSupportedSize.getHeight(), frameRate, ImageFormat.YUV_420
_888); |
500 int expectedFrameSize = mCaptureFormat.mWidth * mCaptureFormat.mHeight | 512 int expectedFrameSize = mCaptureFormat.mWidth * mCaptureFormat.mHeight |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
555 if (mCameraDevice == null) return false; | 567 if (mCameraDevice == null) return false; |
556 mCameraDevice.close(); | 568 mCameraDevice.close(); |
557 changeCameraStateAndNotify(CameraState.STOPPED); | 569 changeCameraStateAndNotify(CameraState.STOPPED); |
558 mCropRect = new Rect(); | 570 mCropRect = new Rect(); |
559 return true; | 571 return true; |
560 } | 572 } |
561 | 573 |
562 public PhotoCapabilities getPhotoCapabilities() { | 574 public PhotoCapabilities getPhotoCapabilities() { |
563 final CameraCharacteristics cameraCharacteristics = getCameraCharacteris
tics(mContext, mId); | 575 final CameraCharacteristics cameraCharacteristics = getCameraCharacteris
tics(mContext, mId); |
564 | 576 |
| 577 int minIso = 0; |
| 578 int maxIso = 0; |
| 579 final Range<Integer> iso_range = |
| 580 cameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_SENS
ITIVITY_RANGE); |
| 581 if (iso_range != null) { |
| 582 minIso = iso_range.getLower(); |
| 583 maxIso = iso_range.getUpper(); |
| 584 } |
| 585 final int currentIso = mPreviewRequest.get(CaptureRequest.SENSOR_SENSITI
VITY); |
| 586 |
| 587 final StreamConfigurationMap streamMap = |
| 588 cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CO
NFIGURATION_MAP); |
| 589 final Size[] supportedSizes = streamMap.getOutputSizes(ImageFormat.JPEG)
; |
| 590 int minWidth = Integer.MAX_VALUE; |
| 591 int minHeight = Integer.MAX_VALUE; |
| 592 int maxWidth = 0; |
| 593 int maxHeight = 0; |
| 594 for (Size size : supportedSizes) { |
| 595 if (size.getWidth() < minWidth) minWidth = size.getWidth(); |
| 596 if (size.getHeight() < minHeight) minHeight = size.getHeight(); |
| 597 if (size.getWidth() > maxWidth) maxWidth = size.getWidth(); |
| 598 if (size.getHeight() > maxHeight) maxHeight = size.getHeight(); |
| 599 } |
| 600 final int currentHeight = mCaptureFormat.getHeight(); |
| 601 final int currentWidth = mCaptureFormat.getWidth(); |
| 602 |
565 // The Min and Max zoom are returned as x100 by the API to avoid using f
loating point. There | 603 // The Min and Max zoom are returned as x100 by the API to avoid using f
loating point. There |
566 // is no min-zoom per se, so clamp it to always 100 (TODO(mcasas): make
const member). | 604 // is no min-zoom per se, so clamp it to always 100 (TODO(mcasas): make
const member). |
567 final int minZoom = 100; | 605 final int minZoom = 100; |
568 final int maxZoom = Math.round(mMaxZoom * 100); | 606 final int maxZoom = Math.round(mMaxZoom * 100); |
569 | |
570 // Width Ratio x100 is used as measure of current zoom. | 607 // Width Ratio x100 is used as measure of current zoom. |
571 final int currentZoom = 100 * mPreviewRequest.get(CaptureRequest.SCALER_
CROP_REGION).width() | 608 final int currentZoom = 100 * mPreviewRequest.get(CaptureRequest.SCALER_
CROP_REGION).width() |
572 / cameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_AC
TIVE_ARRAY_SIZE) | 609 / cameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_AC
TIVE_ARRAY_SIZE) |
573 .width(); | 610 .width(); |
574 | 611 |
575 final int focusMode = mPreviewRequest.get(CaptureRequest.CONTROL_AF_MODE
); | 612 final int focusMode = mPreviewRequest.get(CaptureRequest.CONTROL_AF_MODE
); |
576 Log.d(TAG, "focusMode " + focusMode); | 613 Log.d(TAG, "focusMode " + focusMode); |
577 final boolean isFocusManual = (focusMode == CameraMetadata.CONTROL_AF_MO
DE_OFF) | 614 final boolean isFocusManual = (focusMode == CameraMetadata.CONTROL_AF_MO
DE_OFF) |
578 || (focusMode == CameraMetadata.CONTROL_AF_MODE_EDOF); | 615 || (focusMode == CameraMetadata.CONTROL_AF_MODE_EDOF); |
579 | 616 |
580 return new PhotoCapabilities(maxZoom, minZoom, currentZoom, !isFocusManu
al); | 617 return new PhotoCapabilities(minIso, maxIso, currentIso, maxHeight, minH
eight, |
| 618 currentHeight, maxWidth, minWidth, currentWidth, maxZoom, minZoo
m, currentZoom, |
| 619 !isFocusManual); |
581 } | 620 } |
582 | 621 |
583 @Override | 622 @Override |
584 public void setZoom(int zoom) { | 623 public void setZoom(int zoom) { |
585 final CameraCharacteristics cameraCharacteristics = getCameraCharacteris
tics(mContext, mId); | 624 final CameraCharacteristics cameraCharacteristics = getCameraCharacteris
tics(mContext, mId); |
586 final Rect canvas = | 625 final Rect canvas = |
587 cameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_ACTI
VE_ARRAY_SIZE); | 626 cameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_ACTI
VE_ARRAY_SIZE); |
588 | 627 |
589 final float normalizedZoom = Math.max(100, Math.min(zoom, mMaxZoom * 100
)) / 100; | 628 final float normalizedZoom = Math.max(100, Math.min(zoom, mMaxZoom * 100
)) / 100; |
590 final float cropFactor = (normalizedZoom - 1) / (2 * normalizedZoom); | 629 final float cropFactor = (normalizedZoom - 1) / (2 * normalizedZoom); |
591 | 630 |
592 mCropRect = new Rect(Math.round(canvas.width() * cropFactor), | 631 mCropRect = new Rect(Math.round(canvas.width() * cropFactor), |
593 Math.round(canvas.height() * cropFactor), | 632 Math.round(canvas.height() * cropFactor), |
594 Math.round(canvas.width() * (1 - cropFactor)), | 633 Math.round(canvas.width() * (1 - cropFactor)), |
595 Math.round(canvas.height() * (1 - cropFactor))); | 634 Math.round(canvas.height() * (1 - cropFactor))); |
596 Log.d(TAG, "zoom level " + normalizedZoom + ", rectangle: " + mCropRect.
toString()); | 635 Log.d(TAG, "zoom level " + normalizedZoom + ", rectangle: " + mCropRect.
toString()); |
597 | 636 |
598 final Handler mainHandler = new Handler(mContext.getMainLooper()); | 637 final Handler mainHandler = new Handler(mContext.getMainLooper()); |
599 mainHandler.post(new Runnable() { | 638 mainHandler.post(new Runnable() { |
600 @Override | 639 @Override |
601 public void run() { | 640 public void run() { |
602 mPreviewSession.close(); // Asynchronously kill the CaptureSessi
on. | 641 mPreviewSession.close(); // Asynchronously kill the CaptureSessi
on. |
603 createPreviewObjects(); | 642 createPreviewObjects(); |
604 } | 643 } |
605 }); | 644 }); |
606 } | 645 } |
607 | 646 |
608 @Override | 647 @Override |
609 public boolean takePhoto(final long callbackId) { | 648 public boolean takePhoto(final long callbackId, int width, int height) { |
610 Log.d(TAG, "takePhoto " + callbackId); | 649 Log.d(TAG, "takePhoto " + callbackId); |
611 if (mCameraDevice == null || mCameraState != CameraState.STARTED) return
false; | 650 if (mCameraDevice == null || mCameraState != CameraState.STARTED) return
false; |
612 | 651 |
613 final ImageReader imageReader = ImageReader.newInstance(mCaptureFormat.g
etWidth(), | 652 final CameraCharacteristics cameraCharacteristics = getCameraCharacteris
tics(mContext, mId); |
614 mCaptureFormat.getHeight(), ImageFormat.JPEG, 1 /* maxImages */)
; | 653 final StreamConfigurationMap streamMap = |
| 654 cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CO
NFIGURATION_MAP); |
| 655 final Size[] supportedSizes = streamMap.getOutputSizes(ImageFormat.JPEG)
; |
| 656 final Size closestSize = findClosestSizeInArray(supportedSizes, width, h
eight); |
| 657 |
| 658 Log.d(TAG, "requested resolution: (%dx%d)", width, height); |
| 659 if (closestSize != null) { |
| 660 Log.d(TAG, " matched (%dx%d)", closestSize.getWidth(), closestSize.g
etHeight()); |
| 661 } |
| 662 final ImageReader imageReader = ImageReader.newInstance( |
| 663 (closestSize != null) ? closestSize.getWidth() : mCaptureFormat.
getWidth(), |
| 664 (closestSize != null) ? closestSize.getHeight() : mCaptureFormat
.getHeight(), |
| 665 ImageFormat.JPEG, 1 /* maxImages */); |
615 | 666 |
616 HandlerThread thread = new HandlerThread("CameraPicture"); | 667 HandlerThread thread = new HandlerThread("CameraPicture"); |
617 thread.start(); | 668 thread.start(); |
618 final Handler backgroundHandler = new Handler(thread.getLooper()); | 669 final Handler backgroundHandler = new Handler(thread.getLooper()); |
619 | 670 |
620 final CrPhotoReaderListener photoReaderListener = new CrPhotoReaderListe
ner(callbackId); | 671 final CrPhotoReaderListener photoReaderListener = new CrPhotoReaderListe
ner(callbackId); |
621 imageReader.setOnImageAvailableListener(photoReaderListener, backgroundH
andler); | 672 imageReader.setOnImageAvailableListener(photoReaderListener, backgroundH
andler); |
622 | 673 |
623 final List<Surface> surfaceList = new ArrayList<Surface>(1); | 674 final List<Surface> surfaceList = new ArrayList<Surface>(1); |
624 surfaceList.add(imageReader.getSurface()); | 675 surfaceList.add(imageReader.getSurface()); |
(...skipping 26 matching lines...) Expand all Loading... |
651 return false; | 702 return false; |
652 } | 703 } |
653 return true; | 704 return true; |
654 } | 705 } |
655 | 706 |
656 @Override | 707 @Override |
657 public void deallocate() { | 708 public void deallocate() { |
658 Log.d(TAG, "deallocate"); | 709 Log.d(TAG, "deallocate"); |
659 } | 710 } |
660 } | 711 } |
OLD | NEW |