blob: 6b64e21c6cd67e8930e9b951e631c99d4f952f5c [file] [log] [blame]
Andreas Huber3d3864f2012-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>
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
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
448const char *MediaCodecList::getCodecName(size_t index) const {
449 if (index >= mCodecInfos.size()) {
450 return NULL;
451 }
452
453 const CodecInfo &info = mCodecInfos.itemAt(index);
454 return info.mName.c_str();
455}
456
457bool MediaCodecList::codecHasQuirk(
458 size_t index, const char *quirkName) const {
459 if (index >= mCodecInfos.size()) {
460 return NULL;
461 }
462
463 const CodecInfo &info = mCodecInfos.itemAt(index);
464
465 if (info.mQuirks != 0) {
466 ssize_t index = mCodecQuirks.indexOfKey(quirkName);
467 if (index >= 0 && info.mQuirks & (1ul << mCodecQuirks.valueAt(index))) {
468 return true;
469 }
470 }
471
472 return false;
473}
474
475} // namespace android