blob: de808e55a5792416121bdc2031128610d049ed71 [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
Andreas Huber4c483422009-09-02 16:05:36 -070080#define CODEC_LOGV(x, ...) LOGV("[%s] "x, mComponentName, ##__VA_ARGS__)
81
Andreas Huberbe06d262009-08-14 14:37:10 -070082struct OMXCodecObserver : public BnOMXObserver {
83 OMXCodecObserver(const wp<OMXCodec> &target)
84 : mTarget(target) {
85 }
86
87 // from IOMXObserver
88 virtual void on_message(const omx_message &msg) {
89 sp<OMXCodec> codec = mTarget.promote();
90
91 if (codec.get() != NULL) {
92 codec->on_message(msg);
93 }
94 }
95
96protected:
97 virtual ~OMXCodecObserver() {}
98
99private:
100 wp<OMXCodec> mTarget;
101
102 OMXCodecObserver(const OMXCodecObserver &);
103 OMXCodecObserver &operator=(const OMXCodecObserver &);
104};
105
106static const char *GetCodec(const CodecInfo *info, size_t numInfos,
107 const char *mime, int index) {
108 CHECK(index >= 0);
109 for(size_t i = 0; i < numInfos; ++i) {
110 if (!strcasecmp(mime, info[i].mime)) {
111 if (index == 0) {
112 return info[i].codec;
113 }
114
115 --index;
116 }
117 }
118
119 return NULL;
120}
121
Andreas Huberebf66ea2009-08-19 13:32:58 -0700122enum {
123 kAVCProfileBaseline = 0x42,
124 kAVCProfileMain = 0x4d,
125 kAVCProfileExtended = 0x58,
126 kAVCProfileHigh = 0x64,
127 kAVCProfileHigh10 = 0x6e,
128 kAVCProfileHigh422 = 0x7a,
129 kAVCProfileHigh444 = 0xf4,
130 kAVCProfileCAVLC444Intra = 0x2c
131};
132
133static const char *AVCProfileToString(uint8_t profile) {
134 switch (profile) {
135 case kAVCProfileBaseline:
136 return "Baseline";
137 case kAVCProfileMain:
138 return "Main";
139 case kAVCProfileExtended:
140 return "Extended";
141 case kAVCProfileHigh:
142 return "High";
143 case kAVCProfileHigh10:
144 return "High 10";
145 case kAVCProfileHigh422:
146 return "High 422";
147 case kAVCProfileHigh444:
148 return "High 444";
149 case kAVCProfileCAVLC444Intra:
150 return "CAVLC 444 Intra";
151 default: return "Unknown";
152 }
153}
154
Andreas Huber4c483422009-09-02 16:05:36 -0700155template<class T>
156static void InitOMXParams(T *params) {
157 params->nSize = sizeof(T);
158 params->nVersion.s.nVersionMajor = 1;
159 params->nVersion.s.nVersionMinor = 0;
160 params->nVersion.s.nRevision = 0;
161 params->nVersion.s.nStep = 0;
162}
163
Andreas Huberbe06d262009-08-14 14:37:10 -0700164// static
165sp<OMXCodec> OMXCodec::Create(
166 const sp<IOMX> &omx,
167 const sp<MetaData> &meta, bool createEncoder,
168 const sp<MediaSource> &source) {
169 const char *mime;
170 bool success = meta->findCString(kKeyMIMEType, &mime);
171 CHECK(success);
172
173 const char *componentName = NULL;
174 IOMX::node_id node = 0;
175 for (int index = 0;; ++index) {
176 if (createEncoder) {
177 componentName = GetCodec(
178 kEncoderInfo, sizeof(kEncoderInfo) / sizeof(kEncoderInfo[0]),
179 mime, index);
180 } else {
181 componentName = GetCodec(
182 kDecoderInfo, sizeof(kDecoderInfo) / sizeof(kDecoderInfo[0]),
183 mime, index);
184 }
185
186 if (!componentName) {
187 return NULL;
188 }
189
190 LOGV("Attempting to allocate OMX node '%s'", componentName);
191
192 status_t err = omx->allocate_node(componentName, &node);
193 if (err == OK) {
Andreas Huber4c483422009-09-02 16:05:36 -0700194 LOGV("Successfully allocated OMX node '%s'", componentName);
Andreas Huberbe06d262009-08-14 14:37:10 -0700195 break;
196 }
197 }
198
199 uint32_t quirks = 0;
200 if (!strcmp(componentName, "OMX.PV.avcdec")) {
Andreas Huber4f5e6022009-08-19 09:29:34 -0700201 quirks |= kWantsNALFragments;
Andreas Huberbe06d262009-08-14 14:37:10 -0700202 }
203 if (!strcmp(componentName, "OMX.TI.MP3.decode")) {
204 quirks |= kNeedsFlushBeforeDisable;
205 }
206 if (!strcmp(componentName, "OMX.TI.AAC.decode")) {
207 quirks |= kNeedsFlushBeforeDisable;
Andreas Huber404cc412009-08-25 14:26:05 -0700208 quirks |= kRequiresFlushCompleteEmulation;
Andreas Huber127fcdc2009-08-26 16:27:02 -0700209
210 // The following is currently necessary for proper shutdown
211 // behaviour, but NOT enabled by default in order to make the
212 // bug reproducible...
213 // quirks |= kRequiresFlushBeforeShutdown;
Andreas Huberbe06d262009-08-14 14:37:10 -0700214 }
215 if (!strncmp(componentName, "OMX.qcom.video.encoder.", 23)) {
216 quirks |= kRequiresLoadedToIdleAfterAllocation;
217 quirks |= kRequiresAllocateBufferOnInputPorts;
218 }
219
220 sp<OMXCodec> codec = new OMXCodec(
221 omx, node, quirks, createEncoder, mime, componentName,
222 source);
223
224 uint32_t type;
225 const void *data;
226 size_t size;
227 if (meta->findData(kKeyESDS, &type, &data, &size)) {
228 ESDS esds((const char *)data, size);
229 CHECK_EQ(esds.InitCheck(), OK);
230
231 const void *codec_specific_data;
232 size_t codec_specific_data_size;
233 esds.getCodecSpecificInfo(
234 &codec_specific_data, &codec_specific_data_size);
235
236 printf("found codec-specific data of size %d\n",
237 codec_specific_data_size);
238
239 codec->addCodecSpecificData(
240 codec_specific_data, codec_specific_data_size);
241 } else if (meta->findData(kKeyAVCC, &type, &data, &size)) {
242 printf("found avcc of size %d\n", size);
243
Andreas Huberebf66ea2009-08-19 13:32:58 -0700244 // Parse the AVCDecoderConfigurationRecord
245
246 const uint8_t *ptr = (const uint8_t *)data;
247
248 CHECK(size >= 7);
249 CHECK_EQ(ptr[0], 1); // configurationVersion == 1
250 uint8_t profile = ptr[1];
251 uint8_t level = ptr[3];
252
253 CHECK((ptr[4] >> 2) == 0x3f); // reserved
254
255 size_t lengthSize = 1 + (ptr[4] & 3);
256
257 // commented out check below as H264_QVGA_500_NO_AUDIO.3gp
258 // violates it...
259 // CHECK((ptr[5] >> 5) == 7); // reserved
260
261 size_t numSeqParameterSets = ptr[5] & 31;
262
263 ptr += 6;
Andreas Huberbe06d262009-08-14 14:37:10 -0700264 size -= 6;
Andreas Huberebf66ea2009-08-19 13:32:58 -0700265
266 for (size_t i = 0; i < numSeqParameterSets; ++i) {
267 CHECK(size >= 2);
268 size_t length = U16_AT(ptr);
Andreas Huberbe06d262009-08-14 14:37:10 -0700269
270 ptr += 2;
271 size -= 2;
272
Andreas Huberbe06d262009-08-14 14:37:10 -0700273 CHECK(size >= length);
274
275 codec->addCodecSpecificData(ptr, length);
276
277 ptr += length;
278 size -= length;
Andreas Huberebf66ea2009-08-19 13:32:58 -0700279 }
Andreas Huberbe06d262009-08-14 14:37:10 -0700280
Andreas Huberebf66ea2009-08-19 13:32:58 -0700281 CHECK(size >= 1);
282 size_t numPictureParameterSets = *ptr;
283 ++ptr;
284 --size;
Andreas Huberbe06d262009-08-14 14:37:10 -0700285
Andreas Huberebf66ea2009-08-19 13:32:58 -0700286 for (size_t i = 0; i < numPictureParameterSets; ++i) {
287 CHECK(size >= 2);
288 size_t length = U16_AT(ptr);
289
290 ptr += 2;
291 size -= 2;
292
293 CHECK(size >= length);
294
295 codec->addCodecSpecificData(ptr, length);
296
297 ptr += length;
298 size -= length;
299 }
300
301 LOGI("AVC profile = %d (%s), level = %d",
302 (int)profile, AVCProfileToString(profile), (int)level / 10);
303
304 if (!strcmp(componentName, "OMX.TI.Video.Decoder")
305 && (profile != kAVCProfileBaseline || level > 39)) {
306 // This stream exceeds the decoder's capabilities.
307
308 LOGE("Profile and/or level exceed the decoder's capabilities.");
309 return NULL;
Andreas Huberbe06d262009-08-14 14:37:10 -0700310 }
311 }
312
313 if (!strcasecmp("audio/3gpp", mime)) {
314 codec->setAMRFormat();
315 }
Andreas Huberda050cf22009-09-02 14:01:43 -0700316 if (!strcasecmp("audio/mp4a-latm", mime)) {
Andreas Huber43ad6eaf2009-09-01 16:02:43 -0700317 int32_t numChannels, sampleRate;
318 CHECK(meta->findInt32(kKeyChannelCount, &numChannels));
319 CHECK(meta->findInt32(kKeySampleRate, &sampleRate));
320
321 codec->setAACFormat(numChannels, sampleRate);
Andreas Huberbe06d262009-08-14 14:37:10 -0700322 }
323 if (!strncasecmp(mime, "video/", 6)) {
324 int32_t width, height;
325 bool success = meta->findInt32(kKeyWidth, &width);
326 success = success && meta->findInt32(kKeyHeight, &height);
Andreas Huber5c0a9132009-08-20 11:16:40 -0700327 CHECK(success);
Andreas Huberbe06d262009-08-14 14:37:10 -0700328
329 if (createEncoder) {
330 codec->setVideoInputFormat(mime, width, height);
331 } else {
332 codec->setVideoOutputFormat(mime, width, height);
333 }
334 }
335 if (!strcasecmp(mime, "image/jpeg")
336 && !strcmp(componentName, "OMX.TI.JPEG.decode")) {
337 OMX_COLOR_FORMATTYPE format =
338 OMX_COLOR_Format32bitARGB8888;
339 // OMX_COLOR_FormatYUV420PackedPlanar;
340 // OMX_COLOR_FormatCbYCrY;
341 // OMX_COLOR_FormatYUV411Planar;
342
343 int32_t width, height;
344 bool success = meta->findInt32(kKeyWidth, &width);
345 success = success && meta->findInt32(kKeyHeight, &height);
Andreas Huber5c0a9132009-08-20 11:16:40 -0700346
347 int32_t compressedSize;
348 success = success && meta->findInt32(
Andreas Huberda050cf22009-09-02 14:01:43 -0700349 kKeyMaxInputSize, &compressedSize);
Andreas Huber5c0a9132009-08-20 11:16:40 -0700350
351 CHECK(success);
352 CHECK(compressedSize > 0);
Andreas Huberbe06d262009-08-14 14:37:10 -0700353
354 codec->setImageOutputFormat(format, width, height);
Andreas Huber5c0a9132009-08-20 11:16:40 -0700355 codec->setJPEGInputFormat(width, height, (OMX_U32)compressedSize);
Andreas Huberbe06d262009-08-14 14:37:10 -0700356 }
357
Andreas Huberda050cf22009-09-02 14:01:43 -0700358 int32_t maxInputSize;
359 if (createEncoder && meta->findInt32(kKeyMaxInputSize, &maxInputSize)) {
360 codec->setMinBufferSize(kPortIndexInput, (OMX_U32)maxInputSize);
361 }
362
363 if (!strcmp(componentName, "OMX.TI.AMR.encode")
364 || !strcmp(componentName, "OMX.TI.WBAMR.encode")) {
365 codec->setMinBufferSize(kPortIndexOutput, 8192); // XXX
366 }
367
Andreas Huberbe06d262009-08-14 14:37:10 -0700368 codec->initOutputFormat(meta);
369
370 return codec;
371}
372
Andreas Huberda050cf22009-09-02 14:01:43 -0700373void OMXCodec::setMinBufferSize(OMX_U32 portIndex, OMX_U32 size) {
374 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -0700375 InitOMXParams(&def);
Andreas Huberda050cf22009-09-02 14:01:43 -0700376 def.nPortIndex = portIndex;
377
378 status_t err = mOMX->get_parameter(
379 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
380 CHECK_EQ(err, OK);
381
382 if (def.nBufferSize < size) {
383 def.nBufferSize = size;
384
385 }
386
387 err = mOMX->set_parameter(
388 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
389 CHECK_EQ(err, OK);
390}
391
Andreas Huberbe06d262009-08-14 14:37:10 -0700392status_t OMXCodec::setVideoPortFormatType(
393 OMX_U32 portIndex,
394 OMX_VIDEO_CODINGTYPE compressionFormat,
395 OMX_COLOR_FORMATTYPE colorFormat) {
396 OMX_VIDEO_PARAM_PORTFORMATTYPE format;
Andreas Huber4c483422009-09-02 16:05:36 -0700397 InitOMXParams(&format);
Andreas Huberbe06d262009-08-14 14:37:10 -0700398 format.nPortIndex = portIndex;
399 format.nIndex = 0;
400 bool found = false;
401
402 OMX_U32 index = 0;
403 for (;;) {
404 format.nIndex = index;
405 status_t err = mOMX->get_parameter(
406 mNode, OMX_IndexParamVideoPortFormat,
407 &format, sizeof(format));
408
409 if (err != OK) {
410 return err;
411 }
412
413 // The following assertion is violated by TI's video decoder.
Andreas Huber5c0a9132009-08-20 11:16:40 -0700414 // CHECK_EQ(format.nIndex, index);
Andreas Huberbe06d262009-08-14 14:37:10 -0700415
416#if 1
417 LOGI("portIndex: %ld, index: %ld, eCompressionFormat=%d eColorFormat=%d",
418 portIndex,
419 index, format.eCompressionFormat, format.eColorFormat);
420#endif
421
422 if (!strcmp("OMX.TI.Video.encoder", mComponentName)) {
423 if (portIndex == kPortIndexInput
424 && colorFormat == format.eColorFormat) {
425 // eCompressionFormat does not seem right.
426 found = true;
427 break;
428 }
429 if (portIndex == kPortIndexOutput
430 && compressionFormat == format.eCompressionFormat) {
431 // eColorFormat does not seem right.
432 found = true;
433 break;
434 }
435 }
436
437 if (format.eCompressionFormat == compressionFormat
438 && format.eColorFormat == colorFormat) {
439 found = true;
440 break;
441 }
442
443 ++index;
444 }
445
446 if (!found) {
447 return UNKNOWN_ERROR;
448 }
449
450 LOGI("found a match.");
451 status_t err = mOMX->set_parameter(
452 mNode, OMX_IndexParamVideoPortFormat,
453 &format, sizeof(format));
454
455 return err;
456}
457
458void OMXCodec::setVideoInputFormat(
459 const char *mime, OMX_U32 width, OMX_U32 height) {
460 LOGI("setVideoInputFormat width=%ld, height=%ld", width, height);
461
462 OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused;
463 if (!strcasecmp("video/avc", mime)) {
464 compressionFormat = OMX_VIDEO_CodingAVC;
465 } else if (!strcasecmp("video/mp4v-es", mime)) {
466 compressionFormat = OMX_VIDEO_CodingMPEG4;
467 } else if (!strcasecmp("video/3gpp", mime)) {
468 compressionFormat = OMX_VIDEO_CodingH263;
469 } else {
470 LOGE("Not a supported video mime type: %s", mime);
471 CHECK(!"Should not be here. Not a supported video mime type.");
472 }
473
474 OMX_COLOR_FORMATTYPE colorFormat =
475 0 ? OMX_COLOR_FormatYCbYCr : OMX_COLOR_FormatCbYCrY;
476
477 if (!strncmp("OMX.qcom.video.encoder.", mComponentName, 23)) {
478 colorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
479 }
480
481 setVideoPortFormatType(
482 kPortIndexInput, OMX_VIDEO_CodingUnused,
483 colorFormat);
484
485 setVideoPortFormatType(
486 kPortIndexOutput, compressionFormat, OMX_COLOR_FormatUnused);
487
488 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -0700489 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -0700490 def.nPortIndex = kPortIndexOutput;
491
Andreas Huber4c483422009-09-02 16:05:36 -0700492 OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
493
Andreas Huberbe06d262009-08-14 14:37:10 -0700494 status_t err = mOMX->get_parameter(
495 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
496
497 CHECK_EQ(err, OK);
498 CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
499
500 video_def->nFrameWidth = width;
501 video_def->nFrameHeight = height;
502
503 video_def->eCompressionFormat = compressionFormat;
504 video_def->eColorFormat = OMX_COLOR_FormatUnused;
505
506 err = mOMX->set_parameter(
507 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
508 CHECK_EQ(err, OK);
509
510 ////////////////////////////////////////////////////////////////////////////
511
Andreas Huber4c483422009-09-02 16:05:36 -0700512 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -0700513 def.nPortIndex = kPortIndexInput;
514
515 err = mOMX->get_parameter(
516 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
517 CHECK_EQ(err, OK);
518
519 def.nBufferSize = (width * height * 2); // (width * height * 3) / 2;
Andreas Huber4c483422009-09-02 16:05:36 -0700520 LOGI("Setting nBufferSize = %ld", def.nBufferSize);
Andreas Huberbe06d262009-08-14 14:37:10 -0700521
522 CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
523
524 video_def->nFrameWidth = width;
525 video_def->nFrameHeight = height;
526 video_def->eCompressionFormat = OMX_VIDEO_CodingUnused;
527 video_def->eColorFormat = colorFormat;
528
529 err = mOMX->set_parameter(
530 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
531 CHECK_EQ(err, OK);
532}
533
534void OMXCodec::setVideoOutputFormat(
535 const char *mime, OMX_U32 width, OMX_U32 height) {
536 LOGI("setVideoOutputFormat width=%ld, height=%ld", width, height);
537
Andreas Huberbe06d262009-08-14 14:37:10 -0700538 OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused;
539 if (!strcasecmp("video/avc", mime)) {
540 compressionFormat = OMX_VIDEO_CodingAVC;
541 } else if (!strcasecmp("video/mp4v-es", mime)) {
542 compressionFormat = OMX_VIDEO_CodingMPEG4;
543 } else if (!strcasecmp("video/3gpp", mime)) {
544 compressionFormat = OMX_VIDEO_CodingH263;
545 } else {
546 LOGE("Not a supported video mime type: %s", mime);
547 CHECK(!"Should not be here. Not a supported video mime type.");
548 }
549
550 setVideoPortFormatType(
551 kPortIndexInput, compressionFormat, OMX_COLOR_FormatUnused);
552
553#if 1
554 {
555 OMX_VIDEO_PARAM_PORTFORMATTYPE format;
Andreas Huber4c483422009-09-02 16:05:36 -0700556 InitOMXParams(&format);
Andreas Huberbe06d262009-08-14 14:37:10 -0700557 format.nPortIndex = kPortIndexOutput;
558 format.nIndex = 0;
559
560 status_t err = mOMX->get_parameter(
561 mNode, OMX_IndexParamVideoPortFormat,
562 &format, sizeof(format));
563 CHECK_EQ(err, OK);
564 CHECK_EQ(format.eCompressionFormat, OMX_VIDEO_CodingUnused);
565
566 static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
567
568 CHECK(format.eColorFormat == OMX_COLOR_FormatYUV420Planar
569 || format.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar
570 || format.eColorFormat == OMX_COLOR_FormatCbYCrY
571 || format.eColorFormat == OMX_QCOM_COLOR_FormatYVU420SemiPlanar);
572
573 err = mOMX->set_parameter(
574 mNode, OMX_IndexParamVideoPortFormat,
575 &format, sizeof(format));
576 CHECK_EQ(err, OK);
577 }
578#endif
579
580 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -0700581 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -0700582 def.nPortIndex = kPortIndexInput;
583
Andreas Huber4c483422009-09-02 16:05:36 -0700584 OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
585
Andreas Huberbe06d262009-08-14 14:37:10 -0700586 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
Andreas Huber4c483422009-09-02 16:05:36 -0700612 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -0700613 def.nPortIndex = kPortIndexOutput;
614
615 err = mOMX->get_parameter(
616 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
617 CHECK_EQ(err, OK);
618 CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
619
620#if 0
621 def.nBufferSize =
622 (((width + 15) & -16) * ((height + 15) & -16) * 3) / 2; // YUV420
623#endif
624
625 video_def->nFrameWidth = width;
626 video_def->nFrameHeight = height;
627
628 err = mOMX->set_parameter(
629 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
630 CHECK_EQ(err, OK);
631}
632
633
634OMXCodec::OMXCodec(
635 const sp<IOMX> &omx, IOMX::node_id node, uint32_t quirks,
Andreas Huberebf66ea2009-08-19 13:32:58 -0700636 bool isEncoder,
Andreas Huberbe06d262009-08-14 14:37:10 -0700637 const char *mime,
638 const char *componentName,
639 const sp<MediaSource> &source)
640 : mOMX(omx),
641 mNode(node),
642 mQuirks(quirks),
643 mIsEncoder(isEncoder),
644 mMIME(strdup(mime)),
645 mComponentName(strdup(componentName)),
646 mSource(source),
647 mCodecSpecificDataIndex(0),
Andreas Huberbe06d262009-08-14 14:37:10 -0700648 mState(LOADED),
Andreas Huber42978e52009-08-27 10:08:39 -0700649 mInitialBufferSubmit(true),
Andreas Huberbe06d262009-08-14 14:37:10 -0700650 mSignalledEOS(false),
651 mNoMoreOutputData(false),
652 mSeekTimeUs(-1) {
653 mPortStatus[kPortIndexInput] = ENABLED;
654 mPortStatus[kPortIndexOutput] = ENABLED;
655
656 mObserver = new OMXCodecObserver(this);
657 mOMX->observe_node(mNode, mObserver);
Andreas Huber4c483422009-09-02 16:05:36 -0700658
659 setComponentRole();
660}
661
662void OMXCodec::setComponentRole() {
663 struct MimeToRole {
664 const char *mime;
665 const char *decoderRole;
666 const char *encoderRole;
667 };
668
669 static const MimeToRole kMimeToRole[] = {
670 { "audio/mpeg", "audio_decoder.mp3", "audio_encoder.mp3" },
671 { "audio/3gpp", "audio_decoder.amrnb", "audio_encoder.amrnb" },
672 { "audio/mp4a-latm", "audio_decoder.aac", "audio_encoder.aac" },
673 { "video/avc", "video_decoder.avc", "video_encoder.avc" },
674 { "video/mp4v-es", "video_decoder.mpeg4", "video_encoder.mpeg4" },
675 { "video/3gpp", "video_decoder.h263", "video_encoder.h263" },
676 };
677
678 static const size_t kNumMimeToRole =
679 sizeof(kMimeToRole) / sizeof(kMimeToRole[0]);
680
681 size_t i;
682 for (i = 0; i < kNumMimeToRole; ++i) {
683 if (!strcasecmp(mMIME, kMimeToRole[i].mime)) {
684 break;
685 }
686 }
687
688 if (i == kNumMimeToRole) {
689 return;
690 }
691
692 const char *role =
693 mIsEncoder ? kMimeToRole[i].encoderRole
694 : kMimeToRole[i].decoderRole;
695
696 if (role != NULL) {
697 CODEC_LOGV("Setting component role '%s'.", role);
698
699 OMX_PARAM_COMPONENTROLETYPE roleParams;
700 InitOMXParams(&roleParams);
701
702 strncpy((char *)roleParams.cRole,
703 role, OMX_MAX_STRINGNAME_SIZE - 1);
704
705 roleParams.cRole[OMX_MAX_STRINGNAME_SIZE - 1] = '\0';
706
707 status_t err = mOMX->set_parameter(
708 mNode, OMX_IndexParamStandardComponentRole,
709 &roleParams, sizeof(roleParams));
710
711 if (err != OK) {
712 LOGW("Failed to set standard component role '%s'.", role);
713 }
714 }
Andreas Huberbe06d262009-08-14 14:37:10 -0700715}
716
717OMXCodec::~OMXCodec() {
Andreas Huber4f5e6022009-08-19 09:29:34 -0700718 CHECK(mState == LOADED || mState == ERROR);
Andreas Huberbe06d262009-08-14 14:37:10 -0700719
720 status_t err = mOMX->observe_node(mNode, NULL);
721 CHECK_EQ(err, OK);
722
723 err = mOMX->free_node(mNode);
724 CHECK_EQ(err, OK);
725
726 mNode = NULL;
727 setState(DEAD);
728
729 clearCodecSpecificData();
730
731 free(mComponentName);
732 mComponentName = NULL;
Andreas Huberebf66ea2009-08-19 13:32:58 -0700733
Andreas Huberbe06d262009-08-14 14:37:10 -0700734 free(mMIME);
735 mMIME = NULL;
736}
737
738status_t OMXCodec::init() {
Andreas Huber42978e52009-08-27 10:08:39 -0700739 // mLock is held.
Andreas Huberbe06d262009-08-14 14:37:10 -0700740
741 CHECK_EQ(mState, LOADED);
742
743 status_t err;
744 if (!(mQuirks & kRequiresLoadedToIdleAfterAllocation)) {
745 err = mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
746 CHECK_EQ(err, OK);
Andreas Huberbe06d262009-08-14 14:37:10 -0700747 setState(LOADED_TO_IDLE);
748 }
749
750 err = allocateBuffers();
751 CHECK_EQ(err, OK);
752
753 if (mQuirks & kRequiresLoadedToIdleAfterAllocation) {
754 err = mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
755 CHECK_EQ(err, OK);
756
757 setState(LOADED_TO_IDLE);
758 }
759
760 while (mState != EXECUTING && mState != ERROR) {
761 mAsyncCompletion.wait(mLock);
762 }
763
764 return mState == ERROR ? UNKNOWN_ERROR : OK;
765}
766
767// static
768bool OMXCodec::isIntermediateState(State state) {
769 return state == LOADED_TO_IDLE
770 || state == IDLE_TO_EXECUTING
771 || state == EXECUTING_TO_IDLE
772 || state == IDLE_TO_LOADED
773 || state == RECONFIGURING;
774}
775
776status_t OMXCodec::allocateBuffers() {
777 status_t err = allocateBuffersOnPort(kPortIndexInput);
778
779 if (err != OK) {
780 return err;
781 }
782
783 return allocateBuffersOnPort(kPortIndexOutput);
784}
785
786status_t OMXCodec::allocateBuffersOnPort(OMX_U32 portIndex) {
787 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -0700788 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -0700789 def.nPortIndex = portIndex;
790
791 status_t err = mOMX->get_parameter(
792 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
793
794 if (err != OK) {
795 return err;
796 }
797
Andreas Huber5c0a9132009-08-20 11:16:40 -0700798 size_t totalSize = def.nBufferCountActual * def.nBufferSize;
799 mDealer[portIndex] = new MemoryDealer(totalSize);
800
Andreas Huberbe06d262009-08-14 14:37:10 -0700801 for (OMX_U32 i = 0; i < def.nBufferCountActual; ++i) {
Andreas Huber5c0a9132009-08-20 11:16:40 -0700802 sp<IMemory> mem = mDealer[portIndex]->allocate(def.nBufferSize);
Andreas Huberbe06d262009-08-14 14:37:10 -0700803 CHECK(mem.get() != NULL);
804
805 IOMX::buffer_id buffer;
806 if (portIndex == kPortIndexInput
807 && (mQuirks & kRequiresAllocateBufferOnInputPorts)) {
808 err = mOMX->allocate_buffer_with_backup(
809 mNode, portIndex, mem, &buffer);
Andreas Huber446f44f2009-08-25 17:23:44 -0700810 } else if (portIndex == kPortIndexOutput
811 && (mQuirks & kRequiresAllocateBufferOnOutputPorts)) {
812 err = mOMX->allocate_buffer(
813 mNode, portIndex, def.nBufferSize, &buffer);
Andreas Huberbe06d262009-08-14 14:37:10 -0700814 } else {
815 err = mOMX->use_buffer(mNode, portIndex, mem, &buffer);
816 }
817
818 if (err != OK) {
819 LOGE("allocate_buffer_with_backup failed");
820 return err;
821 }
822
823 BufferInfo info;
824 info.mBuffer = buffer;
825 info.mOwnedByComponent = false;
826 info.mMem = mem;
827 info.mMediaBuffer = NULL;
828
829 if (portIndex == kPortIndexOutput) {
830 info.mMediaBuffer = new MediaBuffer(mem->pointer(), mem->size());
831 info.mMediaBuffer->setObserver(this);
832 }
833
834 mPortBuffers[portIndex].push(info);
835
Andreas Huber4c483422009-09-02 16:05:36 -0700836 CODEC_LOGV("allocated buffer %p on %s port", buffer,
Andreas Huberbe06d262009-08-14 14:37:10 -0700837 portIndex == kPortIndexInput ? "input" : "output");
838 }
839
840 dumpPortStatus(portIndex);
841
842 return OK;
843}
844
845void OMXCodec::on_message(const omx_message &msg) {
846 Mutex::Autolock autoLock(mLock);
847
848 switch (msg.type) {
849 case omx_message::EVENT:
850 {
851 onEvent(
852 msg.u.event_data.event, msg.u.event_data.data1,
853 msg.u.event_data.data2);
854
855 break;
856 }
857
858 case omx_message::EMPTY_BUFFER_DONE:
859 {
860 IOMX::buffer_id buffer = msg.u.extended_buffer_data.buffer;
861
Andreas Huber4c483422009-09-02 16:05:36 -0700862 CODEC_LOGV("EMPTY_BUFFER_DONE(buffer: %p)", buffer);
Andreas Huberbe06d262009-08-14 14:37:10 -0700863
864 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
865 size_t i = 0;
866 while (i < buffers->size() && (*buffers)[i].mBuffer != buffer) {
867 ++i;
868 }
869
870 CHECK(i < buffers->size());
871 if (!(*buffers)[i].mOwnedByComponent) {
872 LOGW("We already own input buffer %p, yet received "
873 "an EMPTY_BUFFER_DONE.", buffer);
874 }
875
876 buffers->editItemAt(i).mOwnedByComponent = false;
877
878 if (mPortStatus[kPortIndexInput] == DISABLING) {
Andreas Huber4c483422009-09-02 16:05:36 -0700879 CODEC_LOGV("Port is disabled, freeing buffer %p", buffer);
Andreas Huberbe06d262009-08-14 14:37:10 -0700880
881 status_t err =
882 mOMX->free_buffer(mNode, kPortIndexInput, buffer);
883 CHECK_EQ(err, OK);
884
885 buffers->removeAt(i);
886 } else if (mPortStatus[kPortIndexInput] != SHUTTING_DOWN) {
887 CHECK_EQ(mPortStatus[kPortIndexInput], ENABLED);
888 drainInputBuffer(&buffers->editItemAt(i));
889 }
890
891 break;
892 }
893
894 case omx_message::FILL_BUFFER_DONE:
895 {
896 IOMX::buffer_id buffer = msg.u.extended_buffer_data.buffer;
897 OMX_U32 flags = msg.u.extended_buffer_data.flags;
898
Andreas Huber4c483422009-09-02 16:05:36 -0700899 CODEC_LOGV("FILL_BUFFER_DONE(buffer: %p, size: %ld, flags: 0x%08lx)",
Andreas Huberbe06d262009-08-14 14:37:10 -0700900 buffer,
901 msg.u.extended_buffer_data.range_length,
902 flags);
903
Andreas Huber4c483422009-09-02 16:05:36 -0700904 CODEC_LOGV("FILL_BUFFER_DONE(timestamp: %lld us (%.2f secs))",
Andreas Huberbe06d262009-08-14 14:37:10 -0700905 msg.u.extended_buffer_data.timestamp,
906 msg.u.extended_buffer_data.timestamp / 1E6);
907
908 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
909 size_t i = 0;
910 while (i < buffers->size() && (*buffers)[i].mBuffer != buffer) {
911 ++i;
912 }
913
914 CHECK(i < buffers->size());
915 BufferInfo *info = &buffers->editItemAt(i);
916
917 if (!info->mOwnedByComponent) {
918 LOGW("We already own output buffer %p, yet received "
919 "a FILL_BUFFER_DONE.", buffer);
920 }
921
922 info->mOwnedByComponent = false;
923
924 if (mPortStatus[kPortIndexOutput] == DISABLING) {
Andreas Huber4c483422009-09-02 16:05:36 -0700925 CODEC_LOGV("Port is disabled, freeing buffer %p", buffer);
Andreas Huberbe06d262009-08-14 14:37:10 -0700926
927 status_t err =
928 mOMX->free_buffer(mNode, kPortIndexOutput, buffer);
929 CHECK_EQ(err, OK);
930
931 buffers->removeAt(i);
Andreas Huberd7795892009-08-26 10:33:47 -0700932 } else if (mPortStatus[kPortIndexOutput] == ENABLED
933 && (flags & OMX_BUFFERFLAG_EOS)) {
Andreas Huber4c483422009-09-02 16:05:36 -0700934 CODEC_LOGV("No more output data.");
Andreas Huberbe06d262009-08-14 14:37:10 -0700935 mNoMoreOutputData = true;
936 mBufferFilled.signal();
937 } else if (mPortStatus[kPortIndexOutput] != SHUTTING_DOWN) {
938 CHECK_EQ(mPortStatus[kPortIndexOutput], ENABLED);
Andreas Huberebf66ea2009-08-19 13:32:58 -0700939
Andreas Huberbe06d262009-08-14 14:37:10 -0700940 MediaBuffer *buffer = info->mMediaBuffer;
941
942 buffer->set_range(
943 msg.u.extended_buffer_data.range_offset,
944 msg.u.extended_buffer_data.range_length);
945
946 buffer->meta_data()->clear();
947
948 buffer->meta_data()->setInt32(
949 kKeyTimeUnits,
950 (msg.u.extended_buffer_data.timestamp + 500) / 1000);
951
952 buffer->meta_data()->setInt32(
953 kKeyTimeScale, 1000);
954
955 if (msg.u.extended_buffer_data.flags & OMX_BUFFERFLAG_SYNCFRAME) {
956 buffer->meta_data()->setInt32(kKeyIsSyncFrame, true);
957 }
958
959 buffer->meta_data()->setPointer(
960 kKeyPlatformPrivate,
961 msg.u.extended_buffer_data.platform_private);
962
963 buffer->meta_data()->setPointer(
964 kKeyBufferID,
965 msg.u.extended_buffer_data.buffer);
966
967 mFilledBuffers.push_back(i);
968 mBufferFilled.signal();
969 }
970
971 break;
972 }
973
974 default:
975 {
976 CHECK(!"should not be here.");
977 break;
978 }
979 }
980}
981
982void OMXCodec::onEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) {
983 switch (event) {
984 case OMX_EventCmdComplete:
985 {
986 onCmdComplete((OMX_COMMANDTYPE)data1, data2);
987 break;
988 }
989
990 case OMX_EventError:
991 {
992 LOGE("ERROR(%ld, %ld)", data1, data2);
993
994 setState(ERROR);
995 break;
996 }
997
998 case OMX_EventPortSettingsChanged:
999 {
1000 onPortSettingsChanged(data1);
1001 break;
1002 }
1003
1004 case OMX_EventBufferFlag:
1005 {
Andreas Huber4c483422009-09-02 16:05:36 -07001006 CODEC_LOGV("EVENT_BUFFER_FLAG(%ld)", data1);
Andreas Huberbe06d262009-08-14 14:37:10 -07001007
1008 if (data1 == kPortIndexOutput) {
1009 mNoMoreOutputData = true;
1010 }
1011 break;
1012 }
1013
1014 default:
1015 {
Andreas Huber4c483422009-09-02 16:05:36 -07001016 CODEC_LOGV("EVENT(%d, %ld, %ld)", event, data1, data2);
Andreas Huberbe06d262009-08-14 14:37:10 -07001017 break;
1018 }
1019 }
1020}
1021
1022void OMXCodec::onCmdComplete(OMX_COMMANDTYPE cmd, OMX_U32 data) {
1023 switch (cmd) {
1024 case OMX_CommandStateSet:
1025 {
1026 onStateChange((OMX_STATETYPE)data);
1027 break;
1028 }
1029
1030 case OMX_CommandPortDisable:
1031 {
1032 OMX_U32 portIndex = data;
Andreas Huber4c483422009-09-02 16:05:36 -07001033 CODEC_LOGV("PORT_DISABLED(%ld)", portIndex);
Andreas Huberbe06d262009-08-14 14:37:10 -07001034
1035 CHECK(mState == EXECUTING || mState == RECONFIGURING);
1036 CHECK_EQ(mPortStatus[portIndex], DISABLING);
1037 CHECK_EQ(mPortBuffers[portIndex].size(), 0);
1038
1039 mPortStatus[portIndex] = DISABLED;
1040
1041 if (mState == RECONFIGURING) {
1042 CHECK_EQ(portIndex, kPortIndexOutput);
1043
1044 enablePortAsync(portIndex);
1045
1046 status_t err = allocateBuffersOnPort(portIndex);
1047 CHECK_EQ(err, OK);
1048 }
1049 break;
1050 }
1051
1052 case OMX_CommandPortEnable:
1053 {
1054 OMX_U32 portIndex = data;
Andreas Huber4c483422009-09-02 16:05:36 -07001055 CODEC_LOGV("PORT_ENABLED(%ld)", portIndex);
Andreas Huberbe06d262009-08-14 14:37:10 -07001056
1057 CHECK(mState == EXECUTING || mState == RECONFIGURING);
1058 CHECK_EQ(mPortStatus[portIndex], ENABLING);
1059
1060 mPortStatus[portIndex] = ENABLED;
1061
1062 if (mState == RECONFIGURING) {
1063 CHECK_EQ(portIndex, kPortIndexOutput);
1064
1065 setState(EXECUTING);
1066
1067 fillOutputBuffers();
1068 }
1069 break;
1070 }
1071
1072 case OMX_CommandFlush:
1073 {
1074 OMX_U32 portIndex = data;
1075
Andreas Huber4c483422009-09-02 16:05:36 -07001076 CODEC_LOGV("FLUSH_DONE(%ld)", portIndex);
Andreas Huberbe06d262009-08-14 14:37:10 -07001077
1078 CHECK_EQ(mPortStatus[portIndex], SHUTTING_DOWN);
1079 mPortStatus[portIndex] = ENABLED;
1080
1081 CHECK_EQ(countBuffersWeOwn(mPortBuffers[portIndex]),
1082 mPortBuffers[portIndex].size());
1083
1084 if (mState == RECONFIGURING) {
1085 CHECK_EQ(portIndex, kPortIndexOutput);
1086
1087 disablePortAsync(portIndex);
Andreas Huber127fcdc2009-08-26 16:27:02 -07001088 } else if (mState == EXECUTING_TO_IDLE) {
1089 if (mPortStatus[kPortIndexInput] == ENABLED
1090 && mPortStatus[kPortIndexOutput] == ENABLED) {
Andreas Huber4c483422009-09-02 16:05:36 -07001091 CODEC_LOGV("Finished flushing both ports, now completing "
Andreas Huber127fcdc2009-08-26 16:27:02 -07001092 "transition from EXECUTING to IDLE.");
1093
1094 mPortStatus[kPortIndexInput] = SHUTTING_DOWN;
1095 mPortStatus[kPortIndexOutput] = SHUTTING_DOWN;
1096
1097 status_t err =
1098 mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
1099 CHECK_EQ(err, OK);
1100 }
Andreas Huberbe06d262009-08-14 14:37:10 -07001101 } else {
1102 // We're flushing both ports in preparation for seeking.
1103
1104 if (mPortStatus[kPortIndexInput] == ENABLED
1105 && mPortStatus[kPortIndexOutput] == ENABLED) {
Andreas Huber4c483422009-09-02 16:05:36 -07001106 CODEC_LOGV("Finished flushing both ports, now continuing from"
Andreas Huberbe06d262009-08-14 14:37:10 -07001107 " seek-time.");
1108
1109 drainInputBuffers();
1110 fillOutputBuffers();
1111 }
1112 }
1113
1114 break;
1115 }
1116
1117 default:
1118 {
Andreas Huber4c483422009-09-02 16:05:36 -07001119 CODEC_LOGV("CMD_COMPLETE(%d, %ld)", cmd, data);
Andreas Huberbe06d262009-08-14 14:37:10 -07001120 break;
1121 }
1122 }
1123}
1124
1125void OMXCodec::onStateChange(OMX_STATETYPE newState) {
1126 switch (newState) {
1127 case OMX_StateIdle:
1128 {
Andreas Huber4c483422009-09-02 16:05:36 -07001129 CODEC_LOGV("Now Idle.");
Andreas Huberbe06d262009-08-14 14:37:10 -07001130 if (mState == LOADED_TO_IDLE) {
1131 status_t err = mOMX->send_command(
1132 mNode, OMX_CommandStateSet, OMX_StateExecuting);
1133
1134 CHECK_EQ(err, OK);
1135
1136 setState(IDLE_TO_EXECUTING);
1137 } else {
1138 CHECK_EQ(mState, EXECUTING_TO_IDLE);
1139
1140 CHECK_EQ(
1141 countBuffersWeOwn(mPortBuffers[kPortIndexInput]),
1142 mPortBuffers[kPortIndexInput].size());
1143
1144 CHECK_EQ(
1145 countBuffersWeOwn(mPortBuffers[kPortIndexOutput]),
1146 mPortBuffers[kPortIndexOutput].size());
1147
1148 status_t err = mOMX->send_command(
1149 mNode, OMX_CommandStateSet, OMX_StateLoaded);
1150
1151 CHECK_EQ(err, OK);
1152
1153 err = freeBuffersOnPort(kPortIndexInput);
1154 CHECK_EQ(err, OK);
1155
1156 err = freeBuffersOnPort(kPortIndexOutput);
1157 CHECK_EQ(err, OK);
1158
1159 mPortStatus[kPortIndexInput] = ENABLED;
1160 mPortStatus[kPortIndexOutput] = ENABLED;
1161
1162 setState(IDLE_TO_LOADED);
1163 }
1164 break;
1165 }
1166
1167 case OMX_StateExecuting:
1168 {
1169 CHECK_EQ(mState, IDLE_TO_EXECUTING);
1170
Andreas Huber4c483422009-09-02 16:05:36 -07001171 CODEC_LOGV("Now Executing.");
Andreas Huberbe06d262009-08-14 14:37:10 -07001172
1173 setState(EXECUTING);
1174
Andreas Huber42978e52009-08-27 10:08:39 -07001175 // Buffers will be submitted to the component in the first
1176 // call to OMXCodec::read as mInitialBufferSubmit is true at
1177 // this point. This ensures that this on_message call returns,
1178 // releases the lock and ::init can notice the state change and
1179 // itself return.
Andreas Huberbe06d262009-08-14 14:37:10 -07001180 break;
1181 }
1182
1183 case OMX_StateLoaded:
1184 {
1185 CHECK_EQ(mState, IDLE_TO_LOADED);
1186
Andreas Huber4c483422009-09-02 16:05:36 -07001187 CODEC_LOGV("Now Loaded.");
Andreas Huberbe06d262009-08-14 14:37:10 -07001188
1189 setState(LOADED);
1190 break;
1191 }
1192
1193 default:
1194 {
1195 CHECK(!"should not be here.");
1196 break;
1197 }
1198 }
1199}
1200
1201// static
1202size_t OMXCodec::countBuffersWeOwn(const Vector<BufferInfo> &buffers) {
1203 size_t n = 0;
1204 for (size_t i = 0; i < buffers.size(); ++i) {
1205 if (!buffers[i].mOwnedByComponent) {
1206 ++n;
1207 }
1208 }
1209
1210 return n;
1211}
1212
1213status_t OMXCodec::freeBuffersOnPort(
1214 OMX_U32 portIndex, bool onlyThoseWeOwn) {
1215 Vector<BufferInfo> *buffers = &mPortBuffers[portIndex];
1216
1217 status_t stickyErr = OK;
1218
1219 for (size_t i = buffers->size(); i-- > 0;) {
1220 BufferInfo *info = &buffers->editItemAt(i);
1221
1222 if (onlyThoseWeOwn && info->mOwnedByComponent) {
1223 continue;
1224 }
1225
1226 CHECK_EQ(info->mOwnedByComponent, false);
1227
1228 status_t err =
1229 mOMX->free_buffer(mNode, portIndex, info->mBuffer);
1230
1231 if (err != OK) {
1232 stickyErr = err;
1233 }
1234
1235 if (info->mMediaBuffer != NULL) {
1236 info->mMediaBuffer->setObserver(NULL);
1237
1238 // Make sure nobody but us owns this buffer at this point.
1239 CHECK_EQ(info->mMediaBuffer->refcount(), 0);
1240
1241 info->mMediaBuffer->release();
1242 }
1243
1244 buffers->removeAt(i);
1245 }
1246
1247 CHECK(onlyThoseWeOwn || buffers->isEmpty());
1248
1249 return stickyErr;
1250}
1251
1252void OMXCodec::onPortSettingsChanged(OMX_U32 portIndex) {
Andreas Huber4c483422009-09-02 16:05:36 -07001253 CODEC_LOGV("PORT_SETTINGS_CHANGED(%ld)", portIndex);
Andreas Huberbe06d262009-08-14 14:37:10 -07001254
1255 CHECK_EQ(mState, EXECUTING);
1256 CHECK_EQ(portIndex, kPortIndexOutput);
1257 setState(RECONFIGURING);
1258
1259 if (mQuirks & kNeedsFlushBeforeDisable) {
Andreas Huber404cc412009-08-25 14:26:05 -07001260 if (!flushPortAsync(portIndex)) {
1261 onCmdComplete(OMX_CommandFlush, portIndex);
1262 }
Andreas Huberbe06d262009-08-14 14:37:10 -07001263 } else {
1264 disablePortAsync(portIndex);
1265 }
1266}
1267
Andreas Huber404cc412009-08-25 14:26:05 -07001268bool OMXCodec::flushPortAsync(OMX_U32 portIndex) {
Andreas Huber127fcdc2009-08-26 16:27:02 -07001269 CHECK(mState == EXECUTING || mState == RECONFIGURING
1270 || mState == EXECUTING_TO_IDLE);
Andreas Huberbe06d262009-08-14 14:37:10 -07001271
Andreas Huber4c483422009-09-02 16:05:36 -07001272 CODEC_LOGV("flushPortAsync(%ld): we own %d out of %d buffers already.",
Andreas Huber404cc412009-08-25 14:26:05 -07001273 portIndex, countBuffersWeOwn(mPortBuffers[portIndex]),
1274 mPortBuffers[portIndex].size());
1275
Andreas Huberbe06d262009-08-14 14:37:10 -07001276 CHECK_EQ(mPortStatus[portIndex], ENABLED);
1277 mPortStatus[portIndex] = SHUTTING_DOWN;
1278
Andreas Huber404cc412009-08-25 14:26:05 -07001279 if ((mQuirks & kRequiresFlushCompleteEmulation)
1280 && countBuffersWeOwn(mPortBuffers[portIndex])
1281 == mPortBuffers[portIndex].size()) {
1282 // No flush is necessary and this component fails to send a
1283 // flush-complete event in this case.
1284
1285 return false;
1286 }
1287
Andreas Huberbe06d262009-08-14 14:37:10 -07001288 status_t err =
1289 mOMX->send_command(mNode, OMX_CommandFlush, portIndex);
1290 CHECK_EQ(err, OK);
Andreas Huber404cc412009-08-25 14:26:05 -07001291
1292 return true;
Andreas Huberbe06d262009-08-14 14:37:10 -07001293}
1294
1295void OMXCodec::disablePortAsync(OMX_U32 portIndex) {
1296 CHECK(mState == EXECUTING || mState == RECONFIGURING);
1297
1298 CHECK_EQ(mPortStatus[portIndex], ENABLED);
1299 mPortStatus[portIndex] = DISABLING;
1300
1301 status_t err =
1302 mOMX->send_command(mNode, OMX_CommandPortDisable, portIndex);
1303 CHECK_EQ(err, OK);
1304
1305 freeBuffersOnPort(portIndex, true);
1306}
1307
1308void OMXCodec::enablePortAsync(OMX_U32 portIndex) {
1309 CHECK(mState == EXECUTING || mState == RECONFIGURING);
1310
1311 CHECK_EQ(mPortStatus[portIndex], DISABLED);
1312 mPortStatus[portIndex] = ENABLING;
1313
1314 status_t err =
1315 mOMX->send_command(mNode, OMX_CommandPortEnable, portIndex);
1316 CHECK_EQ(err, OK);
1317}
1318
1319void OMXCodec::fillOutputBuffers() {
1320 CHECK_EQ(mState, EXECUTING);
1321
1322 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
1323 for (size_t i = 0; i < buffers->size(); ++i) {
1324 fillOutputBuffer(&buffers->editItemAt(i));
1325 }
1326}
1327
1328void OMXCodec::drainInputBuffers() {
Andreas Huberd06e5b82009-08-28 13:18:14 -07001329 CHECK(mState == EXECUTING || mState == RECONFIGURING);
Andreas Huberbe06d262009-08-14 14:37:10 -07001330
1331 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
1332 for (size_t i = 0; i < buffers->size(); ++i) {
1333 drainInputBuffer(&buffers->editItemAt(i));
1334 }
1335}
1336
1337void OMXCodec::drainInputBuffer(BufferInfo *info) {
1338 CHECK_EQ(info->mOwnedByComponent, false);
1339
1340 if (mSignalledEOS) {
1341 return;
1342 }
1343
1344 if (mCodecSpecificDataIndex < mCodecSpecificData.size()) {
1345 const CodecSpecificData *specific =
1346 mCodecSpecificData[mCodecSpecificDataIndex];
1347
1348 size_t size = specific->mSize;
1349
Andreas Huber4f5e6022009-08-19 09:29:34 -07001350 if (!strcasecmp("video/avc", mMIME)
1351 && !(mQuirks & kWantsNALFragments)) {
Andreas Huberbe06d262009-08-14 14:37:10 -07001352 static const uint8_t kNALStartCode[4] =
1353 { 0x00, 0x00, 0x00, 0x01 };
1354
1355 CHECK(info->mMem->size() >= specific->mSize + 4);
1356
1357 size += 4;
1358
1359 memcpy(info->mMem->pointer(), kNALStartCode, 4);
1360 memcpy((uint8_t *)info->mMem->pointer() + 4,
1361 specific->mData, specific->mSize);
1362 } else {
1363 CHECK(info->mMem->size() >= specific->mSize);
1364 memcpy(info->mMem->pointer(), specific->mData, specific->mSize);
1365 }
1366
1367 mOMX->empty_buffer(
1368 mNode, info->mBuffer, 0, size,
1369 OMX_BUFFERFLAG_ENDOFFRAME | OMX_BUFFERFLAG_CODECCONFIG,
1370 0);
1371
1372 info->mOwnedByComponent = true;
1373
1374 ++mCodecSpecificDataIndex;
1375 return;
1376 }
1377
1378 MediaBuffer *srcBuffer;
1379 status_t err;
1380 if (mSeekTimeUs >= 0) {
1381 MediaSource::ReadOptions options;
1382 options.setSeekTo(mSeekTimeUs);
1383 mSeekTimeUs = -1;
1384
1385 err = mSource->read(&srcBuffer, &options);
1386 } else {
1387 err = mSource->read(&srcBuffer);
1388 }
1389
1390 OMX_U32 flags = OMX_BUFFERFLAG_ENDOFFRAME;
1391 OMX_TICKS timestamp = 0;
1392 size_t srcLength = 0;
1393
1394 if (err != OK) {
Andreas Huber4c483422009-09-02 16:05:36 -07001395 CODEC_LOGV("signalling end of input stream.");
Andreas Huberbe06d262009-08-14 14:37:10 -07001396 flags |= OMX_BUFFERFLAG_EOS;
1397
1398 mSignalledEOS = true;
1399 } else {
1400 srcLength = srcBuffer->range_length();
1401
1402 if (info->mMem->size() < srcLength) {
1403 LOGE("info->mMem->size() = %d, srcLength = %d",
1404 info->mMem->size(), srcLength);
1405 }
1406 CHECK(info->mMem->size() >= srcLength);
1407 memcpy(info->mMem->pointer(),
1408 (const uint8_t *)srcBuffer->data() + srcBuffer->range_offset(),
1409 srcLength);
1410
1411 int32_t units, scale;
1412 if (srcBuffer->meta_data()->findInt32(kKeyTimeUnits, &units)
1413 && srcBuffer->meta_data()->findInt32(kKeyTimeScale, &scale)) {
1414 timestamp = ((OMX_TICKS)units * 1000000) / scale;
1415
Andreas Huber4c483422009-09-02 16:05:36 -07001416 CODEC_LOGV("Calling empty_buffer on buffer %p (length %d)",
Andreas Huberbe06d262009-08-14 14:37:10 -07001417 info->mBuffer, srcLength);
Andreas Huber4c483422009-09-02 16:05:36 -07001418 CODEC_LOGV("Calling empty_buffer with timestamp %lld us (%.2f secs)",
Andreas Huberbe06d262009-08-14 14:37:10 -07001419 timestamp, timestamp / 1E6);
1420 }
1421 }
1422
1423 mOMX->empty_buffer(
1424 mNode, info->mBuffer, 0, srcLength,
1425 flags, timestamp);
1426
1427 info->mOwnedByComponent = true;
1428
1429 if (srcBuffer != NULL) {
1430 srcBuffer->release();
1431 srcBuffer = NULL;
1432 }
1433}
1434
1435void OMXCodec::fillOutputBuffer(BufferInfo *info) {
1436 CHECK_EQ(info->mOwnedByComponent, false);
1437
Andreas Huber404cc412009-08-25 14:26:05 -07001438 if (mNoMoreOutputData) {
Andreas Huber4c483422009-09-02 16:05:36 -07001439 CODEC_LOGV("There is no more output data available, not "
Andreas Huber404cc412009-08-25 14:26:05 -07001440 "calling fillOutputBuffer");
1441 return;
1442 }
1443
Andreas Huber4c483422009-09-02 16:05:36 -07001444 CODEC_LOGV("Calling fill_buffer on buffer %p", info->mBuffer);
Andreas Huberbe06d262009-08-14 14:37:10 -07001445 mOMX->fill_buffer(mNode, info->mBuffer);
1446
1447 info->mOwnedByComponent = true;
1448}
1449
1450void OMXCodec::drainInputBuffer(IOMX::buffer_id buffer) {
1451 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
1452 for (size_t i = 0; i < buffers->size(); ++i) {
1453 if ((*buffers)[i].mBuffer == buffer) {
1454 drainInputBuffer(&buffers->editItemAt(i));
1455 return;
1456 }
1457 }
1458
1459 CHECK(!"should not be here.");
1460}
1461
1462void OMXCodec::fillOutputBuffer(IOMX::buffer_id buffer) {
1463 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
1464 for (size_t i = 0; i < buffers->size(); ++i) {
1465 if ((*buffers)[i].mBuffer == buffer) {
1466 fillOutputBuffer(&buffers->editItemAt(i));
1467 return;
1468 }
1469 }
1470
1471 CHECK(!"should not be here.");
1472}
1473
1474void OMXCodec::setState(State newState) {
1475 mState = newState;
1476 mAsyncCompletion.signal();
1477
1478 // This may cause some spurious wakeups but is necessary to
1479 // unblock the reader if we enter ERROR state.
1480 mBufferFilled.signal();
1481}
1482
Andreas Huberda050cf22009-09-02 14:01:43 -07001483void OMXCodec::setRawAudioFormat(
1484 OMX_U32 portIndex, int32_t sampleRate, int32_t numChannels) {
1485 OMX_AUDIO_PARAM_PCMMODETYPE pcmParams;
Andreas Huber4c483422009-09-02 16:05:36 -07001486 InitOMXParams(&pcmParams);
Andreas Huberda050cf22009-09-02 14:01:43 -07001487 pcmParams.nPortIndex = portIndex;
1488
1489 status_t err = mOMX->get_parameter(
1490 mNode, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams));
1491
1492 CHECK_EQ(err, OK);
1493
1494 pcmParams.nChannels = numChannels;
1495 pcmParams.eNumData = OMX_NumericalDataSigned;
1496 pcmParams.bInterleaved = OMX_TRUE;
1497 pcmParams.nBitPerSample = 16;
1498 pcmParams.nSamplingRate = sampleRate;
1499 pcmParams.ePCMMode = OMX_AUDIO_PCMModeLinear;
1500
1501 if (numChannels == 1) {
1502 pcmParams.eChannelMapping[0] = OMX_AUDIO_ChannelCF;
1503 } else {
1504 CHECK_EQ(numChannels, 2);
1505
1506 pcmParams.eChannelMapping[0] = OMX_AUDIO_ChannelLF;
1507 pcmParams.eChannelMapping[1] = OMX_AUDIO_ChannelRF;
1508 }
1509
1510 err = mOMX->set_parameter(
1511 mNode, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams));
1512
1513 CHECK_EQ(err, OK);
1514}
1515
Andreas Huberbe06d262009-08-14 14:37:10 -07001516void OMXCodec::setAMRFormat() {
1517 if (!mIsEncoder) {
1518 OMX_AUDIO_PARAM_AMRTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -07001519 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -07001520 def.nPortIndex = kPortIndexInput;
1521
1522 status_t err =
1523 mOMX->get_parameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
1524
1525 CHECK_EQ(err, OK);
1526
1527 def.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
1528 def.eAMRBandMode = OMX_AUDIO_AMRBandModeNB0;
1529
1530 err = mOMX->set_parameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
1531 CHECK_EQ(err, OK);
1532 }
1533
1534 ////////////////////////
1535
1536 if (mIsEncoder) {
1537 sp<MetaData> format = mSource->getFormat();
1538 int32_t sampleRate;
1539 int32_t numChannels;
1540 CHECK(format->findInt32(kKeySampleRate, &sampleRate));
1541 CHECK(format->findInt32(kKeyChannelCount, &numChannels));
1542
Andreas Huberda050cf22009-09-02 14:01:43 -07001543 setRawAudioFormat(kPortIndexInput, sampleRate, numChannels);
Andreas Huberbe06d262009-08-14 14:37:10 -07001544 }
1545}
1546
Andreas Huber43ad6eaf2009-09-01 16:02:43 -07001547void OMXCodec::setAACFormat(int32_t numChannels, int32_t sampleRate) {
Andreas Huberda050cf22009-09-02 14:01:43 -07001548 if (mIsEncoder) {
1549 setRawAudioFormat(kPortIndexInput, sampleRate, numChannels);
1550 } else {
1551 OMX_AUDIO_PARAM_AACPROFILETYPE profile;
Andreas Huber4c483422009-09-02 16:05:36 -07001552 InitOMXParams(&profile);
Andreas Huberda050cf22009-09-02 14:01:43 -07001553 profile.nPortIndex = kPortIndexInput;
Andreas Huberbe06d262009-08-14 14:37:10 -07001554
Andreas Huberda050cf22009-09-02 14:01:43 -07001555 status_t err = mOMX->get_parameter(
1556 mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile));
1557 CHECK_EQ(err, OK);
Andreas Huberbe06d262009-08-14 14:37:10 -07001558
Andreas Huberda050cf22009-09-02 14:01:43 -07001559 profile.nChannels = numChannels;
1560 profile.nSampleRate = sampleRate;
1561 profile.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4ADTS;
Andreas Huberbe06d262009-08-14 14:37:10 -07001562
Andreas Huberda050cf22009-09-02 14:01:43 -07001563 err = mOMX->set_parameter(
1564 mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile));
1565 CHECK_EQ(err, OK);
1566 }
Andreas Huberbe06d262009-08-14 14:37:10 -07001567}
1568
1569void OMXCodec::setImageOutputFormat(
1570 OMX_COLOR_FORMATTYPE format, OMX_U32 width, OMX_U32 height) {
Andreas Huber4c483422009-09-02 16:05:36 -07001571 CODEC_LOGV("setImageOutputFormat(%ld, %ld)", width, height);
Andreas Huberbe06d262009-08-14 14:37:10 -07001572
1573#if 0
1574 OMX_INDEXTYPE index;
1575 status_t err = mOMX->get_extension_index(
1576 mNode, "OMX.TI.JPEG.decode.Config.OutputColorFormat", &index);
1577 CHECK_EQ(err, OK);
1578
1579 err = mOMX->set_config(mNode, index, &format, sizeof(format));
1580 CHECK_EQ(err, OK);
1581#endif
1582
1583 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -07001584 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -07001585 def.nPortIndex = kPortIndexOutput;
1586
1587 status_t err = mOMX->get_parameter(
1588 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
1589 CHECK_EQ(err, OK);
1590
1591 CHECK_EQ(def.eDomain, OMX_PortDomainImage);
1592
1593 OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
Andreas Huberebf66ea2009-08-19 13:32:58 -07001594
Andreas Huberbe06d262009-08-14 14:37:10 -07001595 CHECK_EQ(imageDef->eCompressionFormat, OMX_IMAGE_CodingUnused);
1596 imageDef->eColorFormat = format;
1597 imageDef->nFrameWidth = width;
1598 imageDef->nFrameHeight = height;
1599
1600 switch (format) {
1601 case OMX_COLOR_FormatYUV420PackedPlanar:
1602 case OMX_COLOR_FormatYUV411Planar:
1603 {
1604 def.nBufferSize = (width * height * 3) / 2;
1605 break;
1606 }
1607
1608 case OMX_COLOR_FormatCbYCrY:
1609 {
1610 def.nBufferSize = width * height * 2;
1611 break;
1612 }
1613
1614 case OMX_COLOR_Format32bitARGB8888:
1615 {
1616 def.nBufferSize = width * height * 4;
1617 break;
1618 }
1619
1620 default:
1621 CHECK(!"Should not be here. Unknown color format.");
1622 break;
1623 }
1624
Andreas Huber5c0a9132009-08-20 11:16:40 -07001625 def.nBufferCountActual = def.nBufferCountMin;
1626
Andreas Huberbe06d262009-08-14 14:37:10 -07001627 err = mOMX->set_parameter(
1628 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
1629 CHECK_EQ(err, OK);
Andreas Huber5c0a9132009-08-20 11:16:40 -07001630}
Andreas Huberbe06d262009-08-14 14:37:10 -07001631
Andreas Huber5c0a9132009-08-20 11:16:40 -07001632void OMXCodec::setJPEGInputFormat(
1633 OMX_U32 width, OMX_U32 height, OMX_U32 compressedSize) {
1634 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -07001635 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -07001636 def.nPortIndex = kPortIndexInput;
1637
Andreas Huber5c0a9132009-08-20 11:16:40 -07001638 status_t err = mOMX->get_parameter(
Andreas Huberbe06d262009-08-14 14:37:10 -07001639 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
1640 CHECK_EQ(err, OK);
1641
Andreas Huber5c0a9132009-08-20 11:16:40 -07001642 CHECK_EQ(def.eDomain, OMX_PortDomainImage);
1643 OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
1644
Andreas Huberbe06d262009-08-14 14:37:10 -07001645 CHECK_EQ(imageDef->eCompressionFormat, OMX_IMAGE_CodingJPEG);
1646 imageDef->nFrameWidth = width;
1647 imageDef->nFrameHeight = height;
1648
Andreas Huber5c0a9132009-08-20 11:16:40 -07001649 def.nBufferSize = compressedSize;
Andreas Huberbe06d262009-08-14 14:37:10 -07001650 def.nBufferCountActual = def.nBufferCountMin;
1651
1652 err = mOMX->set_parameter(
1653 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
1654 CHECK_EQ(err, OK);
1655}
1656
1657void OMXCodec::addCodecSpecificData(const void *data, size_t size) {
1658 CodecSpecificData *specific =
1659 (CodecSpecificData *)malloc(sizeof(CodecSpecificData) + size - 1);
1660
1661 specific->mSize = size;
1662 memcpy(specific->mData, data, size);
1663
1664 mCodecSpecificData.push(specific);
1665}
1666
1667void OMXCodec::clearCodecSpecificData() {
1668 for (size_t i = 0; i < mCodecSpecificData.size(); ++i) {
1669 free(mCodecSpecificData.editItemAt(i));
1670 }
1671 mCodecSpecificData.clear();
1672 mCodecSpecificDataIndex = 0;
1673}
1674
1675status_t OMXCodec::start(MetaData *) {
Andreas Huber42978e52009-08-27 10:08:39 -07001676 Mutex::Autolock autoLock(mLock);
1677
Andreas Huberbe06d262009-08-14 14:37:10 -07001678 if (mState != LOADED) {
1679 return UNKNOWN_ERROR;
1680 }
Andreas Huberebf66ea2009-08-19 13:32:58 -07001681
Andreas Huberbe06d262009-08-14 14:37:10 -07001682 sp<MetaData> params = new MetaData;
Andreas Huber4f5e6022009-08-19 09:29:34 -07001683 if (mQuirks & kWantsNALFragments) {
1684 params->setInt32(kKeyWantsNALFragments, true);
Andreas Huberbe06d262009-08-14 14:37:10 -07001685 }
1686 status_t err = mSource->start(params.get());
1687
1688 if (err != OK) {
1689 return err;
1690 }
1691
1692 mCodecSpecificDataIndex = 0;
Andreas Huber42978e52009-08-27 10:08:39 -07001693 mInitialBufferSubmit = true;
Andreas Huberbe06d262009-08-14 14:37:10 -07001694 mSignalledEOS = false;
1695 mNoMoreOutputData = false;
1696 mSeekTimeUs = -1;
1697 mFilledBuffers.clear();
1698
1699 return init();
1700}
1701
1702status_t OMXCodec::stop() {
Andreas Huber4c483422009-09-02 16:05:36 -07001703 CODEC_LOGV("stop");
Andreas Huberbe06d262009-08-14 14:37:10 -07001704
1705 Mutex::Autolock autoLock(mLock);
1706
1707 while (isIntermediateState(mState)) {
1708 mAsyncCompletion.wait(mLock);
1709 }
1710
1711 switch (mState) {
1712 case LOADED:
1713 case ERROR:
1714 break;
1715
1716 case EXECUTING:
1717 {
1718 setState(EXECUTING_TO_IDLE);
1719
Andreas Huber127fcdc2009-08-26 16:27:02 -07001720 if (mQuirks & kRequiresFlushBeforeShutdown) {
Andreas Huber4c483422009-09-02 16:05:36 -07001721 CODEC_LOGV("This component requires a flush before transitioning "
Andreas Huber127fcdc2009-08-26 16:27:02 -07001722 "from EXECUTING to IDLE...");
Andreas Huberbe06d262009-08-14 14:37:10 -07001723
Andreas Huber127fcdc2009-08-26 16:27:02 -07001724 bool emulateInputFlushCompletion =
1725 !flushPortAsync(kPortIndexInput);
1726
1727 bool emulateOutputFlushCompletion =
1728 !flushPortAsync(kPortIndexOutput);
1729
1730 if (emulateInputFlushCompletion) {
1731 onCmdComplete(OMX_CommandFlush, kPortIndexInput);
1732 }
1733
1734 if (emulateOutputFlushCompletion) {
1735 onCmdComplete(OMX_CommandFlush, kPortIndexOutput);
1736 }
1737 } else {
1738 mPortStatus[kPortIndexInput] = SHUTTING_DOWN;
1739 mPortStatus[kPortIndexOutput] = SHUTTING_DOWN;
1740
1741 status_t err =
1742 mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
1743 CHECK_EQ(err, OK);
1744 }
Andreas Huberbe06d262009-08-14 14:37:10 -07001745
1746 while (mState != LOADED && mState != ERROR) {
1747 mAsyncCompletion.wait(mLock);
1748 }
1749
1750 break;
1751 }
1752
1753 default:
1754 {
1755 CHECK(!"should not be here.");
1756 break;
1757 }
1758 }
1759
1760 mSource->stop();
1761
1762 return OK;
1763}
1764
1765sp<MetaData> OMXCodec::getFormat() {
1766 return mOutputFormat;
1767}
1768
1769status_t OMXCodec::read(
1770 MediaBuffer **buffer, const ReadOptions *options) {
1771 *buffer = NULL;
1772
1773 Mutex::Autolock autoLock(mLock);
1774
Andreas Huberd06e5b82009-08-28 13:18:14 -07001775 if (mState != EXECUTING && mState != RECONFIGURING) {
1776 return UNKNOWN_ERROR;
1777 }
1778
Andreas Huber42978e52009-08-27 10:08:39 -07001779 if (mInitialBufferSubmit) {
1780 mInitialBufferSubmit = false;
1781
1782 drainInputBuffers();
Andreas Huber42978e52009-08-27 10:08:39 -07001783
Andreas Huberd06e5b82009-08-28 13:18:14 -07001784 if (mState == EXECUTING) {
1785 // Otherwise mState == RECONFIGURING and this code will trigger
1786 // after the output port is reenabled.
1787 fillOutputBuffers();
1788 }
Andreas Huberbe06d262009-08-14 14:37:10 -07001789 }
1790
1791 int64_t seekTimeUs;
1792 if (options && options->getSeekTo(&seekTimeUs)) {
Andreas Huber4c483422009-09-02 16:05:36 -07001793 CODEC_LOGV("seeking to %lld us (%.2f secs)", seekTimeUs, seekTimeUs / 1E6);
Andreas Huberbe06d262009-08-14 14:37:10 -07001794
1795 mSignalledEOS = false;
1796 mNoMoreOutputData = false;
1797
1798 CHECK(seekTimeUs >= 0);
1799 mSeekTimeUs = seekTimeUs;
1800
1801 mFilledBuffers.clear();
1802
1803 CHECK_EQ(mState, EXECUTING);
1804
Andreas Huber404cc412009-08-25 14:26:05 -07001805 bool emulateInputFlushCompletion = !flushPortAsync(kPortIndexInput);
1806 bool emulateOutputFlushCompletion = !flushPortAsync(kPortIndexOutput);
1807
1808 if (emulateInputFlushCompletion) {
1809 onCmdComplete(OMX_CommandFlush, kPortIndexInput);
1810 }
1811
1812 if (emulateOutputFlushCompletion) {
1813 onCmdComplete(OMX_CommandFlush, kPortIndexOutput);
1814 }
Andreas Huberbe06d262009-08-14 14:37:10 -07001815 }
1816
1817 while (mState != ERROR && !mNoMoreOutputData && mFilledBuffers.empty()) {
1818 mBufferFilled.wait(mLock);
1819 }
1820
1821 if (mState == ERROR) {
1822 return UNKNOWN_ERROR;
1823 }
1824
1825 if (mFilledBuffers.empty()) {
1826 return ERROR_END_OF_STREAM;
1827 }
1828
1829 size_t index = *mFilledBuffers.begin();
1830 mFilledBuffers.erase(mFilledBuffers.begin());
1831
1832 BufferInfo *info = &mPortBuffers[kPortIndexOutput].editItemAt(index);
1833 info->mMediaBuffer->add_ref();
1834 *buffer = info->mMediaBuffer;
1835
1836 return OK;
1837}
1838
1839void OMXCodec::signalBufferReturned(MediaBuffer *buffer) {
1840 Mutex::Autolock autoLock(mLock);
1841
1842 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
1843 for (size_t i = 0; i < buffers->size(); ++i) {
1844 BufferInfo *info = &buffers->editItemAt(i);
1845
1846 if (info->mMediaBuffer == buffer) {
1847 CHECK_EQ(mPortStatus[kPortIndexOutput], ENABLED);
1848 fillOutputBuffer(info);
1849 return;
1850 }
1851 }
1852
1853 CHECK(!"should not be here.");
1854}
1855
1856static const char *imageCompressionFormatString(OMX_IMAGE_CODINGTYPE type) {
1857 static const char *kNames[] = {
1858 "OMX_IMAGE_CodingUnused",
1859 "OMX_IMAGE_CodingAutoDetect",
1860 "OMX_IMAGE_CodingJPEG",
1861 "OMX_IMAGE_CodingJPEG2K",
1862 "OMX_IMAGE_CodingEXIF",
1863 "OMX_IMAGE_CodingTIFF",
1864 "OMX_IMAGE_CodingGIF",
1865 "OMX_IMAGE_CodingPNG",
1866 "OMX_IMAGE_CodingLZW",
1867 "OMX_IMAGE_CodingBMP",
1868 };
1869
1870 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
1871
1872 if (type < 0 || (size_t)type >= numNames) {
1873 return "UNKNOWN";
1874 } else {
1875 return kNames[type];
1876 }
1877}
1878
1879static const char *colorFormatString(OMX_COLOR_FORMATTYPE type) {
1880 static const char *kNames[] = {
1881 "OMX_COLOR_FormatUnused",
1882 "OMX_COLOR_FormatMonochrome",
1883 "OMX_COLOR_Format8bitRGB332",
1884 "OMX_COLOR_Format12bitRGB444",
1885 "OMX_COLOR_Format16bitARGB4444",
1886 "OMX_COLOR_Format16bitARGB1555",
1887 "OMX_COLOR_Format16bitRGB565",
1888 "OMX_COLOR_Format16bitBGR565",
1889 "OMX_COLOR_Format18bitRGB666",
1890 "OMX_COLOR_Format18bitARGB1665",
Andreas Huberebf66ea2009-08-19 13:32:58 -07001891 "OMX_COLOR_Format19bitARGB1666",
Andreas Huberbe06d262009-08-14 14:37:10 -07001892 "OMX_COLOR_Format24bitRGB888",
1893 "OMX_COLOR_Format24bitBGR888",
1894 "OMX_COLOR_Format24bitARGB1887",
1895 "OMX_COLOR_Format25bitARGB1888",
1896 "OMX_COLOR_Format32bitBGRA8888",
1897 "OMX_COLOR_Format32bitARGB8888",
1898 "OMX_COLOR_FormatYUV411Planar",
1899 "OMX_COLOR_FormatYUV411PackedPlanar",
1900 "OMX_COLOR_FormatYUV420Planar",
1901 "OMX_COLOR_FormatYUV420PackedPlanar",
1902 "OMX_COLOR_FormatYUV420SemiPlanar",
1903 "OMX_COLOR_FormatYUV422Planar",
1904 "OMX_COLOR_FormatYUV422PackedPlanar",
1905 "OMX_COLOR_FormatYUV422SemiPlanar",
1906 "OMX_COLOR_FormatYCbYCr",
1907 "OMX_COLOR_FormatYCrYCb",
1908 "OMX_COLOR_FormatCbYCrY",
1909 "OMX_COLOR_FormatCrYCbY",
1910 "OMX_COLOR_FormatYUV444Interleaved",
1911 "OMX_COLOR_FormatRawBayer8bit",
1912 "OMX_COLOR_FormatRawBayer10bit",
1913 "OMX_COLOR_FormatRawBayer8bitcompressed",
Andreas Huberebf66ea2009-08-19 13:32:58 -07001914 "OMX_COLOR_FormatL2",
1915 "OMX_COLOR_FormatL4",
1916 "OMX_COLOR_FormatL8",
1917 "OMX_COLOR_FormatL16",
1918 "OMX_COLOR_FormatL24",
Andreas Huberbe06d262009-08-14 14:37:10 -07001919 "OMX_COLOR_FormatL32",
1920 "OMX_COLOR_FormatYUV420PackedSemiPlanar",
1921 "OMX_COLOR_FormatYUV422PackedSemiPlanar",
1922 "OMX_COLOR_Format18BitBGR666",
1923 "OMX_COLOR_Format24BitARGB6666",
1924 "OMX_COLOR_Format24BitABGR6666",
1925 };
1926
1927 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
1928
1929 static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
1930
1931 if (type == OMX_QCOM_COLOR_FormatYVU420SemiPlanar) {
1932 return "OMX_QCOM_COLOR_FormatYVU420SemiPlanar";
1933 } else if (type < 0 || (size_t)type >= numNames) {
1934 return "UNKNOWN";
1935 } else {
1936 return kNames[type];
1937 }
1938}
1939
1940static const char *videoCompressionFormatString(OMX_VIDEO_CODINGTYPE type) {
1941 static const char *kNames[] = {
1942 "OMX_VIDEO_CodingUnused",
1943 "OMX_VIDEO_CodingAutoDetect",
1944 "OMX_VIDEO_CodingMPEG2",
1945 "OMX_VIDEO_CodingH263",
1946 "OMX_VIDEO_CodingMPEG4",
1947 "OMX_VIDEO_CodingWMV",
1948 "OMX_VIDEO_CodingRV",
1949 "OMX_VIDEO_CodingAVC",
1950 "OMX_VIDEO_CodingMJPEG",
1951 };
1952
1953 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
1954
1955 if (type < 0 || (size_t)type >= numNames) {
1956 return "UNKNOWN";
1957 } else {
1958 return kNames[type];
1959 }
1960}
1961
1962static const char *audioCodingTypeString(OMX_AUDIO_CODINGTYPE type) {
1963 static const char *kNames[] = {
1964 "OMX_AUDIO_CodingUnused",
1965 "OMX_AUDIO_CodingAutoDetect",
1966 "OMX_AUDIO_CodingPCM",
1967 "OMX_AUDIO_CodingADPCM",
1968 "OMX_AUDIO_CodingAMR",
1969 "OMX_AUDIO_CodingGSMFR",
1970 "OMX_AUDIO_CodingGSMEFR",
1971 "OMX_AUDIO_CodingGSMHR",
1972 "OMX_AUDIO_CodingPDCFR",
1973 "OMX_AUDIO_CodingPDCEFR",
1974 "OMX_AUDIO_CodingPDCHR",
1975 "OMX_AUDIO_CodingTDMAFR",
1976 "OMX_AUDIO_CodingTDMAEFR",
1977 "OMX_AUDIO_CodingQCELP8",
1978 "OMX_AUDIO_CodingQCELP13",
1979 "OMX_AUDIO_CodingEVRC",
1980 "OMX_AUDIO_CodingSMV",
1981 "OMX_AUDIO_CodingG711",
1982 "OMX_AUDIO_CodingG723",
1983 "OMX_AUDIO_CodingG726",
1984 "OMX_AUDIO_CodingG729",
1985 "OMX_AUDIO_CodingAAC",
1986 "OMX_AUDIO_CodingMP3",
1987 "OMX_AUDIO_CodingSBC",
1988 "OMX_AUDIO_CodingVORBIS",
1989 "OMX_AUDIO_CodingWMA",
1990 "OMX_AUDIO_CodingRA",
1991 "OMX_AUDIO_CodingMIDI",
1992 };
1993
1994 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
1995
1996 if (type < 0 || (size_t)type >= numNames) {
1997 return "UNKNOWN";
1998 } else {
1999 return kNames[type];
2000 }
2001}
2002
2003static const char *audioPCMModeString(OMX_AUDIO_PCMMODETYPE type) {
2004 static const char *kNames[] = {
2005 "OMX_AUDIO_PCMModeLinear",
2006 "OMX_AUDIO_PCMModeALaw",
2007 "OMX_AUDIO_PCMModeMULaw",
2008 };
2009
2010 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
2011
2012 if (type < 0 || (size_t)type >= numNames) {
2013 return "UNKNOWN";
2014 } else {
2015 return kNames[type];
2016 }
2017}
2018
2019
2020void OMXCodec::dumpPortStatus(OMX_U32 portIndex) {
2021 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -07002022 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -07002023 def.nPortIndex = portIndex;
2024
2025 status_t err = mOMX->get_parameter(
2026 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
2027 CHECK_EQ(err, OK);
2028
2029 printf("%s Port = {\n", portIndex == kPortIndexInput ? "Input" : "Output");
2030
2031 CHECK((portIndex == kPortIndexInput && def.eDir == OMX_DirInput)
2032 || (portIndex == kPortIndexOutput && def.eDir == OMX_DirOutput));
2033
2034 printf(" nBufferCountActual = %ld\n", def.nBufferCountActual);
2035 printf(" nBufferCountMin = %ld\n", def.nBufferCountMin);
2036 printf(" nBufferSize = %ld\n", def.nBufferSize);
2037
2038 switch (def.eDomain) {
2039 case OMX_PortDomainImage:
2040 {
2041 const OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
2042
2043 printf("\n");
2044 printf(" // Image\n");
2045 printf(" nFrameWidth = %ld\n", imageDef->nFrameWidth);
2046 printf(" nFrameHeight = %ld\n", imageDef->nFrameHeight);
2047 printf(" nStride = %ld\n", imageDef->nStride);
2048
2049 printf(" eCompressionFormat = %s\n",
2050 imageCompressionFormatString(imageDef->eCompressionFormat));
2051
2052 printf(" eColorFormat = %s\n",
2053 colorFormatString(imageDef->eColorFormat));
2054
2055 break;
2056 }
2057
2058 case OMX_PortDomainVideo:
2059 {
2060 OMX_VIDEO_PORTDEFINITIONTYPE *videoDef = &def.format.video;
2061
2062 printf("\n");
2063 printf(" // Video\n");
2064 printf(" nFrameWidth = %ld\n", videoDef->nFrameWidth);
2065 printf(" nFrameHeight = %ld\n", videoDef->nFrameHeight);
2066 printf(" nStride = %ld\n", videoDef->nStride);
2067
2068 printf(" eCompressionFormat = %s\n",
2069 videoCompressionFormatString(videoDef->eCompressionFormat));
2070
2071 printf(" eColorFormat = %s\n",
2072 colorFormatString(videoDef->eColorFormat));
2073
2074 break;
2075 }
2076
2077 case OMX_PortDomainAudio:
2078 {
2079 OMX_AUDIO_PORTDEFINITIONTYPE *audioDef = &def.format.audio;
2080
2081 printf("\n");
2082 printf(" // Audio\n");
2083 printf(" eEncoding = %s\n",
2084 audioCodingTypeString(audioDef->eEncoding));
2085
2086 if (audioDef->eEncoding == OMX_AUDIO_CodingPCM) {
2087 OMX_AUDIO_PARAM_PCMMODETYPE params;
Andreas Huber4c483422009-09-02 16:05:36 -07002088 InitOMXParams(&params);
Andreas Huberbe06d262009-08-14 14:37:10 -07002089 params.nPortIndex = portIndex;
2090
2091 err = mOMX->get_parameter(
2092 mNode, OMX_IndexParamAudioPcm, &params, sizeof(params));
2093 CHECK_EQ(err, OK);
2094
2095 printf(" nSamplingRate = %ld\n", params.nSamplingRate);
2096 printf(" nChannels = %ld\n", params.nChannels);
2097 printf(" bInterleaved = %d\n", params.bInterleaved);
2098 printf(" nBitPerSample = %ld\n", params.nBitPerSample);
2099
2100 printf(" eNumData = %s\n",
2101 params.eNumData == OMX_NumericalDataSigned
2102 ? "signed" : "unsigned");
2103
2104 printf(" ePCMMode = %s\n", audioPCMModeString(params.ePCMMode));
2105 }
2106
2107 break;
2108 }
2109
2110 default:
2111 {
2112 printf(" // Unknown\n");
2113 break;
2114 }
2115 }
2116
2117 printf("}\n");
2118}
2119
2120void OMXCodec::initOutputFormat(const sp<MetaData> &inputFormat) {
2121 mOutputFormat = new MetaData;
2122 mOutputFormat->setCString(kKeyDecoderComponent, mComponentName);
2123
2124 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -07002125 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -07002126 def.nPortIndex = kPortIndexOutput;
2127
2128 status_t err = mOMX->get_parameter(
2129 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
2130 CHECK_EQ(err, OK);
2131
2132 switch (def.eDomain) {
2133 case OMX_PortDomainImage:
2134 {
2135 OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
2136 CHECK_EQ(imageDef->eCompressionFormat, OMX_IMAGE_CodingUnused);
2137
2138 mOutputFormat->setCString(kKeyMIMEType, "image/raw");
2139 mOutputFormat->setInt32(kKeyColorFormat, imageDef->eColorFormat);
2140 mOutputFormat->setInt32(kKeyWidth, imageDef->nFrameWidth);
2141 mOutputFormat->setInt32(kKeyHeight, imageDef->nFrameHeight);
2142 break;
2143 }
2144
2145 case OMX_PortDomainAudio:
2146 {
2147 OMX_AUDIO_PORTDEFINITIONTYPE *audio_def = &def.format.audio;
2148
Andreas Huberda050cf22009-09-02 14:01:43 -07002149 if (audio_def->eEncoding == OMX_AUDIO_CodingPCM) {
2150 OMX_AUDIO_PARAM_PCMMODETYPE params;
Andreas Huber4c483422009-09-02 16:05:36 -07002151 InitOMXParams(&params);
Andreas Huberda050cf22009-09-02 14:01:43 -07002152 params.nPortIndex = kPortIndexOutput;
Andreas Huberbe06d262009-08-14 14:37:10 -07002153
Andreas Huberda050cf22009-09-02 14:01:43 -07002154 err = mOMX->get_parameter(
2155 mNode, OMX_IndexParamAudioPcm, &params, sizeof(params));
2156 CHECK_EQ(err, OK);
Andreas Huberbe06d262009-08-14 14:37:10 -07002157
Andreas Huberda050cf22009-09-02 14:01:43 -07002158 CHECK_EQ(params.eNumData, OMX_NumericalDataSigned);
2159 CHECK_EQ(params.nBitPerSample, 16);
2160 CHECK_EQ(params.ePCMMode, OMX_AUDIO_PCMModeLinear);
Andreas Huberbe06d262009-08-14 14:37:10 -07002161
Andreas Huberda050cf22009-09-02 14:01:43 -07002162 int32_t numChannels, sampleRate;
2163 inputFormat->findInt32(kKeyChannelCount, &numChannels);
2164 inputFormat->findInt32(kKeySampleRate, &sampleRate);
Andreas Huberbe06d262009-08-14 14:37:10 -07002165
Andreas Huberda050cf22009-09-02 14:01:43 -07002166 if ((OMX_U32)numChannels != params.nChannels) {
2167 LOGW("Codec outputs a different number of channels than "
2168 "the input stream contains.");
2169 }
Andreas Huberbe06d262009-08-14 14:37:10 -07002170
Andreas Huberda050cf22009-09-02 14:01:43 -07002171 mOutputFormat->setCString(kKeyMIMEType, "audio/raw");
2172
2173 // Use the codec-advertised number of channels, as some
2174 // codecs appear to output stereo even if the input data is
2175 // mono.
2176 mOutputFormat->setInt32(kKeyChannelCount, params.nChannels);
2177
2178 // The codec-reported sampleRate is not reliable...
2179 mOutputFormat->setInt32(kKeySampleRate, sampleRate);
2180 } else if (audio_def->eEncoding == OMX_AUDIO_CodingAMR) {
2181 mOutputFormat->setCString(kKeyMIMEType, "audio/3gpp");
2182 } else if (audio_def->eEncoding == OMX_AUDIO_CodingAAC) {
2183 mOutputFormat->setCString(kKeyMIMEType, "audio/mp4a-latm");
2184 } else {
2185 CHECK(!"Should not be here. Unknown audio encoding.");
Andreas Huber43ad6eaf2009-09-01 16:02:43 -07002186 }
Andreas Huberbe06d262009-08-14 14:37:10 -07002187 break;
2188 }
2189
2190 case OMX_PortDomainVideo:
2191 {
2192 OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
2193
2194 if (video_def->eCompressionFormat == OMX_VIDEO_CodingUnused) {
2195 mOutputFormat->setCString(kKeyMIMEType, "video/raw");
2196 } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingMPEG4) {
2197 mOutputFormat->setCString(kKeyMIMEType, "video/mp4v-es");
2198 } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingH263) {
2199 mOutputFormat->setCString(kKeyMIMEType, "video/3gpp");
2200 } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingAVC) {
2201 mOutputFormat->setCString(kKeyMIMEType, "video/avc");
2202 } else {
2203 CHECK(!"Unknown compression format.");
2204 }
2205
2206 if (!strcmp(mComponentName, "OMX.PV.avcdec")) {
2207 // This component appears to be lying to me.
2208 mOutputFormat->setInt32(
2209 kKeyWidth, (video_def->nFrameWidth + 15) & -16);
2210 mOutputFormat->setInt32(
2211 kKeyHeight, (video_def->nFrameHeight + 15) & -16);
2212 } else {
2213 mOutputFormat->setInt32(kKeyWidth, video_def->nFrameWidth);
2214 mOutputFormat->setInt32(kKeyHeight, video_def->nFrameHeight);
2215 }
2216
2217 mOutputFormat->setInt32(kKeyColorFormat, video_def->eColorFormat);
2218 break;
2219 }
2220
2221 default:
2222 {
2223 CHECK(!"should not be here, neither audio nor video.");
2224 break;
2225 }
2226 }
2227}
2228
2229} // namespace android