blob: 8eb473895272728cb9a121a33bc9ce57299f4a08 [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>
Andreas Hubere6c40962009-09-10 14:13:30 -070029#include <media/stagefright/MediaDefs.h>
Andreas Huberbe06d262009-08-14 14:37:10 -070030#include <media/stagefright/MediaExtractor.h>
31#include <media/stagefright/MetaData.h>
32#include <media/stagefright/MmapSource.h>
33#include <media/stagefright/OMXCodec.h>
Andreas Huberebf66ea2009-08-19 13:32:58 -070034#include <media/stagefright/Utils.h>
Andreas Huberbe06d262009-08-14 14:37:10 -070035#include <utils/Vector.h>
36
37#include <OMX_Audio.h>
38#include <OMX_Component.h>
39
40namespace android {
41
Andreas Huber8b432b12009-10-07 13:36:52 -070042static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
43
Andreas Huberbe06d262009-08-14 14:37:10 -070044struct CodecInfo {
45 const char *mime;
46 const char *codec;
47};
48
49static const CodecInfo kDecoderInfo[] = {
Andreas Hubere6c40962009-09-10 14:13:30 -070050 { MEDIA_MIMETYPE_IMAGE_JPEG, "OMX.TI.JPEG.decode" },
51 { MEDIA_MIMETYPE_AUDIO_MPEG, "OMX.TI.MP3.decode" },
52 { MEDIA_MIMETYPE_AUDIO_MPEG, "OMX.PV.mp3dec" },
53 { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.TI.AMR.decode" },
54 { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.PV.amrdec" },
55 { MEDIA_MIMETYPE_AUDIO_AMR_WB, "OMX.TI.WBAMR.decode" },
56 { MEDIA_MIMETYPE_AUDIO_AMR_WB, "OMX.PV.amrdec" },
57 { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.TI.AAC.decode" },
58 { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.PV.aacdec" },
59 { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.qcom.video.decoder.mpeg4" },
60 { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.TI.Video.Decoder" },
61 { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.PV.mpeg4dec" },
62 { MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.video.decoder.h263" },
63 { MEDIA_MIMETYPE_VIDEO_H263, "OMX.TI.Video.Decoder" },
64 { MEDIA_MIMETYPE_VIDEO_H263, "OMX.PV.h263dec" },
65 { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.qcom.video.decoder.avc" },
66 { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.TI.Video.Decoder" },
67 { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.PV.avcdec" },
Andreas Huberbe06d262009-08-14 14:37:10 -070068};
69
70static const CodecInfo kEncoderInfo[] = {
Andreas Hubere6c40962009-09-10 14:13:30 -070071 { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.TI.AMR.encode" },
72 { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.PV.amrencnb" },
73 { MEDIA_MIMETYPE_AUDIO_AMR_WB, "OMX.TI.WBAMR.encode" },
74 { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.TI.AAC.encode" },
75 { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.PV.aacenc" },
76 { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.qcom.video.encoder.mpeg4" },
77 { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.TI.Video.encoder" },
78 { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.PV.mpeg4enc" },
79 { MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.video.encoder.h263" },
80 { MEDIA_MIMETYPE_VIDEO_H263, "OMX.TI.Video.encoder" },
81 { MEDIA_MIMETYPE_VIDEO_H263, "OMX.PV.h263enc" },
82 { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.TI.Video.encoder" },
83 { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.PV.avcenc" },
Andreas Huberbe06d262009-08-14 14:37:10 -070084};
85
Andreas Hubere0873732009-09-10 09:57:53 -070086#define CODEC_LOGI(x, ...) LOGI("[%s] "x, mComponentName, ##__VA_ARGS__)
Andreas Huber4c483422009-09-02 16:05:36 -070087#define CODEC_LOGV(x, ...) LOGV("[%s] "x, mComponentName, ##__VA_ARGS__)
88
Andreas Huberbe06d262009-08-14 14:37:10 -070089struct OMXCodecObserver : public BnOMXObserver {
90 OMXCodecObserver(const wp<OMXCodec> &target)
91 : mTarget(target) {
92 }
93
94 // from IOMXObserver
95 virtual void on_message(const omx_message &msg) {
96 sp<OMXCodec> codec = mTarget.promote();
97
98 if (codec.get() != NULL) {
99 codec->on_message(msg);
100 }
101 }
102
103protected:
104 virtual ~OMXCodecObserver() {}
105
106private:
107 wp<OMXCodec> mTarget;
108
109 OMXCodecObserver(const OMXCodecObserver &);
110 OMXCodecObserver &operator=(const OMXCodecObserver &);
111};
112
113static const char *GetCodec(const CodecInfo *info, size_t numInfos,
114 const char *mime, int index) {
115 CHECK(index >= 0);
116 for(size_t i = 0; i < numInfos; ++i) {
117 if (!strcasecmp(mime, info[i].mime)) {
118 if (index == 0) {
119 return info[i].codec;
120 }
121
122 --index;
123 }
124 }
125
126 return NULL;
127}
128
Andreas Huberebf66ea2009-08-19 13:32:58 -0700129enum {
130 kAVCProfileBaseline = 0x42,
131 kAVCProfileMain = 0x4d,
132 kAVCProfileExtended = 0x58,
133 kAVCProfileHigh = 0x64,
134 kAVCProfileHigh10 = 0x6e,
135 kAVCProfileHigh422 = 0x7a,
136 kAVCProfileHigh444 = 0xf4,
137 kAVCProfileCAVLC444Intra = 0x2c
138};
139
140static const char *AVCProfileToString(uint8_t profile) {
141 switch (profile) {
142 case kAVCProfileBaseline:
143 return "Baseline";
144 case kAVCProfileMain:
145 return "Main";
146 case kAVCProfileExtended:
147 return "Extended";
148 case kAVCProfileHigh:
149 return "High";
150 case kAVCProfileHigh10:
151 return "High 10";
152 case kAVCProfileHigh422:
153 return "High 422";
154 case kAVCProfileHigh444:
155 return "High 444";
156 case kAVCProfileCAVLC444Intra:
157 return "CAVLC 444 Intra";
158 default: return "Unknown";
159 }
160}
161
Andreas Huber4c483422009-09-02 16:05:36 -0700162template<class T>
163static void InitOMXParams(T *params) {
164 params->nSize = sizeof(T);
165 params->nVersion.s.nVersionMajor = 1;
166 params->nVersion.s.nVersionMinor = 0;
167 params->nVersion.s.nRevision = 0;
168 params->nVersion.s.nStep = 0;
169}
170
Andreas Huberbe06d262009-08-14 14:37:10 -0700171// static
172sp<OMXCodec> OMXCodec::Create(
173 const sp<IOMX> &omx,
174 const sp<MetaData> &meta, bool createEncoder,
Andreas Hubere6c40962009-09-10 14:13:30 -0700175 const sp<MediaSource> &source,
176 const char *matchComponentName) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700177 const char *mime;
178 bool success = meta->findCString(kKeyMIMEType, &mime);
179 CHECK(success);
180
181 const char *componentName = NULL;
182 IOMX::node_id node = 0;
183 for (int index = 0;; ++index) {
184 if (createEncoder) {
185 componentName = GetCodec(
186 kEncoderInfo, sizeof(kEncoderInfo) / sizeof(kEncoderInfo[0]),
187 mime, index);
188 } else {
189 componentName = GetCodec(
190 kDecoderInfo, sizeof(kDecoderInfo) / sizeof(kDecoderInfo[0]),
191 mime, index);
192 }
193
194 if (!componentName) {
195 return NULL;
196 }
197
Andreas Hubere6c40962009-09-10 14:13:30 -0700198 // If a specific codec is requested, skip the non-matching ones.
199 if (matchComponentName && strcmp(componentName, matchComponentName)) {
200 continue;
201 }
202
Andreas Huberbe06d262009-08-14 14:37:10 -0700203 LOGV("Attempting to allocate OMX node '%s'", componentName);
204
205 status_t err = omx->allocate_node(componentName, &node);
206 if (err == OK) {
Andreas Huber53a76bd2009-10-06 16:20:44 -0700207 LOGV("Successfully allocated OMX node '%s'", componentName);
Andreas Huberbe06d262009-08-14 14:37:10 -0700208 break;
209 }
210 }
211
212 uint32_t quirks = 0;
213 if (!strcmp(componentName, "OMX.PV.avcdec")) {
Andreas Huber4f5e6022009-08-19 09:29:34 -0700214 quirks |= kWantsNALFragments;
Andreas Huberbe06d262009-08-14 14:37:10 -0700215 }
216 if (!strcmp(componentName, "OMX.TI.MP3.decode")) {
217 quirks |= kNeedsFlushBeforeDisable;
218 }
219 if (!strcmp(componentName, "OMX.TI.AAC.decode")) {
220 quirks |= kNeedsFlushBeforeDisable;
Andreas Huber404cc412009-08-25 14:26:05 -0700221 quirks |= kRequiresFlushCompleteEmulation;
Andreas Huberbe06d262009-08-14 14:37:10 -0700222 }
223 if (!strncmp(componentName, "OMX.qcom.video.encoder.", 23)) {
224 quirks |= kRequiresLoadedToIdleAfterAllocation;
225 quirks |= kRequiresAllocateBufferOnInputPorts;
226 }
Andreas Hubera7d0cf42009-09-04 07:48:51 -0700227 if (!strncmp(componentName, "OMX.qcom.video.decoder.", 23)) {
228 // XXX Required on P....on only.
Andreas Huber0446b822009-09-15 15:50:31 -0700229 quirks |= kRequiresAllocateBufferOnInputPorts;
Andreas Hubera7d0cf42009-09-04 07:48:51 -0700230 quirks |= kRequiresAllocateBufferOnOutputPorts;
231 }
Andreas Huberbe06d262009-08-14 14:37:10 -0700232
Andreas Huber2dc64d82009-09-11 12:58:53 -0700233 if (!strncmp(componentName, "OMX.TI.", 7)) {
234 // Apparently I must not use OMX_UseBuffer on either input or
235 // output ports on any of the TI components or quote:
236 // "(I) may have unexpected problem (sic) which can be timing related
237 // and hard to reproduce."
238
239 quirks |= kRequiresAllocateBufferOnInputPorts;
240 quirks |= kRequiresAllocateBufferOnOutputPorts;
241 }
242
Andreas Huberbe06d262009-08-14 14:37:10 -0700243 sp<OMXCodec> codec = new OMXCodec(
244 omx, node, quirks, createEncoder, mime, componentName,
245 source);
246
247 uint32_t type;
248 const void *data;
249 size_t size;
250 if (meta->findData(kKeyESDS, &type, &data, &size)) {
251 ESDS esds((const char *)data, size);
252 CHECK_EQ(esds.InitCheck(), OK);
253
254 const void *codec_specific_data;
255 size_t codec_specific_data_size;
256 esds.getCodecSpecificInfo(
257 &codec_specific_data, &codec_specific_data_size);
258
259 printf("found codec-specific data of size %d\n",
260 codec_specific_data_size);
261
262 codec->addCodecSpecificData(
263 codec_specific_data, codec_specific_data_size);
264 } else if (meta->findData(kKeyAVCC, &type, &data, &size)) {
265 printf("found avcc of size %d\n", size);
266
Andreas Huberebf66ea2009-08-19 13:32:58 -0700267 // Parse the AVCDecoderConfigurationRecord
268
269 const uint8_t *ptr = (const uint8_t *)data;
270
271 CHECK(size >= 7);
272 CHECK_EQ(ptr[0], 1); // configurationVersion == 1
273 uint8_t profile = ptr[1];
274 uint8_t level = ptr[3];
275
276 CHECK((ptr[4] >> 2) == 0x3f); // reserved
277
278 size_t lengthSize = 1 + (ptr[4] & 3);
279
280 // commented out check below as H264_QVGA_500_NO_AUDIO.3gp
281 // violates it...
282 // CHECK((ptr[5] >> 5) == 7); // reserved
283
284 size_t numSeqParameterSets = ptr[5] & 31;
285
286 ptr += 6;
Andreas Huberbe06d262009-08-14 14:37:10 -0700287 size -= 6;
Andreas Huberebf66ea2009-08-19 13:32:58 -0700288
289 for (size_t i = 0; i < numSeqParameterSets; ++i) {
290 CHECK(size >= 2);
291 size_t length = U16_AT(ptr);
Andreas Huberbe06d262009-08-14 14:37:10 -0700292
293 ptr += 2;
294 size -= 2;
295
Andreas Huberbe06d262009-08-14 14:37:10 -0700296 CHECK(size >= length);
297
298 codec->addCodecSpecificData(ptr, length);
299
300 ptr += length;
301 size -= length;
Andreas Huberebf66ea2009-08-19 13:32:58 -0700302 }
Andreas Huberbe06d262009-08-14 14:37:10 -0700303
Andreas Huberebf66ea2009-08-19 13:32:58 -0700304 CHECK(size >= 1);
305 size_t numPictureParameterSets = *ptr;
306 ++ptr;
307 --size;
Andreas Huberbe06d262009-08-14 14:37:10 -0700308
Andreas Huberebf66ea2009-08-19 13:32:58 -0700309 for (size_t i = 0; i < numPictureParameterSets; ++i) {
310 CHECK(size >= 2);
311 size_t length = U16_AT(ptr);
312
313 ptr += 2;
314 size -= 2;
315
316 CHECK(size >= length);
317
318 codec->addCodecSpecificData(ptr, length);
319
320 ptr += length;
321 size -= length;
322 }
323
Andreas Huber53a76bd2009-10-06 16:20:44 -0700324 LOGV("AVC profile = %d (%s), level = %d",
Andreas Huberebf66ea2009-08-19 13:32:58 -0700325 (int)profile, AVCProfileToString(profile), (int)level / 10);
326
Andreas Huber53a76bd2009-10-06 16:20:44 -0700327#if 0
Andreas Huberebf66ea2009-08-19 13:32:58 -0700328 if (!strcmp(componentName, "OMX.TI.Video.Decoder")
329 && (profile != kAVCProfileBaseline || level > 39)) {
330 // This stream exceeds the decoder's capabilities.
331
332 LOGE("Profile and/or level exceed the decoder's capabilities.");
333 return NULL;
Andreas Huberbe06d262009-08-14 14:37:10 -0700334 }
Andreas Huber53a76bd2009-10-06 16:20:44 -0700335#endif
Andreas Huberbe06d262009-08-14 14:37:10 -0700336 }
337
Andreas Hubere6c40962009-09-10 14:13:30 -0700338 if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime)) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700339 codec->setAMRFormat();
340 }
Andreas Hubere6c40962009-09-10 14:13:30 -0700341 if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) {
Andreas Huberee606e62009-09-08 10:19:21 -0700342 codec->setAMRWBFormat();
343 }
Andreas Hubere6c40962009-09-10 14:13:30 -0700344 if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) {
Andreas Huber43ad6eaf2009-09-01 16:02:43 -0700345 int32_t numChannels, sampleRate;
346 CHECK(meta->findInt32(kKeyChannelCount, &numChannels));
347 CHECK(meta->findInt32(kKeySampleRate, &sampleRate));
348
349 codec->setAACFormat(numChannels, sampleRate);
Andreas Huberbe06d262009-08-14 14:37:10 -0700350 }
351 if (!strncasecmp(mime, "video/", 6)) {
352 int32_t width, height;
353 bool success = meta->findInt32(kKeyWidth, &width);
354 success = success && meta->findInt32(kKeyHeight, &height);
Andreas Huber5c0a9132009-08-20 11:16:40 -0700355 CHECK(success);
Andreas Huberbe06d262009-08-14 14:37:10 -0700356
357 if (createEncoder) {
358 codec->setVideoInputFormat(mime, width, height);
359 } else {
360 codec->setVideoOutputFormat(mime, width, height);
361 }
362 }
Andreas Hubere6c40962009-09-10 14:13:30 -0700363 if (!strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_JPEG)
Andreas Huberbe06d262009-08-14 14:37:10 -0700364 && !strcmp(componentName, "OMX.TI.JPEG.decode")) {
365 OMX_COLOR_FORMATTYPE format =
366 OMX_COLOR_Format32bitARGB8888;
367 // OMX_COLOR_FormatYUV420PackedPlanar;
368 // OMX_COLOR_FormatCbYCrY;
369 // OMX_COLOR_FormatYUV411Planar;
370
371 int32_t width, height;
372 bool success = meta->findInt32(kKeyWidth, &width);
373 success = success && meta->findInt32(kKeyHeight, &height);
Andreas Huber5c0a9132009-08-20 11:16:40 -0700374
375 int32_t compressedSize;
376 success = success && meta->findInt32(
Andreas Huberda050cf22009-09-02 14:01:43 -0700377 kKeyMaxInputSize, &compressedSize);
Andreas Huber5c0a9132009-08-20 11:16:40 -0700378
379 CHECK(success);
380 CHECK(compressedSize > 0);
Andreas Huberbe06d262009-08-14 14:37:10 -0700381
382 codec->setImageOutputFormat(format, width, height);
Andreas Huber5c0a9132009-08-20 11:16:40 -0700383 codec->setJPEGInputFormat(width, height, (OMX_U32)compressedSize);
Andreas Huberbe06d262009-08-14 14:37:10 -0700384 }
385
Andreas Huberda050cf22009-09-02 14:01:43 -0700386 int32_t maxInputSize;
387 if (createEncoder && meta->findInt32(kKeyMaxInputSize, &maxInputSize)) {
388 codec->setMinBufferSize(kPortIndexInput, (OMX_U32)maxInputSize);
389 }
390
391 if (!strcmp(componentName, "OMX.TI.AMR.encode")
392 || !strcmp(componentName, "OMX.TI.WBAMR.encode")) {
393 codec->setMinBufferSize(kPortIndexOutput, 8192); // XXX
394 }
395
Andreas Huberbe06d262009-08-14 14:37:10 -0700396 codec->initOutputFormat(meta);
397
398 return codec;
399}
400
Andreas Huberda050cf22009-09-02 14:01:43 -0700401void OMXCodec::setMinBufferSize(OMX_U32 portIndex, OMX_U32 size) {
402 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -0700403 InitOMXParams(&def);
Andreas Huberda050cf22009-09-02 14:01:43 -0700404 def.nPortIndex = portIndex;
405
406 status_t err = mOMX->get_parameter(
407 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
408 CHECK_EQ(err, OK);
409
410 if (def.nBufferSize < size) {
411 def.nBufferSize = size;
412
413 }
414
415 err = mOMX->set_parameter(
416 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
417 CHECK_EQ(err, OK);
418}
419
Andreas Huberbe06d262009-08-14 14:37:10 -0700420status_t OMXCodec::setVideoPortFormatType(
421 OMX_U32 portIndex,
422 OMX_VIDEO_CODINGTYPE compressionFormat,
423 OMX_COLOR_FORMATTYPE colorFormat) {
424 OMX_VIDEO_PARAM_PORTFORMATTYPE format;
Andreas Huber4c483422009-09-02 16:05:36 -0700425 InitOMXParams(&format);
Andreas Huberbe06d262009-08-14 14:37:10 -0700426 format.nPortIndex = portIndex;
427 format.nIndex = 0;
428 bool found = false;
429
430 OMX_U32 index = 0;
431 for (;;) {
432 format.nIndex = index;
433 status_t err = mOMX->get_parameter(
434 mNode, OMX_IndexParamVideoPortFormat,
435 &format, sizeof(format));
436
437 if (err != OK) {
438 return err;
439 }
440
441 // The following assertion is violated by TI's video decoder.
Andreas Huber5c0a9132009-08-20 11:16:40 -0700442 // CHECK_EQ(format.nIndex, index);
Andreas Huberbe06d262009-08-14 14:37:10 -0700443
444#if 1
Andreas Huber53a76bd2009-10-06 16:20:44 -0700445 CODEC_LOGV("portIndex: %ld, index: %ld, eCompressionFormat=%d eColorFormat=%d",
Andreas Huberbe06d262009-08-14 14:37:10 -0700446 portIndex,
447 index, format.eCompressionFormat, format.eColorFormat);
448#endif
449
450 if (!strcmp("OMX.TI.Video.encoder", mComponentName)) {
451 if (portIndex == kPortIndexInput
452 && colorFormat == format.eColorFormat) {
453 // eCompressionFormat does not seem right.
454 found = true;
455 break;
456 }
457 if (portIndex == kPortIndexOutput
458 && compressionFormat == format.eCompressionFormat) {
459 // eColorFormat does not seem right.
460 found = true;
461 break;
462 }
463 }
464
465 if (format.eCompressionFormat == compressionFormat
466 && format.eColorFormat == colorFormat) {
467 found = true;
468 break;
469 }
470
471 ++index;
472 }
473
474 if (!found) {
475 return UNKNOWN_ERROR;
476 }
477
Andreas Huber53a76bd2009-10-06 16:20:44 -0700478 CODEC_LOGV("found a match.");
Andreas Huberbe06d262009-08-14 14:37:10 -0700479 status_t err = mOMX->set_parameter(
480 mNode, OMX_IndexParamVideoPortFormat,
481 &format, sizeof(format));
482
483 return err;
484}
485
486void OMXCodec::setVideoInputFormat(
487 const char *mime, OMX_U32 width, OMX_U32 height) {
Andreas Huber53a76bd2009-10-06 16:20:44 -0700488 CODEC_LOGV("setVideoInputFormat width=%ld, height=%ld", width, height);
Andreas Huberbe06d262009-08-14 14:37:10 -0700489
490 OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused;
Andreas Hubere6c40962009-09-10 14:13:30 -0700491 if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700492 compressionFormat = OMX_VIDEO_CodingAVC;
Andreas Hubere6c40962009-09-10 14:13:30 -0700493 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700494 compressionFormat = OMX_VIDEO_CodingMPEG4;
Andreas Hubere6c40962009-09-10 14:13:30 -0700495 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700496 compressionFormat = OMX_VIDEO_CodingH263;
497 } else {
498 LOGE("Not a supported video mime type: %s", mime);
499 CHECK(!"Should not be here. Not a supported video mime type.");
500 }
501
502 OMX_COLOR_FORMATTYPE colorFormat =
503 0 ? OMX_COLOR_FormatYCbYCr : OMX_COLOR_FormatCbYCrY;
504
505 if (!strncmp("OMX.qcom.video.encoder.", mComponentName, 23)) {
506 colorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
507 }
508
509 setVideoPortFormatType(
510 kPortIndexInput, OMX_VIDEO_CodingUnused,
511 colorFormat);
512
513 setVideoPortFormatType(
514 kPortIndexOutput, compressionFormat, OMX_COLOR_FormatUnused);
515
516 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -0700517 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -0700518 def.nPortIndex = kPortIndexOutput;
519
Andreas Huber4c483422009-09-02 16:05:36 -0700520 OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
521
Andreas Huberbe06d262009-08-14 14:37:10 -0700522 status_t err = mOMX->get_parameter(
523 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
524
525 CHECK_EQ(err, OK);
526 CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
527
528 video_def->nFrameWidth = width;
529 video_def->nFrameHeight = height;
530
531 video_def->eCompressionFormat = compressionFormat;
532 video_def->eColorFormat = OMX_COLOR_FormatUnused;
533
534 err = mOMX->set_parameter(
535 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
536 CHECK_EQ(err, OK);
537
538 ////////////////////////////////////////////////////////////////////////////
539
Andreas Huber4c483422009-09-02 16:05:36 -0700540 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -0700541 def.nPortIndex = kPortIndexInput;
542
543 err = mOMX->get_parameter(
544 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
545 CHECK_EQ(err, OK);
546
547 def.nBufferSize = (width * height * 2); // (width * height * 3) / 2;
Andreas Huber53a76bd2009-10-06 16:20:44 -0700548 CODEC_LOGV("Setting nBufferSize = %ld", def.nBufferSize);
Andreas Huberbe06d262009-08-14 14:37:10 -0700549
550 CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
551
552 video_def->nFrameWidth = width;
553 video_def->nFrameHeight = height;
554 video_def->eCompressionFormat = OMX_VIDEO_CodingUnused;
555 video_def->eColorFormat = colorFormat;
556
557 err = mOMX->set_parameter(
558 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
559 CHECK_EQ(err, OK);
560}
561
562void OMXCodec::setVideoOutputFormat(
563 const char *mime, OMX_U32 width, OMX_U32 height) {
Andreas Huber53a76bd2009-10-06 16:20:44 -0700564 CODEC_LOGV("setVideoOutputFormat width=%ld, height=%ld", width, height);
Andreas Huberbe06d262009-08-14 14:37:10 -0700565
Andreas Huberbe06d262009-08-14 14:37:10 -0700566 OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused;
Andreas Hubere6c40962009-09-10 14:13:30 -0700567 if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700568 compressionFormat = OMX_VIDEO_CodingAVC;
Andreas Hubere6c40962009-09-10 14:13:30 -0700569 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700570 compressionFormat = OMX_VIDEO_CodingMPEG4;
Andreas Hubere6c40962009-09-10 14:13:30 -0700571 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700572 compressionFormat = OMX_VIDEO_CodingH263;
573 } else {
574 LOGE("Not a supported video mime type: %s", mime);
575 CHECK(!"Should not be here. Not a supported video mime type.");
576 }
577
578 setVideoPortFormatType(
579 kPortIndexInput, compressionFormat, OMX_COLOR_FormatUnused);
580
581#if 1
582 {
583 OMX_VIDEO_PARAM_PORTFORMATTYPE format;
Andreas Huber4c483422009-09-02 16:05:36 -0700584 InitOMXParams(&format);
Andreas Huberbe06d262009-08-14 14:37:10 -0700585 format.nPortIndex = kPortIndexOutput;
586 format.nIndex = 0;
587
588 status_t err = mOMX->get_parameter(
589 mNode, OMX_IndexParamVideoPortFormat,
590 &format, sizeof(format));
591 CHECK_EQ(err, OK);
592 CHECK_EQ(format.eCompressionFormat, OMX_VIDEO_CodingUnused);
593
594 static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
595
596 CHECK(format.eColorFormat == OMX_COLOR_FormatYUV420Planar
597 || format.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar
598 || format.eColorFormat == OMX_COLOR_FormatCbYCrY
599 || format.eColorFormat == OMX_QCOM_COLOR_FormatYVU420SemiPlanar);
600
601 err = mOMX->set_parameter(
602 mNode, OMX_IndexParamVideoPortFormat,
603 &format, sizeof(format));
604 CHECK_EQ(err, OK);
605 }
606#endif
607
608 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -0700609 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -0700610 def.nPortIndex = kPortIndexInput;
611
Andreas Huber4c483422009-09-02 16:05:36 -0700612 OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
613
Andreas Huberbe06d262009-08-14 14:37:10 -0700614 status_t err = mOMX->get_parameter(
615 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
616
617 CHECK_EQ(err, OK);
618
619#if 1
620 // XXX Need a (much) better heuristic to compute input buffer sizes.
621 const size_t X = 64 * 1024;
622 if (def.nBufferSize < X) {
623 def.nBufferSize = X;
624 }
625#endif
626
627 CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
628
629 video_def->nFrameWidth = width;
630 video_def->nFrameHeight = height;
631
632 video_def->eColorFormat = OMX_COLOR_FormatUnused;
633
634 err = mOMX->set_parameter(
635 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
636 CHECK_EQ(err, OK);
637
638 ////////////////////////////////////////////////////////////////////////////
639
Andreas Huber4c483422009-09-02 16:05:36 -0700640 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -0700641 def.nPortIndex = kPortIndexOutput;
642
643 err = mOMX->get_parameter(
644 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
645 CHECK_EQ(err, OK);
646 CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
647
648#if 0
649 def.nBufferSize =
650 (((width + 15) & -16) * ((height + 15) & -16) * 3) / 2; // YUV420
651#endif
652
653 video_def->nFrameWidth = width;
654 video_def->nFrameHeight = height;
655
656 err = mOMX->set_parameter(
657 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
658 CHECK_EQ(err, OK);
659}
660
661
662OMXCodec::OMXCodec(
663 const sp<IOMX> &omx, IOMX::node_id node, uint32_t quirks,
Andreas Huberebf66ea2009-08-19 13:32:58 -0700664 bool isEncoder,
Andreas Huberbe06d262009-08-14 14:37:10 -0700665 const char *mime,
666 const char *componentName,
667 const sp<MediaSource> &source)
668 : mOMX(omx),
669 mNode(node),
670 mQuirks(quirks),
671 mIsEncoder(isEncoder),
672 mMIME(strdup(mime)),
673 mComponentName(strdup(componentName)),
674 mSource(source),
675 mCodecSpecificDataIndex(0),
Andreas Huberbe06d262009-08-14 14:37:10 -0700676 mState(LOADED),
Andreas Huber42978e52009-08-27 10:08:39 -0700677 mInitialBufferSubmit(true),
Andreas Huberbe06d262009-08-14 14:37:10 -0700678 mSignalledEOS(false),
679 mNoMoreOutputData(false),
Andreas Hubercfd55572009-10-09 14:11:28 -0700680 mOutputPortSettingsHaveChanged(false),
Andreas Huberbe06d262009-08-14 14:37:10 -0700681 mSeekTimeUs(-1) {
682 mPortStatus[kPortIndexInput] = ENABLED;
683 mPortStatus[kPortIndexOutput] = ENABLED;
684
685 mObserver = new OMXCodecObserver(this);
686 mOMX->observe_node(mNode, mObserver);
Andreas Huber4c483422009-09-02 16:05:36 -0700687
688 setComponentRole();
689}
690
Andreas Hubere6c40962009-09-10 14:13:30 -0700691// static
692void OMXCodec::setComponentRole(
693 const sp<IOMX> &omx, IOMX::node_id node, bool isEncoder,
694 const char *mime) {
Andreas Huber4c483422009-09-02 16:05:36 -0700695 struct MimeToRole {
696 const char *mime;
697 const char *decoderRole;
698 const char *encoderRole;
699 };
700
701 static const MimeToRole kMimeToRole[] = {
Andreas Hubere6c40962009-09-10 14:13:30 -0700702 { MEDIA_MIMETYPE_AUDIO_MPEG,
703 "audio_decoder.mp3", "audio_encoder.mp3" },
704 { MEDIA_MIMETYPE_AUDIO_AMR_NB,
705 "audio_decoder.amrnb", "audio_encoder.amrnb" },
706 { MEDIA_MIMETYPE_AUDIO_AMR_WB,
707 "audio_decoder.amrwb", "audio_encoder.amrwb" },
708 { MEDIA_MIMETYPE_AUDIO_AAC,
709 "audio_decoder.aac", "audio_encoder.aac" },
710 { MEDIA_MIMETYPE_VIDEO_AVC,
711 "video_decoder.avc", "video_encoder.avc" },
712 { MEDIA_MIMETYPE_VIDEO_MPEG4,
713 "video_decoder.mpeg4", "video_encoder.mpeg4" },
714 { MEDIA_MIMETYPE_VIDEO_H263,
715 "video_decoder.h263", "video_encoder.h263" },
Andreas Huber4c483422009-09-02 16:05:36 -0700716 };
717
718 static const size_t kNumMimeToRole =
719 sizeof(kMimeToRole) / sizeof(kMimeToRole[0]);
720
721 size_t i;
722 for (i = 0; i < kNumMimeToRole; ++i) {
Andreas Hubere6c40962009-09-10 14:13:30 -0700723 if (!strcasecmp(mime, kMimeToRole[i].mime)) {
Andreas Huber4c483422009-09-02 16:05:36 -0700724 break;
725 }
726 }
727
728 if (i == kNumMimeToRole) {
729 return;
730 }
731
732 const char *role =
Andreas Hubere6c40962009-09-10 14:13:30 -0700733 isEncoder ? kMimeToRole[i].encoderRole
734 : kMimeToRole[i].decoderRole;
Andreas Huber4c483422009-09-02 16:05:36 -0700735
736 if (role != NULL) {
Andreas Huber4c483422009-09-02 16:05:36 -0700737 OMX_PARAM_COMPONENTROLETYPE roleParams;
738 InitOMXParams(&roleParams);
739
740 strncpy((char *)roleParams.cRole,
741 role, OMX_MAX_STRINGNAME_SIZE - 1);
742
743 roleParams.cRole[OMX_MAX_STRINGNAME_SIZE - 1] = '\0';
744
Andreas Hubere6c40962009-09-10 14:13:30 -0700745 status_t err = omx->set_parameter(
746 node, OMX_IndexParamStandardComponentRole,
Andreas Huber4c483422009-09-02 16:05:36 -0700747 &roleParams, sizeof(roleParams));
748
749 if (err != OK) {
750 LOGW("Failed to set standard component role '%s'.", role);
751 }
752 }
Andreas Huberbe06d262009-08-14 14:37:10 -0700753}
754
Andreas Hubere6c40962009-09-10 14:13:30 -0700755void OMXCodec::setComponentRole() {
756 setComponentRole(mOMX, mNode, mIsEncoder, mMIME);
757}
758
Andreas Huberbe06d262009-08-14 14:37:10 -0700759OMXCodec::~OMXCodec() {
Andreas Huber4f5e6022009-08-19 09:29:34 -0700760 CHECK(mState == LOADED || mState == ERROR);
Andreas Huberbe06d262009-08-14 14:37:10 -0700761
762 status_t err = mOMX->observe_node(mNode, NULL);
763 CHECK_EQ(err, OK);
764
765 err = mOMX->free_node(mNode);
766 CHECK_EQ(err, OK);
767
768 mNode = NULL;
769 setState(DEAD);
770
771 clearCodecSpecificData();
772
773 free(mComponentName);
774 mComponentName = NULL;
Andreas Huberebf66ea2009-08-19 13:32:58 -0700775
Andreas Huberbe06d262009-08-14 14:37:10 -0700776 free(mMIME);
777 mMIME = NULL;
778}
779
780status_t OMXCodec::init() {
Andreas Huber42978e52009-08-27 10:08:39 -0700781 // mLock is held.
Andreas Huberbe06d262009-08-14 14:37:10 -0700782
783 CHECK_EQ(mState, LOADED);
784
785 status_t err;
786 if (!(mQuirks & kRequiresLoadedToIdleAfterAllocation)) {
787 err = mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
788 CHECK_EQ(err, OK);
Andreas Huberbe06d262009-08-14 14:37:10 -0700789 setState(LOADED_TO_IDLE);
790 }
791
792 err = allocateBuffers();
793 CHECK_EQ(err, OK);
794
795 if (mQuirks & kRequiresLoadedToIdleAfterAllocation) {
796 err = mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
797 CHECK_EQ(err, OK);
798
799 setState(LOADED_TO_IDLE);
800 }
801
802 while (mState != EXECUTING && mState != ERROR) {
803 mAsyncCompletion.wait(mLock);
804 }
805
806 return mState == ERROR ? UNKNOWN_ERROR : OK;
807}
808
809// static
810bool OMXCodec::isIntermediateState(State state) {
811 return state == LOADED_TO_IDLE
812 || state == IDLE_TO_EXECUTING
813 || state == EXECUTING_TO_IDLE
814 || state == IDLE_TO_LOADED
815 || state == RECONFIGURING;
816}
817
818status_t OMXCodec::allocateBuffers() {
819 status_t err = allocateBuffersOnPort(kPortIndexInput);
820
821 if (err != OK) {
822 return err;
823 }
824
825 return allocateBuffersOnPort(kPortIndexOutput);
826}
827
828status_t OMXCodec::allocateBuffersOnPort(OMX_U32 portIndex) {
829 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -0700830 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -0700831 def.nPortIndex = portIndex;
832
833 status_t err = mOMX->get_parameter(
834 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
835
836 if (err != OK) {
837 return err;
838 }
839
Andreas Huber5c0a9132009-08-20 11:16:40 -0700840 size_t totalSize = def.nBufferCountActual * def.nBufferSize;
841 mDealer[portIndex] = new MemoryDealer(totalSize);
842
Andreas Huberbe06d262009-08-14 14:37:10 -0700843 for (OMX_U32 i = 0; i < def.nBufferCountActual; ++i) {
Andreas Huber5c0a9132009-08-20 11:16:40 -0700844 sp<IMemory> mem = mDealer[portIndex]->allocate(def.nBufferSize);
Andreas Huberbe06d262009-08-14 14:37:10 -0700845 CHECK(mem.get() != NULL);
846
847 IOMX::buffer_id buffer;
848 if (portIndex == kPortIndexInput
849 && (mQuirks & kRequiresAllocateBufferOnInputPorts)) {
850 err = mOMX->allocate_buffer_with_backup(
851 mNode, portIndex, mem, &buffer);
Andreas Huber446f44f2009-08-25 17:23:44 -0700852 } else if (portIndex == kPortIndexOutput
853 && (mQuirks & kRequiresAllocateBufferOnOutputPorts)) {
Andreas Huber2dc64d82009-09-11 12:58:53 -0700854 err = mOMX->allocate_buffer_with_backup(
855 mNode, portIndex, mem, &buffer);
Andreas Huberbe06d262009-08-14 14:37:10 -0700856 } else {
857 err = mOMX->use_buffer(mNode, portIndex, mem, &buffer);
858 }
859
860 if (err != OK) {
861 LOGE("allocate_buffer_with_backup failed");
862 return err;
863 }
864
865 BufferInfo info;
866 info.mBuffer = buffer;
867 info.mOwnedByComponent = false;
868 info.mMem = mem;
869 info.mMediaBuffer = NULL;
870
871 if (portIndex == kPortIndexOutput) {
872 info.mMediaBuffer = new MediaBuffer(mem->pointer(), mem->size());
873 info.mMediaBuffer->setObserver(this);
874 }
875
876 mPortBuffers[portIndex].push(info);
877
Andreas Huber4c483422009-09-02 16:05:36 -0700878 CODEC_LOGV("allocated buffer %p on %s port", buffer,
Andreas Huberbe06d262009-08-14 14:37:10 -0700879 portIndex == kPortIndexInput ? "input" : "output");
880 }
881
882 dumpPortStatus(portIndex);
883
884 return OK;
885}
886
887void OMXCodec::on_message(const omx_message &msg) {
888 Mutex::Autolock autoLock(mLock);
889
890 switch (msg.type) {
891 case omx_message::EVENT:
892 {
893 onEvent(
894 msg.u.event_data.event, msg.u.event_data.data1,
895 msg.u.event_data.data2);
896
897 break;
898 }
899
900 case omx_message::EMPTY_BUFFER_DONE:
901 {
902 IOMX::buffer_id buffer = msg.u.extended_buffer_data.buffer;
903
Andreas Huber4c483422009-09-02 16:05:36 -0700904 CODEC_LOGV("EMPTY_BUFFER_DONE(buffer: %p)", buffer);
Andreas Huberbe06d262009-08-14 14:37:10 -0700905
906 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
907 size_t i = 0;
908 while (i < buffers->size() && (*buffers)[i].mBuffer != buffer) {
909 ++i;
910 }
911
912 CHECK(i < buffers->size());
913 if (!(*buffers)[i].mOwnedByComponent) {
914 LOGW("We already own input buffer %p, yet received "
915 "an EMPTY_BUFFER_DONE.", buffer);
916 }
917
918 buffers->editItemAt(i).mOwnedByComponent = false;
919
920 if (mPortStatus[kPortIndexInput] == DISABLING) {
Andreas Huber4c483422009-09-02 16:05:36 -0700921 CODEC_LOGV("Port is disabled, freeing buffer %p", buffer);
Andreas Huberbe06d262009-08-14 14:37:10 -0700922
923 status_t err =
924 mOMX->free_buffer(mNode, kPortIndexInput, buffer);
925 CHECK_EQ(err, OK);
926
927 buffers->removeAt(i);
928 } else if (mPortStatus[kPortIndexInput] != SHUTTING_DOWN) {
929 CHECK_EQ(mPortStatus[kPortIndexInput], ENABLED);
930 drainInputBuffer(&buffers->editItemAt(i));
931 }
932
933 break;
934 }
935
936 case omx_message::FILL_BUFFER_DONE:
937 {
938 IOMX::buffer_id buffer = msg.u.extended_buffer_data.buffer;
939 OMX_U32 flags = msg.u.extended_buffer_data.flags;
940
Andreas Huber4c483422009-09-02 16:05:36 -0700941 CODEC_LOGV("FILL_BUFFER_DONE(buffer: %p, size: %ld, flags: 0x%08lx)",
Andreas Huberbe06d262009-08-14 14:37:10 -0700942 buffer,
943 msg.u.extended_buffer_data.range_length,
944 flags);
945
Andreas Huber4c483422009-09-02 16:05:36 -0700946 CODEC_LOGV("FILL_BUFFER_DONE(timestamp: %lld us (%.2f secs))",
Andreas Huberbe06d262009-08-14 14:37:10 -0700947 msg.u.extended_buffer_data.timestamp,
948 msg.u.extended_buffer_data.timestamp / 1E6);
949
950 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
951 size_t i = 0;
952 while (i < buffers->size() && (*buffers)[i].mBuffer != buffer) {
953 ++i;
954 }
955
956 CHECK(i < buffers->size());
957 BufferInfo *info = &buffers->editItemAt(i);
958
959 if (!info->mOwnedByComponent) {
960 LOGW("We already own output buffer %p, yet received "
961 "a FILL_BUFFER_DONE.", buffer);
962 }
963
964 info->mOwnedByComponent = false;
965
966 if (mPortStatus[kPortIndexOutput] == DISABLING) {
Andreas Huber4c483422009-09-02 16:05:36 -0700967 CODEC_LOGV("Port is disabled, freeing buffer %p", buffer);
Andreas Huberbe06d262009-08-14 14:37:10 -0700968
969 status_t err =
970 mOMX->free_buffer(mNode, kPortIndexOutput, buffer);
971 CHECK_EQ(err, OK);
972
973 buffers->removeAt(i);
Andreas Huberd7795892009-08-26 10:33:47 -0700974 } else if (mPortStatus[kPortIndexOutput] == ENABLED
975 && (flags & OMX_BUFFERFLAG_EOS)) {
Andreas Huber4c483422009-09-02 16:05:36 -0700976 CODEC_LOGV("No more output data.");
Andreas Huberbe06d262009-08-14 14:37:10 -0700977 mNoMoreOutputData = true;
978 mBufferFilled.signal();
979 } else if (mPortStatus[kPortIndexOutput] != SHUTTING_DOWN) {
980 CHECK_EQ(mPortStatus[kPortIndexOutput], ENABLED);
Andreas Huberebf66ea2009-08-19 13:32:58 -0700981
Andreas Huberbe06d262009-08-14 14:37:10 -0700982 MediaBuffer *buffer = info->mMediaBuffer;
983
984 buffer->set_range(
985 msg.u.extended_buffer_data.range_offset,
986 msg.u.extended_buffer_data.range_length);
987
988 buffer->meta_data()->clear();
989
Andreas Huberfa8de752009-10-08 10:07:49 -0700990 buffer->meta_data()->setInt64(
991 kKeyTime, msg.u.extended_buffer_data.timestamp);
Andreas Huberbe06d262009-08-14 14:37:10 -0700992
993 if (msg.u.extended_buffer_data.flags & OMX_BUFFERFLAG_SYNCFRAME) {
994 buffer->meta_data()->setInt32(kKeyIsSyncFrame, true);
995 }
996
997 buffer->meta_data()->setPointer(
998 kKeyPlatformPrivate,
999 msg.u.extended_buffer_data.platform_private);
1000
1001 buffer->meta_data()->setPointer(
1002 kKeyBufferID,
1003 msg.u.extended_buffer_data.buffer);
1004
1005 mFilledBuffers.push_back(i);
1006 mBufferFilled.signal();
1007 }
1008
1009 break;
1010 }
1011
1012 default:
1013 {
1014 CHECK(!"should not be here.");
1015 break;
1016 }
1017 }
1018}
1019
1020void OMXCodec::onEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) {
1021 switch (event) {
1022 case OMX_EventCmdComplete:
1023 {
1024 onCmdComplete((OMX_COMMANDTYPE)data1, data2);
1025 break;
1026 }
1027
1028 case OMX_EventError:
1029 {
1030 LOGE("ERROR(%ld, %ld)", data1, data2);
1031
1032 setState(ERROR);
1033 break;
1034 }
1035
1036 case OMX_EventPortSettingsChanged:
1037 {
1038 onPortSettingsChanged(data1);
1039 break;
1040 }
1041
1042 case OMX_EventBufferFlag:
1043 {
Andreas Huber4c483422009-09-02 16:05:36 -07001044 CODEC_LOGV("EVENT_BUFFER_FLAG(%ld)", data1);
Andreas Huberbe06d262009-08-14 14:37:10 -07001045
1046 if (data1 == kPortIndexOutput) {
1047 mNoMoreOutputData = true;
1048 }
1049 break;
1050 }
1051
1052 default:
1053 {
Andreas Huber4c483422009-09-02 16:05:36 -07001054 CODEC_LOGV("EVENT(%d, %ld, %ld)", event, data1, data2);
Andreas Huberbe06d262009-08-14 14:37:10 -07001055 break;
1056 }
1057 }
1058}
1059
1060void OMXCodec::onCmdComplete(OMX_COMMANDTYPE cmd, OMX_U32 data) {
1061 switch (cmd) {
1062 case OMX_CommandStateSet:
1063 {
1064 onStateChange((OMX_STATETYPE)data);
1065 break;
1066 }
1067
1068 case OMX_CommandPortDisable:
1069 {
1070 OMX_U32 portIndex = data;
Andreas Huber4c483422009-09-02 16:05:36 -07001071 CODEC_LOGV("PORT_DISABLED(%ld)", portIndex);
Andreas Huberbe06d262009-08-14 14:37:10 -07001072
1073 CHECK(mState == EXECUTING || mState == RECONFIGURING);
1074 CHECK_EQ(mPortStatus[portIndex], DISABLING);
1075 CHECK_EQ(mPortBuffers[portIndex].size(), 0);
1076
1077 mPortStatus[portIndex] = DISABLED;
1078
1079 if (mState == RECONFIGURING) {
1080 CHECK_EQ(portIndex, kPortIndexOutput);
1081
Andreas Hubercfd55572009-10-09 14:11:28 -07001082 initOutputFormat(mSource->getFormat());
1083 mOutputPortSettingsHaveChanged = true;
1084
Andreas Huberbe06d262009-08-14 14:37:10 -07001085 enablePortAsync(portIndex);
1086
1087 status_t err = allocateBuffersOnPort(portIndex);
1088 CHECK_EQ(err, OK);
1089 }
1090 break;
1091 }
1092
1093 case OMX_CommandPortEnable:
1094 {
1095 OMX_U32 portIndex = data;
Andreas Huber4c483422009-09-02 16:05:36 -07001096 CODEC_LOGV("PORT_ENABLED(%ld)", portIndex);
Andreas Huberbe06d262009-08-14 14:37:10 -07001097
1098 CHECK(mState == EXECUTING || mState == RECONFIGURING);
1099 CHECK_EQ(mPortStatus[portIndex], ENABLING);
1100
1101 mPortStatus[portIndex] = ENABLED;
1102
1103 if (mState == RECONFIGURING) {
1104 CHECK_EQ(portIndex, kPortIndexOutput);
1105
1106 setState(EXECUTING);
1107
1108 fillOutputBuffers();
1109 }
1110 break;
1111 }
1112
1113 case OMX_CommandFlush:
1114 {
1115 OMX_U32 portIndex = data;
1116
Andreas Huber4c483422009-09-02 16:05:36 -07001117 CODEC_LOGV("FLUSH_DONE(%ld)", portIndex);
Andreas Huberbe06d262009-08-14 14:37:10 -07001118
1119 CHECK_EQ(mPortStatus[portIndex], SHUTTING_DOWN);
1120 mPortStatus[portIndex] = ENABLED;
1121
1122 CHECK_EQ(countBuffersWeOwn(mPortBuffers[portIndex]),
1123 mPortBuffers[portIndex].size());
1124
1125 if (mState == RECONFIGURING) {
1126 CHECK_EQ(portIndex, kPortIndexOutput);
1127
1128 disablePortAsync(portIndex);
Andreas Huber127fcdc2009-08-26 16:27:02 -07001129 } else if (mState == EXECUTING_TO_IDLE) {
1130 if (mPortStatus[kPortIndexInput] == ENABLED
1131 && mPortStatus[kPortIndexOutput] == ENABLED) {
Andreas Huber4c483422009-09-02 16:05:36 -07001132 CODEC_LOGV("Finished flushing both ports, now completing "
Andreas Huber127fcdc2009-08-26 16:27:02 -07001133 "transition from EXECUTING to IDLE.");
1134
1135 mPortStatus[kPortIndexInput] = SHUTTING_DOWN;
1136 mPortStatus[kPortIndexOutput] = SHUTTING_DOWN;
1137
1138 status_t err =
1139 mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
1140 CHECK_EQ(err, OK);
1141 }
Andreas Huberbe06d262009-08-14 14:37:10 -07001142 } else {
1143 // We're flushing both ports in preparation for seeking.
1144
1145 if (mPortStatus[kPortIndexInput] == ENABLED
1146 && mPortStatus[kPortIndexOutput] == ENABLED) {
Andreas Huber4c483422009-09-02 16:05:36 -07001147 CODEC_LOGV("Finished flushing both ports, now continuing from"
Andreas Huberbe06d262009-08-14 14:37:10 -07001148 " seek-time.");
1149
Andreas Huber1a77b68e2009-09-17 11:16:52 -07001150 // Clear this flag in case the decoder sent us either
1151 // the EVENT_BUFFER_FLAG(1) or an output buffer with
1152 // the EOS flag set _while_ flushing. Since we're going
1153 // to submit "fresh" input data now, this flag no longer
1154 // applies to our future.
1155 mNoMoreOutputData = false;
1156
Andreas Huberbe06d262009-08-14 14:37:10 -07001157 drainInputBuffers();
1158 fillOutputBuffers();
1159 }
1160 }
1161
1162 break;
1163 }
1164
1165 default:
1166 {
Andreas Huber4c483422009-09-02 16:05:36 -07001167 CODEC_LOGV("CMD_COMPLETE(%d, %ld)", cmd, data);
Andreas Huberbe06d262009-08-14 14:37:10 -07001168 break;
1169 }
1170 }
1171}
1172
1173void OMXCodec::onStateChange(OMX_STATETYPE newState) {
1174 switch (newState) {
1175 case OMX_StateIdle:
1176 {
Andreas Huber4c483422009-09-02 16:05:36 -07001177 CODEC_LOGV("Now Idle.");
Andreas Huberbe06d262009-08-14 14:37:10 -07001178 if (mState == LOADED_TO_IDLE) {
1179 status_t err = mOMX->send_command(
1180 mNode, OMX_CommandStateSet, OMX_StateExecuting);
1181
1182 CHECK_EQ(err, OK);
1183
1184 setState(IDLE_TO_EXECUTING);
1185 } else {
1186 CHECK_EQ(mState, EXECUTING_TO_IDLE);
1187
1188 CHECK_EQ(
1189 countBuffersWeOwn(mPortBuffers[kPortIndexInput]),
1190 mPortBuffers[kPortIndexInput].size());
1191
1192 CHECK_EQ(
1193 countBuffersWeOwn(mPortBuffers[kPortIndexOutput]),
1194 mPortBuffers[kPortIndexOutput].size());
1195
1196 status_t err = mOMX->send_command(
1197 mNode, OMX_CommandStateSet, OMX_StateLoaded);
1198
1199 CHECK_EQ(err, OK);
1200
1201 err = freeBuffersOnPort(kPortIndexInput);
1202 CHECK_EQ(err, OK);
1203
1204 err = freeBuffersOnPort(kPortIndexOutput);
1205 CHECK_EQ(err, OK);
1206
1207 mPortStatus[kPortIndexInput] = ENABLED;
1208 mPortStatus[kPortIndexOutput] = ENABLED;
1209
1210 setState(IDLE_TO_LOADED);
1211 }
1212 break;
1213 }
1214
1215 case OMX_StateExecuting:
1216 {
1217 CHECK_EQ(mState, IDLE_TO_EXECUTING);
1218
Andreas Huber4c483422009-09-02 16:05:36 -07001219 CODEC_LOGV("Now Executing.");
Andreas Huberbe06d262009-08-14 14:37:10 -07001220
1221 setState(EXECUTING);
1222
Andreas Huber42978e52009-08-27 10:08:39 -07001223 // Buffers will be submitted to the component in the first
1224 // call to OMXCodec::read as mInitialBufferSubmit is true at
1225 // this point. This ensures that this on_message call returns,
1226 // releases the lock and ::init can notice the state change and
1227 // itself return.
Andreas Huberbe06d262009-08-14 14:37:10 -07001228 break;
1229 }
1230
1231 case OMX_StateLoaded:
1232 {
1233 CHECK_EQ(mState, IDLE_TO_LOADED);
1234
Andreas Huber4c483422009-09-02 16:05:36 -07001235 CODEC_LOGV("Now Loaded.");
Andreas Huberbe06d262009-08-14 14:37:10 -07001236
1237 setState(LOADED);
1238 break;
1239 }
1240
1241 default:
1242 {
1243 CHECK(!"should not be here.");
1244 break;
1245 }
1246 }
1247}
1248
1249// static
1250size_t OMXCodec::countBuffersWeOwn(const Vector<BufferInfo> &buffers) {
1251 size_t n = 0;
1252 for (size_t i = 0; i < buffers.size(); ++i) {
1253 if (!buffers[i].mOwnedByComponent) {
1254 ++n;
1255 }
1256 }
1257
1258 return n;
1259}
1260
1261status_t OMXCodec::freeBuffersOnPort(
1262 OMX_U32 portIndex, bool onlyThoseWeOwn) {
1263 Vector<BufferInfo> *buffers = &mPortBuffers[portIndex];
1264
1265 status_t stickyErr = OK;
1266
1267 for (size_t i = buffers->size(); i-- > 0;) {
1268 BufferInfo *info = &buffers->editItemAt(i);
1269
1270 if (onlyThoseWeOwn && info->mOwnedByComponent) {
1271 continue;
1272 }
1273
1274 CHECK_EQ(info->mOwnedByComponent, false);
1275
Andreas Huber92022852009-09-14 15:24:14 -07001276 CODEC_LOGV("freeing buffer %p on port %ld", info->mBuffer, portIndex);
1277
Andreas Huberbe06d262009-08-14 14:37:10 -07001278 status_t err =
1279 mOMX->free_buffer(mNode, portIndex, info->mBuffer);
1280
1281 if (err != OK) {
1282 stickyErr = err;
1283 }
1284
1285 if (info->mMediaBuffer != NULL) {
1286 info->mMediaBuffer->setObserver(NULL);
1287
1288 // Make sure nobody but us owns this buffer at this point.
1289 CHECK_EQ(info->mMediaBuffer->refcount(), 0);
1290
1291 info->mMediaBuffer->release();
1292 }
1293
1294 buffers->removeAt(i);
1295 }
1296
1297 CHECK(onlyThoseWeOwn || buffers->isEmpty());
1298
1299 return stickyErr;
1300}
1301
1302void OMXCodec::onPortSettingsChanged(OMX_U32 portIndex) {
Andreas Huber4c483422009-09-02 16:05:36 -07001303 CODEC_LOGV("PORT_SETTINGS_CHANGED(%ld)", portIndex);
Andreas Huberbe06d262009-08-14 14:37:10 -07001304
1305 CHECK_EQ(mState, EXECUTING);
1306 CHECK_EQ(portIndex, kPortIndexOutput);
1307 setState(RECONFIGURING);
1308
1309 if (mQuirks & kNeedsFlushBeforeDisable) {
Andreas Huber404cc412009-08-25 14:26:05 -07001310 if (!flushPortAsync(portIndex)) {
1311 onCmdComplete(OMX_CommandFlush, portIndex);
1312 }
Andreas Huberbe06d262009-08-14 14:37:10 -07001313 } else {
1314 disablePortAsync(portIndex);
1315 }
1316}
1317
Andreas Huber404cc412009-08-25 14:26:05 -07001318bool OMXCodec::flushPortAsync(OMX_U32 portIndex) {
Andreas Huber127fcdc2009-08-26 16:27:02 -07001319 CHECK(mState == EXECUTING || mState == RECONFIGURING
1320 || mState == EXECUTING_TO_IDLE);
Andreas Huberbe06d262009-08-14 14:37:10 -07001321
Andreas Huber4c483422009-09-02 16:05:36 -07001322 CODEC_LOGV("flushPortAsync(%ld): we own %d out of %d buffers already.",
Andreas Huber404cc412009-08-25 14:26:05 -07001323 portIndex, countBuffersWeOwn(mPortBuffers[portIndex]),
1324 mPortBuffers[portIndex].size());
1325
Andreas Huberbe06d262009-08-14 14:37:10 -07001326 CHECK_EQ(mPortStatus[portIndex], ENABLED);
1327 mPortStatus[portIndex] = SHUTTING_DOWN;
1328
Andreas Huber404cc412009-08-25 14:26:05 -07001329 if ((mQuirks & kRequiresFlushCompleteEmulation)
1330 && countBuffersWeOwn(mPortBuffers[portIndex])
1331 == mPortBuffers[portIndex].size()) {
1332 // No flush is necessary and this component fails to send a
1333 // flush-complete event in this case.
1334
1335 return false;
1336 }
1337
Andreas Huberbe06d262009-08-14 14:37:10 -07001338 status_t err =
1339 mOMX->send_command(mNode, OMX_CommandFlush, portIndex);
1340 CHECK_EQ(err, OK);
Andreas Huber404cc412009-08-25 14:26:05 -07001341
1342 return true;
Andreas Huberbe06d262009-08-14 14:37:10 -07001343}
1344
1345void OMXCodec::disablePortAsync(OMX_U32 portIndex) {
1346 CHECK(mState == EXECUTING || mState == RECONFIGURING);
1347
1348 CHECK_EQ(mPortStatus[portIndex], ENABLED);
1349 mPortStatus[portIndex] = DISABLING;
1350
1351 status_t err =
1352 mOMX->send_command(mNode, OMX_CommandPortDisable, portIndex);
1353 CHECK_EQ(err, OK);
1354
1355 freeBuffersOnPort(portIndex, true);
1356}
1357
1358void OMXCodec::enablePortAsync(OMX_U32 portIndex) {
1359 CHECK(mState == EXECUTING || mState == RECONFIGURING);
1360
1361 CHECK_EQ(mPortStatus[portIndex], DISABLED);
1362 mPortStatus[portIndex] = ENABLING;
1363
1364 status_t err =
1365 mOMX->send_command(mNode, OMX_CommandPortEnable, portIndex);
1366 CHECK_EQ(err, OK);
1367}
1368
1369void OMXCodec::fillOutputBuffers() {
1370 CHECK_EQ(mState, EXECUTING);
1371
1372 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
1373 for (size_t i = 0; i < buffers->size(); ++i) {
1374 fillOutputBuffer(&buffers->editItemAt(i));
1375 }
1376}
1377
1378void OMXCodec::drainInputBuffers() {
Andreas Huberd06e5b82009-08-28 13:18:14 -07001379 CHECK(mState == EXECUTING || mState == RECONFIGURING);
Andreas Huberbe06d262009-08-14 14:37:10 -07001380
1381 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
1382 for (size_t i = 0; i < buffers->size(); ++i) {
1383 drainInputBuffer(&buffers->editItemAt(i));
1384 }
1385}
1386
1387void OMXCodec::drainInputBuffer(BufferInfo *info) {
1388 CHECK_EQ(info->mOwnedByComponent, false);
1389
1390 if (mSignalledEOS) {
1391 return;
1392 }
1393
1394 if (mCodecSpecificDataIndex < mCodecSpecificData.size()) {
1395 const CodecSpecificData *specific =
1396 mCodecSpecificData[mCodecSpecificDataIndex];
1397
1398 size_t size = specific->mSize;
1399
Andreas Hubere6c40962009-09-10 14:13:30 -07001400 if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mMIME)
Andreas Huber4f5e6022009-08-19 09:29:34 -07001401 && !(mQuirks & kWantsNALFragments)) {
Andreas Huberbe06d262009-08-14 14:37:10 -07001402 static const uint8_t kNALStartCode[4] =
1403 { 0x00, 0x00, 0x00, 0x01 };
1404
1405 CHECK(info->mMem->size() >= specific->mSize + 4);
1406
1407 size += 4;
1408
1409 memcpy(info->mMem->pointer(), kNALStartCode, 4);
1410 memcpy((uint8_t *)info->mMem->pointer() + 4,
1411 specific->mData, specific->mSize);
1412 } else {
1413 CHECK(info->mMem->size() >= specific->mSize);
1414 memcpy(info->mMem->pointer(), specific->mData, specific->mSize);
1415 }
1416
Andreas Huber3f427072009-10-08 11:02:27 -07001417 status_t err = mOMX->empty_buffer(
Andreas Huberbe06d262009-08-14 14:37:10 -07001418 mNode, info->mBuffer, 0, size,
1419 OMX_BUFFERFLAG_ENDOFFRAME | OMX_BUFFERFLAG_CODECCONFIG,
1420 0);
Andreas Huber3f427072009-10-08 11:02:27 -07001421 CHECK_EQ(err, OK);
Andreas Huberbe06d262009-08-14 14:37:10 -07001422
1423 info->mOwnedByComponent = true;
1424
1425 ++mCodecSpecificDataIndex;
1426 return;
1427 }
1428
1429 MediaBuffer *srcBuffer;
1430 status_t err;
1431 if (mSeekTimeUs >= 0) {
1432 MediaSource::ReadOptions options;
1433 options.setSeekTo(mSeekTimeUs);
1434 mSeekTimeUs = -1;
1435
1436 err = mSource->read(&srcBuffer, &options);
1437 } else {
1438 err = mSource->read(&srcBuffer);
1439 }
1440
1441 OMX_U32 flags = OMX_BUFFERFLAG_ENDOFFRAME;
Andreas Huberfa8de752009-10-08 10:07:49 -07001442 OMX_TICKS timestampUs = 0;
Andreas Huberbe06d262009-08-14 14:37:10 -07001443 size_t srcLength = 0;
1444
1445 if (err != OK) {
Andreas Huber4c483422009-09-02 16:05:36 -07001446 CODEC_LOGV("signalling end of input stream.");
Andreas Huberbe06d262009-08-14 14:37:10 -07001447 flags |= OMX_BUFFERFLAG_EOS;
1448
1449 mSignalledEOS = true;
1450 } else {
1451 srcLength = srcBuffer->range_length();
1452
1453 if (info->mMem->size() < srcLength) {
1454 LOGE("info->mMem->size() = %d, srcLength = %d",
1455 info->mMem->size(), srcLength);
1456 }
1457 CHECK(info->mMem->size() >= srcLength);
1458 memcpy(info->mMem->pointer(),
1459 (const uint8_t *)srcBuffer->data() + srcBuffer->range_offset(),
1460 srcLength);
1461
Andreas Huberfa8de752009-10-08 10:07:49 -07001462 if (srcBuffer->meta_data()->findInt64(kKeyTime, &timestampUs)) {
Andreas Huber4c483422009-09-02 16:05:36 -07001463 CODEC_LOGV("Calling empty_buffer on buffer %p (length %d)",
Andreas Huberbe06d262009-08-14 14:37:10 -07001464 info->mBuffer, srcLength);
Andreas Huber4c483422009-09-02 16:05:36 -07001465 CODEC_LOGV("Calling empty_buffer with timestamp %lld us (%.2f secs)",
Andreas Huberfa8de752009-10-08 10:07:49 -07001466 timestampUs, timestampUs / 1E6);
Andreas Huberbe06d262009-08-14 14:37:10 -07001467 }
1468 }
1469
Andreas Huberbe06d262009-08-14 14:37:10 -07001470 if (srcBuffer != NULL) {
1471 srcBuffer->release();
1472 srcBuffer = NULL;
1473 }
Andreas Huber3f427072009-10-08 11:02:27 -07001474
1475 err = mOMX->empty_buffer(
1476 mNode, info->mBuffer, 0, srcLength,
Andreas Huberfa8de752009-10-08 10:07:49 -07001477 flags, timestampUs);
Andreas Huber3f427072009-10-08 11:02:27 -07001478
1479 if (err != OK) {
1480 setState(ERROR);
1481 return;
1482 }
1483
1484 info->mOwnedByComponent = true;
Andreas Huberbe06d262009-08-14 14:37:10 -07001485}
1486
1487void OMXCodec::fillOutputBuffer(BufferInfo *info) {
1488 CHECK_EQ(info->mOwnedByComponent, false);
1489
Andreas Huber404cc412009-08-25 14:26:05 -07001490 if (mNoMoreOutputData) {
Andreas Huber4c483422009-09-02 16:05:36 -07001491 CODEC_LOGV("There is no more output data available, not "
Andreas Huber404cc412009-08-25 14:26:05 -07001492 "calling fillOutputBuffer");
1493 return;
1494 }
1495
Andreas Huber4c483422009-09-02 16:05:36 -07001496 CODEC_LOGV("Calling fill_buffer on buffer %p", info->mBuffer);
Andreas Huber3f427072009-10-08 11:02:27 -07001497 status_t err = mOMX->fill_buffer(mNode, info->mBuffer);
1498 CHECK_EQ(err, OK);
Andreas Huberbe06d262009-08-14 14:37:10 -07001499
1500 info->mOwnedByComponent = true;
1501}
1502
1503void OMXCodec::drainInputBuffer(IOMX::buffer_id buffer) {
1504 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
1505 for (size_t i = 0; i < buffers->size(); ++i) {
1506 if ((*buffers)[i].mBuffer == buffer) {
1507 drainInputBuffer(&buffers->editItemAt(i));
1508 return;
1509 }
1510 }
1511
1512 CHECK(!"should not be here.");
1513}
1514
1515void OMXCodec::fillOutputBuffer(IOMX::buffer_id buffer) {
1516 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
1517 for (size_t i = 0; i < buffers->size(); ++i) {
1518 if ((*buffers)[i].mBuffer == buffer) {
1519 fillOutputBuffer(&buffers->editItemAt(i));
1520 return;
1521 }
1522 }
1523
1524 CHECK(!"should not be here.");
1525}
1526
1527void OMXCodec::setState(State newState) {
1528 mState = newState;
1529 mAsyncCompletion.signal();
1530
1531 // This may cause some spurious wakeups but is necessary to
1532 // unblock the reader if we enter ERROR state.
1533 mBufferFilled.signal();
1534}
1535
Andreas Huberda050cf22009-09-02 14:01:43 -07001536void OMXCodec::setRawAudioFormat(
1537 OMX_U32 portIndex, int32_t sampleRate, int32_t numChannels) {
1538 OMX_AUDIO_PARAM_PCMMODETYPE pcmParams;
Andreas Huber4c483422009-09-02 16:05:36 -07001539 InitOMXParams(&pcmParams);
Andreas Huberda050cf22009-09-02 14:01:43 -07001540 pcmParams.nPortIndex = portIndex;
1541
1542 status_t err = mOMX->get_parameter(
1543 mNode, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams));
1544
1545 CHECK_EQ(err, OK);
1546
1547 pcmParams.nChannels = numChannels;
1548 pcmParams.eNumData = OMX_NumericalDataSigned;
1549 pcmParams.bInterleaved = OMX_TRUE;
1550 pcmParams.nBitPerSample = 16;
1551 pcmParams.nSamplingRate = sampleRate;
1552 pcmParams.ePCMMode = OMX_AUDIO_PCMModeLinear;
1553
1554 if (numChannels == 1) {
1555 pcmParams.eChannelMapping[0] = OMX_AUDIO_ChannelCF;
1556 } else {
1557 CHECK_EQ(numChannels, 2);
1558
1559 pcmParams.eChannelMapping[0] = OMX_AUDIO_ChannelLF;
1560 pcmParams.eChannelMapping[1] = OMX_AUDIO_ChannelRF;
1561 }
1562
1563 err = mOMX->set_parameter(
1564 mNode, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams));
1565
1566 CHECK_EQ(err, OK);
1567}
1568
Andreas Huberbe06d262009-08-14 14:37:10 -07001569void OMXCodec::setAMRFormat() {
1570 if (!mIsEncoder) {
1571 OMX_AUDIO_PARAM_AMRTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -07001572 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -07001573 def.nPortIndex = kPortIndexInput;
1574
1575 status_t err =
1576 mOMX->get_parameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
1577
1578 CHECK_EQ(err, OK);
1579
1580 def.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
1581 def.eAMRBandMode = OMX_AUDIO_AMRBandModeNB0;
1582
1583 err = mOMX->set_parameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
1584 CHECK_EQ(err, OK);
1585 }
1586
1587 ////////////////////////
1588
1589 if (mIsEncoder) {
1590 sp<MetaData> format = mSource->getFormat();
1591 int32_t sampleRate;
1592 int32_t numChannels;
1593 CHECK(format->findInt32(kKeySampleRate, &sampleRate));
1594 CHECK(format->findInt32(kKeyChannelCount, &numChannels));
1595
Andreas Huberda050cf22009-09-02 14:01:43 -07001596 setRawAudioFormat(kPortIndexInput, sampleRate, numChannels);
Andreas Huberbe06d262009-08-14 14:37:10 -07001597 }
1598}
1599
Andreas Huberee606e62009-09-08 10:19:21 -07001600void OMXCodec::setAMRWBFormat() {
1601 if (!mIsEncoder) {
1602 OMX_AUDIO_PARAM_AMRTYPE def;
1603 InitOMXParams(&def);
1604 def.nPortIndex = kPortIndexInput;
1605
1606 status_t err =
1607 mOMX->get_parameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
1608
1609 CHECK_EQ(err, OK);
1610
1611 def.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
1612 def.eAMRBandMode = OMX_AUDIO_AMRBandModeWB0;
1613
1614 err = mOMX->set_parameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
1615 CHECK_EQ(err, OK);
1616 }
1617
1618 ////////////////////////
1619
1620 if (mIsEncoder) {
1621 sp<MetaData> format = mSource->getFormat();
1622 int32_t sampleRate;
1623 int32_t numChannels;
1624 CHECK(format->findInt32(kKeySampleRate, &sampleRate));
1625 CHECK(format->findInt32(kKeyChannelCount, &numChannels));
1626
1627 setRawAudioFormat(kPortIndexInput, sampleRate, numChannels);
1628 }
1629}
1630
Andreas Huber43ad6eaf2009-09-01 16:02:43 -07001631void OMXCodec::setAACFormat(int32_t numChannels, int32_t sampleRate) {
Andreas Huberda050cf22009-09-02 14:01:43 -07001632 if (mIsEncoder) {
1633 setRawAudioFormat(kPortIndexInput, sampleRate, numChannels);
1634 } else {
1635 OMX_AUDIO_PARAM_AACPROFILETYPE profile;
Andreas Huber4c483422009-09-02 16:05:36 -07001636 InitOMXParams(&profile);
Andreas Huberda050cf22009-09-02 14:01:43 -07001637 profile.nPortIndex = kPortIndexInput;
Andreas Huberbe06d262009-08-14 14:37:10 -07001638
Andreas Huberda050cf22009-09-02 14:01:43 -07001639 status_t err = mOMX->get_parameter(
1640 mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile));
1641 CHECK_EQ(err, OK);
Andreas Huberbe06d262009-08-14 14:37:10 -07001642
Andreas Huberda050cf22009-09-02 14:01:43 -07001643 profile.nChannels = numChannels;
1644 profile.nSampleRate = sampleRate;
1645 profile.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4ADTS;
Andreas Huberbe06d262009-08-14 14:37:10 -07001646
Andreas Huberda050cf22009-09-02 14:01:43 -07001647 err = mOMX->set_parameter(
1648 mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile));
1649 CHECK_EQ(err, OK);
1650 }
Andreas Huberbe06d262009-08-14 14:37:10 -07001651}
1652
1653void OMXCodec::setImageOutputFormat(
1654 OMX_COLOR_FORMATTYPE format, OMX_U32 width, OMX_U32 height) {
Andreas Huber4c483422009-09-02 16:05:36 -07001655 CODEC_LOGV("setImageOutputFormat(%ld, %ld)", width, height);
Andreas Huberbe06d262009-08-14 14:37:10 -07001656
1657#if 0
1658 OMX_INDEXTYPE index;
1659 status_t err = mOMX->get_extension_index(
1660 mNode, "OMX.TI.JPEG.decode.Config.OutputColorFormat", &index);
1661 CHECK_EQ(err, OK);
1662
1663 err = mOMX->set_config(mNode, index, &format, sizeof(format));
1664 CHECK_EQ(err, OK);
1665#endif
1666
1667 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -07001668 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -07001669 def.nPortIndex = kPortIndexOutput;
1670
1671 status_t err = mOMX->get_parameter(
1672 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
1673 CHECK_EQ(err, OK);
1674
1675 CHECK_EQ(def.eDomain, OMX_PortDomainImage);
1676
1677 OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
Andreas Huberebf66ea2009-08-19 13:32:58 -07001678
Andreas Huberbe06d262009-08-14 14:37:10 -07001679 CHECK_EQ(imageDef->eCompressionFormat, OMX_IMAGE_CodingUnused);
1680 imageDef->eColorFormat = format;
1681 imageDef->nFrameWidth = width;
1682 imageDef->nFrameHeight = height;
1683
1684 switch (format) {
1685 case OMX_COLOR_FormatYUV420PackedPlanar:
1686 case OMX_COLOR_FormatYUV411Planar:
1687 {
1688 def.nBufferSize = (width * height * 3) / 2;
1689 break;
1690 }
1691
1692 case OMX_COLOR_FormatCbYCrY:
1693 {
1694 def.nBufferSize = width * height * 2;
1695 break;
1696 }
1697
1698 case OMX_COLOR_Format32bitARGB8888:
1699 {
1700 def.nBufferSize = width * height * 4;
1701 break;
1702 }
1703
Andreas Huber201511c2009-09-08 14:01:44 -07001704 case OMX_COLOR_Format16bitARGB4444:
1705 case OMX_COLOR_Format16bitARGB1555:
1706 case OMX_COLOR_Format16bitRGB565:
1707 case OMX_COLOR_Format16bitBGR565:
1708 {
1709 def.nBufferSize = width * height * 2;
1710 break;
1711 }
1712
Andreas Huberbe06d262009-08-14 14:37:10 -07001713 default:
1714 CHECK(!"Should not be here. Unknown color format.");
1715 break;
1716 }
1717
Andreas Huber5c0a9132009-08-20 11:16:40 -07001718 def.nBufferCountActual = def.nBufferCountMin;
1719
Andreas Huberbe06d262009-08-14 14:37:10 -07001720 err = mOMX->set_parameter(
1721 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
1722 CHECK_EQ(err, OK);
Andreas Huber5c0a9132009-08-20 11:16:40 -07001723}
Andreas Huberbe06d262009-08-14 14:37:10 -07001724
Andreas Huber5c0a9132009-08-20 11:16:40 -07001725void OMXCodec::setJPEGInputFormat(
1726 OMX_U32 width, OMX_U32 height, OMX_U32 compressedSize) {
1727 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -07001728 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -07001729 def.nPortIndex = kPortIndexInput;
1730
Andreas Huber5c0a9132009-08-20 11:16:40 -07001731 status_t err = mOMX->get_parameter(
Andreas Huberbe06d262009-08-14 14:37:10 -07001732 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
1733 CHECK_EQ(err, OK);
1734
Andreas Huber5c0a9132009-08-20 11:16:40 -07001735 CHECK_EQ(def.eDomain, OMX_PortDomainImage);
1736 OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
1737
Andreas Huberbe06d262009-08-14 14:37:10 -07001738 CHECK_EQ(imageDef->eCompressionFormat, OMX_IMAGE_CodingJPEG);
1739 imageDef->nFrameWidth = width;
1740 imageDef->nFrameHeight = height;
1741
Andreas Huber5c0a9132009-08-20 11:16:40 -07001742 def.nBufferSize = compressedSize;
Andreas Huberbe06d262009-08-14 14:37:10 -07001743 def.nBufferCountActual = def.nBufferCountMin;
1744
1745 err = mOMX->set_parameter(
1746 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
1747 CHECK_EQ(err, OK);
1748}
1749
1750void OMXCodec::addCodecSpecificData(const void *data, size_t size) {
1751 CodecSpecificData *specific =
1752 (CodecSpecificData *)malloc(sizeof(CodecSpecificData) + size - 1);
1753
1754 specific->mSize = size;
1755 memcpy(specific->mData, data, size);
1756
1757 mCodecSpecificData.push(specific);
1758}
1759
1760void OMXCodec::clearCodecSpecificData() {
1761 for (size_t i = 0; i < mCodecSpecificData.size(); ++i) {
1762 free(mCodecSpecificData.editItemAt(i));
1763 }
1764 mCodecSpecificData.clear();
1765 mCodecSpecificDataIndex = 0;
1766}
1767
1768status_t OMXCodec::start(MetaData *) {
Andreas Huber42978e52009-08-27 10:08:39 -07001769 Mutex::Autolock autoLock(mLock);
1770
Andreas Huberbe06d262009-08-14 14:37:10 -07001771 if (mState != LOADED) {
1772 return UNKNOWN_ERROR;
1773 }
Andreas Huberebf66ea2009-08-19 13:32:58 -07001774
Andreas Huberbe06d262009-08-14 14:37:10 -07001775 sp<MetaData> params = new MetaData;
Andreas Huber4f5e6022009-08-19 09:29:34 -07001776 if (mQuirks & kWantsNALFragments) {
1777 params->setInt32(kKeyWantsNALFragments, true);
Andreas Huberbe06d262009-08-14 14:37:10 -07001778 }
1779 status_t err = mSource->start(params.get());
1780
1781 if (err != OK) {
1782 return err;
1783 }
1784
1785 mCodecSpecificDataIndex = 0;
Andreas Huber42978e52009-08-27 10:08:39 -07001786 mInitialBufferSubmit = true;
Andreas Huberbe06d262009-08-14 14:37:10 -07001787 mSignalledEOS = false;
1788 mNoMoreOutputData = false;
Andreas Hubercfd55572009-10-09 14:11:28 -07001789 mOutputPortSettingsHaveChanged = false;
Andreas Huberbe06d262009-08-14 14:37:10 -07001790 mSeekTimeUs = -1;
1791 mFilledBuffers.clear();
1792
1793 return init();
1794}
1795
1796status_t OMXCodec::stop() {
Andreas Huber4c483422009-09-02 16:05:36 -07001797 CODEC_LOGV("stop");
Andreas Huberbe06d262009-08-14 14:37:10 -07001798
1799 Mutex::Autolock autoLock(mLock);
1800
1801 while (isIntermediateState(mState)) {
1802 mAsyncCompletion.wait(mLock);
1803 }
1804
1805 switch (mState) {
1806 case LOADED:
1807 case ERROR:
1808 break;
1809
1810 case EXECUTING:
1811 {
1812 setState(EXECUTING_TO_IDLE);
1813
Andreas Huber127fcdc2009-08-26 16:27:02 -07001814 if (mQuirks & kRequiresFlushBeforeShutdown) {
Andreas Huber4c483422009-09-02 16:05:36 -07001815 CODEC_LOGV("This component requires a flush before transitioning "
Andreas Huber127fcdc2009-08-26 16:27:02 -07001816 "from EXECUTING to IDLE...");
Andreas Huberbe06d262009-08-14 14:37:10 -07001817
Andreas Huber127fcdc2009-08-26 16:27:02 -07001818 bool emulateInputFlushCompletion =
1819 !flushPortAsync(kPortIndexInput);
1820
1821 bool emulateOutputFlushCompletion =
1822 !flushPortAsync(kPortIndexOutput);
1823
1824 if (emulateInputFlushCompletion) {
1825 onCmdComplete(OMX_CommandFlush, kPortIndexInput);
1826 }
1827
1828 if (emulateOutputFlushCompletion) {
1829 onCmdComplete(OMX_CommandFlush, kPortIndexOutput);
1830 }
1831 } else {
1832 mPortStatus[kPortIndexInput] = SHUTTING_DOWN;
1833 mPortStatus[kPortIndexOutput] = SHUTTING_DOWN;
1834
1835 status_t err =
1836 mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
1837 CHECK_EQ(err, OK);
1838 }
Andreas Huberbe06d262009-08-14 14:37:10 -07001839
1840 while (mState != LOADED && mState != ERROR) {
1841 mAsyncCompletion.wait(mLock);
1842 }
1843
1844 break;
1845 }
1846
1847 default:
1848 {
1849 CHECK(!"should not be here.");
1850 break;
1851 }
1852 }
1853
1854 mSource->stop();
1855
1856 return OK;
1857}
1858
1859sp<MetaData> OMXCodec::getFormat() {
Andreas Hubercfd55572009-10-09 14:11:28 -07001860 Mutex::Autolock autoLock(mLock);
1861
Andreas Huberbe06d262009-08-14 14:37:10 -07001862 return mOutputFormat;
1863}
1864
1865status_t OMXCodec::read(
1866 MediaBuffer **buffer, const ReadOptions *options) {
1867 *buffer = NULL;
1868
1869 Mutex::Autolock autoLock(mLock);
1870
Andreas Huberd06e5b82009-08-28 13:18:14 -07001871 if (mState != EXECUTING && mState != RECONFIGURING) {
1872 return UNKNOWN_ERROR;
1873 }
1874
Andreas Huber42978e52009-08-27 10:08:39 -07001875 if (mInitialBufferSubmit) {
1876 mInitialBufferSubmit = false;
1877
1878 drainInputBuffers();
Andreas Huber42978e52009-08-27 10:08:39 -07001879
Andreas Huberd06e5b82009-08-28 13:18:14 -07001880 if (mState == EXECUTING) {
1881 // Otherwise mState == RECONFIGURING and this code will trigger
1882 // after the output port is reenabled.
1883 fillOutputBuffers();
1884 }
Andreas Huberbe06d262009-08-14 14:37:10 -07001885 }
1886
1887 int64_t seekTimeUs;
1888 if (options && options->getSeekTo(&seekTimeUs)) {
Andreas Huber4c483422009-09-02 16:05:36 -07001889 CODEC_LOGV("seeking to %lld us (%.2f secs)", seekTimeUs, seekTimeUs / 1E6);
Andreas Huberbe06d262009-08-14 14:37:10 -07001890
1891 mSignalledEOS = false;
1892 mNoMoreOutputData = false;
1893
1894 CHECK(seekTimeUs >= 0);
1895 mSeekTimeUs = seekTimeUs;
1896
1897 mFilledBuffers.clear();
1898
1899 CHECK_EQ(mState, EXECUTING);
1900
Andreas Huber404cc412009-08-25 14:26:05 -07001901 bool emulateInputFlushCompletion = !flushPortAsync(kPortIndexInput);
1902 bool emulateOutputFlushCompletion = !flushPortAsync(kPortIndexOutput);
1903
1904 if (emulateInputFlushCompletion) {
1905 onCmdComplete(OMX_CommandFlush, kPortIndexInput);
1906 }
1907
1908 if (emulateOutputFlushCompletion) {
1909 onCmdComplete(OMX_CommandFlush, kPortIndexOutput);
1910 }
Andreas Huberbe06d262009-08-14 14:37:10 -07001911 }
1912
1913 while (mState != ERROR && !mNoMoreOutputData && mFilledBuffers.empty()) {
1914 mBufferFilled.wait(mLock);
1915 }
1916
1917 if (mState == ERROR) {
1918 return UNKNOWN_ERROR;
1919 }
1920
1921 if (mFilledBuffers.empty()) {
1922 return ERROR_END_OF_STREAM;
1923 }
1924
Andreas Hubercfd55572009-10-09 14:11:28 -07001925 if (mOutputPortSettingsHaveChanged) {
1926 mOutputPortSettingsHaveChanged = false;
1927
1928 return INFO_FORMAT_CHANGED;
1929 }
1930
Andreas Huberbe06d262009-08-14 14:37:10 -07001931 size_t index = *mFilledBuffers.begin();
1932 mFilledBuffers.erase(mFilledBuffers.begin());
1933
1934 BufferInfo *info = &mPortBuffers[kPortIndexOutput].editItemAt(index);
1935 info->mMediaBuffer->add_ref();
1936 *buffer = info->mMediaBuffer;
1937
1938 return OK;
1939}
1940
1941void OMXCodec::signalBufferReturned(MediaBuffer *buffer) {
1942 Mutex::Autolock autoLock(mLock);
1943
1944 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
1945 for (size_t i = 0; i < buffers->size(); ++i) {
1946 BufferInfo *info = &buffers->editItemAt(i);
1947
1948 if (info->mMediaBuffer == buffer) {
1949 CHECK_EQ(mPortStatus[kPortIndexOutput], ENABLED);
1950 fillOutputBuffer(info);
1951 return;
1952 }
1953 }
1954
1955 CHECK(!"should not be here.");
1956}
1957
1958static const char *imageCompressionFormatString(OMX_IMAGE_CODINGTYPE type) {
1959 static const char *kNames[] = {
1960 "OMX_IMAGE_CodingUnused",
1961 "OMX_IMAGE_CodingAutoDetect",
1962 "OMX_IMAGE_CodingJPEG",
1963 "OMX_IMAGE_CodingJPEG2K",
1964 "OMX_IMAGE_CodingEXIF",
1965 "OMX_IMAGE_CodingTIFF",
1966 "OMX_IMAGE_CodingGIF",
1967 "OMX_IMAGE_CodingPNG",
1968 "OMX_IMAGE_CodingLZW",
1969 "OMX_IMAGE_CodingBMP",
1970 };
1971
1972 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
1973
1974 if (type < 0 || (size_t)type >= numNames) {
1975 return "UNKNOWN";
1976 } else {
1977 return kNames[type];
1978 }
1979}
1980
1981static const char *colorFormatString(OMX_COLOR_FORMATTYPE type) {
1982 static const char *kNames[] = {
1983 "OMX_COLOR_FormatUnused",
1984 "OMX_COLOR_FormatMonochrome",
1985 "OMX_COLOR_Format8bitRGB332",
1986 "OMX_COLOR_Format12bitRGB444",
1987 "OMX_COLOR_Format16bitARGB4444",
1988 "OMX_COLOR_Format16bitARGB1555",
1989 "OMX_COLOR_Format16bitRGB565",
1990 "OMX_COLOR_Format16bitBGR565",
1991 "OMX_COLOR_Format18bitRGB666",
1992 "OMX_COLOR_Format18bitARGB1665",
Andreas Huberebf66ea2009-08-19 13:32:58 -07001993 "OMX_COLOR_Format19bitARGB1666",
Andreas Huberbe06d262009-08-14 14:37:10 -07001994 "OMX_COLOR_Format24bitRGB888",
1995 "OMX_COLOR_Format24bitBGR888",
1996 "OMX_COLOR_Format24bitARGB1887",
1997 "OMX_COLOR_Format25bitARGB1888",
1998 "OMX_COLOR_Format32bitBGRA8888",
1999 "OMX_COLOR_Format32bitARGB8888",
2000 "OMX_COLOR_FormatYUV411Planar",
2001 "OMX_COLOR_FormatYUV411PackedPlanar",
2002 "OMX_COLOR_FormatYUV420Planar",
2003 "OMX_COLOR_FormatYUV420PackedPlanar",
2004 "OMX_COLOR_FormatYUV420SemiPlanar",
2005 "OMX_COLOR_FormatYUV422Planar",
2006 "OMX_COLOR_FormatYUV422PackedPlanar",
2007 "OMX_COLOR_FormatYUV422SemiPlanar",
2008 "OMX_COLOR_FormatYCbYCr",
2009 "OMX_COLOR_FormatYCrYCb",
2010 "OMX_COLOR_FormatCbYCrY",
2011 "OMX_COLOR_FormatCrYCbY",
2012 "OMX_COLOR_FormatYUV444Interleaved",
2013 "OMX_COLOR_FormatRawBayer8bit",
2014 "OMX_COLOR_FormatRawBayer10bit",
2015 "OMX_COLOR_FormatRawBayer8bitcompressed",
Andreas Huberebf66ea2009-08-19 13:32:58 -07002016 "OMX_COLOR_FormatL2",
2017 "OMX_COLOR_FormatL4",
2018 "OMX_COLOR_FormatL8",
2019 "OMX_COLOR_FormatL16",
2020 "OMX_COLOR_FormatL24",
Andreas Huberbe06d262009-08-14 14:37:10 -07002021 "OMX_COLOR_FormatL32",
2022 "OMX_COLOR_FormatYUV420PackedSemiPlanar",
2023 "OMX_COLOR_FormatYUV422PackedSemiPlanar",
2024 "OMX_COLOR_Format18BitBGR666",
2025 "OMX_COLOR_Format24BitARGB6666",
2026 "OMX_COLOR_Format24BitABGR6666",
2027 };
2028
2029 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
2030
Andreas Huberbe06d262009-08-14 14:37:10 -07002031 if (type == OMX_QCOM_COLOR_FormatYVU420SemiPlanar) {
2032 return "OMX_QCOM_COLOR_FormatYVU420SemiPlanar";
2033 } else if (type < 0 || (size_t)type >= numNames) {
2034 return "UNKNOWN";
2035 } else {
2036 return kNames[type];
2037 }
2038}
2039
2040static const char *videoCompressionFormatString(OMX_VIDEO_CODINGTYPE type) {
2041 static const char *kNames[] = {
2042 "OMX_VIDEO_CodingUnused",
2043 "OMX_VIDEO_CodingAutoDetect",
2044 "OMX_VIDEO_CodingMPEG2",
2045 "OMX_VIDEO_CodingH263",
2046 "OMX_VIDEO_CodingMPEG4",
2047 "OMX_VIDEO_CodingWMV",
2048 "OMX_VIDEO_CodingRV",
2049 "OMX_VIDEO_CodingAVC",
2050 "OMX_VIDEO_CodingMJPEG",
2051 };
2052
2053 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
2054
2055 if (type < 0 || (size_t)type >= numNames) {
2056 return "UNKNOWN";
2057 } else {
2058 return kNames[type];
2059 }
2060}
2061
2062static const char *audioCodingTypeString(OMX_AUDIO_CODINGTYPE type) {
2063 static const char *kNames[] = {
2064 "OMX_AUDIO_CodingUnused",
2065 "OMX_AUDIO_CodingAutoDetect",
2066 "OMX_AUDIO_CodingPCM",
2067 "OMX_AUDIO_CodingADPCM",
2068 "OMX_AUDIO_CodingAMR",
2069 "OMX_AUDIO_CodingGSMFR",
2070 "OMX_AUDIO_CodingGSMEFR",
2071 "OMX_AUDIO_CodingGSMHR",
2072 "OMX_AUDIO_CodingPDCFR",
2073 "OMX_AUDIO_CodingPDCEFR",
2074 "OMX_AUDIO_CodingPDCHR",
2075 "OMX_AUDIO_CodingTDMAFR",
2076 "OMX_AUDIO_CodingTDMAEFR",
2077 "OMX_AUDIO_CodingQCELP8",
2078 "OMX_AUDIO_CodingQCELP13",
2079 "OMX_AUDIO_CodingEVRC",
2080 "OMX_AUDIO_CodingSMV",
2081 "OMX_AUDIO_CodingG711",
2082 "OMX_AUDIO_CodingG723",
2083 "OMX_AUDIO_CodingG726",
2084 "OMX_AUDIO_CodingG729",
2085 "OMX_AUDIO_CodingAAC",
2086 "OMX_AUDIO_CodingMP3",
2087 "OMX_AUDIO_CodingSBC",
2088 "OMX_AUDIO_CodingVORBIS",
2089 "OMX_AUDIO_CodingWMA",
2090 "OMX_AUDIO_CodingRA",
2091 "OMX_AUDIO_CodingMIDI",
2092 };
2093
2094 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
2095
2096 if (type < 0 || (size_t)type >= numNames) {
2097 return "UNKNOWN";
2098 } else {
2099 return kNames[type];
2100 }
2101}
2102
2103static const char *audioPCMModeString(OMX_AUDIO_PCMMODETYPE type) {
2104 static const char *kNames[] = {
2105 "OMX_AUDIO_PCMModeLinear",
2106 "OMX_AUDIO_PCMModeALaw",
2107 "OMX_AUDIO_PCMModeMULaw",
2108 };
2109
2110 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
2111
2112 if (type < 0 || (size_t)type >= numNames) {
2113 return "UNKNOWN";
2114 } else {
2115 return kNames[type];
2116 }
2117}
2118
Andreas Huber7ae02c82009-09-09 16:29:47 -07002119static const char *amrBandModeString(OMX_AUDIO_AMRBANDMODETYPE type) {
2120 static const char *kNames[] = {
2121 "OMX_AUDIO_AMRBandModeUnused",
2122 "OMX_AUDIO_AMRBandModeNB0",
2123 "OMX_AUDIO_AMRBandModeNB1",
2124 "OMX_AUDIO_AMRBandModeNB2",
2125 "OMX_AUDIO_AMRBandModeNB3",
2126 "OMX_AUDIO_AMRBandModeNB4",
2127 "OMX_AUDIO_AMRBandModeNB5",
2128 "OMX_AUDIO_AMRBandModeNB6",
2129 "OMX_AUDIO_AMRBandModeNB7",
2130 "OMX_AUDIO_AMRBandModeWB0",
2131 "OMX_AUDIO_AMRBandModeWB1",
2132 "OMX_AUDIO_AMRBandModeWB2",
2133 "OMX_AUDIO_AMRBandModeWB3",
2134 "OMX_AUDIO_AMRBandModeWB4",
2135 "OMX_AUDIO_AMRBandModeWB5",
2136 "OMX_AUDIO_AMRBandModeWB6",
2137 "OMX_AUDIO_AMRBandModeWB7",
2138 "OMX_AUDIO_AMRBandModeWB8",
2139 };
2140
2141 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
2142
2143 if (type < 0 || (size_t)type >= numNames) {
2144 return "UNKNOWN";
2145 } else {
2146 return kNames[type];
2147 }
2148}
2149
2150static const char *amrFrameFormatString(OMX_AUDIO_AMRFRAMEFORMATTYPE type) {
2151 static const char *kNames[] = {
2152 "OMX_AUDIO_AMRFrameFormatConformance",
2153 "OMX_AUDIO_AMRFrameFormatIF1",
2154 "OMX_AUDIO_AMRFrameFormatIF2",
2155 "OMX_AUDIO_AMRFrameFormatFSF",
2156 "OMX_AUDIO_AMRFrameFormatRTPPayload",
2157 "OMX_AUDIO_AMRFrameFormatITU",
2158 };
2159
2160 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
2161
2162 if (type < 0 || (size_t)type >= numNames) {
2163 return "UNKNOWN";
2164 } else {
2165 return kNames[type];
2166 }
2167}
Andreas Huberbe06d262009-08-14 14:37:10 -07002168
2169void OMXCodec::dumpPortStatus(OMX_U32 portIndex) {
2170 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -07002171 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -07002172 def.nPortIndex = portIndex;
2173
2174 status_t err = mOMX->get_parameter(
2175 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
2176 CHECK_EQ(err, OK);
2177
2178 printf("%s Port = {\n", portIndex == kPortIndexInput ? "Input" : "Output");
2179
2180 CHECK((portIndex == kPortIndexInput && def.eDir == OMX_DirInput)
2181 || (portIndex == kPortIndexOutput && def.eDir == OMX_DirOutput));
2182
2183 printf(" nBufferCountActual = %ld\n", def.nBufferCountActual);
2184 printf(" nBufferCountMin = %ld\n", def.nBufferCountMin);
2185 printf(" nBufferSize = %ld\n", def.nBufferSize);
2186
2187 switch (def.eDomain) {
2188 case OMX_PortDomainImage:
2189 {
2190 const OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
2191
2192 printf("\n");
2193 printf(" // Image\n");
2194 printf(" nFrameWidth = %ld\n", imageDef->nFrameWidth);
2195 printf(" nFrameHeight = %ld\n", imageDef->nFrameHeight);
2196 printf(" nStride = %ld\n", imageDef->nStride);
2197
2198 printf(" eCompressionFormat = %s\n",
2199 imageCompressionFormatString(imageDef->eCompressionFormat));
2200
2201 printf(" eColorFormat = %s\n",
2202 colorFormatString(imageDef->eColorFormat));
2203
2204 break;
2205 }
2206
2207 case OMX_PortDomainVideo:
2208 {
2209 OMX_VIDEO_PORTDEFINITIONTYPE *videoDef = &def.format.video;
2210
2211 printf("\n");
2212 printf(" // Video\n");
2213 printf(" nFrameWidth = %ld\n", videoDef->nFrameWidth);
2214 printf(" nFrameHeight = %ld\n", videoDef->nFrameHeight);
2215 printf(" nStride = %ld\n", videoDef->nStride);
2216
2217 printf(" eCompressionFormat = %s\n",
2218 videoCompressionFormatString(videoDef->eCompressionFormat));
2219
2220 printf(" eColorFormat = %s\n",
2221 colorFormatString(videoDef->eColorFormat));
2222
2223 break;
2224 }
2225
2226 case OMX_PortDomainAudio:
2227 {
2228 OMX_AUDIO_PORTDEFINITIONTYPE *audioDef = &def.format.audio;
2229
2230 printf("\n");
2231 printf(" // Audio\n");
2232 printf(" eEncoding = %s\n",
2233 audioCodingTypeString(audioDef->eEncoding));
2234
2235 if (audioDef->eEncoding == OMX_AUDIO_CodingPCM) {
2236 OMX_AUDIO_PARAM_PCMMODETYPE params;
Andreas Huber4c483422009-09-02 16:05:36 -07002237 InitOMXParams(&params);
Andreas Huberbe06d262009-08-14 14:37:10 -07002238 params.nPortIndex = portIndex;
2239
2240 err = mOMX->get_parameter(
2241 mNode, OMX_IndexParamAudioPcm, &params, sizeof(params));
2242 CHECK_EQ(err, OK);
2243
2244 printf(" nSamplingRate = %ld\n", params.nSamplingRate);
2245 printf(" nChannels = %ld\n", params.nChannels);
2246 printf(" bInterleaved = %d\n", params.bInterleaved);
2247 printf(" nBitPerSample = %ld\n", params.nBitPerSample);
2248
2249 printf(" eNumData = %s\n",
2250 params.eNumData == OMX_NumericalDataSigned
2251 ? "signed" : "unsigned");
2252
2253 printf(" ePCMMode = %s\n", audioPCMModeString(params.ePCMMode));
Andreas Huber7ae02c82009-09-09 16:29:47 -07002254 } else if (audioDef->eEncoding == OMX_AUDIO_CodingAMR) {
2255 OMX_AUDIO_PARAM_AMRTYPE amr;
2256 InitOMXParams(&amr);
2257 amr.nPortIndex = portIndex;
2258
2259 err = mOMX->get_parameter(
2260 mNode, OMX_IndexParamAudioAmr, &amr, sizeof(amr));
2261 CHECK_EQ(err, OK);
2262
2263 printf(" nChannels = %ld\n", amr.nChannels);
2264 printf(" eAMRBandMode = %s\n",
2265 amrBandModeString(amr.eAMRBandMode));
2266 printf(" eAMRFrameFormat = %s\n",
2267 amrFrameFormatString(amr.eAMRFrameFormat));
Andreas Huberbe06d262009-08-14 14:37:10 -07002268 }
2269
2270 break;
2271 }
2272
2273 default:
2274 {
2275 printf(" // Unknown\n");
2276 break;
2277 }
2278 }
2279
2280 printf("}\n");
2281}
2282
2283void OMXCodec::initOutputFormat(const sp<MetaData> &inputFormat) {
2284 mOutputFormat = new MetaData;
2285 mOutputFormat->setCString(kKeyDecoderComponent, mComponentName);
2286
2287 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -07002288 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -07002289 def.nPortIndex = kPortIndexOutput;
2290
2291 status_t err = mOMX->get_parameter(
2292 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
2293 CHECK_EQ(err, OK);
2294
2295 switch (def.eDomain) {
2296 case OMX_PortDomainImage:
2297 {
2298 OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
2299 CHECK_EQ(imageDef->eCompressionFormat, OMX_IMAGE_CodingUnused);
2300
Andreas Hubere6c40962009-09-10 14:13:30 -07002301 mOutputFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
Andreas Huberbe06d262009-08-14 14:37:10 -07002302 mOutputFormat->setInt32(kKeyColorFormat, imageDef->eColorFormat);
2303 mOutputFormat->setInt32(kKeyWidth, imageDef->nFrameWidth);
2304 mOutputFormat->setInt32(kKeyHeight, imageDef->nFrameHeight);
2305 break;
2306 }
2307
2308 case OMX_PortDomainAudio:
2309 {
2310 OMX_AUDIO_PORTDEFINITIONTYPE *audio_def = &def.format.audio;
2311
Andreas Huberda050cf22009-09-02 14:01:43 -07002312 if (audio_def->eEncoding == OMX_AUDIO_CodingPCM) {
2313 OMX_AUDIO_PARAM_PCMMODETYPE params;
Andreas Huber4c483422009-09-02 16:05:36 -07002314 InitOMXParams(&params);
Andreas Huberda050cf22009-09-02 14:01:43 -07002315 params.nPortIndex = kPortIndexOutput;
Andreas Huberbe06d262009-08-14 14:37:10 -07002316
Andreas Huberda050cf22009-09-02 14:01:43 -07002317 err = mOMX->get_parameter(
2318 mNode, OMX_IndexParamAudioPcm, &params, sizeof(params));
2319 CHECK_EQ(err, OK);
Andreas Huberbe06d262009-08-14 14:37:10 -07002320
Andreas Huberda050cf22009-09-02 14:01:43 -07002321 CHECK_EQ(params.eNumData, OMX_NumericalDataSigned);
2322 CHECK_EQ(params.nBitPerSample, 16);
2323 CHECK_EQ(params.ePCMMode, OMX_AUDIO_PCMModeLinear);
Andreas Huberbe06d262009-08-14 14:37:10 -07002324
Andreas Huberda050cf22009-09-02 14:01:43 -07002325 int32_t numChannels, sampleRate;
2326 inputFormat->findInt32(kKeyChannelCount, &numChannels);
2327 inputFormat->findInt32(kKeySampleRate, &sampleRate);
Andreas Huberbe06d262009-08-14 14:37:10 -07002328
Andreas Huberda050cf22009-09-02 14:01:43 -07002329 if ((OMX_U32)numChannels != params.nChannels) {
2330 LOGW("Codec outputs a different number of channels than "
2331 "the input stream contains.");
2332 }
Andreas Huberbe06d262009-08-14 14:37:10 -07002333
Andreas Hubere6c40962009-09-10 14:13:30 -07002334 mOutputFormat->setCString(
2335 kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
Andreas Huberda050cf22009-09-02 14:01:43 -07002336
2337 // Use the codec-advertised number of channels, as some
2338 // codecs appear to output stereo even if the input data is
2339 // mono.
2340 mOutputFormat->setInt32(kKeyChannelCount, params.nChannels);
2341
2342 // The codec-reported sampleRate is not reliable...
2343 mOutputFormat->setInt32(kKeySampleRate, sampleRate);
2344 } else if (audio_def->eEncoding == OMX_AUDIO_CodingAMR) {
Andreas Huber7ae02c82009-09-09 16:29:47 -07002345 OMX_AUDIO_PARAM_AMRTYPE amr;
2346 InitOMXParams(&amr);
2347 amr.nPortIndex = kPortIndexOutput;
2348
2349 err = mOMX->get_parameter(
2350 mNode, OMX_IndexParamAudioAmr, &amr, sizeof(amr));
2351 CHECK_EQ(err, OK);
2352
2353 CHECK_EQ(amr.nChannels, 1);
2354 mOutputFormat->setInt32(kKeyChannelCount, 1);
2355
2356 if (amr.eAMRBandMode >= OMX_AUDIO_AMRBandModeNB0
2357 && amr.eAMRBandMode <= OMX_AUDIO_AMRBandModeNB7) {
Andreas Hubere6c40962009-09-10 14:13:30 -07002358 mOutputFormat->setCString(
2359 kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AMR_NB);
Andreas Huber7ae02c82009-09-09 16:29:47 -07002360 mOutputFormat->setInt32(kKeySampleRate, 8000);
2361 } else if (amr.eAMRBandMode >= OMX_AUDIO_AMRBandModeWB0
2362 && amr.eAMRBandMode <= OMX_AUDIO_AMRBandModeWB8) {
Andreas Hubere6c40962009-09-10 14:13:30 -07002363 mOutputFormat->setCString(
2364 kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AMR_WB);
Andreas Huber7ae02c82009-09-09 16:29:47 -07002365 mOutputFormat->setInt32(kKeySampleRate, 16000);
2366 } else {
2367 CHECK(!"Unknown AMR band mode.");
2368 }
Andreas Huberda050cf22009-09-02 14:01:43 -07002369 } else if (audio_def->eEncoding == OMX_AUDIO_CodingAAC) {
Andreas Hubere6c40962009-09-10 14:13:30 -07002370 mOutputFormat->setCString(
2371 kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
Andreas Huberda050cf22009-09-02 14:01:43 -07002372 } else {
2373 CHECK(!"Should not be here. Unknown audio encoding.");
Andreas Huber43ad6eaf2009-09-01 16:02:43 -07002374 }
Andreas Huberbe06d262009-08-14 14:37:10 -07002375 break;
2376 }
2377
2378 case OMX_PortDomainVideo:
2379 {
2380 OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
2381
2382 if (video_def->eCompressionFormat == OMX_VIDEO_CodingUnused) {
Andreas Hubere6c40962009-09-10 14:13:30 -07002383 mOutputFormat->setCString(
2384 kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
Andreas Huberbe06d262009-08-14 14:37:10 -07002385 } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingMPEG4) {
Andreas Hubere6c40962009-09-10 14:13:30 -07002386 mOutputFormat->setCString(
2387 kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
Andreas Huberbe06d262009-08-14 14:37:10 -07002388 } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingH263) {
Andreas Hubere6c40962009-09-10 14:13:30 -07002389 mOutputFormat->setCString(
2390 kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263);
Andreas Huberbe06d262009-08-14 14:37:10 -07002391 } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingAVC) {
Andreas Hubere6c40962009-09-10 14:13:30 -07002392 mOutputFormat->setCString(
2393 kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
Andreas Huberbe06d262009-08-14 14:37:10 -07002394 } else {
2395 CHECK(!"Unknown compression format.");
2396 }
2397
2398 if (!strcmp(mComponentName, "OMX.PV.avcdec")) {
2399 // This component appears to be lying to me.
2400 mOutputFormat->setInt32(
2401 kKeyWidth, (video_def->nFrameWidth + 15) & -16);
2402 mOutputFormat->setInt32(
2403 kKeyHeight, (video_def->nFrameHeight + 15) & -16);
2404 } else {
2405 mOutputFormat->setInt32(kKeyWidth, video_def->nFrameWidth);
2406 mOutputFormat->setInt32(kKeyHeight, video_def->nFrameHeight);
2407 }
2408
2409 mOutputFormat->setInt32(kKeyColorFormat, video_def->eColorFormat);
2410 break;
2411 }
2412
2413 default:
2414 {
2415 CHECK(!"should not be here, neither audio nor video.");
2416 break;
2417 }
2418 }
2419}
2420
Andreas Hubere6c40962009-09-10 14:13:30 -07002421////////////////////////////////////////////////////////////////////////////////
2422
2423status_t QueryCodecs(
2424 const sp<IOMX> &omx,
2425 const char *mime, bool queryDecoders,
2426 Vector<CodecCapabilities> *results) {
2427 results->clear();
2428
2429 for (int index = 0;; ++index) {
2430 const char *componentName;
2431
2432 if (!queryDecoders) {
2433 componentName = GetCodec(
2434 kEncoderInfo, sizeof(kEncoderInfo) / sizeof(kEncoderInfo[0]),
2435 mime, index);
2436 } else {
2437 componentName = GetCodec(
2438 kDecoderInfo, sizeof(kDecoderInfo) / sizeof(kDecoderInfo[0]),
2439 mime, index);
2440 }
2441
2442 if (!componentName) {
2443 return OK;
2444 }
2445
2446 IOMX::node_id node;
2447 status_t err = omx->allocate_node(componentName, &node);
2448
2449 if (err != OK) {
2450 continue;
2451 }
2452
2453 OMXCodec::setComponentRole(omx, node, queryDecoders, mime);
2454
2455 results->push();
2456 CodecCapabilities *caps = &results->editItemAt(results->size() - 1);
2457 caps->mComponentName = componentName;
2458
2459 OMX_VIDEO_PARAM_PROFILELEVELTYPE param;
2460 InitOMXParams(&param);
2461
2462 param.nPortIndex = queryDecoders ? 0 : 1;
2463
2464 for (param.nProfileIndex = 0;; ++param.nProfileIndex) {
2465 err = omx->get_parameter(
2466 node, OMX_IndexParamVideoProfileLevelQuerySupported,
2467 &param, sizeof(param));
2468
2469 if (err != OK) {
2470 break;
2471 }
2472
2473 CodecProfileLevel profileLevel;
2474 profileLevel.mProfile = param.eProfile;
2475 profileLevel.mLevel = param.eLevel;
2476
2477 caps->mProfileLevels.push(profileLevel);
2478 }
2479
2480 CHECK_EQ(omx->free_node(node), OK);
2481 }
2482}
2483
Andreas Huberbe06d262009-08-14 14:37:10 -07002484} // namespace android