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

区域一 : 何存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年嵌入式&物联网开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。**

![img](https://img-blog.csdnimg.cn/img_convert/08b01fe45d4d864f8dc8a2e8f99353b7.png)

![img](https://img-blog.csdnimg.cn/img_convert/cf1c35ab90833d200308f4a47c33a44f.jpeg)

![img](https://img-blog.csdnimg.cn/img_convert/a686625cdce534d5a2aab721eaa45d1d.png)

 ![img](https://img-blog.csdnimg.cn/img_convert/aab17dddd4c03d53022a89473dfd43c6.png)

![img](https://img-blog.csdnimg.cn/img_convert/295b3e82aacbc701a1c03d092803711a.png)

![img](https://img-blog.csdnimg.cn/img_convert/73e05664341ca821601c4ed402633ac7.png)

![](https://img-blog.csdnimg.cn/img_convert/8f2c3761e8453435ef079a3bf8592d5a.png)

 

**既有适合小白学习的零基础资料,也有适合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)

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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值