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