CameraMetadataNative.java revision d47699a47a77781c8883f31c48ffae88ba878cf8
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.CaptureRequest;
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.MarshalQueryableBlackLevelPattern;
31import android.hardware.camera2.marshal.impl.MarshalQueryableColorSpaceTransform;
32import android.hardware.camera2.marshal.impl.MarshalQueryableEnum;
33import android.hardware.camera2.marshal.impl.MarshalQueryableHighSpeedVideoConfiguration;
34import android.hardware.camera2.marshal.impl.MarshalQueryableMeteringRectangle;
35import android.hardware.camera2.marshal.impl.MarshalQueryableNativeByteToInteger;
36import android.hardware.camera2.marshal.impl.MarshalQueryablePair;
37import android.hardware.camera2.marshal.impl.MarshalQueryableParcelable;
38import android.hardware.camera2.marshal.impl.MarshalQueryablePrimitive;
39import android.hardware.camera2.marshal.impl.MarshalQueryableRange;
40import android.hardware.camera2.marshal.impl.MarshalQueryableRect;
41import android.hardware.camera2.marshal.impl.MarshalQueryableReprocessFormatsMap;
42import android.hardware.camera2.marshal.impl.MarshalQueryableRggbChannelVector;
43import android.hardware.camera2.marshal.impl.MarshalQueryableSize;
44import android.hardware.camera2.marshal.impl.MarshalQueryableSizeF;
45import android.hardware.camera2.marshal.impl.MarshalQueryableStreamConfiguration;
46import android.hardware.camera2.marshal.impl.MarshalQueryableStreamConfigurationDuration;
47import android.hardware.camera2.marshal.impl.MarshalQueryableString;
48import android.hardware.camera2.params.Face;
49import android.hardware.camera2.params.HighSpeedVideoConfiguration;
50import android.hardware.camera2.params.LensShadingMap;
51import android.hardware.camera2.params.StreamConfiguration;
52import android.hardware.camera2.params.StreamConfigurationDuration;
53import android.hardware.camera2.params.StreamConfigurationMap;
54import android.hardware.camera2.params.TonemapCurve;
55import android.hardware.camera2.utils.TypeReference;
56import android.location.Location;
57import android.location.LocationManager;
58import android.os.Parcelable;
59import android.os.Parcel;
60import android.util.Log;
61import android.util.Size;
62
63import com.android.internal.util.Preconditions;
64
65import java.io.IOException;
66import java.nio.ByteBuffer;
67import java.nio.ByteOrder;
68import java.util.ArrayList;
69import java.util.HashMap;
70
71/**
72 * Implementation of camera metadata marshal/unmarshal across Binder to
73 * the camera service
74 */
75public class CameraMetadataNative implements Parcelable {
76
77    public static class Key<T> {
78        private boolean mHasTag;
79        private int mTag;
80        private final Class<T> mType;
81        private final TypeReference<T> mTypeReference;
82        private final String mName;
83        private final int mHash;
84        /**
85         * Visible for testing only.
86         *
87         * <p>Use the CameraCharacteristics.Key, CaptureResult.Key, or CaptureRequest.Key
88         * for application code or vendor-extended keys.</p>
89         */
90        public Key(String name, Class<T> type) {
91            if (name == null) {
92                throw new NullPointerException("Key needs a valid name");
93            } else if (type == null) {
94                throw new NullPointerException("Type needs to be non-null");
95            }
96            mName = name;
97            mType = type;
98            mTypeReference = TypeReference.createSpecializedTypeReference(type);
99            mHash = mName.hashCode() ^ mTypeReference.hashCode();
100        }
101
102        /**
103         * Visible for testing only.
104         *
105         * <p>Use the CameraCharacteristics.Key, CaptureResult.Key, or CaptureRequest.Key
106         * for application code or vendor-extended keys.</p>
107         */
108        @SuppressWarnings("unchecked")
109        public Key(String name, TypeReference<T> typeReference) {
110            if (name == null) {
111                throw new NullPointerException("Key needs a valid name");
112            } else if (typeReference == null) {
113                throw new NullPointerException("TypeReference needs to be non-null");
114            }
115            mName = name;
116            mType = (Class<T>)typeReference.getRawType();
117            mTypeReference = typeReference;
118            mHash = mName.hashCode() ^ mTypeReference.hashCode();
119        }
120
121        /**
122         * Return a camelCase, period separated name formatted like:
123         * {@code "root.section[.subsections].name"}.
124         *
125         * <p>Built-in keys exposed by the Android SDK are always prefixed with {@code "android."};
126         * keys that are device/platform-specific are prefixed with {@code "com."}.</p>
127         *
128         * <p>For example, {@code CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP} would
129         * have a name of {@code "android.scaler.streamConfigurationMap"}; whereas a device
130         * specific key might look like {@code "com.google.nexus.data.private"}.</p>
131         *
132         * @return String representation of the key name
133         */
134        public final String getName() {
135            return mName;
136        }
137
138        /**
139         * {@inheritDoc}
140         */
141        @Override
142        public final int hashCode() {
143            return mHash;
144        }
145
146        /**
147         * Compare this key against other native keys, request keys, result keys, and
148         * characteristics keys.
149         *
150         * <p>Two keys are considered equal if their name and type reference are equal.</p>
151         *
152         * <p>Note that the equality against non-native keys is one-way. A native key may be equal
153         * to a result key; but that same result key will not be equal to a native key.</p>
154         */
155        @SuppressWarnings("rawtypes")
156        @Override
157        public final boolean equals(Object o) {
158            if (this == o) {
159                return true;
160            }
161
162            if (o == null || this.hashCode() != o.hashCode()) {
163                return false;
164            }
165
166            Key<?> lhs;
167
168            if (o instanceof CaptureResult.Key) {
169                lhs = ((CaptureResult.Key)o).getNativeKey();
170            } else if (o instanceof CaptureRequest.Key) {
171                lhs = ((CaptureRequest.Key)o).getNativeKey();
172            } else if (o instanceof CameraCharacteristics.Key) {
173                lhs = ((CameraCharacteristics.Key)o).getNativeKey();
174            } else if ((o instanceof Key)) {
175                lhs = (Key<?>)o;
176            } else {
177                return false;
178            }
179
180            return mName.equals(lhs.mName) && mTypeReference.equals(lhs.mTypeReference);
181        }
182
183        /**
184         * <p>
185         * Get the tag corresponding to this key. This enables insertion into the
186         * native metadata.
187         * </p>
188         *
189         * <p>This value is looked up the first time, and cached subsequently.</p>
190         *
191         * @return The tag numeric value corresponding to the string
192         */
193        public final int getTag() {
194            if (!mHasTag) {
195                mTag = CameraMetadataNative.getTag(mName);
196                mHasTag = true;
197            }
198            return mTag;
199        }
200
201        /**
202         * Get the raw class backing the type {@code T} for this key.
203         *
204         * <p>The distinction is only important if {@code T} is a generic, e.g.
205         * {@code Range<Integer>} since the nested type will be erased.</p>
206         */
207        public final Class<T> getType() {
208            // TODO: remove this; other places should use #getTypeReference() instead
209            return mType;
210        }
211
212        /**
213         * Get the type reference backing the type {@code T} for this key.
214         *
215         * <p>The distinction is only important if {@code T} is a generic, e.g.
216         * {@code Range<Integer>} since the nested type will be retained.</p>
217         */
218        public final TypeReference<T> getTypeReference() {
219            return mTypeReference;
220        }
221    }
222
223    private static final String TAG = "CameraMetadataJV";
224    private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
225    // this should be in sync with HAL_PIXEL_FORMAT_BLOB defined in graphics.h
226    public static final int NATIVE_JPEG_FORMAT = 0x21;
227
228    private static final String CELLID_PROCESS = "CELLID";
229    private static final String GPS_PROCESS = "GPS";
230    private static final int FACE_LANDMARK_SIZE = 6;
231
232    private static String translateLocationProviderToProcess(final String provider) {
233        if (provider == null) {
234            return null;
235        }
236        switch(provider) {
237            case LocationManager.GPS_PROVIDER:
238                return GPS_PROCESS;
239            case LocationManager.NETWORK_PROVIDER:
240                return CELLID_PROCESS;
241            default:
242                return null;
243        }
244    }
245
246    private static String translateProcessToLocationProvider(final String process) {
247        if (process == null) {
248            return null;
249        }
250        switch(process) {
251            case GPS_PROCESS:
252                return LocationManager.GPS_PROVIDER;
253            case CELLID_PROCESS:
254                return LocationManager.NETWORK_PROVIDER;
255            default:
256                return null;
257        }
258    }
259
260    public CameraMetadataNative() {
261        super();
262        mMetadataPtr = nativeAllocate();
263        if (mMetadataPtr == 0) {
264            throw new OutOfMemoryError("Failed to allocate native CameraMetadata");
265        }
266    }
267
268    /**
269     * Copy constructor - clone metadata
270     */
271    public CameraMetadataNative(CameraMetadataNative other) {
272        super();
273        mMetadataPtr = nativeAllocateCopy(other);
274        if (mMetadataPtr == 0) {
275            throw new OutOfMemoryError("Failed to allocate native CameraMetadata");
276        }
277    }
278
279    /**
280     * Move the contents from {@code other} into a new camera metadata instance.</p>
281     *
282     * <p>After this call, {@code other} will become empty.</p>
283     *
284     * @param other the previous metadata instance which will get pilfered
285     * @return a new metadata instance with the values from {@code other} moved into it
286     */
287    public static CameraMetadataNative move(CameraMetadataNative other) {
288        CameraMetadataNative newObject = new CameraMetadataNative();
289        newObject.swap(other);
290        return newObject;
291    }
292
293    public static final Parcelable.Creator<CameraMetadataNative> CREATOR =
294            new Parcelable.Creator<CameraMetadataNative>() {
295        @Override
296        public CameraMetadataNative createFromParcel(Parcel in) {
297            CameraMetadataNative metadata = new CameraMetadataNative();
298            metadata.readFromParcel(in);
299            return metadata;
300        }
301
302        @Override
303        public CameraMetadataNative[] newArray(int size) {
304            return new CameraMetadataNative[size];
305        }
306    };
307
308    @Override
309    public int describeContents() {
310        return 0;
311    }
312
313    @Override
314    public void writeToParcel(Parcel dest, int flags) {
315        nativeWriteToParcel(dest);
316    }
317
318    /**
319     * @hide
320     */
321    public <T> T get(CameraCharacteristics.Key<T> key) {
322        return get(key.getNativeKey());
323    }
324
325    /**
326     * @hide
327     */
328    public <T> T get(CaptureResult.Key<T> key) {
329        return get(key.getNativeKey());
330    }
331
332    /**
333     * @hide
334     */
335    public <T> T get(CaptureRequest.Key<T> key) {
336        return get(key.getNativeKey());
337    }
338
339    /**
340     * Look-up a metadata field value by its key.
341     *
342     * @param key a non-{@code null} key instance
343     * @return the field corresponding to the {@code key}, or {@code null} if no value was set
344     */
345    public <T> T get(Key<T> key) {
346        Preconditions.checkNotNull(key, "key must not be null");
347
348        // Check if key has been overridden to use a wrapper class on the java side.
349        GetCommand g = sGetCommandMap.get(key);
350        if (g != null) {
351            return g.getValue(this, key);
352        }
353        return getBase(key);
354    }
355
356    public void readFromParcel(Parcel in) {
357        nativeReadFromParcel(in);
358    }
359
360    /**
361     * Set the global client-side vendor tag descriptor to allow use of vendor
362     * tags in camera applications.
363     *
364     * @return int A native status_t value corresponding to one of the
365     * {@link CameraBinderDecorator} integer constants.
366     * @see CameraBinderDecorator#throwOnError
367     *
368     * @hide
369     */
370    public static native int nativeSetupGlobalVendorTagDescriptor();
371
372    /**
373     * Set a camera metadata field to a value. The field definitions can be
374     * found in {@link CameraCharacteristics}, {@link CaptureResult}, and
375     * {@link CaptureRequest}.
376     *
377     * @param key The metadata field to write.
378     * @param value The value to set the field to, which must be of a matching
379     * type to the key.
380     */
381    public <T> void set(Key<T> key, T value) {
382        SetCommand s = sSetCommandMap.get(key);
383        if (s != null) {
384            s.setValue(this, value);
385            return;
386        }
387
388        setBase(key, value);
389    }
390
391    public <T> void set(CaptureRequest.Key<T> key, T value) {
392        set(key.getNativeKey(), value);
393    }
394
395    public <T> void set(CaptureResult.Key<T> key, T value) {
396        set(key.getNativeKey(), value);
397    }
398
399    public <T> void set(CameraCharacteristics.Key<T> key, T value) {
400        set(key.getNativeKey(), value);
401    }
402
403    // Keep up-to-date with camera_metadata.h
404    /**
405     * @hide
406     */
407    public static final int TYPE_BYTE = 0;
408    /**
409     * @hide
410     */
411    public static final int TYPE_INT32 = 1;
412    /**
413     * @hide
414     */
415    public static final int TYPE_FLOAT = 2;
416    /**
417     * @hide
418     */
419    public static final int TYPE_INT64 = 3;
420    /**
421     * @hide
422     */
423    public static final int TYPE_DOUBLE = 4;
424    /**
425     * @hide
426     */
427    public static final int TYPE_RATIONAL = 5;
428    /**
429     * @hide
430     */
431    public static final int NUM_TYPES = 6;
432
433    private void close() {
434        // this sets mMetadataPtr to 0
435        nativeClose();
436        mMetadataPtr = 0; // set it to 0 again to prevent eclipse from making this field final
437    }
438
439    private <T> T getBase(CameraCharacteristics.Key<T> key) {
440        return getBase(key.getNativeKey());
441    }
442
443    private <T> T getBase(CaptureResult.Key<T> key) {
444        return getBase(key.getNativeKey());
445    }
446
447    private <T> T getBase(CaptureRequest.Key<T> key) {
448        return getBase(key.getNativeKey());
449    }
450
451    private <T> T getBase(Key<T> key) {
452        int tag = key.getTag();
453        byte[] values = readValues(tag);
454        if (values == null) {
455            return null;
456        }
457
458        Marshaler<T> marshaler = getMarshalerForKey(key);
459        ByteBuffer buffer = ByteBuffer.wrap(values).order(ByteOrder.nativeOrder());
460        return marshaler.unmarshal(buffer);
461    }
462
463    // Use Command pattern here to avoid lots of expensive if/equals checks in get for overridden
464    // metadata.
465    private static final HashMap<Key<?>, GetCommand> sGetCommandMap =
466            new HashMap<Key<?>, GetCommand>();
467    static {
468        sGetCommandMap.put(
469                CameraCharacteristics.SCALER_AVAILABLE_FORMATS.getNativeKey(), new GetCommand() {
470                    @Override
471                    @SuppressWarnings("unchecked")
472                    public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
473                        return (T) metadata.getAvailableFormats();
474                    }
475                });
476        sGetCommandMap.put(
477                CaptureResult.STATISTICS_FACES.getNativeKey(), new GetCommand() {
478                    @Override
479                    @SuppressWarnings("unchecked")
480                    public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
481                        return (T) metadata.getFaces();
482                    }
483                });
484        sGetCommandMap.put(
485                CaptureResult.STATISTICS_FACE_RECTANGLES.getNativeKey(), new GetCommand() {
486                    @Override
487                    @SuppressWarnings("unchecked")
488                    public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
489                        return (T) metadata.getFaceRectangles();
490                    }
491                });
492        sGetCommandMap.put(
493                CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP.getNativeKey(),
494                        new GetCommand() {
495                    @Override
496                    @SuppressWarnings("unchecked")
497                    public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
498                        return (T) metadata.getStreamConfigurationMap();
499                    }
500                });
501        sGetCommandMap.put(
502                CameraCharacteristics.CONTROL_MAX_REGIONS_AE.getNativeKey(), new GetCommand() {
503                    @Override
504                    @SuppressWarnings("unchecked")
505                    public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
506                        return (T) metadata.getMaxRegions(key);
507                    }
508                });
509        sGetCommandMap.put(
510                CameraCharacteristics.CONTROL_MAX_REGIONS_AWB.getNativeKey(), new GetCommand() {
511                    @Override
512                    @SuppressWarnings("unchecked")
513                    public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
514                        return (T) metadata.getMaxRegions(key);
515                    }
516                });
517        sGetCommandMap.put(
518                CameraCharacteristics.CONTROL_MAX_REGIONS_AF.getNativeKey(), new GetCommand() {
519                    @Override
520                    @SuppressWarnings("unchecked")
521                    public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
522                        return (T) metadata.getMaxRegions(key);
523                    }
524                });
525        sGetCommandMap.put(
526                CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_RAW.getNativeKey(), new GetCommand() {
527                    @Override
528                    @SuppressWarnings("unchecked")
529                    public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
530                        return (T) metadata.getMaxNumOutputs(key);
531                    }
532                });
533        sGetCommandMap.put(
534                CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC.getNativeKey(), new GetCommand() {
535                    @Override
536                    @SuppressWarnings("unchecked")
537                    public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
538                        return (T) metadata.getMaxNumOutputs(key);
539                    }
540                });
541        sGetCommandMap.put(
542                CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC_STALLING.getNativeKey(),
543                        new GetCommand() {
544                    @Override
545                    @SuppressWarnings("unchecked")
546                    public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
547                        return (T) metadata.getMaxNumOutputs(key);
548                    }
549                });
550        sGetCommandMap.put(
551                CaptureRequest.TONEMAP_CURVE.getNativeKey(), new GetCommand() {
552                    @Override
553                    @SuppressWarnings("unchecked")
554                    public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
555                        return (T) metadata.getTonemapCurve();
556                    }
557                });
558        sGetCommandMap.put(
559                CaptureResult.JPEG_GPS_LOCATION.getNativeKey(), new GetCommand() {
560                    @Override
561                    @SuppressWarnings("unchecked")
562                    public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
563                        return (T) metadata.getGpsLocation();
564                    }
565                });
566        sGetCommandMap.put(
567                CaptureResult.STATISTICS_LENS_SHADING_CORRECTION_MAP.getNativeKey(),
568                        new GetCommand() {
569                    @Override
570                    @SuppressWarnings("unchecked")
571                    public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
572                        return (T) metadata.getLensShadingMap();
573                    }
574                });
575    }
576
577    private int[] getAvailableFormats() {
578        int[] availableFormats = getBase(CameraCharacteristics.SCALER_AVAILABLE_FORMATS);
579        if (availableFormats != null) {
580            for (int i = 0; i < availableFormats.length; i++) {
581                // JPEG has different value between native and managed side, need override.
582                if (availableFormats[i] == NATIVE_JPEG_FORMAT) {
583                    availableFormats[i] = ImageFormat.JPEG;
584                }
585            }
586        }
587
588        return availableFormats;
589    }
590
591    private boolean setFaces(Face[] faces) {
592        if (faces == null) {
593            return false;
594        }
595
596        int numFaces = faces.length;
597
598        // Detect if all faces are SIMPLE or not; count # of valid faces
599        boolean fullMode = true;
600        for (Face face : faces) {
601            if (face == null) {
602                numFaces--;
603                Log.w(TAG, "setFaces - null face detected, skipping");
604                continue;
605            }
606
607            if (face.getId() == Face.ID_UNSUPPORTED) {
608                fullMode = false;
609            }
610        }
611
612        Rect[] faceRectangles = new Rect[numFaces];
613        byte[] faceScores = new byte[numFaces];
614        int[] faceIds = null;
615        int[] faceLandmarks = null;
616
617        if (fullMode) {
618            faceIds = new int[numFaces];
619            faceLandmarks = new int[numFaces * FACE_LANDMARK_SIZE];
620        }
621
622        int i = 0;
623        for (Face face : faces) {
624            if (face == null) {
625                continue;
626            }
627
628            faceRectangles[i] = face.getBounds();
629            faceScores[i] = (byte)face.getScore();
630
631            if (fullMode) {
632                faceIds[i] = face.getId();
633
634                int j = 0;
635
636                faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getLeftEyePosition().x;
637                faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getLeftEyePosition().y;
638                faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getRightEyePosition().x;
639                faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getRightEyePosition().y;
640                faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getMouthPosition().x;
641                faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getMouthPosition().y;
642            }
643
644            i++;
645        }
646
647        set(CaptureResult.STATISTICS_FACE_RECTANGLES, faceRectangles);
648        set(CaptureResult.STATISTICS_FACE_IDS, faceIds);
649        set(CaptureResult.STATISTICS_FACE_LANDMARKS, faceLandmarks);
650        set(CaptureResult.STATISTICS_FACE_SCORES, faceScores);
651
652        return true;
653    }
654
655    private Face[] getFaces() {
656        Integer faceDetectMode = get(CaptureResult.STATISTICS_FACE_DETECT_MODE);
657        byte[] faceScores = get(CaptureResult.STATISTICS_FACE_SCORES);
658        Rect[] faceRectangles = get(CaptureResult.STATISTICS_FACE_RECTANGLES);
659        int[] faceIds = get(CaptureResult.STATISTICS_FACE_IDS);
660        int[] faceLandmarks = get(CaptureResult.STATISTICS_FACE_LANDMARKS);
661
662        if (areValuesAllNull(faceDetectMode, faceScores, faceRectangles, faceIds, faceLandmarks)) {
663            return null;
664        }
665
666        if (faceDetectMode == null) {
667            Log.w(TAG, "Face detect mode metadata is null, assuming the mode is SIMPLE");
668            faceDetectMode = CaptureResult.STATISTICS_FACE_DETECT_MODE_SIMPLE;
669        } else {
670            if (faceDetectMode == CaptureResult.STATISTICS_FACE_DETECT_MODE_OFF) {
671                return new Face[0];
672            }
673            if (faceDetectMode != CaptureResult.STATISTICS_FACE_DETECT_MODE_SIMPLE &&
674                    faceDetectMode != CaptureResult.STATISTICS_FACE_DETECT_MODE_FULL) {
675                Log.w(TAG, "Unknown face detect mode: " + faceDetectMode);
676                return new Face[0];
677            }
678        }
679
680        // Face scores and rectangles are required by SIMPLE and FULL mode.
681        if (faceScores == null || faceRectangles == null) {
682            Log.w(TAG, "Expect face scores and rectangles to be non-null");
683            return new Face[0];
684        } else if (faceScores.length != faceRectangles.length) {
685            Log.w(TAG, String.format("Face score size(%d) doesn match face rectangle size(%d)!",
686                    faceScores.length, faceRectangles.length));
687        }
688
689        // To be safe, make number of faces is the minimal of all face info metadata length.
690        int numFaces = Math.min(faceScores.length, faceRectangles.length);
691        // Face id and landmarks are only required by FULL mode.
692        if (faceDetectMode == CaptureResult.STATISTICS_FACE_DETECT_MODE_FULL) {
693            if (faceIds == null || faceLandmarks == null) {
694                Log.w(TAG, "Expect face ids and landmarks to be non-null for FULL mode," +
695                        "fallback to SIMPLE mode");
696                faceDetectMode = CaptureResult.STATISTICS_FACE_DETECT_MODE_SIMPLE;
697            } else {
698                if (faceIds.length != numFaces ||
699                        faceLandmarks.length != numFaces * FACE_LANDMARK_SIZE) {
700                    Log.w(TAG, String.format("Face id size(%d), or face landmark size(%d) don't" +
701                            "match face number(%d)!",
702                            faceIds.length, faceLandmarks.length * FACE_LANDMARK_SIZE, numFaces));
703                }
704                // To be safe, make number of faces is the minimal of all face info metadata length.
705                numFaces = Math.min(numFaces, faceIds.length);
706                numFaces = Math.min(numFaces, faceLandmarks.length / FACE_LANDMARK_SIZE);
707            }
708        }
709
710        ArrayList<Face> faceList = new ArrayList<Face>();
711        if (faceDetectMode == CaptureResult.STATISTICS_FACE_DETECT_MODE_SIMPLE) {
712            for (int i = 0; i < numFaces; i++) {
713                if (faceScores[i] <= Face.SCORE_MAX &&
714                        faceScores[i] >= Face.SCORE_MIN) {
715                    faceList.add(new Face(faceRectangles[i], faceScores[i]));
716                }
717            }
718        } else {
719            // CaptureResult.STATISTICS_FACE_DETECT_MODE_FULL
720            for (int i = 0; i < numFaces; i++) {
721                if (faceScores[i] <= Face.SCORE_MAX &&
722                        faceScores[i] >= Face.SCORE_MIN &&
723                        faceIds[i] >= 0) {
724                    Point leftEye = new Point(faceLandmarks[i*FACE_LANDMARK_SIZE],
725                            faceLandmarks[i*FACE_LANDMARK_SIZE+1]);
726                    Point rightEye = new Point(faceLandmarks[i*FACE_LANDMARK_SIZE+2],
727                            faceLandmarks[i*FACE_LANDMARK_SIZE+3]);
728                    Point mouth = new Point(faceLandmarks[i*FACE_LANDMARK_SIZE+4],
729                            faceLandmarks[i*FACE_LANDMARK_SIZE+5]);
730                    Face face = new Face(faceRectangles[i], faceScores[i], faceIds[i],
731                            leftEye, rightEye, mouth);
732                    faceList.add(face);
733                }
734            }
735        }
736        Face[] faces = new Face[faceList.size()];
737        faceList.toArray(faces);
738        return faces;
739    }
740
741    // Face rectangles are defined as (left, top, right, bottom) instead of
742    // (left, top, width, height) at the native level, so the normal Rect
743    // conversion that does (l, t, w, h) -> (l, t, r, b) is unnecessary. Undo
744    // that conversion here for just the faces.
745    private Rect[] getFaceRectangles() {
746        Rect[] faceRectangles = getBase(CaptureResult.STATISTICS_FACE_RECTANGLES);
747        if (faceRectangles == null) return null;
748
749        Rect[] fixedFaceRectangles = new Rect[faceRectangles.length];
750        for (int i = 0; i < faceRectangles.length; i++) {
751            fixedFaceRectangles[i] = new Rect(
752                    faceRectangles[i].left,
753                    faceRectangles[i].top,
754                    faceRectangles[i].right - faceRectangles[i].left,
755                    faceRectangles[i].bottom - faceRectangles[i].top);
756        }
757        return fixedFaceRectangles;
758    }
759
760    private LensShadingMap getLensShadingMap() {
761        float[] lsmArray = getBase(CaptureResult.STATISTICS_LENS_SHADING_MAP);
762        Size s = get(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE);
763
764        // Do not warn if lsmArray is null while s is not. This is valid.
765        if (lsmArray == null) {
766            return null;
767        }
768
769        if (s == null) {
770            Log.w(TAG, "getLensShadingMap - Lens shading map size was null.");
771            return null;
772        }
773
774        LensShadingMap map = new LensShadingMap(lsmArray, s.getHeight(), s.getWidth());
775        return map;
776    }
777
778    private Location getGpsLocation() {
779        String processingMethod = get(CaptureResult.JPEG_GPS_PROCESSING_METHOD);
780        double[] coords = get(CaptureResult.JPEG_GPS_COORDINATES);
781        Long timeStamp = get(CaptureResult.JPEG_GPS_TIMESTAMP);
782
783        if (areValuesAllNull(processingMethod, coords, timeStamp)) {
784            return null;
785        }
786
787        Location l = new Location(translateProcessToLocationProvider(processingMethod));
788        if (timeStamp != null) {
789            l.setTime(timeStamp);
790        } else {
791            Log.w(TAG, "getGpsLocation - No timestamp for GPS location.");
792        }
793
794        if (coords != null) {
795            l.setLatitude(coords[0]);
796            l.setLongitude(coords[1]);
797            l.setAltitude(coords[2]);
798        } else {
799            Log.w(TAG, "getGpsLocation - No coordinates for GPS location");
800        }
801
802        return l;
803    }
804
805    private boolean setGpsLocation(Location l) {
806        if (l == null) {
807            return false;
808        }
809
810        double[] coords = { l.getLatitude(), l.getLongitude(), l.getAltitude() };
811        String processMethod = translateLocationProviderToProcess(l.getProvider());
812        long timestamp = l.getTime();
813
814        set(CaptureRequest.JPEG_GPS_TIMESTAMP, timestamp);
815        set(CaptureRequest.JPEG_GPS_COORDINATES, coords);
816
817        if (processMethod == null) {
818            Log.w(TAG, "setGpsLocation - No process method, Location is not from a GPS or NETWORK" +
819                    "provider");
820        } else {
821            setBase(CaptureRequest.JPEG_GPS_PROCESSING_METHOD, processMethod);
822        }
823        return true;
824    }
825
826    private StreamConfigurationMap getStreamConfigurationMap() {
827        StreamConfiguration[] configurations = getBase(
828                CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
829        StreamConfigurationDuration[] minFrameDurations = getBase(
830                CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS);
831        StreamConfigurationDuration[] stallDurations = getBase(
832                CameraCharacteristics.SCALER_AVAILABLE_STALL_DURATIONS);
833        HighSpeedVideoConfiguration[] highSpeedVideoConfigurations = getBase(
834                CameraCharacteristics.CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS);
835
836        return new StreamConfigurationMap(
837                configurations, minFrameDurations, stallDurations, highSpeedVideoConfigurations);
838    }
839
840    private <T> Integer getMaxRegions(Key<T> key) {
841        final int AE = 0;
842        final int AWB = 1;
843        final int AF = 2;
844
845        // The order of the elements is: (AE, AWB, AF)
846        int[] maxRegions = getBase(CameraCharacteristics.CONTROL_MAX_REGIONS);
847
848        if (maxRegions == null) {
849            return null;
850        }
851
852        if (key.equals(CameraCharacteristics.CONTROL_MAX_REGIONS_AE)) {
853            return maxRegions[AE];
854        } else if (key.equals(CameraCharacteristics.CONTROL_MAX_REGIONS_AWB)) {
855            return maxRegions[AWB];
856        } else if (key.equals(CameraCharacteristics.CONTROL_MAX_REGIONS_AF)) {
857            return maxRegions[AF];
858        } else {
859            throw new AssertionError("Invalid key " + key);
860        }
861    }
862
863    private <T> Integer getMaxNumOutputs(Key<T> key) {
864        final int RAW = 0;
865        final int PROC = 1;
866        final int PROC_STALLING = 2;
867
868        // The order of the elements is: (raw, proc+nonstalling, proc+stalling)
869        int[] maxNumOutputs = getBase(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_STREAMS);
870
871        if (maxNumOutputs == null) {
872            return null;
873        }
874
875        if (key.equals(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_RAW)) {
876            return maxNumOutputs[RAW];
877        } else if (key.equals(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC)) {
878            return maxNumOutputs[PROC];
879        } else if (key.equals(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC_STALLING)) {
880            return maxNumOutputs[PROC_STALLING];
881        } else {
882            throw new AssertionError("Invalid key " + key);
883        }
884    }
885
886    private <T> TonemapCurve getTonemapCurve() {
887        float[] red = getBase(CaptureRequest.TONEMAP_CURVE_RED);
888        float[] green = getBase(CaptureRequest.TONEMAP_CURVE_GREEN);
889        float[] blue = getBase(CaptureRequest.TONEMAP_CURVE_BLUE);
890
891        if (areValuesAllNull(red, green, blue)) {
892            return null;
893        }
894
895        if (red == null || green == null || blue == null) {
896            Log.w(TAG, "getTonemapCurve - missing tone curve components");
897            return null;
898        }
899        TonemapCurve tc = new TonemapCurve(red, green, blue);
900        return tc;
901    }
902
903    private <T> void setBase(CameraCharacteristics.Key<T> key, T value) {
904        setBase(key.getNativeKey(), value);
905    }
906
907    private <T> void setBase(CaptureResult.Key<T> key, T value) {
908        setBase(key.getNativeKey(), value);
909    }
910
911    private <T> void setBase(CaptureRequest.Key<T> key, T value) {
912        setBase(key.getNativeKey(), value);
913    }
914
915    private <T> void setBase(Key<T> key, T value) {
916        int tag = key.getTag();
917
918        if (value == null) {
919            // Erase the entry
920            writeValues(tag, /*src*/null);
921            return;
922        } // else update the entry to a new value
923
924        Marshaler<T> marshaler = getMarshalerForKey(key);
925        int size = marshaler.calculateMarshalSize(value);
926
927        // TODO: Optimization. Cache the byte[] and reuse if the size is big enough.
928        byte[] values = new byte[size];
929
930        ByteBuffer buffer = ByteBuffer.wrap(values).order(ByteOrder.nativeOrder());
931        marshaler.marshal(value, buffer);
932
933        writeValues(tag, values);
934    }
935
936    // Use Command pattern here to avoid lots of expensive if/equals checks in get for overridden
937    // metadata.
938    private static final HashMap<Key<?>, SetCommand> sSetCommandMap =
939            new HashMap<Key<?>, SetCommand>();
940    static {
941        sSetCommandMap.put(CameraCharacteristics.SCALER_AVAILABLE_FORMATS.getNativeKey(),
942                new SetCommand() {
943            @Override
944            public <T> void setValue(CameraMetadataNative metadata, T value) {
945                metadata.setAvailableFormats((int[]) value);
946            }
947        });
948        sSetCommandMap.put(CaptureResult.STATISTICS_FACE_RECTANGLES.getNativeKey(),
949                new SetCommand() {
950            @Override
951            public <T> void setValue(CameraMetadataNative metadata, T value) {
952                metadata.setFaceRectangles((Rect[]) value);
953            }
954        });
955        sSetCommandMap.put(CaptureResult.STATISTICS_FACES.getNativeKey(),
956                new SetCommand() {
957            @Override
958            public <T> void setValue(CameraMetadataNative metadata, T value) {
959                metadata.setFaces((Face[])value);
960            }
961        });
962        sSetCommandMap.put(CaptureRequest.TONEMAP_CURVE.getNativeKey(), new SetCommand() {
963            @Override
964            public <T> void setValue(CameraMetadataNative metadata, T value) {
965                metadata.setTonemapCurve((TonemapCurve) value);
966            }
967        });
968        sSetCommandMap.put(CaptureResult.JPEG_GPS_LOCATION.getNativeKey(), new SetCommand() {
969            @Override
970            public <T> void setValue(CameraMetadataNative metadata, T value) {
971                metadata.setGpsLocation((Location) value);
972            }
973        });
974    }
975
976    private boolean setAvailableFormats(int[] value) {
977        int[] availableFormat = value;
978        if (value == null) {
979            // Let setBase() to handle the null value case.
980            return false;
981        }
982
983        int[] newValues = new int[availableFormat.length];
984        for (int i = 0; i < availableFormat.length; i++) {
985            newValues[i] = availableFormat[i];
986            if (availableFormat[i] == ImageFormat.JPEG) {
987                newValues[i] = NATIVE_JPEG_FORMAT;
988            }
989        }
990
991        setBase(CameraCharacteristics.SCALER_AVAILABLE_FORMATS, newValues);
992        return true;
993    }
994
995    /**
996     * Convert Face Rectangles from managed side to native side as they have different definitions.
997     * <p>
998     * Managed side face rectangles are defined as: left, top, width, height.
999     * Native side face rectangles are defined as: left, top, right, bottom.
1000     * The input face rectangle need to be converted to native side definition when set is called.
1001     * </p>
1002     *
1003     * @param faceRects Input face rectangles.
1004     * @return true if face rectangles can be set successfully. Otherwise, Let the caller
1005     *             (setBase) to handle it appropriately.
1006     */
1007    private boolean setFaceRectangles(Rect[] faceRects) {
1008        if (faceRects == null) {
1009            return false;
1010        }
1011
1012        Rect[] newFaceRects = new Rect[faceRects.length];
1013        for (int i = 0; i < newFaceRects.length; i++) {
1014            newFaceRects[i] = new Rect(
1015                    faceRects[i].left,
1016                    faceRects[i].top,
1017                    faceRects[i].right + faceRects[i].left,
1018                    faceRects[i].bottom + faceRects[i].top);
1019        }
1020
1021        setBase(CaptureResult.STATISTICS_FACE_RECTANGLES, newFaceRects);
1022        return true;
1023    }
1024
1025    private <T> boolean setTonemapCurve(TonemapCurve tc) {
1026        if (tc == null) {
1027            return false;
1028        }
1029
1030        float[][] curve = new float[3][];
1031        for (int i = TonemapCurve.CHANNEL_RED; i <= TonemapCurve.CHANNEL_BLUE; i++) {
1032            int pointCount = tc.getPointCount(i);
1033            curve[i] = new float[pointCount * TonemapCurve.POINT_SIZE];
1034            tc.copyColorCurve(i, curve[i], 0);
1035        }
1036        setBase(CaptureRequest.TONEMAP_CURVE_RED, curve[0]);
1037        setBase(CaptureRequest.TONEMAP_CURVE_GREEN, curve[1]);
1038        setBase(CaptureRequest.TONEMAP_CURVE_BLUE, curve[2]);
1039
1040        return true;
1041    }
1042
1043    private long mMetadataPtr; // native CameraMetadata*
1044
1045    private native long nativeAllocate();
1046    private native long nativeAllocateCopy(CameraMetadataNative other)
1047            throws NullPointerException;
1048
1049    private native synchronized void nativeWriteToParcel(Parcel dest);
1050    private native synchronized void nativeReadFromParcel(Parcel source);
1051    private native synchronized void nativeSwap(CameraMetadataNative other)
1052            throws NullPointerException;
1053    private native synchronized void nativeClose();
1054    private native synchronized boolean nativeIsEmpty();
1055    private native synchronized int nativeGetEntryCount();
1056
1057    private native synchronized byte[] nativeReadValues(int tag);
1058    private native synchronized void nativeWriteValues(int tag, byte[] src);
1059    private native synchronized void nativeDump() throws IOException; // dump to ALOGD
1060
1061    private static native int nativeGetTagFromKey(String keyName)
1062            throws IllegalArgumentException;
1063    private static native int nativeGetTypeFromTag(int tag)
1064            throws IllegalArgumentException;
1065    private static native void nativeClassInit();
1066
1067    /**
1068     * <p>Perform a 0-copy swap of the internal metadata with another object.</p>
1069     *
1070     * <p>Useful to convert a CameraMetadata into e.g. a CaptureRequest.</p>
1071     *
1072     * @param other Metadata to swap with
1073     * @throws NullPointerException if other was null
1074     * @hide
1075     */
1076    public void swap(CameraMetadataNative other) {
1077        nativeSwap(other);
1078    }
1079
1080    /**
1081     * @hide
1082     */
1083    public int getEntryCount() {
1084        return nativeGetEntryCount();
1085    }
1086
1087    /**
1088     * Does this metadata contain at least 1 entry?
1089     *
1090     * @hide
1091     */
1092    public boolean isEmpty() {
1093        return nativeIsEmpty();
1094    }
1095
1096    /**
1097     * Convert a key string into the equivalent native tag.
1098     *
1099     * @throws IllegalArgumentException if the key was not recognized
1100     * @throws NullPointerException if the key was null
1101     *
1102     * @hide
1103     */
1104    public static int getTag(String key) {
1105        return nativeGetTagFromKey(key);
1106    }
1107
1108    /**
1109     * Get the underlying native type for a tag.
1110     *
1111     * @param tag An integer tag, see e.g. {@link #getTag}
1112     * @return An int enum for the metadata type, see e.g. {@link #TYPE_BYTE}
1113     *
1114     * @hide
1115     */
1116    public static int getNativeType(int tag) {
1117        return nativeGetTypeFromTag(tag);
1118    }
1119
1120    /**
1121     * <p>Updates the existing entry for tag with the new bytes pointed by src, erasing
1122     * the entry if src was null.</p>
1123     *
1124     * <p>An empty array can be passed in to update the entry to 0 elements.</p>
1125     *
1126     * @param tag An integer tag, see e.g. {@link #getTag}
1127     * @param src An array of bytes, or null to erase the entry
1128     *
1129     * @hide
1130     */
1131    public void writeValues(int tag, byte[] src) {
1132        nativeWriteValues(tag, src);
1133    }
1134
1135    /**
1136     * <p>Returns a byte[] of data corresponding to this tag. Use a wrapped bytebuffer to unserialize
1137     * the data properly.</p>
1138     *
1139     * <p>An empty array can be returned to denote an existing entry with 0 elements.</p>
1140     *
1141     * @param tag An integer tag, see e.g. {@link #getTag}
1142     *
1143     * @return {@code null} if there were 0 entries for this tag, a byte[] otherwise.
1144     * @hide
1145     */
1146    public byte[] readValues(int tag) {
1147        // TODO: Optimization. Native code returns a ByteBuffer instead.
1148        return nativeReadValues(tag);
1149    }
1150
1151    /**
1152     * Dumps the native metadata contents to logcat.
1153     *
1154     * <p>Visibility for testing/debugging only. The results will not
1155     * include any synthesized keys, as they are invisible to the native layer.</p>
1156     *
1157     * @hide
1158     */
1159    public void dumpToLog() {
1160        try {
1161            nativeDump();
1162        } catch (IOException e) {
1163            Log.wtf(TAG, "Dump logging failed", e);
1164        }
1165    }
1166
1167    @Override
1168    protected void finalize() throws Throwable {
1169        try {
1170            close();
1171        } finally {
1172            super.finalize();
1173        }
1174    }
1175
1176    /**
1177     * Get the marshaler compatible with the {@code key} and type {@code T}.
1178     *
1179     * @throws UnsupportedOperationException
1180     *          if the native/managed type combination for {@code key} is not supported
1181     */
1182    private static <T> Marshaler<T> getMarshalerForKey(Key<T> key) {
1183        return MarshalRegistry.getMarshaler(key.getTypeReference(),
1184                getNativeType(key.getTag()));
1185    }
1186
1187    @SuppressWarnings({ "unchecked", "rawtypes" })
1188    private static void registerAllMarshalers() {
1189        if (VERBOSE) {
1190            Log.v(TAG, "Shall register metadata marshalers");
1191        }
1192
1193        MarshalQueryable[] queryList = new MarshalQueryable[] {
1194                // marshalers for standard types
1195                new MarshalQueryablePrimitive(),
1196                new MarshalQueryableEnum(),
1197                new MarshalQueryableArray(),
1198
1199                // pseudo standard types, that expand/narrow the native type into a managed type
1200                new MarshalQueryableBoolean(),
1201                new MarshalQueryableNativeByteToInteger(),
1202
1203                // marshalers for custom types
1204                new MarshalQueryableRect(),
1205                new MarshalQueryableSize(),
1206                new MarshalQueryableSizeF(),
1207                new MarshalQueryableString(),
1208                new MarshalQueryableReprocessFormatsMap(),
1209                new MarshalQueryableRange(),
1210                new MarshalQueryablePair(),
1211                new MarshalQueryableMeteringRectangle(),
1212                new MarshalQueryableColorSpaceTransform(),
1213                new MarshalQueryableStreamConfiguration(),
1214                new MarshalQueryableStreamConfigurationDuration(),
1215                new MarshalQueryableRggbChannelVector(),
1216                new MarshalQueryableBlackLevelPattern(),
1217                new MarshalQueryableHighSpeedVideoConfiguration(),
1218
1219                // generic parcelable marshaler (MUST BE LAST since it has lowest priority)
1220                new MarshalQueryableParcelable(),
1221        };
1222
1223        for (MarshalQueryable query : queryList) {
1224            MarshalRegistry.registerMarshalQueryable(query);
1225        }
1226        if (VERBOSE) {
1227            Log.v(TAG, "Registered metadata marshalers");
1228        }
1229    }
1230
1231    /** Check if input arguments are all {@code null}.
1232     *
1233     * @param objs Input arguments for null check
1234     * @return {@code true} if input arguments are all {@code null}, otherwise {@code false}
1235     */
1236    private static boolean areValuesAllNull(Object... objs) {
1237        for (Object o : objs) {
1238            if (o != null) return false;
1239        }
1240        return true;
1241    }
1242
1243    static {
1244        /*
1245         * We use a class initializer to allow the native code to cache some field offsets
1246         */
1247        nativeClassInit();
1248        registerAllMarshalers();
1249    }
1250}
1251