isv_profile.cpp revision 3d148c298841ece27d908dc514fbda2348342c1c
1/*
2 * Copyright (C) 2014 Intel Corporation.  All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17#include <libexpat/expat.h>
18#include <string.h>
19#include <stdio.h>
20#include <utils/Log.h>
21#include "isv_profile.h"
22
23#undef LOG_TAG
24#define LOG_TAG "ISVProfile"
25
26#define QCIF_AREA (176 * 144)
27
28#define DEFAULT_XML_FILE "/etc/video_isv_profile.xml"
29
30using namespace android;
31static const char StatusOn[][5] = {"1frc", "1vpp"};
32
33ISVProfile::ISVProfile(const uint32_t width, const uint32_t height)
34{
35    int i;
36
37    mWidth = width;
38    mHeight = height;
39
40    mCurrentFilter = 0;
41    mCurrentFrcTab = 0;
42    mDefaultVPPStatus = 0;
43    mDefaultFRCStatus = 0;
44
45    mStatus = 0;
46
47    memset(mConfigs, 0, sizeof(ISVConfig) * ProcFilterCount);
48
49    for (i = 0; i < MAX_TAB_SIZE; i++) {
50        mFrcRates[i].input_fps = 0;
51        mFrcRates[i].rate = FRC_RATE_1X;
52    }
53
54    /* get the vpp global setting */
55    //getGlobalStatus();
56
57    /* load the config data from XML file */
58    getDataFromXmlFile();
59
60    /* update the filter status according to the configs */
61    updateFilterStatus();
62
63    /* dump data for debug */
64    dumpConfigData();
65}
66
67ISVProfile::~ISVProfile()
68{
69}
70
71FRC_RATE ISVProfile::getFRCRate(uint32_t inputFps)
72{
73    FRC_RATE rate = FRC_RATE_1X;
74    int i;
75
76    for (i = 0; i < MAX_TAB_SIZE; i++) {
77        if (mFrcRates[i].input_fps == inputFps) {
78            rate = mFrcRates[i].rate;
79            break;
80        }
81    }
82    return rate;
83}
84
85uint32_t ISVProfile::getFilterStatus()
86{
87    return mStatus;
88}
89
90bool ISVProfile::isVPPOn()
91{
92    int32_t status = getGlobalStatus();
93    return (status != -1) ? (((status & VPP_COMMON_ON) != 0) ? true : false) : false;
94}
95
96bool ISVProfile::isFRCOn()
97{
98    int32_t status = getGlobalStatus();
99    return (status != -1) ? (((status & VPP_FRC_ON) != 0) ? true : false) : false;
100}
101
102void ISVProfile::updateFilterStatus() {
103    int i;
104    uint32_t area = mWidth * mHeight;
105
106    for (i = 1; i < ProcFilterCount; i++) {
107        /* check config */
108        if (mConfigs[i].enabled == false)
109            continue;
110
111        if (area > mConfigs[i].minResolution && area <= mConfigs[i].maxResolution)
112            mStatus |= 1 << i;
113        /* we should cover QCIF */
114        else if (area == mConfigs[i].minResolution && area == QCIF_AREA)
115            mStatus |= 1 << i;
116    }
117}
118
119int ISVProfile::getFilterID(const char * name)
120{
121    int index = 0;
122
123    if (strcmp(name, "ProcFilterNoiseReduction") == 0)
124        index = ProcFilterNoiseReduction;
125    else if (strcmp(name, "ProcFilterDeinterlacing") == 0)
126        index = ProcFilterDeinterlacing;
127    else if (strcmp(name, "ProcFilterSharpening") == 0)
128        index = ProcFilterSharpening;
129    else if (strcmp(name, "ProcFilterColorBalance") == 0)
130        index = ProcFilterColorBalance;
131    else if (strcmp(name, "ProcFilterDeblocking") == 0)
132        index = ProcFilterDeblocking;
133    else if (strcmp(name, "ProcFilterFrameRateConversion") == 0)
134        index = ProcFilterFrameRateConversion;
135    else if (strcmp(name, "ProcFilterSkinToneEnhancement") == 0)
136        index = ProcFilterSkinToneEnhancement;
137    else if (strcmp(name, "ProcFilterTotalColorCorrection") == 0)
138        index = ProcFilterTotalColorCorrection;
139    else if (strcmp(name, "ProcFilterNonLinearAnamorphicScaling") == 0)
140        index = ProcFilterNonLinearAnamorphicScaling;
141    else if (strcmp(name, "ProcFilterImageStabilization") == 0)
142        index = ProcFilterImageStabilization;
143    else
144        index = 0;
145
146    mCurrentFilter = index;
147
148    return index;
149}
150
151uint32_t ISVProfile::getResolution(const char * name)
152{
153    uint32_t width = 0, height = 0;
154    char *p = NULL, *str = NULL;
155    int32_t lenth = strlen(name);
156
157    str = (char*)malloc(lenth+1);
158    if (NULL == str) {
159        ALOGE("%s: failed to malloc buffer", __func__);
160        return 0;
161    }
162    strncpy(str, name, lenth);
163    str[lenth] = '\0';
164
165    p = strtok(str, "x");
166    if (p)
167        width = atoi(p);
168    p = strtok(NULL, "x");
169    if (p)
170        height = atoi(p);
171
172    if (str) {
173        free(str);
174        str = NULL;
175    }
176    return width * height;
177}
178
179void ISVProfile::getConfigData(const char *name, const char **atts)
180{
181    int attIndex = 0;
182
183    if (strcmp(name, "VideoPostProcessSettings") == 0) {
184        return;
185    } else if (strcmp(name, "Filter") == 0) {
186        if (strcmp(atts[attIndex], "name") == 0) {
187            if (getFilterID(atts[attIndex + 1]) == 0) {
188                ALOGE("Couldn't parase the filter %s\n", atts[attIndex+1]);
189            }
190        } else {
191            ALOGE("couldn't handle \"%s\" element for Filter\n", name);
192        }
193    } else if (strcmp(name, "enabled") == 0) {
194        if (mCurrentFilter) {
195            if (!strcmp(atts[attIndex], "value") && !strcmp(atts[attIndex + 1], "true"))
196                mConfigs[mCurrentFilter].enabled = true;
197        } else {
198            ALOGE("Skip this element(%s) becaue this filter couldn't be supported\n", name);
199        }
200    } else if (strcmp(name, "minResolution") == 0) {
201        if (mCurrentFilter && !strcmp(atts[attIndex], "value")) {
202            if (!strcmp(atts[attIndex + 1], "0"))
203                mConfigs[mCurrentFilter].minResolution = 0;
204            else if (!strcmp(atts[attIndex + 1], "FFFFFFFF"))
205                mConfigs[mCurrentFilter].minResolution = 0xFFFFFFFF;
206            else
207                mConfigs[mCurrentFilter].minResolution = getResolution(atts[attIndex + 1]);
208        } else {
209            ALOGE("Skip this element(%s) becaue this filter couldn't be supported\n", name);
210        }
211    } else if (strcmp(name, "maxResolution") == 0) {
212        if (mCurrentFilter && !strcmp(atts[attIndex], "value")) {
213            if (!strcmp(atts[attIndex + 1], "0"))
214                mConfigs[mCurrentFilter].maxResolution = 0;
215            else if (!strcmp(atts[attIndex + 1], "FFFFFFFF"))
216                mConfigs[mCurrentFilter].maxResolution = 0xFFFFFFFF;
217            else
218                mConfigs[mCurrentFilter].maxResolution = getResolution(atts[attIndex + 1]);
219        } else {
220            ALOGE("Skip this element(%s) becaue this filter couldn't be supported\n", name);
221        }
222    } else if (strcmp(name, "FRCRate") == 0) {
223        if (mCurrentFilter == ProcFilterFrameRateConversion) {
224            if (!strcmp(atts[attIndex], "input") && !strcmp(atts[attIndex + 2], "rate")) {
225                mFrcRates[mCurrentFrcTab].input_fps = atoi(atts[attIndex + 1]);
226                if (!strcmp(atts[attIndex + 3], "2"))
227                    mFrcRates[mCurrentFrcTab].rate = FRC_RATE_2X;
228                else if (!strcmp(atts[attIndex + 3], "2.5"))
229                    mFrcRates[mCurrentFrcTab].rate = FRC_RATE_2_5X;
230                else if (!strcmp(atts[attIndex + 3], "4"))
231                    mFrcRates[mCurrentFrcTab].rate = FRC_RATE_4X;
232                else
233                     mFrcRates[mCurrentFrcTab].rate = FRC_RATE_1X;
234
235                /* update the pointer */
236                if (mCurrentFrcTab < MAX_TAB_SIZE)
237                    mCurrentFrcTab++;
238            }
239        } else {
240            ALOGE("\"FRCRate\" element is only for ProcFilterFrameRateConversion\n");
241        }
242    } else if (strcmp(name, "parameter") == 0) {
243        /* <parameter /> */
244        handleFilterParameter(name, atts);
245    } else if (strcmp(name, "Parameter") == 0) {
246        /* <Parameter /> */
247        handleCommonParameter(name, atts);
248    } else
249        ALOGE("Couldn't handle this element %s!\n", name);
250}
251
252void ISVProfile::handleFilterParameter(const char *name, const char **atts)
253{
254    int attIndex = 0;
255
256    if (!mCurrentFilter) {
257        ALOGE("\"%s\" must be in Filter element\n");
258        return;
259    }
260
261    if (strcmp(atts[attIndex], "name") || strcmp(atts[attIndex + 2], "value")) {
262        ALOGE("\"%s\" or \"%s\" couldn't match the %s format\n", atts[attIndex], atts[attIndex + 2], name);
263        return;
264    }
265
266}
267
268void ISVProfile::handleCommonParameter(const char *name, const char **atts)
269{
270    int attIndex = 0;
271
272    if (strcmp(atts[attIndex], "name") || strcmp(atts[attIndex + 2], "value")) {
273        ALOGE("\"%s\" or \"%s\" couldn't match the %s format\n", atts[attIndex], atts[attIndex + 2], name);
274        return;
275    }
276
277    /* The default status of VPP */
278    if (strcmp(atts[attIndex + 1], "DefaultVPPStatus") == 0)
279        mDefaultVPPStatus = atoi(atts[attIndex + 3]);
280    /* The default status of FRC */
281    else if (strcmp(atts[attIndex + 1], "DefaultFRCStatus") == 0)
282        mDefaultFRCStatus = atoi(atts[attIndex + 3]);
283}
284
285void ISVProfile::startElement(void *userData, const char *name, const char **atts)
286{
287    ISVProfile *profile = (ISVProfile *)userData;
288
289    profile->getConfigData(name, atts);
290}
291
292void ISVProfile::endElement(void *userData, const char *name)
293{
294    ISVProfile *profile = (ISVProfile *)userData;
295
296    if (!strcmp(name, "Filter"))
297        profile->mCurrentFilter = 0;
298}
299
300void ISVProfile::getDataFromXmlFile()
301{
302    int done;
303    void *pBuf = NULL;
304    FILE *fp = NULL;
305
306    fp = ::fopen(DEFAULT_XML_FILE, "r");
307    if (NULL == fp) {
308        ALOGE("@%s, line:%d, couldn't open profile %s", __func__, __LINE__, DEFAULT_XML_FILE);
309        return;
310    }
311
312    XML_Parser parser = ::XML_ParserCreate(NULL);
313    if (NULL == parser) {
314        ALOGE("@%s, line:%d, parser is NULL", __func__, __LINE__);
315        goto exit;
316    }
317    ::XML_SetUserData(parser, this);
318    ::XML_SetElementHandler(parser, startElement, endElement);
319
320    pBuf = malloc(mBufSize);
321    if (NULL == pBuf) {
322        ALOGE("@%s, line:%d, failed to malloc buffer", __func__, __LINE__);
323        goto exit;
324    }
325
326    do {
327        int len = (int)::fread(pBuf, 1, mBufSize, fp);
328        if (!len) {
329            if (ferror(fp)) {
330                clearerr(fp);
331                goto exit;
332            }
333        }
334        done = len < mBufSize;
335        if (XML_Parse(parser, (const char *)pBuf, len, done) == XML_STATUS_ERROR) {
336            ALOGE("@%s, line:%d, XML_Parse error", __func__, __LINE__);
337            goto exit;
338        }
339    } while (!done);
340
341exit:
342    if (parser)
343        ::XML_ParserFree(parser);
344    if (pBuf)
345        free(pBuf);
346    if (fp)
347    ::fclose(fp);
348}
349
350int32_t ISVProfile::getGlobalStatus()
351{
352    char path[80];
353    int userId = 0;
354    int32_t status = 0;
355    FILE *setting_handle, *config_handle;
356
357    snprintf(path, 80, "/data/user/%d/com.intel.vpp/shared_prefs/vpp_settings.xml", userId);
358    ALOGV("%s: %s",__func__, path);
359    setting_handle = fopen(path, "r");
360    if(setting_handle == NULL) {
361        ALOGE("%s: failed to open file %s\n", __func__, path);
362
363        /* Read the Filter config file to get default value */
364        config_handle = fopen(DEFAULT_XML_FILE, "r");
365        if (config_handle == NULL) {
366            ALOGE("%s: failed to open file %s\n", __func__, DEFAULT_XML_FILE);
367            return -1;
368        }
369
370        char xml_buf[MAX_BUF_SIZE + 1] = {0};
371        memset(xml_buf, 0, MAX_BUF_SIZE);
372        if (fread(xml_buf, 1, MAX_BUF_SIZE, config_handle) <= 0) {
373            ALOGE("%s: failed to read config xml file!\n", __func__);
374            fclose(config_handle);
375            return -1;
376        }
377        xml_buf[MAX_BUF_SIZE] = '\0';
378
379        if (strstr(xml_buf, "name=\"DefaultVPPStatus\" value=\"1\"") != NULL)
380            status |= VPP_COMMON_ON;
381        if (strstr(xml_buf, "name=\"DefaultFRCStatus\" value=\"1\"") != NULL)
382            status |= VPP_FRC_ON;
383
384        ALOGV("%s: using the default status: VPP=%d, FRC=%d\n", __func__,
385            ((status & VPP_COMMON_ON) == 0) ? 0 : 1,
386            ((status & VPP_FRC_ON) == 0) ? 0: 1);
387
388        fclose(config_handle);
389        return status;
390    }
391
392    const int MAXLEN = 1024;
393    char buf[MAXLEN] = {0};
394    memset(buf, 0 ,MAXLEN);
395    if(fread(buf, 1, MAXLEN, setting_handle) <= 0) {
396        ALOGE("%s: failed to read vpp config file %d", __func__, userId);
397        fclose(setting_handle);
398        return -1;
399    }
400    buf[MAXLEN - 1] = '\0';
401
402    if(strstr(buf, StatusOn[0]) != NULL)
403        status |= VPP_FRC_ON;
404
405    if(strstr(buf, StatusOn[1]) != NULL)
406        status |= VPP_COMMON_ON;
407
408    fclose(setting_handle);
409    return status;
410}
411
412void ISVProfile::dumpConfigData()
413{
414    uint32_t i, j;
415    char filterNames[][50] = {
416        "ProcFilterNone",
417        "ProcFilterNoiseReduction",
418        "ProcFilterDeinterlacing",
419        "ProcFilterSharpening",
420        "ProcFilterColorBalance",
421        "ProcFilterDeblocking",
422        "ProcFilterFrameRateConversion",
423        "ProcFilterSkinToneEnhancement",
424        "ProcFilterTotalColorCorrection",
425        "ProcFilterNonLinearAnamorphicScaling",
426        "ProcFilterImageStabilization"
427    };
428    char rateNames[][20] = {
429        "FRC_RATE_0X",
430        "FRC_RATE_1X",
431        "FRC_RATE_2X",
432        "FRC_RATE_2_5X",
433        "FRC_RATE_4X",
434    };
435
436    ALOGV("========== VPP filter configs:==========\n");
437    for (i = 1; i < ProcFilterCount; i++) {
438        ALOGV("name=%s, enabled=%s, minResolution=%d, maxResolution=%d, isOn=%s\n",
439            filterNames[i],
440            (mConfigs[i].enabled == true) ? "true" : "false",
441            mConfigs[i].minResolution,
442            mConfigs[i].maxResolution,
443            ((mStatus & (1 << i)) == 0) ? "false" : "true");
444        if (mConfigs[i].paraSize) {
445            ALOGV("\t\t parameters: ");
446            for(j = 0; j < mConfigs[i].paraSize; j++)
447                ALOGE("%s=%f,", mConfigs[i].paraTables[j].name, mConfigs[i].paraTables[j].value);
448            ALOGV("\n");
449        }
450    }
451
452    ALOGV("========== FRC rate configs:===========\n");
453    for (i = 0; i < MAX_TAB_SIZE; i++) {
454        if (mFrcRates[i].input_fps == 0)
455            break;
456        ALOGV("input_fps=%d, rate=%s\n", mFrcRates[i].input_fps, rateNames[mFrcRates[i].rate]);
457    }
458
459    ALOGI("========== common parameter configs:===========\n");
460    ALOGI("mDefaultVPPStatus=%d\n", mDefaultVPPStatus);
461    ALOGI("mDefaultFRCStatus=%d\n", mDefaultFRCStatus);
462
463}
464