From d8afb4d1a4245b2a9d722cbb358a4d6febed89cf Mon Sep 17 00:00:00 2001 From: Eino-Ville Talvala Date: Fri, 10 Feb 2012 14:27:08 -0800 Subject: [PATCH] Add a camera metadata structure and utility methods Change-Id: I320cc33f31ebd8ce183572a447df8fae691eec0d --- camera/include/system/camera_metadata.h | 327 +++++++++ camera/include/system/camera_metadata_tags.h | 291 ++++++++ camera/src/Android.mk | 24 + camera/src/camera_metadata.c | 500 ++++++++++++++ camera/src/camera_metadata_tag_info.c | 360 ++++++++++ camera/tests/Android.mk | 27 + camera/tests/camera_metadata_tests.cpp | 829 +++++++++++++++++++++++ camera/tests/camera_metadata_tests_fake_vendor.h | 139 ++++ 8 files changed, 2497 insertions(+) create mode 100644 camera/include/system/camera_metadata.h create mode 100644 camera/include/system/camera_metadata_tags.h create mode 100644 camera/src/Android.mk create mode 100644 camera/src/camera_metadata.c create mode 100644 camera/src/camera_metadata_tag_info.c create mode 100644 camera/tests/Android.mk create mode 100644 camera/tests/camera_metadata_tests.cpp create mode 100644 camera/tests/camera_metadata_tests_fake_vendor.h diff --git a/camera/include/system/camera_metadata.h b/camera/include/system/camera_metadata.h new file mode 100644 index 00000000..424fc0f2 --- /dev/null +++ b/camera/include/system/camera_metadata.h @@ -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 +#include +#include + +#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 index 00000000..1fcfacb6 --- /dev/null +++ b/camera/include/system/camera_metadata_tags.h @@ -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 index 00000000..19a6f5b9 --- /dev/null +++ b/camera/src/Android.mk @@ -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 index 00000000..a481bec5 --- /dev/null +++ b/camera/src/camera_metadata.c @@ -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 +#include + +#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 index 00000000..5d394e2f --- /dev/null +++ b/camera/src/camera_metadata_tag_info.c @@ -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 index 00000000..d7a53de1 --- /dev/null +++ b/camera/tests/Android.mk @@ -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 index 00000000..3f1800ec --- /dev/null +++ b/camera/tests/camera_metadata_tests.cpp @@ -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 index 00000000..8522fa66 --- /dev/null +++ b/camera/tests/camera_metadata_tests_fake_vendor.h @@ -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 -- 2.11.0