Camera metadata设计与应用

前言

Android的Camera Metadata是一种数据结构,用于表示图像特征的参数,例如常见的曝光、AE、AWB、flash等参数。在新的Camera API2 / HAL3架构中,这种结构被用来在app-hal之间IPC传输,取代了原先的SetParameter()/GetParameter()方法。

一,metadata设计剖析

1.1 数据结构

源码路径:

system/media/camera/include/system/camera_metadata.h
system/media/camera/include/system/camera_metadata_tags.h
system/media/camera/src/camera_metadata.c
system/media/camera/src/camera_metadata_tag_info.c

http://androidxref.com/9.0.0_r3/xref/system/media/camera/src/camera_metadata.c

Camera Metadata将参数以有序结构体的形式保存在一块连续的内存中。这个结构体的内存分布大致可以分为以下几个区域:

1. 区域一:存储camera_metadata_t结构体的定义,占用内存48Byte。该区域数据结构如下:

struct camera_metadata;
typedef struct camera_metadata camera_metadata_t;#define METADATA_ALIGNMENT ((size_t) 4)
struct camera_metadata {metadata_size_t          size;uint32_t                 version;uint32_t                 flags;metadata_size_t          entry_count;metadata_size_t          entry_capacity;metadata_uptrdiff_t      entries_start; // Offset from camera_metadatametadata_size_t          data_count;metadata_size_t          data_capacity;metadata_uptrdiff_t      data_start; // Offset from camera_metadatauint32_t                 padding;    // padding to 8 bytes boundarymetadata_vendor_id_t     vendor_id;
};
_Static_assert(sizeof(camera_metadata_t) == 48,"Size of camera_metadata_t must be 48");

2. 区域二:保留区,供未来使用。

3. 区域三:序号为0~entry_count-1的camera_metadata_buffer_entry_t结构体对象,简称metadata_entry结构体对象,每个对象有自己的tag。该区域数据结构如下:

typedef struct camera_metadata_entry {size_t   index;uint32_t tag;uint8_t  type;size_t   count;union {uint8_t *u8;int32_t *i32;float   *f;int64_t *i64;double  *d;camera_metadata_rational_t *r;} data;
} camera_metadata_entry_t;

4. 区域四:剩余未使用的Tag结构体的内存保留,该区域大小为(entry_capacity – entry_count)个TAG,也就是(entry_capacity – entry_count)个camera_metadata_buffer_entry_t的空间。

5. 区域五:所有Tag对应的具体metadata数据。仅camera_metadata.c函数使用,外部函数不能使用该数据结构。该区域数据结构如下:

#define DATA_ALIGNMENT ((size_t) 8)
typedef union camera_metadata_data {uint8_t u8;int32_t i32;float   f;int64_t i64;double  d;camera_metadata_rational_t r;
} camera_metadata_data_t;_Static_assert(sizeof(camera_metadata_data_t) == 8,"Size of camera_metadata_data_t must be 8");

6. 区域六:剩余未使用的Tag占用的内存。

从metadata源码定义来看这个结构体包括Head区、Entry区和Data区,典型TLV结构,描述每个Tag对应模型是key-value对,键值映射关系。数据模型概述如下:

metadata增删改查操作 都以camera_metadata_t 的结构体数据为操作对象,相当于handle。

1.2 增删改查
camera_metadata_t* allocate_camera_metadata(size_t entry_capacity, size_t data_capacity)    //metadata 内存分配
void free_camera_metadata(camera_metadata_t *metadata) //释放 metadata 对应内存
int add_camera_metadata_entry(camera_metadata_t *dst, uint32_t tag, const void *data, size_t data_count)    //在 metadata 中增加 tag 和 value
int delete_camera_metadata_entry(camera_metadata_t *dst, size_t index)    //删除 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)    //更新 tag 的 value 值
int find_camera_metadata_entry(camera_metadata_t *src, uint32_t tag, camera_metadata_entry_t *entry)    //根据 tag 查找 value

1.allocate_camera_metadata创建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);void *buffer = calloc(1, memory_needed);camera_metadata_t *metadata = place_camera_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 boundarymemory_needed = ALIGN_TO(memory_needed, ENTRY_ALIGNMENT);memory_needed += sizeof(camera_metadata_buffer_entry_t[entry_count]);// Start buffer list at aligned boundarymemory_needed = ALIGN_TO(memory_needed, DATA_ALIGNMENT);memory_needed += sizeof(uint8_t[data_count]);// Make sure camera metadata can be stacked in continuous memorymemory_needed = ALIGN_TO(memory_needed, METADATA_PACKET_ALIGNMENT);return memory_needed;
}

sizeof(uint8_t[data_count])表示sizeof(uint8_t)*data_count,即数组长度为data_count内存size。

二,provider进程IPC传输hal层metadata

Android metadata通过Binder机制实现app与hal传输,而不是共享内存。

通过源码分析,hal是如何做到可以上报metadata到app。

2.1 metada回调接口注册

这个回调是binder通信机制。

1,获取client注册的ICameraDeviceCallback

ICameraDeviceCallback有processCaptureResult上报metadata接口,根据hidl机制,实体是cameraserver client的。

CameraDeviceSession.cpp - OpenGrok cross reference for /hardware/interfaces/camera/device/3.2/default/CameraDeviceSession.cpp (aospxref.com)

CameraDeviceSession::CameraDeviceSession(camera3_device_t* device,const camera_metadata_t* deviceInfo,const sp<ICameraDeviceCallback>& callback) :camera3_callback_ops({&sProcessCaptureResult, &sNotify, nullptr, nullptr}),mDevice(device),mDeviceVersion(device->common.version),mFreeBufEarly(shouldFreeBufEarly()),mIsAELockAvailable(false),mDerivePostRawSensKey(false),mNumPartialResults(1),mResultBatcher(callback) {mDeviceInfo = deviceInfo;camera_metadata_entry partialResultsCount =mDeviceInfo.find(ANDROID_REQUEST_PARTIAL_RESULT_COUNT);if (partialResultsCount.count > 0) {mNumPartialResults = partialResultsCount.data.i32[0];}mResultBatcher.setNumPartialResults(mNumPartialResults);camera_metadata_entry aeLockAvailableEntry = mDeviceInfo.find(ANDROID_CONTROL_AE_LOCK_AVAILABLE);if (aeLockAvailableEntry.count > 0) {mIsAELockAvailable = (aeLockAvailableEntry.data.u8[0] ==ANDROID_CONTROL_AE_LOCK_AVAILABLE_TRUE);}// Determine whether we need to derive sensitivity boost values for older devices.// If post-RAW sensitivity boost range is listed, so should post-raw sensitivity control// be listed (as the default value 100)if (mDeviceInfo.exists(ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE)) {mDerivePostRawSensKey = true;}mInitFail = initialize();
}

2,processCaptureResult上报metadata数据

void CameraDeviceSession::sProcessCaptureResult(const camera3_callback_ops *cb,const camera3_capture_result *hal_result) {CameraDeviceSession *d =const_cast<CameraDeviceSession*>(static_cast<const CameraDeviceSession*>(cb));CaptureResult result = {};camera3_capture_result shadowResult;bool handlePhysCam = (d->mDeviceVersion >= CAMERA_DEVICE_API_VERSION_3_5);std::vector<::android::hardware::camera::common::V1_0::helper::CameraMetadata> compactMds;std::vector<const camera_metadata_t*> physCamMdArray;sShrinkCaptureResult(&shadowResult, hal_result, &compactMds, &physCamMdArray, handlePhysCam);status_t ret = d->constructCaptureResult(result, &shadowResult);if (ret == OK) {d->mResultBatcher.processCaptureResult(result);}
}

 d->mResultBatcher.processCaptureResult(result);为回调接口,通过binder向cameraserver client发送数据,包含metadata数据。

3,vendor camera.XXX.so库提供给provider调用的camera3接口

 int (*initialize)(const struct camera3_device *, const camera3_callback_ops_t *callback_ops);


camera3.h - OpenGrok cross reference for /hardware/libhardware/include/hardware/camera3.h (aospxref.com)

camera3_callback_ops_t是camera3_callback_ops typedef起的别名。

initialize主要是设置callback回调接口,包含processCaptureResult,为CameraDeviceSession::sProcessCaptureResult。

4,CameraDeviceSession调用内部initialize方法

到这里完成回调接口在vendor camera.XXX.so注册。

2.2 dlopen camera.XXX.so

1,camera.XXX.so hal入口

open中完成camera3_device_ops_t获取。camera_common.h - OpenGrok cross reference for /hardware/libhardware/include/hardware/camera_common.h (aospxref.com)

/*** The id of this module
*/
#define CAMERA_HARDWARE_MODULE_ID "camera"

2,camera hal 接口camera3_device_t

camera3.h - OpenGrok cross reference for /hardware/libhardware/include/hardware/camera3.h (aospxref.com)

typedef struct camera3_device {/*** common.version must equal CAMERA_DEVICE_API_VERSION_3_0 to identify this* device as implementing version 3.0 of the camera device HAL.** Performance requirements:** Camera open (common.module->common.methods->open) should return in 200ms, and must return* in 500ms.* Camera close (common.close) should return in 200ms, and must return in 500ms.**/hw_device_t common;camera3_device_ops_t *ops;void *priv;
} camera3_device_t;

三,provider进程操作hal层metadata实例

hal层通常不直接操作camera_metadata_t结构,一般使用类封装结构CameraMetadata

/frameworks/av/camera/include/camera/CameraMetadata.h

/frameworks/av/camera/CameraMetadata.cpp

1,Staticcharacteristic)注册

int initStaticMetadata(int32_t cameraId, camera_metadata_t **static_metadata) {
...CameraMetadata staticInfo;/*FLASH_INFO*/staticInfo.update(ANDROID_FLASH_INFO_AVAILABLE,&(flash_InfoInfo.available), 1);*static_metadata = staticInfo.release();
...
}

2,metdata读操作

int updataWorkMetadata(const CameraMetadata &frame_settings, uint32_t frame_number) {
...if (frame_settings.exists(ANDROID_CONTROL_AE_ANTIBANDING_MODE)) {uint8_t valueU8 =frame_settings.find(ANDROID_CONTROL_AE_ANTIBANDING_MODE).data.u8[0];}
...
}

3,metdata写操作

camera_metadata_t *translateLocalToFwMetadata(uint32_t frame_number) {CameraMetadata camMetadata;camera_metadata_t *resultMetadata;
...uint8_t enable_zsl = false;camMetadata.update(ANDROID_CONTROL_ENABLE_ZSL,&(enable_zsl), 1);
...resultMetadata = camMetadata.release();return resultMetadata;
}

四,小结

从Android hidl和hal设计来看,总体都是为了解耦,metadata同样如此,解耦同时增加兼容性。

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

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

相关文章

【蓝桥杯单片机入门记录】动态数码管

目录 一、数码管动态显示概述 二、动态数码管原理图 &#xff08;1&#xff09;原理图 &#xff08;2&#xff09;动态数码管如何与芯片相连 &#xff08;3&#xff09;“此器件” ——>锁存器74HC573 三、动态数码管显示例程 &#xff08;1&#xff09;例程1&#xf…

独立站谷歌SEO外包与自建SEO团队:哪个更适合您的业务?

随着数字营销的崛起&#xff0c;搜索引擎优化&#xff08;SEO&#xff09;已成为企业提升在线可见度、吸引潜在客户的关键手段。面对独立站谷歌SEO外包服务和自建SEO团队两种选择&#xff0c;企业往往会感到困惑。本文将深入探讨这两种方式的优势与局限&#xff0c;帮助您做出明…

CentOS 7.9上编译wireshark 3.6

工作环境是Centos 7.9&#xff0c;原本是通过flathub安装的wireshark&#xff0c;但是在gnome的application installer上升级到wireshark 4.2.3之后就运行不起来了&#xff0c;flatpak run org.wireshark.Wireshark启动提示缺少qt6&#xff0c;查了一下wireshark新版是依赖qt6的…

<HarmonyOS第一课>运行Hello World

本课程是基于HarmonyOS 3.1/4.0版本的新技术和特性所推出的系列化课程&#xff0c;每个课程单元里面都包含视频、Codelab、文章和习题&#xff0c;帮助您快速掌握HarmonyOS的应用开发&#xff1b; 通过本章节的学习&#xff0c;您可以安装DevEco Studio开发工具&#xff0c;运行…

docker-集成测试搭建

dockerd守护进程 Dockerd&#xff08;Docker Daemon&#xff09;是 Docker 引擎的守护进程&#xff0c;是运行在后台的一个持续运行的进程&#xff0c;负责管理 Docker 容器、镜像、网络和存储等核心功能。它是 Docker 容器的守护进程&#xff0c;负责接收 Docker API 请求并管…

java面试:Seata 分布式事务

文章目录 引言I Seata 分布式事务1.1 Seata的整体架构1.2 使用 Seata 进行分布式事务管理的步骤1.3 配置Seata Server1.4 Seata分布式模式1.5 高可用II XA模式III TA模式3.1 TA的写隔离3.2 AT模式的优缺点3.3 实现AT模式IV TCC模式 (Try-Confirm-Cancel)补偿事务4.1 空回滚和拒…

Java应用通过jmx_exporter对外暴露jvm指标

示范代码 public class App {public static void main( String[] args ) throws InterruptedException {while(true){Thread.sleep(10000);System.out.println( "Hello World!" );}} } maven打包,生成test-prometheus-1.0-SNAPSHOT.jar 编写config.yaml lowercas…

RISC-V SoC + AI | 在全志 D1「哪吒」开发板上,跑个 ncnn 神经网络推理框架的 demo

引言 D1 是全志科技首款基于 RISC-V 指令集的 SoC&#xff0c;主核是来自阿里平头哥的 64 位的 玄铁 C906。「哪吒」开发板 是全志在线基于全志科技 D1 芯片定制的 AIoT 开发板&#xff0c;是目前还比较罕见的使用 RISC-V SoC 且可运行 GNU/Linux 操作系统的可量产开发板。 n…

Wireshark TS | Linux 系统对时问题

问题描述 节前业务运维同事提交了一个 case &#xff0c;说是部署在新业务区域的 Linux 服务器和老业务区域的 Linux 服务器无法对时&#xff0c;脚本里使用的是 clockdiff 命令&#xff0c;无法正常返回结果&#xff0c;而在老业务区域两台服务器之间执行命令就正常&#xff…

桥接模式(Bridge Pattern)

桥接模式&#xff08;Bridge Pattern&#xff09; 定义 将抽象部分与它的实现部分分离&#xff0c;使它们都可以独立的变化。 属于结构性模式 理解 合成/聚合复用原则的具体实现&#xff0c;将一个整体的多个实现部分独立出来&#xff0c;每个部分都可以独立的变化&#x…

OSI参考模型和TCP/IP网络参考模型

1、OSI参考模型 1.1 产生背景 为了解决网络之间的兼容性问题,实现网络设备间的相互通讯,国际标准化组织ISO于1984年提出了OSIRM(Open System Interconnection Reference Model,开放系统互连参考模型)。OSI参考模型很快成为计算机网络通信的基础模型。由于种种原因,并没有…

android stadio通过wifi热点 adb连接android

问题&#xff1a;有时后忘记带android usb线了&#xff0c;但需要调试 解决办法&#xff1a; 1、准备开发工具adb&#xff0c;需要到sdk下的platform-tools的目录下&#xff0c;或者把这个目录加到系统path里&#xff0c;我的是D:\android\sdk\platform-tools这个目录&#x…

Mysql整理-Mysql事务

MySQL中的事务是一组顺序执行的数据库操作,要么完全执行,要么完全不执行。事务是数据库管理的一个重要概念,尤其是在确保数据完整性和一致性方面。MySQL中的事务遵循ACID属性,这是事务性数据库系统的四个关键特性: 原子性(Atomicity):事务内的所有操作都是作为一个单一…

linux系统---nginx(2)rewrite重写功能

目录 一、rewrite概述 1、rewrite功能 2、跳转场景 二、标准配置指令 1、rewrite日志记录指令 2、未初始化变量告警日志记录指令 3、rewrite 指令 3.1 正则表达式 三、rewrite模块使用实例 1.基于域名的跳转 一、rewrite概述 1、rewrite功能 访问重写 rewrite 是 …

sql 分割字段,并分行

创建测试表格 CREATE TABLE test (id INT PRIMARY KEY, data VARCHAR(100)); INSERT INTO test VALUES (1, A,B,C); INSERT INTO test VALUES (2, D,E,F,G);查询并分割字段 SELECT id, value AS split_data FROM test CROSS APPLY STRING_SPLIT(data, ,) WHERE LEN(value) …

11个Linux性能分析命令

Linux性能分析命令有很多&#xff0c;不同的命令可以用来监控不同的系统资源和活动。根据您的问题&#xff0c;我为您推荐以下11个常用的Linux性能分析命令&#xff1a; uptime&#xff1a;显示系统的运行时间和平均负载。dmesg&#xff1a;显示系统的启动信息和内核的日志信息…

如何改变.net托管的入口main函数

有小伙伴问: .NET托管入口Main函数可以修改成别的函数&#xff0c;用来作为程序的入口吗&#xff1f; 答案&#xff1a;当然是可以的。这也算是.NET里面非常简单的骚操了。本篇来用最新的.NET8演示下&#xff0c;如何修改Main入口。 1.简单控制台例子&#xff1a; namespace…

【JavaEE】_tomcat的安装与使用

目录 1. Tomcat简介 2. Tomcat安装 2.1 下载Tomcat并解压缩 2.2 启动Tomcat 2.2.1 Tomcat乱码问题 2.2.2 Tomcat闪退问题 2.3 访问Tomcat欢迎页面 3. 使用Tomcat部署前端代码 3.1 路径匹配 3.2 文件路径访问与网络访问 4. 静态页面与动态页面 5. 基于tomcat的网站后…

更换个人开发环境后,pycharm连接服务器报错Authentication failed

原因&#xff1a;服务器中更换个人开发环境后&#xff0c;密码变了。 解决&#xff1a;在pycharm中修改服务器开发环境密码即可。 1 找到Tools-Depolyment-Configuration 2 点击SSH Configuration后的省略号 3 修改这里面的Password即可

婚恋交友系统源码-交友APP小程序H5开发-源码交付,支持二开-实名制交友更放心!

一、交友小程序开发的重要性 1. 满足人们的社交需求&#xff1a;交友小程序为人们提供了一个便捷的社交平台&#xff0c;使得人们可以随时随地地结识新朋友&#xff0c;拓展自己的社交圈子。 2. 丰富人们的业余生活&#xff1a;通过交友小程序&#xff0c;人们可以参加各种线…