SoftMPEG4.cpp revision f2af5a2c607e71ff4cd39da28b077c0a68b206fe
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 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 useExtTimestamp = (inHeader->nOffset == 0); 364 365 // decoder deals in ms, OMX in us. 366 uint32_t timestamp = 367 useExtTimestamp ? (inHeader->nTimeStamp + 500) / 1000 : 0xFFFFFFFF; 368 369 int32_t bufferSize = inHeader->nFilledLen; 370 371 if (PVDecodeVideoFrame( 372 mHandle, &bitstream, ×tamp, &bufferSize, 373 &useExtTimestamp, 374 outHeader->pBuffer) != PV_TRUE) { 375 LOGE("failed to decode video frame."); 376 377 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); 378 mSignalledError = true; 379 return; 380 } 381 382 if (portSettingsChanged()) { 383 return; 384 } 385 386 // decoder deals in ms, OMX in us. 387 outHeader->nTimeStamp = timestamp * 1000; 388 389 CHECK_LE(bufferSize, inHeader->nFilledLen); 390 inHeader->nOffset += inHeader->nFilledLen - bufferSize; 391 inHeader->nFilledLen = bufferSize; 392 393 if (inHeader->nFilledLen == 0) { 394 inInfo->mOwnedByUs = false; 395 inQueue.erase(inQueue.begin()); 396 inInfo = NULL; 397 notifyEmptyBufferDone(inHeader); 398 inHeader = NULL; 399 } 400 401 ++mInputBufferCount; 402 403 outHeader->nOffset = 0; 404 outHeader->nFilledLen = (mWidth * mHeight * 3) / 2; 405 outHeader->nFlags = 0; 406 407 List<BufferInfo *>::iterator it = outQueue.begin(); 408 while ((*it)->mHeader != outHeader) { 409 ++it; 410 } 411 412 BufferInfo *outInfo = *it; 413 outInfo->mOwnedByUs = false; 414 outQueue.erase(it); 415 outInfo = NULL; 416 417 notifyFillBufferDone(outHeader); 418 outHeader = NULL; 419 420 ++mNumSamplesOutput; 421 } 422} 423 424bool SoftMPEG4::portSettingsChanged() { 425 int32_t disp_width, disp_height; 426 PVGetVideoDimensions(mHandle, &disp_width, &disp_height); 427 428 int32_t buf_width, buf_height; 429 PVGetBufferDimensions(mHandle, &buf_width, &buf_height); 430 431 CHECK_LE(disp_width, buf_width); 432 CHECK_LE(disp_height, buf_height); 433 434 LOGV("disp_width = %d, disp_height = %d, buf_width = %d, buf_height = %d", 435 disp_width, disp_height, buf_width, buf_height); 436 437 if (mCropRight != disp_width - 1 438 || mCropBottom != disp_height - 1) { 439 mCropLeft = 0; 440 mCropTop = 0; 441 mCropRight = disp_width - 1; 442 mCropBottom = disp_height - 1; 443 444 notify(OMX_EventPortSettingsChanged, 445 1, 446 OMX_IndexConfigCommonOutputCrop, 447 NULL); 448 } 449 450 if (buf_width != mWidth || buf_height != mHeight) { 451 mWidth = buf_width; 452 mHeight = buf_height; 453 454 updatePortDefinitions(); 455 456 if (mMode == MODE_H263) { 457 PVCleanUpVideoDecoder(mHandle); 458 459 uint8_t *vol_data[1]; 460 int32_t vol_size = 0; 461 462 vol_data[0] = NULL; 463 if (!PVInitVideoDecoder( 464 mHandle, vol_data, &vol_size, 1, mWidth, mHeight, 465 H263_MODE)) { 466 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); 467 mSignalledError = true; 468 return true; 469 } 470 } 471 472 mFramesConfigured = false; 473 474 notify(OMX_EventPortSettingsChanged, 1, 0, NULL); 475 mOutputPortSettingsChange = AWAITING_DISABLED; 476 return true; 477 } 478 479 return false; 480} 481 482void SoftMPEG4::onPortFlushCompleted(OMX_U32 portIndex) { 483 if (portIndex == 0 && mInitialized) { 484 CHECK_EQ((int)PVResetVideoDecoder(mHandle), (int)PV_TRUE); 485 } 486} 487 488void SoftMPEG4::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) { 489 if (portIndex != 1) { 490 return; 491 } 492 493 switch (mOutputPortSettingsChange) { 494 case NONE: 495 break; 496 497 case AWAITING_DISABLED: 498 { 499 CHECK(!enabled); 500 mOutputPortSettingsChange = AWAITING_ENABLED; 501 break; 502 } 503 504 default: 505 { 506 CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED); 507 CHECK(enabled); 508 mOutputPortSettingsChange = NONE; 509 break; 510 } 511 } 512} 513 514void SoftMPEG4::updatePortDefinitions() { 515 OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(0)->mDef; 516 def->format.video.nFrameWidth = mWidth; 517 def->format.video.nFrameHeight = mHeight; 518 def->format.video.nStride = def->format.video.nFrameWidth; 519 def->format.video.nSliceHeight = def->format.video.nFrameHeight; 520 521 def = &editPortInfo(1)->mDef; 522 def->format.video.nFrameWidth = mWidth; 523 def->format.video.nFrameHeight = mHeight; 524 def->format.video.nStride = def->format.video.nFrameWidth; 525 def->format.video.nSliceHeight = def->format.video.nFrameHeight; 526 527 def->nBufferSize = 528 (((def->format.video.nFrameWidth + 15) & -16) 529 * ((def->format.video.nFrameHeight + 15) & -16) * 3) / 2; 530} 531 532} // namespace android 533 534android::SoftOMXComponent *createSoftOMXComponent( 535 const char *name, const OMX_CALLBACKTYPE *callbacks, 536 OMX_PTR appData, OMX_COMPONENTTYPE **component) { 537 return new android::SoftMPEG4(name, callbacks, appData, component); 538} 539 540