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