Android Camera 元数据Matada和与3A模式_android camera 3a(1)

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)

**由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**!!


  • 23
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值