首页 > 其他分享 >认识meta

认识meta

时间:2024-06-04 16:30:04浏览次数:19  
标签:count src 认识 camera meta entry data metadata

认识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 (index == src->entry_count) return NOT_FOUND;
    }
    return get_camera_metadata_entry(src, index, entry);
}

// 根据index, 将对应的entry 拿出来
int get_camera_metadata_entry(camera_metadata_t *src,  size_t index,  camera_metadata_entry_t *entry)
 {
    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)  // 大于4字节
    {
        entry->data.u8 = get_data(src) + buffer_entry->data.offset;
    }
    else
    {
        entry->data.u8 = buffer_entry->data.value;  // // 小于4字节
    }
}

int get_camera_metadata_entry(camera_metadata_t *src,  size_t index,  camera_metadata_entry_t *entry) 

更新entry

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) 

step1:当要插入的数据和原来entry的数据长度不相等时,如果entry大于4字节时,

               先删除旧的数据:把下个entry(当前的data.offset + entry_bytes)的data到后面的整个data区,向前移动entry_bytes个字节,覆盖掉当前entry的数据, 然后更新后面的entry的data.offset

                最后把新的tag数据追加到整个data区的后面  

step2:当要插入的数据和原来entry的数据长度相等时,重复利用原来的data内存, 把新的tag数据拷贝到原来的entry的数据区

step3:    如果entry小于等于4字节,直接拷贝到entry->data.value中即可

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)
{
    camera_metadata_buffer_entry_t *entry = get_entries(dst) + index;

    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) // 要插入的数据和原来entry的数据长度不相等
    {
         //entry大于4字节时,先删除旧的数据:把下个entry

标签:count,src,认识,camera,meta,entry,data,metadata
From: https://blog.csdn.net/weixin_39732855/article/details/139442847

相关文章

  • 【Linux系统编程】冯诺依曼体系、操作系统、进程的认识
    目录一、认识冯诺依曼体系二、认识操作系统三、认识进程一、认识冯诺依曼体系我们日常使用的计算机,笔记本和我们不常见的计算机如服务器,它们都遵循冯诺依曼体系。下图是冯诺依曼体系结构的图解:我们可以看到冯诺依曼体系结构由以下硬件组成:输入设备、输出设备、存储器......
  • 认识微服务,认识Spring Cloud
    1.介绍本博客探讨的内容如下所示什么是微服务?什么是springcloud?微服务和springcloud有什么关系?首先,没有在接触springcloud之前,我写的项目都是单体结构, 但随着网站的用户量越来越大,需求也会越来越多,流量也会越来越大。单体架构的弊端也就随之浮现了:后端服务器的压力越来......
  • 自动化测试的认识误区
    误区一:自动化测试是一种比人工测试更先进,更高级的测试手段。自动化测试既有自身的优点,也有其局限性。例如对于需求不明确,或者界面经常发生变动的产品就不适合使用自动化测试。自动化测试与手工测试的关系应该是相辅相成,互相弥补各自的局限性,相互促进。误区二:自动化测试能够发现......
  • 关于GOGC的几点认识
    以下理解来自https://tip.golang.org/doc/gc-guide文章并不好理解。。go的标准库runtime提供了GC的相关能力。栈上的空间不归GOGC管,GOGC只考虑heap空间。所谓的transitive性质:部分衍生空间会纳入到GOGC回收中。GOGC使用tracinggarbagecollection的方式。GC需要关注的......
  • ARC学习(2)基本编程模型认识(二)
    笔者继续来学习一下arc的编程模型的寄存器信息。1、core寄存器深入参数寄存器:r0-r7,8个参数,暂存器:r10-r15保存寄存器:r16-r25调用函数需要保存的寄存器指针寄存器:gp(全局指针)、fp(栈顶指针)、sp(栈底指针)链接寄存器:ilink(异常链接寄存器)、blink(分支链接寄存器)通用目的寄存器......
  • MySQL基础索引知识【索引创建删除 | MyISAM & InnoDB引擎原理认识】
      博客主页:花果山~程序猿-CSDN博客文章分栏:MySQL之旅_花果山~程序猿的博客-CSDN博客关注我一起学习,一起进步,一起探索编程的无限可能吧!让我们一起努力,一起成长!目录 一,索引用处二,磁盘三,mysql与磁盘的基本交互单位四,管理page的数据结构(InnoDB引擎下)单个page多个pa......
  • const filePath = fileURLToPath(new URL('plopfile.js', import.meta.url)); 解释一
    这段代码的作用是获取当前文件所在目录下的plopfile.js文件的绝对路径。这里是逐步解释:import.meta.url:这是ESModules中的一个元属性,它提供了当前模块的绝对URL。在Node.js环境中,当你在一个模块文件中访问import.meta.url时,它会返回该模块文件的文件系统路径转换成的URL格......
  • 你认识nginx吗,nginx是做什么的,nginx可以做什么 --1)nginx介绍
    ngNginx简介Nginx(发音同enginex)是一个异步框架的Web服务器,也可以用作反向代理,负载平衡器和HTTP缓存。该软件由 IgorSysoev 创建,并于2004年首次公开发布。同名公司成立于2011年,以提供支持。Nginx是一款免费的开源软件,根据类BSD许可证的条款发布。一大部分Web服务......
  • 你认识nginx吗,nginx是做什么的,nginx可以做什么 --2)nginx配置
    hello大家今天教大家如何用nginx实验tomcat的负载均衡,同理其他的也可以,如httpd等首先需要准备一个nginx和tomcat包,这里用到的是版本号为然后需要准备最少三台linux虚拟机,然后我们开始吧1.安装tomcat解包tarzxf/mnt/apache-tomcat-8.5.16.tar.gz-C/usr/src   ......
  • 认识Windows操作系统
    开机启动项在Windows系统中,开机启动项通常通过如下配置:注册表启动目录注册表按住WIN+R打开运行,输入regedit打开注册表编辑器用户启动项:\HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Run系统启动项:\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Cu......