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