Home | History | Annotate | Download | only in libstagefright
      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