LegacyMetadataMapper.java revision e663cb77281c4c76241b820f6126543f1c2d859f
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 android.hardware.camera2.legacy;
18
19import android.graphics.ImageFormat;
20import android.graphics.PixelFormat;
21import android.graphics.Rect;
22import android.hardware.Camera;
23import android.hardware.Camera.CameraInfo;
24import android.hardware.Camera.Parameters;
25import android.hardware.camera2.CameraCharacteristics;
26import android.hardware.camera2.CameraDevice;
27import android.hardware.camera2.CameraMetadata;
28import android.hardware.camera2.CaptureRequest;
29import android.hardware.camera2.CaptureResult;
30import android.hardware.camera2.impl.CameraMetadataNative;
31import android.hardware.camera2.params.MeteringRectangle;
32import android.hardware.camera2.params.StreamConfiguration;
33import android.hardware.camera2.params.StreamConfigurationDuration;
34import android.hardware.camera2.utils.ArrayUtils;
35import android.hardware.camera2.utils.ListUtils;
36import android.hardware.camera2.utils.ParamsUtils;
37import android.hardware.camera2.utils.SizeAreaComparator;
38import android.util.Log;
39import android.util.Range;
40import android.util.Size;
41import android.util.SizeF;
42
43import java.util.ArrayList;
44import java.util.Arrays;
45import java.util.Collections;
46import java.util.Comparator;
47import java.util.List;
48
49import static com.android.internal.util.Preconditions.*;
50import static android.hardware.camera2.CameraCharacteristics.*;
51import static android.hardware.camera2.legacy.ParameterUtils.*;
52
53/**
54 * Provide legacy-specific implementations of camera2 metadata for legacy devices, such as the
55 * camera characteristics.
56 */
57@SuppressWarnings("deprecation")
58public class LegacyMetadataMapper {
59    private static final String TAG = "LegacyMetadataMapper";
60    private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
61
62    private static final long NS_PER_MS = 1000000;
63
64    // from graphics.h
65    public static final int HAL_PIXEL_FORMAT_RGBA_8888 = PixelFormat.RGBA_8888;
66    public static final int HAL_PIXEL_FORMAT_BGRA_8888 = 0x5;
67    public static final int HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED = 0x22;
68    public static final int HAL_PIXEL_FORMAT_BLOB = 0x21;
69
70    // for metadata
71    private static final float LENS_INFO_MINIMUM_FOCUS_DISTANCE_FIXED_FOCUS = 0.0f;
72
73    private static final int REQUEST_MAX_NUM_OUTPUT_STREAMS_COUNT_RAW = 0; // no raw support
74    private static final int REQUEST_MAX_NUM_OUTPUT_STREAMS_COUNT_PROC = 3; // preview, video, cb
75    private static final int REQUEST_MAX_NUM_OUTPUT_STREAMS_COUNT_PROC_STALL = 1; // 1 jpeg only
76    private static final int REQUEST_MAX_NUM_INPUT_STREAMS_COUNT = 0; // no reprocessing
77
78    /** Assume 3 HAL1 stages: Exposure, Read-out, Post-Processing */
79    private static final int REQUEST_PIPELINE_MAX_DEPTH_HAL1 = 3;
80    /** Assume 3 shim stages: Preview input, Split output, Format conversion for output */
81    private static final int REQUEST_PIPELINE_MAX_DEPTH_OURS = 3;
82    /* TODO: Update above maxDepth values once we do more performance measurements */
83
84    // For approximating JPEG stall durations
85    private static final long APPROXIMATE_CAPTURE_DELAY_MS = 200; // 200 milliseconds
86    private static final long APPROXIMATE_SENSOR_AREA_PX = (1 << 23); // 8 megapixels
87    private static final long APPROXIMATE_JPEG_ENCODE_TIME_MS = 600; // 600 milliseconds
88
89    static final int UNKNOWN_MODE = -1;
90
91    /*
92     * Development hijinks: Lie about not supporting certain capabilities
93     *
94     * - Unblock some CTS tests from running whose main intent is not the metadata itself
95     *
96     * TODO: Remove these constants and strip out any code that previously relied on them
97     * being set to true.
98     */
99    static final boolean LIE_ABOUT_AE_STATE = false;
100    static final boolean LIE_ABOUT_AE_MAX_REGIONS = false;
101    static final boolean LIE_ABOUT_AF = false;
102    static final boolean LIE_ABOUT_AF_MAX_REGIONS = false;
103    static final boolean LIE_ABOUT_AWB_STATE = false;
104    static final boolean LIE_ABOUT_AWB = false;
105
106    /**
107     * Create characteristics for a legacy device by mapping the {@code parameters}
108     * and {@code info}
109     *
110     * @param parameters A non-{@code null} parameters set
111     * @param info Camera info with camera facing direction and angle of orientation
112     *
113     * @return static camera characteristics for a camera device
114     *
115     * @throws NullPointerException if any of the args were {@code null}
116     */
117    public static CameraCharacteristics createCharacteristics(Camera.Parameters parameters,
118            CameraInfo info) {
119        checkNotNull(parameters, "parameters must not be null");
120        checkNotNull(info, "info must not be null");
121
122        String paramStr = parameters.flatten();
123        android.hardware.CameraInfo outerInfo = new android.hardware.CameraInfo();
124        outerInfo.info = info;
125
126        return createCharacteristics(paramStr, outerInfo);
127    }
128
129    /**
130     * Create characteristics for a legacy device by mapping the {@code parameters}
131     * and {@code info}
132     *
133     * @param parameters A string parseable by {@link Camera.Parameters#unflatten}
134     * @param info Camera info with camera facing direction and angle of orientation
135     * @return static camera characteristics for a camera device
136     *
137     * @throws NullPointerException if any of the args were {@code null}
138     */
139    public static CameraCharacteristics createCharacteristics(String parameters,
140            android.hardware.CameraInfo info) {
141        checkNotNull(parameters, "parameters must not be null");
142        checkNotNull(info, "info must not be null");
143        checkNotNull(info.info, "info.info must not be null");
144
145        CameraMetadataNative m = new CameraMetadataNative();
146
147        mapCharacteristicsFromInfo(m, info.info);
148
149        Camera.Parameters params = Camera.getEmptyParameters();
150        params.unflatten(parameters);
151        mapCharacteristicsFromParameters(m, params);
152
153        if (VERBOSE) {
154            Log.v(TAG, "createCharacteristics metadata:");
155            Log.v(TAG, "--------------------------------------------------- (start)");
156            m.dumpToLog();
157            Log.v(TAG, "--------------------------------------------------- (end)");
158        }
159
160        return new CameraCharacteristics(m);
161    }
162
163    private static void mapCharacteristicsFromInfo(CameraMetadataNative m, CameraInfo i) {
164        m.set(LENS_FACING, i.facing == CameraInfo.CAMERA_FACING_BACK ?
165                LENS_FACING_BACK : LENS_FACING_FRONT);
166        m.set(SENSOR_ORIENTATION, i.orientation);
167    }
168
169    private static void mapCharacteristicsFromParameters(CameraMetadataNative m,
170            Camera.Parameters p) {
171
172        /*
173         * colorCorrection.*
174         */
175        m.set(COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES,
176                new int[] { COLOR_CORRECTION_ABERRATION_MODE_FAST });
177        /*
178         * control.ae*
179         */
180        mapControlAe(m, p);
181        /*
182         * control.af*
183         */
184        mapControlAf(m, p);
185        /*
186         * control.awb*
187         */
188        mapControlAwb(m, p);
189        /*
190         * control.*
191         * - Anything that doesn't have a set of related fields
192         */
193        mapControlOther(m, p);
194        /*
195         * lens.*
196         */
197        mapLens(m, p);
198        /*
199         * flash.*
200         */
201        mapFlash(m, p);
202        /*
203         * jpeg.*
204         */
205        mapJpeg(m, p);
206
207        /*
208         * noiseReduction.*
209         */
210        m.set(NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES,
211                new int[] { NOISE_REDUCTION_MODE_FAST });
212
213        /*
214         * scaler.*
215         */
216        mapScaler(m, p);
217
218        /*
219         * sensor.*
220         */
221        mapSensor(m, p);
222
223        /*
224         * statistics.*
225         */
226        mapStatistics(m, p);
227
228        /*
229         * sync.*
230         */
231        mapSync(m, p);
232
233        /*
234         * info.supportedHardwareLevel
235         */
236        m.set(INFO_SUPPORTED_HARDWARE_LEVEL, INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY);
237
238        /*
239         * scaler.availableStream*, scaler.available*Durations, sensor.info.maxFrameDuration
240         */
241        mapScalerStreamConfigs(m, p);
242
243        // Order matters below: Put this last so that we can read the metadata set previously
244
245        /*
246         * request.*
247         */
248        mapRequest(m, p);
249
250    }
251
252    private static void mapScalerStreamConfigs(CameraMetadataNative m, Camera.Parameters p) {
253
254        ArrayList<StreamConfiguration> availableStreamConfigs = new ArrayList<>();
255        /*
256         * Implementation-defined (preview, recording, etc) -> use camera1 preview sizes
257         * YUV_420_888 cpu callbacks -> use camera1 preview sizes
258         * Other preview callbacks (CPU) -> use camera1 preview sizes
259         * JPEG still capture -> use camera1 still capture sizes
260         *
261         * Use platform-internal format constants here, since StreamConfigurationMap does the
262         * remapping to public format constants.
263         */
264        List<Camera.Size> previewSizes = p.getSupportedPreviewSizes();
265        appendStreamConfig(availableStreamConfigs,
266                HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, previewSizes);
267        appendStreamConfig(availableStreamConfigs,
268                ImageFormat.YUV_420_888, previewSizes);
269        for (int format : p.getSupportedPreviewFormats()) {
270            if (ImageFormat.isPublicFormat(format)) {
271                appendStreamConfig(availableStreamConfigs, format, previewSizes);
272            } else {
273                /*
274                 *  Do not add any formats unknown to us
275                 * (since it would fail runtime checks in StreamConfigurationMap)
276                 */
277                Log.w(TAG,
278                        String.format("mapStreamConfigs - Skipping non-public format %x", format));
279            }
280        }
281
282        List<Camera.Size> jpegSizes = p.getSupportedPictureSizes();
283        appendStreamConfig(availableStreamConfigs,
284                HAL_PIXEL_FORMAT_BLOB, p.getSupportedPictureSizes());
285        /*
286         * scaler.availableStreamConfigurations
287         */
288        m.set(SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
289                availableStreamConfigs.toArray(new StreamConfiguration[0]));
290
291        /*
292         * scaler.availableMinFrameDurations
293         */
294        // No frame durations available
295        m.set(SCALER_AVAILABLE_MIN_FRAME_DURATIONS, new StreamConfigurationDuration[0]);
296
297        StreamConfigurationDuration[] jpegStalls =
298                new StreamConfigurationDuration[jpegSizes.size()];
299        int i = 0;
300        long longestStallDuration = -1;
301        for (Camera.Size s : jpegSizes) {
302            long stallDuration =  calculateJpegStallDuration(s);
303            jpegStalls[i++] = new StreamConfigurationDuration(HAL_PIXEL_FORMAT_BLOB, s.width,
304                    s.height, stallDuration);
305            if (longestStallDuration < stallDuration) {
306                longestStallDuration = stallDuration;
307            }
308        }
309        /*
310         * scaler.availableStallDurations
311         */
312        // Set stall durations for jpeg, other formats use default stall duration
313        m.set(SCALER_AVAILABLE_STALL_DURATIONS, jpegStalls);
314
315        /*
316         * sensor.info.maxFrameDuration
317         */
318        m.set(SENSOR_INFO_MAX_FRAME_DURATION, longestStallDuration);
319    }
320
321    @SuppressWarnings({"unchecked"})
322    private static void mapControlAe(CameraMetadataNative m, Camera.Parameters p) {
323        /*
324         * control.aeAvailableAntiBandingModes
325         */
326        List<String> antiBandingModes = p.getSupportedAntibanding();
327        if (antiBandingModes != null && antiBandingModes.size() > 0) { // antibanding is optional
328            int[] modes = new int[antiBandingModes.size()];
329            int j = 0;
330            for (String mode : antiBandingModes) {
331                int convertedMode = convertAntiBandingMode(mode);
332                if (convertedMode == -1) {
333                    Log.w(TAG, "Antibanding mode " + ((mode == null) ? "NULL" : mode) +
334                            " not supported, skipping...");
335                } else {
336                    modes[j++] = convertedMode;
337                }
338            }
339            m.set(CONTROL_AE_AVAILABLE_ANTIBANDING_MODES, Arrays.copyOf(modes, j));
340        } else {
341            m.set(CONTROL_AE_AVAILABLE_ANTIBANDING_MODES, new int[0]);
342        }
343
344        /*
345         * control.aeAvailableTargetFpsRanges
346         */
347        {
348            List<int[]> fpsRanges = p.getSupportedPreviewFpsRange();
349            if (fpsRanges == null) {
350                throw new AssertionError("Supported FPS ranges cannot be null.");
351            }
352            int rangesSize = fpsRanges.size();
353            if (rangesSize <= 0) {
354                throw new AssertionError("At least one FPS range must be supported.");
355            }
356            Range<Integer>[] ranges = new Range[rangesSize];
357            int i = 0;
358            for (int[] r : fpsRanges) {
359                ranges[i++] = Range.create(r[Camera.Parameters.PREVIEW_FPS_MIN_INDEX],
360                        r[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]);
361            }
362            m.set(CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES, ranges);
363        }
364
365        /*
366         * control.aeAvailableModes
367         */
368        {
369            List<String> flashModes = p.getSupportedFlashModes();
370
371            String[] flashModeStrings = new String[] {
372                    Camera.Parameters.FLASH_MODE_OFF,
373                    Camera.Parameters.FLASH_MODE_AUTO,
374                    Camera.Parameters.FLASH_MODE_ON,
375                    Camera.Parameters.FLASH_MODE_RED_EYE,
376                    // Map these manually
377                    Camera.Parameters.FLASH_MODE_TORCH,
378            };
379            int[] flashModeInts = new int[] {
380                    CONTROL_AE_MODE_ON,
381                    CONTROL_AE_MODE_ON_AUTO_FLASH,
382                    CONTROL_AE_MODE_ON_ALWAYS_FLASH,
383                    CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE
384            };
385            int[] aeAvail = ArrayUtils.convertStringListToIntArray(
386                    flashModes, flashModeStrings, flashModeInts);
387
388            // No flash control -> AE is always on
389            if (aeAvail == null || aeAvail.length == 0) {
390                aeAvail = new int[] {
391                        CONTROL_AE_MODE_ON
392                };
393            }
394
395            // Note that AE_MODE_OFF is never available.
396            m.set(CONTROL_AE_AVAILABLE_MODES, aeAvail);
397        }
398
399        /*
400         * control.aeCompensationRanges
401         */
402        {
403            int min = p.getMinExposureCompensation();
404            int max = p.getMaxExposureCompensation();
405
406            m.set(CONTROL_AE_COMPENSATION_RANGE, Range.create(min, max));
407        }
408
409        /*
410         * control.aeCompensationStep
411         */
412        {
413            float step = p.getExposureCompensationStep();
414
415            m.set(CONTROL_AE_COMPENSATION_STEP, ParamsUtils.createRational(step));
416        }
417    }
418
419
420    @SuppressWarnings({"unchecked"})
421    private static void mapControlAf(CameraMetadataNative m, Camera.Parameters p) {
422        /*
423         * control.afAvailableModes
424         */
425        {
426            List<String> focusModes = p.getSupportedFocusModes();
427
428            String[] focusModeStrings = new String[] {
429                    Camera.Parameters.FOCUS_MODE_AUTO,
430                    Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE,
431                    Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO,
432                    Camera.Parameters.FOCUS_MODE_EDOF,
433                    Camera.Parameters.FOCUS_MODE_INFINITY,
434                    Camera.Parameters.FOCUS_MODE_MACRO,
435                    Camera.Parameters.FOCUS_MODE_FIXED,
436            };
437
438            int[] focusModeInts = new int[] {
439                    CONTROL_AF_MODE_AUTO,
440                    CONTROL_AF_MODE_CONTINUOUS_PICTURE,
441                    CONTROL_AF_MODE_CONTINUOUS_VIDEO,
442                    CONTROL_AF_MODE_EDOF,
443                    CONTROL_AF_MODE_OFF,
444                    CONTROL_AF_MODE_MACRO,
445                    CONTROL_AF_MODE_OFF
446            };
447
448            List<Integer> afAvail = ArrayUtils.convertStringListToIntList(
449                    focusModes, focusModeStrings, focusModeInts);
450
451            // No AF modes supported? That's unpossible!
452            if (afAvail == null || afAvail.size() == 0) {
453                Log.w(TAG, "No AF modes supported (HAL bug); defaulting to AF_MODE_OFF only");
454                afAvail = new ArrayList<Integer>(/*capacity*/1);
455                afAvail.add(CONTROL_AF_MODE_OFF);
456            }
457
458            m.set(CONTROL_AF_AVAILABLE_MODES, ArrayUtils.toIntArray(afAvail));
459
460            if (VERBOSE) {
461                Log.v(TAG, "mapControlAf - control.afAvailableModes set to " +
462                        ListUtils.listToString(afAvail));
463            }
464        }
465    }
466
467    private static void mapControlAwb(CameraMetadataNative m, Camera.Parameters p) {
468        /*
469         * control.awbAvailableModes
470         */
471
472        {
473            List<String> wbModes = p.getSupportedWhiteBalance();
474
475            String[] wbModeStrings = new String[] {
476                    Camera.Parameters.WHITE_BALANCE_AUTO                    ,
477                    Camera.Parameters.WHITE_BALANCE_INCANDESCENT            ,
478                    Camera.Parameters.WHITE_BALANCE_FLUORESCENT             ,
479                    Camera.Parameters.WHITE_BALANCE_WARM_FLUORESCENT        ,
480                    Camera.Parameters.WHITE_BALANCE_DAYLIGHT                ,
481                    Camera.Parameters.WHITE_BALANCE_CLOUDY_DAYLIGHT         ,
482                    Camera.Parameters.WHITE_BALANCE_TWILIGHT                ,
483                    Camera.Parameters.WHITE_BALANCE_SHADE                   ,
484            };
485
486            int[] wbModeInts = new int[] {
487                    CONTROL_AWB_MODE_AUTO,
488                    CONTROL_AWB_MODE_INCANDESCENT            ,
489                    CONTROL_AWB_MODE_FLUORESCENT             ,
490                    CONTROL_AWB_MODE_WARM_FLUORESCENT        ,
491                    CONTROL_AWB_MODE_DAYLIGHT                ,
492                    CONTROL_AWB_MODE_CLOUDY_DAYLIGHT         ,
493                    CONTROL_AWB_MODE_TWILIGHT                ,
494                    CONTROL_AWB_MODE_SHADE                   ,
495                    // Note that CONTROL_AWB_MODE_OFF is unsupported
496            };
497
498            List<Integer> awbAvail = ArrayUtils.convertStringListToIntList(
499                        wbModes, wbModeStrings, wbModeInts);
500
501            // No AWB modes supported? That's unpossible!
502            if (awbAvail == null || awbAvail.size() == 0) {
503                Log.w(TAG, "No AWB modes supported (HAL bug); defaulting to AWB_MODE_AUTO only");
504                awbAvail = new ArrayList<Integer>(/*capacity*/1);
505                awbAvail.add(CONTROL_AWB_MODE_AUTO);
506            }
507
508            m.set(CONTROL_AWB_AVAILABLE_MODES, ArrayUtils.toIntArray(awbAvail));
509
510            if (VERBOSE) {
511                Log.v(TAG, "mapControlAwb - control.awbAvailableModes set to " +
512                        ListUtils.listToString(awbAvail));
513            }
514        }
515    }
516
517    private static void mapControlOther(CameraMetadataNative m, Camera.Parameters p) {
518        /*
519         * android.control.availableVideoStabilizationModes
520         */
521        {
522            int stabModes[] = p.isVideoStabilizationSupported() ?
523                    new int[] { CONTROL_VIDEO_STABILIZATION_MODE_OFF,
524                                CONTROL_VIDEO_STABILIZATION_MODE_ON } :
525                    new int[] { CONTROL_VIDEO_STABILIZATION_MODE_OFF };
526
527            m.set(CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES, stabModes);
528        }
529
530        /*
531         * android.control.maxRegions
532         */
533        final int AE = 0, AWB = 1, AF = 2;
534
535        int[] maxRegions = new int[3];
536        maxRegions[AE] = p.getMaxNumMeteringAreas();
537        maxRegions[AWB] = 0; // AWB regions not supported in API1
538        maxRegions[AF] = p.getMaxNumFocusAreas();
539
540        if (LIE_ABOUT_AE_MAX_REGIONS) {
541            maxRegions[AE] = 0;
542        }
543        if (LIE_ABOUT_AF_MAX_REGIONS) {
544            maxRegions[AF] = 0;
545        }
546
547        m.set(CONTROL_MAX_REGIONS, maxRegions);
548
549        /*
550         * android.control.availableEffects
551         */
552        List<String> effectModes = p.getSupportedColorEffects();
553        int[] supportedEffectModes = (effectModes == null) ? new int[0] :
554                ArrayUtils.convertStringListToIntArray(effectModes, sLegacyEffectMode,
555                        sEffectModes);
556        m.set(CONTROL_AVAILABLE_EFFECTS, supportedEffectModes);
557
558        /*
559         * android.control.availableSceneModes
560         */
561        List<String> sceneModes = p.getSupportedSceneModes();
562        List<Integer> supportedSceneModes =
563                ArrayUtils.convertStringListToIntList(sceneModes, sLegacySceneModes, sSceneModes);
564        if (supportedSceneModes == null) { // camera1 doesn't support scene mode settings
565            supportedSceneModes = new ArrayList<Integer>();
566            supportedSceneModes.add(CONTROL_SCENE_MODE_DISABLED); // disabled is always available
567        }
568        if (p.getMaxNumDetectedFaces() > 0) { // always supports FACE_PRIORITY when face detecting
569            supportedSceneModes.add(CONTROL_SCENE_MODE_FACE_PRIORITY);
570        }
571        m.set(CONTROL_AVAILABLE_SCENE_MODES, ArrayUtils.toIntArray(supportedSceneModes));
572    }
573
574    private static void mapLens(CameraMetadataNative m, Camera.Parameters p) {
575        /*
576         *  We can tell if the lens is fixed focus;
577         *  but if it's not, we can't tell the minimum focus distance, so leave it null then.
578         */
579        if (VERBOSE) {
580            Log.v(TAG, "mapLens - focus-mode='" + p.getFocusMode() + "'");
581        }
582
583        if (Camera.Parameters.FOCUS_MODE_FIXED.equals(p.getFocusMode())) {
584            /*
585             * lens.info.minimumFocusDistance
586             */
587            m.set(LENS_INFO_MINIMUM_FOCUS_DISTANCE, LENS_INFO_MINIMUM_FOCUS_DISTANCE_FIXED_FOCUS);
588
589            if (VERBOSE) {
590                Log.v(TAG, "mapLens - lens.info.minimumFocusDistance = 0");
591            }
592        } else {
593            if (VERBOSE) {
594                Log.v(TAG, "mapLens - lens.info.minimumFocusDistance is unknown");
595            }
596        }
597
598        float[] focalLengths = new float[] { p.getFocalLength() };
599        m.set(LENS_INFO_AVAILABLE_FOCAL_LENGTHS, focalLengths);
600    }
601
602    private static void mapFlash(CameraMetadataNative m, Camera.Parameters p) {
603        boolean flashAvailable = false;
604        List<String> supportedFlashModes = p.getSupportedFlashModes();
605
606        if (supportedFlashModes != null) {
607            // If only 'OFF' is available, we don't really have flash support
608            flashAvailable = !ListUtils.listElementsEqualTo(
609                    supportedFlashModes, Camera.Parameters.FLASH_MODE_OFF);
610        }
611
612        /*
613         * flash.info.available
614         */
615        m.set(FLASH_INFO_AVAILABLE, flashAvailable);
616    }
617
618    private static void mapJpeg(CameraMetadataNative m, Camera.Parameters p) {
619        List<Camera.Size> thumbnailSizes = p.getSupportedJpegThumbnailSizes();
620
621        if (thumbnailSizes != null) {
622            Size[] sizes = convertSizeListToArray(thumbnailSizes);
623            Arrays.sort(sizes, new SizeAreaComparator());
624            m.set(JPEG_AVAILABLE_THUMBNAIL_SIZES, sizes);
625        }
626    }
627
628    private static void mapRequest(CameraMetadataNative m, Parameters p) {
629        /*
630         * request.availableCapabilities
631         */
632        int[] capabilities = { REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE };
633        m.set(REQUEST_AVAILABLE_CAPABILITIES, capabilities);
634
635        /*
636         * request.availableCharacteristicsKeys
637         */
638        {
639            // TODO: check if the underlying key is supported before listing a key as available
640
641            // Note: We only list public keys. Native HALs should list ALL keys regardless of visibility.
642
643            Key<?> availableKeys[] = new Key<?>[] {
644                    CameraCharacteristics.COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES     ,
645                    CameraCharacteristics.CONTROL_AE_AVAILABLE_ANTIBANDING_MODES          ,
646                    CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES                      ,
647                    CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES          ,
648                    CameraCharacteristics.CONTROL_AE_COMPENSATION_RANGE                   ,
649                    CameraCharacteristics.CONTROL_AE_COMPENSATION_STEP                    ,
650                    CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES                      ,
651                    CameraCharacteristics.CONTROL_AVAILABLE_EFFECTS                       ,
652                    CameraCharacteristics.CONTROL_AVAILABLE_SCENE_MODES                   ,
653                    CameraCharacteristics.CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES     ,
654                    CameraCharacteristics.CONTROL_AWB_AVAILABLE_MODES                     ,
655                    CameraCharacteristics.CONTROL_MAX_REGIONS                             ,
656                    CameraCharacteristics.FLASH_INFO_AVAILABLE                            ,
657                    CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL                   ,
658                    CameraCharacteristics.JPEG_AVAILABLE_THUMBNAIL_SIZES                  ,
659                    CameraCharacteristics.LENS_FACING                                     ,
660                    CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS               ,
661                    CameraCharacteristics.NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES ,
662                    CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES                  ,
663                    CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_STREAMS                  ,
664                    CameraCharacteristics.REQUEST_PARTIAL_RESULT_COUNT                    ,
665                    CameraCharacteristics.REQUEST_PIPELINE_MAX_DEPTH                      ,
666                    CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM               ,
667//                    CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP                 ,
668                    CameraCharacteristics.SCALER_CROPPING_TYPE                            ,
669                    CameraCharacteristics.SENSOR_AVAILABLE_TEST_PATTERN_MODES             ,
670                    CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE                   ,
671                    CameraCharacteristics.SENSOR_INFO_PHYSICAL_SIZE                       ,
672                    CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE                    ,
673                    CameraCharacteristics.SENSOR_INFO_TIMESTAMP_SOURCE                    ,
674                    CameraCharacteristics.SENSOR_ORIENTATION                              ,
675                    CameraCharacteristics.STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES     ,
676                    CameraCharacteristics.STATISTICS_INFO_MAX_FACE_COUNT                  ,
677                    CameraCharacteristics.SYNC_MAX_LATENCY                                ,
678            };
679            List<Key<?>> characteristicsKeys = new ArrayList<>(Arrays.asList(availableKeys));
680
681            /*
682             * Add the conditional keys
683             */
684            if (m.get(LENS_INFO_MINIMUM_FOCUS_DISTANCE) != null) {
685                characteristicsKeys.add(LENS_INFO_MINIMUM_FOCUS_DISTANCE);
686            }
687
688            m.set(REQUEST_AVAILABLE_CHARACTERISTICS_KEYS,
689                    getTagsForKeys(characteristicsKeys.toArray(new Key<?>[0])));
690        }
691
692        /*
693         * request.availableRequestKeys
694         */
695        {
696            CaptureRequest.Key<?> defaultAvailableKeys[] = new CaptureRequest.Key<?>[] {
697                    CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE,
698                    CaptureRequest.CONTROL_AE_ANTIBANDING_MODE,
699                    CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION,
700                    CaptureRequest.CONTROL_AE_LOCK,
701                    CaptureRequest.CONTROL_AE_MODE,
702                    CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE,
703                    CaptureRequest.CONTROL_AF_MODE,
704                    CaptureRequest.CONTROL_AF_TRIGGER,
705                    CaptureRequest.CONTROL_AWB_LOCK,
706                    CaptureRequest.CONTROL_AWB_MODE,
707                    CaptureRequest.CONTROL_CAPTURE_INTENT,
708                    CaptureRequest.CONTROL_EFFECT_MODE,
709                    CaptureRequest.CONTROL_MODE,
710                    CaptureRequest.CONTROL_SCENE_MODE,
711                    CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE,
712                    CaptureRequest.FLASH_MODE,
713                    CaptureRequest.JPEG_GPS_COORDINATES,
714                    CaptureRequest.JPEG_GPS_PROCESSING_METHOD,
715                    CaptureRequest.JPEG_GPS_TIMESTAMP,
716                    CaptureRequest.JPEG_ORIENTATION,
717                    CaptureRequest.JPEG_QUALITY,
718                    CaptureRequest.JPEG_THUMBNAIL_QUALITY,
719                    CaptureRequest.JPEG_THUMBNAIL_SIZE,
720                    CaptureRequest.LENS_FOCAL_LENGTH,
721                    CaptureRequest.NOISE_REDUCTION_MODE,
722                    CaptureRequest.SCALER_CROP_REGION,
723                    CaptureRequest.STATISTICS_FACE_DETECT_MODE,
724            };
725            ArrayList<CaptureRequest.Key<?>> availableKeys =
726                    new ArrayList<CaptureRequest.Key<?>>(Arrays.asList(defaultAvailableKeys));
727
728            if (p.getMaxNumMeteringAreas() > 0) {
729                availableKeys.add(CaptureRequest.CONTROL_AE_REGIONS);
730            }
731            if (p.getMaxNumFocusAreas() > 0) {
732                availableKeys.add(CaptureRequest.CONTROL_AF_REGIONS);
733            }
734
735            CaptureRequest.Key<?> availableRequestKeys[] =
736                    new CaptureRequest.Key<?>[availableKeys.size()];
737            availableKeys.toArray(availableRequestKeys);
738            m.set(REQUEST_AVAILABLE_REQUEST_KEYS, getTagsForKeys(availableRequestKeys));
739        }
740
741        /*
742         * request.availableResultKeys
743         */
744        {
745            CaptureResult.Key<?> defaultAvailableKeys[] = new CaptureResult.Key<?>[] {
746                    CaptureResult.COLOR_CORRECTION_ABERRATION_MODE                 ,
747                    CaptureResult.CONTROL_AE_ANTIBANDING_MODE                      ,
748                    CaptureResult.CONTROL_AE_EXPOSURE_COMPENSATION                 ,
749                    CaptureResult.CONTROL_AE_LOCK                                  ,
750                    CaptureResult.CONTROL_AE_MODE                                  ,
751                    CaptureResult.CONTROL_AF_MODE                                  ,
752                    CaptureResult.CONTROL_AF_STATE                                 ,
753                    CaptureResult.CONTROL_AWB_MODE                                 ,
754                    CaptureResult.CONTROL_AWB_LOCK                                 ,
755                    CaptureResult.CONTROL_MODE                                     ,
756                    CaptureResult.FLASH_MODE                                       ,
757                    CaptureResult.JPEG_GPS_COORDINATES                             ,
758                    CaptureResult.JPEG_GPS_PROCESSING_METHOD                       ,
759                    CaptureResult.JPEG_GPS_TIMESTAMP                               ,
760                    CaptureResult.JPEG_ORIENTATION                                 ,
761                    CaptureResult.JPEG_QUALITY                                     ,
762                    CaptureResult.JPEG_THUMBNAIL_QUALITY                           ,
763                    CaptureResult.LENS_FOCAL_LENGTH                                ,
764                    CaptureResult.NOISE_REDUCTION_MODE                             ,
765                    CaptureResult.REQUEST_PIPELINE_DEPTH                           ,
766                    CaptureResult.SCALER_CROP_REGION                               ,
767                    CaptureResult.SENSOR_TIMESTAMP                                 ,
768                    CaptureResult.STATISTICS_FACE_DETECT_MODE                      ,
769//                    CaptureResult.STATISTICS_FACES                                 ,
770            };
771            List<CaptureResult.Key<?>> availableKeys =
772                    new ArrayList<CaptureResult.Key<?>>(Arrays.asList(defaultAvailableKeys));
773
774            if (p.getMaxNumMeteringAreas() > 0) {
775                availableKeys.add(CaptureResult.CONTROL_AE_REGIONS);
776            }
777            if (p.getMaxNumFocusAreas() > 0) {
778                availableKeys.add(CaptureResult.CONTROL_AF_REGIONS);
779            }
780
781            CaptureResult.Key<?> availableResultKeys[] =
782                    new CaptureResult.Key<?>[availableKeys.size()];
783            availableKeys.toArray(availableResultKeys);
784            m.set(REQUEST_AVAILABLE_RESULT_KEYS, getTagsForKeys(availableResultKeys));
785        }
786
787        /*
788         * request.maxNumOutputStreams
789         */
790        int[] outputStreams = {
791                /* RAW */
792                REQUEST_MAX_NUM_OUTPUT_STREAMS_COUNT_RAW,
793                /* Processed & Not-Stalling */
794                REQUEST_MAX_NUM_OUTPUT_STREAMS_COUNT_PROC,
795                /* Processed & Stalling */
796                REQUEST_MAX_NUM_OUTPUT_STREAMS_COUNT_PROC_STALL,
797        };
798        m.set(REQUEST_MAX_NUM_OUTPUT_STREAMS, outputStreams);
799
800        /*
801         * request.maxNumInputStreams
802         */
803        m.set(REQUEST_MAX_NUM_INPUT_STREAMS, REQUEST_MAX_NUM_INPUT_STREAMS_COUNT);
804
805        /*
806         * request.partialResultCount
807         */
808        m.set(REQUEST_PARTIAL_RESULT_COUNT, 1); // No partial results supported
809
810        /*
811         * request.pipelineMaxDepth
812         */
813        m.set(REQUEST_PIPELINE_MAX_DEPTH,
814                (byte)(REQUEST_PIPELINE_MAX_DEPTH_HAL1 + REQUEST_PIPELINE_MAX_DEPTH_OURS));
815    }
816
817    private static void mapScaler(CameraMetadataNative m, Parameters p) {
818        /*
819         * scaler.availableMaxDigitalZoom
820         */
821        m.set(SCALER_AVAILABLE_MAX_DIGITAL_ZOOM, ParameterUtils.getMaxZoomRatio(p));
822
823        /*
824         * scaler.croppingType = CENTER_ONLY
825         */
826        m.set(SCALER_CROPPING_TYPE, SCALER_CROPPING_TYPE_CENTER_ONLY);
827    }
828
829    private static void mapSensor(CameraMetadataNative m, Parameters p) {
830        // Use the largest jpeg size (by area) for both active array and pixel array
831        Size largestJpegSize = getLargestSupportedJpegSizeByArea(p);
832        /*
833         * sensor.info.activeArraySize
834         */
835        {
836            Rect activeArrayRect = ParamsUtils.createRect(largestJpegSize);
837            m.set(SENSOR_INFO_ACTIVE_ARRAY_SIZE, activeArrayRect);
838        }
839
840        /*
841         * sensor.availableTestPatternModes
842         */
843        {
844            // Only "OFF" test pattern mode is available
845            m.set(SENSOR_AVAILABLE_TEST_PATTERN_MODES, new int[] { SENSOR_TEST_PATTERN_MODE_OFF });
846        }
847
848        /*
849         * sensor.info.pixelArraySize
850         */
851        m.set(SENSOR_INFO_PIXEL_ARRAY_SIZE, largestJpegSize);
852
853        /*
854         * sensor.info.physicalSize
855         */
856        {
857            /*
858             * Assume focal length is at infinity focus and that the lens is rectilinear.
859             */
860            float focalLength = p.getFocalLength(); // in mm
861            double angleHor = p.getHorizontalViewAngle() * Math.PI / 180; // to radians
862            double angleVer = p.getVerticalViewAngle() * Math.PI / 180; // to radians
863
864            float height = (float)Math.abs(2 * focalLength * Math.tan(angleVer / 2));
865            float width = (float)Math.abs(2 * focalLength * Math.tan(angleHor / 2));
866
867            m.set(SENSOR_INFO_PHYSICAL_SIZE, new SizeF(width, height)); // in mm
868        }
869
870        /*
871         * sensor.info.timestampSource
872         */
873        {
874            m.set(SENSOR_INFO_TIMESTAMP_SOURCE, SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN);
875        }
876    }
877
878    private static void mapStatistics(CameraMetadataNative m, Parameters p) {
879        /*
880         * statistics.info.availableFaceDetectModes
881         */
882        int[] fdModes;
883
884        if (p.getMaxNumDetectedFaces() > 0) {
885            fdModes = new int[] {
886                STATISTICS_FACE_DETECT_MODE_OFF,
887                STATISTICS_FACE_DETECT_MODE_SIMPLE
888                // FULL is never-listed, since we have no way to query it statically
889            };
890        } else {
891            fdModes = new int[] {
892                STATISTICS_FACE_DETECT_MODE_OFF
893            };
894        }
895        m.set(STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES, fdModes);
896
897        /*
898         * statistics.info.maxFaceCount
899         */
900        m.set(STATISTICS_INFO_MAX_FACE_COUNT, p.getMaxNumDetectedFaces());
901    }
902
903    private static void mapSync(CameraMetadataNative m, Parameters p) {
904        /*
905         * sync.maxLatency
906         */
907        m.set(SYNC_MAX_LATENCY, SYNC_MAX_LATENCY_UNKNOWN);
908    }
909
910    private static void appendStreamConfig(
911            ArrayList<StreamConfiguration> configs, int format, List<Camera.Size> sizes) {
912        for (Camera.Size size : sizes) {
913            StreamConfiguration config =
914                    new StreamConfiguration(format, size.width, size.height, /*input*/false);
915            configs.add(config);
916        }
917    }
918
919    private final static String[] sLegacySceneModes = {
920        Parameters.SCENE_MODE_AUTO,
921        Parameters.SCENE_MODE_ACTION,
922        Parameters.SCENE_MODE_PORTRAIT,
923        Parameters.SCENE_MODE_LANDSCAPE,
924        Parameters.SCENE_MODE_NIGHT,
925        Parameters.SCENE_MODE_NIGHT_PORTRAIT,
926        Parameters.SCENE_MODE_THEATRE,
927        Parameters.SCENE_MODE_BEACH,
928        Parameters.SCENE_MODE_SNOW,
929        Parameters.SCENE_MODE_SUNSET,
930        Parameters.SCENE_MODE_STEADYPHOTO,
931        Parameters.SCENE_MODE_FIREWORKS,
932        Parameters.SCENE_MODE_SPORTS,
933        Parameters.SCENE_MODE_PARTY,
934        Parameters.SCENE_MODE_CANDLELIGHT,
935        Parameters.SCENE_MODE_BARCODE,
936        Parameters.SCENE_MODE_HDR,
937    };
938
939    private final static int[] sSceneModes = {
940        CameraCharacteristics.CONTROL_SCENE_MODE_DISABLED,
941        CameraCharacteristics.CONTROL_SCENE_MODE_ACTION,
942        CameraCharacteristics.CONTROL_SCENE_MODE_PORTRAIT,
943        CameraCharacteristics.CONTROL_SCENE_MODE_LANDSCAPE,
944        CameraCharacteristics.CONTROL_SCENE_MODE_NIGHT,
945        CameraCharacteristics.CONTROL_SCENE_MODE_NIGHT_PORTRAIT,
946        CameraCharacteristics.CONTROL_SCENE_MODE_THEATRE,
947        CameraCharacteristics.CONTROL_SCENE_MODE_BEACH,
948        CameraCharacteristics.CONTROL_SCENE_MODE_SNOW,
949        CameraCharacteristics.CONTROL_SCENE_MODE_SUNSET,
950        CameraCharacteristics.CONTROL_SCENE_MODE_STEADYPHOTO,
951        CameraCharacteristics.CONTROL_SCENE_MODE_FIREWORKS,
952        CameraCharacteristics.CONTROL_SCENE_MODE_SPORTS,
953        CameraCharacteristics.CONTROL_SCENE_MODE_PARTY,
954        CameraCharacteristics.CONTROL_SCENE_MODE_CANDLELIGHT,
955        CameraCharacteristics.CONTROL_SCENE_MODE_BARCODE,
956        CameraCharacteristics.CONTROL_SCENE_MODE_HDR,
957    };
958
959    static int convertSceneModeFromLegacy(String mode) {
960        if (mode == null) {
961            return CameraCharacteristics.CONTROL_SCENE_MODE_DISABLED;
962        }
963        int index = ArrayUtils.getArrayIndex(sLegacySceneModes, mode);
964        if (index < 0) {
965            return UNKNOWN_MODE;
966        }
967        return sSceneModes[index];
968    }
969
970    static String convertSceneModeToLegacy(int mode) {
971        if (mode == CONTROL_SCENE_MODE_FACE_PRIORITY) {
972            // OK: Let LegacyFaceDetectMapper handle turning face detection on/off
973            return Parameters.SCENE_MODE_AUTO;
974        }
975
976        int index = ArrayUtils.getArrayIndex(sSceneModes, mode);
977        if (index < 0) {
978            return null;
979        }
980        return sLegacySceneModes[index];
981    }
982
983    private final static String[] sLegacyEffectMode = {
984        Parameters.EFFECT_NONE,
985        Parameters.EFFECT_MONO,
986        Parameters.EFFECT_NEGATIVE,
987        Parameters.EFFECT_SOLARIZE,
988        Parameters.EFFECT_SEPIA,
989        Parameters.EFFECT_POSTERIZE,
990        Parameters.EFFECT_WHITEBOARD,
991        Parameters.EFFECT_BLACKBOARD,
992        Parameters.EFFECT_AQUA,
993    };
994
995    private final static int[] sEffectModes = {
996        CameraCharacteristics.CONTROL_EFFECT_MODE_OFF,
997        CameraCharacteristics.CONTROL_EFFECT_MODE_MONO,
998        CameraCharacteristics.CONTROL_EFFECT_MODE_NEGATIVE,
999        CameraCharacteristics.CONTROL_EFFECT_MODE_SOLARIZE,
1000        CameraCharacteristics.CONTROL_EFFECT_MODE_SEPIA,
1001        CameraCharacteristics.CONTROL_EFFECT_MODE_POSTERIZE,
1002        CameraCharacteristics.CONTROL_EFFECT_MODE_WHITEBOARD,
1003        CameraCharacteristics.CONTROL_EFFECT_MODE_BLACKBOARD,
1004        CameraCharacteristics.CONTROL_EFFECT_MODE_AQUA,
1005    };
1006
1007    static int convertEffectModeFromLegacy(String mode) {
1008        if (mode == null) {
1009            return CameraCharacteristics.CONTROL_EFFECT_MODE_OFF;
1010        }
1011        int index = ArrayUtils.getArrayIndex(sLegacyEffectMode, mode);
1012        if (index < 0) {
1013            return UNKNOWN_MODE;
1014        }
1015        return sEffectModes[index];
1016    }
1017
1018    static String convertEffectModeToLegacy(int mode) {
1019        int index = ArrayUtils.getArrayIndex(sEffectModes, mode);
1020        if (index < 0) {
1021            return null;
1022        }
1023        return sLegacyEffectMode[index];
1024    }
1025
1026    /**
1027     * Convert the ae antibanding mode from api1 into api2.
1028     *
1029     * @param mode the api1 mode, {@code null} is allowed and will return {@code -1}.
1030     *
1031     * @return The api2 value, or {@code -1} by default if conversion failed
1032     */
1033    private static int convertAntiBandingMode(String mode) {
1034        if (mode == null) {
1035            return -1;
1036        }
1037
1038        switch (mode) {
1039            case Camera.Parameters.ANTIBANDING_OFF: {
1040                return CONTROL_AE_ANTIBANDING_MODE_OFF;
1041            }
1042            case Camera.Parameters.ANTIBANDING_50HZ: {
1043                return CONTROL_AE_ANTIBANDING_MODE_50HZ;
1044            }
1045            case Camera.Parameters.ANTIBANDING_60HZ: {
1046                return CONTROL_AE_ANTIBANDING_MODE_60HZ;
1047            }
1048            case Camera.Parameters.ANTIBANDING_AUTO: {
1049                return CONTROL_AE_ANTIBANDING_MODE_AUTO;
1050            }
1051            default: {
1052                Log.w(TAG, "convertAntiBandingMode - Unknown antibanding mode " + mode);
1053                return -1;
1054            }
1055        }
1056    }
1057
1058    /**
1059     * Convert the ae antibanding mode from api1 into api2.
1060     *
1061     * @param mode the api1 mode, {@code null} is allowed and will return {@code MODE_OFF}.
1062     *
1063     * @return The api2 value, or {@code MODE_OFF} by default if conversion failed
1064     */
1065    static int convertAntiBandingModeOrDefault(String mode) {
1066        int antiBandingMode = convertAntiBandingMode(mode);
1067        if (antiBandingMode == -1) {
1068            return CONTROL_AE_ANTIBANDING_MODE_OFF;
1069        }
1070
1071        return antiBandingMode;
1072    }
1073
1074    private static int[] convertAeFpsRangeToLegacy(Range<Integer> fpsRange) {
1075        int[] legacyFps = new int[2];
1076        legacyFps[Camera.Parameters.PREVIEW_FPS_MIN_INDEX] = fpsRange.getLower();
1077        legacyFps[Camera.Parameters.PREVIEW_FPS_MAX_INDEX] = fpsRange.getUpper();
1078        return legacyFps;
1079    }
1080
1081    /**
1082     * Return the stall duration for a given output jpeg size in nanoseconds.
1083     *
1084     * <p>An 8mp image is chosen to have a stall duration of 0.8 seconds.</p>
1085     */
1086    private static long calculateJpegStallDuration(Camera.Size size) {
1087        long baseDuration = APPROXIMATE_CAPTURE_DELAY_MS * NS_PER_MS; // 200ms for capture
1088        long area = size.width * (long) size.height;
1089        long stallPerArea = APPROXIMATE_JPEG_ENCODE_TIME_MS * NS_PER_MS /
1090                APPROXIMATE_SENSOR_AREA_PX; // 600ms stall for 8mp
1091        return baseDuration + area * stallPerArea;
1092    }
1093
1094    /**
1095     * Set the legacy parameters using the {@link LegacyRequest legacy request}.
1096     *
1097     * <p>The legacy request's parameters are changed as a side effect of calling this
1098     * method.</p>
1099     *
1100     * @param request a non-{@code null} legacy request
1101     */
1102    public static void convertRequestMetadata(LegacyRequest request) {
1103        LegacyRequestMapper.convertRequestMetadata(request);
1104    }
1105
1106    private static final int[] sAllowedTemplates = {
1107            CameraDevice.TEMPLATE_PREVIEW,
1108            CameraDevice.TEMPLATE_STILL_CAPTURE,
1109            CameraDevice.TEMPLATE_RECORD,
1110            // Disallowed templates in legacy mode:
1111            // CameraDevice.TEMPLATE_VIDEO_SNAPSHOT,
1112            // CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG,
1113            // CameraDevice.TEMPLATE_MANUAL
1114    };
1115
1116    /**
1117     * Create a request template
1118     *
1119     * @param c a non-{@code null} camera characteristics for this camera
1120     * @param templateId a non-negative template ID
1121     *
1122     * @return a non-{@code null} request template
1123     *
1124     * @throws IllegalArgumentException if {@code templateId} was invalid
1125     *
1126     * @see android.hardware.camera2.CameraDevice#TEMPLATE_MANUAL
1127     */
1128    public static CameraMetadataNative createRequestTemplate(
1129            CameraCharacteristics c, int templateId) {
1130        if (!ArrayUtils.contains(sAllowedTemplates, templateId)) {
1131            throw new IllegalArgumentException("templateId out of range");
1132        }
1133
1134        CameraMetadataNative m = new CameraMetadataNative();
1135
1136        /*
1137         * NOTE: If adding new code here and it needs to query the static info,
1138         * query the camera characteristics, so we can reuse this for api2 code later
1139         * to create our own templates in the framework
1140         */
1141
1142        /*
1143         * control.*
1144         */
1145
1146        // control.awbMode
1147        m.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_AUTO);
1148        // AWB is always unconditionally available in API1 devices
1149
1150        // control.aeAntibandingMode
1151        m.set(CaptureRequest.CONTROL_AE_ANTIBANDING_MODE, CONTROL_AE_ANTIBANDING_MODE_AUTO);
1152
1153        // control.aeExposureCompensation
1154        m.set(CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION, 0);
1155
1156        // control.aeLock
1157        m.set(CaptureRequest.CONTROL_AE_LOCK, false);
1158
1159        // control.aePrecaptureTrigger
1160        m.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, CONTROL_AE_PRECAPTURE_TRIGGER_IDLE);
1161
1162        // control.afTrigger
1163        m.set(CaptureRequest.CONTROL_AF_TRIGGER, CONTROL_AF_TRIGGER_IDLE);
1164
1165        // control.awbMode
1166        m.set(CaptureRequest.CONTROL_AWB_MODE, CONTROL_AWB_MODE_AUTO);
1167
1168        // control.awbLock
1169        m.set(CaptureRequest.CONTROL_AWB_LOCK, false);
1170
1171        // control.aeRegions, control.awbRegions, control.afRegions
1172        {
1173            Rect activeArray = c.get(SENSOR_INFO_ACTIVE_ARRAY_SIZE);
1174            MeteringRectangle[] activeRegions =  new MeteringRectangle[] {
1175                    new MeteringRectangle(/*x*/0, /*y*/0, /*width*/activeArray.width() - 1,
1176                    /*height*/activeArray.height() - 1,/*weight*/0)};
1177            m.set(CaptureRequest.CONTROL_AE_REGIONS, activeRegions);
1178            m.set(CaptureRequest.CONTROL_AWB_REGIONS, activeRegions);
1179            m.set(CaptureRequest.CONTROL_AF_REGIONS, activeRegions);
1180        }
1181
1182        // control.captureIntent
1183        {
1184            int captureIntent;
1185            switch (templateId) {
1186                case CameraDevice.TEMPLATE_PREVIEW:
1187                    captureIntent = CONTROL_CAPTURE_INTENT_PREVIEW;
1188                    break;
1189                case CameraDevice.TEMPLATE_STILL_CAPTURE:
1190                    captureIntent = CONTROL_CAPTURE_INTENT_STILL_CAPTURE;
1191                    break;
1192                case CameraDevice.TEMPLATE_RECORD:
1193                    captureIntent = CONTROL_CAPTURE_INTENT_VIDEO_RECORD;
1194                    break;
1195                default:
1196                    // Can't get anything else since it's guarded by the IAE check
1197                    throw new AssertionError("Impossible; keep in sync with sAllowedTemplates");
1198            }
1199            m.set(CaptureRequest.CONTROL_CAPTURE_INTENT, captureIntent);
1200        }
1201
1202        // control.aeMode
1203        m.set(CaptureRequest.CONTROL_AE_MODE, CameraMetadata.CONTROL_AE_MODE_ON);
1204        // AE is always unconditionally available in API1 devices
1205
1206        // control.mode
1207        m.set(CaptureRequest.CONTROL_MODE, CONTROL_MODE_AUTO);
1208
1209        // control.afMode
1210        {
1211            Float minimumFocusDistance = c.get(LENS_INFO_MINIMUM_FOCUS_DISTANCE);
1212
1213            int afMode;
1214            if (minimumFocusDistance != null &&
1215                    minimumFocusDistance == LENS_INFO_MINIMUM_FOCUS_DISTANCE_FIXED_FOCUS) {
1216                // Cannot control auto-focus with fixed-focus cameras
1217                afMode = CameraMetadata.CONTROL_AF_MODE_OFF;
1218            } else {
1219                // If a minimum focus distance is reported; the camera must have AF
1220                afMode = CameraMetadata.CONTROL_AF_MODE_AUTO;
1221
1222                if (templateId == CameraDevice.TEMPLATE_RECORD ||
1223                        templateId == CameraDevice.TEMPLATE_VIDEO_SNAPSHOT) {
1224                    if (ArrayUtils.contains(c.get(CONTROL_AF_AVAILABLE_MODES),
1225                            CONTROL_AF_MODE_CONTINUOUS_VIDEO)) {
1226                        afMode = CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_VIDEO;
1227                    }
1228                } else if (templateId == CameraDevice.TEMPLATE_PREVIEW ||
1229                        templateId == CameraDevice.TEMPLATE_STILL_CAPTURE) {
1230                    if (ArrayUtils.contains(c.get(CONTROL_AF_AVAILABLE_MODES),
1231                            CONTROL_AF_MODE_CONTINUOUS_PICTURE)) {
1232                        afMode = CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE;
1233                    }
1234                }
1235            }
1236
1237            if (VERBOSE) {
1238                Log.v(TAG, "createRequestTemplate (templateId=" + templateId + ")," +
1239                        " afMode=" + afMode + ", minimumFocusDistance=" + minimumFocusDistance);
1240            }
1241
1242            m.set(CaptureRequest.CONTROL_AF_MODE, afMode);
1243        }
1244
1245        {
1246            // control.aeTargetFpsRange
1247            Range<Integer>[] availableFpsRange = c.
1248                    get(CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES);
1249
1250            // Pick FPS range with highest max value, tiebreak on higher min value
1251            Range<Integer> bestRange = availableFpsRange[0];
1252            for (Range<Integer> r : availableFpsRange) {
1253                if (bestRange.getUpper() < r.getUpper()) {
1254                    bestRange = r;
1255                } else if (bestRange.getUpper() == r.getUpper() &&
1256                        bestRange.getLower() < r.getLower()) {
1257                    bestRange = r;
1258                }
1259            }
1260            m.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, bestRange);
1261        }
1262
1263        // control.sceneMode -- DISABLED is always available
1264        m.set(CaptureRequest.CONTROL_SCENE_MODE, CONTROL_SCENE_MODE_DISABLED);
1265
1266        /*
1267         * statistics.*
1268         */
1269
1270        // statistics.faceDetectMode
1271        m.set(CaptureRequest.STATISTICS_FACE_DETECT_MODE, STATISTICS_FACE_DETECT_MODE_OFF);
1272
1273        /*
1274         * flash.*
1275         */
1276
1277        // flash.mode
1278        m.set(CaptureRequest.FLASH_MODE, FLASH_MODE_OFF);
1279
1280        /*
1281         * noiseReduction.*
1282         */
1283        m.set(CaptureRequest.NOISE_REDUCTION_MODE, NOISE_REDUCTION_MODE_FAST);
1284
1285        /*
1286         * lens.*
1287         */
1288
1289        // lens.focalLength
1290        m.set(CaptureRequest.LENS_FOCAL_LENGTH,
1291                c.get(CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS)[0]);
1292
1293        // TODO: map other request template values
1294        return m;
1295    }
1296
1297    private static int[] getTagsForKeys(Key<?>[] keys) {
1298        int[] tags = new int[keys.length];
1299
1300        for (int i = 0; i < keys.length; ++i) {
1301            tags[i] = keys[i].getNativeKey().getTag();
1302        }
1303
1304        return tags;
1305    }
1306
1307    private static int[] getTagsForKeys(CaptureRequest.Key<?>[] keys) {
1308        int[] tags = new int[keys.length];
1309
1310        for (int i = 0; i < keys.length; ++i) {
1311            tags[i] = keys[i].getNativeKey().getTag();
1312        }
1313
1314        return tags;
1315    }
1316
1317    private static int[] getTagsForKeys(CaptureResult.Key<?>[] keys) {
1318        int[] tags = new int[keys.length];
1319
1320        for (int i = 0; i < keys.length; ++i) {
1321            tags[i] = keys[i].getNativeKey().getTag();
1322        }
1323
1324        return tags;
1325    }
1326
1327    /**
1328     * Convert the requested AF mode into its equivalent supported parameter.
1329     *
1330     * @param mode {@code CONTROL_AF_MODE}
1331     * @param supportedFocusModes list of camera1's supported focus modes
1332     * @return the stringified af mode, or {@code null} if its not supported
1333     */
1334    static String convertAfModeToLegacy(int mode, List<String> supportedFocusModes) {
1335        if (supportedFocusModes == null || supportedFocusModes.isEmpty()) {
1336            Log.w(TAG, "No focus modes supported; API1 bug");
1337            return null;
1338        }
1339
1340        String param = null;
1341        switch (mode) {
1342            case CONTROL_AF_MODE_AUTO:
1343                param = Parameters.FOCUS_MODE_AUTO;
1344                break;
1345            case CONTROL_AF_MODE_CONTINUOUS_PICTURE:
1346                param = Parameters.FOCUS_MODE_CONTINUOUS_PICTURE;
1347                break;
1348            case CONTROL_AF_MODE_CONTINUOUS_VIDEO:
1349                param = Parameters.FOCUS_MODE_CONTINUOUS_VIDEO;
1350                break;
1351            case CONTROL_AF_MODE_EDOF:
1352                param = Parameters.FOCUS_MODE_EDOF;
1353                break;
1354            case CONTROL_AF_MODE_MACRO:
1355                param = Parameters.FOCUS_MODE_MACRO;
1356                break;
1357            case CONTROL_AF_MODE_OFF:
1358                if (supportedFocusModes.contains(Parameters.FOCUS_MODE_FIXED)) {
1359                    param = Parameters.FOCUS_MODE_FIXED;
1360                } else {
1361                    param = Parameters.FOCUS_MODE_INFINITY;
1362                }
1363        }
1364
1365        if (!supportedFocusModes.contains(param)) {
1366            // Weed out bad user input by setting to the first arbitrary focus mode
1367            String defaultMode = supportedFocusModes.get(0);
1368            Log.w(TAG,
1369                    String.format(
1370                            "convertAfModeToLegacy - ignoring unsupported mode %d, " +
1371                            "defaulting to %s", mode, defaultMode));
1372            param = defaultMode;
1373        }
1374
1375        return param;
1376    }
1377}
1378