OSDN Git Service

Add a camera metadata structure and utility methods
authorEino-Ville Talvala <etalvala@google.com>
Fri, 10 Feb 2012 22:27:08 +0000 (14:27 -0800)
committerEino-Ville Talvala <etalvala@google.com>
Thu, 22 Mar 2012 19:41:22 +0000 (12:41 -0700)
Change-Id: I320cc33f31ebd8ce183572a447df8fae691eec0d

camera/include/system/camera_metadata.h [new file with mode: 0644]
camera/include/system/camera_metadata_tags.h [new file with mode: 0644]
camera/src/Android.mk [new file with mode: 0644]
camera/src/camera_metadata.c [new file with mode: 0644]
camera/src/camera_metadata_tag_info.c [new file with mode: 0644]
camera/tests/Android.mk [new file with mode: 0644]
camera/tests/camera_metadata_tests.cpp [new file with mode: 0644]
camera/tests/camera_metadata_tests_fake_vendor.h [new file with mode: 0644]

diff --git a/camera/include/system/camera_metadata.h b/camera/include/system/camera_metadata.h
new file mode 100644 (file)
index 0000000..424fc0f
--- /dev/null
@@ -0,0 +1,327 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SYSTEM_CORE_INCLUDE_ANDROID_CAMERA_METADATA_H
+#define SYSTEM_CORE_INCLUDE_ANDROID_CAMERA_METADATA_H
+
+#include <string.h>
+#include <stdint.h>
+#include <cutils/compiler.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Tag hierarchy and enum definitions for camera_metadata_entry
+ * =============================================================================
+ */
+
+/**
+ * Main enum definitions are in a separate file to make it easy to
+ * maintain
+ */
+#include "camera_metadata_tags.h"
+
+/**
+ * Enum range for each top-level category
+ */
+ANDROID_API
+extern unsigned int camera_metadata_section_bounds[ANDROID_SECTION_COUNT][2];
+ANDROID_API
+extern const char *camera_metadata_section_names[ANDROID_SECTION_COUNT];
+
+/**
+ * Type definitions for camera_metadata_entry
+ * =============================================================================
+ */
+enum {
+    // Unsigned 8-bit integer (uint8_t)
+    TYPE_BYTE = 0,
+    // Signed 32-bit integer (int32_t)
+    TYPE_INT32 = 1,
+    // 32-bit float (float)
+    TYPE_FLOAT = 2,
+    // Signed 64-bit integer (int64_t)
+    TYPE_INT64 = 3,
+    // 64-bit float (double)
+    TYPE_DOUBLE = 4,
+    // A 64-bit fraction (camera_metadata_rational_t)
+    TYPE_RATIONAL = 5,
+    // Number of type fields
+    NUM_TYPES
+};
+
+typedef struct camera_metadata_rational {
+    int32_t numerator;
+    int32_t denominator;
+} camera_metadata_rational_t;
+
+/**
+ * Size in bytes of each entry type
+ */
+ANDROID_API
+extern size_t camera_metadata_type_sizes[NUM_TYPES];
+
+/**
+ * Main definitions for the metadata entry and array structures
+ * =============================================================================
+ */
+
+/**
+ * A packet of metadata. This is a list of metadata entries, each of which has
+ * an integer tag to identify its meaning, 'type' and 'count' field, and the
+ * data, which contains a 'count' number of entries of type 'type'. The packet
+ * has a fixed capacity for entries and for extra data.  A new entry uses up one
+ * entry slot, and possibly some amount of data capacity; the function
+ * calculate_camera_metadata_entry_data_size() provides the amount of data
+ * capacity that would be used up by an entry.
+ *
+ * Entries are not sorted, and are not forced to be unique - multiple entries
+ * with the same tag are allowed. The packet will not dynamically resize when
+ * full.
+ *
+ * The packet is contiguous in memory, with size in bytes given by
+ * get_camera_metadata_size(). Therefore, it can be copied safely with memcpy()
+ * to a buffer of sufficient size. The copy_camera_metadata() function is
+ * intended for eliminating unused capacity in the destination packet.
+ */
+struct camera_metadata;
+typedef struct camera_metadata camera_metadata_t;
+
+/**
+ * Functions for manipulating camera metadata
+ * =============================================================================
+ */
+
+/**
+ * Allocate a new camera_metadata structure, with some initial space for entries
+ * and extra data. The entry_capacity is measured in entry counts, and
+ * data_capacity in bytes. The resulting structure is all contiguous in memory,
+ * and can be freed with free_camera_metadata().
+ */
+ANDROID_API
+camera_metadata_t *allocate_camera_metadata(size_t entry_capacity,
+        size_t data_capacity);
+
+/**
+ * Place a camera metadata structure into an existing buffer. Returns NULL if
+ * the buffer is too small for the requested number of reserved entries and
+ * bytes of data. The entry_capacity is measured in entry counts, and
+ * data_capacity in bytes. If the buffer is larger than the required space,
+ * unused space will be left at the end. If successful, returns a pointer to the
+ * metadata header placed at the start of the buffer. It is the caller's
+ * responsibility to free the original buffer; do not call
+ * free_camera_metadata() with the returned pointer.
+ */
+ANDROID_API
+camera_metadata_t *place_camera_metadata(void *dst, size_t dst_size,
+        size_t entry_capacity,
+        size_t data_capacity);
+
+/**
+ * Free a camera_metadata structure. Should only be used with structures
+ * allocated with allocate_camera_metadata().
+ */
+ANDROID_API
+void free_camera_metadata(camera_metadata_t *metadata);
+
+/**
+ * Calculate the buffer size needed for a metadata structure of entry_count
+ * metadata entries, needing a total of data_count bytes of extra data storage.
+ */
+ANDROID_API
+size_t calculate_camera_metadata_size(size_t entry_count,
+        size_t data_count);
+
+/**
+ * Get current size of entire metadata structure in bytes, including reserved
+ * but unused space.
+ */
+ANDROID_API
+size_t get_camera_metadata_size(const camera_metadata_t *metadata);
+
+/**
+ * Get size of entire metadata buffer in bytes, not including reserved but
+ * unused space. This is the amount of space needed by copy_camera_metadata for
+ * its dst buffer.
+ */
+ANDROID_API
+size_t get_camera_metadata_compact_size(const camera_metadata_t *metadata);
+
+/**
+ * Get the current number of entries in the metadata packet.
+ */
+ANDROID_API
+size_t get_camera_metadata_entry_count(const camera_metadata_t *metadata);
+
+/**
+ * Get the maximum number of entries that could fit in the metadata packet.
+ */
+ANDROID_API
+size_t get_camera_metadata_entry_capacity(const camera_metadata_t *metadata);
+
+/**
+ * Get the current count of bytes used for value storage in the metadata packet.
+ */
+ANDROID_API
+size_t get_camera_metadata_data_count(const camera_metadata_t *metadata);
+
+/**
+ * Get the maximum count of bytes that could be used for value storage in the
+ * metadata packet.
+ */
+ANDROID_API
+size_t get_camera_metadata_data_capacity(const camera_metadata_t *metadata);
+
+/**
+ * Copy a metadata structure to a memory buffer, compacting it along the
+ * way. That is, in the copied structure, entry_count == entry_capacity, and
+ * data_count == data_capacity.
+ *
+ * If dst_size > get_camera_metadata_compact_size(), the unused bytes are at the
+ * end of the buffer. If dst_size < get_camera_metadata_compact_size(), returns
+ * NULL. Otherwise returns a pointer to the metadata structure header placed at
+ * the start of dst.
+ *
+ * Since the buffer was not allocated by allocate_camera_metadata, the caller is
+ * responsible for freeing the underlying buffer when needed; do not call
+ * free_camera_metadata.
+ */
+ANDROID_API
+camera_metadata_t *copy_camera_metadata(void *dst, size_t dst_size,
+        const camera_metadata_t *src);
+
+/**
+ * Append camera metadata in src to an existing metadata structure in dst.  This
+ * does not resize the destination structure, so if it is too small, a non-zero
+ * value is returned. On success, 0 is returned.
+ */
+ANDROID_API
+int append_camera_metadata(camera_metadata_t *dst, const camera_metadata_t *src);
+
+/**
+ * Calculate the number of bytes of extra data a given metadata entry will take
+ * up. That is, if entry of 'type' with a payload of 'data_count' values is
+ * added, how much will the value returned by get_camera_metadata_data_count()
+ * be increased? This value may be zero, if no extra data storage is needed.
+ */
+ANDROID_API
+size_t calculate_camera_metadata_entry_data_size(uint8_t type,
+        size_t data_count);
+
+/**
+ * Add a metadata entry to a metadata structure. Returns 0 if the addition
+ * succeeded. Returns a non-zero value if there is insufficient reserved space
+ * left to add the entry, or if the tag is unknown.  data_count is the number of
+ * entries in the data array of the tag's type, not a count of
+ * bytes. Vendor-defined tags can not be added using this method, unless
+ * set_vendor_tag_query_ops() has been called first.
+ */
+ANDROID_API
+int add_camera_metadata_entry(camera_metadata_t *dst,
+        uint32_t tag,
+        const void *data,
+        size_t data_count);
+
+/**
+ * Get pointers to the fields for a metadata entry at position index in the
+ * entry array.  The data pointer points either to the entry's data.value field
+ * or to the right offset in camera_metadata_t.data. Returns 0 on
+ * success. Data_count is the number of entries in the data array when cast to
+ * the tag's type, not a count of bytes.
+ *
+ * src and index are inputs; tag, type, data, and data_count are outputs.
+ */
+ANDROID_API
+int get_camera_metadata_entry(camera_metadata_t *src,
+        uint32_t index,
+        uint32_t *tag,
+        uint8_t *type,
+        void **data,
+        size_t *data_count);
+
+/**
+ * Retrieve human-readable name of section the tag is in. Returns NULL if
+ * no such tag is defined. Returns NULL for tags in the vendor section, unless
+ * set_vendor_tag_query_ops() has been used.
+ */
+ANDROID_API
+const char *get_camera_metadata_section_name(uint32_t tag);
+
+/**
+ * Retrieve human-readable name of tag (not including section). Returns NULL if
+ * no such tag is defined. Returns NULL for tags in the vendor section, unless
+ * set_vendor_tag_query_ops() has been used.
+ */
+ANDROID_API
+const char *get_camera_metadata_tag_name(uint32_t tag);
+
+/**
+ * Retrieve the type of a tag. Returns -1 if no such tag is defined. Returns -1
+ * for tags in the vendor section, unless set_vendor_tag_query_ops() has been
+ * used.
+ */
+ANDROID_API
+int get_camera_metadata_tag_type(uint32_t tag);
+
+/**
+ * Set up vendor-specific tag query methods. These are needed to properly add
+ * entries with vendor-specified tags and to use the
+ * get_camera_metadata_section_name, _tag_name, and _tag_type methods with
+ * vendor tags. Returns 0 on success.
+ */
+typedef struct vendor_tag_query_ops {
+    /**
+     * Get vendor section name for a vendor-specified entry tag. Only called for
+     * tags >= 0x80000000. The section name must start with the name of the
+     * vendor in the Java package style. For example, CameraZoom inc must prefix
+     * their sections with "com.camerazoom." Must return NULL if the tag is
+     * outside the bounds of vendor-defined sections.
+     */
+    const char *(*get_camera_vendor_section_name)(uint32_t tag);
+    /**
+     * Get tag name for a vendor-specified entry tag. Only called for tags >=
+     * 0x80000000. Must return NULL if the tag is outside the bounds of
+     * vendor-defined sections.
+     */
+    const char *(*get_camera_vendor_tag_name)(uint32_t tag);
+    /**
+     * Get tag type for a vendor-specified entry tag. Only called for tags >=
+     * 0x80000000. Must return -1 if the tag is outside the bounds of
+     * vendor-defined sections.
+     */
+    int         (*get_camera_vendor_tag_type)(uint32_t tag);
+} vendor_tag_query_ops_t;
+
+ANDROID_API
+int set_camera_metadata_vendor_tag_ops(const vendor_tag_query_ops_t *query_ops);
+
+/**
+ * Print fields in the metadata to the log.
+ * verbosity = 0: Only tag entry information
+ * verbosity = 1: Tag entry information plus at most 16 data values
+ * verbosity = 2: All information
+ */
+ANDROID_API
+void dump_camera_metadata(const camera_metadata_t *metadata,
+        int verbosity);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/camera/include/system/camera_metadata_tags.h b/camera/include/system/camera_metadata_tags.h
new file mode 100644 (file)
index 0000000..1fcfacb
--- /dev/null
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * !! Do not include this file directly !!
+ *
+ * Include camera_metadata.h instead.
+ */
+
+/**
+ * Top level hierarchy definitions for camera metadata. *_INFO sections are for
+ * the static metadata that can be retrived without opening the camera device.
+ * New sections must be added right before ANDROID_SECTION_COUNT to maintain
+ * existing enumerations.
+ */
+enum {
+    ANDROID_REQUEST = 0,
+    ANDROID_LENS,
+    ANDROID_LENS_INFO,
+    ANDROID_SENSOR,
+    ANDROID_SENSOR_INFO,
+    ANDROID_FLASH,
+    ANDROID_FLASH_INFO,
+    ANDROID_HOT_PIXEL,
+    ANDROID_HOT_PIXEL_INFO,
+    ANDROID_DEMOSAIC,
+    ANDROID_DEMOSAIC_INFO,
+    ANDROID_NOISE,
+    ANDROID_NOISE_INFO,
+    ANDROID_SHADING,
+    ANDROID_SHADING_INFO,
+    ANDROID_GEOMETRIC,
+    ANDROID_GEOMETRIC_INFO,
+    ANDROID_COLOR,
+    ANDROID_COLOR_INFO,
+    ANDROID_TONEMAP,
+    ANDROID_TONEMAP_INFO,
+    ANDROID_EDGE,
+    ANDROID_EDGE_INFO,
+    ANDROID_SCALER,
+    ANDROID_SCALER_INFO,
+    ANDROID_JPEG,
+    ANDROID_JPEG_INFO,
+    ANDROID_STATS,
+    ANDROID_STATS_INFO,
+    ANDROID_CONTROL,
+    ANDROID_CONTROL_INFO,
+    ANDROID_SECTION_COUNT,
+
+    VENDOR_SECTION = 0x8000
+};
+
+/**
+ * Hierarchy positions in enum space. All vendor extension tags must be
+ * defined with tag >= VENDOR_SECTION_START
+ */
+enum {
+    ANDROID_REQUEST_START         = ANDROID_REQUEST        << 16,
+    ANDROID_LENS_START            = ANDROID_LENS           << 16,
+    ANDROID_LENS_INFO_START       = ANDROID_LENS_INFO      << 16,
+    ANDROID_SENSOR_START          = ANDROID_SENSOR         << 16,
+    ANDROID_SENSOR_INFO_START     = ANDROID_SENSOR_INFO    << 16,
+    ANDROID_FLASH_START           = ANDROID_FLASH          << 16,
+    ANDROID_FLASH_INFO_START      = ANDROID_FLASH_INFO     << 16,
+    ANDROID_HOT_PIXEL_START       = ANDROID_HOT_PIXEL      << 16,
+    ANDROID_HOT_PIXEL_INFO_START  = ANDROID_HOT_PIXEL_INFO << 16,
+    ANDROID_DEMOSAIC_START        = ANDROID_DEMOSAIC       << 16,
+    ANDROID_DEMOSAIC_INFO_START   = ANDROID_DEMOSAIC_INFO  << 16,
+    ANDROID_NOISE_START           = ANDROID_NOISE          << 16,
+    ANDROID_NOISE_INFO_START      = ANDROID_NOISE_INFO     << 16,
+    ANDROID_SHADING_START         = ANDROID_SHADING        << 16,
+    ANDROID_SHADING_INFO_START    = ANDROID_SHADING_INFO   << 16,
+    ANDROID_GEOMETRIC_START       = ANDROID_GEOMETRIC      << 16,
+    ANDROID_GEOMETRIC_INFO_START  = ANDROID_GEOMETRIC_INFO << 16,
+    ANDROID_COLOR_START           = ANDROID_COLOR          << 16,
+    ANDROID_COLOR_INFO_START      = ANDROID_COLOR_INFO     << 16,
+    ANDROID_TONEMAP_START         = ANDROID_TONEMAP        << 16,
+    ANDROID_TONEMAP_INFO_START    = ANDROID_TONEMAP_INFO   << 16,
+    ANDROID_EDGE_START            = ANDROID_EDGE           << 16,
+    ANDROID_EDGE_INFO_START       = ANDROID_EDGE_INFO      << 16,
+    ANDROID_SCALER_START          = ANDROID_SCALER         << 16,
+    ANDROID_SCALER_INFO_START     = ANDROID_SCALER_INFO    << 16,
+    ANDROID_JPEG_START            = ANDROID_JPEG           << 16,
+    ANDROID_JPEG_INFO_START       = ANDROID_JPEG_INFO      << 16,
+    ANDROID_STATS_START           = ANDROID_STATS          << 16,
+    ANDROID_STATS_INFO_START      = ANDROID_STATS_INFO     << 16,
+    ANDROID_CONTROL_START         = ANDROID_CONTROL        << 16,
+    ANDROID_CONTROL_INFO_START    = ANDROID_CONTROL_INFO   << 16,
+    VENDOR_SECTION_START          = VENDOR_SECTION         << 16
+};
+
+/**
+ * Main enum for defining camera metadata tags.  New entries must always go
+ * before the section _END tag to preserve existing enumeration values.  In
+ * addition, the name and type of the tag needs to be added to
+ * system/media/camera/src/camera_metadata_tag_info.c
+ */
+enum {
+    ANDROID_REQUEST_ID = ANDROID_REQUEST_START,
+    ANDROID_REQUEST_METADATA_MODE,
+    ANDROID_REQUEST_OUTPUT_STREAMS,
+    ANDROID_REQUEST_FRAME_COUNT,
+    ANDROID_REQUEST_END,
+
+    ANDROID_LENS_FOCUS_DISTANCE = ANDROID_LENS_START,
+    ANDROID_LENS_APERTURE,
+    ANDROID_LENS_FOCAL_LENGTH,
+    ANDROID_LENS_FILTER_DENSITY,
+    ANDROID_LENS_OPTICAL_STABILIZATION_MODE,
+    ANDROID_LENS_FOCUS_RANGE,
+    ANDROID_LENS_END,
+
+    ANDROID_LENS_MINIMUM_FOCUS_DISTANCE = ANDROID_LENS_INFO_START,
+    ANDROID_LENS_AVAILABLE_FOCAL_LENGTHS,
+    ANDROID_LENS_AVAILABLE_APERTURES,
+    ANDROID_LENS_AVAILABLE_FILTER_DENSITY,
+    ANDROID_LENS_AVAILABLE_OPTICAL_STABILIZATION,
+    ANDROID_LENS_SHADING_MAP,
+    ANDROID_LENS_GEOMETRIC_CORRECTION_MAP,
+    ANDROID_LENS_FACING,
+    ANDROID_LENS_POSITION,
+    ANDROID_LENS_INFO_END,
+
+    ANDROID_SENSOR_EXPOSURE_TIME = ANDROID_SENSOR_START,
+    ANDROID_SENSOR_FRAME_DURATION,
+    ANDROID_SENSOR_SENSITIVITY,
+    ANDROID_SENSOR_TIMESTAMP,
+    ANDROID_SENSOR_END,
+
+    ANDROID_SENSOR_EXPOSURE_TIME_RANGE = ANDROID_SENSOR_INFO_START,
+    ANDROID_SENSOR_MAX_FRAME_DURATION,
+    ANDROID_SENSOR_SENSITIVITY_RANGE,
+    ANDROID_SENSOR_COLOR_FILTER_ARRANGEMENT,
+    ANDROID_SENSOR_PIXEL_ARRAY_SIZE,
+    ANDROID_SENSOR_ACTIVE_ARRAY_SIZE,
+    ANDROID_SENSOR_WHITE_LEVEL,
+    ANDROID_SENSOR_BLACK_LEVEL_PATTERN,
+    ANDROID_SENSOR_COLOR_TRANSFORM_1,
+    ANDROID_SENSOR_COLOR_TRANSFORM_2,
+    ANDROID_SENSOR_REFERENCE_ILLUMINANT_1,
+    ANDROID_SENSOR_REFERENCE_ILLUMINANT_2,
+    ANDROID_SENSOR_FORWARD_MATRIX_1,
+    ANDROID_SENSOR_FORWARD_MATRIX_2,
+    ANDROID_SENSOR_CALIBRATION_TRANSFORM_1,
+    ANDROID_SENSOR_CALIBRATION_TRANSFORM_2,
+    ANDROID_SENSOR_BASE_GAIN_FACTOR,
+    ANDROID_SENSOR_MAX_ANALOG_SENSITIVITY,
+    ANDROID_SENSOR_NOISE_MODEL_COEFFICIENTS,
+    ANDROID_SENSOR_ORIENTATION,
+    ANDROID_SENSOR_INFO_END,
+
+    ANDROID_FLASH_MODE = ANDROID_FLASH_START,
+    ANDROID_FLASH_FIRING_POWER,
+    ANDROID_FLASH_FIRING_TIME,
+    ANDROID_FLASH_END,
+
+    ANDROID_FLASH_AVAILABLE_MODES = ANDROID_FLASH_INFO_START,
+    ANDROID_FLASH_CHARGE_DURATION,
+    ANDROID_FLASH_INFO_END,
+
+    ANDROID_HOT_PIXEL_MODE = ANDROID_HOT_PIXEL_START,
+    ANDROID_HOT_PIXEL_END,
+
+    ANDROID_HOT_PIXEL_INFO_END = ANDROID_HOT_PIXEL_INFO_START,
+
+    ANDROID_DEMOSAIC_MODE = ANDROID_DEMOSAIC_START,
+    ANDROID_DEMOSAIC_END,
+
+    ANDROID_DEMOSAIC_INFO_END = ANDROID_DEMOSAIC_INFO_START,
+
+    ANDROID_NOISE_MODE = ANDROID_NOISE_START,
+    ANDROID_NOISE_STRENGTH,
+    ANDROID_NOISE_END,
+
+    ANDROID_NOISE_INFO_END = ANDROID_NOISE_INFO_START,
+
+    ANDROID_SHADING_MODE  = ANDROID_SHADING_START,
+    ANDROID_SHADING_END,
+
+    ANDROID_SHADING_INFO_END = ANDROID_SHADING_INFO_START,
+
+    ANDROID_GEOMETRIC_MODE  = ANDROID_GEOMETRIC_START,
+    ANDROID_GEOMETRIC_END,
+
+    ANDROID_GEOMETRIC_INFO_END = ANDROID_GEOMETRIC_INFO_START,
+
+    ANDROID_COLOR_MODE = ANDROID_COLOR_START,
+    ANDROID_COLOR_TRANSFORM,
+    ANDROID_COLOR_END,
+
+    ANDROID_COLOR_AVAILABLE_MODES = ANDROID_COLOR_INFO_START,
+    ANDROID_COLOR_INFO_END,
+
+    ANDROID_TONEMAP_MODE = ANDROID_TONEMAP_START,
+    ANDROID_TONEMAP_CURVE_RED,
+    ANDROID_TONEMAP_CURVE_GREEN,
+    ANDROID_TONEMAP_CURVE_BLUE,
+    ANDROID_TONEMAP_END,
+
+    ANDROID_TONEMAP_MAX_CURVE_POINTS = ANDROID_TONEMAP_INFO_START,
+    ANDROID_TONEMAP_INFO_END,
+
+    ANDROID_EDGE_MODE = ANDROID_EDGE_START,
+    ANDROID_EDGE_STRENGTH,
+    ANDROID_EDGE_END,
+
+    ANDROID_EDGE_INFO_END = ANDROID_EDGE_INFO_START,
+
+    ANDROID_SCALER_SIZE = ANDROID_SCALER_START,
+    ANDROID_SCALER_FORMAT,
+    ANDROID_SCALER_CROP_REGION,
+    ANDROID_SCALER_ROTATION,
+    ANDROID_SCALER_END,
+
+    ANDROID_SCALER_AVAILABLE_FORMATS = ANDROID_SCALER_INFO_START,
+    ANDROID_SCALER_AVAILABLE_SIZES_PER_FORMAT,
+    ANDROID_SCALER_AVAILABLE_SIZES,
+    ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS,
+    ANDROID_SCALER_AVAILABLE_MAX_ZOOM,
+    ANDROID_SCALER_INFO_END,
+
+    ANDROID_JPEG_QUALITY = ANDROID_JPEG_START,
+    ANDROID_JPEG_THUMBNAIL_SIZE,
+    ANDROID_JPEG_THUMBNAIL_QUALITY,
+    ANDROID_JPEG_GPS_COORDINATES,
+    ANDROID_JPEG_GPS_PROCESSING_METHOD,
+    ANDROID_JPEG_GPS_TIMESTAMP,
+    ANDROID_JPEG_ORIENTATION,
+    ANDROID_JPEG_END,
+
+    ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES  = ANDROID_JPEG_INFO_START,
+    ANDROID_JPEG_INFO_END,
+
+    ANDROID_STATS_FACE_DETECT_MODE = ANDROID_STATS_START,
+    ANDROID_STATS_HISTOGRAM_MODE,
+    ANDROID_STATS_SHARPNESS_MAP_MODE,
+    ANDROID_STATS_FACE_RECTANGLES,
+    ANDROID_STATS_FACE_SCORES,
+    ANDROID_STATS_FACE_LANDMARKS,
+    ANDROID_STATS_FACE_IDS,
+    ANDROID_STATS_HISTOGRAM,
+    ANDROID_STATS_SHARPNESS_MAP,
+    ANDROID_STATS_END,
+
+    ANDROID_STATS_AVAILABLE_FACE_DETECT_MODES = ANDROID_STATS_INFO_START,
+    ANDROID_STATS_MAX_FACE_COUNT,
+    ANDROID_STATS_HISTOGRAM_BUCKET_COUNT,
+    ANDROID_STATS_MAX_HISTOGRAM_COUNT,
+    ANDROID_STATS_SHARPNESS_MAP_SIZE,
+    ANDROID_STATS_MAX_SHARPNESS_MAP_VALUE,
+    ANDROID_STATS_INFO_END,
+
+    ANDROID_CONTROL_MODE = ANDROID_CONTROL_START,
+    ANDROID_CONTROL_AE_MODE,
+    ANDROID_CONTROL_AE_REGIONS,
+    ANDROID_CONTROL_AE_EXP_COMPENSATION,
+    ANDROID_CONTROL_AE_TARGET_FPS_RANGE,
+    ANDROID_CONTROL_AE_ANTIBANDING_MODE,
+    ANDROID_CONTROL_AWB_MODE,
+    ANDROID_CONTROL_AWB_REGIONS,
+    ANDROID_CONTROL_AF_MODE,
+    ANDROID_CONTROL_AF_REGIONS,
+    ANDROID_CONTROL_AF_TRIGGER,
+    ANDROID_CONTROL_AF_STATE,
+    ANDROID_CONTROL_VIDEO_STABILIZATION_MODE,
+    ANDROID_CONTROL_END,
+
+    ANDROID_CONTROL_AVAILABLE_MODES = ANDROID_CONTROL_INFO_START,
+    ANDROID_CONTROL_MAX_REGIONS,
+    ANDROID_CONTROL_AE_AVAILABLE_MODES,
+    ANDROID_CONTROL_AE_EXP_COMPENSATION_STEP,
+    ANDROID_CONTROL_AE_EXP_COMPENSATION_RANGE,
+    ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,
+    ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,
+    ANDROID_CONTROL_AWB_AVAILABLE_MODES,
+    ANDROID_CONTROL_AF_AVAILABLE_MODES,
+    ANDROID_CONTROL_INFO_END
+};
diff --git a/camera/src/Android.mk b/camera/src/Android.mk
new file mode 100644 (file)
index 0000000..19a6f5b
--- /dev/null
@@ -0,0 +1,24 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+       camera_metadata.c
+
+LOCAL_C_INCLUDES:= \
+       system/media/camera/include
+
+LOCAL_SHARED_LIBRARIES := \
+       libcutils
+
+LOCAL_MODULE := libcamera_metadata
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_CFLAGS += \
+       -Wall \
+       -fvisibility=hidden \
+
+
+include $(BUILD_SHARED_LIBRARY)
+
+
diff --git a/camera/src/camera_metadata.c b/camera/src/camera_metadata.c
new file mode 100644 (file)
index 0000000..a481bec
--- /dev/null
@@ -0,0 +1,500 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <system/camera_metadata.h>
+#include <cutils/log.h>
+
+#define OK    0
+#define ERROR 1
+
+/**
+ * A single metadata entry, storing an array of values of a given type. If the
+ * array is no larger than 4 bytes in size, it is stored in the data.value[]
+ * array; otherwise, it can found in the parent's data array at index
+ * data.offset.
+ */
+typedef struct camera_metadata_entry {
+    uint32_t tag;
+    size_t   count;
+    union {
+        size_t  offset;
+        uint8_t value[4];
+    } data;
+    uint8_t  type;
+    uint8_t  reserved[3];
+} __attribute__((packed)) camera_metadata_entry_t;
+
+/**
+ * A packet of metadata. This is a list of entries, each of which may point to
+ * its values stored at an offset in data.
+ *
+ * It is assumed by the utility functions that the memory layout of the packet
+ * is as follows:
+ *
+ *   |----------------------------------------|
+ *   | camera_metadata_t                      |
+ *   |                                        |
+ *   |----------------------------------------|
+ *   | reserved for future expansion          |
+ *   |----------------------------------------|
+ *   | camera_metadata_entry_t #0             |
+ *   |----------------------------------------|
+ *   | ....                                   |
+ *   |----------------------------------------|
+ *   | camera_metadata_entry_t #entry_count-1 |
+ *   |----------------------------------------|
+ *   | free space for                         |
+ *   | (entry_capacity-entry_count) entries   |
+ *   |----------------------------------------|
+ *   | start of camera_metadata.data          |
+ *   |                                        |
+ *   |----------------------------------------|
+ *   | free space for                         |
+ *   | (data_capacity-data_count) bytes       |
+ *   |----------------------------------------|
+ *
+ * With the total length of the whole packet being camera_metadata.size bytes.
+ *
+ * In short, the entries and data are contiguous in memory after the metadata
+ * header.
+ */
+struct camera_metadata {
+    size_t                   size;
+    size_t                   entry_count;
+    size_t                   entry_capacity;
+    camera_metadata_entry_t *entries;
+    size_t                   data_count;
+    size_t                   data_capacity;
+    uint8_t                 *data;
+    uint8_t                  reserved[0];
+};
+
+typedef struct tag_info {
+    const char *tag_name;
+    uint8_t     tag_type;
+} tag_info_t;
+
+#include "camera_metadata_tag_info.c"
+
+size_t camera_metadata_type_size[NUM_TYPES] = {
+    [TYPE_BYTE]     = sizeof(uint8_t),
+    [TYPE_INT32]    = sizeof(int32_t),
+    [TYPE_FLOAT]    = sizeof(float),
+    [TYPE_INT64]    = sizeof(int64_t),
+    [TYPE_DOUBLE]   = sizeof(double),
+    [TYPE_RATIONAL] = sizeof(camera_metadata_rational_t)
+};
+
+char *camera_metadata_type_names[NUM_TYPES] = {
+    [TYPE_BYTE]     = "byte",
+    [TYPE_INT32]    = "int32",
+    [TYPE_FLOAT]    = "float",
+    [TYPE_INT64]    = "int64",
+    [TYPE_RATIONAL] = "rational"
+};
+
+camera_metadata_t *allocate_camera_metadata(size_t entry_capacity,
+                                            size_t data_capacity) {
+    size_t memory_needed = calculate_camera_metadata_size(entry_capacity,
+                                                          data_capacity);
+    void *buffer = malloc(memory_needed);
+    return place_camera_metadata(buffer, memory_needed,
+                                 entry_capacity,
+                                 data_capacity);
+}
+
+camera_metadata_t *place_camera_metadata(void *dst,
+                                         size_t dst_size,
+                                         size_t entry_capacity,
+                                         size_t data_capacity) {
+    if (dst == NULL) return NULL;
+    if (entry_capacity == 0) return NULL;
+
+    size_t memory_needed = calculate_camera_metadata_size(entry_capacity,
+                                                          data_capacity);
+    if (memory_needed > dst_size) return NULL;
+
+    camera_metadata_t *metadata = (camera_metadata_t*)dst;
+    metadata->entry_count = 0;
+    metadata->entry_capacity = entry_capacity;
+    metadata->entries = (camera_metadata_entry_t*)(metadata + 1);
+    metadata->data_count = 0;
+    metadata->data_capacity = data_capacity;
+    metadata->size = memory_needed;
+    if (metadata->data_capacity != 0) {
+        metadata->data =
+                (uint8_t*)(metadata->entries + metadata->entry_capacity);
+    } else {
+        metadata->data = NULL;
+    }
+
+    return metadata;
+}
+void free_camera_metadata(camera_metadata_t *metadata) {
+    free(metadata);
+}
+
+size_t calculate_camera_metadata_size(size_t entry_count,
+                                      size_t data_count) {
+    size_t memory_needed = sizeof(camera_metadata_t);
+    memory_needed += sizeof(camera_metadata_entry_t[entry_count]);
+    memory_needed += sizeof(uint8_t[data_count]);
+    return memory_needed;
+}
+
+size_t get_camera_metadata_size(const camera_metadata_t *metadata) {
+    if (metadata == NULL) return ERROR;
+
+    return metadata->size;
+}
+
+size_t get_camera_metadata_compact_size(const camera_metadata_t *metadata) {
+    if (metadata == NULL) return ERROR;
+
+    ptrdiff_t reserved_size = metadata->size -
+            calculate_camera_metadata_size(metadata->entry_capacity,
+                                           metadata->data_capacity);
+
+    return calculate_camera_metadata_size(metadata->entry_count,
+                                          metadata->data_count) + reserved_size;
+}
+
+size_t get_camera_metadata_entry_count(const camera_metadata_t *metadata) {
+    return metadata->entry_count;
+}
+
+size_t get_camera_metadata_entry_capacity(const camera_metadata_t *metadata) {
+    return metadata->entry_capacity;
+}
+
+size_t get_camera_metadata_data_count(const camera_metadata_t *metadata) {
+    return metadata->data_count;
+}
+
+size_t get_camera_metadata_data_capacity(const camera_metadata_t *metadata) {
+    return metadata->data_capacity;
+}
+
+camera_metadata_t* copy_camera_metadata(void *dst, size_t dst_size,
+        const camera_metadata_t *src) {
+    size_t memory_needed = get_camera_metadata_compact_size(src);
+
+    if (dst == NULL) return NULL;
+    if (dst_size < memory_needed) return NULL;
+
+    // If copying a newer version of the structure, there may be additional
+    // header fields we don't know about but need to copy
+    ptrdiff_t reserved_size = src->size -
+            calculate_camera_metadata_size(src->entry_capacity,
+                                           src->data_capacity);
+
+    camera_metadata_t *metadata = (camera_metadata_t*)dst;
+    metadata->entry_count = src->entry_count;
+    metadata->entry_capacity = src->entry_count;
+    metadata->entries = (camera_metadata_entry_t*)
+             ((uint8_t *)(metadata + 1) + reserved_size);
+    metadata->data_count = src->data_count;
+    metadata->data_capacity = src->data_count;
+    metadata->data = (uint8_t *)(metadata->entries + metadata->entry_capacity);
+    metadata->size = memory_needed;
+
+    if (reserved_size > 0) {
+        memcpy(metadata->reserved, src->reserved, reserved_size);
+    }
+    memcpy(metadata->entries, src->entries,
+            sizeof(camera_metadata_entry_t[metadata->entry_count]));
+    memcpy(metadata->data, src->data,
+            sizeof(uint8_t[metadata->data_count]));
+
+    return metadata;
+}
+
+int append_camera_metadata(camera_metadata_t *dst,
+        const camera_metadata_t *src) {
+    if (dst == NULL || src == NULL ) return ERROR;
+
+    if (dst->entry_capacity < src->entry_count + dst->entry_count) return ERROR;
+    if (dst->data_capacity < src->data_count + dst->data_count) return ERROR;
+
+    memcpy(dst->entries + dst->entry_count, src->entries,
+            sizeof(camera_metadata_entry_t[src->entry_count]));
+    memcpy(dst->data + dst->data_count, src->data,
+            sizeof(uint8_t[src->data_count]));
+    if (dst->data_count != 0) {
+        unsigned int i;
+        for (i = dst->entry_count;
+             i < dst->entry_count + src->entry_count;
+             i++) {
+            camera_metadata_entry_t *entry = dst->entries + i;
+            if ( camera_metadata_type_size[entry->type] * entry->count > 4 ) {
+                entry->data.offset += dst->data_count;
+            }
+        }
+    }
+    dst->entry_count += src->entry_count;
+    dst->data_count += src->data_count;
+
+    return OK;
+}
+
+size_t calculate_camera_metadata_entry_data_size(uint8_t type,
+        size_t data_count) {
+    if (type >= NUM_TYPES) return 0;
+    size_t data_bytes = data_count *
+            camera_metadata_type_size[type];
+    return data_bytes <= 4 ? 0 : data_bytes;
+}
+
+int add_camera_metadata_entry_raw(camera_metadata_t *dst,
+        uint32_t tag,
+        uint8_t  type,
+        const void *data,
+        size_t data_count) {
+
+    if (dst == NULL) return ERROR;
+    if (dst->entry_count == dst->entry_capacity) return ERROR;
+    if (data == NULL) return ERROR;
+
+    size_t data_bytes =
+            calculate_camera_metadata_entry_data_size(type, data_count);
+
+    camera_metadata_entry_t *entry = dst->entries + dst->entry_count;
+    entry->tag = tag;
+    entry->type = type;
+    entry->count = data_count;
+
+    if (data_bytes == 0) {
+        memcpy(entry->data.value, data,
+                data_count * camera_metadata_type_size[type] );
+    } else {
+        entry->data.offset = dst->data_count;
+        memcpy(dst->data + entry->data.offset, data, data_bytes);
+        dst->data_count += data_bytes;
+    }
+    dst->entry_count++;
+    return OK;
+}
+
+int add_camera_metadata_entry(camera_metadata_t *dst,
+        uint32_t tag,
+        const void *data,
+        size_t data_count) {
+
+    int type = get_camera_metadata_tag_type(tag);
+    if (type == -1) {
+        ALOGE("Unknown tag %04x (can't find type)", tag);
+        return ERROR;
+    }
+
+    return add_camera_metadata_entry_raw(dst,
+            tag,
+            type,
+            data,
+            data_count);
+}
+
+int get_camera_metadata_entry(camera_metadata_t *src,
+        uint32_t index,
+        uint32_t *tag,
+        uint8_t *type,
+        void **data,
+        size_t *data_count) {
+    if (src == NULL ) return ERROR;
+    if (tag == NULL) return ERROR;
+    if (type == NULL ) return ERROR;
+    if (data == NULL) return ERROR;
+    if (data_count == NULL) return ERROR;
+
+    if (index >= src->entry_count) return ERROR;
+
+    camera_metadata_entry_t *entry = src->entries + index;
+
+    *tag = entry->tag;
+    *type = entry->type;
+    *data_count = entry->count;
+    if (entry->count * camera_metadata_type_size[entry->type] > 4) {
+        *data = src->data + entry->data.offset;
+    } else {
+        *data = entry->data.value;
+    }
+    return OK;
+}
+
+static const vendor_tag_query_ops_t *vendor_tag_ops = NULL;
+
+const char *get_camera_metadata_section_name(uint32_t tag) {
+    uint32_t tag_section = tag >> 16;
+    if (tag_section >= VENDOR_SECTION && vendor_tag_ops != NULL) {
+        return vendor_tag_ops->get_camera_vendor_section_name(tag);
+    }
+    if (tag_section >= ANDROID_SECTION_COUNT) {
+        return NULL;
+    }
+    return camera_metadata_section_names[tag_section];
+}
+
+const char *get_camera_metadata_tag_name(uint32_t tag) {
+    uint32_t tag_section = tag >> 16;
+    if (tag_section >= VENDOR_SECTION && vendor_tag_ops != NULL) {
+        return vendor_tag_ops->get_camera_vendor_tag_name(tag);
+    }
+    if (tag_section >= ANDROID_SECTION_COUNT ||
+        tag >= camera_metadata_section_bounds[tag_section][1] ) {
+        return NULL;
+    }
+    uint32_t tag_index = tag & 0xFFFF;
+    return tag_info[tag_section][tag_index].tag_name;
+}
+
+int get_camera_metadata_tag_type(uint32_t tag) {
+    uint32_t tag_section = tag >> 16;
+    if (tag_section >= VENDOR_SECTION && vendor_tag_ops != NULL) {
+        return vendor_tag_ops->get_camera_vendor_tag_type(tag);
+    }
+    if (tag_section >= ANDROID_SECTION_COUNT ||
+            tag >= camera_metadata_section_bounds[tag_section][1] ) {
+        return -1;
+    }
+    uint32_t tag_index = tag & 0xFFFF;
+    return tag_info[tag_section][tag_index].tag_type;
+}
+
+int set_camera_metadata_vendor_tag_ops(const vendor_tag_query_ops_t *query_ops) {
+    vendor_tag_ops = query_ops;
+    return OK;
+}
+
+void print_data(const uint8_t *data_ptr, int type, int count);
+
+void dump_camera_metadata(const camera_metadata_t *metadata, int verbosity) {
+    if (metadata == NULL) {
+        ALOGE("Metadata is null.");
+        return;
+    }
+    unsigned int i;
+    ALOGD("Dumping camera metadata array. %d entries, %d bytes of extra data.",
+            metadata->entry_count, metadata->data_count);
+    ALOGD("  (%d entries and %d bytes data reserved)",
+            metadata->entry_capacity, metadata->data_capacity);
+    for (i=0; i < metadata->entry_count; i++) {
+        camera_metadata_entry_t *entry = metadata->entries + i;
+
+        const char *tag_name, *tag_section;
+        tag_section = get_camera_metadata_section_name(entry->tag);
+        if (tag_section == NULL) {
+            tag_section = "unknownSection";
+        }
+        tag_name = get_camera_metadata_tag_name(entry->tag);
+        if (tag_name == NULL) {
+            tag_name = "unknownTag";
+        }
+        const char *type_name;
+        if (entry->type >= NUM_TYPES) {
+            type_name = "unknown";
+        } else {
+            type_name = camera_metadata_type_names[entry->type];
+        }
+        ALOGD("Tag: %s.%s (%05x): %s[%d]",
+             tag_section,
+             tag_name,
+             entry->tag,
+             type_name,
+             entry->count);
+
+        if (verbosity < 1) continue;
+
+        if (entry->type >= NUM_TYPES) continue;
+
+        size_t type_size = camera_metadata_type_size[entry->type];
+        uint8_t *data_ptr;
+        if ( type_size * entry->count > 4 ) {
+            if (entry->data.offset >= metadata->data_count) {
+                ALOGE("Malformed entry data offset: %d (max %d)",
+                     entry->data.offset,
+                     metadata->data_count);
+                continue;
+            }
+            data_ptr = metadata->data + entry->data.offset;
+        } else {
+            data_ptr = entry->data.value;
+        }
+        int count = entry->count;
+        if (verbosity < 2 && count > 16) count = 16;
+
+        print_data(data_ptr, entry->type, count);
+    }
+}
+
+void print_data(const uint8_t *data_ptr, int type, int count) {
+    static int values_per_line[NUM_TYPES] = {
+        [TYPE_BYTE]     = 16,
+        [TYPE_INT32]    = 4,
+        [TYPE_FLOAT]    = 8,
+        [TYPE_INT64]    = 2,
+        [TYPE_DOUBLE]   = 4,
+        [TYPE_RATIONAL] = 2,
+    };
+    size_t type_size = camera_metadata_type_size[type];
+
+    int lines = count / values_per_line[type];
+    if (count % values_per_line[type] != 0) lines++;
+
+    char tmp1[80], tmp2[80];
+
+    int index = 0;
+    int j, k;
+    for (j = 0; j < lines; j++) {
+        tmp1[0] = 0;
+        for (k = 0;
+             k < values_per_line[type] && count > 0;
+             k++, count--, index += type_size) {
+
+            switch (type) {
+                case TYPE_BYTE:
+                    snprintf(tmp2, sizeof(tmp2), "%hhu ",
+                            *(data_ptr + index));
+                    break;
+                case TYPE_INT32:
+                    snprintf(tmp2, sizeof(tmp2), "%d ",
+                            *(int32_t*)(data_ptr + index));
+                    break;
+                case TYPE_FLOAT:
+                    snprintf(tmp2, sizeof(tmp2), "%0.2f ",
+                            *(float*)(data_ptr + index));
+                    break;
+                case TYPE_INT64:
+                    snprintf(tmp2, sizeof(tmp2), "%lld ",
+                            *(int64_t*)(data_ptr + index));
+                    break;
+                case TYPE_DOUBLE:
+                    snprintf(tmp2, sizeof(tmp2), "%0.2f ",
+                            *(float*)(data_ptr + index));
+                    break;
+                case TYPE_RATIONAL: {
+                    int32_t numerator = *(int32_t*)(data_ptr + index);
+                    int32_t denominator = *(int32_t*)(data_ptr + index + 4);
+                    snprintf(tmp2, sizeof(tmp2), "(%d / %d) ",
+                            numerator, denominator);
+                    break;
+                }
+                default:
+                    snprintf(tmp2, sizeof(tmp2), "??? ");
+            }
+            strncat(tmp1, tmp2, sizeof(tmp1));
+        }
+        ALOGD(" [ %s]", tmp1);
+    }
+}
diff --git a/camera/src/camera_metadata_tag_info.c b/camera/src/camera_metadata_tag_info.c
new file mode 100644 (file)
index 0000000..5d394e2
--- /dev/null
@@ -0,0 +1,360 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * !! Do not reference this file directly !!
+ *
+ * It is logically a part of camera_metadata.c.  It is broken out for ease of
+ * maintaining the tag info.
+ */
+
+const char *camera_metadata_section_names[ANDROID_SECTION_COUNT] = {
+    "android.request",
+    "android.control",
+    "android.control.info",
+    "android.sensor",
+    "android.sensor.info",
+    "android.lens",
+    "android.lens.info",
+    "android.flash",
+    "android.flash.info",
+    "android.hotPixel",
+    "android.hotPixel.info",
+    "android.demosaic",
+    "android.demosaic.info",
+    "android.noiseReduction",
+    "android.noiseReduction.info",
+    "android.shadingCorrection",
+    "android.shadingCorrection.info",
+    "android.geometricCorrection",
+    "android.geometricCorrection.info",
+    "android.colorCorrection",
+    "android.colorCorrection.info",
+    "android.tonemap",
+    "android.tonemap.info",
+    "android.edge",
+    "android.edge.info",
+    "android.scaler",
+    "android.scaler.info",
+    "android.jpeg",
+    "android.jpeg.info",
+    "android.statistics",
+    "android.statistics.info"
+};
+
+unsigned int camera_metadata_section_bounds[ANDROID_SECTION_COUNT][2] = {
+    { ANDROID_REQUEST_START,        ANDROID_REQUEST_END },
+    { ANDROID_LENS_START,           ANDROID_LENS_END },
+    { ANDROID_LENS_INFO_START,      ANDROID_LENS_INFO_END },
+    { ANDROID_SENSOR_START,         ANDROID_SENSOR_END },
+    { ANDROID_SENSOR_INFO_START,    ANDROID_SENSOR_INFO_END },
+    { ANDROID_FLASH_START,          ANDROID_FLASH_END },
+    { ANDROID_FLASH_INFO_START,     ANDROID_FLASH_INFO_END },
+    { ANDROID_HOT_PIXEL_START,      ANDROID_HOT_PIXEL_END },
+    { ANDROID_HOT_PIXEL_INFO_START, ANDROID_HOT_PIXEL_INFO_END },
+    { ANDROID_DEMOSAIC_START,       ANDROID_DEMOSAIC_END },
+    { ANDROID_DEMOSAIC_INFO_START,  ANDROID_DEMOSAIC_INFO_END },
+    { ANDROID_NOISE_START,          ANDROID_NOISE_END },
+    { ANDROID_NOISE_INFO_START,     ANDROID_NOISE_INFO_END },
+    { ANDROID_SHADING_START,        ANDROID_SHADING_END },
+    { ANDROID_SHADING_INFO_START,   ANDROID_SHADING_INFO_END },
+    { ANDROID_GEOMETRIC_START,      ANDROID_GEOMETRIC_END },
+    { ANDROID_GEOMETRIC_INFO_START, ANDROID_GEOMETRIC_INFO_END },
+    { ANDROID_COLOR_START,          ANDROID_COLOR_END },
+    { ANDROID_COLOR_INFO_START,     ANDROID_COLOR_INFO_END },
+    { ANDROID_TONEMAP_START,        ANDROID_TONEMAP_END },
+    { ANDROID_TONEMAP_INFO_START,   ANDROID_TONEMAP_INFO_END },
+    { ANDROID_EDGE_START,           ANDROID_EDGE_END },
+    { ANDROID_EDGE_INFO_START,      ANDROID_EDGE_INFO_END },
+    { ANDROID_SCALER_START,         ANDROID_SCALER_END },
+    { ANDROID_SCALER_INFO_START,    ANDROID_SCALER_INFO_END },
+    { ANDROID_JPEG_START,           ANDROID_JPEG_END },
+    { ANDROID_JPEG_INFO_START,      ANDROID_JPEG_INFO_END },
+    { ANDROID_STATS_START,          ANDROID_STATS_END },
+    { ANDROID_STATS_INFO_START,     ANDROID_STATS_INFO_END },
+    { ANDROID_CONTROL_START,        ANDROID_CONTROL_END },
+    { ANDROID_CONTROL_INFO_START,   ANDROID_CONTROL_INFO_END }
+};
+
+tag_info_t android_request[ANDROID_REQUEST_END -
+        ANDROID_REQUEST_START] = {
+    { "id",                          TYPE_INT32 },
+    { "metadataMode",                TYPE_BYTE },
+    { "outputStreams",               TYPE_BYTE },
+    { "frameCount",                  TYPE_INT32 }
+};
+
+tag_info_t android_control[ANDROID_CONTROL_END -
+        ANDROID_CONTROL_START] = {
+    { "mode",                        TYPE_BYTE },
+    { "aeMode",                      TYPE_BYTE },
+    { "aeRegions",                   TYPE_INT32 },
+    { "aeExposureCompensation",      TYPE_INT32 },
+    { "aeTargetFpsRange",            TYPE_INT32 },
+    { "aeAntibandingMode",           TYPE_BYTE },
+    { "awbMode",                     TYPE_BYTE },
+    { "awbRegions",                  TYPE_INT32 },
+    { "afMode",                      TYPE_BYTE },
+    { "afRegions",                   TYPE_INT32 },
+    { "afTrigger",                   TYPE_BYTE },
+    { "afState",                     TYPE_BYTE },
+    { "videoStabilizationMode",      TYPE_BYTE }
+};
+
+tag_info_t android_control_info[ANDROID_CONTROL_INFO_END -
+        ANDROID_CONTROL_INFO_START] = {
+    { "availableModes",              TYPE_BYTE },
+    { "maxRegions",                  TYPE_INT32 },
+    { "aeAvailableModes",            TYPE_BYTE },
+    { "aeCompensationStep",          TYPE_RATIONAL },
+    { "aeCompensationRange",         TYPE_INT32 },
+    { "aeAvailableTargetFpsRanges",  TYPE_INT32 },
+    { "aeAvailableAntibandingModes", TYPE_BYTE },
+    { "awbAvailableModes",           TYPE_BYTE },
+    { "afAvailableModes",            TYPE_BYTE }
+};
+
+tag_info_t android_sensor[ANDROID_SENSOR_END -
+        ANDROID_SENSOR_START] = {
+    { "exposureTime",  TYPE_INT64 },
+    { "frameDuration", TYPE_INT64 },
+    { "sensitivity",   TYPE_INT32 },
+    { "timestamp",     TYPE_INT64 }
+};
+
+tag_info_t android_sensor_info[ANDROID_SENSOR_INFO_END -
+        ANDROID_SENSOR_INFO_START] = {
+    { "exposureTimeRange",      TYPE_INT64 },
+    { "maxFrameDuration",       TYPE_INT64 },
+    { "sensitivityRange",       TYPE_INT32 },
+    { "colorFilterArrangement", TYPE_BYTE },
+    { "pixelArraySize",         TYPE_INT32 },
+    { "activeArraySize",        TYPE_INT32 },
+    { "whiteLevel",             TYPE_INT32 },
+    { "blackLevelPattern",      TYPE_INT32 },
+    { "colorTransform1",        TYPE_RATIONAL },
+    { "colorTransform2",        TYPE_RATIONAL },
+    { "referenceIlluminant1",   TYPE_BYTE },
+    { "referenceIlluminant2",   TYPE_BYTE },
+    { "forwardMatrix1",         TYPE_RATIONAL },
+    { "forwardMatrix2",         TYPE_RATIONAL },
+    { "calibrationTransform1",  TYPE_RATIONAL },
+    { "calibrationTransform2",  TYPE_RATIONAL },
+    { "baseGainFactor",         TYPE_RATIONAL },
+    { "maxAnalogSensitivity",   TYPE_INT32 },
+    { "noiseModelCoefficients", TYPE_FLOAT },
+    { "orientation",            TYPE_INT32 }
+};
+
+tag_info_t android_lens[ANDROID_LENS_END -
+        ANDROID_LENS_START] = {
+    { "focusDistance",            TYPE_FLOAT },
+    { "aperture",                 TYPE_FLOAT },
+    { "focalLength",              TYPE_FLOAT },
+    { "filterDensity",            TYPE_FLOAT },
+    { "opticalStabilizationMode", TYPE_BYTE },
+    { "focusRange",               TYPE_FLOAT }
+};
+
+tag_info_t android_lens_info[ANDROID_LENS_INFO_END -
+        ANDROID_LENS_INFO_START] = {
+    { "minimumFocusDistance",               TYPE_FLOAT },
+    { "availableFocalLengths",              TYPE_FLOAT },
+    { "availableApertures",                 TYPE_FLOAT },
+    { "availableFilterDensities",           TYPE_FLOAT },
+    { "availableOpticalStabilizationModes", TYPE_BYTE },
+    { "shadingMap",                         TYPE_FLOAT },
+    { "geometricCorrectionMap",             TYPE_FLOAT },
+    { "facing",                             TYPE_BYTE },
+    { "position",                           TYPE_FLOAT }
+};
+
+tag_info_t android_flash[ANDROID_FLASH_END -
+        ANDROID_FLASH_START] = {
+    { "mode",          TYPE_BYTE },
+    { "firingPower",   TYPE_BYTE },
+    { "firingTime",    TYPE_INT64 }
+};
+
+tag_info_t android_flash_info[ANDROID_FLASH_INFO_END -
+        ANDROID_FLASH_INFO_START] = {
+    { "available",      TYPE_BYTE },
+    { "chargeDuration", TYPE_INT64 },
+};
+
+tag_info_t android_hot_pixel[ANDROID_HOT_PIXEL_END -
+        ANDROID_HOT_PIXEL_START] = {
+    { "mode",           TYPE_BYTE }
+};
+
+tag_info_t android_hot_pixel_info[ANDROID_HOT_PIXEL_INFO_END -
+        ANDROID_HOT_PIXEL_INFO_START];
+
+tag_info_t android_demosaic[ANDROID_DEMOSAIC_END -
+        ANDROID_DEMOSAIC_START] = {
+    { "mode",          TYPE_BYTE }
+};
+
+tag_info_t android_demosaic_info[ANDROID_DEMOSAIC_INFO_END -
+        ANDROID_DEMOSAIC_INFO_START];
+
+tag_info_t android_noise[ANDROID_NOISE_END -
+        ANDROID_NOISE_START] = {
+    { "mode",          TYPE_BYTE },
+    { "strength",      TYPE_BYTE }
+};
+
+tag_info_t android_noise_info[ANDROID_NOISE_INFO_END -
+        ANDROID_NOISE_INFO_START];
+
+tag_info_t android_shading[ANDROID_SHADING_END -
+        ANDROID_SHADING_START] = {
+    { "mode",          TYPE_BYTE }
+};
+
+tag_info_t android_shading_info[ANDROID_SHADING_INFO_END -
+        ANDROID_SHADING_INFO_START];
+
+tag_info_t android_geometric[ANDROID_GEOMETRIC_END -
+        ANDROID_GEOMETRIC_START] = {
+    { "mode",          TYPE_BYTE }
+};
+
+tag_info_t android_geometric_info[ANDROID_GEOMETRIC_INFO_END -
+        ANDROID_GEOMETRIC_INFO_START];
+
+tag_info_t android_color[ANDROID_COLOR_END -
+        ANDROID_COLOR_START] = {
+    { "mode",          TYPE_BYTE },
+    { "transform",     TYPE_FLOAT }
+};
+
+tag_info_t android_color_info[ANDROID_COLOR_INFO_END -
+        ANDROID_COLOR_INFO_START] = {
+    { "availableModes", TYPE_INT32 }
+};
+
+tag_info_t android_tonemap[ANDROID_TONEMAP_END -
+        ANDROID_TONEMAP_START] = {
+    { "mode",          TYPE_BYTE },
+    { "curveRed",      TYPE_FLOAT },
+    { "curveGreen",    TYPE_FLOAT },
+    { "curveBlue",     TYPE_FLOAT }
+};
+
+tag_info_t android_tonemap_info[ANDROID_TONEMAP_INFO_END -
+        ANDROID_TONEMAP_INFO_START] = {
+    { "maxCurvePoints", TYPE_INT32 }
+};
+
+tag_info_t android_edge[ANDROID_EDGE_END -
+        ANDROID_EDGE_START] = {
+    { "mode",          TYPE_BYTE },
+    { "strength",      TYPE_BYTE }
+};
+
+tag_info_t android_edge_info[ANDROID_EDGE_INFO_END -
+        ANDROID_EDGE_INFO_START];
+
+tag_info_t android_scaler[ANDROID_SCALER_END -
+        ANDROID_SCALER_START] = {
+    { "size",          TYPE_INT32 },
+    { "format",        TYPE_BYTE },
+    { "cropRegion",    TYPE_INT32 },
+    { "rotation",      TYPE_INT32 },
+};
+
+tag_info_t android_scaler_info[ANDROID_SCALER_INFO_END -
+        ANDROID_SCALER_INFO_START] = {
+    { "availableFormats",            TYPE_INT32 },
+    { "availableSizesPerFormat",     TYPE_INT32 },
+    { "availableSizes",              TYPE_INT32 },
+    { "availableMinFrameDurations",  TYPE_INT32 },
+    { "availableMaxDigitalZoom",     TYPE_INT32 }
+};
+
+tag_info_t android_jpeg[ANDROID_JPEG_END -
+        ANDROID_JPEG_START] = {
+    { "quality",             TYPE_INT32 },
+    { "thumbnailSize",       TYPE_INT32 },
+    { "thumbnailQuality",    TYPE_INT32 },
+    { "gpsCoordinates",      TYPE_DOUBLE },
+    { "gpsProcessingMethod", TYPE_BYTE },
+    { "gpsTimestamp",        TYPE_INT64 },
+    { "orientation",         TYPE_INT32 }
+};
+
+tag_info_t android_jpeg_info[ANDROID_JPEG_INFO_END -
+        ANDROID_JPEG_INFO_START] = {
+    { "availableThumbnailSizes", TYPE_INT32 }
+};
+
+tag_info_t android_stats[ANDROID_STATS_END -
+        ANDROID_STATS_START] = {
+    { "faceDetectMode",      TYPE_BYTE },
+    { "faceRectangles",      TYPE_INT32 },
+    { "faceScores",          TYPE_BYTE },
+    { "faceLandmarks",       TYPE_INT32 },
+    { "faceIds",             TYPE_INT32 },
+    { "histogramMode",       TYPE_BYTE },
+    { "histogram",           TYPE_INT32 },
+    { "sharpnessMapMode",    TYPE_BYTE },
+    { "sharpnessMap",        TYPE_INT32 }
+};
+
+tag_info_t android_stats_info[ANDROID_STATS_INFO_END -
+        ANDROID_STATS_INFO_START] = {
+    { "availableFaceDetectModes",    TYPE_BYTE },
+    { "maxFaceCount",                TYPE_INT32 },
+    { "histogramBucketCount",        TYPE_INT32 },
+    { "maxHistogramCount",           TYPE_INT32 },
+    { "sharpnessMapSize",            TYPE_INT32 },
+    { "maxSharpnessMapValue",        TYPE_INT32 }
+};
+
+tag_info_t *tag_info[ANDROID_SECTION_COUNT] = {
+    android_request,
+    android_lens,
+    android_lens_info,
+    android_sensor,
+    android_sensor_info,
+    android_flash,
+    android_flash_info,
+    android_hot_pixel,
+    android_hot_pixel_info,
+    android_demosaic,
+    android_demosaic_info,
+    android_noise,
+    android_noise_info,
+    android_shading,
+    android_shading_info,
+    android_geometric,
+    android_geometric_info,
+    android_color,
+    android_color_info,
+    android_tonemap,
+    android_tonemap_info,
+    android_edge,
+    android_edge_info,
+    android_scaler,
+    android_scaler_info,
+    android_jpeg,
+    android_jpeg_info,
+    android_stats,
+    android_stats_info,
+    android_control,
+    android_control_info
+};
diff --git a/camera/tests/Android.mk b/camera/tests/Android.mk
new file mode 100644 (file)
index 0000000..d7a53de
--- /dev/null
@@ -0,0 +1,27 @@
+# Build the unit tests.
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SHARED_LIBRARIES := \
+       libutils \
+       libstlport \
+       libcamera_metadata
+
+LOCAL_STATIC_LIBRARIES := \
+       libgtest \
+       libgtest_main
+
+LOCAL_C_INCLUDES := \
+       bionic \
+       bionic/libstdc++/include \
+       external/gtest/include \
+       external/stlport/stlport \
+       system/media/camera/include \
+
+LOCAL_SRC_FILES := \
+       camera_metadata_tests.cpp
+
+LOCAL_MODULE := camera_metadata_tests
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_EXECUTABLE)
diff --git a/camera/tests/camera_metadata_tests.cpp b/camera/tests/camera_metadata_tests.cpp
new file mode 100644 (file)
index 0000000..3f1800e
--- /dev/null
@@ -0,0 +1,829 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "gtest/gtest.h"
+#include "system/camera_metadata.h"
+
+#include "camera_metadata_tests_fake_vendor.h"
+
+#define EXPECT_NULL(x)     EXPECT_EQ((void*)0, x)
+#define EXPECT_NOT_NULL(x) EXPECT_NE((void*)0, x)
+
+#define OK    0
+#define ERROR 1
+
+TEST(camera_metadata, allocate_normal) {
+    camera_metadata_t *m = NULL;
+    const size_t entry_capacity = 5;
+    const size_t data_capacity = 32;
+
+    m = allocate_camera_metadata(entry_capacity, data_capacity);
+
+    EXPECT_NOT_NULL(m);
+    EXPECT_EQ((size_t)0, get_camera_metadata_entry_count(m));
+    EXPECT_EQ(entry_capacity, get_camera_metadata_entry_capacity(m));
+    EXPECT_EQ((size_t)0, get_camera_metadata_data_count(m));
+    EXPECT_EQ(data_capacity, get_camera_metadata_data_capacity(m));
+
+    free_camera_metadata(m);
+}
+
+TEST(camera_metadata, allocate_nodata) {
+    camera_metadata_t *m = NULL;
+
+    m = allocate_camera_metadata(1, 0);
+
+    EXPECT_NOT_NULL(m);
+    EXPECT_EQ((size_t)0, get_camera_metadata_entry_count(m));
+    EXPECT_EQ((size_t)1, get_camera_metadata_entry_capacity(m));
+    EXPECT_EQ((size_t)0, get_camera_metadata_data_count(m));
+    EXPECT_EQ((size_t)0, get_camera_metadata_data_capacity(m));
+
+    free_camera_metadata(m);
+}
+
+TEST(camera_metadata, allocate_nothing) {
+    camera_metadata_t *m = NULL;
+
+    m = allocate_camera_metadata(0, 0);
+
+    EXPECT_NULL(m);
+}
+
+TEST(camera_metadata, place_normal) {
+    camera_metadata_t *m = NULL;
+    void *buf = NULL;
+
+    const size_t entry_capacity = 5;
+    const size_t data_capacity = 32;
+
+    size_t buf_size = calculate_camera_metadata_size(entry_capacity,
+            data_capacity);
+
+    EXPECT_TRUE(buf_size > 0);
+
+    buf = malloc(buf_size);
+
+    EXPECT_NOT_NULL(buf);
+
+    m = place_camera_metadata(buf, buf_size, entry_capacity, data_capacity);
+
+    EXPECT_EQ(buf, (uint8_t*)m);
+    EXPECT_EQ((size_t)0, get_camera_metadata_entry_count(m));
+    EXPECT_EQ(entry_capacity, get_camera_metadata_entry_capacity(m));
+    EXPECT_EQ((size_t)0, get_camera_metadata_data_count(m));
+    EXPECT_EQ(data_capacity, get_camera_metadata_data_capacity(m));
+
+    free(buf);
+}
+
+TEST(camera_metadata, place_nospace) {
+    camera_metadata_t *m = NULL;
+    void *buf = NULL;
+
+    const size_t entry_capacity = 5;
+    const size_t data_capacity = 32;
+
+    size_t buf_size = calculate_camera_metadata_size(entry_capacity,
+            data_capacity);
+
+    EXPECT_GT(buf_size, (size_t)0);
+
+    buf_size--;
+
+    buf = malloc(buf_size);
+
+    EXPECT_NOT_NULL(buf);
+
+    m = place_camera_metadata(buf, buf_size, entry_capacity, data_capacity);
+
+    EXPECT_NULL(m);
+
+    free(buf);
+}
+
+TEST(camera_metadata, place_extraspace) {
+    camera_metadata_t *m = NULL;
+    uint8_t *buf = NULL;
+
+    const size_t entry_capacity = 5;
+    const size_t data_capacity = 32;
+    const size_t extra_space = 10;
+
+    size_t buf_size = calculate_camera_metadata_size(entry_capacity,
+            data_capacity);
+
+    EXPECT_GT(buf_size, (size_t)0);
+
+    buf_size += extra_space;
+
+    buf = (uint8_t*)malloc(buf_size);
+
+    EXPECT_NOT_NULL(buf);
+
+    m = place_camera_metadata(buf, buf_size, entry_capacity, data_capacity);
+
+    EXPECT_EQ((uint8_t*)m, buf);
+    EXPECT_EQ((size_t)0, get_camera_metadata_entry_count(m));
+    EXPECT_EQ(entry_capacity, get_camera_metadata_entry_capacity(m));
+    EXPECT_EQ((size_t)0, get_camera_metadata_data_count(m));
+    EXPECT_EQ(data_capacity, get_camera_metadata_data_capacity(m));
+    EXPECT_EQ(buf + buf_size - extra_space, (uint8_t*)m + get_camera_metadata_size(m));
+
+    free(buf);
+}
+
+TEST(camera_metadata, get_size) {
+    camera_metadata_t *m = NULL;
+    const size_t entry_capacity = 5;
+    const size_t data_capacity = 32;
+
+    m = allocate_camera_metadata(entry_capacity, data_capacity);
+
+    EXPECT_EQ(calculate_camera_metadata_size(entry_capacity, data_capacity),
+            get_camera_metadata_size(m) );
+
+    EXPECT_EQ(calculate_camera_metadata_size(0,0),
+            get_camera_metadata_compact_size(m) );
+
+    free_camera_metadata(m);
+}
+
+TEST(camera_metadata, add_get_normal) {
+    camera_metadata_t *m = NULL;
+    const size_t entry_capacity = 5;
+    const size_t data_capacity = 80;
+
+    m = allocate_camera_metadata(entry_capacity, data_capacity);
+
+    int result;
+    size_t data_used = 0;
+    size_t entries_used = 0;
+
+    // INT64
+
+    int64_t exposure_time = 1000000000;
+    result = add_camera_metadata_entry(m,
+            ANDROID_SENSOR_EXPOSURE_TIME,
+            &exposure_time, 1);
+    EXPECT_EQ(OK, result);
+    data_used += calculate_camera_metadata_entry_data_size(
+            get_camera_metadata_tag_type(ANDROID_SENSOR_EXPOSURE_TIME), 1);
+    entries_used++;
+
+    // INT32
+
+    int32_t sensitivity = 800;
+    result = add_camera_metadata_entry(m,
+            ANDROID_SENSOR_SENSITIVITY,
+            &sensitivity, 1);
+    EXPECT_EQ(OK, result);
+    data_used += calculate_camera_metadata_entry_data_size(
+            get_camera_metadata_tag_type(ANDROID_SENSOR_SENSITIVITY), 1);
+    entries_used++;
+
+    // FLOAT
+
+    float focusDistance = 0.5f;
+    result = add_camera_metadata_entry(m,
+            ANDROID_LENS_FOCUS_DISTANCE,
+            &focusDistance, 1);
+    EXPECT_EQ(OK, result);
+    data_used += calculate_camera_metadata_entry_data_size(
+            get_camera_metadata_tag_type(ANDROID_LENS_FOCUS_DISTANCE), 1);
+    entries_used++;
+
+    // Array of FLOAT
+
+    float colorTransform[9] = {
+        0.9f, 0.0f, 0.0f,
+        0.2f, 0.5f, 0.0f,
+        0.0f, 0.1f, 0.7f
+    };
+    result = add_camera_metadata_entry(m,
+            ANDROID_COLOR_TRANSFORM,
+            colorTransform, 9);
+    EXPECT_EQ(OK, result);
+    data_used += calculate_camera_metadata_entry_data_size(
+            get_camera_metadata_tag_type(ANDROID_COLOR_TRANSFORM), 9);
+    entries_used++;
+
+    // Check added entries
+
+    uint32_t tag = 0;
+    uint8_t type = 0;
+    int32_t *data_int32;
+    int64_t *data_int64;
+    float *data_float;
+    size_t data_count = 0;
+
+    result = get_camera_metadata_entry(m,
+            0, &tag, &type, (void**)&data_int64, &data_count);
+    EXPECT_EQ(OK, result);
+    EXPECT_EQ(ANDROID_SENSOR_EXPOSURE_TIME, tag);
+    EXPECT_EQ(TYPE_INT64, type);
+    EXPECT_EQ((size_t)1, data_count);
+    EXPECT_EQ(exposure_time, *data_int64);
+
+    result = get_camera_metadata_entry(m,
+            1, &tag, &type, (void**)&data_int32, &data_count);
+    EXPECT_EQ(OK, result);
+    EXPECT_EQ(ANDROID_SENSOR_SENSITIVITY, tag);
+    EXPECT_EQ(TYPE_INT32, type);
+    EXPECT_EQ((size_t)1, data_count);
+    EXPECT_EQ(sensitivity, *data_int32);
+
+    result = get_camera_metadata_entry(m,
+            2, &tag, &type, (void**)&data_float, &data_count);
+    EXPECT_EQ(OK, result);
+    EXPECT_EQ(ANDROID_LENS_FOCUS_DISTANCE, tag);
+    EXPECT_EQ(TYPE_FLOAT, type);
+    EXPECT_EQ((size_t)1, data_count);
+    EXPECT_EQ(focusDistance, *data_float);
+
+    result = get_camera_metadata_entry(m,
+            3, &tag, &type, (void**)&data_float, &data_count);
+    EXPECT_EQ(OK, result);
+    EXPECT_EQ(ANDROID_COLOR_TRANSFORM, tag);
+    EXPECT_EQ(TYPE_FLOAT, type);
+    EXPECT_EQ((size_t)9, data_count);
+    for (unsigned int i=0; i < data_count; i++) {
+        EXPECT_EQ(colorTransform[i], data_float[i] );
+    }
+
+    EXPECT_EQ(calculate_camera_metadata_size(entry_capacity, data_capacity),
+            get_camera_metadata_size(m) );
+
+    EXPECT_EQ(calculate_camera_metadata_size(entries_used, data_used),
+            get_camera_metadata_compact_size(m) );
+
+    dump_camera_metadata(m, 2);
+
+    free_camera_metadata(m);
+}
+
+void add_test_metadata(camera_metadata_t *m, int entry_count) {
+
+    EXPECT_NOT_NULL(m);
+
+    int result;
+    size_t data_used = 0;
+    size_t entries_used = 0;
+    int64_t exposure_time;
+    for (int i=0; i < entry_count; i++ ) {
+        exposure_time = 100 + i * 100;
+        result = add_camera_metadata_entry(m,
+                ANDROID_SENSOR_EXPOSURE_TIME,
+                &exposure_time, 1);
+        EXPECT_EQ(OK, result);
+        data_used += calculate_camera_metadata_entry_data_size(
+                get_camera_metadata_tag_type(ANDROID_SENSOR_EXPOSURE_TIME), 1);
+        entries_used++;
+    }
+    EXPECT_EQ(data_used, get_camera_metadata_data_count(m));
+    EXPECT_EQ(entries_used, get_camera_metadata_entry_count(m));
+    EXPECT_GT(get_camera_metadata_data_capacity(m),
+            get_camera_metadata_data_count(m));
+}
+
+TEST(camera_metadata, add_get_toomany) {
+    camera_metadata_t *m = NULL;
+    const size_t entry_capacity = 5;
+    const size_t data_capacity = 50;
+    int result;
+
+    m = allocate_camera_metadata(entry_capacity, data_capacity);
+
+    add_test_metadata(m, entry_capacity);
+
+    int32_t sensitivity = 100;
+    result = add_camera_metadata_entry(m,
+            ANDROID_SENSOR_SENSITIVITY,
+            &sensitivity, 1);
+
+    EXPECT_EQ(ERROR, result);
+
+    uint32_t tag = 0;
+    uint8_t type = 0;
+    int32_t *data_int32;
+    size_t data_count = 0;
+    for (unsigned int i=0; i < entry_capacity; i++) {
+        int64_t exposure_time = 100 + i * 100;
+        result = get_camera_metadata_entry(m,
+                i, &tag, &type, (void**)&data_int32, &data_count);
+        EXPECT_EQ(OK, result);
+        EXPECT_EQ(ANDROID_SENSOR_EXPOSURE_TIME, tag);
+        EXPECT_EQ(TYPE_INT64, type);
+        EXPECT_EQ((size_t)1, data_count);
+        EXPECT_EQ(exposure_time, *data_int32);
+    }
+    tag = 0;
+    type = 0;
+    data_int32 = NULL;
+    data_count = 0;
+    result = get_camera_metadata_entry(m,
+            entry_capacity, &tag, &type, (void**)&data_int32, &data_count);
+    EXPECT_EQ(ERROR, result);
+    EXPECT_EQ((uint32_t)0, tag);
+    EXPECT_EQ((uint8_t)0, type);
+    EXPECT_EQ((size_t)0, data_count);
+    EXPECT_EQ(NULL, data_int32);
+
+    dump_camera_metadata(m, 2);
+
+    free_camera_metadata(m);
+}
+
+TEST(camera_metadata, copy_metadata) {
+    camera_metadata_t *m = NULL;
+    const size_t entry_capacity = 50;
+    const size_t data_capacity = 450;
+
+    int result;
+
+    m = allocate_camera_metadata(entry_capacity, data_capacity);
+
+    add_test_metadata(m, entry_capacity);
+
+    size_t buf_size = get_camera_metadata_compact_size(m);
+    EXPECT_LT((size_t)0, buf_size);
+
+    uint8_t *buf = (uint8_t*)malloc(buf_size);
+    EXPECT_NOT_NULL(buf);
+
+    camera_metadata_t *m2 = copy_camera_metadata(buf, buf_size, m);
+    EXPECT_NOT_NULL(m2);
+    EXPECT_EQ(buf, (uint8_t*)m2);
+    EXPECT_EQ(get_camera_metadata_entry_count(m),
+            get_camera_metadata_entry_count(m2));
+    EXPECT_EQ(get_camera_metadata_data_count(m),
+            get_camera_metadata_data_count(m2));
+    EXPECT_EQ(get_camera_metadata_entry_capacity(m2),
+            get_camera_metadata_entry_count(m2));
+    EXPECT_EQ(get_camera_metadata_data_capacity(m2),
+            get_camera_metadata_data_count(m2));
+
+    for (unsigned int i=0; i < get_camera_metadata_entry_count(m); i++) {
+        uint32_t tag, tag2;
+        uint8_t type, type2;
+        uint8_t *data, *data2;
+        size_t   data_count, data_count2;
+
+        int result;
+        result = get_camera_metadata_entry(m,
+                i, &tag, &type, (void**)&data, &data_count);
+        EXPECT_EQ(OK, result);
+        result = get_camera_metadata_entry(m2,
+                i, &tag2, &type2, (void**)&data2, &data_count2);
+        EXPECT_EQ(OK, result);
+        EXPECT_EQ(tag, tag2);
+        EXPECT_EQ(type, type2);
+        EXPECT_EQ(data_count, data_count2);
+        for (unsigned int j=0; j < data_count; j++) {
+            EXPECT_EQ(data[j], data2[j]);
+        }
+    }
+
+    free(buf);
+
+    free_camera_metadata(m);
+}
+
+TEST(camera_metadata, copy_metadata_extraspace) {
+    camera_metadata_t *m = NULL;
+    const size_t entry_capacity = 12;
+    const size_t data_capacity = 100;
+
+    const size_t extra_space = 10;
+
+    int result;
+
+    m = allocate_camera_metadata(entry_capacity, data_capacity);
+
+    add_test_metadata(m, entry_capacity);
+
+    size_t buf_size = get_camera_metadata_compact_size(m);
+    EXPECT_LT((size_t)0, buf_size);
+    buf_size += extra_space;
+
+    uint8_t *buf = (uint8_t*)malloc(buf_size);
+    EXPECT_NOT_NULL(buf);
+
+    camera_metadata_t *m2 = copy_camera_metadata(buf, buf_size, m);
+    EXPECT_NOT_NULL(m2);
+    EXPECT_EQ(buf, (uint8_t*)m2);
+    EXPECT_EQ(get_camera_metadata_entry_count(m),
+            get_camera_metadata_entry_count(m2));
+    EXPECT_EQ(get_camera_metadata_data_count(m),
+            get_camera_metadata_data_count(m2));
+    EXPECT_EQ(get_camera_metadata_entry_capacity(m2),
+            get_camera_metadata_entry_count(m2));
+    EXPECT_EQ(get_camera_metadata_data_capacity(m2),
+            get_camera_metadata_data_count(m2));
+    EXPECT_EQ(buf + buf_size - extra_space,
+            (uint8_t*)m2 + get_camera_metadata_size(m2) );
+
+    for (unsigned int i=0; i < get_camera_metadata_entry_count(m); i++) {
+        uint32_t tag, tag2;
+        uint8_t type, type2;
+        uint8_t *data, *data2;
+        size_t   data_count, data_count2;
+
+        int result;
+        result = get_camera_metadata_entry(m,
+                i, &tag, &type, (void**)&data, &data_count);
+        EXPECT_EQ(OK, result);
+        result = get_camera_metadata_entry(m2,
+                i, &tag2, &type2, (void**)&data2, &data_count2);
+        EXPECT_EQ(OK, result);
+        EXPECT_EQ(tag, tag2);
+        EXPECT_EQ(type, type2);
+        EXPECT_EQ(data_count, data_count2);
+        for (unsigned int j=0; j < data_count; j++) {
+            EXPECT_EQ(data[j], data2[j]);
+        }
+    }
+
+    free(buf);
+
+    free_camera_metadata(m);
+}
+
+TEST(camera_metadata, copy_metadata_nospace) {
+    camera_metadata_t *m = NULL;
+    const size_t entry_capacity = 5;
+    const size_t data_capacity = 50;
+
+    int result;
+
+    m = allocate_camera_metadata(entry_capacity, data_capacity);
+
+    add_test_metadata(m, entry_capacity);
+
+    size_t buf_size = get_camera_metadata_compact_size(m);
+    EXPECT_LT((size_t)0, buf_size);
+
+    buf_size--;
+
+    uint8_t *buf = (uint8_t*)malloc(buf_size);
+    EXPECT_NOT_NULL(buf);
+
+    camera_metadata_t *m2 = copy_camera_metadata(buf, buf_size, m);
+    EXPECT_NULL(m2);
+
+    free(buf);
+
+    free_camera_metadata(m);
+}
+
+TEST(camera_metadata, append_metadata) {
+    camera_metadata_t *m = NULL;
+    const size_t entry_capacity = 5;
+    const size_t data_capacity = 50;
+
+    int result;
+
+    m = allocate_camera_metadata(entry_capacity, data_capacity);
+
+    add_test_metadata(m, entry_capacity);
+
+    camera_metadata_t *m2 = NULL;
+
+    m2 = allocate_camera_metadata(entry_capacity*2, data_capacity*2);
+    EXPECT_NOT_NULL(m2);
+
+    result = append_camera_metadata(m2, m);
+
+    EXPECT_EQ(OK, result);
+
+    EXPECT_EQ(get_camera_metadata_entry_count(m), get_camera_metadata_entry_count(m2));
+    EXPECT_EQ(get_camera_metadata_data_count(m),  get_camera_metadata_data_count(m2));
+    EXPECT_EQ(entry_capacity*2, get_camera_metadata_entry_capacity(m2));
+    EXPECT_EQ(data_capacity*2,  get_camera_metadata_data_capacity(m2));
+
+    for (unsigned int i=0; i < get_camera_metadata_entry_count(m); i++) {
+        uint32_t tag, tag2;
+        uint8_t type, type2;
+        uint8_t *data, *data2;
+        size_t   data_count, data_count2;
+
+        int result;
+        result = get_camera_metadata_entry(m,
+                i, &tag, &type, (void**)&data, &data_count);
+        EXPECT_EQ(OK, result);
+        result = get_camera_metadata_entry(m2,
+                i, &tag2, &type2, (void**)&data2, &data_count2);
+        EXPECT_EQ(OK, result);
+        EXPECT_EQ(tag, tag2);
+        EXPECT_EQ(type, type2);
+        EXPECT_EQ(data_count, data_count2);
+        for (unsigned int j=0; j < data_count; j++) {
+            EXPECT_EQ(data[j], data2[j]);
+        }
+    }
+
+    result = append_camera_metadata(m2, m);
+
+    EXPECT_EQ(OK, result);
+
+    EXPECT_EQ(get_camera_metadata_entry_count(m)*2, get_camera_metadata_entry_count(m2));
+    EXPECT_EQ(get_camera_metadata_data_count(m)*2,  get_camera_metadata_data_count(m2));
+    EXPECT_EQ(entry_capacity*2, get_camera_metadata_entry_capacity(m2));
+    EXPECT_EQ(data_capacity*2,  get_camera_metadata_data_capacity(m2));
+
+    for (unsigned int i=0; i < get_camera_metadata_entry_count(m2); i++) {
+        uint32_t tag, tag2;
+        uint8_t type, type2;
+        uint8_t *data, *data2;
+        size_t   data_count, data_count2;
+
+        int result;
+        result = get_camera_metadata_entry(m,
+                i % entry_capacity, &tag, &type, (void**)&data, &data_count);
+        EXPECT_EQ(OK, result);
+        result = get_camera_metadata_entry(m2,
+                i, &tag2, &type2, (void**)&data2, &data_count2);
+        EXPECT_EQ(OK, result);
+        EXPECT_EQ(tag, tag2);
+        EXPECT_EQ(type, type2);
+        EXPECT_EQ(data_count, data_count2);
+        for (unsigned int j=0; j < data_count; j++) {
+            EXPECT_EQ(data[j], data2[j]);
+        }
+    }
+
+    free_camera_metadata(m);
+    free_camera_metadata(m2);
+}
+
+TEST(camera_metadata, append_metadata_nospace) {
+    camera_metadata_t *m = NULL;
+    const size_t entry_capacity = 5;
+    const size_t data_capacity = 50;
+
+    int result;
+
+    m = allocate_camera_metadata(entry_capacity, data_capacity);
+
+    add_test_metadata(m, entry_capacity);
+
+    camera_metadata_t *m2 = NULL;
+
+    m2 = allocate_camera_metadata(entry_capacity-1, data_capacity);
+    EXPECT_NOT_NULL(m2);
+
+    result = append_camera_metadata(m2, m);
+
+    EXPECT_EQ(ERROR, result);
+    EXPECT_EQ((size_t)0, get_camera_metadata_entry_count(m2));
+    EXPECT_EQ((size_t)0, get_camera_metadata_data_count(m2));
+
+    free_camera_metadata(m);
+    free_camera_metadata(m2);
+}
+
+TEST(camera_metadata, append_metadata_onespace) {
+    camera_metadata_t *m = NULL;
+    const size_t entry_capacity = 5;
+    const size_t data_capacity = 50;
+    const size_t entry_capacity2 = entry_capacity * 2 - 2;
+    const size_t data_capacity2 = data_capacity * 2;
+    int result;
+
+    m = allocate_camera_metadata(entry_capacity, data_capacity);
+
+    add_test_metadata(m, entry_capacity);
+
+    camera_metadata_t *m2 = NULL;
+
+    m2 = allocate_camera_metadata(entry_capacity2, data_capacity2);
+    EXPECT_NOT_NULL(m2);
+
+    result = append_camera_metadata(m2, m);
+
+    EXPECT_EQ(OK, result);
+
+    EXPECT_EQ(get_camera_metadata_entry_count(m), get_camera_metadata_entry_count(m2));
+    EXPECT_EQ(get_camera_metadata_data_count(m),  get_camera_metadata_data_count(m2));
+    EXPECT_EQ(entry_capacity2, get_camera_metadata_entry_capacity(m2));
+    EXPECT_EQ(data_capacity2,  get_camera_metadata_data_capacity(m2));
+
+    for (unsigned int i=0; i < get_camera_metadata_entry_count(m); i++) {
+        uint32_t tag, tag2;
+        uint8_t type, type2;
+        uint8_t *data, *data2;
+        size_t   data_count, data_count2;
+
+        int result;
+        result = get_camera_metadata_entry(m,
+                i, &tag, &type, (void**)&data, &data_count);
+        EXPECT_EQ(OK, result);
+        result = get_camera_metadata_entry(m2,
+                i, &tag2, &type2, (void**)&data2, &data_count2);
+        EXPECT_EQ(OK, result);
+        EXPECT_EQ(tag, tag2);
+        EXPECT_EQ(type, type2);
+        EXPECT_EQ(data_count, data_count2);
+        for (unsigned int j=0; j < data_count; j++) {
+            EXPECT_EQ(data[j], data2[j]);
+        }
+    }
+
+    result = append_camera_metadata(m2, m);
+
+    EXPECT_EQ(ERROR, result);
+    EXPECT_EQ(entry_capacity, get_camera_metadata_entry_count(m2));
+    EXPECT_EQ(get_camera_metadata_data_count(m),
+            get_camera_metadata_data_count(m2));
+    EXPECT_EQ(entry_capacity2, get_camera_metadata_entry_capacity(m2));
+    EXPECT_EQ(data_capacity2,  get_camera_metadata_data_capacity(m2));
+
+    for (unsigned int i=0; i < get_camera_metadata_entry_count(m2); i++) {
+        uint32_t tag, tag2;
+        uint8_t type, type2;
+        uint8_t *data, *data2;
+        size_t   data_count, data_count2;
+
+        int result;
+        result = get_camera_metadata_entry(m,
+                i % entry_capacity, &tag, &type, (void**)&data, &data_count);
+        EXPECT_EQ(OK, result);
+        result = get_camera_metadata_entry(m2,
+                i, &tag2, &type2, (void**)&data2, &data_count2);
+        EXPECT_EQ(OK, result);
+        EXPECT_EQ(tag, tag2);
+        EXPECT_EQ(type, type2);
+        EXPECT_EQ(data_count, data_count2);
+        for (unsigned int j=0; j < data_count; j++) {
+            EXPECT_EQ(data[j], data2[j]);
+        }
+    }
+
+    free_camera_metadata(m);
+    free_camera_metadata(m2);
+}
+
+TEST(camera_metadata, vendor_tags) {
+    camera_metadata_t *m = NULL;
+    const size_t entry_capacity = 5;
+    const size_t data_capacity = 50;
+    int result;
+
+    m = allocate_camera_metadata(entry_capacity, data_capacity);
+
+    uint8_t superMode = 5;
+    result = add_camera_metadata_entry(m,
+            FAKEVENDOR_SENSOR_SUPERMODE,
+            &superMode, 1);
+    EXPECT_EQ(ERROR, result);
+
+    result = add_camera_metadata_entry(m,
+            ANDROID_REQUEST_METADATA_MODE,
+            &superMode, 1);
+    EXPECT_EQ(OK, result);
+
+    EXPECT_NULL(get_camera_metadata_section_name(FAKEVENDOR_SENSOR_SUPERMODE));
+    EXPECT_NULL(get_camera_metadata_tag_name(FAKEVENDOR_SENSOR_SUPERMODE));
+    EXPECT_EQ(-1, get_camera_metadata_tag_type(FAKEVENDOR_SENSOR_SUPERMODE));
+
+    set_camera_metadata_vendor_tag_ops(&fakevendor_query_ops);
+
+    result = add_camera_metadata_entry(m,
+            FAKEVENDOR_SENSOR_SUPERMODE,
+            &superMode, 1);
+    EXPECT_EQ(OK, result);
+
+    result = add_camera_metadata_entry(m,
+            ANDROID_REQUEST_METADATA_MODE,
+            &superMode, 1);
+    EXPECT_EQ(OK, result);
+
+    result = add_camera_metadata_entry(m,
+            FAKEVENDOR_SCALER_END,
+            &superMode, 1);
+    EXPECT_EQ(ERROR, result);
+
+    EXPECT_STREQ("com.fakevendor.sensor",
+            get_camera_metadata_section_name(FAKEVENDOR_SENSOR_SUPERMODE));
+    EXPECT_STREQ("superMode",
+            get_camera_metadata_tag_name(FAKEVENDOR_SENSOR_SUPERMODE));
+    EXPECT_EQ(TYPE_BYTE,
+            get_camera_metadata_tag_type(FAKEVENDOR_SENSOR_SUPERMODE));
+
+    EXPECT_STREQ("com.fakevendor.scaler",
+            get_camera_metadata_section_name(FAKEVENDOR_SCALER_END));
+    EXPECT_NULL(get_camera_metadata_tag_name(FAKEVENDOR_SCALER_END));
+    EXPECT_EQ(-1, get_camera_metadata_tag_type(FAKEVENDOR_SCALER_END));
+
+    set_camera_metadata_vendor_tag_ops(NULL);
+
+    result = add_camera_metadata_entry(m,
+            FAKEVENDOR_SENSOR_SUPERMODE,
+            &superMode, 1);
+    EXPECT_EQ(ERROR, result);
+
+    result = add_camera_metadata_entry(m,
+            ANDROID_REQUEST_METADATA_MODE,
+            &superMode, 1);
+    EXPECT_EQ(OK, result);
+
+    EXPECT_NULL(get_camera_metadata_section_name(FAKEVENDOR_SENSOR_SUPERMODE));
+    EXPECT_NULL(get_camera_metadata_tag_name(FAKEVENDOR_SENSOR_SUPERMODE));
+    EXPECT_EQ(-1, get_camera_metadata_tag_type(FAKEVENDOR_SENSOR_SUPERMODE));
+
+    free_camera_metadata(m);
+}
+
+TEST(camera_metadata, add_all_tags) {
+    int total_tag_count = 0;
+    for (int i = 0; i < ANDROID_SECTION_COUNT; i++) {
+        total_tag_count += camera_metadata_section_bounds[i][1] -
+                camera_metadata_section_bounds[i][0];
+    }
+    int entry_data_count = 3;
+    int conservative_data_space = total_tag_count * entry_data_count * 8;
+    uint8_t data[entry_data_count * 8];
+    int32_t *data_int32 = (int32_t *)data;
+    float *data_float   = (float *)data;
+    int64_t *data_int64 = (int64_t *)data;
+    double *data_double = (double *)data;
+    camera_metadata_rational_t *data_rational = (camera_metadata_rational_t *)data;
+
+    camera_metadata_t *m = allocate_camera_metadata(total_tag_count, conservative_data_space);
+
+    ASSERT_NE((void*)NULL, (void*)m);
+
+    int result;
+
+    int counter = 0;
+    for (int i = 0; i < ANDROID_SECTION_COUNT; i++) {
+        for (uint32_t tag = camera_metadata_section_bounds[i][0];
+                tag < camera_metadata_section_bounds[i][1];
+             tag++, counter++) {
+            int type = get_camera_metadata_tag_type(tag);
+            ASSERT_NE(-1, type);
+
+            switch (type) {
+                case TYPE_BYTE:
+                    data[0] = tag & 0xFF;
+                    data[1] = (tag >> 8) & 0xFF;
+                    data[2] = (tag >> 16) & 0xFF;
+                    break;
+                case TYPE_INT32:
+                    data_int32[0] = tag;
+                    data_int32[1] = i;
+                    data_int32[2] = counter;
+                    break;
+                case TYPE_FLOAT:
+                    data_float[0] = tag;
+                    data_float[1] = i;
+                    data_float[2] = counter / (float)total_tag_count;
+                    break;
+                case TYPE_INT64:
+                    data_int64[0] = (int64_t)tag | ( (int64_t)tag << 32);
+                    data_int64[1] = i;
+                    data_int64[2] = counter;
+                    break;
+                case TYPE_DOUBLE:
+                    data_double[0] = tag;
+                    data_double[1] = i;
+                    data_double[2] = counter / (double)total_tag_count;
+                    break;
+                case TYPE_RATIONAL:
+                    data_rational[0].numerator = tag;
+                    data_rational[0].denominator = 1;
+                    data_rational[1].numerator = i;
+                    data_rational[1].denominator = 1;
+                    data_rational[2].numerator = counter;
+                    data_rational[2].denominator = total_tag_count;
+                    break;
+                default:
+                    FAIL() << "Unknown type field encountered:" << type;
+                    break;
+            }
+            result = add_camera_metadata_entry(m,
+                    tag,
+                    data,
+                    entry_data_count);
+            ASSERT_EQ(OK, result);
+
+        }
+    }
+
+    dump_camera_metadata(m, 2);
+
+    free_camera_metadata(m);
+}
diff --git a/camera/tests/camera_metadata_tests_fake_vendor.h b/camera/tests/camera_metadata_tests_fake_vendor.h
new file mode 100644 (file)
index 0000000..8522fa6
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Fake vendor extensions for testing
+ */
+
+#ifndef TESTING_CAMERA_METADATA_FAKEVENDOR_H
+#define TESTING_CAMERA_METADATA_FAKEVENDOR_H
+
+enum vendor_extension_section {
+    FAKEVENDOR_SENSOR = VENDOR_SECTION,
+    FAKEVENDOR_SENSOR_INFO,
+    FAKEVENDOR_COLORCORRECTION,
+    FAKEVENDOR_SCALER,
+    FAKEVENDOR_SECTION_END
+};
+
+const int FAKEVENDOR_SECTION_COUNT = FAKEVENDOR_SECTION_END - VENDOR_SECTION;
+
+enum vendor_extension_section_ranges {
+    FAKEVENDOR_SENSOR_START          = FAKEVENDOR_SENSOR << 16,
+    FAKEVENDOR_SENSOR_I_START        = FAKEVENDOR_SENSOR_INFO << 16,
+    FAKEVENDOR_COLORCORRECTION_START = FAKEVENDOR_COLORCORRECTION << 16,
+    FAKEVENDOR_SCALER_START          = FAKEVENDOR_SCALER << 16
+};
+
+enum vendor_extension_tags {
+    FAKEVENDOR_SENSOR_SUPERMODE = FAKEVENDOR_SENSOR_START,
+    FAKEVENDOR_SENSOR_DOUBLE_EXPOSURE,
+    FAKEVENDOR_SENSOR_END,
+
+    FAKEVENDOR_SENSOR_AVAILABLE_SUPERMODES = FAKEVENDOR_SENSOR_I_START,
+    FAKEVENDOR_SENSOR_I_END,
+
+    FAKEVENDOR_COLORCORRECTION_3DLUT_MODE = FAKEVENDOR_COLORCORRECTION_START,
+    FAKEVENDOR_COLORCORRECTION_3DLUT_TABLES,
+    FAKEVENDOR_COLORCORRECTION_END,
+
+    FAKEVENDOR_SCALER_DOWNSCALE_MODE = FAKEVENDOR_SCALER_START,
+    FAKEVENDOR_SCALER_DOWNSCALE_COEFF,
+    FAKEVENDOR_SCALER_END
+};
+
+typedef struct vendor_tag_info {
+    const char *tag_name;
+    uint8_t     tag_type;
+} vendor_tag_info_t;
+
+const char *fakevendor_section_names[FAKEVENDOR_SECTION_COUNT] = {
+    "com.fakevendor.sensor",
+    "com.fakevendor.sensor.info",
+    "com.fakevendor.colorCorrection",
+    "com.fakevendor.scaler"
+};
+
+unsigned int fakevendor_section_bounds[FAKEVENDOR_SECTION_COUNT][2] = {
+    { FAKEVENDOR_SENSOR_START,          FAKEVENDOR_SENSOR_END },
+    { FAKEVENDOR_SENSOR_I_START,        FAKEVENDOR_SENSOR_I_END },
+    { FAKEVENDOR_COLORCORRECTION_START, FAKEVENDOR_COLORCORRECTION_END },
+    { FAKEVENDOR_SCALER_START,          FAKEVENDOR_SCALER_END}
+};
+
+vendor_tag_info_t fakevendor_sensor[FAKEVENDOR_SENSOR_END -
+        FAKEVENDOR_SENSOR_START] = {
+    { "superMode",       TYPE_BYTE },
+    { "doubleExposure",  TYPE_INT64 }
+};
+
+vendor_tag_info_t fakevendor_sensor_info[FAKEVENDOR_SENSOR_I_END -
+        FAKEVENDOR_SENSOR_I_START] = {
+    { "availableSuperModes",   TYPE_BYTE }
+};
+
+vendor_tag_info_t fakevendor_color_correction[FAKEVENDOR_COLORCORRECTION_END -
+        FAKEVENDOR_COLORCORRECTION_START] = {
+    { "3dLutMode",   TYPE_BYTE },
+    { "3dLutTables", TYPE_FLOAT }
+};
+
+vendor_tag_info_t fakevendor_scaler[FAKEVENDOR_SCALER_END -
+        FAKEVENDOR_SCALER_START] = {
+    { "downscaleMode",  TYPE_BYTE },
+    { "downscaleCoefficients", TYPE_FLOAT }
+};
+
+vendor_tag_info_t *fakevendor_tag_info[FAKEVENDOR_SECTION_COUNT] = {
+    fakevendor_sensor,
+    fakevendor_sensor_info,
+    fakevendor_color_correction,
+    fakevendor_scaler
+};
+
+const char *get_fakevendor_section_name(uint32_t tag) {
+    int tag_section = (tag >> 16) - VENDOR_SECTION;
+    if (tag_section < 0 ||
+            tag_section >= FAKEVENDOR_SECTION_COUNT) return NULL;
+
+    return fakevendor_section_names[tag_section];
+}
+
+const char *get_fakevendor_tag_name(uint32_t tag) {
+    int tag_section = (tag >> 16) - VENDOR_SECTION;
+    if (tag_section < 0
+            || tag_section >= FAKEVENDOR_SECTION_COUNT
+            || tag >= fakevendor_section_bounds[tag_section][1]) return NULL;
+    int tag_index = tag & 0xFFFF;
+    return fakevendor_tag_info[tag_section][tag_index].tag_name;
+}
+
+int get_fakevendor_tag_type(uint32_t tag) {
+    int tag_section = (tag >> 16) - VENDOR_SECTION;
+    if (tag_section < 0
+            || tag_section >= FAKEVENDOR_SECTION_COUNT
+            || tag >= fakevendor_section_bounds[tag_section][1]) return -1;
+    int tag_index = tag & 0xFFFF;
+    return fakevendor_tag_info[tag_section][tag_index].tag_type;
+}
+
+static const vendor_tag_query_ops_t fakevendor_query_ops = {
+    get_fakevendor_section_name,
+    get_fakevendor_tag_name,
+    get_fakevendor_tag_type
+};
+
+#endif