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