blob: eaad4fc06b1e128f02277f34525af22109112e4d [file] [log] [blame]
Andreas Huberbe06d262009-08-14 14:37:10 -07001/*
2 * Copyright (C) 2009 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 "OMXCodec"
19#include <utils/Log.h>
20
21#include <binder/IServiceManager.h>
22#include <binder/MemoryDealer.h>
23#include <binder/ProcessState.h>
24#include <media/IMediaPlayerService.h>
25#include <media/stagefright/ESDS.h>
26#include <media/stagefright/MediaBuffer.h>
27#include <media/stagefright/MediaBufferGroup.h>
28#include <media/stagefright/MediaDebug.h>
29#include <media/stagefright/MediaExtractor.h>
30#include <media/stagefright/MetaData.h>
31#include <media/stagefright/MmapSource.h>
32#include <media/stagefright/OMXCodec.h>
Andreas Huberebf66ea2009-08-19 13:32:58 -070033#include <media/stagefright/Utils.h>
Andreas Huberbe06d262009-08-14 14:37:10 -070034#include <utils/Vector.h>
35
36#include <OMX_Audio.h>
37#include <OMX_Component.h>
38
39namespace android {
40
41struct CodecInfo {
42 const char *mime;
43 const char *codec;
44};
45
46static const CodecInfo kDecoderInfo[] = {
47 { "image/jpeg", "OMX.TI.JPEG.decode" },
48 { "audio/mpeg", "OMX.TI.MP3.decode" },
49 { "audio/mpeg", "OMX.PV.mp3dec" },
50 { "audio/3gpp", "OMX.TI.AMR.decode" },
51 { "audio/3gpp", "OMX.PV.amrdec" },
52 { "audio/mp4a-latm", "OMX.TI.AAC.decode" },
53 { "audio/mp4a-latm", "OMX.PV.aacdec" },
54 { "video/mp4v-es", "OMX.qcom.video.decoder.mpeg4" },
55 { "video/mp4v-es", "OMX.TI.Video.Decoder" },
56 { "video/mp4v-es", "OMX.PV.mpeg4dec" },
57 { "video/3gpp", "OMX.qcom.video.decoder.h263" },
58 { "video/3gpp", "OMX.TI.Video.Decoder" },
59 { "video/3gpp", "OMX.PV.h263dec" },
60 { "video/avc", "OMX.qcom.video.decoder.avc" },
61 { "video/avc", "OMX.TI.Video.Decoder" },
62 { "video/avc", "OMX.PV.avcdec" },
63};
64
65static const CodecInfo kEncoderInfo[] = {
66 { "audio/3gpp", "OMX.TI.AMR.encode" },
67 { "audio/3gpp", "OMX.PV.amrencnb" },
68 { "audio/mp4a-latm", "OMX.TI.AAC.encode" },
69 { "audio/mp4a-latm", "OMX.PV.aacenc" },
70 { "video/mp4v-es", "OMX.qcom.video.encoder.mpeg4" },
71 { "video/mp4v-es", "OMX.TI.Video.encoder" },
72 { "video/mp4v-es", "OMX.PV.mpeg4enc" },
73 { "video/3gpp", "OMX.qcom.video.encoder.h263" },
74 { "video/3gpp", "OMX.TI.Video.encoder" },
75 { "video/3gpp", "OMX.PV.h263enc" },
76 { "video/avc", "OMX.TI.Video.encoder" },
77 { "video/avc", "OMX.PV.avcenc" },
78};
79
80struct OMXCodecObserver : public BnOMXObserver {
81 OMXCodecObserver(const wp<OMXCodec> &target)
82 : mTarget(target) {
83 }
84
85 // from IOMXObserver
86 virtual void on_message(const omx_message &msg) {
87 sp<OMXCodec> codec = mTarget.promote();
88
89 if (codec.get() != NULL) {
90 codec->on_message(msg);
91 }
92 }
93
94protected:
95 virtual ~OMXCodecObserver() {}
96
97private:
98 wp<OMXCodec> mTarget;
99
100 OMXCodecObserver(const OMXCodecObserver &);
101 OMXCodecObserver &operator=(const OMXCodecObserver &);
102};
103
104static const char *GetCodec(const CodecInfo *info, size_t numInfos,
105 const char *mime, int index) {
106 CHECK(index >= 0);
107 for(size_t i = 0; i < numInfos; ++i) {
108 if (!strcasecmp(mime, info[i].mime)) {
109 if (index == 0) {
110 return info[i].codec;
111 }
112
113 --index;
114 }
115 }
116
117 return NULL;
118}
119
Andreas Huberebf66ea2009-08-19 13:32:58 -0700120enum {
121 kAVCProfileBaseline = 0x42,
122 kAVCProfileMain = 0x4d,
123 kAVCProfileExtended = 0x58,
124 kAVCProfileHigh = 0x64,
125 kAVCProfileHigh10 = 0x6e,
126 kAVCProfileHigh422 = 0x7a,
127 kAVCProfileHigh444 = 0xf4,
128 kAVCProfileCAVLC444Intra = 0x2c
129};
130
131static const char *AVCProfileToString(uint8_t profile) {
132 switch (profile) {
133 case kAVCProfileBaseline:
134 return "Baseline";
135 case kAVCProfileMain:
136 return "Main";
137 case kAVCProfileExtended:
138 return "Extended";
139 case kAVCProfileHigh:
140 return "High";
141 case kAVCProfileHigh10:
142 return "High 10";
143 case kAVCProfileHigh422:
144 return "High 422";
145 case kAVCProfileHigh444:
146 return "High 444";
147 case kAVCProfileCAVLC444Intra:
148 return "CAVLC 444 Intra";
149 default: return "Unknown";
150 }
151}
152
Andreas Huberbe06d262009-08-14 14:37:10 -0700153// static
154sp<OMXCodec> OMXCodec::Create(
155 const sp<IOMX> &omx,
156 const sp<MetaData> &meta, bool createEncoder,
157 const sp<MediaSource> &source) {
158 const char *mime;
159 bool success = meta->findCString(kKeyMIMEType, &mime);
160 CHECK(success);
161
162 const char *componentName = NULL;
163 IOMX::node_id node = 0;
164 for (int index = 0;; ++index) {
165 if (createEncoder) {
166 componentName = GetCodec(
167 kEncoderInfo, sizeof(kEncoderInfo) / sizeof(kEncoderInfo[0]),
168 mime, index);
169 } else {
170 componentName = GetCodec(
171 kDecoderInfo, sizeof(kDecoderInfo) / sizeof(kDecoderInfo[0]),
172 mime, index);
173 }
174
175 if (!componentName) {
176 return NULL;
177 }
178
179 LOGV("Attempting to allocate OMX node '%s'", componentName);
180
181 status_t err = omx->allocate_node(componentName, &node);
182 if (err == OK) {
183 break;
184 }
185 }
186
187 uint32_t quirks = 0;
188 if (!strcmp(componentName, "OMX.PV.avcdec")) {
Andreas Huber4f5e6022009-08-19 09:29:34 -0700189 quirks |= kWantsNALFragments;
Andreas Huberbe06d262009-08-14 14:37:10 -0700190 }
191 if (!strcmp(componentName, "OMX.TI.MP3.decode")) {
192 quirks |= kNeedsFlushBeforeDisable;
193 }
194 if (!strcmp(componentName, "OMX.TI.AAC.decode")) {
195 quirks |= kNeedsFlushBeforeDisable;
Andreas Huber404cc412009-08-25 14:26:05 -0700196 quirks |= kRequiresFlushCompleteEmulation;
Andreas Huber127fcdc2009-08-26 16:27:02 -0700197
198 // The following is currently necessary for proper shutdown
199 // behaviour, but NOT enabled by default in order to make the
200 // bug reproducible...
201 // quirks |= kRequiresFlushBeforeShutdown;
Andreas Huberbe06d262009-08-14 14:37:10 -0700202 }
203 if (!strncmp(componentName, "OMX.qcom.video.encoder.", 23)) {
204 quirks |= kRequiresLoadedToIdleAfterAllocation;
205 quirks |= kRequiresAllocateBufferOnInputPorts;
206 }
207
208 sp<OMXCodec> codec = new OMXCodec(
209 omx, node, quirks, createEncoder, mime, componentName,
210 source);
211
212 uint32_t type;
213 const void *data;
214 size_t size;
215 if (meta->findData(kKeyESDS, &type, &data, &size)) {
216 ESDS esds((const char *)data, size);
217 CHECK_EQ(esds.InitCheck(), OK);
218
219 const void *codec_specific_data;
220 size_t codec_specific_data_size;
221 esds.getCodecSpecificInfo(
222 &codec_specific_data, &codec_specific_data_size);
223
224 printf("found codec-specific data of size %d\n",
225 codec_specific_data_size);
226
227 codec->addCodecSpecificData(
228 codec_specific_data, codec_specific_data_size);
229 } else if (meta->findData(kKeyAVCC, &type, &data, &size)) {
230 printf("found avcc of size %d\n", size);
231
Andreas Huberebf66ea2009-08-19 13:32:58 -0700232 // Parse the AVCDecoderConfigurationRecord
233
234 const uint8_t *ptr = (const uint8_t *)data;
235
236 CHECK(size >= 7);
237 CHECK_EQ(ptr[0], 1); // configurationVersion == 1
238 uint8_t profile = ptr[1];
239 uint8_t level = ptr[3];
240
241 CHECK((ptr[4] >> 2) == 0x3f); // reserved
242
243 size_t lengthSize = 1 + (ptr[4] & 3);
244
245 // commented out check below as H264_QVGA_500_NO_AUDIO.3gp
246 // violates it...
247 // CHECK((ptr[5] >> 5) == 7); // reserved
248
249 size_t numSeqParameterSets = ptr[5] & 31;
250
251 ptr += 6;
Andreas Huberbe06d262009-08-14 14:37:10 -0700252 size -= 6;
Andreas Huberebf66ea2009-08-19 13:32:58 -0700253
254 for (size_t i = 0; i < numSeqParameterSets; ++i) {
255 CHECK(size >= 2);
256 size_t length = U16_AT(ptr);
Andreas Huberbe06d262009-08-14 14:37:10 -0700257
258 ptr += 2;
259 size -= 2;
260
Andreas Huberbe06d262009-08-14 14:37:10 -0700261 CHECK(size >= length);
262
263 codec->addCodecSpecificData(ptr, length);
264
265 ptr += length;
266 size -= length;
Andreas Huberebf66ea2009-08-19 13:32:58 -0700267 }
Andreas Huberbe06d262009-08-14 14:37:10 -0700268
Andreas Huberebf66ea2009-08-19 13:32:58 -0700269 CHECK(size >= 1);
270 size_t numPictureParameterSets = *ptr;
271 ++ptr;
272 --size;
Andreas Huberbe06d262009-08-14 14:37:10 -0700273
Andreas Huberebf66ea2009-08-19 13:32:58 -0700274 for (size_t i = 0; i < numPictureParameterSets; ++i) {
275 CHECK(size >= 2);
276 size_t length = U16_AT(ptr);
277
278 ptr += 2;
279 size -= 2;
280
281 CHECK(size >= length);
282
283 codec->addCodecSpecificData(ptr, length);
284
285 ptr += length;
286 size -= length;
287 }
288
289 LOGI("AVC profile = %d (%s), level = %d",
290 (int)profile, AVCProfileToString(profile), (int)level / 10);
291
292 if (!strcmp(componentName, "OMX.TI.Video.Decoder")
293 && (profile != kAVCProfileBaseline || level > 39)) {
294 // This stream exceeds the decoder's capabilities.
295
296 LOGE("Profile and/or level exceed the decoder's capabilities.");
297 return NULL;
Andreas Huberbe06d262009-08-14 14:37:10 -0700298 }
299 }
300
301 if (!strcasecmp("audio/3gpp", mime)) {
302 codec->setAMRFormat();
303 }
304 if (!createEncoder && !strcasecmp("audio/mp4a-latm", mime)) {
305 codec->setAACFormat();
306 }
307 if (!strncasecmp(mime, "video/", 6)) {
308 int32_t width, height;
309 bool success = meta->findInt32(kKeyWidth, &width);
310 success = success && meta->findInt32(kKeyHeight, &height);
Andreas Huber5c0a9132009-08-20 11:16:40 -0700311 CHECK(success);
Andreas Huberbe06d262009-08-14 14:37:10 -0700312
313 if (createEncoder) {
314 codec->setVideoInputFormat(mime, width, height);
315 } else {
316 codec->setVideoOutputFormat(mime, width, height);
317 }
318 }
319 if (!strcasecmp(mime, "image/jpeg")
320 && !strcmp(componentName, "OMX.TI.JPEG.decode")) {
321 OMX_COLOR_FORMATTYPE format =
322 OMX_COLOR_Format32bitARGB8888;
323 // OMX_COLOR_FormatYUV420PackedPlanar;
324 // OMX_COLOR_FormatCbYCrY;
325 // OMX_COLOR_FormatYUV411Planar;
326
327 int32_t width, height;
328 bool success = meta->findInt32(kKeyWidth, &width);
329 success = success && meta->findInt32(kKeyHeight, &height);
Andreas Huber5c0a9132009-08-20 11:16:40 -0700330
331 int32_t compressedSize;
332 success = success && meta->findInt32(
333 kKeyCompressedSize, &compressedSize);
334
335 CHECK(success);
336 CHECK(compressedSize > 0);
Andreas Huberbe06d262009-08-14 14:37:10 -0700337
338 codec->setImageOutputFormat(format, width, height);
Andreas Huber5c0a9132009-08-20 11:16:40 -0700339 codec->setJPEGInputFormat(width, height, (OMX_U32)compressedSize);
Andreas Huberbe06d262009-08-14 14:37:10 -0700340 }
341
342 codec->initOutputFormat(meta);
343
344 return codec;
345}
346
347status_t OMXCodec::setVideoPortFormatType(
348 OMX_U32 portIndex,
349 OMX_VIDEO_CODINGTYPE compressionFormat,
350 OMX_COLOR_FORMATTYPE colorFormat) {
351 OMX_VIDEO_PARAM_PORTFORMATTYPE format;
352 format.nSize = sizeof(format);
353 format.nVersion.s.nVersionMajor = 1;
354 format.nVersion.s.nVersionMinor = 1;
355 format.nPortIndex = portIndex;
356 format.nIndex = 0;
357 bool found = false;
358
359 OMX_U32 index = 0;
360 for (;;) {
361 format.nIndex = index;
362 status_t err = mOMX->get_parameter(
363 mNode, OMX_IndexParamVideoPortFormat,
364 &format, sizeof(format));
365
366 if (err != OK) {
367 return err;
368 }
369
370 // The following assertion is violated by TI's video decoder.
Andreas Huber5c0a9132009-08-20 11:16:40 -0700371 // CHECK_EQ(format.nIndex, index);
Andreas Huberbe06d262009-08-14 14:37:10 -0700372
373#if 1
374 LOGI("portIndex: %ld, index: %ld, eCompressionFormat=%d eColorFormat=%d",
375 portIndex,
376 index, format.eCompressionFormat, format.eColorFormat);
377#endif
378
379 if (!strcmp("OMX.TI.Video.encoder", mComponentName)) {
380 if (portIndex == kPortIndexInput
381 && colorFormat == format.eColorFormat) {
382 // eCompressionFormat does not seem right.
383 found = true;
384 break;
385 }
386 if (portIndex == kPortIndexOutput
387 && compressionFormat == format.eCompressionFormat) {
388 // eColorFormat does not seem right.
389 found = true;
390 break;
391 }
392 }
393
394 if (format.eCompressionFormat == compressionFormat
395 && format.eColorFormat == colorFormat) {
396 found = true;
397 break;
398 }
399
400 ++index;
401 }
402
403 if (!found) {
404 return UNKNOWN_ERROR;
405 }
406
407 LOGI("found a match.");
408 status_t err = mOMX->set_parameter(
409 mNode, OMX_IndexParamVideoPortFormat,
410 &format, sizeof(format));
411
412 return err;
413}
414
415void OMXCodec::setVideoInputFormat(
416 const char *mime, OMX_U32 width, OMX_U32 height) {
417 LOGI("setVideoInputFormat width=%ld, height=%ld", width, height);
418
419 OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused;
420 if (!strcasecmp("video/avc", mime)) {
421 compressionFormat = OMX_VIDEO_CodingAVC;
422 } else if (!strcasecmp("video/mp4v-es", mime)) {
423 compressionFormat = OMX_VIDEO_CodingMPEG4;
424 } else if (!strcasecmp("video/3gpp", mime)) {
425 compressionFormat = OMX_VIDEO_CodingH263;
426 } else {
427 LOGE("Not a supported video mime type: %s", mime);
428 CHECK(!"Should not be here. Not a supported video mime type.");
429 }
430
431 OMX_COLOR_FORMATTYPE colorFormat =
432 0 ? OMX_COLOR_FormatYCbYCr : OMX_COLOR_FormatCbYCrY;
433
434 if (!strncmp("OMX.qcom.video.encoder.", mComponentName, 23)) {
435 colorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
436 }
437
438 setVideoPortFormatType(
439 kPortIndexInput, OMX_VIDEO_CodingUnused,
440 colorFormat);
441
442 setVideoPortFormatType(
443 kPortIndexOutput, compressionFormat, OMX_COLOR_FormatUnused);
444
445 OMX_PARAM_PORTDEFINITIONTYPE def;
446 OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
447
448 def.nSize = sizeof(def);
449 def.nVersion.s.nVersionMajor = 1;
450 def.nVersion.s.nVersionMinor = 1;
451 def.nPortIndex = kPortIndexOutput;
452
453 status_t err = mOMX->get_parameter(
454 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
455
456 CHECK_EQ(err, OK);
457 CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
458
459 video_def->nFrameWidth = width;
460 video_def->nFrameHeight = height;
461
462 video_def->eCompressionFormat = compressionFormat;
463 video_def->eColorFormat = OMX_COLOR_FormatUnused;
464
465 err = mOMX->set_parameter(
466 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
467 CHECK_EQ(err, OK);
468
469 ////////////////////////////////////////////////////////////////////////////
470
471 def.nSize = sizeof(def);
472 def.nVersion.s.nVersionMajor = 1;
473 def.nVersion.s.nVersionMinor = 1;
474 def.nPortIndex = kPortIndexInput;
475
476 err = mOMX->get_parameter(
477 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
478 CHECK_EQ(err, OK);
479
480 def.nBufferSize = (width * height * 2); // (width * height * 3) / 2;
481 LOGI("setting nBufferSize = %ld", def.nBufferSize);
482
483 CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
484
485 video_def->nFrameWidth = width;
486 video_def->nFrameHeight = height;
487 video_def->eCompressionFormat = OMX_VIDEO_CodingUnused;
488 video_def->eColorFormat = colorFormat;
489
490 err = mOMX->set_parameter(
491 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
492 CHECK_EQ(err, OK);
493}
494
495void OMXCodec::setVideoOutputFormat(
496 const char *mime, OMX_U32 width, OMX_U32 height) {
497 LOGI("setVideoOutputFormat width=%ld, height=%ld", width, height);
498
499 // Enabling this code appears to be the right thing(tm), but,...
500 // the TI decoder then loses the ability to output YUV420 and only outputs
501 // YCbYCr (16bit)
Andreas Huber813a8752009-08-27 15:28:12 -0700502
Andreas Huberb5ceb9e2009-08-26 14:48:20 -0700503#if 1
Andreas Huber813a8752009-08-27 15:28:12 -0700504 if (!strcmp("OMX.TI.Video.Decoder", mComponentName)) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700505 OMX_PARAM_COMPONENTROLETYPE role;
506 role.nSize = sizeof(role);
507 role.nVersion.s.nVersionMajor = 1;
508 role.nVersion.s.nVersionMinor = 1;
Andreas Huber813a8752009-08-27 15:28:12 -0700509
510 if (!strcasecmp("video/avc", mime)) {
511 strncpy((char *)role.cRole, "video_decoder.avc",
512 OMX_MAX_STRINGNAME_SIZE - 1);
513 } else if (!strcasecmp("video/mp4v-es", mime)) {
514 strncpy((char *)role.cRole, "video_decoder.mpeg4",
515 OMX_MAX_STRINGNAME_SIZE - 1);
516 } else if (!strcasecmp("video/3gpp", mime)) {
517 strncpy((char *)role.cRole, "video_decoder.h263",
518 OMX_MAX_STRINGNAME_SIZE - 1);
519 }
520
Andreas Huberbe06d262009-08-14 14:37:10 -0700521 role.cRole[OMX_MAX_STRINGNAME_SIZE - 1] = '\0';
522
523 status_t err = mOMX->set_parameter(
524 mNode, OMX_IndexParamStandardComponentRole,
525 &role, sizeof(role));
526 CHECK_EQ(err, OK);
527 }
Andreas Huberb5ceb9e2009-08-26 14:48:20 -0700528#endif
Andreas Huberbe06d262009-08-14 14:37:10 -0700529
530 OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused;
531 if (!strcasecmp("video/avc", mime)) {
532 compressionFormat = OMX_VIDEO_CodingAVC;
533 } else if (!strcasecmp("video/mp4v-es", mime)) {
534 compressionFormat = OMX_VIDEO_CodingMPEG4;
535 } else if (!strcasecmp("video/3gpp", mime)) {
536 compressionFormat = OMX_VIDEO_CodingH263;
537 } else {
538 LOGE("Not a supported video mime type: %s", mime);
539 CHECK(!"Should not be here. Not a supported video mime type.");
540 }
541
542 setVideoPortFormatType(
543 kPortIndexInput, compressionFormat, OMX_COLOR_FormatUnused);
544
545#if 1
546 {
547 OMX_VIDEO_PARAM_PORTFORMATTYPE format;
548 format.nSize = sizeof(format);
549 format.nVersion.s.nVersionMajor = 1;
550 format.nVersion.s.nVersionMinor = 1;
551 format.nPortIndex = kPortIndexOutput;
552 format.nIndex = 0;
553
554 status_t err = mOMX->get_parameter(
555 mNode, OMX_IndexParamVideoPortFormat,
556 &format, sizeof(format));
557 CHECK_EQ(err, OK);
558 CHECK_EQ(format.eCompressionFormat, OMX_VIDEO_CodingUnused);
559
560 static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
561
562 CHECK(format.eColorFormat == OMX_COLOR_FormatYUV420Planar
563 || format.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar
564 || format.eColorFormat == OMX_COLOR_FormatCbYCrY
565 || format.eColorFormat == OMX_QCOM_COLOR_FormatYVU420SemiPlanar);
566
567 err = mOMX->set_parameter(
568 mNode, OMX_IndexParamVideoPortFormat,
569 &format, sizeof(format));
570 CHECK_EQ(err, OK);
571 }
572#endif
573
574 OMX_PARAM_PORTDEFINITIONTYPE def;
575 OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
576
577 def.nSize = sizeof(def);
578 def.nVersion.s.nVersionMajor = 1;
579 def.nVersion.s.nVersionMinor = 1;
580 def.nPortIndex = kPortIndexInput;
581
582 status_t err = mOMX->get_parameter(
583 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
584
585 CHECK_EQ(err, OK);
586
587#if 1
588 // XXX Need a (much) better heuristic to compute input buffer sizes.
589 const size_t X = 64 * 1024;
590 if (def.nBufferSize < X) {
591 def.nBufferSize = X;
592 }
593#endif
594
595 CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
596
597 video_def->nFrameWidth = width;
598 video_def->nFrameHeight = height;
599
600 video_def->eColorFormat = OMX_COLOR_FormatUnused;
601
602 err = mOMX->set_parameter(
603 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
604 CHECK_EQ(err, OK);
605
606 ////////////////////////////////////////////////////////////////////////////
607
608 def.nSize = sizeof(def);
609 def.nVersion.s.nVersionMajor = 1;
610 def.nVersion.s.nVersionMinor = 1;
611 def.nPortIndex = kPortIndexOutput;
612
613 err = mOMX->get_parameter(
614 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
615 CHECK_EQ(err, OK);
616 CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
617
618#if 0
619 def.nBufferSize =
620 (((width + 15) & -16) * ((height + 15) & -16) * 3) / 2; // YUV420
621#endif
622
623 video_def->nFrameWidth = width;
624 video_def->nFrameHeight = height;
625
626 err = mOMX->set_parameter(
627 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
628 CHECK_EQ(err, OK);
629}
630
631
632OMXCodec::OMXCodec(
633 const sp<IOMX> &omx, IOMX::node_id node, uint32_t quirks,
Andreas Huberebf66ea2009-08-19 13:32:58 -0700634 bool isEncoder,
Andreas Huberbe06d262009-08-14 14:37:10 -0700635 const char *mime,
636 const char *componentName,
637 const sp<MediaSource> &source)
638 : mOMX(omx),
639 mNode(node),
640 mQuirks(quirks),
641 mIsEncoder(isEncoder),
642 mMIME(strdup(mime)),
643 mComponentName(strdup(componentName)),
644 mSource(source),
645 mCodecSpecificDataIndex(0),
Andreas Huberbe06d262009-08-14 14:37:10 -0700646 mState(LOADED),
Andreas Huber42978e52009-08-27 10:08:39 -0700647 mInitialBufferSubmit(true),
Andreas Huberbe06d262009-08-14 14:37:10 -0700648 mSignalledEOS(false),
649 mNoMoreOutputData(false),
650 mSeekTimeUs(-1) {
651 mPortStatus[kPortIndexInput] = ENABLED;
652 mPortStatus[kPortIndexOutput] = ENABLED;
653
654 mObserver = new OMXCodecObserver(this);
655 mOMX->observe_node(mNode, mObserver);
656}
657
658OMXCodec::~OMXCodec() {
Andreas Huber4f5e6022009-08-19 09:29:34 -0700659 CHECK(mState == LOADED || mState == ERROR);
Andreas Huberbe06d262009-08-14 14:37:10 -0700660
661 status_t err = mOMX->observe_node(mNode, NULL);
662 CHECK_EQ(err, OK);
663
664 err = mOMX->free_node(mNode);
665 CHECK_EQ(err, OK);
666
667 mNode = NULL;
668 setState(DEAD);
669
670 clearCodecSpecificData();
671
672 free(mComponentName);
673 mComponentName = NULL;
Andreas Huberebf66ea2009-08-19 13:32:58 -0700674
Andreas Huberbe06d262009-08-14 14:37:10 -0700675 free(mMIME);
676 mMIME = NULL;
677}
678
679status_t OMXCodec::init() {
Andreas Huber42978e52009-08-27 10:08:39 -0700680 // mLock is held.
Andreas Huberbe06d262009-08-14 14:37:10 -0700681
682 CHECK_EQ(mState, LOADED);
683
684 status_t err;
685 if (!(mQuirks & kRequiresLoadedToIdleAfterAllocation)) {
686 err = mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
687 CHECK_EQ(err, OK);
688
689 setState(LOADED_TO_IDLE);
690 }
691
692 err = allocateBuffers();
693 CHECK_EQ(err, OK);
694
695 if (mQuirks & kRequiresLoadedToIdleAfterAllocation) {
696 err = mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
697 CHECK_EQ(err, OK);
698
699 setState(LOADED_TO_IDLE);
700 }
701
702 while (mState != EXECUTING && mState != ERROR) {
703 mAsyncCompletion.wait(mLock);
704 }
705
706 return mState == ERROR ? UNKNOWN_ERROR : OK;
707}
708
709// static
710bool OMXCodec::isIntermediateState(State state) {
711 return state == LOADED_TO_IDLE
712 || state == IDLE_TO_EXECUTING
713 || state == EXECUTING_TO_IDLE
714 || state == IDLE_TO_LOADED
715 || state == RECONFIGURING;
716}
717
718status_t OMXCodec::allocateBuffers() {
719 status_t err = allocateBuffersOnPort(kPortIndexInput);
720
721 if (err != OK) {
722 return err;
723 }
724
725 return allocateBuffersOnPort(kPortIndexOutput);
726}
727
728status_t OMXCodec::allocateBuffersOnPort(OMX_U32 portIndex) {
729 OMX_PARAM_PORTDEFINITIONTYPE def;
730 def.nSize = sizeof(def);
731 def.nVersion.s.nVersionMajor = 1;
732 def.nVersion.s.nVersionMinor = 1;
733 def.nVersion.s.nRevision = 0;
734 def.nVersion.s.nStep = 0;
735 def.nPortIndex = portIndex;
736
737 status_t err = mOMX->get_parameter(
738 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
739
740 if (err != OK) {
741 return err;
742 }
743
Andreas Huber5c0a9132009-08-20 11:16:40 -0700744 size_t totalSize = def.nBufferCountActual * def.nBufferSize;
745 mDealer[portIndex] = new MemoryDealer(totalSize);
746
Andreas Huberbe06d262009-08-14 14:37:10 -0700747 for (OMX_U32 i = 0; i < def.nBufferCountActual; ++i) {
Andreas Huber5c0a9132009-08-20 11:16:40 -0700748 sp<IMemory> mem = mDealer[portIndex]->allocate(def.nBufferSize);
Andreas Huberbe06d262009-08-14 14:37:10 -0700749 CHECK(mem.get() != NULL);
750
751 IOMX::buffer_id buffer;
752 if (portIndex == kPortIndexInput
753 && (mQuirks & kRequiresAllocateBufferOnInputPorts)) {
754 err = mOMX->allocate_buffer_with_backup(
755 mNode, portIndex, mem, &buffer);
Andreas Huber446f44f2009-08-25 17:23:44 -0700756 } else if (portIndex == kPortIndexOutput
757 && (mQuirks & kRequiresAllocateBufferOnOutputPorts)) {
758 err = mOMX->allocate_buffer(
759 mNode, portIndex, def.nBufferSize, &buffer);
Andreas Huberbe06d262009-08-14 14:37:10 -0700760 } else {
761 err = mOMX->use_buffer(mNode, portIndex, mem, &buffer);
762 }
763
764 if (err != OK) {
765 LOGE("allocate_buffer_with_backup failed");
766 return err;
767 }
768
769 BufferInfo info;
770 info.mBuffer = buffer;
771 info.mOwnedByComponent = false;
772 info.mMem = mem;
773 info.mMediaBuffer = NULL;
774
775 if (portIndex == kPortIndexOutput) {
776 info.mMediaBuffer = new MediaBuffer(mem->pointer(), mem->size());
777 info.mMediaBuffer->setObserver(this);
778 }
779
780 mPortBuffers[portIndex].push(info);
781
782 LOGV("allocated buffer %p on %s port", buffer,
783 portIndex == kPortIndexInput ? "input" : "output");
784 }
785
786 dumpPortStatus(portIndex);
787
788 return OK;
789}
790
791void OMXCodec::on_message(const omx_message &msg) {
792 Mutex::Autolock autoLock(mLock);
793
794 switch (msg.type) {
795 case omx_message::EVENT:
796 {
797 onEvent(
798 msg.u.event_data.event, msg.u.event_data.data1,
799 msg.u.event_data.data2);
800
801 break;
802 }
803
804 case omx_message::EMPTY_BUFFER_DONE:
805 {
806 IOMX::buffer_id buffer = msg.u.extended_buffer_data.buffer;
807
808 LOGV("EMPTY_BUFFER_DONE(buffer: %p)", buffer);
809
810 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
811 size_t i = 0;
812 while (i < buffers->size() && (*buffers)[i].mBuffer != buffer) {
813 ++i;
814 }
815
816 CHECK(i < buffers->size());
817 if (!(*buffers)[i].mOwnedByComponent) {
818 LOGW("We already own input buffer %p, yet received "
819 "an EMPTY_BUFFER_DONE.", buffer);
820 }
821
822 buffers->editItemAt(i).mOwnedByComponent = false;
823
824 if (mPortStatus[kPortIndexInput] == DISABLING) {
825 LOGV("Port is disabled, freeing buffer %p", buffer);
826
827 status_t err =
828 mOMX->free_buffer(mNode, kPortIndexInput, buffer);
829 CHECK_EQ(err, OK);
830
831 buffers->removeAt(i);
832 } else if (mPortStatus[kPortIndexInput] != SHUTTING_DOWN) {
833 CHECK_EQ(mPortStatus[kPortIndexInput], ENABLED);
834 drainInputBuffer(&buffers->editItemAt(i));
835 }
836
837 break;
838 }
839
840 case omx_message::FILL_BUFFER_DONE:
841 {
842 IOMX::buffer_id buffer = msg.u.extended_buffer_data.buffer;
843 OMX_U32 flags = msg.u.extended_buffer_data.flags;
844
845 LOGV("FILL_BUFFER_DONE(buffer: %p, size: %ld, flags: 0x%08lx)",
846 buffer,
847 msg.u.extended_buffer_data.range_length,
848 flags);
849
850 LOGV("FILL_BUFFER_DONE(timestamp: %lld us (%.2f secs))",
851 msg.u.extended_buffer_data.timestamp,
852 msg.u.extended_buffer_data.timestamp / 1E6);
853
854 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
855 size_t i = 0;
856 while (i < buffers->size() && (*buffers)[i].mBuffer != buffer) {
857 ++i;
858 }
859
860 CHECK(i < buffers->size());
861 BufferInfo *info = &buffers->editItemAt(i);
862
863 if (!info->mOwnedByComponent) {
864 LOGW("We already own output buffer %p, yet received "
865 "a FILL_BUFFER_DONE.", buffer);
866 }
867
868 info->mOwnedByComponent = false;
869
870 if (mPortStatus[kPortIndexOutput] == DISABLING) {
871 LOGV("Port is disabled, freeing buffer %p", buffer);
872
873 status_t err =
874 mOMX->free_buffer(mNode, kPortIndexOutput, buffer);
875 CHECK_EQ(err, OK);
876
877 buffers->removeAt(i);
Andreas Huberd7795892009-08-26 10:33:47 -0700878 } else if (mPortStatus[kPortIndexOutput] == ENABLED
879 && (flags & OMX_BUFFERFLAG_EOS)) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700880 LOGV("No more output data.");
881 mNoMoreOutputData = true;
882 mBufferFilled.signal();
883 } else if (mPortStatus[kPortIndexOutput] != SHUTTING_DOWN) {
884 CHECK_EQ(mPortStatus[kPortIndexOutput], ENABLED);
Andreas Huberebf66ea2009-08-19 13:32:58 -0700885
Andreas Huberbe06d262009-08-14 14:37:10 -0700886 MediaBuffer *buffer = info->mMediaBuffer;
887
888 buffer->set_range(
889 msg.u.extended_buffer_data.range_offset,
890 msg.u.extended_buffer_data.range_length);
891
892 buffer->meta_data()->clear();
893
894 buffer->meta_data()->setInt32(
895 kKeyTimeUnits,
896 (msg.u.extended_buffer_data.timestamp + 500) / 1000);
897
898 buffer->meta_data()->setInt32(
899 kKeyTimeScale, 1000);
900
901 if (msg.u.extended_buffer_data.flags & OMX_BUFFERFLAG_SYNCFRAME) {
902 buffer->meta_data()->setInt32(kKeyIsSyncFrame, true);
903 }
904
905 buffer->meta_data()->setPointer(
906 kKeyPlatformPrivate,
907 msg.u.extended_buffer_data.platform_private);
908
909 buffer->meta_data()->setPointer(
910 kKeyBufferID,
911 msg.u.extended_buffer_data.buffer);
912
913 mFilledBuffers.push_back(i);
914 mBufferFilled.signal();
915 }
916
917 break;
918 }
919
920 default:
921 {
922 CHECK(!"should not be here.");
923 break;
924 }
925 }
926}
927
928void OMXCodec::onEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) {
929 switch (event) {
930 case OMX_EventCmdComplete:
931 {
932 onCmdComplete((OMX_COMMANDTYPE)data1, data2);
933 break;
934 }
935
936 case OMX_EventError:
937 {
938 LOGE("ERROR(%ld, %ld)", data1, data2);
939
940 setState(ERROR);
941 break;
942 }
943
944 case OMX_EventPortSettingsChanged:
945 {
946 onPortSettingsChanged(data1);
947 break;
948 }
949
950 case OMX_EventBufferFlag:
951 {
952 LOGV("EVENT_BUFFER_FLAG(%ld)", data1);
953
954 if (data1 == kPortIndexOutput) {
955 mNoMoreOutputData = true;
956 }
957 break;
958 }
959
960 default:
961 {
962 LOGV("EVENT(%d, %ld, %ld)", event, data1, data2);
963 break;
964 }
965 }
966}
967
968void OMXCodec::onCmdComplete(OMX_COMMANDTYPE cmd, OMX_U32 data) {
969 switch (cmd) {
970 case OMX_CommandStateSet:
971 {
972 onStateChange((OMX_STATETYPE)data);
973 break;
974 }
975
976 case OMX_CommandPortDisable:
977 {
978 OMX_U32 portIndex = data;
979 LOGV("PORT_DISABLED(%ld)", portIndex);
980
981 CHECK(mState == EXECUTING || mState == RECONFIGURING);
982 CHECK_EQ(mPortStatus[portIndex], DISABLING);
983 CHECK_EQ(mPortBuffers[portIndex].size(), 0);
984
985 mPortStatus[portIndex] = DISABLED;
986
987 if (mState == RECONFIGURING) {
988 CHECK_EQ(portIndex, kPortIndexOutput);
989
990 enablePortAsync(portIndex);
991
992 status_t err = allocateBuffersOnPort(portIndex);
993 CHECK_EQ(err, OK);
994 }
995 break;
996 }
997
998 case OMX_CommandPortEnable:
999 {
1000 OMX_U32 portIndex = data;
1001 LOGV("PORT_ENABLED(%ld)", portIndex);
1002
1003 CHECK(mState == EXECUTING || mState == RECONFIGURING);
1004 CHECK_EQ(mPortStatus[portIndex], ENABLING);
1005
1006 mPortStatus[portIndex] = ENABLED;
1007
1008 if (mState == RECONFIGURING) {
1009 CHECK_EQ(portIndex, kPortIndexOutput);
1010
1011 setState(EXECUTING);
1012
1013 fillOutputBuffers();
1014 }
1015 break;
1016 }
1017
1018 case OMX_CommandFlush:
1019 {
1020 OMX_U32 portIndex = data;
1021
1022 LOGV("FLUSH_DONE(%ld)", portIndex);
1023
1024 CHECK_EQ(mPortStatus[portIndex], SHUTTING_DOWN);
1025 mPortStatus[portIndex] = ENABLED;
1026
1027 CHECK_EQ(countBuffersWeOwn(mPortBuffers[portIndex]),
1028 mPortBuffers[portIndex].size());
1029
1030 if (mState == RECONFIGURING) {
1031 CHECK_EQ(portIndex, kPortIndexOutput);
1032
1033 disablePortAsync(portIndex);
Andreas Huber127fcdc2009-08-26 16:27:02 -07001034 } else if (mState == EXECUTING_TO_IDLE) {
1035 if (mPortStatus[kPortIndexInput] == ENABLED
1036 && mPortStatus[kPortIndexOutput] == ENABLED) {
1037 LOGV("Finished flushing both ports, now completing "
1038 "transition from EXECUTING to IDLE.");
1039
1040 mPortStatus[kPortIndexInput] = SHUTTING_DOWN;
1041 mPortStatus[kPortIndexOutput] = SHUTTING_DOWN;
1042
1043 status_t err =
1044 mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
1045 CHECK_EQ(err, OK);
1046 }
Andreas Huberbe06d262009-08-14 14:37:10 -07001047 } else {
1048 // We're flushing both ports in preparation for seeking.
1049
1050 if (mPortStatus[kPortIndexInput] == ENABLED
1051 && mPortStatus[kPortIndexOutput] == ENABLED) {
1052 LOGV("Finished flushing both ports, now continuing from"
1053 " seek-time.");
1054
1055 drainInputBuffers();
1056 fillOutputBuffers();
1057 }
1058 }
1059
1060 break;
1061 }
1062
1063 default:
1064 {
1065 LOGV("CMD_COMPLETE(%d, %ld)", cmd, data);
1066 break;
1067 }
1068 }
1069}
1070
1071void OMXCodec::onStateChange(OMX_STATETYPE newState) {
1072 switch (newState) {
1073 case OMX_StateIdle:
1074 {
1075 LOGV("Now Idle.");
1076 if (mState == LOADED_TO_IDLE) {
1077 status_t err = mOMX->send_command(
1078 mNode, OMX_CommandStateSet, OMX_StateExecuting);
1079
1080 CHECK_EQ(err, OK);
1081
1082 setState(IDLE_TO_EXECUTING);
1083 } else {
1084 CHECK_EQ(mState, EXECUTING_TO_IDLE);
1085
1086 CHECK_EQ(
1087 countBuffersWeOwn(mPortBuffers[kPortIndexInput]),
1088 mPortBuffers[kPortIndexInput].size());
1089
1090 CHECK_EQ(
1091 countBuffersWeOwn(mPortBuffers[kPortIndexOutput]),
1092 mPortBuffers[kPortIndexOutput].size());
1093
1094 status_t err = mOMX->send_command(
1095 mNode, OMX_CommandStateSet, OMX_StateLoaded);
1096
1097 CHECK_EQ(err, OK);
1098
1099 err = freeBuffersOnPort(kPortIndexInput);
1100 CHECK_EQ(err, OK);
1101
1102 err = freeBuffersOnPort(kPortIndexOutput);
1103 CHECK_EQ(err, OK);
1104
1105 mPortStatus[kPortIndexInput] = ENABLED;
1106 mPortStatus[kPortIndexOutput] = ENABLED;
1107
1108 setState(IDLE_TO_LOADED);
1109 }
1110 break;
1111 }
1112
1113 case OMX_StateExecuting:
1114 {
1115 CHECK_EQ(mState, IDLE_TO_EXECUTING);
1116
1117 LOGV("Now Executing.");
1118
1119 setState(EXECUTING);
1120
Andreas Huber42978e52009-08-27 10:08:39 -07001121 // Buffers will be submitted to the component in the first
1122 // call to OMXCodec::read as mInitialBufferSubmit is true at
1123 // this point. This ensures that this on_message call returns,
1124 // releases the lock and ::init can notice the state change and
1125 // itself return.
Andreas Huberbe06d262009-08-14 14:37:10 -07001126 break;
1127 }
1128
1129 case OMX_StateLoaded:
1130 {
1131 CHECK_EQ(mState, IDLE_TO_LOADED);
1132
1133 LOGV("Now Loaded.");
1134
1135 setState(LOADED);
1136 break;
1137 }
1138
1139 default:
1140 {
1141 CHECK(!"should not be here.");
1142 break;
1143 }
1144 }
1145}
1146
1147// static
1148size_t OMXCodec::countBuffersWeOwn(const Vector<BufferInfo> &buffers) {
1149 size_t n = 0;
1150 for (size_t i = 0; i < buffers.size(); ++i) {
1151 if (!buffers[i].mOwnedByComponent) {
1152 ++n;
1153 }
1154 }
1155
1156 return n;
1157}
1158
1159status_t OMXCodec::freeBuffersOnPort(
1160 OMX_U32 portIndex, bool onlyThoseWeOwn) {
1161 Vector<BufferInfo> *buffers = &mPortBuffers[portIndex];
1162
1163 status_t stickyErr = OK;
1164
1165 for (size_t i = buffers->size(); i-- > 0;) {
1166 BufferInfo *info = &buffers->editItemAt(i);
1167
1168 if (onlyThoseWeOwn && info->mOwnedByComponent) {
1169 continue;
1170 }
1171
1172 CHECK_EQ(info->mOwnedByComponent, false);
1173
1174 status_t err =
1175 mOMX->free_buffer(mNode, portIndex, info->mBuffer);
1176
1177 if (err != OK) {
1178 stickyErr = err;
1179 }
1180
1181 if (info->mMediaBuffer != NULL) {
1182 info->mMediaBuffer->setObserver(NULL);
1183
1184 // Make sure nobody but us owns this buffer at this point.
1185 CHECK_EQ(info->mMediaBuffer->refcount(), 0);
1186
1187 info->mMediaBuffer->release();
1188 }
1189
1190 buffers->removeAt(i);
1191 }
1192
1193 CHECK(onlyThoseWeOwn || buffers->isEmpty());
1194
1195 return stickyErr;
1196}
1197
1198void OMXCodec::onPortSettingsChanged(OMX_U32 portIndex) {
1199 LOGV("PORT_SETTINGS_CHANGED(%ld)", portIndex);
1200
1201 CHECK_EQ(mState, EXECUTING);
1202 CHECK_EQ(portIndex, kPortIndexOutput);
1203 setState(RECONFIGURING);
1204
1205 if (mQuirks & kNeedsFlushBeforeDisable) {
Andreas Huber404cc412009-08-25 14:26:05 -07001206 if (!flushPortAsync(portIndex)) {
1207 onCmdComplete(OMX_CommandFlush, portIndex);
1208 }
Andreas Huberbe06d262009-08-14 14:37:10 -07001209 } else {
1210 disablePortAsync(portIndex);
1211 }
1212}
1213
Andreas Huber404cc412009-08-25 14:26:05 -07001214bool OMXCodec::flushPortAsync(OMX_U32 portIndex) {
Andreas Huber127fcdc2009-08-26 16:27:02 -07001215 CHECK(mState == EXECUTING || mState == RECONFIGURING
1216 || mState == EXECUTING_TO_IDLE);
Andreas Huberbe06d262009-08-14 14:37:10 -07001217
Andreas Huber404cc412009-08-25 14:26:05 -07001218 LOGV("flushPortAsync(%ld): we own %d out of %d buffers already.",
1219 portIndex, countBuffersWeOwn(mPortBuffers[portIndex]),
1220 mPortBuffers[portIndex].size());
1221
Andreas Huberbe06d262009-08-14 14:37:10 -07001222 CHECK_EQ(mPortStatus[portIndex], ENABLED);
1223 mPortStatus[portIndex] = SHUTTING_DOWN;
1224
Andreas Huber404cc412009-08-25 14:26:05 -07001225 if ((mQuirks & kRequiresFlushCompleteEmulation)
1226 && countBuffersWeOwn(mPortBuffers[portIndex])
1227 == mPortBuffers[portIndex].size()) {
1228 // No flush is necessary and this component fails to send a
1229 // flush-complete event in this case.
1230
1231 return false;
1232 }
1233
Andreas Huberbe06d262009-08-14 14:37:10 -07001234 status_t err =
1235 mOMX->send_command(mNode, OMX_CommandFlush, portIndex);
1236 CHECK_EQ(err, OK);
Andreas Huber404cc412009-08-25 14:26:05 -07001237
1238 return true;
Andreas Huberbe06d262009-08-14 14:37:10 -07001239}
1240
1241void OMXCodec::disablePortAsync(OMX_U32 portIndex) {
1242 CHECK(mState == EXECUTING || mState == RECONFIGURING);
1243
1244 CHECK_EQ(mPortStatus[portIndex], ENABLED);
1245 mPortStatus[portIndex] = DISABLING;
1246
1247 status_t err =
1248 mOMX->send_command(mNode, OMX_CommandPortDisable, portIndex);
1249 CHECK_EQ(err, OK);
1250
1251 freeBuffersOnPort(portIndex, true);
1252}
1253
1254void OMXCodec::enablePortAsync(OMX_U32 portIndex) {
1255 CHECK(mState == EXECUTING || mState == RECONFIGURING);
1256
1257 CHECK_EQ(mPortStatus[portIndex], DISABLED);
1258 mPortStatus[portIndex] = ENABLING;
1259
1260 status_t err =
1261 mOMX->send_command(mNode, OMX_CommandPortEnable, portIndex);
1262 CHECK_EQ(err, OK);
1263}
1264
1265void OMXCodec::fillOutputBuffers() {
1266 CHECK_EQ(mState, EXECUTING);
1267
1268 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
1269 for (size_t i = 0; i < buffers->size(); ++i) {
1270 fillOutputBuffer(&buffers->editItemAt(i));
1271 }
1272}
1273
1274void OMXCodec::drainInputBuffers() {
Andreas Huberd06e5b82009-08-28 13:18:14 -07001275 CHECK(mState == EXECUTING || mState == RECONFIGURING);
Andreas Huberbe06d262009-08-14 14:37:10 -07001276
1277 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
1278 for (size_t i = 0; i < buffers->size(); ++i) {
1279 drainInputBuffer(&buffers->editItemAt(i));
1280 }
1281}
1282
1283void OMXCodec::drainInputBuffer(BufferInfo *info) {
1284 CHECK_EQ(info->mOwnedByComponent, false);
1285
1286 if (mSignalledEOS) {
1287 return;
1288 }
1289
1290 if (mCodecSpecificDataIndex < mCodecSpecificData.size()) {
1291 const CodecSpecificData *specific =
1292 mCodecSpecificData[mCodecSpecificDataIndex];
1293
1294 size_t size = specific->mSize;
1295
Andreas Huber4f5e6022009-08-19 09:29:34 -07001296 if (!strcasecmp("video/avc", mMIME)
1297 && !(mQuirks & kWantsNALFragments)) {
Andreas Huberbe06d262009-08-14 14:37:10 -07001298 static const uint8_t kNALStartCode[4] =
1299 { 0x00, 0x00, 0x00, 0x01 };
1300
1301 CHECK(info->mMem->size() >= specific->mSize + 4);
1302
1303 size += 4;
1304
1305 memcpy(info->mMem->pointer(), kNALStartCode, 4);
1306 memcpy((uint8_t *)info->mMem->pointer() + 4,
1307 specific->mData, specific->mSize);
1308 } else {
1309 CHECK(info->mMem->size() >= specific->mSize);
1310 memcpy(info->mMem->pointer(), specific->mData, specific->mSize);
1311 }
1312
1313 mOMX->empty_buffer(
1314 mNode, info->mBuffer, 0, size,
1315 OMX_BUFFERFLAG_ENDOFFRAME | OMX_BUFFERFLAG_CODECCONFIG,
1316 0);
1317
1318 info->mOwnedByComponent = true;
1319
1320 ++mCodecSpecificDataIndex;
1321 return;
1322 }
1323
1324 MediaBuffer *srcBuffer;
1325 status_t err;
1326 if (mSeekTimeUs >= 0) {
1327 MediaSource::ReadOptions options;
1328 options.setSeekTo(mSeekTimeUs);
1329 mSeekTimeUs = -1;
1330
1331 err = mSource->read(&srcBuffer, &options);
1332 } else {
1333 err = mSource->read(&srcBuffer);
1334 }
1335
1336 OMX_U32 flags = OMX_BUFFERFLAG_ENDOFFRAME;
1337 OMX_TICKS timestamp = 0;
1338 size_t srcLength = 0;
1339
1340 if (err != OK) {
1341 LOGV("signalling end of input stream.");
1342 flags |= OMX_BUFFERFLAG_EOS;
1343
1344 mSignalledEOS = true;
1345 } else {
1346 srcLength = srcBuffer->range_length();
1347
1348 if (info->mMem->size() < srcLength) {
1349 LOGE("info->mMem->size() = %d, srcLength = %d",
1350 info->mMem->size(), srcLength);
1351 }
1352 CHECK(info->mMem->size() >= srcLength);
1353 memcpy(info->mMem->pointer(),
1354 (const uint8_t *)srcBuffer->data() + srcBuffer->range_offset(),
1355 srcLength);
1356
1357 int32_t units, scale;
1358 if (srcBuffer->meta_data()->findInt32(kKeyTimeUnits, &units)
1359 && srcBuffer->meta_data()->findInt32(kKeyTimeScale, &scale)) {
1360 timestamp = ((OMX_TICKS)units * 1000000) / scale;
1361
1362 LOGV("Calling empty_buffer on buffer %p (length %d)",
1363 info->mBuffer, srcLength);
1364 LOGV("Calling empty_buffer with timestamp %lld us (%.2f secs)",
1365 timestamp, timestamp / 1E6);
1366 }
1367 }
1368
1369 mOMX->empty_buffer(
1370 mNode, info->mBuffer, 0, srcLength,
1371 flags, timestamp);
1372
1373 info->mOwnedByComponent = true;
1374
1375 if (srcBuffer != NULL) {
1376 srcBuffer->release();
1377 srcBuffer = NULL;
1378 }
1379}
1380
1381void OMXCodec::fillOutputBuffer(BufferInfo *info) {
1382 CHECK_EQ(info->mOwnedByComponent, false);
1383
Andreas Huber404cc412009-08-25 14:26:05 -07001384 if (mNoMoreOutputData) {
1385 LOGV("There is no more output data available, not "
1386 "calling fillOutputBuffer");
1387 return;
1388 }
1389
Andreas Huberbe06d262009-08-14 14:37:10 -07001390 LOGV("Calling fill_buffer on buffer %p", info->mBuffer);
1391 mOMX->fill_buffer(mNode, info->mBuffer);
1392
1393 info->mOwnedByComponent = true;
1394}
1395
1396void OMXCodec::drainInputBuffer(IOMX::buffer_id buffer) {
1397 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
1398 for (size_t i = 0; i < buffers->size(); ++i) {
1399 if ((*buffers)[i].mBuffer == buffer) {
1400 drainInputBuffer(&buffers->editItemAt(i));
1401 return;
1402 }
1403 }
1404
1405 CHECK(!"should not be here.");
1406}
1407
1408void OMXCodec::fillOutputBuffer(IOMX::buffer_id buffer) {
1409 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
1410 for (size_t i = 0; i < buffers->size(); ++i) {
1411 if ((*buffers)[i].mBuffer == buffer) {
1412 fillOutputBuffer(&buffers->editItemAt(i));
1413 return;
1414 }
1415 }
1416
1417 CHECK(!"should not be here.");
1418}
1419
1420void OMXCodec::setState(State newState) {
1421 mState = newState;
1422 mAsyncCompletion.signal();
1423
1424 // This may cause some spurious wakeups but is necessary to
1425 // unblock the reader if we enter ERROR state.
1426 mBufferFilled.signal();
1427}
1428
1429void OMXCodec::setAMRFormat() {
1430 if (!mIsEncoder) {
1431 OMX_AUDIO_PARAM_AMRTYPE def;
1432 def.nSize = sizeof(def);
1433 def.nVersion.s.nVersionMajor = 1;
1434 def.nVersion.s.nVersionMinor = 1;
1435 def.nPortIndex = kPortIndexInput;
1436
1437 status_t err =
1438 mOMX->get_parameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
1439
1440 CHECK_EQ(err, OK);
1441
1442 def.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
1443 def.eAMRBandMode = OMX_AUDIO_AMRBandModeNB0;
1444
1445 err = mOMX->set_parameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
1446 CHECK_EQ(err, OK);
1447 }
1448
1449 ////////////////////////
1450
1451 if (mIsEncoder) {
1452 sp<MetaData> format = mSource->getFormat();
1453 int32_t sampleRate;
1454 int32_t numChannels;
1455 CHECK(format->findInt32(kKeySampleRate, &sampleRate));
1456 CHECK(format->findInt32(kKeyChannelCount, &numChannels));
1457
1458 OMX_AUDIO_PARAM_PCMMODETYPE pcmParams;
1459 pcmParams.nSize = sizeof(pcmParams);
1460 pcmParams.nVersion.s.nVersionMajor = 1;
1461 pcmParams.nVersion.s.nVersionMinor = 1;
1462 pcmParams.nPortIndex = kPortIndexInput;
1463
1464 status_t err = mOMX->get_parameter(
1465 mNode, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams));
1466
1467 CHECK_EQ(err, OK);
1468
1469 pcmParams.nChannels = numChannels;
1470 pcmParams.eNumData = OMX_NumericalDataSigned;
1471 pcmParams.bInterleaved = OMX_TRUE;
1472 pcmParams.nBitPerSample = 16;
1473 pcmParams.nSamplingRate = sampleRate;
1474 pcmParams.ePCMMode = OMX_AUDIO_PCMModeLinear;
1475
1476 if (numChannels == 1) {
1477 pcmParams.eChannelMapping[0] = OMX_AUDIO_ChannelCF;
1478 } else {
1479 CHECK_EQ(numChannels, 2);
1480
1481 pcmParams.eChannelMapping[0] = OMX_AUDIO_ChannelLF;
1482 pcmParams.eChannelMapping[1] = OMX_AUDIO_ChannelRF;
1483 }
1484
1485 err = mOMX->set_parameter(
1486 mNode, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams));
1487
1488 CHECK_EQ(err, OK);
1489 }
1490}
1491
1492void OMXCodec::setAACFormat() {
1493 OMX_AUDIO_PARAM_AACPROFILETYPE def;
1494 def.nSize = sizeof(def);
1495 def.nVersion.s.nVersionMajor = 1;
1496 def.nVersion.s.nVersionMinor = 1;
1497 def.nPortIndex = kPortIndexInput;
1498
1499 status_t err =
1500 mOMX->get_parameter(mNode, OMX_IndexParamAudioAac, &def, sizeof(def));
1501 CHECK_EQ(err, OK);
1502
1503 def.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4ADTS;
1504
1505 err = mOMX->set_parameter(mNode, OMX_IndexParamAudioAac, &def, sizeof(def));
1506 CHECK_EQ(err, OK);
1507}
1508
1509void OMXCodec::setImageOutputFormat(
1510 OMX_COLOR_FORMATTYPE format, OMX_U32 width, OMX_U32 height) {
1511 LOGV("setImageOutputFormat(%ld, %ld)", width, height);
1512
1513#if 0
1514 OMX_INDEXTYPE index;
1515 status_t err = mOMX->get_extension_index(
1516 mNode, "OMX.TI.JPEG.decode.Config.OutputColorFormat", &index);
1517 CHECK_EQ(err, OK);
1518
1519 err = mOMX->set_config(mNode, index, &format, sizeof(format));
1520 CHECK_EQ(err, OK);
1521#endif
1522
1523 OMX_PARAM_PORTDEFINITIONTYPE def;
1524 def.nSize = sizeof(def);
1525 def.nVersion.s.nVersionMajor = 1;
1526 def.nVersion.s.nVersionMinor = 1;
1527 def.nPortIndex = kPortIndexOutput;
1528
1529 status_t err = mOMX->get_parameter(
1530 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
1531 CHECK_EQ(err, OK);
1532
1533 CHECK_EQ(def.eDomain, OMX_PortDomainImage);
1534
1535 OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
Andreas Huberebf66ea2009-08-19 13:32:58 -07001536
Andreas Huberbe06d262009-08-14 14:37:10 -07001537 CHECK_EQ(imageDef->eCompressionFormat, OMX_IMAGE_CodingUnused);
1538 imageDef->eColorFormat = format;
1539 imageDef->nFrameWidth = width;
1540 imageDef->nFrameHeight = height;
1541
1542 switch (format) {
1543 case OMX_COLOR_FormatYUV420PackedPlanar:
1544 case OMX_COLOR_FormatYUV411Planar:
1545 {
1546 def.nBufferSize = (width * height * 3) / 2;
1547 break;
1548 }
1549
1550 case OMX_COLOR_FormatCbYCrY:
1551 {
1552 def.nBufferSize = width * height * 2;
1553 break;
1554 }
1555
1556 case OMX_COLOR_Format32bitARGB8888:
1557 {
1558 def.nBufferSize = width * height * 4;
1559 break;
1560 }
1561
1562 default:
1563 CHECK(!"Should not be here. Unknown color format.");
1564 break;
1565 }
1566
Andreas Huber5c0a9132009-08-20 11:16:40 -07001567 def.nBufferCountActual = def.nBufferCountMin;
1568
Andreas Huberbe06d262009-08-14 14:37:10 -07001569 err = mOMX->set_parameter(
1570 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
1571 CHECK_EQ(err, OK);
Andreas Huber5c0a9132009-08-20 11:16:40 -07001572}
Andreas Huberbe06d262009-08-14 14:37:10 -07001573
Andreas Huber5c0a9132009-08-20 11:16:40 -07001574void OMXCodec::setJPEGInputFormat(
1575 OMX_U32 width, OMX_U32 height, OMX_U32 compressedSize) {
1576 OMX_PARAM_PORTDEFINITIONTYPE def;
1577 def.nSize = sizeof(def);
1578 def.nVersion.s.nVersionMajor = 1;
1579 def.nVersion.s.nVersionMinor = 1;
Andreas Huberbe06d262009-08-14 14:37:10 -07001580 def.nPortIndex = kPortIndexInput;
1581
Andreas Huber5c0a9132009-08-20 11:16:40 -07001582 status_t err = mOMX->get_parameter(
Andreas Huberbe06d262009-08-14 14:37:10 -07001583 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
1584 CHECK_EQ(err, OK);
1585
Andreas Huber5c0a9132009-08-20 11:16:40 -07001586 CHECK_EQ(def.eDomain, OMX_PortDomainImage);
1587 OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
1588
Andreas Huberbe06d262009-08-14 14:37:10 -07001589 CHECK_EQ(imageDef->eCompressionFormat, OMX_IMAGE_CodingJPEG);
1590 imageDef->nFrameWidth = width;
1591 imageDef->nFrameHeight = height;
1592
Andreas Huber5c0a9132009-08-20 11:16:40 -07001593 def.nBufferSize = compressedSize;
Andreas Huberbe06d262009-08-14 14:37:10 -07001594 def.nBufferCountActual = def.nBufferCountMin;
1595
1596 err = mOMX->set_parameter(
1597 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
1598 CHECK_EQ(err, OK);
1599}
1600
1601void OMXCodec::addCodecSpecificData(const void *data, size_t size) {
1602 CodecSpecificData *specific =
1603 (CodecSpecificData *)malloc(sizeof(CodecSpecificData) + size - 1);
1604
1605 specific->mSize = size;
1606 memcpy(specific->mData, data, size);
1607
1608 mCodecSpecificData.push(specific);
1609}
1610
1611void OMXCodec::clearCodecSpecificData() {
1612 for (size_t i = 0; i < mCodecSpecificData.size(); ++i) {
1613 free(mCodecSpecificData.editItemAt(i));
1614 }
1615 mCodecSpecificData.clear();
1616 mCodecSpecificDataIndex = 0;
1617}
1618
1619status_t OMXCodec::start(MetaData *) {
Andreas Huber42978e52009-08-27 10:08:39 -07001620 Mutex::Autolock autoLock(mLock);
1621
Andreas Huberbe06d262009-08-14 14:37:10 -07001622 if (mState != LOADED) {
1623 return UNKNOWN_ERROR;
1624 }
Andreas Huberebf66ea2009-08-19 13:32:58 -07001625
Andreas Huberbe06d262009-08-14 14:37:10 -07001626 sp<MetaData> params = new MetaData;
Andreas Huber4f5e6022009-08-19 09:29:34 -07001627 if (mQuirks & kWantsNALFragments) {
1628 params->setInt32(kKeyWantsNALFragments, true);
Andreas Huberbe06d262009-08-14 14:37:10 -07001629 }
1630 status_t err = mSource->start(params.get());
1631
1632 if (err != OK) {
1633 return err;
1634 }
1635
1636 mCodecSpecificDataIndex = 0;
Andreas Huber42978e52009-08-27 10:08:39 -07001637 mInitialBufferSubmit = true;
Andreas Huberbe06d262009-08-14 14:37:10 -07001638 mSignalledEOS = false;
1639 mNoMoreOutputData = false;
1640 mSeekTimeUs = -1;
1641 mFilledBuffers.clear();
1642
1643 return init();
1644}
1645
1646status_t OMXCodec::stop() {
Andreas Huber5c0a9132009-08-20 11:16:40 -07001647 LOGV("stop");
Andreas Huberbe06d262009-08-14 14:37:10 -07001648
1649 Mutex::Autolock autoLock(mLock);
1650
1651 while (isIntermediateState(mState)) {
1652 mAsyncCompletion.wait(mLock);
1653 }
1654
1655 switch (mState) {
1656 case LOADED:
1657 case ERROR:
1658 break;
1659
1660 case EXECUTING:
1661 {
1662 setState(EXECUTING_TO_IDLE);
1663
Andreas Huber127fcdc2009-08-26 16:27:02 -07001664 if (mQuirks & kRequiresFlushBeforeShutdown) {
1665 LOGV("This component requires a flush before transitioning "
1666 "from EXECUTING to IDLE...");
Andreas Huberbe06d262009-08-14 14:37:10 -07001667
Andreas Huber127fcdc2009-08-26 16:27:02 -07001668 bool emulateInputFlushCompletion =
1669 !flushPortAsync(kPortIndexInput);
1670
1671 bool emulateOutputFlushCompletion =
1672 !flushPortAsync(kPortIndexOutput);
1673
1674 if (emulateInputFlushCompletion) {
1675 onCmdComplete(OMX_CommandFlush, kPortIndexInput);
1676 }
1677
1678 if (emulateOutputFlushCompletion) {
1679 onCmdComplete(OMX_CommandFlush, kPortIndexOutput);
1680 }
1681 } else {
1682 mPortStatus[kPortIndexInput] = SHUTTING_DOWN;
1683 mPortStatus[kPortIndexOutput] = SHUTTING_DOWN;
1684
1685 status_t err =
1686 mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
1687 CHECK_EQ(err, OK);
1688 }
Andreas Huberbe06d262009-08-14 14:37:10 -07001689
1690 while (mState != LOADED && mState != ERROR) {
1691 mAsyncCompletion.wait(mLock);
1692 }
1693
1694 break;
1695 }
1696
1697 default:
1698 {
1699 CHECK(!"should not be here.");
1700 break;
1701 }
1702 }
1703
1704 mSource->stop();
1705
1706 return OK;
1707}
1708
1709sp<MetaData> OMXCodec::getFormat() {
1710 return mOutputFormat;
1711}
1712
1713status_t OMXCodec::read(
1714 MediaBuffer **buffer, const ReadOptions *options) {
1715 *buffer = NULL;
1716
1717 Mutex::Autolock autoLock(mLock);
1718
Andreas Huberd06e5b82009-08-28 13:18:14 -07001719 if (mState != EXECUTING && mState != RECONFIGURING) {
1720 return UNKNOWN_ERROR;
1721 }
1722
Andreas Huber42978e52009-08-27 10:08:39 -07001723 if (mInitialBufferSubmit) {
1724 mInitialBufferSubmit = false;
1725
1726 drainInputBuffers();
Andreas Huber42978e52009-08-27 10:08:39 -07001727
Andreas Huberd06e5b82009-08-28 13:18:14 -07001728 if (mState == EXECUTING) {
1729 // Otherwise mState == RECONFIGURING and this code will trigger
1730 // after the output port is reenabled.
1731 fillOutputBuffers();
1732 }
Andreas Huberbe06d262009-08-14 14:37:10 -07001733 }
1734
1735 int64_t seekTimeUs;
1736 if (options && options->getSeekTo(&seekTimeUs)) {
1737 LOGV("seeking to %lld us (%.2f secs)", seekTimeUs, seekTimeUs / 1E6);
1738
1739 mSignalledEOS = false;
1740 mNoMoreOutputData = false;
1741
1742 CHECK(seekTimeUs >= 0);
1743 mSeekTimeUs = seekTimeUs;
1744
1745 mFilledBuffers.clear();
1746
1747 CHECK_EQ(mState, EXECUTING);
1748
Andreas Huber404cc412009-08-25 14:26:05 -07001749 bool emulateInputFlushCompletion = !flushPortAsync(kPortIndexInput);
1750 bool emulateOutputFlushCompletion = !flushPortAsync(kPortIndexOutput);
1751
1752 if (emulateInputFlushCompletion) {
1753 onCmdComplete(OMX_CommandFlush, kPortIndexInput);
1754 }
1755
1756 if (emulateOutputFlushCompletion) {
1757 onCmdComplete(OMX_CommandFlush, kPortIndexOutput);
1758 }
Andreas Huberbe06d262009-08-14 14:37:10 -07001759 }
1760
1761 while (mState != ERROR && !mNoMoreOutputData && mFilledBuffers.empty()) {
1762 mBufferFilled.wait(mLock);
1763 }
1764
1765 if (mState == ERROR) {
1766 return UNKNOWN_ERROR;
1767 }
1768
1769 if (mFilledBuffers.empty()) {
1770 return ERROR_END_OF_STREAM;
1771 }
1772
1773 size_t index = *mFilledBuffers.begin();
1774 mFilledBuffers.erase(mFilledBuffers.begin());
1775
1776 BufferInfo *info = &mPortBuffers[kPortIndexOutput].editItemAt(index);
1777 info->mMediaBuffer->add_ref();
1778 *buffer = info->mMediaBuffer;
1779
1780 return OK;
1781}
1782
1783void OMXCodec::signalBufferReturned(MediaBuffer *buffer) {
1784 Mutex::Autolock autoLock(mLock);
1785
1786 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
1787 for (size_t i = 0; i < buffers->size(); ++i) {
1788 BufferInfo *info = &buffers->editItemAt(i);
1789
1790 if (info->mMediaBuffer == buffer) {
1791 CHECK_EQ(mPortStatus[kPortIndexOutput], ENABLED);
1792 fillOutputBuffer(info);
1793 return;
1794 }
1795 }
1796
1797 CHECK(!"should not be here.");
1798}
1799
1800static const char *imageCompressionFormatString(OMX_IMAGE_CODINGTYPE type) {
1801 static const char *kNames[] = {
1802 "OMX_IMAGE_CodingUnused",
1803 "OMX_IMAGE_CodingAutoDetect",
1804 "OMX_IMAGE_CodingJPEG",
1805 "OMX_IMAGE_CodingJPEG2K",
1806 "OMX_IMAGE_CodingEXIF",
1807 "OMX_IMAGE_CodingTIFF",
1808 "OMX_IMAGE_CodingGIF",
1809 "OMX_IMAGE_CodingPNG",
1810 "OMX_IMAGE_CodingLZW",
1811 "OMX_IMAGE_CodingBMP",
1812 };
1813
1814 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
1815
1816 if (type < 0 || (size_t)type >= numNames) {
1817 return "UNKNOWN";
1818 } else {
1819 return kNames[type];
1820 }
1821}
1822
1823static const char *colorFormatString(OMX_COLOR_FORMATTYPE type) {
1824 static const char *kNames[] = {
1825 "OMX_COLOR_FormatUnused",
1826 "OMX_COLOR_FormatMonochrome",
1827 "OMX_COLOR_Format8bitRGB332",
1828 "OMX_COLOR_Format12bitRGB444",
1829 "OMX_COLOR_Format16bitARGB4444",
1830 "OMX_COLOR_Format16bitARGB1555",
1831 "OMX_COLOR_Format16bitRGB565",
1832 "OMX_COLOR_Format16bitBGR565",
1833 "OMX_COLOR_Format18bitRGB666",
1834 "OMX_COLOR_Format18bitARGB1665",
Andreas Huberebf66ea2009-08-19 13:32:58 -07001835 "OMX_COLOR_Format19bitARGB1666",
Andreas Huberbe06d262009-08-14 14:37:10 -07001836 "OMX_COLOR_Format24bitRGB888",
1837 "OMX_COLOR_Format24bitBGR888",
1838 "OMX_COLOR_Format24bitARGB1887",
1839 "OMX_COLOR_Format25bitARGB1888",
1840 "OMX_COLOR_Format32bitBGRA8888",
1841 "OMX_COLOR_Format32bitARGB8888",
1842 "OMX_COLOR_FormatYUV411Planar",
1843 "OMX_COLOR_FormatYUV411PackedPlanar",
1844 "OMX_COLOR_FormatYUV420Planar",
1845 "OMX_COLOR_FormatYUV420PackedPlanar",
1846 "OMX_COLOR_FormatYUV420SemiPlanar",
1847 "OMX_COLOR_FormatYUV422Planar",
1848 "OMX_COLOR_FormatYUV422PackedPlanar",
1849 "OMX_COLOR_FormatYUV422SemiPlanar",
1850 "OMX_COLOR_FormatYCbYCr",
1851 "OMX_COLOR_FormatYCrYCb",
1852 "OMX_COLOR_FormatCbYCrY",
1853 "OMX_COLOR_FormatCrYCbY",
1854 "OMX_COLOR_FormatYUV444Interleaved",
1855 "OMX_COLOR_FormatRawBayer8bit",
1856 "OMX_COLOR_FormatRawBayer10bit",
1857 "OMX_COLOR_FormatRawBayer8bitcompressed",
Andreas Huberebf66ea2009-08-19 13:32:58 -07001858 "OMX_COLOR_FormatL2",
1859 "OMX_COLOR_FormatL4",
1860 "OMX_COLOR_FormatL8",
1861 "OMX_COLOR_FormatL16",
1862 "OMX_COLOR_FormatL24",
Andreas Huberbe06d262009-08-14 14:37:10 -07001863 "OMX_COLOR_FormatL32",
1864 "OMX_COLOR_FormatYUV420PackedSemiPlanar",
1865 "OMX_COLOR_FormatYUV422PackedSemiPlanar",
1866 "OMX_COLOR_Format18BitBGR666",
1867 "OMX_COLOR_Format24BitARGB6666",
1868 "OMX_COLOR_Format24BitABGR6666",
1869 };
1870
1871 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
1872
1873 static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
1874
1875 if (type == OMX_QCOM_COLOR_FormatYVU420SemiPlanar) {
1876 return "OMX_QCOM_COLOR_FormatYVU420SemiPlanar";
1877 } else if (type < 0 || (size_t)type >= numNames) {
1878 return "UNKNOWN";
1879 } else {
1880 return kNames[type];
1881 }
1882}
1883
1884static const char *videoCompressionFormatString(OMX_VIDEO_CODINGTYPE type) {
1885 static const char *kNames[] = {
1886 "OMX_VIDEO_CodingUnused",
1887 "OMX_VIDEO_CodingAutoDetect",
1888 "OMX_VIDEO_CodingMPEG2",
1889 "OMX_VIDEO_CodingH263",
1890 "OMX_VIDEO_CodingMPEG4",
1891 "OMX_VIDEO_CodingWMV",
1892 "OMX_VIDEO_CodingRV",
1893 "OMX_VIDEO_CodingAVC",
1894 "OMX_VIDEO_CodingMJPEG",
1895 };
1896
1897 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
1898
1899 if (type < 0 || (size_t)type >= numNames) {
1900 return "UNKNOWN";
1901 } else {
1902 return kNames[type];
1903 }
1904}
1905
1906static const char *audioCodingTypeString(OMX_AUDIO_CODINGTYPE type) {
1907 static const char *kNames[] = {
1908 "OMX_AUDIO_CodingUnused",
1909 "OMX_AUDIO_CodingAutoDetect",
1910 "OMX_AUDIO_CodingPCM",
1911 "OMX_AUDIO_CodingADPCM",
1912 "OMX_AUDIO_CodingAMR",
1913 "OMX_AUDIO_CodingGSMFR",
1914 "OMX_AUDIO_CodingGSMEFR",
1915 "OMX_AUDIO_CodingGSMHR",
1916 "OMX_AUDIO_CodingPDCFR",
1917 "OMX_AUDIO_CodingPDCEFR",
1918 "OMX_AUDIO_CodingPDCHR",
1919 "OMX_AUDIO_CodingTDMAFR",
1920 "OMX_AUDIO_CodingTDMAEFR",
1921 "OMX_AUDIO_CodingQCELP8",
1922 "OMX_AUDIO_CodingQCELP13",
1923 "OMX_AUDIO_CodingEVRC",
1924 "OMX_AUDIO_CodingSMV",
1925 "OMX_AUDIO_CodingG711",
1926 "OMX_AUDIO_CodingG723",
1927 "OMX_AUDIO_CodingG726",
1928 "OMX_AUDIO_CodingG729",
1929 "OMX_AUDIO_CodingAAC",
1930 "OMX_AUDIO_CodingMP3",
1931 "OMX_AUDIO_CodingSBC",
1932 "OMX_AUDIO_CodingVORBIS",
1933 "OMX_AUDIO_CodingWMA",
1934 "OMX_AUDIO_CodingRA",
1935 "OMX_AUDIO_CodingMIDI",
1936 };
1937
1938 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
1939
1940 if (type < 0 || (size_t)type >= numNames) {
1941 return "UNKNOWN";
1942 } else {
1943 return kNames[type];
1944 }
1945}
1946
1947static const char *audioPCMModeString(OMX_AUDIO_PCMMODETYPE type) {
1948 static const char *kNames[] = {
1949 "OMX_AUDIO_PCMModeLinear",
1950 "OMX_AUDIO_PCMModeALaw",
1951 "OMX_AUDIO_PCMModeMULaw",
1952 };
1953
1954 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
1955
1956 if (type < 0 || (size_t)type >= numNames) {
1957 return "UNKNOWN";
1958 } else {
1959 return kNames[type];
1960 }
1961}
1962
1963
1964void OMXCodec::dumpPortStatus(OMX_U32 portIndex) {
1965 OMX_PARAM_PORTDEFINITIONTYPE def;
1966 def.nSize = sizeof(def);
1967 def.nVersion.s.nVersionMajor = 1;
1968 def.nVersion.s.nVersionMinor = 1;
1969 def.nPortIndex = portIndex;
1970
1971 status_t err = mOMX->get_parameter(
1972 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
1973 CHECK_EQ(err, OK);
1974
1975 printf("%s Port = {\n", portIndex == kPortIndexInput ? "Input" : "Output");
1976
1977 CHECK((portIndex == kPortIndexInput && def.eDir == OMX_DirInput)
1978 || (portIndex == kPortIndexOutput && def.eDir == OMX_DirOutput));
1979
1980 printf(" nBufferCountActual = %ld\n", def.nBufferCountActual);
1981 printf(" nBufferCountMin = %ld\n", def.nBufferCountMin);
1982 printf(" nBufferSize = %ld\n", def.nBufferSize);
1983
1984 switch (def.eDomain) {
1985 case OMX_PortDomainImage:
1986 {
1987 const OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
1988
1989 printf("\n");
1990 printf(" // Image\n");
1991 printf(" nFrameWidth = %ld\n", imageDef->nFrameWidth);
1992 printf(" nFrameHeight = %ld\n", imageDef->nFrameHeight);
1993 printf(" nStride = %ld\n", imageDef->nStride);
1994
1995 printf(" eCompressionFormat = %s\n",
1996 imageCompressionFormatString(imageDef->eCompressionFormat));
1997
1998 printf(" eColorFormat = %s\n",
1999 colorFormatString(imageDef->eColorFormat));
2000
2001 break;
2002 }
2003
2004 case OMX_PortDomainVideo:
2005 {
2006 OMX_VIDEO_PORTDEFINITIONTYPE *videoDef = &def.format.video;
2007
2008 printf("\n");
2009 printf(" // Video\n");
2010 printf(" nFrameWidth = %ld\n", videoDef->nFrameWidth);
2011 printf(" nFrameHeight = %ld\n", videoDef->nFrameHeight);
2012 printf(" nStride = %ld\n", videoDef->nStride);
2013
2014 printf(" eCompressionFormat = %s\n",
2015 videoCompressionFormatString(videoDef->eCompressionFormat));
2016
2017 printf(" eColorFormat = %s\n",
2018 colorFormatString(videoDef->eColorFormat));
2019
2020 break;
2021 }
2022
2023 case OMX_PortDomainAudio:
2024 {
2025 OMX_AUDIO_PORTDEFINITIONTYPE *audioDef = &def.format.audio;
2026
2027 printf("\n");
2028 printf(" // Audio\n");
2029 printf(" eEncoding = %s\n",
2030 audioCodingTypeString(audioDef->eEncoding));
2031
2032 if (audioDef->eEncoding == OMX_AUDIO_CodingPCM) {
2033 OMX_AUDIO_PARAM_PCMMODETYPE params;
2034 params.nSize = sizeof(params);
2035 params.nVersion.s.nVersionMajor = 1;
2036 params.nVersion.s.nVersionMinor = 1;
2037 params.nPortIndex = portIndex;
2038
2039 err = mOMX->get_parameter(
2040 mNode, OMX_IndexParamAudioPcm, &params, sizeof(params));
2041 CHECK_EQ(err, OK);
2042
2043 printf(" nSamplingRate = %ld\n", params.nSamplingRate);
2044 printf(" nChannels = %ld\n", params.nChannels);
2045 printf(" bInterleaved = %d\n", params.bInterleaved);
2046 printf(" nBitPerSample = %ld\n", params.nBitPerSample);
2047
2048 printf(" eNumData = %s\n",
2049 params.eNumData == OMX_NumericalDataSigned
2050 ? "signed" : "unsigned");
2051
2052 printf(" ePCMMode = %s\n", audioPCMModeString(params.ePCMMode));
2053 }
2054
2055 break;
2056 }
2057
2058 default:
2059 {
2060 printf(" // Unknown\n");
2061 break;
2062 }
2063 }
2064
2065 printf("}\n");
2066}
2067
2068void OMXCodec::initOutputFormat(const sp<MetaData> &inputFormat) {
2069 mOutputFormat = new MetaData;
2070 mOutputFormat->setCString(kKeyDecoderComponent, mComponentName);
2071
2072 OMX_PARAM_PORTDEFINITIONTYPE def;
2073 def.nSize = sizeof(def);
2074 def.nVersion.s.nVersionMajor = 1;
2075 def.nVersion.s.nVersionMinor = 1;
2076 def.nPortIndex = kPortIndexOutput;
2077
2078 status_t err = mOMX->get_parameter(
2079 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
2080 CHECK_EQ(err, OK);
2081
2082 switch (def.eDomain) {
2083 case OMX_PortDomainImage:
2084 {
2085 OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
2086 CHECK_EQ(imageDef->eCompressionFormat, OMX_IMAGE_CodingUnused);
2087
2088 mOutputFormat->setCString(kKeyMIMEType, "image/raw");
2089 mOutputFormat->setInt32(kKeyColorFormat, imageDef->eColorFormat);
2090 mOutputFormat->setInt32(kKeyWidth, imageDef->nFrameWidth);
2091 mOutputFormat->setInt32(kKeyHeight, imageDef->nFrameHeight);
2092 break;
2093 }
2094
2095 case OMX_PortDomainAudio:
2096 {
2097 OMX_AUDIO_PORTDEFINITIONTYPE *audio_def = &def.format.audio;
2098
2099 CHECK_EQ(audio_def->eEncoding, OMX_AUDIO_CodingPCM);
2100
2101 OMX_AUDIO_PARAM_PCMMODETYPE params;
2102 params.nSize = sizeof(params);
2103 params.nVersion.s.nVersionMajor = 1;
2104 params.nVersion.s.nVersionMinor = 1;
2105 params.nPortIndex = kPortIndexOutput;
2106
2107 err = mOMX->get_parameter(
2108 mNode, OMX_IndexParamAudioPcm, &params, sizeof(params));
2109 CHECK_EQ(err, OK);
2110
2111 CHECK_EQ(params.eNumData, OMX_NumericalDataSigned);
2112 CHECK_EQ(params.nBitPerSample, 16);
2113 CHECK_EQ(params.ePCMMode, OMX_AUDIO_PCMModeLinear);
2114
2115 int32_t numChannels, sampleRate;
2116 inputFormat->findInt32(kKeyChannelCount, &numChannels);
2117 inputFormat->findInt32(kKeySampleRate, &sampleRate);
2118
2119 mOutputFormat->setCString(kKeyMIMEType, "audio/raw");
2120 mOutputFormat->setInt32(kKeyChannelCount, numChannels);
2121 mOutputFormat->setInt32(kKeySampleRate, sampleRate);
2122 break;
2123 }
2124
2125 case OMX_PortDomainVideo:
2126 {
2127 OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
2128
2129 if (video_def->eCompressionFormat == OMX_VIDEO_CodingUnused) {
2130 mOutputFormat->setCString(kKeyMIMEType, "video/raw");
2131 } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingMPEG4) {
2132 mOutputFormat->setCString(kKeyMIMEType, "video/mp4v-es");
2133 } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingH263) {
2134 mOutputFormat->setCString(kKeyMIMEType, "video/3gpp");
2135 } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingAVC) {
2136 mOutputFormat->setCString(kKeyMIMEType, "video/avc");
2137 } else {
2138 CHECK(!"Unknown compression format.");
2139 }
2140
2141 if (!strcmp(mComponentName, "OMX.PV.avcdec")) {
2142 // This component appears to be lying to me.
2143 mOutputFormat->setInt32(
2144 kKeyWidth, (video_def->nFrameWidth + 15) & -16);
2145 mOutputFormat->setInt32(
2146 kKeyHeight, (video_def->nFrameHeight + 15) & -16);
2147 } else {
2148 mOutputFormat->setInt32(kKeyWidth, video_def->nFrameWidth);
2149 mOutputFormat->setInt32(kKeyHeight, video_def->nFrameHeight);
2150 }
2151
2152 mOutputFormat->setInt32(kKeyColorFormat, video_def->eColorFormat);
2153 break;
2154 }
2155
2156 default:
2157 {
2158 CHECK(!"should not be here, neither audio nor video.");
2159 break;
2160 }
2161 }
2162}
2163
2164} // namespace android