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 <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 
30 using namespace android;
31 static const char StatusOn[][5] = {"1frc", "1vpp"};
32 
ISVProfile(const uint32_t width,const uint32_t height)33 ISVProfile::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 
~ISVProfile()67 ISVProfile::~ISVProfile()
68 {
69 }
70 
getFRCRate(uint32_t inputFps)71 FRC_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 
getFilterStatus()85 uint32_t ISVProfile::getFilterStatus()
86 {
87     return mStatus;
88 }
89 
isVPPOn()90 bool ISVProfile::isVPPOn()
91 {
92     int32_t status = getGlobalStatus();
93     return (status != -1) ? (((status & VPP_COMMON_ON) != 0) ? true : false) : false;
94 }
95 
isFRCOn()96 bool ISVProfile::isFRCOn()
97 {
98     int32_t status = getGlobalStatus();
99     return (status != -1) ? (((status & VPP_FRC_ON) != 0) ? true : false) : false;
100 }
101 
updateFilterStatus()102 void 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 
getFilterID(const char * name)119 int 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 
getResolution(const char * name)151 uint32_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 
getConfigData(const char * name,const char ** atts)179 void 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 
handleFilterParameter(const char * name,const char ** atts)252 void 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", name);
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 
handleCommonParameter(const char * name,const char ** atts)268 void 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 
startElement(void * userData,const char * name,const char ** atts)285 void ISVProfile::startElement(void *userData, const char *name, const char **atts)
286 {
287     ISVProfile *profile = (ISVProfile *)userData;
288 
289     profile->getConfigData(name, atts);
290 }
291 
endElement(void * userData,const char * name)292 void 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 
getDataFromXmlFile()300 void 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 
341 exit:
342     if (parser)
343         ::XML_ParserFree(parser);
344     if (pBuf)
345         free(pBuf);
346     if (fp)
347     ::fclose(fp);
348 }
349 
getGlobalStatus()350 int32_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 
dumpConfigData()412 void 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