OSDN Git Service

Improvements to camera metadata handling.
authorEino-Ville Talvala <etalvala@google.com>
Thu, 10 May 2012 21:22:28 +0000 (14:22 -0700)
committerEino-Ville Talvala <etalvala@google.com>
Tue, 15 May 2012 01:08:11 +0000 (18:08 -0700)
- Cleaner interface to get/find
- Adds delete entry, an expensive O(n) operation
- Adds update entry, which is O(n) sometimes
- Minor bugfixes:
  - Keep sorted state when appending empty buffers
  - Misspelling of camera_metadata_type_size in header
  - Missing entry in type name array

Bug: 6243944
Change-Id: I316507d6adcc22aff6e7c464c6c484f31ef1510d

camera/include/system/camera_metadata.h
camera/src/camera_metadata.c
camera/tests/camera_metadata_tests.cpp

index 6a11cfb..a1d19b3 100644 (file)
@@ -71,10 +71,32 @@ typedef struct camera_metadata_rational {
 } camera_metadata_rational_t;
 
 /**
+ * A reference to a metadata entry in a buffer.
+ *
+ * The data union pointers point to the real data in the buffer, and can be
+ * modified in-place if the count does not need to change. The count is the
+ * number of entries in data of the entry's type, not a count of bytes.
+ */
+typedef struct camera_metadata_entry {
+    size_t   index;
+    uint32_t tag;
+    uint8_t  type;
+    size_t   count;
+    union {
+        uint8_t *u8;
+        int32_t *i32;
+        float   *f;
+        int64_t *i64;
+        double  *d;
+        camera_metadata_rational_t *r;
+    } data;
+} camera_metadata_entry_t;
+
+/**
  * Size in bytes of each entry type
  */
 ANDROID_API
-extern size_t camera_metadata_type_sizes[NUM_TYPES];
+extern size_t camera_metadata_type_size[NUM_TYPES];
 
 /**
  * Main definitions for the metadata entry and array structures
@@ -90,9 +112,9 @@ extern size_t camera_metadata_type_sizes[NUM_TYPES];
  * 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.
+ * Entries are not sorted by default, 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()
@@ -241,46 +263,63 @@ int add_camera_metadata_entry(camera_metadata_t *dst,
         size_t data_count);
 
 /**
- * Sort the metadata buffer for fast searching. If already sorted, does
- * nothing. Adding or appending entries to the buffer will place the buffer back
- * into an unsorted state.
+ * Sort the metadata buffer for fast searching. If already marked as sorted,
+ * does nothing. Adding or appending entries to the buffer will place the buffer
+ * back into an unsorted state.
  */
 ANDROID_API
 int sort_camera_metadata(camera_metadata_t *dst);
 
 /**
- * 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.
+ * Get metadata entry at position index in the metadata buffer.
  *
- * src and index are inputs; tag, type, data, and data_count are outputs. Any of
- * the outputs can be set to NULL to skip reading that value.
+ * src and index are inputs; the passed-in entry is updated with the details of
+ * the entry. The data pointer points to the real data in the buffer, and can be
+ * updated as long as the data count does not change.
  */
 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);
+        size_t index,
+        camera_metadata_entry_t *entry);
 
 /**
  * Find an entry with given tag value. If not found, returns -ENOENT. Otherwise,
- * returns entry contents like get_camera_metadata_entry. Any of
- * the outputs can be set to NULL to skip reading that value.
+ * returns entry contents like get_camera_metadata_entry.
  *
- * Note: Returns only the first entry with a given tag. To speed up searching
- * for tags, sort the metadata structure first by calling
- * sort_camera_metadata().
+ * If multiple entries with the same tag exist, does not have any guarantees on
+ * which is returned. To speed up searching for tags, sort the metadata
+ * structure first by calling sort_camera_metadata().
  */
 ANDROID_API
 int find_camera_metadata_entry(camera_metadata_t *src,
         uint32_t tag,
-        uint8_t *type,
-        void **data,
-        size_t *data_count);
+        camera_metadata_entry_t *entry);
+
+/**
+ * Delete an entry at given index. This is an expensive operation, since it
+ * requires repacking entries and possibly entry data. This also invalidates any
+ * existing camera_metadata_entry.data pointers to this buffer. Sorting is
+ * maintained.
+ */
+ANDROID_API
+int delete_camera_metadata_entry(camera_metadata_t *dst,
+        size_t index);
+
+/**
+ * Updates a metadata entry with new data. If the data size is changing, may
+ * need to adjust the data array, making this an O(N) operation. If the data
+ * size is the same or still fits in the entry space, this is O(1). Maintains
+ * sorting, but invalidates camera_metadata_entry instances that point to the
+ * updated entry. If a non-NULL value is passed in to entry, the entry structure
+ * is updated to match the new buffer state.  Returns a non-zero value if there
+ * is no room for the new data in the buffer.
+ */
+ANDROID_API
+int update_camera_metadata_entry(camera_metadata_t *dst,
+        size_t index,
+        const void *data,
+        size_t data_count,
+        camera_metadata_entry_t *updated_entry);
 
 /**
  * Retrieve human-readable name of section the tag is in. Returns NULL if
index 1991835..a16b5b7 100644 (file)
@@ -29,7 +29,7 @@
  * array; otherwise, it can found in the parent's data array at index
  * data.offset.
  */
-typedef struct camera_metadata_entry {
+typedef struct camera_metadata_buffer_entry {
     uint32_t tag;
     size_t   count;
     union {
@@ -38,7 +38,7 @@ typedef struct camera_metadata_entry {
     } data;
     uint8_t  type;
     uint8_t  reserved[3];
-} __attribute__((packed)) camera_metadata_entry_t;
+} __attribute__((packed)) camera_metadata_buffer_entry_t;
 
 /**
  * A packet of metadata. This is a list of entries, each of which may point to
@@ -47,27 +47,27 @@ typedef struct camera_metadata_entry {
  * 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       |
- *   |----------------------------------------|
+ *   |-----------------------------------------------|
+ *   | camera_metadata_t                             |
+ *   |                                               |
+ *   |-----------------------------------------------|
+ *   | reserved for future expansion                 |
+ *   |-----------------------------------------------|
+ *   | camera_metadata_buffer_entry_t #0             |
+ *   |-----------------------------------------------|
+ *   | ....                                          |
+ *   |-----------------------------------------------|
+ *   | camera_metadata_buffer_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.
  *
@@ -80,7 +80,7 @@ struct camera_metadata {
     uint32_t                 flags;
     size_t                   entry_count;
     size_t                   entry_capacity;
-    camera_metadata_entry_t *entries;
+    camera_metadata_buffer_entry_t *entries;
     size_t                   data_count;
     size_t                   data_capacity;
     uint8_t                 *data;
@@ -116,6 +116,7 @@ char *camera_metadata_type_names[NUM_TYPES] = {
     [TYPE_INT32]    = "int32",
     [TYPE_FLOAT]    = "float",
     [TYPE_INT64]    = "int64",
+    [TYPE_DOUBLE]   = "double",
     [TYPE_RATIONAL] = "rational"
 };
 
@@ -145,7 +146,7 @@ camera_metadata_t *place_camera_metadata(void *dst,
     metadata->flags = 0;
     metadata->entry_count = 0;
     metadata->entry_capacity = entry_capacity;
-    metadata->entries = (camera_metadata_entry_t*)(metadata + 1);
+    metadata->entries = (camera_metadata_buffer_entry_t*)(metadata + 1);
     metadata->data_count = 0;
     metadata->data_capacity = data_capacity;
     metadata->size = memory_needed;
@@ -165,7 +166,7 @@ void free_camera_metadata(camera_metadata_t *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(camera_metadata_buffer_entry_t[entry_count]);
     memory_needed += sizeof(uint8_t[data_count]);
     return memory_needed;
 }
@@ -221,7 +222,7 @@ camera_metadata_t* copy_camera_metadata(void *dst, size_t dst_size,
     metadata->flags = src->flags;
     metadata->entry_count = src->entry_count;
     metadata->entry_capacity = src->entry_count;
-    metadata->entries = (camera_metadata_entry_t*)
+    metadata->entries = (camera_metadata_buffer_entry_t*)
              ((uint8_t *)(metadata + 1) + reserved_size);
     metadata->data_count = src->data_count;
     metadata->data_capacity = src->data_count;
@@ -232,7 +233,7 @@ camera_metadata_t* copy_camera_metadata(void *dst, size_t dst_size,
         memcpy(metadata->reserved, src->reserved, reserved_size);
     }
     memcpy(metadata->entries, src->entries,
-            sizeof(camera_metadata_entry_t[metadata->entry_count]));
+            sizeof(camera_metadata_buffer_entry_t[metadata->entry_count]));
     memcpy(metadata->data, src->data,
             sizeof(uint8_t[metadata->data_count]));
 
@@ -247,7 +248,7 @@ int append_camera_metadata(camera_metadata_t *dst,
     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]));
+            sizeof(camera_metadata_buffer_entry_t[src->entry_count]));
     memcpy(dst->data + dst->data_count, src->data,
             sizeof(uint8_t[src->data_count]));
     if (dst->data_count != 0) {
@@ -255,15 +256,23 @@ int append_camera_metadata(camera_metadata_t *dst,
         for (i = dst->entry_count;
              i < dst->entry_count + src->entry_count;
              i++) {
-            camera_metadata_entry_t *entry = dst->entries + i;
+            camera_metadata_buffer_entry_t *entry = dst->entries + i;
             if ( camera_metadata_type_size[entry->type] * entry->count > 4 ) {
                 entry->data.offset += dst->data_count;
             }
         }
     }
+    if (dst->entry_count == 0) {
+        // Appending onto empty buffer, keep sorted state
+        dst->flags |= src->flags & FLAG_SORTED;
+    } else if (src->entry_count != 0) {
+        // Both src, dst are nonempty, cannot assume sort remains
+        dst->flags &= ~FLAG_SORTED;
+    } else {
+        // Src is empty, keep dst sorted state
+    }
     dst->entry_count += src->entry_count;
     dst->data_count += src->data_count;
-    dst->flags &= ~FLAG_SORTED;
 
     return OK;
 }
@@ -289,7 +298,7 @@ static int add_camera_metadata_entry_raw(camera_metadata_t *dst,
     size_t data_bytes =
             calculate_camera_metadata_entry_data_size(type, data_count);
 
-    camera_metadata_entry_t *entry = dst->entries + dst->entry_count;
+    camera_metadata_buffer_entry_t *entry = dst->entries + dst->entry_count;
     entry->tag = tag;
     entry->type = type;
     entry->count = data_count;
@@ -326,8 +335,8 @@ int add_camera_metadata_entry(camera_metadata_t *dst,
 }
 
 static int compare_entry_tags(const void *p1, const void *p2) {
-    uint32_t tag1 = ((camera_metadata_entry_t*)p1)->tag;
-    uint32_t tag2 = ((camera_metadata_entry_t*)p2)->tag;
+    uint32_t tag1 = ((camera_metadata_buffer_entry_t*)p1)->tag;
+    uint32_t tag2 = ((camera_metadata_buffer_entry_t*)p2)->tag;
     return  tag1 < tag2 ? -1 :
             tag1 == tag2 ? 0 :
             1;
@@ -338,7 +347,7 @@ int sort_camera_metadata(camera_metadata_t *dst) {
     if (dst->flags & FLAG_SORTED) return OK;
 
     qsort(dst->entries, dst->entry_count,
-            sizeof(camera_metadata_entry_t),
+            sizeof(camera_metadata_buffer_entry_t),
             compare_entry_tags);
     dst->flags |= FLAG_SORTED;
 
@@ -346,67 +355,165 @@ int sort_camera_metadata(camera_metadata_t *dst) {
 }
 
 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;
+        size_t index,
+        camera_metadata_entry_t *entry) {
+    if (src == NULL || entry == NULL) return ERROR;
     if (index >= src->entry_count) return ERROR;
 
-    camera_metadata_entry_t *entry = src->entries + index;
+    camera_metadata_buffer_entry_t *buffer_entry = src->entries + index;
 
-    if (tag != NULL) *tag = entry->tag;
-    if (type != NULL) *type = entry->type;
-    if (data_count != NULL) *data_count = entry->count;
-    if (data != NULL) {
-        if (entry->count * camera_metadata_type_size[entry->type] > 4) {
-            *data = src->data + entry->data.offset;
-        } else {
-            *data = entry->data.value;
-        }
+    entry->index = index;
+    entry->tag = buffer_entry->tag;
+    entry->type = buffer_entry->type;
+    entry->count = buffer_entry->count;
+    if (buffer_entry->count *
+            camera_metadata_type_size[buffer_entry->type] > 4) {
+        entry->data.u8 = src->data + buffer_entry->data.offset;
+    } else {
+        entry->data.u8 = buffer_entry->data.value;
     }
     return OK;
 }
 
 int find_camera_metadata_entry(camera_metadata_t *src,
         uint32_t tag,
-        uint8_t *type,
-        void **data,
-        size_t *data_count) {
+        camera_metadata_entry_t *entry) {
     if (src == NULL) return ERROR;
 
-    camera_metadata_entry_t *entry = NULL;
+    uint32_t index;
     if (src->flags & FLAG_SORTED) {
         // Sorted entries, do a binary search
-        camera_metadata_entry_t key;
+        camera_metadata_buffer_entry_t *search_entry = NULL;
+        camera_metadata_buffer_entry_t key;
         key.tag = tag;
-        entry = bsearch(&key,
+        search_entry = bsearch(&key,
                 src->entries,
                 src->entry_count,
-                sizeof(camera_metadata_entry_t),
+                sizeof(camera_metadata_buffer_entry_t),
                 compare_entry_tags);
+        if (search_entry == NULL) return NOT_FOUND;
+        index = search_entry - src->entries;
     } else {
         // Not sorted, linear search
-        unsigned int i;
-        for (i = 0; i < src->entry_count; i++) {
-            if (src->entries[i].tag == tag) {
-                entry = src->entries + i;
+        for (index = 0; index < src->entry_count; index++) {
+            if (src->entries[index].tag == tag) {
                 break;
             }
         }
+        if (index == src->entry_count) return NOT_FOUND;
     }
-    if (entry == NULL) return NOT_FOUND;
 
-    if (type != NULL) *type = entry->type;
-    if (data_count != NULL) *data_count = entry->count;
-    if (data != NULL) {
-        if (entry->count * camera_metadata_type_size[entry->type] > 4) {
-            *data = src->data + entry->data.offset;
-        } else {
-            *data = entry->data.value;
+    return get_camera_metadata_entry(src, index,
+            entry);
+}
+
+int delete_camera_metadata_entry(camera_metadata_t *dst,
+        size_t index) {
+    if (dst == NULL) return ERROR;
+    if (index >= dst->entry_count) return ERROR;
+
+    camera_metadata_buffer_entry_t *entry = dst->entries + index;
+    size_t data_bytes = calculate_camera_metadata_entry_data_size(entry->type,
+            entry->count);
+
+    if (data_bytes > 0) {
+        // Shift data buffer to overwrite deleted data
+        uint8_t *start = dst->data + entry->data.offset;
+        uint8_t *end = start + data_bytes;
+        size_t length = dst->data_count - entry->data.offset - data_bytes;
+        memmove(start, end, length);
+
+        // Update all entry indices to account for shift
+        camera_metadata_buffer_entry_t *e = dst->entries;
+        size_t i;
+        for (i = 0; i < dst->entry_count; i++) {
+            if (calculate_camera_metadata_entry_data_size(
+                    e->type, e->count) > 0 &&
+                    e->data.offset > entry->data.offset) {
+                e->data.offset -= data_bytes;
+            }
+            ++e;
         }
+        dst->data_count -= data_bytes;
     }
+    // Shift entry array
+    memmove(entry, entry + 1,
+            sizeof(camera_metadata_buffer_entry_t) *
+            (dst->entry_count - index - 1) );
+    dst->entry_count -= 1;
+
+    return OK;
+}
+
+int update_camera_metadata_entry(camera_metadata_t *dst,
+        size_t index,
+        const void *data,
+        size_t data_count,
+        camera_metadata_entry_t *updated_entry) {
+    if (dst == NULL) return ERROR;
+    if (index >= dst->entry_count) return ERROR;
+
+    camera_metadata_buffer_entry_t *entry = dst->entries + index;
+
+    size_t data_bytes =
+            calculate_camera_metadata_entry_data_size(entry->type,
+                    data_count);
+    size_t entry_bytes =
+            calculate_camera_metadata_entry_data_size(entry->type,
+                    entry->count);
+    if (data_bytes != entry_bytes) {
+        // May need to shift/add to data array
+        if (dst->data_capacity < dst->data_count + data_bytes - entry_bytes) {
+            // No room
+            return ERROR;
+        }
+        if (entry_bytes != 0) {
+            // Remove old data
+            uint8_t *start = dst->data + entry->data.offset;
+            uint8_t *end = start + entry_bytes;
+            size_t length = dst->data_count - entry->data.offset - entry_bytes;
+            memmove(start, end, length);
+            dst->data_count -= entry_bytes;
+
+            // Update all entry indices to account for shift
+            camera_metadata_buffer_entry_t *e = dst->entries;
+            size_t i;
+            for (i = 0; i < dst->entry_count; i++) {
+                if (calculate_camera_metadata_entry_data_size(
+                        e->type, e->count) > 0 &&
+                        e->data.offset > entry->data.offset) {
+                    e->data.offset -= entry_bytes;
+                }
+                ++e;
+            }
+        }
+
+        if (data_bytes != 0) {
+            // Append new data
+            entry->data.offset = dst->data_count;
+
+            memcpy(dst->data + entry->data.offset, data, data_bytes);
+            dst->data_count += data_bytes;
+        }
+    } else if (data_bytes != 0) {
+        // data size unchanged, reuse same data location
+        memcpy(dst->data + entry->data.offset, data, data_bytes);
+    }
+
+    if (data_bytes == 0) {
+        // Data fits into entry
+        memcpy(entry->data.value, data,
+                data_count * camera_metadata_type_size[entry->type]);
+    }
+
+    entry->count = data_count;
+
+    if (updated_entry != NULL) {
+        get_camera_metadata_entry(dst,
+                index,
+                updated_entry);
+    }
+
     return OK;
 }
 
@@ -479,7 +586,7 @@ void dump_camera_metadata(const camera_metadata_t *metadata,
     fdprintf(fd, "  Version: %d, Flags: %08x\n",
             metadata->version, metadata->flags);
     for (i=0; i < metadata->entry_count; i++) {
-        camera_metadata_entry_t *entry = metadata->entries + i;
+        camera_metadata_buffer_entry_t *entry = metadata->entries + i;
 
         const char *tag_name, *tag_section;
         tag_section = get_camera_metadata_section_name(entry->tag);
index 53a4c45..6bac8db 100644 (file)
  * limitations under the License.
  */
 
+#define LOG_NDEBUG 1
+#define LOG_TAG "camera_metadata_tests"
+#include "cutils/log.h"
+
 #include <errno.h>
 
 #include "gtest/gtest.h"
@@ -226,45 +230,43 @@ TEST(camera_metadata, add_get_normal) {
 
     // 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;
-
+    camera_metadata_entry entry;
     result = get_camera_metadata_entry(m,
-            0, &tag, &type, (void**)&data_int64, &data_count);
+            0, &entry);
     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);
+    EXPECT_EQ(0, (int)entry.index);
+    EXPECT_EQ(ANDROID_SENSOR_EXPOSURE_TIME, entry.tag);
+    EXPECT_EQ(TYPE_INT64, entry.type);
+    EXPECT_EQ((size_t)1, entry.count);
+    EXPECT_EQ(exposure_time, *entry.data.i64);
 
     result = get_camera_metadata_entry(m,
-            1, &tag, &type, (void**)&data_int32, &data_count);
+            1, &entry);
     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);
+    EXPECT_EQ((size_t)1, entry.index);
+    EXPECT_EQ(ANDROID_SENSOR_SENSITIVITY, entry.tag);
+    EXPECT_EQ(TYPE_INT32, entry.type);
+    EXPECT_EQ((size_t)1, entry.count);
+    EXPECT_EQ(sensitivity, *entry.data.i32);
 
     result = get_camera_metadata_entry(m,
-            2, &tag, &type, (void**)&data_float, &data_count);
+            2, &entry);
     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);
+    EXPECT_EQ((size_t)2, entry.index);
+    EXPECT_EQ(ANDROID_LENS_FOCUS_DISTANCE, entry.tag);
+    EXPECT_EQ(TYPE_FLOAT, entry.type);
+    EXPECT_EQ((size_t)1, entry.count);
+    EXPECT_EQ(focusDistance, *entry.data.f);
 
     result = get_camera_metadata_entry(m,
-            3, &tag, &type, (void**)&data_float, &data_count);
+            3, &entry);
     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((size_t)3, entry.index);
+    EXPECT_EQ(ANDROID_COLOR_TRANSFORM, entry.tag);
+    EXPECT_EQ(TYPE_FLOAT, entry.type);
+    EXPECT_EQ((size_t)9, entry.count);
+    for (unsigned int i=0; i < entry.count; i++) {
+        EXPECT_EQ(colorTransform[i], entry.data.f[i] );
     }
 
     EXPECT_EQ(calculate_camera_metadata_size(entry_capacity, data_capacity),
@@ -273,7 +275,9 @@ TEST(camera_metadata, add_get_normal) {
     EXPECT_EQ(calculate_camera_metadata_size(entries_used, data_used),
             get_camera_metadata_compact_size(m) );
 
-    dump_camera_metadata(m, 0, 2);
+    IF_ALOGV() {
+        dump_camera_metadata(m, 0, 2);
+    }
 
     free_camera_metadata(m);
 }
@@ -319,33 +323,33 @@ TEST(camera_metadata, add_get_toomany) {
 
     EXPECT_EQ(ERROR, result);
 
-    uint32_t tag = 0;
-    uint8_t type = 0;
-    int32_t *data_int32;
-    size_t data_count = 0;
+    camera_metadata_entry entry;
     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);
+                i, &entry);
         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);
+        EXPECT_EQ(i, entry.index);
+        EXPECT_EQ(ANDROID_SENSOR_EXPOSURE_TIME, entry.tag);
+        EXPECT_EQ(TYPE_INT64, entry.type);
+        EXPECT_EQ((size_t)1, entry.count);
+        EXPECT_EQ(exposure_time, *entry.data.i64);
     }
-    tag = 0;
-    type = 0;
-    data_int32 = NULL;
-    data_count = 0;
+    entry.tag = 1234;
+    entry.type = 56;
+    entry.data.u8 = NULL;
+    entry.count = 7890;
     result = get_camera_metadata_entry(m,
-            entry_capacity, &tag, &type, (void**)&data_int32, &data_count);
+            entry_capacity, &entry);
     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);
+    EXPECT_EQ((uint32_t)1234, entry.tag);
+    EXPECT_EQ((uint8_t)56, entry.type);
+    EXPECT_EQ(NULL, entry.data.u8);
+    EXPECT_EQ((size_t)7890, entry.count);
 
-    dump_camera_metadata(m, 0, 2);
+    IF_ALOGV() {
+        dump_camera_metadata(m, 0, 2);
+    }
 
     free_camera_metadata(m);
 }
@@ -380,23 +384,20 @@ TEST(camera_metadata, copy_metadata) {
             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;
-
+        camera_metadata_entry e1, e2;
         int result;
-        result = get_camera_metadata_entry(m,
-                i, &tag, &type, (void**)&data, &data_count);
+        result = get_camera_metadata_entry(m, i, &e1);
         EXPECT_EQ(OK, result);
-        result = get_camera_metadata_entry(m2,
-                i, &tag2, &type2, (void**)&data2, &data_count2);
+        result = get_camera_metadata_entry(m2, i, &e2);
         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]);
+        EXPECT_EQ(e1.index, e2.index);
+        EXPECT_EQ(e1.tag, e2.tag);
+        EXPECT_EQ(e1.type, e2.type);
+        EXPECT_EQ(e1.count, e2.count);
+        for (unsigned int j=0;
+             j < e1.count * camera_metadata_type_size[e1.type];
+             j++) {
+            EXPECT_EQ(e1.data.u8[j], e2.data.u8[j]);
         }
     }
 
@@ -440,23 +441,22 @@ TEST(camera_metadata, copy_metadata_extraspace) {
             (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;
+        camera_metadata_entry e1, e2;
 
         int result;
-        result = get_camera_metadata_entry(m,
-                i, &tag, &type, (void**)&data, &data_count);
+        result = get_camera_metadata_entry(m, i, &e1);
         EXPECT_EQ(OK, result);
-        result = get_camera_metadata_entry(m2,
-                i, &tag2, &type2, (void**)&data2, &data_count2);
+        EXPECT_EQ(i, e1.index);
+        result = get_camera_metadata_entry(m2, i, &e2);
         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]);
+        EXPECT_EQ(e1.index, e2.index);
+        EXPECT_EQ(e1.tag, e2.tag);
+        EXPECT_EQ(e1.type, e2.type);
+        EXPECT_EQ(e1.count, e2.count);
+        for (unsigned int j=0;
+             j < e1.count * camera_metadata_type_size[e1.type];
+             j++) {
+            EXPECT_EQ(e1.data.u8[j], e2.data.u8[j]);
         }
     }
 
@@ -512,29 +512,29 @@ TEST(camera_metadata, append_metadata) {
 
     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(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;
-
+        camera_metadata_entry e1, e2;
         int result;
-        result = get_camera_metadata_entry(m,
-                i, &tag, &type, (void**)&data, &data_count);
+        result = get_camera_metadata_entry(m, i, &e1);
         EXPECT_EQ(OK, result);
-        result = get_camera_metadata_entry(m2,
-                i, &tag2, &type2, (void**)&data2, &data_count2);
+        EXPECT_EQ(i, e1.index);
+        result = get_camera_metadata_entry(m2, i, &e2);
         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]);
+        EXPECT_EQ(e1.index, e2.index);
+        EXPECT_EQ(e1.tag, e2.tag);
+        EXPECT_EQ(e1.type, e2.type);
+        EXPECT_EQ(e1.count, e2.count);
+        for (unsigned int j=0;
+             j < e1.count * camera_metadata_type_size[e1.type];
+             j++) {
+            EXPECT_EQ(e1.data.u8[j], e2.data.u8[j]);
         }
     }
 
@@ -542,29 +542,32 @@ TEST(camera_metadata, append_metadata) {
 
     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(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;
+        camera_metadata_entry e1, e2;
 
         int result;
         result = get_camera_metadata_entry(m,
-                i % entry_capacity, &tag, &type, (void**)&data, &data_count);
+                i % entry_capacity, &e1);
         EXPECT_EQ(OK, result);
+        EXPECT_EQ(i % entry_capacity, e1.index);
         result = get_camera_metadata_entry(m2,
-                i, &tag2, &type2, (void**)&data2, &data_count2);
+                i, &e2);
         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]);
+        EXPECT_EQ(i, e2.index);
+        EXPECT_EQ(e1.tag, e2.tag);
+        EXPECT_EQ(e1.type, e2.type);
+        EXPECT_EQ(e1.count, e2.count);
+        for (unsigned int j=0;
+             j < e1.count * camera_metadata_type_size[e1.type];
+             j++) {
+            EXPECT_EQ(e1.data.u8[j], e2.data.u8[j]);
         }
     }
 
@@ -619,29 +622,30 @@ TEST(camera_metadata, append_metadata_onespace) {
 
     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(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;
+        camera_metadata_entry e1, e2;
 
         int result;
-        result = get_camera_metadata_entry(m,
-                i, &tag, &type, (void**)&data, &data_count);
+        result = get_camera_metadata_entry(m, i, &e1);
         EXPECT_EQ(OK, result);
-        result = get_camera_metadata_entry(m2,
-                i, &tag2, &type2, (void**)&data2, &data_count2);
+        EXPECT_EQ(i, e1.index);
+        result = get_camera_metadata_entry(m2, i, &e2);
         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]);
+        EXPECT_EQ(e1.index, e2.index);
+        EXPECT_EQ(e1.tag, e2.tag);
+        EXPECT_EQ(e1.type, e2.type);
+        EXPECT_EQ(e1.count, e2.count);
+        for (unsigned int j=0;
+             j < e1.count * camera_metadata_type_size[e1.type];
+             j++) {
+            EXPECT_EQ(e1.data.u8[j], e2.data.u8[j]);
         }
     }
 
@@ -655,23 +659,23 @@ TEST(camera_metadata, append_metadata_onespace) {
     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;
+        camera_metadata_entry e1, e2;
 
         int result;
         result = get_camera_metadata_entry(m,
-                i % entry_capacity, &tag, &type, (void**)&data, &data_count);
+                i % entry_capacity, &e1);
         EXPECT_EQ(OK, result);
-        result = get_camera_metadata_entry(m2,
-                i, &tag2, &type2, (void**)&data2, &data_count2);
+        EXPECT_EQ(i % entry_capacity, e1.index);
+        result = get_camera_metadata_entry(m2, i, &e2);
         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]);
+        EXPECT_EQ(i, e2.index);
+        EXPECT_EQ(e1.tag, e2.tag);
+        EXPECT_EQ(e1.type, e2.type);
+        EXPECT_EQ(e1.count, e2.count);
+        for (unsigned int j=0;
+             j < e1.count * camera_metadata_type_size[e1.type];
+             j++) {
+            EXPECT_EQ(e1.data.u8[j], e2.data.u8[j]);
         }
     }
 
@@ -763,9 +767,11 @@ TEST(camera_metadata, add_all_tags) {
     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_rational_t *data_rational =
+            (camera_metadata_rational_t *)data;
 
-    camera_metadata_t *m = allocate_camera_metadata(total_tag_count, conservative_data_space);
+    camera_metadata_t *m = allocate_camera_metadata(total_tag_count,
+            conservative_data_space);
 
     ASSERT_NE((void*)NULL, (void*)m);
 
@@ -826,7 +832,9 @@ TEST(camera_metadata, add_all_tags) {
         }
     }
 
-    dump_camera_metadata(m, 0, 2);
+    IF_ALOGV() {
+        dump_camera_metadata(m, 0, 2);
+    }
 
     free_camera_metadata(m);
 }
@@ -871,55 +879,672 @@ TEST(camera_metadata, sort_metadata) {
     EXPECT_EQ(OK, result);
 
     // Test unsorted find
-    uint8_t type;
-    float  *f;
-    size_t  data_count;
+    camera_metadata_entry_t entry;
     result = find_camera_metadata_entry(m,
             ANDROID_LENS_FOCUS_DISTANCE,
-            &type,
-            (void**)&f,
-            &data_count);
+            &entry);
     EXPECT_EQ(OK, result);
-    EXPECT_EQ(TYPE_FLOAT, type);
-    EXPECT_EQ(1, (int)data_count);
-    EXPECT_EQ(focus_distance, *f);
+    EXPECT_EQ(ANDROID_LENS_FOCUS_DISTANCE, entry.tag);
+    EXPECT_EQ((size_t)1, entry.index);
+    EXPECT_EQ(TYPE_FLOAT, entry.type);
+    EXPECT_EQ((size_t)1, entry.count);
+    EXPECT_EQ(focus_distance, *entry.data.f);
 
     result = find_camera_metadata_entry(m,
             ANDROID_NOISE_STRENGTH,
-            &type,
-            (void**)&f,
-            &data_count);
+            &entry);
     EXPECT_EQ(NOT_FOUND, result);
+    EXPECT_EQ((size_t)1, entry.index);
+    EXPECT_EQ(ANDROID_LENS_FOCUS_DISTANCE, entry.tag);
+    EXPECT_EQ(TYPE_FLOAT, entry.type);
+    EXPECT_EQ((size_t)1, entry.count);
+    EXPECT_EQ(focus_distance, *entry.data.f);
 
     // Sort
-    std::cout << "Pre-sorted metadata" << std::endl;
-    dump_camera_metadata(m, 0, 2);
+    IF_ALOGV() {
+        std::cout << "Pre-sorted metadata" << std::endl;
+        dump_camera_metadata(m, 0, 2);
+    }
 
     result = sort_camera_metadata(m);
     EXPECT_EQ(OK, result);
 
-    std::cout << "Sorted metadata" << std::endl;
-    dump_camera_metadata(m, 0, 2);
+    IF_ALOGV() {
+        std::cout << "Sorted metadata" << std::endl;
+        dump_camera_metadata(m, 0, 2);
+    }
 
     // Test sorted find
 
     result = find_camera_metadata_entry(m,
             ANDROID_LENS_FOCUS_DISTANCE,
-            &type,
-            (void**)&f,
-            &data_count);
+            &entry);
     EXPECT_EQ(OK, result);
-    EXPECT_EQ(TYPE_FLOAT, type);
-    EXPECT_EQ(1, (int)data_count);
-    EXPECT_EQ(focus_distance, *f);
+    EXPECT_EQ((size_t)0, entry.index);
+    EXPECT_EQ(ANDROID_LENS_FOCUS_DISTANCE, entry.tag);
+    EXPECT_EQ(TYPE_FLOAT, entry.type);
+    EXPECT_EQ((size_t)1, (size_t)entry.count);
+    EXPECT_EQ(focus_distance, *entry.data.f);
 
     result = find_camera_metadata_entry(m,
             ANDROID_NOISE_STRENGTH,
-            &type,
-            (void**)&f,
-            &data_count);
+            &entry);
     EXPECT_EQ(NOT_FOUND, result);
+    EXPECT_EQ((size_t)0, entry.index);
+    EXPECT_EQ(ANDROID_LENS_FOCUS_DISTANCE, entry.tag);
+    EXPECT_EQ(TYPE_FLOAT, entry.type);
+    EXPECT_EQ((size_t)1, entry.count);
+    EXPECT_EQ(focus_distance, *entry.data.f);
 
 
     free_camera_metadata(m);
 }
+
+TEST(camera_metadata, delete_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);
+
+    size_t num_entries = 5;
+    size_t data_per_entry =
+            calculate_camera_metadata_entry_data_size(TYPE_INT64, 1);
+    size_t num_data = num_entries * data_per_entry;
+
+    // Delete an entry with data
+
+    add_test_metadata(m, num_entries);
+    EXPECT_EQ(num_entries, get_camera_metadata_entry_count(m));
+    EXPECT_EQ(num_data, get_camera_metadata_data_count(m));
+
+    result = delete_camera_metadata_entry(m, 1);
+    EXPECT_EQ(OK, result);
+    num_entries--;
+    num_data -= data_per_entry;
+
+    EXPECT_EQ(num_entries, get_camera_metadata_entry_count(m));
+    EXPECT_EQ(entry_capacity, get_camera_metadata_entry_capacity(m));
+    EXPECT_EQ(num_data, get_camera_metadata_data_count(m));
+    EXPECT_EQ(data_capacity, get_camera_metadata_data_capacity(m));
+
+    result = delete_camera_metadata_entry(m, 4);
+    EXPECT_EQ(ERROR, result);
+
+    EXPECT_EQ(num_entries, get_camera_metadata_entry_count(m));
+    EXPECT_EQ(entry_capacity, get_camera_metadata_entry_capacity(m));
+    EXPECT_EQ(num_data, get_camera_metadata_data_count(m));
+    EXPECT_EQ(data_capacity, get_camera_metadata_data_capacity(m));
+
+    for (size_t i = 0; i < num_entries; i++) {
+        camera_metadata_entry e;
+        result = get_camera_metadata_entry(m, i, &e);
+        EXPECT_EQ(OK, result);
+        EXPECT_EQ(i, e.index);
+        EXPECT_EQ(ANDROID_SENSOR_EXPOSURE_TIME, e.tag);
+        EXPECT_EQ(TYPE_INT64, e.type);
+        int64_t exposureTime = i < 1 ? 100 : 200 + 100 * i;
+        EXPECT_EQ(exposureTime, *e.data.i64);
+    }
+
+    // Delete an entry with no data, at end of array
+
+    int32_t frameCount = 12;
+    result = add_camera_metadata_entry(m,
+            ANDROID_REQUEST_FRAME_COUNT,
+            &frameCount, 1);
+    EXPECT_EQ(OK, result);
+    num_entries++;
+
+    EXPECT_EQ(num_entries, get_camera_metadata_entry_count(m));
+    EXPECT_EQ(entry_capacity, get_camera_metadata_entry_capacity(m));
+    EXPECT_EQ(num_data, get_camera_metadata_data_count(m));
+    EXPECT_EQ(data_capacity, get_camera_metadata_data_capacity(m));
+
+    camera_metadata_entry e;
+    result = get_camera_metadata_entry(m, 4, &e);
+    EXPECT_EQ(OK, result);
+
+    EXPECT_EQ((size_t)4, e.index);
+    EXPECT_EQ(ANDROID_REQUEST_FRAME_COUNT, e.tag);
+    EXPECT_EQ(TYPE_INT32, e.type);
+    EXPECT_EQ((size_t)1, e.count);
+    EXPECT_EQ(frameCount, *e.data.i32);
+
+    result = delete_camera_metadata_entry(m, 4);
+    EXPECT_EQ(OK, result);
+
+    num_entries--;
+    EXPECT_EQ(num_entries, get_camera_metadata_entry_count(m));
+    EXPECT_EQ(entry_capacity, get_camera_metadata_entry_capacity(m));
+    EXPECT_EQ(num_data, get_camera_metadata_data_count(m));
+    EXPECT_EQ(data_capacity, get_camera_metadata_data_capacity(m));
+
+    result = delete_camera_metadata_entry(m, 4);
+    EXPECT_EQ(ERROR, result);
+
+    result = get_camera_metadata_entry(m, 4, &e);
+    EXPECT_EQ(ERROR, result);
+
+    EXPECT_EQ(num_entries, get_camera_metadata_entry_count(m));
+    EXPECT_EQ(entry_capacity, get_camera_metadata_entry_capacity(m));
+    EXPECT_EQ(num_data, get_camera_metadata_data_count(m));
+    EXPECT_EQ(data_capacity, get_camera_metadata_data_capacity(m));
+
+    // Delete with extra data on end of array
+    result = delete_camera_metadata_entry(m, 3);
+    EXPECT_EQ(OK, result);
+    num_entries--;
+    num_data -= data_per_entry;
+
+    for (size_t i = 0; i < num_entries; i++) {
+        camera_metadata_entry e2;
+        result = get_camera_metadata_entry(m, i, &e2);
+        EXPECT_EQ(OK, result);
+        EXPECT_EQ(i, e2.index);
+        EXPECT_EQ(ANDROID_SENSOR_EXPOSURE_TIME, e2.tag);
+        EXPECT_EQ(TYPE_INT64, e2.type);
+        int64_t exposureTime = i < 1 ? 100 : 200 + 100 * i;
+        EXPECT_EQ(exposureTime, *e2.data.i64);
+    }
+
+    // Delete without extra data in front of array
+
+    frameCount = 1001;
+    result = add_camera_metadata_entry(m,
+            ANDROID_REQUEST_FRAME_COUNT,
+            &frameCount, 1);
+    EXPECT_EQ(OK, result);
+    num_entries++;
+
+    EXPECT_EQ(num_entries, get_camera_metadata_entry_count(m));
+    EXPECT_EQ(entry_capacity, get_camera_metadata_entry_capacity(m));
+    EXPECT_EQ(num_data, get_camera_metadata_data_count(m));
+    EXPECT_EQ(data_capacity, get_camera_metadata_data_capacity(m));
+
+    result = sort_camera_metadata(m);
+    EXPECT_EQ(OK, result);
+
+    result = find_camera_metadata_entry(m,
+            ANDROID_REQUEST_FRAME_COUNT, &e);
+    EXPECT_EQ(OK, result);
+    EXPECT_EQ((size_t)0, e.index);
+    EXPECT_EQ(ANDROID_REQUEST_FRAME_COUNT, e.tag);
+    EXPECT_EQ(TYPE_INT32, e.type);
+    EXPECT_EQ((size_t)1, e.count);
+    EXPECT_EQ(frameCount, *e.data.i32);
+
+    result = delete_camera_metadata_entry(m, e.index);
+    EXPECT_EQ(OK, result);
+    num_entries--;
+
+    EXPECT_EQ(num_entries, get_camera_metadata_entry_count(m));
+    EXPECT_EQ(entry_capacity, get_camera_metadata_entry_capacity(m));
+    EXPECT_EQ(num_data, get_camera_metadata_data_count(m));
+    EXPECT_EQ(data_capacity, get_camera_metadata_data_capacity(m));
+
+    for (size_t i = 0; i < num_entries; i++) {
+        camera_metadata_entry e2;
+        result = get_camera_metadata_entry(m, i, &e2);
+        EXPECT_EQ(OK, result);
+        EXPECT_EQ(i, e2.index);
+        EXPECT_EQ(ANDROID_SENSOR_EXPOSURE_TIME, e2.tag);
+        EXPECT_EQ(TYPE_INT64, e2.type);
+        int64_t exposureTime = i < 1 ? 100 : 200 + 100 * i;
+        EXPECT_EQ(exposureTime, *e2.data.i64);
+    }
+}
+
+TEST(camera_metadata, update_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);
+
+    size_t num_entries = 5;
+    size_t data_per_entry =
+            calculate_camera_metadata_entry_data_size(TYPE_INT64, 1);
+    size_t num_data = num_entries * data_per_entry;
+
+    add_test_metadata(m, num_entries);
+    EXPECT_EQ(num_entries, get_camera_metadata_entry_count(m));
+    EXPECT_EQ(num_data, get_camera_metadata_data_count(m));
+
+    // Update with same-size data, doesn't fit in entry
+
+    int64_t newExposureTime = 1000;
+    camera_metadata_entry_t e;
+    result = update_camera_metadata_entry(m,
+            0, &newExposureTime, 1, &e);
+    EXPECT_EQ(OK, result);
+
+    EXPECT_EQ((size_t)0, e.index);
+    EXPECT_EQ(ANDROID_SENSOR_EXPOSURE_TIME, e.tag);
+    EXPECT_EQ(TYPE_INT64, e.type);
+    EXPECT_EQ((size_t)1, e.count);
+    EXPECT_EQ(newExposureTime, *e.data.i64);
+
+    e.count = 0;
+    result = get_camera_metadata_entry(m,
+            0, &e);
+
+    EXPECT_EQ((size_t)0, e.index);
+    EXPECT_EQ(ANDROID_SENSOR_EXPOSURE_TIME, e.tag);
+    EXPECT_EQ(TYPE_INT64, e.type);
+    EXPECT_EQ((size_t)1, e.count);
+    EXPECT_EQ(newExposureTime, *e.data.i64);
+
+    for (size_t i = 1; i < num_entries; i++) {
+        camera_metadata_entry e2;
+        result = get_camera_metadata_entry(m, i, &e2);
+        EXPECT_EQ(OK, result);
+        EXPECT_EQ(i, e2.index);
+        EXPECT_EQ(ANDROID_SENSOR_EXPOSURE_TIME, e2.tag);
+        EXPECT_EQ(TYPE_INT64, e2.type);
+        int64_t exposureTime = 100 + 100 * i;
+        EXPECT_EQ(exposureTime, *e2.data.i64);
+    }
+
+    // Update with larger data
+    int64_t newExposures[2] = { 5000, 6000 };
+    result = update_camera_metadata_entry(m,
+            0, newExposures, 2, &e);
+    EXPECT_EQ(OK, result);
+    num_data += data_per_entry;
+
+    EXPECT_EQ(num_entries, get_camera_metadata_entry_count(m));
+    EXPECT_EQ(num_data, get_camera_metadata_data_count(m));
+
+    EXPECT_EQ((size_t)0, e.index);
+    EXPECT_EQ(ANDROID_SENSOR_EXPOSURE_TIME, e.tag);
+    EXPECT_EQ(TYPE_INT64, e.type);
+    EXPECT_EQ((size_t)2, e.count);
+    EXPECT_EQ(newExposures[0], e.data.i64[0]);
+    EXPECT_EQ(newExposures[1], e.data.i64[1]);
+
+    e.count = 0;
+    result = get_camera_metadata_entry(m,
+            0, &e);
+
+    EXPECT_EQ((size_t)0, e.index);
+    EXPECT_EQ(ANDROID_SENSOR_EXPOSURE_TIME, e.tag);
+    EXPECT_EQ(TYPE_INT64, e.type);
+    EXPECT_EQ((size_t)2, e.count);
+    EXPECT_EQ(newExposures[0], e.data.i64[0]);
+    EXPECT_EQ(newExposures[1], e.data.i64[1]);
+
+    for (size_t i = 1; i < num_entries; i++) {
+        camera_metadata_entry e2;
+        result = get_camera_metadata_entry(m, i, &e2);
+        EXPECT_EQ(OK, result);
+        EXPECT_EQ(i, e2.index);
+        EXPECT_EQ(ANDROID_SENSOR_EXPOSURE_TIME, e2.tag);
+        EXPECT_EQ(TYPE_INT64, e2.type);
+        int64_t exposureTime = 100 + 100 * i;
+        EXPECT_EQ(exposureTime, *e2.data.i64);
+    }
+
+    // Update with smaller data
+    newExposureTime = 100;
+    result = update_camera_metadata_entry(m,
+            0, &newExposureTime, 1, &e);
+    EXPECT_EQ(OK, result);
+
+    num_data -= data_per_entry;
+
+    EXPECT_EQ(num_entries, get_camera_metadata_entry_count(m));
+    EXPECT_EQ(num_data, get_camera_metadata_data_count(m));
+
+    EXPECT_EQ((size_t)0, e.index);
+    EXPECT_EQ(ANDROID_SENSOR_EXPOSURE_TIME, e.tag);
+    EXPECT_EQ(TYPE_INT64, e.type);
+    EXPECT_EQ((size_t)1, e.count);
+    EXPECT_EQ(newExposureTime, *e.data.i64);
+
+    e.count = 0;
+    result = get_camera_metadata_entry(m,
+            0, &e);
+
+    EXPECT_EQ((size_t)0, e.index);
+    EXPECT_EQ(ANDROID_SENSOR_EXPOSURE_TIME, e.tag);
+    EXPECT_EQ(TYPE_INT64, e.type);
+    EXPECT_EQ((size_t)1, e.count);
+    EXPECT_EQ(newExposureTime, *e.data.i64);
+
+    for (size_t i = 1; i < num_entries; i++) {
+        camera_metadata_entry e2;
+        result = get_camera_metadata_entry(m, i, &e2);
+        EXPECT_EQ(OK, result);
+        EXPECT_EQ(i, e2.index);
+        EXPECT_EQ(ANDROID_SENSOR_EXPOSURE_TIME, e2.tag);
+        EXPECT_EQ(TYPE_INT64, e2.type);
+        int64_t exposureTime = 100 + 100 * i;
+        EXPECT_EQ(exposureTime, *e2.data.i64);
+    }
+
+    // Update with size fitting in entry
+
+    int32_t frameCount = 1001;
+    result = add_camera_metadata_entry(m,
+            ANDROID_REQUEST_FRAME_COUNT,
+            &frameCount, 1);
+    EXPECT_EQ(OK, result);
+    num_entries++;
+
+    EXPECT_EQ(num_entries, get_camera_metadata_entry_count(m));
+    EXPECT_EQ(entry_capacity, get_camera_metadata_entry_capacity(m));
+    EXPECT_EQ(num_data, get_camera_metadata_data_count(m));
+    EXPECT_EQ(data_capacity, get_camera_metadata_data_capacity(m));
+
+    result = sort_camera_metadata(m);
+    EXPECT_EQ(OK, result);
+
+    result = find_camera_metadata_entry(m,
+            ANDROID_REQUEST_FRAME_COUNT, &e);
+    EXPECT_EQ(OK, result);
+    EXPECT_EQ((size_t)0, e.index);
+    EXPECT_EQ(ANDROID_REQUEST_FRAME_COUNT, e.tag);
+    EXPECT_EQ(TYPE_INT32, e.type);
+    EXPECT_EQ((size_t)1, e.count);
+    EXPECT_EQ(frameCount, *e.data.i32);
+
+    int32_t newFrameCount = 0x12349876;
+    result = update_camera_metadata_entry(m,
+            0, &newFrameCount, 1, &e);
+
+    EXPECT_EQ(OK, result);
+    EXPECT_EQ((size_t)0, e.index);
+    EXPECT_EQ(ANDROID_REQUEST_FRAME_COUNT, e.tag);
+    EXPECT_EQ(TYPE_INT32, e.type);
+    EXPECT_EQ((size_t)1, e.count);
+    EXPECT_EQ(newFrameCount, *e.data.i32);
+
+    result = find_camera_metadata_entry(m,
+            ANDROID_REQUEST_FRAME_COUNT, &e);
+
+    EXPECT_EQ(OK, result);
+    EXPECT_EQ((size_t)0, e.index);
+    EXPECT_EQ(ANDROID_REQUEST_FRAME_COUNT, e.tag);
+    EXPECT_EQ(TYPE_INT32, e.type);
+    EXPECT_EQ((size_t)1, e.count);
+    EXPECT_EQ(newFrameCount, *e.data.i32);
+
+    for (size_t i = 1; i < num_entries; i++) {
+        camera_metadata_entry e2;
+        result = get_camera_metadata_entry(m, i, &e2);
+        EXPECT_EQ(OK, result);
+        EXPECT_EQ(i, e2.index);
+        EXPECT_EQ(ANDROID_SENSOR_EXPOSURE_TIME, e2.tag);
+        EXPECT_EQ(TYPE_INT64, e2.type);
+        int64_t exposureTime = 100 * i;
+        EXPECT_EQ(exposureTime, *e2.data.i64);
+    }
+
+    // Update to bigger than entry
+
+    int32_t newFrameCounts[4] = { 0x0, 0x1, 0x10, 0x100 };
+
+    result = update_camera_metadata_entry(m,
+            0, &newFrameCounts, 4, &e);
+
+    EXPECT_EQ(OK, result);
+
+    num_data += calculate_camera_metadata_entry_data_size(TYPE_INT32,
+            4);
+
+    EXPECT_EQ(num_entries, get_camera_metadata_entry_count(m));
+    EXPECT_EQ(num_data, get_camera_metadata_data_count(m));
+
+    EXPECT_EQ((size_t)0, e.index);
+    EXPECT_EQ(ANDROID_REQUEST_FRAME_COUNT, e.tag);
+    EXPECT_EQ(TYPE_INT32, e.type);
+    EXPECT_EQ((size_t)4, e.count);
+    EXPECT_EQ(newFrameCounts[0], e.data.i32[0]);
+    EXPECT_EQ(newFrameCounts[1], e.data.i32[1]);
+    EXPECT_EQ(newFrameCounts[2], e.data.i32[2]);
+    EXPECT_EQ(newFrameCounts[3], e.data.i32[3]);
+
+    e.count = 0;
+
+    result = find_camera_metadata_entry(m,
+            ANDROID_REQUEST_FRAME_COUNT, &e);
+
+    EXPECT_EQ(OK, result);
+    EXPECT_EQ((size_t)0, e.index);
+    EXPECT_EQ(ANDROID_REQUEST_FRAME_COUNT, e.tag);
+    EXPECT_EQ(TYPE_INT32, e.type);
+    EXPECT_EQ((size_t)4, e.count);
+    EXPECT_EQ(newFrameCounts[0], e.data.i32[0]);
+    EXPECT_EQ(newFrameCounts[1], e.data.i32[1]);
+    EXPECT_EQ(newFrameCounts[2], e.data.i32[2]);
+    EXPECT_EQ(newFrameCounts[3], e.data.i32[3]);
+
+    for (size_t i = 1; i < num_entries; i++) {
+        camera_metadata_entry e2;
+        result = get_camera_metadata_entry(m, i, &e2);
+        EXPECT_EQ(OK, result);
+        EXPECT_EQ(i, e2.index);
+        EXPECT_EQ(ANDROID_SENSOR_EXPOSURE_TIME, e2.tag);
+        EXPECT_EQ(TYPE_INT64, e2.type);
+        int64_t exposureTime = 100 * i;
+        EXPECT_EQ(exposureTime, *e2.data.i64);
+    }
+
+    // Update to smaller than entry
+    result = update_camera_metadata_entry(m,
+            0, &newFrameCount, 1, &e);
+
+    EXPECT_EQ(OK, result);
+
+    num_data -= camera_metadata_type_size[TYPE_INT32] * 4;
+
+    EXPECT_EQ(num_entries, get_camera_metadata_entry_count(m));
+    EXPECT_EQ(num_data, get_camera_metadata_data_count(m));
+
+    EXPECT_EQ((size_t)0, e.index);
+    EXPECT_EQ(ANDROID_REQUEST_FRAME_COUNT, e.tag);
+    EXPECT_EQ(TYPE_INT32, e.type);
+    EXPECT_EQ((size_t)1, e.count);
+    EXPECT_EQ(newFrameCount, *e.data.i32);
+
+    result = find_camera_metadata_entry(m,
+            ANDROID_REQUEST_FRAME_COUNT, &e);
+
+    EXPECT_EQ(OK, result);
+    EXPECT_EQ((size_t)0, e.index);
+    EXPECT_EQ(ANDROID_REQUEST_FRAME_COUNT, e.tag);
+    EXPECT_EQ(TYPE_INT32, e.type);
+    EXPECT_EQ((size_t)1, e.count);
+    EXPECT_EQ(newFrameCount, *e.data.i32);
+
+    for (size_t i = 1; i < num_entries; i++) {
+        camera_metadata_entry_t e2;
+        result = get_camera_metadata_entry(m, i, &e2);
+        EXPECT_EQ(OK, result);
+        EXPECT_EQ(i, e2.index);
+        EXPECT_EQ(ANDROID_SENSOR_EXPOSURE_TIME, e2.tag);
+        EXPECT_EQ(TYPE_INT64, e2.type);
+        int64_t exposureTime = 100 * i;
+        EXPECT_EQ(exposureTime, *e2.data.i64);
+    }
+
+    // Setup new buffer with no spare data space
+
+    result = update_camera_metadata_entry(m,
+            1, newExposures, 2, &e);
+    EXPECT_EQ(OK, result);
+
+    num_data += data_per_entry;
+
+    EXPECT_EQ(num_entries, get_camera_metadata_entry_count(m));
+    EXPECT_EQ(num_data, get_camera_metadata_data_count(m));
+
+    EXPECT_EQ((size_t)1, e.index);
+    EXPECT_EQ(ANDROID_SENSOR_EXPOSURE_TIME, e.tag);
+    EXPECT_EQ(TYPE_INT64, e.type);
+    EXPECT_EQ((size_t)2, e.count);
+    EXPECT_EQ(newExposures[0], e.data.i64[0]);
+    EXPECT_EQ(newExposures[1], e.data.i64[1]);
+
+    camera_metadata_t *m2;
+    m2 = allocate_camera_metadata(get_camera_metadata_entry_count(m),
+            get_camera_metadata_data_count(m));
+    EXPECT_NOT_NULL(m2);
+
+    result = append_camera_metadata(m2, m);
+    EXPECT_EQ(OK, result);
+
+    result = find_camera_metadata_entry(m2,
+            ANDROID_REQUEST_FRAME_COUNT, &e);
+
+    EXPECT_EQ(OK, result);
+    EXPECT_EQ((size_t)0, e.index);
+    EXPECT_EQ(ANDROID_REQUEST_FRAME_COUNT, e.tag);
+    EXPECT_EQ(TYPE_INT32, e.type);
+    EXPECT_EQ((size_t)1, e.count);
+    EXPECT_EQ(newFrameCount, *e.data.i32);
+
+    // Update when there's no more room
+
+    result = update_camera_metadata_entry(m2,
+            0, &newFrameCounts, 4, &e);
+    EXPECT_EQ(ERROR, result);
+
+    EXPECT_EQ(num_entries, get_camera_metadata_entry_count(m2));
+    EXPECT_EQ(num_data, get_camera_metadata_data_count(m2));
+
+    EXPECT_EQ((size_t)0, e.index);
+    EXPECT_EQ(ANDROID_REQUEST_FRAME_COUNT, e.tag);
+    EXPECT_EQ(TYPE_INT32, e.type);
+    EXPECT_EQ((size_t)1, e.count);
+    EXPECT_EQ(newFrameCount, *e.data.i32);
+
+    // Update when there's no data room, but change fits into entry
+
+    newFrameCount = 5;
+    result = update_camera_metadata_entry(m2,
+            0, &newFrameCount, 1, &e);
+    EXPECT_EQ(OK, result);
+
+    EXPECT_EQ(num_entries, get_camera_metadata_entry_count(m2));
+    EXPECT_EQ(num_data, get_camera_metadata_data_count(m2));
+
+    EXPECT_EQ((size_t)0, e.index);
+    EXPECT_EQ(ANDROID_REQUEST_FRAME_COUNT, e.tag);
+    EXPECT_EQ(TYPE_INT32, e.type);
+    EXPECT_EQ((size_t)1, e.count);
+    EXPECT_EQ(newFrameCount, *e.data.i32);
+
+    result = find_camera_metadata_entry(m2,
+            ANDROID_REQUEST_FRAME_COUNT, &e);
+
+    EXPECT_EQ(OK, result);
+    EXPECT_EQ((size_t)0, e.index);
+    EXPECT_EQ(ANDROID_REQUEST_FRAME_COUNT, e.tag);
+    EXPECT_EQ(TYPE_INT32, e.type);
+    EXPECT_EQ((size_t)1, e.count);
+    EXPECT_EQ(newFrameCount, *e.data.i32);
+
+    result = get_camera_metadata_entry(m2, 1, &e);
+    EXPECT_EQ((size_t)1, e.index);
+    EXPECT_EQ(ANDROID_SENSOR_EXPOSURE_TIME, e.tag);
+    EXPECT_EQ(TYPE_INT64, e.type);
+    EXPECT_EQ((size_t)2, e.count);
+    EXPECT_EQ(newExposures[0], e.data.i64[0]);
+    EXPECT_EQ(newExposures[1], e.data.i64[1]);
+
+    for (size_t i = 2; i < num_entries; i++) {
+        camera_metadata_entry_t e2;
+        result = get_camera_metadata_entry(m2, i, &e2);
+        EXPECT_EQ(OK, result);
+        EXPECT_EQ(i, e2.index);
+        EXPECT_EQ(ANDROID_SENSOR_EXPOSURE_TIME, e2.tag);
+        EXPECT_EQ(TYPE_INT64, e2.type);
+        int64_t exposureTime = 100 * i;
+        EXPECT_EQ(exposureTime, *e2.data.i64);
+    }
+
+    // Update when there's no data room, but data size doesn't change
+
+    newExposures[0] = 1000;
+
+    result = update_camera_metadata_entry(m2,
+            1, newExposures, 2, &e);
+    EXPECT_EQ(OK, result);
+
+    EXPECT_EQ(num_entries, get_camera_metadata_entry_count(m2));
+    EXPECT_EQ(num_data, get_camera_metadata_data_count(m2));
+
+    EXPECT_EQ((size_t)1, e.index);
+    EXPECT_EQ(ANDROID_SENSOR_EXPOSURE_TIME, e.tag);
+    EXPECT_EQ(TYPE_INT64, e.type);
+    EXPECT_EQ((size_t)2, e.count);
+    EXPECT_EQ(newExposures[0], e.data.i64[0]);
+    EXPECT_EQ(newExposures[1], e.data.i64[1]);
+
+    result = find_camera_metadata_entry(m2,
+            ANDROID_REQUEST_FRAME_COUNT, &e);
+
+    EXPECT_EQ(OK, result);
+    EXPECT_EQ((size_t)0, e.index);
+    EXPECT_EQ(ANDROID_REQUEST_FRAME_COUNT, e.tag);
+    EXPECT_EQ(TYPE_INT32, e.type);
+    EXPECT_EQ((size_t)1, e.count);
+    EXPECT_EQ(newFrameCount, *e.data.i32);
+
+    for (size_t i = 2; i < num_entries; i++) {
+        camera_metadata_entry_t e2;
+        result = get_camera_metadata_entry(m2, i, &e2);
+        EXPECT_EQ(OK, result);
+        EXPECT_EQ(i, e2.index);
+        EXPECT_EQ(ANDROID_SENSOR_EXPOSURE_TIME, e2.tag);
+        EXPECT_EQ(TYPE_INT64, e2.type);
+        int64_t exposureTime = 100 * i;
+        EXPECT_EQ(exposureTime, *e2.data.i64);
+    }
+
+    // Update when there's no data room, but data size shrinks
+
+    result = update_camera_metadata_entry(m2,
+            1, &newExposureTime, 1, &e);
+    EXPECT_EQ(OK, result);
+
+    num_data -= calculate_camera_metadata_entry_data_size(TYPE_INT64, 2);
+    num_data += calculate_camera_metadata_entry_data_size(TYPE_INT64, 1);
+
+    EXPECT_EQ(num_entries, get_camera_metadata_entry_count(m2));
+    EXPECT_EQ(num_data, get_camera_metadata_data_count(m2));
+
+    EXPECT_EQ((size_t)1, e.index);
+    EXPECT_EQ(ANDROID_SENSOR_EXPOSURE_TIME, e.tag);
+    EXPECT_EQ(TYPE_INT64, e.type);
+    EXPECT_EQ((size_t)1, e.count);
+    EXPECT_EQ(newExposureTime, e.data.i64[0]);
+
+    result = find_camera_metadata_entry(m2,
+            ANDROID_REQUEST_FRAME_COUNT, &e);
+
+    EXPECT_EQ(OK, result);
+    EXPECT_EQ((size_t)0, e.index);
+    EXPECT_EQ(ANDROID_REQUEST_FRAME_COUNT, e.tag);
+    EXPECT_EQ(TYPE_INT32, e.type);
+    EXPECT_EQ((size_t)1, e.count);
+    EXPECT_EQ(newFrameCount, *e.data.i32);
+
+    for (size_t i = 2; i < num_entries; i++) {
+        camera_metadata_entry_t e2;
+        result = get_camera_metadata_entry(m2, i, &e2);
+        EXPECT_EQ(OK, result);
+        EXPECT_EQ(i, e2.index);
+        EXPECT_EQ(ANDROID_SENSOR_EXPOSURE_TIME, e2.tag);
+        EXPECT_EQ(TYPE_INT64, e2.type);
+        int64_t exposureTime = 100 * i;
+        EXPECT_EQ(exposureTime, *e2.data.i64);
+    }
+
+}