认识meta

目录

认识meta

camera_metadata的存储结构

camera_metadata的基本操作

申请camera_metadata

增加entry

查找entry

更新entry

删除entry

对tag的查找操作

vendor_tag_ops和vendor_cache_ops是Andriod提供的接口

propertyID

Camxhal3metadatautil.cpp文件理解

InitializeMetadataTable()函数详解

camxhal3metadatautil.cpp中的接口


认识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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/22456.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Redisson 分布式锁 - RLock、RReadWriteLock、RSemaphore、RCountDownLatch(配置、使用、原理)

目录 前言 Redisson 分布式锁 环境配置 1&#xff09;版本说明 2&#xff09;依赖如下 3&#xff09;配置文件如下 4&#xff09;项目配置 RLock 1&#xff09;使用方式 2&#xff09;加锁解释 3&#xff09;加锁时手动设置时间 4&#xff09;加锁时&#xff0c;到…

揭秘FL Studio21.2.8中文版一键解锁音乐创作新境界!

在音乐制作的广阔天地里&#xff0c;随着技术的不断进步和数字音频工作站&#xff08;DAW&#xff09;软件的普及&#xff0c;越来越多的音乐爱好者和专业制作人开始涉足音乐创作的奇妙旅程。其中&#xff0c;FL Studio以其强大的功能、直观的操作界面和丰富的音色资源&#xf…

LED驱动IC:HC2106,1W升压型DC/DC白光LED驱动器HC2106系列,供应给大功率白光LED灯提供能源、恒流源

LED驱动IC&#xff1a; HC2106&#xff1a;1W升压型DC/DC白光LED驱动器HC2106系列 概述&#xff1a;HC2106系列芯片是针对LED应用设计的PFM 控制模式的开关型DC/DC 升压恒流芯片&#xff0c;通过外接电阻可使输出电流值恒定在0mA&#xff5e;500mA。 HC2106可以给一个、多个…

算法004:盛水最多的容器

这道题比较简单&#xff0c;使用双指针。 要求的是最大面积&#xff0c;对于一个水桶&#xff08;水杯来说&#xff09;&#xff0c;面积的算法是固定的&#xff0c;就是底乘以高。 在这个题中&#xff0c;我们把左边的位置设为left&#xff0c;右边的位置设为right&#xff…

一个月飙升 9k star!打破常规的 git 客户端

作为一名程序员&#xff0c;想必大家每天都要使用 git 来管理自己的代码吧。有些大佬喜欢使用命令行来进行 git 的操作&#xff0c;有些新入门的小白程序员则比较喜欢使用各种 git 客户端来可视化的管理代码&#xff0c;而有些程序员则喜欢使用 IDE 中集成的 git 功能来做代码的…

力扣234. 回文链表

给你一个单链表的头节点 head &#xff0c;请你判断该链表是否为回文链表。如果是&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 示例 1&#xff1a; 输入&#xff1a;head [1,2,2,1] 输出&#xff1a;true # Definition for singly-linked list. # c…

R语言探索与分析17-CPI的分析和研究

一、选题背景 CPI&#xff08;居民消费价格指数&#xff09;作为一个重要的宏观经济指标&#xff0c;扮演着评估通货膨胀和居民生活水平的关键角色。在湖北省这个经济活跃的地区&#xff0c;CPI的波动对于居民生活、企业经营以及政府宏观经济政策制定都具有重要的影响。因此&a…

打造卓越任务调度体系:实用攻略与技巧解析

写这篇文章&#xff0c;想和大家从头到脚说说任务调度&#xff0c;希望大家读完之后&#xff0c;能够理解实现一个任务调度系统的核心逻辑。 1 Quartz Quartz 是一款 Java 开源任务调度框架&#xff0c;也是很多 Java 工程师接触任务调度的起点。 下图显示了任务调度的整体流…

基于STC12C5A60S2系列1T 8051单片机实现一主单片机与一从单片机相互发送数据的RS485通信功能

基于STC12C5A60S2系列1T 8051单片机实现一主单片机与一从单片机相互发送数据的RS485通信功能的RS485通信功能 STC12C5A60S2系列1T 8051单片机管脚图STC12C5A60S2系列1T 8051单片机串口通信介绍STC12C5A60S2系列1T 8051单片机串口通信的结构基于STC12C5A60S2系列1T 8051单片机串…

zdppy_api 中间件请求原理详解

单个中间件的逻辑 整体执行流程&#xff1a; 1、客户端发起请求2、中间件拦截请求&#xff0c;在请求开始之前执行业务逻辑3、API服务接收到中间件处理之后的请求&#xff0c;和数据库交互&#xff0c;请求数据4、数据库返回数据5、API处理数据库的数据&#xff0c;然后给客户…

【第十一课】空间数据基础与处理——属性数据管理

一、前言 Arcgis分析离不开两大主体数据&#xff0c;一是空间&#xff0c;二是经济属性。在运用 Aecgis 进行分析时&#xff0c;经常会碰到一些涉及多要素的属性更改或填写&#xff0c; 如果按照普通的方法&#xff0c;每个属性进行修改或填写的话&#xff0c;工作量是很大的&…

Apache OFBiz 路径遍历导致RCE漏洞复现(CVE-2024-36104)

0x01 产品简介 Apache OFBiz是一个电子商务平台,用于构建大中型企业级、跨平台、跨数据库、跨应用服务器的多层、分布式电子商务类应用系统。是美国阿帕奇(Apache)基金会的一套企业资源计划(ERP)系统。该系统提供了一整套基于Java的Web应用程序组件和工具。 0x02 漏洞概…

【深入理解计算机系统第3版】补码加法

感觉这部分有点难&#xff0c;所以稍微整理记一下。 抱歉中英混合&#xff0c;来回切换输入法真的很折磨人。 负溢出 正常 正溢出 以4位补码加法为例&#xff0c;理解下表(书中P64) 补码最大值Tmax 2^3 - 1 7, 补码最小值Tmin -2^3 -8 xyz x yz z mod 2^4zU2Tw(z)溢…

超燃混剪热门视频素材去哪里找? 爆款超燃网站合集分享

在今天的数字时代&#xff0c;短视频已成为传播信息和个人表达的主流方式。无论你是混剪爱好者还是自媒体创作者&#xff0c;掌握如何获取和利用高质量的视频素材是关键。本文将介绍几个顶级的视频素材网站&#xff0c;包括国内外的平台&#xff0c;帮助你创建引人入胜的视频作…

【数据结构】二叉搜索树--BST,Binary Search Tree

文章目录 二叉搜索树1. 二叉搜索树的概念2. 二叉搜索树的接口2.1 查找非递归查找递归查找 2.2 中序遍历2.3 插入非递归插入递归插入 2.4 删除非递归删除递归删除 3. 二叉搜索树的应用key搜索模型kv搜索模型 5. oj题 二叉搜索树 1. 二叉搜索树的概念 二叉搜索树又称二叉排序树…

12-学生们参加各科测试的次数(高频 SQL 50 题基础版)

12-学生们参加各科测试的次数 -- 学生表中&#xff0c;id是唯一的&#xff0c;将他作为主表 -- CROSS JOIN产生了一个结果集&#xff0c;该结果集是两个关联表的行的乘积 -- 2行表,与3行表使用cross join,得到2*36行数据 select st.student_id, st.student_name,su.subject_na…

Vxe UI vxe-upload vue上传组件,显示进度条的方法

vxe-upload vue 上传组件 查看官网 https://vxeui.com 显示进度条很简单&#xff0c;需要后台支持进度就可以了&#xff0c;后台实现逻辑具体可以百度&#xff0c;这里只介绍前端逻辑。 vue 上传附件 相关参数说明&#xff0c;具体可以看文档&#xff1a; multiple 是否允许…

现代密码学-国密算法

商用密码算法种类 商用密码算法 密码学概念、协议与算法之间的依赖关系 数字签名、证书-公钥密码、散列类算法 消息验证码-对称密码 &#xff0c;散列类 安全目标与算法之间的关系 机密性--对称密码、公钥密码 完整性--散列类算法 可用性--散列类、公钥密码 真实性--公…

项目雅景临居---模块2 标签管理

一、 [根据类型]查询标签列表 Autowiredprivate LabelInfoService service;Operation(summary "&#xff08;根据类型&#xff09;查询标签列表")GetMapping("list")public Result<List<LabelInfo>> labelList(RequestParam(required false)…

Linux学习笔记6 进程角度看内存泄露

一&#xff0c;从进程角度看堆区内存申请与释放问题 1&#xff0c;c语言中的内存泄漏 内存溢出&#xff1a;申请内存时&#xff0c;没用足够的内存可以使用。 内存泄露&#xff1a;严格来说&#xff0c;只有对象不会再被程序用到了&#xff0c;但是GC又不能回收它们的情况&…