camera3_profiles_rkxxxx.xml的解析流程 基于RK3576 android14

最近需要为定制的Camera添加一种特殊的数据格式,原本camera3_profiles_rkxxxx.xml有三种BLOB,YCbCr_420_888,IMPLEMENTATION_DEFINED,这三种分别对应JPEG,YUV_420_888, PRIVATE。我新增的格式无论是替代已有的三种,还是添加一种,都会导致xml无法正常解析,找了一段时间资料,发现这部分内容很少有人提及,大部分摄像头都用YCbCr_420_888这种格式搞定了,所以只能自己从头分析研究这个xml文件的解析流程,希望能找到出路。

camera3_profiles_rkxxxx.xml的读取是在hardware/rockchip/camera/common/platformdata/ChromeCameraProfiles.cpp中。

status_t ChromeCameraProfiles::init()
{
    status_t status = OK;

    LOGI("@%s", __FUNCTION__);

    // determine the xml file name
    getXmlConfigName();

    status = CameraProfiles::init();
    if (status) {
        LOGE("CameraProfiles base init error:%d", status);
        return status;
    }

    // Parse common sections
    getDataFromXmlFile();

    createConfParser();

    LOGI("@%s exit!", __FUNCTION__);
    return OK;
}

在hardware/rockchip/camera/common/platformdata/CameraProfiles.cpp中读取xml中的内容getDataFromXmlFile,createConfParser。
具体的细节数据操作在hardware/rockchip/camera/common/platformdata/CameraMetadataHelper.cpp中,其中使用的相关section和tag的函数如get_camera_metadata_section_name和get_camera_metadata_tag_name,实现代码在system/media/camera/src/Camera_metadata.c中。

在回到我们的目标,是为了实现添加Camera支持的数据格式。camera3_profiles_rkxxxx.xml中关于数据格式的解析是使用下面这个函数:

/**
 * This function will handle all the android static metadata related elements of sensor.
 *
 * It will be called in the function startElement
 * This method parses the input from the XML file, that can be manipulated.
 * So extra care is applied in the validation of strings
 *
 * \param name: the element's name.
 * \param atts: the element's attribute.
 */
void ChromeCameraProfiles::handleAndroidStaticMetadata(const char *name, const char **atts)
{
    if (!validateStaticMetadata(name, atts))
        return;

    // Find tag
    const metadata_tag_t *tagInfo = findTagInfo(name, android_static_tags_table, STATIC_TAGS_TABLE_SIZE);
    if (tagInfo == nullptr)
        return;

    int count = 0;
    camera_metadata_t * currentMeta = nullptr;
    MetaValueRefTable mvrt;
    std::vector<MetaValueRefTable> refTables;
    LOGI("@%s: Parsing static tag %s: value %s", __FUNCTION__, tagInfo->name,  atts[1]);

    /**
     * Complex parsing types done manually (exceptions)
     * scene overrides uses different tables for each entry one from ae/awb/af
     * mode
     */
    if (tagInfo->value == ANDROID_SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP) {
        mvrt.table      = android_scaler_availableFormats_values;
        mvrt.tableSize  = ELEMENT(android_scaler_availableFormats_values);
        refTables.push_back(mvrt);
        count = parseAvailableInputOutputFormatsMap(atts[1], tagInfo, refTables,
                METADATASIZE, mMetadataCache);
    } else if ((tagInfo->value == ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS) ||
               (tagInfo->value == ANDROID_REQUEST_AVAILABLE_RESULT_KEYS)) {
        count = parseAvailableKeys(atts[1], tagInfo, METADATASIZE, mMetadataCache);
    } else if (tagInfo->value == ANDROID_SYNC_MAX_LATENCY) {
        count = parseEnumAndNumbers(atts[1], tagInfo, METADATASIZE, mMetadataCache);
    } else { /* Parsing of generic types */
        if (tagInfo->arrayTypedef == STREAM_CONFIGURATION) {
            mvrt.table      = android_scaler_availableFormats_values;
            mvrt.tableSize  = ELEMENT(android_scaler_availableFormats_values);
            refTables.push_back(mvrt);
            mvrt.table      = android_scaler_availableStreamConfigurations_values;
            mvrt.tableSize  = ELEMENT(android_scaler_availableStreamConfigurations_values);
            refTables.push_back(mvrt);
            count = parseStreamConfig(atts[1], tagInfo, refTables, METADATASIZE, mMetadataCache);
        } else if (tagInfo->arrayTypedef == STREAM_CONFIGURATION_DURATION) {
            mvrt.table      = android_scaler_availableFormats_values;
            mvrt.tableSize  = ELEMENT(android_scaler_availableFormats_values);
            refTables.push_back(mvrt);
            count = parseStreamConfigDuration(atts[1], tagInfo, refTables, METADATASIZE,
                    mMetadataCache);
        } else {
            count = parseGenericTypes(atts[1], tagInfo, METADATASIZE, mMetadataCache);
        }
    }

    if (count == 0) {
        LOGW("Error parsing static tag %s. ignoring", tagInfo->name);
        return;
    }

    LOGI("@%s: writing static tag %s: count %d", __FUNCTION__,
                                                 tagInfo->name,
                                                 count);

    if (mStaticMeta.size() > 0) {
        currentMeta = mStaticMeta.at(mSensorIndex);
    } else {
        LOGE("Camera isn't added, unable to get the static metadata");
        return;
    }
    if (add_camera_metadata_entry(currentMeta, tagInfo->value, mMetadataCache, count)) {
        LOGE("call add_camera_metadata_entry fail for tag:%s", get_camera_metadata_tag_name(tagInfo->value));
    }
    else
        // save the key to mCharacteristicsKeys used to update the
        // REQUEST_AVAILABLE_CHARACTERISTICS_KEYS
        mCharacteristicsKeys[mSensorIndex].push_back(tagInfo->value);
}

从其中的log看,我添加的新的数据格式可以读出。问题是出在了下面关于详细内容的解析部分:

            mvrt.table      = android_scaler_availableFormats_values;
            mvrt.tableSize  = ELEMENT(android_scaler_availableFormats_values);
            refTables.push_back(mvrt);
            count = parseStreamConfigDuration(atts[1], tagInfo, refTables, METADATASIZE,
                    mMetadataCache);

这里是把读取出来的字符和一张已知字符的表格进行了对应:

const metadata_value_t android_scaler_availableFormats_values[] = {
                 {"RAW16", ANDROID_SCALER_AVAILABLE_FORMATS_RAW16 },
                 {"RAW_OPAQUE", ANDROID_SCALER_AVAILABLE_FORMATS_RAW_OPAQUE },
                 {"YV12", ANDROID_SCALER_AVAILABLE_FORMATS_YV12 },
                 {"YCrCb_420_SP", ANDROID_SCALER_AVAILABLE_FORMATS_YCrCb_420_SP },
                 {"IMPLEMENTATION_DEFINED", ANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED },
                 {"YCbCr_420_888", ANDROID_SCALER_AVAILABLE_FORMATS_YCbCr_420_888 },
                 {"BLOB", ANDROID_SCALER_AVAILABLE_FORMATS_BLOB },
         };

我们新增的类型,不存在与这张表格中,所以最后会出现解析异常的问题。根据已有的几种类型,添加自定义类型,就可以通过xml的解析部分了。

const metadata_value_t android_scaler_availableFormats_values[] = {
                 {"RAW16", ANDROID_SCALER_AVAILABLE_FORMATS_RAW16 },
                 {"RAW_OPAQUE", ANDROID_SCALER_AVAILABLE_FORMATS_RAW_OPAQUE },
                 {"YV12", ANDROID_SCALER_AVAILABLE_FORMATS_YV12 },
                 {"YCrCb_420_SP", ANDROID_SCALER_AVAILABLE_FORMATS_YCrCb_420_SP },
                 {"IMPLEMENTATION_DEFINED", ANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED },
                 {"YCbCr_420_888", ANDROID_SCALER_AVAILABLE_FORMATS_YCbCr_420_888 },
                 {"BLOB", ANDROID_SCALER_AVAILABLE_FORMATS_BLOB },
                 {"Y8", ANDROID_SCALER_AVAILABLE_FORMATS_Y8 },
         };

不过关于添加新的数据格式还有其他内容需要更改,本文只涉及camera3_profiles_rkxxxx.xml的相关解析流程分析。

RK3566芯片搭配Android 11系统确实支持Camera2 API的高级功能,包括自定义录像帧率。在Camera2 API中,你可以通过`MediaRecorder`类和`SurfaceTexture`来调整视频编码器的参数,包括帧率。 `media_profiles_default.xml`是一个预设的媒体配置文件,通常位于`frameworks/vr/res/media/profiles`目录下。这个文件定义了各种常见的视频编码配置,其中包含了帧率、分辨率和其他关键设置。如果你想添加或修改自定义帧率,你需要在XML中创建一个新的`<video>`标签,并设置其`frame-rate`属性。 下面是一个简单的例子: ```xml <video> <encoding name="my_custom_profile"> <!-- 其他配置项 --> <framerate>30</framerate> <!-- 自定义帧率,如30fps --> </encoding> </video> ``` 要在应用中使用这个配置,你可以在代码里加载这个配置并传递给`MediaRecorder`的构造函数: ```java // 加载自定义配置 InputStream inputStream = getResources().openRawResource(R.xml.my_custom_profile); MediaRecorder mediaRecorder = new MediaRecorder.Builder(context) .setVideoSource(MediaRecorder.VideoSource.SURFACE_TEXTURE) .setOutputFormat(MediaRecorder.OutputFormat.MPEG_4) // 使用自定义配置 .setVideoEncoderProfile(MediaRecorder.VideoEncoderProfile.values()[getEncoderIndex("my_custom_profile")]) .initialize(inputStream) // ...其他设置... .build(); ``` 注意,你需要确保`my_custom_profile`在`media_profiles_default.xml`中有正确的索引对应值(`getEncoderIndex()`函数),并且`getEncoderIndex()`是你自己实现的一个方法,用于查找配置文件中指定配置对应的编码器类型。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值