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