转载链接:
https://www.cnblogs.com/blogs-of-lxl/p/10981303.html
https://blog.csdn.net/Ciellee/article/details/105807436
Camera API2/HAL3架构下使用了全新的CameraMetadata结构取代了之前的SetParameter/Paramters等操作,实现了Java到native到HAL3的参数传递。
引入了管道的概念将安卓设备和摄像头之间联系起来,系统向摄像头发送 Capture 请求,而摄像头会返回 CameraMetadata,这一切建立在一个叫作 CameraCaptureSession 的会话中。
Camera_metadata数据结构在Camera流程中起到了很大重要,可以说所有的自顶层下发给hal层的参数都是通过camera_metadata传递的。今天我们就来好好看看它到底如何保存的,以及它的数据组织形式如何表现。
Camera_metadata数据结构相关的主要有以下几个文件:
system/media/camera/include/system/Camera_metadata_tags.h
system/media/camera/src/camera_metadata_tag_info.c
system/media/camera/src/Camera_metadata.c
system/media/camera/include/system/Camera_metadata.h
Framework/av/camera/CameraMetadata.cpp
Framework/av/include/camera/CameraMetadata.h
在camera_metadata.c代码中有下面一副图,这里就是camera_metadata的内存分布。camera_metadata数据结构是一块连续的内存空间。在内存开始处放置的是一个struct camera_metadata的对象,这里面记录了该数据块包含的基本信息,具体大家就看下面代码中的结构体注释吧。紧接着头部下面是entry数据空间,这个空间记录了每一个tag的数据,数据大小和在数据区的偏移地址。紧接着entry下面的是真正的数据区域了,这个区域保存了所有大小大于4字节的Tag数据。具体后面代码中有详细描述。
android代码中的一个Camera_Metadata数据内存块中最小基本单元是struct camera_metadata_buffer_entry,总的entry数目等信息需要struct camera_metadata数据来维护.
/**
* A packet of metadata. This is a list of entries, each of which may point to
* its values stored at an offset in data.
*
* It is assumed by the utility functions that the memory layout of the packet
* is as follows:
*
* |-----------------------------------------------|
* | camera_metadata_t |
* | |
* |-----------------------------------------------|
* | reserved for future expansion |
* |-----------------------------------------------|
* | camera_metadata_buffer_entry_t #0 |
* |-----------------------------------------------|
* | .... |
* |-----------------------------------------------|
* | camera_metadata_buffer_entry_t #entry_count-1 |
* |-----------------------------------------------|
* | free space for |
* | (entry_capacity-entry_count) entries |
* |-----------------------------------------------|
* | start of camera_metadata.data |
* | |
* |-----------------------------------------------|
* | free space for |
* | (data_capacity-data_count) bytes |
* |-----------------------------------------------|
*
* With the total length of the whole packet being camera_metadata.size bytes.
*
* In short, the entries and data are contiguous in memory after the metadata
* header.
*/
struct camera_metadata {
metadata_size_t size; //整个metadata数据大小
uint32_t version;
uint32_t flags;
metadata_size_t entry_count; //已经添加TAG的入口数量,(即内存块中已经包含多少TAG了)
metadata_size_t entry_capacity; //最大能容纳TAG的入口数量(即最大能放多少tag)
metadata_uptrdiff_t entries_start; // 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;
};
Camera2Client 使用 API1 传递参数采用的逻辑是还是在Java层预留了setParameters接口,只是当Parameter在设置时比起CameraClient而言,是将这个Parameter根据不同的TAG形式直接绑定到CameraMetadata mPreviewRequest/mRecordRequest/mCaptureRequest中,这些数据会由Capture_Request转为camera3_capture_request中的camera_metadata_t settings完成参数从Java到native到HAL3的传递。
但是在Camera API2下,不再需要那么复杂的转换过程,在Java层中直接对参数进行设置并将其封装到Capture_Request即可,即参数控制由Java层来完成。这也体现了API2中Request和Result在APP中就大量存在的原因。对此为了和Framework Native层相关TAG数据的统一,在Java层中大量出现的参数设置是通过Section Tag的name来交由Native完成转换生成在Java层的TAG。
(1)Java层对应代码位置:frameworks\base\core\java\android\hardware\camera2\impl\CameraMetadataNative.java
private <T> T getBase(Key<T> key) {
int tag = nativeGetTagFromKeyLocal(key.getName());
byte[] values = readValues(tag);
if (values == null) {
tag = nativeGetTagFromKeyLocal(key.mFallbackName);
values = readValues(tag);
}
int nativeType = nativeGetTypeFromTagLocal(tag);
Marshaler<T> marshaler = getMarshalerForKey(key, nativeType);
ByteBuffer buffer = ByteBuffer.wrap(values).order(ByteOrder.nativeOrder());
return marshaler.unmarshal(buffer);
}
(2)Native层对应代码位置:frameworks/base/core/jni/android_hardware_camera2_CameraMetadata.cpp
static const JNINativeMethod gCameraMetadataMethods[] = {
// static methods
{ "nativeGetTagFromKey",
"(Ljava/lang/String;J)I",
(void *)CameraMetadata_getTagFromKey },
{ "nativeGetTypeFromTag",
"(IJ)I",
(void *)CameraMetadata_getTypeFromTag },
{ "nativeSetupGlobalVendorTagDescriptor",
"()I",
(void*)CameraMetadata_setupGlobalVendorTagDescriptor },
// instance methods
......
其中CameraMetadata_getTagFromKey是实现将一个Java层的string转为一个tag的值,如:android.control.mode。对比最初不同的Section name就可以发现前面两个x.y的字符串就是代表是Section name.而后面mode即是在该section下的tag数值,所以通过对这个string的分析可知,就可以定位对应的section以及tag值,这样返回到Java层的就是key相应的tag值了。
继续追踪到 \system\media\camera\src\camera_metadata.c:
// Declared in system/media/private/camera/include/camera_metadata_hidden.h
const char *get_local_camera_metadata_tag_name_vendor_id(uint32_t tag,
metadata_vendor_id_t id) {
//这里我们传进去的Tag是ANDROID_FLASH_MODE,即4<<16+2.(+2请看看开始那个长图最右边偏移),由移动16位得到4.
uint32_t tag_section = tag >> 16;
if (tag_section >= VENDOR_SECTION && vendor_cache_ops != NULL &&
id != CAMERA_METADATA_INVALID_VENDOR_ID) {
return vendor_cache_ops->get_tag_name(tag, id);
} else if (tag_section >= VENDOR_SECTION && vendor_tag_ops != NULL) {
return vendor_tag_ops->get_tag_name(
vendor_tag_ops,
tag);
}
if (tag_section >= ANDROID_SECTION_COUNT || //这里就是判断tag_section段序号是否已经超出了界限。
tag >= camera_metadata_section_bounds[tag_section][1] ) { // 关键是camera_metadata_section_bounds这个数组,保存了各个tag的绑定信息
//看看下面对应的结构体(4<<16+2) < ANDROID_FLASH_END
return NULL;
}
uint32_t tag_index = tag & 0xFFFF;//这里按位与(4<<16+2) & 0xFFFF = 2;
//这里tag_section=4 tag_index=2.请看下面的tag_info结构体,返回的tag_type = TYPE_BYTE,好了得到这个值,我们可以继续上面的分析。
return tag_info[tag_section][tag_index].tag_name;
}
system\media\camera\src\camera_metadata.c
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]; //看下面结构体就知道了,这里data_bytes = 1 * 1;
return data_bytes <= 4 ? 0 : ALIGN_TO(data_bytes, DATA_ALIGNMENT); //由于这里<=4成立,返回的是0
}
// camera_metadata.c 结构体
const size_t camera_metadata_type_size[NUM_TYPES] = {
[TYPE_BYTE] = sizeof(uint8_t),
[TYPE_INT32] = sizeof(int32_t),
[TYPE_FLOAT] = sizeof(float),
[TYPE_INT64] = sizeof(int64_t),
[TYPE_DOUBLE] = sizeof(double),
[TYPE_RATIONAL] = sizeof(camera_metadata_rational_t)
};
其他相关文件的调用关系如下图:
其中camera_metadata_tag_info.h包含了所有的基本宏,其中包含了下面的section枚举类型,在代码中可以看到,每一个section的大小是64K,因为他们根据之前枚举变量向左偏移16位每个段有64K,根据这样层层包扎,所以说每一个tag的值都是不同的,而且有序的组织在一起。
其中 camera_metadata_tags.h 包含了所有的基本宏,每一个section的大小是64K(每个枚举值左移16位):
/**
* !! Do not include this file directly !!
*
* Include camera_metadata.h instead.
*/
/**
* ! Do not edit this file directly !
*
* Generated automatically from camera_metadata_tags.mako
*/
/** TODO: Nearly every enum in this file needs a description */
/**
* Top level hierarchy definitions for camera metadata. *_INFO sections are for
* the static metadata that can be retrived without opening the camera device.
* New sections must be added right before ANDROID_SECTION_COUNT to maintain
* existing enumerations.
*/
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_LOGICAL_MULTI_CAMERA,
ANDROID_DISTORTION_CORRECTION,
ANDROID_SECTION_COUNT,
VENDOR_SECTION = 0x8000
} camera_metadata_section_t;
/**
* Hierarchy positions in enum space. All vendor extension tags must be
* defined with tag >= VENDOR_SECTION_START
*/
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,
ANDROID_LOGICAL_MULTI_CAMERA_START
= ANDROID_LOGICAL_MULTI_CAMERA
<< 16,
ANDROID_DISTORTION_CORRECTION_START
= ANDROID_DISTORTION_CORRECTION
<< 16,
VENDOR_SECTION_START = VENDOR_SECTION << 16
} camera_metadata_section_start_t;
而每个MODE的END值是根据START后的填充枚举变量偏移所得:
/**
* Main enum for defining camera metadata tags. New entries must always go
* before the section _END tag to preserve existing enumeration values. In
* addition, the name and type of the tag needs to be added to
* system/media/camera/src/camera_metadata_tag_info.c
*/
typedef enum camera_metadata_tag {
ANDROID_COLOR_CORRECTION_MODE = // enum | public | HIDL v3.2
ANDROID_COLOR_CORRECTION_START,
ANDROID_COLOR_CORRECTION_TRANSFORM, // rational[] | public | HIDL v3.2
ANDROID_COLOR_CORRECTION_GAINS, // float[] | public | HIDL v3.2
ANDROID_COLOR_CORRECTION_ABERRATION_MODE, // enum | public | HIDL v3.2
ANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES,
// byte[] | public | HIDL v3.2
ANDROID_COLOR_CORRECTION_END,
ANDROID_CONTROL_AE_ANTIBANDING_MODE = // enum | public | HIDL v3.2
ANDROID_CONTROL_START,
ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION, // int32 | public | HIDL v3.2
ANDROID_CONTROL_AE_LOCK, // enum | public | HIDL v3.2
ANDROID_CONTROL_AE_MODE, // enum | public | HIDL v3.2
ANDROID_CONTROL_AE_REGIONS, // int32[] | public | HIDL v3.2
ANDROID_CONTROL_AE_TARGET_FPS_RANGE, // int32[] | public | HIDL v3.2
ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER, // enum | public | HIDL v3.2
ANDROID_CONTROL_AF_MODE, // enum | public | HIDL v3.2
ANDROID_CONTROL_AF_REGIONS, // int32[] | public | HIDL v3.2
ANDROID_CONTROL_AF_TRIGGER, // enum | public | HIDL v3.2
ANDROID_CONTROL_AWB_LOCK, // enum | public | HIDL v3.2
ANDROID_CONTROL_AWB_MODE, // enum | public | HIDL v3.2
ANDROID_CONTROL_AWB_REGIONS, // int32[] | public | HIDL v3.2
ANDROID_CONTROL_CAPTURE_INTENT, // enum | public | HIDL v3.2
ANDROID_CONTROL_EFFECT_MODE, // enum | public | HIDL v3.2
ANDROID_CONTROL_MODE, // enum | public | HIDL v3.2
ANDROID_CONTROL_SCENE_MODE, // enum | public | HIDL v3.2
ANDROID_CONTROL_VIDEO_STABILIZATION_MODE, // enum | public | HIDL v3.2
ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES, // byte[] | public | HIDL v3.2
ANDROID_CONTROL_AE_AVAILABLE_MODES, // byte[] | public | HIDL v3.2
ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES, // int32[] | public | HIDL v3.2
ANDROID_CONTROL_AE_COMPENSATION_RANGE, // int32[] | public | HIDL v3.2
ANDROID_CONTROL_AE_COMPENSATION_STEP, // rational | public | HIDL v3.2
ANDROID_CONTROL_AF_AVAILABLE_MODES, // byte[] | public | HIDL v3.2
ANDROID_CONTROL_AVAILABLE_EFFECTS, // byte[] | public | HIDL v3.2
ANDROID_CONTROL_AVAILABLE_SCENE_MODES, // byte[] | public | HIDL v3.2
ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,
// byte[] | public | HIDL v3.2
ANDROID_CONTROL_AWB_AVAILABLE_MODES, // byte[] | public | HIDL v3.2
ANDROID_CONTROL_MAX_REGIONS, // int32[] | ndk_public | HIDL v3.2
ANDROID_CONTROL_SCENE_MODE_OVERRIDES, // byte[] | system | HIDL v3.2
ANDROID_CONTROL_AE_PRECAPTURE_ID, // int32 | system | HIDL v3.2
ANDROID_CONTROL_AE_STATE, // enum | public | HIDL v3.2
ANDROID_CONTROL_AF_STATE, // enum | public | HIDL v3.2
ANDROID_CONTROL_AF_TRIGGER_ID, // int32 | system | HIDL v3.2
ANDROID_CONTROL_AWB_STATE, // enum | public | HIDL v3.2
ANDROID_CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS,
// int32[] | hidden | HIDL v3.2
ANDROID_CONTROL_AE_LOCK_AVAILABLE, // enum | public | HIDL v3.2
ANDROID_CONTROL_AWB_LOCK_AVAILABLE, // enum | public | HIDL v3.2
ANDROID_CONTROL_AVAILABLE_MODES, // byte[] | public | HIDL v3.2
ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE, // int32[] | public | HIDL v3.2
ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST, // int32 | public | HIDL v3.2
ANDROID_CONTROL_ENABLE_ZSL, // enum | public | HIDL v3.2
ANDROID_CONTROL_AF_SCENE_CHANGE, // enum | public | HIDL v3.3
ANDROID_CONTROL_END, ......
对应关系如图所示:
然后在 camera_metadata_tag_info.c 中进行了映射和绑定,前面Native层CameraMetadata_getTagFromKey调用的camera_metadata_section_bounds实现在这里:
/**
* ! Do not edit this file directly !
*
* Generated automatically from camera_metadata_tag_info.mako
*/
const char *camera_metadata_section_names[ANDROID_SECTION_COUNT] = {
[ANDROID_COLOR_CORRECTION] = "android.colorCorrection",
[ANDROID_CONTROL] = "android.control",
[ANDROID_DEMOSAIC] = "android.demosaic",
[ANDROID_EDGE] = "android.edge",
[ANDROID_FLASH] = "android.flash",
[ANDROID_FLASH_INFO] = "android.flash.info",
[ANDROID_HOT_PIXEL] = "android.hotPixel",
[ANDROID_JPEG] = "android.jpeg",
[ANDROID_LENS] = "android.lens",
[ANDROID_LENS_INFO] = "android.lens.info",
[ANDROID_NOISE_REDUCTION] = "android.noiseReduction",
[ANDROID_QUIRKS] = "android.quirks",
[ANDROID_REQUEST] = "android.request",
[ANDROID_SCALER] = "android.scaler",
[ANDROID_SENSOR] = "android.sensor",
[ANDROID_SENSOR_INFO] = "android.sensor.info",
[ANDROID_SHADING] = "android.shading",
[ANDROID_STATISTICS] = "android.statistics",
[ANDROID_STATISTICS_INFO] = "android.statistics.info",
[ANDROID_TONEMAP] = "android.tonemap",
[ANDROID_LED] = "android.led",
[ANDROID_INFO] = "android.info",
[ANDROID_BLACK_LEVEL] = "android.blackLevel",
[ANDROID_SYNC] = "android.sync",
[ANDROID_REPROCESS] = "android.reprocess",
[ANDROID_DEPTH] = "android.depth",
[ANDROID_LOGICAL_MULTI_CAMERA] = "android.logicalMultiCamera",
[ANDROID_DISTORTION_CORRECTION]
= "android.distortionCorrection",
};
unsigned int camera_metadata_section_bounds[ANDROID_SECTION_COUNT][2] = {
[ANDROID_COLOR_CORRECTION] = { ANDROID_COLOR_CORRECTION_START,
ANDROID_COLOR_CORRECTION_END },
[ANDROID_CONTROL] = { ANDROID_CONTROL_START,
ANDROID_CONTROL_END },
[ANDROID_DEMOSAIC] = { ANDROID_DEMOSAIC_START,
ANDROID_DEMOSAIC_END },
[ANDROID_EDGE] = { ANDROID_EDGE_START,
ANDROID_EDGE_END },
[ANDROID_FLASH] = { ANDROID_FLASH_START,
ANDROID_FLASH_END },
[ANDROID_FLASH_INFO] = { ANDROID_FLASH_INFO_START, //刚才上面我们得到section num =4,就是这里了,而且取的ANDROID_FLASH_END
ANDROID_FLASH_INFO_END },
[ANDROID_HOT_PIXEL] = { ANDROID_HOT_PIXEL_START,
ANDROID_HOT_PIXEL_END },
[ANDROID_JPEG] = { ANDROID_JPEG_START,
ANDROID_JPEG_END },
[ANDROID_LENS] = { ANDROID_LENS_START,
ANDROID_LENS_END },
[ANDROID_LENS_INFO] = { ANDROID_LENS_INFO_START,
ANDROID_LENS_INFO_END },
[ANDROID_NOISE_REDUCTION] = { ANDROID_NOISE_REDUCTION_START,
ANDROID_NOISE_REDUCTION_END },
[ANDROID_QUIRKS] = { ANDROID_QUIRKS_START,
ANDROID_QUIRKS_END },
[ANDROID_REQUEST] = { ANDROID_REQUEST_START,
ANDROID_REQUEST_END },
[ANDROID_SCALER] = { ANDROID_SCALER_START,
ANDROID_SCALER_END },
[ANDROID_SENSOR] = { ANDROID_SENSOR_START,
ANDROID_SENSOR_END },
[ANDROID_SENSOR_INFO] = { ANDROID_SENSOR_INFO_START,
ANDROID_SENSOR_INFO_END },
[ANDROID_SHADING] = { ANDROID_SHADING_START,
ANDROID_SHADING_END },
[ANDROID_STATISTICS] = { ANDROID_STATISTICS_START,
ANDROID_STATISTICS_END },
[ANDROID_STATISTICS_INFO] = { ANDROID_STATISTICS_INFO_START,
ANDROID_STATISTICS_INFO_END },
[ANDROID_TONEMAP] = { ANDROID_TONEMAP_START,
ANDROID_TONEMAP_END },
[ANDROID_LED] = { ANDROID_LED_START,
ANDROID_LED_END },
[ANDROID_INFO] = { ANDROID_INFO_START,
ANDROID_INFO_END },
[ANDROID_BLACK_LEVEL] = { ANDROID_BLACK_LEVEL_START,
ANDROID_BLACK_LEVEL_END },
[ANDROID_SYNC] = { ANDROID_SYNC_START,
ANDROID_SYNC_END },
[ANDROID_REPROCESS] = { ANDROID_REPROCESS_START,
ANDROID_REPROCESS_END },
[ANDROID_DEPTH] = { ANDROID_DEPTH_START,
ANDROID_DEPTH_END },
[ANDROID_LOGICAL_MULTI_CAMERA] = { ANDROID_LOGICAL_MULTI_CAMERA_START,
ANDROID_LOGICAL_MULTI_CAMERA_END },
[ANDROID_DISTORTION_CORRECTION]
= { ANDROID_DISTORTION_CORRECTION_START,
ANDROID_DISTORTION_CORRECTION_END },
};
由 tag_info 结构体统一管理:
static tag_info_t android_color_correction[ANDROID_COLOR_CORRECTION_END -
ANDROID_COLOR_CORRECTION_START] = {
[ ANDROID_COLOR_CORRECTION_MODE - ANDROID_COLOR_CORRECTION_START ] =
{ "mode", TYPE_BYTE },
[ ANDROID_COLOR_CORRECTION_TRANSFORM - ANDROID_COLOR_CORRECTION_START ] =
{ "transform", TYPE_RATIONAL
},
[ ANDROID_COLOR_CORRECTION_GAINS - ANDROID_COLOR_CORRECTION_START ] =
{ "gains", TYPE_FLOAT },
[ ANDROID_COLOR_CORRECTION_ABERRATION_MODE - ANDROID_COLOR_CORRECTION_START ] =
{ "aberrationMode", TYPE_BYTE },
[ ANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES - ANDROID_COLOR_CORRECTION_START ] =
{ "availableAberrationModes", TYPE_BYTE },
};
-------------------------------------------------------------
tag_info_t *tag_info[ANDROID_SECTION_COUNT] = {
android_color_correction,
android_control,
android_demosaic,
android_edge,
android_flash,//ANDROID_FLASH_MODE tag的section_count=4 。
};
下图是Camera Metadata对不同section以及相应section下不同tag的布局图,以最常见的android.control Section为例进行描述:
如果要写数据,那么在native同样需要一个CameraMetadata对象,这里是在Java构造CameraMetadataNative时实现的,调用的native接口是nativeAllocate():
// instance methods
{ "nativeAllocate",
"()J",
(void*)CameraMetadata_allocate },
static jlong CameraMetadata_allocate(JNIEnv *env, jobject thiz) {
ALOGV("%s", __FUNCTION__);
return reinterpret_cast<jlong>(new CameraMetadata());
}
CameraMetadata::CameraMetadata(size_t entryCapacity, size_t dataCapacity) :
mLocked(false)
{
mBuffer = allocate_camera_metadata(entryCapacity, dataCapacity);
}
函数allocate_camera_metadata()是重新根据入口数和数据大小计算、申请buffer。紧接着第二个place_camera_metadata()就是对刚申请的buffer,初始化一些变量,为后面更新,插入tag数据做准备。
camera_metadata_t *allocate_camera_metadata(size_t entry_capacity,
size_t data_capacity) { //传入的参数是(2,0)
if (entry_capacity == 0) return NULL;
size_t memory_needed = calculate_camera_metadata_size(entry_capacity, //返回的是header+2*sizeof(entry)大小
data_capacity);
void *buffer = malloc(memory_needed); //malloc申请一块连续的内存,
return 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) {
if (dst == NULL) return NULL;
if (entry_capacity == 0) 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; //初始化entry_count =0
metadata->entry_capacity = entry_capacity; //最大的入口数量,针对ANDROID_FLASH_MODE这里是2个。
metadata->entries_start =
ALIGN_TO(sizeof(camera_metadata_t), ENTRY_ALIGNMENT); //entry数据域的开始处紧挨着camera_metadata_t 头部。
metadata->data_count = 0; //初始化为0
metadata->data_capacity = data_capacity; //因为没有申请内存,这里也是0
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); //计算data数据区域的偏移地址。数据区域紧挨着entry区域末尾。
return metadata;}//根据入口数量和数据数量,计算实际camera_metadata需要的内存块大小(header+sizeof(camera_entry)+sizeof(data)。
size_t calculate_camera_metadata_size(size_t entry_count,
size_t data_count) { //针对我们上面讲的例子,传入的参数是(2,0)
size_t memory_needed = sizeof(camera_metadata_t); //这里计算header大小了。
// Start entry list at aligned boundary
memory_needed = ALIGN_TO(memory_needed, ENTRY_ALIGNMENT); //按字节对齐后的大小
memory_needed += sizeof(camera_metadata_buffer_entry_t[entry_count]); //紧接着是entry数据区的大小了,这里申请了2个entry内存空间。
// Start buffer list at aligned boundary
memory_needed = ALIGN_TO(memory_needed, DATA_ALIGNMENT); //同样对齐
memory_needed += sizeof(uint8_t[data_count]); //data_count = 0
return memory_needed; //返回的最后算出的大小
}
CameraMetadata数据内存块中组成的最小基本单元是struct camera_metadata_buffer_entry,总的entry数目等信息需要struct camera_metadata_t来维护。
结构图如下:
{
UINT32 SensorTimestampTag = 0x000E0010;
camera_metadata_entry_t entry = { 0 };
camera_metadata_t* pMetadata =
const_cast<camera_metadata_t*>(static_cast<const camera_metadata_t*>(pResult->pResultMetadata));
UINT64 timestamp = m_shutterTimestamp[applicationFrameNum % MaxOutstandingRequests];
INT32 status = find_camera_metadata_entry(pMetadata, SensorTimestampTag, &entry);
if (-ENOENT == status) //没有查找到tag时,则认为是一个新的tag,需要添加到大数据结构中
{
status = add_camera_metadata_entry(pMetadata, SensorTimestampTag, ×tamp, 1);
}
else if (0 == status)
{
status = update_camera_metadata_entry(pMetadata, entry.index, ×tamp, 1, NULL);
}
}
find_camera_metadata_entry函数非常好理解,获取对应tag的entry结构体,并将数据保存在entry传入的参数中。
注:struct camera_metadata_buffer_entry_t; //内部使用记录tag数据
struct camera_metadata_entry_t; //外部引用
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) { //之前初始化时,flags = 0,这里不成立,跳到else处
// 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++) { //这里由于entry_count =0 因为根本就没有添加任何东西。
if (search_entry->tag == tag) {
break;
}
}
if (index == src->entry_count) return NOT_FOUND; //返回NOT_FOUNT
}
return get_camera_metadata_entry(src, index, //找到index的tag entry
entry);
}
int add_camera_metadata_entry(camera_metadata_t *dst,
uint32_t tag,
const void *data,
size_t data_count) { //这里传入的参数为(mBuffer,ANDROID_FLASH_MODE,5,1)
int type = get_camera_metadata_tag_type(tag);
if (type == -1) {
ALOGE("%s: Unknown tag %04x.", __FUNCTION__, tag);
return ERROR;
}
return add_camera_metadata_entry_raw(dst, //这里传入的参数为(mBuffer,ANDROID_FLASH_MODE,BYTE_TYPE,5,1) DOWN
tag,
type,
data,
data_count);
}
//下面是真正干实事的方法,这里会将外部传入的tag信息,存放到各自的家中
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 == NULL) return ERROR;
size_t data_bytes =
calculate_camera_metadata_entry_data_size(type, data_count); //计算要使用的内存大小这里1*1,但是返回的是0
if (data_bytes + dst->data_count > dst->data_capacity) return ERROR; //用的空间+当前数据位置指针,不能大于数据最大空间。
size_t data_payload_bytes =
data_count * camera_metadata_type_size[type]; //data_count =1,data_payload_bytes =1;
camera_metadata_buffer_entry_t *entry = get_entries(dst) + dst->entry_count;//得到当前空闲的entry对象。
memset(entry, 0, sizeof(camera_metadata_buffer_entry_t)); //清0
entry->tag = tag; //ANDROID_FLASH_MODE.
entry->type = type; //BYTE_TYPE
entry->count = data_count; //没有占用data数据域,这里就是0了。
if (data_bytes == 0) {
memcpy(entry->data.value, data,
data_payload_bytes); //小于4字节的,直接放到entry数据域。
} else {
entry->data.offset = dst->data_count;
memcpy(get_data(dst) + entry->data.offset, data,
data_payload_bytes);
dst->data_count += data_bytes;
}
dst->entry_count++; //入口位置记录指针+1.
dst->flags &= ~FLAG_SORTED;
return OK; //到这里ANDROID_FLASH_MODE就添加进去了。
}
update更新并建立参数过程:CameraMetadata支持不同类型的数据更新或者保存到camera_metadata_t中tag所在的entry当中去,以一个更新单字节的数据为例,data_count指定了数据的个数,而tag指定了要更新的entry。
update()方法的整个实现,其中看起很简短,但是其中做了很多工作,我们一一来分解。
status_t CameraMetadata::update(uint32_t tag,
const int32_t *data, size_t data_count) {
status_t res;
if (mLocked) {
ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
return INVALID_OPERATION;
}
if ( (res = checkType(tag, TYPE_INT32)) != OK) {
return res;
}
return updateImpl(tag, (const void*)data, data_count);
}
首先是通过checkType,主要是通过tag找到get_camera_metadata_tag_type其所应当支持的tag_type(因为具体的TAG是已经通过camera_metadata_tag_info.c源文件中的tag_info这个表指定了其应该具备的tag_type),比较两者是否一致,一致后才允许后续的操作。如这里需要TYPE_BYTE一致:
const char *get_camera_metadata_tag_name(uint32_t tag) {
uint32_t tag_section = tag >> 16;
if (tag_section >= VENDOR_SECTION && vendor_tag_ops != NULL) {
return vendor_tag_ops->get_tag_name(
vendor_tag_ops,
tag);
}
if (tag_section >= ANDROID_SECTION_COUNT ||
tag >= camera_metadata_section_bounds[tag_section][1] ) {
return NULL;
}
uint32_t tag_index = tag & 0xFFFF;//取tag在section中的index,低16位
return tag_info[tag_section][tag_index].tag_name;//定位section然后再说tag
}
int get_camera_metadata_tag_type(uint32_t tag) {
uint32_t tag_section = tag >> 16;
if (tag_section >= VENDOR_SECTION && vendor_tag_ops != NULL) {
return vendor_tag_ops->get_tag_type(
vendor_tag_ops,
tag);
}
if (tag_section >= ANDROID_SECTION_COUNT ||
tag >= camera_metadata_section_bounds[tag_section][1] ) {
return -1;
}
uint32_t tag_index = tag & 0xFFFF;
return tag_info[tag_section][tag_index].tag_type;
}
分别是通过tag取货section id即tag>>16,就定位到所属的section tag_info_t[],再通过在在该section中定位tag index一般是tag&0xFFFF的低16位为在该tag在section中的偏移值,进而找到tag自身的struct tag_info_t.
updataImpl函数主要是讲所有要写入的数据进行update操作:
status_t CameraMetadata::updateImpl(uint32_t tag, const void *data,
size_t data_count) {
status_t res;
if (mLocked) {
ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
return INVALID_OPERATION;
}
int type = get_camera_metadata_tag_type(tag);
if (type == -1) {
ALOGE("%s: Tag %d not found", __FUNCTION__, tag);
return BAD_VALUE;
}
size_t data_size = calculate_camera_metadata_entry_data_size(type,
data_count);
res = resizeIfNeeded(1, data_size);//新建camera_metadata_t
if (res == OK) {
camera_metadata_entry_t entry;
res = find_camera_metadata_entry(mBuffer, tag, &entry);
if (res == NAME_NOT_FOUND) {
res = add_camera_metadata_entry(mBuffer,
tag, data, data_count);//将当前新的tag以及数据加入到camera_metadata_t
} else if (res == OK) {
res = update_camera_metadata_entry(mBuffer,
entry.index, data, data_count, NULL);
}
}
if (res != OK) {
ALOGE("%s: Unable to update metadata entry %s.%s (%x): %s (%d)",
__FUNCTION__, get_camera_metadata_section_name(tag),
get_camera_metadata_tag_name(tag), tag, strerror(-res), res);
}
IF_ALOGV() {
ALOGE_IF(validate_camera_metadata_structure(mBuffer, /*size*/NULL) !=
OK,
"%s: Failed to validate metadata structure after update %p",
__FUNCTION__, mBuffer);
}
return res;
}
frameworks\av\camera\CameraMetadata.cpp
status_t CameraMetadata::resizeIfNeeded(size_t extraEntries, size_t extraData) { //由上面可以得到extraEntries =1,extraData = 0
if (mBuffer == NULL) { //开始的地方我们看得到mBuffer被初始化成NULL
//这里可知传入的参数是(2,0),我们看的出,它提前多申请了一个entry的空间。
mBuffer = allocate_camera_metadata(extraEntries * 2, extraData * 2);
if (mBuffer == NULL) {
ALOGE("%s: Can't allocate larger metadata buffer", __FUNCTION__);
return NO_MEMORY;
}
} else {
//获取当前metadata保存的Tag数量
size_t currentEntryCount = get_camera_metadata_entry_count(mBuffer);
//获取当前metadata数据快能最大存放tag的数量
size_t currentEntryCap = get_camera_metadata_entry_capacity(mBuffer);
//得到更新后我们实际存放的tag数量。
size_t newEntryCount = currentEntryCount +
extraEntries;
// 如果这个实际存放的数量,已经超出它能存放的范围,那么就把能力放大2倍,指数倍增加。
newEntryCount = (newEntryCount > currentEntryCap) ?
newEntryCount * 2 : currentEntryCap;
//获取当前数据区已经使用了多少字节。
size_t currentDataCount = get_camera_metadata_data_count(mBuffer);
//数据区总的大小。
size_t currentDataCap = get_camera_metadata_data_capacity(mBuffer);
//当前已使用的数据 + 将要加入进来的数据=实际要存入数据区的数据
size_t newDataCount = currentDataCount +
extraData;
//如果实际要存放的数据大于目前数据区总的大小,那么就把数据区放大2倍,同样呈指数增加
newDataCount = (newDataCount > currentDataCap) ?
newDataCount * 2 : currentDataCap;
if (newEntryCount > currentEntryCap ||
newDataCount > currentDataCap) {
camera_metadata_t *oldBuffer = mBuffer;
//如果超处之前的能力,就会重新申请buffer
mBuffer = allocate_camera_metadata(newEntryCount,
newDataCount);
if (mBuffer == NULL) {
ALOGE("%s: Can't allocate larger metadata buffer", __FUNCTION__);
return NO_MEMORY;
}
//将之前的数据拷贝到新的mbuffer中。
append_camera_metadata(mBuffer, oldBuffer);
//释放老的mBuffer,你懂得
free_camera_metadata(oldBuffer);
}
}
return OK;
}
最终可以明确的是CameraMetadata相关的参数是被Java层来set/get,但本质是在native层进行了实现,后续如果相关控制参数是被打包到CaptureRequest中时传入到native时即操作的还是native中的CameraMetadata。
下面以API2中java层中设置AF的工作模式为例,来说明这个参数设置的过程:
//Java部分代码
mPreviewBuilder.set(CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
session.setRepeatingRequest(mPreviewBuilder.build(), mSessionCaptureCallback, mHandler);
/* @see #CONTROL_AF_MODE_OFF* @see #CONTROL_AF_MODE_AUTO* @see #CONTROL_AF_MODE_MACRO* @see #CONTROL_AF_MODE_CONTINUOUS_VIDEO* @see #CONTROL_AF_MODE_CONTINUOUS_PICTURE* @see #CONTROL_AF_MODE_EDOF*/public static final Key<Integer> CONTROL_AF_MODE =
new Key<Integer>("android.control.afMode", int.class);
public Key(String name, Class<T> type) {
mKey = new CameraMetadataNative.Key<T>(name, type);
}
在CameraMetadataNative.java中Key的构造:
public Key(String name, Class<T> type) {
if (name == null) {
throw new NullPointerException("Key needs a valid name");
} else if (type == null) {
throw new NullPointerException("Type needs to be non-null");
}
mName = name;
mType = type;
mTypeReference = TypeReference.createSpecializedTypeReference(type);
mHash = mName.hashCode() ^ mTypeReference.hashCode();
}
其中CONTROL_AF_MODE_CONTINUOUS_PICTURE定义在CameraMetadata.java中
逐一定位set的入口:
a. mPreviewBuilder是CaptureRequest.java的build类,其会构建一个CaptureRequest:
public Builder(CameraMetadataNative template) {
mRequest = new CaptureRequest(template);
}
private CaptureRequest() {
mSettings = new CameraMetadataNative();
mSurfaceSet = new HashSet<Surface>();
}
mSetting建立的是一个CameraMetadataNative对象,主要用于和Native层进行接口交互,构造如下:
public CameraMetadataNative() {
super();
mMetadataPtr = nativeAllocate();
if (mMetadataPtr == 0) {
throw new OutOfMemoryError("Failed to allocate native CameraMetadata");
}
}
b. CaptureRequest.Build.set()
public <T> void set(Key<T> key, T value) {
mRequest.mSettings.set(key, value);
}
public <T> void set(CaptureRequest.Key<T> key, T value) {
set(key.getNativeKey(), value);
}
考虑到CaptureRequest extend CameraMetadata,则CaptureRequest.java中getNativeKey:
public CameraMetadataNative.Key<T> getNativeKey() {
return mKey;
}
mKey即为之前构造的CameraMetadataNative.Key:
public <T> void set(Key<T> key, T value) {
SetCommand s = sSetCommandMap.get(key);
if (s != null) {
s.setValue(this, value);
return;
}
setBase(key, value);
}
private <T> void setBase(Key<T> key, T value) {
int tag = key.getTag();
if (value == null) {
// Erase the entry
writeValues(tag, /*src*/null);
return;
} // else update the entry to a new value
Marshaler<T> marshaler = getMarshalerForKey(key);
int size = marshaler.calculateMarshalSize(value);
// TODO: Optimization. Cache the byte[] and reuse if the size is big enough.
byte[] values = new byte[size];
ByteBuffer buffer = ByteBuffer.wrap(values).order(ByteOrder.nativeOrder());
marshaler.marshal(value, buffer);
writeValues(tag, values);
}
首先来看key.getTag()函数的实现,他是将这个key交由Native层后转为一个真正的在Java层中的tag值:
public final int getTag() {
if (!mHasTag) {
mTag = CameraMetadataNative.getTag(mName);
mHasTag = true;
}
return mTag;
}
public static int getTag(String key) {
return nativeGetTagFromKey(key);
}
是将Java层的String交由Native来转为一个Java层的tag值。
再来看writeValues的实现,同样调用的是一个native接口,很好的阐明了CameraMetadataNative的意思:
public void writeValues(int tag, byte[] src) {
nativeWriteValues(tag, src);
}
同样和开头native层代码部分对应起来了。