blob: 7c8defc02ddd2994687dd4c2a512ed3417bb0221 [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)) {
Andreas Huber43ad6eaf2009-09-01 16:02:43 -0700305 int32_t numChannels, sampleRate;
306 CHECK(meta->findInt32(kKeyChannelCount, &numChannels));
307 CHECK(meta->findInt32(kKeySampleRate, &sampleRate));
308
309 codec->setAACFormat(numChannels, sampleRate);
Andreas Huberbe06d262009-08-14 14:37:10 -0700310 }
311 if (!strncasecmp(mime, "video/", 6)) {
312 int32_t width, height;
313 bool success = meta->findInt32(kKeyWidth, &width);
314 success = success && meta->findInt32(kKeyHeight, &height);
Andreas Huber5c0a9132009-08-20 11:16:40 -0700315 CHECK(success);
Andreas Huberbe06d262009-08-14 14:37:10 -0700316
317 if (createEncoder) {
318 codec->setVideoInputFormat(mime, width, height);
319 } else {
320 codec->setVideoOutputFormat(mime, width, height);
321 }
322 }
323 if (!strcasecmp(mime, "image/jpeg")
324 && !strcmp(componentName, "OMX.TI.JPEG.decode")) {
325 OMX_COLOR_FORMATTYPE format =
326 OMX_COLOR_Format32bitARGB8888;
327 // OMX_COLOR_FormatYUV420PackedPlanar;
328 // OMX_COLOR_FormatCbYCrY;
329 // OMX_COLOR_FormatYUV411Planar;
330
331 int32_t width, height;
332 bool success = meta->findInt32(kKeyWidth, &width);
333 success = success && meta->findInt32(kKeyHeight, &height);
Andreas Huber5c0a9132009-08-20 11:16:40 -0700334
335 int32_t compressedSize;
336 success = success && meta->findInt32(
337 kKeyCompressedSize, &compressedSize);
338
339 CHECK(success);
340 CHECK(compressedSize > 0);
Andreas Huberbe06d262009-08-14 14:37:10 -0700341
342 codec->setImageOutputFormat(format, width, height);
Andreas Huber5c0a9132009-08-20 11:16:40 -0700343 codec->setJPEGInputFormat(width, height, (OMX_U32)compressedSize);
Andreas Huberbe06d262009-08-14 14:37:10 -0700344 }
345
346 codec->initOutputFormat(meta);
347
348 return codec;
349}
350
351status_t OMXCodec::setVideoPortFormatType(
352 OMX_U32 portIndex,
353 OMX_VIDEO_CODINGTYPE compressionFormat,
354 OMX_COLOR_FORMATTYPE colorFormat) {
355 OMX_VIDEO_PARAM_PORTFORMATTYPE format;
356 format.nSize = sizeof(format);
357 format.nVersion.s.nVersionMajor = 1;
358 format.nVersion.s.nVersionMinor = 1;
359 format.nPortIndex = portIndex;
360 format.nIndex = 0;
361 bool found = false;
362
363 OMX_U32 index = 0;
364 for (;;) {
365 format.nIndex = index;
366 status_t err = mOMX->get_parameter(
367 mNode, OMX_IndexParamVideoPortFormat,
368 &format, sizeof(format));
369
370 if (err != OK) {
371 return err;
372 }
373
374 // The following assertion is violated by TI's video decoder.
Andreas Huber5c0a9132009-08-20 11:16:40 -0700375 // CHECK_EQ(format.nIndex, index);
Andreas Huberbe06d262009-08-14 14:37:10 -0700376
377#if 1
378 LOGI("portIndex: %ld, index: %ld, eCompressionFormat=%d eColorFormat=%d",
379 portIndex,
380 index, format.eCompressionFormat, format.eColorFormat);
381#endif
382
383 if (!strcmp("OMX.TI.Video.encoder", mComponentName)) {
384 if (portIndex == kPortIndexInput
385 && colorFormat == format.eColorFormat) {
386 // eCompressionFormat does not seem right.
387 found = true;
388 break;
389 }
390 if (portIndex == kPortIndexOutput
391 && compressionFormat == format.eCompressionFormat) {
392 // eColorFormat does not seem right.
393 found = true;
394 break;
395 }
396 }
397
398 if (format.eCompressionFormat == compressionFormat
399 && format.eColorFormat == colorFormat) {
400 found = true;
401 break;
402 }
403
404 ++index;
405 }
406
407 if (!found) {
408 return UNKNOWN_ERROR;
409 }
410
411 LOGI("found a match.");
412 status_t err = mOMX->set_parameter(
413 mNode, OMX_IndexParamVideoPortFormat,
414 &format, sizeof(format));
415
416 return err;
417}
418
419void OMXCodec::setVideoInputFormat(
420 const char *mime, OMX_U32 width, OMX_U32 height) {
421 LOGI("setVideoInputFormat width=%ld, height=%ld", width, height);
422
423 OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused;
424 if (!strcasecmp("video/avc", mime)) {
425 compressionFormat = OMX_VIDEO_CodingAVC;
426 } else if (!strcasecmp("video/mp4v-es", mime)) {
427 compressionFormat = OMX_VIDEO_CodingMPEG4;
428 } else if (!strcasecmp("video/3gpp", mime)) {
429 compressionFormat = OMX_VIDEO_CodingH263;
430 } else {
431 LOGE("Not a supported video mime type: %s", mime);
432 CHECK(!"Should not be here. Not a supported video mime type.");
433 }
434
435 OMX_COLOR_FORMATTYPE colorFormat =
436 0 ? OMX_COLOR_FormatYCbYCr : OMX_COLOR_FormatCbYCrY;
437
438 if (!strncmp("OMX.qcom.video.encoder.", mComponentName, 23)) {
439 colorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
440 }
441
442 setVideoPortFormatType(
443 kPortIndexInput, OMX_VIDEO_CodingUnused,
444 colorFormat);
445
446 setVideoPortFormatType(
447 kPortIndexOutput, compressionFormat, OMX_COLOR_FormatUnused);
448
449 OMX_PARAM_PORTDEFINITIONTYPE def;
450 OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
451
452 def.nSize = sizeof(def);
453 def.nVersion.s.nVersionMajor = 1;
454 def.nVersion.s.nVersionMinor = 1;
455 def.nPortIndex = kPortIndexOutput;
456
457 status_t err = mOMX->get_parameter(
458 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
459
460 CHECK_EQ(err, OK);
461 CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
462
463 video_def->nFrameWidth = width;
464 video_def->nFrameHeight = height;
465
466 video_def->eCompressionFormat = compressionFormat;
467 video_def->eColorFormat = OMX_COLOR_FormatUnused;
468
469 err = mOMX->set_parameter(
470 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
471 CHECK_EQ(err, OK);
472
473 ////////////////////////////////////////////////////////////////////////////
474
475 def.nSize = sizeof(def);
476 def.nVersion.s.nVersionMajor = 1;
477 def.nVersion.s.nVersionMinor = 1;
478 def.nPortIndex = kPortIndexInput;
479
480 err = mOMX->get_parameter(
481 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
482 CHECK_EQ(err, OK);
483
484 def.nBufferSize = (width * height * 2); // (width * height * 3) / 2;
485 LOGI("setting nBufferSize = %ld", def.nBufferSize);
486
487 CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
488
489 video_def->nFrameWidth = width;
490 video_def->nFrameHeight = height;
491 video_def->eCompressionFormat = OMX_VIDEO_CodingUnused;
492 video_def->eColorFormat = colorFormat;
493
494 err = mOMX->set_parameter(
495 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
496 CHECK_EQ(err, OK);
497}
498
499void OMXCodec::setVideoOutputFormat(
500 const char *mime, OMX_U32 width, OMX_U32 height) {
501 LOGI("setVideoOutputFormat width=%ld, height=%ld", width, height);
502
503 // Enabling this code appears to be the right thing(tm), but,...
504 // the TI decoder then loses the ability to output YUV420 and only outputs
505 // YCbYCr (16bit)
Andreas Huber813a8752009-08-27 15:28:12 -0700506
Andreas Huberb5ceb9e2009-08-26 14:48:20 -0700507#if 1
Andreas Huber813a8752009-08-27 15:28:12 -0700508 if (!strcmp("OMX.TI.Video.Decoder", mComponentName)) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700509 OMX_PARAM_COMPONENTROLETYPE role;
510 role.nSize = sizeof(role);
511 role.nVersion.s.nVersionMajor = 1;
512 role.nVersion.s.nVersionMinor = 1;
Andreas Huber813a8752009-08-27 15:28:12 -0700513
514 if (!strcasecmp("video/avc", mime)) {
515 strncpy((char *)role.cRole, "video_decoder.avc",
516 OMX_MAX_STRINGNAME_SIZE - 1);
517 } else if (!strcasecmp("video/mp4v-es", mime)) {
518 strncpy((char *)role.cRole, "video_decoder.mpeg4",
519 OMX_MAX_STRINGNAME_SIZE - 1);
520 } else if (!strcasecmp("video/3gpp", mime)) {
521 strncpy((char *)role.cRole, "video_decoder.h263",
522 OMX_MAX_STRINGNAME_SIZE - 1);
523 }
524
Andreas Huberbe06d262009-08-14 14:37:10 -0700525 role.cRole[OMX_MAX_STRINGNAME_SIZE - 1] = '\0';
526
527 status_t err = mOMX->set_parameter(
528 mNode, OMX_IndexParamStandardComponentRole,
529 &role, sizeof(role));
530 CHECK_EQ(err, OK);
531 }
Andreas Huberb5ceb9e2009-08-26 14:48:20 -0700532#endif
Andreas Huberbe06d262009-08-14 14:37:10 -0700533
534 OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused;
535 if (!strcasecmp("video/avc", mime)) {
536 compressionFormat = OMX_VIDEO_CodingAVC;
537 } else if (!strcasecmp("video/mp4v-es", mime)) {
538 compressionFormat = OMX_VIDEO_CodingMPEG4;
539 } else if (!strcasecmp("video/3gpp", mime)) {
540 compressionFormat = OMX_VIDEO_CodingH263;
541 } else {
542 LOGE("Not a supported video mime type: %s", mime);
543 CHECK(!"Should not be here. Not a supported video mime type.");
544 }
545
546 setVideoPortFormatType(
547 kPortIndexInput, compressionFormat, OMX_COLOR_FormatUnused);
548
549#if 1
550 {
551 OMX_VIDEO_PARAM_PORTFORMATTYPE format;
552 format.nSize = sizeof(format);
553 format.nVersion.s.nVersionMajor = 1;
554 format.nVersion.s.nVersionMinor = 1;
555 format.nPortIndex = kPortIndexOutput;
556 format.nIndex = 0;
557
558 status_t err = mOMX->get_parameter(
559 mNode, OMX_IndexParamVideoPortFormat,
560 &format, sizeof(format));
561 CHECK_EQ(err, OK);
562 CHECK_EQ(format.eCompressionFormat, OMX_VIDEO_CodingUnused);
563
564 static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
565
566 CHECK(format.eColorFormat == OMX_COLOR_FormatYUV420Planar
567 || format.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar
568 || format.eColorFormat == OMX_COLOR_FormatCbYCrY
569 || format.eColorFormat == OMX_QCOM_COLOR_FormatYVU420SemiPlanar);
570
571 err = mOMX->set_parameter(
572 mNode, OMX_IndexParamVideoPortFormat,
573 &format, sizeof(format));
574 CHECK_EQ(err, OK);
575 }
576#endif
577
578 OMX_PARAM_PORTDEFINITIONTYPE def;
579 OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
580
581 def.nSize = sizeof(def);
582 def.nVersion.s.nVersionMajor = 1;
583 def.nVersion.s.nVersionMinor = 1;
584 def.nPortIndex = kPortIndexInput;
585
586 status_t err = mOMX->get_parameter(
587 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
588
589 CHECK_EQ(err, OK);
590
591#if 1
592 // XXX Need a (much) better heuristic to compute input buffer sizes.
593 const size_t X = 64 * 1024;
594 if (def.nBufferSize < X) {
595 def.nBufferSize = X;
596 }
597#endif
598
599 CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
600
601 video_def->nFrameWidth = width;
602 video_def->nFrameHeight = height;
603
604 video_def->eColorFormat = OMX_COLOR_FormatUnused;
605
606 err = mOMX->set_parameter(
607 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
608 CHECK_EQ(err, OK);
609
610 ////////////////////////////////////////////////////////////////////////////
611
612 def.nSize = sizeof(def);
613 def.nVersion.s.nVersionMajor = 1;
614 def.nVersion.s.nVersionMinor = 1;
615 def.nPortIndex = kPortIndexOutput;
616
617 err = mOMX->get_parameter(
618 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
619 CHECK_EQ(err, OK);
620 CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
621
622#if 0
623 def.nBufferSize =
624 (((width + 15) & -16) * ((height + 15) & -16) * 3) / 2; // YUV420
625#endif
626
627 video_def->nFrameWidth = width;
628 video_def->nFrameHeight = height;
629
630 err = mOMX->set_parameter(
631 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
632 CHECK_EQ(err, OK);
633}
634
635
636OMXCodec::OMXCodec(
637 const sp<IOMX> &omx, IOMX::node_id node, uint32_t quirks,
Andreas Huberebf66ea2009-08-19 13:32:58 -0700638 bool isEncoder,
Andreas Huberbe06d262009-08-14 14:37:10 -0700639 const char *mime,
640 const char *componentName,
641 const sp<MediaSource> &source)
642 : mOMX(omx),
643 mNode(node),
644 mQuirks(quirks),
645 mIsEncoder(isEncoder),
646 mMIME(strdup(mime)),
647 mComponentName(strdup(componentName)),
648 mSource(source),
649 mCodecSpecificDataIndex(0),
Andreas Huberbe06d262009-08-14 14:37:10 -0700650 mState(LOADED),
Andreas Huber42978e52009-08-27 10:08:39 -0700651 mInitialBufferSubmit(true),
Andreas Huberbe06d262009-08-14 14:37:10 -0700652 mSignalledEOS(false),
653 mNoMoreOutputData(false),
654 mSeekTimeUs(-1) {
655 mPortStatus[kPortIndexInput] = ENABLED;
656 mPortStatus[kPortIndexOutput] = ENABLED;
657
658 mObserver = new OMXCodecObserver(this);
659 mOMX->observe_node(mNode, mObserver);
660}
661
662OMXCodec::~OMXCodec() {
Andreas Huber4f5e6022009-08-19 09:29:34 -0700663 CHECK(mState == LOADED || mState == ERROR);
Andreas Huberbe06d262009-08-14 14:37:10 -0700664
665 status_t err = mOMX->observe_node(mNode, NULL);
666 CHECK_EQ(err, OK);
667
668 err = mOMX->free_node(mNode);
669 CHECK_EQ(err, OK);
670
671 mNode = NULL;
672 setState(DEAD);
673
674 clearCodecSpecificData();
675
676 free(mComponentName);
677 mComponentName = NULL;
Andreas Huberebf66ea2009-08-19 13:32:58 -0700678
Andreas Huberbe06d262009-08-14 14:37:10 -0700679 free(mMIME);
680 mMIME = NULL;
681}
682
683status_t OMXCodec::init() {
Andreas Huber42978e52009-08-27 10:08:39 -0700684 // mLock is held.
Andreas Huberbe06d262009-08-14 14:37:10 -0700685
686 CHECK_EQ(mState, LOADED);
687
688 status_t err;
689 if (!(mQuirks & kRequiresLoadedToIdleAfterAllocation)) {
690 err = mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
691 CHECK_EQ(err, OK);
692
693 setState(LOADED_TO_IDLE);
694 }
695
696 err = allocateBuffers();
697 CHECK_EQ(err, OK);
698
699 if (mQuirks & kRequiresLoadedToIdleAfterAllocation) {
700 err = mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
701 CHECK_EQ(err, OK);
702
703 setState(LOADED_TO_IDLE);
704 }
705
706 while (mState != EXECUTING && mState != ERROR) {
707 mAsyncCompletion.wait(mLock);
708 }
709
710 return mState == ERROR ? UNKNOWN_ERROR : OK;
711}
712
713// static
714bool OMXCodec::isIntermediateState(State state) {
715 return state == LOADED_TO_IDLE
716 || state == IDLE_TO_EXECUTING
717 || state == EXECUTING_TO_IDLE
718 || state == IDLE_TO_LOADED
719 || state == RECONFIGURING;
720}
721
722status_t OMXCodec::allocateBuffers() {
723 status_t err = allocateBuffersOnPort(kPortIndexInput);
724
725 if (err != OK) {
726 return err;
727 }
728
729 return allocateBuffersOnPort(kPortIndexOutput);
730}
731
732status_t OMXCodec::allocateBuffersOnPort(OMX_U32 portIndex) {
733 OMX_PARAM_PORTDEFINITIONTYPE def;
734 def.nSize = sizeof(def);
735 def.nVersion.s.nVersionMajor = 1;
736 def.nVersion.s.nVersionMinor = 1;
737 def.nVersion.s.nRevision = 0;
738 def.nVersion.s.nStep = 0;
739 def.nPortIndex = portIndex;
740
741 status_t err = mOMX->get_parameter(
742 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
743
744 if (err != OK) {
745 return err;
746 }
747
Andreas Huber5c0a9132009-08-20 11:16:40 -0700748 size_t totalSize = def.nBufferCountActual * def.nBufferSize;
749 mDealer[portIndex] = new MemoryDealer(totalSize);
750
Andreas Huberbe06d262009-08-14 14:37:10 -0700751 for (OMX_U32 i = 0; i < def.nBufferCountActual; ++i) {
Andreas Huber5c0a9132009-08-20 11:16:40 -0700752 sp<IMemory> mem = mDealer[portIndex]->allocate(def.nBufferSize);
Andreas Huberbe06d262009-08-14 14:37:10 -0700753 CHECK(mem.get() != NULL);
754
755 IOMX::buffer_id buffer;
756 if (portIndex == kPortIndexInput
757 && (mQuirks & kRequiresAllocateBufferOnInputPorts)) {
758 err = mOMX->allocate_buffer_with_backup(
759 mNode, portIndex, mem, &buffer);
Andreas Huber446f44f2009-08-25 17:23:44 -0700760 } else if (portIndex == kPortIndexOutput
761 && (mQuirks & kRequiresAllocateBufferOnOutputPorts)) {
762 err = mOMX->allocate_buffer(
763 mNode, portIndex, def.nBufferSize, &buffer);
Andreas Huberbe06d262009-08-14 14:37:10 -0700764 } else {
765 err = mOMX->use_buffer(mNode, portIndex, mem, &buffer);
766 }
767
768 if (err != OK) {
769 LOGE("allocate_buffer_with_backup failed");
770 return err;
771 }
772
773 BufferInfo info;
774 info.mBuffer = buffer;
775 info.mOwnedByComponent = false;
776 info.mMem = mem;
777 info.mMediaBuffer = NULL;
778
779 if (portIndex == kPortIndexOutput) {
780 info.mMediaBuffer = new MediaBuffer(mem->pointer(), mem->size());
781 info.mMediaBuffer->setObserver(this);
782 }
783
784 mPortBuffers[portIndex].push(info);
785
786 LOGV("allocated buffer %p on %s port", buffer,
787 portIndex == kPortIndexInput ? "input" : "output");
788 }
789
790 dumpPortStatus(portIndex);
791
792 return OK;
793}
794
795void OMXCodec::on_message(const omx_message &msg) {
796 Mutex::Autolock autoLock(mLock);
797
798 switch (msg.type) {
799 case omx_message::EVENT:
800 {
801 onEvent(
802 msg.u.event_data.event, msg.u.event_data.data1,
803 msg.u.event_data.data2);
804
805 break;
806 }
807
808 case omx_message::EMPTY_BUFFER_DONE:
809 {
810 IOMX::buffer_id buffer = msg.u.extended_buffer_data.buffer;
811
812 LOGV("EMPTY_BUFFER_DONE(buffer: %p)", buffer);
813
814 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
815 size_t i = 0;
816 while (i < buffers->size() && (*buffers)[i].mBuffer != buffer) {
817 ++i;
818 }
819
820 CHECK(i < buffers->size());
821 if (!(*buffers)[i].mOwnedByComponent) {
822 LOGW("We already own input buffer %p, yet received "
823 "an EMPTY_BUFFER_DONE.", buffer);
824 }
825
826 buffers->editItemAt(i).mOwnedByComponent = false;
827
828 if (mPortStatus[kPortIndexInput] == DISABLING) {
829 LOGV("Port is disabled, freeing buffer %p", buffer);
830
831 status_t err =
832 mOMX->free_buffer(mNode, kPortIndexInput, buffer);
833 CHECK_EQ(err, OK);
834
835 buffers->removeAt(i);
836 } else if (mPortStatus[kPortIndexInput] != SHUTTING_DOWN) {
837 CHECK_EQ(mPortStatus[kPortIndexInput], ENABLED);
838 drainInputBuffer(&buffers->editItemAt(i));
839 }
840
841 break;
842 }
843
844 case omx_message::FILL_BUFFER_DONE:
845 {
846 IOMX::buffer_id buffer = msg.u.extended_buffer_data.buffer;
847 OMX_U32 flags = msg.u.extended_buffer_data.flags;
848
849 LOGV("FILL_BUFFER_DONE(buffer: %p, size: %ld, flags: 0x%08lx)",
850 buffer,
851 msg.u.extended_buffer_data.range_length,
852 flags);
853
854 LOGV("FILL_BUFFER_DONE(timestamp: %lld us (%.2f secs))",
855 msg.u.extended_buffer_data.timestamp,
856 msg.u.extended_buffer_data.timestamp / 1E6);
857
858 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
859 size_t i = 0;
860 while (i < buffers->size() && (*buffers)[i].mBuffer != buffer) {
861 ++i;
862 }
863
864 CHECK(i < buffers->size());
865 BufferInfo *info = &buffers->editItemAt(i);
866
867 if (!info->mOwnedByComponent) {
868 LOGW("We already own output buffer %p, yet received "
869 "a FILL_BUFFER_DONE.", buffer);
870 }
871
872 info->mOwnedByComponent = false;
873
874 if (mPortStatus[kPortIndexOutput] == DISABLING) {
875 LOGV("Port is disabled, freeing buffer %p", buffer);
876
877 status_t err =
878 mOMX->free_buffer(mNode, kPortIndexOutput, buffer);
879 CHECK_EQ(err, OK);
880
881 buffers->removeAt(i);
Andreas Huberd7795892009-08-26 10:33:47 -0700882 } else if (mPortStatus[kPortIndexOutput] == ENABLED
883 && (flags & OMX_BUFFERFLAG_EOS)) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700884 LOGV("No more output data.");
885 mNoMoreOutputData = true;
886 mBufferFilled.signal();
887 } else if (mPortStatus[kPortIndexOutput] != SHUTTING_DOWN) {
888 CHECK_EQ(mPortStatus[kPortIndexOutput], ENABLED);
Andreas Huberebf66ea2009-08-19 13:32:58 -0700889
Andreas Huberbe06d262009-08-14 14:37:10 -0700890 MediaBuffer *buffer = info->mMediaBuffer;
891
892 buffer->set_range(
893 msg.u.extended_buffer_data.range_offset,
894 msg.u.extended_buffer_data.range_length);
895
896 buffer->meta_data()->clear();
897
898 buffer->meta_data()->setInt32(
899 kKeyTimeUnits,
900 (msg.u.extended_buffer_data.timestamp + 500) / 1000);
901
902 buffer->meta_data()->setInt32(
903 kKeyTimeScale, 1000);
904
905 if (msg.u.extended_buffer_data.flags & OMX_BUFFERFLAG_SYNCFRAME) {
906 buffer->meta_data()->setInt32(kKeyIsSyncFrame, true);
907 }
908
909 buffer->meta_data()->setPointer(
910 kKeyPlatformPrivate,
911 msg.u.extended_buffer_data.platform_private);
912
913 buffer->meta_data()->setPointer(
914 kKeyBufferID,
915 msg.u.extended_buffer_data.buffer);
916
917 mFilledBuffers.push_back(i);
918 mBufferFilled.signal();
919 }
920
921 break;
922 }
923
924 default:
925 {
926 CHECK(!"should not be here.");
927 break;
928 }
929 }
930}
931
932void OMXCodec::onEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) {
933 switch (event) {
934 case OMX_EventCmdComplete:
935 {
936 onCmdComplete((OMX_COMMANDTYPE)data1, data2);
937 break;
938 }
939
940 case OMX_EventError:
941 {
942 LOGE("ERROR(%ld, %ld)", data1, data2);
943
944 setState(ERROR);
945 break;
946 }
947
948 case OMX_EventPortSettingsChanged:
949 {
950 onPortSettingsChanged(data1);
951 break;
952 }
953
954 case OMX_EventBufferFlag:
955 {
956 LOGV("EVENT_BUFFER_FLAG(%ld)", data1);
957
958 if (data1 == kPortIndexOutput) {
959 mNoMoreOutputData = true;
960 }
961 break;
962 }
963
964 default:
965 {
966 LOGV("EVENT(%d, %ld, %ld)", event, data1, data2);
967 break;
968 }
969 }
970}
971
972void OMXCodec::onCmdComplete(OMX_COMMANDTYPE cmd, OMX_U32 data) {
973 switch (cmd) {
974 case OMX_CommandStateSet:
975 {
976 onStateChange((OMX_STATETYPE)data);
977 break;
978 }
979
980 case OMX_CommandPortDisable:
981 {
982 OMX_U32 portIndex = data;
983 LOGV("PORT_DISABLED(%ld)", portIndex);
984
985 CHECK(mState == EXECUTING || mState == RECONFIGURING);
986 CHECK_EQ(mPortStatus[portIndex], DISABLING);
987 CHECK_EQ(mPortBuffers[portIndex].size(), 0);
988
989 mPortStatus[portIndex] = DISABLED;
990
991 if (mState == RECONFIGURING) {
992 CHECK_EQ(portIndex, kPortIndexOutput);
993
994 enablePortAsync(portIndex);
995
996 status_t err = allocateBuffersOnPort(portIndex);
997 CHECK_EQ(err, OK);
998 }
999 break;
1000 }
1001
1002 case OMX_CommandPortEnable:
1003 {
1004 OMX_U32 portIndex = data;
1005 LOGV("PORT_ENABLED(%ld)", portIndex);
1006
1007 CHECK(mState == EXECUTING || mState == RECONFIGURING);
1008 CHECK_EQ(mPortStatus[portIndex], ENABLING);
1009
1010 mPortStatus[portIndex] = ENABLED;
1011
1012 if (mState == RECONFIGURING) {
1013 CHECK_EQ(portIndex, kPortIndexOutput);
1014
1015 setState(EXECUTING);
1016
1017 fillOutputBuffers();
1018 }
1019 break;
1020 }
1021
1022 case OMX_CommandFlush:
1023 {
1024 OMX_U32 portIndex = data;
1025
1026 LOGV("FLUSH_DONE(%ld)", portIndex);
1027
1028 CHECK_EQ(mPortStatus[portIndex], SHUTTING_DOWN);
1029 mPortStatus[portIndex] = ENABLED;
1030
1031 CHECK_EQ(countBuffersWeOwn(mPortBuffers[portIndex]),
1032 mPortBuffers[portIndex].size());
1033
1034 if (mState == RECONFIGURING) {
1035 CHECK_EQ(portIndex, kPortIndexOutput);
1036
1037 disablePortAsync(portIndex);
Andreas Huber127fcdc2009-08-26 16:27:02 -07001038 } else if (mState == EXECUTING_TO_IDLE) {
1039 if (mPortStatus[kPortIndexInput] == ENABLED
1040 && mPortStatus[kPortIndexOutput] == ENABLED) {
1041 LOGV("Finished flushing both ports, now completing "
1042 "transition from EXECUTING to IDLE.");
1043
1044 mPortStatus[kPortIndexInput] = SHUTTING_DOWN;
1045 mPortStatus[kPortIndexOutput] = SHUTTING_DOWN;
1046
1047 status_t err =
1048 mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
1049 CHECK_EQ(err, OK);
1050 }
Andreas Huberbe06d262009-08-14 14:37:10 -07001051 } else {
1052 // We're flushing both ports in preparation for seeking.
1053
1054 if (mPortStatus[kPortIndexInput] == ENABLED
1055 && mPortStatus[kPortIndexOutput] == ENABLED) {
1056 LOGV("Finished flushing both ports, now continuing from"
1057 " seek-time.");
1058
1059 drainInputBuffers();
1060 fillOutputBuffers();
1061 }
1062 }
1063
1064 break;
1065 }
1066
1067 default:
1068 {
1069 LOGV("CMD_COMPLETE(%d, %ld)", cmd, data);
1070 break;
1071 }
1072 }
1073}
1074
1075void OMXCodec::onStateChange(OMX_STATETYPE newState) {
1076 switch (newState) {
1077 case OMX_StateIdle:
1078 {
1079 LOGV("Now Idle.");
1080 if (mState == LOADED_TO_IDLE) {
1081 status_t err = mOMX->send_command(
1082 mNode, OMX_CommandStateSet, OMX_StateExecuting);
1083
1084 CHECK_EQ(err, OK);
1085
1086 setState(IDLE_TO_EXECUTING);
1087 } else {
1088 CHECK_EQ(mState, EXECUTING_TO_IDLE);
1089
1090 CHECK_EQ(
1091 countBuffersWeOwn(mPortBuffers[kPortIndexInput]),
1092 mPortBuffers[kPortIndexInput].size());
1093
1094 CHECK_EQ(
1095 countBuffersWeOwn(mPortBuffers[kPortIndexOutput]),
1096 mPortBuffers[kPortIndexOutput].size());
1097
1098 status_t err = mOMX->send_command(
1099 mNode, OMX_CommandStateSet, OMX_StateLoaded);
1100
1101 CHECK_EQ(err, OK);
1102
1103 err = freeBuffersOnPort(kPortIndexInput);
1104 CHECK_EQ(err, OK);
1105
1106 err = freeBuffersOnPort(kPortIndexOutput);
1107 CHECK_EQ(err, OK);
1108
1109 mPortStatus[kPortIndexInput] = ENABLED;
1110 mPortStatus[kPortIndexOutput] = ENABLED;
1111
1112 setState(IDLE_TO_LOADED);
1113 }
1114 break;
1115 }
1116
1117 case OMX_StateExecuting:
1118 {
1119 CHECK_EQ(mState, IDLE_TO_EXECUTING);
1120
1121 LOGV("Now Executing.");
1122
1123 setState(EXECUTING);
1124
Andreas Huber42978e52009-08-27 10:08:39 -07001125 // Buffers will be submitted to the component in the first
1126 // call to OMXCodec::read as mInitialBufferSubmit is true at
1127 // this point. This ensures that this on_message call returns,
1128 // releases the lock and ::init can notice the state change and
1129 // itself return.
Andreas Huberbe06d262009-08-14 14:37:10 -07001130 break;
1131 }
1132
1133 case OMX_StateLoaded:
1134 {
1135 CHECK_EQ(mState, IDLE_TO_LOADED);
1136
1137 LOGV("Now Loaded.");
1138
1139 setState(LOADED);
1140 break;
1141 }
1142
1143 default:
1144 {
1145 CHECK(!"should not be here.");
1146 break;
1147 }
1148 }
1149}
1150
1151// static
1152size_t OMXCodec::countBuffersWeOwn(const Vector<BufferInfo> &buffers) {
1153 size_t n = 0;
1154 for (size_t i = 0; i < buffers.size(); ++i) {
1155 if (!buffers[i].mOwnedByComponent) {
1156 ++n;
1157 }
1158 }
1159
1160 return n;
1161}
1162
1163status_t OMXCodec::freeBuffersOnPort(
1164 OMX_U32 portIndex, bool onlyThoseWeOwn) {
1165 Vector<BufferInfo> *buffers = &mPortBuffers[portIndex];
1166
1167 status_t stickyErr = OK;
1168
1169 for (size_t i = buffers->size(); i-- > 0;) {
1170 BufferInfo *info = &buffers->editItemAt(i);
1171
1172 if (onlyThoseWeOwn && info->mOwnedByComponent) {
1173 continue;
1174 }
1175
1176 CHECK_EQ(info->mOwnedByComponent, false);
1177
1178 status_t err =
1179 mOMX->free_buffer(mNode, portIndex, info->mBuffer);
1180
1181 if (err != OK) {
1182 stickyErr = err;
1183 }
1184
1185 if (info->mMediaBuffer != NULL) {
1186 info->mMediaBuffer->setObserver(NULL);
1187
1188 // Make sure nobody but us owns this buffer at this point.
1189 CHECK_EQ(info->mMediaBuffer->refcount(), 0);
1190
1191 info->mMediaBuffer->release();
1192 }
1193
1194 buffers->removeAt(i);
1195 }
1196
1197 CHECK(onlyThoseWeOwn || buffers->isEmpty());
1198
1199 return stickyErr;
1200}
1201
1202void OMXCodec::onPortSettingsChanged(OMX_U32 portIndex) {
1203 LOGV("PORT_SETTINGS_CHANGED(%ld)", portIndex);
1204
1205 CHECK_EQ(mState, EXECUTING);
1206 CHECK_EQ(portIndex, kPortIndexOutput);
1207 setState(RECONFIGURING);
1208
1209 if (mQuirks & kNeedsFlushBeforeDisable) {
Andreas Huber404cc412009-08-25 14:26:05 -07001210 if (!flushPortAsync(portIndex)) {
1211 onCmdComplete(OMX_CommandFlush, portIndex);
1212 }
Andreas Huberbe06d262009-08-14 14:37:10 -07001213 } else {
1214 disablePortAsync(portIndex);
1215 }
1216}
1217
Andreas Huber404cc412009-08-25 14:26:05 -07001218bool OMXCodec::flushPortAsync(OMX_U32 portIndex) {
Andreas Huber127fcdc2009-08-26 16:27:02 -07001219 CHECK(mState == EXECUTING || mState == RECONFIGURING
1220 || mState == EXECUTING_TO_IDLE);
Andreas Huberbe06d262009-08-14 14:37:10 -07001221
Andreas Huber404cc412009-08-25 14:26:05 -07001222 LOGV("flushPortAsync(%ld): we own %d out of %d buffers already.",
1223 portIndex, countBuffersWeOwn(mPortBuffers[portIndex]),
1224 mPortBuffers[portIndex].size());
1225
Andreas Huberbe06d262009-08-14 14:37:10 -07001226 CHECK_EQ(mPortStatus[portIndex], ENABLED);
1227 mPortStatus[portIndex] = SHUTTING_DOWN;
1228
Andreas Huber404cc412009-08-25 14:26:05 -07001229 if ((mQuirks & kRequiresFlushCompleteEmulation)
1230 && countBuffersWeOwn(mPortBuffers[portIndex])
1231 == mPortBuffers[portIndex].size()) {
1232 // No flush is necessary and this component fails to send a
1233 // flush-complete event in this case.
1234
1235 return false;
1236 }
1237
Andreas Huberbe06d262009-08-14 14:37:10 -07001238 status_t err =
1239 mOMX->send_command(mNode, OMX_CommandFlush, portIndex);
1240 CHECK_EQ(err, OK);
Andreas Huber404cc412009-08-25 14:26:05 -07001241
1242 return true;
Andreas Huberbe06d262009-08-14 14:37:10 -07001243}
1244
1245void OMXCodec::disablePortAsync(OMX_U32 portIndex) {
1246 CHECK(mState == EXECUTING || mState == RECONFIGURING);
1247
1248 CHECK_EQ(mPortStatus[portIndex], ENABLED);
1249 mPortStatus[portIndex] = DISABLING;
1250
1251 status_t err =
1252 mOMX->send_command(mNode, OMX_CommandPortDisable, portIndex);
1253 CHECK_EQ(err, OK);
1254
1255 freeBuffersOnPort(portIndex, true);
1256}
1257
1258void OMXCodec::enablePortAsync(OMX_U32 portIndex) {
1259 CHECK(mState == EXECUTING || mState == RECONFIGURING);
1260
1261 CHECK_EQ(mPortStatus[portIndex], DISABLED);
1262 mPortStatus[portIndex] = ENABLING;
1263
1264 status_t err =
1265 mOMX->send_command(mNode, OMX_CommandPortEnable, portIndex);
1266 CHECK_EQ(err, OK);
1267}
1268
1269void OMXCodec::fillOutputBuffers() {
1270 CHECK_EQ(mState, EXECUTING);
1271
1272 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
1273 for (size_t i = 0; i < buffers->size(); ++i) {
1274 fillOutputBuffer(&buffers->editItemAt(i));
1275 }
1276}
1277
1278void OMXCodec::drainInputBuffers() {
Andreas Huberd06e5b82009-08-28 13:18:14 -07001279 CHECK(mState == EXECUTING || mState == RECONFIGURING);
Andreas Huberbe06d262009-08-14 14:37:10 -07001280
1281 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
1282 for (size_t i = 0; i < buffers->size(); ++i) {
1283 drainInputBuffer(&buffers->editItemAt(i));
1284 }
1285}
1286
1287void OMXCodec::drainInputBuffer(BufferInfo *info) {
1288 CHECK_EQ(info->mOwnedByComponent, false);
1289
1290 if (mSignalledEOS) {
1291 return;
1292 }
1293
1294 if (mCodecSpecificDataIndex < mCodecSpecificData.size()) {
1295 const CodecSpecificData *specific =
1296 mCodecSpecificData[mCodecSpecificDataIndex];
1297
1298 size_t size = specific->mSize;
1299
Andreas Huber4f5e6022009-08-19 09:29:34 -07001300 if (!strcasecmp("video/avc", mMIME)
1301 && !(mQuirks & kWantsNALFragments)) {
Andreas Huberbe06d262009-08-14 14:37:10 -07001302 static const uint8_t kNALStartCode[4] =
1303 { 0x00, 0x00, 0x00, 0x01 };
1304
1305 CHECK(info->mMem->size() >= specific->mSize + 4);
1306
1307 size += 4;
1308
1309 memcpy(info->mMem->pointer(), kNALStartCode, 4);
1310 memcpy((uint8_t *)info->mMem->pointer() + 4,
1311 specific->mData, specific->mSize);
1312 } else {
1313 CHECK(info->mMem->size() >= specific->mSize);
1314 memcpy(info->mMem->pointer(), specific->mData, specific->mSize);
1315 }
1316
1317 mOMX->empty_buffer(
1318 mNode, info->mBuffer, 0, size,
1319 OMX_BUFFERFLAG_ENDOFFRAME | OMX_BUFFERFLAG_CODECCONFIG,
1320 0);
1321
1322 info->mOwnedByComponent = true;
1323
1324 ++mCodecSpecificDataIndex;
1325 return;
1326 }
1327
1328 MediaBuffer *srcBuffer;
1329 status_t err;
1330 if (mSeekTimeUs >= 0) {
1331 MediaSource::ReadOptions options;
1332 options.setSeekTo(mSeekTimeUs);
1333 mSeekTimeUs = -1;
1334
1335 err = mSource->read(&srcBuffer, &options);
1336 } else {
1337 err = mSource->read(&srcBuffer);
1338 }
1339
1340 OMX_U32 flags = OMX_BUFFERFLAG_ENDOFFRAME;
1341 OMX_TICKS timestamp = 0;
1342 size_t srcLength = 0;
1343
1344 if (err != OK) {
1345 LOGV("signalling end of input stream.");
1346 flags |= OMX_BUFFERFLAG_EOS;
1347
1348 mSignalledEOS = true;
1349 } else {
1350 srcLength = srcBuffer->range_length();
1351
1352 if (info->mMem->size() < srcLength) {
1353 LOGE("info->mMem->size() = %d, srcLength = %d",
1354 info->mMem->size(), srcLength);
1355 }
1356 CHECK(info->mMem->size() >= srcLength);
1357 memcpy(info->mMem->pointer(),
1358 (const uint8_t *)srcBuffer->data() + srcBuffer->range_offset(),
1359 srcLength);
1360
1361 int32_t units, scale;
1362 if (srcBuffer->meta_data()->findInt32(kKeyTimeUnits, &units)
1363 && srcBuffer->meta_data()->findInt32(kKeyTimeScale, &scale)) {
1364 timestamp = ((OMX_TICKS)units * 1000000) / scale;
1365
1366 LOGV("Calling empty_buffer on buffer %p (length %d)",
1367 info->mBuffer, srcLength);
1368 LOGV("Calling empty_buffer with timestamp %lld us (%.2f secs)",
1369 timestamp, timestamp / 1E6);
1370 }
1371 }
1372
1373 mOMX->empty_buffer(
1374 mNode, info->mBuffer, 0, srcLength,
1375 flags, timestamp);
1376
1377 info->mOwnedByComponent = true;
1378
1379 if (srcBuffer != NULL) {
1380 srcBuffer->release();
1381 srcBuffer = NULL;
1382 }
1383}
1384
1385void OMXCodec::fillOutputBuffer(BufferInfo *info) {
1386 CHECK_EQ(info->mOwnedByComponent, false);
1387
Andreas Huber404cc412009-08-25 14:26:05 -07001388 if (mNoMoreOutputData) {
1389 LOGV("There is no more output data available, not "
1390 "calling fillOutputBuffer");
1391 return;
1392 }
1393
Andreas Huberbe06d262009-08-14 14:37:10 -07001394 LOGV("Calling fill_buffer on buffer %p", info->mBuffer);
1395 mOMX->fill_buffer(mNode, info->mBuffer);
1396
1397 info->mOwnedByComponent = true;
1398}
1399
1400void OMXCodec::drainInputBuffer(IOMX::buffer_id buffer) {
1401 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
1402 for (size_t i = 0; i < buffers->size(); ++i) {
1403 if ((*buffers)[i].mBuffer == buffer) {
1404 drainInputBuffer(&buffers->editItemAt(i));
1405 return;
1406 }
1407 }
1408
1409 CHECK(!"should not be here.");
1410}
1411
1412void OMXCodec::fillOutputBuffer(IOMX::buffer_id buffer) {
1413 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
1414 for (size_t i = 0; i < buffers->size(); ++i) {
1415 if ((*buffers)[i].mBuffer == buffer) {
1416 fillOutputBuffer(&buffers->editItemAt(i));
1417 return;
1418 }
1419 }
1420
1421 CHECK(!"should not be here.");
1422}
1423
1424void OMXCodec::setState(State newState) {
1425 mState = newState;
1426 mAsyncCompletion.signal();
1427
1428 // This may cause some spurious wakeups but is necessary to
1429 // unblock the reader if we enter ERROR state.
1430 mBufferFilled.signal();
1431}
1432
1433void OMXCodec::setAMRFormat() {
1434 if (!mIsEncoder) {
1435 OMX_AUDIO_PARAM_AMRTYPE def;
1436 def.nSize = sizeof(def);
1437 def.nVersion.s.nVersionMajor = 1;
1438 def.nVersion.s.nVersionMinor = 1;
1439 def.nPortIndex = kPortIndexInput;
1440
1441 status_t err =
1442 mOMX->get_parameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
1443
1444 CHECK_EQ(err, OK);
1445
1446 def.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
1447 def.eAMRBandMode = OMX_AUDIO_AMRBandModeNB0;
1448
1449 err = mOMX->set_parameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
1450 CHECK_EQ(err, OK);
1451 }
1452
1453 ////////////////////////
1454
1455 if (mIsEncoder) {
1456 sp<MetaData> format = mSource->getFormat();
1457 int32_t sampleRate;
1458 int32_t numChannels;
1459 CHECK(format->findInt32(kKeySampleRate, &sampleRate));
1460 CHECK(format->findInt32(kKeyChannelCount, &numChannels));
1461
1462 OMX_AUDIO_PARAM_PCMMODETYPE pcmParams;
1463 pcmParams.nSize = sizeof(pcmParams);
1464 pcmParams.nVersion.s.nVersionMajor = 1;
1465 pcmParams.nVersion.s.nVersionMinor = 1;
1466 pcmParams.nPortIndex = kPortIndexInput;
1467
1468 status_t err = mOMX->get_parameter(
1469 mNode, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams));
1470
1471 CHECK_EQ(err, OK);
1472
1473 pcmParams.nChannels = numChannels;
1474 pcmParams.eNumData = OMX_NumericalDataSigned;
1475 pcmParams.bInterleaved = OMX_TRUE;
1476 pcmParams.nBitPerSample = 16;
1477 pcmParams.nSamplingRate = sampleRate;
1478 pcmParams.ePCMMode = OMX_AUDIO_PCMModeLinear;
1479
1480 if (numChannels == 1) {
1481 pcmParams.eChannelMapping[0] = OMX_AUDIO_ChannelCF;
1482 } else {
1483 CHECK_EQ(numChannels, 2);
1484
1485 pcmParams.eChannelMapping[0] = OMX_AUDIO_ChannelLF;
1486 pcmParams.eChannelMapping[1] = OMX_AUDIO_ChannelRF;
1487 }
1488
1489 err = mOMX->set_parameter(
1490 mNode, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams));
1491
1492 CHECK_EQ(err, OK);
1493 }
1494}
1495
Andreas Huber43ad6eaf2009-09-01 16:02:43 -07001496void OMXCodec::setAACFormat(int32_t numChannels, int32_t sampleRate) {
1497 OMX_AUDIO_PARAM_AACPROFILETYPE profile;
1498 profile.nSize = sizeof(profile);
1499 profile.nVersion.s.nVersionMajor = 1;
1500 profile.nVersion.s.nVersionMinor = 1;
1501 profile.nPortIndex = kPortIndexInput;
Andreas Huberbe06d262009-08-14 14:37:10 -07001502
1503 status_t err =
Andreas Huber43ad6eaf2009-09-01 16:02:43 -07001504 mOMX->get_parameter(mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile));
Andreas Huberbe06d262009-08-14 14:37:10 -07001505 CHECK_EQ(err, OK);
1506
Andreas Huber43ad6eaf2009-09-01 16:02:43 -07001507 profile.nChannels = numChannels;
1508 profile.nSampleRate = sampleRate;
1509 profile.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4ADTS;
Andreas Huberbe06d262009-08-14 14:37:10 -07001510
Andreas Huber43ad6eaf2009-09-01 16:02:43 -07001511 err = mOMX->set_parameter(mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile));
Andreas Huberbe06d262009-08-14 14:37:10 -07001512 CHECK_EQ(err, OK);
1513}
1514
1515void OMXCodec::setImageOutputFormat(
1516 OMX_COLOR_FORMATTYPE format, OMX_U32 width, OMX_U32 height) {
1517 LOGV("setImageOutputFormat(%ld, %ld)", width, height);
1518
1519#if 0
1520 OMX_INDEXTYPE index;
1521 status_t err = mOMX->get_extension_index(
1522 mNode, "OMX.TI.JPEG.decode.Config.OutputColorFormat", &index);
1523 CHECK_EQ(err, OK);
1524
1525 err = mOMX->set_config(mNode, index, &format, sizeof(format));
1526 CHECK_EQ(err, OK);
1527#endif
1528
1529 OMX_PARAM_PORTDEFINITIONTYPE def;
1530 def.nSize = sizeof(def);
1531 def.nVersion.s.nVersionMajor = 1;
1532 def.nVersion.s.nVersionMinor = 1;
1533 def.nPortIndex = kPortIndexOutput;
1534
1535 status_t err = mOMX->get_parameter(
1536 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
1537 CHECK_EQ(err, OK);
1538
1539 CHECK_EQ(def.eDomain, OMX_PortDomainImage);
1540
1541 OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
Andreas Huberebf66ea2009-08-19 13:32:58 -07001542
Andreas Huberbe06d262009-08-14 14:37:10 -07001543 CHECK_EQ(imageDef->eCompressionFormat, OMX_IMAGE_CodingUnused);
1544 imageDef->eColorFormat = format;
1545 imageDef->nFrameWidth = width;
1546 imageDef->nFrameHeight = height;
1547
1548 switch (format) {
1549 case OMX_COLOR_FormatYUV420PackedPlanar:
1550 case OMX_COLOR_FormatYUV411Planar:
1551 {
1552 def.nBufferSize = (width * height * 3) / 2;
1553 break;
1554 }
1555
1556 case OMX_COLOR_FormatCbYCrY:
1557 {
1558 def.nBufferSize = width * height * 2;
1559 break;
1560 }
1561
1562 case OMX_COLOR_Format32bitARGB8888:
1563 {
1564 def.nBufferSize = width * height * 4;
1565 break;
1566 }
1567
1568 default:
1569 CHECK(!"Should not be here. Unknown color format.");
1570 break;
1571 }
1572
Andreas Huber5c0a9132009-08-20 11:16:40 -07001573 def.nBufferCountActual = def.nBufferCountMin;
1574
Andreas Huberbe06d262009-08-14 14:37:10 -07001575 err = mOMX->set_parameter(
1576 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
1577 CHECK_EQ(err, OK);
Andreas Huber5c0a9132009-08-20 11:16:40 -07001578}
Andreas Huberbe06d262009-08-14 14:37:10 -07001579
Andreas Huber5c0a9132009-08-20 11:16:40 -07001580void OMXCodec::setJPEGInputFormat(
1581 OMX_U32 width, OMX_U32 height, OMX_U32 compressedSize) {
1582 OMX_PARAM_PORTDEFINITIONTYPE def;
1583 def.nSize = sizeof(def);
1584 def.nVersion.s.nVersionMajor = 1;
1585 def.nVersion.s.nVersionMinor = 1;
Andreas Huberbe06d262009-08-14 14:37:10 -07001586 def.nPortIndex = kPortIndexInput;
1587
Andreas Huber5c0a9132009-08-20 11:16:40 -07001588 status_t err = mOMX->get_parameter(
Andreas Huberbe06d262009-08-14 14:37:10 -07001589 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
1590 CHECK_EQ(err, OK);
1591
Andreas Huber5c0a9132009-08-20 11:16:40 -07001592 CHECK_EQ(def.eDomain, OMX_PortDomainImage);
1593 OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
1594
Andreas Huberbe06d262009-08-14 14:37:10 -07001595 CHECK_EQ(imageDef->eCompressionFormat, OMX_IMAGE_CodingJPEG);
1596 imageDef->nFrameWidth = width;
1597 imageDef->nFrameHeight = height;
1598
Andreas Huber5c0a9132009-08-20 11:16:40 -07001599 def.nBufferSize = compressedSize;
Andreas Huberbe06d262009-08-14 14:37:10 -07001600 def.nBufferCountActual = def.nBufferCountMin;
1601
1602 err = mOMX->set_parameter(
1603 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
1604 CHECK_EQ(err, OK);
1605}
1606
1607void OMXCodec::addCodecSpecificData(const void *data, size_t size) {
1608 CodecSpecificData *specific =
1609 (CodecSpecificData *)malloc(sizeof(CodecSpecificData) + size - 1);
1610
1611 specific->mSize = size;
1612 memcpy(specific->mData, data, size);
1613
1614 mCodecSpecificData.push(specific);
1615}
1616
1617void OMXCodec::clearCodecSpecificData() {
1618 for (size_t i = 0; i < mCodecSpecificData.size(); ++i) {
1619 free(mCodecSpecificData.editItemAt(i));
1620 }
1621 mCodecSpecificData.clear();
1622 mCodecSpecificDataIndex = 0;
1623}
1624
1625status_t OMXCodec::start(MetaData *) {
Andreas Huber42978e52009-08-27 10:08:39 -07001626 Mutex::Autolock autoLock(mLock);
1627
Andreas Huberbe06d262009-08-14 14:37:10 -07001628 if (mState != LOADED) {
1629 return UNKNOWN_ERROR;
1630 }
Andreas Huberebf66ea2009-08-19 13:32:58 -07001631
Andreas Huberbe06d262009-08-14 14:37:10 -07001632 sp<MetaData> params = new MetaData;
Andreas Huber4f5e6022009-08-19 09:29:34 -07001633 if (mQuirks & kWantsNALFragments) {
1634 params->setInt32(kKeyWantsNALFragments, true);
Andreas Huberbe06d262009-08-14 14:37:10 -07001635 }
1636 status_t err = mSource->start(params.get());
1637
1638 if (err != OK) {
1639 return err;
1640 }
1641
1642 mCodecSpecificDataIndex = 0;
Andreas Huber42978e52009-08-27 10:08:39 -07001643 mInitialBufferSubmit = true;
Andreas Huberbe06d262009-08-14 14:37:10 -07001644 mSignalledEOS = false;
1645 mNoMoreOutputData = false;
1646 mSeekTimeUs = -1;
1647 mFilledBuffers.clear();
1648
1649 return init();
1650}
1651
1652status_t OMXCodec::stop() {
Andreas Huber5c0a9132009-08-20 11:16:40 -07001653 LOGV("stop");
Andreas Huberbe06d262009-08-14 14:37:10 -07001654
1655 Mutex::Autolock autoLock(mLock);
1656
1657 while (isIntermediateState(mState)) {
1658 mAsyncCompletion.wait(mLock);
1659 }
1660
1661 switch (mState) {
1662 case LOADED:
1663 case ERROR:
1664 break;
1665
1666 case EXECUTING:
1667 {
1668 setState(EXECUTING_TO_IDLE);
1669
Andreas Huber127fcdc2009-08-26 16:27:02 -07001670 if (mQuirks & kRequiresFlushBeforeShutdown) {
1671 LOGV("This component requires a flush before transitioning "
1672 "from EXECUTING to IDLE...");
Andreas Huberbe06d262009-08-14 14:37:10 -07001673
Andreas Huber127fcdc2009-08-26 16:27:02 -07001674 bool emulateInputFlushCompletion =
1675 !flushPortAsync(kPortIndexInput);
1676
1677 bool emulateOutputFlushCompletion =
1678 !flushPortAsync(kPortIndexOutput);
1679
1680 if (emulateInputFlushCompletion) {
1681 onCmdComplete(OMX_CommandFlush, kPortIndexInput);
1682 }
1683
1684 if (emulateOutputFlushCompletion) {
1685 onCmdComplete(OMX_CommandFlush, kPortIndexOutput);
1686 }
1687 } else {
1688 mPortStatus[kPortIndexInput] = SHUTTING_DOWN;
1689 mPortStatus[kPortIndexOutput] = SHUTTING_DOWN;
1690
1691 status_t err =
1692 mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
1693 CHECK_EQ(err, OK);
1694 }
Andreas Huberbe06d262009-08-14 14:37:10 -07001695
1696 while (mState != LOADED && mState != ERROR) {
1697 mAsyncCompletion.wait(mLock);
1698 }
1699
1700 break;
1701 }
1702
1703 default:
1704 {
1705 CHECK(!"should not be here.");
1706 break;
1707 }
1708 }
1709
1710 mSource->stop();
1711
1712 return OK;
1713}
1714
1715sp<MetaData> OMXCodec::getFormat() {
1716 return mOutputFormat;
1717}
1718
1719status_t OMXCodec::read(
1720 MediaBuffer **buffer, const ReadOptions *options) {
1721 *buffer = NULL;
1722
1723 Mutex::Autolock autoLock(mLock);
1724
Andreas Huberd06e5b82009-08-28 13:18:14 -07001725 if (mState != EXECUTING && mState != RECONFIGURING) {
1726 return UNKNOWN_ERROR;
1727 }
1728
Andreas Huber42978e52009-08-27 10:08:39 -07001729 if (mInitialBufferSubmit) {
1730 mInitialBufferSubmit = false;
1731
1732 drainInputBuffers();
Andreas Huber42978e52009-08-27 10:08:39 -07001733
Andreas Huberd06e5b82009-08-28 13:18:14 -07001734 if (mState == EXECUTING) {
1735 // Otherwise mState == RECONFIGURING and this code will trigger
1736 // after the output port is reenabled.
1737 fillOutputBuffers();
1738 }
Andreas Huberbe06d262009-08-14 14:37:10 -07001739 }
1740
1741 int64_t seekTimeUs;
1742 if (options && options->getSeekTo(&seekTimeUs)) {
1743 LOGV("seeking to %lld us (%.2f secs)", seekTimeUs, seekTimeUs / 1E6);
1744
1745 mSignalledEOS = false;
1746 mNoMoreOutputData = false;
1747
1748 CHECK(seekTimeUs >= 0);
1749 mSeekTimeUs = seekTimeUs;
1750
1751 mFilledBuffers.clear();
1752
1753 CHECK_EQ(mState, EXECUTING);
1754
Andreas Huber404cc412009-08-25 14:26:05 -07001755 bool emulateInputFlushCompletion = !flushPortAsync(kPortIndexInput);
1756 bool emulateOutputFlushCompletion = !flushPortAsync(kPortIndexOutput);
1757
1758 if (emulateInputFlushCompletion) {
1759 onCmdComplete(OMX_CommandFlush, kPortIndexInput);
1760 }
1761
1762 if (emulateOutputFlushCompletion) {
1763 onCmdComplete(OMX_CommandFlush, kPortIndexOutput);
1764 }
Andreas Huberbe06d262009-08-14 14:37:10 -07001765 }
1766
1767 while (mState != ERROR && !mNoMoreOutputData && mFilledBuffers.empty()) {
1768 mBufferFilled.wait(mLock);
1769 }
1770
1771 if (mState == ERROR) {
1772 return UNKNOWN_ERROR;
1773 }
1774
1775 if (mFilledBuffers.empty()) {
1776 return ERROR_END_OF_STREAM;
1777 }
1778
1779 size_t index = *mFilledBuffers.begin();
1780 mFilledBuffers.erase(mFilledBuffers.begin());
1781
1782 BufferInfo *info = &mPortBuffers[kPortIndexOutput].editItemAt(index);
1783 info->mMediaBuffer->add_ref();
1784 *buffer = info->mMediaBuffer;
1785
1786 return OK;
1787}
1788
1789void OMXCodec::signalBufferReturned(MediaBuffer *buffer) {
1790 Mutex::Autolock autoLock(mLock);
1791
1792 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
1793 for (size_t i = 0; i < buffers->size(); ++i) {
1794 BufferInfo *info = &buffers->editItemAt(i);
1795
1796 if (info->mMediaBuffer == buffer) {
1797 CHECK_EQ(mPortStatus[kPortIndexOutput], ENABLED);
1798 fillOutputBuffer(info);
1799 return;
1800 }
1801 }
1802
1803 CHECK(!"should not be here.");
1804}
1805
1806static const char *imageCompressionFormatString(OMX_IMAGE_CODINGTYPE type) {
1807 static const char *kNames[] = {
1808 "OMX_IMAGE_CodingUnused",
1809 "OMX_IMAGE_CodingAutoDetect",
1810 "OMX_IMAGE_CodingJPEG",
1811 "OMX_IMAGE_CodingJPEG2K",
1812 "OMX_IMAGE_CodingEXIF",
1813 "OMX_IMAGE_CodingTIFF",
1814 "OMX_IMAGE_CodingGIF",
1815 "OMX_IMAGE_CodingPNG",
1816 "OMX_IMAGE_CodingLZW",
1817 "OMX_IMAGE_CodingBMP",
1818 };
1819
1820 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
1821
1822 if (type < 0 || (size_t)type >= numNames) {
1823 return "UNKNOWN";
1824 } else {
1825 return kNames[type];
1826 }
1827}
1828
1829static const char *colorFormatString(OMX_COLOR_FORMATTYPE type) {
1830 static const char *kNames[] = {
1831 "OMX_COLOR_FormatUnused",
1832 "OMX_COLOR_FormatMonochrome",
1833 "OMX_COLOR_Format8bitRGB332",
1834 "OMX_COLOR_Format12bitRGB444",
1835 "OMX_COLOR_Format16bitARGB4444",
1836 "OMX_COLOR_Format16bitARGB1555",
1837 "OMX_COLOR_Format16bitRGB565",
1838 "OMX_COLOR_Format16bitBGR565",
1839 "OMX_COLOR_Format18bitRGB666",
1840 "OMX_COLOR_Format18bitARGB1665",
Andreas Huberebf66ea2009-08-19 13:32:58 -07001841 "OMX_COLOR_Format19bitARGB1666",
Andreas Huberbe06d262009-08-14 14:37:10 -07001842 "OMX_COLOR_Format24bitRGB888",
1843 "OMX_COLOR_Format24bitBGR888",
1844 "OMX_COLOR_Format24bitARGB1887",
1845 "OMX_COLOR_Format25bitARGB1888",
1846 "OMX_COLOR_Format32bitBGRA8888",
1847 "OMX_COLOR_Format32bitARGB8888",
1848 "OMX_COLOR_FormatYUV411Planar",
1849 "OMX_COLOR_FormatYUV411PackedPlanar",
1850 "OMX_COLOR_FormatYUV420Planar",
1851 "OMX_COLOR_FormatYUV420PackedPlanar",
1852 "OMX_COLOR_FormatYUV420SemiPlanar",
1853 "OMX_COLOR_FormatYUV422Planar",
1854 "OMX_COLOR_FormatYUV422PackedPlanar",
1855 "OMX_COLOR_FormatYUV422SemiPlanar",
1856 "OMX_COLOR_FormatYCbYCr",
1857 "OMX_COLOR_FormatYCrYCb",
1858 "OMX_COLOR_FormatCbYCrY",
1859 "OMX_COLOR_FormatCrYCbY",
1860 "OMX_COLOR_FormatYUV444Interleaved",
1861 "OMX_COLOR_FormatRawBayer8bit",
1862 "OMX_COLOR_FormatRawBayer10bit",
1863 "OMX_COLOR_FormatRawBayer8bitcompressed",
Andreas Huberebf66ea2009-08-19 13:32:58 -07001864 "OMX_COLOR_FormatL2",
1865 "OMX_COLOR_FormatL4",
1866 "OMX_COLOR_FormatL8",
1867 "OMX_COLOR_FormatL16",
1868 "OMX_COLOR_FormatL24",
Andreas Huberbe06d262009-08-14 14:37:10 -07001869 "OMX_COLOR_FormatL32",
1870 "OMX_COLOR_FormatYUV420PackedSemiPlanar",
1871 "OMX_COLOR_FormatYUV422PackedSemiPlanar",
1872 "OMX_COLOR_Format18BitBGR666",
1873 "OMX_COLOR_Format24BitARGB6666",
1874 "OMX_COLOR_Format24BitABGR6666",
1875 };
1876
1877 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
1878
1879 static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
1880
1881 if (type == OMX_QCOM_COLOR_FormatYVU420SemiPlanar) {
1882 return "OMX_QCOM_COLOR_FormatYVU420SemiPlanar";
1883 } else if (type < 0 || (size_t)type >= numNames) {
1884 return "UNKNOWN";
1885 } else {
1886 return kNames[type];
1887 }
1888}
1889
1890static const char *videoCompressionFormatString(OMX_VIDEO_CODINGTYPE type) {
1891 static const char *kNames[] = {
1892 "OMX_VIDEO_CodingUnused",
1893 "OMX_VIDEO_CodingAutoDetect",
1894 "OMX_VIDEO_CodingMPEG2",
1895 "OMX_VIDEO_CodingH263",
1896 "OMX_VIDEO_CodingMPEG4",
1897 "OMX_VIDEO_CodingWMV",
1898 "OMX_VIDEO_CodingRV",
1899 "OMX_VIDEO_CodingAVC",
1900 "OMX_VIDEO_CodingMJPEG",
1901 };
1902
1903 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
1904
1905 if (type < 0 || (size_t)type >= numNames) {
1906 return "UNKNOWN";
1907 } else {
1908 return kNames[type];
1909 }
1910}
1911
1912static const char *audioCodingTypeString(OMX_AUDIO_CODINGTYPE type) {
1913 static const char *kNames[] = {
1914 "OMX_AUDIO_CodingUnused",
1915 "OMX_AUDIO_CodingAutoDetect",
1916 "OMX_AUDIO_CodingPCM",
1917 "OMX_AUDIO_CodingADPCM",
1918 "OMX_AUDIO_CodingAMR",
1919 "OMX_AUDIO_CodingGSMFR",
1920 "OMX_AUDIO_CodingGSMEFR",
1921 "OMX_AUDIO_CodingGSMHR",
1922 "OMX_AUDIO_CodingPDCFR",
1923 "OMX_AUDIO_CodingPDCEFR",
1924 "OMX_AUDIO_CodingPDCHR",
1925 "OMX_AUDIO_CodingTDMAFR",
1926 "OMX_AUDIO_CodingTDMAEFR",
1927 "OMX_AUDIO_CodingQCELP8",
1928 "OMX_AUDIO_CodingQCELP13",
1929 "OMX_AUDIO_CodingEVRC",
1930 "OMX_AUDIO_CodingSMV",
1931 "OMX_AUDIO_CodingG711",
1932 "OMX_AUDIO_CodingG723",
1933 "OMX_AUDIO_CodingG726",
1934 "OMX_AUDIO_CodingG729",
1935 "OMX_AUDIO_CodingAAC",
1936 "OMX_AUDIO_CodingMP3",
1937 "OMX_AUDIO_CodingSBC",
1938 "OMX_AUDIO_CodingVORBIS",
1939 "OMX_AUDIO_CodingWMA",
1940 "OMX_AUDIO_CodingRA",
1941 "OMX_AUDIO_CodingMIDI",
1942 };
1943
1944 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
1945
1946 if (type < 0 || (size_t)type >= numNames) {
1947 return "UNKNOWN";
1948 } else {
1949 return kNames[type];
1950 }
1951}
1952
1953static const char *audioPCMModeString(OMX_AUDIO_PCMMODETYPE type) {
1954 static const char *kNames[] = {
1955 "OMX_AUDIO_PCMModeLinear",
1956 "OMX_AUDIO_PCMModeALaw",
1957 "OMX_AUDIO_PCMModeMULaw",
1958 };
1959
1960 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
1961
1962 if (type < 0 || (size_t)type >= numNames) {
1963 return "UNKNOWN";
1964 } else {
1965 return kNames[type];
1966 }
1967}
1968
1969
1970void OMXCodec::dumpPortStatus(OMX_U32 portIndex) {
1971 OMX_PARAM_PORTDEFINITIONTYPE def;
1972 def.nSize = sizeof(def);
1973 def.nVersion.s.nVersionMajor = 1;
1974 def.nVersion.s.nVersionMinor = 1;
1975 def.nPortIndex = portIndex;
1976
1977 status_t err = mOMX->get_parameter(
1978 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
1979 CHECK_EQ(err, OK);
1980
1981 printf("%s Port = {\n", portIndex == kPortIndexInput ? "Input" : "Output");
1982
1983 CHECK((portIndex == kPortIndexInput && def.eDir == OMX_DirInput)
1984 || (portIndex == kPortIndexOutput && def.eDir == OMX_DirOutput));
1985
1986 printf(" nBufferCountActual = %ld\n", def.nBufferCountActual);
1987 printf(" nBufferCountMin = %ld\n", def.nBufferCountMin);
1988 printf(" nBufferSize = %ld\n", def.nBufferSize);
1989
1990 switch (def.eDomain) {
1991 case OMX_PortDomainImage:
1992 {
1993 const OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
1994
1995 printf("\n");
1996 printf(" // Image\n");
1997 printf(" nFrameWidth = %ld\n", imageDef->nFrameWidth);
1998 printf(" nFrameHeight = %ld\n", imageDef->nFrameHeight);
1999 printf(" nStride = %ld\n", imageDef->nStride);
2000
2001 printf(" eCompressionFormat = %s\n",
2002 imageCompressionFormatString(imageDef->eCompressionFormat));
2003
2004 printf(" eColorFormat = %s\n",
2005 colorFormatString(imageDef->eColorFormat));
2006
2007 break;
2008 }
2009
2010 case OMX_PortDomainVideo:
2011 {
2012 OMX_VIDEO_PORTDEFINITIONTYPE *videoDef = &def.format.video;
2013
2014 printf("\n");
2015 printf(" // Video\n");
2016 printf(" nFrameWidth = %ld\n", videoDef->nFrameWidth);
2017 printf(" nFrameHeight = %ld\n", videoDef->nFrameHeight);
2018 printf(" nStride = %ld\n", videoDef->nStride);
2019
2020 printf(" eCompressionFormat = %s\n",
2021 videoCompressionFormatString(videoDef->eCompressionFormat));
2022
2023 printf(" eColorFormat = %s\n",
2024 colorFormatString(videoDef->eColorFormat));
2025
2026 break;
2027 }
2028
2029 case OMX_PortDomainAudio:
2030 {
2031 OMX_AUDIO_PORTDEFINITIONTYPE *audioDef = &def.format.audio;
2032
2033 printf("\n");
2034 printf(" // Audio\n");
2035 printf(" eEncoding = %s\n",
2036 audioCodingTypeString(audioDef->eEncoding));
2037
2038 if (audioDef->eEncoding == OMX_AUDIO_CodingPCM) {
2039 OMX_AUDIO_PARAM_PCMMODETYPE params;
2040 params.nSize = sizeof(params);
2041 params.nVersion.s.nVersionMajor = 1;
2042 params.nVersion.s.nVersionMinor = 1;
2043 params.nPortIndex = portIndex;
2044
2045 err = mOMX->get_parameter(
2046 mNode, OMX_IndexParamAudioPcm, &params, sizeof(params));
2047 CHECK_EQ(err, OK);
2048
2049 printf(" nSamplingRate = %ld\n", params.nSamplingRate);
2050 printf(" nChannels = %ld\n", params.nChannels);
2051 printf(" bInterleaved = %d\n", params.bInterleaved);
2052 printf(" nBitPerSample = %ld\n", params.nBitPerSample);
2053
2054 printf(" eNumData = %s\n",
2055 params.eNumData == OMX_NumericalDataSigned
2056 ? "signed" : "unsigned");
2057
2058 printf(" ePCMMode = %s\n", audioPCMModeString(params.ePCMMode));
2059 }
2060
2061 break;
2062 }
2063
2064 default:
2065 {
2066 printf(" // Unknown\n");
2067 break;
2068 }
2069 }
2070
2071 printf("}\n");
2072}
2073
2074void OMXCodec::initOutputFormat(const sp<MetaData> &inputFormat) {
2075 mOutputFormat = new MetaData;
2076 mOutputFormat->setCString(kKeyDecoderComponent, mComponentName);
2077
2078 OMX_PARAM_PORTDEFINITIONTYPE def;
2079 def.nSize = sizeof(def);
2080 def.nVersion.s.nVersionMajor = 1;
2081 def.nVersion.s.nVersionMinor = 1;
2082 def.nPortIndex = kPortIndexOutput;
2083
2084 status_t err = mOMX->get_parameter(
2085 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
2086 CHECK_EQ(err, OK);
2087
2088 switch (def.eDomain) {
2089 case OMX_PortDomainImage:
2090 {
2091 OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
2092 CHECK_EQ(imageDef->eCompressionFormat, OMX_IMAGE_CodingUnused);
2093
2094 mOutputFormat->setCString(kKeyMIMEType, "image/raw");
2095 mOutputFormat->setInt32(kKeyColorFormat, imageDef->eColorFormat);
2096 mOutputFormat->setInt32(kKeyWidth, imageDef->nFrameWidth);
2097 mOutputFormat->setInt32(kKeyHeight, imageDef->nFrameHeight);
2098 break;
2099 }
2100
2101 case OMX_PortDomainAudio:
2102 {
2103 OMX_AUDIO_PORTDEFINITIONTYPE *audio_def = &def.format.audio;
2104
2105 CHECK_EQ(audio_def->eEncoding, OMX_AUDIO_CodingPCM);
2106
2107 OMX_AUDIO_PARAM_PCMMODETYPE params;
2108 params.nSize = sizeof(params);
2109 params.nVersion.s.nVersionMajor = 1;
2110 params.nVersion.s.nVersionMinor = 1;
2111 params.nPortIndex = kPortIndexOutput;
2112
2113 err = mOMX->get_parameter(
2114 mNode, OMX_IndexParamAudioPcm, &params, sizeof(params));
2115 CHECK_EQ(err, OK);
2116
2117 CHECK_EQ(params.eNumData, OMX_NumericalDataSigned);
2118 CHECK_EQ(params.nBitPerSample, 16);
2119 CHECK_EQ(params.ePCMMode, OMX_AUDIO_PCMModeLinear);
2120
2121 int32_t numChannels, sampleRate;
2122 inputFormat->findInt32(kKeyChannelCount, &numChannels);
2123 inputFormat->findInt32(kKeySampleRate, &sampleRate);
2124
Andreas Huber43ad6eaf2009-09-01 16:02:43 -07002125 if ((OMX_U32)numChannels != params.nChannels) {
2126 LOGW("Codec outputs a different number of channels than "
2127 "the input stream contains.");
2128 }
2129
Andreas Huberbe06d262009-08-14 14:37:10 -07002130 mOutputFormat->setCString(kKeyMIMEType, "audio/raw");
Andreas Huber43ad6eaf2009-09-01 16:02:43 -07002131
2132 // Use the codec-advertised number of channels, as some
2133 // codecs appear to output stereo even if the input data is
2134 // mono.
2135 mOutputFormat->setInt32(kKeyChannelCount, params.nChannels);
2136
2137 // The codec-reported sampleRate is not reliable...
Andreas Huberbe06d262009-08-14 14:37:10 -07002138 mOutputFormat->setInt32(kKeySampleRate, sampleRate);
2139 break;
2140 }
2141
2142 case OMX_PortDomainVideo:
2143 {
2144 OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
2145
2146 if (video_def->eCompressionFormat == OMX_VIDEO_CodingUnused) {
2147 mOutputFormat->setCString(kKeyMIMEType, "video/raw");
2148 } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingMPEG4) {
2149 mOutputFormat->setCString(kKeyMIMEType, "video/mp4v-es");
2150 } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingH263) {
2151 mOutputFormat->setCString(kKeyMIMEType, "video/3gpp");
2152 } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingAVC) {
2153 mOutputFormat->setCString(kKeyMIMEType, "video/avc");
2154 } else {
2155 CHECK(!"Unknown compression format.");
2156 }
2157
2158 if (!strcmp(mComponentName, "OMX.PV.avcdec")) {
2159 // This component appears to be lying to me.
2160 mOutputFormat->setInt32(
2161 kKeyWidth, (video_def->nFrameWidth + 15) & -16);
2162 mOutputFormat->setInt32(
2163 kKeyHeight, (video_def->nFrameHeight + 15) & -16);
2164 } else {
2165 mOutputFormat->setInt32(kKeyWidth, video_def->nFrameWidth);
2166 mOutputFormat->setInt32(kKeyHeight, video_def->nFrameHeight);
2167 }
2168
2169 mOutputFormat->setInt32(kKeyColorFormat, video_def->eColorFormat);
2170 break;
2171 }
2172
2173 default:
2174 {
2175 CHECK(!"should not be here, neither audio nor video.");
2176 break;
2177 }
2178 }
2179}
2180
2181} // namespace android