blob: 13e1662900a4cb1268114d55d03d55204881367d [file] [log] [blame]
Andreas Huber4b3913a2011-05-11 14:13:42 -07001/*
2 * Copyright (C) 2011 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 "SoftMPEG4"
19#include <utils/Log.h>
20
21#include "SoftMPEG4.h"
22
23#include <media/stagefright/foundation/ADebug.h>
24#include <media/stagefright/MediaDefs.h>
25#include <media/stagefright/MediaErrors.h>
26
27#include "mp4dec_api.h"
28
29namespace android {
30
31template<class T>
32static void InitOMXParams(T *params) {
33 params->nSize = sizeof(T);
34 params->nVersion.s.nVersionMajor = 1;
35 params->nVersion.s.nVersionMinor = 0;
36 params->nVersion.s.nRevision = 0;
37 params->nVersion.s.nStep = 0;
38}
39
40SoftMPEG4::SoftMPEG4(
41 const char *name,
42 const OMX_CALLBACKTYPE *callbacks,
43 OMX_PTR appData,
44 OMX_COMPONENTTYPE **component)
45 : SimpleSoftOMXComponent(name, callbacks, appData, component),
46 mMode(MODE_MPEG4),
47 mHandle(new tagvideoDecControls),
48 mInputBufferCount(0),
49 mWidth(352),
50 mHeight(288),
51 mCropLeft(0),
52 mCropTop(0),
53 mCropRight(mWidth - 1),
54 mCropBottom(mHeight - 1),
55 mSignalledError(false),
56 mInitialized(false),
57 mFramesConfigured(false),
58 mNumSamplesOutput(0),
59 mOutputPortSettingsChange(NONE) {
60 if (!strcmp(name, "OMX.google.h263.decoder")) {
61 mMode = MODE_H263;
62 } else {
63 CHECK(!strcmp(name, "OMX.google.mpeg4.decoder"));
64 }
65
66 initPorts();
67 CHECK_EQ(initDecoder(), (status_t)OK);
68}
69
70SoftMPEG4::~SoftMPEG4() {
71 if (mInitialized) {
72 PVCleanUpVideoDecoder(mHandle);
73 }
74
75 delete mHandle;
76 mHandle = NULL;
77}
78
79void SoftMPEG4::initPorts() {
80 OMX_PARAM_PORTDEFINITIONTYPE def;
81 InitOMXParams(&def);
82
83 def.nPortIndex = 0;
84 def.eDir = OMX_DirInput;
85 def.nBufferCountMin = kNumInputBuffers;
86 def.nBufferCountActual = def.nBufferCountMin;
87 def.nBufferSize = 8192;
88 def.bEnabled = OMX_TRUE;
89 def.bPopulated = OMX_FALSE;
90 def.eDomain = OMX_PortDomainVideo;
91 def.bBuffersContiguous = OMX_FALSE;
92 def.nBufferAlignment = 1;
93
94 def.format.video.cMIMEType =
95 (mMode == MODE_MPEG4)
96 ? const_cast<char *>(MEDIA_MIMETYPE_VIDEO_MPEG4)
97 : const_cast<char *>(MEDIA_MIMETYPE_VIDEO_H263);
98
99 def.format.video.pNativeRender = NULL;
100 def.format.video.nFrameWidth = mWidth;
101 def.format.video.nFrameHeight = mHeight;
102 def.format.video.nStride = def.format.video.nFrameWidth;
103 def.format.video.nSliceHeight = def.format.video.nFrameHeight;
104 def.format.video.nBitrate = 0;
105 def.format.video.xFramerate = 0;
106 def.format.video.bFlagErrorConcealment = OMX_FALSE;
107
108 def.format.video.eCompressionFormat =
109 mMode == MODE_MPEG4 ? OMX_VIDEO_CodingMPEG4 : OMX_VIDEO_CodingH263;
110
111 def.format.video.eColorFormat = OMX_COLOR_FormatUnused;
112 def.format.video.pNativeWindow = NULL;
113
114 addPort(def);
115
116 def.nPortIndex = 1;
117 def.eDir = OMX_DirOutput;
118 def.nBufferCountMin = kNumOutputBuffers;
119 def.nBufferCountActual = def.nBufferCountMin;
120 def.bEnabled = OMX_TRUE;
121 def.bPopulated = OMX_FALSE;
122 def.eDomain = OMX_PortDomainVideo;
123 def.bBuffersContiguous = OMX_FALSE;
124 def.nBufferAlignment = 2;
125
126 def.format.video.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_VIDEO_RAW);
127 def.format.video.pNativeRender = NULL;
128 def.format.video.nFrameWidth = mWidth;
129 def.format.video.nFrameHeight = mHeight;
130 def.format.video.nStride = def.format.video.nFrameWidth;
131 def.format.video.nSliceHeight = def.format.video.nFrameHeight;
132 def.format.video.nBitrate = 0;
133 def.format.video.xFramerate = 0;
134 def.format.video.bFlagErrorConcealment = OMX_FALSE;
135 def.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused;
136 def.format.video.eColorFormat = OMX_COLOR_FormatYUV420Planar;
137 def.format.video.pNativeWindow = NULL;
138
139 def.nBufferSize =
140 (def.format.video.nFrameWidth * def.format.video.nFrameHeight * 3) / 2;
141
142 addPort(def);
143}
144
145status_t SoftMPEG4::initDecoder() {
146 memset(mHandle, 0, sizeof(tagvideoDecControls));
147 return OK;
148}
149
150OMX_ERRORTYPE SoftMPEG4::internalGetParameter(
151 OMX_INDEXTYPE index, OMX_PTR params) {
152 switch (index) {
153 case OMX_IndexParamVideoPortFormat:
154 {
155 OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams =
156 (OMX_VIDEO_PARAM_PORTFORMATTYPE *)params;
157
158 if (formatParams->nPortIndex > 1) {
159 return OMX_ErrorUndefined;
160 }
161
162 if (formatParams->nIndex != 0) {
163 return OMX_ErrorNoMore;
164 }
165
166 if (formatParams->nPortIndex == 0) {
167 formatParams->eCompressionFormat =
168 (mMode == MODE_MPEG4)
169 ? OMX_VIDEO_CodingMPEG4 : OMX_VIDEO_CodingH263;
170
171 formatParams->eColorFormat = OMX_COLOR_FormatUnused;
172 formatParams->xFramerate = 0;
173 } else {
174 CHECK_EQ(formatParams->nPortIndex, 1u);
175
176 formatParams->eCompressionFormat = OMX_VIDEO_CodingUnused;
177 formatParams->eColorFormat = OMX_COLOR_FormatYUV420Planar;
178 formatParams->xFramerate = 0;
179 }
180
181 return OMX_ErrorNone;
182 }
183
184 default:
185 return SimpleSoftOMXComponent::internalGetParameter(index, params);
186 }
187}
188
189OMX_ERRORTYPE SoftMPEG4::internalSetParameter(
190 OMX_INDEXTYPE index, const OMX_PTR params) {
191 switch (index) {
192 case OMX_IndexParamStandardComponentRole:
193 {
194 const OMX_PARAM_COMPONENTROLETYPE *roleParams =
195 (const OMX_PARAM_COMPONENTROLETYPE *)params;
196
197 if (mMode == MODE_MPEG4) {
198 if (strncmp((const char *)roleParams->cRole,
199 "video_decoder.mpeg4",
200 OMX_MAX_STRINGNAME_SIZE - 1)) {
201 return OMX_ErrorUndefined;
202 }
203 } else {
204 if (strncmp((const char *)roleParams->cRole,
205 "video_decoder.h263",
206 OMX_MAX_STRINGNAME_SIZE - 1)) {
207 return OMX_ErrorUndefined;
208 }
209 }
210
211 return OMX_ErrorNone;
212 }
213
214 case OMX_IndexParamVideoPortFormat:
215 {
216 OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams =
217 (OMX_VIDEO_PARAM_PORTFORMATTYPE *)params;
218
219 if (formatParams->nPortIndex > 1) {
220 return OMX_ErrorUndefined;
221 }
222
223 if (formatParams->nIndex != 0) {
224 return OMX_ErrorNoMore;
225 }
226
227 return OMX_ErrorNone;
228 }
229
230 default:
231 return SimpleSoftOMXComponent::internalSetParameter(index, params);
232 }
233}
234
235OMX_ERRORTYPE SoftMPEG4::getConfig(
236 OMX_INDEXTYPE index, OMX_PTR params) {
237 switch (index) {
238 case OMX_IndexConfigCommonOutputCrop:
239 {
240 OMX_CONFIG_RECTTYPE *rectParams = (OMX_CONFIG_RECTTYPE *)params;
241
242 if (rectParams->nPortIndex != 1) {
243 return OMX_ErrorUndefined;
244 }
245
246 rectParams->nLeft = mCropLeft;
247 rectParams->nTop = mCropTop;
248 rectParams->nWidth = mCropRight - mCropLeft + 1;
249 rectParams->nHeight = mCropBottom - mCropTop + 1;
250
251 return OMX_ErrorNone;
252 }
253
254 default:
255 return OMX_ErrorUnsupportedIndex;
256 }
257}
258
259void SoftMPEG4::onQueueFilled(OMX_U32 portIndex) {
260 if (mSignalledError || mOutputPortSettingsChange != NONE) {
261 return;
262 }
263
264 List<BufferInfo *> &inQueue = getPortQueue(0);
265 List<BufferInfo *> &outQueue = getPortQueue(1);
266
267 while (!inQueue.empty() && outQueue.size() == kNumOutputBuffers) {
268 BufferInfo *inInfo = *inQueue.begin();
269 OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
270
271 PortInfo *port = editPortInfo(1);
272
273 OMX_BUFFERHEADERTYPE *outHeader =
274 port->mBuffers.editItemAt(mNumSamplesOutput & 1).mHeader;
275
276 if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
277 inQueue.erase(inQueue.begin());
278 inInfo->mOwnedByUs = false;
279 notifyEmptyBufferDone(inHeader);
280
281 ++mInputBufferCount;
282
283 outHeader->nFilledLen = 0;
284 outHeader->nFlags = OMX_BUFFERFLAG_EOS;
285
286 List<BufferInfo *>::iterator it = outQueue.begin();
287 while ((*it)->mHeader != outHeader) {
288 ++it;
289 }
290
291 BufferInfo *outInfo = *it;
292 outInfo->mOwnedByUs = false;
293 outQueue.erase(it);
294 outInfo = NULL;
295
296 notifyFillBufferDone(outHeader);
297 outHeader = NULL;
298 return;
299 }
300
301 uint8_t *bitstream = inHeader->pBuffer + inHeader->nOffset;
302
303 if (!mInitialized) {
304 uint8_t *vol_data[1];
305 int32_t vol_size = 0;
306
307 vol_data[0] = NULL;
308
309 if (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) {
310 vol_data[0] = bitstream;
311 vol_size = inHeader->nFilledLen;
312 }
313
314 MP4DecodingMode mode =
315 (mMode == MODE_MPEG4) ? MPEG4_MODE : H263_MODE;
316
317 Bool success = PVInitVideoDecoder(
318 mHandle, vol_data, &vol_size, 1, mWidth, mHeight, mode);
319
320 if (!success) {
321 LOGW("PVInitVideoDecoder failed. Unsupported content?");
322
323 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
324 mSignalledError = true;
325 return;
326 }
327
328 MP4DecodingMode actualMode = PVGetDecBitstreamMode(mHandle);
329 if (mode != actualMode) {
330 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
331 mSignalledError = true;
332 return;
333 }
334
335 PVSetPostProcType((VideoDecControls *) mHandle, 0);
336
337 if (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) {
338 inInfo->mOwnedByUs = false;
339 inQueue.erase(inQueue.begin());
340 inInfo = NULL;
341 notifyEmptyBufferDone(inHeader);
342 inHeader = NULL;
343 }
344
345 mInitialized = true;
346
347 if (mode == MPEG4_MODE && portSettingsChanged()) {
348 return;
349 }
350
351 continue;
352 }
353
354 if (!mFramesConfigured) {
355 PortInfo *port = editPortInfo(1);
356 OMX_BUFFERHEADERTYPE *outHeader = port->mBuffers.editItemAt(1).mHeader;
357
358 PVSetReferenceYUV(mHandle, outHeader->pBuffer);
359
360 mFramesConfigured = true;
361 }
362
363 uint32_t timestamp = 0xFFFFFFFF;
364 int32_t bufferSize = inHeader->nFilledLen;
365
366 uint32_t useExtTimestamp = 0;
367 if (PVDecodeVideoFrame(
368 mHandle, &bitstream, &timestamp, &bufferSize,
369 &useExtTimestamp,
370 outHeader->pBuffer) != PV_TRUE) {
371 LOGE("failed to decode video frame.");
372
373 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
374 mSignalledError = true;
375 return;
376 }
377
378 if (portSettingsChanged()) {
379 return;
380 }
381
382 outHeader->nTimeStamp = inHeader->nTimeStamp;
383
384 inInfo->mOwnedByUs = false;
385 inQueue.erase(inQueue.begin());
386 inInfo = NULL;
387 notifyEmptyBufferDone(inHeader);
388 inHeader = NULL;
389
390 ++mInputBufferCount;
391
392 outHeader->nOffset = 0;
393 outHeader->nFilledLen = (mWidth * mHeight * 3) / 2;
394 outHeader->nFlags = 0;
395
396 List<BufferInfo *>::iterator it = outQueue.begin();
397 while ((*it)->mHeader != outHeader) {
398 ++it;
399 }
400
401 BufferInfo *outInfo = *it;
402 outInfo->mOwnedByUs = false;
403 outQueue.erase(it);
404 outInfo = NULL;
405
406 notifyFillBufferDone(outHeader);
407 outHeader = NULL;
408
409 ++mNumSamplesOutput;
410 }
411}
412
413bool SoftMPEG4::portSettingsChanged() {
414 int32_t disp_width, disp_height;
415 PVGetVideoDimensions(mHandle, &disp_width, &disp_height);
416
417 int32_t buf_width, buf_height;
418 PVGetBufferDimensions(mHandle, &buf_width, &buf_height);
419
420 CHECK_LE(disp_width, buf_width);
421 CHECK_LE(disp_height, buf_height);
422
423 LOGV("disp_width = %d, disp_height = %d, buf_width = %d, buf_height = %d",
424 disp_width, disp_height, buf_width, buf_height);
425
426 if (mCropRight != disp_width - 1
427 || mCropBottom != disp_height - 1) {
428 mCropLeft = 0;
429 mCropTop = 0;
430 mCropRight = disp_width - 1;
431 mCropBottom = disp_height - 1;
432
433 notify(OMX_EventPortSettingsChanged,
434 1,
435 OMX_IndexConfigCommonOutputCrop,
436 NULL);
437 }
438
439 if (buf_width != mWidth || buf_height != mHeight) {
440 mWidth = buf_width;
441 mHeight = buf_height;
442
443 updatePortDefinitions();
444
445 if (mMode == MODE_H263) {
446 PVCleanUpVideoDecoder(mHandle);
447
448 uint8_t *vol_data[1];
449 int32_t vol_size = 0;
450
451 vol_data[0] = NULL;
452 if (!PVInitVideoDecoder(
453 mHandle, vol_data, &vol_size, 1, mWidth, mHeight,
454 H263_MODE)) {
455 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
456 mSignalledError = true;
457 return true;
458 }
459 }
460
461 mFramesConfigured = false;
462
463 notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
464 mOutputPortSettingsChange = AWAITING_DISABLED;
465 return true;
466 }
467
468 return false;
469}
470
471void SoftMPEG4::onPortFlushCompleted(OMX_U32 portIndex) {
472 if (portIndex == 0 && mInitialized) {
473 CHECK_EQ((int)PVResetVideoDecoder(mHandle), (int)PV_TRUE);
474 }
475}
476
477void SoftMPEG4::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) {
478 if (portIndex != 1) {
479 return;
480 }
481
482 switch (mOutputPortSettingsChange) {
483 case NONE:
484 break;
485
486 case AWAITING_DISABLED:
487 {
488 CHECK(!enabled);
489 mOutputPortSettingsChange = AWAITING_ENABLED;
490 break;
491 }
492
493 default:
494 {
495 CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED);
496 CHECK(enabled);
497 mOutputPortSettingsChange = NONE;
498 break;
499 }
500 }
501}
502
503void SoftMPEG4::updatePortDefinitions() {
504 OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(0)->mDef;
505 def->format.video.nFrameWidth = mWidth;
506 def->format.video.nFrameHeight = mHeight;
507 def->format.video.nStride = def->format.video.nFrameWidth;
508 def->format.video.nSliceHeight = def->format.video.nFrameHeight;
509
510 def = &editPortInfo(1)->mDef;
511 def->format.video.nFrameWidth = mWidth;
512 def->format.video.nFrameHeight = mHeight;
513 def->format.video.nStride = def->format.video.nFrameWidth;
514 def->format.video.nSliceHeight = def->format.video.nFrameHeight;
515
516 def->nBufferSize =
517 (((def->format.video.nFrameWidth + 15) & -16)
518 * ((def->format.video.nFrameHeight + 15) & -16) * 3) / 2;
519}
520
521} // namespace android
522
523android::SoftOMXComponent *createSoftOMXComponent(
524 const char *name, const OMX_CALLBACKTYPE *callbacks,
525 OMX_PTR appData, OMX_COMPONENTTYPE **component) {
526 return new android::SoftMPEG4(name, callbacks, appData, component);
527}
528