/* * Copyright (C) 2014 Intel Corporation. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ #include <libexpat/expat.h> #include <string.h> #include <stdio.h> #include <utils/Log.h> #include "isv_profile.h" #undef LOG_TAG #define LOG_TAG "ISVProfile" #define QCIF_AREA (176 * 144) #define DEFAULT_XML_FILE "/etc/video_isv_profile.xml" using namespace android; static const char StatusOn[][5] = {"1frc", "1vpp"}; ISVProfile::ISVProfile(const uint32_t width, const uint32_t height) { int i; mWidth = width; mHeight = height; mCurrentFilter = 0; mCurrentFrcTab = 0; mDefaultVPPStatus = 0; mDefaultFRCStatus = 0; mStatus = 0; memset(mConfigs, 0, sizeof(ISVConfig) * ProcFilterCount); for (i = 0; i < MAX_TAB_SIZE; i++) { mFrcRates[i].input_fps = 0; mFrcRates[i].rate = FRC_RATE_1X; } /* get the vpp global setting */ //getGlobalStatus(); /* load the config data from XML file */ getDataFromXmlFile(); /* update the filter status according to the configs */ updateFilterStatus(); /* dump data for debug */ dumpConfigData(); } ISVProfile::~ISVProfile() { } FRC_RATE ISVProfile::getFRCRate(uint32_t inputFps) { FRC_RATE rate = FRC_RATE_1X; int i; for (i = 0; i < MAX_TAB_SIZE; i++) { if (mFrcRates[i].input_fps == inputFps) { rate = mFrcRates[i].rate; break; } } return rate; } uint32_t ISVProfile::getFilterStatus() { return mStatus; } bool ISVProfile::isVPPOn() { int32_t status = getGlobalStatus(); return (status != -1) ? (((status & VPP_COMMON_ON) != 0) ? true : false) : false; } bool ISVProfile::isFRCOn() { int32_t status = getGlobalStatus(); return (status != -1) ? (((status & VPP_FRC_ON) != 0) ? true : false) : false; } void ISVProfile::updateFilterStatus() { int i; uint32_t area = mWidth * mHeight; for (i = 1; i < ProcFilterCount; i++) { /* check config */ if (mConfigs[i].enabled == false) continue; if (area > mConfigs[i].minResolution && area <= mConfigs[i].maxResolution) mStatus |= 1 << i; /* we should cover QCIF */ else if (area == mConfigs[i].minResolution && area == QCIF_AREA) mStatus |= 1 << i; } } int ISVProfile::getFilterID(const char * name) { int index = 0; if (strcmp(name, "ProcFilterNoiseReduction") == 0) index = ProcFilterNoiseReduction; else if (strcmp(name, "ProcFilterDeinterlacing") == 0) index = ProcFilterDeinterlacing; else if (strcmp(name, "ProcFilterSharpening") == 0) index = ProcFilterSharpening; else if (strcmp(name, "ProcFilterColorBalance") == 0) index = ProcFilterColorBalance; else if (strcmp(name, "ProcFilterDeblocking") == 0) index = ProcFilterDeblocking; else if (strcmp(name, "ProcFilterFrameRateConversion") == 0) index = ProcFilterFrameRateConversion; else if (strcmp(name, "ProcFilterSkinToneEnhancement") == 0) index = ProcFilterSkinToneEnhancement; else if (strcmp(name, "ProcFilterTotalColorCorrection") == 0) index = ProcFilterTotalColorCorrection; else if (strcmp(name, "ProcFilterNonLinearAnamorphicScaling") == 0) index = ProcFilterNonLinearAnamorphicScaling; else if (strcmp(name, "ProcFilterImageStabilization") == 0) index = ProcFilterImageStabilization; else index = 0; mCurrentFilter = index; return index; } uint32_t ISVProfile::getResolution(const char * name) { uint32_t width = 0, height = 0; char *p = NULL, *str = NULL; int32_t lenth = strlen(name); str = (char*)malloc(lenth+1); if (NULL == str) { ALOGE("%s: failed to malloc buffer", __func__); return 0; } strncpy(str, name, lenth); str[lenth] = '\0'; p = strtok(str, "x"); if (p) width = atoi(p); p = strtok(NULL, "x"); if (p) height = atoi(p); if (str) { free(str); str = NULL; } return width * height; } void ISVProfile::getConfigData(const char *name, const char **atts) { int attIndex = 0; if (strcmp(name, "VideoPostProcessSettings") == 0) { return; } else if (strcmp(name, "Filter") == 0) { if (strcmp(atts[attIndex], "name") == 0) { if (getFilterID(atts[attIndex + 1]) == 0) { ALOGE("Couldn't parase the filter %s\n", atts[attIndex+1]); } } else { ALOGE("couldn't handle \"%s\" element for Filter\n", name); } } else if (strcmp(name, "enabled") == 0) { if (mCurrentFilter) { if (!strcmp(atts[attIndex], "value") && !strcmp(atts[attIndex + 1], "true")) mConfigs[mCurrentFilter].enabled = true; } else { ALOGE("Skip this element(%s) becaue this filter couldn't be supported\n", name); } } else if (strcmp(name, "minResolution") == 0) { if (mCurrentFilter && !strcmp(atts[attIndex], "value")) { if (!strcmp(atts[attIndex + 1], "0")) mConfigs[mCurrentFilter].minResolution = 0; else if (!strcmp(atts[attIndex + 1], "FFFFFFFF")) mConfigs[mCurrentFilter].minResolution = 0xFFFFFFFF; else mConfigs[mCurrentFilter].minResolution = getResolution(atts[attIndex + 1]); } else { ALOGE("Skip this element(%s) becaue this filter couldn't be supported\n", name); } } else if (strcmp(name, "maxResolution") == 0) { if (mCurrentFilter && !strcmp(atts[attIndex], "value")) { if (!strcmp(atts[attIndex + 1], "0")) mConfigs[mCurrentFilter].maxResolution = 0; else if (!strcmp(atts[attIndex + 1], "FFFFFFFF")) mConfigs[mCurrentFilter].maxResolution = 0xFFFFFFFF; else mConfigs[mCurrentFilter].maxResolution = getResolution(atts[attIndex + 1]); } else { ALOGE("Skip this element(%s) becaue this filter couldn't be supported\n", name); } } else if (strcmp(name, "FRCRate") == 0) { if (mCurrentFilter == ProcFilterFrameRateConversion) { if (!strcmp(atts[attIndex], "input") && !strcmp(atts[attIndex + 2], "rate")) { mFrcRates[mCurrentFrcTab].input_fps = atoi(atts[attIndex + 1]); if (!strcmp(atts[attIndex + 3], "2")) mFrcRates[mCurrentFrcTab].rate = FRC_RATE_2X; else if (!strcmp(atts[attIndex + 3], "2.5")) mFrcRates[mCurrentFrcTab].rate = FRC_RATE_2_5X; else if (!strcmp(atts[attIndex + 3], "4")) mFrcRates[mCurrentFrcTab].rate = FRC_RATE_4X; else mFrcRates[mCurrentFrcTab].rate = FRC_RATE_1X; /* update the pointer */ if (mCurrentFrcTab < MAX_TAB_SIZE) mCurrentFrcTab++; } } else { ALOGE("\"FRCRate\" element is only for ProcFilterFrameRateConversion\n"); } } else if (strcmp(name, "parameter") == 0) { /* <parameter /> */ handleFilterParameter(name, atts); } else if (strcmp(name, "Parameter") == 0) { /* <Parameter /> */ handleCommonParameter(name, atts); } else ALOGE("Couldn't handle this element %s!\n", name); } void ISVProfile::handleFilterParameter(const char *name, const char **atts) { int attIndex = 0; if (!mCurrentFilter) { ALOGE("\"%s\" must be in Filter element\n", name); return; } if (strcmp(atts[attIndex], "name") || strcmp(atts[attIndex + 2], "value")) { ALOGE("\"%s\" or \"%s\" couldn't match the %s format\n", atts[attIndex], atts[attIndex + 2], name); return; } } void ISVProfile::handleCommonParameter(const char *name, const char **atts) { int attIndex = 0; if (strcmp(atts[attIndex], "name") || strcmp(atts[attIndex + 2], "value")) { ALOGE("\"%s\" or \"%s\" couldn't match the %s format\n", atts[attIndex], atts[attIndex + 2], name); return; } /* The default status of VPP */ if (strcmp(atts[attIndex + 1], "DefaultVPPStatus") == 0) mDefaultVPPStatus = atoi(atts[attIndex + 3]); /* The default status of FRC */ else if (strcmp(atts[attIndex + 1], "DefaultFRCStatus") == 0) mDefaultFRCStatus = atoi(atts[attIndex + 3]); } void ISVProfile::startElement(void *userData, const char *name, const char **atts) { ISVProfile *profile = (ISVProfile *)userData; profile->getConfigData(name, atts); } void ISVProfile::endElement(void *userData, const char *name) { ISVProfile *profile = (ISVProfile *)userData; if (!strcmp(name, "Filter")) profile->mCurrentFilter = 0; } void ISVProfile::getDataFromXmlFile() { int done; void *pBuf = NULL; FILE *fp = NULL; fp = ::fopen(DEFAULT_XML_FILE, "r"); if (NULL == fp) { ALOGE("@%s, line:%d, couldn't open profile %s", __func__, __LINE__, DEFAULT_XML_FILE); return; } XML_Parser parser = ::XML_ParserCreate(NULL); if (NULL == parser) { ALOGE("@%s, line:%d, parser is NULL", __func__, __LINE__); goto exit; } ::XML_SetUserData(parser, this); ::XML_SetElementHandler(parser, startElement, endElement); pBuf = malloc(mBufSize); if (NULL == pBuf) { ALOGE("@%s, line:%d, failed to malloc buffer", __func__, __LINE__); goto exit; } do { int len = (int)::fread(pBuf, 1, mBufSize, fp); if (!len) { if (ferror(fp)) { clearerr(fp); goto exit; } } done = len < mBufSize; if (XML_Parse(parser, (const char *)pBuf, len, done) == XML_STATUS_ERROR) { ALOGE("@%s, line:%d, XML_Parse error", __func__, __LINE__); goto exit; } } while (!done); exit: if (parser) ::XML_ParserFree(parser); if (pBuf) free(pBuf); if (fp) ::fclose(fp); } int32_t ISVProfile::getGlobalStatus() { char path[80]; int userId = 0; int32_t status = 0; FILE *setting_handle, *config_handle; snprintf(path, 80, "/data/user/%d/com.intel.vpp/shared_prefs/vpp_settings.xml", userId); ALOGV("%s: %s",__func__, path); setting_handle = fopen(path, "r"); if(setting_handle == NULL) { ALOGE("%s: failed to open file %s\n", __func__, path); /* Read the Filter config file to get default value */ config_handle = fopen(DEFAULT_XML_FILE, "r"); if (config_handle == NULL) { ALOGE("%s: failed to open file %s\n", __func__, DEFAULT_XML_FILE); return -1; } char xml_buf[MAX_BUF_SIZE + 1] = {0}; memset(xml_buf, 0, MAX_BUF_SIZE); if (fread(xml_buf, 1, MAX_BUF_SIZE, config_handle) <= 0) { ALOGE("%s: failed to read config xml file!\n", __func__); fclose(config_handle); return -1; } xml_buf[MAX_BUF_SIZE] = '\0'; if (strstr(xml_buf, "name=\"DefaultVPPStatus\" value=\"1\"") != NULL) status |= VPP_COMMON_ON; if (strstr(xml_buf, "name=\"DefaultFRCStatus\" value=\"1\"") != NULL) status |= VPP_FRC_ON; ALOGV("%s: using the default status: VPP=%d, FRC=%d\n", __func__, ((status & VPP_COMMON_ON) == 0) ? 0 : 1, ((status & VPP_FRC_ON) == 0) ? 0: 1); fclose(config_handle); return status; } const int MAXLEN = 1024; char buf[MAXLEN] = {0}; memset(buf, 0 ,MAXLEN); if(fread(buf, 1, MAXLEN, setting_handle) <= 0) { ALOGE("%s: failed to read vpp config file %d", __func__, userId); fclose(setting_handle); return -1; } buf[MAXLEN - 1] = '\0'; if(strstr(buf, StatusOn[0]) != NULL) status |= VPP_FRC_ON; if(strstr(buf, StatusOn[1]) != NULL) status |= VPP_COMMON_ON; fclose(setting_handle); return status; } void ISVProfile::dumpConfigData() { uint32_t i, j; char filterNames[][50] = { "ProcFilterNone", "ProcFilterNoiseReduction", "ProcFilterDeinterlacing", "ProcFilterSharpening", "ProcFilterColorBalance", "ProcFilterDeblocking", "ProcFilterFrameRateConversion", "ProcFilterSkinToneEnhancement", "ProcFilterTotalColorCorrection", "ProcFilterNonLinearAnamorphicScaling", "ProcFilterImageStabilization" }; char rateNames[][20] = { "FRC_RATE_0X", "FRC_RATE_1X", "FRC_RATE_2X", "FRC_RATE_2_5X", "FRC_RATE_4X", }; ALOGV("========== VPP filter configs:==========\n"); for (i = 1; i < ProcFilterCount; i++) { ALOGV("name=%s, enabled=%s, minResolution=%d, maxResolution=%d, isOn=%s\n", filterNames[i], (mConfigs[i].enabled == true) ? "true" : "false", mConfigs[i].minResolution, mConfigs[i].maxResolution, ((mStatus & (1 << i)) == 0) ? "false" : "true"); if (mConfigs[i].paraSize) { ALOGV("\t\t parameters: "); for(j = 0; j < mConfigs[i].paraSize; j++) ALOGE("%s=%f,", mConfigs[i].paraTables[j].name, mConfigs[i].paraTables[j].value); ALOGV("\n"); } } ALOGV("========== FRC rate configs:===========\n"); for (i = 0; i < MAX_TAB_SIZE; i++) { if (mFrcRates[i].input_fps == 0) break; ALOGV("input_fps=%d, rate=%s\n", mFrcRates[i].input_fps, rateNames[mFrcRates[i].rate]); } ALOGI("========== common parameter configs:===========\n"); ALOGI("mDefaultVPPStatus=%d\n", mDefaultVPPStatus); ALOGI("mDefaultFRCStatus=%d\n", mDefaultFRCStatus); }