CameraMetadataNative.java revision 72f9f0a96e4476ef231d5001cb30521ad4ce5b1e
1/* 2 * Copyright (C) 2013 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.impl; 18 19import android.graphics.ImageFormat; 20import android.graphics.Point; 21import android.graphics.Rect; 22import android.hardware.camera2.CameraCharacteristics; 23import android.hardware.camera2.CameraMetadata; 24import android.hardware.camera2.CaptureResult; 25import android.hardware.camera2.marshal.Marshaler; 26import android.hardware.camera2.marshal.MarshalQueryable; 27import android.hardware.camera2.marshal.MarshalRegistry; 28import android.hardware.camera2.marshal.impl.MarshalQueryableArray; 29import android.hardware.camera2.marshal.impl.MarshalQueryableBoolean; 30import android.hardware.camera2.marshal.impl.MarshalQueryableColorSpaceTransform; 31import android.hardware.camera2.marshal.impl.MarshalQueryableEnum; 32import android.hardware.camera2.marshal.impl.MarshalQueryableMeteringRectangle; 33import android.hardware.camera2.marshal.impl.MarshalQueryableNativeByteToInteger; 34import android.hardware.camera2.marshal.impl.MarshalQueryableParcelable; 35import android.hardware.camera2.marshal.impl.MarshalQueryablePrimitive; 36import android.hardware.camera2.marshal.impl.MarshalQueryableRange; 37import android.hardware.camera2.marshal.impl.MarshalQueryableRect; 38import android.hardware.camera2.marshal.impl.MarshalQueryableReprocessFormatsMap; 39import android.hardware.camera2.marshal.impl.MarshalQueryableRggbChannelVector; 40import android.hardware.camera2.marshal.impl.MarshalQueryableSize; 41import android.hardware.camera2.marshal.impl.MarshalQueryableSizeF; 42import android.hardware.camera2.marshal.impl.MarshalQueryableStreamConfiguration; 43import android.hardware.camera2.marshal.impl.MarshalQueryableStreamConfigurationDuration; 44import android.hardware.camera2.marshal.impl.MarshalQueryableString; 45import android.hardware.camera2.params.Face; 46import android.hardware.camera2.params.StreamConfiguration; 47import android.hardware.camera2.params.StreamConfigurationDuration; 48import android.hardware.camera2.params.StreamConfigurationMap; 49import android.os.Parcelable; 50import android.os.Parcel; 51import android.util.Log; 52 53import java.nio.ByteBuffer; 54import java.nio.ByteOrder; 55import java.util.ArrayList; 56 57/** 58 * Implementation of camera metadata marshal/unmarshal across Binder to 59 * the camera service 60 */ 61public class CameraMetadataNative extends CameraMetadata implements Parcelable { 62 63 private static final String TAG = "CameraMetadataJV"; 64 private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); 65 // this should be in sync with HAL_PIXEL_FORMAT_BLOB defined in graphics.h 66 private static final int NATIVE_JPEG_FORMAT = 0x21; 67 68 public CameraMetadataNative() { 69 super(); 70 mMetadataPtr = nativeAllocate(); 71 if (mMetadataPtr == 0) { 72 throw new OutOfMemoryError("Failed to allocate native CameraMetadata"); 73 } 74 } 75 76 /** 77 * Copy constructor - clone metadata 78 */ 79 public CameraMetadataNative(CameraMetadataNative other) { 80 super(); 81 mMetadataPtr = nativeAllocateCopy(other); 82 if (mMetadataPtr == 0) { 83 throw new OutOfMemoryError("Failed to allocate native CameraMetadata"); 84 } 85 } 86 87 public static final Parcelable.Creator<CameraMetadataNative> CREATOR = 88 new Parcelable.Creator<CameraMetadataNative>() { 89 @Override 90 public CameraMetadataNative createFromParcel(Parcel in) { 91 CameraMetadataNative metadata = new CameraMetadataNative(); 92 metadata.readFromParcel(in); 93 return metadata; 94 } 95 96 @Override 97 public CameraMetadataNative[] newArray(int size) { 98 return new CameraMetadataNative[size]; 99 } 100 }; 101 102 @Override 103 public int describeContents() { 104 return 0; 105 } 106 107 @Override 108 public void writeToParcel(Parcel dest, int flags) { 109 nativeWriteToParcel(dest); 110 } 111 112 @Override 113 public <T> T get(Key<T> key) { 114 T value = getOverride(key); 115 if (value != null) { 116 return value; 117 } 118 119 return getBase(key); 120 } 121 122 public void readFromParcel(Parcel in) { 123 nativeReadFromParcel(in); 124 } 125 126 /** 127 * Set the global client-side vendor tag descriptor to allow use of vendor 128 * tags in camera applications. 129 * 130 * @return int A native status_t value corresponding to one of the 131 * {@link CameraBinderDecorator} integer constants. 132 * @see CameraBinderDecorator#throwOnError 133 * 134 * @hide 135 */ 136 public static native int nativeSetupGlobalVendorTagDescriptor(); 137 138 /** 139 * Set a camera metadata field to a value. The field definitions can be 140 * found in {@link CameraCharacteristics}, {@link CaptureResult}, and 141 * {@link CaptureRequest}. 142 * 143 * @param key The metadata field to write. 144 * @param value The value to set the field to, which must be of a matching 145 * type to the key. 146 */ 147 public <T> void set(Key<T> key, T value) { 148 if (setOverride(key, value)) { 149 return; 150 } 151 152 setBase(key, value); 153 } 154 155 // Keep up-to-date with camera_metadata.h 156 /** 157 * @hide 158 */ 159 public static final int TYPE_BYTE = 0; 160 /** 161 * @hide 162 */ 163 public static final int TYPE_INT32 = 1; 164 /** 165 * @hide 166 */ 167 public static final int TYPE_FLOAT = 2; 168 /** 169 * @hide 170 */ 171 public static final int TYPE_INT64 = 3; 172 /** 173 * @hide 174 */ 175 public static final int TYPE_DOUBLE = 4; 176 /** 177 * @hide 178 */ 179 public static final int TYPE_RATIONAL = 5; 180 /** 181 * @hide 182 */ 183 public static final int NUM_TYPES = 6; 184 185 private void close() { 186 // this sets mMetadataPtr to 0 187 nativeClose(); 188 mMetadataPtr = 0; // set it to 0 again to prevent eclipse from making this field final 189 } 190 191 private <T> T getBase(Key<T> key) { 192 int tag = key.getTag(); 193 byte[] values = readValues(tag); 194 if (values == null) { 195 return null; 196 } 197 198 Marshaler<T> marshaler = getMarshalerForKey(key); 199 ByteBuffer buffer = ByteBuffer.wrap(values).order(ByteOrder.nativeOrder()); 200 return marshaler.unmarshal(buffer); 201 } 202 203 // Need overwrite some metadata that has different definitions between native 204 // and managed sides. 205 @SuppressWarnings("unchecked") 206 private <T> T getOverride(Key<T> key) { 207 if (key.equals(CameraCharacteristics.SCALER_AVAILABLE_FORMATS)) { 208 return (T) getAvailableFormats(); 209 } else if (key.equals(CaptureResult.STATISTICS_FACES)) { 210 return (T) getFaces(); 211 } else if (key.equals(CaptureResult.STATISTICS_FACE_RECTANGLES)) { 212 return (T) getFaceRectangles(); 213 } else if (key.equals(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)) { 214 return (T) getStreamConfigurationMap(); 215 } 216 217 // For other keys, get() falls back to getBase() 218 return null; 219 } 220 221 private int[] getAvailableFormats() { 222 int[] availableFormats = getBase(CameraCharacteristics.SCALER_AVAILABLE_FORMATS); 223 if (availableFormats != null) { 224 for (int i = 0; i < availableFormats.length; i++) { 225 // JPEG has different value between native and managed side, need override. 226 if (availableFormats[i] == NATIVE_JPEG_FORMAT) { 227 availableFormats[i] = ImageFormat.JPEG; 228 } 229 } 230 } 231 232 return availableFormats; 233 } 234 235 private Face[] getFaces() { 236 final int FACE_LANDMARK_SIZE = 6; 237 238 Integer faceDetectMode = get(CaptureResult.STATISTICS_FACE_DETECT_MODE); 239 if (faceDetectMode == null) { 240 Log.w(TAG, "Face detect mode metadata is null, assuming the mode is SIMPLE"); 241 faceDetectMode = CaptureResult.STATISTICS_FACE_DETECT_MODE_SIMPLE; 242 } else { 243 if (faceDetectMode == CaptureResult.STATISTICS_FACE_DETECT_MODE_OFF) { 244 return new Face[0]; 245 } 246 if (faceDetectMode != CaptureResult.STATISTICS_FACE_DETECT_MODE_SIMPLE && 247 faceDetectMode != CaptureResult.STATISTICS_FACE_DETECT_MODE_FULL) { 248 Log.w(TAG, "Unknown face detect mode: " + faceDetectMode); 249 return new Face[0]; 250 } 251 } 252 253 // Face scores and rectangles are required by SIMPLE and FULL mode. 254 byte[] faceScores = get(CaptureResult.STATISTICS_FACE_SCORES); 255 Rect[] faceRectangles = get(CaptureResult.STATISTICS_FACE_RECTANGLES); 256 if (faceScores == null || faceRectangles == null) { 257 Log.w(TAG, "Expect face scores and rectangles to be non-null"); 258 return new Face[0]; 259 } else if (faceScores.length != faceRectangles.length) { 260 Log.w(TAG, String.format("Face score size(%d) doesn match face rectangle size(%d)!", 261 faceScores.length, faceRectangles.length)); 262 } 263 264 // To be safe, make number of faces is the minimal of all face info metadata length. 265 int numFaces = Math.min(faceScores.length, faceRectangles.length); 266 // Face id and landmarks are only required by FULL mode. 267 int[] faceIds = get(CaptureResult.STATISTICS_FACE_IDS); 268 int[] faceLandmarks = get(CaptureResult.STATISTICS_FACE_LANDMARKS); 269 if (faceDetectMode == CaptureResult.STATISTICS_FACE_DETECT_MODE_FULL) { 270 if (faceIds == null || faceLandmarks == null) { 271 Log.w(TAG, "Expect face ids and landmarks to be non-null for FULL mode," + 272 "fallback to SIMPLE mode"); 273 faceDetectMode = CaptureResult.STATISTICS_FACE_DETECT_MODE_SIMPLE; 274 } else { 275 if (faceIds.length != numFaces || 276 faceLandmarks.length != numFaces * FACE_LANDMARK_SIZE) { 277 Log.w(TAG, String.format("Face id size(%d), or face landmark size(%d) don't" + 278 "match face number(%d)!", 279 faceIds.length, faceLandmarks.length * FACE_LANDMARK_SIZE, numFaces)); 280 } 281 // To be safe, make number of faces is the minimal of all face info metadata length. 282 numFaces = Math.min(numFaces, faceIds.length); 283 numFaces = Math.min(numFaces, faceLandmarks.length / FACE_LANDMARK_SIZE); 284 } 285 } 286 287 ArrayList<Face> faceList = new ArrayList<Face>(); 288 if (faceDetectMode == CaptureResult.STATISTICS_FACE_DETECT_MODE_SIMPLE) { 289 for (int i = 0; i < numFaces; i++) { 290 if (faceScores[i] <= Face.SCORE_MAX && 291 faceScores[i] >= Face.SCORE_MIN) { 292 faceList.add(new Face(faceRectangles[i], faceScores[i])); 293 } 294 } 295 } else { 296 // CaptureResult.STATISTICS_FACE_DETECT_MODE_FULL 297 for (int i = 0; i < numFaces; i++) { 298 if (faceScores[i] <= Face.SCORE_MAX && 299 faceScores[i] >= Face.SCORE_MIN && 300 faceIds[i] >= 0) { 301 Point leftEye = new Point(faceLandmarks[i*6], faceLandmarks[i*6+1]); 302 Point rightEye = new Point(faceLandmarks[i*6+2], faceLandmarks[i*6+3]); 303 Point mouth = new Point(faceLandmarks[i*6+4], faceLandmarks[i*6+5]); 304 Face face = new Face(faceRectangles[i], faceScores[i], faceIds[i], 305 leftEye, rightEye, mouth); 306 faceList.add(face); 307 } 308 } 309 } 310 Face[] faces = new Face[faceList.size()]; 311 faceList.toArray(faces); 312 return faces; 313 } 314 315 // Face rectangles are defined as (left, top, right, bottom) instead of 316 // (left, top, width, height) at the native level, so the normal Rect 317 // conversion that does (l, t, w, h) -> (l, t, r, b) is unnecessary. Undo 318 // that conversion here for just the faces. 319 private Rect[] getFaceRectangles() { 320 Rect[] faceRectangles = getBase(CaptureResult.STATISTICS_FACE_RECTANGLES); 321 if (faceRectangles == null) return null; 322 323 Rect[] fixedFaceRectangles = new Rect[faceRectangles.length]; 324 for (int i = 0; i < faceRectangles.length; i++) { 325 fixedFaceRectangles[i] = new Rect( 326 faceRectangles[i].left, 327 faceRectangles[i].top, 328 faceRectangles[i].right - faceRectangles[i].left, 329 faceRectangles[i].bottom - faceRectangles[i].top); 330 } 331 return fixedFaceRectangles; 332 } 333 334 private StreamConfigurationMap getStreamConfigurationMap() { 335 StreamConfiguration[] configurations = getBase( 336 CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS); 337 StreamConfigurationDuration[] minFrameDurations = getBase( 338 CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS); 339 StreamConfigurationDuration[] stallDurations = getBase( 340 CameraCharacteristics.SCALER_AVAILABLE_STALL_DURATIONS); 341 342 return new StreamConfigurationMap(configurations, minFrameDurations, stallDurations); 343 } 344 345 private <T> void setBase(Key<T> key, T value) { 346 int tag = key.getTag(); 347 348 if (value == null) { 349 // Erase the entry 350 writeValues(tag, /*src*/null); 351 return; 352 } // else update the entry to a new value 353 354 Marshaler<T> marshaler = getMarshalerForKey(key); 355 int size = marshaler.calculateMarshalSize(value); 356 357 // TODO: Optimization. Cache the byte[] and reuse if the size is big enough. 358 byte[] values = new byte[size]; 359 360 ByteBuffer buffer = ByteBuffer.wrap(values).order(ByteOrder.nativeOrder()); 361 marshaler.marshal(value, buffer); 362 363 writeValues(tag, values); 364 } 365 366 // Set the camera metadata override. 367 private <T> boolean setOverride(Key<T> key, T value) { 368 if (key.equals(CameraCharacteristics.SCALER_AVAILABLE_FORMATS)) { 369 return setAvailableFormats((int[]) value); 370 } else if (key.equals(CaptureResult.STATISTICS_FACE_RECTANGLES)) { 371 return setFaceRectangles((Rect[]) value); 372 } 373 374 // For other keys, set() falls back to setBase(). 375 return false; 376 } 377 378 private boolean setAvailableFormats(int[] value) { 379 int[] availableFormat = value; 380 if (value == null) { 381 // Let setBase() to handle the null value case. 382 return false; 383 } 384 385 int[] newValues = new int[availableFormat.length]; 386 for (int i = 0; i < availableFormat.length; i++) { 387 newValues[i] = availableFormat[i]; 388 if (availableFormat[i] == ImageFormat.JPEG) { 389 newValues[i] = NATIVE_JPEG_FORMAT; 390 } 391 } 392 393 setBase(CameraCharacteristics.SCALER_AVAILABLE_FORMATS, newValues); 394 return true; 395 } 396 397 /** 398 * Convert Face Rectangles from managed side to native side as they have different definitions. 399 * <p> 400 * Managed side face rectangles are defined as: left, top, width, height. 401 * Native side face rectangles are defined as: left, top, right, bottom. 402 * The input face rectangle need to be converted to native side definition when set is called. 403 * </p> 404 * 405 * @param faceRects Input face rectangles. 406 * @return true if face rectangles can be set successfully. Otherwise, Let the caller 407 * (setBase) to handle it appropriately. 408 */ 409 private boolean setFaceRectangles(Rect[] faceRects) { 410 if (faceRects == null) { 411 return false; 412 } 413 414 Rect[] newFaceRects = new Rect[faceRects.length]; 415 for (int i = 0; i < newFaceRects.length; i++) { 416 newFaceRects[i] = new Rect( 417 faceRects[i].left, 418 faceRects[i].top, 419 faceRects[i].right + faceRects[i].left, 420 faceRects[i].bottom + faceRects[i].top); 421 } 422 423 setBase(CaptureResult.STATISTICS_FACE_RECTANGLES, newFaceRects); 424 return true; 425 } 426 427 private long mMetadataPtr; // native CameraMetadata* 428 429 private native long nativeAllocate(); 430 private native long nativeAllocateCopy(CameraMetadataNative other) 431 throws NullPointerException; 432 433 private native synchronized void nativeWriteToParcel(Parcel dest); 434 private native synchronized void nativeReadFromParcel(Parcel source); 435 private native synchronized void nativeSwap(CameraMetadataNative other) 436 throws NullPointerException; 437 private native synchronized void nativeClose(); 438 private native synchronized boolean nativeIsEmpty(); 439 private native synchronized int nativeGetEntryCount(); 440 441 private native synchronized byte[] nativeReadValues(int tag); 442 private native synchronized void nativeWriteValues(int tag, byte[] src); 443 444 private static native int nativeGetTagFromKey(String keyName) 445 throws IllegalArgumentException; 446 private static native int nativeGetTypeFromTag(int tag) 447 throws IllegalArgumentException; 448 private static native void nativeClassInit(); 449 450 /** 451 * <p>Perform a 0-copy swap of the internal metadata with another object.</p> 452 * 453 * <p>Useful to convert a CameraMetadata into e.g. a CaptureRequest.</p> 454 * 455 * @param other Metadata to swap with 456 * @throws NullPointerException if other was null 457 * @hide 458 */ 459 public void swap(CameraMetadataNative other) { 460 nativeSwap(other); 461 } 462 463 /** 464 * @hide 465 */ 466 public int getEntryCount() { 467 return nativeGetEntryCount(); 468 } 469 470 /** 471 * Does this metadata contain at least 1 entry? 472 * 473 * @hide 474 */ 475 public boolean isEmpty() { 476 return nativeIsEmpty(); 477 } 478 479 /** 480 * Convert a key string into the equivalent native tag. 481 * 482 * @throws IllegalArgumentException if the key was not recognized 483 * @throws NullPointerException if the key was null 484 * 485 * @hide 486 */ 487 public static int getTag(String key) { 488 return nativeGetTagFromKey(key); 489 } 490 491 /** 492 * Get the underlying native type for a tag. 493 * 494 * @param tag An integer tag, see e.g. {@link #getTag} 495 * @return An int enum for the metadata type, see e.g. {@link #TYPE_BYTE} 496 * 497 * @hide 498 */ 499 public static int getNativeType(int tag) { 500 return nativeGetTypeFromTag(tag); 501 } 502 503 /** 504 * <p>Updates the existing entry for tag with the new bytes pointed by src, erasing 505 * the entry if src was null.</p> 506 * 507 * <p>An empty array can be passed in to update the entry to 0 elements.</p> 508 * 509 * @param tag An integer tag, see e.g. {@link #getTag} 510 * @param src An array of bytes, or null to erase the entry 511 * 512 * @hide 513 */ 514 public void writeValues(int tag, byte[] src) { 515 nativeWriteValues(tag, src); 516 } 517 518 /** 519 * <p>Returns a byte[] of data corresponding to this tag. Use a wrapped bytebuffer to unserialize 520 * the data properly.</p> 521 * 522 * <p>An empty array can be returned to denote an existing entry with 0 elements.</p> 523 * 524 * @param tag An integer tag, see e.g. {@link #getTag} 525 * 526 * @return {@code null} if there were 0 entries for this tag, a byte[] otherwise. 527 * @hide 528 */ 529 public byte[] readValues(int tag) { 530 // TODO: Optimization. Native code returns a ByteBuffer instead. 531 return nativeReadValues(tag); 532 } 533 534 @Override 535 protected void finalize() throws Throwable { 536 try { 537 close(); 538 } finally { 539 super.finalize(); 540 } 541 } 542 543 /** 544 * Get the marshaler compatible with the {@code key} and type {@code T}. 545 * 546 * @throws UnsupportedOperationException 547 * if the native/managed type combination for {@code key} is not supported 548 */ 549 private static <T> Marshaler<T> getMarshalerForKey(Key<T> key) { 550 return MarshalRegistry.getMarshaler(key.getTypeReference(), 551 getNativeType(key.getTag())); 552 } 553 554 @SuppressWarnings({ "unchecked", "rawtypes" }) 555 private static void registerAllMarshalers() { 556 if (VERBOSE) { 557 Log.v(TAG, "Shall register metadata marshalers"); 558 } 559 560 MarshalQueryable[] queryList = new MarshalQueryable[] { 561 // marshalers for standard types 562 new MarshalQueryablePrimitive(), 563 new MarshalQueryableEnum(), 564 new MarshalQueryableArray(), 565 566 // pseudo standard types, that expand/narrow the native type into a managed type 567 new MarshalQueryableBoolean(), 568 new MarshalQueryableNativeByteToInteger(), 569 570 // marshalers for custom types 571 new MarshalQueryableRect(), 572 new MarshalQueryableSize(), 573 new MarshalQueryableSizeF(), 574 new MarshalQueryableString(), 575 new MarshalQueryableReprocessFormatsMap(), 576 new MarshalQueryableRange(), 577 new MarshalQueryableMeteringRectangle(), 578 new MarshalQueryableColorSpaceTransform(), 579 new MarshalQueryableStreamConfiguration(), 580 new MarshalQueryableStreamConfigurationDuration(), 581 new MarshalQueryableRggbChannelVector(), 582 583 // generic parcelable marshaler (MUST BE LAST since it has lowest priority) 584 new MarshalQueryableParcelable(), 585 }; 586 587 for (MarshalQueryable query : queryList) { 588 MarshalRegistry.registerMarshalQueryable(query); 589 } 590 if (VERBOSE) { 591 Log.v(TAG, "Registered metadata marshalers"); 592 } 593 } 594 595 static { 596 /* 597 * We use a class initializer to allow the native code to cache some field offsets 598 */ 599 nativeClassInit(); 600 registerAllMarshalers(); 601 } 602 603} 604