CameraMetadataNative.java revision 0a551f1487e00a598b20b1bc58a1ccd7226e7091
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.ReprocessFormatsMap;
52import android.hardware.camera2.params.StreamConfiguration;
53import android.hardware.camera2.params.StreamConfigurationDuration;
54import android.hardware.camera2.params.StreamConfigurationMap;
55import android.hardware.camera2.params.TonemapCurve;
56import android.hardware.camera2.utils.TypeReference;
57import android.location.Location;
58import android.location.LocationManager;
59import android.os.Parcelable;
60import android.os.Parcel;
61import android.util.Log;
62import android.util.Size;
63
64import com.android.internal.util.Preconditions;
65
66import java.io.IOException;
67import java.nio.ByteBuffer;
68import java.nio.ByteOrder;
69import java.util.ArrayList;
70import java.util.HashMap;
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        byte[] faceScores = get(CaptureResult.STATISTICS_FACE_SCORES);
659        Rect[] faceRectangles = get(CaptureResult.STATISTICS_FACE_RECTANGLES);
660        int[] faceIds = get(CaptureResult.STATISTICS_FACE_IDS);
661        int[] faceLandmarks = get(CaptureResult.STATISTICS_FACE_LANDMARKS);
662
663        if (areValuesAllNull(faceDetectMode, faceScores, faceRectangles, faceIds, faceLandmarks)) {
664            return null;
665        }
666
667        if (faceDetectMode == null) {
668            Log.w(TAG, "Face detect mode metadata is null, assuming the mode is SIMPLE");
669            faceDetectMode = CaptureResult.STATISTICS_FACE_DETECT_MODE_SIMPLE;
670        } else {
671            if (faceDetectMode == CaptureResult.STATISTICS_FACE_DETECT_MODE_OFF) {
672                return new Face[0];
673            }
674            if (faceDetectMode != CaptureResult.STATISTICS_FACE_DETECT_MODE_SIMPLE &&
675                    faceDetectMode != CaptureResult.STATISTICS_FACE_DETECT_MODE_FULL) {
676                Log.w(TAG, "Unknown face detect mode: " + faceDetectMode);
677                return new Face[0];
678            }
679        }
680
681        // Face scores and rectangles are required by SIMPLE and FULL mode.
682        if (faceScores == null || faceRectangles == null) {
683            Log.w(TAG, "Expect face scores and rectangles to be non-null");
684            return new Face[0];
685        } else if (faceScores.length != faceRectangles.length) {
686            Log.w(TAG, String.format("Face score size(%d) doesn match face rectangle size(%d)!",
687                    faceScores.length, faceRectangles.length));
688        }
689
690        // To be safe, make number of faces is the minimal of all face info metadata length.
691        int numFaces = Math.min(faceScores.length, faceRectangles.length);
692        // Face id and landmarks are only required by FULL mode.
693        if (faceDetectMode == CaptureResult.STATISTICS_FACE_DETECT_MODE_FULL) {
694            if (faceIds == null || faceLandmarks == null) {
695                Log.w(TAG, "Expect face ids and landmarks to be non-null for FULL mode," +
696                        "fallback to SIMPLE mode");
697                faceDetectMode = CaptureResult.STATISTICS_FACE_DETECT_MODE_SIMPLE;
698            } else {
699                if (faceIds.length != numFaces ||
700                        faceLandmarks.length != numFaces * FACE_LANDMARK_SIZE) {
701                    Log.w(TAG, String.format("Face id size(%d), or face landmark size(%d) don't" +
702                            "match face number(%d)!",
703                            faceIds.length, faceLandmarks.length * FACE_LANDMARK_SIZE, numFaces));
704                }
705                // To be safe, make number of faces is the minimal of all face info metadata length.
706                numFaces = Math.min(numFaces, faceIds.length);
707                numFaces = Math.min(numFaces, faceLandmarks.length / FACE_LANDMARK_SIZE);
708            }
709        }
710
711        ArrayList<Face> faceList = new ArrayList<Face>();
712        if (faceDetectMode == CaptureResult.STATISTICS_FACE_DETECT_MODE_SIMPLE) {
713            for (int i = 0; i < numFaces; i++) {
714                if (faceScores[i] <= Face.SCORE_MAX &&
715                        faceScores[i] >= Face.SCORE_MIN) {
716                    faceList.add(new Face(faceRectangles[i], faceScores[i]));
717                }
718            }
719        } else {
720            // CaptureResult.STATISTICS_FACE_DETECT_MODE_FULL
721            for (int i = 0; i < numFaces; i++) {
722                if (faceScores[i] <= Face.SCORE_MAX &&
723                        faceScores[i] >= Face.SCORE_MIN &&
724                        faceIds[i] >= 0) {
725                    Point leftEye = new Point(faceLandmarks[i*FACE_LANDMARK_SIZE],
726                            faceLandmarks[i*FACE_LANDMARK_SIZE+1]);
727                    Point rightEye = new Point(faceLandmarks[i*FACE_LANDMARK_SIZE+2],
728                            faceLandmarks[i*FACE_LANDMARK_SIZE+3]);
729                    Point mouth = new Point(faceLandmarks[i*FACE_LANDMARK_SIZE+4],
730                            faceLandmarks[i*FACE_LANDMARK_SIZE+5]);
731                    Face face = new Face(faceRectangles[i], faceScores[i], faceIds[i],
732                            leftEye, rightEye, mouth);
733                    faceList.add(face);
734                }
735            }
736        }
737        Face[] faces = new Face[faceList.size()];
738        faceList.toArray(faces);
739        return faces;
740    }
741
742    // Face rectangles are defined as (left, top, right, bottom) instead of
743    // (left, top, width, height) at the native level, so the normal Rect
744    // conversion that does (l, t, w, h) -> (l, t, r, b) is unnecessary. Undo
745    // that conversion here for just the faces.
746    private Rect[] getFaceRectangles() {
747        Rect[] faceRectangles = getBase(CaptureResult.STATISTICS_FACE_RECTANGLES);
748        if (faceRectangles == null) return null;
749
750        Rect[] fixedFaceRectangles = new Rect[faceRectangles.length];
751        for (int i = 0; i < faceRectangles.length; i++) {
752            fixedFaceRectangles[i] = new Rect(
753                    faceRectangles[i].left,
754                    faceRectangles[i].top,
755                    faceRectangles[i].right - faceRectangles[i].left,
756                    faceRectangles[i].bottom - faceRectangles[i].top);
757        }
758        return fixedFaceRectangles;
759    }
760
761    private LensShadingMap getLensShadingMap() {
762        float[] lsmArray = getBase(CaptureResult.STATISTICS_LENS_SHADING_MAP);
763        Size s = get(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE);
764
765        // Do not warn if lsmArray is null while s is not. This is valid.
766        if (lsmArray == null) {
767            return null;
768        }
769
770        if (s == null) {
771            Log.w(TAG, "getLensShadingMap - Lens shading map size was null.");
772            return null;
773        }
774
775        LensShadingMap map = new LensShadingMap(lsmArray, s.getHeight(), s.getWidth());
776        return map;
777    }
778
779    private Location getGpsLocation() {
780        String processingMethod = get(CaptureResult.JPEG_GPS_PROCESSING_METHOD);
781        double[] coords = get(CaptureResult.JPEG_GPS_COORDINATES);
782        Long timeStamp = get(CaptureResult.JPEG_GPS_TIMESTAMP);
783
784        if (areValuesAllNull(processingMethod, coords, timeStamp)) {
785            return null;
786        }
787
788        Location l = new Location(translateProcessToLocationProvider(processingMethod));
789        if (timeStamp != null) {
790            l.setTime(timeStamp);
791        } else {
792            Log.w(TAG, "getGpsLocation - No timestamp for GPS location.");
793        }
794
795        if (coords != null) {
796            l.setLatitude(coords[0]);
797            l.setLongitude(coords[1]);
798            l.setAltitude(coords[2]);
799        } else {
800            Log.w(TAG, "getGpsLocation - No coordinates for GPS location");
801        }
802
803        return l;
804    }
805
806    private boolean setGpsLocation(Location l) {
807        if (l == null) {
808            return false;
809        }
810
811        double[] coords = { l.getLatitude(), l.getLongitude(), l.getAltitude() };
812        String processMethod = translateLocationProviderToProcess(l.getProvider());
813        long timestamp = l.getTime();
814
815        set(CaptureRequest.JPEG_GPS_TIMESTAMP, timestamp);
816        set(CaptureRequest.JPEG_GPS_COORDINATES, coords);
817
818        if (processMethod == null) {
819            Log.w(TAG, "setGpsLocation - No process method, Location is not from a GPS or NETWORK" +
820                    "provider");
821        } else {
822            setBase(CaptureRequest.JPEG_GPS_PROCESSING_METHOD, processMethod);
823        }
824        return true;
825    }
826
827    private StreamConfigurationMap getStreamConfigurationMap() {
828        StreamConfiguration[] configurations = getBase(
829                CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
830        StreamConfigurationDuration[] minFrameDurations = getBase(
831                CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS);
832        StreamConfigurationDuration[] stallDurations = getBase(
833                CameraCharacteristics.SCALER_AVAILABLE_STALL_DURATIONS);
834        StreamConfiguration[] depthConfigurations = getBase(
835                CameraCharacteristics.DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS);
836        StreamConfigurationDuration[] depthMinFrameDurations = getBase(
837                CameraCharacteristics.DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS);
838        StreamConfigurationDuration[] depthStallDurations = getBase(
839                CameraCharacteristics.DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS);
840        HighSpeedVideoConfiguration[] highSpeedVideoConfigurations = getBase(
841                CameraCharacteristics.CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS);
842        ReprocessFormatsMap inputOutputFormatsMap = getBase(
843                CameraCharacteristics.SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP);
844
845        return new StreamConfigurationMap(
846                configurations, minFrameDurations, stallDurations,
847                depthConfigurations, depthMinFrameDurations, depthStallDurations,
848                highSpeedVideoConfigurations, inputOutputFormatsMap);
849    }
850
851    private <T> Integer getMaxRegions(Key<T> key) {
852        final int AE = 0;
853        final int AWB = 1;
854        final int AF = 2;
855
856        // The order of the elements is: (AE, AWB, AF)
857        int[] maxRegions = getBase(CameraCharacteristics.CONTROL_MAX_REGIONS);
858
859        if (maxRegions == null) {
860            return null;
861        }
862
863        if (key.equals(CameraCharacteristics.CONTROL_MAX_REGIONS_AE)) {
864            return maxRegions[AE];
865        } else if (key.equals(CameraCharacteristics.CONTROL_MAX_REGIONS_AWB)) {
866            return maxRegions[AWB];
867        } else if (key.equals(CameraCharacteristics.CONTROL_MAX_REGIONS_AF)) {
868            return maxRegions[AF];
869        } else {
870            throw new AssertionError("Invalid key " + key);
871        }
872    }
873
874    private <T> Integer getMaxNumOutputs(Key<T> key) {
875        final int RAW = 0;
876        final int PROC = 1;
877        final int PROC_STALLING = 2;
878
879        // The order of the elements is: (raw, proc+nonstalling, proc+stalling)
880        int[] maxNumOutputs = getBase(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_STREAMS);
881
882        if (maxNumOutputs == null) {
883            return null;
884        }
885
886        if (key.equals(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_RAW)) {
887            return maxNumOutputs[RAW];
888        } else if (key.equals(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC)) {
889            return maxNumOutputs[PROC];
890        } else if (key.equals(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC_STALLING)) {
891            return maxNumOutputs[PROC_STALLING];
892        } else {
893            throw new AssertionError("Invalid key " + key);
894        }
895    }
896
897    private <T> TonemapCurve getTonemapCurve() {
898        float[] red = getBase(CaptureRequest.TONEMAP_CURVE_RED);
899        float[] green = getBase(CaptureRequest.TONEMAP_CURVE_GREEN);
900        float[] blue = getBase(CaptureRequest.TONEMAP_CURVE_BLUE);
901
902        if (areValuesAllNull(red, green, blue)) {
903            return null;
904        }
905
906        if (red == null || green == null || blue == null) {
907            Log.w(TAG, "getTonemapCurve - missing tone curve components");
908            return null;
909        }
910        TonemapCurve tc = new TonemapCurve(red, green, blue);
911        return tc;
912    }
913
914    private <T> void setBase(CameraCharacteristics.Key<T> key, T value) {
915        setBase(key.getNativeKey(), value);
916    }
917
918    private <T> void setBase(CaptureResult.Key<T> key, T value) {
919        setBase(key.getNativeKey(), value);
920    }
921
922    private <T> void setBase(CaptureRequest.Key<T> key, T value) {
923        setBase(key.getNativeKey(), value);
924    }
925
926    private <T> void setBase(Key<T> key, T value) {
927        int tag = key.getTag();
928
929        if (value == null) {
930            // Erase the entry
931            writeValues(tag, /*src*/null);
932            return;
933        } // else update the entry to a new value
934
935        Marshaler<T> marshaler = getMarshalerForKey(key);
936        int size = marshaler.calculateMarshalSize(value);
937
938        // TODO: Optimization. Cache the byte[] and reuse if the size is big enough.
939        byte[] values = new byte[size];
940
941        ByteBuffer buffer = ByteBuffer.wrap(values).order(ByteOrder.nativeOrder());
942        marshaler.marshal(value, buffer);
943
944        writeValues(tag, values);
945    }
946
947    // Use Command pattern here to avoid lots of expensive if/equals checks in get for overridden
948    // metadata.
949    private static final HashMap<Key<?>, SetCommand> sSetCommandMap =
950            new HashMap<Key<?>, SetCommand>();
951    static {
952        sSetCommandMap.put(CameraCharacteristics.SCALER_AVAILABLE_FORMATS.getNativeKey(),
953                new SetCommand() {
954            @Override
955            public <T> void setValue(CameraMetadataNative metadata, T value) {
956                metadata.setAvailableFormats((int[]) value);
957            }
958        });
959        sSetCommandMap.put(CaptureResult.STATISTICS_FACE_RECTANGLES.getNativeKey(),
960                new SetCommand() {
961            @Override
962            public <T> void setValue(CameraMetadataNative metadata, T value) {
963                metadata.setFaceRectangles((Rect[]) value);
964            }
965        });
966        sSetCommandMap.put(CaptureResult.STATISTICS_FACES.getNativeKey(),
967                new SetCommand() {
968            @Override
969            public <T> void setValue(CameraMetadataNative metadata, T value) {
970                metadata.setFaces((Face[])value);
971            }
972        });
973        sSetCommandMap.put(CaptureRequest.TONEMAP_CURVE.getNativeKey(), new SetCommand() {
974            @Override
975            public <T> void setValue(CameraMetadataNative metadata, T value) {
976                metadata.setTonemapCurve((TonemapCurve) value);
977            }
978        });
979        sSetCommandMap.put(CaptureResult.JPEG_GPS_LOCATION.getNativeKey(), new SetCommand() {
980            @Override
981            public <T> void setValue(CameraMetadataNative metadata, T value) {
982                metadata.setGpsLocation((Location) value);
983            }
984        });
985    }
986
987    private boolean setAvailableFormats(int[] value) {
988        int[] availableFormat = value;
989        if (value == null) {
990            // Let setBase() to handle the null value case.
991            return false;
992        }
993
994        int[] newValues = new int[availableFormat.length];
995        for (int i = 0; i < availableFormat.length; i++) {
996            newValues[i] = availableFormat[i];
997            if (availableFormat[i] == ImageFormat.JPEG) {
998                newValues[i] = NATIVE_JPEG_FORMAT;
999            }
1000        }
1001
1002        setBase(CameraCharacteristics.SCALER_AVAILABLE_FORMATS, newValues);
1003        return true;
1004    }
1005
1006    /**
1007     * Convert Face Rectangles from managed side to native side as they have different definitions.
1008     * <p>
1009     * Managed side face rectangles are defined as: left, top, width, height.
1010     * Native side face rectangles are defined as: left, top, right, bottom.
1011     * The input face rectangle need to be converted to native side definition when set is called.
1012     * </p>
1013     *
1014     * @param faceRects Input face rectangles.
1015     * @return true if face rectangles can be set successfully. Otherwise, Let the caller
1016     *             (setBase) to handle it appropriately.
1017     */
1018    private boolean setFaceRectangles(Rect[] faceRects) {
1019        if (faceRects == null) {
1020            return false;
1021        }
1022
1023        Rect[] newFaceRects = new Rect[faceRects.length];
1024        for (int i = 0; i < newFaceRects.length; i++) {
1025            newFaceRects[i] = new Rect(
1026                    faceRects[i].left,
1027                    faceRects[i].top,
1028                    faceRects[i].right + faceRects[i].left,
1029                    faceRects[i].bottom + faceRects[i].top);
1030        }
1031
1032        setBase(CaptureResult.STATISTICS_FACE_RECTANGLES, newFaceRects);
1033        return true;
1034    }
1035
1036    private <T> boolean setTonemapCurve(TonemapCurve tc) {
1037        if (tc == null) {
1038            return false;
1039        }
1040
1041        float[][] curve = new float[3][];
1042        for (int i = TonemapCurve.CHANNEL_RED; i <= TonemapCurve.CHANNEL_BLUE; i++) {
1043            int pointCount = tc.getPointCount(i);
1044            curve[i] = new float[pointCount * TonemapCurve.POINT_SIZE];
1045            tc.copyColorCurve(i, curve[i], 0);
1046        }
1047        setBase(CaptureRequest.TONEMAP_CURVE_RED, curve[0]);
1048        setBase(CaptureRequest.TONEMAP_CURVE_GREEN, curve[1]);
1049        setBase(CaptureRequest.TONEMAP_CURVE_BLUE, curve[2]);
1050
1051        return true;
1052    }
1053
1054    private long mMetadataPtr; // native CameraMetadata*
1055
1056    private native long nativeAllocate();
1057    private native long nativeAllocateCopy(CameraMetadataNative other)
1058            throws NullPointerException;
1059
1060    private native synchronized void nativeWriteToParcel(Parcel dest);
1061    private native synchronized void nativeReadFromParcel(Parcel source);
1062    private native synchronized void nativeSwap(CameraMetadataNative other)
1063            throws NullPointerException;
1064    private native synchronized void nativeClose();
1065    private native synchronized boolean nativeIsEmpty();
1066    private native synchronized int nativeGetEntryCount();
1067
1068    private native synchronized byte[] nativeReadValues(int tag);
1069    private native synchronized void nativeWriteValues(int tag, byte[] src);
1070    private native synchronized void nativeDump() throws IOException; // dump to ALOGD
1071
1072    private static native int nativeGetTagFromKey(String keyName)
1073            throws IllegalArgumentException;
1074    private static native int nativeGetTypeFromTag(int tag)
1075            throws IllegalArgumentException;
1076    private static native void nativeClassInit();
1077
1078    /**
1079     * <p>Perform a 0-copy swap of the internal metadata with another object.</p>
1080     *
1081     * <p>Useful to convert a CameraMetadata into e.g. a CaptureRequest.</p>
1082     *
1083     * @param other Metadata to swap with
1084     * @throws NullPointerException if other was null
1085     * @hide
1086     */
1087    public void swap(CameraMetadataNative other) {
1088        nativeSwap(other);
1089    }
1090
1091    /**
1092     * @hide
1093     */
1094    public int getEntryCount() {
1095        return nativeGetEntryCount();
1096    }
1097
1098    /**
1099     * Does this metadata contain at least 1 entry?
1100     *
1101     * @hide
1102     */
1103    public boolean isEmpty() {
1104        return nativeIsEmpty();
1105    }
1106
1107    /**
1108     * Convert a key string into the equivalent native tag.
1109     *
1110     * @throws IllegalArgumentException if the key was not recognized
1111     * @throws NullPointerException if the key was null
1112     *
1113     * @hide
1114     */
1115    public static int getTag(String key) {
1116        return nativeGetTagFromKey(key);
1117    }
1118
1119    /**
1120     * Get the underlying native type for a tag.
1121     *
1122     * @param tag An integer tag, see e.g. {@link #getTag}
1123     * @return An int enum for the metadata type, see e.g. {@link #TYPE_BYTE}
1124     *
1125     * @hide
1126     */
1127    public static int getNativeType(int tag) {
1128        return nativeGetTypeFromTag(tag);
1129    }
1130
1131    /**
1132     * <p>Updates the existing entry for tag with the new bytes pointed by src, erasing
1133     * the entry if src was null.</p>
1134     *
1135     * <p>An empty array can be passed in to update the entry to 0 elements.</p>
1136     *
1137     * @param tag An integer tag, see e.g. {@link #getTag}
1138     * @param src An array of bytes, or null to erase the entry
1139     *
1140     * @hide
1141     */
1142    public void writeValues(int tag, byte[] src) {
1143        nativeWriteValues(tag, src);
1144    }
1145
1146    /**
1147     * <p>Returns a byte[] of data corresponding to this tag. Use a wrapped bytebuffer to unserialize
1148     * the data properly.</p>
1149     *
1150     * <p>An empty array can be returned to denote an existing entry with 0 elements.</p>
1151     *
1152     * @param tag An integer tag, see e.g. {@link #getTag}
1153     *
1154     * @return {@code null} if there were 0 entries for this tag, a byte[] otherwise.
1155     * @hide
1156     */
1157    public byte[] readValues(int tag) {
1158        // TODO: Optimization. Native code returns a ByteBuffer instead.
1159        return nativeReadValues(tag);
1160    }
1161
1162    /**
1163     * Dumps the native metadata contents to logcat.
1164     *
1165     * <p>Visibility for testing/debugging only. The results will not
1166     * include any synthesized keys, as they are invisible to the native layer.</p>
1167     *
1168     * @hide
1169     */
1170    public void dumpToLog() {
1171        try {
1172            nativeDump();
1173        } catch (IOException e) {
1174            Log.wtf(TAG, "Dump logging failed", e);
1175        }
1176    }
1177
1178    @Override
1179    protected void finalize() throws Throwable {
1180        try {
1181            close();
1182        } finally {
1183            super.finalize();
1184        }
1185    }
1186
1187    /**
1188     * Get the marshaler compatible with the {@code key} and type {@code T}.
1189     *
1190     * @throws UnsupportedOperationException
1191     *          if the native/managed type combination for {@code key} is not supported
1192     */
1193    private static <T> Marshaler<T> getMarshalerForKey(Key<T> key) {
1194        return MarshalRegistry.getMarshaler(key.getTypeReference(),
1195                getNativeType(key.getTag()));
1196    }
1197
1198    @SuppressWarnings({ "unchecked", "rawtypes" })
1199    private static void registerAllMarshalers() {
1200        if (VERBOSE) {
1201            Log.v(TAG, "Shall register metadata marshalers");
1202        }
1203
1204        MarshalQueryable[] queryList = new MarshalQueryable[] {
1205                // marshalers for standard types
1206                new MarshalQueryablePrimitive(),
1207                new MarshalQueryableEnum(),
1208                new MarshalQueryableArray(),
1209
1210                // pseudo standard types, that expand/narrow the native type into a managed type
1211                new MarshalQueryableBoolean(),
1212                new MarshalQueryableNativeByteToInteger(),
1213
1214                // marshalers for custom types
1215                new MarshalQueryableRect(),
1216                new MarshalQueryableSize(),
1217                new MarshalQueryableSizeF(),
1218                new MarshalQueryableString(),
1219                new MarshalQueryableReprocessFormatsMap(),
1220                new MarshalQueryableRange(),
1221                new MarshalQueryablePair(),
1222                new MarshalQueryableMeteringRectangle(),
1223                new MarshalQueryableColorSpaceTransform(),
1224                new MarshalQueryableStreamConfiguration(),
1225                new MarshalQueryableStreamConfigurationDuration(),
1226                new MarshalQueryableRggbChannelVector(),
1227                new MarshalQueryableBlackLevelPattern(),
1228                new MarshalQueryableHighSpeedVideoConfiguration(),
1229
1230                // generic parcelable marshaler (MUST BE LAST since it has lowest priority)
1231                new MarshalQueryableParcelable(),
1232        };
1233
1234        for (MarshalQueryable query : queryList) {
1235            MarshalRegistry.registerMarshalQueryable(query);
1236        }
1237        if (VERBOSE) {
1238            Log.v(TAG, "Registered metadata marshalers");
1239        }
1240    }
1241
1242    /** Check if input arguments are all {@code null}.
1243     *
1244     * @param objs Input arguments for null check
1245     * @return {@code true} if input arguments are all {@code null}, otherwise {@code false}
1246     */
1247    private static boolean areValuesAllNull(Object... objs) {
1248        for (Object o : objs) {
1249            if (o != null) return false;
1250        }
1251        return true;
1252    }
1253
1254    static {
1255        /*
1256         * We use a class initializer to allow the native code to cache some field offsets
1257         */
1258        nativeClassInit();
1259        registerAllMarshalers();
1260    }
1261}
1262