blob: f8c0bda807990476684207628300fafc6d9b7ca2 [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
Andreas Huberbd7b43b2009-10-13 10:22:55 -070021#include "include/ESDS.h"
22
Andreas Huberbe06d262009-08-14 14:37:10 -070023#include <binder/IServiceManager.h>
24#include <binder/MemoryDealer.h>
25#include <binder/ProcessState.h>
26#include <media/IMediaPlayerService.h>
Andreas Huberbe06d262009-08-14 14:37:10 -070027#include <media/stagefright/MediaBuffer.h>
28#include <media/stagefright/MediaBufferGroup.h>
29#include <media/stagefright/MediaDebug.h>
Andreas Hubere6c40962009-09-10 14:13:30 -070030#include <media/stagefright/MediaDefs.h>
Andreas Huberbe06d262009-08-14 14:37:10 -070031#include <media/stagefright/MediaExtractor.h>
32#include <media/stagefright/MetaData.h>
33#include <media/stagefright/MmapSource.h>
34#include <media/stagefright/OMXCodec.h>
Andreas Huberebf66ea2009-08-19 13:32:58 -070035#include <media/stagefright/Utils.h>
Andreas Huberbe06d262009-08-14 14:37:10 -070036#include <utils/Vector.h>
37
38#include <OMX_Audio.h>
39#include <OMX_Component.h>
40
41namespace android {
42
Andreas Huber8b432b12009-10-07 13:36:52 -070043static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
44
Andreas Huberbe06d262009-08-14 14:37:10 -070045struct CodecInfo {
46 const char *mime;
47 const char *codec;
48};
49
50static const CodecInfo kDecoderInfo[] = {
Andreas Hubere6c40962009-09-10 14:13:30 -070051 { MEDIA_MIMETYPE_IMAGE_JPEG, "OMX.TI.JPEG.decode" },
52 { MEDIA_MIMETYPE_AUDIO_MPEG, "OMX.TI.MP3.decode" },
53 { MEDIA_MIMETYPE_AUDIO_MPEG, "OMX.PV.mp3dec" },
54 { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.TI.AMR.decode" },
55 { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.PV.amrdec" },
56 { MEDIA_MIMETYPE_AUDIO_AMR_WB, "OMX.TI.WBAMR.decode" },
57 { MEDIA_MIMETYPE_AUDIO_AMR_WB, "OMX.PV.amrdec" },
58 { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.TI.AAC.decode" },
59 { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.PV.aacdec" },
60 { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.qcom.video.decoder.mpeg4" },
61 { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.TI.Video.Decoder" },
62 { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.PV.mpeg4dec" },
63 { MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.video.decoder.h263" },
64 { MEDIA_MIMETYPE_VIDEO_H263, "OMX.TI.Video.Decoder" },
65 { MEDIA_MIMETYPE_VIDEO_H263, "OMX.PV.h263dec" },
66 { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.qcom.video.decoder.avc" },
67 { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.TI.Video.Decoder" },
68 { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.PV.avcdec" },
Andreas Huberbe06d262009-08-14 14:37:10 -070069};
70
71static const CodecInfo kEncoderInfo[] = {
Andreas Hubere6c40962009-09-10 14:13:30 -070072 { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.TI.AMR.encode" },
73 { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.PV.amrencnb" },
74 { MEDIA_MIMETYPE_AUDIO_AMR_WB, "OMX.TI.WBAMR.encode" },
75 { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.TI.AAC.encode" },
76 { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.PV.aacenc" },
77 { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.qcom.video.encoder.mpeg4" },
78 { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.TI.Video.encoder" },
79 { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.PV.mpeg4enc" },
80 { MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.video.encoder.h263" },
81 { MEDIA_MIMETYPE_VIDEO_H263, "OMX.TI.Video.encoder" },
82 { MEDIA_MIMETYPE_VIDEO_H263, "OMX.PV.h263enc" },
83 { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.TI.Video.encoder" },
84 { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.PV.avcenc" },
Andreas Huberbe06d262009-08-14 14:37:10 -070085};
86
Andreas Hubere0873732009-09-10 09:57:53 -070087#define CODEC_LOGI(x, ...) LOGI("[%s] "x, mComponentName, ##__VA_ARGS__)
Andreas Huber4c483422009-09-02 16:05:36 -070088#define CODEC_LOGV(x, ...) LOGV("[%s] "x, mComponentName, ##__VA_ARGS__)
89
Andreas Huberbe06d262009-08-14 14:37:10 -070090struct OMXCodecObserver : public BnOMXObserver {
Andreas Huber784202e2009-10-15 13:46:54 -070091 OMXCodecObserver() {
92 }
93
94 void setCodec(const sp<OMXCodec> &target) {
95 mTarget = target;
Andreas Huberbe06d262009-08-14 14:37:10 -070096 }
97
98 // from IOMXObserver
Andreas Huber784202e2009-10-15 13:46:54 -070099 virtual void onMessage(const omx_message &msg) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700100 sp<OMXCodec> codec = mTarget.promote();
101
102 if (codec.get() != NULL) {
103 codec->on_message(msg);
104 }
105 }
106
107protected:
108 virtual ~OMXCodecObserver() {}
109
110private:
111 wp<OMXCodec> mTarget;
112
113 OMXCodecObserver(const OMXCodecObserver &);
114 OMXCodecObserver &operator=(const OMXCodecObserver &);
115};
116
117static const char *GetCodec(const CodecInfo *info, size_t numInfos,
118 const char *mime, int index) {
119 CHECK(index >= 0);
120 for(size_t i = 0; i < numInfos; ++i) {
121 if (!strcasecmp(mime, info[i].mime)) {
122 if (index == 0) {
123 return info[i].codec;
124 }
125
126 --index;
127 }
128 }
129
130 return NULL;
131}
132
Andreas Huberebf66ea2009-08-19 13:32:58 -0700133enum {
134 kAVCProfileBaseline = 0x42,
135 kAVCProfileMain = 0x4d,
136 kAVCProfileExtended = 0x58,
137 kAVCProfileHigh = 0x64,
138 kAVCProfileHigh10 = 0x6e,
139 kAVCProfileHigh422 = 0x7a,
140 kAVCProfileHigh444 = 0xf4,
141 kAVCProfileCAVLC444Intra = 0x2c
142};
143
144static const char *AVCProfileToString(uint8_t profile) {
145 switch (profile) {
146 case kAVCProfileBaseline:
147 return "Baseline";
148 case kAVCProfileMain:
149 return "Main";
150 case kAVCProfileExtended:
151 return "Extended";
152 case kAVCProfileHigh:
153 return "High";
154 case kAVCProfileHigh10:
155 return "High 10";
156 case kAVCProfileHigh422:
157 return "High 422";
158 case kAVCProfileHigh444:
159 return "High 444";
160 case kAVCProfileCAVLC444Intra:
161 return "CAVLC 444 Intra";
162 default: return "Unknown";
163 }
164}
165
Andreas Huber4c483422009-09-02 16:05:36 -0700166template<class T>
167static void InitOMXParams(T *params) {
168 params->nSize = sizeof(T);
169 params->nVersion.s.nVersionMajor = 1;
170 params->nVersion.s.nVersionMinor = 0;
171 params->nVersion.s.nRevision = 0;
172 params->nVersion.s.nStep = 0;
173}
174
Andreas Huberbe06d262009-08-14 14:37:10 -0700175// static
176sp<OMXCodec> OMXCodec::Create(
177 const sp<IOMX> &omx,
178 const sp<MetaData> &meta, bool createEncoder,
Andreas Hubere6c40962009-09-10 14:13:30 -0700179 const sp<MediaSource> &source,
180 const char *matchComponentName) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700181 const char *mime;
182 bool success = meta->findCString(kKeyMIMEType, &mime);
183 CHECK(success);
184
185 const char *componentName = NULL;
Andreas Huber784202e2009-10-15 13:46:54 -0700186 sp<OMXCodecObserver> observer = new OMXCodecObserver;
Andreas Huberbe06d262009-08-14 14:37:10 -0700187 IOMX::node_id node = 0;
188 for (int index = 0;; ++index) {
189 if (createEncoder) {
190 componentName = GetCodec(
191 kEncoderInfo, sizeof(kEncoderInfo) / sizeof(kEncoderInfo[0]),
192 mime, index);
193 } else {
194 componentName = GetCodec(
195 kDecoderInfo, sizeof(kDecoderInfo) / sizeof(kDecoderInfo[0]),
196 mime, index);
197 }
198
199 if (!componentName) {
200 return NULL;
201 }
202
Andreas Hubere6c40962009-09-10 14:13:30 -0700203 // If a specific codec is requested, skip the non-matching ones.
204 if (matchComponentName && strcmp(componentName, matchComponentName)) {
205 continue;
206 }
207
Andreas Huberbe06d262009-08-14 14:37:10 -0700208 LOGV("Attempting to allocate OMX node '%s'", componentName);
209
Andreas Huber784202e2009-10-15 13:46:54 -0700210 status_t err = omx->allocateNode(componentName, observer, &node);
Andreas Huberbe06d262009-08-14 14:37:10 -0700211 if (err == OK) {
Andreas Huber53a76bd2009-10-06 16:20:44 -0700212 LOGV("Successfully allocated OMX node '%s'", componentName);
Andreas Huberbe06d262009-08-14 14:37:10 -0700213 break;
214 }
215 }
216
217 uint32_t quirks = 0;
218 if (!strcmp(componentName, "OMX.PV.avcdec")) {
Andreas Huber4f5e6022009-08-19 09:29:34 -0700219 quirks |= kWantsNALFragments;
Andreas Huberbe06d262009-08-14 14:37:10 -0700220 }
221 if (!strcmp(componentName, "OMX.TI.MP3.decode")) {
222 quirks |= kNeedsFlushBeforeDisable;
223 }
224 if (!strcmp(componentName, "OMX.TI.AAC.decode")) {
225 quirks |= kNeedsFlushBeforeDisable;
Andreas Huber404cc412009-08-25 14:26:05 -0700226 quirks |= kRequiresFlushCompleteEmulation;
Andreas Huberbe06d262009-08-14 14:37:10 -0700227 }
228 if (!strncmp(componentName, "OMX.qcom.video.encoder.", 23)) {
229 quirks |= kRequiresLoadedToIdleAfterAllocation;
230 quirks |= kRequiresAllocateBufferOnInputPorts;
231 }
Andreas Hubera7d0cf42009-09-04 07:48:51 -0700232 if (!strncmp(componentName, "OMX.qcom.video.decoder.", 23)) {
233 // XXX Required on P....on only.
234 quirks |= kRequiresAllocateBufferOnOutputPorts;
235 }
Andreas Huberbe06d262009-08-14 14:37:10 -0700236
Andreas Huber2dc64d82009-09-11 12:58:53 -0700237 if (!strncmp(componentName, "OMX.TI.", 7)) {
238 // Apparently I must not use OMX_UseBuffer on either input or
239 // output ports on any of the TI components or quote:
240 // "(I) may have unexpected problem (sic) which can be timing related
241 // and hard to reproduce."
242
243 quirks |= kRequiresAllocateBufferOnInputPorts;
244 quirks |= kRequiresAllocateBufferOnOutputPorts;
245 }
246
Andreas Huberbe06d262009-08-14 14:37:10 -0700247 sp<OMXCodec> codec = new OMXCodec(
248 omx, node, quirks, createEncoder, mime, componentName,
249 source);
250
Andreas Huber784202e2009-10-15 13:46:54 -0700251 observer->setCodec(codec);
252
Andreas Huberbe06d262009-08-14 14:37:10 -0700253 uint32_t type;
254 const void *data;
255 size_t size;
256 if (meta->findData(kKeyESDS, &type, &data, &size)) {
257 ESDS esds((const char *)data, size);
258 CHECK_EQ(esds.InitCheck(), OK);
259
260 const void *codec_specific_data;
261 size_t codec_specific_data_size;
262 esds.getCodecSpecificInfo(
263 &codec_specific_data, &codec_specific_data_size);
264
265 printf("found codec-specific data of size %d\n",
266 codec_specific_data_size);
267
268 codec->addCodecSpecificData(
269 codec_specific_data, codec_specific_data_size);
270 } else if (meta->findData(kKeyAVCC, &type, &data, &size)) {
271 printf("found avcc of size %d\n", size);
272
Andreas Huberebf66ea2009-08-19 13:32:58 -0700273 // Parse the AVCDecoderConfigurationRecord
274
275 const uint8_t *ptr = (const uint8_t *)data;
276
277 CHECK(size >= 7);
278 CHECK_EQ(ptr[0], 1); // configurationVersion == 1
279 uint8_t profile = ptr[1];
280 uint8_t level = ptr[3];
281
282 CHECK((ptr[4] >> 2) == 0x3f); // reserved
283
284 size_t lengthSize = 1 + (ptr[4] & 3);
285
286 // commented out check below as H264_QVGA_500_NO_AUDIO.3gp
287 // violates it...
288 // CHECK((ptr[5] >> 5) == 7); // reserved
289
290 size_t numSeqParameterSets = ptr[5] & 31;
291
292 ptr += 6;
Andreas Huberbe06d262009-08-14 14:37:10 -0700293 size -= 6;
Andreas Huberebf66ea2009-08-19 13:32:58 -0700294
295 for (size_t i = 0; i < numSeqParameterSets; ++i) {
296 CHECK(size >= 2);
297 size_t length = U16_AT(ptr);
Andreas Huberbe06d262009-08-14 14:37:10 -0700298
299 ptr += 2;
300 size -= 2;
301
Andreas Huberbe06d262009-08-14 14:37:10 -0700302 CHECK(size >= length);
303
304 codec->addCodecSpecificData(ptr, length);
305
306 ptr += length;
307 size -= length;
Andreas Huberebf66ea2009-08-19 13:32:58 -0700308 }
Andreas Huberbe06d262009-08-14 14:37:10 -0700309
Andreas Huberebf66ea2009-08-19 13:32:58 -0700310 CHECK(size >= 1);
311 size_t numPictureParameterSets = *ptr;
312 ++ptr;
313 --size;
Andreas Huberbe06d262009-08-14 14:37:10 -0700314
Andreas Huberebf66ea2009-08-19 13:32:58 -0700315 for (size_t i = 0; i < numPictureParameterSets; ++i) {
316 CHECK(size >= 2);
317 size_t length = U16_AT(ptr);
318
319 ptr += 2;
320 size -= 2;
321
322 CHECK(size >= length);
323
324 codec->addCodecSpecificData(ptr, length);
325
326 ptr += length;
327 size -= length;
328 }
329
Andreas Huber53a76bd2009-10-06 16:20:44 -0700330 LOGV("AVC profile = %d (%s), level = %d",
Andreas Huberebf66ea2009-08-19 13:32:58 -0700331 (int)profile, AVCProfileToString(profile), (int)level / 10);
332
333 if (!strcmp(componentName, "OMX.TI.Video.Decoder")
334 && (profile != kAVCProfileBaseline || level > 39)) {
Andreas Huber784202e2009-10-15 13:46:54 -0700335 // This stream exceeds the decoder's capabilities. The decoder
336 // does not handle this gracefully and would clobber the heap
337 // and wreak havoc instead...
Andreas Huberebf66ea2009-08-19 13:32:58 -0700338
339 LOGE("Profile and/or level exceed the decoder's capabilities.");
340 return NULL;
Andreas Huberbe06d262009-08-14 14:37:10 -0700341 }
342 }
343
Andreas Hubere6c40962009-09-10 14:13:30 -0700344 if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime)) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700345 codec->setAMRFormat();
346 }
Andreas Hubere6c40962009-09-10 14:13:30 -0700347 if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) {
Andreas Huberee606e62009-09-08 10:19:21 -0700348 codec->setAMRWBFormat();
349 }
Andreas Hubere6c40962009-09-10 14:13:30 -0700350 if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) {
Andreas Huber43ad6eaf2009-09-01 16:02:43 -0700351 int32_t numChannels, sampleRate;
352 CHECK(meta->findInt32(kKeyChannelCount, &numChannels));
353 CHECK(meta->findInt32(kKeySampleRate, &sampleRate));
354
355 codec->setAACFormat(numChannels, sampleRate);
Andreas Huberbe06d262009-08-14 14:37:10 -0700356 }
357 if (!strncasecmp(mime, "video/", 6)) {
358 int32_t width, height;
359 bool success = meta->findInt32(kKeyWidth, &width);
360 success = success && meta->findInt32(kKeyHeight, &height);
Andreas Huber5c0a9132009-08-20 11:16:40 -0700361 CHECK(success);
Andreas Huberbe06d262009-08-14 14:37:10 -0700362
363 if (createEncoder) {
364 codec->setVideoInputFormat(mime, width, height);
365 } else {
366 codec->setVideoOutputFormat(mime, width, height);
367 }
368 }
Andreas Hubere6c40962009-09-10 14:13:30 -0700369 if (!strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_JPEG)
Andreas Huberbe06d262009-08-14 14:37:10 -0700370 && !strcmp(componentName, "OMX.TI.JPEG.decode")) {
371 OMX_COLOR_FORMATTYPE format =
372 OMX_COLOR_Format32bitARGB8888;
373 // OMX_COLOR_FormatYUV420PackedPlanar;
374 // OMX_COLOR_FormatCbYCrY;
375 // OMX_COLOR_FormatYUV411Planar;
376
377 int32_t width, height;
378 bool success = meta->findInt32(kKeyWidth, &width);
379 success = success && meta->findInt32(kKeyHeight, &height);
Andreas Huber5c0a9132009-08-20 11:16:40 -0700380
381 int32_t compressedSize;
382 success = success && meta->findInt32(
Andreas Huberda050cf22009-09-02 14:01:43 -0700383 kKeyMaxInputSize, &compressedSize);
Andreas Huber5c0a9132009-08-20 11:16:40 -0700384
385 CHECK(success);
386 CHECK(compressedSize > 0);
Andreas Huberbe06d262009-08-14 14:37:10 -0700387
388 codec->setImageOutputFormat(format, width, height);
Andreas Huber5c0a9132009-08-20 11:16:40 -0700389 codec->setJPEGInputFormat(width, height, (OMX_U32)compressedSize);
Andreas Huberbe06d262009-08-14 14:37:10 -0700390 }
391
Andreas Huberda050cf22009-09-02 14:01:43 -0700392 int32_t maxInputSize;
393 if (createEncoder && meta->findInt32(kKeyMaxInputSize, &maxInputSize)) {
394 codec->setMinBufferSize(kPortIndexInput, (OMX_U32)maxInputSize);
395 }
396
397 if (!strcmp(componentName, "OMX.TI.AMR.encode")
398 || !strcmp(componentName, "OMX.TI.WBAMR.encode")) {
399 codec->setMinBufferSize(kPortIndexOutput, 8192); // XXX
400 }
401
Andreas Huberbe06d262009-08-14 14:37:10 -0700402 codec->initOutputFormat(meta);
403
404 return codec;
405}
406
Andreas Huberda050cf22009-09-02 14:01:43 -0700407void OMXCodec::setMinBufferSize(OMX_U32 portIndex, OMX_U32 size) {
408 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -0700409 InitOMXParams(&def);
Andreas Huberda050cf22009-09-02 14:01:43 -0700410 def.nPortIndex = portIndex;
411
Andreas Huber784202e2009-10-15 13:46:54 -0700412 status_t err = mOMX->getParameter(
Andreas Huberda050cf22009-09-02 14:01:43 -0700413 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
414 CHECK_EQ(err, OK);
415
416 if (def.nBufferSize < size) {
417 def.nBufferSize = size;
418
419 }
420
Andreas Huber784202e2009-10-15 13:46:54 -0700421 err = mOMX->setParameter(
Andreas Huberda050cf22009-09-02 14:01:43 -0700422 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
423 CHECK_EQ(err, OK);
424}
425
Andreas Huberbe06d262009-08-14 14:37:10 -0700426status_t OMXCodec::setVideoPortFormatType(
427 OMX_U32 portIndex,
428 OMX_VIDEO_CODINGTYPE compressionFormat,
429 OMX_COLOR_FORMATTYPE colorFormat) {
430 OMX_VIDEO_PARAM_PORTFORMATTYPE format;
Andreas Huber4c483422009-09-02 16:05:36 -0700431 InitOMXParams(&format);
Andreas Huberbe06d262009-08-14 14:37:10 -0700432 format.nPortIndex = portIndex;
433 format.nIndex = 0;
434 bool found = false;
435
436 OMX_U32 index = 0;
437 for (;;) {
438 format.nIndex = index;
Andreas Huber784202e2009-10-15 13:46:54 -0700439 status_t err = mOMX->getParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -0700440 mNode, OMX_IndexParamVideoPortFormat,
441 &format, sizeof(format));
442
443 if (err != OK) {
444 return err;
445 }
446
447 // The following assertion is violated by TI's video decoder.
Andreas Huber5c0a9132009-08-20 11:16:40 -0700448 // CHECK_EQ(format.nIndex, index);
Andreas Huberbe06d262009-08-14 14:37:10 -0700449
450#if 1
Andreas Huber53a76bd2009-10-06 16:20:44 -0700451 CODEC_LOGV("portIndex: %ld, index: %ld, eCompressionFormat=%d eColorFormat=%d",
Andreas Huberbe06d262009-08-14 14:37:10 -0700452 portIndex,
453 index, format.eCompressionFormat, format.eColorFormat);
454#endif
455
456 if (!strcmp("OMX.TI.Video.encoder", mComponentName)) {
457 if (portIndex == kPortIndexInput
458 && colorFormat == format.eColorFormat) {
459 // eCompressionFormat does not seem right.
460 found = true;
461 break;
462 }
463 if (portIndex == kPortIndexOutput
464 && compressionFormat == format.eCompressionFormat) {
465 // eColorFormat does not seem right.
466 found = true;
467 break;
468 }
469 }
470
471 if (format.eCompressionFormat == compressionFormat
472 && format.eColorFormat == colorFormat) {
473 found = true;
474 break;
475 }
476
477 ++index;
478 }
479
480 if (!found) {
481 return UNKNOWN_ERROR;
482 }
483
Andreas Huber53a76bd2009-10-06 16:20:44 -0700484 CODEC_LOGV("found a match.");
Andreas Huber784202e2009-10-15 13:46:54 -0700485 status_t err = mOMX->setParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -0700486 mNode, OMX_IndexParamVideoPortFormat,
487 &format, sizeof(format));
488
489 return err;
490}
491
492void OMXCodec::setVideoInputFormat(
493 const char *mime, OMX_U32 width, OMX_U32 height) {
Andreas Huber53a76bd2009-10-06 16:20:44 -0700494 CODEC_LOGV("setVideoInputFormat width=%ld, height=%ld", width, height);
Andreas Huberbe06d262009-08-14 14:37:10 -0700495
496 OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused;
Andreas Hubere6c40962009-09-10 14:13:30 -0700497 if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700498 compressionFormat = OMX_VIDEO_CodingAVC;
Andreas Hubere6c40962009-09-10 14:13:30 -0700499 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700500 compressionFormat = OMX_VIDEO_CodingMPEG4;
Andreas Hubere6c40962009-09-10 14:13:30 -0700501 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700502 compressionFormat = OMX_VIDEO_CodingH263;
503 } else {
504 LOGE("Not a supported video mime type: %s", mime);
505 CHECK(!"Should not be here. Not a supported video mime type.");
506 }
507
508 OMX_COLOR_FORMATTYPE colorFormat =
509 0 ? OMX_COLOR_FormatYCbYCr : OMX_COLOR_FormatCbYCrY;
510
511 if (!strncmp("OMX.qcom.video.encoder.", mComponentName, 23)) {
512 colorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
513 }
514
515 setVideoPortFormatType(
516 kPortIndexInput, OMX_VIDEO_CodingUnused,
517 colorFormat);
518
519 setVideoPortFormatType(
520 kPortIndexOutput, compressionFormat, OMX_COLOR_FormatUnused);
521
522 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -0700523 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -0700524 def.nPortIndex = kPortIndexOutput;
525
Andreas Huber4c483422009-09-02 16:05:36 -0700526 OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
527
Andreas Huber784202e2009-10-15 13:46:54 -0700528 status_t err = mOMX->getParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -0700529 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
530
531 CHECK_EQ(err, OK);
532 CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
533
534 video_def->nFrameWidth = width;
535 video_def->nFrameHeight = height;
536
537 video_def->eCompressionFormat = compressionFormat;
538 video_def->eColorFormat = OMX_COLOR_FormatUnused;
539
Andreas Huber784202e2009-10-15 13:46:54 -0700540 err = mOMX->setParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -0700541 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
542 CHECK_EQ(err, OK);
543
544 ////////////////////////////////////////////////////////////////////////////
545
Andreas Huber4c483422009-09-02 16:05:36 -0700546 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -0700547 def.nPortIndex = kPortIndexInput;
548
Andreas Huber784202e2009-10-15 13:46:54 -0700549 err = mOMX->getParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -0700550 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
551 CHECK_EQ(err, OK);
552
553 def.nBufferSize = (width * height * 2); // (width * height * 3) / 2;
Andreas Huber53a76bd2009-10-06 16:20:44 -0700554 CODEC_LOGV("Setting nBufferSize = %ld", def.nBufferSize);
Andreas Huberbe06d262009-08-14 14:37:10 -0700555
556 CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
557
558 video_def->nFrameWidth = width;
559 video_def->nFrameHeight = height;
560 video_def->eCompressionFormat = OMX_VIDEO_CodingUnused;
561 video_def->eColorFormat = colorFormat;
562
Andreas Huber784202e2009-10-15 13:46:54 -0700563 err = mOMX->setParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -0700564 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
565 CHECK_EQ(err, OK);
566}
567
568void OMXCodec::setVideoOutputFormat(
569 const char *mime, OMX_U32 width, OMX_U32 height) {
Andreas Huber53a76bd2009-10-06 16:20:44 -0700570 CODEC_LOGV("setVideoOutputFormat width=%ld, height=%ld", width, height);
Andreas Huberbe06d262009-08-14 14:37:10 -0700571
Andreas Huberbe06d262009-08-14 14:37:10 -0700572 OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused;
Andreas Hubere6c40962009-09-10 14:13:30 -0700573 if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700574 compressionFormat = OMX_VIDEO_CodingAVC;
Andreas Hubere6c40962009-09-10 14:13:30 -0700575 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700576 compressionFormat = OMX_VIDEO_CodingMPEG4;
Andreas Hubere6c40962009-09-10 14:13:30 -0700577 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700578 compressionFormat = OMX_VIDEO_CodingH263;
579 } else {
580 LOGE("Not a supported video mime type: %s", mime);
581 CHECK(!"Should not be here. Not a supported video mime type.");
582 }
583
584 setVideoPortFormatType(
585 kPortIndexInput, compressionFormat, OMX_COLOR_FormatUnused);
586
587#if 1
588 {
589 OMX_VIDEO_PARAM_PORTFORMATTYPE format;
Andreas Huber4c483422009-09-02 16:05:36 -0700590 InitOMXParams(&format);
Andreas Huberbe06d262009-08-14 14:37:10 -0700591 format.nPortIndex = kPortIndexOutput;
592 format.nIndex = 0;
593
Andreas Huber784202e2009-10-15 13:46:54 -0700594 status_t err = mOMX->getParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -0700595 mNode, OMX_IndexParamVideoPortFormat,
596 &format, sizeof(format));
597 CHECK_EQ(err, OK);
598 CHECK_EQ(format.eCompressionFormat, OMX_VIDEO_CodingUnused);
599
600 static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
601
602 CHECK(format.eColorFormat == OMX_COLOR_FormatYUV420Planar
603 || format.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar
604 || format.eColorFormat == OMX_COLOR_FormatCbYCrY
605 || format.eColorFormat == OMX_QCOM_COLOR_FormatYVU420SemiPlanar);
606
Andreas Huber784202e2009-10-15 13:46:54 -0700607 err = mOMX->setParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -0700608 mNode, OMX_IndexParamVideoPortFormat,
609 &format, sizeof(format));
610 CHECK_EQ(err, OK);
611 }
612#endif
613
614 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -0700615 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -0700616 def.nPortIndex = kPortIndexInput;
617
Andreas Huber4c483422009-09-02 16:05:36 -0700618 OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
619
Andreas Huber784202e2009-10-15 13:46:54 -0700620 status_t err = mOMX->getParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -0700621 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
622
623 CHECK_EQ(err, OK);
624
625#if 1
626 // XXX Need a (much) better heuristic to compute input buffer sizes.
627 const size_t X = 64 * 1024;
628 if (def.nBufferSize < X) {
629 def.nBufferSize = X;
630 }
631#endif
632
633 CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
634
635 video_def->nFrameWidth = width;
636 video_def->nFrameHeight = height;
637
638 video_def->eColorFormat = OMX_COLOR_FormatUnused;
639
Andreas Huber784202e2009-10-15 13:46:54 -0700640 err = mOMX->setParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -0700641 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
642 CHECK_EQ(err, OK);
643
644 ////////////////////////////////////////////////////////////////////////////
645
Andreas Huber4c483422009-09-02 16:05:36 -0700646 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -0700647 def.nPortIndex = kPortIndexOutput;
648
Andreas Huber784202e2009-10-15 13:46:54 -0700649 err = mOMX->getParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -0700650 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
651 CHECK_EQ(err, OK);
652 CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
653
654#if 0
655 def.nBufferSize =
656 (((width + 15) & -16) * ((height + 15) & -16) * 3) / 2; // YUV420
657#endif
658
659 video_def->nFrameWidth = width;
660 video_def->nFrameHeight = height;
661
Andreas Huber784202e2009-10-15 13:46:54 -0700662 err = mOMX->setParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -0700663 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
664 CHECK_EQ(err, OK);
665}
666
667
668OMXCodec::OMXCodec(
669 const sp<IOMX> &omx, IOMX::node_id node, uint32_t quirks,
Andreas Huberebf66ea2009-08-19 13:32:58 -0700670 bool isEncoder,
Andreas Huberbe06d262009-08-14 14:37:10 -0700671 const char *mime,
672 const char *componentName,
673 const sp<MediaSource> &source)
674 : mOMX(omx),
675 mNode(node),
676 mQuirks(quirks),
677 mIsEncoder(isEncoder),
678 mMIME(strdup(mime)),
679 mComponentName(strdup(componentName)),
680 mSource(source),
681 mCodecSpecificDataIndex(0),
Andreas Huberbe06d262009-08-14 14:37:10 -0700682 mState(LOADED),
Andreas Huber42978e52009-08-27 10:08:39 -0700683 mInitialBufferSubmit(true),
Andreas Huberbe06d262009-08-14 14:37:10 -0700684 mSignalledEOS(false),
685 mNoMoreOutputData(false),
Andreas Hubercfd55572009-10-09 14:11:28 -0700686 mOutputPortSettingsHaveChanged(false),
Andreas Huberbe06d262009-08-14 14:37:10 -0700687 mSeekTimeUs(-1) {
688 mPortStatus[kPortIndexInput] = ENABLED;
689 mPortStatus[kPortIndexOutput] = ENABLED;
690
Andreas Huber4c483422009-09-02 16:05:36 -0700691 setComponentRole();
692}
693
Andreas Hubere6c40962009-09-10 14:13:30 -0700694// static
695void OMXCodec::setComponentRole(
696 const sp<IOMX> &omx, IOMX::node_id node, bool isEncoder,
697 const char *mime) {
Andreas Huber4c483422009-09-02 16:05:36 -0700698 struct MimeToRole {
699 const char *mime;
700 const char *decoderRole;
701 const char *encoderRole;
702 };
703
704 static const MimeToRole kMimeToRole[] = {
Andreas Hubere6c40962009-09-10 14:13:30 -0700705 { MEDIA_MIMETYPE_AUDIO_MPEG,
706 "audio_decoder.mp3", "audio_encoder.mp3" },
707 { MEDIA_MIMETYPE_AUDIO_AMR_NB,
708 "audio_decoder.amrnb", "audio_encoder.amrnb" },
709 { MEDIA_MIMETYPE_AUDIO_AMR_WB,
710 "audio_decoder.amrwb", "audio_encoder.amrwb" },
711 { MEDIA_MIMETYPE_AUDIO_AAC,
712 "audio_decoder.aac", "audio_encoder.aac" },
713 { MEDIA_MIMETYPE_VIDEO_AVC,
714 "video_decoder.avc", "video_encoder.avc" },
715 { MEDIA_MIMETYPE_VIDEO_MPEG4,
716 "video_decoder.mpeg4", "video_encoder.mpeg4" },
717 { MEDIA_MIMETYPE_VIDEO_H263,
718 "video_decoder.h263", "video_encoder.h263" },
Andreas Huber4c483422009-09-02 16:05:36 -0700719 };
720
721 static const size_t kNumMimeToRole =
722 sizeof(kMimeToRole) / sizeof(kMimeToRole[0]);
723
724 size_t i;
725 for (i = 0; i < kNumMimeToRole; ++i) {
Andreas Hubere6c40962009-09-10 14:13:30 -0700726 if (!strcasecmp(mime, kMimeToRole[i].mime)) {
Andreas Huber4c483422009-09-02 16:05:36 -0700727 break;
728 }
729 }
730
731 if (i == kNumMimeToRole) {
732 return;
733 }
734
735 const char *role =
Andreas Hubere6c40962009-09-10 14:13:30 -0700736 isEncoder ? kMimeToRole[i].encoderRole
737 : kMimeToRole[i].decoderRole;
Andreas Huber4c483422009-09-02 16:05:36 -0700738
739 if (role != NULL) {
Andreas Huber4c483422009-09-02 16:05:36 -0700740 OMX_PARAM_COMPONENTROLETYPE roleParams;
741 InitOMXParams(&roleParams);
742
743 strncpy((char *)roleParams.cRole,
744 role, OMX_MAX_STRINGNAME_SIZE - 1);
745
746 roleParams.cRole[OMX_MAX_STRINGNAME_SIZE - 1] = '\0';
747
Andreas Huber784202e2009-10-15 13:46:54 -0700748 status_t err = omx->setParameter(
Andreas Hubere6c40962009-09-10 14:13:30 -0700749 node, OMX_IndexParamStandardComponentRole,
Andreas Huber4c483422009-09-02 16:05:36 -0700750 &roleParams, sizeof(roleParams));
751
752 if (err != OK) {
753 LOGW("Failed to set standard component role '%s'.", role);
754 }
755 }
Andreas Huberbe06d262009-08-14 14:37:10 -0700756}
757
Andreas Hubere6c40962009-09-10 14:13:30 -0700758void OMXCodec::setComponentRole() {
759 setComponentRole(mOMX, mNode, mIsEncoder, mMIME);
760}
761
Andreas Huberbe06d262009-08-14 14:37:10 -0700762OMXCodec::~OMXCodec() {
Andreas Huber4f5e6022009-08-19 09:29:34 -0700763 CHECK(mState == LOADED || mState == ERROR);
Andreas Huberbe06d262009-08-14 14:37:10 -0700764
Andreas Huber784202e2009-10-15 13:46:54 -0700765 status_t err = mOMX->freeNode(mNode);
Andreas Huberbe06d262009-08-14 14:37:10 -0700766 CHECK_EQ(err, OK);
767
768 mNode = NULL;
769 setState(DEAD);
770
771 clearCodecSpecificData();
772
773 free(mComponentName);
774 mComponentName = NULL;
Andreas Huberebf66ea2009-08-19 13:32:58 -0700775
Andreas Huberbe06d262009-08-14 14:37:10 -0700776 free(mMIME);
777 mMIME = NULL;
778}
779
780status_t OMXCodec::init() {
Andreas Huber42978e52009-08-27 10:08:39 -0700781 // mLock is held.
Andreas Huberbe06d262009-08-14 14:37:10 -0700782
783 CHECK_EQ(mState, LOADED);
784
785 status_t err;
786 if (!(mQuirks & kRequiresLoadedToIdleAfterAllocation)) {
Andreas Huber784202e2009-10-15 13:46:54 -0700787 err = mOMX->sendCommand(mNode, OMX_CommandStateSet, OMX_StateIdle);
Andreas Huberbe06d262009-08-14 14:37:10 -0700788 CHECK_EQ(err, OK);
Andreas Huberbe06d262009-08-14 14:37:10 -0700789 setState(LOADED_TO_IDLE);
790 }
791
792 err = allocateBuffers();
793 CHECK_EQ(err, OK);
794
795 if (mQuirks & kRequiresLoadedToIdleAfterAllocation) {
Andreas Huber784202e2009-10-15 13:46:54 -0700796 err = mOMX->sendCommand(mNode, OMX_CommandStateSet, OMX_StateIdle);
Andreas Huberbe06d262009-08-14 14:37:10 -0700797 CHECK_EQ(err, OK);
798
799 setState(LOADED_TO_IDLE);
800 }
801
802 while (mState != EXECUTING && mState != ERROR) {
803 mAsyncCompletion.wait(mLock);
804 }
805
806 return mState == ERROR ? UNKNOWN_ERROR : OK;
807}
808
809// static
810bool OMXCodec::isIntermediateState(State state) {
811 return state == LOADED_TO_IDLE
812 || state == IDLE_TO_EXECUTING
813 || state == EXECUTING_TO_IDLE
814 || state == IDLE_TO_LOADED
815 || state == RECONFIGURING;
816}
817
818status_t OMXCodec::allocateBuffers() {
819 status_t err = allocateBuffersOnPort(kPortIndexInput);
820
821 if (err != OK) {
822 return err;
823 }
824
825 return allocateBuffersOnPort(kPortIndexOutput);
826}
827
828status_t OMXCodec::allocateBuffersOnPort(OMX_U32 portIndex) {
829 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -0700830 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -0700831 def.nPortIndex = portIndex;
832
Andreas Huber784202e2009-10-15 13:46:54 -0700833 status_t err = mOMX->getParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -0700834 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
835
836 if (err != OK) {
837 return err;
838 }
839
Andreas Huber5c0a9132009-08-20 11:16:40 -0700840 size_t totalSize = def.nBufferCountActual * def.nBufferSize;
841 mDealer[portIndex] = new MemoryDealer(totalSize);
842
Andreas Huberbe06d262009-08-14 14:37:10 -0700843 for (OMX_U32 i = 0; i < def.nBufferCountActual; ++i) {
Andreas Huber5c0a9132009-08-20 11:16:40 -0700844 sp<IMemory> mem = mDealer[portIndex]->allocate(def.nBufferSize);
Andreas Huberbe06d262009-08-14 14:37:10 -0700845 CHECK(mem.get() != NULL);
846
847 IOMX::buffer_id buffer;
848 if (portIndex == kPortIndexInput
849 && (mQuirks & kRequiresAllocateBufferOnInputPorts)) {
Andreas Huber784202e2009-10-15 13:46:54 -0700850 err = mOMX->allocateBufferWithBackup(
Andreas Huberbe06d262009-08-14 14:37:10 -0700851 mNode, portIndex, mem, &buffer);
Andreas Huber446f44f2009-08-25 17:23:44 -0700852 } else if (portIndex == kPortIndexOutput
853 && (mQuirks & kRequiresAllocateBufferOnOutputPorts)) {
Andreas Huber784202e2009-10-15 13:46:54 -0700854 err = mOMX->allocateBufferWithBackup(
Andreas Huber2dc64d82009-09-11 12:58:53 -0700855 mNode, portIndex, mem, &buffer);
Andreas Huberbe06d262009-08-14 14:37:10 -0700856 } else {
Andreas Huber784202e2009-10-15 13:46:54 -0700857 err = mOMX->useBuffer(mNode, portIndex, mem, &buffer);
Andreas Huberbe06d262009-08-14 14:37:10 -0700858 }
859
860 if (err != OK) {
861 LOGE("allocate_buffer_with_backup failed");
862 return err;
863 }
864
865 BufferInfo info;
866 info.mBuffer = buffer;
867 info.mOwnedByComponent = false;
868 info.mMem = mem;
869 info.mMediaBuffer = NULL;
870
871 if (portIndex == kPortIndexOutput) {
872 info.mMediaBuffer = new MediaBuffer(mem->pointer(), mem->size());
873 info.mMediaBuffer->setObserver(this);
874 }
875
876 mPortBuffers[portIndex].push(info);
877
Andreas Huber4c483422009-09-02 16:05:36 -0700878 CODEC_LOGV("allocated buffer %p on %s port", buffer,
Andreas Huberbe06d262009-08-14 14:37:10 -0700879 portIndex == kPortIndexInput ? "input" : "output");
880 }
881
882 dumpPortStatus(portIndex);
883
884 return OK;
885}
886
887void OMXCodec::on_message(const omx_message &msg) {
888 Mutex::Autolock autoLock(mLock);
889
890 switch (msg.type) {
891 case omx_message::EVENT:
892 {
893 onEvent(
894 msg.u.event_data.event, msg.u.event_data.data1,
895 msg.u.event_data.data2);
896
897 break;
898 }
899
900 case omx_message::EMPTY_BUFFER_DONE:
901 {
902 IOMX::buffer_id buffer = msg.u.extended_buffer_data.buffer;
903
Andreas Huber4c483422009-09-02 16:05:36 -0700904 CODEC_LOGV("EMPTY_BUFFER_DONE(buffer: %p)", buffer);
Andreas Huberbe06d262009-08-14 14:37:10 -0700905
906 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
907 size_t i = 0;
908 while (i < buffers->size() && (*buffers)[i].mBuffer != buffer) {
909 ++i;
910 }
911
912 CHECK(i < buffers->size());
913 if (!(*buffers)[i].mOwnedByComponent) {
914 LOGW("We already own input buffer %p, yet received "
915 "an EMPTY_BUFFER_DONE.", buffer);
916 }
917
918 buffers->editItemAt(i).mOwnedByComponent = false;
919
920 if (mPortStatus[kPortIndexInput] == DISABLING) {
Andreas Huber4c483422009-09-02 16:05:36 -0700921 CODEC_LOGV("Port is disabled, freeing buffer %p", buffer);
Andreas Huberbe06d262009-08-14 14:37:10 -0700922
923 status_t err =
Andreas Huber784202e2009-10-15 13:46:54 -0700924 mOMX->freeBuffer(mNode, kPortIndexInput, buffer);
Andreas Huberbe06d262009-08-14 14:37:10 -0700925 CHECK_EQ(err, OK);
926
927 buffers->removeAt(i);
928 } else if (mPortStatus[kPortIndexInput] != SHUTTING_DOWN) {
929 CHECK_EQ(mPortStatus[kPortIndexInput], ENABLED);
930 drainInputBuffer(&buffers->editItemAt(i));
931 }
932
933 break;
934 }
935
936 case omx_message::FILL_BUFFER_DONE:
937 {
938 IOMX::buffer_id buffer = msg.u.extended_buffer_data.buffer;
939 OMX_U32 flags = msg.u.extended_buffer_data.flags;
940
Andreas Huber4c483422009-09-02 16:05:36 -0700941 CODEC_LOGV("FILL_BUFFER_DONE(buffer: %p, size: %ld, flags: 0x%08lx)",
Andreas Huberbe06d262009-08-14 14:37:10 -0700942 buffer,
943 msg.u.extended_buffer_data.range_length,
944 flags);
945
Andreas Huber4c483422009-09-02 16:05:36 -0700946 CODEC_LOGV("FILL_BUFFER_DONE(timestamp: %lld us (%.2f secs))",
Andreas Huberbe06d262009-08-14 14:37:10 -0700947 msg.u.extended_buffer_data.timestamp,
948 msg.u.extended_buffer_data.timestamp / 1E6);
949
950 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
951 size_t i = 0;
952 while (i < buffers->size() && (*buffers)[i].mBuffer != buffer) {
953 ++i;
954 }
955
956 CHECK(i < buffers->size());
957 BufferInfo *info = &buffers->editItemAt(i);
958
959 if (!info->mOwnedByComponent) {
960 LOGW("We already own output buffer %p, yet received "
961 "a FILL_BUFFER_DONE.", buffer);
962 }
963
964 info->mOwnedByComponent = false;
965
966 if (mPortStatus[kPortIndexOutput] == DISABLING) {
Andreas Huber4c483422009-09-02 16:05:36 -0700967 CODEC_LOGV("Port is disabled, freeing buffer %p", buffer);
Andreas Huberbe06d262009-08-14 14:37:10 -0700968
969 status_t err =
Andreas Huber784202e2009-10-15 13:46:54 -0700970 mOMX->freeBuffer(mNode, kPortIndexOutput, buffer);
Andreas Huberbe06d262009-08-14 14:37:10 -0700971 CHECK_EQ(err, OK);
972
973 buffers->removeAt(i);
Andreas Huberd7795892009-08-26 10:33:47 -0700974 } else if (mPortStatus[kPortIndexOutput] == ENABLED
975 && (flags & OMX_BUFFERFLAG_EOS)) {
Andreas Huber4c483422009-09-02 16:05:36 -0700976 CODEC_LOGV("No more output data.");
Andreas Huberbe06d262009-08-14 14:37:10 -0700977 mNoMoreOutputData = true;
978 mBufferFilled.signal();
979 } else if (mPortStatus[kPortIndexOutput] != SHUTTING_DOWN) {
980 CHECK_EQ(mPortStatus[kPortIndexOutput], ENABLED);
Andreas Huberebf66ea2009-08-19 13:32:58 -0700981
Andreas Huberbe06d262009-08-14 14:37:10 -0700982 MediaBuffer *buffer = info->mMediaBuffer;
983
984 buffer->set_range(
985 msg.u.extended_buffer_data.range_offset,
986 msg.u.extended_buffer_data.range_length);
987
988 buffer->meta_data()->clear();
989
Andreas Huberfa8de752009-10-08 10:07:49 -0700990 buffer->meta_data()->setInt64(
991 kKeyTime, msg.u.extended_buffer_data.timestamp);
Andreas Huberbe06d262009-08-14 14:37:10 -0700992
993 if (msg.u.extended_buffer_data.flags & OMX_BUFFERFLAG_SYNCFRAME) {
994 buffer->meta_data()->setInt32(kKeyIsSyncFrame, true);
995 }
996
997 buffer->meta_data()->setPointer(
998 kKeyPlatformPrivate,
999 msg.u.extended_buffer_data.platform_private);
1000
1001 buffer->meta_data()->setPointer(
1002 kKeyBufferID,
1003 msg.u.extended_buffer_data.buffer);
1004
1005 mFilledBuffers.push_back(i);
1006 mBufferFilled.signal();
1007 }
1008
1009 break;
1010 }
1011
1012 default:
1013 {
1014 CHECK(!"should not be here.");
1015 break;
1016 }
1017 }
1018}
1019
1020void OMXCodec::onEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) {
1021 switch (event) {
1022 case OMX_EventCmdComplete:
1023 {
1024 onCmdComplete((OMX_COMMANDTYPE)data1, data2);
1025 break;
1026 }
1027
1028 case OMX_EventError:
1029 {
1030 LOGE("ERROR(%ld, %ld)", data1, data2);
1031
1032 setState(ERROR);
1033 break;
1034 }
1035
1036 case OMX_EventPortSettingsChanged:
1037 {
1038 onPortSettingsChanged(data1);
1039 break;
1040 }
1041
1042 case OMX_EventBufferFlag:
1043 {
Andreas Huber4c483422009-09-02 16:05:36 -07001044 CODEC_LOGV("EVENT_BUFFER_FLAG(%ld)", data1);
Andreas Huberbe06d262009-08-14 14:37:10 -07001045
1046 if (data1 == kPortIndexOutput) {
1047 mNoMoreOutputData = true;
1048 }
1049 break;
1050 }
1051
1052 default:
1053 {
Andreas Huber4c483422009-09-02 16:05:36 -07001054 CODEC_LOGV("EVENT(%d, %ld, %ld)", event, data1, data2);
Andreas Huberbe06d262009-08-14 14:37:10 -07001055 break;
1056 }
1057 }
1058}
1059
Andreas Huberb1678602009-10-19 13:06:40 -07001060// Has the format changed in any way that the client would have to be aware of?
1061static bool formatHasNotablyChanged(
1062 const sp<MetaData> &from, const sp<MetaData> &to) {
1063 if (from.get() == NULL && to.get() == NULL) {
1064 return false;
1065 }
1066
Andreas Huberf68c1682009-10-21 14:01:30 -07001067 if ((from.get() == NULL && to.get() != NULL)
1068 || (from.get() != NULL && to.get() == NULL)) {
Andreas Huberb1678602009-10-19 13:06:40 -07001069 return true;
1070 }
1071
1072 const char *mime_from, *mime_to;
1073 CHECK(from->findCString(kKeyMIMEType, &mime_from));
1074 CHECK(to->findCString(kKeyMIMEType, &mime_to));
1075
1076 if (strcasecmp(mime_from, mime_to)) {
1077 return true;
1078 }
1079
1080 if (!strcasecmp(mime_from, MEDIA_MIMETYPE_VIDEO_RAW)) {
1081 int32_t colorFormat_from, colorFormat_to;
1082 CHECK(from->findInt32(kKeyColorFormat, &colorFormat_from));
1083 CHECK(to->findInt32(kKeyColorFormat, &colorFormat_to));
1084
1085 if (colorFormat_from != colorFormat_to) {
1086 return true;
1087 }
1088
1089 int32_t width_from, width_to;
1090 CHECK(from->findInt32(kKeyWidth, &width_from));
1091 CHECK(to->findInt32(kKeyWidth, &width_to));
1092
1093 if (width_from != width_to) {
1094 return true;
1095 }
1096
1097 int32_t height_from, height_to;
1098 CHECK(from->findInt32(kKeyHeight, &height_from));
1099 CHECK(to->findInt32(kKeyHeight, &height_to));
1100
1101 if (height_from != height_to) {
1102 return true;
1103 }
1104 } else if (!strcasecmp(mime_from, MEDIA_MIMETYPE_AUDIO_RAW)) {
1105 int32_t numChannels_from, numChannels_to;
1106 CHECK(from->findInt32(kKeyChannelCount, &numChannels_from));
1107 CHECK(to->findInt32(kKeyChannelCount, &numChannels_to));
1108
1109 if (numChannels_from != numChannels_to) {
1110 return true;
1111 }
1112
1113 int32_t sampleRate_from, sampleRate_to;
1114 CHECK(from->findInt32(kKeySampleRate, &sampleRate_from));
1115 CHECK(to->findInt32(kKeySampleRate, &sampleRate_to));
1116
1117 if (sampleRate_from != sampleRate_to) {
1118 return true;
1119 }
1120 }
1121
1122 return false;
1123}
1124
Andreas Huberbe06d262009-08-14 14:37:10 -07001125void OMXCodec::onCmdComplete(OMX_COMMANDTYPE cmd, OMX_U32 data) {
1126 switch (cmd) {
1127 case OMX_CommandStateSet:
1128 {
1129 onStateChange((OMX_STATETYPE)data);
1130 break;
1131 }
1132
1133 case OMX_CommandPortDisable:
1134 {
1135 OMX_U32 portIndex = data;
Andreas Huber4c483422009-09-02 16:05:36 -07001136 CODEC_LOGV("PORT_DISABLED(%ld)", portIndex);
Andreas Huberbe06d262009-08-14 14:37:10 -07001137
1138 CHECK(mState == EXECUTING || mState == RECONFIGURING);
1139 CHECK_EQ(mPortStatus[portIndex], DISABLING);
1140 CHECK_EQ(mPortBuffers[portIndex].size(), 0);
1141
1142 mPortStatus[portIndex] = DISABLED;
1143
1144 if (mState == RECONFIGURING) {
1145 CHECK_EQ(portIndex, kPortIndexOutput);
1146
Andreas Huberb1678602009-10-19 13:06:40 -07001147 sp<MetaData> oldOutputFormat = mOutputFormat;
Andreas Hubercfd55572009-10-09 14:11:28 -07001148 initOutputFormat(mSource->getFormat());
Andreas Huberb1678602009-10-19 13:06:40 -07001149
1150 // Don't notify clients if the output port settings change
1151 // wasn't of importance to them, i.e. it may be that just the
1152 // number of buffers has changed and nothing else.
1153 mOutputPortSettingsHaveChanged =
1154 formatHasNotablyChanged(oldOutputFormat, mOutputFormat);
Andreas Hubercfd55572009-10-09 14:11:28 -07001155
Andreas Huberbe06d262009-08-14 14:37:10 -07001156 enablePortAsync(portIndex);
1157
1158 status_t err = allocateBuffersOnPort(portIndex);
1159 CHECK_EQ(err, OK);
1160 }
1161 break;
1162 }
1163
1164 case OMX_CommandPortEnable:
1165 {
1166 OMX_U32 portIndex = data;
Andreas Huber4c483422009-09-02 16:05:36 -07001167 CODEC_LOGV("PORT_ENABLED(%ld)", portIndex);
Andreas Huberbe06d262009-08-14 14:37:10 -07001168
1169 CHECK(mState == EXECUTING || mState == RECONFIGURING);
1170 CHECK_EQ(mPortStatus[portIndex], ENABLING);
1171
1172 mPortStatus[portIndex] = ENABLED;
1173
1174 if (mState == RECONFIGURING) {
1175 CHECK_EQ(portIndex, kPortIndexOutput);
1176
1177 setState(EXECUTING);
1178
1179 fillOutputBuffers();
1180 }
1181 break;
1182 }
1183
1184 case OMX_CommandFlush:
1185 {
1186 OMX_U32 portIndex = data;
1187
Andreas Huber4c483422009-09-02 16:05:36 -07001188 CODEC_LOGV("FLUSH_DONE(%ld)", portIndex);
Andreas Huberbe06d262009-08-14 14:37:10 -07001189
1190 CHECK_EQ(mPortStatus[portIndex], SHUTTING_DOWN);
1191 mPortStatus[portIndex] = ENABLED;
1192
1193 CHECK_EQ(countBuffersWeOwn(mPortBuffers[portIndex]),
1194 mPortBuffers[portIndex].size());
1195
1196 if (mState == RECONFIGURING) {
1197 CHECK_EQ(portIndex, kPortIndexOutput);
1198
1199 disablePortAsync(portIndex);
Andreas Huber127fcdc2009-08-26 16:27:02 -07001200 } else if (mState == EXECUTING_TO_IDLE) {
1201 if (mPortStatus[kPortIndexInput] == ENABLED
1202 && mPortStatus[kPortIndexOutput] == ENABLED) {
Andreas Huber4c483422009-09-02 16:05:36 -07001203 CODEC_LOGV("Finished flushing both ports, now completing "
Andreas Huber127fcdc2009-08-26 16:27:02 -07001204 "transition from EXECUTING to IDLE.");
1205
1206 mPortStatus[kPortIndexInput] = SHUTTING_DOWN;
1207 mPortStatus[kPortIndexOutput] = SHUTTING_DOWN;
1208
1209 status_t err =
Andreas Huber784202e2009-10-15 13:46:54 -07001210 mOMX->sendCommand(mNode, OMX_CommandStateSet, OMX_StateIdle);
Andreas Huber127fcdc2009-08-26 16:27:02 -07001211 CHECK_EQ(err, OK);
1212 }
Andreas Huberbe06d262009-08-14 14:37:10 -07001213 } else {
1214 // We're flushing both ports in preparation for seeking.
1215
1216 if (mPortStatus[kPortIndexInput] == ENABLED
1217 && mPortStatus[kPortIndexOutput] == ENABLED) {
Andreas Huber4c483422009-09-02 16:05:36 -07001218 CODEC_LOGV("Finished flushing both ports, now continuing from"
Andreas Huberbe06d262009-08-14 14:37:10 -07001219 " seek-time.");
1220
Andreas Huber1a77b68e2009-09-17 11:16:52 -07001221 // Clear this flag in case the decoder sent us either
1222 // the EVENT_BUFFER_FLAG(1) or an output buffer with
1223 // the EOS flag set _while_ flushing. Since we're going
1224 // to submit "fresh" input data now, this flag no longer
1225 // applies to our future.
1226 mNoMoreOutputData = false;
1227
Andreas Huberbe06d262009-08-14 14:37:10 -07001228 drainInputBuffers();
1229 fillOutputBuffers();
1230 }
1231 }
1232
1233 break;
1234 }
1235
1236 default:
1237 {
Andreas Huber4c483422009-09-02 16:05:36 -07001238 CODEC_LOGV("CMD_COMPLETE(%d, %ld)", cmd, data);
Andreas Huberbe06d262009-08-14 14:37:10 -07001239 break;
1240 }
1241 }
1242}
1243
1244void OMXCodec::onStateChange(OMX_STATETYPE newState) {
1245 switch (newState) {
1246 case OMX_StateIdle:
1247 {
Andreas Huber4c483422009-09-02 16:05:36 -07001248 CODEC_LOGV("Now Idle.");
Andreas Huberbe06d262009-08-14 14:37:10 -07001249 if (mState == LOADED_TO_IDLE) {
Andreas Huber784202e2009-10-15 13:46:54 -07001250 status_t err = mOMX->sendCommand(
Andreas Huberbe06d262009-08-14 14:37:10 -07001251 mNode, OMX_CommandStateSet, OMX_StateExecuting);
1252
1253 CHECK_EQ(err, OK);
1254
1255 setState(IDLE_TO_EXECUTING);
1256 } else {
1257 CHECK_EQ(mState, EXECUTING_TO_IDLE);
1258
1259 CHECK_EQ(
1260 countBuffersWeOwn(mPortBuffers[kPortIndexInput]),
1261 mPortBuffers[kPortIndexInput].size());
1262
1263 CHECK_EQ(
1264 countBuffersWeOwn(mPortBuffers[kPortIndexOutput]),
1265 mPortBuffers[kPortIndexOutput].size());
1266
Andreas Huber784202e2009-10-15 13:46:54 -07001267 status_t err = mOMX->sendCommand(
Andreas Huberbe06d262009-08-14 14:37:10 -07001268 mNode, OMX_CommandStateSet, OMX_StateLoaded);
1269
1270 CHECK_EQ(err, OK);
1271
1272 err = freeBuffersOnPort(kPortIndexInput);
1273 CHECK_EQ(err, OK);
1274
1275 err = freeBuffersOnPort(kPortIndexOutput);
1276 CHECK_EQ(err, OK);
1277
1278 mPortStatus[kPortIndexInput] = ENABLED;
1279 mPortStatus[kPortIndexOutput] = ENABLED;
1280
1281 setState(IDLE_TO_LOADED);
1282 }
1283 break;
1284 }
1285
1286 case OMX_StateExecuting:
1287 {
1288 CHECK_EQ(mState, IDLE_TO_EXECUTING);
1289
Andreas Huber4c483422009-09-02 16:05:36 -07001290 CODEC_LOGV("Now Executing.");
Andreas Huberbe06d262009-08-14 14:37:10 -07001291
1292 setState(EXECUTING);
1293
Andreas Huber42978e52009-08-27 10:08:39 -07001294 // Buffers will be submitted to the component in the first
1295 // call to OMXCodec::read as mInitialBufferSubmit is true at
1296 // this point. This ensures that this on_message call returns,
1297 // releases the lock and ::init can notice the state change and
1298 // itself return.
Andreas Huberbe06d262009-08-14 14:37:10 -07001299 break;
1300 }
1301
1302 case OMX_StateLoaded:
1303 {
1304 CHECK_EQ(mState, IDLE_TO_LOADED);
1305
Andreas Huber4c483422009-09-02 16:05:36 -07001306 CODEC_LOGV("Now Loaded.");
Andreas Huberbe06d262009-08-14 14:37:10 -07001307
1308 setState(LOADED);
1309 break;
1310 }
1311
1312 default:
1313 {
1314 CHECK(!"should not be here.");
1315 break;
1316 }
1317 }
1318}
1319
1320// static
1321size_t OMXCodec::countBuffersWeOwn(const Vector<BufferInfo> &buffers) {
1322 size_t n = 0;
1323 for (size_t i = 0; i < buffers.size(); ++i) {
1324 if (!buffers[i].mOwnedByComponent) {
1325 ++n;
1326 }
1327 }
1328
1329 return n;
1330}
1331
1332status_t OMXCodec::freeBuffersOnPort(
1333 OMX_U32 portIndex, bool onlyThoseWeOwn) {
1334 Vector<BufferInfo> *buffers = &mPortBuffers[portIndex];
1335
1336 status_t stickyErr = OK;
1337
1338 for (size_t i = buffers->size(); i-- > 0;) {
1339 BufferInfo *info = &buffers->editItemAt(i);
1340
1341 if (onlyThoseWeOwn && info->mOwnedByComponent) {
1342 continue;
1343 }
1344
1345 CHECK_EQ(info->mOwnedByComponent, false);
1346
Andreas Huber92022852009-09-14 15:24:14 -07001347 CODEC_LOGV("freeing buffer %p on port %ld", info->mBuffer, portIndex);
1348
Andreas Huberbe06d262009-08-14 14:37:10 -07001349 status_t err =
Andreas Huber784202e2009-10-15 13:46:54 -07001350 mOMX->freeBuffer(mNode, portIndex, info->mBuffer);
Andreas Huberbe06d262009-08-14 14:37:10 -07001351
1352 if (err != OK) {
1353 stickyErr = err;
1354 }
1355
1356 if (info->mMediaBuffer != NULL) {
1357 info->mMediaBuffer->setObserver(NULL);
1358
1359 // Make sure nobody but us owns this buffer at this point.
1360 CHECK_EQ(info->mMediaBuffer->refcount(), 0);
1361
1362 info->mMediaBuffer->release();
1363 }
1364
1365 buffers->removeAt(i);
1366 }
1367
1368 CHECK(onlyThoseWeOwn || buffers->isEmpty());
1369
1370 return stickyErr;
1371}
1372
1373void OMXCodec::onPortSettingsChanged(OMX_U32 portIndex) {
Andreas Huber4c483422009-09-02 16:05:36 -07001374 CODEC_LOGV("PORT_SETTINGS_CHANGED(%ld)", portIndex);
Andreas Huberbe06d262009-08-14 14:37:10 -07001375
1376 CHECK_EQ(mState, EXECUTING);
1377 CHECK_EQ(portIndex, kPortIndexOutput);
1378 setState(RECONFIGURING);
1379
1380 if (mQuirks & kNeedsFlushBeforeDisable) {
Andreas Huber404cc412009-08-25 14:26:05 -07001381 if (!flushPortAsync(portIndex)) {
1382 onCmdComplete(OMX_CommandFlush, portIndex);
1383 }
Andreas Huberbe06d262009-08-14 14:37:10 -07001384 } else {
1385 disablePortAsync(portIndex);
1386 }
1387}
1388
Andreas Huber404cc412009-08-25 14:26:05 -07001389bool OMXCodec::flushPortAsync(OMX_U32 portIndex) {
Andreas Huber127fcdc2009-08-26 16:27:02 -07001390 CHECK(mState == EXECUTING || mState == RECONFIGURING
1391 || mState == EXECUTING_TO_IDLE);
Andreas Huberbe06d262009-08-14 14:37:10 -07001392
Andreas Huber4c483422009-09-02 16:05:36 -07001393 CODEC_LOGV("flushPortAsync(%ld): we own %d out of %d buffers already.",
Andreas Huber404cc412009-08-25 14:26:05 -07001394 portIndex, countBuffersWeOwn(mPortBuffers[portIndex]),
1395 mPortBuffers[portIndex].size());
1396
Andreas Huberbe06d262009-08-14 14:37:10 -07001397 CHECK_EQ(mPortStatus[portIndex], ENABLED);
1398 mPortStatus[portIndex] = SHUTTING_DOWN;
1399
Andreas Huber404cc412009-08-25 14:26:05 -07001400 if ((mQuirks & kRequiresFlushCompleteEmulation)
1401 && countBuffersWeOwn(mPortBuffers[portIndex])
1402 == mPortBuffers[portIndex].size()) {
1403 // No flush is necessary and this component fails to send a
1404 // flush-complete event in this case.
1405
1406 return false;
1407 }
1408
Andreas Huberbe06d262009-08-14 14:37:10 -07001409 status_t err =
Andreas Huber784202e2009-10-15 13:46:54 -07001410 mOMX->sendCommand(mNode, OMX_CommandFlush, portIndex);
Andreas Huberbe06d262009-08-14 14:37:10 -07001411 CHECK_EQ(err, OK);
Andreas Huber404cc412009-08-25 14:26:05 -07001412
1413 return true;
Andreas Huberbe06d262009-08-14 14:37:10 -07001414}
1415
1416void OMXCodec::disablePortAsync(OMX_U32 portIndex) {
1417 CHECK(mState == EXECUTING || mState == RECONFIGURING);
1418
1419 CHECK_EQ(mPortStatus[portIndex], ENABLED);
1420 mPortStatus[portIndex] = DISABLING;
1421
1422 status_t err =
Andreas Huber784202e2009-10-15 13:46:54 -07001423 mOMX->sendCommand(mNode, OMX_CommandPortDisable, portIndex);
Andreas Huberbe06d262009-08-14 14:37:10 -07001424 CHECK_EQ(err, OK);
1425
1426 freeBuffersOnPort(portIndex, true);
1427}
1428
1429void OMXCodec::enablePortAsync(OMX_U32 portIndex) {
1430 CHECK(mState == EXECUTING || mState == RECONFIGURING);
1431
1432 CHECK_EQ(mPortStatus[portIndex], DISABLED);
1433 mPortStatus[portIndex] = ENABLING;
1434
1435 status_t err =
Andreas Huber784202e2009-10-15 13:46:54 -07001436 mOMX->sendCommand(mNode, OMX_CommandPortEnable, portIndex);
Andreas Huberbe06d262009-08-14 14:37:10 -07001437 CHECK_EQ(err, OK);
1438}
1439
1440void OMXCodec::fillOutputBuffers() {
1441 CHECK_EQ(mState, EXECUTING);
1442
1443 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
1444 for (size_t i = 0; i < buffers->size(); ++i) {
1445 fillOutputBuffer(&buffers->editItemAt(i));
1446 }
1447}
1448
1449void OMXCodec::drainInputBuffers() {
Andreas Huberd06e5b82009-08-28 13:18:14 -07001450 CHECK(mState == EXECUTING || mState == RECONFIGURING);
Andreas Huberbe06d262009-08-14 14:37:10 -07001451
1452 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
1453 for (size_t i = 0; i < buffers->size(); ++i) {
1454 drainInputBuffer(&buffers->editItemAt(i));
1455 }
1456}
1457
1458void OMXCodec::drainInputBuffer(BufferInfo *info) {
1459 CHECK_EQ(info->mOwnedByComponent, false);
1460
1461 if (mSignalledEOS) {
1462 return;
1463 }
1464
1465 if (mCodecSpecificDataIndex < mCodecSpecificData.size()) {
1466 const CodecSpecificData *specific =
1467 mCodecSpecificData[mCodecSpecificDataIndex];
1468
1469 size_t size = specific->mSize;
1470
Andreas Hubere6c40962009-09-10 14:13:30 -07001471 if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mMIME)
Andreas Huber4f5e6022009-08-19 09:29:34 -07001472 && !(mQuirks & kWantsNALFragments)) {
Andreas Huberbe06d262009-08-14 14:37:10 -07001473 static const uint8_t kNALStartCode[4] =
1474 { 0x00, 0x00, 0x00, 0x01 };
1475
1476 CHECK(info->mMem->size() >= specific->mSize + 4);
1477
1478 size += 4;
1479
1480 memcpy(info->mMem->pointer(), kNALStartCode, 4);
1481 memcpy((uint8_t *)info->mMem->pointer() + 4,
1482 specific->mData, specific->mSize);
1483 } else {
1484 CHECK(info->mMem->size() >= specific->mSize);
1485 memcpy(info->mMem->pointer(), specific->mData, specific->mSize);
1486 }
1487
Andreas Huber784202e2009-10-15 13:46:54 -07001488 status_t err = mOMX->emptyBuffer(
Andreas Huberbe06d262009-08-14 14:37:10 -07001489 mNode, info->mBuffer, 0, size,
1490 OMX_BUFFERFLAG_ENDOFFRAME | OMX_BUFFERFLAG_CODECCONFIG,
1491 0);
Andreas Huber3f427072009-10-08 11:02:27 -07001492 CHECK_EQ(err, OK);
Andreas Huberbe06d262009-08-14 14:37:10 -07001493
1494 info->mOwnedByComponent = true;
1495
1496 ++mCodecSpecificDataIndex;
1497 return;
1498 }
1499
1500 MediaBuffer *srcBuffer;
1501 status_t err;
1502 if (mSeekTimeUs >= 0) {
1503 MediaSource::ReadOptions options;
1504 options.setSeekTo(mSeekTimeUs);
1505 mSeekTimeUs = -1;
1506
1507 err = mSource->read(&srcBuffer, &options);
1508 } else {
1509 err = mSource->read(&srcBuffer);
1510 }
1511
1512 OMX_U32 flags = OMX_BUFFERFLAG_ENDOFFRAME;
Andreas Huberfa8de752009-10-08 10:07:49 -07001513 OMX_TICKS timestampUs = 0;
Andreas Huberbe06d262009-08-14 14:37:10 -07001514 size_t srcLength = 0;
1515
1516 if (err != OK) {
Andreas Huber4c483422009-09-02 16:05:36 -07001517 CODEC_LOGV("signalling end of input stream.");
Andreas Huberbe06d262009-08-14 14:37:10 -07001518 flags |= OMX_BUFFERFLAG_EOS;
1519
1520 mSignalledEOS = true;
1521 } else {
1522 srcLength = srcBuffer->range_length();
1523
1524 if (info->mMem->size() < srcLength) {
1525 LOGE("info->mMem->size() = %d, srcLength = %d",
1526 info->mMem->size(), srcLength);
1527 }
1528 CHECK(info->mMem->size() >= srcLength);
1529 memcpy(info->mMem->pointer(),
1530 (const uint8_t *)srcBuffer->data() + srcBuffer->range_offset(),
1531 srcLength);
1532
Andreas Huberfa8de752009-10-08 10:07:49 -07001533 if (srcBuffer->meta_data()->findInt64(kKeyTime, &timestampUs)) {
Andreas Huber784202e2009-10-15 13:46:54 -07001534 CODEC_LOGV("Calling emptyBuffer on buffer %p (length %d)",
Andreas Huberbe06d262009-08-14 14:37:10 -07001535 info->mBuffer, srcLength);
Andreas Huber784202e2009-10-15 13:46:54 -07001536 CODEC_LOGV("Calling emptyBuffer with timestamp %lld us (%.2f secs)",
Andreas Huberfa8de752009-10-08 10:07:49 -07001537 timestampUs, timestampUs / 1E6);
Andreas Huberbe06d262009-08-14 14:37:10 -07001538 }
1539 }
1540
Andreas Huberbe06d262009-08-14 14:37:10 -07001541 if (srcBuffer != NULL) {
1542 srcBuffer->release();
1543 srcBuffer = NULL;
1544 }
Andreas Huber3f427072009-10-08 11:02:27 -07001545
Andreas Huber784202e2009-10-15 13:46:54 -07001546 err = mOMX->emptyBuffer(
Andreas Huber3f427072009-10-08 11:02:27 -07001547 mNode, info->mBuffer, 0, srcLength,
Andreas Huberfa8de752009-10-08 10:07:49 -07001548 flags, timestampUs);
Andreas Huber3f427072009-10-08 11:02:27 -07001549
1550 if (err != OK) {
1551 setState(ERROR);
1552 return;
1553 }
1554
1555 info->mOwnedByComponent = true;
Andreas Huberbe06d262009-08-14 14:37:10 -07001556}
1557
1558void OMXCodec::fillOutputBuffer(BufferInfo *info) {
1559 CHECK_EQ(info->mOwnedByComponent, false);
1560
Andreas Huber404cc412009-08-25 14:26:05 -07001561 if (mNoMoreOutputData) {
Andreas Huber4c483422009-09-02 16:05:36 -07001562 CODEC_LOGV("There is no more output data available, not "
Andreas Huber404cc412009-08-25 14:26:05 -07001563 "calling fillOutputBuffer");
1564 return;
1565 }
1566
Andreas Huber4c483422009-09-02 16:05:36 -07001567 CODEC_LOGV("Calling fill_buffer on buffer %p", info->mBuffer);
Andreas Huber784202e2009-10-15 13:46:54 -07001568 status_t err = mOMX->fillBuffer(mNode, info->mBuffer);
Andreas Huber3f427072009-10-08 11:02:27 -07001569 CHECK_EQ(err, OK);
Andreas Huberbe06d262009-08-14 14:37:10 -07001570
1571 info->mOwnedByComponent = true;
1572}
1573
1574void OMXCodec::drainInputBuffer(IOMX::buffer_id buffer) {
1575 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
1576 for (size_t i = 0; i < buffers->size(); ++i) {
1577 if ((*buffers)[i].mBuffer == buffer) {
1578 drainInputBuffer(&buffers->editItemAt(i));
1579 return;
1580 }
1581 }
1582
1583 CHECK(!"should not be here.");
1584}
1585
1586void OMXCodec::fillOutputBuffer(IOMX::buffer_id buffer) {
1587 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
1588 for (size_t i = 0; i < buffers->size(); ++i) {
1589 if ((*buffers)[i].mBuffer == buffer) {
1590 fillOutputBuffer(&buffers->editItemAt(i));
1591 return;
1592 }
1593 }
1594
1595 CHECK(!"should not be here.");
1596}
1597
1598void OMXCodec::setState(State newState) {
1599 mState = newState;
1600 mAsyncCompletion.signal();
1601
1602 // This may cause some spurious wakeups but is necessary to
1603 // unblock the reader if we enter ERROR state.
1604 mBufferFilled.signal();
1605}
1606
Andreas Huberda050cf22009-09-02 14:01:43 -07001607void OMXCodec::setRawAudioFormat(
1608 OMX_U32 portIndex, int32_t sampleRate, int32_t numChannels) {
1609 OMX_AUDIO_PARAM_PCMMODETYPE pcmParams;
Andreas Huber4c483422009-09-02 16:05:36 -07001610 InitOMXParams(&pcmParams);
Andreas Huberda050cf22009-09-02 14:01:43 -07001611 pcmParams.nPortIndex = portIndex;
1612
Andreas Huber784202e2009-10-15 13:46:54 -07001613 status_t err = mOMX->getParameter(
Andreas Huberda050cf22009-09-02 14:01:43 -07001614 mNode, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams));
1615
1616 CHECK_EQ(err, OK);
1617
1618 pcmParams.nChannels = numChannels;
1619 pcmParams.eNumData = OMX_NumericalDataSigned;
1620 pcmParams.bInterleaved = OMX_TRUE;
1621 pcmParams.nBitPerSample = 16;
1622 pcmParams.nSamplingRate = sampleRate;
1623 pcmParams.ePCMMode = OMX_AUDIO_PCMModeLinear;
1624
1625 if (numChannels == 1) {
1626 pcmParams.eChannelMapping[0] = OMX_AUDIO_ChannelCF;
1627 } else {
1628 CHECK_EQ(numChannels, 2);
1629
1630 pcmParams.eChannelMapping[0] = OMX_AUDIO_ChannelLF;
1631 pcmParams.eChannelMapping[1] = OMX_AUDIO_ChannelRF;
1632 }
1633
Andreas Huber784202e2009-10-15 13:46:54 -07001634 err = mOMX->setParameter(
Andreas Huberda050cf22009-09-02 14:01:43 -07001635 mNode, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams));
1636
1637 CHECK_EQ(err, OK);
1638}
1639
Andreas Huberbe06d262009-08-14 14:37:10 -07001640void OMXCodec::setAMRFormat() {
1641 if (!mIsEncoder) {
1642 OMX_AUDIO_PARAM_AMRTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -07001643 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -07001644 def.nPortIndex = kPortIndexInput;
1645
1646 status_t err =
Andreas Huber784202e2009-10-15 13:46:54 -07001647 mOMX->getParameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
Andreas Huberbe06d262009-08-14 14:37:10 -07001648
1649 CHECK_EQ(err, OK);
1650
1651 def.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
1652 def.eAMRBandMode = OMX_AUDIO_AMRBandModeNB0;
1653
Andreas Huber784202e2009-10-15 13:46:54 -07001654 err = mOMX->setParameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
Andreas Huberbe06d262009-08-14 14:37:10 -07001655 CHECK_EQ(err, OK);
1656 }
1657
1658 ////////////////////////
1659
1660 if (mIsEncoder) {
1661 sp<MetaData> format = mSource->getFormat();
1662 int32_t sampleRate;
1663 int32_t numChannels;
1664 CHECK(format->findInt32(kKeySampleRate, &sampleRate));
1665 CHECK(format->findInt32(kKeyChannelCount, &numChannels));
1666
Andreas Huberda050cf22009-09-02 14:01:43 -07001667 setRawAudioFormat(kPortIndexInput, sampleRate, numChannels);
Andreas Huberbe06d262009-08-14 14:37:10 -07001668 }
1669}
1670
Andreas Huberee606e62009-09-08 10:19:21 -07001671void OMXCodec::setAMRWBFormat() {
1672 if (!mIsEncoder) {
1673 OMX_AUDIO_PARAM_AMRTYPE def;
1674 InitOMXParams(&def);
1675 def.nPortIndex = kPortIndexInput;
1676
1677 status_t err =
Andreas Huber784202e2009-10-15 13:46:54 -07001678 mOMX->getParameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
Andreas Huberee606e62009-09-08 10:19:21 -07001679
1680 CHECK_EQ(err, OK);
1681
1682 def.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
1683 def.eAMRBandMode = OMX_AUDIO_AMRBandModeWB0;
1684
Andreas Huber784202e2009-10-15 13:46:54 -07001685 err = mOMX->setParameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
Andreas Huberee606e62009-09-08 10:19:21 -07001686 CHECK_EQ(err, OK);
1687 }
1688
1689 ////////////////////////
1690
1691 if (mIsEncoder) {
1692 sp<MetaData> format = mSource->getFormat();
1693 int32_t sampleRate;
1694 int32_t numChannels;
1695 CHECK(format->findInt32(kKeySampleRate, &sampleRate));
1696 CHECK(format->findInt32(kKeyChannelCount, &numChannels));
1697
1698 setRawAudioFormat(kPortIndexInput, sampleRate, numChannels);
1699 }
1700}
1701
Andreas Huber43ad6eaf2009-09-01 16:02:43 -07001702void OMXCodec::setAACFormat(int32_t numChannels, int32_t sampleRate) {
Andreas Huberda050cf22009-09-02 14:01:43 -07001703 if (mIsEncoder) {
1704 setRawAudioFormat(kPortIndexInput, sampleRate, numChannels);
1705 } else {
1706 OMX_AUDIO_PARAM_AACPROFILETYPE profile;
Andreas Huber4c483422009-09-02 16:05:36 -07001707 InitOMXParams(&profile);
Andreas Huberda050cf22009-09-02 14:01:43 -07001708 profile.nPortIndex = kPortIndexInput;
Andreas Huberbe06d262009-08-14 14:37:10 -07001709
Andreas Huber784202e2009-10-15 13:46:54 -07001710 status_t err = mOMX->getParameter(
Andreas Huberda050cf22009-09-02 14:01:43 -07001711 mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile));
1712 CHECK_EQ(err, OK);
Andreas Huberbe06d262009-08-14 14:37:10 -07001713
Andreas Huberda050cf22009-09-02 14:01:43 -07001714 profile.nChannels = numChannels;
1715 profile.nSampleRate = sampleRate;
1716 profile.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4ADTS;
Andreas Huberbe06d262009-08-14 14:37:10 -07001717
Andreas Huber784202e2009-10-15 13:46:54 -07001718 err = mOMX->setParameter(
Andreas Huberda050cf22009-09-02 14:01:43 -07001719 mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile));
1720 CHECK_EQ(err, OK);
1721 }
Andreas Huberbe06d262009-08-14 14:37:10 -07001722}
1723
1724void OMXCodec::setImageOutputFormat(
1725 OMX_COLOR_FORMATTYPE format, OMX_U32 width, OMX_U32 height) {
Andreas Huber4c483422009-09-02 16:05:36 -07001726 CODEC_LOGV("setImageOutputFormat(%ld, %ld)", width, height);
Andreas Huberbe06d262009-08-14 14:37:10 -07001727
1728#if 0
1729 OMX_INDEXTYPE index;
1730 status_t err = mOMX->get_extension_index(
1731 mNode, "OMX.TI.JPEG.decode.Config.OutputColorFormat", &index);
1732 CHECK_EQ(err, OK);
1733
1734 err = mOMX->set_config(mNode, index, &format, sizeof(format));
1735 CHECK_EQ(err, OK);
1736#endif
1737
1738 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -07001739 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -07001740 def.nPortIndex = kPortIndexOutput;
1741
Andreas Huber784202e2009-10-15 13:46:54 -07001742 status_t err = mOMX->getParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -07001743 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
1744 CHECK_EQ(err, OK);
1745
1746 CHECK_EQ(def.eDomain, OMX_PortDomainImage);
1747
1748 OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
Andreas Huberebf66ea2009-08-19 13:32:58 -07001749
Andreas Huberbe06d262009-08-14 14:37:10 -07001750 CHECK_EQ(imageDef->eCompressionFormat, OMX_IMAGE_CodingUnused);
1751 imageDef->eColorFormat = format;
1752 imageDef->nFrameWidth = width;
1753 imageDef->nFrameHeight = height;
1754
1755 switch (format) {
1756 case OMX_COLOR_FormatYUV420PackedPlanar:
1757 case OMX_COLOR_FormatYUV411Planar:
1758 {
1759 def.nBufferSize = (width * height * 3) / 2;
1760 break;
1761 }
1762
1763 case OMX_COLOR_FormatCbYCrY:
1764 {
1765 def.nBufferSize = width * height * 2;
1766 break;
1767 }
1768
1769 case OMX_COLOR_Format32bitARGB8888:
1770 {
1771 def.nBufferSize = width * height * 4;
1772 break;
1773 }
1774
Andreas Huber201511c2009-09-08 14:01:44 -07001775 case OMX_COLOR_Format16bitARGB4444:
1776 case OMX_COLOR_Format16bitARGB1555:
1777 case OMX_COLOR_Format16bitRGB565:
1778 case OMX_COLOR_Format16bitBGR565:
1779 {
1780 def.nBufferSize = width * height * 2;
1781 break;
1782 }
1783
Andreas Huberbe06d262009-08-14 14:37:10 -07001784 default:
1785 CHECK(!"Should not be here. Unknown color format.");
1786 break;
1787 }
1788
Andreas Huber5c0a9132009-08-20 11:16:40 -07001789 def.nBufferCountActual = def.nBufferCountMin;
1790
Andreas Huber784202e2009-10-15 13:46:54 -07001791 err = mOMX->setParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -07001792 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
1793 CHECK_EQ(err, OK);
Andreas Huber5c0a9132009-08-20 11:16:40 -07001794}
Andreas Huberbe06d262009-08-14 14:37:10 -07001795
Andreas Huber5c0a9132009-08-20 11:16:40 -07001796void OMXCodec::setJPEGInputFormat(
1797 OMX_U32 width, OMX_U32 height, OMX_U32 compressedSize) {
1798 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -07001799 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -07001800 def.nPortIndex = kPortIndexInput;
1801
Andreas Huber784202e2009-10-15 13:46:54 -07001802 status_t err = mOMX->getParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -07001803 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
1804 CHECK_EQ(err, OK);
1805
Andreas Huber5c0a9132009-08-20 11:16:40 -07001806 CHECK_EQ(def.eDomain, OMX_PortDomainImage);
1807 OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
1808
Andreas Huberbe06d262009-08-14 14:37:10 -07001809 CHECK_EQ(imageDef->eCompressionFormat, OMX_IMAGE_CodingJPEG);
1810 imageDef->nFrameWidth = width;
1811 imageDef->nFrameHeight = height;
1812
Andreas Huber5c0a9132009-08-20 11:16:40 -07001813 def.nBufferSize = compressedSize;
Andreas Huberbe06d262009-08-14 14:37:10 -07001814 def.nBufferCountActual = def.nBufferCountMin;
1815
Andreas Huber784202e2009-10-15 13:46:54 -07001816 err = mOMX->setParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -07001817 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
1818 CHECK_EQ(err, OK);
1819}
1820
1821void OMXCodec::addCodecSpecificData(const void *data, size_t size) {
1822 CodecSpecificData *specific =
1823 (CodecSpecificData *)malloc(sizeof(CodecSpecificData) + size - 1);
1824
1825 specific->mSize = size;
1826 memcpy(specific->mData, data, size);
1827
1828 mCodecSpecificData.push(specific);
1829}
1830
1831void OMXCodec::clearCodecSpecificData() {
1832 for (size_t i = 0; i < mCodecSpecificData.size(); ++i) {
1833 free(mCodecSpecificData.editItemAt(i));
1834 }
1835 mCodecSpecificData.clear();
1836 mCodecSpecificDataIndex = 0;
1837}
1838
1839status_t OMXCodec::start(MetaData *) {
Andreas Huber42978e52009-08-27 10:08:39 -07001840 Mutex::Autolock autoLock(mLock);
1841
Andreas Huberbe06d262009-08-14 14:37:10 -07001842 if (mState != LOADED) {
1843 return UNKNOWN_ERROR;
1844 }
Andreas Huberebf66ea2009-08-19 13:32:58 -07001845
Andreas Huberbe06d262009-08-14 14:37:10 -07001846 sp<MetaData> params = new MetaData;
Andreas Huber4f5e6022009-08-19 09:29:34 -07001847 if (mQuirks & kWantsNALFragments) {
1848 params->setInt32(kKeyWantsNALFragments, true);
Andreas Huberbe06d262009-08-14 14:37:10 -07001849 }
1850 status_t err = mSource->start(params.get());
1851
1852 if (err != OK) {
1853 return err;
1854 }
1855
1856 mCodecSpecificDataIndex = 0;
Andreas Huber42978e52009-08-27 10:08:39 -07001857 mInitialBufferSubmit = true;
Andreas Huberbe06d262009-08-14 14:37:10 -07001858 mSignalledEOS = false;
1859 mNoMoreOutputData = false;
Andreas Hubercfd55572009-10-09 14:11:28 -07001860 mOutputPortSettingsHaveChanged = false;
Andreas Huberbe06d262009-08-14 14:37:10 -07001861 mSeekTimeUs = -1;
1862 mFilledBuffers.clear();
1863
1864 return init();
1865}
1866
1867status_t OMXCodec::stop() {
Andreas Huber4c483422009-09-02 16:05:36 -07001868 CODEC_LOGV("stop");
Andreas Huberbe06d262009-08-14 14:37:10 -07001869
1870 Mutex::Autolock autoLock(mLock);
1871
1872 while (isIntermediateState(mState)) {
1873 mAsyncCompletion.wait(mLock);
1874 }
1875
1876 switch (mState) {
1877 case LOADED:
1878 case ERROR:
1879 break;
1880
1881 case EXECUTING:
1882 {
1883 setState(EXECUTING_TO_IDLE);
1884
Andreas Huber127fcdc2009-08-26 16:27:02 -07001885 if (mQuirks & kRequiresFlushBeforeShutdown) {
Andreas Huber4c483422009-09-02 16:05:36 -07001886 CODEC_LOGV("This component requires a flush before transitioning "
Andreas Huber127fcdc2009-08-26 16:27:02 -07001887 "from EXECUTING to IDLE...");
Andreas Huberbe06d262009-08-14 14:37:10 -07001888
Andreas Huber127fcdc2009-08-26 16:27:02 -07001889 bool emulateInputFlushCompletion =
1890 !flushPortAsync(kPortIndexInput);
1891
1892 bool emulateOutputFlushCompletion =
1893 !flushPortAsync(kPortIndexOutput);
1894
1895 if (emulateInputFlushCompletion) {
1896 onCmdComplete(OMX_CommandFlush, kPortIndexInput);
1897 }
1898
1899 if (emulateOutputFlushCompletion) {
1900 onCmdComplete(OMX_CommandFlush, kPortIndexOutput);
1901 }
1902 } else {
1903 mPortStatus[kPortIndexInput] = SHUTTING_DOWN;
1904 mPortStatus[kPortIndexOutput] = SHUTTING_DOWN;
1905
1906 status_t err =
Andreas Huber784202e2009-10-15 13:46:54 -07001907 mOMX->sendCommand(mNode, OMX_CommandStateSet, OMX_StateIdle);
Andreas Huber127fcdc2009-08-26 16:27:02 -07001908 CHECK_EQ(err, OK);
1909 }
Andreas Huberbe06d262009-08-14 14:37:10 -07001910
1911 while (mState != LOADED && mState != ERROR) {
1912 mAsyncCompletion.wait(mLock);
1913 }
1914
1915 break;
1916 }
1917
1918 default:
1919 {
1920 CHECK(!"should not be here.");
1921 break;
1922 }
1923 }
1924
1925 mSource->stop();
1926
1927 return OK;
1928}
1929
1930sp<MetaData> OMXCodec::getFormat() {
Andreas Hubercfd55572009-10-09 14:11:28 -07001931 Mutex::Autolock autoLock(mLock);
1932
Andreas Huberbe06d262009-08-14 14:37:10 -07001933 return mOutputFormat;
1934}
1935
1936status_t OMXCodec::read(
1937 MediaBuffer **buffer, const ReadOptions *options) {
1938 *buffer = NULL;
1939
1940 Mutex::Autolock autoLock(mLock);
1941
Andreas Huberd06e5b82009-08-28 13:18:14 -07001942 if (mState != EXECUTING && mState != RECONFIGURING) {
1943 return UNKNOWN_ERROR;
1944 }
1945
Andreas Hubere981c332009-10-22 13:49:30 -07001946 bool seeking = false;
1947 int64_t seekTimeUs;
1948 if (options && options->getSeekTo(&seekTimeUs)) {
1949 seeking = true;
1950 }
1951
Andreas Huber42978e52009-08-27 10:08:39 -07001952 if (mInitialBufferSubmit) {
1953 mInitialBufferSubmit = false;
1954
Andreas Hubere981c332009-10-22 13:49:30 -07001955 if (seeking) {
1956 CHECK(seekTimeUs >= 0);
1957 mSeekTimeUs = seekTimeUs;
1958
1959 // There's no reason to trigger the code below, there's
1960 // nothing to flush yet.
1961 seeking = false;
1962 }
1963
Andreas Huber42978e52009-08-27 10:08:39 -07001964 drainInputBuffers();
Andreas Huber42978e52009-08-27 10:08:39 -07001965
Andreas Huberd06e5b82009-08-28 13:18:14 -07001966 if (mState == EXECUTING) {
1967 // Otherwise mState == RECONFIGURING and this code will trigger
1968 // after the output port is reenabled.
1969 fillOutputBuffers();
1970 }
Andreas Huberbe06d262009-08-14 14:37:10 -07001971 }
1972
Andreas Hubere981c332009-10-22 13:49:30 -07001973 if (seeking) {
Andreas Huber4c483422009-09-02 16:05:36 -07001974 CODEC_LOGV("seeking to %lld us (%.2f secs)", seekTimeUs, seekTimeUs / 1E6);
Andreas Huberbe06d262009-08-14 14:37:10 -07001975
1976 mSignalledEOS = false;
1977 mNoMoreOutputData = false;
1978
1979 CHECK(seekTimeUs >= 0);
1980 mSeekTimeUs = seekTimeUs;
1981
1982 mFilledBuffers.clear();
1983
1984 CHECK_EQ(mState, EXECUTING);
1985
Andreas Huber404cc412009-08-25 14:26:05 -07001986 bool emulateInputFlushCompletion = !flushPortAsync(kPortIndexInput);
1987 bool emulateOutputFlushCompletion = !flushPortAsync(kPortIndexOutput);
1988
1989 if (emulateInputFlushCompletion) {
1990 onCmdComplete(OMX_CommandFlush, kPortIndexInput);
1991 }
1992
1993 if (emulateOutputFlushCompletion) {
1994 onCmdComplete(OMX_CommandFlush, kPortIndexOutput);
1995 }
Andreas Huberbe06d262009-08-14 14:37:10 -07001996 }
1997
1998 while (mState != ERROR && !mNoMoreOutputData && mFilledBuffers.empty()) {
1999 mBufferFilled.wait(mLock);
2000 }
2001
2002 if (mState == ERROR) {
2003 return UNKNOWN_ERROR;
2004 }
2005
2006 if (mFilledBuffers.empty()) {
2007 return ERROR_END_OF_STREAM;
2008 }
2009
Andreas Hubercfd55572009-10-09 14:11:28 -07002010 if (mOutputPortSettingsHaveChanged) {
2011 mOutputPortSettingsHaveChanged = false;
2012
2013 return INFO_FORMAT_CHANGED;
2014 }
2015
Andreas Huberbe06d262009-08-14 14:37:10 -07002016 size_t index = *mFilledBuffers.begin();
2017 mFilledBuffers.erase(mFilledBuffers.begin());
2018
2019 BufferInfo *info = &mPortBuffers[kPortIndexOutput].editItemAt(index);
2020 info->mMediaBuffer->add_ref();
2021 *buffer = info->mMediaBuffer;
2022
2023 return OK;
2024}
2025
2026void OMXCodec::signalBufferReturned(MediaBuffer *buffer) {
2027 Mutex::Autolock autoLock(mLock);
2028
2029 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
2030 for (size_t i = 0; i < buffers->size(); ++i) {
2031 BufferInfo *info = &buffers->editItemAt(i);
2032
2033 if (info->mMediaBuffer == buffer) {
2034 CHECK_EQ(mPortStatus[kPortIndexOutput], ENABLED);
2035 fillOutputBuffer(info);
2036 return;
2037 }
2038 }
2039
2040 CHECK(!"should not be here.");
2041}
2042
2043static const char *imageCompressionFormatString(OMX_IMAGE_CODINGTYPE type) {
2044 static const char *kNames[] = {
2045 "OMX_IMAGE_CodingUnused",
2046 "OMX_IMAGE_CodingAutoDetect",
2047 "OMX_IMAGE_CodingJPEG",
2048 "OMX_IMAGE_CodingJPEG2K",
2049 "OMX_IMAGE_CodingEXIF",
2050 "OMX_IMAGE_CodingTIFF",
2051 "OMX_IMAGE_CodingGIF",
2052 "OMX_IMAGE_CodingPNG",
2053 "OMX_IMAGE_CodingLZW",
2054 "OMX_IMAGE_CodingBMP",
2055 };
2056
2057 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
2058
2059 if (type < 0 || (size_t)type >= numNames) {
2060 return "UNKNOWN";
2061 } else {
2062 return kNames[type];
2063 }
2064}
2065
2066static const char *colorFormatString(OMX_COLOR_FORMATTYPE type) {
2067 static const char *kNames[] = {
2068 "OMX_COLOR_FormatUnused",
2069 "OMX_COLOR_FormatMonochrome",
2070 "OMX_COLOR_Format8bitRGB332",
2071 "OMX_COLOR_Format12bitRGB444",
2072 "OMX_COLOR_Format16bitARGB4444",
2073 "OMX_COLOR_Format16bitARGB1555",
2074 "OMX_COLOR_Format16bitRGB565",
2075 "OMX_COLOR_Format16bitBGR565",
2076 "OMX_COLOR_Format18bitRGB666",
2077 "OMX_COLOR_Format18bitARGB1665",
Andreas Huberebf66ea2009-08-19 13:32:58 -07002078 "OMX_COLOR_Format19bitARGB1666",
Andreas Huberbe06d262009-08-14 14:37:10 -07002079 "OMX_COLOR_Format24bitRGB888",
2080 "OMX_COLOR_Format24bitBGR888",
2081 "OMX_COLOR_Format24bitARGB1887",
2082 "OMX_COLOR_Format25bitARGB1888",
2083 "OMX_COLOR_Format32bitBGRA8888",
2084 "OMX_COLOR_Format32bitARGB8888",
2085 "OMX_COLOR_FormatYUV411Planar",
2086 "OMX_COLOR_FormatYUV411PackedPlanar",
2087 "OMX_COLOR_FormatYUV420Planar",
2088 "OMX_COLOR_FormatYUV420PackedPlanar",
2089 "OMX_COLOR_FormatYUV420SemiPlanar",
2090 "OMX_COLOR_FormatYUV422Planar",
2091 "OMX_COLOR_FormatYUV422PackedPlanar",
2092 "OMX_COLOR_FormatYUV422SemiPlanar",
2093 "OMX_COLOR_FormatYCbYCr",
2094 "OMX_COLOR_FormatYCrYCb",
2095 "OMX_COLOR_FormatCbYCrY",
2096 "OMX_COLOR_FormatCrYCbY",
2097 "OMX_COLOR_FormatYUV444Interleaved",
2098 "OMX_COLOR_FormatRawBayer8bit",
2099 "OMX_COLOR_FormatRawBayer10bit",
2100 "OMX_COLOR_FormatRawBayer8bitcompressed",
Andreas Huberebf66ea2009-08-19 13:32:58 -07002101 "OMX_COLOR_FormatL2",
2102 "OMX_COLOR_FormatL4",
2103 "OMX_COLOR_FormatL8",
2104 "OMX_COLOR_FormatL16",
2105 "OMX_COLOR_FormatL24",
Andreas Huberbe06d262009-08-14 14:37:10 -07002106 "OMX_COLOR_FormatL32",
2107 "OMX_COLOR_FormatYUV420PackedSemiPlanar",
2108 "OMX_COLOR_FormatYUV422PackedSemiPlanar",
2109 "OMX_COLOR_Format18BitBGR666",
2110 "OMX_COLOR_Format24BitARGB6666",
2111 "OMX_COLOR_Format24BitABGR6666",
2112 };
2113
2114 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
2115
Andreas Huberbe06d262009-08-14 14:37:10 -07002116 if (type == OMX_QCOM_COLOR_FormatYVU420SemiPlanar) {
2117 return "OMX_QCOM_COLOR_FormatYVU420SemiPlanar";
2118 } else if (type < 0 || (size_t)type >= numNames) {
2119 return "UNKNOWN";
2120 } else {
2121 return kNames[type];
2122 }
2123}
2124
2125static const char *videoCompressionFormatString(OMX_VIDEO_CODINGTYPE type) {
2126 static const char *kNames[] = {
2127 "OMX_VIDEO_CodingUnused",
2128 "OMX_VIDEO_CodingAutoDetect",
2129 "OMX_VIDEO_CodingMPEG2",
2130 "OMX_VIDEO_CodingH263",
2131 "OMX_VIDEO_CodingMPEG4",
2132 "OMX_VIDEO_CodingWMV",
2133 "OMX_VIDEO_CodingRV",
2134 "OMX_VIDEO_CodingAVC",
2135 "OMX_VIDEO_CodingMJPEG",
2136 };
2137
2138 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
2139
2140 if (type < 0 || (size_t)type >= numNames) {
2141 return "UNKNOWN";
2142 } else {
2143 return kNames[type];
2144 }
2145}
2146
2147static const char *audioCodingTypeString(OMX_AUDIO_CODINGTYPE type) {
2148 static const char *kNames[] = {
2149 "OMX_AUDIO_CodingUnused",
2150 "OMX_AUDIO_CodingAutoDetect",
2151 "OMX_AUDIO_CodingPCM",
2152 "OMX_AUDIO_CodingADPCM",
2153 "OMX_AUDIO_CodingAMR",
2154 "OMX_AUDIO_CodingGSMFR",
2155 "OMX_AUDIO_CodingGSMEFR",
2156 "OMX_AUDIO_CodingGSMHR",
2157 "OMX_AUDIO_CodingPDCFR",
2158 "OMX_AUDIO_CodingPDCEFR",
2159 "OMX_AUDIO_CodingPDCHR",
2160 "OMX_AUDIO_CodingTDMAFR",
2161 "OMX_AUDIO_CodingTDMAEFR",
2162 "OMX_AUDIO_CodingQCELP8",
2163 "OMX_AUDIO_CodingQCELP13",
2164 "OMX_AUDIO_CodingEVRC",
2165 "OMX_AUDIO_CodingSMV",
2166 "OMX_AUDIO_CodingG711",
2167 "OMX_AUDIO_CodingG723",
2168 "OMX_AUDIO_CodingG726",
2169 "OMX_AUDIO_CodingG729",
2170 "OMX_AUDIO_CodingAAC",
2171 "OMX_AUDIO_CodingMP3",
2172 "OMX_AUDIO_CodingSBC",
2173 "OMX_AUDIO_CodingVORBIS",
2174 "OMX_AUDIO_CodingWMA",
2175 "OMX_AUDIO_CodingRA",
2176 "OMX_AUDIO_CodingMIDI",
2177 };
2178
2179 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
2180
2181 if (type < 0 || (size_t)type >= numNames) {
2182 return "UNKNOWN";
2183 } else {
2184 return kNames[type];
2185 }
2186}
2187
2188static const char *audioPCMModeString(OMX_AUDIO_PCMMODETYPE type) {
2189 static const char *kNames[] = {
2190 "OMX_AUDIO_PCMModeLinear",
2191 "OMX_AUDIO_PCMModeALaw",
2192 "OMX_AUDIO_PCMModeMULaw",
2193 };
2194
2195 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
2196
2197 if (type < 0 || (size_t)type >= numNames) {
2198 return "UNKNOWN";
2199 } else {
2200 return kNames[type];
2201 }
2202}
2203
Andreas Huber7ae02c82009-09-09 16:29:47 -07002204static const char *amrBandModeString(OMX_AUDIO_AMRBANDMODETYPE type) {
2205 static const char *kNames[] = {
2206 "OMX_AUDIO_AMRBandModeUnused",
2207 "OMX_AUDIO_AMRBandModeNB0",
2208 "OMX_AUDIO_AMRBandModeNB1",
2209 "OMX_AUDIO_AMRBandModeNB2",
2210 "OMX_AUDIO_AMRBandModeNB3",
2211 "OMX_AUDIO_AMRBandModeNB4",
2212 "OMX_AUDIO_AMRBandModeNB5",
2213 "OMX_AUDIO_AMRBandModeNB6",
2214 "OMX_AUDIO_AMRBandModeNB7",
2215 "OMX_AUDIO_AMRBandModeWB0",
2216 "OMX_AUDIO_AMRBandModeWB1",
2217 "OMX_AUDIO_AMRBandModeWB2",
2218 "OMX_AUDIO_AMRBandModeWB3",
2219 "OMX_AUDIO_AMRBandModeWB4",
2220 "OMX_AUDIO_AMRBandModeWB5",
2221 "OMX_AUDIO_AMRBandModeWB6",
2222 "OMX_AUDIO_AMRBandModeWB7",
2223 "OMX_AUDIO_AMRBandModeWB8",
2224 };
2225
2226 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
2227
2228 if (type < 0 || (size_t)type >= numNames) {
2229 return "UNKNOWN";
2230 } else {
2231 return kNames[type];
2232 }
2233}
2234
2235static const char *amrFrameFormatString(OMX_AUDIO_AMRFRAMEFORMATTYPE type) {
2236 static const char *kNames[] = {
2237 "OMX_AUDIO_AMRFrameFormatConformance",
2238 "OMX_AUDIO_AMRFrameFormatIF1",
2239 "OMX_AUDIO_AMRFrameFormatIF2",
2240 "OMX_AUDIO_AMRFrameFormatFSF",
2241 "OMX_AUDIO_AMRFrameFormatRTPPayload",
2242 "OMX_AUDIO_AMRFrameFormatITU",
2243 };
2244
2245 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
2246
2247 if (type < 0 || (size_t)type >= numNames) {
2248 return "UNKNOWN";
2249 } else {
2250 return kNames[type];
2251 }
2252}
Andreas Huberbe06d262009-08-14 14:37:10 -07002253
2254void OMXCodec::dumpPortStatus(OMX_U32 portIndex) {
2255 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -07002256 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -07002257 def.nPortIndex = portIndex;
2258
Andreas Huber784202e2009-10-15 13:46:54 -07002259 status_t err = mOMX->getParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -07002260 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
2261 CHECK_EQ(err, OK);
2262
2263 printf("%s Port = {\n", portIndex == kPortIndexInput ? "Input" : "Output");
2264
2265 CHECK((portIndex == kPortIndexInput && def.eDir == OMX_DirInput)
2266 || (portIndex == kPortIndexOutput && def.eDir == OMX_DirOutput));
2267
2268 printf(" nBufferCountActual = %ld\n", def.nBufferCountActual);
2269 printf(" nBufferCountMin = %ld\n", def.nBufferCountMin);
2270 printf(" nBufferSize = %ld\n", def.nBufferSize);
2271
2272 switch (def.eDomain) {
2273 case OMX_PortDomainImage:
2274 {
2275 const OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
2276
2277 printf("\n");
2278 printf(" // Image\n");
2279 printf(" nFrameWidth = %ld\n", imageDef->nFrameWidth);
2280 printf(" nFrameHeight = %ld\n", imageDef->nFrameHeight);
2281 printf(" nStride = %ld\n", imageDef->nStride);
2282
2283 printf(" eCompressionFormat = %s\n",
2284 imageCompressionFormatString(imageDef->eCompressionFormat));
2285
2286 printf(" eColorFormat = %s\n",
2287 colorFormatString(imageDef->eColorFormat));
2288
2289 break;
2290 }
2291
2292 case OMX_PortDomainVideo:
2293 {
2294 OMX_VIDEO_PORTDEFINITIONTYPE *videoDef = &def.format.video;
2295
2296 printf("\n");
2297 printf(" // Video\n");
2298 printf(" nFrameWidth = %ld\n", videoDef->nFrameWidth);
2299 printf(" nFrameHeight = %ld\n", videoDef->nFrameHeight);
2300 printf(" nStride = %ld\n", videoDef->nStride);
2301
2302 printf(" eCompressionFormat = %s\n",
2303 videoCompressionFormatString(videoDef->eCompressionFormat));
2304
2305 printf(" eColorFormat = %s\n",
2306 colorFormatString(videoDef->eColorFormat));
2307
2308 break;
2309 }
2310
2311 case OMX_PortDomainAudio:
2312 {
2313 OMX_AUDIO_PORTDEFINITIONTYPE *audioDef = &def.format.audio;
2314
2315 printf("\n");
2316 printf(" // Audio\n");
2317 printf(" eEncoding = %s\n",
2318 audioCodingTypeString(audioDef->eEncoding));
2319
2320 if (audioDef->eEncoding == OMX_AUDIO_CodingPCM) {
2321 OMX_AUDIO_PARAM_PCMMODETYPE params;
Andreas Huber4c483422009-09-02 16:05:36 -07002322 InitOMXParams(&params);
Andreas Huberbe06d262009-08-14 14:37:10 -07002323 params.nPortIndex = portIndex;
2324
Andreas Huber784202e2009-10-15 13:46:54 -07002325 err = mOMX->getParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -07002326 mNode, OMX_IndexParamAudioPcm, &params, sizeof(params));
2327 CHECK_EQ(err, OK);
2328
2329 printf(" nSamplingRate = %ld\n", params.nSamplingRate);
2330 printf(" nChannels = %ld\n", params.nChannels);
2331 printf(" bInterleaved = %d\n", params.bInterleaved);
2332 printf(" nBitPerSample = %ld\n", params.nBitPerSample);
2333
2334 printf(" eNumData = %s\n",
2335 params.eNumData == OMX_NumericalDataSigned
2336 ? "signed" : "unsigned");
2337
2338 printf(" ePCMMode = %s\n", audioPCMModeString(params.ePCMMode));
Andreas Huber7ae02c82009-09-09 16:29:47 -07002339 } else if (audioDef->eEncoding == OMX_AUDIO_CodingAMR) {
2340 OMX_AUDIO_PARAM_AMRTYPE amr;
2341 InitOMXParams(&amr);
2342 amr.nPortIndex = portIndex;
2343
Andreas Huber784202e2009-10-15 13:46:54 -07002344 err = mOMX->getParameter(
Andreas Huber7ae02c82009-09-09 16:29:47 -07002345 mNode, OMX_IndexParamAudioAmr, &amr, sizeof(amr));
2346 CHECK_EQ(err, OK);
2347
2348 printf(" nChannels = %ld\n", amr.nChannels);
2349 printf(" eAMRBandMode = %s\n",
2350 amrBandModeString(amr.eAMRBandMode));
2351 printf(" eAMRFrameFormat = %s\n",
2352 amrFrameFormatString(amr.eAMRFrameFormat));
Andreas Huberbe06d262009-08-14 14:37:10 -07002353 }
2354
2355 break;
2356 }
2357
2358 default:
2359 {
2360 printf(" // Unknown\n");
2361 break;
2362 }
2363 }
2364
2365 printf("}\n");
2366}
2367
2368void OMXCodec::initOutputFormat(const sp<MetaData> &inputFormat) {
2369 mOutputFormat = new MetaData;
2370 mOutputFormat->setCString(kKeyDecoderComponent, mComponentName);
2371
2372 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -07002373 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -07002374 def.nPortIndex = kPortIndexOutput;
2375
Andreas Huber784202e2009-10-15 13:46:54 -07002376 status_t err = mOMX->getParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -07002377 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
2378 CHECK_EQ(err, OK);
2379
2380 switch (def.eDomain) {
2381 case OMX_PortDomainImage:
2382 {
2383 OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
2384 CHECK_EQ(imageDef->eCompressionFormat, OMX_IMAGE_CodingUnused);
2385
Andreas Hubere6c40962009-09-10 14:13:30 -07002386 mOutputFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
Andreas Huberbe06d262009-08-14 14:37:10 -07002387 mOutputFormat->setInt32(kKeyColorFormat, imageDef->eColorFormat);
2388 mOutputFormat->setInt32(kKeyWidth, imageDef->nFrameWidth);
2389 mOutputFormat->setInt32(kKeyHeight, imageDef->nFrameHeight);
2390 break;
2391 }
2392
2393 case OMX_PortDomainAudio:
2394 {
2395 OMX_AUDIO_PORTDEFINITIONTYPE *audio_def = &def.format.audio;
2396
Andreas Huberda050cf22009-09-02 14:01:43 -07002397 if (audio_def->eEncoding == OMX_AUDIO_CodingPCM) {
2398 OMX_AUDIO_PARAM_PCMMODETYPE params;
Andreas Huber4c483422009-09-02 16:05:36 -07002399 InitOMXParams(&params);
Andreas Huberda050cf22009-09-02 14:01:43 -07002400 params.nPortIndex = kPortIndexOutput;
Andreas Huberbe06d262009-08-14 14:37:10 -07002401
Andreas Huber784202e2009-10-15 13:46:54 -07002402 err = mOMX->getParameter(
Andreas Huberda050cf22009-09-02 14:01:43 -07002403 mNode, OMX_IndexParamAudioPcm, &params, sizeof(params));
2404 CHECK_EQ(err, OK);
Andreas Huberbe06d262009-08-14 14:37:10 -07002405
Andreas Huberda050cf22009-09-02 14:01:43 -07002406 CHECK_EQ(params.eNumData, OMX_NumericalDataSigned);
2407 CHECK_EQ(params.nBitPerSample, 16);
2408 CHECK_EQ(params.ePCMMode, OMX_AUDIO_PCMModeLinear);
Andreas Huberbe06d262009-08-14 14:37:10 -07002409
Andreas Huberda050cf22009-09-02 14:01:43 -07002410 int32_t numChannels, sampleRate;
2411 inputFormat->findInt32(kKeyChannelCount, &numChannels);
2412 inputFormat->findInt32(kKeySampleRate, &sampleRate);
Andreas Huberbe06d262009-08-14 14:37:10 -07002413
Andreas Huberda050cf22009-09-02 14:01:43 -07002414 if ((OMX_U32)numChannels != params.nChannels) {
2415 LOGW("Codec outputs a different number of channels than "
2416 "the input stream contains.");
2417 }
Andreas Huberbe06d262009-08-14 14:37:10 -07002418
Andreas Hubere6c40962009-09-10 14:13:30 -07002419 mOutputFormat->setCString(
2420 kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
Andreas Huberda050cf22009-09-02 14:01:43 -07002421
2422 // Use the codec-advertised number of channels, as some
2423 // codecs appear to output stereo even if the input data is
2424 // mono.
2425 mOutputFormat->setInt32(kKeyChannelCount, params.nChannels);
2426
2427 // The codec-reported sampleRate is not reliable...
2428 mOutputFormat->setInt32(kKeySampleRate, sampleRate);
2429 } else if (audio_def->eEncoding == OMX_AUDIO_CodingAMR) {
Andreas Huber7ae02c82009-09-09 16:29:47 -07002430 OMX_AUDIO_PARAM_AMRTYPE amr;
2431 InitOMXParams(&amr);
2432 amr.nPortIndex = kPortIndexOutput;
2433
Andreas Huber784202e2009-10-15 13:46:54 -07002434 err = mOMX->getParameter(
Andreas Huber7ae02c82009-09-09 16:29:47 -07002435 mNode, OMX_IndexParamAudioAmr, &amr, sizeof(amr));
2436 CHECK_EQ(err, OK);
2437
2438 CHECK_EQ(amr.nChannels, 1);
2439 mOutputFormat->setInt32(kKeyChannelCount, 1);
2440
2441 if (amr.eAMRBandMode >= OMX_AUDIO_AMRBandModeNB0
2442 && amr.eAMRBandMode <= OMX_AUDIO_AMRBandModeNB7) {
Andreas Hubere6c40962009-09-10 14:13:30 -07002443 mOutputFormat->setCString(
2444 kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AMR_NB);
Andreas Huber7ae02c82009-09-09 16:29:47 -07002445 mOutputFormat->setInt32(kKeySampleRate, 8000);
2446 } else if (amr.eAMRBandMode >= OMX_AUDIO_AMRBandModeWB0
2447 && amr.eAMRBandMode <= OMX_AUDIO_AMRBandModeWB8) {
Andreas Hubere6c40962009-09-10 14:13:30 -07002448 mOutputFormat->setCString(
2449 kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AMR_WB);
Andreas Huber7ae02c82009-09-09 16:29:47 -07002450 mOutputFormat->setInt32(kKeySampleRate, 16000);
2451 } else {
2452 CHECK(!"Unknown AMR band mode.");
2453 }
Andreas Huberda050cf22009-09-02 14:01:43 -07002454 } else if (audio_def->eEncoding == OMX_AUDIO_CodingAAC) {
Andreas Hubere6c40962009-09-10 14:13:30 -07002455 mOutputFormat->setCString(
2456 kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
Andreas Huberda050cf22009-09-02 14:01:43 -07002457 } else {
2458 CHECK(!"Should not be here. Unknown audio encoding.");
Andreas Huber43ad6eaf2009-09-01 16:02:43 -07002459 }
Andreas Huberbe06d262009-08-14 14:37:10 -07002460 break;
2461 }
2462
2463 case OMX_PortDomainVideo:
2464 {
2465 OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
2466
2467 if (video_def->eCompressionFormat == OMX_VIDEO_CodingUnused) {
Andreas Hubere6c40962009-09-10 14:13:30 -07002468 mOutputFormat->setCString(
2469 kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
Andreas Huberbe06d262009-08-14 14:37:10 -07002470 } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingMPEG4) {
Andreas Hubere6c40962009-09-10 14:13:30 -07002471 mOutputFormat->setCString(
2472 kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
Andreas Huberbe06d262009-08-14 14:37:10 -07002473 } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingH263) {
Andreas Hubere6c40962009-09-10 14:13:30 -07002474 mOutputFormat->setCString(
2475 kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263);
Andreas Huberbe06d262009-08-14 14:37:10 -07002476 } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingAVC) {
Andreas Hubere6c40962009-09-10 14:13:30 -07002477 mOutputFormat->setCString(
2478 kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
Andreas Huberbe06d262009-08-14 14:37:10 -07002479 } else {
2480 CHECK(!"Unknown compression format.");
2481 }
2482
2483 if (!strcmp(mComponentName, "OMX.PV.avcdec")) {
2484 // This component appears to be lying to me.
2485 mOutputFormat->setInt32(
2486 kKeyWidth, (video_def->nFrameWidth + 15) & -16);
2487 mOutputFormat->setInt32(
2488 kKeyHeight, (video_def->nFrameHeight + 15) & -16);
2489 } else {
2490 mOutputFormat->setInt32(kKeyWidth, video_def->nFrameWidth);
2491 mOutputFormat->setInt32(kKeyHeight, video_def->nFrameHeight);
2492 }
2493
2494 mOutputFormat->setInt32(kKeyColorFormat, video_def->eColorFormat);
2495 break;
2496 }
2497
2498 default:
2499 {
2500 CHECK(!"should not be here, neither audio nor video.");
2501 break;
2502 }
2503 }
2504}
2505
Andreas Hubere6c40962009-09-10 14:13:30 -07002506////////////////////////////////////////////////////////////////////////////////
2507
2508status_t QueryCodecs(
2509 const sp<IOMX> &omx,
2510 const char *mime, bool queryDecoders,
2511 Vector<CodecCapabilities> *results) {
2512 results->clear();
2513
2514 for (int index = 0;; ++index) {
2515 const char *componentName;
2516
2517 if (!queryDecoders) {
2518 componentName = GetCodec(
2519 kEncoderInfo, sizeof(kEncoderInfo) / sizeof(kEncoderInfo[0]),
2520 mime, index);
2521 } else {
2522 componentName = GetCodec(
2523 kDecoderInfo, sizeof(kDecoderInfo) / sizeof(kDecoderInfo[0]),
2524 mime, index);
2525 }
2526
2527 if (!componentName) {
2528 return OK;
2529 }
2530
Andreas Huber784202e2009-10-15 13:46:54 -07002531 sp<OMXCodecObserver> observer = new OMXCodecObserver;
Andreas Hubere6c40962009-09-10 14:13:30 -07002532 IOMX::node_id node;
Andreas Huber784202e2009-10-15 13:46:54 -07002533 status_t err = omx->allocateNode(componentName, observer, &node);
Andreas Hubere6c40962009-09-10 14:13:30 -07002534
2535 if (err != OK) {
2536 continue;
2537 }
2538
2539 OMXCodec::setComponentRole(omx, node, queryDecoders, mime);
2540
2541 results->push();
2542 CodecCapabilities *caps = &results->editItemAt(results->size() - 1);
2543 caps->mComponentName = componentName;
2544
2545 OMX_VIDEO_PARAM_PROFILELEVELTYPE param;
2546 InitOMXParams(&param);
2547
2548 param.nPortIndex = queryDecoders ? 0 : 1;
2549
2550 for (param.nProfileIndex = 0;; ++param.nProfileIndex) {
Andreas Huber784202e2009-10-15 13:46:54 -07002551 err = omx->getParameter(
Andreas Hubere6c40962009-09-10 14:13:30 -07002552 node, OMX_IndexParamVideoProfileLevelQuerySupported,
2553 &param, sizeof(param));
2554
2555 if (err != OK) {
2556 break;
2557 }
2558
2559 CodecProfileLevel profileLevel;
2560 profileLevel.mProfile = param.eProfile;
2561 profileLevel.mLevel = param.eLevel;
2562
2563 caps->mProfileLevels.push(profileLevel);
2564 }
2565
Andreas Huber784202e2009-10-15 13:46:54 -07002566 CHECK_EQ(omx->freeNode(node), OK);
Andreas Hubere6c40962009-09-10 14:13:30 -07002567 }
2568}
2569
Andreas Huberbe06d262009-08-14 14:37:10 -07002570} // namespace android