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