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
if (dst->data_capacity < dst->data_count + data_bytes - entry_bytes) {
// No room
return ERROR;
}
// 4. 删除旧的tag对应的value,实现类似delete函数
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;
}
}
// 5. 将新的tag对应的value插入到最后方
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) {
// 6. data的size相等时直接override
// 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);
}
assert(validate_camera_metadata_structure(dst, NULL) == OK);
return OK;
}
**4.Camera 3A 状态与模式**
虽然实际的3A算法取决于HAL的实现,但是HAL接口定义了高级状态机描述,以允许HAL设备和框架就3A的当前状态进行通信并触发3A事件。
## 最后
**自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。**
**深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。**
**因此收集整理了一份《2024年嵌入式&物联网开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。**
![img](https://img-blog.csdnimg.cn/img_convert/ede3e501c2668e2a9cb9e94207f3a2db.png)
![img](https://img-blog.csdnimg.cn/img_convert/9fa27290acff042fa7d44572defd5a6c.jpeg)
![img](https://img-blog.csdnimg.cn/img_convert/9ec7c056eda06261d9cfd4de72fd6037.png)
![img](https://img-blog.csdnimg.cn/img_convert/6a1fe5859eb7a9649359e3ccbae92b46.png)
![img](https://img-blog.csdnimg.cn/img_convert/a87cc538290f9397ea8368da1aff789b.png)
![img](https://img-blog.csdnimg.cn/img_convert/c5dd259205fe53a1939aad5014bd1893.png)
![](https://img-blog.csdnimg.cn/img_convert/5feabf55ee667d5acb79529eb3725fdb.png)
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!**
[**如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!**](https://bbs.csdn.net/topics/618654289)
**由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**!!
aktF-1715537797794)]
[外链图片转存中...(img-ov9H5HX4-1715537797794)]
[外链图片转存中...(img-mAvBkAE6-1715537797795)]
[外链图片转存中...(img-E9GyD75s-1715537797795)]
[外链图片转存中...(img-kL06cNGV-1715537797796)]
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!**
[**如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!**](https://bbs.csdn.net/topics/618654289)
**由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**!!