MediaCodecList.cpp revision dcec687af73ee38d8e0053a378b6bc7d5efe0bb8
1/* 2 * Copyright 2012, The Android Open Source Project 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//#define LOG_NDEBUG 0 18#define LOG_TAG "MediaCodecList" 19#include <utils/Log.h> 20 21#include <media/stagefright/MediaCodecList.h> 22 23#include <media/stagefright/foundation/ADebug.h> 24#include <media/stagefright/MediaErrors.h> 25#include <media/stagefright/OMXClient.h> 26#include <media/stagefright/OMXCodec.h> 27#include <utils/threads.h> 28 29#include <libexpat/expat.h> 30 31namespace android { 32 33static Mutex sInitMutex; 34 35// static 36MediaCodecList *MediaCodecList::sCodecList; 37 38// static 39const MediaCodecList *MediaCodecList::getInstance() { 40 Mutex::Autolock autoLock(sInitMutex); 41 42 if (sCodecList == NULL) { 43 sCodecList = new MediaCodecList; 44 } 45 46 return sCodecList->initCheck() == OK ? sCodecList : NULL; 47} 48 49MediaCodecList::MediaCodecList() 50 : mInitCheck(NO_INIT) { 51 parseTopLevelXMLFile("/etc/media_codecs.xml"); 52} 53 54void MediaCodecList::parseTopLevelXMLFile(const char *codecs_xml) { 55 // get href_base 56 char *href_base_end = strrchr(codecs_xml, '/'); 57 if (href_base_end != NULL) { 58 mHrefBase = AString(codecs_xml, href_base_end - codecs_xml + 1); 59 } 60 61 mInitCheck = OK; 62 mCurrentSection = SECTION_TOPLEVEL; 63 mDepth = 0; 64 65 parseXMLFile(codecs_xml); 66 67 if (mInitCheck != OK) { 68 mCodecInfos.clear(); 69 mCodecQuirks.clear(); 70 return; 71 } 72 73 for (size_t i = mCodecInfos.size(); i-- > 0;) { 74 CodecInfo *info = &mCodecInfos.editItemAt(i); 75 76 if (info->mTypes == 0) { 77 // No types supported by this component??? 78 ALOGW("Component %s does not support any type of media?", 79 info->mName.c_str()); 80 81 mCodecInfos.removeAt(i); 82 } 83 } 84 85#if 0 86 for (size_t i = 0; i < mCodecInfos.size(); ++i) { 87 const CodecInfo &info = mCodecInfos.itemAt(i); 88 89 AString line = info.mName; 90 line.append(" supports "); 91 for (size_t j = 0; j < mTypes.size(); ++j) { 92 uint32_t value = mTypes.valueAt(j); 93 94 if (info.mTypes & (1ul << value)) { 95 line.append(mTypes.keyAt(j)); 96 line.append(" "); 97 } 98 } 99 100 ALOGI("%s", line.c_str()); 101 } 102#endif 103} 104 105MediaCodecList::~MediaCodecList() { 106} 107 108status_t MediaCodecList::initCheck() const { 109 return mInitCheck; 110} 111 112void MediaCodecList::parseXMLFile(const char *path) { 113 FILE *file = fopen(path, "r"); 114 115 if (file == NULL) { 116 ALOGW("unable to open media codecs configuration xml file: %s", path); 117 mInitCheck = NAME_NOT_FOUND; 118 return; 119 } 120 121 XML_Parser parser = ::XML_ParserCreate(NULL); 122 CHECK(parser != NULL); 123 124 ::XML_SetUserData(parser, this); 125 ::XML_SetElementHandler( 126 parser, StartElementHandlerWrapper, EndElementHandlerWrapper); 127 128 const int BUFF_SIZE = 512; 129 while (mInitCheck == OK) { 130 void *buff = ::XML_GetBuffer(parser, BUFF_SIZE); 131 if (buff == NULL) { 132 ALOGE("failed in call to XML_GetBuffer()"); 133 mInitCheck = UNKNOWN_ERROR; 134 break; 135 } 136 137 int bytes_read = ::fread(buff, 1, BUFF_SIZE, file); 138 if (bytes_read < 0) { 139 ALOGE("failed in call to read"); 140 mInitCheck = ERROR_IO; 141 break; 142 } 143 144 XML_Status status = ::XML_ParseBuffer(parser, bytes_read, bytes_read == 0); 145 if (status != XML_STATUS_OK) { 146 ALOGE("malformed (%s)", ::XML_ErrorString(::XML_GetErrorCode(parser))); 147 mInitCheck = ERROR_MALFORMED; 148 break; 149 } 150 151 if (bytes_read == 0) { 152 break; 153 } 154 } 155 156 ::XML_ParserFree(parser); 157 158 fclose(file); 159 file = NULL; 160} 161 162// static 163void MediaCodecList::StartElementHandlerWrapper( 164 void *me, const char *name, const char **attrs) { 165 static_cast<MediaCodecList *>(me)->startElementHandler(name, attrs); 166} 167 168// static 169void MediaCodecList::EndElementHandlerWrapper(void *me, const char *name) { 170 static_cast<MediaCodecList *>(me)->endElementHandler(name); 171} 172 173status_t MediaCodecList::includeXMLFile(const char **attrs) { 174 const char *href = NULL; 175 size_t i = 0; 176 while (attrs[i] != NULL) { 177 if (!strcmp(attrs[i], "href")) { 178 if (attrs[i + 1] == NULL) { 179 return -EINVAL; 180 } 181 href = attrs[i + 1]; 182 ++i; 183 } else { 184 return -EINVAL; 185 } 186 ++i; 187 } 188 189 // For security reasons and for simplicity, file names can only contain 190 // [a-zA-Z0-9_.] and must start with media_codecs_ and end with .xml 191 for (i = 0; href[i] != '\0'; i++) { 192 if (href[i] == '.' || href[i] == '_' || 193 (href[i] >= '0' && href[i] <= '9') || 194 (href[i] >= 'A' && href[i] <= 'Z') || 195 (href[i] >= 'a' && href[i] <= 'z')) { 196 continue; 197 } 198 ALOGE("invalid include file name: %s", href); 199 return -EINVAL; 200 } 201 202 AString filename = href; 203 if (!filename.startsWith("media_codecs_") || 204 !filename.endsWith(".xml")) { 205 ALOGE("invalid include file name: %s", href); 206 return -EINVAL; 207 } 208 filename.insert(mHrefBase, 0); 209 210 parseXMLFile(filename.c_str()); 211 return mInitCheck; 212} 213 214void MediaCodecList::startElementHandler( 215 const char *name, const char **attrs) { 216 if (mInitCheck != OK) { 217 return; 218 } 219 220 if (!strcmp(name, "Include")) { 221 mInitCheck = includeXMLFile(attrs); 222 if (mInitCheck == OK) { 223 mPastSections.push(mCurrentSection); 224 mCurrentSection = SECTION_INCLUDE; 225 } 226 ++mDepth; 227 return; 228 } 229 230 switch (mCurrentSection) { 231 case SECTION_TOPLEVEL: 232 { 233 if (!strcmp(name, "Decoders")) { 234 mCurrentSection = SECTION_DECODERS; 235 } else if (!strcmp(name, "Encoders")) { 236 mCurrentSection = SECTION_ENCODERS; 237 } 238 break; 239 } 240 241 case SECTION_DECODERS: 242 { 243 if (!strcmp(name, "MediaCodec")) { 244 mInitCheck = 245 addMediaCodecFromAttributes(false /* encoder */, attrs); 246 247 mCurrentSection = SECTION_DECODER; 248 } 249 break; 250 } 251 252 case SECTION_ENCODERS: 253 { 254 if (!strcmp(name, "MediaCodec")) { 255 mInitCheck = 256 addMediaCodecFromAttributes(true /* encoder */, attrs); 257 258 mCurrentSection = SECTION_ENCODER; 259 } 260 break; 261 } 262 263 case SECTION_DECODER: 264 case SECTION_ENCODER: 265 { 266 if (!strcmp(name, "Quirk")) { 267 mInitCheck = addQuirk(attrs); 268 } else if (!strcmp(name, "Type")) { 269 mInitCheck = addTypeFromAttributes(attrs); 270 } 271 break; 272 } 273 274 default: 275 break; 276 } 277 278 ++mDepth; 279} 280 281void MediaCodecList::endElementHandler(const char *name) { 282 if (mInitCheck != OK) { 283 return; 284 } 285 286 switch (mCurrentSection) { 287 case SECTION_DECODERS: 288 { 289 if (!strcmp(name, "Decoders")) { 290 mCurrentSection = SECTION_TOPLEVEL; 291 } 292 break; 293 } 294 295 case SECTION_ENCODERS: 296 { 297 if (!strcmp(name, "Encoders")) { 298 mCurrentSection = SECTION_TOPLEVEL; 299 } 300 break; 301 } 302 303 case SECTION_DECODER: 304 { 305 if (!strcmp(name, "MediaCodec")) { 306 mCurrentSection = SECTION_DECODERS; 307 } 308 break; 309 } 310 311 case SECTION_ENCODER: 312 { 313 if (!strcmp(name, "MediaCodec")) { 314 mCurrentSection = SECTION_ENCODERS; 315 } 316 break; 317 } 318 319 case SECTION_INCLUDE: 320 { 321 if (!strcmp(name, "Include") && mPastSections.size() > 0) { 322 mCurrentSection = mPastSections.top(); 323 mPastSections.pop(); 324 } 325 break; 326 } 327 328 default: 329 break; 330 } 331 332 --mDepth; 333} 334 335status_t MediaCodecList::addMediaCodecFromAttributes( 336 bool encoder, const char **attrs) { 337 const char *name = NULL; 338 const char *type = NULL; 339 340 size_t i = 0; 341 while (attrs[i] != NULL) { 342 if (!strcmp(attrs[i], "name")) { 343 if (attrs[i + 1] == NULL) { 344 return -EINVAL; 345 } 346 name = attrs[i + 1]; 347 ++i; 348 } else if (!strcmp(attrs[i], "type")) { 349 if (attrs[i + 1] == NULL) { 350 return -EINVAL; 351 } 352 type = attrs[i + 1]; 353 ++i; 354 } else { 355 return -EINVAL; 356 } 357 358 ++i; 359 } 360 361 if (name == NULL) { 362 return -EINVAL; 363 } 364 365 addMediaCodec(encoder, name, type); 366 367 return OK; 368} 369 370void MediaCodecList::addMediaCodec( 371 bool encoder, const char *name, const char *type) { 372 mCodecInfos.push(); 373 CodecInfo *info = &mCodecInfos.editItemAt(mCodecInfos.size() - 1); 374 info->mName = name; 375 info->mIsEncoder = encoder; 376 info->mTypes = 0; 377 info->mQuirks = 0; 378 379 if (type != NULL) { 380 addType(type); 381 } 382} 383 384status_t MediaCodecList::addQuirk(const char **attrs) { 385 const char *name = NULL; 386 387 size_t i = 0; 388 while (attrs[i] != NULL) { 389 if (!strcmp(attrs[i], "name")) { 390 if (attrs[i + 1] == NULL) { 391 return -EINVAL; 392 } 393 name = attrs[i + 1]; 394 ++i; 395 } else { 396 return -EINVAL; 397 } 398 399 ++i; 400 } 401 402 if (name == NULL) { 403 return -EINVAL; 404 } 405 406 uint32_t bit; 407 ssize_t index = mCodecQuirks.indexOfKey(name); 408 if (index < 0) { 409 bit = mCodecQuirks.size(); 410 411 if (bit == 32) { 412 ALOGW("Too many distinct quirk names in configuration."); 413 return OK; 414 } 415 416 mCodecQuirks.add(name, bit); 417 } else { 418 bit = mCodecQuirks.valueAt(index); 419 } 420 421 CodecInfo *info = &mCodecInfos.editItemAt(mCodecInfos.size() - 1); 422 info->mQuirks |= 1ul << bit; 423 424 return OK; 425} 426 427status_t MediaCodecList::addTypeFromAttributes(const char **attrs) { 428 const char *name = NULL; 429 430 size_t i = 0; 431 while (attrs[i] != NULL) { 432 if (!strcmp(attrs[i], "name")) { 433 if (attrs[i + 1] == NULL) { 434 return -EINVAL; 435 } 436 name = attrs[i + 1]; 437 ++i; 438 } else { 439 return -EINVAL; 440 } 441 442 ++i; 443 } 444 445 if (name == NULL) { 446 return -EINVAL; 447 } 448 449 addType(name); 450 451 return OK; 452} 453 454void MediaCodecList::addType(const char *name) { 455 uint32_t bit; 456 ssize_t index = mTypes.indexOfKey(name); 457 if (index < 0) { 458 bit = mTypes.size(); 459 460 if (bit == 32) { 461 ALOGW("Too many distinct type names in configuration."); 462 return; 463 } 464 465 mTypes.add(name, bit); 466 } else { 467 bit = mTypes.valueAt(index); 468 } 469 470 CodecInfo *info = &mCodecInfos.editItemAt(mCodecInfos.size() - 1); 471 info->mTypes |= 1ul << bit; 472} 473 474ssize_t MediaCodecList::findCodecByType( 475 const char *type, bool encoder, size_t startIndex) const { 476 ssize_t typeIndex = mTypes.indexOfKey(type); 477 478 if (typeIndex < 0) { 479 return -ENOENT; 480 } 481 482 uint32_t typeMask = 1ul << mTypes.valueAt(typeIndex); 483 484 while (startIndex < mCodecInfos.size()) { 485 const CodecInfo &info = mCodecInfos.itemAt(startIndex); 486 487 if (info.mIsEncoder == encoder && (info.mTypes & typeMask)) { 488 return startIndex; 489 } 490 491 ++startIndex; 492 } 493 494 return -ENOENT; 495} 496 497ssize_t MediaCodecList::findCodecByName(const char *name) const { 498 for (size_t i = 0; i < mCodecInfos.size(); ++i) { 499 const CodecInfo &info = mCodecInfos.itemAt(i); 500 501 if (info.mName == name) { 502 return i; 503 } 504 } 505 506 return -ENOENT; 507} 508 509size_t MediaCodecList::countCodecs() const { 510 return mCodecInfos.size(); 511} 512 513const char *MediaCodecList::getCodecName(size_t index) const { 514 if (index >= mCodecInfos.size()) { 515 return NULL; 516 } 517 518 const CodecInfo &info = mCodecInfos.itemAt(index); 519 return info.mName.c_str(); 520} 521 522bool MediaCodecList::isEncoder(size_t index) const { 523 if (index >= mCodecInfos.size()) { 524 return NULL; 525 } 526 527 const CodecInfo &info = mCodecInfos.itemAt(index); 528 return info.mIsEncoder; 529} 530 531bool MediaCodecList::codecHasQuirk( 532 size_t index, const char *quirkName) const { 533 if (index >= mCodecInfos.size()) { 534 return NULL; 535 } 536 537 const CodecInfo &info = mCodecInfos.itemAt(index); 538 539 if (info.mQuirks != 0) { 540 ssize_t index = mCodecQuirks.indexOfKey(quirkName); 541 if (index >= 0 && info.mQuirks & (1ul << mCodecQuirks.valueAt(index))) { 542 return true; 543 } 544 } 545 546 return false; 547} 548 549status_t MediaCodecList::getSupportedTypes( 550 size_t index, Vector<AString> *types) const { 551 types->clear(); 552 553 if (index >= mCodecInfos.size()) { 554 return -ERANGE; 555 } 556 557 const CodecInfo &info = mCodecInfos.itemAt(index); 558 559 for (size_t i = 0; i < mTypes.size(); ++i) { 560 uint32_t typeMask = 1ul << mTypes.valueAt(i); 561 562 if (info.mTypes & typeMask) { 563 types->push(mTypes.keyAt(i)); 564 } 565 } 566 567 return OK; 568} 569 570status_t MediaCodecList::getCodecCapabilities( 571 size_t index, const char *type, 572 Vector<ProfileLevel> *profileLevels, 573 Vector<uint32_t> *colorFormats, 574 uint32_t *flags) const { 575 profileLevels->clear(); 576 colorFormats->clear(); 577 578 if (index >= mCodecInfos.size()) { 579 return -ERANGE; 580 } 581 582 const CodecInfo &info = mCodecInfos.itemAt(index); 583 584 OMXClient client; 585 status_t err = client.connect(); 586 if (err != OK) { 587 return err; 588 } 589 590 CodecCapabilities caps; 591 err = QueryCodec( 592 client.interface(), 593 info.mName.c_str(), type, info.mIsEncoder, &caps); 594 595 if (err != OK) { 596 return err; 597 } 598 599 for (size_t i = 0; i < caps.mProfileLevels.size(); ++i) { 600 const CodecProfileLevel &src = caps.mProfileLevels.itemAt(i); 601 602 ProfileLevel profileLevel; 603 profileLevel.mProfile = src.mProfile; 604 profileLevel.mLevel = src.mLevel; 605 profileLevels->push(profileLevel); 606 } 607 608 for (size_t i = 0; i < caps.mColorFormats.size(); ++i) { 609 colorFormats->push(caps.mColorFormats.itemAt(i)); 610 } 611 612 *flags = caps.mFlags; 613 614 return OK; 615} 616 617} // namespace android 618