Android Camera HAL3 Vendor Tag 定制私有化

时间:2025-01-28 08:11:28

最近需要搞个私有参数下来作为apk 设置开关使用,想到之前HAL1 的使用过增加 Parameters 来实现,所以自然想到了现在的 vendor tag,下面是android source code 的使用,可以作为例子。

其实mtk自己已经实现了一套,只是作为参考代码没有这么清晰。

代码路径:vendor/mediatek/hardware/mtkcam/utils/metadata/vendortag/

下面给出android source code ,代码以及路径如下

代码路径:system/media/camera/tests/camera_metadata_tests.cpp

TEST(camera_metadata, vendor_tags) {
    camera_metadata_t *m = NULL;
    const size_t entry_capacity = 5;
    const size_t data_capacity = 50;
    int result;
    m = allocate_camera_metadata(entry_capacity, data_capacity);
    uint8_t superMode = 5;
    result = add_camera_metadata_entry(m,
            FAKEVENDOR_SENSOR_SUPERMODE,
            &superMode, 1);
    EXPECT_EQ(ERROR, result);
    EXPECT_EQ(OK, validate_camera_metadata_structure(m, NULL));
    result = add_camera_metadata_entry(m,
            ANDROID_REQUEST_METADATA_MODE,
            &superMode, 1);
    EXPECT_EQ(OK, result);
    EXPECT_EQ(OK, validate_camera_metadata_structure(m, NULL));
    EXPECT_NULL(get_camera_metadata_section_name(FAKEVENDOR_SENSOR_SUPERMODE));
    EXPECT_NULL(get_camera_metadata_tag_name(FAKEVENDOR_SENSOR_SUPERMODE));
    EXPECT_EQ(-1, get_camera_metadata_tag_type(FAKEVENDOR_SENSOR_SUPERMODE));
    set_camera_metadata_vendor_ops(&fakevendor_ops);
    result = add_camera_metadata_entry(m,
            FAKEVENDOR_SENSOR_SUPERMODE,
            &superMode, 1);
    EXPECT_EQ(OK, result);
    EXPECT_EQ(OK, validate_camera_metadata_structure(m, NULL));
    result = add_camera_metadata_entry(m,
            ANDROID_REQUEST_METADATA_MODE,
            &superMode, 1);
    EXPECT_EQ(OK, result);
    EXPECT_EQ(OK, validate_camera_metadata_structure(m, NULL));
    result = add_camera_metadata_entry(m,
            FAKEVENDOR_SCALER_END,
            &superMode, 1);
    EXPECT_EQ(ERROR, result);
    EXPECT_EQ(OK, validate_camera_metadata_structure(m, NULL));
    EXPECT_STREQ("",
            get_camera_metadata_section_name(FAKEVENDOR_SENSOR_SUPERMODE));
    EXPECT_STREQ("superMode",
            get_camera_metadata_tag_name(FAKEVENDOR_SENSOR_SUPERMODE));
    EXPECT_EQ(TYPE_BYTE,
            get_camera_metadata_tag_type(FAKEVENDOR_SENSOR_SUPERMODE));
    EXPECT_STREQ("",
            get_camera_metadata_section_name(FAKEVENDOR_SCALER_END));
    EXPECT_NULL(get_camera_metadata_tag_name(FAKEVENDOR_SCALER_END));
    EXPECT_EQ(-1, get_camera_metadata_tag_type(FAKEVENDOR_SCALER_END));
    set_camera_metadata_vendor_ops(NULL);
    // TODO: fix vendor ops. Then the below 3 validations should fail.
    EXPECT_EQ(OK, validate_camera_metadata_structure(m, NULL));
    result = add_camera_metadata_entry(m,
            FAKEVENDOR_SENSOR_SUPERMODE,
            &superMode, 1);
    EXPECT_EQ(ERROR, result);
    EXPECT_EQ(OK, validate_camera_metadata_structure(m, NULL));
    result = add_camera_metadata_entry(m,
            ANDROID_REQUEST_METADATA_MODE,
            &superMode, 1);
    EXPECT_EQ(OK, result);
    EXPECT_EQ(OK, validate_camera_metadata_structure(m, NULL));
    EXPECT_NULL(get_camera_metadata_section_name(FAKEVENDOR_SENSOR_SUPERMODE));
    EXPECT_NULL(get_camera_metadata_tag_name(FAKEVENDOR_SENSOR_SUPERMODE));
    EXPECT_EQ(-1, get_camera_metadata_tag_type(FAKEVENDOR_SENSOR_SUPERMODE));
    // Remove all vendor entries so validation passes
    {
        camera_metadata_ro_entry_t entry;
        EXPECT_EQ(OK, find_camera_metadata_ro_entry(m,
                                                    FAKEVENDOR_SENSOR_SUPERMODE,
                                                    &entry));
        EXPECT_EQ(OK, delete_camera_metadata_entry(m, ));
    }
    FINISH_USING_CAMERA_METADATA(m);
}

代码路径:system/media/camera/tests/camera_metadata_tests_fake_vendor.h

#ifndef TESTING_CAMERA_METADATA_FAKEVENDOR_H
#define TESTING_CAMERA_METADATA_FAKEVENDOR_H
#include <>
#include <system/camera_metadata.h>
#include <system/camera_vendor_tags.h>
enum vendor_extension_section {
    FAKEVENDOR_SENSOR = VENDOR_SECTION,
    FAKEVENDOR_SENSOR_INFO,
    FAKEVENDOR_COLORCORRECTION,
    FAKEVENDOR_SCALER,
    FAKEVENDOR_SECTION_END
};
const int FAKEVENDOR_SECTION_COUNT = FAKEVENDOR_SECTION_END - VENDOR_SECTION;
enum vendor_extension_section_ranges {
    FAKEVENDOR_SENSOR_START          = FAKEVENDOR_SENSOR << 16,
    FAKEVENDOR_SENSOR_I_START        = FAKEVENDOR_SENSOR_INFO << 16,
    FAKEVENDOR_COLORCORRECTION_START = FAKEVENDOR_COLORCORRECTION << 16,
    FAKEVENDOR_SCALER_START          = FAKEVENDOR_SCALER << 16
};
enum vendor_extension_tags {
    FAKEVENDOR_SENSOR_SUPERMODE = FAKEVENDOR_SENSOR_START,
    FAKEVENDOR_SENSOR_DOUBLE_EXPOSURE,
    FAKEVENDOR_SENSOR_END,
    FAKEVENDOR_SENSOR_AVAILABLE_SUPERMODES = FAKEVENDOR_SENSOR_I_START,
    FAKEVENDOR_SENSOR_I_END,
    FAKEVENDOR_COLORCORRECTION_3DLUT_MODE = FAKEVENDOR_COLORCORRECTION_START,
    FAKEVENDOR_COLORCORRECTION_3DLUT_TABLES,
    FAKEVENDOR_COLORCORRECTION_END,
    FAKEVENDOR_SCALER_DOWNSCALE_MODE = FAKEVENDOR_SCALER_START,
    FAKEVENDOR_SCALER_DOWNSCALE_COEFF,
    FAKEVENDOR_SCALER_END
};
typedef struct vendor_tag_info {
    const char *tag_name;
    uint8_t     tag_type;
} vendor_tag_info_t;
const char *fakevendor_section_names[FAKEVENDOR_SECTION_COUNT] = {
    "",
    "",
    "",
    ""
};
uint32_t fakevendor_section_bounds[FAKEVENDOR_SECTION_COUNT][2] = {
    { (uint32_t) FAKEVENDOR_SENSOR_START,          (uint32_t) FAKEVENDOR_SENSOR_END },
    { (uint32_t) FAKEVENDOR_SENSOR_I_START,        (uint32_t) FAKEVENDOR_SENSOR_I_END },
    { (uint32_t) FAKEVENDOR_COLORCORRECTION_START, (uint32_t) FAKEVENDOR_COLORCORRECTION_END },
    { (uint32_t) FAKEVENDOR_SCALER_START,          (uint32_t) FAKEVENDOR_SCALER_END}
};
vendor_tag_info_t fakevendor_sensor[FAKEVENDOR_SENSOR_END -
        FAKEVENDOR_SENSOR_START] = {
    { "superMode",       TYPE_BYTE },
    { "doubleExposure",  TYPE_INT64 }
};
vendor_tag_info_t fakevendor_sensor_info[FAKEVENDOR_SENSOR_I_END -
        FAKEVENDOR_SENSOR_I_START] = {
    { "availableSuperModes",   TYPE_BYTE }
};
vendor_tag_info_t fakevendor_color_correction[FAKEVENDOR_COLORCORRECTION_END -
        FAKEVENDOR_COLORCORRECTION_START] = {
    { "3dLutMode",   TYPE_BYTE },
    { "3dLutTables", TYPE_FLOAT }
};
vendor_tag_info_t fakevendor_scaler[FAKEVENDOR_SCALER_END -
        FAKEVENDOR_SCALER_START] = {
    { "downscaleMode",  TYPE_BYTE },
    { "downscaleCoefficients", TYPE_FLOAT }
};
vendor_tag_info_t *fakevendor_tag_info[FAKEVENDOR_SECTION_COUNT] = {
    fakevendor_sensor,
    fakevendor_sensor_info,
    fakevendor_color_correction,
    fakevendor_scaler
};
const char *get_fakevendor_section_name(const vendor_tag_ops_t *v,
        uint32_t tag);
const char *get_fakevendor_tag_name(const vendor_tag_ops_t *v,
        uint32_t tag);
int get_fakevendor_tag_type(const vendor_tag_ops_t *v,
        uint32_t tag);
int get_fakevendor_tag_count(const vendor_tag_ops_t *v);
void get_fakevendor_tags(const vendor_tag_ops_t *v, uint32_t *tag_array);
static const vendor_tag_ops_t fakevendor_ops = {
    get_fakevendor_tag_count,
    get_fakevendor_tags,
    get_fakevendor_section_name,
    get_fakevendor_tag_name,
    get_fakevendor_tag_type,
    {NULL}
};
const char *get_fakevendor_section_name(const vendor_tag_ops_t *v,
        uint32_t tag) {
    if (v != &fakevendor_ops) return NULL;
    int tag_section = (tag >> 16) - VENDOR_SECTION;
    if (tag_section < 0 ||
            tag_section >= FAKEVENDOR_SECTION_COUNT) return NULL;
    return fakevendor_section_names[tag_section];
}
const char *get_fakevendor_tag_name(const vendor_tag_ops_t *v,
        uint32_t tag) {
    if (v != &fakevendor_ops) return NULL;
    int tag_section = (tag >> 16) - VENDOR_SECTION;
    if (tag_section < 0
            || tag_section >= FAKEVENDOR_SECTION_COUNT
            || tag >= fakevendor_section_bounds[tag_section][1]) return NULL;
    int tag_index = tag & 0xFFFF;
    return fakevendor_tag_info[tag_section][tag_index].tag_name;
}
int get_fakevendor_tag_type(const vendor_tag_ops_t *v,
        uint32_t tag) {
    if (v != &fakevendor_ops) return -1;
    int tag_section = (tag >> 16) - VENDOR_SECTION;
    if (tag_section < 0
            || tag_section >= FAKEVENDOR_SECTION_COUNT
            || tag >= fakevendor_section_bounds[tag_section][1]) return -1;
    int tag_index = tag & 0xFFFF;
    return fakevendor_tag_info[tag_section][tag_index].tag_type;
}
int get_fakevendor_tag_count(const vendor_tag_ops_t *v) {
    int section;
    unsigned int start, end;
    int count = 0;
    if (v != &fakevendor_ops) return -1;
    for (section = 0; section < FAKEVENDOR_SECTION_COUNT; section++) {
        start = fakevendor_section_bounds[section][0];
        end = fakevendor_section_bounds[section][1];
        count += end - start;
    }
    return count;
}
void get_fakevendor_tags(const vendor_tag_ops_t *v, uint32_t *tag_array) {
    int section;
    unsigned int start, end, tag;
    if (v != &fakevendor_ops || tag_array == NULL) return;
    for (section = 0; section < FAKEVENDOR_SECTION_COUNT; section++) {
        start = fakevendor_section_bounds[section][0];
        end = fakevendor_section_bounds[section][1];
        for (tag = start; tag < end; tag++) {
            *tag_array++ = tag;
        }
    }
}
#endif

需要注意的地方:

1.VENDOR_SECTION

如果你想增加自己的section,就可以在VENDOR_SECTION = 0x8000后面添加自己的section。本人由于参数较少,也没有分类的必要,所以就使用默认的VENDOR_SECTION.

原理:

代码路径:system/media/camera/src/camera_metadata.c

int set_camera_metadata_vendor_ops(const vendor_tag_ops_t* ops) {
    vendor_tag_ops = ops;
    return OK;
}
// Declared in system/media/private/camera/include/camera_metadata_hidden.h
const char *get_local_camera_metadata_section_name_vendor_id(uint32_t tag,
        metadata_vendor_id_t id) {
    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_section_name(tag, id);
    } else if (tag_section >= VENDOR_SECTION && vendor_tag_ops != NULL) {
        return vendor_tag_ops->get_section_name(
            vendor_tag_ops,
            tag);
    }
    if (tag_section >= ANDROID_SECTION_COUNT) {
        return NULL;
    }
    return camera_metadata_section_names[tag_section];
}

可以明显发现是根据判断tag_section 是否大于 VENDOR_SECTION 来判断是私有的还是android 原生的

下面给出两个关于metadata介绍的链接

  1. Android Camera API2中采用CameraMetadata用于从APP到HAL的参数交互
  2. Android Camera之CameraMetadata分析