1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.ex.camera2.portability;
18
19import static android.hardware.camera2.CameraCharacteristics.*;
20
21import android.graphics.ImageFormat;
22import android.graphics.Point;
23import android.graphics.SurfaceTexture;
24import android.hardware.camera2.CameraCharacteristics;
25import android.hardware.camera2.params.StreamConfigurationMap;
26import android.media.MediaRecorder;
27import android.util.Range;
28import android.util.Rational;
29
30import com.android.ex.camera2.portability.debug.Log;
31
32import java.util.ArrayList;
33import java.util.Arrays;
34
35/**
36 * The subclass of {@link CameraCapabilities} for Android Camera 2 API.
37 */
38public class AndroidCamera2Capabilities extends CameraCapabilities {
39    private static Log.Tag TAG = new Log.Tag("AndCam2Capabs");
40
41    AndroidCamera2Capabilities(CameraCharacteristics p) {
42        super(new Stringifier());
43
44        StreamConfigurationMap s = p.get(SCALER_STREAM_CONFIGURATION_MAP);
45
46        for (Range<Integer> fpsRange : p.get(CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES)) {
47            mSupportedPreviewFpsRange.add(new int[] { fpsRange.getLower(), fpsRange.getUpper() });
48        }
49
50        // TODO: We only support TextureView preview rendering
51        mSupportedPreviewSizes.addAll(Size.buildListFromAndroidSizes(Arrays.asList(
52                s.getOutputSizes(SurfaceTexture.class))));
53        for (int format : s.getOutputFormats()) {
54            mSupportedPreviewFormats.add(format);
55        }
56
57        // TODO: We only support MediaRecorder video capture
58        mSupportedVideoSizes.addAll(Size.buildListFromAndroidSizes(Arrays.asList(
59                s.getOutputSizes(MediaRecorder.class))));
60
61        // TODO: We only support JPEG image capture
62        mSupportedPhotoSizes.addAll(Size.buildListFromAndroidSizes(Arrays.asList(
63                s.getOutputSizes(ImageFormat.JPEG))));
64        mSupportedPhotoFormats.addAll(mSupportedPreviewFormats);
65
66        buildSceneModes(p);
67        buildFlashModes(p);
68        buildFocusModes(p);
69        buildWhiteBalances(p);
70        // TODO: Populate mSupportedFeatures
71
72        // TODO: Populate mPreferredPreviewSizeForVideo
73
74        Range<Integer> ecRange = p.get(CONTROL_AE_COMPENSATION_RANGE);
75        mMinExposureCompensation = ecRange.getLower();
76        mMaxExposureCompensation = ecRange.getUpper();
77
78        Rational ecStep = p.get(CONTROL_AE_COMPENSATION_STEP);
79        mExposureCompensationStep = (float) ecStep.getNumerator() / ecStep.getDenominator();
80
81        mMaxNumOfFacesSupported = p.get(STATISTICS_INFO_MAX_FACE_COUNT);
82        mMaxNumOfMeteringArea = p.get(CONTROL_MAX_REGIONS_AE);
83
84        mMaxZoomRatio = p.get(SCALER_AVAILABLE_MAX_DIGITAL_ZOOM);
85        // TODO: Populate mHorizontalViewAngle
86        // TODO: Populate mVerticalViewAngle
87        // TODO: Populate mZoomRatioList
88        // TODO: Populate mMaxZoomIndex
89
90        if (supports(FocusMode.AUTO)) {
91            mMaxNumOfFocusAreas = p.get(CONTROL_MAX_REGIONS_AF);
92            if (mMaxNumOfFocusAreas > 0) {
93                mSupportedFeatures.add(Feature.FOCUS_AREA);
94            }
95        }
96        if (mMaxNumOfMeteringArea > 0) {
97            mSupportedFeatures.add(Feature.METERING_AREA);
98        }
99
100        if (mMaxZoomRatio > CameraCapabilities.ZOOM_RATIO_UNZOOMED) {
101            mSupportedFeatures.add(Feature.ZOOM);
102        }
103
104        // TODO: Detect other features
105    }
106
107    private void buildSceneModes(CameraCharacteristics p) {
108        int[] scenes = p.get(CONTROL_AVAILABLE_SCENE_MODES);
109        if (scenes != null) {
110            for (int scene : scenes) {
111                SceneMode equiv = sceneModeFromInt(scene);
112                if (equiv != null) {
113                    mSupportedSceneModes.add(equiv);
114                }
115            }
116        }
117    }
118
119    private void buildFlashModes(CameraCharacteristics p) {
120        mSupportedFlashModes.add(FlashMode.OFF);
121        if (p.get(FLASH_INFO_AVAILABLE)) {
122            mSupportedFlashModes.add(FlashMode.AUTO);
123            mSupportedFlashModes.add(FlashMode.ON);
124            mSupportedFlashModes.add(FlashMode.TORCH);
125            for (int expose : p.get(CONTROL_AE_AVAILABLE_MODES)) {
126                if (expose == CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE) {
127                    mSupportedFlashModes.add(FlashMode.RED_EYE);
128                }
129            }
130        }
131    }
132
133    private void buildFocusModes(CameraCharacteristics p) {
134        int[] focuses = p.get(CONTROL_AF_AVAILABLE_MODES);
135        if (focuses != null) {
136            for (int focus : focuses) {
137                FocusMode equiv = focusModeFromInt(focus);
138                if (equiv != null) {
139                    mSupportedFocusModes.add(equiv);
140                }
141            }
142        }
143    }
144
145    private void buildWhiteBalances(CameraCharacteristics p) {
146        int[] bals = p.get(CONTROL_AWB_AVAILABLE_MODES);
147        if (bals != null) {
148            for (int bal : bals) {
149                WhiteBalance equiv = whiteBalanceFromInt(bal);
150                if (equiv != null) {
151                    mSupportedWhiteBalances.add(equiv);
152                }
153            }
154        }
155    }
156
157    /**
158     * Converts the API-related integer representation of the focus mode to the
159     * abstract representation.
160     *
161     * @param fm The integral representation.
162     * @return The mode represented by the input integer, or {@code null} if it
163     *         cannot be converted.
164     */
165    public static FocusMode focusModeFromInt(int fm) {
166        switch (fm) {
167            case CONTROL_AF_MODE_AUTO:
168                return FocusMode.AUTO;
169            case CONTROL_AF_MODE_CONTINUOUS_PICTURE:
170                return FocusMode.CONTINUOUS_PICTURE;
171            case CONTROL_AF_MODE_CONTINUOUS_VIDEO:
172                return FocusMode.CONTINUOUS_VIDEO;
173            case CONTROL_AF_MODE_EDOF:
174                return FocusMode.EXTENDED_DOF;
175            case CONTROL_AF_MODE_OFF:
176                return FocusMode.FIXED;
177            // TODO: We cannot support INFINITY
178            case CONTROL_AF_MODE_MACRO:
179                return FocusMode.MACRO;
180        }
181        Log.w(TAG, "Unable to convert from API 2 focus mode: " + fm);
182        return null;
183    }
184
185    /**
186     * Converts the API-related integer representation of the scene mode to the
187     * abstract representation.
188     *
189     * @param sm The integral representation.
190     * @return The mode represented by the input integer, or {@code null} if it
191     *         cannot be converted.
192     */
193    public static SceneMode sceneModeFromInt(int sm) {
194        switch (sm) {
195            case CONTROL_SCENE_MODE_DISABLED:
196                return SceneMode.AUTO;
197            case CONTROL_SCENE_MODE_ACTION:
198                return SceneMode.ACTION;
199            case CONTROL_SCENE_MODE_BARCODE:
200                return SceneMode.BARCODE;
201            case CONTROL_SCENE_MODE_BEACH:
202                return SceneMode.BEACH;
203            case CONTROL_SCENE_MODE_CANDLELIGHT:
204                return SceneMode.CANDLELIGHT;
205            case CONTROL_SCENE_MODE_FIREWORKS:
206                return SceneMode.FIREWORKS;
207            case CONTROL_SCENE_MODE_LANDSCAPE:
208                return SceneMode.LANDSCAPE;
209            case CONTROL_SCENE_MODE_NIGHT:
210                return SceneMode.NIGHT;
211            // TODO: We cannot support NIGHT_PORTRAIT
212            case CONTROL_SCENE_MODE_PARTY:
213                return SceneMode.PARTY;
214            case CONTROL_SCENE_MODE_PORTRAIT:
215                return SceneMode.PORTRAIT;
216            case CONTROL_SCENE_MODE_SNOW:
217                return SceneMode.SNOW;
218            case CONTROL_SCENE_MODE_SPORTS:
219                return SceneMode.SPORTS;
220            case CONTROL_SCENE_MODE_STEADYPHOTO:
221                return SceneMode.STEADYPHOTO;
222            case CONTROL_SCENE_MODE_SUNSET:
223                return SceneMode.SUNSET;
224            case CONTROL_SCENE_MODE_THEATRE:
225                return SceneMode.THEATRE;
226            case CONTROL_SCENE_MODE_HDR:
227                return SceneMode.HDR;
228            // TODO: We cannot expose FACE_PRIORITY, or HIGH_SPEED_VIDEO
229        }
230
231        Log.w(TAG, "Unable to convert from API 2 scene mode: " + sm);
232        return null;
233    }
234
235    /**
236     * Converts the API-related integer representation of the white balance to
237     * the abstract representation.
238     *
239     * @param wb The integral representation.
240     * @return The balance represented by the input integer, or {@code null} if
241     *         it cannot be converted.
242     */
243    public static WhiteBalance whiteBalanceFromInt(int wb) {
244        switch (wb) {
245            case CONTROL_AWB_MODE_AUTO:
246                return WhiteBalance.AUTO;
247            case CONTROL_AWB_MODE_CLOUDY_DAYLIGHT:
248                return WhiteBalance.CLOUDY_DAYLIGHT;
249            case CONTROL_AWB_MODE_DAYLIGHT:
250                return WhiteBalance.DAYLIGHT;
251            case CONTROL_AWB_MODE_FLUORESCENT:
252                return WhiteBalance.FLUORESCENT;
253            case CONTROL_AWB_MODE_INCANDESCENT:
254                return WhiteBalance.INCANDESCENT;
255            case CONTROL_AWB_MODE_SHADE:
256                return WhiteBalance.SHADE;
257            case CONTROL_AWB_MODE_TWILIGHT:
258                return WhiteBalance.TWILIGHT;
259            case CONTROL_AWB_MODE_WARM_FLUORESCENT:
260                return WhiteBalance.WARM_FLUORESCENT;
261        }
262        Log.w(TAG, "Unable to convert from API 2 white balance: " + wb);
263        return null;
264    }
265}
266