认识meta
camera_metadata的存储结构
camera_metadata.c 中定义了camera中使用的metadata, 其中包括metadata的数据结构,和对metadata这个数据结构的操作。camera_metadata.c文件是通过 camera_metadata_tag_info.mako自定生成的。
camera_metadata实际上就是一块连续的内存:这块内存是使用calloc()函数在堆上申请的。
camera_metadata_buffer_entry的定义:
typedef struct camera_metadata_buffer_entry {
uint32_t tag; //entry唯一的标识
uint32_t count; //该entry中存储的数据的个数, count × camera_metadata_type_size[type] 是总的字节数
union {
uint32_t offset;
uint8_t value[4];
} data; //tag对应的数据, 如果数据的字节数小于4,就存在value[4]中。否则将数据存在data区,具体的偏移就是data_start+offset。
uint8_t type; //数据的类型,一般是TYPE_BYTE , TYPE_INT32, TYPE_FLOAT, TYPE_INT64, TYPE_DOUBLE, TYPE_RATIONAL(分数(分子和分母))
uint8_t reserved[3];
} camera_metadata_buffer_entry_t;
camera_metadata的结构体定义:
struct camera_metadata {
metadata_size_t size; //当前metadata的总内存(总字节数)
uint32_t version; //当前metadata的版本号
uint32_t flags; //表示metadata中的entry是否进行过排序,查找更快
metadata_size_t entry_count; //当前metadata中存储的entry个数
metadata_size_t entry_capacity; //metadata中一共能存储的entry的个数,entry的容量
metadata_uptrdiff_t entries_start; //entry的起始地址
metadata_size_t data_count; //数据区当前存了多少个字节数
metadata_size_t data_capacity; //数据区一共能存多少的字节数
metadata_uptrdiff_t data_start; //数据区的起始地址
uint32_t padding; //为了字节对齐
metadata_vendor_id_t vendor_id; //
};
camera_metadata的基本操作
申请camera_metadata
camera_metadata_t *allocate_camera_metadata(size_t entry_capacity, size_t data_capacity) //申请一块内存给metadata,并且赋初始值
step1:计算metadata需要申请的内存字节数: memory_needed = sizeof(camera_metadata_t) + sizeof(camera_metadata_buffer_entry_t[entry_capacity]) + sizeof(uint8_t[data_capacity]) 头部 + entry区 + 数据区
step2: 使用calloc函数申请内存:void *buffer = calloc(1, memory_needed);
step3: 调用place_camera_metadata() 函数为头部的机构体camera_metadata_t内部变量赋值,camera_metadata_t *metadata = place_camera_metadata(buffer, memory_needed, entry_capacity, data_capacity);
camera_metadata_t *place_camera_metadata(void *dst, size_t dst_size, size_t entry_capacity, size_t data_capacity)
{
camera_metadata_t *metadata = (camera_metadata_t*)dst;
metadata->version = CURRENT_METADATA_VERSION; //meta的版本号
metadata->flags = 0; //是否排序
metadata->entry_count = 0; //当前的entry数
metadata->entry_capacity = entry_capacity; //总的可以存储的entry数
metadata->entries_start =ALIGN_TO(sizeof(camera_metadata_t), ENTRY_ALIGNMENT); //entries_start是在metadata内部的偏移,使用时entry的首地址: ((uint8_t*)metadata + metadata->entries_start)
metadata->data_count = 0; //当前使用的data区字节数
metadata->data_capacity = data_capacity; //当前可用的总data区字节数
metadata->size = memory_needed;
size_t data_unaligned = (uint8_t*)(get_entries(metadata) + metadata->entry_capacity) - (uint8_t*)metadata; //data_start是数据区域在metadata内部的偏移
metadata->data_start = ALIGN_TO(data_unaligned, DATA_ALIGNMENT);
metadata->vendor_id = CAMERA_METADATA_INVALID_VENDOR_ID;
return metadata;
}
camera_metadata_t *allocate_copy_camera_metadata_checked (const camera_metadata_t *src, size_t src_size) //先申请一块内存,然后把src的meta拷贝过去
camera_metadata_t* copy_camera_metadata(void *dst, size_t dst_size, const camera_metadata_t *src) //将src的metadata拷贝到dst的内存中
step1:计算src的内存字节数,dst_size必须要大于src的size,才能拷贝
step2:将src的metadata头部赋值给dst的头部
step3:拷贝entry区域和data区到dst
camera_metadata_t* copy_camera_metadata(void *dst, size_t dst_size,const camera_metadata_t *src) //void *dst是在外面申请好的一块buffer
{
size_t memory_needed = get_camera_metadata_compact_size(src); //sizeof(camera_metadata_t) + sizeof(camera_metadata_buffer_entry_t[entry_count] + sizeof(uint8_t[data_count]
camera_metadata_t *metadata = place_camera_metadata(dst, dst_size, src->entry_count, src->data_count); //将src的entry_count和data_count作为dst的entry_capacity和data_capacity
metadata->flags = src->flags;
metadata->entry_count = src->entry_count;
metadata->data_count = src->data_count;
metadata->vendor_id = src->vendor_id;
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]));
return metadata;
}
int append_camera_metadata(camera_metadata_t *dst, const camera_metadata_t *src) //将src的metadata中的entry和data追加在dst后
step1:将src的entry_count个entry和data都拷贝memcpy到dst的entry后面和data后面
step2:更新dst的entry->data.offset和其他的成员
int append_camera_metadata(camera_metadata_t *dst, const camera_metadata_t *src)
{
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]));
//更新dst中新加入的entry->data.offset
if (dst->data_count != 0) {
camera_metadata_buffer_entry_t *entry = get_entries(dst) + dst->entry_count; //新增的src的entry 起始地址
for (size_t i = 0; i < src->entry_count; i++, entry++) {
if ( calculate_camera_metadata_entry_data_size(entry->type, entry->count) > 0 ) //data 大于4字节
{
entry->data.offset += dst->data_count; // entry->data.offset在src中本身是有偏移的,所以只需要对每个偏移加上 dst->data_count就可以了
}
}
}
if (dst->entry_count == 0) {
dst->flags |= src->flags & FLAG_SORTED; //dst为空,使用src的存储方式
} else if (src->entry_count != 0) {
dst->flags &= ~FLAG_SORTED; //dst和src都不为空,使用无排序方式
}
dst->entry_count += src->entry_count;
dst->data_count += src->data_count;
dst->vendor_id = src->vendor_id;
}
camera_metadata_t *clone_camera_metadata(const camera_metadata_t *src) //深拷贝
step1:申请一个camera_metadata_t的内存,大小和src一样大
step2:将src append到这块内存中
camera_metadata_t *clone_camera_metadata(const camera_metadata_t *src)
{
camera_metadata_t *clone = allocate_camera_metadata(get_camera_metadata_entry_count(src), get_camera_metadata_data_count(src));
if (clone != NULL)
{
append_camera_metadata(clone, src);
}
return clone;
}
增加entry
int add_camera_metadata_entry(camera_metadata_t *dst, uint32_t tag, const void *data, size_t data_count) 调用下面的add_camera_metadata_entry_raw
static int add_camera_metadata_entry_raw(camera_metadata_t *dst, uint32_t tag, uint8_t type, const void *data, size_t data_count)
step1:从dst的entry末尾取出一个entry,*entry = get_entriesget_entries(dst) + dst->entry_count
step2:计算entry数据总字节数,如果总字节数 < 4, 直接使用memcpy把data复制到entry→data.value
step3:否则 就给entry->data.offset赋值为dst→data_count, 然后使用memcpy将数据拷贝到entry->data.offset位置
add_camera_metadata_entry_raw 折叠源码
static int add_camera_metadata_entry_raw(camera_metadata_t *dst, uint32_t tag, uint8_t type, const void *data, size_t data_count)
{
size_t data_bytes = calculate_camera_metadata_entry_data_size(type, data_count); //计算entry数据总字节数,如果小于4字节就返回0
size_t data_payload_bytes = data_count * camera_metadata_type_size[type]; //计算entry数据总字节数,不考虑对齐
camera_metadata_buffer_entry_t *entry = get_entries(dst) + dst->entry_count;
memset(entry, 0, sizeof(camera_metadata_buffer_entry_t));
entry->tag = tag;
entry->type = type;
entry->count = data_count;
if (data_bytes == 0)
{
memcpy(entry->data.value, data, data_payload_bytes); //总字节数 <= 4, 直接使用memcpy把data复制到entry→data.value
}
else
{
entry->data.offset = dst->data_count; //总字节数 > 4, 给entry->data.offset赋值为dst→data_count, 然后使用memcpy将数据拷贝到entry->data.offset位置
memcpy(get_data(dst) + entry->data.offset, data, data_payload_bytes);
dst->data_count += data_bytes; //更新data_count
}
dst->entry_count++;
dst->flags &= ~FLAG_SORTED; //不排序
}
查找entry
int find_camera_metadata_entry(camera_metadata_t *src, uint32_t tag, camera_metadata_entry_t *entry)
step1:从src中找到tag对应的entry的index
step2:根据index将entry拿出来
int find_camera_metadata_entry(camera_metadata_t *src, uint32_t tag, camera_metadata_entry_t *entry)
{
uint32_t index;
if (src->flags & FLAG_SORTED) //有排序,二分法查找
{
camera_metadata_buffer_entry_t *search_entry = NULL;
camera_metadata_buffer_entry_t key;
key.tag = tag;
search_entry = bsearch(&key, 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 - get_entries(src);
}
else
{ //线性查找
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;
}
return get_camera_metadata_entry(src, index, entry);
}
// 根据index, 将对应的entry 拿出来
int get_camera_metadata_entry(camera_metadata_t *src, size_t index, camera_metadata_entry_t *entry)
{
camera_metadata_buffer_entry_t *buffer_entry = get_entries(src) + index;
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) // 大于4字节
{
entry->data.u8 = get_data(src) + buffer_entry->data.offset;
}
else
{
entry->data.u8 = buffer_entry->data.value; // // 小于4字节
}
}
int get_camera_metadata_entry(camera_metadata_t *src, size_t index, camera_metadata_entry_t *entry)
更新entry
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)
step1:当要插入的数据和原来entry的数据长度不相等时,如果entry大于4字节时,
先删除旧的数据:把下个entry(当前的data.offset + entry_bytes)的data到后面的整个data区,向前移动entry_bytes个字节,覆盖掉当前entry的数据, 然后更新后面的entry的data.offset
最后把新的tag数据追加到整个data区的后面
step2:当要插入的数据和原来entry的数据长度相等时,重复利用原来的data内存, 把新的tag数据拷贝到原来的entry的数据区
step3: 如果entry小于等于4字节,直接拷贝到entry->data.value中即可
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)
{
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) // 要插入的数据和原来entry的数据长度不相等
{
//entry大于4字节时,先删除旧的数据:把下个entry
标签:count,src,认识,camera,meta,entry,data,metadata
From: https://blog.csdn.net/weixin_39732855/article/details/139442847