OSDN Git Service

Camera: Actually make camera_metadata memcopyable
[android-x86/system-media.git] / camera / src / camera_metadata.c
index a16b5b7..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[]
@@ -38,7 +51,7 @@ typedef struct camera_metadata_buffer_entry {
     } data;
     uint8_t  type;
     uint8_t  reserved[3];
-} __attribute__((packed)) camera_metadata_buffer_entry_t;
+} camera_metadata_buffer_entry_t;
 
 /**
  * A packet of metadata. This is a list of entries, each of which may point to
@@ -80,10 +93,11 @@ struct camera_metadata {
     uint32_t                 flags;
     size_t                   entry_count;
     size_t                   entry_capacity;
-    camera_metadata_buffer_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,7 +125,7 @@ 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",
@@ -120,8 +134,20 @@ char *camera_metadata_type_names[NUM_TYPES] = {
     [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);
@@ -146,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_buffer_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;
 }
@@ -166,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);
+    // 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;
 }
@@ -180,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) {
@@ -211,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_buffer_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,
+    memcpy(get_entries(metadata), get_entries(src),
             sizeof(camera_metadata_buffer_entry_t[metadata->entry_count]));
-    memcpy(metadata->data, src->data,
+    memcpy(get_data(metadata), get_data(src),
             sizeof(uint8_t[metadata->data_count]));
+    metadata->user = NULL;
 
     return metadata;
 }
@@ -247,17 +263,15 @@ 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,
+    memcpy(get_entries(dst) + dst->entry_count, get_entries(src),
             sizeof(camera_metadata_buffer_entry_t[src->entry_count]));
-    memcpy(dst->data + dst->data_count, src->data,
+    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_buffer_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;
             }
         }
@@ -277,12 +291,28 @@ int append_camera_metadata(camera_metadata_t *dst,
     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,
@@ -297,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_buffer_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++;
@@ -346,7 +380,7 @@ 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,
+    qsort(get_entries(dst), dst->entry_count,
             sizeof(camera_metadata_buffer_entry_t),
             compare_entry_tags);
     dst->flags |= FLAG_SORTED;
@@ -360,7 +394,7 @@ int get_camera_metadata_entry(camera_metadata_t *src,
     if (src == NULL || entry == NULL) return ERROR;
     if (index >= src->entry_count) return ERROR;
 
-    camera_metadata_buffer_entry_t *buffer_entry = src->entries + index;
+    camera_metadata_buffer_entry_t *buffer_entry = get_entries(src) + index;
 
     entry->index = index;
     entry->tag = buffer_entry->tag;
@@ -368,7 +402,7 @@ int get_camera_metadata_entry(camera_metadata_t *src,
     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;
+        entry->data.u8 = get_data(src) + buffer_entry->data.offset;
     } else {
         entry->data.u8 = buffer_entry->data.value;
     }
@@ -387,16 +421,17 @@ int find_camera_metadata_entry(camera_metadata_t *src,
         camera_metadata_buffer_entry_t key;
         key.tag = tag;
         search_entry = bsearch(&key,
-                src->entries,
+                get_entries(src),
                 src->entry_count,
                 sizeof(camera_metadata_buffer_entry_t),
                 compare_entry_tags);
         if (search_entry == NULL) return NOT_FOUND;
-        index = search_entry - src->entries;
+        index = search_entry - get_entries(src);
     } else {
         // Not sorted, linear search
-        for (index = 0; index < src->entry_count; index++) {
-            if (src->entries[index].tag == tag) {
+        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;
             }
         }
@@ -407,24 +442,32 @@ int find_camera_metadata_entry(camera_metadata_t *src,
             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 = dst->entries + index;
+    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 = dst->data + entry->data.offset;
+        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 = dst->entries;
+        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(
@@ -453,11 +496,14 @@ int update_camera_metadata_entry(camera_metadata_t *dst,
     if (dst == NULL) return ERROR;
     if (index >= dst->entry_count) return ERROR;
 
-    camera_metadata_buffer_entry_t *entry = dst->entries + index;
+    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);
@@ -469,14 +515,14 @@ int update_camera_metadata_entry(camera_metadata_t *dst,
         }
         if (entry_bytes != 0) {
             // Remove old data
-            uint8_t *start = dst->data + entry->data.offset;
+            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 = dst->entries;
+            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(
@@ -492,18 +538,18 @@ int update_camera_metadata_entry(camera_metadata_t *dst,
             // Append new data
             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;
         }
     } else if (data_bytes != 0) {
         // data size unchanged, reuse same data location
-        memcpy(dst->data + entry->data.offset, data, data_bytes);
+        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_count * camera_metadata_type_size[entry->type]);
+                data_payload_bytes);
     }
 
     entry->count = data_count;
@@ -517,6 +563,18 @@ int update_camera_metadata_entry(camera_metadata_t *dst,
     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;
+}
+
 static const vendor_tag_query_ops_t *vendor_tag_ops = NULL;
 
 const char *get_camera_metadata_section_name(uint32_t tag) {
@@ -567,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_buffer_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);
@@ -603,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,
@@ -624,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,
@@ -652,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) {
@@ -676,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);