blob: 7e9b8ad7cf9632e875bb8c5528ee892cac764d06 [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 Huberdacaa732009-12-07 09:56:32 -080021#include "include/AACDecoder.h"
Andreas Huberbd7b43b2009-10-13 10:22:55 -070022#include "include/ESDS.h"
23
Andreas Huberbe06d262009-08-14 14:37:10 -070024#include <binder/IServiceManager.h>
25#include <binder/MemoryDealer.h>
26#include <binder/ProcessState.h>
27#include <media/IMediaPlayerService.h>
Andreas Huberbe06d262009-08-14 14:37:10 -070028#include <media/stagefright/MediaBuffer.h>
29#include <media/stagefright/MediaBufferGroup.h>
30#include <media/stagefright/MediaDebug.h>
Andreas Hubere6c40962009-09-10 14:13:30 -070031#include <media/stagefright/MediaDefs.h>
Andreas Huberbe06d262009-08-14 14:37:10 -070032#include <media/stagefright/MediaExtractor.h>
33#include <media/stagefright/MetaData.h>
Andreas Huberbe06d262009-08-14 14:37:10 -070034#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 Hubere13526a2009-10-22 10:43:34 -0700175static bool IsSoftwareCodec(const char *componentName) {
176 if (!strncmp("OMX.PV.", componentName, 7)) {
177 return true;
Andreas Huberbe06d262009-08-14 14:37:10 -0700178 }
179
Andreas Hubere13526a2009-10-22 10:43:34 -0700180 return false;
181}
182
183static int CompareSoftwareCodecsFirst(
184 const String8 *elem1, const String8 *elem2) {
185 bool isSoftwareCodec1 = IsSoftwareCodec(elem1->string());
186 bool isSoftwareCodec2 = IsSoftwareCodec(elem2->string());
187
188 if (isSoftwareCodec1) {
189 if (isSoftwareCodec2) { return 0; }
190 return -1;
191 }
192
193 if (isSoftwareCodec2) {
194 return 1;
195 }
196
197 return 0;
198}
199
200// static
201uint32_t OMXCodec::getComponentQuirks(const char *componentName) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700202 uint32_t quirks = 0;
Andreas Hubere13526a2009-10-22 10:43:34 -0700203
Andreas Huberbe06d262009-08-14 14:37:10 -0700204 if (!strcmp(componentName, "OMX.PV.avcdec")) {
Andreas Huber4f5e6022009-08-19 09:29:34 -0700205 quirks |= kWantsNALFragments;
Andreas Huberbe06d262009-08-14 14:37:10 -0700206 }
207 if (!strcmp(componentName, "OMX.TI.MP3.decode")) {
208 quirks |= kNeedsFlushBeforeDisable;
209 }
210 if (!strcmp(componentName, "OMX.TI.AAC.decode")) {
211 quirks |= kNeedsFlushBeforeDisable;
Andreas Huber404cc412009-08-25 14:26:05 -0700212 quirks |= kRequiresFlushCompleteEmulation;
Andreas Huberbe06d262009-08-14 14:37:10 -0700213 }
214 if (!strncmp(componentName, "OMX.qcom.video.encoder.", 23)) {
215 quirks |= kRequiresLoadedToIdleAfterAllocation;
216 quirks |= kRequiresAllocateBufferOnInputPorts;
Andreas Huberb482ce82009-10-29 12:02:48 -0700217 quirks |= kRequiresAllocateBufferOnOutputPorts;
Andreas Huberbe06d262009-08-14 14:37:10 -0700218 }
Andreas Hubera7d0cf42009-09-04 07:48:51 -0700219 if (!strncmp(componentName, "OMX.qcom.video.decoder.", 23)) {
220 // XXX Required on P....on only.
221 quirks |= kRequiresAllocateBufferOnOutputPorts;
222 }
Andreas Huberbe06d262009-08-14 14:37:10 -0700223
Andreas Huber2dc64d82009-09-11 12:58:53 -0700224 if (!strncmp(componentName, "OMX.TI.", 7)) {
225 // Apparently I must not use OMX_UseBuffer on either input or
226 // output ports on any of the TI components or quote:
227 // "(I) may have unexpected problem (sic) which can be timing related
228 // and hard to reproduce."
229
230 quirks |= kRequiresAllocateBufferOnInputPorts;
231 quirks |= kRequiresAllocateBufferOnOutputPorts;
232 }
233
Andreas Hubere13526a2009-10-22 10:43:34 -0700234 return quirks;
235}
236
237// static
238void OMXCodec::findMatchingCodecs(
239 const char *mime,
240 bool createEncoder, const char *matchComponentName,
241 uint32_t flags,
242 Vector<String8> *matchingCodecs) {
243 matchingCodecs->clear();
244
245 for (int index = 0;; ++index) {
246 const char *componentName;
247
248 if (createEncoder) {
249 componentName = GetCodec(
250 kEncoderInfo,
251 sizeof(kEncoderInfo) / sizeof(kEncoderInfo[0]),
252 mime, index);
253 } else {
254 componentName = GetCodec(
255 kDecoderInfo,
256 sizeof(kDecoderInfo) / sizeof(kDecoderInfo[0]),
257 mime, index);
258 }
259
260 if (!componentName) {
261 break;
262 }
263
264 // If a specific codec is requested, skip the non-matching ones.
265 if (matchComponentName && strcmp(componentName, matchComponentName)) {
266 continue;
267 }
268
269 matchingCodecs->push(String8(componentName));
270 }
271
272 if (flags & kPreferSoftwareCodecs) {
273 matchingCodecs->sort(CompareSoftwareCodecsFirst);
274 }
275}
276
277// static
Andreas Huber91eb0352009-12-07 09:43:00 -0800278sp<MediaSource> OMXCodec::Create(
Andreas Hubere13526a2009-10-22 10:43:34 -0700279 const sp<IOMX> &omx,
280 const sp<MetaData> &meta, bool createEncoder,
281 const sp<MediaSource> &source,
282 const char *matchComponentName,
283 uint32_t flags) {
284 const char *mime;
285 bool success = meta->findCString(kKeyMIMEType, &mime);
286 CHECK(success);
287
Andreas Huberdacaa732009-12-07 09:56:32 -0800288 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
289 return new AACDecoder(source);
290 }
291
Andreas Hubere13526a2009-10-22 10:43:34 -0700292 Vector<String8> matchingCodecs;
293 findMatchingCodecs(
294 mime, createEncoder, matchComponentName, flags, &matchingCodecs);
295
296 if (matchingCodecs.isEmpty()) {
297 return NULL;
298 }
299
300 sp<OMXCodecObserver> observer = new OMXCodecObserver;
301 IOMX::node_id node = 0;
302 success = false;
303
304 const char *componentName;
305 for (size_t i = 0; i < matchingCodecs.size(); ++i) {
306 componentName = matchingCodecs[i].string();
307
308 LOGV("Attempting to allocate OMX node '%s'", componentName);
309
310 status_t err = omx->allocateNode(componentName, observer, &node);
311 if (err == OK) {
312 LOGV("Successfully allocated OMX node '%s'", componentName);
313
314 success = true;
315 break;
316 }
317 }
318
319 if (!success) {
320 return NULL;
321 }
322
Andreas Huberbe06d262009-08-14 14:37:10 -0700323 sp<OMXCodec> codec = new OMXCodec(
Andreas Hubere13526a2009-10-22 10:43:34 -0700324 omx, node, getComponentQuirks(componentName),
325 createEncoder, mime, componentName,
Andreas Huberbe06d262009-08-14 14:37:10 -0700326 source);
327
Andreas Huber784202e2009-10-15 13:46:54 -0700328 observer->setCodec(codec);
329
Andreas Huberbe06d262009-08-14 14:37:10 -0700330 uint32_t type;
331 const void *data;
332 size_t size;
333 if (meta->findData(kKeyESDS, &type, &data, &size)) {
334 ESDS esds((const char *)data, size);
335 CHECK_EQ(esds.InitCheck(), OK);
336
337 const void *codec_specific_data;
338 size_t codec_specific_data_size;
339 esds.getCodecSpecificInfo(
340 &codec_specific_data, &codec_specific_data_size);
341
342 printf("found codec-specific data of size %d\n",
343 codec_specific_data_size);
344
345 codec->addCodecSpecificData(
346 codec_specific_data, codec_specific_data_size);
347 } else if (meta->findData(kKeyAVCC, &type, &data, &size)) {
348 printf("found avcc of size %d\n", size);
349
Andreas Huberebf66ea2009-08-19 13:32:58 -0700350 // Parse the AVCDecoderConfigurationRecord
351
352 const uint8_t *ptr = (const uint8_t *)data;
353
354 CHECK(size >= 7);
355 CHECK_EQ(ptr[0], 1); // configurationVersion == 1
356 uint8_t profile = ptr[1];
357 uint8_t level = ptr[3];
358
Andreas Huber44e15c42009-11-23 14:39:38 -0800359 // There is decodable content out there that fails the following
360 // assertion, let's be lenient for now...
361 // CHECK((ptr[4] >> 2) == 0x3f); // reserved
Andreas Huberebf66ea2009-08-19 13:32:58 -0700362
363 size_t lengthSize = 1 + (ptr[4] & 3);
364
365 // commented out check below as H264_QVGA_500_NO_AUDIO.3gp
366 // violates it...
367 // CHECK((ptr[5] >> 5) == 7); // reserved
368
369 size_t numSeqParameterSets = ptr[5] & 31;
370
371 ptr += 6;
Andreas Huberbe06d262009-08-14 14:37:10 -0700372 size -= 6;
Andreas Huberebf66ea2009-08-19 13:32:58 -0700373
374 for (size_t i = 0; i < numSeqParameterSets; ++i) {
375 CHECK(size >= 2);
376 size_t length = U16_AT(ptr);
Andreas Huberbe06d262009-08-14 14:37:10 -0700377
378 ptr += 2;
379 size -= 2;
380
Andreas Huberbe06d262009-08-14 14:37:10 -0700381 CHECK(size >= length);
382
383 codec->addCodecSpecificData(ptr, length);
384
385 ptr += length;
386 size -= length;
Andreas Huberebf66ea2009-08-19 13:32:58 -0700387 }
Andreas Huberbe06d262009-08-14 14:37:10 -0700388
Andreas Huberebf66ea2009-08-19 13:32:58 -0700389 CHECK(size >= 1);
390 size_t numPictureParameterSets = *ptr;
391 ++ptr;
392 --size;
Andreas Huberbe06d262009-08-14 14:37:10 -0700393
Andreas Huberebf66ea2009-08-19 13:32:58 -0700394 for (size_t i = 0; i < numPictureParameterSets; ++i) {
395 CHECK(size >= 2);
396 size_t length = U16_AT(ptr);
397
398 ptr += 2;
399 size -= 2;
400
401 CHECK(size >= length);
402
403 codec->addCodecSpecificData(ptr, length);
404
405 ptr += length;
406 size -= length;
407 }
408
Andreas Huber53a76bd2009-10-06 16:20:44 -0700409 LOGV("AVC profile = %d (%s), level = %d",
Andreas Huberebf66ea2009-08-19 13:32:58 -0700410 (int)profile, AVCProfileToString(profile), (int)level / 10);
411
412 if (!strcmp(componentName, "OMX.TI.Video.Decoder")
413 && (profile != kAVCProfileBaseline || level > 39)) {
Andreas Huber784202e2009-10-15 13:46:54 -0700414 // This stream exceeds the decoder's capabilities. The decoder
415 // does not handle this gracefully and would clobber the heap
416 // and wreak havoc instead...
Andreas Huberebf66ea2009-08-19 13:32:58 -0700417
418 LOGE("Profile and/or level exceed the decoder's capabilities.");
419 return NULL;
Andreas Huberbe06d262009-08-14 14:37:10 -0700420 }
421 }
422
Andreas Hubere6c40962009-09-10 14:13:30 -0700423 if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime)) {
Andreas Huber8768f2c2009-12-01 15:26:54 -0800424 codec->setAMRFormat(false /* isWAMR */);
Andreas Huberbe06d262009-08-14 14:37:10 -0700425 }
Andreas Hubere6c40962009-09-10 14:13:30 -0700426 if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) {
Andreas Huber8768f2c2009-12-01 15:26:54 -0800427 codec->setAMRFormat(true /* isWAMR */);
Andreas Huberee606e62009-09-08 10:19:21 -0700428 }
Andreas Hubere6c40962009-09-10 14:13:30 -0700429 if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) {
Andreas Huber43ad6eaf2009-09-01 16:02:43 -0700430 int32_t numChannels, sampleRate;
431 CHECK(meta->findInt32(kKeyChannelCount, &numChannels));
432 CHECK(meta->findInt32(kKeySampleRate, &sampleRate));
433
434 codec->setAACFormat(numChannels, sampleRate);
Andreas Huberbe06d262009-08-14 14:37:10 -0700435 }
436 if (!strncasecmp(mime, "video/", 6)) {
437 int32_t width, height;
438 bool success = meta->findInt32(kKeyWidth, &width);
439 success = success && meta->findInt32(kKeyHeight, &height);
Andreas Huber5c0a9132009-08-20 11:16:40 -0700440 CHECK(success);
Andreas Huberbe06d262009-08-14 14:37:10 -0700441
442 if (createEncoder) {
443 codec->setVideoInputFormat(mime, width, height);
444 } else {
445 codec->setVideoOutputFormat(mime, width, height);
446 }
447 }
Andreas Hubere6c40962009-09-10 14:13:30 -0700448 if (!strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_JPEG)
Andreas Huberbe06d262009-08-14 14:37:10 -0700449 && !strcmp(componentName, "OMX.TI.JPEG.decode")) {
450 OMX_COLOR_FORMATTYPE format =
451 OMX_COLOR_Format32bitARGB8888;
452 // OMX_COLOR_FormatYUV420PackedPlanar;
453 // OMX_COLOR_FormatCbYCrY;
454 // OMX_COLOR_FormatYUV411Planar;
455
456 int32_t width, height;
457 bool success = meta->findInt32(kKeyWidth, &width);
458 success = success && meta->findInt32(kKeyHeight, &height);
Andreas Huber5c0a9132009-08-20 11:16:40 -0700459
460 int32_t compressedSize;
461 success = success && meta->findInt32(
Andreas Huberda050cf22009-09-02 14:01:43 -0700462 kKeyMaxInputSize, &compressedSize);
Andreas Huber5c0a9132009-08-20 11:16:40 -0700463
464 CHECK(success);
465 CHECK(compressedSize > 0);
Andreas Huberbe06d262009-08-14 14:37:10 -0700466
467 codec->setImageOutputFormat(format, width, height);
Andreas Huber5c0a9132009-08-20 11:16:40 -0700468 codec->setJPEGInputFormat(width, height, (OMX_U32)compressedSize);
Andreas Huberbe06d262009-08-14 14:37:10 -0700469 }
470
Andreas Huberda050cf22009-09-02 14:01:43 -0700471 int32_t maxInputSize;
Andreas Huber1bceff92009-11-23 14:03:32 -0800472 if (meta->findInt32(kKeyMaxInputSize, &maxInputSize)) {
Andreas Huberda050cf22009-09-02 14:01:43 -0700473 codec->setMinBufferSize(kPortIndexInput, (OMX_U32)maxInputSize);
474 }
475
476 if (!strcmp(componentName, "OMX.TI.AMR.encode")
477 || !strcmp(componentName, "OMX.TI.WBAMR.encode")) {
478 codec->setMinBufferSize(kPortIndexOutput, 8192); // XXX
479 }
480
Andreas Huberbe06d262009-08-14 14:37:10 -0700481 codec->initOutputFormat(meta);
482
483 return codec;
484}
485
Andreas Huberda050cf22009-09-02 14:01:43 -0700486void OMXCodec::setMinBufferSize(OMX_U32 portIndex, OMX_U32 size) {
487 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -0700488 InitOMXParams(&def);
Andreas Huberda050cf22009-09-02 14:01:43 -0700489 def.nPortIndex = portIndex;
490
Andreas Huber784202e2009-10-15 13:46:54 -0700491 status_t err = mOMX->getParameter(
Andreas Huberda050cf22009-09-02 14:01:43 -0700492 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
493 CHECK_EQ(err, OK);
494
495 if (def.nBufferSize < size) {
496 def.nBufferSize = size;
Andreas Huberda050cf22009-09-02 14:01:43 -0700497 }
498
Andreas Huber784202e2009-10-15 13:46:54 -0700499 err = mOMX->setParameter(
Andreas Huberda050cf22009-09-02 14:01:43 -0700500 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
501 CHECK_EQ(err, OK);
Andreas Huber1bceff92009-11-23 14:03:32 -0800502
503 err = mOMX->getParameter(
504 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
505 CHECK_EQ(err, OK);
506
507 // Make sure the setting actually stuck.
508 CHECK(def.nBufferSize >= size);
Andreas Huberda050cf22009-09-02 14:01:43 -0700509}
510
Andreas Huberbe06d262009-08-14 14:37:10 -0700511status_t OMXCodec::setVideoPortFormatType(
512 OMX_U32 portIndex,
513 OMX_VIDEO_CODINGTYPE compressionFormat,
514 OMX_COLOR_FORMATTYPE colorFormat) {
515 OMX_VIDEO_PARAM_PORTFORMATTYPE format;
Andreas Huber4c483422009-09-02 16:05:36 -0700516 InitOMXParams(&format);
Andreas Huberbe06d262009-08-14 14:37:10 -0700517 format.nPortIndex = portIndex;
518 format.nIndex = 0;
519 bool found = false;
520
521 OMX_U32 index = 0;
522 for (;;) {
523 format.nIndex = index;
Andreas Huber784202e2009-10-15 13:46:54 -0700524 status_t err = mOMX->getParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -0700525 mNode, OMX_IndexParamVideoPortFormat,
526 &format, sizeof(format));
527
528 if (err != OK) {
529 return err;
530 }
531
532 // The following assertion is violated by TI's video decoder.
Andreas Huber5c0a9132009-08-20 11:16:40 -0700533 // CHECK_EQ(format.nIndex, index);
Andreas Huberbe06d262009-08-14 14:37:10 -0700534
535#if 1
Andreas Huber53a76bd2009-10-06 16:20:44 -0700536 CODEC_LOGV("portIndex: %ld, index: %ld, eCompressionFormat=%d eColorFormat=%d",
Andreas Huberbe06d262009-08-14 14:37:10 -0700537 portIndex,
538 index, format.eCompressionFormat, format.eColorFormat);
539#endif
540
541 if (!strcmp("OMX.TI.Video.encoder", mComponentName)) {
542 if (portIndex == kPortIndexInput
543 && colorFormat == format.eColorFormat) {
544 // eCompressionFormat does not seem right.
545 found = true;
546 break;
547 }
548 if (portIndex == kPortIndexOutput
549 && compressionFormat == format.eCompressionFormat) {
550 // eColorFormat does not seem right.
551 found = true;
552 break;
553 }
554 }
555
556 if (format.eCompressionFormat == compressionFormat
557 && format.eColorFormat == colorFormat) {
558 found = true;
559 break;
560 }
561
562 ++index;
563 }
564
565 if (!found) {
566 return UNKNOWN_ERROR;
567 }
568
Andreas Huber53a76bd2009-10-06 16:20:44 -0700569 CODEC_LOGV("found a match.");
Andreas Huber784202e2009-10-15 13:46:54 -0700570 status_t err = mOMX->setParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -0700571 mNode, OMX_IndexParamVideoPortFormat,
572 &format, sizeof(format));
573
574 return err;
575}
576
Andreas Huberb482ce82009-10-29 12:02:48 -0700577static size_t getFrameSize(
578 OMX_COLOR_FORMATTYPE colorFormat, int32_t width, int32_t height) {
579 switch (colorFormat) {
580 case OMX_COLOR_FormatYCbYCr:
581 case OMX_COLOR_FormatCbYCrY:
582 return width * height * 2;
583
584 case OMX_COLOR_FormatYUV420SemiPlanar:
585 return (width * height * 3) / 2;
586
587 default:
588 CHECK(!"Should not be here. Unsupported color format.");
589 break;
590 }
591}
592
Andreas Huberbe06d262009-08-14 14:37:10 -0700593void OMXCodec::setVideoInputFormat(
594 const char *mime, OMX_U32 width, OMX_U32 height) {
Andreas Huber53a76bd2009-10-06 16:20:44 -0700595 CODEC_LOGV("setVideoInputFormat width=%ld, height=%ld", width, height);
Andreas Huberbe06d262009-08-14 14:37:10 -0700596
597 OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused;
Andreas Hubere6c40962009-09-10 14:13:30 -0700598 if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700599 compressionFormat = OMX_VIDEO_CodingAVC;
Andreas Hubere6c40962009-09-10 14:13:30 -0700600 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700601 compressionFormat = OMX_VIDEO_CodingMPEG4;
Andreas Hubere6c40962009-09-10 14:13:30 -0700602 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700603 compressionFormat = OMX_VIDEO_CodingH263;
604 } else {
605 LOGE("Not a supported video mime type: %s", mime);
606 CHECK(!"Should not be here. Not a supported video mime type.");
607 }
608
Andreas Huberea6a38c2009-11-16 15:43:38 -0800609 OMX_COLOR_FORMATTYPE colorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
610 if (!strcasecmp("OMX.TI.Video.encoder", mComponentName)) {
611 colorFormat = OMX_COLOR_FormatYCbYCr;
Andreas Huberbe06d262009-08-14 14:37:10 -0700612 }
613
Andreas Huberb482ce82009-10-29 12:02:48 -0700614 CHECK_EQ(setVideoPortFormatType(
Andreas Huberbe06d262009-08-14 14:37:10 -0700615 kPortIndexInput, OMX_VIDEO_CodingUnused,
Andreas Huberb482ce82009-10-29 12:02:48 -0700616 colorFormat), OK);
Andreas Huberbe06d262009-08-14 14:37:10 -0700617
Andreas Huberb482ce82009-10-29 12:02:48 -0700618 CHECK_EQ(setVideoPortFormatType(
619 kPortIndexOutput, compressionFormat, OMX_COLOR_FormatUnused),
620 OK);
Andreas Huberbe06d262009-08-14 14:37:10 -0700621
622 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -0700623 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -0700624 def.nPortIndex = kPortIndexOutput;
625
Andreas Huber4c483422009-09-02 16:05:36 -0700626 OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
627
Andreas Huber784202e2009-10-15 13:46:54 -0700628 status_t err = mOMX->getParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -0700629 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
630
631 CHECK_EQ(err, OK);
632 CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
633
634 video_def->nFrameWidth = width;
635 video_def->nFrameHeight = height;
636
637 video_def->eCompressionFormat = compressionFormat;
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 = kPortIndexInput;
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
Andreas Huberb482ce82009-10-29 12:02:48 -0700653 def.nBufferSize = getFrameSize(colorFormat, width, height);
Andreas Huber53a76bd2009-10-06 16:20:44 -0700654 CODEC_LOGV("Setting nBufferSize = %ld", def.nBufferSize);
Andreas Huberbe06d262009-08-14 14:37:10 -0700655
656 CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
657
658 video_def->nFrameWidth = width;
659 video_def->nFrameHeight = height;
660 video_def->eCompressionFormat = OMX_VIDEO_CodingUnused;
661 video_def->eColorFormat = colorFormat;
662
Andreas Huberb482ce82009-10-29 12:02:48 -0700663 video_def->xFramerate = 24 << 16; // XXX crucial!
664
Andreas Huber784202e2009-10-15 13:46:54 -0700665 err = mOMX->setParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -0700666 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
667 CHECK_EQ(err, OK);
Andreas Huberb482ce82009-10-29 12:02:48 -0700668
669 switch (compressionFormat) {
670 case OMX_VIDEO_CodingMPEG4:
671 {
672 CHECK_EQ(setupMPEG4EncoderParameters(), OK);
673 break;
674 }
675
676 case OMX_VIDEO_CodingH263:
677 break;
678
Andreas Huberea6a38c2009-11-16 15:43:38 -0800679 case OMX_VIDEO_CodingAVC:
680 {
681 CHECK_EQ(setupAVCEncoderParameters(), OK);
682 break;
683 }
684
Andreas Huberb482ce82009-10-29 12:02:48 -0700685 default:
686 CHECK(!"Support for this compressionFormat to be implemented.");
687 break;
688 }
689}
690
691status_t OMXCodec::setupMPEG4EncoderParameters() {
692 OMX_VIDEO_PARAM_MPEG4TYPE mpeg4type;
693 InitOMXParams(&mpeg4type);
694 mpeg4type.nPortIndex = kPortIndexOutput;
695
696 status_t err = mOMX->getParameter(
697 mNode, OMX_IndexParamVideoMpeg4, &mpeg4type, sizeof(mpeg4type));
698 CHECK_EQ(err, OK);
699
700 mpeg4type.nSliceHeaderSpacing = 0;
701 mpeg4type.bSVH = OMX_FALSE;
702 mpeg4type.bGov = OMX_FALSE;
703
704 mpeg4type.nAllowedPictureTypes =
705 OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP;
706
707 mpeg4type.nPFrames = 23;
708 mpeg4type.nBFrames = 0;
709
710 mpeg4type.nIDCVLCThreshold = 0;
711 mpeg4type.bACPred = OMX_TRUE;
712 mpeg4type.nMaxPacketSize = 256;
713 mpeg4type.nTimeIncRes = 1000;
714 mpeg4type.nHeaderExtension = 0;
715 mpeg4type.bReversibleVLC = OMX_FALSE;
716
717 mpeg4type.eProfile = OMX_VIDEO_MPEG4ProfileCore;
718 mpeg4type.eLevel = OMX_VIDEO_MPEG4Level2;
719
720 err = mOMX->setParameter(
721 mNode, OMX_IndexParamVideoMpeg4, &mpeg4type, sizeof(mpeg4type));
722 CHECK_EQ(err, OK);
723
724 // ----------------
725
726 OMX_VIDEO_PARAM_BITRATETYPE bitrateType;
727 InitOMXParams(&bitrateType);
728 bitrateType.nPortIndex = kPortIndexOutput;
729
730 err = mOMX->getParameter(
731 mNode, OMX_IndexParamVideoBitrate,
732 &bitrateType, sizeof(bitrateType));
733 CHECK_EQ(err, OK);
734
735 bitrateType.eControlRate = OMX_Video_ControlRateVariable;
736 bitrateType.nTargetBitrate = 1000000;
737
738 err = mOMX->setParameter(
739 mNode, OMX_IndexParamVideoBitrate,
740 &bitrateType, sizeof(bitrateType));
741 CHECK_EQ(err, OK);
742
743 // ----------------
744
745 OMX_VIDEO_PARAM_ERRORCORRECTIONTYPE errorCorrectionType;
746 InitOMXParams(&errorCorrectionType);
747 errorCorrectionType.nPortIndex = kPortIndexOutput;
748
749 err = mOMX->getParameter(
750 mNode, OMX_IndexParamVideoErrorCorrection,
751 &errorCorrectionType, sizeof(errorCorrectionType));
752 CHECK_EQ(err, OK);
753
754 errorCorrectionType.bEnableHEC = OMX_FALSE;
755 errorCorrectionType.bEnableResync = OMX_TRUE;
756 errorCorrectionType.nResynchMarkerSpacing = 256;
757 errorCorrectionType.bEnableDataPartitioning = OMX_FALSE;
758 errorCorrectionType.bEnableRVLC = OMX_FALSE;
759
760 err = mOMX->setParameter(
761 mNode, OMX_IndexParamVideoErrorCorrection,
762 &errorCorrectionType, sizeof(errorCorrectionType));
763 CHECK_EQ(err, OK);
764
765 return OK;
Andreas Huberbe06d262009-08-14 14:37:10 -0700766}
767
Andreas Huberea6a38c2009-11-16 15:43:38 -0800768status_t OMXCodec::setupAVCEncoderParameters() {
769 OMX_VIDEO_PARAM_AVCTYPE h264type;
770 InitOMXParams(&h264type);
771 h264type.nPortIndex = kPortIndexOutput;
772
773 status_t err = mOMX->getParameter(
774 mNode, OMX_IndexParamVideoAvc, &h264type, sizeof(h264type));
775 CHECK_EQ(err, OK);
776
777 h264type.nAllowedPictureTypes =
778 OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP;
779
780 h264type.nSliceHeaderSpacing = 0;
781 h264type.nBFrames = 0;
782 h264type.bUseHadamard = OMX_TRUE;
783 h264type.nRefFrames = 1;
784 h264type.nRefIdx10ActiveMinus1 = 0;
785 h264type.nRefIdx11ActiveMinus1 = 0;
786 h264type.bEnableUEP = OMX_FALSE;
787 h264type.bEnableFMO = OMX_FALSE;
788 h264type.bEnableASO = OMX_FALSE;
789 h264type.bEnableRS = OMX_FALSE;
790 h264type.eProfile = OMX_VIDEO_AVCProfileBaseline;
791 h264type.eLevel = OMX_VIDEO_AVCLevel1b;
792 h264type.bFrameMBsOnly = OMX_TRUE;
793 h264type.bMBAFF = OMX_FALSE;
794 h264type.bEntropyCodingCABAC = OMX_FALSE;
795 h264type.bWeightedPPrediction = OMX_FALSE;
796 h264type.bconstIpred = OMX_FALSE;
797 h264type.bDirect8x8Inference = OMX_FALSE;
798 h264type.bDirectSpatialTemporal = OMX_FALSE;
799 h264type.nCabacInitIdc = 0;
800 h264type.eLoopFilterMode = OMX_VIDEO_AVCLoopFilterEnable;
801
802 err = mOMX->setParameter(
803 mNode, OMX_IndexParamVideoAvc, &h264type, sizeof(h264type));
804 CHECK_EQ(err, OK);
805
806 OMX_VIDEO_PARAM_BITRATETYPE bitrateType;
807 InitOMXParams(&bitrateType);
808 bitrateType.nPortIndex = kPortIndexOutput;
809
810 err = mOMX->getParameter(
811 mNode, OMX_IndexParamVideoBitrate,
812 &bitrateType, sizeof(bitrateType));
813 CHECK_EQ(err, OK);
814
815 bitrateType.eControlRate = OMX_Video_ControlRateVariable;
816 bitrateType.nTargetBitrate = 1000000;
817
818 err = mOMX->setParameter(
819 mNode, OMX_IndexParamVideoBitrate,
820 &bitrateType, sizeof(bitrateType));
821 CHECK_EQ(err, OK);
822
823 return OK;
824}
825
Andreas Huberbe06d262009-08-14 14:37:10 -0700826void OMXCodec::setVideoOutputFormat(
827 const char *mime, OMX_U32 width, OMX_U32 height) {
Andreas Huber53a76bd2009-10-06 16:20:44 -0700828 CODEC_LOGV("setVideoOutputFormat width=%ld, height=%ld", width, height);
Andreas Huberbe06d262009-08-14 14:37:10 -0700829
Andreas Huberbe06d262009-08-14 14:37:10 -0700830 OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused;
Andreas Hubere6c40962009-09-10 14:13:30 -0700831 if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700832 compressionFormat = OMX_VIDEO_CodingAVC;
Andreas Hubere6c40962009-09-10 14:13:30 -0700833 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700834 compressionFormat = OMX_VIDEO_CodingMPEG4;
Andreas Hubere6c40962009-09-10 14:13:30 -0700835 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700836 compressionFormat = OMX_VIDEO_CodingH263;
837 } else {
838 LOGE("Not a supported video mime type: %s", mime);
839 CHECK(!"Should not be here. Not a supported video mime type.");
840 }
841
842 setVideoPortFormatType(
843 kPortIndexInput, compressionFormat, OMX_COLOR_FormatUnused);
844
845#if 1
846 {
847 OMX_VIDEO_PARAM_PORTFORMATTYPE format;
Andreas Huber4c483422009-09-02 16:05:36 -0700848 InitOMXParams(&format);
Andreas Huberbe06d262009-08-14 14:37:10 -0700849 format.nPortIndex = kPortIndexOutput;
850 format.nIndex = 0;
851
Andreas Huber784202e2009-10-15 13:46:54 -0700852 status_t err = mOMX->getParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -0700853 mNode, OMX_IndexParamVideoPortFormat,
854 &format, sizeof(format));
855 CHECK_EQ(err, OK);
856 CHECK_EQ(format.eCompressionFormat, OMX_VIDEO_CodingUnused);
857
858 static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
859
860 CHECK(format.eColorFormat == OMX_COLOR_FormatYUV420Planar
861 || format.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar
862 || format.eColorFormat == OMX_COLOR_FormatCbYCrY
863 || format.eColorFormat == OMX_QCOM_COLOR_FormatYVU420SemiPlanar);
864
Andreas Huber784202e2009-10-15 13:46:54 -0700865 err = mOMX->setParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -0700866 mNode, OMX_IndexParamVideoPortFormat,
867 &format, sizeof(format));
868 CHECK_EQ(err, OK);
869 }
870#endif
871
872 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -0700873 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -0700874 def.nPortIndex = kPortIndexInput;
875
Andreas Huber4c483422009-09-02 16:05:36 -0700876 OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
877
Andreas Huber784202e2009-10-15 13:46:54 -0700878 status_t err = mOMX->getParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -0700879 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
880
881 CHECK_EQ(err, OK);
882
883#if 1
884 // XXX Need a (much) better heuristic to compute input buffer sizes.
885 const size_t X = 64 * 1024;
886 if (def.nBufferSize < X) {
887 def.nBufferSize = X;
888 }
889#endif
890
891 CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
892
893 video_def->nFrameWidth = width;
894 video_def->nFrameHeight = height;
895
Andreas Huberb482ce82009-10-29 12:02:48 -0700896 video_def->eCompressionFormat = compressionFormat;
Andreas Huberbe06d262009-08-14 14:37:10 -0700897 video_def->eColorFormat = OMX_COLOR_FormatUnused;
898
Andreas Huber784202e2009-10-15 13:46:54 -0700899 err = mOMX->setParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -0700900 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
901 CHECK_EQ(err, OK);
902
903 ////////////////////////////////////////////////////////////////////////////
904
Andreas Huber4c483422009-09-02 16:05:36 -0700905 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -0700906 def.nPortIndex = kPortIndexOutput;
907
Andreas Huber784202e2009-10-15 13:46:54 -0700908 err = mOMX->getParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -0700909 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
910 CHECK_EQ(err, OK);
911 CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
912
913#if 0
914 def.nBufferSize =
915 (((width + 15) & -16) * ((height + 15) & -16) * 3) / 2; // YUV420
916#endif
917
918 video_def->nFrameWidth = width;
919 video_def->nFrameHeight = height;
920
Andreas Huber784202e2009-10-15 13:46:54 -0700921 err = mOMX->setParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -0700922 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
923 CHECK_EQ(err, OK);
924}
925
Andreas Huberbe06d262009-08-14 14:37:10 -0700926OMXCodec::OMXCodec(
927 const sp<IOMX> &omx, IOMX::node_id node, uint32_t quirks,
Andreas Huberebf66ea2009-08-19 13:32:58 -0700928 bool isEncoder,
Andreas Huberbe06d262009-08-14 14:37:10 -0700929 const char *mime,
930 const char *componentName,
931 const sp<MediaSource> &source)
932 : mOMX(omx),
933 mNode(node),
934 mQuirks(quirks),
935 mIsEncoder(isEncoder),
936 mMIME(strdup(mime)),
937 mComponentName(strdup(componentName)),
938 mSource(source),
939 mCodecSpecificDataIndex(0),
Andreas Huberbe06d262009-08-14 14:37:10 -0700940 mState(LOADED),
Andreas Huber42978e52009-08-27 10:08:39 -0700941 mInitialBufferSubmit(true),
Andreas Huberbe06d262009-08-14 14:37:10 -0700942 mSignalledEOS(false),
943 mNoMoreOutputData(false),
Andreas Hubercfd55572009-10-09 14:11:28 -0700944 mOutputPortSettingsHaveChanged(false),
Andreas Huberbe06d262009-08-14 14:37:10 -0700945 mSeekTimeUs(-1) {
946 mPortStatus[kPortIndexInput] = ENABLED;
947 mPortStatus[kPortIndexOutput] = ENABLED;
948
Andreas Huber4c483422009-09-02 16:05:36 -0700949 setComponentRole();
950}
951
Andreas Hubere6c40962009-09-10 14:13:30 -0700952// static
953void OMXCodec::setComponentRole(
954 const sp<IOMX> &omx, IOMX::node_id node, bool isEncoder,
955 const char *mime) {
Andreas Huber4c483422009-09-02 16:05:36 -0700956 struct MimeToRole {
957 const char *mime;
958 const char *decoderRole;
959 const char *encoderRole;
960 };
961
962 static const MimeToRole kMimeToRole[] = {
Andreas Hubere6c40962009-09-10 14:13:30 -0700963 { MEDIA_MIMETYPE_AUDIO_MPEG,
964 "audio_decoder.mp3", "audio_encoder.mp3" },
965 { MEDIA_MIMETYPE_AUDIO_AMR_NB,
966 "audio_decoder.amrnb", "audio_encoder.amrnb" },
967 { MEDIA_MIMETYPE_AUDIO_AMR_WB,
968 "audio_decoder.amrwb", "audio_encoder.amrwb" },
969 { MEDIA_MIMETYPE_AUDIO_AAC,
970 "audio_decoder.aac", "audio_encoder.aac" },
971 { MEDIA_MIMETYPE_VIDEO_AVC,
972 "video_decoder.avc", "video_encoder.avc" },
973 { MEDIA_MIMETYPE_VIDEO_MPEG4,
974 "video_decoder.mpeg4", "video_encoder.mpeg4" },
975 { MEDIA_MIMETYPE_VIDEO_H263,
976 "video_decoder.h263", "video_encoder.h263" },
Andreas Huber4c483422009-09-02 16:05:36 -0700977 };
978
979 static const size_t kNumMimeToRole =
980 sizeof(kMimeToRole) / sizeof(kMimeToRole[0]);
981
982 size_t i;
983 for (i = 0; i < kNumMimeToRole; ++i) {
Andreas Hubere6c40962009-09-10 14:13:30 -0700984 if (!strcasecmp(mime, kMimeToRole[i].mime)) {
Andreas Huber4c483422009-09-02 16:05:36 -0700985 break;
986 }
987 }
988
989 if (i == kNumMimeToRole) {
990 return;
991 }
992
993 const char *role =
Andreas Hubere6c40962009-09-10 14:13:30 -0700994 isEncoder ? kMimeToRole[i].encoderRole
995 : kMimeToRole[i].decoderRole;
Andreas Huber4c483422009-09-02 16:05:36 -0700996
997 if (role != NULL) {
Andreas Huber4c483422009-09-02 16:05:36 -0700998 OMX_PARAM_COMPONENTROLETYPE roleParams;
999 InitOMXParams(&roleParams);
1000
1001 strncpy((char *)roleParams.cRole,
1002 role, OMX_MAX_STRINGNAME_SIZE - 1);
1003
1004 roleParams.cRole[OMX_MAX_STRINGNAME_SIZE - 1] = '\0';
1005
Andreas Huber784202e2009-10-15 13:46:54 -07001006 status_t err = omx->setParameter(
Andreas Hubere6c40962009-09-10 14:13:30 -07001007 node, OMX_IndexParamStandardComponentRole,
Andreas Huber4c483422009-09-02 16:05:36 -07001008 &roleParams, sizeof(roleParams));
1009
1010 if (err != OK) {
1011 LOGW("Failed to set standard component role '%s'.", role);
1012 }
1013 }
Andreas Huberbe06d262009-08-14 14:37:10 -07001014}
1015
Andreas Hubere6c40962009-09-10 14:13:30 -07001016void OMXCodec::setComponentRole() {
1017 setComponentRole(mOMX, mNode, mIsEncoder, mMIME);
1018}
1019
Andreas Huberbe06d262009-08-14 14:37:10 -07001020OMXCodec::~OMXCodec() {
Andreas Huber4f5e6022009-08-19 09:29:34 -07001021 CHECK(mState == LOADED || mState == ERROR);
Andreas Huberbe06d262009-08-14 14:37:10 -07001022
Andreas Huber784202e2009-10-15 13:46:54 -07001023 status_t err = mOMX->freeNode(mNode);
Andreas Huberbe06d262009-08-14 14:37:10 -07001024 CHECK_EQ(err, OK);
1025
1026 mNode = NULL;
1027 setState(DEAD);
1028
1029 clearCodecSpecificData();
1030
1031 free(mComponentName);
1032 mComponentName = NULL;
Andreas Huberebf66ea2009-08-19 13:32:58 -07001033
Andreas Huberbe06d262009-08-14 14:37:10 -07001034 free(mMIME);
1035 mMIME = NULL;
1036}
1037
1038status_t OMXCodec::init() {
Andreas Huber42978e52009-08-27 10:08:39 -07001039 // mLock is held.
Andreas Huberbe06d262009-08-14 14:37:10 -07001040
1041 CHECK_EQ(mState, LOADED);
1042
1043 status_t err;
1044 if (!(mQuirks & kRequiresLoadedToIdleAfterAllocation)) {
Andreas Huber784202e2009-10-15 13:46:54 -07001045 err = mOMX->sendCommand(mNode, OMX_CommandStateSet, OMX_StateIdle);
Andreas Huberbe06d262009-08-14 14:37:10 -07001046 CHECK_EQ(err, OK);
Andreas Huberbe06d262009-08-14 14:37:10 -07001047 setState(LOADED_TO_IDLE);
1048 }
1049
1050 err = allocateBuffers();
1051 CHECK_EQ(err, OK);
1052
1053 if (mQuirks & kRequiresLoadedToIdleAfterAllocation) {
Andreas Huber784202e2009-10-15 13:46:54 -07001054 err = mOMX->sendCommand(mNode, OMX_CommandStateSet, OMX_StateIdle);
Andreas Huberbe06d262009-08-14 14:37:10 -07001055 CHECK_EQ(err, OK);
1056
1057 setState(LOADED_TO_IDLE);
1058 }
1059
1060 while (mState != EXECUTING && mState != ERROR) {
1061 mAsyncCompletion.wait(mLock);
1062 }
1063
1064 return mState == ERROR ? UNKNOWN_ERROR : OK;
1065}
1066
1067// static
1068bool OMXCodec::isIntermediateState(State state) {
1069 return state == LOADED_TO_IDLE
1070 || state == IDLE_TO_EXECUTING
1071 || state == EXECUTING_TO_IDLE
1072 || state == IDLE_TO_LOADED
1073 || state == RECONFIGURING;
1074}
1075
1076status_t OMXCodec::allocateBuffers() {
1077 status_t err = allocateBuffersOnPort(kPortIndexInput);
1078
1079 if (err != OK) {
1080 return err;
1081 }
1082
1083 return allocateBuffersOnPort(kPortIndexOutput);
1084}
1085
1086status_t OMXCodec::allocateBuffersOnPort(OMX_U32 portIndex) {
1087 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -07001088 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -07001089 def.nPortIndex = portIndex;
1090
Andreas Huber784202e2009-10-15 13:46:54 -07001091 status_t err = mOMX->getParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -07001092 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
1093
1094 if (err != OK) {
1095 return err;
1096 }
1097
Andreas Huber5c0a9132009-08-20 11:16:40 -07001098 size_t totalSize = def.nBufferCountActual * def.nBufferSize;
1099 mDealer[portIndex] = new MemoryDealer(totalSize);
1100
Andreas Huberbe06d262009-08-14 14:37:10 -07001101 for (OMX_U32 i = 0; i < def.nBufferCountActual; ++i) {
Andreas Huber5c0a9132009-08-20 11:16:40 -07001102 sp<IMemory> mem = mDealer[portIndex]->allocate(def.nBufferSize);
Andreas Huberbe06d262009-08-14 14:37:10 -07001103 CHECK(mem.get() != NULL);
1104
1105 IOMX::buffer_id buffer;
1106 if (portIndex == kPortIndexInput
1107 && (mQuirks & kRequiresAllocateBufferOnInputPorts)) {
Andreas Huber784202e2009-10-15 13:46:54 -07001108 err = mOMX->allocateBufferWithBackup(
Andreas Huberbe06d262009-08-14 14:37:10 -07001109 mNode, portIndex, mem, &buffer);
Andreas Huber446f44f2009-08-25 17:23:44 -07001110 } else if (portIndex == kPortIndexOutput
1111 && (mQuirks & kRequiresAllocateBufferOnOutputPorts)) {
Andreas Huber784202e2009-10-15 13:46:54 -07001112 err = mOMX->allocateBufferWithBackup(
Andreas Huber2dc64d82009-09-11 12:58:53 -07001113 mNode, portIndex, mem, &buffer);
Andreas Huberbe06d262009-08-14 14:37:10 -07001114 } else {
Andreas Huber784202e2009-10-15 13:46:54 -07001115 err = mOMX->useBuffer(mNode, portIndex, mem, &buffer);
Andreas Huberbe06d262009-08-14 14:37:10 -07001116 }
1117
1118 if (err != OK) {
1119 LOGE("allocate_buffer_with_backup failed");
1120 return err;
1121 }
1122
1123 BufferInfo info;
1124 info.mBuffer = buffer;
1125 info.mOwnedByComponent = false;
1126 info.mMem = mem;
1127 info.mMediaBuffer = NULL;
1128
1129 if (portIndex == kPortIndexOutput) {
1130 info.mMediaBuffer = new MediaBuffer(mem->pointer(), mem->size());
1131 info.mMediaBuffer->setObserver(this);
1132 }
1133
1134 mPortBuffers[portIndex].push(info);
1135
Andreas Huber4c483422009-09-02 16:05:36 -07001136 CODEC_LOGV("allocated buffer %p on %s port", buffer,
Andreas Huberbe06d262009-08-14 14:37:10 -07001137 portIndex == kPortIndexInput ? "input" : "output");
1138 }
1139
1140 dumpPortStatus(portIndex);
1141
1142 return OK;
1143}
1144
1145void OMXCodec::on_message(const omx_message &msg) {
1146 Mutex::Autolock autoLock(mLock);
1147
1148 switch (msg.type) {
1149 case omx_message::EVENT:
1150 {
1151 onEvent(
1152 msg.u.event_data.event, msg.u.event_data.data1,
1153 msg.u.event_data.data2);
1154
1155 break;
1156 }
1157
1158 case omx_message::EMPTY_BUFFER_DONE:
1159 {
1160 IOMX::buffer_id buffer = msg.u.extended_buffer_data.buffer;
1161
Andreas Huber4c483422009-09-02 16:05:36 -07001162 CODEC_LOGV("EMPTY_BUFFER_DONE(buffer: %p)", buffer);
Andreas Huberbe06d262009-08-14 14:37:10 -07001163
1164 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
1165 size_t i = 0;
1166 while (i < buffers->size() && (*buffers)[i].mBuffer != buffer) {
1167 ++i;
1168 }
1169
1170 CHECK(i < buffers->size());
1171 if (!(*buffers)[i].mOwnedByComponent) {
1172 LOGW("We already own input buffer %p, yet received "
1173 "an EMPTY_BUFFER_DONE.", buffer);
1174 }
1175
1176 buffers->editItemAt(i).mOwnedByComponent = false;
1177
1178 if (mPortStatus[kPortIndexInput] == DISABLING) {
Andreas Huber4c483422009-09-02 16:05:36 -07001179 CODEC_LOGV("Port is disabled, freeing buffer %p", buffer);
Andreas Huberbe06d262009-08-14 14:37:10 -07001180
1181 status_t err =
Andreas Huber784202e2009-10-15 13:46:54 -07001182 mOMX->freeBuffer(mNode, kPortIndexInput, buffer);
Andreas Huberbe06d262009-08-14 14:37:10 -07001183 CHECK_EQ(err, OK);
1184
1185 buffers->removeAt(i);
1186 } else if (mPortStatus[kPortIndexInput] != SHUTTING_DOWN) {
1187 CHECK_EQ(mPortStatus[kPortIndexInput], ENABLED);
1188 drainInputBuffer(&buffers->editItemAt(i));
1189 }
1190
1191 break;
1192 }
1193
1194 case omx_message::FILL_BUFFER_DONE:
1195 {
1196 IOMX::buffer_id buffer = msg.u.extended_buffer_data.buffer;
1197 OMX_U32 flags = msg.u.extended_buffer_data.flags;
1198
Andreas Huber4c483422009-09-02 16:05:36 -07001199 CODEC_LOGV("FILL_BUFFER_DONE(buffer: %p, size: %ld, flags: 0x%08lx)",
Andreas Huberbe06d262009-08-14 14:37:10 -07001200 buffer,
1201 msg.u.extended_buffer_data.range_length,
1202 flags);
1203
Andreas Huber4c483422009-09-02 16:05:36 -07001204 CODEC_LOGV("FILL_BUFFER_DONE(timestamp: %lld us (%.2f secs))",
Andreas Huberbe06d262009-08-14 14:37:10 -07001205 msg.u.extended_buffer_data.timestamp,
1206 msg.u.extended_buffer_data.timestamp / 1E6);
1207
1208 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
1209 size_t i = 0;
1210 while (i < buffers->size() && (*buffers)[i].mBuffer != buffer) {
1211 ++i;
1212 }
1213
1214 CHECK(i < buffers->size());
1215 BufferInfo *info = &buffers->editItemAt(i);
1216
1217 if (!info->mOwnedByComponent) {
1218 LOGW("We already own output buffer %p, yet received "
1219 "a FILL_BUFFER_DONE.", buffer);
1220 }
1221
1222 info->mOwnedByComponent = false;
1223
1224 if (mPortStatus[kPortIndexOutput] == DISABLING) {
Andreas Huber4c483422009-09-02 16:05:36 -07001225 CODEC_LOGV("Port is disabled, freeing buffer %p", buffer);
Andreas Huberbe06d262009-08-14 14:37:10 -07001226
1227 status_t err =
Andreas Huber784202e2009-10-15 13:46:54 -07001228 mOMX->freeBuffer(mNode, kPortIndexOutput, buffer);
Andreas Huberbe06d262009-08-14 14:37:10 -07001229 CHECK_EQ(err, OK);
1230
1231 buffers->removeAt(i);
Andreas Huberd7795892009-08-26 10:33:47 -07001232 } else if (mPortStatus[kPortIndexOutput] == ENABLED
1233 && (flags & OMX_BUFFERFLAG_EOS)) {
Andreas Huber4c483422009-09-02 16:05:36 -07001234 CODEC_LOGV("No more output data.");
Andreas Huberbe06d262009-08-14 14:37:10 -07001235 mNoMoreOutputData = true;
1236 mBufferFilled.signal();
1237 } else if (mPortStatus[kPortIndexOutput] != SHUTTING_DOWN) {
1238 CHECK_EQ(mPortStatus[kPortIndexOutput], ENABLED);
Andreas Huberebf66ea2009-08-19 13:32:58 -07001239
Andreas Huberbe06d262009-08-14 14:37:10 -07001240 MediaBuffer *buffer = info->mMediaBuffer;
1241
1242 buffer->set_range(
1243 msg.u.extended_buffer_data.range_offset,
1244 msg.u.extended_buffer_data.range_length);
1245
1246 buffer->meta_data()->clear();
1247
Andreas Huberfa8de752009-10-08 10:07:49 -07001248 buffer->meta_data()->setInt64(
1249 kKeyTime, msg.u.extended_buffer_data.timestamp);
Andreas Huberbe06d262009-08-14 14:37:10 -07001250
1251 if (msg.u.extended_buffer_data.flags & OMX_BUFFERFLAG_SYNCFRAME) {
1252 buffer->meta_data()->setInt32(kKeyIsSyncFrame, true);
1253 }
Andreas Huberea6a38c2009-11-16 15:43:38 -08001254 if (msg.u.extended_buffer_data.flags & OMX_BUFFERFLAG_CODECCONFIG) {
1255 buffer->meta_data()->setInt32(kKeyIsCodecConfig, true);
1256 }
Andreas Huberbe06d262009-08-14 14:37:10 -07001257
1258 buffer->meta_data()->setPointer(
1259 kKeyPlatformPrivate,
1260 msg.u.extended_buffer_data.platform_private);
1261
1262 buffer->meta_data()->setPointer(
1263 kKeyBufferID,
1264 msg.u.extended_buffer_data.buffer);
1265
1266 mFilledBuffers.push_back(i);
1267 mBufferFilled.signal();
1268 }
1269
1270 break;
1271 }
1272
1273 default:
1274 {
1275 CHECK(!"should not be here.");
1276 break;
1277 }
1278 }
1279}
1280
1281void OMXCodec::onEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) {
1282 switch (event) {
1283 case OMX_EventCmdComplete:
1284 {
1285 onCmdComplete((OMX_COMMANDTYPE)data1, data2);
1286 break;
1287 }
1288
1289 case OMX_EventError:
1290 {
1291 LOGE("ERROR(%ld, %ld)", data1, data2);
1292
1293 setState(ERROR);
1294 break;
1295 }
1296
1297 case OMX_EventPortSettingsChanged:
1298 {
1299 onPortSettingsChanged(data1);
1300 break;
1301 }
1302
1303 case OMX_EventBufferFlag:
1304 {
Andreas Huber4c483422009-09-02 16:05:36 -07001305 CODEC_LOGV("EVENT_BUFFER_FLAG(%ld)", data1);
Andreas Huberbe06d262009-08-14 14:37:10 -07001306
1307 if (data1 == kPortIndexOutput) {
1308 mNoMoreOutputData = true;
1309 }
1310 break;
1311 }
1312
1313 default:
1314 {
Andreas Huber4c483422009-09-02 16:05:36 -07001315 CODEC_LOGV("EVENT(%d, %ld, %ld)", event, data1, data2);
Andreas Huberbe06d262009-08-14 14:37:10 -07001316 break;
1317 }
1318 }
1319}
1320
Andreas Huberb1678602009-10-19 13:06:40 -07001321// Has the format changed in any way that the client would have to be aware of?
1322static bool formatHasNotablyChanged(
1323 const sp<MetaData> &from, const sp<MetaData> &to) {
1324 if (from.get() == NULL && to.get() == NULL) {
1325 return false;
1326 }
1327
Andreas Huberf68c1682009-10-21 14:01:30 -07001328 if ((from.get() == NULL && to.get() != NULL)
1329 || (from.get() != NULL && to.get() == NULL)) {
Andreas Huberb1678602009-10-19 13:06:40 -07001330 return true;
1331 }
1332
1333 const char *mime_from, *mime_to;
1334 CHECK(from->findCString(kKeyMIMEType, &mime_from));
1335 CHECK(to->findCString(kKeyMIMEType, &mime_to));
1336
1337 if (strcasecmp(mime_from, mime_to)) {
1338 return true;
1339 }
1340
1341 if (!strcasecmp(mime_from, MEDIA_MIMETYPE_VIDEO_RAW)) {
1342 int32_t colorFormat_from, colorFormat_to;
1343 CHECK(from->findInt32(kKeyColorFormat, &colorFormat_from));
1344 CHECK(to->findInt32(kKeyColorFormat, &colorFormat_to));
1345
1346 if (colorFormat_from != colorFormat_to) {
1347 return true;
1348 }
1349
1350 int32_t width_from, width_to;
1351 CHECK(from->findInt32(kKeyWidth, &width_from));
1352 CHECK(to->findInt32(kKeyWidth, &width_to));
1353
1354 if (width_from != width_to) {
1355 return true;
1356 }
1357
1358 int32_t height_from, height_to;
1359 CHECK(from->findInt32(kKeyHeight, &height_from));
1360 CHECK(to->findInt32(kKeyHeight, &height_to));
1361
1362 if (height_from != height_to) {
1363 return true;
1364 }
1365 } else if (!strcasecmp(mime_from, MEDIA_MIMETYPE_AUDIO_RAW)) {
1366 int32_t numChannels_from, numChannels_to;
1367 CHECK(from->findInt32(kKeyChannelCount, &numChannels_from));
1368 CHECK(to->findInt32(kKeyChannelCount, &numChannels_to));
1369
1370 if (numChannels_from != numChannels_to) {
1371 return true;
1372 }
1373
1374 int32_t sampleRate_from, sampleRate_to;
1375 CHECK(from->findInt32(kKeySampleRate, &sampleRate_from));
1376 CHECK(to->findInt32(kKeySampleRate, &sampleRate_to));
1377
1378 if (sampleRate_from != sampleRate_to) {
1379 return true;
1380 }
1381 }
1382
1383 return false;
1384}
1385
Andreas Huberbe06d262009-08-14 14:37:10 -07001386void OMXCodec::onCmdComplete(OMX_COMMANDTYPE cmd, OMX_U32 data) {
1387 switch (cmd) {
1388 case OMX_CommandStateSet:
1389 {
1390 onStateChange((OMX_STATETYPE)data);
1391 break;
1392 }
1393
1394 case OMX_CommandPortDisable:
1395 {
1396 OMX_U32 portIndex = data;
Andreas Huber4c483422009-09-02 16:05:36 -07001397 CODEC_LOGV("PORT_DISABLED(%ld)", portIndex);
Andreas Huberbe06d262009-08-14 14:37:10 -07001398
1399 CHECK(mState == EXECUTING || mState == RECONFIGURING);
1400 CHECK_EQ(mPortStatus[portIndex], DISABLING);
1401 CHECK_EQ(mPortBuffers[portIndex].size(), 0);
1402
1403 mPortStatus[portIndex] = DISABLED;
1404
1405 if (mState == RECONFIGURING) {
1406 CHECK_EQ(portIndex, kPortIndexOutput);
1407
Andreas Huberb1678602009-10-19 13:06:40 -07001408 sp<MetaData> oldOutputFormat = mOutputFormat;
Andreas Hubercfd55572009-10-09 14:11:28 -07001409 initOutputFormat(mSource->getFormat());
Andreas Huberb1678602009-10-19 13:06:40 -07001410
1411 // Don't notify clients if the output port settings change
1412 // wasn't of importance to them, i.e. it may be that just the
1413 // number of buffers has changed and nothing else.
1414 mOutputPortSettingsHaveChanged =
1415 formatHasNotablyChanged(oldOutputFormat, mOutputFormat);
Andreas Hubercfd55572009-10-09 14:11:28 -07001416
Andreas Huberbe06d262009-08-14 14:37:10 -07001417 enablePortAsync(portIndex);
1418
1419 status_t err = allocateBuffersOnPort(portIndex);
1420 CHECK_EQ(err, OK);
1421 }
1422 break;
1423 }
1424
1425 case OMX_CommandPortEnable:
1426 {
1427 OMX_U32 portIndex = data;
Andreas Huber4c483422009-09-02 16:05:36 -07001428 CODEC_LOGV("PORT_ENABLED(%ld)", portIndex);
Andreas Huberbe06d262009-08-14 14:37:10 -07001429
1430 CHECK(mState == EXECUTING || mState == RECONFIGURING);
1431 CHECK_EQ(mPortStatus[portIndex], ENABLING);
1432
1433 mPortStatus[portIndex] = ENABLED;
1434
1435 if (mState == RECONFIGURING) {
1436 CHECK_EQ(portIndex, kPortIndexOutput);
1437
1438 setState(EXECUTING);
1439
1440 fillOutputBuffers();
1441 }
1442 break;
1443 }
1444
1445 case OMX_CommandFlush:
1446 {
1447 OMX_U32 portIndex = data;
1448
Andreas Huber4c483422009-09-02 16:05:36 -07001449 CODEC_LOGV("FLUSH_DONE(%ld)", portIndex);
Andreas Huberbe06d262009-08-14 14:37:10 -07001450
1451 CHECK_EQ(mPortStatus[portIndex], SHUTTING_DOWN);
1452 mPortStatus[portIndex] = ENABLED;
1453
1454 CHECK_EQ(countBuffersWeOwn(mPortBuffers[portIndex]),
1455 mPortBuffers[portIndex].size());
1456
1457 if (mState == RECONFIGURING) {
1458 CHECK_EQ(portIndex, kPortIndexOutput);
1459
1460 disablePortAsync(portIndex);
Andreas Huber127fcdc2009-08-26 16:27:02 -07001461 } else if (mState == EXECUTING_TO_IDLE) {
1462 if (mPortStatus[kPortIndexInput] == ENABLED
1463 && mPortStatus[kPortIndexOutput] == ENABLED) {
Andreas Huber4c483422009-09-02 16:05:36 -07001464 CODEC_LOGV("Finished flushing both ports, now completing "
Andreas Huber127fcdc2009-08-26 16:27:02 -07001465 "transition from EXECUTING to IDLE.");
1466
1467 mPortStatus[kPortIndexInput] = SHUTTING_DOWN;
1468 mPortStatus[kPortIndexOutput] = SHUTTING_DOWN;
1469
1470 status_t err =
Andreas Huber784202e2009-10-15 13:46:54 -07001471 mOMX->sendCommand(mNode, OMX_CommandStateSet, OMX_StateIdle);
Andreas Huber127fcdc2009-08-26 16:27:02 -07001472 CHECK_EQ(err, OK);
1473 }
Andreas Huberbe06d262009-08-14 14:37:10 -07001474 } else {
1475 // We're flushing both ports in preparation for seeking.
1476
1477 if (mPortStatus[kPortIndexInput] == ENABLED
1478 && mPortStatus[kPortIndexOutput] == ENABLED) {
Andreas Huber4c483422009-09-02 16:05:36 -07001479 CODEC_LOGV("Finished flushing both ports, now continuing from"
Andreas Huberbe06d262009-08-14 14:37:10 -07001480 " seek-time.");
1481
Andreas Huber1a77b68e2009-09-17 11:16:52 -07001482 // Clear this flag in case the decoder sent us either
1483 // the EVENT_BUFFER_FLAG(1) or an output buffer with
1484 // the EOS flag set _while_ flushing. Since we're going
1485 // to submit "fresh" input data now, this flag no longer
1486 // applies to our future.
1487 mNoMoreOutputData = false;
1488
Andreas Huberbe06d262009-08-14 14:37:10 -07001489 drainInputBuffers();
1490 fillOutputBuffers();
1491 }
1492 }
1493
1494 break;
1495 }
1496
1497 default:
1498 {
Andreas Huber4c483422009-09-02 16:05:36 -07001499 CODEC_LOGV("CMD_COMPLETE(%d, %ld)", cmd, data);
Andreas Huberbe06d262009-08-14 14:37:10 -07001500 break;
1501 }
1502 }
1503}
1504
1505void OMXCodec::onStateChange(OMX_STATETYPE newState) {
1506 switch (newState) {
1507 case OMX_StateIdle:
1508 {
Andreas Huber4c483422009-09-02 16:05:36 -07001509 CODEC_LOGV("Now Idle.");
Andreas Huberbe06d262009-08-14 14:37:10 -07001510 if (mState == LOADED_TO_IDLE) {
Andreas Huber784202e2009-10-15 13:46:54 -07001511 status_t err = mOMX->sendCommand(
Andreas Huberbe06d262009-08-14 14:37:10 -07001512 mNode, OMX_CommandStateSet, OMX_StateExecuting);
1513
1514 CHECK_EQ(err, OK);
1515
1516 setState(IDLE_TO_EXECUTING);
1517 } else {
1518 CHECK_EQ(mState, EXECUTING_TO_IDLE);
1519
1520 CHECK_EQ(
1521 countBuffersWeOwn(mPortBuffers[kPortIndexInput]),
1522 mPortBuffers[kPortIndexInput].size());
1523
1524 CHECK_EQ(
1525 countBuffersWeOwn(mPortBuffers[kPortIndexOutput]),
1526 mPortBuffers[kPortIndexOutput].size());
1527
Andreas Huber784202e2009-10-15 13:46:54 -07001528 status_t err = mOMX->sendCommand(
Andreas Huberbe06d262009-08-14 14:37:10 -07001529 mNode, OMX_CommandStateSet, OMX_StateLoaded);
1530
1531 CHECK_EQ(err, OK);
1532
1533 err = freeBuffersOnPort(kPortIndexInput);
1534 CHECK_EQ(err, OK);
1535
1536 err = freeBuffersOnPort(kPortIndexOutput);
1537 CHECK_EQ(err, OK);
1538
1539 mPortStatus[kPortIndexInput] = ENABLED;
1540 mPortStatus[kPortIndexOutput] = ENABLED;
1541
1542 setState(IDLE_TO_LOADED);
1543 }
1544 break;
1545 }
1546
1547 case OMX_StateExecuting:
1548 {
1549 CHECK_EQ(mState, IDLE_TO_EXECUTING);
1550
Andreas Huber4c483422009-09-02 16:05:36 -07001551 CODEC_LOGV("Now Executing.");
Andreas Huberbe06d262009-08-14 14:37:10 -07001552
1553 setState(EXECUTING);
1554
Andreas Huber42978e52009-08-27 10:08:39 -07001555 // Buffers will be submitted to the component in the first
1556 // call to OMXCodec::read as mInitialBufferSubmit is true at
1557 // this point. This ensures that this on_message call returns,
1558 // releases the lock and ::init can notice the state change and
1559 // itself return.
Andreas Huberbe06d262009-08-14 14:37:10 -07001560 break;
1561 }
1562
1563 case OMX_StateLoaded:
1564 {
1565 CHECK_EQ(mState, IDLE_TO_LOADED);
1566
Andreas Huber4c483422009-09-02 16:05:36 -07001567 CODEC_LOGV("Now Loaded.");
Andreas Huberbe06d262009-08-14 14:37:10 -07001568
1569 setState(LOADED);
1570 break;
1571 }
1572
1573 default:
1574 {
1575 CHECK(!"should not be here.");
1576 break;
1577 }
1578 }
1579}
1580
1581// static
1582size_t OMXCodec::countBuffersWeOwn(const Vector<BufferInfo> &buffers) {
1583 size_t n = 0;
1584 for (size_t i = 0; i < buffers.size(); ++i) {
1585 if (!buffers[i].mOwnedByComponent) {
1586 ++n;
1587 }
1588 }
1589
1590 return n;
1591}
1592
1593status_t OMXCodec::freeBuffersOnPort(
1594 OMX_U32 portIndex, bool onlyThoseWeOwn) {
1595 Vector<BufferInfo> *buffers = &mPortBuffers[portIndex];
1596
1597 status_t stickyErr = OK;
1598
1599 for (size_t i = buffers->size(); i-- > 0;) {
1600 BufferInfo *info = &buffers->editItemAt(i);
1601
1602 if (onlyThoseWeOwn && info->mOwnedByComponent) {
1603 continue;
1604 }
1605
1606 CHECK_EQ(info->mOwnedByComponent, false);
1607
Andreas Huber92022852009-09-14 15:24:14 -07001608 CODEC_LOGV("freeing buffer %p on port %ld", info->mBuffer, portIndex);
1609
Andreas Huberbe06d262009-08-14 14:37:10 -07001610 status_t err =
Andreas Huber784202e2009-10-15 13:46:54 -07001611 mOMX->freeBuffer(mNode, portIndex, info->mBuffer);
Andreas Huberbe06d262009-08-14 14:37:10 -07001612
1613 if (err != OK) {
1614 stickyErr = err;
1615 }
1616
1617 if (info->mMediaBuffer != NULL) {
1618 info->mMediaBuffer->setObserver(NULL);
1619
1620 // Make sure nobody but us owns this buffer at this point.
1621 CHECK_EQ(info->mMediaBuffer->refcount(), 0);
1622
1623 info->mMediaBuffer->release();
1624 }
1625
1626 buffers->removeAt(i);
1627 }
1628
1629 CHECK(onlyThoseWeOwn || buffers->isEmpty());
1630
1631 return stickyErr;
1632}
1633
1634void OMXCodec::onPortSettingsChanged(OMX_U32 portIndex) {
Andreas Huber4c483422009-09-02 16:05:36 -07001635 CODEC_LOGV("PORT_SETTINGS_CHANGED(%ld)", portIndex);
Andreas Huberbe06d262009-08-14 14:37:10 -07001636
1637 CHECK_EQ(mState, EXECUTING);
1638 CHECK_EQ(portIndex, kPortIndexOutput);
1639 setState(RECONFIGURING);
1640
1641 if (mQuirks & kNeedsFlushBeforeDisable) {
Andreas Huber404cc412009-08-25 14:26:05 -07001642 if (!flushPortAsync(portIndex)) {
1643 onCmdComplete(OMX_CommandFlush, portIndex);
1644 }
Andreas Huberbe06d262009-08-14 14:37:10 -07001645 } else {
1646 disablePortAsync(portIndex);
1647 }
1648}
1649
Andreas Huber404cc412009-08-25 14:26:05 -07001650bool OMXCodec::flushPortAsync(OMX_U32 portIndex) {
Andreas Huber127fcdc2009-08-26 16:27:02 -07001651 CHECK(mState == EXECUTING || mState == RECONFIGURING
1652 || mState == EXECUTING_TO_IDLE);
Andreas Huberbe06d262009-08-14 14:37:10 -07001653
Andreas Huber4c483422009-09-02 16:05:36 -07001654 CODEC_LOGV("flushPortAsync(%ld): we own %d out of %d buffers already.",
Andreas Huber404cc412009-08-25 14:26:05 -07001655 portIndex, countBuffersWeOwn(mPortBuffers[portIndex]),
1656 mPortBuffers[portIndex].size());
1657
Andreas Huberbe06d262009-08-14 14:37:10 -07001658 CHECK_EQ(mPortStatus[portIndex], ENABLED);
1659 mPortStatus[portIndex] = SHUTTING_DOWN;
1660
Andreas Huber404cc412009-08-25 14:26:05 -07001661 if ((mQuirks & kRequiresFlushCompleteEmulation)
1662 && countBuffersWeOwn(mPortBuffers[portIndex])
1663 == mPortBuffers[portIndex].size()) {
1664 // No flush is necessary and this component fails to send a
1665 // flush-complete event in this case.
1666
1667 return false;
1668 }
1669
Andreas Huberbe06d262009-08-14 14:37:10 -07001670 status_t err =
Andreas Huber784202e2009-10-15 13:46:54 -07001671 mOMX->sendCommand(mNode, OMX_CommandFlush, portIndex);
Andreas Huberbe06d262009-08-14 14:37:10 -07001672 CHECK_EQ(err, OK);
Andreas Huber404cc412009-08-25 14:26:05 -07001673
1674 return true;
Andreas Huberbe06d262009-08-14 14:37:10 -07001675}
1676
1677void OMXCodec::disablePortAsync(OMX_U32 portIndex) {
1678 CHECK(mState == EXECUTING || mState == RECONFIGURING);
1679
1680 CHECK_EQ(mPortStatus[portIndex], ENABLED);
1681 mPortStatus[portIndex] = DISABLING;
1682
1683 status_t err =
Andreas Huber784202e2009-10-15 13:46:54 -07001684 mOMX->sendCommand(mNode, OMX_CommandPortDisable, portIndex);
Andreas Huberbe06d262009-08-14 14:37:10 -07001685 CHECK_EQ(err, OK);
1686
1687 freeBuffersOnPort(portIndex, true);
1688}
1689
1690void OMXCodec::enablePortAsync(OMX_U32 portIndex) {
1691 CHECK(mState == EXECUTING || mState == RECONFIGURING);
1692
1693 CHECK_EQ(mPortStatus[portIndex], DISABLED);
1694 mPortStatus[portIndex] = ENABLING;
1695
1696 status_t err =
Andreas Huber784202e2009-10-15 13:46:54 -07001697 mOMX->sendCommand(mNode, OMX_CommandPortEnable, portIndex);
Andreas Huberbe06d262009-08-14 14:37:10 -07001698 CHECK_EQ(err, OK);
1699}
1700
1701void OMXCodec::fillOutputBuffers() {
1702 CHECK_EQ(mState, EXECUTING);
1703
1704 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
1705 for (size_t i = 0; i < buffers->size(); ++i) {
1706 fillOutputBuffer(&buffers->editItemAt(i));
1707 }
1708}
1709
1710void OMXCodec::drainInputBuffers() {
Andreas Huberd06e5b82009-08-28 13:18:14 -07001711 CHECK(mState == EXECUTING || mState == RECONFIGURING);
Andreas Huberbe06d262009-08-14 14:37:10 -07001712
1713 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
1714 for (size_t i = 0; i < buffers->size(); ++i) {
1715 drainInputBuffer(&buffers->editItemAt(i));
1716 }
1717}
1718
1719void OMXCodec::drainInputBuffer(BufferInfo *info) {
1720 CHECK_EQ(info->mOwnedByComponent, false);
1721
1722 if (mSignalledEOS) {
1723 return;
1724 }
1725
1726 if (mCodecSpecificDataIndex < mCodecSpecificData.size()) {
1727 const CodecSpecificData *specific =
1728 mCodecSpecificData[mCodecSpecificDataIndex];
1729
1730 size_t size = specific->mSize;
1731
Andreas Hubere6c40962009-09-10 14:13:30 -07001732 if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mMIME)
Andreas Huber4f5e6022009-08-19 09:29:34 -07001733 && !(mQuirks & kWantsNALFragments)) {
Andreas Huberbe06d262009-08-14 14:37:10 -07001734 static const uint8_t kNALStartCode[4] =
1735 { 0x00, 0x00, 0x00, 0x01 };
1736
1737 CHECK(info->mMem->size() >= specific->mSize + 4);
1738
1739 size += 4;
1740
1741 memcpy(info->mMem->pointer(), kNALStartCode, 4);
1742 memcpy((uint8_t *)info->mMem->pointer() + 4,
1743 specific->mData, specific->mSize);
1744 } else {
1745 CHECK(info->mMem->size() >= specific->mSize);
1746 memcpy(info->mMem->pointer(), specific->mData, specific->mSize);
1747 }
1748
Andreas Huber784202e2009-10-15 13:46:54 -07001749 status_t err = mOMX->emptyBuffer(
Andreas Huberbe06d262009-08-14 14:37:10 -07001750 mNode, info->mBuffer, 0, size,
1751 OMX_BUFFERFLAG_ENDOFFRAME | OMX_BUFFERFLAG_CODECCONFIG,
1752 0);
Andreas Huber3f427072009-10-08 11:02:27 -07001753 CHECK_EQ(err, OK);
Andreas Huberbe06d262009-08-14 14:37:10 -07001754
1755 info->mOwnedByComponent = true;
1756
1757 ++mCodecSpecificDataIndex;
1758 return;
1759 }
1760
1761 MediaBuffer *srcBuffer;
1762 status_t err;
1763 if (mSeekTimeUs >= 0) {
1764 MediaSource::ReadOptions options;
1765 options.setSeekTo(mSeekTimeUs);
1766 mSeekTimeUs = -1;
1767
1768 err = mSource->read(&srcBuffer, &options);
1769 } else {
1770 err = mSource->read(&srcBuffer);
1771 }
1772
1773 OMX_U32 flags = OMX_BUFFERFLAG_ENDOFFRAME;
Andreas Huberfa8de752009-10-08 10:07:49 -07001774 OMX_TICKS timestampUs = 0;
Andreas Huberbe06d262009-08-14 14:37:10 -07001775 size_t srcLength = 0;
1776
1777 if (err != OK) {
Andreas Huber4c483422009-09-02 16:05:36 -07001778 CODEC_LOGV("signalling end of input stream.");
Andreas Huberbe06d262009-08-14 14:37:10 -07001779 flags |= OMX_BUFFERFLAG_EOS;
1780
1781 mSignalledEOS = true;
1782 } else {
1783 srcLength = srcBuffer->range_length();
1784
1785 if (info->mMem->size() < srcLength) {
1786 LOGE("info->mMem->size() = %d, srcLength = %d",
1787 info->mMem->size(), srcLength);
1788 }
1789 CHECK(info->mMem->size() >= srcLength);
1790 memcpy(info->mMem->pointer(),
1791 (const uint8_t *)srcBuffer->data() + srcBuffer->range_offset(),
1792 srcLength);
1793
Andreas Huberfa8de752009-10-08 10:07:49 -07001794 if (srcBuffer->meta_data()->findInt64(kKeyTime, &timestampUs)) {
Andreas Huber784202e2009-10-15 13:46:54 -07001795 CODEC_LOGV("Calling emptyBuffer on buffer %p (length %d)",
Andreas Huberbe06d262009-08-14 14:37:10 -07001796 info->mBuffer, srcLength);
Andreas Huber784202e2009-10-15 13:46:54 -07001797 CODEC_LOGV("Calling emptyBuffer with timestamp %lld us (%.2f secs)",
Andreas Huberfa8de752009-10-08 10:07:49 -07001798 timestampUs, timestampUs / 1E6);
Andreas Huberbe06d262009-08-14 14:37:10 -07001799 }
1800 }
1801
Andreas Huberbe06d262009-08-14 14:37:10 -07001802 if (srcBuffer != NULL) {
1803 srcBuffer->release();
1804 srcBuffer = NULL;
1805 }
Andreas Huber3f427072009-10-08 11:02:27 -07001806
Andreas Huber784202e2009-10-15 13:46:54 -07001807 err = mOMX->emptyBuffer(
Andreas Huber3f427072009-10-08 11:02:27 -07001808 mNode, info->mBuffer, 0, srcLength,
Andreas Huberfa8de752009-10-08 10:07:49 -07001809 flags, timestampUs);
Andreas Huber3f427072009-10-08 11:02:27 -07001810
1811 if (err != OK) {
1812 setState(ERROR);
1813 return;
1814 }
1815
1816 info->mOwnedByComponent = true;
Andreas Huberea6a38c2009-11-16 15:43:38 -08001817
1818 // This component does not ever signal the EOS flag on output buffers,
1819 // Thanks for nothing.
1820 if (mSignalledEOS && !strcmp(mComponentName, "OMX.TI.Video.encoder")) {
1821 mNoMoreOutputData = true;
1822 mBufferFilled.signal();
1823 }
Andreas Huberbe06d262009-08-14 14:37:10 -07001824}
1825
1826void OMXCodec::fillOutputBuffer(BufferInfo *info) {
1827 CHECK_EQ(info->mOwnedByComponent, false);
1828
Andreas Huber404cc412009-08-25 14:26:05 -07001829 if (mNoMoreOutputData) {
Andreas Huber4c483422009-09-02 16:05:36 -07001830 CODEC_LOGV("There is no more output data available, not "
Andreas Huber404cc412009-08-25 14:26:05 -07001831 "calling fillOutputBuffer");
1832 return;
1833 }
1834
Andreas Huber4c483422009-09-02 16:05:36 -07001835 CODEC_LOGV("Calling fill_buffer on buffer %p", info->mBuffer);
Andreas Huber784202e2009-10-15 13:46:54 -07001836 status_t err = mOMX->fillBuffer(mNode, info->mBuffer);
Andreas Huber3f427072009-10-08 11:02:27 -07001837 CHECK_EQ(err, OK);
Andreas Huberbe06d262009-08-14 14:37:10 -07001838
1839 info->mOwnedByComponent = true;
1840}
1841
1842void OMXCodec::drainInputBuffer(IOMX::buffer_id buffer) {
1843 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
1844 for (size_t i = 0; i < buffers->size(); ++i) {
1845 if ((*buffers)[i].mBuffer == buffer) {
1846 drainInputBuffer(&buffers->editItemAt(i));
1847 return;
1848 }
1849 }
1850
1851 CHECK(!"should not be here.");
1852}
1853
1854void OMXCodec::fillOutputBuffer(IOMX::buffer_id buffer) {
1855 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
1856 for (size_t i = 0; i < buffers->size(); ++i) {
1857 if ((*buffers)[i].mBuffer == buffer) {
1858 fillOutputBuffer(&buffers->editItemAt(i));
1859 return;
1860 }
1861 }
1862
1863 CHECK(!"should not be here.");
1864}
1865
1866void OMXCodec::setState(State newState) {
1867 mState = newState;
1868 mAsyncCompletion.signal();
1869
1870 // This may cause some spurious wakeups but is necessary to
1871 // unblock the reader if we enter ERROR state.
1872 mBufferFilled.signal();
1873}
1874
Andreas Huberda050cf22009-09-02 14:01:43 -07001875void OMXCodec::setRawAudioFormat(
1876 OMX_U32 portIndex, int32_t sampleRate, int32_t numChannels) {
1877 OMX_AUDIO_PARAM_PCMMODETYPE pcmParams;
Andreas Huber4c483422009-09-02 16:05:36 -07001878 InitOMXParams(&pcmParams);
Andreas Huberda050cf22009-09-02 14:01:43 -07001879 pcmParams.nPortIndex = portIndex;
1880
Andreas Huber784202e2009-10-15 13:46:54 -07001881 status_t err = mOMX->getParameter(
Andreas Huberda050cf22009-09-02 14:01:43 -07001882 mNode, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams));
1883
1884 CHECK_EQ(err, OK);
1885
1886 pcmParams.nChannels = numChannels;
1887 pcmParams.eNumData = OMX_NumericalDataSigned;
1888 pcmParams.bInterleaved = OMX_TRUE;
1889 pcmParams.nBitPerSample = 16;
1890 pcmParams.nSamplingRate = sampleRate;
1891 pcmParams.ePCMMode = OMX_AUDIO_PCMModeLinear;
1892
1893 if (numChannels == 1) {
1894 pcmParams.eChannelMapping[0] = OMX_AUDIO_ChannelCF;
1895 } else {
1896 CHECK_EQ(numChannels, 2);
1897
1898 pcmParams.eChannelMapping[0] = OMX_AUDIO_ChannelLF;
1899 pcmParams.eChannelMapping[1] = OMX_AUDIO_ChannelRF;
1900 }
1901
Andreas Huber784202e2009-10-15 13:46:54 -07001902 err = mOMX->setParameter(
Andreas Huberda050cf22009-09-02 14:01:43 -07001903 mNode, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams));
1904
1905 CHECK_EQ(err, OK);
1906}
1907
Andreas Huber8768f2c2009-12-01 15:26:54 -08001908void OMXCodec::setAMRFormat(bool isWAMR) {
1909 OMX_U32 portIndex = mIsEncoder ? kPortIndexOutput : kPortIndexInput;
Andreas Huberbe06d262009-08-14 14:37:10 -07001910
Andreas Huber8768f2c2009-12-01 15:26:54 -08001911 OMX_AUDIO_PARAM_AMRTYPE def;
1912 InitOMXParams(&def);
1913 def.nPortIndex = portIndex;
Andreas Huberbe06d262009-08-14 14:37:10 -07001914
Andreas Huber8768f2c2009-12-01 15:26:54 -08001915 status_t err =
1916 mOMX->getParameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
Andreas Huberbe06d262009-08-14 14:37:10 -07001917
Andreas Huber8768f2c2009-12-01 15:26:54 -08001918 CHECK_EQ(err, OK);
Andreas Huberbe06d262009-08-14 14:37:10 -07001919
Andreas Huber8768f2c2009-12-01 15:26:54 -08001920 def.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
1921 def.eAMRBandMode =
1922 isWAMR ? OMX_AUDIO_AMRBandModeWB0 : OMX_AUDIO_AMRBandModeNB0;
Andreas Huberbe06d262009-08-14 14:37:10 -07001923
Andreas Huber8768f2c2009-12-01 15:26:54 -08001924 err = mOMX->setParameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
1925 CHECK_EQ(err, OK);
Andreas Huberee606e62009-09-08 10:19:21 -07001926
1927 ////////////////////////
1928
1929 if (mIsEncoder) {
1930 sp<MetaData> format = mSource->getFormat();
1931 int32_t sampleRate;
1932 int32_t numChannels;
1933 CHECK(format->findInt32(kKeySampleRate, &sampleRate));
1934 CHECK(format->findInt32(kKeyChannelCount, &numChannels));
1935
1936 setRawAudioFormat(kPortIndexInput, sampleRate, numChannels);
1937 }
1938}
1939
Andreas Huber43ad6eaf2009-09-01 16:02:43 -07001940void OMXCodec::setAACFormat(int32_t numChannels, int32_t sampleRate) {
Andreas Huberda050cf22009-09-02 14:01:43 -07001941 if (mIsEncoder) {
1942 setRawAudioFormat(kPortIndexInput, sampleRate, numChannels);
1943 } else {
1944 OMX_AUDIO_PARAM_AACPROFILETYPE profile;
Andreas Huber4c483422009-09-02 16:05:36 -07001945 InitOMXParams(&profile);
Andreas Huberda050cf22009-09-02 14:01:43 -07001946 profile.nPortIndex = kPortIndexInput;
Andreas Huberbe06d262009-08-14 14:37:10 -07001947
Andreas Huber784202e2009-10-15 13:46:54 -07001948 status_t err = mOMX->getParameter(
Andreas Huberda050cf22009-09-02 14:01:43 -07001949 mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile));
1950 CHECK_EQ(err, OK);
Andreas Huberbe06d262009-08-14 14:37:10 -07001951
Andreas Huberda050cf22009-09-02 14:01:43 -07001952 profile.nChannels = numChannels;
1953 profile.nSampleRate = sampleRate;
1954 profile.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4ADTS;
Andreas Huberbe06d262009-08-14 14:37:10 -07001955
Andreas Huber784202e2009-10-15 13:46:54 -07001956 err = mOMX->setParameter(
Andreas Huberda050cf22009-09-02 14:01:43 -07001957 mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile));
1958 CHECK_EQ(err, OK);
1959 }
Andreas Huberbe06d262009-08-14 14:37:10 -07001960}
1961
1962void OMXCodec::setImageOutputFormat(
1963 OMX_COLOR_FORMATTYPE format, OMX_U32 width, OMX_U32 height) {
Andreas Huber4c483422009-09-02 16:05:36 -07001964 CODEC_LOGV("setImageOutputFormat(%ld, %ld)", width, height);
Andreas Huberbe06d262009-08-14 14:37:10 -07001965
1966#if 0
1967 OMX_INDEXTYPE index;
1968 status_t err = mOMX->get_extension_index(
1969 mNode, "OMX.TI.JPEG.decode.Config.OutputColorFormat", &index);
1970 CHECK_EQ(err, OK);
1971
1972 err = mOMX->set_config(mNode, index, &format, sizeof(format));
1973 CHECK_EQ(err, OK);
1974#endif
1975
1976 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -07001977 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -07001978 def.nPortIndex = kPortIndexOutput;
1979
Andreas Huber784202e2009-10-15 13:46:54 -07001980 status_t err = mOMX->getParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -07001981 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
1982 CHECK_EQ(err, OK);
1983
1984 CHECK_EQ(def.eDomain, OMX_PortDomainImage);
1985
1986 OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
Andreas Huberebf66ea2009-08-19 13:32:58 -07001987
Andreas Huberbe06d262009-08-14 14:37:10 -07001988 CHECK_EQ(imageDef->eCompressionFormat, OMX_IMAGE_CodingUnused);
1989 imageDef->eColorFormat = format;
1990 imageDef->nFrameWidth = width;
1991 imageDef->nFrameHeight = height;
1992
1993 switch (format) {
1994 case OMX_COLOR_FormatYUV420PackedPlanar:
1995 case OMX_COLOR_FormatYUV411Planar:
1996 {
1997 def.nBufferSize = (width * height * 3) / 2;
1998 break;
1999 }
2000
2001 case OMX_COLOR_FormatCbYCrY:
2002 {
2003 def.nBufferSize = width * height * 2;
2004 break;
2005 }
2006
2007 case OMX_COLOR_Format32bitARGB8888:
2008 {
2009 def.nBufferSize = width * height * 4;
2010 break;
2011 }
2012
Andreas Huber201511c2009-09-08 14:01:44 -07002013 case OMX_COLOR_Format16bitARGB4444:
2014 case OMX_COLOR_Format16bitARGB1555:
2015 case OMX_COLOR_Format16bitRGB565:
2016 case OMX_COLOR_Format16bitBGR565:
2017 {
2018 def.nBufferSize = width * height * 2;
2019 break;
2020 }
2021
Andreas Huberbe06d262009-08-14 14:37:10 -07002022 default:
2023 CHECK(!"Should not be here. Unknown color format.");
2024 break;
2025 }
2026
Andreas Huber5c0a9132009-08-20 11:16:40 -07002027 def.nBufferCountActual = def.nBufferCountMin;
2028
Andreas Huber784202e2009-10-15 13:46:54 -07002029 err = mOMX->setParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -07002030 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
2031 CHECK_EQ(err, OK);
Andreas Huber5c0a9132009-08-20 11:16:40 -07002032}
Andreas Huberbe06d262009-08-14 14:37:10 -07002033
Andreas Huber5c0a9132009-08-20 11:16:40 -07002034void OMXCodec::setJPEGInputFormat(
2035 OMX_U32 width, OMX_U32 height, OMX_U32 compressedSize) {
2036 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -07002037 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -07002038 def.nPortIndex = kPortIndexInput;
2039
Andreas Huber784202e2009-10-15 13:46:54 -07002040 status_t err = mOMX->getParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -07002041 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
2042 CHECK_EQ(err, OK);
2043
Andreas Huber5c0a9132009-08-20 11:16:40 -07002044 CHECK_EQ(def.eDomain, OMX_PortDomainImage);
2045 OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
2046
Andreas Huberbe06d262009-08-14 14:37:10 -07002047 CHECK_EQ(imageDef->eCompressionFormat, OMX_IMAGE_CodingJPEG);
2048 imageDef->nFrameWidth = width;
2049 imageDef->nFrameHeight = height;
2050
Andreas Huber5c0a9132009-08-20 11:16:40 -07002051 def.nBufferSize = compressedSize;
Andreas Huberbe06d262009-08-14 14:37:10 -07002052 def.nBufferCountActual = def.nBufferCountMin;
2053
Andreas Huber784202e2009-10-15 13:46:54 -07002054 err = mOMX->setParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -07002055 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
2056 CHECK_EQ(err, OK);
2057}
2058
2059void OMXCodec::addCodecSpecificData(const void *data, size_t size) {
2060 CodecSpecificData *specific =
2061 (CodecSpecificData *)malloc(sizeof(CodecSpecificData) + size - 1);
2062
2063 specific->mSize = size;
2064 memcpy(specific->mData, data, size);
2065
2066 mCodecSpecificData.push(specific);
2067}
2068
2069void OMXCodec::clearCodecSpecificData() {
2070 for (size_t i = 0; i < mCodecSpecificData.size(); ++i) {
2071 free(mCodecSpecificData.editItemAt(i));
2072 }
2073 mCodecSpecificData.clear();
2074 mCodecSpecificDataIndex = 0;
2075}
2076
2077status_t OMXCodec::start(MetaData *) {
Andreas Huber42978e52009-08-27 10:08:39 -07002078 Mutex::Autolock autoLock(mLock);
2079
Andreas Huberbe06d262009-08-14 14:37:10 -07002080 if (mState != LOADED) {
2081 return UNKNOWN_ERROR;
2082 }
Andreas Huberebf66ea2009-08-19 13:32:58 -07002083
Andreas Huberbe06d262009-08-14 14:37:10 -07002084 sp<MetaData> params = new MetaData;
Andreas Huber4f5e6022009-08-19 09:29:34 -07002085 if (mQuirks & kWantsNALFragments) {
2086 params->setInt32(kKeyWantsNALFragments, true);
Andreas Huberbe06d262009-08-14 14:37:10 -07002087 }
2088 status_t err = mSource->start(params.get());
2089
2090 if (err != OK) {
2091 return err;
2092 }
2093
2094 mCodecSpecificDataIndex = 0;
Andreas Huber42978e52009-08-27 10:08:39 -07002095 mInitialBufferSubmit = true;
Andreas Huberbe06d262009-08-14 14:37:10 -07002096 mSignalledEOS = false;
2097 mNoMoreOutputData = false;
Andreas Hubercfd55572009-10-09 14:11:28 -07002098 mOutputPortSettingsHaveChanged = false;
Andreas Huberbe06d262009-08-14 14:37:10 -07002099 mSeekTimeUs = -1;
2100 mFilledBuffers.clear();
2101
2102 return init();
2103}
2104
2105status_t OMXCodec::stop() {
Andreas Huber4c483422009-09-02 16:05:36 -07002106 CODEC_LOGV("stop");
Andreas Huberbe06d262009-08-14 14:37:10 -07002107
2108 Mutex::Autolock autoLock(mLock);
2109
2110 while (isIntermediateState(mState)) {
2111 mAsyncCompletion.wait(mLock);
2112 }
2113
2114 switch (mState) {
2115 case LOADED:
2116 case ERROR:
2117 break;
2118
2119 case EXECUTING:
2120 {
2121 setState(EXECUTING_TO_IDLE);
2122
Andreas Huber127fcdc2009-08-26 16:27:02 -07002123 if (mQuirks & kRequiresFlushBeforeShutdown) {
Andreas Huber4c483422009-09-02 16:05:36 -07002124 CODEC_LOGV("This component requires a flush before transitioning "
Andreas Huber127fcdc2009-08-26 16:27:02 -07002125 "from EXECUTING to IDLE...");
Andreas Huberbe06d262009-08-14 14:37:10 -07002126
Andreas Huber127fcdc2009-08-26 16:27:02 -07002127 bool emulateInputFlushCompletion =
2128 !flushPortAsync(kPortIndexInput);
2129
2130 bool emulateOutputFlushCompletion =
2131 !flushPortAsync(kPortIndexOutput);
2132
2133 if (emulateInputFlushCompletion) {
2134 onCmdComplete(OMX_CommandFlush, kPortIndexInput);
2135 }
2136
2137 if (emulateOutputFlushCompletion) {
2138 onCmdComplete(OMX_CommandFlush, kPortIndexOutput);
2139 }
2140 } else {
2141 mPortStatus[kPortIndexInput] = SHUTTING_DOWN;
2142 mPortStatus[kPortIndexOutput] = SHUTTING_DOWN;
2143
2144 status_t err =
Andreas Huber784202e2009-10-15 13:46:54 -07002145 mOMX->sendCommand(mNode, OMX_CommandStateSet, OMX_StateIdle);
Andreas Huber127fcdc2009-08-26 16:27:02 -07002146 CHECK_EQ(err, OK);
2147 }
Andreas Huberbe06d262009-08-14 14:37:10 -07002148
2149 while (mState != LOADED && mState != ERROR) {
2150 mAsyncCompletion.wait(mLock);
2151 }
2152
2153 break;
2154 }
2155
2156 default:
2157 {
2158 CHECK(!"should not be here.");
2159 break;
2160 }
2161 }
2162
2163 mSource->stop();
2164
2165 return OK;
2166}
2167
2168sp<MetaData> OMXCodec::getFormat() {
Andreas Hubercfd55572009-10-09 14:11:28 -07002169 Mutex::Autolock autoLock(mLock);
2170
Andreas Huberbe06d262009-08-14 14:37:10 -07002171 return mOutputFormat;
2172}
2173
2174status_t OMXCodec::read(
2175 MediaBuffer **buffer, const ReadOptions *options) {
2176 *buffer = NULL;
2177
2178 Mutex::Autolock autoLock(mLock);
2179
Andreas Huberd06e5b82009-08-28 13:18:14 -07002180 if (mState != EXECUTING && mState != RECONFIGURING) {
2181 return UNKNOWN_ERROR;
2182 }
2183
Andreas Hubere981c332009-10-22 13:49:30 -07002184 bool seeking = false;
2185 int64_t seekTimeUs;
2186 if (options && options->getSeekTo(&seekTimeUs)) {
2187 seeking = true;
2188 }
2189
Andreas Huber42978e52009-08-27 10:08:39 -07002190 if (mInitialBufferSubmit) {
2191 mInitialBufferSubmit = false;
2192
Andreas Hubere981c332009-10-22 13:49:30 -07002193 if (seeking) {
2194 CHECK(seekTimeUs >= 0);
2195 mSeekTimeUs = seekTimeUs;
2196
2197 // There's no reason to trigger the code below, there's
2198 // nothing to flush yet.
2199 seeking = false;
2200 }
2201
Andreas Huber42978e52009-08-27 10:08:39 -07002202 drainInputBuffers();
Andreas Huber42978e52009-08-27 10:08:39 -07002203
Andreas Huberd06e5b82009-08-28 13:18:14 -07002204 if (mState == EXECUTING) {
2205 // Otherwise mState == RECONFIGURING and this code will trigger
2206 // after the output port is reenabled.
2207 fillOutputBuffers();
2208 }
Andreas Huberbe06d262009-08-14 14:37:10 -07002209 }
2210
Andreas Hubere981c332009-10-22 13:49:30 -07002211 if (seeking) {
Andreas Huber4c483422009-09-02 16:05:36 -07002212 CODEC_LOGV("seeking to %lld us (%.2f secs)", seekTimeUs, seekTimeUs / 1E6);
Andreas Huberbe06d262009-08-14 14:37:10 -07002213
2214 mSignalledEOS = false;
2215 mNoMoreOutputData = false;
2216
2217 CHECK(seekTimeUs >= 0);
2218 mSeekTimeUs = seekTimeUs;
2219
2220 mFilledBuffers.clear();
2221
2222 CHECK_EQ(mState, EXECUTING);
2223
Andreas Huber404cc412009-08-25 14:26:05 -07002224 bool emulateInputFlushCompletion = !flushPortAsync(kPortIndexInput);
2225 bool emulateOutputFlushCompletion = !flushPortAsync(kPortIndexOutput);
2226
2227 if (emulateInputFlushCompletion) {
2228 onCmdComplete(OMX_CommandFlush, kPortIndexInput);
2229 }
2230
2231 if (emulateOutputFlushCompletion) {
2232 onCmdComplete(OMX_CommandFlush, kPortIndexOutput);
2233 }
Andreas Huberbe06d262009-08-14 14:37:10 -07002234 }
2235
2236 while (mState != ERROR && !mNoMoreOutputData && mFilledBuffers.empty()) {
2237 mBufferFilled.wait(mLock);
2238 }
2239
2240 if (mState == ERROR) {
2241 return UNKNOWN_ERROR;
2242 }
2243
2244 if (mFilledBuffers.empty()) {
2245 return ERROR_END_OF_STREAM;
2246 }
2247
Andreas Hubercfd55572009-10-09 14:11:28 -07002248 if (mOutputPortSettingsHaveChanged) {
2249 mOutputPortSettingsHaveChanged = false;
2250
2251 return INFO_FORMAT_CHANGED;
2252 }
2253
Andreas Huberbe06d262009-08-14 14:37:10 -07002254 size_t index = *mFilledBuffers.begin();
2255 mFilledBuffers.erase(mFilledBuffers.begin());
2256
2257 BufferInfo *info = &mPortBuffers[kPortIndexOutput].editItemAt(index);
2258 info->mMediaBuffer->add_ref();
2259 *buffer = info->mMediaBuffer;
2260
2261 return OK;
2262}
2263
2264void OMXCodec::signalBufferReturned(MediaBuffer *buffer) {
2265 Mutex::Autolock autoLock(mLock);
2266
2267 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
2268 for (size_t i = 0; i < buffers->size(); ++i) {
2269 BufferInfo *info = &buffers->editItemAt(i);
2270
2271 if (info->mMediaBuffer == buffer) {
2272 CHECK_EQ(mPortStatus[kPortIndexOutput], ENABLED);
2273 fillOutputBuffer(info);
2274 return;
2275 }
2276 }
2277
2278 CHECK(!"should not be here.");
2279}
2280
2281static const char *imageCompressionFormatString(OMX_IMAGE_CODINGTYPE type) {
2282 static const char *kNames[] = {
2283 "OMX_IMAGE_CodingUnused",
2284 "OMX_IMAGE_CodingAutoDetect",
2285 "OMX_IMAGE_CodingJPEG",
2286 "OMX_IMAGE_CodingJPEG2K",
2287 "OMX_IMAGE_CodingEXIF",
2288 "OMX_IMAGE_CodingTIFF",
2289 "OMX_IMAGE_CodingGIF",
2290 "OMX_IMAGE_CodingPNG",
2291 "OMX_IMAGE_CodingLZW",
2292 "OMX_IMAGE_CodingBMP",
2293 };
2294
2295 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
2296
2297 if (type < 0 || (size_t)type >= numNames) {
2298 return "UNKNOWN";
2299 } else {
2300 return kNames[type];
2301 }
2302}
2303
2304static const char *colorFormatString(OMX_COLOR_FORMATTYPE type) {
2305 static const char *kNames[] = {
2306 "OMX_COLOR_FormatUnused",
2307 "OMX_COLOR_FormatMonochrome",
2308 "OMX_COLOR_Format8bitRGB332",
2309 "OMX_COLOR_Format12bitRGB444",
2310 "OMX_COLOR_Format16bitARGB4444",
2311 "OMX_COLOR_Format16bitARGB1555",
2312 "OMX_COLOR_Format16bitRGB565",
2313 "OMX_COLOR_Format16bitBGR565",
2314 "OMX_COLOR_Format18bitRGB666",
2315 "OMX_COLOR_Format18bitARGB1665",
Andreas Huberebf66ea2009-08-19 13:32:58 -07002316 "OMX_COLOR_Format19bitARGB1666",
Andreas Huberbe06d262009-08-14 14:37:10 -07002317 "OMX_COLOR_Format24bitRGB888",
2318 "OMX_COLOR_Format24bitBGR888",
2319 "OMX_COLOR_Format24bitARGB1887",
2320 "OMX_COLOR_Format25bitARGB1888",
2321 "OMX_COLOR_Format32bitBGRA8888",
2322 "OMX_COLOR_Format32bitARGB8888",
2323 "OMX_COLOR_FormatYUV411Planar",
2324 "OMX_COLOR_FormatYUV411PackedPlanar",
2325 "OMX_COLOR_FormatYUV420Planar",
2326 "OMX_COLOR_FormatYUV420PackedPlanar",
2327 "OMX_COLOR_FormatYUV420SemiPlanar",
2328 "OMX_COLOR_FormatYUV422Planar",
2329 "OMX_COLOR_FormatYUV422PackedPlanar",
2330 "OMX_COLOR_FormatYUV422SemiPlanar",
2331 "OMX_COLOR_FormatYCbYCr",
2332 "OMX_COLOR_FormatYCrYCb",
2333 "OMX_COLOR_FormatCbYCrY",
2334 "OMX_COLOR_FormatCrYCbY",
2335 "OMX_COLOR_FormatYUV444Interleaved",
2336 "OMX_COLOR_FormatRawBayer8bit",
2337 "OMX_COLOR_FormatRawBayer10bit",
2338 "OMX_COLOR_FormatRawBayer8bitcompressed",
Andreas Huberebf66ea2009-08-19 13:32:58 -07002339 "OMX_COLOR_FormatL2",
2340 "OMX_COLOR_FormatL4",
2341 "OMX_COLOR_FormatL8",
2342 "OMX_COLOR_FormatL16",
2343 "OMX_COLOR_FormatL24",
Andreas Huberbe06d262009-08-14 14:37:10 -07002344 "OMX_COLOR_FormatL32",
2345 "OMX_COLOR_FormatYUV420PackedSemiPlanar",
2346 "OMX_COLOR_FormatYUV422PackedSemiPlanar",
2347 "OMX_COLOR_Format18BitBGR666",
2348 "OMX_COLOR_Format24BitARGB6666",
2349 "OMX_COLOR_Format24BitABGR6666",
2350 };
2351
2352 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
2353
Andreas Huberbe06d262009-08-14 14:37:10 -07002354 if (type == OMX_QCOM_COLOR_FormatYVU420SemiPlanar) {
2355 return "OMX_QCOM_COLOR_FormatYVU420SemiPlanar";
2356 } else if (type < 0 || (size_t)type >= numNames) {
2357 return "UNKNOWN";
2358 } else {
2359 return kNames[type];
2360 }
2361}
2362
2363static const char *videoCompressionFormatString(OMX_VIDEO_CODINGTYPE type) {
2364 static const char *kNames[] = {
2365 "OMX_VIDEO_CodingUnused",
2366 "OMX_VIDEO_CodingAutoDetect",
2367 "OMX_VIDEO_CodingMPEG2",
2368 "OMX_VIDEO_CodingH263",
2369 "OMX_VIDEO_CodingMPEG4",
2370 "OMX_VIDEO_CodingWMV",
2371 "OMX_VIDEO_CodingRV",
2372 "OMX_VIDEO_CodingAVC",
2373 "OMX_VIDEO_CodingMJPEG",
2374 };
2375
2376 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
2377
2378 if (type < 0 || (size_t)type >= numNames) {
2379 return "UNKNOWN";
2380 } else {
2381 return kNames[type];
2382 }
2383}
2384
2385static const char *audioCodingTypeString(OMX_AUDIO_CODINGTYPE type) {
2386 static const char *kNames[] = {
2387 "OMX_AUDIO_CodingUnused",
2388 "OMX_AUDIO_CodingAutoDetect",
2389 "OMX_AUDIO_CodingPCM",
2390 "OMX_AUDIO_CodingADPCM",
2391 "OMX_AUDIO_CodingAMR",
2392 "OMX_AUDIO_CodingGSMFR",
2393 "OMX_AUDIO_CodingGSMEFR",
2394 "OMX_AUDIO_CodingGSMHR",
2395 "OMX_AUDIO_CodingPDCFR",
2396 "OMX_AUDIO_CodingPDCEFR",
2397 "OMX_AUDIO_CodingPDCHR",
2398 "OMX_AUDIO_CodingTDMAFR",
2399 "OMX_AUDIO_CodingTDMAEFR",
2400 "OMX_AUDIO_CodingQCELP8",
2401 "OMX_AUDIO_CodingQCELP13",
2402 "OMX_AUDIO_CodingEVRC",
2403 "OMX_AUDIO_CodingSMV",
2404 "OMX_AUDIO_CodingG711",
2405 "OMX_AUDIO_CodingG723",
2406 "OMX_AUDIO_CodingG726",
2407 "OMX_AUDIO_CodingG729",
2408 "OMX_AUDIO_CodingAAC",
2409 "OMX_AUDIO_CodingMP3",
2410 "OMX_AUDIO_CodingSBC",
2411 "OMX_AUDIO_CodingVORBIS",
2412 "OMX_AUDIO_CodingWMA",
2413 "OMX_AUDIO_CodingRA",
2414 "OMX_AUDIO_CodingMIDI",
2415 };
2416
2417 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
2418
2419 if (type < 0 || (size_t)type >= numNames) {
2420 return "UNKNOWN";
2421 } else {
2422 return kNames[type];
2423 }
2424}
2425
2426static const char *audioPCMModeString(OMX_AUDIO_PCMMODETYPE type) {
2427 static const char *kNames[] = {
2428 "OMX_AUDIO_PCMModeLinear",
2429 "OMX_AUDIO_PCMModeALaw",
2430 "OMX_AUDIO_PCMModeMULaw",
2431 };
2432
2433 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
2434
2435 if (type < 0 || (size_t)type >= numNames) {
2436 return "UNKNOWN";
2437 } else {
2438 return kNames[type];
2439 }
2440}
2441
Andreas Huber7ae02c82009-09-09 16:29:47 -07002442static const char *amrBandModeString(OMX_AUDIO_AMRBANDMODETYPE type) {
2443 static const char *kNames[] = {
2444 "OMX_AUDIO_AMRBandModeUnused",
2445 "OMX_AUDIO_AMRBandModeNB0",
2446 "OMX_AUDIO_AMRBandModeNB1",
2447 "OMX_AUDIO_AMRBandModeNB2",
2448 "OMX_AUDIO_AMRBandModeNB3",
2449 "OMX_AUDIO_AMRBandModeNB4",
2450 "OMX_AUDIO_AMRBandModeNB5",
2451 "OMX_AUDIO_AMRBandModeNB6",
2452 "OMX_AUDIO_AMRBandModeNB7",
2453 "OMX_AUDIO_AMRBandModeWB0",
2454 "OMX_AUDIO_AMRBandModeWB1",
2455 "OMX_AUDIO_AMRBandModeWB2",
2456 "OMX_AUDIO_AMRBandModeWB3",
2457 "OMX_AUDIO_AMRBandModeWB4",
2458 "OMX_AUDIO_AMRBandModeWB5",
2459 "OMX_AUDIO_AMRBandModeWB6",
2460 "OMX_AUDIO_AMRBandModeWB7",
2461 "OMX_AUDIO_AMRBandModeWB8",
2462 };
2463
2464 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
2465
2466 if (type < 0 || (size_t)type >= numNames) {
2467 return "UNKNOWN";
2468 } else {
2469 return kNames[type];
2470 }
2471}
2472
2473static const char *amrFrameFormatString(OMX_AUDIO_AMRFRAMEFORMATTYPE type) {
2474 static const char *kNames[] = {
2475 "OMX_AUDIO_AMRFrameFormatConformance",
2476 "OMX_AUDIO_AMRFrameFormatIF1",
2477 "OMX_AUDIO_AMRFrameFormatIF2",
2478 "OMX_AUDIO_AMRFrameFormatFSF",
2479 "OMX_AUDIO_AMRFrameFormatRTPPayload",
2480 "OMX_AUDIO_AMRFrameFormatITU",
2481 };
2482
2483 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
2484
2485 if (type < 0 || (size_t)type >= numNames) {
2486 return "UNKNOWN";
2487 } else {
2488 return kNames[type];
2489 }
2490}
Andreas Huberbe06d262009-08-14 14:37:10 -07002491
2492void OMXCodec::dumpPortStatus(OMX_U32 portIndex) {
2493 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -07002494 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -07002495 def.nPortIndex = portIndex;
2496
Andreas Huber784202e2009-10-15 13:46:54 -07002497 status_t err = mOMX->getParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -07002498 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
2499 CHECK_EQ(err, OK);
2500
2501 printf("%s Port = {\n", portIndex == kPortIndexInput ? "Input" : "Output");
2502
2503 CHECK((portIndex == kPortIndexInput && def.eDir == OMX_DirInput)
2504 || (portIndex == kPortIndexOutput && def.eDir == OMX_DirOutput));
2505
2506 printf(" nBufferCountActual = %ld\n", def.nBufferCountActual);
2507 printf(" nBufferCountMin = %ld\n", def.nBufferCountMin);
2508 printf(" nBufferSize = %ld\n", def.nBufferSize);
2509
2510 switch (def.eDomain) {
2511 case OMX_PortDomainImage:
2512 {
2513 const OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
2514
2515 printf("\n");
2516 printf(" // Image\n");
2517 printf(" nFrameWidth = %ld\n", imageDef->nFrameWidth);
2518 printf(" nFrameHeight = %ld\n", imageDef->nFrameHeight);
2519 printf(" nStride = %ld\n", imageDef->nStride);
2520
2521 printf(" eCompressionFormat = %s\n",
2522 imageCompressionFormatString(imageDef->eCompressionFormat));
2523
2524 printf(" eColorFormat = %s\n",
2525 colorFormatString(imageDef->eColorFormat));
2526
2527 break;
2528 }
2529
2530 case OMX_PortDomainVideo:
2531 {
2532 OMX_VIDEO_PORTDEFINITIONTYPE *videoDef = &def.format.video;
2533
2534 printf("\n");
2535 printf(" // Video\n");
2536 printf(" nFrameWidth = %ld\n", videoDef->nFrameWidth);
2537 printf(" nFrameHeight = %ld\n", videoDef->nFrameHeight);
2538 printf(" nStride = %ld\n", videoDef->nStride);
2539
2540 printf(" eCompressionFormat = %s\n",
2541 videoCompressionFormatString(videoDef->eCompressionFormat));
2542
2543 printf(" eColorFormat = %s\n",
2544 colorFormatString(videoDef->eColorFormat));
2545
2546 break;
2547 }
2548
2549 case OMX_PortDomainAudio:
2550 {
2551 OMX_AUDIO_PORTDEFINITIONTYPE *audioDef = &def.format.audio;
2552
2553 printf("\n");
2554 printf(" // Audio\n");
2555 printf(" eEncoding = %s\n",
2556 audioCodingTypeString(audioDef->eEncoding));
2557
2558 if (audioDef->eEncoding == OMX_AUDIO_CodingPCM) {
2559 OMX_AUDIO_PARAM_PCMMODETYPE params;
Andreas Huber4c483422009-09-02 16:05:36 -07002560 InitOMXParams(&params);
Andreas Huberbe06d262009-08-14 14:37:10 -07002561 params.nPortIndex = portIndex;
2562
Andreas Huber784202e2009-10-15 13:46:54 -07002563 err = mOMX->getParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -07002564 mNode, OMX_IndexParamAudioPcm, &params, sizeof(params));
2565 CHECK_EQ(err, OK);
2566
2567 printf(" nSamplingRate = %ld\n", params.nSamplingRate);
2568 printf(" nChannels = %ld\n", params.nChannels);
2569 printf(" bInterleaved = %d\n", params.bInterleaved);
2570 printf(" nBitPerSample = %ld\n", params.nBitPerSample);
2571
2572 printf(" eNumData = %s\n",
2573 params.eNumData == OMX_NumericalDataSigned
2574 ? "signed" : "unsigned");
2575
2576 printf(" ePCMMode = %s\n", audioPCMModeString(params.ePCMMode));
Andreas Huber7ae02c82009-09-09 16:29:47 -07002577 } else if (audioDef->eEncoding == OMX_AUDIO_CodingAMR) {
2578 OMX_AUDIO_PARAM_AMRTYPE amr;
2579 InitOMXParams(&amr);
2580 amr.nPortIndex = portIndex;
2581
Andreas Huber784202e2009-10-15 13:46:54 -07002582 err = mOMX->getParameter(
Andreas Huber7ae02c82009-09-09 16:29:47 -07002583 mNode, OMX_IndexParamAudioAmr, &amr, sizeof(amr));
2584 CHECK_EQ(err, OK);
2585
2586 printf(" nChannels = %ld\n", amr.nChannels);
2587 printf(" eAMRBandMode = %s\n",
2588 amrBandModeString(amr.eAMRBandMode));
2589 printf(" eAMRFrameFormat = %s\n",
2590 amrFrameFormatString(amr.eAMRFrameFormat));
Andreas Huberbe06d262009-08-14 14:37:10 -07002591 }
2592
2593 break;
2594 }
2595
2596 default:
2597 {
2598 printf(" // Unknown\n");
2599 break;
2600 }
2601 }
2602
2603 printf("}\n");
2604}
2605
2606void OMXCodec::initOutputFormat(const sp<MetaData> &inputFormat) {
2607 mOutputFormat = new MetaData;
2608 mOutputFormat->setCString(kKeyDecoderComponent, mComponentName);
2609
2610 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -07002611 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -07002612 def.nPortIndex = kPortIndexOutput;
2613
Andreas Huber784202e2009-10-15 13:46:54 -07002614 status_t err = mOMX->getParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -07002615 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
2616 CHECK_EQ(err, OK);
2617
2618 switch (def.eDomain) {
2619 case OMX_PortDomainImage:
2620 {
2621 OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
2622 CHECK_EQ(imageDef->eCompressionFormat, OMX_IMAGE_CodingUnused);
2623
Andreas Hubere6c40962009-09-10 14:13:30 -07002624 mOutputFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
Andreas Huberbe06d262009-08-14 14:37:10 -07002625 mOutputFormat->setInt32(kKeyColorFormat, imageDef->eColorFormat);
2626 mOutputFormat->setInt32(kKeyWidth, imageDef->nFrameWidth);
2627 mOutputFormat->setInt32(kKeyHeight, imageDef->nFrameHeight);
2628 break;
2629 }
2630
2631 case OMX_PortDomainAudio:
2632 {
2633 OMX_AUDIO_PORTDEFINITIONTYPE *audio_def = &def.format.audio;
2634
Andreas Huberda050cf22009-09-02 14:01:43 -07002635 if (audio_def->eEncoding == OMX_AUDIO_CodingPCM) {
2636 OMX_AUDIO_PARAM_PCMMODETYPE params;
Andreas Huber4c483422009-09-02 16:05:36 -07002637 InitOMXParams(&params);
Andreas Huberda050cf22009-09-02 14:01:43 -07002638 params.nPortIndex = kPortIndexOutput;
Andreas Huberbe06d262009-08-14 14:37:10 -07002639
Andreas Huber784202e2009-10-15 13:46:54 -07002640 err = mOMX->getParameter(
Andreas Huberda050cf22009-09-02 14:01:43 -07002641 mNode, OMX_IndexParamAudioPcm, &params, sizeof(params));
2642 CHECK_EQ(err, OK);
Andreas Huberbe06d262009-08-14 14:37:10 -07002643
Andreas Huberda050cf22009-09-02 14:01:43 -07002644 CHECK_EQ(params.eNumData, OMX_NumericalDataSigned);
2645 CHECK_EQ(params.nBitPerSample, 16);
2646 CHECK_EQ(params.ePCMMode, OMX_AUDIO_PCMModeLinear);
Andreas Huberbe06d262009-08-14 14:37:10 -07002647
Andreas Huberda050cf22009-09-02 14:01:43 -07002648 int32_t numChannels, sampleRate;
2649 inputFormat->findInt32(kKeyChannelCount, &numChannels);
2650 inputFormat->findInt32(kKeySampleRate, &sampleRate);
Andreas Huberbe06d262009-08-14 14:37:10 -07002651
Andreas Huberda050cf22009-09-02 14:01:43 -07002652 if ((OMX_U32)numChannels != params.nChannels) {
2653 LOGW("Codec outputs a different number of channels than "
2654 "the input stream contains.");
2655 }
Andreas Huberbe06d262009-08-14 14:37:10 -07002656
Andreas Hubere6c40962009-09-10 14:13:30 -07002657 mOutputFormat->setCString(
2658 kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
Andreas Huberda050cf22009-09-02 14:01:43 -07002659
2660 // Use the codec-advertised number of channels, as some
2661 // codecs appear to output stereo even if the input data is
2662 // mono.
2663 mOutputFormat->setInt32(kKeyChannelCount, params.nChannels);
2664
2665 // The codec-reported sampleRate is not reliable...
2666 mOutputFormat->setInt32(kKeySampleRate, sampleRate);
2667 } else if (audio_def->eEncoding == OMX_AUDIO_CodingAMR) {
Andreas Huber7ae02c82009-09-09 16:29:47 -07002668 OMX_AUDIO_PARAM_AMRTYPE amr;
2669 InitOMXParams(&amr);
2670 amr.nPortIndex = kPortIndexOutput;
2671
Andreas Huber784202e2009-10-15 13:46:54 -07002672 err = mOMX->getParameter(
Andreas Huber7ae02c82009-09-09 16:29:47 -07002673 mNode, OMX_IndexParamAudioAmr, &amr, sizeof(amr));
2674 CHECK_EQ(err, OK);
2675
2676 CHECK_EQ(amr.nChannels, 1);
2677 mOutputFormat->setInt32(kKeyChannelCount, 1);
2678
2679 if (amr.eAMRBandMode >= OMX_AUDIO_AMRBandModeNB0
2680 && amr.eAMRBandMode <= OMX_AUDIO_AMRBandModeNB7) {
Andreas Hubere6c40962009-09-10 14:13:30 -07002681 mOutputFormat->setCString(
2682 kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AMR_NB);
Andreas Huber7ae02c82009-09-09 16:29:47 -07002683 mOutputFormat->setInt32(kKeySampleRate, 8000);
2684 } else if (amr.eAMRBandMode >= OMX_AUDIO_AMRBandModeWB0
2685 && amr.eAMRBandMode <= OMX_AUDIO_AMRBandModeWB8) {
Andreas Hubere6c40962009-09-10 14:13:30 -07002686 mOutputFormat->setCString(
2687 kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AMR_WB);
Andreas Huber7ae02c82009-09-09 16:29:47 -07002688 mOutputFormat->setInt32(kKeySampleRate, 16000);
2689 } else {
2690 CHECK(!"Unknown AMR band mode.");
2691 }
Andreas Huberda050cf22009-09-02 14:01:43 -07002692 } else if (audio_def->eEncoding == OMX_AUDIO_CodingAAC) {
Andreas Hubere6c40962009-09-10 14:13:30 -07002693 mOutputFormat->setCString(
2694 kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
Andreas Huberda050cf22009-09-02 14:01:43 -07002695 } else {
2696 CHECK(!"Should not be here. Unknown audio encoding.");
Andreas Huber43ad6eaf2009-09-01 16:02:43 -07002697 }
Andreas Huberbe06d262009-08-14 14:37:10 -07002698 break;
2699 }
2700
2701 case OMX_PortDomainVideo:
2702 {
2703 OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
2704
2705 if (video_def->eCompressionFormat == OMX_VIDEO_CodingUnused) {
Andreas Hubere6c40962009-09-10 14:13:30 -07002706 mOutputFormat->setCString(
2707 kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
Andreas Huberbe06d262009-08-14 14:37:10 -07002708 } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingMPEG4) {
Andreas Hubere6c40962009-09-10 14:13:30 -07002709 mOutputFormat->setCString(
2710 kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
Andreas Huberbe06d262009-08-14 14:37:10 -07002711 } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingH263) {
Andreas Hubere6c40962009-09-10 14:13:30 -07002712 mOutputFormat->setCString(
2713 kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263);
Andreas Huberbe06d262009-08-14 14:37:10 -07002714 } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingAVC) {
Andreas Hubere6c40962009-09-10 14:13:30 -07002715 mOutputFormat->setCString(
2716 kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
Andreas Huberbe06d262009-08-14 14:37:10 -07002717 } else {
2718 CHECK(!"Unknown compression format.");
2719 }
2720
2721 if (!strcmp(mComponentName, "OMX.PV.avcdec")) {
2722 // This component appears to be lying to me.
2723 mOutputFormat->setInt32(
2724 kKeyWidth, (video_def->nFrameWidth + 15) & -16);
2725 mOutputFormat->setInt32(
2726 kKeyHeight, (video_def->nFrameHeight + 15) & -16);
2727 } else {
2728 mOutputFormat->setInt32(kKeyWidth, video_def->nFrameWidth);
2729 mOutputFormat->setInt32(kKeyHeight, video_def->nFrameHeight);
2730 }
2731
2732 mOutputFormat->setInt32(kKeyColorFormat, video_def->eColorFormat);
2733 break;
2734 }
2735
2736 default:
2737 {
2738 CHECK(!"should not be here, neither audio nor video.");
2739 break;
2740 }
2741 }
2742}
2743
Andreas Hubere6c40962009-09-10 14:13:30 -07002744////////////////////////////////////////////////////////////////////////////////
2745
2746status_t QueryCodecs(
2747 const sp<IOMX> &omx,
2748 const char *mime, bool queryDecoders,
2749 Vector<CodecCapabilities> *results) {
2750 results->clear();
2751
2752 for (int index = 0;; ++index) {
2753 const char *componentName;
2754
2755 if (!queryDecoders) {
2756 componentName = GetCodec(
2757 kEncoderInfo, sizeof(kEncoderInfo) / sizeof(kEncoderInfo[0]),
2758 mime, index);
2759 } else {
2760 componentName = GetCodec(
2761 kDecoderInfo, sizeof(kDecoderInfo) / sizeof(kDecoderInfo[0]),
2762 mime, index);
2763 }
2764
2765 if (!componentName) {
2766 return OK;
2767 }
2768
Andreas Huber784202e2009-10-15 13:46:54 -07002769 sp<OMXCodecObserver> observer = new OMXCodecObserver;
Andreas Hubere6c40962009-09-10 14:13:30 -07002770 IOMX::node_id node;
Andreas Huber784202e2009-10-15 13:46:54 -07002771 status_t err = omx->allocateNode(componentName, observer, &node);
Andreas Hubere6c40962009-09-10 14:13:30 -07002772
2773 if (err != OK) {
2774 continue;
2775 }
2776
2777 OMXCodec::setComponentRole(omx, node, queryDecoders, mime);
2778
2779 results->push();
2780 CodecCapabilities *caps = &results->editItemAt(results->size() - 1);
2781 caps->mComponentName = componentName;
2782
2783 OMX_VIDEO_PARAM_PROFILELEVELTYPE param;
2784 InitOMXParams(&param);
2785
2786 param.nPortIndex = queryDecoders ? 0 : 1;
2787
2788 for (param.nProfileIndex = 0;; ++param.nProfileIndex) {
Andreas Huber784202e2009-10-15 13:46:54 -07002789 err = omx->getParameter(
Andreas Hubere6c40962009-09-10 14:13:30 -07002790 node, OMX_IndexParamVideoProfileLevelQuerySupported,
2791 &param, sizeof(param));
2792
2793 if (err != OK) {
2794 break;
2795 }
2796
2797 CodecProfileLevel profileLevel;
2798 profileLevel.mProfile = param.eProfile;
2799 profileLevel.mLevel = param.eLevel;
2800
2801 caps->mProfileLevels.push(profileLevel);
2802 }
2803
Andreas Huber784202e2009-10-15 13:46:54 -07002804 CHECK_EQ(omx->freeNode(node), OK);
Andreas Hubere6c40962009-09-10 14:13:30 -07002805 }
2806}
2807
Andreas Huberbe06d262009-08-14 14:37:10 -07002808} // namespace android