blob: a964d17a1baf232eb6ee4e0edebc0a8b9b6e0cf7 [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
42struct CodecInfo {
43 const char *mime;
44 const char *codec;
45};
46
47static const CodecInfo kDecoderInfo[] = {
Andreas Hubere6c40962009-09-10 14:13:30 -070048 { MEDIA_MIMETYPE_IMAGE_JPEG, "OMX.TI.JPEG.decode" },
49 { MEDIA_MIMETYPE_AUDIO_MPEG, "OMX.TI.MP3.decode" },
50 { MEDIA_MIMETYPE_AUDIO_MPEG, "OMX.PV.mp3dec" },
51 { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.TI.AMR.decode" },
52 { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.PV.amrdec" },
53 { MEDIA_MIMETYPE_AUDIO_AMR_WB, "OMX.TI.WBAMR.decode" },
54 { MEDIA_MIMETYPE_AUDIO_AMR_WB, "OMX.PV.amrdec" },
55 { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.TI.AAC.decode" },
56 { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.PV.aacdec" },
57 { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.qcom.video.decoder.mpeg4" },
58 { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.TI.Video.Decoder" },
59 { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.PV.mpeg4dec" },
60 { MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.video.decoder.h263" },
61 { MEDIA_MIMETYPE_VIDEO_H263, "OMX.TI.Video.Decoder" },
62 { MEDIA_MIMETYPE_VIDEO_H263, "OMX.PV.h263dec" },
63 { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.qcom.video.decoder.avc" },
64 { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.TI.Video.Decoder" },
65 { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.PV.avcdec" },
Andreas Huberbe06d262009-08-14 14:37:10 -070066};
67
68static const CodecInfo kEncoderInfo[] = {
Andreas Hubere6c40962009-09-10 14:13:30 -070069 { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.TI.AMR.encode" },
70 { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.PV.amrencnb" },
71 { MEDIA_MIMETYPE_AUDIO_AMR_WB, "OMX.TI.WBAMR.encode" },
72 { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.TI.AAC.encode" },
73 { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.PV.aacenc" },
74 { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.qcom.video.encoder.mpeg4" },
75 { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.TI.Video.encoder" },
76 { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.PV.mpeg4enc" },
77 { MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.video.encoder.h263" },
78 { MEDIA_MIMETYPE_VIDEO_H263, "OMX.TI.Video.encoder" },
79 { MEDIA_MIMETYPE_VIDEO_H263, "OMX.PV.h263enc" },
80 { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.TI.Video.encoder" },
81 { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.PV.avcenc" },
Andreas Huberbe06d262009-08-14 14:37:10 -070082};
83
Andreas Hubere0873732009-09-10 09:57:53 -070084#define CODEC_LOGI(x, ...) LOGI("[%s] "x, mComponentName, ##__VA_ARGS__)
Andreas Huber4c483422009-09-02 16:05:36 -070085#define CODEC_LOGV(x, ...) LOGV("[%s] "x, mComponentName, ##__VA_ARGS__)
86
Andreas Huberbe06d262009-08-14 14:37:10 -070087struct OMXCodecObserver : public BnOMXObserver {
88 OMXCodecObserver(const wp<OMXCodec> &target)
89 : mTarget(target) {
90 }
91
92 // from IOMXObserver
93 virtual void on_message(const omx_message &msg) {
94 sp<OMXCodec> codec = mTarget.promote();
95
96 if (codec.get() != NULL) {
97 codec->on_message(msg);
98 }
99 }
100
101protected:
102 virtual ~OMXCodecObserver() {}
103
104private:
105 wp<OMXCodec> mTarget;
106
107 OMXCodecObserver(const OMXCodecObserver &);
108 OMXCodecObserver &operator=(const OMXCodecObserver &);
109};
110
111static const char *GetCodec(const CodecInfo *info, size_t numInfos,
112 const char *mime, int index) {
113 CHECK(index >= 0);
114 for(size_t i = 0; i < numInfos; ++i) {
115 if (!strcasecmp(mime, info[i].mime)) {
116 if (index == 0) {
117 return info[i].codec;
118 }
119
120 --index;
121 }
122 }
123
124 return NULL;
125}
126
Andreas Huberebf66ea2009-08-19 13:32:58 -0700127enum {
128 kAVCProfileBaseline = 0x42,
129 kAVCProfileMain = 0x4d,
130 kAVCProfileExtended = 0x58,
131 kAVCProfileHigh = 0x64,
132 kAVCProfileHigh10 = 0x6e,
133 kAVCProfileHigh422 = 0x7a,
134 kAVCProfileHigh444 = 0xf4,
135 kAVCProfileCAVLC444Intra = 0x2c
136};
137
138static const char *AVCProfileToString(uint8_t profile) {
139 switch (profile) {
140 case kAVCProfileBaseline:
141 return "Baseline";
142 case kAVCProfileMain:
143 return "Main";
144 case kAVCProfileExtended:
145 return "Extended";
146 case kAVCProfileHigh:
147 return "High";
148 case kAVCProfileHigh10:
149 return "High 10";
150 case kAVCProfileHigh422:
151 return "High 422";
152 case kAVCProfileHigh444:
153 return "High 444";
154 case kAVCProfileCAVLC444Intra:
155 return "CAVLC 444 Intra";
156 default: return "Unknown";
157 }
158}
159
Andreas Huber4c483422009-09-02 16:05:36 -0700160template<class T>
161static void InitOMXParams(T *params) {
162 params->nSize = sizeof(T);
163 params->nVersion.s.nVersionMajor = 1;
164 params->nVersion.s.nVersionMinor = 0;
165 params->nVersion.s.nRevision = 0;
166 params->nVersion.s.nStep = 0;
167}
168
Andreas Huberbe06d262009-08-14 14:37:10 -0700169// static
170sp<OMXCodec> OMXCodec::Create(
171 const sp<IOMX> &omx,
172 const sp<MetaData> &meta, bool createEncoder,
Andreas Hubere6c40962009-09-10 14:13:30 -0700173 const sp<MediaSource> &source,
174 const char *matchComponentName) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700175 const char *mime;
176 bool success = meta->findCString(kKeyMIMEType, &mime);
177 CHECK(success);
178
179 const char *componentName = NULL;
180 IOMX::node_id node = 0;
181 for (int index = 0;; ++index) {
182 if (createEncoder) {
183 componentName = GetCodec(
184 kEncoderInfo, sizeof(kEncoderInfo) / sizeof(kEncoderInfo[0]),
185 mime, index);
186 } else {
187 componentName = GetCodec(
188 kDecoderInfo, sizeof(kDecoderInfo) / sizeof(kDecoderInfo[0]),
189 mime, index);
190 }
191
192 if (!componentName) {
193 return NULL;
194 }
195
Andreas Hubere6c40962009-09-10 14:13:30 -0700196 // If a specific codec is requested, skip the non-matching ones.
197 if (matchComponentName && strcmp(componentName, matchComponentName)) {
198 continue;
199 }
200
Andreas Huberbe06d262009-08-14 14:37:10 -0700201 LOGV("Attempting to allocate OMX node '%s'", componentName);
202
203 status_t err = omx->allocate_node(componentName, &node);
204 if (err == OK) {
Andreas Hubera7d0cf42009-09-04 07:48:51 -0700205 LOGI("Successfully allocated OMX node '%s'", componentName);
Andreas Huberbe06d262009-08-14 14:37:10 -0700206 break;
207 }
208 }
209
210 uint32_t quirks = 0;
211 if (!strcmp(componentName, "OMX.PV.avcdec")) {
Andreas Huber4f5e6022009-08-19 09:29:34 -0700212 quirks |= kWantsNALFragments;
Andreas Huberbe06d262009-08-14 14:37:10 -0700213 }
214 if (!strcmp(componentName, "OMX.TI.MP3.decode")) {
215 quirks |= kNeedsFlushBeforeDisable;
216 }
217 if (!strcmp(componentName, "OMX.TI.AAC.decode")) {
218 quirks |= kNeedsFlushBeforeDisable;
Andreas Huber404cc412009-08-25 14:26:05 -0700219 quirks |= kRequiresFlushCompleteEmulation;
Andreas Huber127fcdc2009-08-26 16:27:02 -0700220
221 // The following is currently necessary for proper shutdown
222 // behaviour, but NOT enabled by default in order to make the
223 // bug reproducible...
224 // quirks |= kRequiresFlushBeforeShutdown;
Andreas Huberbe06d262009-08-14 14:37:10 -0700225 }
226 if (!strncmp(componentName, "OMX.qcom.video.encoder.", 23)) {
227 quirks |= kRequiresLoadedToIdleAfterAllocation;
228 quirks |= kRequiresAllocateBufferOnInputPorts;
229 }
Andreas Hubera7d0cf42009-09-04 07:48:51 -0700230 if (!strncmp(componentName, "OMX.qcom.video.decoder.", 23)) {
231 // XXX Required on P....on only.
232 quirks |= kRequiresAllocateBufferOnOutputPorts;
233 }
Andreas Huberbe06d262009-08-14 14:37:10 -0700234
235 sp<OMXCodec> codec = new OMXCodec(
236 omx, node, quirks, createEncoder, mime, componentName,
237 source);
238
239 uint32_t type;
240 const void *data;
241 size_t size;
242 if (meta->findData(kKeyESDS, &type, &data, &size)) {
243 ESDS esds((const char *)data, size);
244 CHECK_EQ(esds.InitCheck(), OK);
245
246 const void *codec_specific_data;
247 size_t codec_specific_data_size;
248 esds.getCodecSpecificInfo(
249 &codec_specific_data, &codec_specific_data_size);
250
251 printf("found codec-specific data of size %d\n",
252 codec_specific_data_size);
253
254 codec->addCodecSpecificData(
255 codec_specific_data, codec_specific_data_size);
256 } else if (meta->findData(kKeyAVCC, &type, &data, &size)) {
257 printf("found avcc of size %d\n", size);
258
Andreas Huberebf66ea2009-08-19 13:32:58 -0700259 // Parse the AVCDecoderConfigurationRecord
260
261 const uint8_t *ptr = (const uint8_t *)data;
262
263 CHECK(size >= 7);
264 CHECK_EQ(ptr[0], 1); // configurationVersion == 1
265 uint8_t profile = ptr[1];
266 uint8_t level = ptr[3];
267
268 CHECK((ptr[4] >> 2) == 0x3f); // reserved
269
270 size_t lengthSize = 1 + (ptr[4] & 3);
271
272 // commented out check below as H264_QVGA_500_NO_AUDIO.3gp
273 // violates it...
274 // CHECK((ptr[5] >> 5) == 7); // reserved
275
276 size_t numSeqParameterSets = ptr[5] & 31;
277
278 ptr += 6;
Andreas Huberbe06d262009-08-14 14:37:10 -0700279 size -= 6;
Andreas Huberebf66ea2009-08-19 13:32:58 -0700280
281 for (size_t i = 0; i < numSeqParameterSets; ++i) {
282 CHECK(size >= 2);
283 size_t length = U16_AT(ptr);
Andreas Huberbe06d262009-08-14 14:37:10 -0700284
285 ptr += 2;
286 size -= 2;
287
Andreas Huberbe06d262009-08-14 14:37:10 -0700288 CHECK(size >= length);
289
290 codec->addCodecSpecificData(ptr, length);
291
292 ptr += length;
293 size -= length;
Andreas Huberebf66ea2009-08-19 13:32:58 -0700294 }
Andreas Huberbe06d262009-08-14 14:37:10 -0700295
Andreas Huberebf66ea2009-08-19 13:32:58 -0700296 CHECK(size >= 1);
297 size_t numPictureParameterSets = *ptr;
298 ++ptr;
299 --size;
Andreas Huberbe06d262009-08-14 14:37:10 -0700300
Andreas Huberebf66ea2009-08-19 13:32:58 -0700301 for (size_t i = 0; i < numPictureParameterSets; ++i) {
302 CHECK(size >= 2);
303 size_t length = U16_AT(ptr);
304
305 ptr += 2;
306 size -= 2;
307
308 CHECK(size >= length);
309
310 codec->addCodecSpecificData(ptr, length);
311
312 ptr += length;
313 size -= length;
314 }
315
316 LOGI("AVC profile = %d (%s), level = %d",
317 (int)profile, AVCProfileToString(profile), (int)level / 10);
318
319 if (!strcmp(componentName, "OMX.TI.Video.Decoder")
320 && (profile != kAVCProfileBaseline || level > 39)) {
321 // This stream exceeds the decoder's capabilities.
322
323 LOGE("Profile and/or level exceed the decoder's capabilities.");
324 return NULL;
Andreas Huberbe06d262009-08-14 14:37:10 -0700325 }
326 }
327
Andreas Hubere6c40962009-09-10 14:13:30 -0700328 if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime)) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700329 codec->setAMRFormat();
330 }
Andreas Hubere6c40962009-09-10 14:13:30 -0700331 if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) {
Andreas Huberee606e62009-09-08 10:19:21 -0700332 codec->setAMRWBFormat();
333 }
Andreas Hubere6c40962009-09-10 14:13:30 -0700334 if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) {
Andreas Huber43ad6eaf2009-09-01 16:02:43 -0700335 int32_t numChannels, sampleRate;
336 CHECK(meta->findInt32(kKeyChannelCount, &numChannels));
337 CHECK(meta->findInt32(kKeySampleRate, &sampleRate));
338
339 codec->setAACFormat(numChannels, sampleRate);
Andreas Huberbe06d262009-08-14 14:37:10 -0700340 }
341 if (!strncasecmp(mime, "video/", 6)) {
342 int32_t width, height;
343 bool success = meta->findInt32(kKeyWidth, &width);
344 success = success && meta->findInt32(kKeyHeight, &height);
Andreas Huber5c0a9132009-08-20 11:16:40 -0700345 CHECK(success);
Andreas Huberbe06d262009-08-14 14:37:10 -0700346
347 if (createEncoder) {
348 codec->setVideoInputFormat(mime, width, height);
349 } else {
350 codec->setVideoOutputFormat(mime, width, height);
351 }
352 }
Andreas Hubere6c40962009-09-10 14:13:30 -0700353 if (!strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_JPEG)
Andreas Huberbe06d262009-08-14 14:37:10 -0700354 && !strcmp(componentName, "OMX.TI.JPEG.decode")) {
355 OMX_COLOR_FORMATTYPE format =
356 OMX_COLOR_Format32bitARGB8888;
357 // OMX_COLOR_FormatYUV420PackedPlanar;
358 // OMX_COLOR_FormatCbYCrY;
359 // OMX_COLOR_FormatYUV411Planar;
360
361 int32_t width, height;
362 bool success = meta->findInt32(kKeyWidth, &width);
363 success = success && meta->findInt32(kKeyHeight, &height);
Andreas Huber5c0a9132009-08-20 11:16:40 -0700364
365 int32_t compressedSize;
366 success = success && meta->findInt32(
Andreas Huberda050cf22009-09-02 14:01:43 -0700367 kKeyMaxInputSize, &compressedSize);
Andreas Huber5c0a9132009-08-20 11:16:40 -0700368
369 CHECK(success);
370 CHECK(compressedSize > 0);
Andreas Huberbe06d262009-08-14 14:37:10 -0700371
372 codec->setImageOutputFormat(format, width, height);
Andreas Huber5c0a9132009-08-20 11:16:40 -0700373 codec->setJPEGInputFormat(width, height, (OMX_U32)compressedSize);
Andreas Huberbe06d262009-08-14 14:37:10 -0700374 }
375
Andreas Huberda050cf22009-09-02 14:01:43 -0700376 int32_t maxInputSize;
377 if (createEncoder && meta->findInt32(kKeyMaxInputSize, &maxInputSize)) {
378 codec->setMinBufferSize(kPortIndexInput, (OMX_U32)maxInputSize);
379 }
380
381 if (!strcmp(componentName, "OMX.TI.AMR.encode")
382 || !strcmp(componentName, "OMX.TI.WBAMR.encode")) {
383 codec->setMinBufferSize(kPortIndexOutput, 8192); // XXX
384 }
385
Andreas Huberbe06d262009-08-14 14:37:10 -0700386 codec->initOutputFormat(meta);
387
388 return codec;
389}
390
Andreas Huberda050cf22009-09-02 14:01:43 -0700391void OMXCodec::setMinBufferSize(OMX_U32 portIndex, OMX_U32 size) {
392 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -0700393 InitOMXParams(&def);
Andreas Huberda050cf22009-09-02 14:01:43 -0700394 def.nPortIndex = portIndex;
395
396 status_t err = mOMX->get_parameter(
397 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
398 CHECK_EQ(err, OK);
399
400 if (def.nBufferSize < size) {
401 def.nBufferSize = size;
402
403 }
404
405 err = mOMX->set_parameter(
406 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
407 CHECK_EQ(err, OK);
408}
409
Andreas Huberbe06d262009-08-14 14:37:10 -0700410status_t OMXCodec::setVideoPortFormatType(
411 OMX_U32 portIndex,
412 OMX_VIDEO_CODINGTYPE compressionFormat,
413 OMX_COLOR_FORMATTYPE colorFormat) {
414 OMX_VIDEO_PARAM_PORTFORMATTYPE format;
Andreas Huber4c483422009-09-02 16:05:36 -0700415 InitOMXParams(&format);
Andreas Huberbe06d262009-08-14 14:37:10 -0700416 format.nPortIndex = portIndex;
417 format.nIndex = 0;
418 bool found = false;
419
420 OMX_U32 index = 0;
421 for (;;) {
422 format.nIndex = index;
423 status_t err = mOMX->get_parameter(
424 mNode, OMX_IndexParamVideoPortFormat,
425 &format, sizeof(format));
426
427 if (err != OK) {
428 return err;
429 }
430
431 // The following assertion is violated by TI's video decoder.
Andreas Huber5c0a9132009-08-20 11:16:40 -0700432 // CHECK_EQ(format.nIndex, index);
Andreas Huberbe06d262009-08-14 14:37:10 -0700433
434#if 1
Andreas Hubere0873732009-09-10 09:57:53 -0700435 CODEC_LOGI("portIndex: %ld, index: %ld, eCompressionFormat=%d eColorFormat=%d",
Andreas Huberbe06d262009-08-14 14:37:10 -0700436 portIndex,
437 index, format.eCompressionFormat, format.eColorFormat);
438#endif
439
440 if (!strcmp("OMX.TI.Video.encoder", mComponentName)) {
441 if (portIndex == kPortIndexInput
442 && colorFormat == format.eColorFormat) {
443 // eCompressionFormat does not seem right.
444 found = true;
445 break;
446 }
447 if (portIndex == kPortIndexOutput
448 && compressionFormat == format.eCompressionFormat) {
449 // eColorFormat does not seem right.
450 found = true;
451 break;
452 }
453 }
454
455 if (format.eCompressionFormat == compressionFormat
456 && format.eColorFormat == colorFormat) {
457 found = true;
458 break;
459 }
460
461 ++index;
462 }
463
464 if (!found) {
465 return UNKNOWN_ERROR;
466 }
467
Andreas Hubere0873732009-09-10 09:57:53 -0700468 CODEC_LOGI("found a match.");
Andreas Huberbe06d262009-08-14 14:37:10 -0700469 status_t err = mOMX->set_parameter(
470 mNode, OMX_IndexParamVideoPortFormat,
471 &format, sizeof(format));
472
473 return err;
474}
475
476void OMXCodec::setVideoInputFormat(
477 const char *mime, OMX_U32 width, OMX_U32 height) {
Andreas Hubere0873732009-09-10 09:57:53 -0700478 CODEC_LOGI("setVideoInputFormat width=%ld, height=%ld", width, height);
Andreas Huberbe06d262009-08-14 14:37:10 -0700479
480 OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused;
Andreas Hubere6c40962009-09-10 14:13:30 -0700481 if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700482 compressionFormat = OMX_VIDEO_CodingAVC;
Andreas Hubere6c40962009-09-10 14:13:30 -0700483 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700484 compressionFormat = OMX_VIDEO_CodingMPEG4;
Andreas Hubere6c40962009-09-10 14:13:30 -0700485 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700486 compressionFormat = OMX_VIDEO_CodingH263;
487 } else {
488 LOGE("Not a supported video mime type: %s", mime);
489 CHECK(!"Should not be here. Not a supported video mime type.");
490 }
491
492 OMX_COLOR_FORMATTYPE colorFormat =
493 0 ? OMX_COLOR_FormatYCbYCr : OMX_COLOR_FormatCbYCrY;
494
495 if (!strncmp("OMX.qcom.video.encoder.", mComponentName, 23)) {
496 colorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
497 }
498
499 setVideoPortFormatType(
500 kPortIndexInput, OMX_VIDEO_CodingUnused,
501 colorFormat);
502
503 setVideoPortFormatType(
504 kPortIndexOutput, compressionFormat, OMX_COLOR_FormatUnused);
505
506 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -0700507 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -0700508 def.nPortIndex = kPortIndexOutput;
509
Andreas Huber4c483422009-09-02 16:05:36 -0700510 OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
511
Andreas Huberbe06d262009-08-14 14:37:10 -0700512 status_t err = mOMX->get_parameter(
513 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
514
515 CHECK_EQ(err, OK);
516 CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
517
518 video_def->nFrameWidth = width;
519 video_def->nFrameHeight = height;
520
521 video_def->eCompressionFormat = compressionFormat;
522 video_def->eColorFormat = OMX_COLOR_FormatUnused;
523
524 err = mOMX->set_parameter(
525 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
526 CHECK_EQ(err, OK);
527
528 ////////////////////////////////////////////////////////////////////////////
529
Andreas Huber4c483422009-09-02 16:05:36 -0700530 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -0700531 def.nPortIndex = kPortIndexInput;
532
533 err = mOMX->get_parameter(
534 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
535 CHECK_EQ(err, OK);
536
537 def.nBufferSize = (width * height * 2); // (width * height * 3) / 2;
Andreas Hubere0873732009-09-10 09:57:53 -0700538 CODEC_LOGI("Setting nBufferSize = %ld", def.nBufferSize);
Andreas Huberbe06d262009-08-14 14:37:10 -0700539
540 CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
541
542 video_def->nFrameWidth = width;
543 video_def->nFrameHeight = height;
544 video_def->eCompressionFormat = OMX_VIDEO_CodingUnused;
545 video_def->eColorFormat = colorFormat;
546
547 err = mOMX->set_parameter(
548 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
549 CHECK_EQ(err, OK);
550}
551
552void OMXCodec::setVideoOutputFormat(
553 const char *mime, OMX_U32 width, OMX_U32 height) {
Andreas Hubere0873732009-09-10 09:57:53 -0700554 CODEC_LOGI("setVideoOutputFormat width=%ld, height=%ld", width, height);
Andreas Huberbe06d262009-08-14 14:37:10 -0700555
Andreas Huberbe06d262009-08-14 14:37:10 -0700556 OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused;
Andreas Hubere6c40962009-09-10 14:13:30 -0700557 if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700558 compressionFormat = OMX_VIDEO_CodingAVC;
Andreas Hubere6c40962009-09-10 14:13:30 -0700559 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700560 compressionFormat = OMX_VIDEO_CodingMPEG4;
Andreas Hubere6c40962009-09-10 14:13:30 -0700561 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700562 compressionFormat = OMX_VIDEO_CodingH263;
563 } else {
564 LOGE("Not a supported video mime type: %s", mime);
565 CHECK(!"Should not be here. Not a supported video mime type.");
566 }
567
568 setVideoPortFormatType(
569 kPortIndexInput, compressionFormat, OMX_COLOR_FormatUnused);
570
571#if 1
572 {
573 OMX_VIDEO_PARAM_PORTFORMATTYPE format;
Andreas Huber4c483422009-09-02 16:05:36 -0700574 InitOMXParams(&format);
Andreas Huberbe06d262009-08-14 14:37:10 -0700575 format.nPortIndex = kPortIndexOutput;
576 format.nIndex = 0;
577
578 status_t err = mOMX->get_parameter(
579 mNode, OMX_IndexParamVideoPortFormat,
580 &format, sizeof(format));
581 CHECK_EQ(err, OK);
582 CHECK_EQ(format.eCompressionFormat, OMX_VIDEO_CodingUnused);
583
584 static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
585
586 CHECK(format.eColorFormat == OMX_COLOR_FormatYUV420Planar
587 || format.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar
588 || format.eColorFormat == OMX_COLOR_FormatCbYCrY
589 || format.eColorFormat == OMX_QCOM_COLOR_FormatYVU420SemiPlanar);
590
591 err = mOMX->set_parameter(
592 mNode, OMX_IndexParamVideoPortFormat,
593 &format, sizeof(format));
594 CHECK_EQ(err, OK);
595 }
596#endif
597
598 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -0700599 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -0700600 def.nPortIndex = kPortIndexInput;
601
Andreas Huber4c483422009-09-02 16:05:36 -0700602 OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
603
Andreas Huberbe06d262009-08-14 14:37:10 -0700604 status_t err = mOMX->get_parameter(
605 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
606
607 CHECK_EQ(err, OK);
608
609#if 1
610 // XXX Need a (much) better heuristic to compute input buffer sizes.
611 const size_t X = 64 * 1024;
612 if (def.nBufferSize < X) {
613 def.nBufferSize = X;
614 }
615#endif
616
617 CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
618
619 video_def->nFrameWidth = width;
620 video_def->nFrameHeight = height;
621
622 video_def->eColorFormat = OMX_COLOR_FormatUnused;
623
624 err = mOMX->set_parameter(
625 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
626 CHECK_EQ(err, OK);
627
628 ////////////////////////////////////////////////////////////////////////////
629
Andreas Huber4c483422009-09-02 16:05:36 -0700630 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -0700631 def.nPortIndex = kPortIndexOutput;
632
633 err = mOMX->get_parameter(
634 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
635 CHECK_EQ(err, OK);
636 CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
637
638#if 0
639 def.nBufferSize =
640 (((width + 15) & -16) * ((height + 15) & -16) * 3) / 2; // YUV420
641#endif
642
643 video_def->nFrameWidth = width;
644 video_def->nFrameHeight = height;
645
646 err = mOMX->set_parameter(
647 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
648 CHECK_EQ(err, OK);
649}
650
651
652OMXCodec::OMXCodec(
653 const sp<IOMX> &omx, IOMX::node_id node, uint32_t quirks,
Andreas Huberebf66ea2009-08-19 13:32:58 -0700654 bool isEncoder,
Andreas Huberbe06d262009-08-14 14:37:10 -0700655 const char *mime,
656 const char *componentName,
657 const sp<MediaSource> &source)
658 : mOMX(omx),
659 mNode(node),
660 mQuirks(quirks),
661 mIsEncoder(isEncoder),
662 mMIME(strdup(mime)),
663 mComponentName(strdup(componentName)),
664 mSource(source),
665 mCodecSpecificDataIndex(0),
Andreas Huberbe06d262009-08-14 14:37:10 -0700666 mState(LOADED),
Andreas Huber42978e52009-08-27 10:08:39 -0700667 mInitialBufferSubmit(true),
Andreas Huberbe06d262009-08-14 14:37:10 -0700668 mSignalledEOS(false),
669 mNoMoreOutputData(false),
670 mSeekTimeUs(-1) {
671 mPortStatus[kPortIndexInput] = ENABLED;
672 mPortStatus[kPortIndexOutput] = ENABLED;
673
674 mObserver = new OMXCodecObserver(this);
675 mOMX->observe_node(mNode, mObserver);
Andreas Huber4c483422009-09-02 16:05:36 -0700676
677 setComponentRole();
678}
679
Andreas Hubere6c40962009-09-10 14:13:30 -0700680// static
681void OMXCodec::setComponentRole(
682 const sp<IOMX> &omx, IOMX::node_id node, bool isEncoder,
683 const char *mime) {
Andreas Huber4c483422009-09-02 16:05:36 -0700684 struct MimeToRole {
685 const char *mime;
686 const char *decoderRole;
687 const char *encoderRole;
688 };
689
690 static const MimeToRole kMimeToRole[] = {
Andreas Hubere6c40962009-09-10 14:13:30 -0700691 { MEDIA_MIMETYPE_AUDIO_MPEG,
692 "audio_decoder.mp3", "audio_encoder.mp3" },
693 { MEDIA_MIMETYPE_AUDIO_AMR_NB,
694 "audio_decoder.amrnb", "audio_encoder.amrnb" },
695 { MEDIA_MIMETYPE_AUDIO_AMR_WB,
696 "audio_decoder.amrwb", "audio_encoder.amrwb" },
697 { MEDIA_MIMETYPE_AUDIO_AAC,
698 "audio_decoder.aac", "audio_encoder.aac" },
699 { MEDIA_MIMETYPE_VIDEO_AVC,
700 "video_decoder.avc", "video_encoder.avc" },
701 { MEDIA_MIMETYPE_VIDEO_MPEG4,
702 "video_decoder.mpeg4", "video_encoder.mpeg4" },
703 { MEDIA_MIMETYPE_VIDEO_H263,
704 "video_decoder.h263", "video_encoder.h263" },
Andreas Huber4c483422009-09-02 16:05:36 -0700705 };
706
707 static const size_t kNumMimeToRole =
708 sizeof(kMimeToRole) / sizeof(kMimeToRole[0]);
709
710 size_t i;
711 for (i = 0; i < kNumMimeToRole; ++i) {
Andreas Hubere6c40962009-09-10 14:13:30 -0700712 if (!strcasecmp(mime, kMimeToRole[i].mime)) {
Andreas Huber4c483422009-09-02 16:05:36 -0700713 break;
714 }
715 }
716
717 if (i == kNumMimeToRole) {
718 return;
719 }
720
721 const char *role =
Andreas Hubere6c40962009-09-10 14:13:30 -0700722 isEncoder ? kMimeToRole[i].encoderRole
723 : kMimeToRole[i].decoderRole;
Andreas Huber4c483422009-09-02 16:05:36 -0700724
725 if (role != NULL) {
Andreas Huber4c483422009-09-02 16:05:36 -0700726 OMX_PARAM_COMPONENTROLETYPE roleParams;
727 InitOMXParams(&roleParams);
728
729 strncpy((char *)roleParams.cRole,
730 role, OMX_MAX_STRINGNAME_SIZE - 1);
731
732 roleParams.cRole[OMX_MAX_STRINGNAME_SIZE - 1] = '\0';
733
Andreas Hubere6c40962009-09-10 14:13:30 -0700734 status_t err = omx->set_parameter(
735 node, OMX_IndexParamStandardComponentRole,
Andreas Huber4c483422009-09-02 16:05:36 -0700736 &roleParams, sizeof(roleParams));
737
738 if (err != OK) {
739 LOGW("Failed to set standard component role '%s'.", role);
740 }
741 }
Andreas Huberbe06d262009-08-14 14:37:10 -0700742}
743
Andreas Hubere6c40962009-09-10 14:13:30 -0700744void OMXCodec::setComponentRole() {
745 setComponentRole(mOMX, mNode, mIsEncoder, mMIME);
746}
747
Andreas Huberbe06d262009-08-14 14:37:10 -0700748OMXCodec::~OMXCodec() {
Andreas Huber4f5e6022009-08-19 09:29:34 -0700749 CHECK(mState == LOADED || mState == ERROR);
Andreas Huberbe06d262009-08-14 14:37:10 -0700750
751 status_t err = mOMX->observe_node(mNode, NULL);
752 CHECK_EQ(err, OK);
753
754 err = mOMX->free_node(mNode);
755 CHECK_EQ(err, OK);
756
757 mNode = NULL;
758 setState(DEAD);
759
760 clearCodecSpecificData();
761
762 free(mComponentName);
763 mComponentName = NULL;
Andreas Huberebf66ea2009-08-19 13:32:58 -0700764
Andreas Huberbe06d262009-08-14 14:37:10 -0700765 free(mMIME);
766 mMIME = NULL;
767}
768
769status_t OMXCodec::init() {
Andreas Huber42978e52009-08-27 10:08:39 -0700770 // mLock is held.
Andreas Huberbe06d262009-08-14 14:37:10 -0700771
772 CHECK_EQ(mState, LOADED);
773
774 status_t err;
775 if (!(mQuirks & kRequiresLoadedToIdleAfterAllocation)) {
776 err = mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
777 CHECK_EQ(err, OK);
Andreas Huberbe06d262009-08-14 14:37:10 -0700778 setState(LOADED_TO_IDLE);
779 }
780
781 err = allocateBuffers();
782 CHECK_EQ(err, OK);
783
784 if (mQuirks & kRequiresLoadedToIdleAfterAllocation) {
785 err = mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
786 CHECK_EQ(err, OK);
787
788 setState(LOADED_TO_IDLE);
789 }
790
791 while (mState != EXECUTING && mState != ERROR) {
792 mAsyncCompletion.wait(mLock);
793 }
794
795 return mState == ERROR ? UNKNOWN_ERROR : OK;
796}
797
798// static
799bool OMXCodec::isIntermediateState(State state) {
800 return state == LOADED_TO_IDLE
801 || state == IDLE_TO_EXECUTING
802 || state == EXECUTING_TO_IDLE
803 || state == IDLE_TO_LOADED
804 || state == RECONFIGURING;
805}
806
807status_t OMXCodec::allocateBuffers() {
808 status_t err = allocateBuffersOnPort(kPortIndexInput);
809
810 if (err != OK) {
811 return err;
812 }
813
814 return allocateBuffersOnPort(kPortIndexOutput);
815}
816
817status_t OMXCodec::allocateBuffersOnPort(OMX_U32 portIndex) {
818 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -0700819 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -0700820 def.nPortIndex = portIndex;
821
822 status_t err = mOMX->get_parameter(
823 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
824
825 if (err != OK) {
826 return err;
827 }
828
Andreas Huber5c0a9132009-08-20 11:16:40 -0700829 size_t totalSize = def.nBufferCountActual * def.nBufferSize;
830 mDealer[portIndex] = new MemoryDealer(totalSize);
831
Andreas Huberbe06d262009-08-14 14:37:10 -0700832 for (OMX_U32 i = 0; i < def.nBufferCountActual; ++i) {
Andreas Huber5c0a9132009-08-20 11:16:40 -0700833 sp<IMemory> mem = mDealer[portIndex]->allocate(def.nBufferSize);
Andreas Huberbe06d262009-08-14 14:37:10 -0700834 CHECK(mem.get() != NULL);
835
836 IOMX::buffer_id buffer;
837 if (portIndex == kPortIndexInput
838 && (mQuirks & kRequiresAllocateBufferOnInputPorts)) {
839 err = mOMX->allocate_buffer_with_backup(
840 mNode, portIndex, mem, &buffer);
Andreas Huber446f44f2009-08-25 17:23:44 -0700841 } else if (portIndex == kPortIndexOutput
842 && (mQuirks & kRequiresAllocateBufferOnOutputPorts)) {
843 err = mOMX->allocate_buffer(
844 mNode, portIndex, def.nBufferSize, &buffer);
Andreas Huberbe06d262009-08-14 14:37:10 -0700845 } else {
846 err = mOMX->use_buffer(mNode, portIndex, mem, &buffer);
847 }
848
849 if (err != OK) {
850 LOGE("allocate_buffer_with_backup failed");
851 return err;
852 }
853
854 BufferInfo info;
855 info.mBuffer = buffer;
856 info.mOwnedByComponent = false;
857 info.mMem = mem;
858 info.mMediaBuffer = NULL;
859
860 if (portIndex == kPortIndexOutput) {
861 info.mMediaBuffer = new MediaBuffer(mem->pointer(), mem->size());
862 info.mMediaBuffer->setObserver(this);
863 }
864
865 mPortBuffers[portIndex].push(info);
866
Andreas Huber4c483422009-09-02 16:05:36 -0700867 CODEC_LOGV("allocated buffer %p on %s port", buffer,
Andreas Huberbe06d262009-08-14 14:37:10 -0700868 portIndex == kPortIndexInput ? "input" : "output");
869 }
870
871 dumpPortStatus(portIndex);
872
873 return OK;
874}
875
876void OMXCodec::on_message(const omx_message &msg) {
877 Mutex::Autolock autoLock(mLock);
878
879 switch (msg.type) {
880 case omx_message::EVENT:
881 {
882 onEvent(
883 msg.u.event_data.event, msg.u.event_data.data1,
884 msg.u.event_data.data2);
885
886 break;
887 }
888
889 case omx_message::EMPTY_BUFFER_DONE:
890 {
891 IOMX::buffer_id buffer = msg.u.extended_buffer_data.buffer;
892
Andreas Huber4c483422009-09-02 16:05:36 -0700893 CODEC_LOGV("EMPTY_BUFFER_DONE(buffer: %p)", buffer);
Andreas Huberbe06d262009-08-14 14:37:10 -0700894
895 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
896 size_t i = 0;
897 while (i < buffers->size() && (*buffers)[i].mBuffer != buffer) {
898 ++i;
899 }
900
901 CHECK(i < buffers->size());
902 if (!(*buffers)[i].mOwnedByComponent) {
903 LOGW("We already own input buffer %p, yet received "
904 "an EMPTY_BUFFER_DONE.", buffer);
905 }
906
907 buffers->editItemAt(i).mOwnedByComponent = false;
908
909 if (mPortStatus[kPortIndexInput] == DISABLING) {
Andreas Huber4c483422009-09-02 16:05:36 -0700910 CODEC_LOGV("Port is disabled, freeing buffer %p", buffer);
Andreas Huberbe06d262009-08-14 14:37:10 -0700911
912 status_t err =
913 mOMX->free_buffer(mNode, kPortIndexInput, buffer);
914 CHECK_EQ(err, OK);
915
916 buffers->removeAt(i);
917 } else if (mPortStatus[kPortIndexInput] != SHUTTING_DOWN) {
918 CHECK_EQ(mPortStatus[kPortIndexInput], ENABLED);
919 drainInputBuffer(&buffers->editItemAt(i));
920 }
921
922 break;
923 }
924
925 case omx_message::FILL_BUFFER_DONE:
926 {
927 IOMX::buffer_id buffer = msg.u.extended_buffer_data.buffer;
928 OMX_U32 flags = msg.u.extended_buffer_data.flags;
929
Andreas Huber4c483422009-09-02 16:05:36 -0700930 CODEC_LOGV("FILL_BUFFER_DONE(buffer: %p, size: %ld, flags: 0x%08lx)",
Andreas Huberbe06d262009-08-14 14:37:10 -0700931 buffer,
932 msg.u.extended_buffer_data.range_length,
933 flags);
934
Andreas Huber4c483422009-09-02 16:05:36 -0700935 CODEC_LOGV("FILL_BUFFER_DONE(timestamp: %lld us (%.2f secs))",
Andreas Huberbe06d262009-08-14 14:37:10 -0700936 msg.u.extended_buffer_data.timestamp,
937 msg.u.extended_buffer_data.timestamp / 1E6);
938
939 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
940 size_t i = 0;
941 while (i < buffers->size() && (*buffers)[i].mBuffer != buffer) {
942 ++i;
943 }
944
945 CHECK(i < buffers->size());
946 BufferInfo *info = &buffers->editItemAt(i);
947
948 if (!info->mOwnedByComponent) {
949 LOGW("We already own output buffer %p, yet received "
950 "a FILL_BUFFER_DONE.", buffer);
951 }
952
953 info->mOwnedByComponent = false;
954
955 if (mPortStatus[kPortIndexOutput] == DISABLING) {
Andreas Huber4c483422009-09-02 16:05:36 -0700956 CODEC_LOGV("Port is disabled, freeing buffer %p", buffer);
Andreas Huberbe06d262009-08-14 14:37:10 -0700957
958 status_t err =
959 mOMX->free_buffer(mNode, kPortIndexOutput, buffer);
960 CHECK_EQ(err, OK);
961
962 buffers->removeAt(i);
Andreas Huberd7795892009-08-26 10:33:47 -0700963 } else if (mPortStatus[kPortIndexOutput] == ENABLED
964 && (flags & OMX_BUFFERFLAG_EOS)) {
Andreas Huber4c483422009-09-02 16:05:36 -0700965 CODEC_LOGV("No more output data.");
Andreas Huberbe06d262009-08-14 14:37:10 -0700966 mNoMoreOutputData = true;
967 mBufferFilled.signal();
968 } else if (mPortStatus[kPortIndexOutput] != SHUTTING_DOWN) {
969 CHECK_EQ(mPortStatus[kPortIndexOutput], ENABLED);
Andreas Huberebf66ea2009-08-19 13:32:58 -0700970
Andreas Huberbe06d262009-08-14 14:37:10 -0700971 MediaBuffer *buffer = info->mMediaBuffer;
972
973 buffer->set_range(
974 msg.u.extended_buffer_data.range_offset,
975 msg.u.extended_buffer_data.range_length);
976
977 buffer->meta_data()->clear();
978
979 buffer->meta_data()->setInt32(
980 kKeyTimeUnits,
981 (msg.u.extended_buffer_data.timestamp + 500) / 1000);
982
983 buffer->meta_data()->setInt32(
984 kKeyTimeScale, 1000);
985
986 if (msg.u.extended_buffer_data.flags & OMX_BUFFERFLAG_SYNCFRAME) {
987 buffer->meta_data()->setInt32(kKeyIsSyncFrame, true);
988 }
989
990 buffer->meta_data()->setPointer(
991 kKeyPlatformPrivate,
992 msg.u.extended_buffer_data.platform_private);
993
994 buffer->meta_data()->setPointer(
995 kKeyBufferID,
996 msg.u.extended_buffer_data.buffer);
997
998 mFilledBuffers.push_back(i);
999 mBufferFilled.signal();
1000 }
1001
1002 break;
1003 }
1004
1005 default:
1006 {
1007 CHECK(!"should not be here.");
1008 break;
1009 }
1010 }
1011}
1012
1013void OMXCodec::onEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) {
1014 switch (event) {
1015 case OMX_EventCmdComplete:
1016 {
1017 onCmdComplete((OMX_COMMANDTYPE)data1, data2);
1018 break;
1019 }
1020
1021 case OMX_EventError:
1022 {
1023 LOGE("ERROR(%ld, %ld)", data1, data2);
1024
1025 setState(ERROR);
1026 break;
1027 }
1028
1029 case OMX_EventPortSettingsChanged:
1030 {
1031 onPortSettingsChanged(data1);
1032 break;
1033 }
1034
1035 case OMX_EventBufferFlag:
1036 {
Andreas Huber4c483422009-09-02 16:05:36 -07001037 CODEC_LOGV("EVENT_BUFFER_FLAG(%ld)", data1);
Andreas Huberbe06d262009-08-14 14:37:10 -07001038
1039 if (data1 == kPortIndexOutput) {
1040 mNoMoreOutputData = true;
1041 }
1042 break;
1043 }
1044
1045 default:
1046 {
Andreas Huber4c483422009-09-02 16:05:36 -07001047 CODEC_LOGV("EVENT(%d, %ld, %ld)", event, data1, data2);
Andreas Huberbe06d262009-08-14 14:37:10 -07001048 break;
1049 }
1050 }
1051}
1052
1053void OMXCodec::onCmdComplete(OMX_COMMANDTYPE cmd, OMX_U32 data) {
1054 switch (cmd) {
1055 case OMX_CommandStateSet:
1056 {
1057 onStateChange((OMX_STATETYPE)data);
1058 break;
1059 }
1060
1061 case OMX_CommandPortDisable:
1062 {
1063 OMX_U32 portIndex = data;
Andreas Huber4c483422009-09-02 16:05:36 -07001064 CODEC_LOGV("PORT_DISABLED(%ld)", portIndex);
Andreas Huberbe06d262009-08-14 14:37:10 -07001065
1066 CHECK(mState == EXECUTING || mState == RECONFIGURING);
1067 CHECK_EQ(mPortStatus[portIndex], DISABLING);
1068 CHECK_EQ(mPortBuffers[portIndex].size(), 0);
1069
1070 mPortStatus[portIndex] = DISABLED;
1071
1072 if (mState == RECONFIGURING) {
1073 CHECK_EQ(portIndex, kPortIndexOutput);
1074
1075 enablePortAsync(portIndex);
1076
1077 status_t err = allocateBuffersOnPort(portIndex);
1078 CHECK_EQ(err, OK);
1079 }
1080 break;
1081 }
1082
1083 case OMX_CommandPortEnable:
1084 {
1085 OMX_U32 portIndex = data;
Andreas Huber4c483422009-09-02 16:05:36 -07001086 CODEC_LOGV("PORT_ENABLED(%ld)", portIndex);
Andreas Huberbe06d262009-08-14 14:37:10 -07001087
1088 CHECK(mState == EXECUTING || mState == RECONFIGURING);
1089 CHECK_EQ(mPortStatus[portIndex], ENABLING);
1090
1091 mPortStatus[portIndex] = ENABLED;
1092
1093 if (mState == RECONFIGURING) {
1094 CHECK_EQ(portIndex, kPortIndexOutput);
1095
1096 setState(EXECUTING);
1097
1098 fillOutputBuffers();
1099 }
1100 break;
1101 }
1102
1103 case OMX_CommandFlush:
1104 {
1105 OMX_U32 portIndex = data;
1106
Andreas Huber4c483422009-09-02 16:05:36 -07001107 CODEC_LOGV("FLUSH_DONE(%ld)", portIndex);
Andreas Huberbe06d262009-08-14 14:37:10 -07001108
1109 CHECK_EQ(mPortStatus[portIndex], SHUTTING_DOWN);
1110 mPortStatus[portIndex] = ENABLED;
1111
1112 CHECK_EQ(countBuffersWeOwn(mPortBuffers[portIndex]),
1113 mPortBuffers[portIndex].size());
1114
1115 if (mState == RECONFIGURING) {
1116 CHECK_EQ(portIndex, kPortIndexOutput);
1117
1118 disablePortAsync(portIndex);
Andreas Huber127fcdc2009-08-26 16:27:02 -07001119 } else if (mState == EXECUTING_TO_IDLE) {
1120 if (mPortStatus[kPortIndexInput] == ENABLED
1121 && mPortStatus[kPortIndexOutput] == ENABLED) {
Andreas Huber4c483422009-09-02 16:05:36 -07001122 CODEC_LOGV("Finished flushing both ports, now completing "
Andreas Huber127fcdc2009-08-26 16:27:02 -07001123 "transition from EXECUTING to IDLE.");
1124
1125 mPortStatus[kPortIndexInput] = SHUTTING_DOWN;
1126 mPortStatus[kPortIndexOutput] = SHUTTING_DOWN;
1127
1128 status_t err =
1129 mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
1130 CHECK_EQ(err, OK);
1131 }
Andreas Huberbe06d262009-08-14 14:37:10 -07001132 } else {
1133 // We're flushing both ports in preparation for seeking.
1134
1135 if (mPortStatus[kPortIndexInput] == ENABLED
1136 && mPortStatus[kPortIndexOutput] == ENABLED) {
Andreas Huber4c483422009-09-02 16:05:36 -07001137 CODEC_LOGV("Finished flushing both ports, now continuing from"
Andreas Huberbe06d262009-08-14 14:37:10 -07001138 " seek-time.");
1139
1140 drainInputBuffers();
1141 fillOutputBuffers();
1142 }
1143 }
1144
1145 break;
1146 }
1147
1148 default:
1149 {
Andreas Huber4c483422009-09-02 16:05:36 -07001150 CODEC_LOGV("CMD_COMPLETE(%d, %ld)", cmd, data);
Andreas Huberbe06d262009-08-14 14:37:10 -07001151 break;
1152 }
1153 }
1154}
1155
1156void OMXCodec::onStateChange(OMX_STATETYPE newState) {
1157 switch (newState) {
1158 case OMX_StateIdle:
1159 {
Andreas Huber4c483422009-09-02 16:05:36 -07001160 CODEC_LOGV("Now Idle.");
Andreas Huberbe06d262009-08-14 14:37:10 -07001161 if (mState == LOADED_TO_IDLE) {
1162 status_t err = mOMX->send_command(
1163 mNode, OMX_CommandStateSet, OMX_StateExecuting);
1164
1165 CHECK_EQ(err, OK);
1166
1167 setState(IDLE_TO_EXECUTING);
1168 } else {
1169 CHECK_EQ(mState, EXECUTING_TO_IDLE);
1170
1171 CHECK_EQ(
1172 countBuffersWeOwn(mPortBuffers[kPortIndexInput]),
1173 mPortBuffers[kPortIndexInput].size());
1174
1175 CHECK_EQ(
1176 countBuffersWeOwn(mPortBuffers[kPortIndexOutput]),
1177 mPortBuffers[kPortIndexOutput].size());
1178
1179 status_t err = mOMX->send_command(
1180 mNode, OMX_CommandStateSet, OMX_StateLoaded);
1181
1182 CHECK_EQ(err, OK);
1183
1184 err = freeBuffersOnPort(kPortIndexInput);
1185 CHECK_EQ(err, OK);
1186
1187 err = freeBuffersOnPort(kPortIndexOutput);
1188 CHECK_EQ(err, OK);
1189
1190 mPortStatus[kPortIndexInput] = ENABLED;
1191 mPortStatus[kPortIndexOutput] = ENABLED;
1192
1193 setState(IDLE_TO_LOADED);
1194 }
1195 break;
1196 }
1197
1198 case OMX_StateExecuting:
1199 {
1200 CHECK_EQ(mState, IDLE_TO_EXECUTING);
1201
Andreas Huber4c483422009-09-02 16:05:36 -07001202 CODEC_LOGV("Now Executing.");
Andreas Huberbe06d262009-08-14 14:37:10 -07001203
1204 setState(EXECUTING);
1205
Andreas Huber42978e52009-08-27 10:08:39 -07001206 // Buffers will be submitted to the component in the first
1207 // call to OMXCodec::read as mInitialBufferSubmit is true at
1208 // this point. This ensures that this on_message call returns,
1209 // releases the lock and ::init can notice the state change and
1210 // itself return.
Andreas Huberbe06d262009-08-14 14:37:10 -07001211 break;
1212 }
1213
1214 case OMX_StateLoaded:
1215 {
1216 CHECK_EQ(mState, IDLE_TO_LOADED);
1217
Andreas Huber4c483422009-09-02 16:05:36 -07001218 CODEC_LOGV("Now Loaded.");
Andreas Huberbe06d262009-08-14 14:37:10 -07001219
1220 setState(LOADED);
1221 break;
1222 }
1223
1224 default:
1225 {
1226 CHECK(!"should not be here.");
1227 break;
1228 }
1229 }
1230}
1231
1232// static
1233size_t OMXCodec::countBuffersWeOwn(const Vector<BufferInfo> &buffers) {
1234 size_t n = 0;
1235 for (size_t i = 0; i < buffers.size(); ++i) {
1236 if (!buffers[i].mOwnedByComponent) {
1237 ++n;
1238 }
1239 }
1240
1241 return n;
1242}
1243
1244status_t OMXCodec::freeBuffersOnPort(
1245 OMX_U32 portIndex, bool onlyThoseWeOwn) {
1246 Vector<BufferInfo> *buffers = &mPortBuffers[portIndex];
1247
1248 status_t stickyErr = OK;
1249
1250 for (size_t i = buffers->size(); i-- > 0;) {
1251 BufferInfo *info = &buffers->editItemAt(i);
1252
1253 if (onlyThoseWeOwn && info->mOwnedByComponent) {
1254 continue;
1255 }
1256
1257 CHECK_EQ(info->mOwnedByComponent, false);
1258
1259 status_t err =
1260 mOMX->free_buffer(mNode, portIndex, info->mBuffer);
1261
1262 if (err != OK) {
1263 stickyErr = err;
1264 }
1265
1266 if (info->mMediaBuffer != NULL) {
1267 info->mMediaBuffer->setObserver(NULL);
1268
1269 // Make sure nobody but us owns this buffer at this point.
1270 CHECK_EQ(info->mMediaBuffer->refcount(), 0);
1271
1272 info->mMediaBuffer->release();
1273 }
1274
1275 buffers->removeAt(i);
1276 }
1277
1278 CHECK(onlyThoseWeOwn || buffers->isEmpty());
1279
1280 return stickyErr;
1281}
1282
1283void OMXCodec::onPortSettingsChanged(OMX_U32 portIndex) {
Andreas Huber4c483422009-09-02 16:05:36 -07001284 CODEC_LOGV("PORT_SETTINGS_CHANGED(%ld)", portIndex);
Andreas Huberbe06d262009-08-14 14:37:10 -07001285
1286 CHECK_EQ(mState, EXECUTING);
1287 CHECK_EQ(portIndex, kPortIndexOutput);
1288 setState(RECONFIGURING);
1289
1290 if (mQuirks & kNeedsFlushBeforeDisable) {
Andreas Huber404cc412009-08-25 14:26:05 -07001291 if (!flushPortAsync(portIndex)) {
1292 onCmdComplete(OMX_CommandFlush, portIndex);
1293 }
Andreas Huberbe06d262009-08-14 14:37:10 -07001294 } else {
1295 disablePortAsync(portIndex);
1296 }
1297}
1298
Andreas Huber404cc412009-08-25 14:26:05 -07001299bool OMXCodec::flushPortAsync(OMX_U32 portIndex) {
Andreas Huber127fcdc2009-08-26 16:27:02 -07001300 CHECK(mState == EXECUTING || mState == RECONFIGURING
1301 || mState == EXECUTING_TO_IDLE);
Andreas Huberbe06d262009-08-14 14:37:10 -07001302
Andreas Huber4c483422009-09-02 16:05:36 -07001303 CODEC_LOGV("flushPortAsync(%ld): we own %d out of %d buffers already.",
Andreas Huber404cc412009-08-25 14:26:05 -07001304 portIndex, countBuffersWeOwn(mPortBuffers[portIndex]),
1305 mPortBuffers[portIndex].size());
1306
Andreas Huberbe06d262009-08-14 14:37:10 -07001307 CHECK_EQ(mPortStatus[portIndex], ENABLED);
1308 mPortStatus[portIndex] = SHUTTING_DOWN;
1309
Andreas Huber404cc412009-08-25 14:26:05 -07001310 if ((mQuirks & kRequiresFlushCompleteEmulation)
1311 && countBuffersWeOwn(mPortBuffers[portIndex])
1312 == mPortBuffers[portIndex].size()) {
1313 // No flush is necessary and this component fails to send a
1314 // flush-complete event in this case.
1315
1316 return false;
1317 }
1318
Andreas Huberbe06d262009-08-14 14:37:10 -07001319 status_t err =
1320 mOMX->send_command(mNode, OMX_CommandFlush, portIndex);
1321 CHECK_EQ(err, OK);
Andreas Huber404cc412009-08-25 14:26:05 -07001322
1323 return true;
Andreas Huberbe06d262009-08-14 14:37:10 -07001324}
1325
1326void OMXCodec::disablePortAsync(OMX_U32 portIndex) {
1327 CHECK(mState == EXECUTING || mState == RECONFIGURING);
1328
1329 CHECK_EQ(mPortStatus[portIndex], ENABLED);
1330 mPortStatus[portIndex] = DISABLING;
1331
1332 status_t err =
1333 mOMX->send_command(mNode, OMX_CommandPortDisable, portIndex);
1334 CHECK_EQ(err, OK);
1335
1336 freeBuffersOnPort(portIndex, true);
1337}
1338
1339void OMXCodec::enablePortAsync(OMX_U32 portIndex) {
1340 CHECK(mState == EXECUTING || mState == RECONFIGURING);
1341
1342 CHECK_EQ(mPortStatus[portIndex], DISABLED);
1343 mPortStatus[portIndex] = ENABLING;
1344
1345 status_t err =
1346 mOMX->send_command(mNode, OMX_CommandPortEnable, portIndex);
1347 CHECK_EQ(err, OK);
1348}
1349
1350void OMXCodec::fillOutputBuffers() {
1351 CHECK_EQ(mState, EXECUTING);
1352
1353 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
1354 for (size_t i = 0; i < buffers->size(); ++i) {
1355 fillOutputBuffer(&buffers->editItemAt(i));
1356 }
1357}
1358
1359void OMXCodec::drainInputBuffers() {
Andreas Huberd06e5b82009-08-28 13:18:14 -07001360 CHECK(mState == EXECUTING || mState == RECONFIGURING);
Andreas Huberbe06d262009-08-14 14:37:10 -07001361
1362 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
1363 for (size_t i = 0; i < buffers->size(); ++i) {
1364 drainInputBuffer(&buffers->editItemAt(i));
1365 }
1366}
1367
1368void OMXCodec::drainInputBuffer(BufferInfo *info) {
1369 CHECK_EQ(info->mOwnedByComponent, false);
1370
1371 if (mSignalledEOS) {
1372 return;
1373 }
1374
1375 if (mCodecSpecificDataIndex < mCodecSpecificData.size()) {
1376 const CodecSpecificData *specific =
1377 mCodecSpecificData[mCodecSpecificDataIndex];
1378
1379 size_t size = specific->mSize;
1380
Andreas Hubere6c40962009-09-10 14:13:30 -07001381 if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mMIME)
Andreas Huber4f5e6022009-08-19 09:29:34 -07001382 && !(mQuirks & kWantsNALFragments)) {
Andreas Huberbe06d262009-08-14 14:37:10 -07001383 static const uint8_t kNALStartCode[4] =
1384 { 0x00, 0x00, 0x00, 0x01 };
1385
1386 CHECK(info->mMem->size() >= specific->mSize + 4);
1387
1388 size += 4;
1389
1390 memcpy(info->mMem->pointer(), kNALStartCode, 4);
1391 memcpy((uint8_t *)info->mMem->pointer() + 4,
1392 specific->mData, specific->mSize);
1393 } else {
1394 CHECK(info->mMem->size() >= specific->mSize);
1395 memcpy(info->mMem->pointer(), specific->mData, specific->mSize);
1396 }
1397
1398 mOMX->empty_buffer(
1399 mNode, info->mBuffer, 0, size,
1400 OMX_BUFFERFLAG_ENDOFFRAME | OMX_BUFFERFLAG_CODECCONFIG,
1401 0);
1402
1403 info->mOwnedByComponent = true;
1404
1405 ++mCodecSpecificDataIndex;
1406 return;
1407 }
1408
1409 MediaBuffer *srcBuffer;
1410 status_t err;
1411 if (mSeekTimeUs >= 0) {
1412 MediaSource::ReadOptions options;
1413 options.setSeekTo(mSeekTimeUs);
1414 mSeekTimeUs = -1;
1415
1416 err = mSource->read(&srcBuffer, &options);
1417 } else {
1418 err = mSource->read(&srcBuffer);
1419 }
1420
1421 OMX_U32 flags = OMX_BUFFERFLAG_ENDOFFRAME;
1422 OMX_TICKS timestamp = 0;
1423 size_t srcLength = 0;
1424
1425 if (err != OK) {
Andreas Huber4c483422009-09-02 16:05:36 -07001426 CODEC_LOGV("signalling end of input stream.");
Andreas Huberbe06d262009-08-14 14:37:10 -07001427 flags |= OMX_BUFFERFLAG_EOS;
1428
1429 mSignalledEOS = true;
1430 } else {
1431 srcLength = srcBuffer->range_length();
1432
1433 if (info->mMem->size() < srcLength) {
1434 LOGE("info->mMem->size() = %d, srcLength = %d",
1435 info->mMem->size(), srcLength);
1436 }
1437 CHECK(info->mMem->size() >= srcLength);
1438 memcpy(info->mMem->pointer(),
1439 (const uint8_t *)srcBuffer->data() + srcBuffer->range_offset(),
1440 srcLength);
1441
1442 int32_t units, scale;
1443 if (srcBuffer->meta_data()->findInt32(kKeyTimeUnits, &units)
1444 && srcBuffer->meta_data()->findInt32(kKeyTimeScale, &scale)) {
1445 timestamp = ((OMX_TICKS)units * 1000000) / scale;
1446
Andreas Huber4c483422009-09-02 16:05:36 -07001447 CODEC_LOGV("Calling empty_buffer on buffer %p (length %d)",
Andreas Huberbe06d262009-08-14 14:37:10 -07001448 info->mBuffer, srcLength);
Andreas Huber4c483422009-09-02 16:05:36 -07001449 CODEC_LOGV("Calling empty_buffer with timestamp %lld us (%.2f secs)",
Andreas Huberbe06d262009-08-14 14:37:10 -07001450 timestamp, timestamp / 1E6);
1451 }
1452 }
1453
1454 mOMX->empty_buffer(
1455 mNode, info->mBuffer, 0, srcLength,
1456 flags, timestamp);
1457
1458 info->mOwnedByComponent = true;
1459
1460 if (srcBuffer != NULL) {
1461 srcBuffer->release();
1462 srcBuffer = NULL;
1463 }
1464}
1465
1466void OMXCodec::fillOutputBuffer(BufferInfo *info) {
1467 CHECK_EQ(info->mOwnedByComponent, false);
1468
Andreas Huber404cc412009-08-25 14:26:05 -07001469 if (mNoMoreOutputData) {
Andreas Huber4c483422009-09-02 16:05:36 -07001470 CODEC_LOGV("There is no more output data available, not "
Andreas Huber404cc412009-08-25 14:26:05 -07001471 "calling fillOutputBuffer");
1472 return;
1473 }
1474
Andreas Huber4c483422009-09-02 16:05:36 -07001475 CODEC_LOGV("Calling fill_buffer on buffer %p", info->mBuffer);
Andreas Huberbe06d262009-08-14 14:37:10 -07001476 mOMX->fill_buffer(mNode, info->mBuffer);
1477
1478 info->mOwnedByComponent = true;
1479}
1480
1481void OMXCodec::drainInputBuffer(IOMX::buffer_id buffer) {
1482 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
1483 for (size_t i = 0; i < buffers->size(); ++i) {
1484 if ((*buffers)[i].mBuffer == buffer) {
1485 drainInputBuffer(&buffers->editItemAt(i));
1486 return;
1487 }
1488 }
1489
1490 CHECK(!"should not be here.");
1491}
1492
1493void OMXCodec::fillOutputBuffer(IOMX::buffer_id buffer) {
1494 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
1495 for (size_t i = 0; i < buffers->size(); ++i) {
1496 if ((*buffers)[i].mBuffer == buffer) {
1497 fillOutputBuffer(&buffers->editItemAt(i));
1498 return;
1499 }
1500 }
1501
1502 CHECK(!"should not be here.");
1503}
1504
1505void OMXCodec::setState(State newState) {
1506 mState = newState;
1507 mAsyncCompletion.signal();
1508
1509 // This may cause some spurious wakeups but is necessary to
1510 // unblock the reader if we enter ERROR state.
1511 mBufferFilled.signal();
1512}
1513
Andreas Huberda050cf22009-09-02 14:01:43 -07001514void OMXCodec::setRawAudioFormat(
1515 OMX_U32 portIndex, int32_t sampleRate, int32_t numChannels) {
1516 OMX_AUDIO_PARAM_PCMMODETYPE pcmParams;
Andreas Huber4c483422009-09-02 16:05:36 -07001517 InitOMXParams(&pcmParams);
Andreas Huberda050cf22009-09-02 14:01:43 -07001518 pcmParams.nPortIndex = portIndex;
1519
1520 status_t err = mOMX->get_parameter(
1521 mNode, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams));
1522
1523 CHECK_EQ(err, OK);
1524
1525 pcmParams.nChannels = numChannels;
1526 pcmParams.eNumData = OMX_NumericalDataSigned;
1527 pcmParams.bInterleaved = OMX_TRUE;
1528 pcmParams.nBitPerSample = 16;
1529 pcmParams.nSamplingRate = sampleRate;
1530 pcmParams.ePCMMode = OMX_AUDIO_PCMModeLinear;
1531
1532 if (numChannels == 1) {
1533 pcmParams.eChannelMapping[0] = OMX_AUDIO_ChannelCF;
1534 } else {
1535 CHECK_EQ(numChannels, 2);
1536
1537 pcmParams.eChannelMapping[0] = OMX_AUDIO_ChannelLF;
1538 pcmParams.eChannelMapping[1] = OMX_AUDIO_ChannelRF;
1539 }
1540
1541 err = mOMX->set_parameter(
1542 mNode, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams));
1543
1544 CHECK_EQ(err, OK);
1545}
1546
Andreas Huberbe06d262009-08-14 14:37:10 -07001547void OMXCodec::setAMRFormat() {
1548 if (!mIsEncoder) {
1549 OMX_AUDIO_PARAM_AMRTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -07001550 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -07001551 def.nPortIndex = kPortIndexInput;
1552
1553 status_t err =
1554 mOMX->get_parameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
1555
1556 CHECK_EQ(err, OK);
1557
1558 def.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
1559 def.eAMRBandMode = OMX_AUDIO_AMRBandModeNB0;
1560
1561 err = mOMX->set_parameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
1562 CHECK_EQ(err, OK);
1563 }
1564
1565 ////////////////////////
1566
1567 if (mIsEncoder) {
1568 sp<MetaData> format = mSource->getFormat();
1569 int32_t sampleRate;
1570 int32_t numChannels;
1571 CHECK(format->findInt32(kKeySampleRate, &sampleRate));
1572 CHECK(format->findInt32(kKeyChannelCount, &numChannels));
1573
Andreas Huberda050cf22009-09-02 14:01:43 -07001574 setRawAudioFormat(kPortIndexInput, sampleRate, numChannels);
Andreas Huberbe06d262009-08-14 14:37:10 -07001575 }
1576}
1577
Andreas Huberee606e62009-09-08 10:19:21 -07001578void OMXCodec::setAMRWBFormat() {
1579 if (!mIsEncoder) {
1580 OMX_AUDIO_PARAM_AMRTYPE def;
1581 InitOMXParams(&def);
1582 def.nPortIndex = kPortIndexInput;
1583
1584 status_t err =
1585 mOMX->get_parameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
1586
1587 CHECK_EQ(err, OK);
1588
1589 def.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
1590 def.eAMRBandMode = OMX_AUDIO_AMRBandModeWB0;
1591
1592 err = mOMX->set_parameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
1593 CHECK_EQ(err, OK);
1594 }
1595
1596 ////////////////////////
1597
1598 if (mIsEncoder) {
1599 sp<MetaData> format = mSource->getFormat();
1600 int32_t sampleRate;
1601 int32_t numChannels;
1602 CHECK(format->findInt32(kKeySampleRate, &sampleRate));
1603 CHECK(format->findInt32(kKeyChannelCount, &numChannels));
1604
1605 setRawAudioFormat(kPortIndexInput, sampleRate, numChannels);
1606 }
1607}
1608
Andreas Huber43ad6eaf2009-09-01 16:02:43 -07001609void OMXCodec::setAACFormat(int32_t numChannels, int32_t sampleRate) {
Andreas Huberda050cf22009-09-02 14:01:43 -07001610 if (mIsEncoder) {
1611 setRawAudioFormat(kPortIndexInput, sampleRate, numChannels);
1612 } else {
1613 OMX_AUDIO_PARAM_AACPROFILETYPE profile;
Andreas Huber4c483422009-09-02 16:05:36 -07001614 InitOMXParams(&profile);
Andreas Huberda050cf22009-09-02 14:01:43 -07001615 profile.nPortIndex = kPortIndexInput;
Andreas Huberbe06d262009-08-14 14:37:10 -07001616
Andreas Huberda050cf22009-09-02 14:01:43 -07001617 status_t err = mOMX->get_parameter(
1618 mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile));
1619 CHECK_EQ(err, OK);
Andreas Huberbe06d262009-08-14 14:37:10 -07001620
Andreas Huberda050cf22009-09-02 14:01:43 -07001621 profile.nChannels = numChannels;
1622 profile.nSampleRate = sampleRate;
1623 profile.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4ADTS;
Andreas Huberbe06d262009-08-14 14:37:10 -07001624
Andreas Huberda050cf22009-09-02 14:01:43 -07001625 err = mOMX->set_parameter(
1626 mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile));
1627 CHECK_EQ(err, OK);
1628 }
Andreas Huberbe06d262009-08-14 14:37:10 -07001629}
1630
1631void OMXCodec::setImageOutputFormat(
1632 OMX_COLOR_FORMATTYPE format, OMX_U32 width, OMX_U32 height) {
Andreas Huber4c483422009-09-02 16:05:36 -07001633 CODEC_LOGV("setImageOutputFormat(%ld, %ld)", width, height);
Andreas Huberbe06d262009-08-14 14:37:10 -07001634
1635#if 0
1636 OMX_INDEXTYPE index;
1637 status_t err = mOMX->get_extension_index(
1638 mNode, "OMX.TI.JPEG.decode.Config.OutputColorFormat", &index);
1639 CHECK_EQ(err, OK);
1640
1641 err = mOMX->set_config(mNode, index, &format, sizeof(format));
1642 CHECK_EQ(err, OK);
1643#endif
1644
1645 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -07001646 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -07001647 def.nPortIndex = kPortIndexOutput;
1648
1649 status_t err = mOMX->get_parameter(
1650 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
1651 CHECK_EQ(err, OK);
1652
1653 CHECK_EQ(def.eDomain, OMX_PortDomainImage);
1654
1655 OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
Andreas Huberebf66ea2009-08-19 13:32:58 -07001656
Andreas Huberbe06d262009-08-14 14:37:10 -07001657 CHECK_EQ(imageDef->eCompressionFormat, OMX_IMAGE_CodingUnused);
1658 imageDef->eColorFormat = format;
1659 imageDef->nFrameWidth = width;
1660 imageDef->nFrameHeight = height;
1661
1662 switch (format) {
1663 case OMX_COLOR_FormatYUV420PackedPlanar:
1664 case OMX_COLOR_FormatYUV411Planar:
1665 {
1666 def.nBufferSize = (width * height * 3) / 2;
1667 break;
1668 }
1669
1670 case OMX_COLOR_FormatCbYCrY:
1671 {
1672 def.nBufferSize = width * height * 2;
1673 break;
1674 }
1675
1676 case OMX_COLOR_Format32bitARGB8888:
1677 {
1678 def.nBufferSize = width * height * 4;
1679 break;
1680 }
1681
Andreas Huber201511c2009-09-08 14:01:44 -07001682 case OMX_COLOR_Format16bitARGB4444:
1683 case OMX_COLOR_Format16bitARGB1555:
1684 case OMX_COLOR_Format16bitRGB565:
1685 case OMX_COLOR_Format16bitBGR565:
1686 {
1687 def.nBufferSize = width * height * 2;
1688 break;
1689 }
1690
Andreas Huberbe06d262009-08-14 14:37:10 -07001691 default:
1692 CHECK(!"Should not be here. Unknown color format.");
1693 break;
1694 }
1695
Andreas Huber5c0a9132009-08-20 11:16:40 -07001696 def.nBufferCountActual = def.nBufferCountMin;
1697
Andreas Huberbe06d262009-08-14 14:37:10 -07001698 err = mOMX->set_parameter(
1699 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
1700 CHECK_EQ(err, OK);
Andreas Huber5c0a9132009-08-20 11:16:40 -07001701}
Andreas Huberbe06d262009-08-14 14:37:10 -07001702
Andreas Huber5c0a9132009-08-20 11:16:40 -07001703void OMXCodec::setJPEGInputFormat(
1704 OMX_U32 width, OMX_U32 height, OMX_U32 compressedSize) {
1705 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -07001706 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -07001707 def.nPortIndex = kPortIndexInput;
1708
Andreas Huber5c0a9132009-08-20 11:16:40 -07001709 status_t err = mOMX->get_parameter(
Andreas Huberbe06d262009-08-14 14:37:10 -07001710 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
1711 CHECK_EQ(err, OK);
1712
Andreas Huber5c0a9132009-08-20 11:16:40 -07001713 CHECK_EQ(def.eDomain, OMX_PortDomainImage);
1714 OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
1715
Andreas Huberbe06d262009-08-14 14:37:10 -07001716 CHECK_EQ(imageDef->eCompressionFormat, OMX_IMAGE_CodingJPEG);
1717 imageDef->nFrameWidth = width;
1718 imageDef->nFrameHeight = height;
1719
Andreas Huber5c0a9132009-08-20 11:16:40 -07001720 def.nBufferSize = compressedSize;
Andreas Huberbe06d262009-08-14 14:37:10 -07001721 def.nBufferCountActual = def.nBufferCountMin;
1722
1723 err = mOMX->set_parameter(
1724 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
1725 CHECK_EQ(err, OK);
1726}
1727
1728void OMXCodec::addCodecSpecificData(const void *data, size_t size) {
1729 CodecSpecificData *specific =
1730 (CodecSpecificData *)malloc(sizeof(CodecSpecificData) + size - 1);
1731
1732 specific->mSize = size;
1733 memcpy(specific->mData, data, size);
1734
1735 mCodecSpecificData.push(specific);
1736}
1737
1738void OMXCodec::clearCodecSpecificData() {
1739 for (size_t i = 0; i < mCodecSpecificData.size(); ++i) {
1740 free(mCodecSpecificData.editItemAt(i));
1741 }
1742 mCodecSpecificData.clear();
1743 mCodecSpecificDataIndex = 0;
1744}
1745
1746status_t OMXCodec::start(MetaData *) {
Andreas Huber42978e52009-08-27 10:08:39 -07001747 Mutex::Autolock autoLock(mLock);
1748
Andreas Huberbe06d262009-08-14 14:37:10 -07001749 if (mState != LOADED) {
1750 return UNKNOWN_ERROR;
1751 }
Andreas Huberebf66ea2009-08-19 13:32:58 -07001752
Andreas Huberbe06d262009-08-14 14:37:10 -07001753 sp<MetaData> params = new MetaData;
Andreas Huber4f5e6022009-08-19 09:29:34 -07001754 if (mQuirks & kWantsNALFragments) {
1755 params->setInt32(kKeyWantsNALFragments, true);
Andreas Huberbe06d262009-08-14 14:37:10 -07001756 }
1757 status_t err = mSource->start(params.get());
1758
1759 if (err != OK) {
1760 return err;
1761 }
1762
1763 mCodecSpecificDataIndex = 0;
Andreas Huber42978e52009-08-27 10:08:39 -07001764 mInitialBufferSubmit = true;
Andreas Huberbe06d262009-08-14 14:37:10 -07001765 mSignalledEOS = false;
1766 mNoMoreOutputData = false;
1767 mSeekTimeUs = -1;
1768 mFilledBuffers.clear();
1769
1770 return init();
1771}
1772
1773status_t OMXCodec::stop() {
Andreas Huber4c483422009-09-02 16:05:36 -07001774 CODEC_LOGV("stop");
Andreas Huberbe06d262009-08-14 14:37:10 -07001775
1776 Mutex::Autolock autoLock(mLock);
1777
1778 while (isIntermediateState(mState)) {
1779 mAsyncCompletion.wait(mLock);
1780 }
1781
1782 switch (mState) {
1783 case LOADED:
1784 case ERROR:
1785 break;
1786
1787 case EXECUTING:
1788 {
1789 setState(EXECUTING_TO_IDLE);
1790
Andreas Huber127fcdc2009-08-26 16:27:02 -07001791 if (mQuirks & kRequiresFlushBeforeShutdown) {
Andreas Huber4c483422009-09-02 16:05:36 -07001792 CODEC_LOGV("This component requires a flush before transitioning "
Andreas Huber127fcdc2009-08-26 16:27:02 -07001793 "from EXECUTING to IDLE...");
Andreas Huberbe06d262009-08-14 14:37:10 -07001794
Andreas Huber127fcdc2009-08-26 16:27:02 -07001795 bool emulateInputFlushCompletion =
1796 !flushPortAsync(kPortIndexInput);
1797
1798 bool emulateOutputFlushCompletion =
1799 !flushPortAsync(kPortIndexOutput);
1800
1801 if (emulateInputFlushCompletion) {
1802 onCmdComplete(OMX_CommandFlush, kPortIndexInput);
1803 }
1804
1805 if (emulateOutputFlushCompletion) {
1806 onCmdComplete(OMX_CommandFlush, kPortIndexOutput);
1807 }
1808 } else {
1809 mPortStatus[kPortIndexInput] = SHUTTING_DOWN;
1810 mPortStatus[kPortIndexOutput] = SHUTTING_DOWN;
1811
1812 status_t err =
1813 mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
1814 CHECK_EQ(err, OK);
1815 }
Andreas Huberbe06d262009-08-14 14:37:10 -07001816
1817 while (mState != LOADED && mState != ERROR) {
1818 mAsyncCompletion.wait(mLock);
1819 }
1820
1821 break;
1822 }
1823
1824 default:
1825 {
1826 CHECK(!"should not be here.");
1827 break;
1828 }
1829 }
1830
1831 mSource->stop();
1832
1833 return OK;
1834}
1835
1836sp<MetaData> OMXCodec::getFormat() {
1837 return mOutputFormat;
1838}
1839
1840status_t OMXCodec::read(
1841 MediaBuffer **buffer, const ReadOptions *options) {
1842 *buffer = NULL;
1843
1844 Mutex::Autolock autoLock(mLock);
1845
Andreas Huberd06e5b82009-08-28 13:18:14 -07001846 if (mState != EXECUTING && mState != RECONFIGURING) {
1847 return UNKNOWN_ERROR;
1848 }
1849
Andreas Huber42978e52009-08-27 10:08:39 -07001850 if (mInitialBufferSubmit) {
1851 mInitialBufferSubmit = false;
1852
1853 drainInputBuffers();
Andreas Huber42978e52009-08-27 10:08:39 -07001854
Andreas Huberd06e5b82009-08-28 13:18:14 -07001855 if (mState == EXECUTING) {
1856 // Otherwise mState == RECONFIGURING and this code will trigger
1857 // after the output port is reenabled.
1858 fillOutputBuffers();
1859 }
Andreas Huberbe06d262009-08-14 14:37:10 -07001860 }
1861
1862 int64_t seekTimeUs;
1863 if (options && options->getSeekTo(&seekTimeUs)) {
Andreas Huber4c483422009-09-02 16:05:36 -07001864 CODEC_LOGV("seeking to %lld us (%.2f secs)", seekTimeUs, seekTimeUs / 1E6);
Andreas Huberbe06d262009-08-14 14:37:10 -07001865
1866 mSignalledEOS = false;
1867 mNoMoreOutputData = false;
1868
1869 CHECK(seekTimeUs >= 0);
1870 mSeekTimeUs = seekTimeUs;
1871
1872 mFilledBuffers.clear();
1873
1874 CHECK_EQ(mState, EXECUTING);
1875
Andreas Huber404cc412009-08-25 14:26:05 -07001876 bool emulateInputFlushCompletion = !flushPortAsync(kPortIndexInput);
1877 bool emulateOutputFlushCompletion = !flushPortAsync(kPortIndexOutput);
1878
1879 if (emulateInputFlushCompletion) {
1880 onCmdComplete(OMX_CommandFlush, kPortIndexInput);
1881 }
1882
1883 if (emulateOutputFlushCompletion) {
1884 onCmdComplete(OMX_CommandFlush, kPortIndexOutput);
1885 }
Andreas Huberbe06d262009-08-14 14:37:10 -07001886 }
1887
1888 while (mState != ERROR && !mNoMoreOutputData && mFilledBuffers.empty()) {
1889 mBufferFilled.wait(mLock);
1890 }
1891
1892 if (mState == ERROR) {
1893 return UNKNOWN_ERROR;
1894 }
1895
1896 if (mFilledBuffers.empty()) {
1897 return ERROR_END_OF_STREAM;
1898 }
1899
1900 size_t index = *mFilledBuffers.begin();
1901 mFilledBuffers.erase(mFilledBuffers.begin());
1902
1903 BufferInfo *info = &mPortBuffers[kPortIndexOutput].editItemAt(index);
1904 info->mMediaBuffer->add_ref();
1905 *buffer = info->mMediaBuffer;
1906
1907 return OK;
1908}
1909
1910void OMXCodec::signalBufferReturned(MediaBuffer *buffer) {
1911 Mutex::Autolock autoLock(mLock);
1912
1913 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
1914 for (size_t i = 0; i < buffers->size(); ++i) {
1915 BufferInfo *info = &buffers->editItemAt(i);
1916
1917 if (info->mMediaBuffer == buffer) {
1918 CHECK_EQ(mPortStatus[kPortIndexOutput], ENABLED);
1919 fillOutputBuffer(info);
1920 return;
1921 }
1922 }
1923
1924 CHECK(!"should not be here.");
1925}
1926
1927static const char *imageCompressionFormatString(OMX_IMAGE_CODINGTYPE type) {
1928 static const char *kNames[] = {
1929 "OMX_IMAGE_CodingUnused",
1930 "OMX_IMAGE_CodingAutoDetect",
1931 "OMX_IMAGE_CodingJPEG",
1932 "OMX_IMAGE_CodingJPEG2K",
1933 "OMX_IMAGE_CodingEXIF",
1934 "OMX_IMAGE_CodingTIFF",
1935 "OMX_IMAGE_CodingGIF",
1936 "OMX_IMAGE_CodingPNG",
1937 "OMX_IMAGE_CodingLZW",
1938 "OMX_IMAGE_CodingBMP",
1939 };
1940
1941 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
1942
1943 if (type < 0 || (size_t)type >= numNames) {
1944 return "UNKNOWN";
1945 } else {
1946 return kNames[type];
1947 }
1948}
1949
1950static const char *colorFormatString(OMX_COLOR_FORMATTYPE type) {
1951 static const char *kNames[] = {
1952 "OMX_COLOR_FormatUnused",
1953 "OMX_COLOR_FormatMonochrome",
1954 "OMX_COLOR_Format8bitRGB332",
1955 "OMX_COLOR_Format12bitRGB444",
1956 "OMX_COLOR_Format16bitARGB4444",
1957 "OMX_COLOR_Format16bitARGB1555",
1958 "OMX_COLOR_Format16bitRGB565",
1959 "OMX_COLOR_Format16bitBGR565",
1960 "OMX_COLOR_Format18bitRGB666",
1961 "OMX_COLOR_Format18bitARGB1665",
Andreas Huberebf66ea2009-08-19 13:32:58 -07001962 "OMX_COLOR_Format19bitARGB1666",
Andreas Huberbe06d262009-08-14 14:37:10 -07001963 "OMX_COLOR_Format24bitRGB888",
1964 "OMX_COLOR_Format24bitBGR888",
1965 "OMX_COLOR_Format24bitARGB1887",
1966 "OMX_COLOR_Format25bitARGB1888",
1967 "OMX_COLOR_Format32bitBGRA8888",
1968 "OMX_COLOR_Format32bitARGB8888",
1969 "OMX_COLOR_FormatYUV411Planar",
1970 "OMX_COLOR_FormatYUV411PackedPlanar",
1971 "OMX_COLOR_FormatYUV420Planar",
1972 "OMX_COLOR_FormatYUV420PackedPlanar",
1973 "OMX_COLOR_FormatYUV420SemiPlanar",
1974 "OMX_COLOR_FormatYUV422Planar",
1975 "OMX_COLOR_FormatYUV422PackedPlanar",
1976 "OMX_COLOR_FormatYUV422SemiPlanar",
1977 "OMX_COLOR_FormatYCbYCr",
1978 "OMX_COLOR_FormatYCrYCb",
1979 "OMX_COLOR_FormatCbYCrY",
1980 "OMX_COLOR_FormatCrYCbY",
1981 "OMX_COLOR_FormatYUV444Interleaved",
1982 "OMX_COLOR_FormatRawBayer8bit",
1983 "OMX_COLOR_FormatRawBayer10bit",
1984 "OMX_COLOR_FormatRawBayer8bitcompressed",
Andreas Huberebf66ea2009-08-19 13:32:58 -07001985 "OMX_COLOR_FormatL2",
1986 "OMX_COLOR_FormatL4",
1987 "OMX_COLOR_FormatL8",
1988 "OMX_COLOR_FormatL16",
1989 "OMX_COLOR_FormatL24",
Andreas Huberbe06d262009-08-14 14:37:10 -07001990 "OMX_COLOR_FormatL32",
1991 "OMX_COLOR_FormatYUV420PackedSemiPlanar",
1992 "OMX_COLOR_FormatYUV422PackedSemiPlanar",
1993 "OMX_COLOR_Format18BitBGR666",
1994 "OMX_COLOR_Format24BitARGB6666",
1995 "OMX_COLOR_Format24BitABGR6666",
1996 };
1997
1998 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
1999
2000 static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
2001
2002 if (type == OMX_QCOM_COLOR_FormatYVU420SemiPlanar) {
2003 return "OMX_QCOM_COLOR_FormatYVU420SemiPlanar";
2004 } else if (type < 0 || (size_t)type >= numNames) {
2005 return "UNKNOWN";
2006 } else {
2007 return kNames[type];
2008 }
2009}
2010
2011static const char *videoCompressionFormatString(OMX_VIDEO_CODINGTYPE type) {
2012 static const char *kNames[] = {
2013 "OMX_VIDEO_CodingUnused",
2014 "OMX_VIDEO_CodingAutoDetect",
2015 "OMX_VIDEO_CodingMPEG2",
2016 "OMX_VIDEO_CodingH263",
2017 "OMX_VIDEO_CodingMPEG4",
2018 "OMX_VIDEO_CodingWMV",
2019 "OMX_VIDEO_CodingRV",
2020 "OMX_VIDEO_CodingAVC",
2021 "OMX_VIDEO_CodingMJPEG",
2022 };
2023
2024 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
2025
2026 if (type < 0 || (size_t)type >= numNames) {
2027 return "UNKNOWN";
2028 } else {
2029 return kNames[type];
2030 }
2031}
2032
2033static const char *audioCodingTypeString(OMX_AUDIO_CODINGTYPE type) {
2034 static const char *kNames[] = {
2035 "OMX_AUDIO_CodingUnused",
2036 "OMX_AUDIO_CodingAutoDetect",
2037 "OMX_AUDIO_CodingPCM",
2038 "OMX_AUDIO_CodingADPCM",
2039 "OMX_AUDIO_CodingAMR",
2040 "OMX_AUDIO_CodingGSMFR",
2041 "OMX_AUDIO_CodingGSMEFR",
2042 "OMX_AUDIO_CodingGSMHR",
2043 "OMX_AUDIO_CodingPDCFR",
2044 "OMX_AUDIO_CodingPDCEFR",
2045 "OMX_AUDIO_CodingPDCHR",
2046 "OMX_AUDIO_CodingTDMAFR",
2047 "OMX_AUDIO_CodingTDMAEFR",
2048 "OMX_AUDIO_CodingQCELP8",
2049 "OMX_AUDIO_CodingQCELP13",
2050 "OMX_AUDIO_CodingEVRC",
2051 "OMX_AUDIO_CodingSMV",
2052 "OMX_AUDIO_CodingG711",
2053 "OMX_AUDIO_CodingG723",
2054 "OMX_AUDIO_CodingG726",
2055 "OMX_AUDIO_CodingG729",
2056 "OMX_AUDIO_CodingAAC",
2057 "OMX_AUDIO_CodingMP3",
2058 "OMX_AUDIO_CodingSBC",
2059 "OMX_AUDIO_CodingVORBIS",
2060 "OMX_AUDIO_CodingWMA",
2061 "OMX_AUDIO_CodingRA",
2062 "OMX_AUDIO_CodingMIDI",
2063 };
2064
2065 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
2066
2067 if (type < 0 || (size_t)type >= numNames) {
2068 return "UNKNOWN";
2069 } else {
2070 return kNames[type];
2071 }
2072}
2073
2074static const char *audioPCMModeString(OMX_AUDIO_PCMMODETYPE type) {
2075 static const char *kNames[] = {
2076 "OMX_AUDIO_PCMModeLinear",
2077 "OMX_AUDIO_PCMModeALaw",
2078 "OMX_AUDIO_PCMModeMULaw",
2079 };
2080
2081 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
2082
2083 if (type < 0 || (size_t)type >= numNames) {
2084 return "UNKNOWN";
2085 } else {
2086 return kNames[type];
2087 }
2088}
2089
Andreas Huber7ae02c82009-09-09 16:29:47 -07002090static const char *amrBandModeString(OMX_AUDIO_AMRBANDMODETYPE type) {
2091 static const char *kNames[] = {
2092 "OMX_AUDIO_AMRBandModeUnused",
2093 "OMX_AUDIO_AMRBandModeNB0",
2094 "OMX_AUDIO_AMRBandModeNB1",
2095 "OMX_AUDIO_AMRBandModeNB2",
2096 "OMX_AUDIO_AMRBandModeNB3",
2097 "OMX_AUDIO_AMRBandModeNB4",
2098 "OMX_AUDIO_AMRBandModeNB5",
2099 "OMX_AUDIO_AMRBandModeNB6",
2100 "OMX_AUDIO_AMRBandModeNB7",
2101 "OMX_AUDIO_AMRBandModeWB0",
2102 "OMX_AUDIO_AMRBandModeWB1",
2103 "OMX_AUDIO_AMRBandModeWB2",
2104 "OMX_AUDIO_AMRBandModeWB3",
2105 "OMX_AUDIO_AMRBandModeWB4",
2106 "OMX_AUDIO_AMRBandModeWB5",
2107 "OMX_AUDIO_AMRBandModeWB6",
2108 "OMX_AUDIO_AMRBandModeWB7",
2109 "OMX_AUDIO_AMRBandModeWB8",
2110 };
2111
2112 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
2113
2114 if (type < 0 || (size_t)type >= numNames) {
2115 return "UNKNOWN";
2116 } else {
2117 return kNames[type];
2118 }
2119}
2120
2121static const char *amrFrameFormatString(OMX_AUDIO_AMRFRAMEFORMATTYPE type) {
2122 static const char *kNames[] = {
2123 "OMX_AUDIO_AMRFrameFormatConformance",
2124 "OMX_AUDIO_AMRFrameFormatIF1",
2125 "OMX_AUDIO_AMRFrameFormatIF2",
2126 "OMX_AUDIO_AMRFrameFormatFSF",
2127 "OMX_AUDIO_AMRFrameFormatRTPPayload",
2128 "OMX_AUDIO_AMRFrameFormatITU",
2129 };
2130
2131 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
2132
2133 if (type < 0 || (size_t)type >= numNames) {
2134 return "UNKNOWN";
2135 } else {
2136 return kNames[type];
2137 }
2138}
Andreas Huberbe06d262009-08-14 14:37:10 -07002139
2140void OMXCodec::dumpPortStatus(OMX_U32 portIndex) {
2141 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -07002142 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -07002143 def.nPortIndex = portIndex;
2144
2145 status_t err = mOMX->get_parameter(
2146 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
2147 CHECK_EQ(err, OK);
2148
2149 printf("%s Port = {\n", portIndex == kPortIndexInput ? "Input" : "Output");
2150
2151 CHECK((portIndex == kPortIndexInput && def.eDir == OMX_DirInput)
2152 || (portIndex == kPortIndexOutput && def.eDir == OMX_DirOutput));
2153
2154 printf(" nBufferCountActual = %ld\n", def.nBufferCountActual);
2155 printf(" nBufferCountMin = %ld\n", def.nBufferCountMin);
2156 printf(" nBufferSize = %ld\n", def.nBufferSize);
2157
2158 switch (def.eDomain) {
2159 case OMX_PortDomainImage:
2160 {
2161 const OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
2162
2163 printf("\n");
2164 printf(" // Image\n");
2165 printf(" nFrameWidth = %ld\n", imageDef->nFrameWidth);
2166 printf(" nFrameHeight = %ld\n", imageDef->nFrameHeight);
2167 printf(" nStride = %ld\n", imageDef->nStride);
2168
2169 printf(" eCompressionFormat = %s\n",
2170 imageCompressionFormatString(imageDef->eCompressionFormat));
2171
2172 printf(" eColorFormat = %s\n",
2173 colorFormatString(imageDef->eColorFormat));
2174
2175 break;
2176 }
2177
2178 case OMX_PortDomainVideo:
2179 {
2180 OMX_VIDEO_PORTDEFINITIONTYPE *videoDef = &def.format.video;
2181
2182 printf("\n");
2183 printf(" // Video\n");
2184 printf(" nFrameWidth = %ld\n", videoDef->nFrameWidth);
2185 printf(" nFrameHeight = %ld\n", videoDef->nFrameHeight);
2186 printf(" nStride = %ld\n", videoDef->nStride);
2187
2188 printf(" eCompressionFormat = %s\n",
2189 videoCompressionFormatString(videoDef->eCompressionFormat));
2190
2191 printf(" eColorFormat = %s\n",
2192 colorFormatString(videoDef->eColorFormat));
2193
2194 break;
2195 }
2196
2197 case OMX_PortDomainAudio:
2198 {
2199 OMX_AUDIO_PORTDEFINITIONTYPE *audioDef = &def.format.audio;
2200
2201 printf("\n");
2202 printf(" // Audio\n");
2203 printf(" eEncoding = %s\n",
2204 audioCodingTypeString(audioDef->eEncoding));
2205
2206 if (audioDef->eEncoding == OMX_AUDIO_CodingPCM) {
2207 OMX_AUDIO_PARAM_PCMMODETYPE params;
Andreas Huber4c483422009-09-02 16:05:36 -07002208 InitOMXParams(&params);
Andreas Huberbe06d262009-08-14 14:37:10 -07002209 params.nPortIndex = portIndex;
2210
2211 err = mOMX->get_parameter(
2212 mNode, OMX_IndexParamAudioPcm, &params, sizeof(params));
2213 CHECK_EQ(err, OK);
2214
2215 printf(" nSamplingRate = %ld\n", params.nSamplingRate);
2216 printf(" nChannels = %ld\n", params.nChannels);
2217 printf(" bInterleaved = %d\n", params.bInterleaved);
2218 printf(" nBitPerSample = %ld\n", params.nBitPerSample);
2219
2220 printf(" eNumData = %s\n",
2221 params.eNumData == OMX_NumericalDataSigned
2222 ? "signed" : "unsigned");
2223
2224 printf(" ePCMMode = %s\n", audioPCMModeString(params.ePCMMode));
Andreas Huber7ae02c82009-09-09 16:29:47 -07002225 } else if (audioDef->eEncoding == OMX_AUDIO_CodingAMR) {
2226 OMX_AUDIO_PARAM_AMRTYPE amr;
2227 InitOMXParams(&amr);
2228 amr.nPortIndex = portIndex;
2229
2230 err = mOMX->get_parameter(
2231 mNode, OMX_IndexParamAudioAmr, &amr, sizeof(amr));
2232 CHECK_EQ(err, OK);
2233
2234 printf(" nChannels = %ld\n", amr.nChannels);
2235 printf(" eAMRBandMode = %s\n",
2236 amrBandModeString(amr.eAMRBandMode));
2237 printf(" eAMRFrameFormat = %s\n",
2238 amrFrameFormatString(amr.eAMRFrameFormat));
Andreas Huberbe06d262009-08-14 14:37:10 -07002239 }
2240
2241 break;
2242 }
2243
2244 default:
2245 {
2246 printf(" // Unknown\n");
2247 break;
2248 }
2249 }
2250
2251 printf("}\n");
2252}
2253
2254void OMXCodec::initOutputFormat(const sp<MetaData> &inputFormat) {
2255 mOutputFormat = new MetaData;
2256 mOutputFormat->setCString(kKeyDecoderComponent, mComponentName);
2257
2258 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -07002259 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -07002260 def.nPortIndex = kPortIndexOutput;
2261
2262 status_t err = mOMX->get_parameter(
2263 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
2264 CHECK_EQ(err, OK);
2265
2266 switch (def.eDomain) {
2267 case OMX_PortDomainImage:
2268 {
2269 OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
2270 CHECK_EQ(imageDef->eCompressionFormat, OMX_IMAGE_CodingUnused);
2271
Andreas Hubere6c40962009-09-10 14:13:30 -07002272 mOutputFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
Andreas Huberbe06d262009-08-14 14:37:10 -07002273 mOutputFormat->setInt32(kKeyColorFormat, imageDef->eColorFormat);
2274 mOutputFormat->setInt32(kKeyWidth, imageDef->nFrameWidth);
2275 mOutputFormat->setInt32(kKeyHeight, imageDef->nFrameHeight);
2276 break;
2277 }
2278
2279 case OMX_PortDomainAudio:
2280 {
2281 OMX_AUDIO_PORTDEFINITIONTYPE *audio_def = &def.format.audio;
2282
Andreas Huberda050cf22009-09-02 14:01:43 -07002283 if (audio_def->eEncoding == OMX_AUDIO_CodingPCM) {
2284 OMX_AUDIO_PARAM_PCMMODETYPE params;
Andreas Huber4c483422009-09-02 16:05:36 -07002285 InitOMXParams(&params);
Andreas Huberda050cf22009-09-02 14:01:43 -07002286 params.nPortIndex = kPortIndexOutput;
Andreas Huberbe06d262009-08-14 14:37:10 -07002287
Andreas Huberda050cf22009-09-02 14:01:43 -07002288 err = mOMX->get_parameter(
2289 mNode, OMX_IndexParamAudioPcm, &params, sizeof(params));
2290 CHECK_EQ(err, OK);
Andreas Huberbe06d262009-08-14 14:37:10 -07002291
Andreas Huberda050cf22009-09-02 14:01:43 -07002292 CHECK_EQ(params.eNumData, OMX_NumericalDataSigned);
2293 CHECK_EQ(params.nBitPerSample, 16);
2294 CHECK_EQ(params.ePCMMode, OMX_AUDIO_PCMModeLinear);
Andreas Huberbe06d262009-08-14 14:37:10 -07002295
Andreas Huberda050cf22009-09-02 14:01:43 -07002296 int32_t numChannels, sampleRate;
2297 inputFormat->findInt32(kKeyChannelCount, &numChannels);
2298 inputFormat->findInt32(kKeySampleRate, &sampleRate);
Andreas Huberbe06d262009-08-14 14:37:10 -07002299
Andreas Huberda050cf22009-09-02 14:01:43 -07002300 if ((OMX_U32)numChannels != params.nChannels) {
2301 LOGW("Codec outputs a different number of channels than "
2302 "the input stream contains.");
2303 }
Andreas Huberbe06d262009-08-14 14:37:10 -07002304
Andreas Hubere6c40962009-09-10 14:13:30 -07002305 mOutputFormat->setCString(
2306 kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
Andreas Huberda050cf22009-09-02 14:01:43 -07002307
2308 // Use the codec-advertised number of channels, as some
2309 // codecs appear to output stereo even if the input data is
2310 // mono.
2311 mOutputFormat->setInt32(kKeyChannelCount, params.nChannels);
2312
2313 // The codec-reported sampleRate is not reliable...
2314 mOutputFormat->setInt32(kKeySampleRate, sampleRate);
2315 } else if (audio_def->eEncoding == OMX_AUDIO_CodingAMR) {
Andreas Huber7ae02c82009-09-09 16:29:47 -07002316 OMX_AUDIO_PARAM_AMRTYPE amr;
2317 InitOMXParams(&amr);
2318 amr.nPortIndex = kPortIndexOutput;
2319
2320 err = mOMX->get_parameter(
2321 mNode, OMX_IndexParamAudioAmr, &amr, sizeof(amr));
2322 CHECK_EQ(err, OK);
2323
2324 CHECK_EQ(amr.nChannels, 1);
2325 mOutputFormat->setInt32(kKeyChannelCount, 1);
2326
2327 if (amr.eAMRBandMode >= OMX_AUDIO_AMRBandModeNB0
2328 && amr.eAMRBandMode <= OMX_AUDIO_AMRBandModeNB7) {
Andreas Hubere6c40962009-09-10 14:13:30 -07002329 mOutputFormat->setCString(
2330 kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AMR_NB);
Andreas Huber7ae02c82009-09-09 16:29:47 -07002331 mOutputFormat->setInt32(kKeySampleRate, 8000);
2332 } else if (amr.eAMRBandMode >= OMX_AUDIO_AMRBandModeWB0
2333 && amr.eAMRBandMode <= OMX_AUDIO_AMRBandModeWB8) {
Andreas Hubere6c40962009-09-10 14:13:30 -07002334 mOutputFormat->setCString(
2335 kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AMR_WB);
Andreas Huber7ae02c82009-09-09 16:29:47 -07002336 mOutputFormat->setInt32(kKeySampleRate, 16000);
2337 } else {
2338 CHECK(!"Unknown AMR band mode.");
2339 }
Andreas Huberda050cf22009-09-02 14:01:43 -07002340 } else if (audio_def->eEncoding == OMX_AUDIO_CodingAAC) {
Andreas Hubere6c40962009-09-10 14:13:30 -07002341 mOutputFormat->setCString(
2342 kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
Andreas Huberda050cf22009-09-02 14:01:43 -07002343 } else {
2344 CHECK(!"Should not be here. Unknown audio encoding.");
Andreas Huber43ad6eaf2009-09-01 16:02:43 -07002345 }
Andreas Huberbe06d262009-08-14 14:37:10 -07002346 break;
2347 }
2348
2349 case OMX_PortDomainVideo:
2350 {
2351 OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
2352
2353 if (video_def->eCompressionFormat == OMX_VIDEO_CodingUnused) {
Andreas Hubere6c40962009-09-10 14:13:30 -07002354 mOutputFormat->setCString(
2355 kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
Andreas Huberbe06d262009-08-14 14:37:10 -07002356 } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingMPEG4) {
Andreas Hubere6c40962009-09-10 14:13:30 -07002357 mOutputFormat->setCString(
2358 kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
Andreas Huberbe06d262009-08-14 14:37:10 -07002359 } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingH263) {
Andreas Hubere6c40962009-09-10 14:13:30 -07002360 mOutputFormat->setCString(
2361 kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263);
Andreas Huberbe06d262009-08-14 14:37:10 -07002362 } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingAVC) {
Andreas Hubere6c40962009-09-10 14:13:30 -07002363 mOutputFormat->setCString(
2364 kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
Andreas Huberbe06d262009-08-14 14:37:10 -07002365 } else {
2366 CHECK(!"Unknown compression format.");
2367 }
2368
2369 if (!strcmp(mComponentName, "OMX.PV.avcdec")) {
2370 // This component appears to be lying to me.
2371 mOutputFormat->setInt32(
2372 kKeyWidth, (video_def->nFrameWidth + 15) & -16);
2373 mOutputFormat->setInt32(
2374 kKeyHeight, (video_def->nFrameHeight + 15) & -16);
2375 } else {
2376 mOutputFormat->setInt32(kKeyWidth, video_def->nFrameWidth);
2377 mOutputFormat->setInt32(kKeyHeight, video_def->nFrameHeight);
2378 }
2379
2380 mOutputFormat->setInt32(kKeyColorFormat, video_def->eColorFormat);
2381 break;
2382 }
2383
2384 default:
2385 {
2386 CHECK(!"should not be here, neither audio nor video.");
2387 break;
2388 }
2389 }
2390}
2391
Andreas Hubere6c40962009-09-10 14:13:30 -07002392////////////////////////////////////////////////////////////////////////////////
2393
2394status_t QueryCodecs(
2395 const sp<IOMX> &omx,
2396 const char *mime, bool queryDecoders,
2397 Vector<CodecCapabilities> *results) {
2398 results->clear();
2399
2400 for (int index = 0;; ++index) {
2401 const char *componentName;
2402
2403 if (!queryDecoders) {
2404 componentName = GetCodec(
2405 kEncoderInfo, sizeof(kEncoderInfo) / sizeof(kEncoderInfo[0]),
2406 mime, index);
2407 } else {
2408 componentName = GetCodec(
2409 kDecoderInfo, sizeof(kDecoderInfo) / sizeof(kDecoderInfo[0]),
2410 mime, index);
2411 }
2412
2413 if (!componentName) {
2414 return OK;
2415 }
2416
2417 IOMX::node_id node;
2418 status_t err = omx->allocate_node(componentName, &node);
2419
2420 if (err != OK) {
2421 continue;
2422 }
2423
2424 OMXCodec::setComponentRole(omx, node, queryDecoders, mime);
2425
2426 results->push();
2427 CodecCapabilities *caps = &results->editItemAt(results->size() - 1);
2428 caps->mComponentName = componentName;
2429
2430 OMX_VIDEO_PARAM_PROFILELEVELTYPE param;
2431 InitOMXParams(&param);
2432
2433 param.nPortIndex = queryDecoders ? 0 : 1;
2434
2435 for (param.nProfileIndex = 0;; ++param.nProfileIndex) {
2436 err = omx->get_parameter(
2437 node, OMX_IndexParamVideoProfileLevelQuerySupported,
2438 &param, sizeof(param));
2439
2440 if (err != OK) {
2441 break;
2442 }
2443
2444 CodecProfileLevel profileLevel;
2445 profileLevel.mProfile = param.eProfile;
2446 profileLevel.mLevel = param.eLevel;
2447
2448 caps->mProfileLevels.push(profileLevel);
2449 }
2450
2451 CHECK_EQ(omx->free_node(node), OK);
2452 }
2453}
2454
Andreas Huberbe06d262009-08-14 14:37:10 -07002455} // namespace android