blob: 297cb87a4ed9578f9726cb8737927ab1b44213a1 [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 Hubera7d0cf42009-09-04 07:48:51 -0700207 LOGI("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
324 LOGI("AVC profile = %d (%s), level = %d",
325 (int)profile, AVCProfileToString(profile), (int)level / 10);
326
327 if (!strcmp(componentName, "OMX.TI.Video.Decoder")
328 && (profile != kAVCProfileBaseline || level > 39)) {
329 // This stream exceeds the decoder's capabilities.
330
331 LOGE("Profile and/or level exceed the decoder's capabilities.");
332 return NULL;
Andreas Huberbe06d262009-08-14 14:37:10 -0700333 }
334 }
335
Andreas Hubere6c40962009-09-10 14:13:30 -0700336 if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime)) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700337 codec->setAMRFormat();
338 }
Andreas Hubere6c40962009-09-10 14:13:30 -0700339 if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) {
Andreas Huberee606e62009-09-08 10:19:21 -0700340 codec->setAMRWBFormat();
341 }
Andreas Hubere6c40962009-09-10 14:13:30 -0700342 if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) {
Andreas Huber43ad6eaf2009-09-01 16:02:43 -0700343 int32_t numChannels, sampleRate;
344 CHECK(meta->findInt32(kKeyChannelCount, &numChannels));
345 CHECK(meta->findInt32(kKeySampleRate, &sampleRate));
346
347 codec->setAACFormat(numChannels, sampleRate);
Andreas Huberbe06d262009-08-14 14:37:10 -0700348 }
349 if (!strncasecmp(mime, "video/", 6)) {
350 int32_t width, height;
351 bool success = meta->findInt32(kKeyWidth, &width);
352 success = success && meta->findInt32(kKeyHeight, &height);
Andreas Huber5c0a9132009-08-20 11:16:40 -0700353 CHECK(success);
Andreas Huberbe06d262009-08-14 14:37:10 -0700354
355 if (createEncoder) {
356 codec->setVideoInputFormat(mime, width, height);
357 } else {
358 codec->setVideoOutputFormat(mime, width, height);
359 }
360 }
Andreas Hubere6c40962009-09-10 14:13:30 -0700361 if (!strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_JPEG)
Andreas Huberbe06d262009-08-14 14:37:10 -0700362 && !strcmp(componentName, "OMX.TI.JPEG.decode")) {
363 OMX_COLOR_FORMATTYPE format =
364 OMX_COLOR_Format32bitARGB8888;
365 // OMX_COLOR_FormatYUV420PackedPlanar;
366 // OMX_COLOR_FormatCbYCrY;
367 // OMX_COLOR_FormatYUV411Planar;
368
369 int32_t width, height;
370 bool success = meta->findInt32(kKeyWidth, &width);
371 success = success && meta->findInt32(kKeyHeight, &height);
Andreas Huber5c0a9132009-08-20 11:16:40 -0700372
373 int32_t compressedSize;
374 success = success && meta->findInt32(
Andreas Huberda050cf22009-09-02 14:01:43 -0700375 kKeyMaxInputSize, &compressedSize);
Andreas Huber5c0a9132009-08-20 11:16:40 -0700376
377 CHECK(success);
378 CHECK(compressedSize > 0);
Andreas Huberbe06d262009-08-14 14:37:10 -0700379
380 codec->setImageOutputFormat(format, width, height);
Andreas Huber5c0a9132009-08-20 11:16:40 -0700381 codec->setJPEGInputFormat(width, height, (OMX_U32)compressedSize);
Andreas Huberbe06d262009-08-14 14:37:10 -0700382 }
383
Andreas Huberda050cf22009-09-02 14:01:43 -0700384 int32_t maxInputSize;
385 if (createEncoder && meta->findInt32(kKeyMaxInputSize, &maxInputSize)) {
386 codec->setMinBufferSize(kPortIndexInput, (OMX_U32)maxInputSize);
387 }
388
389 if (!strcmp(componentName, "OMX.TI.AMR.encode")
390 || !strcmp(componentName, "OMX.TI.WBAMR.encode")) {
391 codec->setMinBufferSize(kPortIndexOutput, 8192); // XXX
392 }
393
Andreas Huberbe06d262009-08-14 14:37:10 -0700394 codec->initOutputFormat(meta);
395
396 return codec;
397}
398
Andreas Huberda050cf22009-09-02 14:01:43 -0700399void OMXCodec::setMinBufferSize(OMX_U32 portIndex, OMX_U32 size) {
400 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -0700401 InitOMXParams(&def);
Andreas Huberda050cf22009-09-02 14:01:43 -0700402 def.nPortIndex = portIndex;
403
404 status_t err = mOMX->get_parameter(
405 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
406 CHECK_EQ(err, OK);
407
408 if (def.nBufferSize < size) {
409 def.nBufferSize = size;
410
411 }
412
413 err = mOMX->set_parameter(
414 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
415 CHECK_EQ(err, OK);
416}
417
Andreas Huberbe06d262009-08-14 14:37:10 -0700418status_t OMXCodec::setVideoPortFormatType(
419 OMX_U32 portIndex,
420 OMX_VIDEO_CODINGTYPE compressionFormat,
421 OMX_COLOR_FORMATTYPE colorFormat) {
422 OMX_VIDEO_PARAM_PORTFORMATTYPE format;
Andreas Huber4c483422009-09-02 16:05:36 -0700423 InitOMXParams(&format);
Andreas Huberbe06d262009-08-14 14:37:10 -0700424 format.nPortIndex = portIndex;
425 format.nIndex = 0;
426 bool found = false;
427
428 OMX_U32 index = 0;
429 for (;;) {
430 format.nIndex = index;
431 status_t err = mOMX->get_parameter(
432 mNode, OMX_IndexParamVideoPortFormat,
433 &format, sizeof(format));
434
435 if (err != OK) {
436 return err;
437 }
438
439 // The following assertion is violated by TI's video decoder.
Andreas Huber5c0a9132009-08-20 11:16:40 -0700440 // CHECK_EQ(format.nIndex, index);
Andreas Huberbe06d262009-08-14 14:37:10 -0700441
442#if 1
Andreas Hubere0873732009-09-10 09:57:53 -0700443 CODEC_LOGI("portIndex: %ld, index: %ld, eCompressionFormat=%d eColorFormat=%d",
Andreas Huberbe06d262009-08-14 14:37:10 -0700444 portIndex,
445 index, format.eCompressionFormat, format.eColorFormat);
446#endif
447
448 if (!strcmp("OMX.TI.Video.encoder", mComponentName)) {
449 if (portIndex == kPortIndexInput
450 && colorFormat == format.eColorFormat) {
451 // eCompressionFormat does not seem right.
452 found = true;
453 break;
454 }
455 if (portIndex == kPortIndexOutput
456 && compressionFormat == format.eCompressionFormat) {
457 // eColorFormat does not seem right.
458 found = true;
459 break;
460 }
461 }
462
463 if (format.eCompressionFormat == compressionFormat
464 && format.eColorFormat == colorFormat) {
465 found = true;
466 break;
467 }
468
469 ++index;
470 }
471
472 if (!found) {
473 return UNKNOWN_ERROR;
474 }
475
Andreas Hubere0873732009-09-10 09:57:53 -0700476 CODEC_LOGI("found a match.");
Andreas Huberbe06d262009-08-14 14:37:10 -0700477 status_t err = mOMX->set_parameter(
478 mNode, OMX_IndexParamVideoPortFormat,
479 &format, sizeof(format));
480
481 return err;
482}
483
484void OMXCodec::setVideoInputFormat(
485 const char *mime, OMX_U32 width, OMX_U32 height) {
Andreas Hubere0873732009-09-10 09:57:53 -0700486 CODEC_LOGI("setVideoInputFormat width=%ld, height=%ld", width, height);
Andreas Huberbe06d262009-08-14 14:37:10 -0700487
488 OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused;
Andreas Hubere6c40962009-09-10 14:13:30 -0700489 if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700490 compressionFormat = OMX_VIDEO_CodingAVC;
Andreas Hubere6c40962009-09-10 14:13:30 -0700491 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700492 compressionFormat = OMX_VIDEO_CodingMPEG4;
Andreas Hubere6c40962009-09-10 14:13:30 -0700493 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700494 compressionFormat = OMX_VIDEO_CodingH263;
495 } else {
496 LOGE("Not a supported video mime type: %s", mime);
497 CHECK(!"Should not be here. Not a supported video mime type.");
498 }
499
500 OMX_COLOR_FORMATTYPE colorFormat =
501 0 ? OMX_COLOR_FormatYCbYCr : OMX_COLOR_FormatCbYCrY;
502
503 if (!strncmp("OMX.qcom.video.encoder.", mComponentName, 23)) {
504 colorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
505 }
506
507 setVideoPortFormatType(
508 kPortIndexInput, OMX_VIDEO_CodingUnused,
509 colorFormat);
510
511 setVideoPortFormatType(
512 kPortIndexOutput, compressionFormat, OMX_COLOR_FormatUnused);
513
514 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -0700515 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -0700516 def.nPortIndex = kPortIndexOutput;
517
Andreas Huber4c483422009-09-02 16:05:36 -0700518 OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
519
Andreas Huberbe06d262009-08-14 14:37:10 -0700520 status_t err = mOMX->get_parameter(
521 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
522
523 CHECK_EQ(err, OK);
524 CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
525
526 video_def->nFrameWidth = width;
527 video_def->nFrameHeight = height;
528
529 video_def->eCompressionFormat = compressionFormat;
530 video_def->eColorFormat = OMX_COLOR_FormatUnused;
531
532 err = mOMX->set_parameter(
533 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
534 CHECK_EQ(err, OK);
535
536 ////////////////////////////////////////////////////////////////////////////
537
Andreas Huber4c483422009-09-02 16:05:36 -0700538 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -0700539 def.nPortIndex = kPortIndexInput;
540
541 err = mOMX->get_parameter(
542 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
543 CHECK_EQ(err, OK);
544
545 def.nBufferSize = (width * height * 2); // (width * height * 3) / 2;
Andreas Hubere0873732009-09-10 09:57:53 -0700546 CODEC_LOGI("Setting nBufferSize = %ld", def.nBufferSize);
Andreas Huberbe06d262009-08-14 14:37:10 -0700547
548 CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
549
550 video_def->nFrameWidth = width;
551 video_def->nFrameHeight = height;
552 video_def->eCompressionFormat = OMX_VIDEO_CodingUnused;
553 video_def->eColorFormat = colorFormat;
554
555 err = mOMX->set_parameter(
556 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
557 CHECK_EQ(err, OK);
558}
559
560void OMXCodec::setVideoOutputFormat(
561 const char *mime, OMX_U32 width, OMX_U32 height) {
Andreas Hubere0873732009-09-10 09:57:53 -0700562 CODEC_LOGI("setVideoOutputFormat width=%ld, height=%ld", width, height);
Andreas Huberbe06d262009-08-14 14:37:10 -0700563
Andreas Huberbe06d262009-08-14 14:37:10 -0700564 OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused;
Andreas Hubere6c40962009-09-10 14:13:30 -0700565 if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700566 compressionFormat = OMX_VIDEO_CodingAVC;
Andreas Hubere6c40962009-09-10 14:13:30 -0700567 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700568 compressionFormat = OMX_VIDEO_CodingMPEG4;
Andreas Hubere6c40962009-09-10 14:13:30 -0700569 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700570 compressionFormat = OMX_VIDEO_CodingH263;
571 } else {
572 LOGE("Not a supported video mime type: %s", mime);
573 CHECK(!"Should not be here. Not a supported video mime type.");
574 }
575
576 setVideoPortFormatType(
577 kPortIndexInput, compressionFormat, OMX_COLOR_FormatUnused);
578
579#if 1
580 {
581 OMX_VIDEO_PARAM_PORTFORMATTYPE format;
Andreas Huber4c483422009-09-02 16:05:36 -0700582 InitOMXParams(&format);
Andreas Huberbe06d262009-08-14 14:37:10 -0700583 format.nPortIndex = kPortIndexOutput;
584 format.nIndex = 0;
585
586 status_t err = mOMX->get_parameter(
587 mNode, OMX_IndexParamVideoPortFormat,
588 &format, sizeof(format));
589 CHECK_EQ(err, OK);
590 CHECK_EQ(format.eCompressionFormat, OMX_VIDEO_CodingUnused);
591
592 static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
593
594 CHECK(format.eColorFormat == OMX_COLOR_FormatYUV420Planar
595 || format.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar
596 || format.eColorFormat == OMX_COLOR_FormatCbYCrY
597 || format.eColorFormat == OMX_QCOM_COLOR_FormatYVU420SemiPlanar);
598
599 err = mOMX->set_parameter(
600 mNode, OMX_IndexParamVideoPortFormat,
601 &format, sizeof(format));
602 CHECK_EQ(err, OK);
603 }
604#endif
605
606 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -0700607 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -0700608 def.nPortIndex = kPortIndexInput;
609
Andreas Huber4c483422009-09-02 16:05:36 -0700610 OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
611
Andreas Huberbe06d262009-08-14 14:37:10 -0700612 status_t err = mOMX->get_parameter(
613 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
614
615 CHECK_EQ(err, OK);
616
617#if 1
618 // XXX Need a (much) better heuristic to compute input buffer sizes.
619 const size_t X = 64 * 1024;
620 if (def.nBufferSize < X) {
621 def.nBufferSize = X;
622 }
623#endif
624
625 CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
626
627 video_def->nFrameWidth = width;
628 video_def->nFrameHeight = height;
629
630 video_def->eColorFormat = OMX_COLOR_FormatUnused;
631
632 err = mOMX->set_parameter(
633 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
634 CHECK_EQ(err, OK);
635
636 ////////////////////////////////////////////////////////////////////////////
637
Andreas Huber4c483422009-09-02 16:05:36 -0700638 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -0700639 def.nPortIndex = kPortIndexOutput;
640
641 err = mOMX->get_parameter(
642 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
643 CHECK_EQ(err, OK);
644 CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
645
646#if 0
647 def.nBufferSize =
648 (((width + 15) & -16) * ((height + 15) & -16) * 3) / 2; // YUV420
649#endif
650
651 video_def->nFrameWidth = width;
652 video_def->nFrameHeight = height;
653
654 err = mOMX->set_parameter(
655 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
656 CHECK_EQ(err, OK);
657}
658
659
660OMXCodec::OMXCodec(
661 const sp<IOMX> &omx, IOMX::node_id node, uint32_t quirks,
Andreas Huberebf66ea2009-08-19 13:32:58 -0700662 bool isEncoder,
Andreas Huberbe06d262009-08-14 14:37:10 -0700663 const char *mime,
664 const char *componentName,
665 const sp<MediaSource> &source)
666 : mOMX(omx),
667 mNode(node),
668 mQuirks(quirks),
669 mIsEncoder(isEncoder),
670 mMIME(strdup(mime)),
671 mComponentName(strdup(componentName)),
672 mSource(source),
673 mCodecSpecificDataIndex(0),
Andreas Huberbe06d262009-08-14 14:37:10 -0700674 mState(LOADED),
Andreas Huber42978e52009-08-27 10:08:39 -0700675 mInitialBufferSubmit(true),
Andreas Huberbe06d262009-08-14 14:37:10 -0700676 mSignalledEOS(false),
677 mNoMoreOutputData(false),
678 mSeekTimeUs(-1) {
679 mPortStatus[kPortIndexInput] = ENABLED;
680 mPortStatus[kPortIndexOutput] = ENABLED;
681
682 mObserver = new OMXCodecObserver(this);
683 mOMX->observe_node(mNode, mObserver);
Andreas Huber4c483422009-09-02 16:05:36 -0700684
685 setComponentRole();
686}
687
Andreas Hubere6c40962009-09-10 14:13:30 -0700688// static
689void OMXCodec::setComponentRole(
690 const sp<IOMX> &omx, IOMX::node_id node, bool isEncoder,
691 const char *mime) {
Andreas Huber4c483422009-09-02 16:05:36 -0700692 struct MimeToRole {
693 const char *mime;
694 const char *decoderRole;
695 const char *encoderRole;
696 };
697
698 static const MimeToRole kMimeToRole[] = {
Andreas Hubere6c40962009-09-10 14:13:30 -0700699 { MEDIA_MIMETYPE_AUDIO_MPEG,
700 "audio_decoder.mp3", "audio_encoder.mp3" },
701 { MEDIA_MIMETYPE_AUDIO_AMR_NB,
702 "audio_decoder.amrnb", "audio_encoder.amrnb" },
703 { MEDIA_MIMETYPE_AUDIO_AMR_WB,
704 "audio_decoder.amrwb", "audio_encoder.amrwb" },
705 { MEDIA_MIMETYPE_AUDIO_AAC,
706 "audio_decoder.aac", "audio_encoder.aac" },
707 { MEDIA_MIMETYPE_VIDEO_AVC,
708 "video_decoder.avc", "video_encoder.avc" },
709 { MEDIA_MIMETYPE_VIDEO_MPEG4,
710 "video_decoder.mpeg4", "video_encoder.mpeg4" },
711 { MEDIA_MIMETYPE_VIDEO_H263,
712 "video_decoder.h263", "video_encoder.h263" },
Andreas Huber4c483422009-09-02 16:05:36 -0700713 };
714
715 static const size_t kNumMimeToRole =
716 sizeof(kMimeToRole) / sizeof(kMimeToRole[0]);
717
718 size_t i;
719 for (i = 0; i < kNumMimeToRole; ++i) {
Andreas Hubere6c40962009-09-10 14:13:30 -0700720 if (!strcasecmp(mime, kMimeToRole[i].mime)) {
Andreas Huber4c483422009-09-02 16:05:36 -0700721 break;
722 }
723 }
724
725 if (i == kNumMimeToRole) {
726 return;
727 }
728
729 const char *role =
Andreas Hubere6c40962009-09-10 14:13:30 -0700730 isEncoder ? kMimeToRole[i].encoderRole
731 : kMimeToRole[i].decoderRole;
Andreas Huber4c483422009-09-02 16:05:36 -0700732
733 if (role != NULL) {
Andreas Huber4c483422009-09-02 16:05:36 -0700734 OMX_PARAM_COMPONENTROLETYPE roleParams;
735 InitOMXParams(&roleParams);
736
737 strncpy((char *)roleParams.cRole,
738 role, OMX_MAX_STRINGNAME_SIZE - 1);
739
740 roleParams.cRole[OMX_MAX_STRINGNAME_SIZE - 1] = '\0';
741
Andreas Hubere6c40962009-09-10 14:13:30 -0700742 status_t err = omx->set_parameter(
743 node, OMX_IndexParamStandardComponentRole,
Andreas Huber4c483422009-09-02 16:05:36 -0700744 &roleParams, sizeof(roleParams));
745
746 if (err != OK) {
747 LOGW("Failed to set standard component role '%s'.", role);
748 }
749 }
Andreas Huberbe06d262009-08-14 14:37:10 -0700750}
751
Andreas Hubere6c40962009-09-10 14:13:30 -0700752void OMXCodec::setComponentRole() {
753 setComponentRole(mOMX, mNode, mIsEncoder, mMIME);
754}
755
Andreas Huberbe06d262009-08-14 14:37:10 -0700756OMXCodec::~OMXCodec() {
Andreas Huber4f5e6022009-08-19 09:29:34 -0700757 CHECK(mState == LOADED || mState == ERROR);
Andreas Huberbe06d262009-08-14 14:37:10 -0700758
759 status_t err = mOMX->observe_node(mNode, NULL);
760 CHECK_EQ(err, OK);
761
762 err = mOMX->free_node(mNode);
763 CHECK_EQ(err, OK);
764
765 mNode = NULL;
766 setState(DEAD);
767
768 clearCodecSpecificData();
769
770 free(mComponentName);
771 mComponentName = NULL;
Andreas Huberebf66ea2009-08-19 13:32:58 -0700772
Andreas Huberbe06d262009-08-14 14:37:10 -0700773 free(mMIME);
774 mMIME = NULL;
775}
776
777status_t OMXCodec::init() {
Andreas Huber42978e52009-08-27 10:08:39 -0700778 // mLock is held.
Andreas Huberbe06d262009-08-14 14:37:10 -0700779
780 CHECK_EQ(mState, LOADED);
781
782 status_t err;
783 if (!(mQuirks & kRequiresLoadedToIdleAfterAllocation)) {
784 err = mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
785 CHECK_EQ(err, OK);
Andreas Huberbe06d262009-08-14 14:37:10 -0700786 setState(LOADED_TO_IDLE);
787 }
788
789 err = allocateBuffers();
790 CHECK_EQ(err, OK);
791
792 if (mQuirks & kRequiresLoadedToIdleAfterAllocation) {
793 err = mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
794 CHECK_EQ(err, OK);
795
796 setState(LOADED_TO_IDLE);
797 }
798
799 while (mState != EXECUTING && mState != ERROR) {
800 mAsyncCompletion.wait(mLock);
801 }
802
803 return mState == ERROR ? UNKNOWN_ERROR : OK;
804}
805
806// static
807bool OMXCodec::isIntermediateState(State state) {
808 return state == LOADED_TO_IDLE
809 || state == IDLE_TO_EXECUTING
810 || state == EXECUTING_TO_IDLE
811 || state == IDLE_TO_LOADED
812 || state == RECONFIGURING;
813}
814
815status_t OMXCodec::allocateBuffers() {
816 status_t err = allocateBuffersOnPort(kPortIndexInput);
817
818 if (err != OK) {
819 return err;
820 }
821
822 return allocateBuffersOnPort(kPortIndexOutput);
823}
824
825status_t OMXCodec::allocateBuffersOnPort(OMX_U32 portIndex) {
826 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -0700827 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -0700828 def.nPortIndex = portIndex;
829
830 status_t err = mOMX->get_parameter(
831 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
832
833 if (err != OK) {
834 return err;
835 }
836
Andreas Huber5c0a9132009-08-20 11:16:40 -0700837 size_t totalSize = def.nBufferCountActual * def.nBufferSize;
838 mDealer[portIndex] = new MemoryDealer(totalSize);
839
Andreas Huberbe06d262009-08-14 14:37:10 -0700840 for (OMX_U32 i = 0; i < def.nBufferCountActual; ++i) {
Andreas Huber5c0a9132009-08-20 11:16:40 -0700841 sp<IMemory> mem = mDealer[portIndex]->allocate(def.nBufferSize);
Andreas Huberbe06d262009-08-14 14:37:10 -0700842 CHECK(mem.get() != NULL);
843
844 IOMX::buffer_id buffer;
845 if (portIndex == kPortIndexInput
846 && (mQuirks & kRequiresAllocateBufferOnInputPorts)) {
847 err = mOMX->allocate_buffer_with_backup(
848 mNode, portIndex, mem, &buffer);
Andreas Huber446f44f2009-08-25 17:23:44 -0700849 } else if (portIndex == kPortIndexOutput
850 && (mQuirks & kRequiresAllocateBufferOnOutputPorts)) {
Andreas Huber2dc64d82009-09-11 12:58:53 -0700851 err = mOMX->allocate_buffer_with_backup(
852 mNode, portIndex, mem, &buffer);
Andreas Huberbe06d262009-08-14 14:37:10 -0700853 } else {
854 err = mOMX->use_buffer(mNode, portIndex, mem, &buffer);
855 }
856
857 if (err != OK) {
858 LOGE("allocate_buffer_with_backup failed");
859 return err;
860 }
861
862 BufferInfo info;
863 info.mBuffer = buffer;
864 info.mOwnedByComponent = false;
865 info.mMem = mem;
866 info.mMediaBuffer = NULL;
867
868 if (portIndex == kPortIndexOutput) {
869 info.mMediaBuffer = new MediaBuffer(mem->pointer(), mem->size());
870 info.mMediaBuffer->setObserver(this);
871 }
872
873 mPortBuffers[portIndex].push(info);
874
Andreas Huber4c483422009-09-02 16:05:36 -0700875 CODEC_LOGV("allocated buffer %p on %s port", buffer,
Andreas Huberbe06d262009-08-14 14:37:10 -0700876 portIndex == kPortIndexInput ? "input" : "output");
877 }
878
879 dumpPortStatus(portIndex);
880
881 return OK;
882}
883
884void OMXCodec::on_message(const omx_message &msg) {
885 Mutex::Autolock autoLock(mLock);
886
887 switch (msg.type) {
888 case omx_message::EVENT:
889 {
890 onEvent(
891 msg.u.event_data.event, msg.u.event_data.data1,
892 msg.u.event_data.data2);
893
894 break;
895 }
896
897 case omx_message::EMPTY_BUFFER_DONE:
898 {
899 IOMX::buffer_id buffer = msg.u.extended_buffer_data.buffer;
900
Andreas Huber4c483422009-09-02 16:05:36 -0700901 CODEC_LOGV("EMPTY_BUFFER_DONE(buffer: %p)", buffer);
Andreas Huberbe06d262009-08-14 14:37:10 -0700902
903 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
904 size_t i = 0;
905 while (i < buffers->size() && (*buffers)[i].mBuffer != buffer) {
906 ++i;
907 }
908
909 CHECK(i < buffers->size());
910 if (!(*buffers)[i].mOwnedByComponent) {
911 LOGW("We already own input buffer %p, yet received "
912 "an EMPTY_BUFFER_DONE.", buffer);
913 }
914
915 buffers->editItemAt(i).mOwnedByComponent = false;
916
917 if (mPortStatus[kPortIndexInput] == DISABLING) {
Andreas Huber4c483422009-09-02 16:05:36 -0700918 CODEC_LOGV("Port is disabled, freeing buffer %p", buffer);
Andreas Huberbe06d262009-08-14 14:37:10 -0700919
920 status_t err =
921 mOMX->free_buffer(mNode, kPortIndexInput, buffer);
922 CHECK_EQ(err, OK);
923
924 buffers->removeAt(i);
925 } else if (mPortStatus[kPortIndexInput] != SHUTTING_DOWN) {
926 CHECK_EQ(mPortStatus[kPortIndexInput], ENABLED);
927 drainInputBuffer(&buffers->editItemAt(i));
928 }
929
930 break;
931 }
932
933 case omx_message::FILL_BUFFER_DONE:
934 {
935 IOMX::buffer_id buffer = msg.u.extended_buffer_data.buffer;
936 OMX_U32 flags = msg.u.extended_buffer_data.flags;
937
Andreas Huber4c483422009-09-02 16:05:36 -0700938 CODEC_LOGV("FILL_BUFFER_DONE(buffer: %p, size: %ld, flags: 0x%08lx)",
Andreas Huberbe06d262009-08-14 14:37:10 -0700939 buffer,
940 msg.u.extended_buffer_data.range_length,
941 flags);
942
Andreas Huber4c483422009-09-02 16:05:36 -0700943 CODEC_LOGV("FILL_BUFFER_DONE(timestamp: %lld us (%.2f secs))",
Andreas Huberbe06d262009-08-14 14:37:10 -0700944 msg.u.extended_buffer_data.timestamp,
945 msg.u.extended_buffer_data.timestamp / 1E6);
946
947 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
948 size_t i = 0;
949 while (i < buffers->size() && (*buffers)[i].mBuffer != buffer) {
950 ++i;
951 }
952
953 CHECK(i < buffers->size());
954 BufferInfo *info = &buffers->editItemAt(i);
955
956 if (!info->mOwnedByComponent) {
957 LOGW("We already own output buffer %p, yet received "
958 "a FILL_BUFFER_DONE.", buffer);
959 }
960
961 info->mOwnedByComponent = false;
962
963 if (mPortStatus[kPortIndexOutput] == DISABLING) {
Andreas Huber4c483422009-09-02 16:05:36 -0700964 CODEC_LOGV("Port is disabled, freeing buffer %p", buffer);
Andreas Huberbe06d262009-08-14 14:37:10 -0700965
966 status_t err =
967 mOMX->free_buffer(mNode, kPortIndexOutput, buffer);
968 CHECK_EQ(err, OK);
969
970 buffers->removeAt(i);
Andreas Huberd7795892009-08-26 10:33:47 -0700971 } else if (mPortStatus[kPortIndexOutput] == ENABLED
972 && (flags & OMX_BUFFERFLAG_EOS)) {
Andreas Huber4c483422009-09-02 16:05:36 -0700973 CODEC_LOGV("No more output data.");
Andreas Huberbe06d262009-08-14 14:37:10 -0700974 mNoMoreOutputData = true;
975 mBufferFilled.signal();
976 } else if (mPortStatus[kPortIndexOutput] != SHUTTING_DOWN) {
977 CHECK_EQ(mPortStatus[kPortIndexOutput], ENABLED);
Andreas Huberebf66ea2009-08-19 13:32:58 -0700978
Andreas Huberbe06d262009-08-14 14:37:10 -0700979 MediaBuffer *buffer = info->mMediaBuffer;
980
981 buffer->set_range(
982 msg.u.extended_buffer_data.range_offset,
983 msg.u.extended_buffer_data.range_length);
984
985 buffer->meta_data()->clear();
986
987 buffer->meta_data()->setInt32(
988 kKeyTimeUnits,
989 (msg.u.extended_buffer_data.timestamp + 500) / 1000);
990
991 buffer->meta_data()->setInt32(
992 kKeyTimeScale, 1000);
993
994 if (msg.u.extended_buffer_data.flags & OMX_BUFFERFLAG_SYNCFRAME) {
995 buffer->meta_data()->setInt32(kKeyIsSyncFrame, true);
996 }
997
998 buffer->meta_data()->setPointer(
999 kKeyPlatformPrivate,
1000 msg.u.extended_buffer_data.platform_private);
1001
1002 buffer->meta_data()->setPointer(
1003 kKeyBufferID,
1004 msg.u.extended_buffer_data.buffer);
1005
1006 mFilledBuffers.push_back(i);
1007 mBufferFilled.signal();
1008 }
1009
1010 break;
1011 }
1012
1013 default:
1014 {
1015 CHECK(!"should not be here.");
1016 break;
1017 }
1018 }
1019}
1020
1021void OMXCodec::onEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) {
1022 switch (event) {
1023 case OMX_EventCmdComplete:
1024 {
1025 onCmdComplete((OMX_COMMANDTYPE)data1, data2);
1026 break;
1027 }
1028
1029 case OMX_EventError:
1030 {
1031 LOGE("ERROR(%ld, %ld)", data1, data2);
1032
1033 setState(ERROR);
1034 break;
1035 }
1036
1037 case OMX_EventPortSettingsChanged:
1038 {
1039 onPortSettingsChanged(data1);
1040 break;
1041 }
1042
1043 case OMX_EventBufferFlag:
1044 {
Andreas Huber4c483422009-09-02 16:05:36 -07001045 CODEC_LOGV("EVENT_BUFFER_FLAG(%ld)", data1);
Andreas Huberbe06d262009-08-14 14:37:10 -07001046
1047 if (data1 == kPortIndexOutput) {
1048 mNoMoreOutputData = true;
1049 }
1050 break;
1051 }
1052
1053 default:
1054 {
Andreas Huber4c483422009-09-02 16:05:36 -07001055 CODEC_LOGV("EVENT(%d, %ld, %ld)", event, data1, data2);
Andreas Huberbe06d262009-08-14 14:37:10 -07001056 break;
1057 }
1058 }
1059}
1060
1061void OMXCodec::onCmdComplete(OMX_COMMANDTYPE cmd, OMX_U32 data) {
1062 switch (cmd) {
1063 case OMX_CommandStateSet:
1064 {
1065 onStateChange((OMX_STATETYPE)data);
1066 break;
1067 }
1068
1069 case OMX_CommandPortDisable:
1070 {
1071 OMX_U32 portIndex = data;
Andreas Huber4c483422009-09-02 16:05:36 -07001072 CODEC_LOGV("PORT_DISABLED(%ld)", portIndex);
Andreas Huberbe06d262009-08-14 14:37:10 -07001073
1074 CHECK(mState == EXECUTING || mState == RECONFIGURING);
1075 CHECK_EQ(mPortStatus[portIndex], DISABLING);
1076 CHECK_EQ(mPortBuffers[portIndex].size(), 0);
1077
1078 mPortStatus[portIndex] = DISABLED;
1079
1080 if (mState == RECONFIGURING) {
1081 CHECK_EQ(portIndex, kPortIndexOutput);
1082
1083 enablePortAsync(portIndex);
1084
1085 status_t err = allocateBuffersOnPort(portIndex);
1086 CHECK_EQ(err, OK);
1087 }
1088 break;
1089 }
1090
1091 case OMX_CommandPortEnable:
1092 {
1093 OMX_U32 portIndex = data;
Andreas Huber4c483422009-09-02 16:05:36 -07001094 CODEC_LOGV("PORT_ENABLED(%ld)", portIndex);
Andreas Huberbe06d262009-08-14 14:37:10 -07001095
1096 CHECK(mState == EXECUTING || mState == RECONFIGURING);
1097 CHECK_EQ(mPortStatus[portIndex], ENABLING);
1098
1099 mPortStatus[portIndex] = ENABLED;
1100
1101 if (mState == RECONFIGURING) {
1102 CHECK_EQ(portIndex, kPortIndexOutput);
1103
1104 setState(EXECUTING);
1105
1106 fillOutputBuffers();
1107 }
1108 break;
1109 }
1110
1111 case OMX_CommandFlush:
1112 {
1113 OMX_U32 portIndex = data;
1114
Andreas Huber4c483422009-09-02 16:05:36 -07001115 CODEC_LOGV("FLUSH_DONE(%ld)", portIndex);
Andreas Huberbe06d262009-08-14 14:37:10 -07001116
1117 CHECK_EQ(mPortStatus[portIndex], SHUTTING_DOWN);
1118 mPortStatus[portIndex] = ENABLED;
1119
1120 CHECK_EQ(countBuffersWeOwn(mPortBuffers[portIndex]),
1121 mPortBuffers[portIndex].size());
1122
1123 if (mState == RECONFIGURING) {
1124 CHECK_EQ(portIndex, kPortIndexOutput);
1125
1126 disablePortAsync(portIndex);
Andreas Huber127fcdc2009-08-26 16:27:02 -07001127 } else if (mState == EXECUTING_TO_IDLE) {
1128 if (mPortStatus[kPortIndexInput] == ENABLED
1129 && mPortStatus[kPortIndexOutput] == ENABLED) {
Andreas Huber4c483422009-09-02 16:05:36 -07001130 CODEC_LOGV("Finished flushing both ports, now completing "
Andreas Huber127fcdc2009-08-26 16:27:02 -07001131 "transition from EXECUTING to IDLE.");
1132
1133 mPortStatus[kPortIndexInput] = SHUTTING_DOWN;
1134 mPortStatus[kPortIndexOutput] = SHUTTING_DOWN;
1135
1136 status_t err =
1137 mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
1138 CHECK_EQ(err, OK);
1139 }
Andreas Huberbe06d262009-08-14 14:37:10 -07001140 } else {
1141 // We're flushing both ports in preparation for seeking.
1142
1143 if (mPortStatus[kPortIndexInput] == ENABLED
1144 && mPortStatus[kPortIndexOutput] == ENABLED) {
Andreas Huber4c483422009-09-02 16:05:36 -07001145 CODEC_LOGV("Finished flushing both ports, now continuing from"
Andreas Huberbe06d262009-08-14 14:37:10 -07001146 " seek-time.");
1147
Andreas Huber1a77b68e2009-09-17 11:16:52 -07001148 // Clear this flag in case the decoder sent us either
1149 // the EVENT_BUFFER_FLAG(1) or an output buffer with
1150 // the EOS flag set _while_ flushing. Since we're going
1151 // to submit "fresh" input data now, this flag no longer
1152 // applies to our future.
1153 mNoMoreOutputData = false;
1154
Andreas Huberbe06d262009-08-14 14:37:10 -07001155 drainInputBuffers();
1156 fillOutputBuffers();
1157 }
1158 }
1159
1160 break;
1161 }
1162
1163 default:
1164 {
Andreas Huber4c483422009-09-02 16:05:36 -07001165 CODEC_LOGV("CMD_COMPLETE(%d, %ld)", cmd, data);
Andreas Huberbe06d262009-08-14 14:37:10 -07001166 break;
1167 }
1168 }
1169}
1170
1171void OMXCodec::onStateChange(OMX_STATETYPE newState) {
1172 switch (newState) {
1173 case OMX_StateIdle:
1174 {
Andreas Huber4c483422009-09-02 16:05:36 -07001175 CODEC_LOGV("Now Idle.");
Andreas Huberbe06d262009-08-14 14:37:10 -07001176 if (mState == LOADED_TO_IDLE) {
1177 status_t err = mOMX->send_command(
1178 mNode, OMX_CommandStateSet, OMX_StateExecuting);
1179
1180 CHECK_EQ(err, OK);
1181
1182 setState(IDLE_TO_EXECUTING);
1183 } else {
1184 CHECK_EQ(mState, EXECUTING_TO_IDLE);
1185
1186 CHECK_EQ(
1187 countBuffersWeOwn(mPortBuffers[kPortIndexInput]),
1188 mPortBuffers[kPortIndexInput].size());
1189
1190 CHECK_EQ(
1191 countBuffersWeOwn(mPortBuffers[kPortIndexOutput]),
1192 mPortBuffers[kPortIndexOutput].size());
1193
1194 status_t err = mOMX->send_command(
1195 mNode, OMX_CommandStateSet, OMX_StateLoaded);
1196
1197 CHECK_EQ(err, OK);
1198
1199 err = freeBuffersOnPort(kPortIndexInput);
1200 CHECK_EQ(err, OK);
1201
1202 err = freeBuffersOnPort(kPortIndexOutput);
1203 CHECK_EQ(err, OK);
1204
1205 mPortStatus[kPortIndexInput] = ENABLED;
1206 mPortStatus[kPortIndexOutput] = ENABLED;
1207
1208 setState(IDLE_TO_LOADED);
1209 }
1210 break;
1211 }
1212
1213 case OMX_StateExecuting:
1214 {
1215 CHECK_EQ(mState, IDLE_TO_EXECUTING);
1216
Andreas Huber4c483422009-09-02 16:05:36 -07001217 CODEC_LOGV("Now Executing.");
Andreas Huberbe06d262009-08-14 14:37:10 -07001218
1219 setState(EXECUTING);
1220
Andreas Huber42978e52009-08-27 10:08:39 -07001221 // Buffers will be submitted to the component in the first
1222 // call to OMXCodec::read as mInitialBufferSubmit is true at
1223 // this point. This ensures that this on_message call returns,
1224 // releases the lock and ::init can notice the state change and
1225 // itself return.
Andreas Huberbe06d262009-08-14 14:37:10 -07001226 break;
1227 }
1228
1229 case OMX_StateLoaded:
1230 {
1231 CHECK_EQ(mState, IDLE_TO_LOADED);
1232
Andreas Huber4c483422009-09-02 16:05:36 -07001233 CODEC_LOGV("Now Loaded.");
Andreas Huberbe06d262009-08-14 14:37:10 -07001234
1235 setState(LOADED);
1236 break;
1237 }
1238
1239 default:
1240 {
1241 CHECK(!"should not be here.");
1242 break;
1243 }
1244 }
1245}
1246
1247// static
1248size_t OMXCodec::countBuffersWeOwn(const Vector<BufferInfo> &buffers) {
1249 size_t n = 0;
1250 for (size_t i = 0; i < buffers.size(); ++i) {
1251 if (!buffers[i].mOwnedByComponent) {
1252 ++n;
1253 }
1254 }
1255
1256 return n;
1257}
1258
1259status_t OMXCodec::freeBuffersOnPort(
1260 OMX_U32 portIndex, bool onlyThoseWeOwn) {
1261 Vector<BufferInfo> *buffers = &mPortBuffers[portIndex];
1262
1263 status_t stickyErr = OK;
1264
1265 for (size_t i = buffers->size(); i-- > 0;) {
1266 BufferInfo *info = &buffers->editItemAt(i);
1267
1268 if (onlyThoseWeOwn && info->mOwnedByComponent) {
1269 continue;
1270 }
1271
1272 CHECK_EQ(info->mOwnedByComponent, false);
1273
Andreas Huber92022852009-09-14 15:24:14 -07001274 CODEC_LOGV("freeing buffer %p on port %ld", info->mBuffer, portIndex);
1275
Andreas Huberbe06d262009-08-14 14:37:10 -07001276 status_t err =
1277 mOMX->free_buffer(mNode, portIndex, info->mBuffer);
1278
1279 if (err != OK) {
1280 stickyErr = err;
1281 }
1282
1283 if (info->mMediaBuffer != NULL) {
1284 info->mMediaBuffer->setObserver(NULL);
1285
1286 // Make sure nobody but us owns this buffer at this point.
1287 CHECK_EQ(info->mMediaBuffer->refcount(), 0);
1288
1289 info->mMediaBuffer->release();
1290 }
1291
1292 buffers->removeAt(i);
1293 }
1294
1295 CHECK(onlyThoseWeOwn || buffers->isEmpty());
1296
1297 return stickyErr;
1298}
1299
1300void OMXCodec::onPortSettingsChanged(OMX_U32 portIndex) {
Andreas Huber4c483422009-09-02 16:05:36 -07001301 CODEC_LOGV("PORT_SETTINGS_CHANGED(%ld)", portIndex);
Andreas Huberbe06d262009-08-14 14:37:10 -07001302
1303 CHECK_EQ(mState, EXECUTING);
1304 CHECK_EQ(portIndex, kPortIndexOutput);
1305 setState(RECONFIGURING);
1306
1307 if (mQuirks & kNeedsFlushBeforeDisable) {
Andreas Huber404cc412009-08-25 14:26:05 -07001308 if (!flushPortAsync(portIndex)) {
1309 onCmdComplete(OMX_CommandFlush, portIndex);
1310 }
Andreas Huberbe06d262009-08-14 14:37:10 -07001311 } else {
1312 disablePortAsync(portIndex);
1313 }
1314}
1315
Andreas Huber404cc412009-08-25 14:26:05 -07001316bool OMXCodec::flushPortAsync(OMX_U32 portIndex) {
Andreas Huber127fcdc2009-08-26 16:27:02 -07001317 CHECK(mState == EXECUTING || mState == RECONFIGURING
1318 || mState == EXECUTING_TO_IDLE);
Andreas Huberbe06d262009-08-14 14:37:10 -07001319
Andreas Huber4c483422009-09-02 16:05:36 -07001320 CODEC_LOGV("flushPortAsync(%ld): we own %d out of %d buffers already.",
Andreas Huber404cc412009-08-25 14:26:05 -07001321 portIndex, countBuffersWeOwn(mPortBuffers[portIndex]),
1322 mPortBuffers[portIndex].size());
1323
Andreas Huberbe06d262009-08-14 14:37:10 -07001324 CHECK_EQ(mPortStatus[portIndex], ENABLED);
1325 mPortStatus[portIndex] = SHUTTING_DOWN;
1326
Andreas Huber404cc412009-08-25 14:26:05 -07001327 if ((mQuirks & kRequiresFlushCompleteEmulation)
1328 && countBuffersWeOwn(mPortBuffers[portIndex])
1329 == mPortBuffers[portIndex].size()) {
1330 // No flush is necessary and this component fails to send a
1331 // flush-complete event in this case.
1332
1333 return false;
1334 }
1335
Andreas Huberbe06d262009-08-14 14:37:10 -07001336 status_t err =
1337 mOMX->send_command(mNode, OMX_CommandFlush, portIndex);
1338 CHECK_EQ(err, OK);
Andreas Huber404cc412009-08-25 14:26:05 -07001339
1340 return true;
Andreas Huberbe06d262009-08-14 14:37:10 -07001341}
1342
1343void OMXCodec::disablePortAsync(OMX_U32 portIndex) {
1344 CHECK(mState == EXECUTING || mState == RECONFIGURING);
1345
1346 CHECK_EQ(mPortStatus[portIndex], ENABLED);
1347 mPortStatus[portIndex] = DISABLING;
1348
1349 status_t err =
1350 mOMX->send_command(mNode, OMX_CommandPortDisable, portIndex);
1351 CHECK_EQ(err, OK);
1352
1353 freeBuffersOnPort(portIndex, true);
1354}
1355
1356void OMXCodec::enablePortAsync(OMX_U32 portIndex) {
1357 CHECK(mState == EXECUTING || mState == RECONFIGURING);
1358
1359 CHECK_EQ(mPortStatus[portIndex], DISABLED);
1360 mPortStatus[portIndex] = ENABLING;
1361
1362 status_t err =
1363 mOMX->send_command(mNode, OMX_CommandPortEnable, portIndex);
1364 CHECK_EQ(err, OK);
1365}
1366
1367void OMXCodec::fillOutputBuffers() {
1368 CHECK_EQ(mState, EXECUTING);
1369
1370 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
1371 for (size_t i = 0; i < buffers->size(); ++i) {
1372 fillOutputBuffer(&buffers->editItemAt(i));
1373 }
1374}
1375
1376void OMXCodec::drainInputBuffers() {
Andreas Huberd06e5b82009-08-28 13:18:14 -07001377 CHECK(mState == EXECUTING || mState == RECONFIGURING);
Andreas Huberbe06d262009-08-14 14:37:10 -07001378
1379 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
1380 for (size_t i = 0; i < buffers->size(); ++i) {
1381 drainInputBuffer(&buffers->editItemAt(i));
1382 }
1383}
1384
1385void OMXCodec::drainInputBuffer(BufferInfo *info) {
1386 CHECK_EQ(info->mOwnedByComponent, false);
1387
1388 if (mSignalledEOS) {
1389 return;
1390 }
1391
1392 if (mCodecSpecificDataIndex < mCodecSpecificData.size()) {
1393 const CodecSpecificData *specific =
1394 mCodecSpecificData[mCodecSpecificDataIndex];
1395
1396 size_t size = specific->mSize;
1397
Andreas Hubere6c40962009-09-10 14:13:30 -07001398 if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mMIME)
Andreas Huber4f5e6022009-08-19 09:29:34 -07001399 && !(mQuirks & kWantsNALFragments)) {
Andreas Huberbe06d262009-08-14 14:37:10 -07001400 static const uint8_t kNALStartCode[4] =
1401 { 0x00, 0x00, 0x00, 0x01 };
1402
1403 CHECK(info->mMem->size() >= specific->mSize + 4);
1404
1405 size += 4;
1406
1407 memcpy(info->mMem->pointer(), kNALStartCode, 4);
1408 memcpy((uint8_t *)info->mMem->pointer() + 4,
1409 specific->mData, specific->mSize);
1410 } else {
1411 CHECK(info->mMem->size() >= specific->mSize);
1412 memcpy(info->mMem->pointer(), specific->mData, specific->mSize);
1413 }
1414
Andreas Huber3f427072009-10-08 11:02:27 -07001415 status_t err = mOMX->empty_buffer(
Andreas Huberbe06d262009-08-14 14:37:10 -07001416 mNode, info->mBuffer, 0, size,
1417 OMX_BUFFERFLAG_ENDOFFRAME | OMX_BUFFERFLAG_CODECCONFIG,
1418 0);
Andreas Huber3f427072009-10-08 11:02:27 -07001419 CHECK_EQ(err, OK);
Andreas Huberbe06d262009-08-14 14:37:10 -07001420
1421 info->mOwnedByComponent = true;
1422
1423 ++mCodecSpecificDataIndex;
1424 return;
1425 }
1426
1427 MediaBuffer *srcBuffer;
1428 status_t err;
1429 if (mSeekTimeUs >= 0) {
1430 MediaSource::ReadOptions options;
1431 options.setSeekTo(mSeekTimeUs);
1432 mSeekTimeUs = -1;
1433
1434 err = mSource->read(&srcBuffer, &options);
1435 } else {
1436 err = mSource->read(&srcBuffer);
1437 }
1438
1439 OMX_U32 flags = OMX_BUFFERFLAG_ENDOFFRAME;
1440 OMX_TICKS timestamp = 0;
1441 size_t srcLength = 0;
1442
1443 if (err != OK) {
Andreas Huber4c483422009-09-02 16:05:36 -07001444 CODEC_LOGV("signalling end of input stream.");
Andreas Huberbe06d262009-08-14 14:37:10 -07001445 flags |= OMX_BUFFERFLAG_EOS;
1446
1447 mSignalledEOS = true;
1448 } else {
1449 srcLength = srcBuffer->range_length();
1450
1451 if (info->mMem->size() < srcLength) {
1452 LOGE("info->mMem->size() = %d, srcLength = %d",
1453 info->mMem->size(), srcLength);
1454 }
1455 CHECK(info->mMem->size() >= srcLength);
1456 memcpy(info->mMem->pointer(),
1457 (const uint8_t *)srcBuffer->data() + srcBuffer->range_offset(),
1458 srcLength);
1459
1460 int32_t units, scale;
1461 if (srcBuffer->meta_data()->findInt32(kKeyTimeUnits, &units)
1462 && srcBuffer->meta_data()->findInt32(kKeyTimeScale, &scale)) {
1463 timestamp = ((OMX_TICKS)units * 1000000) / scale;
1464
Andreas Huber4c483422009-09-02 16:05:36 -07001465 CODEC_LOGV("Calling empty_buffer on buffer %p (length %d)",
Andreas Huberbe06d262009-08-14 14:37:10 -07001466 info->mBuffer, srcLength);
Andreas Huber4c483422009-09-02 16:05:36 -07001467 CODEC_LOGV("Calling empty_buffer with timestamp %lld us (%.2f secs)",
Andreas Huberbe06d262009-08-14 14:37:10 -07001468 timestamp, timestamp / 1E6);
1469 }
1470 }
1471
Andreas Huberbe06d262009-08-14 14:37:10 -07001472 if (srcBuffer != NULL) {
1473 srcBuffer->release();
1474 srcBuffer = NULL;
1475 }
Andreas Huber3f427072009-10-08 11:02:27 -07001476
1477 err = mOMX->empty_buffer(
1478 mNode, info->mBuffer, 0, srcLength,
1479 flags, timestamp);
1480
1481 if (err != OK) {
1482 setState(ERROR);
1483 return;
1484 }
1485
1486 info->mOwnedByComponent = true;
Andreas Huberbe06d262009-08-14 14:37:10 -07001487}
1488
1489void OMXCodec::fillOutputBuffer(BufferInfo *info) {
1490 CHECK_EQ(info->mOwnedByComponent, false);
1491
Andreas Huber404cc412009-08-25 14:26:05 -07001492 if (mNoMoreOutputData) {
Andreas Huber4c483422009-09-02 16:05:36 -07001493 CODEC_LOGV("There is no more output data available, not "
Andreas Huber404cc412009-08-25 14:26:05 -07001494 "calling fillOutputBuffer");
1495 return;
1496 }
1497
Andreas Huber4c483422009-09-02 16:05:36 -07001498 CODEC_LOGV("Calling fill_buffer on buffer %p", info->mBuffer);
Andreas Huber3f427072009-10-08 11:02:27 -07001499 status_t err = mOMX->fill_buffer(mNode, info->mBuffer);
1500 CHECK_EQ(err, OK);
Andreas Huberbe06d262009-08-14 14:37:10 -07001501
1502 info->mOwnedByComponent = true;
1503}
1504
1505void OMXCodec::drainInputBuffer(IOMX::buffer_id buffer) {
1506 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
1507 for (size_t i = 0; i < buffers->size(); ++i) {
1508 if ((*buffers)[i].mBuffer == buffer) {
1509 drainInputBuffer(&buffers->editItemAt(i));
1510 return;
1511 }
1512 }
1513
1514 CHECK(!"should not be here.");
1515}
1516
1517void OMXCodec::fillOutputBuffer(IOMX::buffer_id buffer) {
1518 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
1519 for (size_t i = 0; i < buffers->size(); ++i) {
1520 if ((*buffers)[i].mBuffer == buffer) {
1521 fillOutputBuffer(&buffers->editItemAt(i));
1522 return;
1523 }
1524 }
1525
1526 CHECK(!"should not be here.");
1527}
1528
1529void OMXCodec::setState(State newState) {
1530 mState = newState;
1531 mAsyncCompletion.signal();
1532
1533 // This may cause some spurious wakeups but is necessary to
1534 // unblock the reader if we enter ERROR state.
1535 mBufferFilled.signal();
1536}
1537
Andreas Huberda050cf22009-09-02 14:01:43 -07001538void OMXCodec::setRawAudioFormat(
1539 OMX_U32 portIndex, int32_t sampleRate, int32_t numChannels) {
1540 OMX_AUDIO_PARAM_PCMMODETYPE pcmParams;
Andreas Huber4c483422009-09-02 16:05:36 -07001541 InitOMXParams(&pcmParams);
Andreas Huberda050cf22009-09-02 14:01:43 -07001542 pcmParams.nPortIndex = portIndex;
1543
1544 status_t err = mOMX->get_parameter(
1545 mNode, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams));
1546
1547 CHECK_EQ(err, OK);
1548
1549 pcmParams.nChannels = numChannels;
1550 pcmParams.eNumData = OMX_NumericalDataSigned;
1551 pcmParams.bInterleaved = OMX_TRUE;
1552 pcmParams.nBitPerSample = 16;
1553 pcmParams.nSamplingRate = sampleRate;
1554 pcmParams.ePCMMode = OMX_AUDIO_PCMModeLinear;
1555
1556 if (numChannels == 1) {
1557 pcmParams.eChannelMapping[0] = OMX_AUDIO_ChannelCF;
1558 } else {
1559 CHECK_EQ(numChannels, 2);
1560
1561 pcmParams.eChannelMapping[0] = OMX_AUDIO_ChannelLF;
1562 pcmParams.eChannelMapping[1] = OMX_AUDIO_ChannelRF;
1563 }
1564
1565 err = mOMX->set_parameter(
1566 mNode, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams));
1567
1568 CHECK_EQ(err, OK);
1569}
1570
Andreas Huberbe06d262009-08-14 14:37:10 -07001571void OMXCodec::setAMRFormat() {
1572 if (!mIsEncoder) {
1573 OMX_AUDIO_PARAM_AMRTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -07001574 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -07001575 def.nPortIndex = kPortIndexInput;
1576
1577 status_t err =
1578 mOMX->get_parameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
1579
1580 CHECK_EQ(err, OK);
1581
1582 def.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
1583 def.eAMRBandMode = OMX_AUDIO_AMRBandModeNB0;
1584
1585 err = mOMX->set_parameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
1586 CHECK_EQ(err, OK);
1587 }
1588
1589 ////////////////////////
1590
1591 if (mIsEncoder) {
1592 sp<MetaData> format = mSource->getFormat();
1593 int32_t sampleRate;
1594 int32_t numChannels;
1595 CHECK(format->findInt32(kKeySampleRate, &sampleRate));
1596 CHECK(format->findInt32(kKeyChannelCount, &numChannels));
1597
Andreas Huberda050cf22009-09-02 14:01:43 -07001598 setRawAudioFormat(kPortIndexInput, sampleRate, numChannels);
Andreas Huberbe06d262009-08-14 14:37:10 -07001599 }
1600}
1601
Andreas Huberee606e62009-09-08 10:19:21 -07001602void OMXCodec::setAMRWBFormat() {
1603 if (!mIsEncoder) {
1604 OMX_AUDIO_PARAM_AMRTYPE def;
1605 InitOMXParams(&def);
1606 def.nPortIndex = kPortIndexInput;
1607
1608 status_t err =
1609 mOMX->get_parameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
1610
1611 CHECK_EQ(err, OK);
1612
1613 def.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
1614 def.eAMRBandMode = OMX_AUDIO_AMRBandModeWB0;
1615
1616 err = mOMX->set_parameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
1617 CHECK_EQ(err, OK);
1618 }
1619
1620 ////////////////////////
1621
1622 if (mIsEncoder) {
1623 sp<MetaData> format = mSource->getFormat();
1624 int32_t sampleRate;
1625 int32_t numChannels;
1626 CHECK(format->findInt32(kKeySampleRate, &sampleRate));
1627 CHECK(format->findInt32(kKeyChannelCount, &numChannels));
1628
1629 setRawAudioFormat(kPortIndexInput, sampleRate, numChannels);
1630 }
1631}
1632
Andreas Huber43ad6eaf2009-09-01 16:02:43 -07001633void OMXCodec::setAACFormat(int32_t numChannels, int32_t sampleRate) {
Andreas Huberda050cf22009-09-02 14:01:43 -07001634 if (mIsEncoder) {
1635 setRawAudioFormat(kPortIndexInput, sampleRate, numChannels);
1636 } else {
1637 OMX_AUDIO_PARAM_AACPROFILETYPE profile;
Andreas Huber4c483422009-09-02 16:05:36 -07001638 InitOMXParams(&profile);
Andreas Huberda050cf22009-09-02 14:01:43 -07001639 profile.nPortIndex = kPortIndexInput;
Andreas Huberbe06d262009-08-14 14:37:10 -07001640
Andreas Huberda050cf22009-09-02 14:01:43 -07001641 status_t err = mOMX->get_parameter(
1642 mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile));
1643 CHECK_EQ(err, OK);
Andreas Huberbe06d262009-08-14 14:37:10 -07001644
Andreas Huberda050cf22009-09-02 14:01:43 -07001645 profile.nChannels = numChannels;
1646 profile.nSampleRate = sampleRate;
1647 profile.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4ADTS;
Andreas Huberbe06d262009-08-14 14:37:10 -07001648
Andreas Huberda050cf22009-09-02 14:01:43 -07001649 err = mOMX->set_parameter(
1650 mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile));
1651 CHECK_EQ(err, OK);
1652 }
Andreas Huberbe06d262009-08-14 14:37:10 -07001653}
1654
1655void OMXCodec::setImageOutputFormat(
1656 OMX_COLOR_FORMATTYPE format, OMX_U32 width, OMX_U32 height) {
Andreas Huber4c483422009-09-02 16:05:36 -07001657 CODEC_LOGV("setImageOutputFormat(%ld, %ld)", width, height);
Andreas Huberbe06d262009-08-14 14:37:10 -07001658
1659#if 0
1660 OMX_INDEXTYPE index;
1661 status_t err = mOMX->get_extension_index(
1662 mNode, "OMX.TI.JPEG.decode.Config.OutputColorFormat", &index);
1663 CHECK_EQ(err, OK);
1664
1665 err = mOMX->set_config(mNode, index, &format, sizeof(format));
1666 CHECK_EQ(err, OK);
1667#endif
1668
1669 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -07001670 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -07001671 def.nPortIndex = kPortIndexOutput;
1672
1673 status_t err = mOMX->get_parameter(
1674 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
1675 CHECK_EQ(err, OK);
1676
1677 CHECK_EQ(def.eDomain, OMX_PortDomainImage);
1678
1679 OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
Andreas Huberebf66ea2009-08-19 13:32:58 -07001680
Andreas Huberbe06d262009-08-14 14:37:10 -07001681 CHECK_EQ(imageDef->eCompressionFormat, OMX_IMAGE_CodingUnused);
1682 imageDef->eColorFormat = format;
1683 imageDef->nFrameWidth = width;
1684 imageDef->nFrameHeight = height;
1685
1686 switch (format) {
1687 case OMX_COLOR_FormatYUV420PackedPlanar:
1688 case OMX_COLOR_FormatYUV411Planar:
1689 {
1690 def.nBufferSize = (width * height * 3) / 2;
1691 break;
1692 }
1693
1694 case OMX_COLOR_FormatCbYCrY:
1695 {
1696 def.nBufferSize = width * height * 2;
1697 break;
1698 }
1699
1700 case OMX_COLOR_Format32bitARGB8888:
1701 {
1702 def.nBufferSize = width * height * 4;
1703 break;
1704 }
1705
Andreas Huber201511c2009-09-08 14:01:44 -07001706 case OMX_COLOR_Format16bitARGB4444:
1707 case OMX_COLOR_Format16bitARGB1555:
1708 case OMX_COLOR_Format16bitRGB565:
1709 case OMX_COLOR_Format16bitBGR565:
1710 {
1711 def.nBufferSize = width * height * 2;
1712 break;
1713 }
1714
Andreas Huberbe06d262009-08-14 14:37:10 -07001715 default:
1716 CHECK(!"Should not be here. Unknown color format.");
1717 break;
1718 }
1719
Andreas Huber5c0a9132009-08-20 11:16:40 -07001720 def.nBufferCountActual = def.nBufferCountMin;
1721
Andreas Huberbe06d262009-08-14 14:37:10 -07001722 err = mOMX->set_parameter(
1723 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
1724 CHECK_EQ(err, OK);
Andreas Huber5c0a9132009-08-20 11:16:40 -07001725}
Andreas Huberbe06d262009-08-14 14:37:10 -07001726
Andreas Huber5c0a9132009-08-20 11:16:40 -07001727void OMXCodec::setJPEGInputFormat(
1728 OMX_U32 width, OMX_U32 height, OMX_U32 compressedSize) {
1729 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -07001730 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -07001731 def.nPortIndex = kPortIndexInput;
1732
Andreas Huber5c0a9132009-08-20 11:16:40 -07001733 status_t err = mOMX->get_parameter(
Andreas Huberbe06d262009-08-14 14:37:10 -07001734 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
1735 CHECK_EQ(err, OK);
1736
Andreas Huber5c0a9132009-08-20 11:16:40 -07001737 CHECK_EQ(def.eDomain, OMX_PortDomainImage);
1738 OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
1739
Andreas Huberbe06d262009-08-14 14:37:10 -07001740 CHECK_EQ(imageDef->eCompressionFormat, OMX_IMAGE_CodingJPEG);
1741 imageDef->nFrameWidth = width;
1742 imageDef->nFrameHeight = height;
1743
Andreas Huber5c0a9132009-08-20 11:16:40 -07001744 def.nBufferSize = compressedSize;
Andreas Huberbe06d262009-08-14 14:37:10 -07001745 def.nBufferCountActual = def.nBufferCountMin;
1746
1747 err = mOMX->set_parameter(
1748 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
1749 CHECK_EQ(err, OK);
1750}
1751
1752void OMXCodec::addCodecSpecificData(const void *data, size_t size) {
1753 CodecSpecificData *specific =
1754 (CodecSpecificData *)malloc(sizeof(CodecSpecificData) + size - 1);
1755
1756 specific->mSize = size;
1757 memcpy(specific->mData, data, size);
1758
1759 mCodecSpecificData.push(specific);
1760}
1761
1762void OMXCodec::clearCodecSpecificData() {
1763 for (size_t i = 0; i < mCodecSpecificData.size(); ++i) {
1764 free(mCodecSpecificData.editItemAt(i));
1765 }
1766 mCodecSpecificData.clear();
1767 mCodecSpecificDataIndex = 0;
1768}
1769
1770status_t OMXCodec::start(MetaData *) {
Andreas Huber42978e52009-08-27 10:08:39 -07001771 Mutex::Autolock autoLock(mLock);
1772
Andreas Huberbe06d262009-08-14 14:37:10 -07001773 if (mState != LOADED) {
1774 return UNKNOWN_ERROR;
1775 }
Andreas Huberebf66ea2009-08-19 13:32:58 -07001776
Andreas Huberbe06d262009-08-14 14:37:10 -07001777 sp<MetaData> params = new MetaData;
Andreas Huber4f5e6022009-08-19 09:29:34 -07001778 if (mQuirks & kWantsNALFragments) {
1779 params->setInt32(kKeyWantsNALFragments, true);
Andreas Huberbe06d262009-08-14 14:37:10 -07001780 }
1781 status_t err = mSource->start(params.get());
1782
1783 if (err != OK) {
1784 return err;
1785 }
1786
1787 mCodecSpecificDataIndex = 0;
Andreas Huber42978e52009-08-27 10:08:39 -07001788 mInitialBufferSubmit = true;
Andreas Huberbe06d262009-08-14 14:37:10 -07001789 mSignalledEOS = false;
1790 mNoMoreOutputData = false;
1791 mSeekTimeUs = -1;
1792 mFilledBuffers.clear();
1793
1794 return init();
1795}
1796
1797status_t OMXCodec::stop() {
Andreas Huber4c483422009-09-02 16:05:36 -07001798 CODEC_LOGV("stop");
Andreas Huberbe06d262009-08-14 14:37:10 -07001799
1800 Mutex::Autolock autoLock(mLock);
1801
1802 while (isIntermediateState(mState)) {
1803 mAsyncCompletion.wait(mLock);
1804 }
1805
1806 switch (mState) {
1807 case LOADED:
1808 case ERROR:
1809 break;
1810
1811 case EXECUTING:
1812 {
1813 setState(EXECUTING_TO_IDLE);
1814
Andreas Huber127fcdc2009-08-26 16:27:02 -07001815 if (mQuirks & kRequiresFlushBeforeShutdown) {
Andreas Huber4c483422009-09-02 16:05:36 -07001816 CODEC_LOGV("This component requires a flush before transitioning "
Andreas Huber127fcdc2009-08-26 16:27:02 -07001817 "from EXECUTING to IDLE...");
Andreas Huberbe06d262009-08-14 14:37:10 -07001818
Andreas Huber127fcdc2009-08-26 16:27:02 -07001819 bool emulateInputFlushCompletion =
1820 !flushPortAsync(kPortIndexInput);
1821
1822 bool emulateOutputFlushCompletion =
1823 !flushPortAsync(kPortIndexOutput);
1824
1825 if (emulateInputFlushCompletion) {
1826 onCmdComplete(OMX_CommandFlush, kPortIndexInput);
1827 }
1828
1829 if (emulateOutputFlushCompletion) {
1830 onCmdComplete(OMX_CommandFlush, kPortIndexOutput);
1831 }
1832 } else {
1833 mPortStatus[kPortIndexInput] = SHUTTING_DOWN;
1834 mPortStatus[kPortIndexOutput] = SHUTTING_DOWN;
1835
1836 status_t err =
1837 mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
1838 CHECK_EQ(err, OK);
1839 }
Andreas Huberbe06d262009-08-14 14:37:10 -07001840
1841 while (mState != LOADED && mState != ERROR) {
1842 mAsyncCompletion.wait(mLock);
1843 }
1844
1845 break;
1846 }
1847
1848 default:
1849 {
1850 CHECK(!"should not be here.");
1851 break;
1852 }
1853 }
1854
1855 mSource->stop();
1856
1857 return OK;
1858}
1859
1860sp<MetaData> OMXCodec::getFormat() {
1861 return mOutputFormat;
1862}
1863
1864status_t OMXCodec::read(
1865 MediaBuffer **buffer, const ReadOptions *options) {
1866 *buffer = NULL;
1867
1868 Mutex::Autolock autoLock(mLock);
1869
Andreas Huberd06e5b82009-08-28 13:18:14 -07001870 if (mState != EXECUTING && mState != RECONFIGURING) {
1871 return UNKNOWN_ERROR;
1872 }
1873
Andreas Huber42978e52009-08-27 10:08:39 -07001874 if (mInitialBufferSubmit) {
1875 mInitialBufferSubmit = false;
1876
1877 drainInputBuffers();
Andreas Huber42978e52009-08-27 10:08:39 -07001878
Andreas Huberd06e5b82009-08-28 13:18:14 -07001879 if (mState == EXECUTING) {
1880 // Otherwise mState == RECONFIGURING and this code will trigger
1881 // after the output port is reenabled.
1882 fillOutputBuffers();
1883 }
Andreas Huberbe06d262009-08-14 14:37:10 -07001884 }
1885
1886 int64_t seekTimeUs;
1887 if (options && options->getSeekTo(&seekTimeUs)) {
Andreas Huber4c483422009-09-02 16:05:36 -07001888 CODEC_LOGV("seeking to %lld us (%.2f secs)", seekTimeUs, seekTimeUs / 1E6);
Andreas Huberbe06d262009-08-14 14:37:10 -07001889
1890 mSignalledEOS = false;
1891 mNoMoreOutputData = false;
1892
1893 CHECK(seekTimeUs >= 0);
1894 mSeekTimeUs = seekTimeUs;
1895
1896 mFilledBuffers.clear();
1897
1898 CHECK_EQ(mState, EXECUTING);
1899
Andreas Huber404cc412009-08-25 14:26:05 -07001900 bool emulateInputFlushCompletion = !flushPortAsync(kPortIndexInput);
1901 bool emulateOutputFlushCompletion = !flushPortAsync(kPortIndexOutput);
1902
1903 if (emulateInputFlushCompletion) {
1904 onCmdComplete(OMX_CommandFlush, kPortIndexInput);
1905 }
1906
1907 if (emulateOutputFlushCompletion) {
1908 onCmdComplete(OMX_CommandFlush, kPortIndexOutput);
1909 }
Andreas Huberbe06d262009-08-14 14:37:10 -07001910 }
1911
1912 while (mState != ERROR && !mNoMoreOutputData && mFilledBuffers.empty()) {
1913 mBufferFilled.wait(mLock);
1914 }
1915
1916 if (mState == ERROR) {
1917 return UNKNOWN_ERROR;
1918 }
1919
1920 if (mFilledBuffers.empty()) {
1921 return ERROR_END_OF_STREAM;
1922 }
1923
1924 size_t index = *mFilledBuffers.begin();
1925 mFilledBuffers.erase(mFilledBuffers.begin());
1926
1927 BufferInfo *info = &mPortBuffers[kPortIndexOutput].editItemAt(index);
1928 info->mMediaBuffer->add_ref();
1929 *buffer = info->mMediaBuffer;
1930
1931 return OK;
1932}
1933
1934void OMXCodec::signalBufferReturned(MediaBuffer *buffer) {
1935 Mutex::Autolock autoLock(mLock);
1936
1937 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
1938 for (size_t i = 0; i < buffers->size(); ++i) {
1939 BufferInfo *info = &buffers->editItemAt(i);
1940
1941 if (info->mMediaBuffer == buffer) {
1942 CHECK_EQ(mPortStatus[kPortIndexOutput], ENABLED);
1943 fillOutputBuffer(info);
1944 return;
1945 }
1946 }
1947
1948 CHECK(!"should not be here.");
1949}
1950
1951static const char *imageCompressionFormatString(OMX_IMAGE_CODINGTYPE type) {
1952 static const char *kNames[] = {
1953 "OMX_IMAGE_CodingUnused",
1954 "OMX_IMAGE_CodingAutoDetect",
1955 "OMX_IMAGE_CodingJPEG",
1956 "OMX_IMAGE_CodingJPEG2K",
1957 "OMX_IMAGE_CodingEXIF",
1958 "OMX_IMAGE_CodingTIFF",
1959 "OMX_IMAGE_CodingGIF",
1960 "OMX_IMAGE_CodingPNG",
1961 "OMX_IMAGE_CodingLZW",
1962 "OMX_IMAGE_CodingBMP",
1963 };
1964
1965 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
1966
1967 if (type < 0 || (size_t)type >= numNames) {
1968 return "UNKNOWN";
1969 } else {
1970 return kNames[type];
1971 }
1972}
1973
1974static const char *colorFormatString(OMX_COLOR_FORMATTYPE type) {
1975 static const char *kNames[] = {
1976 "OMX_COLOR_FormatUnused",
1977 "OMX_COLOR_FormatMonochrome",
1978 "OMX_COLOR_Format8bitRGB332",
1979 "OMX_COLOR_Format12bitRGB444",
1980 "OMX_COLOR_Format16bitARGB4444",
1981 "OMX_COLOR_Format16bitARGB1555",
1982 "OMX_COLOR_Format16bitRGB565",
1983 "OMX_COLOR_Format16bitBGR565",
1984 "OMX_COLOR_Format18bitRGB666",
1985 "OMX_COLOR_Format18bitARGB1665",
Andreas Huberebf66ea2009-08-19 13:32:58 -07001986 "OMX_COLOR_Format19bitARGB1666",
Andreas Huberbe06d262009-08-14 14:37:10 -07001987 "OMX_COLOR_Format24bitRGB888",
1988 "OMX_COLOR_Format24bitBGR888",
1989 "OMX_COLOR_Format24bitARGB1887",
1990 "OMX_COLOR_Format25bitARGB1888",
1991 "OMX_COLOR_Format32bitBGRA8888",
1992 "OMX_COLOR_Format32bitARGB8888",
1993 "OMX_COLOR_FormatYUV411Planar",
1994 "OMX_COLOR_FormatYUV411PackedPlanar",
1995 "OMX_COLOR_FormatYUV420Planar",
1996 "OMX_COLOR_FormatYUV420PackedPlanar",
1997 "OMX_COLOR_FormatYUV420SemiPlanar",
1998 "OMX_COLOR_FormatYUV422Planar",
1999 "OMX_COLOR_FormatYUV422PackedPlanar",
2000 "OMX_COLOR_FormatYUV422SemiPlanar",
2001 "OMX_COLOR_FormatYCbYCr",
2002 "OMX_COLOR_FormatYCrYCb",
2003 "OMX_COLOR_FormatCbYCrY",
2004 "OMX_COLOR_FormatCrYCbY",
2005 "OMX_COLOR_FormatYUV444Interleaved",
2006 "OMX_COLOR_FormatRawBayer8bit",
2007 "OMX_COLOR_FormatRawBayer10bit",
2008 "OMX_COLOR_FormatRawBayer8bitcompressed",
Andreas Huberebf66ea2009-08-19 13:32:58 -07002009 "OMX_COLOR_FormatL2",
2010 "OMX_COLOR_FormatL4",
2011 "OMX_COLOR_FormatL8",
2012 "OMX_COLOR_FormatL16",
2013 "OMX_COLOR_FormatL24",
Andreas Huberbe06d262009-08-14 14:37:10 -07002014 "OMX_COLOR_FormatL32",
2015 "OMX_COLOR_FormatYUV420PackedSemiPlanar",
2016 "OMX_COLOR_FormatYUV422PackedSemiPlanar",
2017 "OMX_COLOR_Format18BitBGR666",
2018 "OMX_COLOR_Format24BitARGB6666",
2019 "OMX_COLOR_Format24BitABGR6666",
2020 };
2021
2022 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
2023
Andreas Huberbe06d262009-08-14 14:37:10 -07002024 if (type == OMX_QCOM_COLOR_FormatYVU420SemiPlanar) {
2025 return "OMX_QCOM_COLOR_FormatYVU420SemiPlanar";
2026 } else if (type < 0 || (size_t)type >= numNames) {
2027 return "UNKNOWN";
2028 } else {
2029 return kNames[type];
2030 }
2031}
2032
2033static const char *videoCompressionFormatString(OMX_VIDEO_CODINGTYPE type) {
2034 static const char *kNames[] = {
2035 "OMX_VIDEO_CodingUnused",
2036 "OMX_VIDEO_CodingAutoDetect",
2037 "OMX_VIDEO_CodingMPEG2",
2038 "OMX_VIDEO_CodingH263",
2039 "OMX_VIDEO_CodingMPEG4",
2040 "OMX_VIDEO_CodingWMV",
2041 "OMX_VIDEO_CodingRV",
2042 "OMX_VIDEO_CodingAVC",
2043 "OMX_VIDEO_CodingMJPEG",
2044 };
2045
2046 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
2047
2048 if (type < 0 || (size_t)type >= numNames) {
2049 return "UNKNOWN";
2050 } else {
2051 return kNames[type];
2052 }
2053}
2054
2055static const char *audioCodingTypeString(OMX_AUDIO_CODINGTYPE type) {
2056 static const char *kNames[] = {
2057 "OMX_AUDIO_CodingUnused",
2058 "OMX_AUDIO_CodingAutoDetect",
2059 "OMX_AUDIO_CodingPCM",
2060 "OMX_AUDIO_CodingADPCM",
2061 "OMX_AUDIO_CodingAMR",
2062 "OMX_AUDIO_CodingGSMFR",
2063 "OMX_AUDIO_CodingGSMEFR",
2064 "OMX_AUDIO_CodingGSMHR",
2065 "OMX_AUDIO_CodingPDCFR",
2066 "OMX_AUDIO_CodingPDCEFR",
2067 "OMX_AUDIO_CodingPDCHR",
2068 "OMX_AUDIO_CodingTDMAFR",
2069 "OMX_AUDIO_CodingTDMAEFR",
2070 "OMX_AUDIO_CodingQCELP8",
2071 "OMX_AUDIO_CodingQCELP13",
2072 "OMX_AUDIO_CodingEVRC",
2073 "OMX_AUDIO_CodingSMV",
2074 "OMX_AUDIO_CodingG711",
2075 "OMX_AUDIO_CodingG723",
2076 "OMX_AUDIO_CodingG726",
2077 "OMX_AUDIO_CodingG729",
2078 "OMX_AUDIO_CodingAAC",
2079 "OMX_AUDIO_CodingMP3",
2080 "OMX_AUDIO_CodingSBC",
2081 "OMX_AUDIO_CodingVORBIS",
2082 "OMX_AUDIO_CodingWMA",
2083 "OMX_AUDIO_CodingRA",
2084 "OMX_AUDIO_CodingMIDI",
2085 };
2086
2087 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
2088
2089 if (type < 0 || (size_t)type >= numNames) {
2090 return "UNKNOWN";
2091 } else {
2092 return kNames[type];
2093 }
2094}
2095
2096static const char *audioPCMModeString(OMX_AUDIO_PCMMODETYPE type) {
2097 static const char *kNames[] = {
2098 "OMX_AUDIO_PCMModeLinear",
2099 "OMX_AUDIO_PCMModeALaw",
2100 "OMX_AUDIO_PCMModeMULaw",
2101 };
2102
2103 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
2104
2105 if (type < 0 || (size_t)type >= numNames) {
2106 return "UNKNOWN";
2107 } else {
2108 return kNames[type];
2109 }
2110}
2111
Andreas Huber7ae02c82009-09-09 16:29:47 -07002112static const char *amrBandModeString(OMX_AUDIO_AMRBANDMODETYPE type) {
2113 static const char *kNames[] = {
2114 "OMX_AUDIO_AMRBandModeUnused",
2115 "OMX_AUDIO_AMRBandModeNB0",
2116 "OMX_AUDIO_AMRBandModeNB1",
2117 "OMX_AUDIO_AMRBandModeNB2",
2118 "OMX_AUDIO_AMRBandModeNB3",
2119 "OMX_AUDIO_AMRBandModeNB4",
2120 "OMX_AUDIO_AMRBandModeNB5",
2121 "OMX_AUDIO_AMRBandModeNB6",
2122 "OMX_AUDIO_AMRBandModeNB7",
2123 "OMX_AUDIO_AMRBandModeWB0",
2124 "OMX_AUDIO_AMRBandModeWB1",
2125 "OMX_AUDIO_AMRBandModeWB2",
2126 "OMX_AUDIO_AMRBandModeWB3",
2127 "OMX_AUDIO_AMRBandModeWB4",
2128 "OMX_AUDIO_AMRBandModeWB5",
2129 "OMX_AUDIO_AMRBandModeWB6",
2130 "OMX_AUDIO_AMRBandModeWB7",
2131 "OMX_AUDIO_AMRBandModeWB8",
2132 };
2133
2134 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
2135
2136 if (type < 0 || (size_t)type >= numNames) {
2137 return "UNKNOWN";
2138 } else {
2139 return kNames[type];
2140 }
2141}
2142
2143static const char *amrFrameFormatString(OMX_AUDIO_AMRFRAMEFORMATTYPE type) {
2144 static const char *kNames[] = {
2145 "OMX_AUDIO_AMRFrameFormatConformance",
2146 "OMX_AUDIO_AMRFrameFormatIF1",
2147 "OMX_AUDIO_AMRFrameFormatIF2",
2148 "OMX_AUDIO_AMRFrameFormatFSF",
2149 "OMX_AUDIO_AMRFrameFormatRTPPayload",
2150 "OMX_AUDIO_AMRFrameFormatITU",
2151 };
2152
2153 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
2154
2155 if (type < 0 || (size_t)type >= numNames) {
2156 return "UNKNOWN";
2157 } else {
2158 return kNames[type];
2159 }
2160}
Andreas Huberbe06d262009-08-14 14:37:10 -07002161
2162void OMXCodec::dumpPortStatus(OMX_U32 portIndex) {
2163 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -07002164 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -07002165 def.nPortIndex = portIndex;
2166
2167 status_t err = mOMX->get_parameter(
2168 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
2169 CHECK_EQ(err, OK);
2170
2171 printf("%s Port = {\n", portIndex == kPortIndexInput ? "Input" : "Output");
2172
2173 CHECK((portIndex == kPortIndexInput && def.eDir == OMX_DirInput)
2174 || (portIndex == kPortIndexOutput && def.eDir == OMX_DirOutput));
2175
2176 printf(" nBufferCountActual = %ld\n", def.nBufferCountActual);
2177 printf(" nBufferCountMin = %ld\n", def.nBufferCountMin);
2178 printf(" nBufferSize = %ld\n", def.nBufferSize);
2179
2180 switch (def.eDomain) {
2181 case OMX_PortDomainImage:
2182 {
2183 const OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
2184
2185 printf("\n");
2186 printf(" // Image\n");
2187 printf(" nFrameWidth = %ld\n", imageDef->nFrameWidth);
2188 printf(" nFrameHeight = %ld\n", imageDef->nFrameHeight);
2189 printf(" nStride = %ld\n", imageDef->nStride);
2190
2191 printf(" eCompressionFormat = %s\n",
2192 imageCompressionFormatString(imageDef->eCompressionFormat));
2193
2194 printf(" eColorFormat = %s\n",
2195 colorFormatString(imageDef->eColorFormat));
2196
2197 break;
2198 }
2199
2200 case OMX_PortDomainVideo:
2201 {
2202 OMX_VIDEO_PORTDEFINITIONTYPE *videoDef = &def.format.video;
2203
2204 printf("\n");
2205 printf(" // Video\n");
2206 printf(" nFrameWidth = %ld\n", videoDef->nFrameWidth);
2207 printf(" nFrameHeight = %ld\n", videoDef->nFrameHeight);
2208 printf(" nStride = %ld\n", videoDef->nStride);
2209
2210 printf(" eCompressionFormat = %s\n",
2211 videoCompressionFormatString(videoDef->eCompressionFormat));
2212
2213 printf(" eColorFormat = %s\n",
2214 colorFormatString(videoDef->eColorFormat));
2215
2216 break;
2217 }
2218
2219 case OMX_PortDomainAudio:
2220 {
2221 OMX_AUDIO_PORTDEFINITIONTYPE *audioDef = &def.format.audio;
2222
2223 printf("\n");
2224 printf(" // Audio\n");
2225 printf(" eEncoding = %s\n",
2226 audioCodingTypeString(audioDef->eEncoding));
2227
2228 if (audioDef->eEncoding == OMX_AUDIO_CodingPCM) {
2229 OMX_AUDIO_PARAM_PCMMODETYPE params;
Andreas Huber4c483422009-09-02 16:05:36 -07002230 InitOMXParams(&params);
Andreas Huberbe06d262009-08-14 14:37:10 -07002231 params.nPortIndex = portIndex;
2232
2233 err = mOMX->get_parameter(
2234 mNode, OMX_IndexParamAudioPcm, &params, sizeof(params));
2235 CHECK_EQ(err, OK);
2236
2237 printf(" nSamplingRate = %ld\n", params.nSamplingRate);
2238 printf(" nChannels = %ld\n", params.nChannels);
2239 printf(" bInterleaved = %d\n", params.bInterleaved);
2240 printf(" nBitPerSample = %ld\n", params.nBitPerSample);
2241
2242 printf(" eNumData = %s\n",
2243 params.eNumData == OMX_NumericalDataSigned
2244 ? "signed" : "unsigned");
2245
2246 printf(" ePCMMode = %s\n", audioPCMModeString(params.ePCMMode));
Andreas Huber7ae02c82009-09-09 16:29:47 -07002247 } else if (audioDef->eEncoding == OMX_AUDIO_CodingAMR) {
2248 OMX_AUDIO_PARAM_AMRTYPE amr;
2249 InitOMXParams(&amr);
2250 amr.nPortIndex = portIndex;
2251
2252 err = mOMX->get_parameter(
2253 mNode, OMX_IndexParamAudioAmr, &amr, sizeof(amr));
2254 CHECK_EQ(err, OK);
2255
2256 printf(" nChannels = %ld\n", amr.nChannels);
2257 printf(" eAMRBandMode = %s\n",
2258 amrBandModeString(amr.eAMRBandMode));
2259 printf(" eAMRFrameFormat = %s\n",
2260 amrFrameFormatString(amr.eAMRFrameFormat));
Andreas Huberbe06d262009-08-14 14:37:10 -07002261 }
2262
2263 break;
2264 }
2265
2266 default:
2267 {
2268 printf(" // Unknown\n");
2269 break;
2270 }
2271 }
2272
2273 printf("}\n");
2274}
2275
2276void OMXCodec::initOutputFormat(const sp<MetaData> &inputFormat) {
2277 mOutputFormat = new MetaData;
2278 mOutputFormat->setCString(kKeyDecoderComponent, mComponentName);
2279
2280 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -07002281 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -07002282 def.nPortIndex = kPortIndexOutput;
2283
2284 status_t err = mOMX->get_parameter(
2285 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
2286 CHECK_EQ(err, OK);
2287
2288 switch (def.eDomain) {
2289 case OMX_PortDomainImage:
2290 {
2291 OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
2292 CHECK_EQ(imageDef->eCompressionFormat, OMX_IMAGE_CodingUnused);
2293
Andreas Hubere6c40962009-09-10 14:13:30 -07002294 mOutputFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
Andreas Huberbe06d262009-08-14 14:37:10 -07002295 mOutputFormat->setInt32(kKeyColorFormat, imageDef->eColorFormat);
2296 mOutputFormat->setInt32(kKeyWidth, imageDef->nFrameWidth);
2297 mOutputFormat->setInt32(kKeyHeight, imageDef->nFrameHeight);
2298 break;
2299 }
2300
2301 case OMX_PortDomainAudio:
2302 {
2303 OMX_AUDIO_PORTDEFINITIONTYPE *audio_def = &def.format.audio;
2304
Andreas Huberda050cf22009-09-02 14:01:43 -07002305 if (audio_def->eEncoding == OMX_AUDIO_CodingPCM) {
2306 OMX_AUDIO_PARAM_PCMMODETYPE params;
Andreas Huber4c483422009-09-02 16:05:36 -07002307 InitOMXParams(&params);
Andreas Huberda050cf22009-09-02 14:01:43 -07002308 params.nPortIndex = kPortIndexOutput;
Andreas Huberbe06d262009-08-14 14:37:10 -07002309
Andreas Huberda050cf22009-09-02 14:01:43 -07002310 err = mOMX->get_parameter(
2311 mNode, OMX_IndexParamAudioPcm, &params, sizeof(params));
2312 CHECK_EQ(err, OK);
Andreas Huberbe06d262009-08-14 14:37:10 -07002313
Andreas Huberda050cf22009-09-02 14:01:43 -07002314 CHECK_EQ(params.eNumData, OMX_NumericalDataSigned);
2315 CHECK_EQ(params.nBitPerSample, 16);
2316 CHECK_EQ(params.ePCMMode, OMX_AUDIO_PCMModeLinear);
Andreas Huberbe06d262009-08-14 14:37:10 -07002317
Andreas Huberda050cf22009-09-02 14:01:43 -07002318 int32_t numChannels, sampleRate;
2319 inputFormat->findInt32(kKeyChannelCount, &numChannels);
2320 inputFormat->findInt32(kKeySampleRate, &sampleRate);
Andreas Huberbe06d262009-08-14 14:37:10 -07002321
Andreas Huberda050cf22009-09-02 14:01:43 -07002322 if ((OMX_U32)numChannels != params.nChannels) {
2323 LOGW("Codec outputs a different number of channels than "
2324 "the input stream contains.");
2325 }
Andreas Huberbe06d262009-08-14 14:37:10 -07002326
Andreas Hubere6c40962009-09-10 14:13:30 -07002327 mOutputFormat->setCString(
2328 kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
Andreas Huberda050cf22009-09-02 14:01:43 -07002329
2330 // Use the codec-advertised number of channels, as some
2331 // codecs appear to output stereo even if the input data is
2332 // mono.
2333 mOutputFormat->setInt32(kKeyChannelCount, params.nChannels);
2334
2335 // The codec-reported sampleRate is not reliable...
2336 mOutputFormat->setInt32(kKeySampleRate, sampleRate);
2337 } else if (audio_def->eEncoding == OMX_AUDIO_CodingAMR) {
Andreas Huber7ae02c82009-09-09 16:29:47 -07002338 OMX_AUDIO_PARAM_AMRTYPE amr;
2339 InitOMXParams(&amr);
2340 amr.nPortIndex = kPortIndexOutput;
2341
2342 err = mOMX->get_parameter(
2343 mNode, OMX_IndexParamAudioAmr, &amr, sizeof(amr));
2344 CHECK_EQ(err, OK);
2345
2346 CHECK_EQ(amr.nChannels, 1);
2347 mOutputFormat->setInt32(kKeyChannelCount, 1);
2348
2349 if (amr.eAMRBandMode >= OMX_AUDIO_AMRBandModeNB0
2350 && amr.eAMRBandMode <= OMX_AUDIO_AMRBandModeNB7) {
Andreas Hubere6c40962009-09-10 14:13:30 -07002351 mOutputFormat->setCString(
2352 kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AMR_NB);
Andreas Huber7ae02c82009-09-09 16:29:47 -07002353 mOutputFormat->setInt32(kKeySampleRate, 8000);
2354 } else if (amr.eAMRBandMode >= OMX_AUDIO_AMRBandModeWB0
2355 && amr.eAMRBandMode <= OMX_AUDIO_AMRBandModeWB8) {
Andreas Hubere6c40962009-09-10 14:13:30 -07002356 mOutputFormat->setCString(
2357 kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AMR_WB);
Andreas Huber7ae02c82009-09-09 16:29:47 -07002358 mOutputFormat->setInt32(kKeySampleRate, 16000);
2359 } else {
2360 CHECK(!"Unknown AMR band mode.");
2361 }
Andreas Huberda050cf22009-09-02 14:01:43 -07002362 } else if (audio_def->eEncoding == OMX_AUDIO_CodingAAC) {
Andreas Hubere6c40962009-09-10 14:13:30 -07002363 mOutputFormat->setCString(
2364 kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
Andreas Huberda050cf22009-09-02 14:01:43 -07002365 } else {
2366 CHECK(!"Should not be here. Unknown audio encoding.");
Andreas Huber43ad6eaf2009-09-01 16:02:43 -07002367 }
Andreas Huberbe06d262009-08-14 14:37:10 -07002368 break;
2369 }
2370
2371 case OMX_PortDomainVideo:
2372 {
2373 OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
2374
2375 if (video_def->eCompressionFormat == OMX_VIDEO_CodingUnused) {
Andreas Hubere6c40962009-09-10 14:13:30 -07002376 mOutputFormat->setCString(
2377 kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
Andreas Huberbe06d262009-08-14 14:37:10 -07002378 } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingMPEG4) {
Andreas Hubere6c40962009-09-10 14:13:30 -07002379 mOutputFormat->setCString(
2380 kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
Andreas Huberbe06d262009-08-14 14:37:10 -07002381 } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingH263) {
Andreas Hubere6c40962009-09-10 14:13:30 -07002382 mOutputFormat->setCString(
2383 kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263);
Andreas Huberbe06d262009-08-14 14:37:10 -07002384 } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingAVC) {
Andreas Hubere6c40962009-09-10 14:13:30 -07002385 mOutputFormat->setCString(
2386 kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
Andreas Huberbe06d262009-08-14 14:37:10 -07002387 } else {
2388 CHECK(!"Unknown compression format.");
2389 }
2390
2391 if (!strcmp(mComponentName, "OMX.PV.avcdec")) {
2392 // This component appears to be lying to me.
2393 mOutputFormat->setInt32(
2394 kKeyWidth, (video_def->nFrameWidth + 15) & -16);
2395 mOutputFormat->setInt32(
2396 kKeyHeight, (video_def->nFrameHeight + 15) & -16);
2397 } else {
2398 mOutputFormat->setInt32(kKeyWidth, video_def->nFrameWidth);
2399 mOutputFormat->setInt32(kKeyHeight, video_def->nFrameHeight);
2400 }
2401
2402 mOutputFormat->setInt32(kKeyColorFormat, video_def->eColorFormat);
2403 break;
2404 }
2405
2406 default:
2407 {
2408 CHECK(!"should not be here, neither audio nor video.");
2409 break;
2410 }
2411 }
2412}
2413
Andreas Hubere6c40962009-09-10 14:13:30 -07002414////////////////////////////////////////////////////////////////////////////////
2415
2416status_t QueryCodecs(
2417 const sp<IOMX> &omx,
2418 const char *mime, bool queryDecoders,
2419 Vector<CodecCapabilities> *results) {
2420 results->clear();
2421
2422 for (int index = 0;; ++index) {
2423 const char *componentName;
2424
2425 if (!queryDecoders) {
2426 componentName = GetCodec(
2427 kEncoderInfo, sizeof(kEncoderInfo) / sizeof(kEncoderInfo[0]),
2428 mime, index);
2429 } else {
2430 componentName = GetCodec(
2431 kDecoderInfo, sizeof(kDecoderInfo) / sizeof(kDecoderInfo[0]),
2432 mime, index);
2433 }
2434
2435 if (!componentName) {
2436 return OK;
2437 }
2438
2439 IOMX::node_id node;
2440 status_t err = omx->allocate_node(componentName, &node);
2441
2442 if (err != OK) {
2443 continue;
2444 }
2445
2446 OMXCodec::setComponentRole(omx, node, queryDecoders, mime);
2447
2448 results->push();
2449 CodecCapabilities *caps = &results->editItemAt(results->size() - 1);
2450 caps->mComponentName = componentName;
2451
2452 OMX_VIDEO_PARAM_PROFILELEVELTYPE param;
2453 InitOMXParams(&param);
2454
2455 param.nPortIndex = queryDecoders ? 0 : 1;
2456
2457 for (param.nProfileIndex = 0;; ++param.nProfileIndex) {
2458 err = omx->get_parameter(
2459 node, OMX_IndexParamVideoProfileLevelQuerySupported,
2460 &param, sizeof(param));
2461
2462 if (err != OK) {
2463 break;
2464 }
2465
2466 CodecProfileLevel profileLevel;
2467 profileLevel.mProfile = param.eProfile;
2468 profileLevel.mLevel = param.eLevel;
2469
2470 caps->mProfileLevels.push(profileLevel);
2471 }
2472
2473 CHECK_EQ(omx->free_node(node), OK);
2474 }
2475}
2476
Andreas Huberbe06d262009-08-14 14:37:10 -07002477} // namespace android