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