Home | History | Annotate | Download | only in legacy
      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.Rect;
     20 import android.hardware.Camera;
     21 import android.hardware.Camera.Parameters;
     22 import android.hardware.camera2.CameraCharacteristics;
     23 import android.hardware.camera2.CaptureRequest;
     24 import android.hardware.camera2.CaptureResult;
     25 import android.hardware.camera2.impl.CameraMetadataNative;
     26 import android.hardware.camera2.legacy.ParameterUtils.WeightedRectangle;
     27 import android.hardware.camera2.legacy.ParameterUtils.ZoomData;
     28 import android.hardware.camera2.params.MeteringRectangle;
     29 import android.hardware.camera2.utils.ListUtils;
     30 import android.hardware.camera2.utils.ParamsUtils;
     31 import android.util.Log;
     32 import android.util.Size;
     33 
     34 import java.util.ArrayList;
     35 import java.util.List;
     36 
     37 import static android.hardware.camera2.CaptureResult.*;
     38 
     39 /**
     40  * Provide legacy-specific implementations of camera2 CaptureResult for legacy devices.
     41  */
     42 @SuppressWarnings("deprecation")
     43 public class LegacyResultMapper {
     44     private static final String TAG = "LegacyResultMapper";
     45     private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
     46 
     47     private LegacyRequest mCachedRequest = null;
     48     private CameraMetadataNative mCachedResult = null;
     49 
     50     /**
     51      * Generate capture result metadata from the legacy camera request.
     52      *
     53      * <p>This method caches and reuses the result from the previous call to this method if
     54      * the {@code parameters} of the subsequent {@link LegacyRequest} passed to this method
     55      * have not changed.</p>
     56      *
     57      * @param legacyRequest a non-{@code null} legacy request containing the latest parameters
     58      * @param timestamp the timestamp to use for this result in nanoseconds.
     59      *
     60      * @return {@link CameraMetadataNative} object containing result metadata.
     61      */
     62     public CameraMetadataNative cachedConvertResultMetadata(
     63             LegacyRequest legacyRequest, long timestamp) {
     64         CameraMetadataNative result;
     65         boolean cached;
     66 
     67         /*
     68          * Attempt to look up the result from the cache if the parameters haven't changed
     69          */
     70         if (mCachedRequest != null && legacyRequest.parameters.same(mCachedRequest.parameters)) {
     71             result = new CameraMetadataNative(mCachedResult);
     72             cached = true;
     73         } else {
     74             result = convertResultMetadata(legacyRequest);
     75             cached = false;
     76 
     77             // Always cache a *copy* of the metadata result,
     78             // since api2's client side takes ownership of it after it receives a result
     79             mCachedRequest = legacyRequest;
     80             mCachedResult = new CameraMetadataNative(result);
     81         }
     82 
     83         /*
     84          * Unconditionally set fields that change in every single frame
     85          */
     86         {
     87             // sensor.timestamp
     88             result.set(SENSOR_TIMESTAMP, timestamp);
     89         }
     90 
     91         if (VERBOSE) {
     92             Log.v(TAG, "cachedConvertResultMetadata - cached? " + cached +
     93                     " timestamp = " + timestamp);
     94 
     95             Log.v(TAG, "----- beginning of result dump ------");
     96             result.dumpToLog();
     97             Log.v(TAG, "----- end of result dump ------");
     98         }
     99 
    100         return result;
    101     }
    102 
    103     /**
    104      * Generate capture result metadata from the legacy camera request.
    105      *
    106      * @param legacyRequest a non-{@code null} legacy request containing the latest parameters
    107      * @return a {@link CameraMetadataNative} object containing result metadata.
    108      */
    109     private static CameraMetadataNative convertResultMetadata(LegacyRequest legacyRequest) {
    110         CameraCharacteristics characteristics = legacyRequest.characteristics;
    111         CaptureRequest request = legacyRequest.captureRequest;
    112         Size previewSize = legacyRequest.previewSize;
    113         Camera.Parameters params = legacyRequest.parameters;
    114 
    115         CameraMetadataNative result = new CameraMetadataNative();
    116 
    117         Rect activeArraySize = characteristics.get(
    118                 CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
    119         ZoomData zoomData = ParameterUtils.convertScalerCropRegion(activeArraySize,
    120                 request.get(CaptureRequest.SCALER_CROP_REGION), previewSize, params);
    121 
    122         /*
    123          * colorCorrection
    124          */
    125         // colorCorrection.aberrationMode
    126         {
    127             // Always hardcoded to FAST
    128             result.set(COLOR_CORRECTION_ABERRATION_MODE, COLOR_CORRECTION_ABERRATION_MODE_FAST);
    129         }
    130 
    131         /*
    132          * control
    133          */
    134 
    135         /*
    136          * control.ae*
    137          */
    138         mapAe(result, characteristics, request, activeArraySize, zoomData, /*out*/params);
    139 
    140         /*
    141          * control.af*
    142          */
    143         mapAf(result, activeArraySize, zoomData, /*out*/params);
    144 
    145         /*
    146          * control.awb*
    147          */
    148         mapAwb(result, /*out*/params);
    149 
    150         /*
    151          * control.captureIntent
    152          */
    153         {
    154             int captureIntent = ParamsUtils.getOrDefault(request,
    155                     CaptureRequest.CONTROL_CAPTURE_INTENT,
    156                     /*defaultValue*/CaptureRequest.CONTROL_CAPTURE_INTENT_PREVIEW);
    157 
    158             captureIntent = LegacyRequestMapper.filterSupportedCaptureIntent(captureIntent);
    159 
    160             result.set(CONTROL_CAPTURE_INTENT, captureIntent);
    161         }
    162 
    163         /*
    164          * control.mode
    165          */
    166         {
    167             int controlMode = ParamsUtils.getOrDefault(request, CaptureRequest.CONTROL_MODE,
    168                     CONTROL_MODE_AUTO);
    169             if (controlMode == CaptureResult.CONTROL_MODE_USE_SCENE_MODE) {
    170                 result.set(CONTROL_MODE, CONTROL_MODE_USE_SCENE_MODE);
    171             } else {
    172                 result.set(CONTROL_MODE, CONTROL_MODE_AUTO);
    173             }
    174         }
    175 
    176         /*
    177          * control.sceneMode
    178          */
    179         {
    180             String legacySceneMode = params.getSceneMode();
    181             int mode = LegacyMetadataMapper.convertSceneModeFromLegacy(legacySceneMode);
    182             if (mode != LegacyMetadataMapper.UNKNOWN_MODE) {
    183                 result.set(CaptureResult.CONTROL_SCENE_MODE, mode);
    184                 // In case of SCENE_MODE == FACE_PRIORITY, LegacyFaceDetectMapper will override
    185                 // the result to say SCENE_MODE == FACE_PRIORITY.
    186             }  else {
    187                 Log.w(TAG, "Unknown scene mode " + legacySceneMode +
    188                         " returned by camera HAL, setting to disabled.");
    189                 result.set(CaptureResult.CONTROL_SCENE_MODE, CONTROL_SCENE_MODE_DISABLED);
    190             }
    191         }
    192 
    193         /*
    194          * control.effectMode
    195          */
    196         {
    197             String legacyEffectMode = params.getColorEffect();
    198             int mode = LegacyMetadataMapper.convertEffectModeFromLegacy(legacyEffectMode);
    199             if (mode != LegacyMetadataMapper.UNKNOWN_MODE) {
    200                 result.set(CaptureResult.CONTROL_EFFECT_MODE, mode);
    201             } else {
    202                 Log.w(TAG, "Unknown effect mode " + legacyEffectMode +
    203                         " returned by camera HAL, setting to off.");
    204                 result.set(CaptureResult.CONTROL_EFFECT_MODE, CONTROL_EFFECT_MODE_OFF);
    205             }
    206         }
    207 
    208         // control.videoStabilizationMode
    209         {
    210             int stabMode =
    211                     (params.isVideoStabilizationSupported() && params.getVideoStabilization()) ?
    212                         CONTROL_VIDEO_STABILIZATION_MODE_ON :
    213                         CONTROL_VIDEO_STABILIZATION_MODE_OFF;
    214             result.set(CONTROL_VIDEO_STABILIZATION_MODE, stabMode);
    215         }
    216 
    217         /*
    218          * flash
    219          */
    220         {
    221             // flash.mode, flash.state mapped in mapAeAndFlashMode
    222         }
    223 
    224         /*
    225          * lens
    226          */
    227         // lens.focusDistance
    228         {
    229             if (Parameters.FOCUS_MODE_INFINITY.equals(params.getFocusMode())) {
    230                 result.set(CaptureResult.LENS_FOCUS_DISTANCE, 0.0f);
    231             }
    232         }
    233 
    234         // lens.focalLength
    235         result.set(CaptureResult.LENS_FOCAL_LENGTH, params.getFocalLength());
    236 
    237         /*
    238          * request
    239          */
    240         // request.pipelineDepth
    241         result.set(REQUEST_PIPELINE_DEPTH,
    242                 characteristics.get(CameraCharacteristics.REQUEST_PIPELINE_MAX_DEPTH));
    243 
    244         /*
    245          * scaler
    246          */
    247         mapScaler(result, zoomData, /*out*/params);
    248 
    249         /*
    250          * sensor
    251          */
    252         // sensor.timestamp varies every frame; mapping is done in #cachedConvertResultMetadata
    253         {
    254             // Unconditionally no test patterns
    255             result.set(SENSOR_TEST_PATTERN_MODE, SENSOR_TEST_PATTERN_MODE_OFF);
    256         }
    257 
    258         /*
    259          * jpeg
    260          */
    261         // jpeg.gpsLocation
    262         result.set(JPEG_GPS_LOCATION, request.get(CaptureRequest.JPEG_GPS_LOCATION));
    263 
    264         // jpeg.orientation
    265         result.set(JPEG_ORIENTATION, request.get(CaptureRequest.JPEG_ORIENTATION));
    266 
    267         // jpeg.quality
    268         result.set(JPEG_QUALITY, (byte) params.getJpegQuality());
    269 
    270         // jpeg.thumbnailQuality
    271         result.set(JPEG_THUMBNAIL_QUALITY, (byte) params.getJpegThumbnailQuality());
    272 
    273         // jpeg.thumbnailSize
    274         Camera.Size s = params.getJpegThumbnailSize();
    275         if (s != null) {
    276             result.set(JPEG_THUMBNAIL_SIZE, ParameterUtils.convertSize(s));
    277         } else {
    278             Log.w(TAG, "Null thumbnail size received from parameters.");
    279         }
    280 
    281         /*
    282          * noiseReduction.*
    283          */
    284         // noiseReduction.mode
    285         result.set(NOISE_REDUCTION_MODE, NOISE_REDUCTION_MODE_FAST);
    286 
    287         return result;
    288     }
    289 
    290     private static void mapAe(CameraMetadataNative m,
    291             CameraCharacteristics characteristics,
    292             CaptureRequest request, Rect activeArray, ZoomData zoomData, /*out*/Parameters p) {
    293         // control.aeAntiBandingMode
    294         {
    295             int antiBandingMode = LegacyMetadataMapper.convertAntiBandingModeOrDefault(
    296                     p.getAntibanding());
    297             m.set(CONTROL_AE_ANTIBANDING_MODE, antiBandingMode);
    298         }
    299 
    300         // control.aeExposureCompensation
    301         {
    302             m.set(CONTROL_AE_EXPOSURE_COMPENSATION, p.getExposureCompensation());
    303         }
    304 
    305         // control.aeLock
    306         {
    307             boolean lock = p.isAutoExposureLockSupported() ? p.getAutoExposureLock() : false;
    308             m.set(CONTROL_AE_LOCK, lock);
    309             if (VERBOSE) {
    310                 Log.v(TAG,
    311                         "mapAe - android.control.aeLock = " + lock +
    312                         ", supported = " + p.isAutoExposureLockSupported());
    313             }
    314 
    315             Boolean requestLock = request.get(CaptureRequest.CONTROL_AE_LOCK);
    316             if (requestLock != null && requestLock != lock) {
    317                 Log.w(TAG,
    318                         "mapAe - android.control.aeLock was requested to " + requestLock +
    319                         " but resulted in " + lock);
    320             }
    321         }
    322 
    323         // control.aeMode, flash.mode, flash.state
    324         mapAeAndFlashMode(m, characteristics, p);
    325 
    326         // control.aeState
    327         if (LegacyMetadataMapper.LIE_ABOUT_AE_STATE) {
    328             // Lie to pass CTS temporarily.
    329             // TODO: Implement precapture trigger, after which we can report CONVERGED ourselves
    330             m.set(CONTROL_AE_STATE, CONTROL_AE_STATE_CONVERGED);
    331         }
    332 
    333         // control.aeRegions
    334         if (p.getMaxNumMeteringAreas() > 0) {
    335             if (VERBOSE) {
    336                 String meteringAreas = p.get("metering-areas");
    337                 Log.v(TAG, "mapAe - parameter dump; metering-areas: " + meteringAreas);
    338             }
    339 
    340             MeteringRectangle[] meteringRectArray = getMeteringRectangles(activeArray,
    341                     zoomData, p.getMeteringAreas(), "AE");
    342 
    343             m.set(CONTROL_AE_REGIONS, meteringRectArray);
    344         }
    345 
    346     }
    347 
    348     private static void mapAf(CameraMetadataNative m,
    349             Rect activeArray, ZoomData zoomData, Camera.Parameters p) {
    350         // control.afMode
    351         m.set(CaptureResult.CONTROL_AF_MODE, convertLegacyAfMode(p.getFocusMode()));
    352 
    353         // control.afRegions
    354         if (p.getMaxNumFocusAreas() > 0) {
    355             if (VERBOSE) {
    356                 String focusAreas = p.get("focus-areas");
    357                 Log.v(TAG, "mapAe - parameter dump; focus-areas: " + focusAreas);
    358             }
    359 
    360             MeteringRectangle[] meteringRectArray = getMeteringRectangles(activeArray,
    361                     zoomData, p.getFocusAreas(), "AF");
    362 
    363             m.set(CONTROL_AF_REGIONS, meteringRectArray);
    364         }
    365     }
    366 
    367     private static void mapAwb(CameraMetadataNative m, Camera.Parameters p) {
    368         // control.awbLock
    369         {
    370             boolean lock = p.isAutoWhiteBalanceLockSupported() ?
    371                     p.getAutoWhiteBalanceLock() : false;
    372             m.set(CONTROL_AWB_LOCK, lock);
    373         }
    374 
    375         // control.awbMode
    376         {
    377             int awbMode = convertLegacyAwbMode(p.getWhiteBalance());
    378             m.set(CONTROL_AWB_MODE, awbMode);
    379         }
    380     }
    381 
    382     private static MeteringRectangle[] getMeteringRectangles(Rect activeArray, ZoomData zoomData,
    383             List<Camera.Area> meteringAreaList, String regionName) {
    384         List<MeteringRectangle> meteringRectList = new ArrayList<>();
    385         if (meteringAreaList != null) {
    386             for (Camera.Area area : meteringAreaList) {
    387                 WeightedRectangle rect =
    388                         ParameterUtils.convertCameraAreaToActiveArrayRectangle(
    389                                 activeArray, zoomData, area);
    390 
    391                 meteringRectList.add(rect.toMetering());
    392             }
    393         }
    394 
    395         if (VERBOSE) {
    396             Log.v(TAG,
    397                     "Metering rectangles for " + regionName + ": "
    398                      + ListUtils.listToString(meteringRectList));
    399         }
    400 
    401         return meteringRectList.toArray(new MeteringRectangle[0]);
    402     }
    403 
    404     /** Map results for control.aeMode, flash.mode, flash.state */
    405     private static void mapAeAndFlashMode(CameraMetadataNative m,
    406             CameraCharacteristics characteristics, Parameters p) {
    407         // Default: AE mode on but flash never fires
    408         int flashMode = FLASH_MODE_OFF;
    409         // If there is no flash on this camera, the state is always unavailable
    410         // , otherwise it's only known for TORCH/SINGLE modes
    411         Integer flashState = characteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE)
    412                 ? null : FLASH_STATE_UNAVAILABLE;
    413         int aeMode = CONTROL_AE_MODE_ON;
    414 
    415         String flashModeSetting = p.getFlashMode();
    416 
    417         if (flashModeSetting != null) {
    418             switch (flashModeSetting) {
    419                 case Parameters.FLASH_MODE_OFF:
    420                     break; // ok, using default
    421                 case Parameters.FLASH_MODE_AUTO:
    422                     aeMode = CONTROL_AE_MODE_ON_AUTO_FLASH;
    423                     break;
    424                 case Parameters.FLASH_MODE_ON:
    425                     // flashMode = SINGLE + aeMode = ON is indistinguishable from ON_ALWAYS_FLASH
    426                     flashMode = FLASH_MODE_SINGLE;
    427                     aeMode = CONTROL_AE_MODE_ON_ALWAYS_FLASH;
    428                     flashState = FLASH_STATE_FIRED;
    429                     break;
    430                 case Parameters.FLASH_MODE_RED_EYE:
    431                     aeMode = CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE;
    432                     break;
    433                 case Parameters.FLASH_MODE_TORCH:
    434                     flashMode = FLASH_MODE_TORCH;
    435                     flashState = FLASH_STATE_FIRED;
    436                     break;
    437                 default:
    438                     Log.w(TAG,
    439                             "mapAeAndFlashMode - Ignoring unknown flash mode " + p.getFlashMode());
    440             }
    441         }
    442 
    443         // flash.state
    444         m.set(FLASH_STATE, flashState);
    445         // flash.mode
    446         m.set(FLASH_MODE, flashMode);
    447         // control.aeMode
    448         m.set(CONTROL_AE_MODE, aeMode);
    449     }
    450 
    451     private static int convertLegacyAfMode(String mode) {
    452         if (mode == null) {
    453             Log.w(TAG, "convertLegacyAfMode - no AF mode, default to OFF");
    454             return CONTROL_AF_MODE_OFF;
    455         }
    456 
    457         switch (mode) {
    458             case Parameters.FOCUS_MODE_AUTO:
    459                 return CONTROL_AF_MODE_AUTO;
    460             case Parameters.FOCUS_MODE_CONTINUOUS_PICTURE:
    461                 return CONTROL_AF_MODE_CONTINUOUS_PICTURE;
    462             case Parameters.FOCUS_MODE_CONTINUOUS_VIDEO:
    463                 return CONTROL_AF_MODE_CONTINUOUS_VIDEO;
    464             case Parameters.FOCUS_MODE_EDOF:
    465                 return CONTROL_AF_MODE_EDOF;
    466             case Parameters.FOCUS_MODE_MACRO:
    467                 return CONTROL_AF_MODE_MACRO;
    468             case Parameters.FOCUS_MODE_FIXED:
    469                 return CONTROL_AF_MODE_OFF;
    470             case Parameters.FOCUS_MODE_INFINITY:
    471                 return CONTROL_AF_MODE_OFF;
    472             default:
    473                 Log.w(TAG, "convertLegacyAfMode - unknown mode " + mode + " , ignoring");
    474                 return CONTROL_AF_MODE_OFF;
    475         }
    476     }
    477 
    478     private static int convertLegacyAwbMode(String mode) {
    479         if (mode == null) {
    480             // OK: camera1 api may not support changing WB modes; assume AUTO
    481             return CONTROL_AWB_MODE_AUTO;
    482         }
    483 
    484         switch (mode) {
    485             case Camera.Parameters.WHITE_BALANCE_AUTO:
    486                 return CONTROL_AWB_MODE_AUTO;
    487             case Camera.Parameters.WHITE_BALANCE_INCANDESCENT:
    488                 return CONTROL_AWB_MODE_INCANDESCENT;
    489             case Camera.Parameters.WHITE_BALANCE_FLUORESCENT:
    490                 return CONTROL_AWB_MODE_FLUORESCENT;
    491             case Camera.Parameters.WHITE_BALANCE_WARM_FLUORESCENT:
    492                 return CONTROL_AWB_MODE_WARM_FLUORESCENT;
    493             case Camera.Parameters.WHITE_BALANCE_DAYLIGHT:
    494                 return CONTROL_AWB_MODE_DAYLIGHT;
    495             case Camera.Parameters.WHITE_BALANCE_CLOUDY_DAYLIGHT:
    496                 return CONTROL_AWB_MODE_CLOUDY_DAYLIGHT;
    497             case Camera.Parameters.WHITE_BALANCE_TWILIGHT:
    498                 return CONTROL_AWB_MODE_TWILIGHT;
    499             case Camera.Parameters.WHITE_BALANCE_SHADE:
    500                 return CONTROL_AWB_MODE_SHADE;
    501             default:
    502                 Log.w(TAG, "convertAwbMode - unrecognized WB mode " + mode);
    503                 return CONTROL_AWB_MODE_AUTO;
    504         }
    505     }
    506 
    507     /** Map results for scaler.* */
    508     private static void mapScaler(CameraMetadataNative m,
    509             ZoomData zoomData,
    510             /*out*/Parameters p) {
    511         /*
    512          * scaler.cropRegion
    513          */
    514         {
    515             m.set(SCALER_CROP_REGION, zoomData.reportedCrop);
    516         }
    517     }
    518 }
    519