SoftMPEG4.cpp revision bbba88cb1bdc34705d1477208990a06904c022e7
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 timestamp = 0xFFFFFFFF; 364 int32_t bufferSize = inHeader->nFilledLen; 365 366 uint32_t useExtTimestamp = 0; 367 if (PVDecodeVideoFrame( 368 mHandle, &bitstream, ×tamp, &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 529