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