LegacyMetadataMapper.java revision 91b9aabc9fa0c058ecc4a8b3f486540c28fe1cc0
1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.hardware.camera2.legacy; 18 19import android.graphics.ImageFormat; 20import android.hardware.Camera; 21import android.hardware.Camera.CameraInfo; 22import android.hardware.Camera.Size; 23import android.hardware.camera2.CameraCharacteristics; 24import android.hardware.camera2.CaptureRequest; 25import android.hardware.camera2.CaptureResult; 26import android.hardware.camera2.impl.CameraMetadataNative; 27import android.hardware.camera2.params.StreamConfiguration; 28import android.hardware.camera2.params.StreamConfigurationDuration; 29import android.util.Log; 30import android.util.Range; 31 32import java.util.ArrayList; 33import java.util.Arrays; 34import java.util.List; 35 36import static com.android.internal.util.Preconditions.*; 37import static android.hardware.camera2.CameraCharacteristics.*; 38 39/** 40 * Provide legacy-specific implementations of camera2 metadata for legacy devices, such as the 41 * camera characteristics. 42 */ 43public class LegacyMetadataMapper { 44 private static final String TAG = "LegacyMetadataMapper"; 45 private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); 46 47 // from graphics.h 48 private static final int HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED = 0x22; 49 private static final int HAL_PIXEL_FORMAT_BLOB = 0x21; 50 51 private static final long APPROXIMATE_CAPTURE_DELAY_MS = 200; // ms 52 private static final long APPROXIMATE_SENSOR_AREA = (1 << 23); // 8mp 53 private static final long APPROXIMATE_JPEG_ENCODE_TIME = 600; // ms 54 private static final long NS_PER_MS = 1000000; 55 56 /** 57 * Create characteristics for a legacy device by mapping the {@code parameters} 58 * and {@code info} 59 * 60 * @param parameters A string parseable by {@link Camera.Parameters#unflatten} 61 * @param info Camera info with camera facing direction and angle of orientation 62 * @return static camera characteristics for a camera device 63 * 64 * @throws NullPointerException if any of the args were {@code null} 65 */ 66 public static CameraCharacteristics createCharacteristics(String parameters, 67 android.hardware.CameraInfo info) { 68 checkNotNull(parameters, "parameters must not be null"); 69 checkNotNull(info, "info must not be null"); 70 checkNotNull(info.info, "info.info must not be null"); 71 72 CameraMetadataNative m = new CameraMetadataNative(); 73 74 mapCameraInfo(m, info.info); 75 76 Camera.Parameters params = Camera.getEmptyParameters(); 77 params.unflatten(parameters); 78 mapCameraParameters(m, params); 79 80 if (VERBOSE) { 81 Log.v(TAG, "createCharacteristics metadata:"); 82 Log.v(TAG, "--------------------------------------------------- (start)"); 83 m.dumpToLog(); 84 Log.v(TAG, "--------------------------------------------------- (end)"); 85 } 86 87 return new CameraCharacteristics(m); 88 } 89 90 private static void mapCameraInfo(CameraMetadataNative m, CameraInfo i) { 91 m.set(LENS_FACING, i.facing == CameraInfo.CAMERA_FACING_BACK ? 92 LENS_FACING_BACK : LENS_FACING_FRONT); 93 m.set(SENSOR_ORIENTATION, i.orientation); 94 } 95 96 private static void mapCameraParameters(CameraMetadataNative m, Camera.Parameters p) { 97 mapStreamConfigs(m, p); 98 mapAeConfig(m, p); 99 mapCapabilities(m, p); 100 101 // TODO: map other fields 102 } 103 104 private static void mapStreamConfigs(CameraMetadataNative m, Camera.Parameters p) { 105 106 ArrayList<StreamConfiguration> availableStreamConfigs = new ArrayList<>(); 107 /* 108 * Implementation-defined (preview, recording, etc) -> use camera1 preview sizes 109 * YUV_420_888 cpu callbacks -> use camera1 preview sizes 110 * Other preview callbacks (CPU) -> use camera1 preview sizes 111 * JPEG still capture -> use camera1 still capture sizes 112 * 113 * Use platform-internal format constants here, since StreamConfigurationMap does the 114 * remapping to public format constants. 115 */ 116 List<Size> previewSizes = p.getSupportedPreviewSizes(); 117 appendStreamConfig(availableStreamConfigs, 118 HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, previewSizes); 119 appendStreamConfig(availableStreamConfigs, 120 ImageFormat.YUV_420_888, previewSizes); 121 for (int format : p.getSupportedPreviewFormats()) { 122 if (ImageFormat.isPublicFormat(format)) { 123 appendStreamConfig(availableStreamConfigs, format, previewSizes); 124 } else { 125 /* 126 * Do not add any formats unknown to us 127 * (since it would fail runtime checks in StreamConfigurationMap) 128 */ 129 Log.w(TAG, 130 String.format("mapStreamConfigs - Skipping non-public format %x", format)); 131 } 132 } 133 134 List<Camera.Size> jpegSizes = p.getSupportedPictureSizes(); 135 appendStreamConfig(availableStreamConfigs, 136 HAL_PIXEL_FORMAT_BLOB, p.getSupportedPictureSizes()); 137 m.set(SCALER_AVAILABLE_STREAM_CONFIGURATIONS, 138 availableStreamConfigs.toArray(new StreamConfiguration[0])); 139 140 // No frame durations available 141 m.set(SCALER_AVAILABLE_MIN_FRAME_DURATIONS, new StreamConfigurationDuration[0]); 142 143 StreamConfigurationDuration[] jpegStalls = 144 new StreamConfigurationDuration[jpegSizes.size()]; 145 int i = 0; 146 long longestStallDuration = -1; 147 for (Camera.Size s : jpegSizes) { 148 long stallDuration = calculateJpegStallDuration(s); 149 jpegStalls[i++] = new StreamConfigurationDuration(HAL_PIXEL_FORMAT_BLOB, s.width, 150 s.height, stallDuration); 151 if (longestStallDuration < stallDuration) { 152 longestStallDuration = stallDuration; 153 } 154 } 155 // Set stall durations for jpeg, other formats use default stall duration 156 m.set(SCALER_AVAILABLE_STALL_DURATIONS, jpegStalls); 157 158 m.set(SENSOR_INFO_MAX_FRAME_DURATION, longestStallDuration); 159 } 160 161 @SuppressWarnings({"unchecked"}) 162 private static void mapAeConfig(CameraMetadataNative m, Camera.Parameters p) { 163 164 List<int[]> fpsRanges = p.getSupportedPreviewFpsRange(); 165 if (fpsRanges == null) { 166 throw new AssertionError("Supported FPS ranges cannot be null."); 167 } 168 int rangesSize = fpsRanges.size(); 169 if (rangesSize <= 0) { 170 throw new AssertionError("At least one FPS range must be supported."); 171 } 172 Range<Integer>[] ranges = new Range[rangesSize]; 173 int i = 0; 174 for (int[] r : fpsRanges) { 175 ranges[i++] = Range.create(r[Camera.Parameters.PREVIEW_FPS_MIN_INDEX], 176 r[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]); 177 } 178 m.set(CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES, ranges); 179 180 List<String> antiBandingModes = p.getSupportedAntibanding(); 181 int antiBandingModesSize = antiBandingModes.size(); 182 if (antiBandingModesSize > 0) { 183 int[] modes = new int[antiBandingModesSize]; 184 int j = 0; 185 for (String mode : antiBandingModes) { 186 int convertedMode = convertAntiBandingMode(mode); 187 if (convertedMode == -1) { 188 Log.w(TAG, "Antibanding mode " + ((mode == null) ? "NULL" : mode) + 189 " not supported, skipping..."); 190 } else { 191 modes[j++] = convertedMode; 192 } 193 } 194 m.set(CONTROL_AE_AVAILABLE_ANTIBANDING_MODES, Arrays.copyOf(modes, j)); 195 } 196 } 197 198 private static void mapCapabilities(CameraMetadataNative m, Camera.Parameters p) { 199 int[] capabilities = { REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE }; 200 m.set(REQUEST_AVAILABLE_CAPABILITIES, capabilities); 201 } 202 203 private static void appendStreamConfig( 204 ArrayList<StreamConfiguration> configs, int format, List<Camera.Size> sizes) { 205 for (Camera.Size size : sizes) { 206 StreamConfiguration config = 207 new StreamConfiguration(format, size.width, size.height, /*input*/false); 208 configs.add(config); 209 } 210 } 211 212 /** 213 * Returns -1 if the anti-banding mode string is null, or not supported. 214 */ 215 private static int convertAntiBandingMode(final String mode) { 216 if (mode == null) { 217 return -1; 218 } 219 switch(mode) { 220 case Camera.Parameters.ANTIBANDING_OFF: { 221 return CONTROL_AE_ANTIBANDING_MODE_OFF; 222 } 223 case Camera.Parameters.ANTIBANDING_50HZ: { 224 return CONTROL_AE_ANTIBANDING_MODE_50HZ; 225 } 226 case Camera.Parameters.ANTIBANDING_60HZ: { 227 return CONTROL_AE_ANTIBANDING_MODE_60HZ; 228 } 229 case Camera.Parameters.ANTIBANDING_AUTO: { 230 return CONTROL_AE_ANTIBANDING_MODE_AUTO; 231 } 232 default: { 233 return -1; 234 } 235 } 236 } 237 238 /** 239 * Returns null if the anti-banding mode enum is not supported. 240 */ 241 private static String convertAntiBandingModeToLegacy(int mode) { 242 switch(mode) { 243 case CONTROL_AE_ANTIBANDING_MODE_OFF: { 244 return Camera.Parameters.ANTIBANDING_OFF; 245 } 246 case CONTROL_AE_ANTIBANDING_MODE_50HZ: { 247 return Camera.Parameters.ANTIBANDING_50HZ; 248 } 249 case CONTROL_AE_ANTIBANDING_MODE_60HZ: { 250 return Camera.Parameters.ANTIBANDING_60HZ; 251 } 252 case CONTROL_AE_ANTIBANDING_MODE_AUTO: { 253 return Camera.Parameters.ANTIBANDING_AUTO; 254 } 255 default: { 256 return null; 257 } 258 } 259 } 260 261 262 private static int[] convertAeFpsRangeToLegacy(Range<Integer> fpsRange) { 263 int[] legacyFps = new int[2]; 264 legacyFps[Camera.Parameters.PREVIEW_FPS_MIN_INDEX] = fpsRange.getLower(); 265 legacyFps[Camera.Parameters.PREVIEW_FPS_MAX_INDEX] = fpsRange.getUpper(); 266 return legacyFps; 267 } 268 269 /** 270 * Return the stall duration for a given output jpeg size in nanoseconds. 271 * 272 * <p>An 8mp image is chosen to have a stall duration of 0.8 seconds.</p> 273 */ 274 private static long calculateJpegStallDuration(Camera.Size size) { 275 long baseDuration = APPROXIMATE_CAPTURE_DELAY_MS * NS_PER_MS; // 200ms for capture 276 long area = size.width * (long) size.height; 277 long stallPerArea = APPROXIMATE_JPEG_ENCODE_TIME * NS_PER_MS / 278 APPROXIMATE_SENSOR_AREA; // 600ms stall for 8mp 279 return baseDuration + area * stallPerArea; 280 } 281 282 /** 283 * Generate capture result metadata from legacy camera parameters. 284 * 285 * @param params a {@link Camera.Parameters} object to generate metadata from. 286 * @param request the {@link CaptureRequest} used for this result. 287 * @param timestamp the timestamp to use for this result in nanoseconds. 288 * @return a {@link CameraMetadataNative} object containing result metadata. 289 */ 290 public static CameraMetadataNative convertResultMetadata(Camera.Parameters params, 291 CaptureRequest request, 292 long timestamp) { 293 CameraMetadataNative result = new CameraMetadataNative(); 294 result.set(CaptureResult.LENS_FOCAL_LENGTH, params.getFocalLength()); 295 result.set(CaptureResult.SENSOR_TIMESTAMP, timestamp); 296 297 // TODO: Remaining result metadata tags conversions. 298 return result; 299 } 300 301 /** 302 * Set the legacy parameters using the request metadata. 303 * 304 * @param request a {@link CaptureRequest} object to generate parameters from. 305 * @param params the a {@link Camera.Parameters} to set parameters in. 306 */ 307 public static void convertRequestMetadata(CaptureRequest request, 308 /*out*/Camera.Parameters params) { 309 Integer antiBandingMode = request.get(CaptureRequest.CONTROL_AE_ANTIBANDING_MODE); 310 if (antiBandingMode != null) { 311 String legacyMode = convertAntiBandingModeToLegacy(antiBandingMode); 312 if (legacyMode != null) params.setAntibanding(legacyMode); 313 } 314 315 Range<Integer> aeFpsRange = request.get(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE); 316 if (aeFpsRange != null) { 317 int[] legacyFps = convertAeFpsRangeToLegacy(aeFpsRange); 318 params.setPreviewFpsRange(legacyFps[Camera.Parameters.PREVIEW_FPS_MIN_INDEX], 319 legacyFps[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]); 320 } 321 } 322} 323