blob: ec9f6d319d57fa2ced2ea0f71a12ba157a53a08d [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;
196 }
197 if (!strncmp(componentName, "OMX.qcom.video.encoder.", 23)) {
198 quirks |= kRequiresLoadedToIdleAfterAllocation;
199 quirks |= kRequiresAllocateBufferOnInputPorts;
200 }
201
202 sp<OMXCodec> codec = new OMXCodec(
203 omx, node, quirks, createEncoder, mime, componentName,
204 source);
205
206 uint32_t type;
207 const void *data;
208 size_t size;
209 if (meta->findData(kKeyESDS, &type, &data, &size)) {
210 ESDS esds((const char *)data, size);
211 CHECK_EQ(esds.InitCheck(), OK);
212
213 const void *codec_specific_data;
214 size_t codec_specific_data_size;
215 esds.getCodecSpecificInfo(
216 &codec_specific_data, &codec_specific_data_size);
217
218 printf("found codec-specific data of size %d\n",
219 codec_specific_data_size);
220
221 codec->addCodecSpecificData(
222 codec_specific_data, codec_specific_data_size);
223 } else if (meta->findData(kKeyAVCC, &type, &data, &size)) {
224 printf("found avcc of size %d\n", size);
225
Andreas Huberebf66ea2009-08-19 13:32:58 -0700226 // Parse the AVCDecoderConfigurationRecord
227
228 const uint8_t *ptr = (const uint8_t *)data;
229
230 CHECK(size >= 7);
231 CHECK_EQ(ptr[0], 1); // configurationVersion == 1
232 uint8_t profile = ptr[1];
233 uint8_t level = ptr[3];
234
235 CHECK((ptr[4] >> 2) == 0x3f); // reserved
236
237 size_t lengthSize = 1 + (ptr[4] & 3);
238
239 // commented out check below as H264_QVGA_500_NO_AUDIO.3gp
240 // violates it...
241 // CHECK((ptr[5] >> 5) == 7); // reserved
242
243 size_t numSeqParameterSets = ptr[5] & 31;
244
245 ptr += 6;
Andreas Huberbe06d262009-08-14 14:37:10 -0700246 size -= 6;
Andreas Huberebf66ea2009-08-19 13:32:58 -0700247
248 for (size_t i = 0; i < numSeqParameterSets; ++i) {
249 CHECK(size >= 2);
250 size_t length = U16_AT(ptr);
Andreas Huberbe06d262009-08-14 14:37:10 -0700251
252 ptr += 2;
253 size -= 2;
254
Andreas Huberbe06d262009-08-14 14:37:10 -0700255 CHECK(size >= length);
256
257 codec->addCodecSpecificData(ptr, length);
258
259 ptr += length;
260 size -= length;
Andreas Huberebf66ea2009-08-19 13:32:58 -0700261 }
Andreas Huberbe06d262009-08-14 14:37:10 -0700262
Andreas Huberebf66ea2009-08-19 13:32:58 -0700263 CHECK(size >= 1);
264 size_t numPictureParameterSets = *ptr;
265 ++ptr;
266 --size;
Andreas Huberbe06d262009-08-14 14:37:10 -0700267
Andreas Huberebf66ea2009-08-19 13:32:58 -0700268 for (size_t i = 0; i < numPictureParameterSets; ++i) {
269 CHECK(size >= 2);
270 size_t length = U16_AT(ptr);
271
272 ptr += 2;
273 size -= 2;
274
275 CHECK(size >= length);
276
277 codec->addCodecSpecificData(ptr, length);
278
279 ptr += length;
280 size -= length;
281 }
282
283 LOGI("AVC profile = %d (%s), level = %d",
284 (int)profile, AVCProfileToString(profile), (int)level / 10);
285
286 if (!strcmp(componentName, "OMX.TI.Video.Decoder")
287 && (profile != kAVCProfileBaseline || level > 39)) {
288 // This stream exceeds the decoder's capabilities.
289
290 LOGE("Profile and/or level exceed the decoder's capabilities.");
291 return NULL;
Andreas Huberbe06d262009-08-14 14:37:10 -0700292 }
293 }
294
295 if (!strcasecmp("audio/3gpp", mime)) {
296 codec->setAMRFormat();
297 }
298 if (!createEncoder && !strcasecmp("audio/mp4a-latm", mime)) {
299 codec->setAACFormat();
300 }
301 if (!strncasecmp(mime, "video/", 6)) {
302 int32_t width, height;
303 bool success = meta->findInt32(kKeyWidth, &width);
304 success = success && meta->findInt32(kKeyHeight, &height);
Andreas Huber5c0a9132009-08-20 11:16:40 -0700305 CHECK(success);
Andreas Huberbe06d262009-08-14 14:37:10 -0700306
307 if (createEncoder) {
308 codec->setVideoInputFormat(mime, width, height);
309 } else {
310 codec->setVideoOutputFormat(mime, width, height);
311 }
312 }
313 if (!strcasecmp(mime, "image/jpeg")
314 && !strcmp(componentName, "OMX.TI.JPEG.decode")) {
315 OMX_COLOR_FORMATTYPE format =
316 OMX_COLOR_Format32bitARGB8888;
317 // OMX_COLOR_FormatYUV420PackedPlanar;
318 // OMX_COLOR_FormatCbYCrY;
319 // OMX_COLOR_FormatYUV411Planar;
320
321 int32_t width, height;
322 bool success = meta->findInt32(kKeyWidth, &width);
323 success = success && meta->findInt32(kKeyHeight, &height);
Andreas Huber5c0a9132009-08-20 11:16:40 -0700324
325 int32_t compressedSize;
326 success = success && meta->findInt32(
327 kKeyCompressedSize, &compressedSize);
328
329 CHECK(success);
330 CHECK(compressedSize > 0);
Andreas Huberbe06d262009-08-14 14:37:10 -0700331
332 codec->setImageOutputFormat(format, width, height);
Andreas Huber5c0a9132009-08-20 11:16:40 -0700333 codec->setJPEGInputFormat(width, height, (OMX_U32)compressedSize);
Andreas Huberbe06d262009-08-14 14:37:10 -0700334 }
335
336 codec->initOutputFormat(meta);
337
338 return codec;
339}
340
341status_t OMXCodec::setVideoPortFormatType(
342 OMX_U32 portIndex,
343 OMX_VIDEO_CODINGTYPE compressionFormat,
344 OMX_COLOR_FORMATTYPE colorFormat) {
345 OMX_VIDEO_PARAM_PORTFORMATTYPE format;
346 format.nSize = sizeof(format);
347 format.nVersion.s.nVersionMajor = 1;
348 format.nVersion.s.nVersionMinor = 1;
349 format.nPortIndex = portIndex;
350 format.nIndex = 0;
351 bool found = false;
352
353 OMX_U32 index = 0;
354 for (;;) {
355 format.nIndex = index;
356 status_t err = mOMX->get_parameter(
357 mNode, OMX_IndexParamVideoPortFormat,
358 &format, sizeof(format));
359
360 if (err != OK) {
361 return err;
362 }
363
364 // The following assertion is violated by TI's video decoder.
Andreas Huber5c0a9132009-08-20 11:16:40 -0700365 // CHECK_EQ(format.nIndex, index);
Andreas Huberbe06d262009-08-14 14:37:10 -0700366
367#if 1
368 LOGI("portIndex: %ld, index: %ld, eCompressionFormat=%d eColorFormat=%d",
369 portIndex,
370 index, format.eCompressionFormat, format.eColorFormat);
371#endif
372
373 if (!strcmp("OMX.TI.Video.encoder", mComponentName)) {
374 if (portIndex == kPortIndexInput
375 && colorFormat == format.eColorFormat) {
376 // eCompressionFormat does not seem right.
377 found = true;
378 break;
379 }
380 if (portIndex == kPortIndexOutput
381 && compressionFormat == format.eCompressionFormat) {
382 // eColorFormat does not seem right.
383 found = true;
384 break;
385 }
386 }
387
388 if (format.eCompressionFormat == compressionFormat
389 && format.eColorFormat == colorFormat) {
390 found = true;
391 break;
392 }
393
394 ++index;
395 }
396
397 if (!found) {
398 return UNKNOWN_ERROR;
399 }
400
401 LOGI("found a match.");
402 status_t err = mOMX->set_parameter(
403 mNode, OMX_IndexParamVideoPortFormat,
404 &format, sizeof(format));
405
406 return err;
407}
408
409void OMXCodec::setVideoInputFormat(
410 const char *mime, OMX_U32 width, OMX_U32 height) {
411 LOGI("setVideoInputFormat width=%ld, height=%ld", width, height);
412
413 OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused;
414 if (!strcasecmp("video/avc", mime)) {
415 compressionFormat = OMX_VIDEO_CodingAVC;
416 } else if (!strcasecmp("video/mp4v-es", mime)) {
417 compressionFormat = OMX_VIDEO_CodingMPEG4;
418 } else if (!strcasecmp("video/3gpp", mime)) {
419 compressionFormat = OMX_VIDEO_CodingH263;
420 } else {
421 LOGE("Not a supported video mime type: %s", mime);
422 CHECK(!"Should not be here. Not a supported video mime type.");
423 }
424
425 OMX_COLOR_FORMATTYPE colorFormat =
426 0 ? OMX_COLOR_FormatYCbYCr : OMX_COLOR_FormatCbYCrY;
427
428 if (!strncmp("OMX.qcom.video.encoder.", mComponentName, 23)) {
429 colorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
430 }
431
432 setVideoPortFormatType(
433 kPortIndexInput, OMX_VIDEO_CodingUnused,
434 colorFormat);
435
436 setVideoPortFormatType(
437 kPortIndexOutput, compressionFormat, OMX_COLOR_FormatUnused);
438
439 OMX_PARAM_PORTDEFINITIONTYPE def;
440 OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
441
442 def.nSize = sizeof(def);
443 def.nVersion.s.nVersionMajor = 1;
444 def.nVersion.s.nVersionMinor = 1;
445 def.nPortIndex = kPortIndexOutput;
446
447 status_t err = mOMX->get_parameter(
448 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
449
450 CHECK_EQ(err, OK);
451 CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
452
453 video_def->nFrameWidth = width;
454 video_def->nFrameHeight = height;
455
456 video_def->eCompressionFormat = compressionFormat;
457 video_def->eColorFormat = OMX_COLOR_FormatUnused;
458
459 err = mOMX->set_parameter(
460 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
461 CHECK_EQ(err, OK);
462
463 ////////////////////////////////////////////////////////////////////////////
464
465 def.nSize = sizeof(def);
466 def.nVersion.s.nVersionMajor = 1;
467 def.nVersion.s.nVersionMinor = 1;
468 def.nPortIndex = kPortIndexInput;
469
470 err = mOMX->get_parameter(
471 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
472 CHECK_EQ(err, OK);
473
474 def.nBufferSize = (width * height * 2); // (width * height * 3) / 2;
475 LOGI("setting nBufferSize = %ld", def.nBufferSize);
476
477 CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
478
479 video_def->nFrameWidth = width;
480 video_def->nFrameHeight = height;
481 video_def->eCompressionFormat = OMX_VIDEO_CodingUnused;
482 video_def->eColorFormat = colorFormat;
483
484 err = mOMX->set_parameter(
485 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
486 CHECK_EQ(err, OK);
487}
488
489void OMXCodec::setVideoOutputFormat(
490 const char *mime, OMX_U32 width, OMX_U32 height) {
491 LOGI("setVideoOutputFormat width=%ld, height=%ld", width, height);
492
493 // Enabling this code appears to be the right thing(tm), but,...
494 // the TI decoder then loses the ability to output YUV420 and only outputs
495 // YCbYCr (16bit)
496 if (!strcmp("OMX.TI.Video.Decoder", mComponentName)
497 && !strcasecmp("video/avc", mime)) {
498 OMX_PARAM_COMPONENTROLETYPE role;
499 role.nSize = sizeof(role);
500 role.nVersion.s.nVersionMajor = 1;
501 role.nVersion.s.nVersionMinor = 1;
502 strncpy((char *)role.cRole, "video_decoder.avc",
503 OMX_MAX_STRINGNAME_SIZE - 1);
504 role.cRole[OMX_MAX_STRINGNAME_SIZE - 1] = '\0';
505
506 status_t err = mOMX->set_parameter(
507 mNode, OMX_IndexParamStandardComponentRole,
508 &role, sizeof(role));
509 CHECK_EQ(err, OK);
510 }
511
512 OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused;
513 if (!strcasecmp("video/avc", mime)) {
514 compressionFormat = OMX_VIDEO_CodingAVC;
515 } else if (!strcasecmp("video/mp4v-es", mime)) {
516 compressionFormat = OMX_VIDEO_CodingMPEG4;
517 } else if (!strcasecmp("video/3gpp", mime)) {
518 compressionFormat = OMX_VIDEO_CodingH263;
519 } else {
520 LOGE("Not a supported video mime type: %s", mime);
521 CHECK(!"Should not be here. Not a supported video mime type.");
522 }
523
524 setVideoPortFormatType(
525 kPortIndexInput, compressionFormat, OMX_COLOR_FormatUnused);
526
527#if 1
528 {
529 OMX_VIDEO_PARAM_PORTFORMATTYPE format;
530 format.nSize = sizeof(format);
531 format.nVersion.s.nVersionMajor = 1;
532 format.nVersion.s.nVersionMinor = 1;
533 format.nPortIndex = kPortIndexOutput;
534 format.nIndex = 0;
535
536 status_t err = mOMX->get_parameter(
537 mNode, OMX_IndexParamVideoPortFormat,
538 &format, sizeof(format));
539 CHECK_EQ(err, OK);
540 CHECK_EQ(format.eCompressionFormat, OMX_VIDEO_CodingUnused);
541
542 static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
543
544 CHECK(format.eColorFormat == OMX_COLOR_FormatYUV420Planar
545 || format.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar
546 || format.eColorFormat == OMX_COLOR_FormatCbYCrY
547 || format.eColorFormat == OMX_QCOM_COLOR_FormatYVU420SemiPlanar);
548
549 err = mOMX->set_parameter(
550 mNode, OMX_IndexParamVideoPortFormat,
551 &format, sizeof(format));
552 CHECK_EQ(err, OK);
553 }
554#endif
555
556 OMX_PARAM_PORTDEFINITIONTYPE def;
557 OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
558
559 def.nSize = sizeof(def);
560 def.nVersion.s.nVersionMajor = 1;
561 def.nVersion.s.nVersionMinor = 1;
562 def.nPortIndex = kPortIndexInput;
563
564 status_t err = mOMX->get_parameter(
565 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
566
567 CHECK_EQ(err, OK);
568
569#if 1
570 // XXX Need a (much) better heuristic to compute input buffer sizes.
571 const size_t X = 64 * 1024;
572 if (def.nBufferSize < X) {
573 def.nBufferSize = X;
574 }
575#endif
576
577 CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
578
579 video_def->nFrameWidth = width;
580 video_def->nFrameHeight = height;
581
582 video_def->eColorFormat = OMX_COLOR_FormatUnused;
583
584 err = mOMX->set_parameter(
585 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
586 CHECK_EQ(err, OK);
587
588 ////////////////////////////////////////////////////////////////////////////
589
590 def.nSize = sizeof(def);
591 def.nVersion.s.nVersionMajor = 1;
592 def.nVersion.s.nVersionMinor = 1;
593 def.nPortIndex = kPortIndexOutput;
594
595 err = mOMX->get_parameter(
596 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
597 CHECK_EQ(err, OK);
598 CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
599
600#if 0
601 def.nBufferSize =
602 (((width + 15) & -16) * ((height + 15) & -16) * 3) / 2; // YUV420
603#endif
604
605 video_def->nFrameWidth = width;
606 video_def->nFrameHeight = height;
607
608 err = mOMX->set_parameter(
609 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
610 CHECK_EQ(err, OK);
611}
612
613
614OMXCodec::OMXCodec(
615 const sp<IOMX> &omx, IOMX::node_id node, uint32_t quirks,
Andreas Huberebf66ea2009-08-19 13:32:58 -0700616 bool isEncoder,
Andreas Huberbe06d262009-08-14 14:37:10 -0700617 const char *mime,
618 const char *componentName,
619 const sp<MediaSource> &source)
620 : mOMX(omx),
621 mNode(node),
622 mQuirks(quirks),
623 mIsEncoder(isEncoder),
624 mMIME(strdup(mime)),
625 mComponentName(strdup(componentName)),
626 mSource(source),
627 mCodecSpecificDataIndex(0),
Andreas Huberbe06d262009-08-14 14:37:10 -0700628 mState(LOADED),
629 mSignalledEOS(false),
630 mNoMoreOutputData(false),
631 mSeekTimeUs(-1) {
632 mPortStatus[kPortIndexInput] = ENABLED;
633 mPortStatus[kPortIndexOutput] = ENABLED;
634
635 mObserver = new OMXCodecObserver(this);
636 mOMX->observe_node(mNode, mObserver);
637}
638
639OMXCodec::~OMXCodec() {
Andreas Huber4f5e6022009-08-19 09:29:34 -0700640 CHECK(mState == LOADED || mState == ERROR);
Andreas Huberbe06d262009-08-14 14:37:10 -0700641
642 status_t err = mOMX->observe_node(mNode, NULL);
643 CHECK_EQ(err, OK);
644
645 err = mOMX->free_node(mNode);
646 CHECK_EQ(err, OK);
647
648 mNode = NULL;
649 setState(DEAD);
650
651 clearCodecSpecificData();
652
653 free(mComponentName);
654 mComponentName = NULL;
Andreas Huberebf66ea2009-08-19 13:32:58 -0700655
Andreas Huberbe06d262009-08-14 14:37:10 -0700656 free(mMIME);
657 mMIME = NULL;
658}
659
660status_t OMXCodec::init() {
661 Mutex::Autolock autoLock(mLock);
662
663 CHECK_EQ(mState, LOADED);
664
665 status_t err;
666 if (!(mQuirks & kRequiresLoadedToIdleAfterAllocation)) {
667 err = mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
668 CHECK_EQ(err, OK);
669
670 setState(LOADED_TO_IDLE);
671 }
672
673 err = allocateBuffers();
674 CHECK_EQ(err, OK);
675
676 if (mQuirks & kRequiresLoadedToIdleAfterAllocation) {
677 err = mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
678 CHECK_EQ(err, OK);
679
680 setState(LOADED_TO_IDLE);
681 }
682
683 while (mState != EXECUTING && mState != ERROR) {
684 mAsyncCompletion.wait(mLock);
685 }
686
687 return mState == ERROR ? UNKNOWN_ERROR : OK;
688}
689
690// static
691bool OMXCodec::isIntermediateState(State state) {
692 return state == LOADED_TO_IDLE
693 || state == IDLE_TO_EXECUTING
694 || state == EXECUTING_TO_IDLE
695 || state == IDLE_TO_LOADED
696 || state == RECONFIGURING;
697}
698
699status_t OMXCodec::allocateBuffers() {
700 status_t err = allocateBuffersOnPort(kPortIndexInput);
701
702 if (err != OK) {
703 return err;
704 }
705
706 return allocateBuffersOnPort(kPortIndexOutput);
707}
708
709status_t OMXCodec::allocateBuffersOnPort(OMX_U32 portIndex) {
710 OMX_PARAM_PORTDEFINITIONTYPE def;
711 def.nSize = sizeof(def);
712 def.nVersion.s.nVersionMajor = 1;
713 def.nVersion.s.nVersionMinor = 1;
714 def.nVersion.s.nRevision = 0;
715 def.nVersion.s.nStep = 0;
716 def.nPortIndex = portIndex;
717
718 status_t err = mOMX->get_parameter(
719 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
720
721 if (err != OK) {
722 return err;
723 }
724
Andreas Huber5c0a9132009-08-20 11:16:40 -0700725 size_t totalSize = def.nBufferCountActual * def.nBufferSize;
726 mDealer[portIndex] = new MemoryDealer(totalSize);
727
Andreas Huberbe06d262009-08-14 14:37:10 -0700728 for (OMX_U32 i = 0; i < def.nBufferCountActual; ++i) {
Andreas Huber5c0a9132009-08-20 11:16:40 -0700729 sp<IMemory> mem = mDealer[portIndex]->allocate(def.nBufferSize);
Andreas Huberbe06d262009-08-14 14:37:10 -0700730 CHECK(mem.get() != NULL);
731
732 IOMX::buffer_id buffer;
733 if (portIndex == kPortIndexInput
734 && (mQuirks & kRequiresAllocateBufferOnInputPorts)) {
735 err = mOMX->allocate_buffer_with_backup(
736 mNode, portIndex, mem, &buffer);
737 } else {
738 err = mOMX->use_buffer(mNode, portIndex, mem, &buffer);
739 }
740
741 if (err != OK) {
742 LOGE("allocate_buffer_with_backup failed");
743 return err;
744 }
745
746 BufferInfo info;
747 info.mBuffer = buffer;
748 info.mOwnedByComponent = false;
749 info.mMem = mem;
750 info.mMediaBuffer = NULL;
751
752 if (portIndex == kPortIndexOutput) {
753 info.mMediaBuffer = new MediaBuffer(mem->pointer(), mem->size());
754 info.mMediaBuffer->setObserver(this);
755 }
756
757 mPortBuffers[portIndex].push(info);
758
759 LOGV("allocated buffer %p on %s port", buffer,
760 portIndex == kPortIndexInput ? "input" : "output");
761 }
762
763 dumpPortStatus(portIndex);
764
765 return OK;
766}
767
768void OMXCodec::on_message(const omx_message &msg) {
769 Mutex::Autolock autoLock(mLock);
770
771 switch (msg.type) {
772 case omx_message::EVENT:
773 {
774 onEvent(
775 msg.u.event_data.event, msg.u.event_data.data1,
776 msg.u.event_data.data2);
777
778 break;
779 }
780
781 case omx_message::EMPTY_BUFFER_DONE:
782 {
783 IOMX::buffer_id buffer = msg.u.extended_buffer_data.buffer;
784
785 LOGV("EMPTY_BUFFER_DONE(buffer: %p)", buffer);
786
787 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
788 size_t i = 0;
789 while (i < buffers->size() && (*buffers)[i].mBuffer != buffer) {
790 ++i;
791 }
792
793 CHECK(i < buffers->size());
794 if (!(*buffers)[i].mOwnedByComponent) {
795 LOGW("We already own input buffer %p, yet received "
796 "an EMPTY_BUFFER_DONE.", buffer);
797 }
798
799 buffers->editItemAt(i).mOwnedByComponent = false;
800
801 if (mPortStatus[kPortIndexInput] == DISABLING) {
802 LOGV("Port is disabled, freeing buffer %p", buffer);
803
804 status_t err =
805 mOMX->free_buffer(mNode, kPortIndexInput, buffer);
806 CHECK_EQ(err, OK);
807
808 buffers->removeAt(i);
809 } else if (mPortStatus[kPortIndexInput] != SHUTTING_DOWN) {
810 CHECK_EQ(mPortStatus[kPortIndexInput], ENABLED);
811 drainInputBuffer(&buffers->editItemAt(i));
812 }
813
814 break;
815 }
816
817 case omx_message::FILL_BUFFER_DONE:
818 {
819 IOMX::buffer_id buffer = msg.u.extended_buffer_data.buffer;
820 OMX_U32 flags = msg.u.extended_buffer_data.flags;
821
822 LOGV("FILL_BUFFER_DONE(buffer: %p, size: %ld, flags: 0x%08lx)",
823 buffer,
824 msg.u.extended_buffer_data.range_length,
825 flags);
826
827 LOGV("FILL_BUFFER_DONE(timestamp: %lld us (%.2f secs))",
828 msg.u.extended_buffer_data.timestamp,
829 msg.u.extended_buffer_data.timestamp / 1E6);
830
831 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
832 size_t i = 0;
833 while (i < buffers->size() && (*buffers)[i].mBuffer != buffer) {
834 ++i;
835 }
836
837 CHECK(i < buffers->size());
838 BufferInfo *info = &buffers->editItemAt(i);
839
840 if (!info->mOwnedByComponent) {
841 LOGW("We already own output buffer %p, yet received "
842 "a FILL_BUFFER_DONE.", buffer);
843 }
844
845 info->mOwnedByComponent = false;
846
847 if (mPortStatus[kPortIndexOutput] == DISABLING) {
848 LOGV("Port is disabled, freeing buffer %p", buffer);
849
850 status_t err =
851 mOMX->free_buffer(mNode, kPortIndexOutput, buffer);
852 CHECK_EQ(err, OK);
853
854 buffers->removeAt(i);
855 } else if (flags & OMX_BUFFERFLAG_EOS) {
856 LOGV("No more output data.");
857 mNoMoreOutputData = true;
858 mBufferFilled.signal();
859 } else if (mPortStatus[kPortIndexOutput] != SHUTTING_DOWN) {
860 CHECK_EQ(mPortStatus[kPortIndexOutput], ENABLED);
Andreas Huberebf66ea2009-08-19 13:32:58 -0700861
Andreas Huberbe06d262009-08-14 14:37:10 -0700862 MediaBuffer *buffer = info->mMediaBuffer;
863
864 buffer->set_range(
865 msg.u.extended_buffer_data.range_offset,
866 msg.u.extended_buffer_data.range_length);
867
868 buffer->meta_data()->clear();
869
870 buffer->meta_data()->setInt32(
871 kKeyTimeUnits,
872 (msg.u.extended_buffer_data.timestamp + 500) / 1000);
873
874 buffer->meta_data()->setInt32(
875 kKeyTimeScale, 1000);
876
877 if (msg.u.extended_buffer_data.flags & OMX_BUFFERFLAG_SYNCFRAME) {
878 buffer->meta_data()->setInt32(kKeyIsSyncFrame, true);
879 }
880
881 buffer->meta_data()->setPointer(
882 kKeyPlatformPrivate,
883 msg.u.extended_buffer_data.platform_private);
884
885 buffer->meta_data()->setPointer(
886 kKeyBufferID,
887 msg.u.extended_buffer_data.buffer);
888
889 mFilledBuffers.push_back(i);
890 mBufferFilled.signal();
891 }
892
893 break;
894 }
895
896 default:
897 {
898 CHECK(!"should not be here.");
899 break;
900 }
901 }
902}
903
904void OMXCodec::onEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) {
905 switch (event) {
906 case OMX_EventCmdComplete:
907 {
908 onCmdComplete((OMX_COMMANDTYPE)data1, data2);
909 break;
910 }
911
912 case OMX_EventError:
913 {
914 LOGE("ERROR(%ld, %ld)", data1, data2);
915
916 setState(ERROR);
917 break;
918 }
919
920 case OMX_EventPortSettingsChanged:
921 {
922 onPortSettingsChanged(data1);
923 break;
924 }
925
926 case OMX_EventBufferFlag:
927 {
928 LOGV("EVENT_BUFFER_FLAG(%ld)", data1);
929
930 if (data1 == kPortIndexOutput) {
931 mNoMoreOutputData = true;
932 }
933 break;
934 }
935
936 default:
937 {
938 LOGV("EVENT(%d, %ld, %ld)", event, data1, data2);
939 break;
940 }
941 }
942}
943
944void OMXCodec::onCmdComplete(OMX_COMMANDTYPE cmd, OMX_U32 data) {
945 switch (cmd) {
946 case OMX_CommandStateSet:
947 {
948 onStateChange((OMX_STATETYPE)data);
949 break;
950 }
951
952 case OMX_CommandPortDisable:
953 {
954 OMX_U32 portIndex = data;
955 LOGV("PORT_DISABLED(%ld)", portIndex);
956
957 CHECK(mState == EXECUTING || mState == RECONFIGURING);
958 CHECK_EQ(mPortStatus[portIndex], DISABLING);
959 CHECK_EQ(mPortBuffers[portIndex].size(), 0);
960
961 mPortStatus[portIndex] = DISABLED;
962
963 if (mState == RECONFIGURING) {
964 CHECK_EQ(portIndex, kPortIndexOutput);
965
966 enablePortAsync(portIndex);
967
968 status_t err = allocateBuffersOnPort(portIndex);
969 CHECK_EQ(err, OK);
970 }
971 break;
972 }
973
974 case OMX_CommandPortEnable:
975 {
976 OMX_U32 portIndex = data;
977 LOGV("PORT_ENABLED(%ld)", portIndex);
978
979 CHECK(mState == EXECUTING || mState == RECONFIGURING);
980 CHECK_EQ(mPortStatus[portIndex], ENABLING);
981
982 mPortStatus[portIndex] = ENABLED;
983
984 if (mState == RECONFIGURING) {
985 CHECK_EQ(portIndex, kPortIndexOutput);
986
987 setState(EXECUTING);
988
989 fillOutputBuffers();
990 }
991 break;
992 }
993
994 case OMX_CommandFlush:
995 {
996 OMX_U32 portIndex = data;
997
998 LOGV("FLUSH_DONE(%ld)", portIndex);
999
1000 CHECK_EQ(mPortStatus[portIndex], SHUTTING_DOWN);
1001 mPortStatus[portIndex] = ENABLED;
1002
1003 CHECK_EQ(countBuffersWeOwn(mPortBuffers[portIndex]),
1004 mPortBuffers[portIndex].size());
1005
1006 if (mState == RECONFIGURING) {
1007 CHECK_EQ(portIndex, kPortIndexOutput);
1008
1009 disablePortAsync(portIndex);
1010 } else {
1011 // We're flushing both ports in preparation for seeking.
1012
1013 if (mPortStatus[kPortIndexInput] == ENABLED
1014 && mPortStatus[kPortIndexOutput] == ENABLED) {
1015 LOGV("Finished flushing both ports, now continuing from"
1016 " seek-time.");
1017
1018 drainInputBuffers();
1019 fillOutputBuffers();
1020 }
1021 }
1022
1023 break;
1024 }
1025
1026 default:
1027 {
1028 LOGV("CMD_COMPLETE(%d, %ld)", cmd, data);
1029 break;
1030 }
1031 }
1032}
1033
1034void OMXCodec::onStateChange(OMX_STATETYPE newState) {
1035 switch (newState) {
1036 case OMX_StateIdle:
1037 {
1038 LOGV("Now Idle.");
1039 if (mState == LOADED_TO_IDLE) {
1040 status_t err = mOMX->send_command(
1041 mNode, OMX_CommandStateSet, OMX_StateExecuting);
1042
1043 CHECK_EQ(err, OK);
1044
1045 setState(IDLE_TO_EXECUTING);
1046 } else {
1047 CHECK_EQ(mState, EXECUTING_TO_IDLE);
1048
1049 CHECK_EQ(
1050 countBuffersWeOwn(mPortBuffers[kPortIndexInput]),
1051 mPortBuffers[kPortIndexInput].size());
1052
1053 CHECK_EQ(
1054 countBuffersWeOwn(mPortBuffers[kPortIndexOutput]),
1055 mPortBuffers[kPortIndexOutput].size());
1056
1057 status_t err = mOMX->send_command(
1058 mNode, OMX_CommandStateSet, OMX_StateLoaded);
1059
1060 CHECK_EQ(err, OK);
1061
1062 err = freeBuffersOnPort(kPortIndexInput);
1063 CHECK_EQ(err, OK);
1064
1065 err = freeBuffersOnPort(kPortIndexOutput);
1066 CHECK_EQ(err, OK);
1067
1068 mPortStatus[kPortIndexInput] = ENABLED;
1069 mPortStatus[kPortIndexOutput] = ENABLED;
1070
1071 setState(IDLE_TO_LOADED);
1072 }
1073 break;
1074 }
1075
1076 case OMX_StateExecuting:
1077 {
1078 CHECK_EQ(mState, IDLE_TO_EXECUTING);
1079
1080 LOGV("Now Executing.");
1081
1082 setState(EXECUTING);
1083
1084 drainInputBuffers();
1085 fillOutputBuffers();
1086 break;
1087 }
1088
1089 case OMX_StateLoaded:
1090 {
1091 CHECK_EQ(mState, IDLE_TO_LOADED);
1092
1093 LOGV("Now Loaded.");
1094
1095 setState(LOADED);
1096 break;
1097 }
1098
1099 default:
1100 {
1101 CHECK(!"should not be here.");
1102 break;
1103 }
1104 }
1105}
1106
1107// static
1108size_t OMXCodec::countBuffersWeOwn(const Vector<BufferInfo> &buffers) {
1109 size_t n = 0;
1110 for (size_t i = 0; i < buffers.size(); ++i) {
1111 if (!buffers[i].mOwnedByComponent) {
1112 ++n;
1113 }
1114 }
1115
1116 return n;
1117}
1118
1119status_t OMXCodec::freeBuffersOnPort(
1120 OMX_U32 portIndex, bool onlyThoseWeOwn) {
1121 Vector<BufferInfo> *buffers = &mPortBuffers[portIndex];
1122
1123 status_t stickyErr = OK;
1124
1125 for (size_t i = buffers->size(); i-- > 0;) {
1126 BufferInfo *info = &buffers->editItemAt(i);
1127
1128 if (onlyThoseWeOwn && info->mOwnedByComponent) {
1129 continue;
1130 }
1131
1132 CHECK_EQ(info->mOwnedByComponent, false);
1133
1134 status_t err =
1135 mOMX->free_buffer(mNode, portIndex, info->mBuffer);
1136
1137 if (err != OK) {
1138 stickyErr = err;
1139 }
1140
1141 if (info->mMediaBuffer != NULL) {
1142 info->mMediaBuffer->setObserver(NULL);
1143
1144 // Make sure nobody but us owns this buffer at this point.
1145 CHECK_EQ(info->mMediaBuffer->refcount(), 0);
1146
1147 info->mMediaBuffer->release();
1148 }
1149
1150 buffers->removeAt(i);
1151 }
1152
1153 CHECK(onlyThoseWeOwn || buffers->isEmpty());
1154
1155 return stickyErr;
1156}
1157
1158void OMXCodec::onPortSettingsChanged(OMX_U32 portIndex) {
1159 LOGV("PORT_SETTINGS_CHANGED(%ld)", portIndex);
1160
1161 CHECK_EQ(mState, EXECUTING);
1162 CHECK_EQ(portIndex, kPortIndexOutput);
1163 setState(RECONFIGURING);
1164
1165 if (mQuirks & kNeedsFlushBeforeDisable) {
1166 flushPortAsync(portIndex);
1167 } else {
1168 disablePortAsync(portIndex);
1169 }
1170}
1171
1172void OMXCodec::flushPortAsync(OMX_U32 portIndex) {
1173 CHECK(mState == EXECUTING || mState == RECONFIGURING);
1174
1175 CHECK_EQ(mPortStatus[portIndex], ENABLED);
1176 mPortStatus[portIndex] = SHUTTING_DOWN;
1177
1178 status_t err =
1179 mOMX->send_command(mNode, OMX_CommandFlush, portIndex);
1180 CHECK_EQ(err, OK);
1181}
1182
1183void OMXCodec::disablePortAsync(OMX_U32 portIndex) {
1184 CHECK(mState == EXECUTING || mState == RECONFIGURING);
1185
1186 CHECK_EQ(mPortStatus[portIndex], ENABLED);
1187 mPortStatus[portIndex] = DISABLING;
1188
1189 status_t err =
1190 mOMX->send_command(mNode, OMX_CommandPortDisable, portIndex);
1191 CHECK_EQ(err, OK);
1192
1193 freeBuffersOnPort(portIndex, true);
1194}
1195
1196void OMXCodec::enablePortAsync(OMX_U32 portIndex) {
1197 CHECK(mState == EXECUTING || mState == RECONFIGURING);
1198
1199 CHECK_EQ(mPortStatus[portIndex], DISABLED);
1200 mPortStatus[portIndex] = ENABLING;
1201
1202 status_t err =
1203 mOMX->send_command(mNode, OMX_CommandPortEnable, portIndex);
1204 CHECK_EQ(err, OK);
1205}
1206
1207void OMXCodec::fillOutputBuffers() {
1208 CHECK_EQ(mState, EXECUTING);
1209
1210 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
1211 for (size_t i = 0; i < buffers->size(); ++i) {
1212 fillOutputBuffer(&buffers->editItemAt(i));
1213 }
1214}
1215
1216void OMXCodec::drainInputBuffers() {
1217 CHECK_EQ(mState, EXECUTING);
1218
1219 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
1220 for (size_t i = 0; i < buffers->size(); ++i) {
1221 drainInputBuffer(&buffers->editItemAt(i));
1222 }
1223}
1224
1225void OMXCodec::drainInputBuffer(BufferInfo *info) {
1226 CHECK_EQ(info->mOwnedByComponent, false);
1227
1228 if (mSignalledEOS) {
1229 return;
1230 }
1231
1232 if (mCodecSpecificDataIndex < mCodecSpecificData.size()) {
1233 const CodecSpecificData *specific =
1234 mCodecSpecificData[mCodecSpecificDataIndex];
1235
1236 size_t size = specific->mSize;
1237
Andreas Huber4f5e6022009-08-19 09:29:34 -07001238 if (!strcasecmp("video/avc", mMIME)
1239 && !(mQuirks & kWantsNALFragments)) {
Andreas Huberbe06d262009-08-14 14:37:10 -07001240 static const uint8_t kNALStartCode[4] =
1241 { 0x00, 0x00, 0x00, 0x01 };
1242
1243 CHECK(info->mMem->size() >= specific->mSize + 4);
1244
1245 size += 4;
1246
1247 memcpy(info->mMem->pointer(), kNALStartCode, 4);
1248 memcpy((uint8_t *)info->mMem->pointer() + 4,
1249 specific->mData, specific->mSize);
1250 } else {
1251 CHECK(info->mMem->size() >= specific->mSize);
1252 memcpy(info->mMem->pointer(), specific->mData, specific->mSize);
1253 }
1254
1255 mOMX->empty_buffer(
1256 mNode, info->mBuffer, 0, size,
1257 OMX_BUFFERFLAG_ENDOFFRAME | OMX_BUFFERFLAG_CODECCONFIG,
1258 0);
1259
1260 info->mOwnedByComponent = true;
1261
1262 ++mCodecSpecificDataIndex;
1263 return;
1264 }
1265
1266 MediaBuffer *srcBuffer;
1267 status_t err;
1268 if (mSeekTimeUs >= 0) {
1269 MediaSource::ReadOptions options;
1270 options.setSeekTo(mSeekTimeUs);
1271 mSeekTimeUs = -1;
1272
1273 err = mSource->read(&srcBuffer, &options);
1274 } else {
1275 err = mSource->read(&srcBuffer);
1276 }
1277
1278 OMX_U32 flags = OMX_BUFFERFLAG_ENDOFFRAME;
1279 OMX_TICKS timestamp = 0;
1280 size_t srcLength = 0;
1281
1282 if (err != OK) {
1283 LOGV("signalling end of input stream.");
1284 flags |= OMX_BUFFERFLAG_EOS;
1285
1286 mSignalledEOS = true;
1287 } else {
1288 srcLength = srcBuffer->range_length();
1289
1290 if (info->mMem->size() < srcLength) {
1291 LOGE("info->mMem->size() = %d, srcLength = %d",
1292 info->mMem->size(), srcLength);
1293 }
1294 CHECK(info->mMem->size() >= srcLength);
1295 memcpy(info->mMem->pointer(),
1296 (const uint8_t *)srcBuffer->data() + srcBuffer->range_offset(),
1297 srcLength);
1298
1299 int32_t units, scale;
1300 if (srcBuffer->meta_data()->findInt32(kKeyTimeUnits, &units)
1301 && srcBuffer->meta_data()->findInt32(kKeyTimeScale, &scale)) {
1302 timestamp = ((OMX_TICKS)units * 1000000) / scale;
1303
1304 LOGV("Calling empty_buffer on buffer %p (length %d)",
1305 info->mBuffer, srcLength);
1306 LOGV("Calling empty_buffer with timestamp %lld us (%.2f secs)",
1307 timestamp, timestamp / 1E6);
1308 }
1309 }
1310
1311 mOMX->empty_buffer(
1312 mNode, info->mBuffer, 0, srcLength,
1313 flags, timestamp);
1314
1315 info->mOwnedByComponent = true;
1316
1317 if (srcBuffer != NULL) {
1318 srcBuffer->release();
1319 srcBuffer = NULL;
1320 }
1321}
1322
1323void OMXCodec::fillOutputBuffer(BufferInfo *info) {
1324 CHECK_EQ(info->mOwnedByComponent, false);
1325
1326 LOGV("Calling fill_buffer on buffer %p", info->mBuffer);
1327 mOMX->fill_buffer(mNode, info->mBuffer);
1328
1329 info->mOwnedByComponent = true;
1330}
1331
1332void OMXCodec::drainInputBuffer(IOMX::buffer_id buffer) {
1333 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
1334 for (size_t i = 0; i < buffers->size(); ++i) {
1335 if ((*buffers)[i].mBuffer == buffer) {
1336 drainInputBuffer(&buffers->editItemAt(i));
1337 return;
1338 }
1339 }
1340
1341 CHECK(!"should not be here.");
1342}
1343
1344void OMXCodec::fillOutputBuffer(IOMX::buffer_id buffer) {
1345 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
1346 for (size_t i = 0; i < buffers->size(); ++i) {
1347 if ((*buffers)[i].mBuffer == buffer) {
1348 fillOutputBuffer(&buffers->editItemAt(i));
1349 return;
1350 }
1351 }
1352
1353 CHECK(!"should not be here.");
1354}
1355
1356void OMXCodec::setState(State newState) {
1357 mState = newState;
1358 mAsyncCompletion.signal();
1359
1360 // This may cause some spurious wakeups but is necessary to
1361 // unblock the reader if we enter ERROR state.
1362 mBufferFilled.signal();
1363}
1364
1365void OMXCodec::setAMRFormat() {
1366 if (!mIsEncoder) {
1367 OMX_AUDIO_PARAM_AMRTYPE def;
1368 def.nSize = sizeof(def);
1369 def.nVersion.s.nVersionMajor = 1;
1370 def.nVersion.s.nVersionMinor = 1;
1371 def.nPortIndex = kPortIndexInput;
1372
1373 status_t err =
1374 mOMX->get_parameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
1375
1376 CHECK_EQ(err, OK);
1377
1378 def.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
1379 def.eAMRBandMode = OMX_AUDIO_AMRBandModeNB0;
1380
1381 err = mOMX->set_parameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
1382 CHECK_EQ(err, OK);
1383 }
1384
1385 ////////////////////////
1386
1387 if (mIsEncoder) {
1388 sp<MetaData> format = mSource->getFormat();
1389 int32_t sampleRate;
1390 int32_t numChannels;
1391 CHECK(format->findInt32(kKeySampleRate, &sampleRate));
1392 CHECK(format->findInt32(kKeyChannelCount, &numChannels));
1393
1394 OMX_AUDIO_PARAM_PCMMODETYPE pcmParams;
1395 pcmParams.nSize = sizeof(pcmParams);
1396 pcmParams.nVersion.s.nVersionMajor = 1;
1397 pcmParams.nVersion.s.nVersionMinor = 1;
1398 pcmParams.nPortIndex = kPortIndexInput;
1399
1400 status_t err = mOMX->get_parameter(
1401 mNode, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams));
1402
1403 CHECK_EQ(err, OK);
1404
1405 pcmParams.nChannels = numChannels;
1406 pcmParams.eNumData = OMX_NumericalDataSigned;
1407 pcmParams.bInterleaved = OMX_TRUE;
1408 pcmParams.nBitPerSample = 16;
1409 pcmParams.nSamplingRate = sampleRate;
1410 pcmParams.ePCMMode = OMX_AUDIO_PCMModeLinear;
1411
1412 if (numChannels == 1) {
1413 pcmParams.eChannelMapping[0] = OMX_AUDIO_ChannelCF;
1414 } else {
1415 CHECK_EQ(numChannels, 2);
1416
1417 pcmParams.eChannelMapping[0] = OMX_AUDIO_ChannelLF;
1418 pcmParams.eChannelMapping[1] = OMX_AUDIO_ChannelRF;
1419 }
1420
1421 err = mOMX->set_parameter(
1422 mNode, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams));
1423
1424 CHECK_EQ(err, OK);
1425 }
1426}
1427
1428void OMXCodec::setAACFormat() {
1429 OMX_AUDIO_PARAM_AACPROFILETYPE def;
1430 def.nSize = sizeof(def);
1431 def.nVersion.s.nVersionMajor = 1;
1432 def.nVersion.s.nVersionMinor = 1;
1433 def.nPortIndex = kPortIndexInput;
1434
1435 status_t err =
1436 mOMX->get_parameter(mNode, OMX_IndexParamAudioAac, &def, sizeof(def));
1437 CHECK_EQ(err, OK);
1438
1439 def.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4ADTS;
1440
1441 err = mOMX->set_parameter(mNode, OMX_IndexParamAudioAac, &def, sizeof(def));
1442 CHECK_EQ(err, OK);
1443}
1444
1445void OMXCodec::setImageOutputFormat(
1446 OMX_COLOR_FORMATTYPE format, OMX_U32 width, OMX_U32 height) {
1447 LOGV("setImageOutputFormat(%ld, %ld)", width, height);
1448
1449#if 0
1450 OMX_INDEXTYPE index;
1451 status_t err = mOMX->get_extension_index(
1452 mNode, "OMX.TI.JPEG.decode.Config.OutputColorFormat", &index);
1453 CHECK_EQ(err, OK);
1454
1455 err = mOMX->set_config(mNode, index, &format, sizeof(format));
1456 CHECK_EQ(err, OK);
1457#endif
1458
1459 OMX_PARAM_PORTDEFINITIONTYPE def;
1460 def.nSize = sizeof(def);
1461 def.nVersion.s.nVersionMajor = 1;
1462 def.nVersion.s.nVersionMinor = 1;
1463 def.nPortIndex = kPortIndexOutput;
1464
1465 status_t err = mOMX->get_parameter(
1466 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
1467 CHECK_EQ(err, OK);
1468
1469 CHECK_EQ(def.eDomain, OMX_PortDomainImage);
1470
1471 OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
Andreas Huberebf66ea2009-08-19 13:32:58 -07001472
Andreas Huberbe06d262009-08-14 14:37:10 -07001473 CHECK_EQ(imageDef->eCompressionFormat, OMX_IMAGE_CodingUnused);
1474 imageDef->eColorFormat = format;
1475 imageDef->nFrameWidth = width;
1476 imageDef->nFrameHeight = height;
1477
1478 switch (format) {
1479 case OMX_COLOR_FormatYUV420PackedPlanar:
1480 case OMX_COLOR_FormatYUV411Planar:
1481 {
1482 def.nBufferSize = (width * height * 3) / 2;
1483 break;
1484 }
1485
1486 case OMX_COLOR_FormatCbYCrY:
1487 {
1488 def.nBufferSize = width * height * 2;
1489 break;
1490 }
1491
1492 case OMX_COLOR_Format32bitARGB8888:
1493 {
1494 def.nBufferSize = width * height * 4;
1495 break;
1496 }
1497
1498 default:
1499 CHECK(!"Should not be here. Unknown color format.");
1500 break;
1501 }
1502
Andreas Huber5c0a9132009-08-20 11:16:40 -07001503 def.nBufferCountActual = def.nBufferCountMin;
1504
Andreas Huberbe06d262009-08-14 14:37:10 -07001505 err = mOMX->set_parameter(
1506 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
1507 CHECK_EQ(err, OK);
Andreas Huber5c0a9132009-08-20 11:16:40 -07001508}
Andreas Huberbe06d262009-08-14 14:37:10 -07001509
Andreas Huber5c0a9132009-08-20 11:16:40 -07001510void OMXCodec::setJPEGInputFormat(
1511 OMX_U32 width, OMX_U32 height, OMX_U32 compressedSize) {
1512 OMX_PARAM_PORTDEFINITIONTYPE def;
1513 def.nSize = sizeof(def);
1514 def.nVersion.s.nVersionMajor = 1;
1515 def.nVersion.s.nVersionMinor = 1;
Andreas Huberbe06d262009-08-14 14:37:10 -07001516 def.nPortIndex = kPortIndexInput;
1517
Andreas Huber5c0a9132009-08-20 11:16:40 -07001518 status_t err = mOMX->get_parameter(
Andreas Huberbe06d262009-08-14 14:37:10 -07001519 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
1520 CHECK_EQ(err, OK);
1521
Andreas Huber5c0a9132009-08-20 11:16:40 -07001522 CHECK_EQ(def.eDomain, OMX_PortDomainImage);
1523 OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
1524
Andreas Huberbe06d262009-08-14 14:37:10 -07001525 CHECK_EQ(imageDef->eCompressionFormat, OMX_IMAGE_CodingJPEG);
1526 imageDef->nFrameWidth = width;
1527 imageDef->nFrameHeight = height;
1528
Andreas Huber5c0a9132009-08-20 11:16:40 -07001529 def.nBufferSize = compressedSize;
Andreas Huberbe06d262009-08-14 14:37:10 -07001530 def.nBufferCountActual = def.nBufferCountMin;
1531
1532 err = mOMX->set_parameter(
1533 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
1534 CHECK_EQ(err, OK);
1535}
1536
1537void OMXCodec::addCodecSpecificData(const void *data, size_t size) {
1538 CodecSpecificData *specific =
1539 (CodecSpecificData *)malloc(sizeof(CodecSpecificData) + size - 1);
1540
1541 specific->mSize = size;
1542 memcpy(specific->mData, data, size);
1543
1544 mCodecSpecificData.push(specific);
1545}
1546
1547void OMXCodec::clearCodecSpecificData() {
1548 for (size_t i = 0; i < mCodecSpecificData.size(); ++i) {
1549 free(mCodecSpecificData.editItemAt(i));
1550 }
1551 mCodecSpecificData.clear();
1552 mCodecSpecificDataIndex = 0;
1553}
1554
1555status_t OMXCodec::start(MetaData *) {
1556 if (mState != LOADED) {
1557 return UNKNOWN_ERROR;
1558 }
Andreas Huberebf66ea2009-08-19 13:32:58 -07001559
Andreas Huberbe06d262009-08-14 14:37:10 -07001560 sp<MetaData> params = new MetaData;
Andreas Huber4f5e6022009-08-19 09:29:34 -07001561 if (mQuirks & kWantsNALFragments) {
1562 params->setInt32(kKeyWantsNALFragments, true);
Andreas Huberbe06d262009-08-14 14:37:10 -07001563 }
1564 status_t err = mSource->start(params.get());
1565
1566 if (err != OK) {
1567 return err;
1568 }
1569
1570 mCodecSpecificDataIndex = 0;
1571 mSignalledEOS = false;
1572 mNoMoreOutputData = false;
1573 mSeekTimeUs = -1;
1574 mFilledBuffers.clear();
1575
1576 return init();
1577}
1578
1579status_t OMXCodec::stop() {
Andreas Huber5c0a9132009-08-20 11:16:40 -07001580 LOGV("stop");
Andreas Huberbe06d262009-08-14 14:37:10 -07001581
1582 Mutex::Autolock autoLock(mLock);
1583
1584 while (isIntermediateState(mState)) {
1585 mAsyncCompletion.wait(mLock);
1586 }
1587
1588 switch (mState) {
1589 case LOADED:
1590 case ERROR:
1591 break;
1592
1593 case EXECUTING:
1594 {
1595 setState(EXECUTING_TO_IDLE);
1596
1597 mPortStatus[kPortIndexInput] = SHUTTING_DOWN;
1598 mPortStatus[kPortIndexOutput] = SHUTTING_DOWN;
1599
1600 status_t err =
1601 mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
1602 CHECK_EQ(err, OK);
1603
1604 while (mState != LOADED && mState != ERROR) {
1605 mAsyncCompletion.wait(mLock);
1606 }
1607
1608 break;
1609 }
1610
1611 default:
1612 {
1613 CHECK(!"should not be here.");
1614 break;
1615 }
1616 }
1617
1618 mSource->stop();
1619
1620 return OK;
1621}
1622
1623sp<MetaData> OMXCodec::getFormat() {
1624 return mOutputFormat;
1625}
1626
1627status_t OMXCodec::read(
1628 MediaBuffer **buffer, const ReadOptions *options) {
1629 *buffer = NULL;
1630
1631 Mutex::Autolock autoLock(mLock);
1632
1633 if (mState != EXECUTING && mState != RECONFIGURING) {
1634 return UNKNOWN_ERROR;
1635 }
1636
1637 int64_t seekTimeUs;
1638 if (options && options->getSeekTo(&seekTimeUs)) {
1639 LOGV("seeking to %lld us (%.2f secs)", seekTimeUs, seekTimeUs / 1E6);
1640
1641 mSignalledEOS = false;
1642 mNoMoreOutputData = false;
1643
1644 CHECK(seekTimeUs >= 0);
1645 mSeekTimeUs = seekTimeUs;
1646
1647 mFilledBuffers.clear();
1648
1649 CHECK_EQ(mState, EXECUTING);
1650
1651 flushPortAsync(kPortIndexInput);
1652 flushPortAsync(kPortIndexOutput);
1653 }
1654
1655 while (mState != ERROR && !mNoMoreOutputData && mFilledBuffers.empty()) {
1656 mBufferFilled.wait(mLock);
1657 }
1658
1659 if (mState == ERROR) {
1660 return UNKNOWN_ERROR;
1661 }
1662
1663 if (mFilledBuffers.empty()) {
1664 return ERROR_END_OF_STREAM;
1665 }
1666
1667 size_t index = *mFilledBuffers.begin();
1668 mFilledBuffers.erase(mFilledBuffers.begin());
1669
1670 BufferInfo *info = &mPortBuffers[kPortIndexOutput].editItemAt(index);
1671 info->mMediaBuffer->add_ref();
1672 *buffer = info->mMediaBuffer;
1673
1674 return OK;
1675}
1676
1677void OMXCodec::signalBufferReturned(MediaBuffer *buffer) {
1678 Mutex::Autolock autoLock(mLock);
1679
1680 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
1681 for (size_t i = 0; i < buffers->size(); ++i) {
1682 BufferInfo *info = &buffers->editItemAt(i);
1683
1684 if (info->mMediaBuffer == buffer) {
1685 CHECK_EQ(mPortStatus[kPortIndexOutput], ENABLED);
1686 fillOutputBuffer(info);
1687 return;
1688 }
1689 }
1690
1691 CHECK(!"should not be here.");
1692}
1693
1694static const char *imageCompressionFormatString(OMX_IMAGE_CODINGTYPE type) {
1695 static const char *kNames[] = {
1696 "OMX_IMAGE_CodingUnused",
1697 "OMX_IMAGE_CodingAutoDetect",
1698 "OMX_IMAGE_CodingJPEG",
1699 "OMX_IMAGE_CodingJPEG2K",
1700 "OMX_IMAGE_CodingEXIF",
1701 "OMX_IMAGE_CodingTIFF",
1702 "OMX_IMAGE_CodingGIF",
1703 "OMX_IMAGE_CodingPNG",
1704 "OMX_IMAGE_CodingLZW",
1705 "OMX_IMAGE_CodingBMP",
1706 };
1707
1708 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
1709
1710 if (type < 0 || (size_t)type >= numNames) {
1711 return "UNKNOWN";
1712 } else {
1713 return kNames[type];
1714 }
1715}
1716
1717static const char *colorFormatString(OMX_COLOR_FORMATTYPE type) {
1718 static const char *kNames[] = {
1719 "OMX_COLOR_FormatUnused",
1720 "OMX_COLOR_FormatMonochrome",
1721 "OMX_COLOR_Format8bitRGB332",
1722 "OMX_COLOR_Format12bitRGB444",
1723 "OMX_COLOR_Format16bitARGB4444",
1724 "OMX_COLOR_Format16bitARGB1555",
1725 "OMX_COLOR_Format16bitRGB565",
1726 "OMX_COLOR_Format16bitBGR565",
1727 "OMX_COLOR_Format18bitRGB666",
1728 "OMX_COLOR_Format18bitARGB1665",
Andreas Huberebf66ea2009-08-19 13:32:58 -07001729 "OMX_COLOR_Format19bitARGB1666",
Andreas Huberbe06d262009-08-14 14:37:10 -07001730 "OMX_COLOR_Format24bitRGB888",
1731 "OMX_COLOR_Format24bitBGR888",
1732 "OMX_COLOR_Format24bitARGB1887",
1733 "OMX_COLOR_Format25bitARGB1888",
1734 "OMX_COLOR_Format32bitBGRA8888",
1735 "OMX_COLOR_Format32bitARGB8888",
1736 "OMX_COLOR_FormatYUV411Planar",
1737 "OMX_COLOR_FormatYUV411PackedPlanar",
1738 "OMX_COLOR_FormatYUV420Planar",
1739 "OMX_COLOR_FormatYUV420PackedPlanar",
1740 "OMX_COLOR_FormatYUV420SemiPlanar",
1741 "OMX_COLOR_FormatYUV422Planar",
1742 "OMX_COLOR_FormatYUV422PackedPlanar",
1743 "OMX_COLOR_FormatYUV422SemiPlanar",
1744 "OMX_COLOR_FormatYCbYCr",
1745 "OMX_COLOR_FormatYCrYCb",
1746 "OMX_COLOR_FormatCbYCrY",
1747 "OMX_COLOR_FormatCrYCbY",
1748 "OMX_COLOR_FormatYUV444Interleaved",
1749 "OMX_COLOR_FormatRawBayer8bit",
1750 "OMX_COLOR_FormatRawBayer10bit",
1751 "OMX_COLOR_FormatRawBayer8bitcompressed",
Andreas Huberebf66ea2009-08-19 13:32:58 -07001752 "OMX_COLOR_FormatL2",
1753 "OMX_COLOR_FormatL4",
1754 "OMX_COLOR_FormatL8",
1755 "OMX_COLOR_FormatL16",
1756 "OMX_COLOR_FormatL24",
Andreas Huberbe06d262009-08-14 14:37:10 -07001757 "OMX_COLOR_FormatL32",
1758 "OMX_COLOR_FormatYUV420PackedSemiPlanar",
1759 "OMX_COLOR_FormatYUV422PackedSemiPlanar",
1760 "OMX_COLOR_Format18BitBGR666",
1761 "OMX_COLOR_Format24BitARGB6666",
1762 "OMX_COLOR_Format24BitABGR6666",
1763 };
1764
1765 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
1766
1767 static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
1768
1769 if (type == OMX_QCOM_COLOR_FormatYVU420SemiPlanar) {
1770 return "OMX_QCOM_COLOR_FormatYVU420SemiPlanar";
1771 } else if (type < 0 || (size_t)type >= numNames) {
1772 return "UNKNOWN";
1773 } else {
1774 return kNames[type];
1775 }
1776}
1777
1778static const char *videoCompressionFormatString(OMX_VIDEO_CODINGTYPE type) {
1779 static const char *kNames[] = {
1780 "OMX_VIDEO_CodingUnused",
1781 "OMX_VIDEO_CodingAutoDetect",
1782 "OMX_VIDEO_CodingMPEG2",
1783 "OMX_VIDEO_CodingH263",
1784 "OMX_VIDEO_CodingMPEG4",
1785 "OMX_VIDEO_CodingWMV",
1786 "OMX_VIDEO_CodingRV",
1787 "OMX_VIDEO_CodingAVC",
1788 "OMX_VIDEO_CodingMJPEG",
1789 };
1790
1791 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
1792
1793 if (type < 0 || (size_t)type >= numNames) {
1794 return "UNKNOWN";
1795 } else {
1796 return kNames[type];
1797 }
1798}
1799
1800static const char *audioCodingTypeString(OMX_AUDIO_CODINGTYPE type) {
1801 static const char *kNames[] = {
1802 "OMX_AUDIO_CodingUnused",
1803 "OMX_AUDIO_CodingAutoDetect",
1804 "OMX_AUDIO_CodingPCM",
1805 "OMX_AUDIO_CodingADPCM",
1806 "OMX_AUDIO_CodingAMR",
1807 "OMX_AUDIO_CodingGSMFR",
1808 "OMX_AUDIO_CodingGSMEFR",
1809 "OMX_AUDIO_CodingGSMHR",
1810 "OMX_AUDIO_CodingPDCFR",
1811 "OMX_AUDIO_CodingPDCEFR",
1812 "OMX_AUDIO_CodingPDCHR",
1813 "OMX_AUDIO_CodingTDMAFR",
1814 "OMX_AUDIO_CodingTDMAEFR",
1815 "OMX_AUDIO_CodingQCELP8",
1816 "OMX_AUDIO_CodingQCELP13",
1817 "OMX_AUDIO_CodingEVRC",
1818 "OMX_AUDIO_CodingSMV",
1819 "OMX_AUDIO_CodingG711",
1820 "OMX_AUDIO_CodingG723",
1821 "OMX_AUDIO_CodingG726",
1822 "OMX_AUDIO_CodingG729",
1823 "OMX_AUDIO_CodingAAC",
1824 "OMX_AUDIO_CodingMP3",
1825 "OMX_AUDIO_CodingSBC",
1826 "OMX_AUDIO_CodingVORBIS",
1827 "OMX_AUDIO_CodingWMA",
1828 "OMX_AUDIO_CodingRA",
1829 "OMX_AUDIO_CodingMIDI",
1830 };
1831
1832 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
1833
1834 if (type < 0 || (size_t)type >= numNames) {
1835 return "UNKNOWN";
1836 } else {
1837 return kNames[type];
1838 }
1839}
1840
1841static const char *audioPCMModeString(OMX_AUDIO_PCMMODETYPE type) {
1842 static const char *kNames[] = {
1843 "OMX_AUDIO_PCMModeLinear",
1844 "OMX_AUDIO_PCMModeALaw",
1845 "OMX_AUDIO_PCMModeMULaw",
1846 };
1847
1848 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
1849
1850 if (type < 0 || (size_t)type >= numNames) {
1851 return "UNKNOWN";
1852 } else {
1853 return kNames[type];
1854 }
1855}
1856
1857
1858void OMXCodec::dumpPortStatus(OMX_U32 portIndex) {
1859 OMX_PARAM_PORTDEFINITIONTYPE def;
1860 def.nSize = sizeof(def);
1861 def.nVersion.s.nVersionMajor = 1;
1862 def.nVersion.s.nVersionMinor = 1;
1863 def.nPortIndex = portIndex;
1864
1865 status_t err = mOMX->get_parameter(
1866 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
1867 CHECK_EQ(err, OK);
1868
1869 printf("%s Port = {\n", portIndex == kPortIndexInput ? "Input" : "Output");
1870
1871 CHECK((portIndex == kPortIndexInput && def.eDir == OMX_DirInput)
1872 || (portIndex == kPortIndexOutput && def.eDir == OMX_DirOutput));
1873
1874 printf(" nBufferCountActual = %ld\n", def.nBufferCountActual);
1875 printf(" nBufferCountMin = %ld\n", def.nBufferCountMin);
1876 printf(" nBufferSize = %ld\n", def.nBufferSize);
1877
1878 switch (def.eDomain) {
1879 case OMX_PortDomainImage:
1880 {
1881 const OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
1882
1883 printf("\n");
1884 printf(" // Image\n");
1885 printf(" nFrameWidth = %ld\n", imageDef->nFrameWidth);
1886 printf(" nFrameHeight = %ld\n", imageDef->nFrameHeight);
1887 printf(" nStride = %ld\n", imageDef->nStride);
1888
1889 printf(" eCompressionFormat = %s\n",
1890 imageCompressionFormatString(imageDef->eCompressionFormat));
1891
1892 printf(" eColorFormat = %s\n",
1893 colorFormatString(imageDef->eColorFormat));
1894
1895 break;
1896 }
1897
1898 case OMX_PortDomainVideo:
1899 {
1900 OMX_VIDEO_PORTDEFINITIONTYPE *videoDef = &def.format.video;
1901
1902 printf("\n");
1903 printf(" // Video\n");
1904 printf(" nFrameWidth = %ld\n", videoDef->nFrameWidth);
1905 printf(" nFrameHeight = %ld\n", videoDef->nFrameHeight);
1906 printf(" nStride = %ld\n", videoDef->nStride);
1907
1908 printf(" eCompressionFormat = %s\n",
1909 videoCompressionFormatString(videoDef->eCompressionFormat));
1910
1911 printf(" eColorFormat = %s\n",
1912 colorFormatString(videoDef->eColorFormat));
1913
1914 break;
1915 }
1916
1917 case OMX_PortDomainAudio:
1918 {
1919 OMX_AUDIO_PORTDEFINITIONTYPE *audioDef = &def.format.audio;
1920
1921 printf("\n");
1922 printf(" // Audio\n");
1923 printf(" eEncoding = %s\n",
1924 audioCodingTypeString(audioDef->eEncoding));
1925
1926 if (audioDef->eEncoding == OMX_AUDIO_CodingPCM) {
1927 OMX_AUDIO_PARAM_PCMMODETYPE params;
1928 params.nSize = sizeof(params);
1929 params.nVersion.s.nVersionMajor = 1;
1930 params.nVersion.s.nVersionMinor = 1;
1931 params.nPortIndex = portIndex;
1932
1933 err = mOMX->get_parameter(
1934 mNode, OMX_IndexParamAudioPcm, &params, sizeof(params));
1935 CHECK_EQ(err, OK);
1936
1937 printf(" nSamplingRate = %ld\n", params.nSamplingRate);
1938 printf(" nChannels = %ld\n", params.nChannels);
1939 printf(" bInterleaved = %d\n", params.bInterleaved);
1940 printf(" nBitPerSample = %ld\n", params.nBitPerSample);
1941
1942 printf(" eNumData = %s\n",
1943 params.eNumData == OMX_NumericalDataSigned
1944 ? "signed" : "unsigned");
1945
1946 printf(" ePCMMode = %s\n", audioPCMModeString(params.ePCMMode));
1947 }
1948
1949 break;
1950 }
1951
1952 default:
1953 {
1954 printf(" // Unknown\n");
1955 break;
1956 }
1957 }
1958
1959 printf("}\n");
1960}
1961
1962void OMXCodec::initOutputFormat(const sp<MetaData> &inputFormat) {
1963 mOutputFormat = new MetaData;
1964 mOutputFormat->setCString(kKeyDecoderComponent, mComponentName);
1965
1966 OMX_PARAM_PORTDEFINITIONTYPE def;
1967 def.nSize = sizeof(def);
1968 def.nVersion.s.nVersionMajor = 1;
1969 def.nVersion.s.nVersionMinor = 1;
1970 def.nPortIndex = kPortIndexOutput;
1971
1972 status_t err = mOMX->get_parameter(
1973 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
1974 CHECK_EQ(err, OK);
1975
1976 switch (def.eDomain) {
1977 case OMX_PortDomainImage:
1978 {
1979 OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
1980 CHECK_EQ(imageDef->eCompressionFormat, OMX_IMAGE_CodingUnused);
1981
1982 mOutputFormat->setCString(kKeyMIMEType, "image/raw");
1983 mOutputFormat->setInt32(kKeyColorFormat, imageDef->eColorFormat);
1984 mOutputFormat->setInt32(kKeyWidth, imageDef->nFrameWidth);
1985 mOutputFormat->setInt32(kKeyHeight, imageDef->nFrameHeight);
1986 break;
1987 }
1988
1989 case OMX_PortDomainAudio:
1990 {
1991 OMX_AUDIO_PORTDEFINITIONTYPE *audio_def = &def.format.audio;
1992
1993 CHECK_EQ(audio_def->eEncoding, OMX_AUDIO_CodingPCM);
1994
1995 OMX_AUDIO_PARAM_PCMMODETYPE params;
1996 params.nSize = sizeof(params);
1997 params.nVersion.s.nVersionMajor = 1;
1998 params.nVersion.s.nVersionMinor = 1;
1999 params.nPortIndex = kPortIndexOutput;
2000
2001 err = mOMX->get_parameter(
2002 mNode, OMX_IndexParamAudioPcm, &params, sizeof(params));
2003 CHECK_EQ(err, OK);
2004
2005 CHECK_EQ(params.eNumData, OMX_NumericalDataSigned);
2006 CHECK_EQ(params.nBitPerSample, 16);
2007 CHECK_EQ(params.ePCMMode, OMX_AUDIO_PCMModeLinear);
2008
2009 int32_t numChannels, sampleRate;
2010 inputFormat->findInt32(kKeyChannelCount, &numChannels);
2011 inputFormat->findInt32(kKeySampleRate, &sampleRate);
2012
2013 mOutputFormat->setCString(kKeyMIMEType, "audio/raw");
2014 mOutputFormat->setInt32(kKeyChannelCount, numChannels);
2015 mOutputFormat->setInt32(kKeySampleRate, sampleRate);
2016 break;
2017 }
2018
2019 case OMX_PortDomainVideo:
2020 {
2021 OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
2022
2023 if (video_def->eCompressionFormat == OMX_VIDEO_CodingUnused) {
2024 mOutputFormat->setCString(kKeyMIMEType, "video/raw");
2025 } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingMPEG4) {
2026 mOutputFormat->setCString(kKeyMIMEType, "video/mp4v-es");
2027 } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingH263) {
2028 mOutputFormat->setCString(kKeyMIMEType, "video/3gpp");
2029 } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingAVC) {
2030 mOutputFormat->setCString(kKeyMIMEType, "video/avc");
2031 } else {
2032 CHECK(!"Unknown compression format.");
2033 }
2034
2035 if (!strcmp(mComponentName, "OMX.PV.avcdec")) {
2036 // This component appears to be lying to me.
2037 mOutputFormat->setInt32(
2038 kKeyWidth, (video_def->nFrameWidth + 15) & -16);
2039 mOutputFormat->setInt32(
2040 kKeyHeight, (video_def->nFrameHeight + 15) & -16);
2041 } else {
2042 mOutputFormat->setInt32(kKeyWidth, video_def->nFrameWidth);
2043 mOutputFormat->setInt32(kKeyHeight, video_def->nFrameHeight);
2044 }
2045
2046 mOutputFormat->setInt32(kKeyColorFormat, video_def->eColorFormat);
2047 break;
2048 }
2049
2050 default:
2051 {
2052 CHECK(!"should not be here, neither audio nor video.");
2053 break;
2054 }
2055 }
2056}
2057
2058} // namespace android