区域一 : 何存camera_metadata_t 结构体定义,占用内存 96 Byte
区域二 : 保留区,供未来使用
区域三 : 何存所有 Tag 结构体定义,TAG[0]、TAG[1]、…、TAG[entry_count-1]
区域四 : 剩余未使用的 Tag 结构体的内存保留,该区域大小为 (entry_capacity - entry_count) 个TAG
区域五 : 所有 Tag对应的具体 metadata 数据
区域六 : 剩余未使用的 Tag 占用的内存
# system/media/camera/src/camera_metadata.c
#define METADATA_ALIGNMENT ((size_t) 4)
struct camera_metadata {
metadata_size_t size; //整个metadata数据大小
uint32_t version; //version
uint32_t flags;
metadata_size_t entry_count; //已经添加TAG的入口数量,(即内存块中已经包含多少TAG了)
metadata_size_t entry_capacity; //最大能容纳TAG的入口数量(即最大能放多少tag)
metadata_uptrdiff_t entries_start; //TAG区域相对开始处的偏移 Offset from camera_metadata
metadata_size_t data_count; //记录数据段当前已用的内存空间
metadata_size_t data_capacity; //总的数据段内存空间
metadata_uptrdiff_t data_start; //数据区相对开始处的偏移 Offset from camera_metadata
uint32_t padding; // padding to 8 bytes boundary
metadata_vendor_id_t vendor_id; // vendor id
};
typedef struct camera_metadata camera_metadata_t;
基本宏定义 camera_metadata_tags.h:
Camera MetaData 中所有的TAG 定义在 camera_metadata_tags.h 中。
可以看出,目录系统默认定义了 26 个Tag,分别如下:
# system/media/camera/include/system/camera_metadata_tags.h
typedef enum camera_metadata_section {
ANDROID_COLOR_CORRECTION,
ANDROID_CONTROL, // 控制数据
ANDROID_DEMOSAIC,
ANDROID_EDGE,
ANDROID_FLASH, //
ANDROID_FLASH_INFO,
ANDROID_HOT_PIXEL,
ANDROID_JPEG,
ANDROID_LENS,
ANDROID_LENS_INFO,
ANDROID_NOISE_REDUCTION,
ANDROID_QUIRKS,
ANDROID_REQUEST,
ANDROID_SCALER,
ANDROID_SENSOR,
ANDROID_SENSOR_INFO,
ANDROID_SHADING,
ANDROID_STATISTICS,
ANDROID_STATISTICS_INFO,
ANDROID_TONEMAP,
ANDROID_LED,
ANDROID_INFO,
ANDROID_BLACK_LEVEL,
ANDROID_SYNC,
ANDROID_REPROCESS,
ANDROID_DEPTH,
ANDROID_SECTION_COUNT,
VENDOR_SECTION = 0x8000
} camera_metadata_section_t;
camera metadata可以分为三类:安卓自带(谷歌),原厂定义(高通,联发科),第三方厂商(vivo,oppo,华为,其他)。
由于在内存中,各个tag 数据都是以有序的结构体形式保存起来,各个tag 对应的偏移地址如下:
typedef enum camera_metadata_section_start {
ANDROID_COLOR_CORRECTION_START = ANDROID_COLOR_CORRECTION << 16,
ANDROID_CONTROL_START = ANDROID_CONTROL << 16,
ANDROID_DEMOSAIC_START = ANDROID_DEMOSAIC << 16,
ANDROID_EDGE_START = ANDROID_EDGE << 16,
ANDROID_FLASH_START = ANDROID_FLASH << 16,
ANDROID_FLASH_INFO_START = ANDROID_FLASH_INFO << 16,
ANDROID_HOT_PIXEL_START = ANDROID_HOT_PIXEL << 16,
ANDROID_JPEG_START = ANDROID_JPEG << 16,
ANDROID_LENS_START = ANDROID_LENS << 16,
ANDROID_LENS_INFO_START = ANDROID_LENS_INFO << 16,
ANDROID_NOISE_REDUCTION_START = ANDROID_NOISE_REDUCTION << 16,
ANDROID_QUIRKS_START = ANDROID_QUIRKS << 16,
ANDROID_REQUEST_START = ANDROID_REQUEST << 16,
ANDROID_SCALER_START = ANDROID_SCALER << 16,
ANDROID_SENSOR_START = ANDROID_SENSOR << 16,
ANDROID_SENSOR_INFO_START = ANDROID_SENSOR_INFO << 16,
ANDROID_SHADING_START = ANDROID_SHADING << 16,
ANDROID_STATISTICS_START = ANDROID_STATISTICS << 16,
ANDROID_STATISTICS_INFO_START = ANDROID_STATISTICS_INFO << 16,
ANDROID_TONEMAP_START = ANDROID_TONEMAP << 16,
ANDROID_LED_START = ANDROID_LED << 16,
ANDROID_INFO_START = ANDROID_INFO << 16,
ANDROID_BLACK_LEVEL_START = ANDROID_BLACK_LEVEL << 16,
ANDROID_SYNC_START = ANDROID_SYNC << 16,
ANDROID_REPROCESS_START = ANDROID_REPROCESS << 16,
ANDROID_DEPTH_START = ANDROID_DEPTH << 16,
VENDOR_SECTION_START = VENDOR_SECTION << 16
} camera_metadata_section_start_t;
接下来,定义了,各个TAG 对应换详细的参数,每个 TAG 以 ##TAG##_START
和 ##TAG##_END
结束。
如前文所提到,用户只能通过调用函数接口,来访问camera_metadata_t里面的内容。函数接口实现的源码位于:system/media/camera/src/camera_metadata.c。这个文件有上千行,这里仅提到几个关键的函数。
3.metadata关键函数接口
如前文所提到,用户只能通过调用函数接口,来访问camera_metadata_t里面的内容。函数接口实现的源码位于:system/media/camera/src/camera_metadata.c。这个文件有上千行,这里仅提到几个关键的函数。
allocate_camera_metadata (分配metadata)
// 传入max entry和max data,给metadata分配地址空间
camera_metadata_t *allocate_camera_metadata(size_t entry_capacity, size_t data_capacity) {
size_t memory_needed = calculate_camera_metadata_size(entry_capacity, data_capacity); // 1. 计算size
void *buffer = calloc(1, memory_needed); // 2. 分配memory
camera_metadata_t *metadata = place_camera_metadata( // 3. 生成metadata
buffer, memory_needed, entry_capacity, data_capacity);
if (!metadata) {
/* This should not happen when memory_needed is the same
* calculated in this function and in place_camera_metadata.
*/
free(buffer);
}
return 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]);
// Make sure camera metadata can be stacked in continuous memory
memory_needed = ALIGN_TO(memory_needed, METADATA_PACKET_ALIGNMENT);
return memory_needed;
}
camera_metadata_t *place_camera_metadata(void *dst,
size_t dst_size,
size_t entry_capacity,
size_t data_capacity) {
if (dst == NULL) return NULL;
size_t memory_needed = calculate_camera_metadata_size(entry_capacity,
data_capacity);
if (memory_needed > dst_size) return NULL;
camera_metadata_t *metadata = (camera_metadata_t*)dst;
metadata->version = CURRENT_METADATA_VERSION;
metadata->flags = 0;
metadata->entry_count = 0;
metadata->entry_capacity = entry_capacity;
metadata->entries_start =
ALIGN_TO(sizeof(camera_metadata_t), ENTRY_ALIGNMENT);
metadata->data_count = 0;
metadata->data_capacity = data_capacity;
metadata->size = memory_needed;
size_t data_unaligned = (uint8_t*)(get_entries(metadata) +
metadata->entry_capacity) - (uint8_t*)metadata;
metadata->data_start = ALIGN_TO(data_unaligned, DATA_ALIGNMENT);
metadata->vendor_id = CAMERA_METADATA_INVALID_VENDOR_ID;
assert(validate_camera_metadata_structure(metadata, NULL) == OK);
return metadata;
}
find_camera_metadata_entry(从metadata中根据tag查找value)
这个函数的基本逻辑可以参考上文描述从metadata中“查”tag的逻辑。
int find_camera_metadata_entry(camera_metadata_t *src, uint32_t tag, camera_metadata_entry_t *entry) {
if (src == NULL) return ERROR;
uint32_t index;
if (src->flags & FLAG_SORTED) {
// Sorted entries, do a binary search
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 {
// Not sorted, linear search
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);
}
int get_camera_metadata_entry(camera_metadata_t *src,
size_t index,
camera_metadata_entry_t *entry) {
if (src == NULL || entry == NULL) return ERROR;
if (index >= src->entry_count) return ERROR;
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) {
entry->data.u8 = get_data(src) + buffer_entry->data.offset;
} else {
entry->data.u8 = buffer_entry->data.value;
}
return OK;
}
add_camera_metadata_entry(增加tag和value到metadata)
int add_camera_metadata_entry(camera_metadata_t *dst, uint32_t tag, const void *data, size_t data_count) {
// 1.根据tag,找到该tag对应的value的type。这个函数的具体实现不再粘贴出来,里面涉及到tag section相关结构体,后文描述
int type = get_local_camera_metadata_tag_type(tag, dst);
if (type == -1) {
ALOGE("%s: Unknown tag %04x.", __FUNCTION__, tag);
return ERROR;
}
// 2.将tag和data添加到metadata中。
return add_camera_metadata_entry_raw(dst, tag, type, data, data_count);
}
static int add_camera_metadata_entry_raw(camera_metadata_t *dst, uint32_t tag, uint8_t type, const void *data, size_t data_count) {
if (dst == NULL) return ERROR;
if (dst->entry_count == dst->entry_capacity) return ERROR;
if (data_count && data == NULL) return ERROR;
// 1. 计算size,并进行4字节判断。如果小于4字节,将返回0。
size_t data_bytes = calculate_camera_metadata_entry_data_size(type, data_count);
if (data_bytes + dst->data_count > dst->data_capacity) return ERROR;
// 2. 计算数据的size
size_t data_payload_bytes = data_count * camera_metadata_type_size[type];
// 3. 生成camera_metadata_buffer_entry_t
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;
// 4. copy数据到entry中
if (data_bytes == 0) {
memcpy(entry->data.value, data, data_payload_bytes);
} else {
entry->data.offset = dst->data_count;
memcpy(get_data(dst) + entry->data.offset, data,
data_payload_bytes);
dst->data_count += data_bytes;
}
// 5. 增加一个entry
dst->entry_count++;
dst->flags &= ~FLAG_SORTED; // add后,是没有经过排序的
assert(validate_camera_metadata_structure(dst, NULL) == OK);
return OK;
}
size_t calculate_camera_metadata_entry_data_size(uint8_t type,
size_t data_count) {
if (type >= NUM_TYPES) return 0;
size_t data_bytes = data_count *
camera_metadata_type_size[type];
return data_bytes <= 4 ? 0 : ALIGN_TO(data_bytes, DATA_ALIGNMENT);
}
delete_camera_metadata_entry(删除tag)
删除的逻辑相对有点复杂,因为tag对应的value可能在data数组的中间,需要后面的内容,覆盖要删除的内容。
int delete_camera_metadata_entry(camera_metadata_t *dst, size_t index) {
if (dst == NULL) return ERROR;
if (index >= dst->entry_count) return ERROR;
// 1. 根据index,找到对应的entry
camera_metadata_buffer_entry_t *entry = get_entries(dst) + index;
// 2. 获取value的size
size_t data_bytes = calculate_camera_metadata_entry_data_size(entry->type,
entry->count);
if (data_bytes > 0) {
// 3. data_bypes > 0,value的size>4字节,所以存储的data数组中
// 这里开始对data数组的内容进行memmove
// 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; // data_count是数组总长度,offset是value的起始位置,data_types是value的长度。相减就是value后面的数据的长度
memmove(start, end, length); // value后面的数据向前移动到start位置,从end开始计算length个字节
// 4. 更新当前tag之后的entry的offset
// 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;
}
// 5. 移动entry
// Shift entry array
memmove(entry, entry + 1, sizeof(camera_metadata_buffer_entry_t) * (dst->entry_count - index - 1) );
dst->entry_count -= 1;
assert(validate_camera_metadata_structure(dst, NULL) == OK);
return OK;
}
size_t calculate_camera_metadata_entry_data_size(uint8_t type,
size_t data_count) {
if (type >= NUM_TYPES) return 0;
size_t data_bytes = data_count *
camera_metadata_type_size[type];
return data_bytes <= 4 ? 0 : ALIGN_TO(data_bytes, DATA_ALIGNMENT);
}
update_camera_metadata_entry(更新tag的value值)
在调用 update_camera_metadata_entry() 更新tag前,一定要通过 find_camera_metadata_entry() 找到对应的entry,通过该entry获取其index(即entry在metadata的index)。
PS:参数updated_entry,是用于获取update之后的tag。
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;
// 1. 根据index找到对应的entry
camera_metadata_buffer_entry_t *entry = get_entries(dst) + index;
// 2. data_bytes是新的value的size,如果小于4,就是0;
// data_payload_bytes是新的value真正的size;
// entry_bytes是就的value的size
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) {
// 新的value和旧的value的size不同时,需要进行下述操作
// 3. 确定data的容量是否可以满足新的value
// May need to shift/add to data array
## 最后
**自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。**
**深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。**
**因此收集整理了一份《2024年嵌入式&物联网开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。**







**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!**
[**如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!**](https://bbs.youkuaiyun.com/topics/618654289)
**由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**!!
IwnC-1715537867283)]
[外链图片转存中...(img-1TgwbcJu-1715537867283)]
[外链图片转存中...(img-eq2C68Zy-1715537867284)]
[外链图片转存中...(img-GSdpBSq5-1715537867285)]
[外链图片转存中...(img-jwRz4oIu-1715537867286)]
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!**
[**如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!**](https://bbs.youkuaiyun.com/topics/618654289)
**由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**!!