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