/* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.ex.camera2.portability; import static android.hardware.camera2.CameraCharacteristics.*; import android.graphics.ImageFormat; import android.graphics.Point; import android.graphics.SurfaceTexture; import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.params.StreamConfigurationMap; import android.media.MediaRecorder; import android.util.Range; import android.util.Rational; import com.android.ex.camera2.portability.debug.Log; import java.util.ArrayList; import java.util.Arrays; /** * The subclass of {@link CameraCapabilities} for Android Camera 2 API. */ public class AndroidCamera2Capabilities extends CameraCapabilities { private static Log.Tag TAG = new Log.Tag("AndCam2Capabs"); AndroidCamera2Capabilities(CameraCharacteristics p) { super(new Stringifier()); StreamConfigurationMap s = p.get(SCALER_STREAM_CONFIGURATION_MAP); for (Range<Integer> fpsRange : p.get(CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES)) { mSupportedPreviewFpsRange.add(new int[] { fpsRange.getLower(), fpsRange.getUpper() }); } // TODO: We only support TextureView preview rendering mSupportedPreviewSizes.addAll(Size.buildListFromAndroidSizes(Arrays.asList( s.getOutputSizes(SurfaceTexture.class)))); for (int format : s.getOutputFormats()) { mSupportedPreviewFormats.add(format); } // TODO: We only support MediaRecorder video capture mSupportedVideoSizes.addAll(Size.buildListFromAndroidSizes(Arrays.asList( s.getOutputSizes(MediaRecorder.class)))); // TODO: We only support JPEG image capture mSupportedPhotoSizes.addAll(Size.buildListFromAndroidSizes(Arrays.asList( s.getOutputSizes(ImageFormat.JPEG)))); mSupportedPhotoFormats.addAll(mSupportedPreviewFormats); buildSceneModes(p); buildFlashModes(p); buildFocusModes(p); buildWhiteBalances(p); // TODO: Populate mSupportedFeatures // TODO: Populate mPreferredPreviewSizeForVideo Range<Integer> ecRange = p.get(CONTROL_AE_COMPENSATION_RANGE); mMinExposureCompensation = ecRange.getLower(); mMaxExposureCompensation = ecRange.getUpper(); Rational ecStep = p.get(CONTROL_AE_COMPENSATION_STEP); mExposureCompensationStep = (float) ecStep.getNumerator() / ecStep.getDenominator(); mMaxNumOfFacesSupported = p.get(STATISTICS_INFO_MAX_FACE_COUNT); mMaxNumOfMeteringArea = p.get(CONTROL_MAX_REGIONS_AE); mMaxZoomRatio = p.get(SCALER_AVAILABLE_MAX_DIGITAL_ZOOM); // TODO: Populate mHorizontalViewAngle // TODO: Populate mVerticalViewAngle // TODO: Populate mZoomRatioList // TODO: Populate mMaxZoomIndex if (supports(FocusMode.AUTO)) { mMaxNumOfFocusAreas = p.get(CONTROL_MAX_REGIONS_AF); if (mMaxNumOfFocusAreas > 0) { mSupportedFeatures.add(Feature.FOCUS_AREA); } } if (mMaxNumOfMeteringArea > 0) { mSupportedFeatures.add(Feature.METERING_AREA); } if (mMaxZoomRatio > CameraCapabilities.ZOOM_RATIO_UNZOOMED) { mSupportedFeatures.add(Feature.ZOOM); } // TODO: Detect other features } private void buildSceneModes(CameraCharacteristics p) { int[] scenes = p.get(CONTROL_AVAILABLE_SCENE_MODES); if (scenes != null) { for (int scene : scenes) { SceneMode equiv = sceneModeFromInt(scene); if (equiv != null) { mSupportedSceneModes.add(equiv); } } } } private void buildFlashModes(CameraCharacteristics p) { mSupportedFlashModes.add(FlashMode.OFF); if (p.get(FLASH_INFO_AVAILABLE)) { mSupportedFlashModes.add(FlashMode.AUTO); mSupportedFlashModes.add(FlashMode.ON); mSupportedFlashModes.add(FlashMode.TORCH); for (int expose : p.get(CONTROL_AE_AVAILABLE_MODES)) { if (expose == CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE) { mSupportedFlashModes.add(FlashMode.RED_EYE); } } } } private void buildFocusModes(CameraCharacteristics p) { int[] focuses = p.get(CONTROL_AF_AVAILABLE_MODES); if (focuses != null) { for (int focus : focuses) { FocusMode equiv = focusModeFromInt(focus); if (equiv != null) { mSupportedFocusModes.add(equiv); } } } } private void buildWhiteBalances(CameraCharacteristics p) { int[] bals = p.get(CONTROL_AWB_AVAILABLE_MODES); if (bals != null) { for (int bal : bals) { WhiteBalance equiv = whiteBalanceFromInt(bal); if (equiv != null) { mSupportedWhiteBalances.add(equiv); } } } } /** * Converts the API-related integer representation of the focus mode to the * abstract representation. * * @param fm The integral representation. * @return The mode represented by the input integer, or {@code null} if it * cannot be converted. */ public static FocusMode focusModeFromInt(int fm) { switch (fm) { case CONTROL_AF_MODE_AUTO: return FocusMode.AUTO; case CONTROL_AF_MODE_CONTINUOUS_PICTURE: return FocusMode.CONTINUOUS_PICTURE; case CONTROL_AF_MODE_CONTINUOUS_VIDEO: return FocusMode.CONTINUOUS_VIDEO; case CONTROL_AF_MODE_EDOF: return FocusMode.EXTENDED_DOF; case CONTROL_AF_MODE_OFF: return FocusMode.FIXED; // TODO: We cannot support INFINITY case CONTROL_AF_MODE_MACRO: return FocusMode.MACRO; } Log.w(TAG, "Unable to convert from API 2 focus mode: " + fm); return null; } /** * Converts the API-related integer representation of the scene mode to the * abstract representation. * * @param sm The integral representation. * @return The mode represented by the input integer, or {@code null} if it * cannot be converted. */ public static SceneMode sceneModeFromInt(int sm) { switch (sm) { case CONTROL_SCENE_MODE_DISABLED: return SceneMode.AUTO; case CONTROL_SCENE_MODE_ACTION: return SceneMode.ACTION; case CONTROL_SCENE_MODE_BARCODE: return SceneMode.BARCODE; case CONTROL_SCENE_MODE_BEACH: return SceneMode.BEACH; case CONTROL_SCENE_MODE_CANDLELIGHT: return SceneMode.CANDLELIGHT; case CONTROL_SCENE_MODE_FIREWORKS: return SceneMode.FIREWORKS; case CONTROL_SCENE_MODE_LANDSCAPE: return SceneMode.LANDSCAPE; case CONTROL_SCENE_MODE_NIGHT: return SceneMode.NIGHT; // TODO: We cannot support NIGHT_PORTRAIT case CONTROL_SCENE_MODE_PARTY: return SceneMode.PARTY; case CONTROL_SCENE_MODE_PORTRAIT: return SceneMode.PORTRAIT; case CONTROL_SCENE_MODE_SNOW: return SceneMode.SNOW; case CONTROL_SCENE_MODE_SPORTS: return SceneMode.SPORTS; case CONTROL_SCENE_MODE_STEADYPHOTO: return SceneMode.STEADYPHOTO; case CONTROL_SCENE_MODE_SUNSET: return SceneMode.SUNSET; case CONTROL_SCENE_MODE_THEATRE: return SceneMode.THEATRE; case CONTROL_SCENE_MODE_HDR: return SceneMode.HDR; // TODO: We cannot expose FACE_PRIORITY, or HIGH_SPEED_VIDEO } Log.w(TAG, "Unable to convert from API 2 scene mode: " + sm); return null; } /** * Converts the API-related integer representation of the white balance to * the abstract representation. * * @param wb The integral representation. * @return The balance represented by the input integer, or {@code null} if * it cannot be converted. */ public static WhiteBalance whiteBalanceFromInt(int wb) { switch (wb) { case CONTROL_AWB_MODE_AUTO: return WhiteBalance.AUTO; case CONTROL_AWB_MODE_CLOUDY_DAYLIGHT: return WhiteBalance.CLOUDY_DAYLIGHT; case CONTROL_AWB_MODE_DAYLIGHT: return WhiteBalance.DAYLIGHT; case CONTROL_AWB_MODE_FLUORESCENT: return WhiteBalance.FLUORESCENT; case CONTROL_AWB_MODE_INCANDESCENT: return WhiteBalance.INCANDESCENT; case CONTROL_AWB_MODE_SHADE: return WhiteBalance.SHADE; case CONTROL_AWB_MODE_TWILIGHT: return WhiteBalance.TWILIGHT; case CONTROL_AWB_MODE_WARM_FLUORESCENT: return WhiteBalance.WARM_FLUORESCENT; } Log.w(TAG, "Unable to convert from API 2 white balance: " + wb); return null; } }