SoftMPEG4.cpp revision 269a355679fce6a71523faeefc2ff575abbd1a8e
1/* 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#include <media/IOMX.h> 27 28#include "mp4dec_api.h" 29 30namespace android { 31 32static const CodecProfileLevel kM4VProfileLevels[] = { 33 { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level0 }, 34 { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level0b }, 35 { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level1 }, 36 { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level2 }, 37 { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level3 }, 38}; 39 40static const CodecProfileLevel kH263ProfileLevels[] = { 41 { OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level10 }, 42 { OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level20 }, 43 { OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level30 }, 44 { OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level45 }, 45 { OMX_VIDEO_H263ProfileISWV2, OMX_VIDEO_H263Level10 }, 46 { OMX_VIDEO_H263ProfileISWV2, OMX_VIDEO_H263Level20 }, 47 { OMX_VIDEO_H263ProfileISWV2, OMX_VIDEO_H263Level30 }, 48 { OMX_VIDEO_H263ProfileISWV2, OMX_VIDEO_H263Level45 }, 49}; 50 51template<class T> 52static void InitOMXParams(T *params) { 53 params->nSize = sizeof(T); 54 params->nVersion.s.nVersionMajor = 1; 55 params->nVersion.s.nVersionMinor = 0; 56 params->nVersion.s.nRevision = 0; 57 params->nVersion.s.nStep = 0; 58} 59 60SoftMPEG4::SoftMPEG4( 61 const char *name, 62 const OMX_CALLBACKTYPE *callbacks, 63 OMX_PTR appData, 64 OMX_COMPONENTTYPE **component) 65 : SimpleSoftOMXComponent(name, callbacks, appData, component), 66 mMode(MODE_MPEG4), 67 mHandle(new tagvideoDecControls), 68 mInputBufferCount(0), 69 mWidth(352), 70 mHeight(288), 71 mCropLeft(0), 72 mCropTop(0), 73 mCropRight(mWidth - 1), 74 mCropBottom(mHeight - 1), 75 mSignalledError(false), 76 mInitialized(false), 77 mFramesConfigured(false), 78 mNumSamplesOutput(0), 79 mPvTime(0), 80 mOutputPortSettingsChange(NONE) { 81 if (!strcmp(name, "OMX.google.h263.decoder")) { 82 mMode = MODE_H263; 83 } else { 84 CHECK(!strcmp(name, "OMX.google.mpeg4.decoder")); 85 } 86 87 initPorts(); 88 CHECK_EQ(initDecoder(), (status_t)OK); 89} 90 91SoftMPEG4::~SoftMPEG4() { 92 if (mInitialized) { 93 PVCleanUpVideoDecoder(mHandle); 94 } 95 96 delete mHandle; 97 mHandle = NULL; 98} 99 100void SoftMPEG4::initPorts() { 101 OMX_PARAM_PORTDEFINITIONTYPE def; 102 InitOMXParams(&def); 103 104 def.nPortIndex = 0; 105 def.eDir = OMX_DirInput; 106 def.nBufferCountMin = kNumInputBuffers; 107 def.nBufferCountActual = def.nBufferCountMin; 108 def.nBufferSize = 8192; 109 def.bEnabled = OMX_TRUE; 110 def.bPopulated = OMX_FALSE; 111 def.eDomain = OMX_PortDomainVideo; 112 def.bBuffersContiguous = OMX_FALSE; 113 def.nBufferAlignment = 1; 114 115 def.format.video.cMIMEType = 116 (mMode == MODE_MPEG4) 117 ? const_cast<char *>(MEDIA_MIMETYPE_VIDEO_MPEG4) 118 : const_cast<char *>(MEDIA_MIMETYPE_VIDEO_H263); 119 120 def.format.video.pNativeRender = NULL; 121 def.format.video.nFrameWidth = mWidth; 122 def.format.video.nFrameHeight = mHeight; 123 def.format.video.nStride = def.format.video.nFrameWidth; 124 def.format.video.nSliceHeight = def.format.video.nFrameHeight; 125 def.format.video.nBitrate = 0; 126 def.format.video.xFramerate = 0; 127 def.format.video.bFlagErrorConcealment = OMX_FALSE; 128 129 def.format.video.eCompressionFormat = 130 mMode == MODE_MPEG4 ? OMX_VIDEO_CodingMPEG4 : OMX_VIDEO_CodingH263; 131 132 def.format.video.eColorFormat = OMX_COLOR_FormatUnused; 133 def.format.video.pNativeWindow = NULL; 134 135 addPort(def); 136 137 def.nPortIndex = 1; 138 def.eDir = OMX_DirOutput; 139 def.nBufferCountMin = kNumOutputBuffers; 140 def.nBufferCountActual = def.nBufferCountMin; 141 def.bEnabled = OMX_TRUE; 142 def.bPopulated = OMX_FALSE; 143 def.eDomain = OMX_PortDomainVideo; 144 def.bBuffersContiguous = OMX_FALSE; 145 def.nBufferAlignment = 2; 146 147 def.format.video.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_VIDEO_RAW); 148 def.format.video.pNativeRender = NULL; 149 def.format.video.nFrameWidth = mWidth; 150 def.format.video.nFrameHeight = mHeight; 151 def.format.video.nStride = def.format.video.nFrameWidth; 152 def.format.video.nSliceHeight = def.format.video.nFrameHeight; 153 def.format.video.nBitrate = 0; 154 def.format.video.xFramerate = 0; 155 def.format.video.bFlagErrorConcealment = OMX_FALSE; 156 def.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused; 157 def.format.video.eColorFormat = OMX_COLOR_FormatYUV420Planar; 158 def.format.video.pNativeWindow = NULL; 159 160 def.nBufferSize = 161 (def.format.video.nFrameWidth * def.format.video.nFrameHeight * 3) / 2; 162 163 addPort(def); 164} 165 166status_t SoftMPEG4::initDecoder() { 167 memset(mHandle, 0, sizeof(tagvideoDecControls)); 168 return OK; 169} 170 171OMX_ERRORTYPE SoftMPEG4::internalGetParameter( 172 OMX_INDEXTYPE index, OMX_PTR params) { 173 switch (index) { 174 case OMX_IndexParamVideoPortFormat: 175 { 176 OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams = 177 (OMX_VIDEO_PARAM_PORTFORMATTYPE *)params; 178 179 if (formatParams->nPortIndex > 1) { 180 return OMX_ErrorUndefined; 181 } 182 183 if (formatParams->nIndex != 0) { 184 return OMX_ErrorNoMore; 185 } 186 187 if (formatParams->nPortIndex == 0) { 188 formatParams->eCompressionFormat = 189 (mMode == MODE_MPEG4) 190 ? OMX_VIDEO_CodingMPEG4 : OMX_VIDEO_CodingH263; 191 192 formatParams->eColorFormat = OMX_COLOR_FormatUnused; 193 formatParams->xFramerate = 0; 194 } else { 195 CHECK_EQ(formatParams->nPortIndex, 1u); 196 197 formatParams->eCompressionFormat = OMX_VIDEO_CodingUnused; 198 formatParams->eColorFormat = OMX_COLOR_FormatYUV420Planar; 199 formatParams->xFramerate = 0; 200 } 201 202 return OMX_ErrorNone; 203 } 204 205 case OMX_IndexParamVideoProfileLevelQuerySupported: 206 { 207 OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileLevel = 208 (OMX_VIDEO_PARAM_PROFILELEVELTYPE *) params; 209 210 if (profileLevel->nPortIndex != 0) { // Input port only 211 ALOGE("Invalid port index: %ld", profileLevel->nPortIndex); 212 return OMX_ErrorUnsupportedIndex; 213 } 214 215 size_t index = profileLevel->nProfileIndex; 216 if (mMode == MODE_H263) { 217 size_t nProfileLevels = 218 sizeof(kH263ProfileLevels) / sizeof(kH263ProfileLevels[0]); 219 if (index >= nProfileLevels) { 220 return OMX_ErrorNoMore; 221 } 222 223 profileLevel->eProfile = kH263ProfileLevels[index].mProfile; 224 profileLevel->eLevel = kH263ProfileLevels[index].mLevel; 225 } else { 226 size_t nProfileLevels = 227 sizeof(kM4VProfileLevels) / sizeof(kM4VProfileLevels[0]); 228 if (index >= nProfileLevels) { 229 return OMX_ErrorNoMore; 230 } 231 232 profileLevel->eProfile = kM4VProfileLevels[index].mProfile; 233 profileLevel->eLevel = kM4VProfileLevels[index].mLevel; 234 } 235 return OMX_ErrorNone; 236 } 237 238 default: 239 return SimpleSoftOMXComponent::internalGetParameter(index, params); 240 } 241} 242 243OMX_ERRORTYPE SoftMPEG4::internalSetParameter( 244 OMX_INDEXTYPE index, const OMX_PTR params) { 245 switch (index) { 246 case OMX_IndexParamStandardComponentRole: 247 { 248 const OMX_PARAM_COMPONENTROLETYPE *roleParams = 249 (const OMX_PARAM_COMPONENTROLETYPE *)params; 250 251 if (mMode == MODE_MPEG4) { 252 if (strncmp((const char *)roleParams->cRole, 253 "video_decoder.mpeg4", 254 OMX_MAX_STRINGNAME_SIZE - 1)) { 255 return OMX_ErrorUndefined; 256 } 257 } else { 258 if (strncmp((const char *)roleParams->cRole, 259 "video_decoder.h263", 260 OMX_MAX_STRINGNAME_SIZE - 1)) { 261 return OMX_ErrorUndefined; 262 } 263 } 264 265 return OMX_ErrorNone; 266 } 267 268 case OMX_IndexParamVideoPortFormat: 269 { 270 OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams = 271 (OMX_VIDEO_PARAM_PORTFORMATTYPE *)params; 272 273 if (formatParams->nPortIndex > 1) { 274 return OMX_ErrorUndefined; 275 } 276 277 if (formatParams->nIndex != 0) { 278 return OMX_ErrorNoMore; 279 } 280 281 return OMX_ErrorNone; 282 } 283 284 default: 285 return SimpleSoftOMXComponent::internalSetParameter(index, params); 286 } 287} 288 289OMX_ERRORTYPE SoftMPEG4::getConfig( 290 OMX_INDEXTYPE index, OMX_PTR params) { 291 switch (index) { 292 case OMX_IndexConfigCommonOutputCrop: 293 { 294 OMX_CONFIG_RECTTYPE *rectParams = (OMX_CONFIG_RECTTYPE *)params; 295 296 if (rectParams->nPortIndex != 1) { 297 return OMX_ErrorUndefined; 298 } 299 300 rectParams->nLeft = mCropLeft; 301 rectParams->nTop = mCropTop; 302 rectParams->nWidth = mCropRight - mCropLeft + 1; 303 rectParams->nHeight = mCropBottom - mCropTop + 1; 304 305 return OMX_ErrorNone; 306 } 307 308 default: 309 return OMX_ErrorUnsupportedIndex; 310 } 311} 312 313void SoftMPEG4::onQueueFilled(OMX_U32 portIndex) { 314 if (mSignalledError || mOutputPortSettingsChange != NONE) { 315 return; 316 } 317 318 List<BufferInfo *> &inQueue = getPortQueue(0); 319 List<BufferInfo *> &outQueue = getPortQueue(1); 320 321 while (!inQueue.empty() && outQueue.size() == kNumOutputBuffers) { 322 BufferInfo *inInfo = *inQueue.begin(); 323 OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; 324 325 PortInfo *port = editPortInfo(1); 326 327 OMX_BUFFERHEADERTYPE *outHeader = 328 port->mBuffers.editItemAt(mNumSamplesOutput & 1).mHeader; 329 330 if ((inHeader->nFlags & OMX_BUFFERFLAG_EOS) && inHeader->nFilledLen == 0) { 331 inQueue.erase(inQueue.begin()); 332 inInfo->mOwnedByUs = false; 333 notifyEmptyBufferDone(inHeader); 334 335 ++mInputBufferCount; 336 337 outHeader->nFilledLen = 0; 338 outHeader->nFlags = OMX_BUFFERFLAG_EOS; 339 340 List<BufferInfo *>::iterator it = outQueue.begin(); 341 while ((*it)->mHeader != outHeader) { 342 ++it; 343 } 344 345 BufferInfo *outInfo = *it; 346 outInfo->mOwnedByUs = false; 347 outQueue.erase(it); 348 outInfo = NULL; 349 350 notifyFillBufferDone(outHeader); 351 outHeader = NULL; 352 return; 353 } 354 355 uint8_t *bitstream = inHeader->pBuffer + inHeader->nOffset; 356 357 if (!mInitialized) { 358 uint8_t *vol_data[1]; 359 int32_t vol_size = 0; 360 361 vol_data[0] = NULL; 362 363 if (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) { 364 vol_data[0] = bitstream; 365 vol_size = inHeader->nFilledLen; 366 } 367 368 MP4DecodingMode mode = 369 (mMode == MODE_MPEG4) ? MPEG4_MODE : H263_MODE; 370 371 Bool success = PVInitVideoDecoder( 372 mHandle, vol_data, &vol_size, 1, mWidth, mHeight, mode); 373 374 if (!success) { 375 ALOGW("PVInitVideoDecoder failed. Unsupported content?"); 376 377 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); 378 mSignalledError = true; 379 return; 380 } 381 382 MP4DecodingMode actualMode = PVGetDecBitstreamMode(mHandle); 383 if (mode != actualMode) { 384 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); 385 mSignalledError = true; 386 return; 387 } 388 389 PVSetPostProcType((VideoDecControls *) mHandle, 0); 390 391 if (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) { 392 inInfo->mOwnedByUs = false; 393 inQueue.erase(inQueue.begin()); 394 inInfo = NULL; 395 notifyEmptyBufferDone(inHeader); 396 inHeader = NULL; 397 } 398 399 mInitialized = true; 400 401 if (mode == MPEG4_MODE && portSettingsChanged()) { 402 return; 403 } 404 405 continue; 406 } 407 408 if (!mFramesConfigured) { 409 PortInfo *port = editPortInfo(1); 410 OMX_BUFFERHEADERTYPE *outHeader = port->mBuffers.editItemAt(1).mHeader; 411 412 PVSetReferenceYUV(mHandle, outHeader->pBuffer); 413 414 mFramesConfigured = true; 415 } 416 417 uint32_t useExtTimestamp = (inHeader->nOffset == 0); 418 419 // decoder deals in ms (int32_t), OMX in us (int64_t) 420 // so use fake timestamp instead 421 uint32_t timestamp = 0xFFFFFFFF; 422 if (useExtTimestamp) { 423 mPvToOmxTimeMap.add(mPvTime, inHeader->nTimeStamp); 424 timestamp = mPvTime; 425 mPvTime++; 426 } 427 428 int32_t bufferSize = inHeader->nFilledLen; 429 int32_t tmp = bufferSize; 430 431 // The PV decoder is lying to us, sometimes it'll claim to only have 432 // consumed a subset of the buffer when it clearly consumed all of it. 433 // ignore whatever it says... 434 if (PVDecodeVideoFrame( 435 mHandle, &bitstream, ×tamp, &tmp, 436 &useExtTimestamp, 437 outHeader->pBuffer) != PV_TRUE) { 438 ALOGE("failed to decode video frame."); 439 440 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); 441 mSignalledError = true; 442 return; 443 } 444 445 if (portSettingsChanged()) { 446 return; 447 } 448 449 // decoder deals in ms, OMX in us. 450 outHeader->nTimeStamp = mPvToOmxTimeMap.valueFor(timestamp); 451 mPvToOmxTimeMap.removeItem(timestamp); 452 453 inHeader->nOffset += bufferSize; 454 inHeader->nFilledLen = 0; 455 if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { 456 outHeader->nFlags = OMX_BUFFERFLAG_EOS; 457 } else { 458 outHeader->nFlags = 0; 459 } 460 461 if (inHeader->nFilledLen == 0) { 462 inInfo->mOwnedByUs = false; 463 inQueue.erase(inQueue.begin()); 464 inInfo = NULL; 465 notifyEmptyBufferDone(inHeader); 466 inHeader = NULL; 467 } 468 469 ++mInputBufferCount; 470 471 outHeader->nOffset = 0; 472 outHeader->nFilledLen = (mWidth * mHeight * 3) / 2; 473 474 List<BufferInfo *>::iterator it = outQueue.begin(); 475 while ((*it)->mHeader != outHeader) { 476 ++it; 477 } 478 479 BufferInfo *outInfo = *it; 480 outInfo->mOwnedByUs = false; 481 outQueue.erase(it); 482 outInfo = NULL; 483 484 notifyFillBufferDone(outHeader); 485 outHeader = NULL; 486 487 ++mNumSamplesOutput; 488 } 489} 490 491bool SoftMPEG4::portSettingsChanged() { 492 int32_t disp_width, disp_height; 493 PVGetVideoDimensions(mHandle, &disp_width, &disp_height); 494 495 int32_t buf_width, buf_height; 496 PVGetBufferDimensions(mHandle, &buf_width, &buf_height); 497 498 CHECK_LE(disp_width, buf_width); 499 CHECK_LE(disp_height, buf_height); 500 501 ALOGV("disp_width = %d, disp_height = %d, buf_width = %d, buf_height = %d", 502 disp_width, disp_height, buf_width, buf_height); 503 504 if (mCropRight != disp_width - 1 505 || mCropBottom != disp_height - 1) { 506 mCropLeft = 0; 507 mCropTop = 0; 508 mCropRight = disp_width - 1; 509 mCropBottom = disp_height - 1; 510 511 notify(OMX_EventPortSettingsChanged, 512 1, 513 OMX_IndexConfigCommonOutputCrop, 514 NULL); 515 } 516 517 if (buf_width != mWidth || buf_height != mHeight) { 518 mWidth = buf_width; 519 mHeight = buf_height; 520 521 updatePortDefinitions(); 522 523 if (mMode == MODE_H263) { 524 PVCleanUpVideoDecoder(mHandle); 525 526 uint8_t *vol_data[1]; 527 int32_t vol_size = 0; 528 529 vol_data[0] = NULL; 530 if (!PVInitVideoDecoder( 531 mHandle, vol_data, &vol_size, 1, mWidth, mHeight, 532 H263_MODE)) { 533 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); 534 mSignalledError = true; 535 return true; 536 } 537 } 538 539 mFramesConfigured = false; 540 541 notify(OMX_EventPortSettingsChanged, 1, 0, NULL); 542 mOutputPortSettingsChange = AWAITING_DISABLED; 543 return true; 544 } 545 546 return false; 547} 548 549void SoftMPEG4::onPortFlushCompleted(OMX_U32 portIndex) { 550 if (portIndex == 0 && mInitialized) { 551 CHECK_EQ((int)PVResetVideoDecoder(mHandle), (int)PV_TRUE); 552 } 553} 554 555void SoftMPEG4::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) { 556 if (portIndex != 1) { 557 return; 558 } 559 560 switch (mOutputPortSettingsChange) { 561 case NONE: 562 break; 563 564 case AWAITING_DISABLED: 565 { 566 CHECK(!enabled); 567 mOutputPortSettingsChange = AWAITING_ENABLED; 568 break; 569 } 570 571 default: 572 { 573 CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED); 574 CHECK(enabled); 575 mOutputPortSettingsChange = NONE; 576 break; 577 } 578 } 579} 580 581void SoftMPEG4::onReset() { 582 mPvToOmxTimeMap.clear(); 583 mSignalledError = false; 584 mOutputPortSettingsChange = NONE; 585 mFramesConfigured = false; 586 if (mInitialized) { 587 PVCleanUpVideoDecoder(mHandle); 588 mInitialized = false; 589 } 590} 591 592void SoftMPEG4::updatePortDefinitions() { 593 OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(0)->mDef; 594 def->format.video.nFrameWidth = mWidth; 595 def->format.video.nFrameHeight = mHeight; 596 def->format.video.nStride = def->format.video.nFrameWidth; 597 def->format.video.nSliceHeight = def->format.video.nFrameHeight; 598 599 def = &editPortInfo(1)->mDef; 600 def->format.video.nFrameWidth = mWidth; 601 def->format.video.nFrameHeight = mHeight; 602 def->format.video.nStride = def->format.video.nFrameWidth; 603 def->format.video.nSliceHeight = def->format.video.nFrameHeight; 604 605 def->nBufferSize = 606 (((def->format.video.nFrameWidth + 15) & -16) 607 * ((def->format.video.nFrameHeight + 15) & -16) * 3) / 2; 608} 609 610} // namespace android 611 612android::SoftOMXComponent *createSoftOMXComponent( 613 const char *name, const OMX_CALLBACKTYPE *callbacks, 614 OMX_PTR appData, OMX_COMPONENTTYPE **component) { 615 return new android::SoftMPEG4(name, callbacks, appData, component); 616} 617 618