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