OSDN Git Service

Camera: Actually make camera_metadata memcopyable
[android-x86/system-media.git] / camera / src / camera_metadata.c
index 1991835..e04b32c 100644 (file)
 #define OK         0
 #define ERROR      1
 #define NOT_FOUND -ENOENT
+
+#define _Alignas(T) \
+    ({struct _AlignasStruct { char c; T field; };       \
+        offsetof(struct _AlignasStruct, field); })
+
+// Align entry buffers as the compiler would
+#define ENTRY_ALIGNMENT _Alignas(camera_metadata_buffer_entry_t)
+// Align data buffer to largest supported data type
+#define DATA_ALIGNMENT _Alignas(camera_metadata_rational_t)
+
+#define ALIGN_TO(val, alignment) \
+    (((uint32_t)(val) + ((alignment) - 1)) & ~((alignment) - 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 {
+typedef struct camera_metadata_buffer_entry {
     uint32_t tag;
     size_t   count;
     union {
@@ -38,7 +51,7 @@ typedef struct camera_metadata_entry {
     } data;
     uint8_t  type;
     uint8_t  reserved[3];
-} __attribute__((packed)) camera_metadata_entry_t;
+} camera_metadata_buffer_entry_t;
 
 /**
  * A packet of metadata. This is a list of entries, each of which may point to
@@ -47,27 +60,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,10 +93,11 @@ struct camera_metadata {
     uint32_t                 flags;
     size_t                   entry_count;
     size_t                   entry_capacity;
-    camera_metadata_entry_t *entries;
+    ptrdiff_t                entries_start; // Offset from camera_metadata
     size_t                   data_count;
     size_t                   data_capacity;
-    uint8_t                 *data;
+    ptrdiff_t                data_start; // Offset from camera_metadata
+    void                    *user; // User set pointer, not copied with buffer
     uint8_t                  reserved[0];
 };
 
@@ -102,7 +116,7 @@ typedef struct tag_info {
 
 #include "camera_metadata_tag_info.c"
 
-size_t camera_metadata_type_size[NUM_TYPES] = {
+const size_t camera_metadata_type_size[NUM_TYPES] = {
     [TYPE_BYTE]     = sizeof(uint8_t),
     [TYPE_INT32]    = sizeof(int32_t),
     [TYPE_FLOAT]    = sizeof(float),
@@ -111,16 +125,29 @@ size_t camera_metadata_type_size[NUM_TYPES] = {
     [TYPE_RATIONAL] = sizeof(camera_metadata_rational_t)
 };
 
-char *camera_metadata_type_names[NUM_TYPES] = {
+const char *camera_metadata_type_names[NUM_TYPES] = {
     [TYPE_BYTE]     = "byte",
     [TYPE_INT32]    = "int32",
     [TYPE_FLOAT]    = "float",
     [TYPE_INT64]    = "int64",
+    [TYPE_DOUBLE]   = "double",
     [TYPE_RATIONAL] = "rational"
 };
 
+static camera_metadata_buffer_entry_t *get_entries(
+        const camera_metadata_t *metadata) {
+    return (camera_metadata_buffer_entry_t*)
+            ((uint8_t*)metadata + metadata->entries_start);
+}
+
+static uint8_t *get_data(const camera_metadata_t *metadata) {
+    return (uint8_t*)metadata + metadata->data_start;
+}
+
 camera_metadata_t *allocate_camera_metadata(size_t entry_capacity,
                                             size_t data_capacity) {
+    if (entry_capacity == 0) return NULL;
+
     size_t memory_needed = calculate_camera_metadata_size(entry_capacity,
                                                           data_capacity);
     void *buffer = malloc(memory_needed);
@@ -145,16 +172,19 @@ 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_start =
+            ALIGN_TO(sizeof(camera_metadata_t), ENTRY_ALIGNMENT);
     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);
+        size_t data_unaligned = (uint8_t*)(get_entries(metadata) +
+                metadata->entry_capacity) - (uint8_t*)metadata;
+        metadata->data_start = ALIGN_TO(data_unaligned, DATA_ALIGNMENT);
     } else {
-        metadata->data = NULL;
+        metadata->data_start = 0;
     }
+    metadata->user = NULL;
 
     return metadata;
 }
@@ -165,7 +195,11 @@ 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]);
+    // Start entry list at aligned boundary
+    memory_needed = ALIGN_TO(memory_needed, ENTRY_ALIGNMENT);
+    memory_needed += sizeof(camera_metadata_buffer_entry_t[entry_count]);
+    // Start buffer list at aligned boundary
+    memory_needed = ALIGN_TO(memory_needed, DATA_ALIGNMENT);
     memory_needed += sizeof(uint8_t[data_count]);
     return memory_needed;
 }
@@ -179,12 +213,8 @@ size_t get_camera_metadata_size(const camera_metadata_t *metadata) {
 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;
+                                          metadata->data_count);
 }
 
 size_t get_camera_metadata_entry_count(const camera_metadata_t *metadata) {
@@ -210,31 +240,18 @@ camera_metadata_t* copy_camera_metadata(void *dst, size_t dst_size,
     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 =
+        place_camera_metadata(dst, dst_size, src->entry_count, src->data_count);
 
-    camera_metadata_t *metadata = (camera_metadata_t*)dst;
-    metadata->version = CURRENT_METADATA_VERSION;
     metadata->flags = src->flags;
     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,
+    memcpy(get_entries(metadata), get_entries(src),
+            sizeof(camera_metadata_buffer_entry_t[metadata->entry_count]));
+    memcpy(get_data(metadata), get_data(src),
             sizeof(uint8_t[metadata->data_count]));
+    metadata->user = NULL;
 
     return metadata;
 }
@@ -246,34 +263,56 @@ int append_camera_metadata(camera_metadata_t *dst,
     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,
+    memcpy(get_entries(dst) + dst->entry_count, get_entries(src),
+            sizeof(camera_metadata_buffer_entry_t[src->entry_count]));
+    memcpy(get_data(dst) + dst->data_count, get_data(src),
             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 ) {
+        camera_metadata_buffer_entry_t *entry = get_entries(dst) + dst->entry_count;
+        for (size_t i = 0; i < src->entry_count; i++, entry++) {
+            if ( calculate_camera_metadata_entry_data_size(entry->type,
+                            entry->count) > 0 ) {
                 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;
 }
 
+camera_metadata_t *clone_camera_metadata(const camera_metadata_t *src) {
+    int res;
+    if (src == NULL) return NULL;
+    camera_metadata_t *clone = allocate_camera_metadata(
+        get_camera_metadata_entry_count(src),
+        get_camera_metadata_data_count(src));
+    if (clone != NULL) {
+        res = append_camera_metadata(clone, src);
+        if (res != OK) {
+            free_camera_metadata(clone);
+            clone = NULL;
+        }
+    }
+    return clone;
+}
+
 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;
+    return data_bytes <= 4 ? 0 : ALIGN_TO(data_bytes, DATA_ALIGNMENT);
 }
 
 static int add_camera_metadata_entry_raw(camera_metadata_t *dst,
@@ -288,18 +327,22 @@ static int add_camera_metadata_entry_raw(camera_metadata_t *dst,
 
     size_t data_bytes =
             calculate_camera_metadata_entry_data_size(type, data_count);
+    if (data_bytes + dst->data_count > dst->data_capacity) return ERROR;
 
-    camera_metadata_entry_t *entry = dst->entries + dst->entry_count;
+    size_t data_payload_bytes =
+            data_count * camera_metadata_type_size[type];
+    camera_metadata_buffer_entry_t *entry = get_entries(dst) + 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] );
+                data_payload_bytes);
     } else {
         entry->data.offset = dst->data_count;
-        memcpy(dst->data + entry->data.offset, data, data_bytes);
+        memcpy(get_data(dst) + entry->data.offset, data,
+                data_payload_bytes);
         dst->data_count += data_bytes;
     }
     dst->entry_count++;
@@ -326,8 +369,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;
@@ -337,8 +380,8 @@ int sort_camera_metadata(camera_metadata_t *dst) {
     if (dst == NULL) return ERROR;
     if (dst->flags & FLAG_SORTED) return OK;
 
-    qsort(dst->entries, dst->entry_count,
-            sizeof(camera_metadata_entry_t),
+    qsort(get_entries(dst), dst->entry_count,
+            sizeof(camera_metadata_buffer_entry_t),
             compare_entry_tags);
     dst->flags |= FLAG_SORTED;
 
@@ -346,67 +389,189 @@ 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 = get_entries(src) + 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 = get_data(src) + 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,
-                src->entries,
+        search_entry = bsearch(&key,
+                get_entries(src),
                 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 - get_entries(src);
     } 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;
+        camera_metadata_buffer_entry_t *search_entry = get_entries(src);
+        for (index = 0; index < src->entry_count; index++, search_entry++) {
+            if (search_entry->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 find_camera_metadata_ro_entry(const camera_metadata_t *src,
+        uint32_t tag,
+        camera_metadata_ro_entry_t *entry) {
+    return find_camera_metadata_entry((camera_metadata_t*)src, tag,
+            (camera_metadata_entry_t*)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 = get_entries(dst) + 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 = get_data(dst) + 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 = get_entries(dst);
+        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 = get_entries(dst) + index;
+
+    size_t data_bytes =
+            calculate_camera_metadata_entry_data_size(entry->type,
+                    data_count);
+    size_t data_payload_bytes =
+            data_count * camera_metadata_type_size[entry->type];
+
+    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 = get_data(dst) + 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 = get_entries(dst);
+            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(get_data(dst) + entry->data.offset, data, data_payload_bytes);
+            dst->data_count += data_bytes;
+        }
+    } else if (data_bytes != 0) {
+        // data size unchanged, reuse same data location
+        memcpy(get_data(dst) + entry->data.offset, data, data_payload_bytes);
+    }
+
+    if (data_bytes == 0) {
+        // Data fits into entry
+        memcpy(entry->data.value, data,
+                data_payload_bytes);
+    }
+
+    entry->count = data_count;
+
+    if (updated_entry != NULL) {
+        get_camera_metadata_entry(dst,
+                index,
+                updated_entry);
     }
+
+    return OK;
+}
+
+int set_camera_metadata_user_pointer(camera_metadata_t *dst, void* user) {
+    if (dst == NULL) return ERROR;
+    dst->user = user;
+    return OK;
+}
+
+int get_camera_metadata_user_pointer(camera_metadata_t *dst, void** user) {
+    if (dst == NULL) return ERROR;
+    *user = dst->user;
     return OK;
 }
 
@@ -460,26 +625,35 @@ int set_camera_metadata_vendor_tag_ops(const vendor_tag_query_ops_t *query_ops)
     return OK;
 }
 
-static void print_data(int fd, const uint8_t *data_ptr, int type, int count);
+static void print_data(int fd, const uint8_t *data_ptr, int type, int count,
+        int indentation);
 
 void dump_camera_metadata(const camera_metadata_t *metadata,
         int fd,
         int verbosity) {
+    dump_indented_camera_metadata(metadata, fd, verbosity, 0);
+}
+
+void dump_indented_camera_metadata(const camera_metadata_t *metadata,
+        int fd,
+        int verbosity,
+        int indentation) {
     if (metadata == NULL) {
-        ALOGE("%s: Metadata is null.", __FUNCTION__);
+        fdprintf(fd, "%*sDumping camera metadata array: Not allocated\n",
+                indentation, "");
         return;
     }
     unsigned int i;
     fdprintf(fd,
-            "Dumping camera metadata array. %d entries, "
-            "%d bytes of extra data.\n",
-            metadata->entry_count, metadata->data_count);
-    fdprintf(fd, "  (%d entries and %d bytes data reserved)\n",
-            metadata->entry_capacity, metadata->data_capacity);
-    fdprintf(fd, "  Version: %d, Flags: %08x\n",
+            "%*sDumping camera metadata array: %d / %d entries, "
+            "%d / %d bytes of extra data.\n", indentation, "",
+            metadata->entry_count, metadata->entry_capacity,
+            metadata->data_count, metadata->data_capacity);
+    fdprintf(fd, "%*sVersion: %d, Flags: %08x\n",
+            indentation + 2, "",
             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 = get_entries(metadata);
+    for (i=0; i < metadata->entry_count; i++, entry++) {
 
         const char *tag_name, *tag_section;
         tag_section = get_camera_metadata_section_name(entry->tag);
@@ -496,7 +670,8 @@ void dump_camera_metadata(const camera_metadata_t *metadata,
         } else {
             type_name = camera_metadata_type_names[entry->type];
         }
-        fdprintf(fd, "Tag: %s.%s (%05x): %s[%d]\n",
+        fdprintf(fd, "%*s%s.%s (%05x): %s[%d]\n",
+             indentation + 2, "",
              tag_section,
              tag_name,
              entry->tag,
@@ -517,18 +692,19 @@ void dump_camera_metadata(const camera_metadata_t *metadata,
                         metadata->data_count);
                 continue;
             }
-            data_ptr = metadata->data + entry->data.offset;
+            data_ptr = get_data(metadata) + entry->data.offset;
         } else {
             data_ptr = entry->data.value;
         }
         int count = entry->count;
         if (verbosity < 2 && count > 16) count = 16;
 
-        print_data(fd, data_ptr, entry->type, count);
+        print_data(fd, data_ptr, entry->type, count, indentation);
     }
 }
 
-static void print_data(int fd, const uint8_t *data_ptr, int type, int count) {
+static void print_data(int fd, const uint8_t *data_ptr,
+        int type, int count, int indentation) {
     static int values_per_line[NUM_TYPES] = {
         [TYPE_BYTE]     = 16,
         [TYPE_INT32]    = 4,
@@ -545,7 +721,7 @@ static void print_data(int fd, const uint8_t *data_ptr, int type, int count) {
     int index = 0;
     int j, k;
     for (j = 0; j < lines; j++) {
-        fdprintf(fd, " [");
+        fdprintf(fd, "%*s[", indentation + 4, "");
         for (k = 0;
              k < values_per_line[type] && count > 0;
              k++, count--, index += type_size) {
@@ -569,7 +745,7 @@ static void print_data(int fd, const uint8_t *data_ptr, int type, int count) {
                     break;
                 case TYPE_DOUBLE:
                     fdprintf(fd, "%0.2f ",
-                            *(float*)(data_ptr + index));
+                            *(double*)(data_ptr + index));
                     break;
                 case TYPE_RATIONAL: {
                     int32_t numerator = *(int32_t*)(data_ptr + index);