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…

<HarmonyOS第一课>运行Hello World

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

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…

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

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

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

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

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;人们可以参加各种线…

lv21 QT 常用控件 2

1 QT GUI 类继承简介 布局管理器 输出控件 输入控件 按钮 容器 2 按钮示例 #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QCheckBox> #include <QLineEdit> #include <QPushButton>class Widget : public QWidget {Q_OBJECTpublic…

探究前端路由hash和history的实现原理(包教包会)

今天我们来讲一讲前端中很重要的一个部分路由&#xff08;router&#xff09;&#xff0c;想必前端小伙伴对‘路由’一词都不会感到陌生。但是如果哪天面试官问你&#xff0c;能大概说一说前端路由的实现原理吗&#xff1f; 你又会如何应对呢&#xff1f; 今天勇宝就带着大家一…

LeetCode 0938.二叉搜索树的范围和:深度优先搜索(可中序遍历)

【LetMeFly】938.二叉搜索树的范围和&#xff1a;深度优先搜索&#xff08;可中序遍历&#xff09; 力扣题目链接&#xff1a;https://leetcode.cn/problems/range-sum-of-bst/ 给定二叉搜索树的根结点 root&#xff0c;返回值位于范围 [low, high] 之间的所有结点的值的和。…

动态规划课堂2-----路径问题

目录 引言&#xff1a; 例题1&#xff1a;不同路径 例题2&#xff1a;不同路径II 例题3&#xff1a;礼物的最⼤价值 例题4&#xff1a;下降路径最⼩和 例题5&#xff1a;最小路径和 结语&#xff1a; 引言&#xff1a; 在学习完动态规划斐波那契数列模型后&#xff0c;…

信息安全计划

任何管理人员或人力资源专业人士都知道&#xff0c;除非彻底记录标准和实践&#xff0c;否则永远无法真正实施和执行标准和实践。正如您可能想象的那样&#xff0c;在保护您的网络、技术和数据系统免受网络威胁以及在发生这些事件时规划最及时、高效和有效的响应时&#xff0c;…

Linux环境搭建Jenkins(详细图文)

目录 简介Jenkins 特点 一、环境准备 1.jdk环境准备 2.maven环境准备 3.git环境准备 二、安装部署Jenkins&#xff08;采用war包方式&#xff09; 1.下载Jenkins ​2.启动war包 1&#xff09;将下载好的Jenkins的war包上传到服务器上 2&#xff09;编辑启动脚本,方便…

nginx反向代理和负载均衡配置

配置文件 位置 : /usr/local/software/nginx/conf vim nginx.conf 在http大括号下配置: upstream wnBalance{ server ip:端口 weight比重 :1或者2; 1为配重高 server ip:端口 weight1; } wnBalance : 代表括号中两个ip的变量名 位置 : /usr/local/so…

图像的压缩感知的MATLAB实现(第3种方案)

前面介绍了两种不同的压缩感知实现&#xff1a; 图像压缩感知的MATLAB实现&#xff08;OMP&#xff09; 压缩感知的图像仿真&#xff08;MATLAB源代码&#xff09; 上述两种方法还存在着“速度慢、精度低”等不足。 本篇介绍一种新的方法。 压缩感知&#xff08;Compressed S…

Vue-Cropper头像裁剪插件使用

1. 效果预览 2. 插件介绍 官网地址&#xff1a;[GitHub - xyxiao001/vue-cropper: A simple picture clipping plugin for vue](https://github.com/xyxiao001/vue-cropper?fromthosefree.com) 3 . 插件使用 下载插件 npm install vue-croppernext3 . 封装好的代码&#x…