1 /*
2  * * Copyright (c) 2015 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 
18 //#define LOG_NDEBUG 0
19 #define LOG_TAG "MRM_Arbitrator"
20 
21 #include <expat.h>
22 #include <string.h>
23 #include <stdio.h>
24 #include <utils/Log.h>
25 #include <unistd.h>
26 #include "MediaResourceArbitrator.h"
27 
28 using namespace android;
29 
30 
MediaResourceArbitrator()31 MediaResourceArbitrator::MediaResourceArbitrator()
32     : mIsEncoderUnderFullLoad (false),
33       mIsDecoderUnderFullLoad (false) {
34     ALOGV("construct MediaResourceArbitrator");
35     pthread_mutex_init(&mArbitratorLock, NULL);
36     //InitializeCodecNameTypeMap();
37     //InitializeResolutionNameTypeMap();
38 }
39 
40 
~MediaResourceArbitrator()41 MediaResourceArbitrator::~MediaResourceArbitrator() {}
42 
43 
Config(const char * configFilePath)44 ArbitratorErrorType MediaResourceArbitrator::Config(const char* configFilePath) {
45     FILE *fp = NULL;
46 
47     fp = ::fopen(configFilePath, "r");
48     if (fp == NULL) {
49         ALOGV("%s: can not open config xml file.\
50                try to set up default codec limitation");
51         SetupDefaultCodecLimitation();
52         return ArbitratorErrorNone;
53     }
54 
55     ParseXMLFile(fp);
56     return ArbitratorErrorNone;
57 }
58 
59 
CheckIfFullLoad(bool isEncoder)60 bool MediaResourceArbitrator::CheckIfFullLoad(bool isEncoder) {
61     if (isEncoder) {
62         return mIsEncoderUnderFullLoad;
63     } else {
64         return mIsDecoderUnderFullLoad;
65     }
66 }
67 
68 
AddResource(CodecType codecType,bool isEncoder,bool isSecured,ResolutionType resolution,uint frameRate)69 ArbitratorErrorType MediaResourceArbitrator::AddResource(
70                     /* in */  CodecType codecType,
71                     /* in */  bool isEncoder,
72                     /* in */  bool isSecured,
73                     /* in */  ResolutionType resolution,
74                     /* in */  uint frameRate) {
75     ALOGV("MediaResourceArbitrator::AddResource ++");
76     pthread_mutex_lock(&mArbitratorLock);
77 
78     ArbitratorErrorType err = ArbitratorErrorNone;
79 
80     if (CheckIfFullLoad(isEncoder) == true) {
81         pthread_mutex_unlock(&mArbitratorLock);
82         return ArbitratorErrorInsufficientResources;
83     }
84 
85     CodecInfo resource;
86     resource.codecType = codecType;
87     resource.isEncoder = isEncoder;
88     resource.isSecured = isSecured;
89     resource.resolution = resolution;
90     resource.frameRate = frameRate;
91 
92     ALOGV("Adding resource: codecType = %d, isEncoder = %d, isSecured = %d, resolution = %d, frameRate = %d",
93           codecType, isEncoder, isSecured, resolution, frameRate);
94 
95     if (isEncoder) {
96         mLivingEncodersTable.livingEncoders.push_back(resource);
97         if (resolution > mLivingEncodersTable.maxResolution) {
98             mLivingEncodersTable.maxResolution = resolution;
99         }
100         if (frameRate > mLivingEncodersTable.maxFrameRate) {
101             mLivingEncodersTable.maxFrameRate = frameRate;
102         }
103     } else { // decoder
104          mLivingDecodersTable.livingDecoders.push_back(resource);
105         if (resolution > mLivingDecodersTable.maxResolution) {
106             mLivingDecodersTable.maxResolution = resolution;
107         }
108         if (frameRate > mLivingDecodersTable.maxFrameRate) {
109             mLivingDecodersTable.maxFrameRate = frameRate;
110         }
111     }
112 
113     err = ArbitrateFullLoad(resource);
114     pthread_mutex_unlock(&mArbitratorLock);
115 
116     ALOGV("AddResource --");
117     return err;
118 }
119 
120 
GetLivingCodecsNum(void)121 uint MediaResourceArbitrator::GetLivingCodecsNum(void) {
122     return mLivingDecodersTable.livingDecoders.size() +
123            mLivingEncodersTable.livingEncoders.size();
124 }
125 
126 
127 
RemoveResource(CodecType codecType,bool isEncoder,bool isSecured,ResolutionType resolution,uint frameRate)128 ArbitratorErrorType MediaResourceArbitrator::RemoveResource(
129                                    CodecType codecType,
130                                    bool isEncoder,
131                                    bool isSecured,
132                                    ResolutionType resolution,
133                                    uint frameRate) {
134     ALOGV("MediaResourceArbitrator::RemoveResource");
135 
136     uint i;
137     ArbitratorErrorType err = ArbitratorErrorNone;
138 
139     pthread_mutex_lock(&mArbitratorLock);
140 
141     if (isEncoder) {
142         for(i=0; i<mLivingEncodersTable.livingEncoders.size(); i++) {
143             const CodecInfo& livingCodec = mLivingEncodersTable.livingEncoders[i];
144             if ((livingCodec.codecType == codecType) &&
145                 (livingCodec.resolution == resolution) &&
146                 (livingCodec.frameRate == frameRate)) {
147                 mLivingEncodersTable.livingEncoders.removeAt(i);
148                 break;
149             }
150         }
151         mIsEncoderUnderFullLoad = false;
152     } else {
153         for(i=0; i<mLivingDecodersTable.livingDecoders.size(); i++) {
154             const CodecInfo& livingCodec = mLivingDecodersTable.livingDecoders[i];
155             if ((livingCodec.codecType == codecType) &&
156                 (livingCodec.resolution == resolution) &&
157                 (livingCodec.isSecured == isSecured) &&
158                 (livingCodec.frameRate == frameRate)) {
159                 mLivingDecodersTable.livingDecoders.removeAt(i);
160                 break;
161             }
162         }
163         mIsDecoderUnderFullLoad = false;
164     }
165     pthread_mutex_unlock(&mArbitratorLock);
166     return err;
167 }
168 
169 
ParseXMLFile(FILE * fp)170 void MediaResourceArbitrator::ParseXMLFile(FILE* fp) {
171     ALOGV("MediaResourceArbitrator::ParseXMLFile");
172 
173     int done;
174     void *pBuf = NULL;
175 
176     XML_Parser parser = ::XML_ParserCreate(NULL);
177     if (NULL == parser) {
178         ALOGE("@%s, line:%d, parser is NULL", __func__, __LINE__);
179         goto exit;
180     }
181     ::XML_SetUserData(parser, this);
182     ::XML_SetElementHandler(parser, startElement, endElement);
183 
184     pBuf = malloc(mBufSize);
185     if (NULL == pBuf) {
186         ALOGE("@%s, line:%d, failed to malloc buffer", __func__, __LINE__);
187         goto exit;
188     }
189 
190     do {
191         int len = (int)::fread(pBuf, 1, mBufSize, fp);
192         if (!len) {
193             if (ferror(fp)) {
194                 clearerr(fp);
195                 goto exit;
196             }
197         }
198         done = len < mBufSize;
199         if (XML_Parse(parser, (const char *)pBuf, len, done) == XML_STATUS_ERROR) {
200             ALOGE("@%s, line:%d, XML_Parse error", __func__, __LINE__);
201             goto exit;
202         }
203     } while (!done);
204 
205 exit:
206     if (parser)
207         ::XML_ParserFree(parser);
208     if (pBuf)
209         free(pBuf);
210     if (fp)
211     ::fclose(fp);
212 
213 }
214 
215 
ArbitrateFullLoad(CodecInfo & codec)216 ArbitratorErrorType MediaResourceArbitrator::ArbitrateFullLoad(CodecInfo& codec) {
217     ALOGV("MediaResourceArbitrator::ArbitrateFullLoad");
218     ALOGV("giving codec type :%d, isEncoder = %d, frameRate = %d",
219            codec.codecType, codec.isEncoder, codec.frameRate);
220     ArbitratorErrorType err = ArbitratorErrorNone;
221     int livingInstanceNum = 0;
222 
223     if (codec.isEncoder == true) {
224         livingInstanceNum = mLivingEncodersTable.livingEncoders.size();
225     } else {
226         livingInstanceNum = mLivingDecodersTable.livingDecoders.size();
227     }
228 
229     ALOGV("current living codec number of %s is %d",
230            codec.isEncoder ? "encoder" : "decoder", livingInstanceNum);
231 
232     // check if living instance number reaches the limitation
233     int targetInstanceLimit = 5; // most optimistic
234     uint i,j;
235 
236     if (codec.isEncoder == false) { // decoder
237         for (i=0; i<mLivingDecodersTable.livingDecoders.size(); i++) {
238             const CodecInfo& livingCodec = mLivingDecodersTable.livingDecoders[i];
239             for (j=0; j<mDecoderLimitInfos.size(); j++) {
240                 const CodecInfo& targetCodec = mDecoderLimitInfos[j].codecInfo;
241                 ALOGV("%dth codec in DecoderLimitInfos.",j);
242                 if (CheckCodecMatched(livingCodec, targetCodec) == true) {
243                     if (targetInstanceLimit > mDecoderLimitInfos[j].instanceLimit) {
244                         targetInstanceLimit = mDecoderLimitInfos[j].instanceLimit;
245                         break;
246                     }
247                 }
248             }
249         }
250         ALOGV("Go through decoder limit table and get current instance limit = %d",
251               targetInstanceLimit);
252         if (livingInstanceNum >= targetInstanceLimit) {
253             ALOGV("setting full load flag to true.");
254             mIsDecoderUnderFullLoad = true;
255         } else {
256             ALOGV("setting full load flag to false.");
257             mIsDecoderUnderFullLoad = false;
258         }
259     } else { // encoder
260         for(i=0; i<mLivingEncodersTable.livingEncoders.size(); i++) {
261             const CodecInfo& livingCodec = mLivingEncodersTable.livingEncoders[i];
262             for (j=0; j<mEncoderLimitInfos.size(); j++) {
263                 const CodecInfo& targetCodec = mEncoderLimitInfos[j].codecInfo;
264                 if (CheckCodecMatched(livingCodec, targetCodec) == true) {
265                     if (targetInstanceLimit > mEncoderLimitInfos[j].instanceLimit) {
266                         targetInstanceLimit = mEncoderLimitInfos[j].instanceLimit;
267                         break;
268                     }
269                 }
270             }
271         }
272         ALOGV("Go through encoder limit table and get current instance limit = %d",
273               targetInstanceLimit);
274         if (livingInstanceNum >= targetInstanceLimit) {
275             ALOGV("setting full load flag to true.");
276             mIsEncoderUnderFullLoad = true;
277         } else {
278             ALOGV("setting full load flag to false.");
279             mIsEncoderUnderFullLoad = false;
280         }
281     }
282 
283     return err;
284 }
285 
286 
CheckCodecMatched(const CodecInfo & sourceCodec,const CodecInfo & targetCodec)287 bool MediaResourceArbitrator::CheckCodecMatched(
288                                   const CodecInfo& sourceCodec,
289                                   const CodecInfo& targetCodec) {
290     ALOGV("CheckCodecMatched");
291     return ((sourceCodec.codecType == targetCodec.codecType) &&
292             (sourceCodec.isSecured == targetCodec.isSecured) &&
293             (sourceCodec.resolution == targetCodec.resolution) &&
294             (sourceCodec.frameRate == targetCodec.frameRate));
295 }
296 
297 
DumpCodecTypeFromVector(void)298 void MediaResourceArbitrator::DumpCodecTypeFromVector(void) {
299     unsigned int i;
300     ALOGV("MediaResourceArbitrator::DumpCodecTypeFromVector");
301     for (i=0; i<mCodecNameTypeMap.size(); i++) {
302         ALOGV("codec type in vector %s : %d",
303                mCodecNameTypeMap.keyAt(i), mCodecNameTypeMap.valueAt(i));
304     }
305 }
306 
307 
MapCodecTypeFromName(const char * name)308 CodecType MediaResourceArbitrator::MapCodecTypeFromName(const char* name) {
309     if (strcmp(name, "CODEC_TYPE_AVC") == 0) {
310         return CODEC_TYPE_AVC;
311     } else if (strcmp(name, "CODEC_TYPE_HEVC") == 0) {
312         return CODEC_TYPE_HEVC;
313     } else if (strcmp(name, "CODEC_TYPE_VP8") == 0) {
314         return CODEC_TYPE_VP8;
315     } else if (strcmp(name, "CODEC_TYPE_VP9") == 0) {
316         return CODEC_TYPE_VP9;
317     } else if (strcmp(name, "CODEC_TYPE_MPEG2") == 0) {
318         return CODEC_TYPE_MPEG2;
319     } else if (strcmp(name, "CODEC_TYPE_MPEG4") == 0){
320         return CODEC_TYPE_MPEG4;
321     } else if (strcmp(name, "CODEC_TYPE_H263") == 0) {
322         return CODEC_TYPE_H263;
323     } else if (strcmp(name, "CODEC_TYPE_WMV") == 0) {
324         return CODEC_TYPE_WMV;
325     } else if (strcmp(name, "CODEC_TYPE_VC1") == 0) {
326         return CODEC_TYPE_VC1;
327     } else {
328         ALOGE("unknown codec name: %s, try to return avc", name);
329         return CODEC_TYPE_AVC;
330     }
331 }
332 
333 
334 ResolutionType MediaResourceArbitrator::
MapResolutionTypeFromName(const char * name)335                    MapResolutionTypeFromName(const char* name) {
336     if (strcmp(name, "480") == 0) {
337         return Resolution_480;
338     } else if (strcmp(name, "720") == 0) {
339         return Resolution_720;
340     } else if (strcmp(name, "1080") == 0) {
341         return Resolution_1080;
342     } else if (strcmp(name, "2K") == 0) {
343         return Resolution_2K;
344     } else if (strcmp(name, "4K") == 0) {
345         return Resolution_4K;
346     } else {
347         ALOGE("unkown resolution name: %s, try to return 1080", name);
348         return Resolution_1080;
349     }
350 }
351 
352 
InitializeCodecNameTypeMap(void)353 void MediaResourceArbitrator::InitializeCodecNameTypeMap(void) {
354     ALOGV("MediaResourceArbitrator::InitializeCodecNameTypeMap");
355     mCodecNameTypeMap.add("CODEC_TYPE_AVC", CODEC_TYPE_AVC);
356     mCodecNameTypeMap.add("CODEC_TYPE_HEVC", CODEC_TYPE_HEVC);
357     mCodecNameTypeMap.add("CODEC_TYPE_VP8", CODEC_TYPE_VP8);
358     mCodecNameTypeMap.add("CODEC_TYPE_VP9", CODEC_TYPE_VP9);
359     mCodecNameTypeMap.add("CODEC_TYPE_MPEG4", CODEC_TYPE_MPEG4);
360     mCodecNameTypeMap.add("CODEC_TYPE_MPEG2", CODEC_TYPE_MPEG2);
361     mCodecNameTypeMap.add("CODEC_TYPE_H263", CODEC_TYPE_H263);
362     mCodecNameTypeMap.add("CODEC_TYPE_VC1", CODEC_TYPE_VC1);
363     mCodecNameTypeMap.add("CODEC_TYPE_WMV", CODEC_TYPE_WMV);
364     //DumpCodecTypeFromVector();
365 }
366 
367 
InitializeResolutionNameTypeMap(void)368 void MediaResourceArbitrator::InitializeResolutionNameTypeMap(void) {
369     ALOGV("MediaResourceArbitrator::InitializeResolutionNameTypeMap");
370     mResolutionNameTypeMap.add("480", Resolution_480);
371     mResolutionNameTypeMap.add("720", Resolution_720);
372     mResolutionNameTypeMap.add("1080", Resolution_1080);
373     mResolutionNameTypeMap.add("2K", Resolution_2K);
374     mResolutionNameTypeMap.add("4K", Resolution_4K);
375 }
376 
377 // Hard coded limitation
SetupDefaultCodecLimitation(void)378 void MediaResourceArbitrator::SetupDefaultCodecLimitation(void) {
379     ALOGV("MediaResourceArbitrator::SetupDefaultCodecLimitation");
380     uint i,j,k;
381     CodecType codecType;
382     ResolutionType resolutionType;
383     uint frameRate;
384 
385     // non-secure decoders
386     for (i=(int)CODEC_TYPE_AVC; i<(int)CODEC_TYPE_MAX; i++) {
387             codecType = (CodecType)i;
388         for (j=(int)Resolution_CIF; j<(int)Resolution_MAX; j++) {
389             resolutionType = (ResolutionType)j;
390             for (k=0; k<2; k++) {
391                 frameRate = (k+1)*30;
392                 bool isSecured = false;
393                 CodecLimitInfo codecLimitInfo;
394                 codecLimitInfo.codecInfo.codecType = codecType;
395                 codecLimitInfo.codecInfo.resolution = resolutionType;
396                 codecLimitInfo.codecInfo.isSecured = isSecured;
397                 codecLimitInfo.codecInfo.isEncoder = false;
398                 codecLimitInfo.codecInfo.frameRate = frameRate;
399                 codecLimitInfo.instanceLimit = 2;
400                 mDecoderLimitInfos.add(codecLimitInfo);
401             }
402         }
403     }
404 
405     // secure avc decoder
406     codecType = CODEC_TYPE_AVC;
407     for (j=(int)Resolution_CIF; j<(int)Resolution_MAX; j++) {
408         resolutionType = (ResolutionType)j;
409         for (k=0; k<2; k++) {
410             frameRate = (k+1)*30;
411             bool isSecured = true;
412             CodecLimitInfo codecLimitInfo;
413             codecLimitInfo.codecInfo.codecType = codecType;
414             codecLimitInfo.codecInfo.resolution = resolutionType;
415             codecLimitInfo.codecInfo.isSecured = isSecured;
416             codecLimitInfo.codecInfo.isEncoder = false;
417             codecLimitInfo.instanceLimit = 2;
418             mDecoderLimitInfos.add(codecLimitInfo);
419         }
420     }
421 
422     // Encoder limitation Map
423     for (i=(int)CODEC_TYPE_AVC; i<(int)CODEC_TYPE_MAX; i++) {
424             codecType = (CodecType)i;
425         for (j=(int)Resolution_CIF; j<(int)Resolution_MAX; j++) {
426             resolutionType = (ResolutionType)j;
427             for (k=0; k<2; k++) {
428                 frameRate = (k+1)*30;
429                 bool isSecured = false;
430                 CodecLimitInfo codecLimitInfo;
431                 codecLimitInfo.codecInfo.codecType = codecType;
432                 codecLimitInfo.codecInfo.resolution = resolutionType;
433                 codecLimitInfo.codecInfo.isSecured = isSecured;
434                 codecLimitInfo.codecInfo.isEncoder = true;
435                 codecLimitInfo.instanceLimit = 2;
436                 mEncoderLimitInfos.add(codecLimitInfo);
437             }
438         }
439     }
440 }
441 
442 
getConfigData(const char * name,const char ** atts)443 void MediaResourceArbitrator::getConfigData(const char *name,
444                                             const char **atts) {
445     ALOGV("MediaResourceArbitrator::getConfigData");
446     int attIndex = 0;
447     if (strcmp(name, "CodecResourcesLimitation") == 0) {
448         return;
449     } else if (strcmp(name, "Codec") == 0) {
450         if (strcmp(atts[attIndex], "name") == 0) {
451             ALOGV("Parsing codec %s", atts[attIndex+1]);
452             mIfParsingCodec = true;
453         } else {
454             ALOGE("Codec tag with no name, anything wrong?");
455         }
456     } else if (strcmp(name, "codecType") == 0) {
457         ALOGV("parse tag codecType");
458         if (mIfParsingCodec) {
459             if (strcmp(atts[attIndex], "value") == 0) {
460                 //DumpCodecTypeFromVector();
461                 mParsingCodecLimitInfo.codecInfo.codecType =
462                     MapCodecTypeFromName((const char*)atts[attIndex+1]);
463             }
464         } else {
465             ALOGE("Skip this element(%s) becaue this codec couldn't be supported\n", name);
466         }
467     } else if (strcmp(name, "isEncoder") == 0) {
468         ALOGV("parse tag isEncoder");
469         if (mIfParsingCodec && !strcmp(atts[attIndex], "value")) {
470             if (!strcmp(atts[attIndex + 1], "false"))
471                 mParsingCodecLimitInfo.codecInfo.isEncoder = false;
472             else {
473                 mParsingCodecLimitInfo.codecInfo.isEncoder = true;
474             }
475         } else {
476             ALOGE("Skip this element(%s) becaue this tag couldn't be supported\n", name);
477         }
478     } else if (strcmp(name, "isSecured") == 0) {
479         ALOGV("parse tag isSecured");
480         if (mIfParsingCodec && !strcmp(atts[attIndex], "value")) {
481             if (!strcmp(atts[attIndex + 1], "false"))
482                 mParsingCodecLimitInfo.codecInfo.isSecured = false;
483             else {
484                 mParsingCodecLimitInfo.codecInfo.isSecured = true;
485             }
486         } else {
487             ALOGE("Skip this element(%s) becaue this tag couldn't be supported\n", name);
488         }
489     } else if (strcmp(name, "resolutionType") == 0) {
490         ALOGV("parse tag resolutionType");
491         if (mIfParsingCodec) {
492             if (strcmp(atts[attIndex], "value") == 0) {
493                 mParsingCodecLimitInfo.codecInfo.resolution =
494                     MapResolutionTypeFromName((const char*)atts[attIndex+1]);
495                     //mResolutionNameTypeMap.valueFor(atts[attIndex+1]);
496             }
497         } else {
498             ALOGE("Skip this element(%s) becaue this codec couldn't be supported\n", name);
499         }
500     } else if (strcmp(name, "frameRate") == 0) {
501         ALOGV("parse tag frameRate");
502         if (mIfParsingCodec) {
503             if (strcmp(atts[attIndex], "value") == 0) {
504                 mParsingCodecLimitInfo.codecInfo.frameRate = atoi(atts[attIndex+1]);
505             }
506         } else {
507             ALOGE("Skip this element(%s) becaue this codec couldn't be supported\n", name);
508         }
509     } else if (strcmp(name, "instanceLimit") == 0) {
510         ALOGV("parse tag instanceLimit");
511         if (mIfParsingCodec) {
512             if (strcmp(atts[attIndex], "value") == 0) {
513                 mParsingCodecLimitInfo.instanceLimit = atoi(atts[attIndex+1]);
514             }
515         } else {
516             ALOGE("Skip this element(%s) becaue this codec couldn't be supported\n", name);
517         }
518     }
519 }
520 
521 // Start tag
startElement(void * userData,const char * name,const char ** atts)522 void MediaResourceArbitrator::startElement(void *userData,
523                                            const char *name,
524                                            const char **atts) {
525     MediaResourceArbitrator* arbitrator = (MediaResourceArbitrator*)userData;
526     arbitrator->getConfigData(name, atts);
527 }
528 
529 
530 // End tag
endElement(void * userData,const char * name)531 void MediaResourceArbitrator::endElement(void *userData, const char *name) {
532     MediaResourceArbitrator* arbitrator = (MediaResourceArbitrator*)userData;
533     if (strcmp(name, "Codec") == 0) {
534         if (arbitrator->mParsingCodecLimitInfo.codecInfo.isEncoder == true) {
535             arbitrator->mEncoderLimitInfos.push_back(arbitrator->mParsingCodecLimitInfo);
536         } else {
537             arbitrator->mDecoderLimitInfos.push_back(arbitrator->mParsingCodecLimitInfo);
538         }
539         arbitrator->mIfParsingCodec = false;
540     }
541 }
542