blob: d24337f2dd959257473392c630c278830e741b89 [file] [log] [blame]
Andreas Huberafc16d62012-02-29 15:47:17 -08001/*
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>
Andreas Huber69829f32012-03-30 13:02:09 -070025#include <media/stagefright/OMXClient.h>
26#include <media/stagefright/OMXCodec.h>
Andreas Huberafc16d62012-02-29 15:47:17 -080027#include <utils/threads.h>
28
Elliott Hughese8057dd2012-09-09 14:58:14 -070029#include <libexpat/expat.h>
Andreas Huberafc16d62012-02-29 15:47:17 -080030
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 (mInitCheck == OK) {
61 // These are currently still used by the video editing suite.
62
63 addMediaCodec(true /* encoder */, "AACEncoder", "audio/mp4a-latm");
Andreas Huberecdd39c2012-03-29 11:31:12 -070064
65 addMediaCodec(
66 false /* encoder */, "OMX.google.raw.decoder", "audio/raw");
Andreas Huberafc16d62012-02-29 15:47:17 -080067 }
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
92MediaCodecList::~MediaCodecList() {
93}
94
95status_t MediaCodecList::initCheck() const {
96 return mInitCheck;
97}
98
99void 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
162void MediaCodecList::StartElementHandlerWrapper(
163 void *me, const char *name, const char **attrs) {
164 static_cast<MediaCodecList *>(me)->startElementHandler(name, attrs);
165}
166
167// static
168void MediaCodecList::EndElementHandlerWrapper(void *me, const char *name) {
169 static_cast<MediaCodecList *>(me)->endElementHandler(name);
170}
171
172void 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
229void 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
274status_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
309void 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
323status_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
366status_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
393void 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
413ssize_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
436ssize_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
Andreas Huber69829f32012-03-30 13:02:09 -0700448size_t MediaCodecList::countCodecs() const {
449 return mCodecInfos.size();
450}
451
Andreas Huberafc16d62012-02-29 15:47:17 -0800452const 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
Andreas Huber69829f32012-03-30 13:02:09 -0700461bool 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
Andreas Huberafc16d62012-02-29 15:47:17 -0800470bool 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
Andreas Huber69829f32012-03-30 13:02:09 -0700488status_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
509status_t MediaCodecList::getCodecCapabilities(
510 size_t index, const char *type,
511 Vector<ProfileLevel> *profileLevels,
512 Vector<uint32_t> *colorFormats) const {
513 profileLevels->clear();
514 colorFormats->clear();
515
516 if (index >= mCodecInfos.size()) {
517 return -ERANGE;
518 }
519
520 const CodecInfo &info = mCodecInfos.itemAt(index);
521
522 OMXClient client;
523 status_t err = client.connect();
524 if (err != OK) {
525 return err;
526 }
527
528 CodecCapabilities caps;
529 err = QueryCodec(
530 client.interface(),
531 info.mName.c_str(), type, info.mIsEncoder, &caps);
532
533 if (err != OK) {
534 return err;
535 }
536
537 for (size_t i = 0; i < caps.mProfileLevels.size(); ++i) {
538 const CodecProfileLevel &src = caps.mProfileLevels.itemAt(i);
539
540 ProfileLevel profileLevel;
541 profileLevel.mProfile = src.mProfile;
542 profileLevel.mLevel = src.mLevel;
543 profileLevels->push(profileLevel);
544 }
545
546 for (size_t i = 0; i < caps.mColorFormats.size(); ++i) {
547 colorFormats->push(caps.mColorFormats.itemAt(i));
548 }
549
550 return OK;
551}
552
Andreas Huberafc16d62012-02-29 15:47:17 -0800553} // namespace android