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