blob: fc3c05b8818f60bb850a9d329eab36d49ea14f2e [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 Huber8c7ab032009-12-07 11:23:44 -080021#if BUILD_WITH_FULL_STAGEFRIGHT
Andreas Huberdacaa732009-12-07 09:56:32 -080022#include "include/AACDecoder.h"
Andreas Hubera30d4002009-12-08 15:40:06 -080023#include "include/AMRNBDecoder.h"
24#include "include/AMRWBDecoder.h"
Andreas Huber4a0ec3f2009-12-10 09:44:29 -080025#include "include/AVCDecoder.h"
Andreas Huber250f2432009-12-07 14:22:35 -080026#include "include/MP3Decoder.h"
Andreas Huber8c7ab032009-12-07 11:23:44 -080027#endif
28
Andreas Huberbd7b43b2009-10-13 10:22:55 -070029#include "include/ESDS.h"
30
Andreas Huberbe06d262009-08-14 14:37:10 -070031#include <binder/IServiceManager.h>
32#include <binder/MemoryDealer.h>
33#include <binder/ProcessState.h>
34#include <media/IMediaPlayerService.h>
Andreas Huberbe06d262009-08-14 14:37:10 -070035#include <media/stagefright/MediaBuffer.h>
36#include <media/stagefright/MediaBufferGroup.h>
37#include <media/stagefright/MediaDebug.h>
Andreas Hubere6c40962009-09-10 14:13:30 -070038#include <media/stagefright/MediaDefs.h>
Andreas Huberbe06d262009-08-14 14:37:10 -070039#include <media/stagefright/MediaExtractor.h>
40#include <media/stagefright/MetaData.h>
Andreas Huberbe06d262009-08-14 14:37:10 -070041#include <media/stagefright/OMXCodec.h>
Andreas Huberebf66ea2009-08-19 13:32:58 -070042#include <media/stagefright/Utils.h>
Andreas Huberbe06d262009-08-14 14:37:10 -070043#include <utils/Vector.h>
44
45#include <OMX_Audio.h>
46#include <OMX_Component.h>
47
48namespace android {
49
Andreas Huber8b432b12009-10-07 13:36:52 -070050static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
51
Andreas Huberbe06d262009-08-14 14:37:10 -070052struct CodecInfo {
53 const char *mime;
54 const char *codec;
55};
56
57static const CodecInfo kDecoderInfo[] = {
Andreas Hubere6c40962009-09-10 14:13:30 -070058 { MEDIA_MIMETYPE_IMAGE_JPEG, "OMX.TI.JPEG.decode" },
59 { MEDIA_MIMETYPE_AUDIO_MPEG, "OMX.TI.MP3.decode" },
60 { MEDIA_MIMETYPE_AUDIO_MPEG, "OMX.PV.mp3dec" },
61 { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.TI.AMR.decode" },
62 { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.PV.amrdec" },
63 { MEDIA_MIMETYPE_AUDIO_AMR_WB, "OMX.TI.WBAMR.decode" },
64 { MEDIA_MIMETYPE_AUDIO_AMR_WB, "OMX.PV.amrdec" },
65 { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.TI.AAC.decode" },
66 { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.PV.aacdec" },
67 { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.qcom.video.decoder.mpeg4" },
68 { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.TI.Video.Decoder" },
69 { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.PV.mpeg4dec" },
70 { MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.video.decoder.h263" },
71 { MEDIA_MIMETYPE_VIDEO_H263, "OMX.TI.Video.Decoder" },
72 { MEDIA_MIMETYPE_VIDEO_H263, "OMX.PV.h263dec" },
73 { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.qcom.video.decoder.avc" },
74 { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.TI.Video.Decoder" },
75 { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.PV.avcdec" },
Andreas Huberbe06d262009-08-14 14:37:10 -070076};
77
78static const CodecInfo kEncoderInfo[] = {
Andreas Hubere6c40962009-09-10 14:13:30 -070079 { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.TI.AMR.encode" },
80 { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.PV.amrencnb" },
81 { MEDIA_MIMETYPE_AUDIO_AMR_WB, "OMX.TI.WBAMR.encode" },
82 { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.TI.AAC.encode" },
83 { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.PV.aacenc" },
84 { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.qcom.video.encoder.mpeg4" },
85 { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.TI.Video.encoder" },
86 { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.PV.mpeg4enc" },
87 { MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.video.encoder.h263" },
88 { MEDIA_MIMETYPE_VIDEO_H263, "OMX.TI.Video.encoder" },
89 { MEDIA_MIMETYPE_VIDEO_H263, "OMX.PV.h263enc" },
90 { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.TI.Video.encoder" },
91 { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.PV.avcenc" },
Andreas Huberbe06d262009-08-14 14:37:10 -070092};
93
Andreas Hubere0873732009-09-10 09:57:53 -070094#define CODEC_LOGI(x, ...) LOGI("[%s] "x, mComponentName, ##__VA_ARGS__)
Andreas Huber4c483422009-09-02 16:05:36 -070095#define CODEC_LOGV(x, ...) LOGV("[%s] "x, mComponentName, ##__VA_ARGS__)
96
Andreas Huberbe06d262009-08-14 14:37:10 -070097struct OMXCodecObserver : public BnOMXObserver {
Andreas Huber784202e2009-10-15 13:46:54 -070098 OMXCodecObserver() {
99 }
100
101 void setCodec(const sp<OMXCodec> &target) {
102 mTarget = target;
Andreas Huberbe06d262009-08-14 14:37:10 -0700103 }
104
105 // from IOMXObserver
Andreas Huber784202e2009-10-15 13:46:54 -0700106 virtual void onMessage(const omx_message &msg) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700107 sp<OMXCodec> codec = mTarget.promote();
108
109 if (codec.get() != NULL) {
110 codec->on_message(msg);
111 }
112 }
113
114protected:
115 virtual ~OMXCodecObserver() {}
116
117private:
118 wp<OMXCodec> mTarget;
119
120 OMXCodecObserver(const OMXCodecObserver &);
121 OMXCodecObserver &operator=(const OMXCodecObserver &);
122};
123
124static const char *GetCodec(const CodecInfo *info, size_t numInfos,
125 const char *mime, int index) {
126 CHECK(index >= 0);
127 for(size_t i = 0; i < numInfos; ++i) {
128 if (!strcasecmp(mime, info[i].mime)) {
129 if (index == 0) {
130 return info[i].codec;
131 }
132
133 --index;
134 }
135 }
136
137 return NULL;
138}
139
Andreas Huberebf66ea2009-08-19 13:32:58 -0700140enum {
141 kAVCProfileBaseline = 0x42,
142 kAVCProfileMain = 0x4d,
143 kAVCProfileExtended = 0x58,
144 kAVCProfileHigh = 0x64,
145 kAVCProfileHigh10 = 0x6e,
146 kAVCProfileHigh422 = 0x7a,
147 kAVCProfileHigh444 = 0xf4,
148 kAVCProfileCAVLC444Intra = 0x2c
149};
150
151static const char *AVCProfileToString(uint8_t profile) {
152 switch (profile) {
153 case kAVCProfileBaseline:
154 return "Baseline";
155 case kAVCProfileMain:
156 return "Main";
157 case kAVCProfileExtended:
158 return "Extended";
159 case kAVCProfileHigh:
160 return "High";
161 case kAVCProfileHigh10:
162 return "High 10";
163 case kAVCProfileHigh422:
164 return "High 422";
165 case kAVCProfileHigh444:
166 return "High 444";
167 case kAVCProfileCAVLC444Intra:
168 return "CAVLC 444 Intra";
169 default: return "Unknown";
170 }
171}
172
Andreas Huber4c483422009-09-02 16:05:36 -0700173template<class T>
174static void InitOMXParams(T *params) {
175 params->nSize = sizeof(T);
176 params->nVersion.s.nVersionMajor = 1;
177 params->nVersion.s.nVersionMinor = 0;
178 params->nVersion.s.nRevision = 0;
179 params->nVersion.s.nStep = 0;
180}
181
Andreas Hubere13526a2009-10-22 10:43:34 -0700182static bool IsSoftwareCodec(const char *componentName) {
183 if (!strncmp("OMX.PV.", componentName, 7)) {
184 return true;
Andreas Huberbe06d262009-08-14 14:37:10 -0700185 }
186
Andreas Hubere13526a2009-10-22 10:43:34 -0700187 return false;
188}
189
190static int CompareSoftwareCodecsFirst(
191 const String8 *elem1, const String8 *elem2) {
192 bool isSoftwareCodec1 = IsSoftwareCodec(elem1->string());
193 bool isSoftwareCodec2 = IsSoftwareCodec(elem2->string());
194
195 if (isSoftwareCodec1) {
196 if (isSoftwareCodec2) { return 0; }
197 return -1;
198 }
199
200 if (isSoftwareCodec2) {
201 return 1;
202 }
203
204 return 0;
205}
206
207// static
208uint32_t OMXCodec::getComponentQuirks(const char *componentName) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700209 uint32_t quirks = 0;
Andreas Hubere13526a2009-10-22 10:43:34 -0700210
Andreas Huberbe06d262009-08-14 14:37:10 -0700211 if (!strcmp(componentName, "OMX.PV.avcdec")) {
Andreas Huber4f5e6022009-08-19 09:29:34 -0700212 quirks |= kWantsNALFragments;
Andreas Huberbe06d262009-08-14 14:37:10 -0700213 }
214 if (!strcmp(componentName, "OMX.TI.MP3.decode")) {
215 quirks |= kNeedsFlushBeforeDisable;
216 }
217 if (!strcmp(componentName, "OMX.TI.AAC.decode")) {
218 quirks |= kNeedsFlushBeforeDisable;
Andreas Huber404cc412009-08-25 14:26:05 -0700219 quirks |= kRequiresFlushCompleteEmulation;
Andreas Huberbe06d262009-08-14 14:37:10 -0700220 }
221 if (!strncmp(componentName, "OMX.qcom.video.encoder.", 23)) {
222 quirks |= kRequiresLoadedToIdleAfterAllocation;
223 quirks |= kRequiresAllocateBufferOnInputPorts;
Andreas Huberb482ce82009-10-29 12:02:48 -0700224 quirks |= kRequiresAllocateBufferOnOutputPorts;
Andreas Huberbe06d262009-08-14 14:37:10 -0700225 }
Andreas Hubera7d0cf42009-09-04 07:48:51 -0700226 if (!strncmp(componentName, "OMX.qcom.video.decoder.", 23)) {
227 // XXX Required on P....on only.
228 quirks |= kRequiresAllocateBufferOnOutputPorts;
229 }
Andreas Huberbe06d262009-08-14 14:37:10 -0700230
Andreas Huber2dc64d82009-09-11 12:58:53 -0700231 if (!strncmp(componentName, "OMX.TI.", 7)) {
232 // Apparently I must not use OMX_UseBuffer on either input or
233 // output ports on any of the TI components or quote:
234 // "(I) may have unexpected problem (sic) which can be timing related
235 // and hard to reproduce."
236
237 quirks |= kRequiresAllocateBufferOnInputPorts;
238 quirks |= kRequiresAllocateBufferOnOutputPorts;
239 }
240
Andreas Hubere13526a2009-10-22 10:43:34 -0700241 return quirks;
242}
243
244// static
245void OMXCodec::findMatchingCodecs(
246 const char *mime,
247 bool createEncoder, const char *matchComponentName,
248 uint32_t flags,
249 Vector<String8> *matchingCodecs) {
250 matchingCodecs->clear();
251
252 for (int index = 0;; ++index) {
253 const char *componentName;
254
255 if (createEncoder) {
256 componentName = GetCodec(
257 kEncoderInfo,
258 sizeof(kEncoderInfo) / sizeof(kEncoderInfo[0]),
259 mime, index);
260 } else {
261 componentName = GetCodec(
262 kDecoderInfo,
263 sizeof(kDecoderInfo) / sizeof(kDecoderInfo[0]),
264 mime, index);
265 }
266
267 if (!componentName) {
268 break;
269 }
270
271 // If a specific codec is requested, skip the non-matching ones.
272 if (matchComponentName && strcmp(componentName, matchComponentName)) {
273 continue;
274 }
275
276 matchingCodecs->push(String8(componentName));
277 }
278
279 if (flags & kPreferSoftwareCodecs) {
280 matchingCodecs->sort(CompareSoftwareCodecsFirst);
281 }
282}
283
284// static
Andreas Huber91eb0352009-12-07 09:43:00 -0800285sp<MediaSource> OMXCodec::Create(
Andreas Hubere13526a2009-10-22 10:43:34 -0700286 const sp<IOMX> &omx,
287 const sp<MetaData> &meta, bool createEncoder,
288 const sp<MediaSource> &source,
289 const char *matchComponentName,
290 uint32_t flags) {
291 const char *mime;
292 bool success = meta->findCString(kKeyMIMEType, &mime);
293 CHECK(success);
294
Andreas Huber8c7ab032009-12-07 11:23:44 -0800295#if BUILD_WITH_FULL_STAGEFRIGHT
Andreas Huberdacaa732009-12-07 09:56:32 -0800296 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
297 return new AACDecoder(source);
Andreas Hubera30d4002009-12-08 15:40:06 -0800298 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB)) {
299 return new AMRNBDecoder(source);
300 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB)) {
301 return new AMRWBDecoder(source);
Andreas Huber250f2432009-12-07 14:22:35 -0800302 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {
303 return new MP3Decoder(source);
Andreas Huber4a0ec3f2009-12-10 09:44:29 -0800304 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)
305 && (flags & kPreferSoftwareCodecs)) {
306 return new AVCDecoder(source);
Andreas Huberdacaa732009-12-07 09:56:32 -0800307 }
Andreas Huber8c7ab032009-12-07 11:23:44 -0800308#endif
Andreas Huberdacaa732009-12-07 09:56:32 -0800309
Andreas Hubere13526a2009-10-22 10:43:34 -0700310 Vector<String8> matchingCodecs;
311 findMatchingCodecs(
312 mime, createEncoder, matchComponentName, flags, &matchingCodecs);
313
314 if (matchingCodecs.isEmpty()) {
315 return NULL;
316 }
317
318 sp<OMXCodecObserver> observer = new OMXCodecObserver;
319 IOMX::node_id node = 0;
320 success = false;
321
322 const char *componentName;
323 for (size_t i = 0; i < matchingCodecs.size(); ++i) {
324 componentName = matchingCodecs[i].string();
325
326 LOGV("Attempting to allocate OMX node '%s'", componentName);
327
328 status_t err = omx->allocateNode(componentName, observer, &node);
329 if (err == OK) {
330 LOGV("Successfully allocated OMX node '%s'", componentName);
331
332 success = true;
333 break;
334 }
335 }
336
337 if (!success) {
338 return NULL;
339 }
340
Andreas Huberbe06d262009-08-14 14:37:10 -0700341 sp<OMXCodec> codec = new OMXCodec(
Andreas Hubere13526a2009-10-22 10:43:34 -0700342 omx, node, getComponentQuirks(componentName),
343 createEncoder, mime, componentName,
Andreas Huberbe06d262009-08-14 14:37:10 -0700344 source);
345
Andreas Huber784202e2009-10-15 13:46:54 -0700346 observer->setCodec(codec);
347
Andreas Huberbe06d262009-08-14 14:37:10 -0700348 uint32_t type;
349 const void *data;
350 size_t size;
351 if (meta->findData(kKeyESDS, &type, &data, &size)) {
352 ESDS esds((const char *)data, size);
353 CHECK_EQ(esds.InitCheck(), OK);
354
355 const void *codec_specific_data;
356 size_t codec_specific_data_size;
357 esds.getCodecSpecificInfo(
358 &codec_specific_data, &codec_specific_data_size);
359
360 printf("found codec-specific data of size %d\n",
361 codec_specific_data_size);
362
363 codec->addCodecSpecificData(
364 codec_specific_data, codec_specific_data_size);
365 } else if (meta->findData(kKeyAVCC, &type, &data, &size)) {
366 printf("found avcc of size %d\n", size);
367
Andreas Huberebf66ea2009-08-19 13:32:58 -0700368 // Parse the AVCDecoderConfigurationRecord
369
370 const uint8_t *ptr = (const uint8_t *)data;
371
372 CHECK(size >= 7);
373 CHECK_EQ(ptr[0], 1); // configurationVersion == 1
374 uint8_t profile = ptr[1];
375 uint8_t level = ptr[3];
376
Andreas Huber44e15c42009-11-23 14:39:38 -0800377 // There is decodable content out there that fails the following
378 // assertion, let's be lenient for now...
379 // CHECK((ptr[4] >> 2) == 0x3f); // reserved
Andreas Huberebf66ea2009-08-19 13:32:58 -0700380
381 size_t lengthSize = 1 + (ptr[4] & 3);
382
383 // commented out check below as H264_QVGA_500_NO_AUDIO.3gp
384 // violates it...
385 // CHECK((ptr[5] >> 5) == 7); // reserved
386
387 size_t numSeqParameterSets = ptr[5] & 31;
388
389 ptr += 6;
Andreas Huberbe06d262009-08-14 14:37:10 -0700390 size -= 6;
Andreas Huberebf66ea2009-08-19 13:32:58 -0700391
392 for (size_t i = 0; i < numSeqParameterSets; ++i) {
393 CHECK(size >= 2);
394 size_t length = U16_AT(ptr);
Andreas Huberbe06d262009-08-14 14:37:10 -0700395
396 ptr += 2;
397 size -= 2;
398
Andreas Huberbe06d262009-08-14 14:37:10 -0700399 CHECK(size >= length);
400
401 codec->addCodecSpecificData(ptr, length);
402
403 ptr += length;
404 size -= length;
Andreas Huberebf66ea2009-08-19 13:32:58 -0700405 }
Andreas Huberbe06d262009-08-14 14:37:10 -0700406
Andreas Huberebf66ea2009-08-19 13:32:58 -0700407 CHECK(size >= 1);
408 size_t numPictureParameterSets = *ptr;
409 ++ptr;
410 --size;
Andreas Huberbe06d262009-08-14 14:37:10 -0700411
Andreas Huberebf66ea2009-08-19 13:32:58 -0700412 for (size_t i = 0; i < numPictureParameterSets; ++i) {
413 CHECK(size >= 2);
414 size_t length = U16_AT(ptr);
415
416 ptr += 2;
417 size -= 2;
418
419 CHECK(size >= length);
420
421 codec->addCodecSpecificData(ptr, length);
422
423 ptr += length;
424 size -= length;
425 }
426
Andreas Huber53a76bd2009-10-06 16:20:44 -0700427 LOGV("AVC profile = %d (%s), level = %d",
Andreas Huberebf66ea2009-08-19 13:32:58 -0700428 (int)profile, AVCProfileToString(profile), (int)level / 10);
429
430 if (!strcmp(componentName, "OMX.TI.Video.Decoder")
431 && (profile != kAVCProfileBaseline || level > 39)) {
Andreas Huber784202e2009-10-15 13:46:54 -0700432 // This stream exceeds the decoder's capabilities. The decoder
433 // does not handle this gracefully and would clobber the heap
434 // and wreak havoc instead...
Andreas Huberebf66ea2009-08-19 13:32:58 -0700435
436 LOGE("Profile and/or level exceed the decoder's capabilities.");
437 return NULL;
Andreas Huberbe06d262009-08-14 14:37:10 -0700438 }
439 }
440
Andreas Hubere6c40962009-09-10 14:13:30 -0700441 if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime)) {
Andreas Huber8768f2c2009-12-01 15:26:54 -0800442 codec->setAMRFormat(false /* isWAMR */);
Andreas Huberbe06d262009-08-14 14:37:10 -0700443 }
Andreas Hubere6c40962009-09-10 14:13:30 -0700444 if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) {
Andreas Huber8768f2c2009-12-01 15:26:54 -0800445 codec->setAMRFormat(true /* isWAMR */);
Andreas Huberee606e62009-09-08 10:19:21 -0700446 }
Andreas Hubere6c40962009-09-10 14:13:30 -0700447 if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) {
Andreas Huber43ad6eaf2009-09-01 16:02:43 -0700448 int32_t numChannels, sampleRate;
449 CHECK(meta->findInt32(kKeyChannelCount, &numChannels));
450 CHECK(meta->findInt32(kKeySampleRate, &sampleRate));
451
452 codec->setAACFormat(numChannels, sampleRate);
Andreas Huberbe06d262009-08-14 14:37:10 -0700453 }
454 if (!strncasecmp(mime, "video/", 6)) {
455 int32_t width, height;
456 bool success = meta->findInt32(kKeyWidth, &width);
457 success = success && meta->findInt32(kKeyHeight, &height);
Andreas Huber5c0a9132009-08-20 11:16:40 -0700458 CHECK(success);
Andreas Huberbe06d262009-08-14 14:37:10 -0700459
460 if (createEncoder) {
461 codec->setVideoInputFormat(mime, width, height);
462 } else {
463 codec->setVideoOutputFormat(mime, width, height);
464 }
465 }
Andreas Hubere6c40962009-09-10 14:13:30 -0700466 if (!strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_JPEG)
Andreas Huberbe06d262009-08-14 14:37:10 -0700467 && !strcmp(componentName, "OMX.TI.JPEG.decode")) {
468 OMX_COLOR_FORMATTYPE format =
469 OMX_COLOR_Format32bitARGB8888;
470 // OMX_COLOR_FormatYUV420PackedPlanar;
471 // OMX_COLOR_FormatCbYCrY;
472 // OMX_COLOR_FormatYUV411Planar;
473
474 int32_t width, height;
475 bool success = meta->findInt32(kKeyWidth, &width);
476 success = success && meta->findInt32(kKeyHeight, &height);
Andreas Huber5c0a9132009-08-20 11:16:40 -0700477
478 int32_t compressedSize;
479 success = success && meta->findInt32(
Andreas Huberda050cf22009-09-02 14:01:43 -0700480 kKeyMaxInputSize, &compressedSize);
Andreas Huber5c0a9132009-08-20 11:16:40 -0700481
482 CHECK(success);
483 CHECK(compressedSize > 0);
Andreas Huberbe06d262009-08-14 14:37:10 -0700484
485 codec->setImageOutputFormat(format, width, height);
Andreas Huber5c0a9132009-08-20 11:16:40 -0700486 codec->setJPEGInputFormat(width, height, (OMX_U32)compressedSize);
Andreas Huberbe06d262009-08-14 14:37:10 -0700487 }
488
Andreas Huberda050cf22009-09-02 14:01:43 -0700489 int32_t maxInputSize;
Andreas Huber1bceff92009-11-23 14:03:32 -0800490 if (meta->findInt32(kKeyMaxInputSize, &maxInputSize)) {
Andreas Huberda050cf22009-09-02 14:01:43 -0700491 codec->setMinBufferSize(kPortIndexInput, (OMX_U32)maxInputSize);
492 }
493
494 if (!strcmp(componentName, "OMX.TI.AMR.encode")
495 || !strcmp(componentName, "OMX.TI.WBAMR.encode")) {
496 codec->setMinBufferSize(kPortIndexOutput, 8192); // XXX
497 }
498
Andreas Huberbe06d262009-08-14 14:37:10 -0700499 codec->initOutputFormat(meta);
500
501 return codec;
502}
503
Andreas Huberda050cf22009-09-02 14:01:43 -0700504void OMXCodec::setMinBufferSize(OMX_U32 portIndex, OMX_U32 size) {
505 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -0700506 InitOMXParams(&def);
Andreas Huberda050cf22009-09-02 14:01:43 -0700507 def.nPortIndex = portIndex;
508
Andreas Huber784202e2009-10-15 13:46:54 -0700509 status_t err = mOMX->getParameter(
Andreas Huberda050cf22009-09-02 14:01:43 -0700510 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
511 CHECK_EQ(err, OK);
512
513 if (def.nBufferSize < size) {
514 def.nBufferSize = size;
Andreas Huberda050cf22009-09-02 14:01:43 -0700515 }
516
Andreas Huber784202e2009-10-15 13:46:54 -0700517 err = mOMX->setParameter(
Andreas Huberda050cf22009-09-02 14:01:43 -0700518 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
519 CHECK_EQ(err, OK);
Andreas Huber1bceff92009-11-23 14:03:32 -0800520
521 err = mOMX->getParameter(
522 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
523 CHECK_EQ(err, OK);
524
525 // Make sure the setting actually stuck.
526 CHECK(def.nBufferSize >= size);
Andreas Huberda050cf22009-09-02 14:01:43 -0700527}
528
Andreas Huberbe06d262009-08-14 14:37:10 -0700529status_t OMXCodec::setVideoPortFormatType(
530 OMX_U32 portIndex,
531 OMX_VIDEO_CODINGTYPE compressionFormat,
532 OMX_COLOR_FORMATTYPE colorFormat) {
533 OMX_VIDEO_PARAM_PORTFORMATTYPE format;
Andreas Huber4c483422009-09-02 16:05:36 -0700534 InitOMXParams(&format);
Andreas Huberbe06d262009-08-14 14:37:10 -0700535 format.nPortIndex = portIndex;
536 format.nIndex = 0;
537 bool found = false;
538
539 OMX_U32 index = 0;
540 for (;;) {
541 format.nIndex = index;
Andreas Huber784202e2009-10-15 13:46:54 -0700542 status_t err = mOMX->getParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -0700543 mNode, OMX_IndexParamVideoPortFormat,
544 &format, sizeof(format));
545
546 if (err != OK) {
547 return err;
548 }
549
550 // The following assertion is violated by TI's video decoder.
Andreas Huber5c0a9132009-08-20 11:16:40 -0700551 // CHECK_EQ(format.nIndex, index);
Andreas Huberbe06d262009-08-14 14:37:10 -0700552
553#if 1
Andreas Huber53a76bd2009-10-06 16:20:44 -0700554 CODEC_LOGV("portIndex: %ld, index: %ld, eCompressionFormat=%d eColorFormat=%d",
Andreas Huberbe06d262009-08-14 14:37:10 -0700555 portIndex,
556 index, format.eCompressionFormat, format.eColorFormat);
557#endif
558
559 if (!strcmp("OMX.TI.Video.encoder", mComponentName)) {
560 if (portIndex == kPortIndexInput
561 && colorFormat == format.eColorFormat) {
562 // eCompressionFormat does not seem right.
563 found = true;
564 break;
565 }
566 if (portIndex == kPortIndexOutput
567 && compressionFormat == format.eCompressionFormat) {
568 // eColorFormat does not seem right.
569 found = true;
570 break;
571 }
572 }
573
574 if (format.eCompressionFormat == compressionFormat
575 && format.eColorFormat == colorFormat) {
576 found = true;
577 break;
578 }
579
580 ++index;
581 }
582
583 if (!found) {
584 return UNKNOWN_ERROR;
585 }
586
Andreas Huber53a76bd2009-10-06 16:20:44 -0700587 CODEC_LOGV("found a match.");
Andreas Huber784202e2009-10-15 13:46:54 -0700588 status_t err = mOMX->setParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -0700589 mNode, OMX_IndexParamVideoPortFormat,
590 &format, sizeof(format));
591
592 return err;
593}
594
Andreas Huberb482ce82009-10-29 12:02:48 -0700595static size_t getFrameSize(
596 OMX_COLOR_FORMATTYPE colorFormat, int32_t width, int32_t height) {
597 switch (colorFormat) {
598 case OMX_COLOR_FormatYCbYCr:
599 case OMX_COLOR_FormatCbYCrY:
600 return width * height * 2;
601
602 case OMX_COLOR_FormatYUV420SemiPlanar:
603 return (width * height * 3) / 2;
604
605 default:
606 CHECK(!"Should not be here. Unsupported color format.");
607 break;
608 }
609}
610
Andreas Huberbe06d262009-08-14 14:37:10 -0700611void OMXCodec::setVideoInputFormat(
612 const char *mime, OMX_U32 width, OMX_U32 height) {
Andreas Huber53a76bd2009-10-06 16:20:44 -0700613 CODEC_LOGV("setVideoInputFormat width=%ld, height=%ld", width, height);
Andreas Huberbe06d262009-08-14 14:37:10 -0700614
615 OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused;
Andreas Hubere6c40962009-09-10 14:13:30 -0700616 if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700617 compressionFormat = OMX_VIDEO_CodingAVC;
Andreas Hubere6c40962009-09-10 14:13:30 -0700618 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700619 compressionFormat = OMX_VIDEO_CodingMPEG4;
Andreas Hubere6c40962009-09-10 14:13:30 -0700620 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700621 compressionFormat = OMX_VIDEO_CodingH263;
622 } else {
623 LOGE("Not a supported video mime type: %s", mime);
624 CHECK(!"Should not be here. Not a supported video mime type.");
625 }
626
Andreas Huberea6a38c2009-11-16 15:43:38 -0800627 OMX_COLOR_FORMATTYPE colorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
628 if (!strcasecmp("OMX.TI.Video.encoder", mComponentName)) {
629 colorFormat = OMX_COLOR_FormatYCbYCr;
Andreas Huberbe06d262009-08-14 14:37:10 -0700630 }
631
Andreas Huberb482ce82009-10-29 12:02:48 -0700632 CHECK_EQ(setVideoPortFormatType(
Andreas Huberbe06d262009-08-14 14:37:10 -0700633 kPortIndexInput, OMX_VIDEO_CodingUnused,
Andreas Huberb482ce82009-10-29 12:02:48 -0700634 colorFormat), OK);
Andreas Huberbe06d262009-08-14 14:37:10 -0700635
Andreas Huberb482ce82009-10-29 12:02:48 -0700636 CHECK_EQ(setVideoPortFormatType(
637 kPortIndexOutput, compressionFormat, OMX_COLOR_FormatUnused),
638 OK);
Andreas Huberbe06d262009-08-14 14:37:10 -0700639
640 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -0700641 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -0700642 def.nPortIndex = kPortIndexOutput;
643
Andreas Huber4c483422009-09-02 16:05:36 -0700644 OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
645
Andreas Huber784202e2009-10-15 13:46:54 -0700646 status_t err = mOMX->getParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -0700647 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
648
649 CHECK_EQ(err, OK);
650 CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
651
652 video_def->nFrameWidth = width;
653 video_def->nFrameHeight = height;
654
655 video_def->eCompressionFormat = compressionFormat;
656 video_def->eColorFormat = OMX_COLOR_FormatUnused;
657
Andreas Huber784202e2009-10-15 13:46:54 -0700658 err = mOMX->setParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -0700659 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
660 CHECK_EQ(err, OK);
661
662 ////////////////////////////////////////////////////////////////////////////
663
Andreas Huber4c483422009-09-02 16:05:36 -0700664 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -0700665 def.nPortIndex = kPortIndexInput;
666
Andreas Huber784202e2009-10-15 13:46:54 -0700667 err = mOMX->getParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -0700668 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
669 CHECK_EQ(err, OK);
670
Andreas Huberb482ce82009-10-29 12:02:48 -0700671 def.nBufferSize = getFrameSize(colorFormat, width, height);
Andreas Huber53a76bd2009-10-06 16:20:44 -0700672 CODEC_LOGV("Setting nBufferSize = %ld", def.nBufferSize);
Andreas Huberbe06d262009-08-14 14:37:10 -0700673
674 CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
675
676 video_def->nFrameWidth = width;
677 video_def->nFrameHeight = height;
678 video_def->eCompressionFormat = OMX_VIDEO_CodingUnused;
679 video_def->eColorFormat = colorFormat;
680
Andreas Huberb482ce82009-10-29 12:02:48 -0700681 video_def->xFramerate = 24 << 16; // XXX crucial!
682
Andreas Huber784202e2009-10-15 13:46:54 -0700683 err = mOMX->setParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -0700684 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
685 CHECK_EQ(err, OK);
Andreas Huberb482ce82009-10-29 12:02:48 -0700686
687 switch (compressionFormat) {
688 case OMX_VIDEO_CodingMPEG4:
689 {
690 CHECK_EQ(setupMPEG4EncoderParameters(), OK);
691 break;
692 }
693
694 case OMX_VIDEO_CodingH263:
695 break;
696
Andreas Huberea6a38c2009-11-16 15:43:38 -0800697 case OMX_VIDEO_CodingAVC:
698 {
699 CHECK_EQ(setupAVCEncoderParameters(), OK);
700 break;
701 }
702
Andreas Huberb482ce82009-10-29 12:02:48 -0700703 default:
704 CHECK(!"Support for this compressionFormat to be implemented.");
705 break;
706 }
707}
708
709status_t OMXCodec::setupMPEG4EncoderParameters() {
710 OMX_VIDEO_PARAM_MPEG4TYPE mpeg4type;
711 InitOMXParams(&mpeg4type);
712 mpeg4type.nPortIndex = kPortIndexOutput;
713
714 status_t err = mOMX->getParameter(
715 mNode, OMX_IndexParamVideoMpeg4, &mpeg4type, sizeof(mpeg4type));
716 CHECK_EQ(err, OK);
717
718 mpeg4type.nSliceHeaderSpacing = 0;
719 mpeg4type.bSVH = OMX_FALSE;
720 mpeg4type.bGov = OMX_FALSE;
721
722 mpeg4type.nAllowedPictureTypes =
723 OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP;
724
725 mpeg4type.nPFrames = 23;
726 mpeg4type.nBFrames = 0;
727
728 mpeg4type.nIDCVLCThreshold = 0;
729 mpeg4type.bACPred = OMX_TRUE;
730 mpeg4type.nMaxPacketSize = 256;
731 mpeg4type.nTimeIncRes = 1000;
732 mpeg4type.nHeaderExtension = 0;
733 mpeg4type.bReversibleVLC = OMX_FALSE;
734
735 mpeg4type.eProfile = OMX_VIDEO_MPEG4ProfileCore;
736 mpeg4type.eLevel = OMX_VIDEO_MPEG4Level2;
737
738 err = mOMX->setParameter(
739 mNode, OMX_IndexParamVideoMpeg4, &mpeg4type, sizeof(mpeg4type));
740 CHECK_EQ(err, OK);
741
742 // ----------------
743
744 OMX_VIDEO_PARAM_BITRATETYPE bitrateType;
745 InitOMXParams(&bitrateType);
746 bitrateType.nPortIndex = kPortIndexOutput;
747
748 err = mOMX->getParameter(
749 mNode, OMX_IndexParamVideoBitrate,
750 &bitrateType, sizeof(bitrateType));
751 CHECK_EQ(err, OK);
752
753 bitrateType.eControlRate = OMX_Video_ControlRateVariable;
754 bitrateType.nTargetBitrate = 1000000;
755
756 err = mOMX->setParameter(
757 mNode, OMX_IndexParamVideoBitrate,
758 &bitrateType, sizeof(bitrateType));
759 CHECK_EQ(err, OK);
760
761 // ----------------
762
763 OMX_VIDEO_PARAM_ERRORCORRECTIONTYPE errorCorrectionType;
764 InitOMXParams(&errorCorrectionType);
765 errorCorrectionType.nPortIndex = kPortIndexOutput;
766
767 err = mOMX->getParameter(
768 mNode, OMX_IndexParamVideoErrorCorrection,
769 &errorCorrectionType, sizeof(errorCorrectionType));
770 CHECK_EQ(err, OK);
771
772 errorCorrectionType.bEnableHEC = OMX_FALSE;
773 errorCorrectionType.bEnableResync = OMX_TRUE;
774 errorCorrectionType.nResynchMarkerSpacing = 256;
775 errorCorrectionType.bEnableDataPartitioning = OMX_FALSE;
776 errorCorrectionType.bEnableRVLC = OMX_FALSE;
777
778 err = mOMX->setParameter(
779 mNode, OMX_IndexParamVideoErrorCorrection,
780 &errorCorrectionType, sizeof(errorCorrectionType));
781 CHECK_EQ(err, OK);
782
783 return OK;
Andreas Huberbe06d262009-08-14 14:37:10 -0700784}
785
Andreas Huberea6a38c2009-11-16 15:43:38 -0800786status_t OMXCodec::setupAVCEncoderParameters() {
787 OMX_VIDEO_PARAM_AVCTYPE h264type;
788 InitOMXParams(&h264type);
789 h264type.nPortIndex = kPortIndexOutput;
790
791 status_t err = mOMX->getParameter(
792 mNode, OMX_IndexParamVideoAvc, &h264type, sizeof(h264type));
793 CHECK_EQ(err, OK);
794
795 h264type.nAllowedPictureTypes =
796 OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP;
797
798 h264type.nSliceHeaderSpacing = 0;
799 h264type.nBFrames = 0;
800 h264type.bUseHadamard = OMX_TRUE;
801 h264type.nRefFrames = 1;
802 h264type.nRefIdx10ActiveMinus1 = 0;
803 h264type.nRefIdx11ActiveMinus1 = 0;
804 h264type.bEnableUEP = OMX_FALSE;
805 h264type.bEnableFMO = OMX_FALSE;
806 h264type.bEnableASO = OMX_FALSE;
807 h264type.bEnableRS = OMX_FALSE;
808 h264type.eProfile = OMX_VIDEO_AVCProfileBaseline;
809 h264type.eLevel = OMX_VIDEO_AVCLevel1b;
810 h264type.bFrameMBsOnly = OMX_TRUE;
811 h264type.bMBAFF = OMX_FALSE;
812 h264type.bEntropyCodingCABAC = OMX_FALSE;
813 h264type.bWeightedPPrediction = OMX_FALSE;
814 h264type.bconstIpred = OMX_FALSE;
815 h264type.bDirect8x8Inference = OMX_FALSE;
816 h264type.bDirectSpatialTemporal = OMX_FALSE;
817 h264type.nCabacInitIdc = 0;
818 h264type.eLoopFilterMode = OMX_VIDEO_AVCLoopFilterEnable;
819
820 err = mOMX->setParameter(
821 mNode, OMX_IndexParamVideoAvc, &h264type, sizeof(h264type));
822 CHECK_EQ(err, OK);
823
824 OMX_VIDEO_PARAM_BITRATETYPE bitrateType;
825 InitOMXParams(&bitrateType);
826 bitrateType.nPortIndex = kPortIndexOutput;
827
828 err = mOMX->getParameter(
829 mNode, OMX_IndexParamVideoBitrate,
830 &bitrateType, sizeof(bitrateType));
831 CHECK_EQ(err, OK);
832
833 bitrateType.eControlRate = OMX_Video_ControlRateVariable;
834 bitrateType.nTargetBitrate = 1000000;
835
836 err = mOMX->setParameter(
837 mNode, OMX_IndexParamVideoBitrate,
838 &bitrateType, sizeof(bitrateType));
839 CHECK_EQ(err, OK);
840
841 return OK;
842}
843
Andreas Huberbe06d262009-08-14 14:37:10 -0700844void OMXCodec::setVideoOutputFormat(
845 const char *mime, OMX_U32 width, OMX_U32 height) {
Andreas Huber53a76bd2009-10-06 16:20:44 -0700846 CODEC_LOGV("setVideoOutputFormat width=%ld, height=%ld", width, height);
Andreas Huberbe06d262009-08-14 14:37:10 -0700847
Andreas Huberbe06d262009-08-14 14:37:10 -0700848 OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused;
Andreas Hubere6c40962009-09-10 14:13:30 -0700849 if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700850 compressionFormat = OMX_VIDEO_CodingAVC;
Andreas Hubere6c40962009-09-10 14:13:30 -0700851 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700852 compressionFormat = OMX_VIDEO_CodingMPEG4;
Andreas Hubere6c40962009-09-10 14:13:30 -0700853 } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700854 compressionFormat = OMX_VIDEO_CodingH263;
855 } else {
856 LOGE("Not a supported video mime type: %s", mime);
857 CHECK(!"Should not be here. Not a supported video mime type.");
858 }
859
860 setVideoPortFormatType(
861 kPortIndexInput, compressionFormat, OMX_COLOR_FormatUnused);
862
863#if 1
864 {
865 OMX_VIDEO_PARAM_PORTFORMATTYPE format;
Andreas Huber4c483422009-09-02 16:05:36 -0700866 InitOMXParams(&format);
Andreas Huberbe06d262009-08-14 14:37:10 -0700867 format.nPortIndex = kPortIndexOutput;
868 format.nIndex = 0;
869
Andreas Huber784202e2009-10-15 13:46:54 -0700870 status_t err = mOMX->getParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -0700871 mNode, OMX_IndexParamVideoPortFormat,
872 &format, sizeof(format));
873 CHECK_EQ(err, OK);
874 CHECK_EQ(format.eCompressionFormat, OMX_VIDEO_CodingUnused);
875
876 static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
877
878 CHECK(format.eColorFormat == OMX_COLOR_FormatYUV420Planar
879 || format.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar
880 || format.eColorFormat == OMX_COLOR_FormatCbYCrY
881 || format.eColorFormat == OMX_QCOM_COLOR_FormatYVU420SemiPlanar);
882
Andreas Huber784202e2009-10-15 13:46:54 -0700883 err = mOMX->setParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -0700884 mNode, OMX_IndexParamVideoPortFormat,
885 &format, sizeof(format));
886 CHECK_EQ(err, OK);
887 }
888#endif
889
890 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -0700891 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -0700892 def.nPortIndex = kPortIndexInput;
893
Andreas Huber4c483422009-09-02 16:05:36 -0700894 OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
895
Andreas Huber784202e2009-10-15 13:46:54 -0700896 status_t err = mOMX->getParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -0700897 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
898
899 CHECK_EQ(err, OK);
900
901#if 1
902 // XXX Need a (much) better heuristic to compute input buffer sizes.
903 const size_t X = 64 * 1024;
904 if (def.nBufferSize < X) {
905 def.nBufferSize = X;
906 }
907#endif
908
909 CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
910
911 video_def->nFrameWidth = width;
912 video_def->nFrameHeight = height;
913
Andreas Huberb482ce82009-10-29 12:02:48 -0700914 video_def->eCompressionFormat = compressionFormat;
Andreas Huberbe06d262009-08-14 14:37:10 -0700915 video_def->eColorFormat = OMX_COLOR_FormatUnused;
916
Andreas Huber784202e2009-10-15 13:46:54 -0700917 err = mOMX->setParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -0700918 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
919 CHECK_EQ(err, OK);
920
921 ////////////////////////////////////////////////////////////////////////////
922
Andreas Huber4c483422009-09-02 16:05:36 -0700923 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -0700924 def.nPortIndex = kPortIndexOutput;
925
Andreas Huber784202e2009-10-15 13:46:54 -0700926 err = mOMX->getParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -0700927 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
928 CHECK_EQ(err, OK);
929 CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
930
931#if 0
932 def.nBufferSize =
933 (((width + 15) & -16) * ((height + 15) & -16) * 3) / 2; // YUV420
934#endif
935
936 video_def->nFrameWidth = width;
937 video_def->nFrameHeight = height;
938
Andreas Huber784202e2009-10-15 13:46:54 -0700939 err = mOMX->setParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -0700940 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
941 CHECK_EQ(err, OK);
942}
943
Andreas Huberbe06d262009-08-14 14:37:10 -0700944OMXCodec::OMXCodec(
945 const sp<IOMX> &omx, IOMX::node_id node, uint32_t quirks,
Andreas Huberebf66ea2009-08-19 13:32:58 -0700946 bool isEncoder,
Andreas Huberbe06d262009-08-14 14:37:10 -0700947 const char *mime,
948 const char *componentName,
949 const sp<MediaSource> &source)
950 : mOMX(omx),
951 mNode(node),
952 mQuirks(quirks),
953 mIsEncoder(isEncoder),
954 mMIME(strdup(mime)),
955 mComponentName(strdup(componentName)),
956 mSource(source),
957 mCodecSpecificDataIndex(0),
Andreas Huberbe06d262009-08-14 14:37:10 -0700958 mState(LOADED),
Andreas Huber42978e52009-08-27 10:08:39 -0700959 mInitialBufferSubmit(true),
Andreas Huberbe06d262009-08-14 14:37:10 -0700960 mSignalledEOS(false),
961 mNoMoreOutputData(false),
Andreas Hubercfd55572009-10-09 14:11:28 -0700962 mOutputPortSettingsHaveChanged(false),
Andreas Huberbe06d262009-08-14 14:37:10 -0700963 mSeekTimeUs(-1) {
964 mPortStatus[kPortIndexInput] = ENABLED;
965 mPortStatus[kPortIndexOutput] = ENABLED;
966
Andreas Huber4c483422009-09-02 16:05:36 -0700967 setComponentRole();
968}
969
Andreas Hubere6c40962009-09-10 14:13:30 -0700970// static
971void OMXCodec::setComponentRole(
972 const sp<IOMX> &omx, IOMX::node_id node, bool isEncoder,
973 const char *mime) {
Andreas Huber4c483422009-09-02 16:05:36 -0700974 struct MimeToRole {
975 const char *mime;
976 const char *decoderRole;
977 const char *encoderRole;
978 };
979
980 static const MimeToRole kMimeToRole[] = {
Andreas Hubere6c40962009-09-10 14:13:30 -0700981 { MEDIA_MIMETYPE_AUDIO_MPEG,
982 "audio_decoder.mp3", "audio_encoder.mp3" },
983 { MEDIA_MIMETYPE_AUDIO_AMR_NB,
984 "audio_decoder.amrnb", "audio_encoder.amrnb" },
985 { MEDIA_MIMETYPE_AUDIO_AMR_WB,
986 "audio_decoder.amrwb", "audio_encoder.amrwb" },
987 { MEDIA_MIMETYPE_AUDIO_AAC,
988 "audio_decoder.aac", "audio_encoder.aac" },
989 { MEDIA_MIMETYPE_VIDEO_AVC,
990 "video_decoder.avc", "video_encoder.avc" },
991 { MEDIA_MIMETYPE_VIDEO_MPEG4,
992 "video_decoder.mpeg4", "video_encoder.mpeg4" },
993 { MEDIA_MIMETYPE_VIDEO_H263,
994 "video_decoder.h263", "video_encoder.h263" },
Andreas Huber4c483422009-09-02 16:05:36 -0700995 };
996
997 static const size_t kNumMimeToRole =
998 sizeof(kMimeToRole) / sizeof(kMimeToRole[0]);
999
1000 size_t i;
1001 for (i = 0; i < kNumMimeToRole; ++i) {
Andreas Hubere6c40962009-09-10 14:13:30 -07001002 if (!strcasecmp(mime, kMimeToRole[i].mime)) {
Andreas Huber4c483422009-09-02 16:05:36 -07001003 break;
1004 }
1005 }
1006
1007 if (i == kNumMimeToRole) {
1008 return;
1009 }
1010
1011 const char *role =
Andreas Hubere6c40962009-09-10 14:13:30 -07001012 isEncoder ? kMimeToRole[i].encoderRole
1013 : kMimeToRole[i].decoderRole;
Andreas Huber4c483422009-09-02 16:05:36 -07001014
1015 if (role != NULL) {
Andreas Huber4c483422009-09-02 16:05:36 -07001016 OMX_PARAM_COMPONENTROLETYPE roleParams;
1017 InitOMXParams(&roleParams);
1018
1019 strncpy((char *)roleParams.cRole,
1020 role, OMX_MAX_STRINGNAME_SIZE - 1);
1021
1022 roleParams.cRole[OMX_MAX_STRINGNAME_SIZE - 1] = '\0';
1023
Andreas Huber784202e2009-10-15 13:46:54 -07001024 status_t err = omx->setParameter(
Andreas Hubere6c40962009-09-10 14:13:30 -07001025 node, OMX_IndexParamStandardComponentRole,
Andreas Huber4c483422009-09-02 16:05:36 -07001026 &roleParams, sizeof(roleParams));
1027
1028 if (err != OK) {
1029 LOGW("Failed to set standard component role '%s'.", role);
1030 }
1031 }
Andreas Huberbe06d262009-08-14 14:37:10 -07001032}
1033
Andreas Hubere6c40962009-09-10 14:13:30 -07001034void OMXCodec::setComponentRole() {
1035 setComponentRole(mOMX, mNode, mIsEncoder, mMIME);
1036}
1037
Andreas Huberbe06d262009-08-14 14:37:10 -07001038OMXCodec::~OMXCodec() {
Andreas Huber4f5e6022009-08-19 09:29:34 -07001039 CHECK(mState == LOADED || mState == ERROR);
Andreas Huberbe06d262009-08-14 14:37:10 -07001040
Andreas Huber784202e2009-10-15 13:46:54 -07001041 status_t err = mOMX->freeNode(mNode);
Andreas Huberbe06d262009-08-14 14:37:10 -07001042 CHECK_EQ(err, OK);
1043
1044 mNode = NULL;
1045 setState(DEAD);
1046
1047 clearCodecSpecificData();
1048
1049 free(mComponentName);
1050 mComponentName = NULL;
Andreas Huberebf66ea2009-08-19 13:32:58 -07001051
Andreas Huberbe06d262009-08-14 14:37:10 -07001052 free(mMIME);
1053 mMIME = NULL;
1054}
1055
1056status_t OMXCodec::init() {
Andreas Huber42978e52009-08-27 10:08:39 -07001057 // mLock is held.
Andreas Huberbe06d262009-08-14 14:37:10 -07001058
1059 CHECK_EQ(mState, LOADED);
1060
1061 status_t err;
1062 if (!(mQuirks & kRequiresLoadedToIdleAfterAllocation)) {
Andreas Huber784202e2009-10-15 13:46:54 -07001063 err = mOMX->sendCommand(mNode, OMX_CommandStateSet, OMX_StateIdle);
Andreas Huberbe06d262009-08-14 14:37:10 -07001064 CHECK_EQ(err, OK);
Andreas Huberbe06d262009-08-14 14:37:10 -07001065 setState(LOADED_TO_IDLE);
1066 }
1067
1068 err = allocateBuffers();
1069 CHECK_EQ(err, OK);
1070
1071 if (mQuirks & kRequiresLoadedToIdleAfterAllocation) {
Andreas Huber784202e2009-10-15 13:46:54 -07001072 err = mOMX->sendCommand(mNode, OMX_CommandStateSet, OMX_StateIdle);
Andreas Huberbe06d262009-08-14 14:37:10 -07001073 CHECK_EQ(err, OK);
1074
1075 setState(LOADED_TO_IDLE);
1076 }
1077
1078 while (mState != EXECUTING && mState != ERROR) {
1079 mAsyncCompletion.wait(mLock);
1080 }
1081
1082 return mState == ERROR ? UNKNOWN_ERROR : OK;
1083}
1084
1085// static
1086bool OMXCodec::isIntermediateState(State state) {
1087 return state == LOADED_TO_IDLE
1088 || state == IDLE_TO_EXECUTING
1089 || state == EXECUTING_TO_IDLE
1090 || state == IDLE_TO_LOADED
1091 || state == RECONFIGURING;
1092}
1093
1094status_t OMXCodec::allocateBuffers() {
1095 status_t err = allocateBuffersOnPort(kPortIndexInput);
1096
1097 if (err != OK) {
1098 return err;
1099 }
1100
1101 return allocateBuffersOnPort(kPortIndexOutput);
1102}
1103
1104status_t OMXCodec::allocateBuffersOnPort(OMX_U32 portIndex) {
1105 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -07001106 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -07001107 def.nPortIndex = portIndex;
1108
Andreas Huber784202e2009-10-15 13:46:54 -07001109 status_t err = mOMX->getParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -07001110 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
1111
1112 if (err != OK) {
1113 return err;
1114 }
1115
Andreas Huber5c0a9132009-08-20 11:16:40 -07001116 size_t totalSize = def.nBufferCountActual * def.nBufferSize;
1117 mDealer[portIndex] = new MemoryDealer(totalSize);
1118
Andreas Huberbe06d262009-08-14 14:37:10 -07001119 for (OMX_U32 i = 0; i < def.nBufferCountActual; ++i) {
Andreas Huber5c0a9132009-08-20 11:16:40 -07001120 sp<IMemory> mem = mDealer[portIndex]->allocate(def.nBufferSize);
Andreas Huberbe06d262009-08-14 14:37:10 -07001121 CHECK(mem.get() != NULL);
1122
1123 IOMX::buffer_id buffer;
1124 if (portIndex == kPortIndexInput
1125 && (mQuirks & kRequiresAllocateBufferOnInputPorts)) {
Andreas Huber784202e2009-10-15 13:46:54 -07001126 err = mOMX->allocateBufferWithBackup(
Andreas Huberbe06d262009-08-14 14:37:10 -07001127 mNode, portIndex, mem, &buffer);
Andreas Huber446f44f2009-08-25 17:23:44 -07001128 } else if (portIndex == kPortIndexOutput
1129 && (mQuirks & kRequiresAllocateBufferOnOutputPorts)) {
Andreas Huber784202e2009-10-15 13:46:54 -07001130 err = mOMX->allocateBufferWithBackup(
Andreas Huber2dc64d82009-09-11 12:58:53 -07001131 mNode, portIndex, mem, &buffer);
Andreas Huberbe06d262009-08-14 14:37:10 -07001132 } else {
Andreas Huber784202e2009-10-15 13:46:54 -07001133 err = mOMX->useBuffer(mNode, portIndex, mem, &buffer);
Andreas Huberbe06d262009-08-14 14:37:10 -07001134 }
1135
1136 if (err != OK) {
1137 LOGE("allocate_buffer_with_backup failed");
1138 return err;
1139 }
1140
1141 BufferInfo info;
1142 info.mBuffer = buffer;
1143 info.mOwnedByComponent = false;
1144 info.mMem = mem;
1145 info.mMediaBuffer = NULL;
1146
1147 if (portIndex == kPortIndexOutput) {
1148 info.mMediaBuffer = new MediaBuffer(mem->pointer(), mem->size());
1149 info.mMediaBuffer->setObserver(this);
1150 }
1151
1152 mPortBuffers[portIndex].push(info);
1153
Andreas Huber4c483422009-09-02 16:05:36 -07001154 CODEC_LOGV("allocated buffer %p on %s port", buffer,
Andreas Huberbe06d262009-08-14 14:37:10 -07001155 portIndex == kPortIndexInput ? "input" : "output");
1156 }
1157
1158 dumpPortStatus(portIndex);
1159
1160 return OK;
1161}
1162
1163void OMXCodec::on_message(const omx_message &msg) {
1164 Mutex::Autolock autoLock(mLock);
1165
1166 switch (msg.type) {
1167 case omx_message::EVENT:
1168 {
1169 onEvent(
1170 msg.u.event_data.event, msg.u.event_data.data1,
1171 msg.u.event_data.data2);
1172
1173 break;
1174 }
1175
1176 case omx_message::EMPTY_BUFFER_DONE:
1177 {
1178 IOMX::buffer_id buffer = msg.u.extended_buffer_data.buffer;
1179
Andreas Huber4c483422009-09-02 16:05:36 -07001180 CODEC_LOGV("EMPTY_BUFFER_DONE(buffer: %p)", buffer);
Andreas Huberbe06d262009-08-14 14:37:10 -07001181
1182 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
1183 size_t i = 0;
1184 while (i < buffers->size() && (*buffers)[i].mBuffer != buffer) {
1185 ++i;
1186 }
1187
1188 CHECK(i < buffers->size());
1189 if (!(*buffers)[i].mOwnedByComponent) {
1190 LOGW("We already own input buffer %p, yet received "
1191 "an EMPTY_BUFFER_DONE.", buffer);
1192 }
1193
1194 buffers->editItemAt(i).mOwnedByComponent = false;
1195
1196 if (mPortStatus[kPortIndexInput] == DISABLING) {
Andreas Huber4c483422009-09-02 16:05:36 -07001197 CODEC_LOGV("Port is disabled, freeing buffer %p", buffer);
Andreas Huberbe06d262009-08-14 14:37:10 -07001198
1199 status_t err =
Andreas Huber784202e2009-10-15 13:46:54 -07001200 mOMX->freeBuffer(mNode, kPortIndexInput, buffer);
Andreas Huberbe06d262009-08-14 14:37:10 -07001201 CHECK_EQ(err, OK);
1202
1203 buffers->removeAt(i);
1204 } else if (mPortStatus[kPortIndexInput] != SHUTTING_DOWN) {
1205 CHECK_EQ(mPortStatus[kPortIndexInput], ENABLED);
1206 drainInputBuffer(&buffers->editItemAt(i));
1207 }
1208
1209 break;
1210 }
1211
1212 case omx_message::FILL_BUFFER_DONE:
1213 {
1214 IOMX::buffer_id buffer = msg.u.extended_buffer_data.buffer;
1215 OMX_U32 flags = msg.u.extended_buffer_data.flags;
1216
Andreas Huber4c483422009-09-02 16:05:36 -07001217 CODEC_LOGV("FILL_BUFFER_DONE(buffer: %p, size: %ld, flags: 0x%08lx)",
Andreas Huberbe06d262009-08-14 14:37:10 -07001218 buffer,
1219 msg.u.extended_buffer_data.range_length,
1220 flags);
1221
Andreas Huber4c483422009-09-02 16:05:36 -07001222 CODEC_LOGV("FILL_BUFFER_DONE(timestamp: %lld us (%.2f secs))",
Andreas Huberbe06d262009-08-14 14:37:10 -07001223 msg.u.extended_buffer_data.timestamp,
1224 msg.u.extended_buffer_data.timestamp / 1E6);
1225
1226 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
1227 size_t i = 0;
1228 while (i < buffers->size() && (*buffers)[i].mBuffer != buffer) {
1229 ++i;
1230 }
1231
1232 CHECK(i < buffers->size());
1233 BufferInfo *info = &buffers->editItemAt(i);
1234
1235 if (!info->mOwnedByComponent) {
1236 LOGW("We already own output buffer %p, yet received "
1237 "a FILL_BUFFER_DONE.", buffer);
1238 }
1239
1240 info->mOwnedByComponent = false;
1241
1242 if (mPortStatus[kPortIndexOutput] == DISABLING) {
Andreas Huber4c483422009-09-02 16:05:36 -07001243 CODEC_LOGV("Port is disabled, freeing buffer %p", buffer);
Andreas Huberbe06d262009-08-14 14:37:10 -07001244
1245 status_t err =
Andreas Huber784202e2009-10-15 13:46:54 -07001246 mOMX->freeBuffer(mNode, kPortIndexOutput, buffer);
Andreas Huberbe06d262009-08-14 14:37:10 -07001247 CHECK_EQ(err, OK);
1248
1249 buffers->removeAt(i);
Andreas Huberd7795892009-08-26 10:33:47 -07001250 } else if (mPortStatus[kPortIndexOutput] == ENABLED
1251 && (flags & OMX_BUFFERFLAG_EOS)) {
Andreas Huber4c483422009-09-02 16:05:36 -07001252 CODEC_LOGV("No more output data.");
Andreas Huberbe06d262009-08-14 14:37:10 -07001253 mNoMoreOutputData = true;
1254 mBufferFilled.signal();
1255 } else if (mPortStatus[kPortIndexOutput] != SHUTTING_DOWN) {
1256 CHECK_EQ(mPortStatus[kPortIndexOutput], ENABLED);
Andreas Huberebf66ea2009-08-19 13:32:58 -07001257
Andreas Huberbe06d262009-08-14 14:37:10 -07001258 MediaBuffer *buffer = info->mMediaBuffer;
1259
1260 buffer->set_range(
1261 msg.u.extended_buffer_data.range_offset,
1262 msg.u.extended_buffer_data.range_length);
1263
1264 buffer->meta_data()->clear();
1265
Andreas Huberfa8de752009-10-08 10:07:49 -07001266 buffer->meta_data()->setInt64(
1267 kKeyTime, msg.u.extended_buffer_data.timestamp);
Andreas Huberbe06d262009-08-14 14:37:10 -07001268
1269 if (msg.u.extended_buffer_data.flags & OMX_BUFFERFLAG_SYNCFRAME) {
1270 buffer->meta_data()->setInt32(kKeyIsSyncFrame, true);
1271 }
Andreas Huberea6a38c2009-11-16 15:43:38 -08001272 if (msg.u.extended_buffer_data.flags & OMX_BUFFERFLAG_CODECCONFIG) {
1273 buffer->meta_data()->setInt32(kKeyIsCodecConfig, true);
1274 }
Andreas Huberbe06d262009-08-14 14:37:10 -07001275
1276 buffer->meta_data()->setPointer(
1277 kKeyPlatformPrivate,
1278 msg.u.extended_buffer_data.platform_private);
1279
1280 buffer->meta_data()->setPointer(
1281 kKeyBufferID,
1282 msg.u.extended_buffer_data.buffer);
1283
1284 mFilledBuffers.push_back(i);
1285 mBufferFilled.signal();
1286 }
1287
1288 break;
1289 }
1290
1291 default:
1292 {
1293 CHECK(!"should not be here.");
1294 break;
1295 }
1296 }
1297}
1298
1299void OMXCodec::onEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) {
1300 switch (event) {
1301 case OMX_EventCmdComplete:
1302 {
1303 onCmdComplete((OMX_COMMANDTYPE)data1, data2);
1304 break;
1305 }
1306
1307 case OMX_EventError:
1308 {
1309 LOGE("ERROR(%ld, %ld)", data1, data2);
1310
1311 setState(ERROR);
1312 break;
1313 }
1314
1315 case OMX_EventPortSettingsChanged:
1316 {
1317 onPortSettingsChanged(data1);
1318 break;
1319 }
1320
1321 case OMX_EventBufferFlag:
1322 {
Andreas Huber4c483422009-09-02 16:05:36 -07001323 CODEC_LOGV("EVENT_BUFFER_FLAG(%ld)", data1);
Andreas Huberbe06d262009-08-14 14:37:10 -07001324
1325 if (data1 == kPortIndexOutput) {
1326 mNoMoreOutputData = true;
1327 }
1328 break;
1329 }
1330
1331 default:
1332 {
Andreas Huber4c483422009-09-02 16:05:36 -07001333 CODEC_LOGV("EVENT(%d, %ld, %ld)", event, data1, data2);
Andreas Huberbe06d262009-08-14 14:37:10 -07001334 break;
1335 }
1336 }
1337}
1338
Andreas Huberb1678602009-10-19 13:06:40 -07001339// Has the format changed in any way that the client would have to be aware of?
1340static bool formatHasNotablyChanged(
1341 const sp<MetaData> &from, const sp<MetaData> &to) {
1342 if (from.get() == NULL && to.get() == NULL) {
1343 return false;
1344 }
1345
Andreas Huberf68c1682009-10-21 14:01:30 -07001346 if ((from.get() == NULL && to.get() != NULL)
1347 || (from.get() != NULL && to.get() == NULL)) {
Andreas Huberb1678602009-10-19 13:06:40 -07001348 return true;
1349 }
1350
1351 const char *mime_from, *mime_to;
1352 CHECK(from->findCString(kKeyMIMEType, &mime_from));
1353 CHECK(to->findCString(kKeyMIMEType, &mime_to));
1354
1355 if (strcasecmp(mime_from, mime_to)) {
1356 return true;
1357 }
1358
1359 if (!strcasecmp(mime_from, MEDIA_MIMETYPE_VIDEO_RAW)) {
1360 int32_t colorFormat_from, colorFormat_to;
1361 CHECK(from->findInt32(kKeyColorFormat, &colorFormat_from));
1362 CHECK(to->findInt32(kKeyColorFormat, &colorFormat_to));
1363
1364 if (colorFormat_from != colorFormat_to) {
1365 return true;
1366 }
1367
1368 int32_t width_from, width_to;
1369 CHECK(from->findInt32(kKeyWidth, &width_from));
1370 CHECK(to->findInt32(kKeyWidth, &width_to));
1371
1372 if (width_from != width_to) {
1373 return true;
1374 }
1375
1376 int32_t height_from, height_to;
1377 CHECK(from->findInt32(kKeyHeight, &height_from));
1378 CHECK(to->findInt32(kKeyHeight, &height_to));
1379
1380 if (height_from != height_to) {
1381 return true;
1382 }
1383 } else if (!strcasecmp(mime_from, MEDIA_MIMETYPE_AUDIO_RAW)) {
1384 int32_t numChannels_from, numChannels_to;
1385 CHECK(from->findInt32(kKeyChannelCount, &numChannels_from));
1386 CHECK(to->findInt32(kKeyChannelCount, &numChannels_to));
1387
1388 if (numChannels_from != numChannels_to) {
1389 return true;
1390 }
1391
1392 int32_t sampleRate_from, sampleRate_to;
1393 CHECK(from->findInt32(kKeySampleRate, &sampleRate_from));
1394 CHECK(to->findInt32(kKeySampleRate, &sampleRate_to));
1395
1396 if (sampleRate_from != sampleRate_to) {
1397 return true;
1398 }
1399 }
1400
1401 return false;
1402}
1403
Andreas Huberbe06d262009-08-14 14:37:10 -07001404void OMXCodec::onCmdComplete(OMX_COMMANDTYPE cmd, OMX_U32 data) {
1405 switch (cmd) {
1406 case OMX_CommandStateSet:
1407 {
1408 onStateChange((OMX_STATETYPE)data);
1409 break;
1410 }
1411
1412 case OMX_CommandPortDisable:
1413 {
1414 OMX_U32 portIndex = data;
Andreas Huber4c483422009-09-02 16:05:36 -07001415 CODEC_LOGV("PORT_DISABLED(%ld)", portIndex);
Andreas Huberbe06d262009-08-14 14:37:10 -07001416
1417 CHECK(mState == EXECUTING || mState == RECONFIGURING);
1418 CHECK_EQ(mPortStatus[portIndex], DISABLING);
1419 CHECK_EQ(mPortBuffers[portIndex].size(), 0);
1420
1421 mPortStatus[portIndex] = DISABLED;
1422
1423 if (mState == RECONFIGURING) {
1424 CHECK_EQ(portIndex, kPortIndexOutput);
1425
Andreas Huberb1678602009-10-19 13:06:40 -07001426 sp<MetaData> oldOutputFormat = mOutputFormat;
Andreas Hubercfd55572009-10-09 14:11:28 -07001427 initOutputFormat(mSource->getFormat());
Andreas Huberb1678602009-10-19 13:06:40 -07001428
1429 // Don't notify clients if the output port settings change
1430 // wasn't of importance to them, i.e. it may be that just the
1431 // number of buffers has changed and nothing else.
1432 mOutputPortSettingsHaveChanged =
1433 formatHasNotablyChanged(oldOutputFormat, mOutputFormat);
Andreas Hubercfd55572009-10-09 14:11:28 -07001434
Andreas Huberbe06d262009-08-14 14:37:10 -07001435 enablePortAsync(portIndex);
1436
1437 status_t err = allocateBuffersOnPort(portIndex);
1438 CHECK_EQ(err, OK);
1439 }
1440 break;
1441 }
1442
1443 case OMX_CommandPortEnable:
1444 {
1445 OMX_U32 portIndex = data;
Andreas Huber4c483422009-09-02 16:05:36 -07001446 CODEC_LOGV("PORT_ENABLED(%ld)", portIndex);
Andreas Huberbe06d262009-08-14 14:37:10 -07001447
1448 CHECK(mState == EXECUTING || mState == RECONFIGURING);
1449 CHECK_EQ(mPortStatus[portIndex], ENABLING);
1450
1451 mPortStatus[portIndex] = ENABLED;
1452
1453 if (mState == RECONFIGURING) {
1454 CHECK_EQ(portIndex, kPortIndexOutput);
1455
1456 setState(EXECUTING);
1457
1458 fillOutputBuffers();
1459 }
1460 break;
1461 }
1462
1463 case OMX_CommandFlush:
1464 {
1465 OMX_U32 portIndex = data;
1466
Andreas Huber4c483422009-09-02 16:05:36 -07001467 CODEC_LOGV("FLUSH_DONE(%ld)", portIndex);
Andreas Huberbe06d262009-08-14 14:37:10 -07001468
1469 CHECK_EQ(mPortStatus[portIndex], SHUTTING_DOWN);
1470 mPortStatus[portIndex] = ENABLED;
1471
1472 CHECK_EQ(countBuffersWeOwn(mPortBuffers[portIndex]),
1473 mPortBuffers[portIndex].size());
1474
1475 if (mState == RECONFIGURING) {
1476 CHECK_EQ(portIndex, kPortIndexOutput);
1477
1478 disablePortAsync(portIndex);
Andreas Huber127fcdc2009-08-26 16:27:02 -07001479 } else if (mState == EXECUTING_TO_IDLE) {
1480 if (mPortStatus[kPortIndexInput] == ENABLED
1481 && mPortStatus[kPortIndexOutput] == ENABLED) {
Andreas Huber4c483422009-09-02 16:05:36 -07001482 CODEC_LOGV("Finished flushing both ports, now completing "
Andreas Huber127fcdc2009-08-26 16:27:02 -07001483 "transition from EXECUTING to IDLE.");
1484
1485 mPortStatus[kPortIndexInput] = SHUTTING_DOWN;
1486 mPortStatus[kPortIndexOutput] = SHUTTING_DOWN;
1487
1488 status_t err =
Andreas Huber784202e2009-10-15 13:46:54 -07001489 mOMX->sendCommand(mNode, OMX_CommandStateSet, OMX_StateIdle);
Andreas Huber127fcdc2009-08-26 16:27:02 -07001490 CHECK_EQ(err, OK);
1491 }
Andreas Huberbe06d262009-08-14 14:37:10 -07001492 } else {
1493 // We're flushing both ports in preparation for seeking.
1494
1495 if (mPortStatus[kPortIndexInput] == ENABLED
1496 && mPortStatus[kPortIndexOutput] == ENABLED) {
Andreas Huber4c483422009-09-02 16:05:36 -07001497 CODEC_LOGV("Finished flushing both ports, now continuing from"
Andreas Huberbe06d262009-08-14 14:37:10 -07001498 " seek-time.");
1499
Andreas Huber1a77b68e2009-09-17 11:16:52 -07001500 // Clear this flag in case the decoder sent us either
1501 // the EVENT_BUFFER_FLAG(1) or an output buffer with
1502 // the EOS flag set _while_ flushing. Since we're going
1503 // to submit "fresh" input data now, this flag no longer
1504 // applies to our future.
1505 mNoMoreOutputData = false;
1506
Andreas Huberbe06d262009-08-14 14:37:10 -07001507 drainInputBuffers();
1508 fillOutputBuffers();
1509 }
1510 }
1511
1512 break;
1513 }
1514
1515 default:
1516 {
Andreas Huber4c483422009-09-02 16:05:36 -07001517 CODEC_LOGV("CMD_COMPLETE(%d, %ld)", cmd, data);
Andreas Huberbe06d262009-08-14 14:37:10 -07001518 break;
1519 }
1520 }
1521}
1522
1523void OMXCodec::onStateChange(OMX_STATETYPE newState) {
1524 switch (newState) {
1525 case OMX_StateIdle:
1526 {
Andreas Huber4c483422009-09-02 16:05:36 -07001527 CODEC_LOGV("Now Idle.");
Andreas Huberbe06d262009-08-14 14:37:10 -07001528 if (mState == LOADED_TO_IDLE) {
Andreas Huber784202e2009-10-15 13:46:54 -07001529 status_t err = mOMX->sendCommand(
Andreas Huberbe06d262009-08-14 14:37:10 -07001530 mNode, OMX_CommandStateSet, OMX_StateExecuting);
1531
1532 CHECK_EQ(err, OK);
1533
1534 setState(IDLE_TO_EXECUTING);
1535 } else {
1536 CHECK_EQ(mState, EXECUTING_TO_IDLE);
1537
1538 CHECK_EQ(
1539 countBuffersWeOwn(mPortBuffers[kPortIndexInput]),
1540 mPortBuffers[kPortIndexInput].size());
1541
1542 CHECK_EQ(
1543 countBuffersWeOwn(mPortBuffers[kPortIndexOutput]),
1544 mPortBuffers[kPortIndexOutput].size());
1545
Andreas Huber784202e2009-10-15 13:46:54 -07001546 status_t err = mOMX->sendCommand(
Andreas Huberbe06d262009-08-14 14:37:10 -07001547 mNode, OMX_CommandStateSet, OMX_StateLoaded);
1548
1549 CHECK_EQ(err, OK);
1550
1551 err = freeBuffersOnPort(kPortIndexInput);
1552 CHECK_EQ(err, OK);
1553
1554 err = freeBuffersOnPort(kPortIndexOutput);
1555 CHECK_EQ(err, OK);
1556
1557 mPortStatus[kPortIndexInput] = ENABLED;
1558 mPortStatus[kPortIndexOutput] = ENABLED;
1559
1560 setState(IDLE_TO_LOADED);
1561 }
1562 break;
1563 }
1564
1565 case OMX_StateExecuting:
1566 {
1567 CHECK_EQ(mState, IDLE_TO_EXECUTING);
1568
Andreas Huber4c483422009-09-02 16:05:36 -07001569 CODEC_LOGV("Now Executing.");
Andreas Huberbe06d262009-08-14 14:37:10 -07001570
1571 setState(EXECUTING);
1572
Andreas Huber42978e52009-08-27 10:08:39 -07001573 // Buffers will be submitted to the component in the first
1574 // call to OMXCodec::read as mInitialBufferSubmit is true at
1575 // this point. This ensures that this on_message call returns,
1576 // releases the lock and ::init can notice the state change and
1577 // itself return.
Andreas Huberbe06d262009-08-14 14:37:10 -07001578 break;
1579 }
1580
1581 case OMX_StateLoaded:
1582 {
1583 CHECK_EQ(mState, IDLE_TO_LOADED);
1584
Andreas Huber4c483422009-09-02 16:05:36 -07001585 CODEC_LOGV("Now Loaded.");
Andreas Huberbe06d262009-08-14 14:37:10 -07001586
1587 setState(LOADED);
1588 break;
1589 }
1590
1591 default:
1592 {
1593 CHECK(!"should not be here.");
1594 break;
1595 }
1596 }
1597}
1598
1599// static
1600size_t OMXCodec::countBuffersWeOwn(const Vector<BufferInfo> &buffers) {
1601 size_t n = 0;
1602 for (size_t i = 0; i < buffers.size(); ++i) {
1603 if (!buffers[i].mOwnedByComponent) {
1604 ++n;
1605 }
1606 }
1607
1608 return n;
1609}
1610
1611status_t OMXCodec::freeBuffersOnPort(
1612 OMX_U32 portIndex, bool onlyThoseWeOwn) {
1613 Vector<BufferInfo> *buffers = &mPortBuffers[portIndex];
1614
1615 status_t stickyErr = OK;
1616
1617 for (size_t i = buffers->size(); i-- > 0;) {
1618 BufferInfo *info = &buffers->editItemAt(i);
1619
1620 if (onlyThoseWeOwn && info->mOwnedByComponent) {
1621 continue;
1622 }
1623
1624 CHECK_EQ(info->mOwnedByComponent, false);
1625
Andreas Huber92022852009-09-14 15:24:14 -07001626 CODEC_LOGV("freeing buffer %p on port %ld", info->mBuffer, portIndex);
1627
Andreas Huberbe06d262009-08-14 14:37:10 -07001628 status_t err =
Andreas Huber784202e2009-10-15 13:46:54 -07001629 mOMX->freeBuffer(mNode, portIndex, info->mBuffer);
Andreas Huberbe06d262009-08-14 14:37:10 -07001630
1631 if (err != OK) {
1632 stickyErr = err;
1633 }
1634
1635 if (info->mMediaBuffer != NULL) {
1636 info->mMediaBuffer->setObserver(NULL);
1637
1638 // Make sure nobody but us owns this buffer at this point.
1639 CHECK_EQ(info->mMediaBuffer->refcount(), 0);
1640
1641 info->mMediaBuffer->release();
1642 }
1643
1644 buffers->removeAt(i);
1645 }
1646
1647 CHECK(onlyThoseWeOwn || buffers->isEmpty());
1648
1649 return stickyErr;
1650}
1651
1652void OMXCodec::onPortSettingsChanged(OMX_U32 portIndex) {
Andreas Huber4c483422009-09-02 16:05:36 -07001653 CODEC_LOGV("PORT_SETTINGS_CHANGED(%ld)", portIndex);
Andreas Huberbe06d262009-08-14 14:37:10 -07001654
1655 CHECK_EQ(mState, EXECUTING);
1656 CHECK_EQ(portIndex, kPortIndexOutput);
1657 setState(RECONFIGURING);
1658
1659 if (mQuirks & kNeedsFlushBeforeDisable) {
Andreas Huber404cc412009-08-25 14:26:05 -07001660 if (!flushPortAsync(portIndex)) {
1661 onCmdComplete(OMX_CommandFlush, portIndex);
1662 }
Andreas Huberbe06d262009-08-14 14:37:10 -07001663 } else {
1664 disablePortAsync(portIndex);
1665 }
1666}
1667
Andreas Huber404cc412009-08-25 14:26:05 -07001668bool OMXCodec::flushPortAsync(OMX_U32 portIndex) {
Andreas Huber127fcdc2009-08-26 16:27:02 -07001669 CHECK(mState == EXECUTING || mState == RECONFIGURING
1670 || mState == EXECUTING_TO_IDLE);
Andreas Huberbe06d262009-08-14 14:37:10 -07001671
Andreas Huber4c483422009-09-02 16:05:36 -07001672 CODEC_LOGV("flushPortAsync(%ld): we own %d out of %d buffers already.",
Andreas Huber404cc412009-08-25 14:26:05 -07001673 portIndex, countBuffersWeOwn(mPortBuffers[portIndex]),
1674 mPortBuffers[portIndex].size());
1675
Andreas Huberbe06d262009-08-14 14:37:10 -07001676 CHECK_EQ(mPortStatus[portIndex], ENABLED);
1677 mPortStatus[portIndex] = SHUTTING_DOWN;
1678
Andreas Huber404cc412009-08-25 14:26:05 -07001679 if ((mQuirks & kRequiresFlushCompleteEmulation)
1680 && countBuffersWeOwn(mPortBuffers[portIndex])
1681 == mPortBuffers[portIndex].size()) {
1682 // No flush is necessary and this component fails to send a
1683 // flush-complete event in this case.
1684
1685 return false;
1686 }
1687
Andreas Huberbe06d262009-08-14 14:37:10 -07001688 status_t err =
Andreas Huber784202e2009-10-15 13:46:54 -07001689 mOMX->sendCommand(mNode, OMX_CommandFlush, portIndex);
Andreas Huberbe06d262009-08-14 14:37:10 -07001690 CHECK_EQ(err, OK);
Andreas Huber404cc412009-08-25 14:26:05 -07001691
1692 return true;
Andreas Huberbe06d262009-08-14 14:37:10 -07001693}
1694
1695void OMXCodec::disablePortAsync(OMX_U32 portIndex) {
1696 CHECK(mState == EXECUTING || mState == RECONFIGURING);
1697
1698 CHECK_EQ(mPortStatus[portIndex], ENABLED);
1699 mPortStatus[portIndex] = DISABLING;
1700
1701 status_t err =
Andreas Huber784202e2009-10-15 13:46:54 -07001702 mOMX->sendCommand(mNode, OMX_CommandPortDisable, portIndex);
Andreas Huberbe06d262009-08-14 14:37:10 -07001703 CHECK_EQ(err, OK);
1704
1705 freeBuffersOnPort(portIndex, true);
1706}
1707
1708void OMXCodec::enablePortAsync(OMX_U32 portIndex) {
1709 CHECK(mState == EXECUTING || mState == RECONFIGURING);
1710
1711 CHECK_EQ(mPortStatus[portIndex], DISABLED);
1712 mPortStatus[portIndex] = ENABLING;
1713
1714 status_t err =
Andreas Huber784202e2009-10-15 13:46:54 -07001715 mOMX->sendCommand(mNode, OMX_CommandPortEnable, portIndex);
Andreas Huberbe06d262009-08-14 14:37:10 -07001716 CHECK_EQ(err, OK);
1717}
1718
1719void OMXCodec::fillOutputBuffers() {
1720 CHECK_EQ(mState, EXECUTING);
1721
1722 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
1723 for (size_t i = 0; i < buffers->size(); ++i) {
1724 fillOutputBuffer(&buffers->editItemAt(i));
1725 }
1726}
1727
1728void OMXCodec::drainInputBuffers() {
Andreas Huberd06e5b82009-08-28 13:18:14 -07001729 CHECK(mState == EXECUTING || mState == RECONFIGURING);
Andreas Huberbe06d262009-08-14 14:37:10 -07001730
1731 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
1732 for (size_t i = 0; i < buffers->size(); ++i) {
1733 drainInputBuffer(&buffers->editItemAt(i));
1734 }
1735}
1736
1737void OMXCodec::drainInputBuffer(BufferInfo *info) {
1738 CHECK_EQ(info->mOwnedByComponent, false);
1739
1740 if (mSignalledEOS) {
1741 return;
1742 }
1743
1744 if (mCodecSpecificDataIndex < mCodecSpecificData.size()) {
1745 const CodecSpecificData *specific =
1746 mCodecSpecificData[mCodecSpecificDataIndex];
1747
1748 size_t size = specific->mSize;
1749
Andreas Hubere6c40962009-09-10 14:13:30 -07001750 if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mMIME)
Andreas Huber4f5e6022009-08-19 09:29:34 -07001751 && !(mQuirks & kWantsNALFragments)) {
Andreas Huberbe06d262009-08-14 14:37:10 -07001752 static const uint8_t kNALStartCode[4] =
1753 { 0x00, 0x00, 0x00, 0x01 };
1754
1755 CHECK(info->mMem->size() >= specific->mSize + 4);
1756
1757 size += 4;
1758
1759 memcpy(info->mMem->pointer(), kNALStartCode, 4);
1760 memcpy((uint8_t *)info->mMem->pointer() + 4,
1761 specific->mData, specific->mSize);
1762 } else {
1763 CHECK(info->mMem->size() >= specific->mSize);
1764 memcpy(info->mMem->pointer(), specific->mData, specific->mSize);
1765 }
1766
Andreas Huber784202e2009-10-15 13:46:54 -07001767 status_t err = mOMX->emptyBuffer(
Andreas Huberbe06d262009-08-14 14:37:10 -07001768 mNode, info->mBuffer, 0, size,
1769 OMX_BUFFERFLAG_ENDOFFRAME | OMX_BUFFERFLAG_CODECCONFIG,
1770 0);
Andreas Huber3f427072009-10-08 11:02:27 -07001771 CHECK_EQ(err, OK);
Andreas Huberbe06d262009-08-14 14:37:10 -07001772
1773 info->mOwnedByComponent = true;
1774
1775 ++mCodecSpecificDataIndex;
1776 return;
1777 }
1778
1779 MediaBuffer *srcBuffer;
1780 status_t err;
1781 if (mSeekTimeUs >= 0) {
1782 MediaSource::ReadOptions options;
1783 options.setSeekTo(mSeekTimeUs);
1784 mSeekTimeUs = -1;
1785
1786 err = mSource->read(&srcBuffer, &options);
1787 } else {
1788 err = mSource->read(&srcBuffer);
1789 }
1790
1791 OMX_U32 flags = OMX_BUFFERFLAG_ENDOFFRAME;
Andreas Huberfa8de752009-10-08 10:07:49 -07001792 OMX_TICKS timestampUs = 0;
Andreas Huberbe06d262009-08-14 14:37:10 -07001793 size_t srcLength = 0;
1794
1795 if (err != OK) {
Andreas Huber4c483422009-09-02 16:05:36 -07001796 CODEC_LOGV("signalling end of input stream.");
Andreas Huberbe06d262009-08-14 14:37:10 -07001797 flags |= OMX_BUFFERFLAG_EOS;
1798
1799 mSignalledEOS = true;
1800 } else {
1801 srcLength = srcBuffer->range_length();
1802
1803 if (info->mMem->size() < srcLength) {
1804 LOGE("info->mMem->size() = %d, srcLength = %d",
1805 info->mMem->size(), srcLength);
1806 }
1807 CHECK(info->mMem->size() >= srcLength);
1808 memcpy(info->mMem->pointer(),
1809 (const uint8_t *)srcBuffer->data() + srcBuffer->range_offset(),
1810 srcLength);
1811
Andreas Huberfa8de752009-10-08 10:07:49 -07001812 if (srcBuffer->meta_data()->findInt64(kKeyTime, &timestampUs)) {
Andreas Huber784202e2009-10-15 13:46:54 -07001813 CODEC_LOGV("Calling emptyBuffer on buffer %p (length %d)",
Andreas Huberbe06d262009-08-14 14:37:10 -07001814 info->mBuffer, srcLength);
Andreas Huber784202e2009-10-15 13:46:54 -07001815 CODEC_LOGV("Calling emptyBuffer with timestamp %lld us (%.2f secs)",
Andreas Huberfa8de752009-10-08 10:07:49 -07001816 timestampUs, timestampUs / 1E6);
Andreas Huberbe06d262009-08-14 14:37:10 -07001817 }
1818 }
1819
Andreas Huberbe06d262009-08-14 14:37:10 -07001820 if (srcBuffer != NULL) {
1821 srcBuffer->release();
1822 srcBuffer = NULL;
1823 }
Andreas Huber3f427072009-10-08 11:02:27 -07001824
Andreas Huber784202e2009-10-15 13:46:54 -07001825 err = mOMX->emptyBuffer(
Andreas Huber3f427072009-10-08 11:02:27 -07001826 mNode, info->mBuffer, 0, srcLength,
Andreas Huberfa8de752009-10-08 10:07:49 -07001827 flags, timestampUs);
Andreas Huber3f427072009-10-08 11:02:27 -07001828
1829 if (err != OK) {
1830 setState(ERROR);
1831 return;
1832 }
1833
1834 info->mOwnedByComponent = true;
Andreas Huberea6a38c2009-11-16 15:43:38 -08001835
1836 // This component does not ever signal the EOS flag on output buffers,
1837 // Thanks for nothing.
1838 if (mSignalledEOS && !strcmp(mComponentName, "OMX.TI.Video.encoder")) {
1839 mNoMoreOutputData = true;
1840 mBufferFilled.signal();
1841 }
Andreas Huberbe06d262009-08-14 14:37:10 -07001842}
1843
1844void OMXCodec::fillOutputBuffer(BufferInfo *info) {
1845 CHECK_EQ(info->mOwnedByComponent, false);
1846
Andreas Huber404cc412009-08-25 14:26:05 -07001847 if (mNoMoreOutputData) {
Andreas Huber4c483422009-09-02 16:05:36 -07001848 CODEC_LOGV("There is no more output data available, not "
Andreas Huber404cc412009-08-25 14:26:05 -07001849 "calling fillOutputBuffer");
1850 return;
1851 }
1852
Andreas Huber4c483422009-09-02 16:05:36 -07001853 CODEC_LOGV("Calling fill_buffer on buffer %p", info->mBuffer);
Andreas Huber784202e2009-10-15 13:46:54 -07001854 status_t err = mOMX->fillBuffer(mNode, info->mBuffer);
Andreas Huber3f427072009-10-08 11:02:27 -07001855 CHECK_EQ(err, OK);
Andreas Huberbe06d262009-08-14 14:37:10 -07001856
1857 info->mOwnedByComponent = true;
1858}
1859
1860void OMXCodec::drainInputBuffer(IOMX::buffer_id buffer) {
1861 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
1862 for (size_t i = 0; i < buffers->size(); ++i) {
1863 if ((*buffers)[i].mBuffer == buffer) {
1864 drainInputBuffer(&buffers->editItemAt(i));
1865 return;
1866 }
1867 }
1868
1869 CHECK(!"should not be here.");
1870}
1871
1872void OMXCodec::fillOutputBuffer(IOMX::buffer_id buffer) {
1873 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
1874 for (size_t i = 0; i < buffers->size(); ++i) {
1875 if ((*buffers)[i].mBuffer == buffer) {
1876 fillOutputBuffer(&buffers->editItemAt(i));
1877 return;
1878 }
1879 }
1880
1881 CHECK(!"should not be here.");
1882}
1883
1884void OMXCodec::setState(State newState) {
1885 mState = newState;
1886 mAsyncCompletion.signal();
1887
1888 // This may cause some spurious wakeups but is necessary to
1889 // unblock the reader if we enter ERROR state.
1890 mBufferFilled.signal();
1891}
1892
Andreas Huberda050cf22009-09-02 14:01:43 -07001893void OMXCodec::setRawAudioFormat(
1894 OMX_U32 portIndex, int32_t sampleRate, int32_t numChannels) {
1895 OMX_AUDIO_PARAM_PCMMODETYPE pcmParams;
Andreas Huber4c483422009-09-02 16:05:36 -07001896 InitOMXParams(&pcmParams);
Andreas Huberda050cf22009-09-02 14:01:43 -07001897 pcmParams.nPortIndex = portIndex;
1898
Andreas Huber784202e2009-10-15 13:46:54 -07001899 status_t err = mOMX->getParameter(
Andreas Huberda050cf22009-09-02 14:01:43 -07001900 mNode, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams));
1901
1902 CHECK_EQ(err, OK);
1903
1904 pcmParams.nChannels = numChannels;
1905 pcmParams.eNumData = OMX_NumericalDataSigned;
1906 pcmParams.bInterleaved = OMX_TRUE;
1907 pcmParams.nBitPerSample = 16;
1908 pcmParams.nSamplingRate = sampleRate;
1909 pcmParams.ePCMMode = OMX_AUDIO_PCMModeLinear;
1910
1911 if (numChannels == 1) {
1912 pcmParams.eChannelMapping[0] = OMX_AUDIO_ChannelCF;
1913 } else {
1914 CHECK_EQ(numChannels, 2);
1915
1916 pcmParams.eChannelMapping[0] = OMX_AUDIO_ChannelLF;
1917 pcmParams.eChannelMapping[1] = OMX_AUDIO_ChannelRF;
1918 }
1919
Andreas Huber784202e2009-10-15 13:46:54 -07001920 err = mOMX->setParameter(
Andreas Huberda050cf22009-09-02 14:01:43 -07001921 mNode, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams));
1922
1923 CHECK_EQ(err, OK);
1924}
1925
Andreas Huber8768f2c2009-12-01 15:26:54 -08001926void OMXCodec::setAMRFormat(bool isWAMR) {
1927 OMX_U32 portIndex = mIsEncoder ? kPortIndexOutput : kPortIndexInput;
Andreas Huberbe06d262009-08-14 14:37:10 -07001928
Andreas Huber8768f2c2009-12-01 15:26:54 -08001929 OMX_AUDIO_PARAM_AMRTYPE def;
1930 InitOMXParams(&def);
1931 def.nPortIndex = portIndex;
Andreas Huberbe06d262009-08-14 14:37:10 -07001932
Andreas Huber8768f2c2009-12-01 15:26:54 -08001933 status_t err =
1934 mOMX->getParameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
Andreas Huberbe06d262009-08-14 14:37:10 -07001935
Andreas Huber8768f2c2009-12-01 15:26:54 -08001936 CHECK_EQ(err, OK);
Andreas Huberbe06d262009-08-14 14:37:10 -07001937
Andreas Huber8768f2c2009-12-01 15:26:54 -08001938 def.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
1939 def.eAMRBandMode =
1940 isWAMR ? OMX_AUDIO_AMRBandModeWB0 : OMX_AUDIO_AMRBandModeNB0;
Andreas Huberbe06d262009-08-14 14:37:10 -07001941
Andreas Huber8768f2c2009-12-01 15:26:54 -08001942 err = mOMX->setParameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
1943 CHECK_EQ(err, OK);
Andreas Huberee606e62009-09-08 10:19:21 -07001944
1945 ////////////////////////
1946
1947 if (mIsEncoder) {
1948 sp<MetaData> format = mSource->getFormat();
1949 int32_t sampleRate;
1950 int32_t numChannels;
1951 CHECK(format->findInt32(kKeySampleRate, &sampleRate));
1952 CHECK(format->findInt32(kKeyChannelCount, &numChannels));
1953
1954 setRawAudioFormat(kPortIndexInput, sampleRate, numChannels);
1955 }
1956}
1957
Andreas Huber43ad6eaf2009-09-01 16:02:43 -07001958void OMXCodec::setAACFormat(int32_t numChannels, int32_t sampleRate) {
Andreas Huberda050cf22009-09-02 14:01:43 -07001959 if (mIsEncoder) {
1960 setRawAudioFormat(kPortIndexInput, sampleRate, numChannels);
1961 } else {
1962 OMX_AUDIO_PARAM_AACPROFILETYPE profile;
Andreas Huber4c483422009-09-02 16:05:36 -07001963 InitOMXParams(&profile);
Andreas Huberda050cf22009-09-02 14:01:43 -07001964 profile.nPortIndex = kPortIndexInput;
Andreas Huberbe06d262009-08-14 14:37:10 -07001965
Andreas Huber784202e2009-10-15 13:46:54 -07001966 status_t err = mOMX->getParameter(
Andreas Huberda050cf22009-09-02 14:01:43 -07001967 mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile));
1968 CHECK_EQ(err, OK);
Andreas Huberbe06d262009-08-14 14:37:10 -07001969
Andreas Huberda050cf22009-09-02 14:01:43 -07001970 profile.nChannels = numChannels;
1971 profile.nSampleRate = sampleRate;
1972 profile.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4ADTS;
Andreas Huberbe06d262009-08-14 14:37:10 -07001973
Andreas Huber784202e2009-10-15 13:46:54 -07001974 err = mOMX->setParameter(
Andreas Huberda050cf22009-09-02 14:01:43 -07001975 mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile));
1976 CHECK_EQ(err, OK);
1977 }
Andreas Huberbe06d262009-08-14 14:37:10 -07001978}
1979
1980void OMXCodec::setImageOutputFormat(
1981 OMX_COLOR_FORMATTYPE format, OMX_U32 width, OMX_U32 height) {
Andreas Huber4c483422009-09-02 16:05:36 -07001982 CODEC_LOGV("setImageOutputFormat(%ld, %ld)", width, height);
Andreas Huberbe06d262009-08-14 14:37:10 -07001983
1984#if 0
1985 OMX_INDEXTYPE index;
1986 status_t err = mOMX->get_extension_index(
1987 mNode, "OMX.TI.JPEG.decode.Config.OutputColorFormat", &index);
1988 CHECK_EQ(err, OK);
1989
1990 err = mOMX->set_config(mNode, index, &format, sizeof(format));
1991 CHECK_EQ(err, OK);
1992#endif
1993
1994 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -07001995 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -07001996 def.nPortIndex = kPortIndexOutput;
1997
Andreas Huber784202e2009-10-15 13:46:54 -07001998 status_t err = mOMX->getParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -07001999 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
2000 CHECK_EQ(err, OK);
2001
2002 CHECK_EQ(def.eDomain, OMX_PortDomainImage);
2003
2004 OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
Andreas Huberebf66ea2009-08-19 13:32:58 -07002005
Andreas Huberbe06d262009-08-14 14:37:10 -07002006 CHECK_EQ(imageDef->eCompressionFormat, OMX_IMAGE_CodingUnused);
2007 imageDef->eColorFormat = format;
2008 imageDef->nFrameWidth = width;
2009 imageDef->nFrameHeight = height;
2010
2011 switch (format) {
2012 case OMX_COLOR_FormatYUV420PackedPlanar:
2013 case OMX_COLOR_FormatYUV411Planar:
2014 {
2015 def.nBufferSize = (width * height * 3) / 2;
2016 break;
2017 }
2018
2019 case OMX_COLOR_FormatCbYCrY:
2020 {
2021 def.nBufferSize = width * height * 2;
2022 break;
2023 }
2024
2025 case OMX_COLOR_Format32bitARGB8888:
2026 {
2027 def.nBufferSize = width * height * 4;
2028 break;
2029 }
2030
Andreas Huber201511c2009-09-08 14:01:44 -07002031 case OMX_COLOR_Format16bitARGB4444:
2032 case OMX_COLOR_Format16bitARGB1555:
2033 case OMX_COLOR_Format16bitRGB565:
2034 case OMX_COLOR_Format16bitBGR565:
2035 {
2036 def.nBufferSize = width * height * 2;
2037 break;
2038 }
2039
Andreas Huberbe06d262009-08-14 14:37:10 -07002040 default:
2041 CHECK(!"Should not be here. Unknown color format.");
2042 break;
2043 }
2044
Andreas Huber5c0a9132009-08-20 11:16:40 -07002045 def.nBufferCountActual = def.nBufferCountMin;
2046
Andreas Huber784202e2009-10-15 13:46:54 -07002047 err = mOMX->setParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -07002048 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
2049 CHECK_EQ(err, OK);
Andreas Huber5c0a9132009-08-20 11:16:40 -07002050}
Andreas Huberbe06d262009-08-14 14:37:10 -07002051
Andreas Huber5c0a9132009-08-20 11:16:40 -07002052void OMXCodec::setJPEGInputFormat(
2053 OMX_U32 width, OMX_U32 height, OMX_U32 compressedSize) {
2054 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -07002055 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -07002056 def.nPortIndex = kPortIndexInput;
2057
Andreas Huber784202e2009-10-15 13:46:54 -07002058 status_t err = mOMX->getParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -07002059 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
2060 CHECK_EQ(err, OK);
2061
Andreas Huber5c0a9132009-08-20 11:16:40 -07002062 CHECK_EQ(def.eDomain, OMX_PortDomainImage);
2063 OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
2064
Andreas Huberbe06d262009-08-14 14:37:10 -07002065 CHECK_EQ(imageDef->eCompressionFormat, OMX_IMAGE_CodingJPEG);
2066 imageDef->nFrameWidth = width;
2067 imageDef->nFrameHeight = height;
2068
Andreas Huber5c0a9132009-08-20 11:16:40 -07002069 def.nBufferSize = compressedSize;
Andreas Huberbe06d262009-08-14 14:37:10 -07002070 def.nBufferCountActual = def.nBufferCountMin;
2071
Andreas Huber784202e2009-10-15 13:46:54 -07002072 err = mOMX->setParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -07002073 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
2074 CHECK_EQ(err, OK);
2075}
2076
2077void OMXCodec::addCodecSpecificData(const void *data, size_t size) {
2078 CodecSpecificData *specific =
2079 (CodecSpecificData *)malloc(sizeof(CodecSpecificData) + size - 1);
2080
2081 specific->mSize = size;
2082 memcpy(specific->mData, data, size);
2083
2084 mCodecSpecificData.push(specific);
2085}
2086
2087void OMXCodec::clearCodecSpecificData() {
2088 for (size_t i = 0; i < mCodecSpecificData.size(); ++i) {
2089 free(mCodecSpecificData.editItemAt(i));
2090 }
2091 mCodecSpecificData.clear();
2092 mCodecSpecificDataIndex = 0;
2093}
2094
2095status_t OMXCodec::start(MetaData *) {
Andreas Huber42978e52009-08-27 10:08:39 -07002096 Mutex::Autolock autoLock(mLock);
2097
Andreas Huberbe06d262009-08-14 14:37:10 -07002098 if (mState != LOADED) {
2099 return UNKNOWN_ERROR;
2100 }
Andreas Huberebf66ea2009-08-19 13:32:58 -07002101
Andreas Huberbe06d262009-08-14 14:37:10 -07002102 sp<MetaData> params = new MetaData;
Andreas Huber4f5e6022009-08-19 09:29:34 -07002103 if (mQuirks & kWantsNALFragments) {
2104 params->setInt32(kKeyWantsNALFragments, true);
Andreas Huberbe06d262009-08-14 14:37:10 -07002105 }
2106 status_t err = mSource->start(params.get());
2107
2108 if (err != OK) {
2109 return err;
2110 }
2111
2112 mCodecSpecificDataIndex = 0;
Andreas Huber42978e52009-08-27 10:08:39 -07002113 mInitialBufferSubmit = true;
Andreas Huberbe06d262009-08-14 14:37:10 -07002114 mSignalledEOS = false;
2115 mNoMoreOutputData = false;
Andreas Hubercfd55572009-10-09 14:11:28 -07002116 mOutputPortSettingsHaveChanged = false;
Andreas Huberbe06d262009-08-14 14:37:10 -07002117 mSeekTimeUs = -1;
2118 mFilledBuffers.clear();
2119
2120 return init();
2121}
2122
2123status_t OMXCodec::stop() {
Andreas Huber4c483422009-09-02 16:05:36 -07002124 CODEC_LOGV("stop");
Andreas Huberbe06d262009-08-14 14:37:10 -07002125
2126 Mutex::Autolock autoLock(mLock);
2127
2128 while (isIntermediateState(mState)) {
2129 mAsyncCompletion.wait(mLock);
2130 }
2131
2132 switch (mState) {
2133 case LOADED:
2134 case ERROR:
2135 break;
2136
2137 case EXECUTING:
2138 {
2139 setState(EXECUTING_TO_IDLE);
2140
Andreas Huber127fcdc2009-08-26 16:27:02 -07002141 if (mQuirks & kRequiresFlushBeforeShutdown) {
Andreas Huber4c483422009-09-02 16:05:36 -07002142 CODEC_LOGV("This component requires a flush before transitioning "
Andreas Huber127fcdc2009-08-26 16:27:02 -07002143 "from EXECUTING to IDLE...");
Andreas Huberbe06d262009-08-14 14:37:10 -07002144
Andreas Huber127fcdc2009-08-26 16:27:02 -07002145 bool emulateInputFlushCompletion =
2146 !flushPortAsync(kPortIndexInput);
2147
2148 bool emulateOutputFlushCompletion =
2149 !flushPortAsync(kPortIndexOutput);
2150
2151 if (emulateInputFlushCompletion) {
2152 onCmdComplete(OMX_CommandFlush, kPortIndexInput);
2153 }
2154
2155 if (emulateOutputFlushCompletion) {
2156 onCmdComplete(OMX_CommandFlush, kPortIndexOutput);
2157 }
2158 } else {
2159 mPortStatus[kPortIndexInput] = SHUTTING_DOWN;
2160 mPortStatus[kPortIndexOutput] = SHUTTING_DOWN;
2161
2162 status_t err =
Andreas Huber784202e2009-10-15 13:46:54 -07002163 mOMX->sendCommand(mNode, OMX_CommandStateSet, OMX_StateIdle);
Andreas Huber127fcdc2009-08-26 16:27:02 -07002164 CHECK_EQ(err, OK);
2165 }
Andreas Huberbe06d262009-08-14 14:37:10 -07002166
2167 while (mState != LOADED && mState != ERROR) {
2168 mAsyncCompletion.wait(mLock);
2169 }
2170
2171 break;
2172 }
2173
2174 default:
2175 {
2176 CHECK(!"should not be here.");
2177 break;
2178 }
2179 }
2180
2181 mSource->stop();
2182
2183 return OK;
2184}
2185
2186sp<MetaData> OMXCodec::getFormat() {
Andreas Hubercfd55572009-10-09 14:11:28 -07002187 Mutex::Autolock autoLock(mLock);
2188
Andreas Huberbe06d262009-08-14 14:37:10 -07002189 return mOutputFormat;
2190}
2191
2192status_t OMXCodec::read(
2193 MediaBuffer **buffer, const ReadOptions *options) {
2194 *buffer = NULL;
2195
2196 Mutex::Autolock autoLock(mLock);
2197
Andreas Huberd06e5b82009-08-28 13:18:14 -07002198 if (mState != EXECUTING && mState != RECONFIGURING) {
2199 return UNKNOWN_ERROR;
2200 }
2201
Andreas Hubere981c332009-10-22 13:49:30 -07002202 bool seeking = false;
2203 int64_t seekTimeUs;
2204 if (options && options->getSeekTo(&seekTimeUs)) {
2205 seeking = true;
2206 }
2207
Andreas Huber42978e52009-08-27 10:08:39 -07002208 if (mInitialBufferSubmit) {
2209 mInitialBufferSubmit = false;
2210
Andreas Hubere981c332009-10-22 13:49:30 -07002211 if (seeking) {
2212 CHECK(seekTimeUs >= 0);
2213 mSeekTimeUs = seekTimeUs;
2214
2215 // There's no reason to trigger the code below, there's
2216 // nothing to flush yet.
2217 seeking = false;
2218 }
2219
Andreas Huber42978e52009-08-27 10:08:39 -07002220 drainInputBuffers();
Andreas Huber42978e52009-08-27 10:08:39 -07002221
Andreas Huberd06e5b82009-08-28 13:18:14 -07002222 if (mState == EXECUTING) {
2223 // Otherwise mState == RECONFIGURING and this code will trigger
2224 // after the output port is reenabled.
2225 fillOutputBuffers();
2226 }
Andreas Huberbe06d262009-08-14 14:37:10 -07002227 }
2228
Andreas Hubere981c332009-10-22 13:49:30 -07002229 if (seeking) {
Andreas Huber4c483422009-09-02 16:05:36 -07002230 CODEC_LOGV("seeking to %lld us (%.2f secs)", seekTimeUs, seekTimeUs / 1E6);
Andreas Huberbe06d262009-08-14 14:37:10 -07002231
2232 mSignalledEOS = false;
2233 mNoMoreOutputData = false;
2234
2235 CHECK(seekTimeUs >= 0);
2236 mSeekTimeUs = seekTimeUs;
2237
2238 mFilledBuffers.clear();
2239
2240 CHECK_EQ(mState, EXECUTING);
2241
Andreas Huber404cc412009-08-25 14:26:05 -07002242 bool emulateInputFlushCompletion = !flushPortAsync(kPortIndexInput);
2243 bool emulateOutputFlushCompletion = !flushPortAsync(kPortIndexOutput);
2244
2245 if (emulateInputFlushCompletion) {
2246 onCmdComplete(OMX_CommandFlush, kPortIndexInput);
2247 }
2248
2249 if (emulateOutputFlushCompletion) {
2250 onCmdComplete(OMX_CommandFlush, kPortIndexOutput);
2251 }
Andreas Huberbe06d262009-08-14 14:37:10 -07002252 }
2253
2254 while (mState != ERROR && !mNoMoreOutputData && mFilledBuffers.empty()) {
2255 mBufferFilled.wait(mLock);
2256 }
2257
2258 if (mState == ERROR) {
2259 return UNKNOWN_ERROR;
2260 }
2261
2262 if (mFilledBuffers.empty()) {
2263 return ERROR_END_OF_STREAM;
2264 }
2265
Andreas Hubercfd55572009-10-09 14:11:28 -07002266 if (mOutputPortSettingsHaveChanged) {
2267 mOutputPortSettingsHaveChanged = false;
2268
2269 return INFO_FORMAT_CHANGED;
2270 }
2271
Andreas Huberbe06d262009-08-14 14:37:10 -07002272 size_t index = *mFilledBuffers.begin();
2273 mFilledBuffers.erase(mFilledBuffers.begin());
2274
2275 BufferInfo *info = &mPortBuffers[kPortIndexOutput].editItemAt(index);
2276 info->mMediaBuffer->add_ref();
2277 *buffer = info->mMediaBuffer;
2278
2279 return OK;
2280}
2281
2282void OMXCodec::signalBufferReturned(MediaBuffer *buffer) {
2283 Mutex::Autolock autoLock(mLock);
2284
2285 Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
2286 for (size_t i = 0; i < buffers->size(); ++i) {
2287 BufferInfo *info = &buffers->editItemAt(i);
2288
2289 if (info->mMediaBuffer == buffer) {
2290 CHECK_EQ(mPortStatus[kPortIndexOutput], ENABLED);
2291 fillOutputBuffer(info);
2292 return;
2293 }
2294 }
2295
2296 CHECK(!"should not be here.");
2297}
2298
2299static const char *imageCompressionFormatString(OMX_IMAGE_CODINGTYPE type) {
2300 static const char *kNames[] = {
2301 "OMX_IMAGE_CodingUnused",
2302 "OMX_IMAGE_CodingAutoDetect",
2303 "OMX_IMAGE_CodingJPEG",
2304 "OMX_IMAGE_CodingJPEG2K",
2305 "OMX_IMAGE_CodingEXIF",
2306 "OMX_IMAGE_CodingTIFF",
2307 "OMX_IMAGE_CodingGIF",
2308 "OMX_IMAGE_CodingPNG",
2309 "OMX_IMAGE_CodingLZW",
2310 "OMX_IMAGE_CodingBMP",
2311 };
2312
2313 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
2314
2315 if (type < 0 || (size_t)type >= numNames) {
2316 return "UNKNOWN";
2317 } else {
2318 return kNames[type];
2319 }
2320}
2321
2322static const char *colorFormatString(OMX_COLOR_FORMATTYPE type) {
2323 static const char *kNames[] = {
2324 "OMX_COLOR_FormatUnused",
2325 "OMX_COLOR_FormatMonochrome",
2326 "OMX_COLOR_Format8bitRGB332",
2327 "OMX_COLOR_Format12bitRGB444",
2328 "OMX_COLOR_Format16bitARGB4444",
2329 "OMX_COLOR_Format16bitARGB1555",
2330 "OMX_COLOR_Format16bitRGB565",
2331 "OMX_COLOR_Format16bitBGR565",
2332 "OMX_COLOR_Format18bitRGB666",
2333 "OMX_COLOR_Format18bitARGB1665",
Andreas Huberebf66ea2009-08-19 13:32:58 -07002334 "OMX_COLOR_Format19bitARGB1666",
Andreas Huberbe06d262009-08-14 14:37:10 -07002335 "OMX_COLOR_Format24bitRGB888",
2336 "OMX_COLOR_Format24bitBGR888",
2337 "OMX_COLOR_Format24bitARGB1887",
2338 "OMX_COLOR_Format25bitARGB1888",
2339 "OMX_COLOR_Format32bitBGRA8888",
2340 "OMX_COLOR_Format32bitARGB8888",
2341 "OMX_COLOR_FormatYUV411Planar",
2342 "OMX_COLOR_FormatYUV411PackedPlanar",
2343 "OMX_COLOR_FormatYUV420Planar",
2344 "OMX_COLOR_FormatYUV420PackedPlanar",
2345 "OMX_COLOR_FormatYUV420SemiPlanar",
2346 "OMX_COLOR_FormatYUV422Planar",
2347 "OMX_COLOR_FormatYUV422PackedPlanar",
2348 "OMX_COLOR_FormatYUV422SemiPlanar",
2349 "OMX_COLOR_FormatYCbYCr",
2350 "OMX_COLOR_FormatYCrYCb",
2351 "OMX_COLOR_FormatCbYCrY",
2352 "OMX_COLOR_FormatCrYCbY",
2353 "OMX_COLOR_FormatYUV444Interleaved",
2354 "OMX_COLOR_FormatRawBayer8bit",
2355 "OMX_COLOR_FormatRawBayer10bit",
2356 "OMX_COLOR_FormatRawBayer8bitcompressed",
Andreas Huberebf66ea2009-08-19 13:32:58 -07002357 "OMX_COLOR_FormatL2",
2358 "OMX_COLOR_FormatL4",
2359 "OMX_COLOR_FormatL8",
2360 "OMX_COLOR_FormatL16",
2361 "OMX_COLOR_FormatL24",
Andreas Huberbe06d262009-08-14 14:37:10 -07002362 "OMX_COLOR_FormatL32",
2363 "OMX_COLOR_FormatYUV420PackedSemiPlanar",
2364 "OMX_COLOR_FormatYUV422PackedSemiPlanar",
2365 "OMX_COLOR_Format18BitBGR666",
2366 "OMX_COLOR_Format24BitARGB6666",
2367 "OMX_COLOR_Format24BitABGR6666",
2368 };
2369
2370 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
2371
Andreas Huberbe06d262009-08-14 14:37:10 -07002372 if (type == OMX_QCOM_COLOR_FormatYVU420SemiPlanar) {
2373 return "OMX_QCOM_COLOR_FormatYVU420SemiPlanar";
2374 } else if (type < 0 || (size_t)type >= numNames) {
2375 return "UNKNOWN";
2376 } else {
2377 return kNames[type];
2378 }
2379}
2380
2381static const char *videoCompressionFormatString(OMX_VIDEO_CODINGTYPE type) {
2382 static const char *kNames[] = {
2383 "OMX_VIDEO_CodingUnused",
2384 "OMX_VIDEO_CodingAutoDetect",
2385 "OMX_VIDEO_CodingMPEG2",
2386 "OMX_VIDEO_CodingH263",
2387 "OMX_VIDEO_CodingMPEG4",
2388 "OMX_VIDEO_CodingWMV",
2389 "OMX_VIDEO_CodingRV",
2390 "OMX_VIDEO_CodingAVC",
2391 "OMX_VIDEO_CodingMJPEG",
2392 };
2393
2394 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
2395
2396 if (type < 0 || (size_t)type >= numNames) {
2397 return "UNKNOWN";
2398 } else {
2399 return kNames[type];
2400 }
2401}
2402
2403static const char *audioCodingTypeString(OMX_AUDIO_CODINGTYPE type) {
2404 static const char *kNames[] = {
2405 "OMX_AUDIO_CodingUnused",
2406 "OMX_AUDIO_CodingAutoDetect",
2407 "OMX_AUDIO_CodingPCM",
2408 "OMX_AUDIO_CodingADPCM",
2409 "OMX_AUDIO_CodingAMR",
2410 "OMX_AUDIO_CodingGSMFR",
2411 "OMX_AUDIO_CodingGSMEFR",
2412 "OMX_AUDIO_CodingGSMHR",
2413 "OMX_AUDIO_CodingPDCFR",
2414 "OMX_AUDIO_CodingPDCEFR",
2415 "OMX_AUDIO_CodingPDCHR",
2416 "OMX_AUDIO_CodingTDMAFR",
2417 "OMX_AUDIO_CodingTDMAEFR",
2418 "OMX_AUDIO_CodingQCELP8",
2419 "OMX_AUDIO_CodingQCELP13",
2420 "OMX_AUDIO_CodingEVRC",
2421 "OMX_AUDIO_CodingSMV",
2422 "OMX_AUDIO_CodingG711",
2423 "OMX_AUDIO_CodingG723",
2424 "OMX_AUDIO_CodingG726",
2425 "OMX_AUDIO_CodingG729",
2426 "OMX_AUDIO_CodingAAC",
2427 "OMX_AUDIO_CodingMP3",
2428 "OMX_AUDIO_CodingSBC",
2429 "OMX_AUDIO_CodingVORBIS",
2430 "OMX_AUDIO_CodingWMA",
2431 "OMX_AUDIO_CodingRA",
2432 "OMX_AUDIO_CodingMIDI",
2433 };
2434
2435 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
2436
2437 if (type < 0 || (size_t)type >= numNames) {
2438 return "UNKNOWN";
2439 } else {
2440 return kNames[type];
2441 }
2442}
2443
2444static const char *audioPCMModeString(OMX_AUDIO_PCMMODETYPE type) {
2445 static const char *kNames[] = {
2446 "OMX_AUDIO_PCMModeLinear",
2447 "OMX_AUDIO_PCMModeALaw",
2448 "OMX_AUDIO_PCMModeMULaw",
2449 };
2450
2451 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
2452
2453 if (type < 0 || (size_t)type >= numNames) {
2454 return "UNKNOWN";
2455 } else {
2456 return kNames[type];
2457 }
2458}
2459
Andreas Huber7ae02c82009-09-09 16:29:47 -07002460static const char *amrBandModeString(OMX_AUDIO_AMRBANDMODETYPE type) {
2461 static const char *kNames[] = {
2462 "OMX_AUDIO_AMRBandModeUnused",
2463 "OMX_AUDIO_AMRBandModeNB0",
2464 "OMX_AUDIO_AMRBandModeNB1",
2465 "OMX_AUDIO_AMRBandModeNB2",
2466 "OMX_AUDIO_AMRBandModeNB3",
2467 "OMX_AUDIO_AMRBandModeNB4",
2468 "OMX_AUDIO_AMRBandModeNB5",
2469 "OMX_AUDIO_AMRBandModeNB6",
2470 "OMX_AUDIO_AMRBandModeNB7",
2471 "OMX_AUDIO_AMRBandModeWB0",
2472 "OMX_AUDIO_AMRBandModeWB1",
2473 "OMX_AUDIO_AMRBandModeWB2",
2474 "OMX_AUDIO_AMRBandModeWB3",
2475 "OMX_AUDIO_AMRBandModeWB4",
2476 "OMX_AUDIO_AMRBandModeWB5",
2477 "OMX_AUDIO_AMRBandModeWB6",
2478 "OMX_AUDIO_AMRBandModeWB7",
2479 "OMX_AUDIO_AMRBandModeWB8",
2480 };
2481
2482 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
2483
2484 if (type < 0 || (size_t)type >= numNames) {
2485 return "UNKNOWN";
2486 } else {
2487 return kNames[type];
2488 }
2489}
2490
2491static const char *amrFrameFormatString(OMX_AUDIO_AMRFRAMEFORMATTYPE type) {
2492 static const char *kNames[] = {
2493 "OMX_AUDIO_AMRFrameFormatConformance",
2494 "OMX_AUDIO_AMRFrameFormatIF1",
2495 "OMX_AUDIO_AMRFrameFormatIF2",
2496 "OMX_AUDIO_AMRFrameFormatFSF",
2497 "OMX_AUDIO_AMRFrameFormatRTPPayload",
2498 "OMX_AUDIO_AMRFrameFormatITU",
2499 };
2500
2501 size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
2502
2503 if (type < 0 || (size_t)type >= numNames) {
2504 return "UNKNOWN";
2505 } else {
2506 return kNames[type];
2507 }
2508}
Andreas Huberbe06d262009-08-14 14:37:10 -07002509
2510void OMXCodec::dumpPortStatus(OMX_U32 portIndex) {
2511 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -07002512 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -07002513 def.nPortIndex = portIndex;
2514
Andreas Huber784202e2009-10-15 13:46:54 -07002515 status_t err = mOMX->getParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -07002516 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
2517 CHECK_EQ(err, OK);
2518
2519 printf("%s Port = {\n", portIndex == kPortIndexInput ? "Input" : "Output");
2520
2521 CHECK((portIndex == kPortIndexInput && def.eDir == OMX_DirInput)
2522 || (portIndex == kPortIndexOutput && def.eDir == OMX_DirOutput));
2523
2524 printf(" nBufferCountActual = %ld\n", def.nBufferCountActual);
2525 printf(" nBufferCountMin = %ld\n", def.nBufferCountMin);
2526 printf(" nBufferSize = %ld\n", def.nBufferSize);
2527
2528 switch (def.eDomain) {
2529 case OMX_PortDomainImage:
2530 {
2531 const OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
2532
2533 printf("\n");
2534 printf(" // Image\n");
2535 printf(" nFrameWidth = %ld\n", imageDef->nFrameWidth);
2536 printf(" nFrameHeight = %ld\n", imageDef->nFrameHeight);
2537 printf(" nStride = %ld\n", imageDef->nStride);
2538
2539 printf(" eCompressionFormat = %s\n",
2540 imageCompressionFormatString(imageDef->eCompressionFormat));
2541
2542 printf(" eColorFormat = %s\n",
2543 colorFormatString(imageDef->eColorFormat));
2544
2545 break;
2546 }
2547
2548 case OMX_PortDomainVideo:
2549 {
2550 OMX_VIDEO_PORTDEFINITIONTYPE *videoDef = &def.format.video;
2551
2552 printf("\n");
2553 printf(" // Video\n");
2554 printf(" nFrameWidth = %ld\n", videoDef->nFrameWidth);
2555 printf(" nFrameHeight = %ld\n", videoDef->nFrameHeight);
2556 printf(" nStride = %ld\n", videoDef->nStride);
2557
2558 printf(" eCompressionFormat = %s\n",
2559 videoCompressionFormatString(videoDef->eCompressionFormat));
2560
2561 printf(" eColorFormat = %s\n",
2562 colorFormatString(videoDef->eColorFormat));
2563
2564 break;
2565 }
2566
2567 case OMX_PortDomainAudio:
2568 {
2569 OMX_AUDIO_PORTDEFINITIONTYPE *audioDef = &def.format.audio;
2570
2571 printf("\n");
2572 printf(" // Audio\n");
2573 printf(" eEncoding = %s\n",
2574 audioCodingTypeString(audioDef->eEncoding));
2575
2576 if (audioDef->eEncoding == OMX_AUDIO_CodingPCM) {
2577 OMX_AUDIO_PARAM_PCMMODETYPE params;
Andreas Huber4c483422009-09-02 16:05:36 -07002578 InitOMXParams(&params);
Andreas Huberbe06d262009-08-14 14:37:10 -07002579 params.nPortIndex = portIndex;
2580
Andreas Huber784202e2009-10-15 13:46:54 -07002581 err = mOMX->getParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -07002582 mNode, OMX_IndexParamAudioPcm, &params, sizeof(params));
2583 CHECK_EQ(err, OK);
2584
2585 printf(" nSamplingRate = %ld\n", params.nSamplingRate);
2586 printf(" nChannels = %ld\n", params.nChannels);
2587 printf(" bInterleaved = %d\n", params.bInterleaved);
2588 printf(" nBitPerSample = %ld\n", params.nBitPerSample);
2589
2590 printf(" eNumData = %s\n",
2591 params.eNumData == OMX_NumericalDataSigned
2592 ? "signed" : "unsigned");
2593
2594 printf(" ePCMMode = %s\n", audioPCMModeString(params.ePCMMode));
Andreas Huber7ae02c82009-09-09 16:29:47 -07002595 } else if (audioDef->eEncoding == OMX_AUDIO_CodingAMR) {
2596 OMX_AUDIO_PARAM_AMRTYPE amr;
2597 InitOMXParams(&amr);
2598 amr.nPortIndex = portIndex;
2599
Andreas Huber784202e2009-10-15 13:46:54 -07002600 err = mOMX->getParameter(
Andreas Huber7ae02c82009-09-09 16:29:47 -07002601 mNode, OMX_IndexParamAudioAmr, &amr, sizeof(amr));
2602 CHECK_EQ(err, OK);
2603
2604 printf(" nChannels = %ld\n", amr.nChannels);
2605 printf(" eAMRBandMode = %s\n",
2606 amrBandModeString(amr.eAMRBandMode));
2607 printf(" eAMRFrameFormat = %s\n",
2608 amrFrameFormatString(amr.eAMRFrameFormat));
Andreas Huberbe06d262009-08-14 14:37:10 -07002609 }
2610
2611 break;
2612 }
2613
2614 default:
2615 {
2616 printf(" // Unknown\n");
2617 break;
2618 }
2619 }
2620
2621 printf("}\n");
2622}
2623
2624void OMXCodec::initOutputFormat(const sp<MetaData> &inputFormat) {
2625 mOutputFormat = new MetaData;
2626 mOutputFormat->setCString(kKeyDecoderComponent, mComponentName);
2627
2628 OMX_PARAM_PORTDEFINITIONTYPE def;
Andreas Huber4c483422009-09-02 16:05:36 -07002629 InitOMXParams(&def);
Andreas Huberbe06d262009-08-14 14:37:10 -07002630 def.nPortIndex = kPortIndexOutput;
2631
Andreas Huber784202e2009-10-15 13:46:54 -07002632 status_t err = mOMX->getParameter(
Andreas Huberbe06d262009-08-14 14:37:10 -07002633 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
2634 CHECK_EQ(err, OK);
2635
2636 switch (def.eDomain) {
2637 case OMX_PortDomainImage:
2638 {
2639 OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
2640 CHECK_EQ(imageDef->eCompressionFormat, OMX_IMAGE_CodingUnused);
2641
Andreas Hubere6c40962009-09-10 14:13:30 -07002642 mOutputFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
Andreas Huberbe06d262009-08-14 14:37:10 -07002643 mOutputFormat->setInt32(kKeyColorFormat, imageDef->eColorFormat);
2644 mOutputFormat->setInt32(kKeyWidth, imageDef->nFrameWidth);
2645 mOutputFormat->setInt32(kKeyHeight, imageDef->nFrameHeight);
2646 break;
2647 }
2648
2649 case OMX_PortDomainAudio:
2650 {
2651 OMX_AUDIO_PORTDEFINITIONTYPE *audio_def = &def.format.audio;
2652
Andreas Huberda050cf22009-09-02 14:01:43 -07002653 if (audio_def->eEncoding == OMX_AUDIO_CodingPCM) {
2654 OMX_AUDIO_PARAM_PCMMODETYPE params;
Andreas Huber4c483422009-09-02 16:05:36 -07002655 InitOMXParams(&params);
Andreas Huberda050cf22009-09-02 14:01:43 -07002656 params.nPortIndex = kPortIndexOutput;
Andreas Huberbe06d262009-08-14 14:37:10 -07002657
Andreas Huber784202e2009-10-15 13:46:54 -07002658 err = mOMX->getParameter(
Andreas Huberda050cf22009-09-02 14:01:43 -07002659 mNode, OMX_IndexParamAudioPcm, &params, sizeof(params));
2660 CHECK_EQ(err, OK);
Andreas Huberbe06d262009-08-14 14:37:10 -07002661
Andreas Huberda050cf22009-09-02 14:01:43 -07002662 CHECK_EQ(params.eNumData, OMX_NumericalDataSigned);
2663 CHECK_EQ(params.nBitPerSample, 16);
2664 CHECK_EQ(params.ePCMMode, OMX_AUDIO_PCMModeLinear);
Andreas Huberbe06d262009-08-14 14:37:10 -07002665
Andreas Huberda050cf22009-09-02 14:01:43 -07002666 int32_t numChannels, sampleRate;
2667 inputFormat->findInt32(kKeyChannelCount, &numChannels);
2668 inputFormat->findInt32(kKeySampleRate, &sampleRate);
Andreas Huberbe06d262009-08-14 14:37:10 -07002669
Andreas Huberda050cf22009-09-02 14:01:43 -07002670 if ((OMX_U32)numChannels != params.nChannels) {
2671 LOGW("Codec outputs a different number of channels than "
2672 "the input stream contains.");
2673 }
Andreas Huberbe06d262009-08-14 14:37:10 -07002674
Andreas Hubere6c40962009-09-10 14:13:30 -07002675 mOutputFormat->setCString(
2676 kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
Andreas Huberda050cf22009-09-02 14:01:43 -07002677
2678 // Use the codec-advertised number of channels, as some
2679 // codecs appear to output stereo even if the input data is
2680 // mono.
2681 mOutputFormat->setInt32(kKeyChannelCount, params.nChannels);
2682
2683 // The codec-reported sampleRate is not reliable...
2684 mOutputFormat->setInt32(kKeySampleRate, sampleRate);
2685 } else if (audio_def->eEncoding == OMX_AUDIO_CodingAMR) {
Andreas Huber7ae02c82009-09-09 16:29:47 -07002686 OMX_AUDIO_PARAM_AMRTYPE amr;
2687 InitOMXParams(&amr);
2688 amr.nPortIndex = kPortIndexOutput;
2689
Andreas Huber784202e2009-10-15 13:46:54 -07002690 err = mOMX->getParameter(
Andreas Huber7ae02c82009-09-09 16:29:47 -07002691 mNode, OMX_IndexParamAudioAmr, &amr, sizeof(amr));
2692 CHECK_EQ(err, OK);
2693
2694 CHECK_EQ(amr.nChannels, 1);
2695 mOutputFormat->setInt32(kKeyChannelCount, 1);
2696
2697 if (amr.eAMRBandMode >= OMX_AUDIO_AMRBandModeNB0
2698 && amr.eAMRBandMode <= OMX_AUDIO_AMRBandModeNB7) {
Andreas Hubere6c40962009-09-10 14:13:30 -07002699 mOutputFormat->setCString(
2700 kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AMR_NB);
Andreas Huber7ae02c82009-09-09 16:29:47 -07002701 mOutputFormat->setInt32(kKeySampleRate, 8000);
2702 } else if (amr.eAMRBandMode >= OMX_AUDIO_AMRBandModeWB0
2703 && amr.eAMRBandMode <= OMX_AUDIO_AMRBandModeWB8) {
Andreas Hubere6c40962009-09-10 14:13:30 -07002704 mOutputFormat->setCString(
2705 kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AMR_WB);
Andreas Huber7ae02c82009-09-09 16:29:47 -07002706 mOutputFormat->setInt32(kKeySampleRate, 16000);
2707 } else {
2708 CHECK(!"Unknown AMR band mode.");
2709 }
Andreas Huberda050cf22009-09-02 14:01:43 -07002710 } else if (audio_def->eEncoding == OMX_AUDIO_CodingAAC) {
Andreas Hubere6c40962009-09-10 14:13:30 -07002711 mOutputFormat->setCString(
2712 kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
Andreas Huberda050cf22009-09-02 14:01:43 -07002713 } else {
2714 CHECK(!"Should not be here. Unknown audio encoding.");
Andreas Huber43ad6eaf2009-09-01 16:02:43 -07002715 }
Andreas Huberbe06d262009-08-14 14:37:10 -07002716 break;
2717 }
2718
2719 case OMX_PortDomainVideo:
2720 {
2721 OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
2722
2723 if (video_def->eCompressionFormat == OMX_VIDEO_CodingUnused) {
Andreas Hubere6c40962009-09-10 14:13:30 -07002724 mOutputFormat->setCString(
2725 kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
Andreas Huberbe06d262009-08-14 14:37:10 -07002726 } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingMPEG4) {
Andreas Hubere6c40962009-09-10 14:13:30 -07002727 mOutputFormat->setCString(
2728 kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
Andreas Huberbe06d262009-08-14 14:37:10 -07002729 } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingH263) {
Andreas Hubere6c40962009-09-10 14:13:30 -07002730 mOutputFormat->setCString(
2731 kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263);
Andreas Huberbe06d262009-08-14 14:37:10 -07002732 } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingAVC) {
Andreas Hubere6c40962009-09-10 14:13:30 -07002733 mOutputFormat->setCString(
2734 kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
Andreas Huberbe06d262009-08-14 14:37:10 -07002735 } else {
2736 CHECK(!"Unknown compression format.");
2737 }
2738
2739 if (!strcmp(mComponentName, "OMX.PV.avcdec")) {
2740 // This component appears to be lying to me.
2741 mOutputFormat->setInt32(
2742 kKeyWidth, (video_def->nFrameWidth + 15) & -16);
2743 mOutputFormat->setInt32(
2744 kKeyHeight, (video_def->nFrameHeight + 15) & -16);
2745 } else {
2746 mOutputFormat->setInt32(kKeyWidth, video_def->nFrameWidth);
2747 mOutputFormat->setInt32(kKeyHeight, video_def->nFrameHeight);
2748 }
2749
2750 mOutputFormat->setInt32(kKeyColorFormat, video_def->eColorFormat);
2751 break;
2752 }
2753
2754 default:
2755 {
2756 CHECK(!"should not be here, neither audio nor video.");
2757 break;
2758 }
2759 }
2760}
2761
Andreas Hubere6c40962009-09-10 14:13:30 -07002762////////////////////////////////////////////////////////////////////////////////
2763
2764status_t QueryCodecs(
2765 const sp<IOMX> &omx,
2766 const char *mime, bool queryDecoders,
2767 Vector<CodecCapabilities> *results) {
2768 results->clear();
2769
2770 for (int index = 0;; ++index) {
2771 const char *componentName;
2772
2773 if (!queryDecoders) {
2774 componentName = GetCodec(
2775 kEncoderInfo, sizeof(kEncoderInfo) / sizeof(kEncoderInfo[0]),
2776 mime, index);
2777 } else {
2778 componentName = GetCodec(
2779 kDecoderInfo, sizeof(kDecoderInfo) / sizeof(kDecoderInfo[0]),
2780 mime, index);
2781 }
2782
2783 if (!componentName) {
2784 return OK;
2785 }
2786
Andreas Huber784202e2009-10-15 13:46:54 -07002787 sp<OMXCodecObserver> observer = new OMXCodecObserver;
Andreas Hubere6c40962009-09-10 14:13:30 -07002788 IOMX::node_id node;
Andreas Huber784202e2009-10-15 13:46:54 -07002789 status_t err = omx->allocateNode(componentName, observer, &node);
Andreas Hubere6c40962009-09-10 14:13:30 -07002790
2791 if (err != OK) {
2792 continue;
2793 }
2794
2795 OMXCodec::setComponentRole(omx, node, queryDecoders, mime);
2796
2797 results->push();
2798 CodecCapabilities *caps = &results->editItemAt(results->size() - 1);
2799 caps->mComponentName = componentName;
2800
2801 OMX_VIDEO_PARAM_PROFILELEVELTYPE param;
2802 InitOMXParams(&param);
2803
2804 param.nPortIndex = queryDecoders ? 0 : 1;
2805
2806 for (param.nProfileIndex = 0;; ++param.nProfileIndex) {
Andreas Huber784202e2009-10-15 13:46:54 -07002807 err = omx->getParameter(
Andreas Hubere6c40962009-09-10 14:13:30 -07002808 node, OMX_IndexParamVideoProfileLevelQuerySupported,
2809 &param, sizeof(param));
2810
2811 if (err != OK) {
2812 break;
2813 }
2814
2815 CodecProfileLevel profileLevel;
2816 profileLevel.mProfile = param.eProfile;
2817 profileLevel.mLevel = param.eLevel;
2818
2819 caps->mProfileLevels.push(profileLevel);
2820 }
2821
Andreas Huber784202e2009-10-15 13:46:54 -07002822 CHECK_EQ(omx->freeNode(node), OK);
Andreas Hubere6c40962009-09-10 14:13:30 -07002823 }
2824}
2825
Andreas Huberbe06d262009-08-14 14:37:10 -07002826} // namespace android