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 "SoftAVC" 19 #include <utils/Log.h> 20 21 #include "SoftAVC.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 29 namespace android { 30 31 static const CodecProfileLevel kProfileLevels[] = { 32 { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel1 }, 33 { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel1b }, 34 { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel11 }, 35 { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel12 }, 36 { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel13 }, 37 { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel2 }, 38 { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel21 }, 39 { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel22 }, 40 { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel3 }, 41 { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel31 }, 42 { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel32 }, 43 { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel4 }, 44 { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel41 }, 45 { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel42 }, 46 { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel5 }, 47 { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel51 }, 48 }; 49 50 template<class T> 51 static void InitOMXParams(T *params) { 52 params->nSize = sizeof(T); 53 params->nVersion.s.nVersionMajor = 1; 54 params->nVersion.s.nVersionMinor = 0; 55 params->nVersion.s.nRevision = 0; 56 params->nVersion.s.nStep = 0; 57 } 58 59 SoftAVC::SoftAVC( 60 const char *name, 61 const OMX_CALLBACKTYPE *callbacks, 62 OMX_PTR appData, 63 OMX_COMPONENTTYPE **component) 64 : SimpleSoftOMXComponent(name, callbacks, appData, component), 65 mHandle(NULL), 66 mInputBufferCount(0), 67 mWidth(320), 68 mHeight(240), 69 mPictureSize(mWidth * mHeight * 3 / 2), 70 mCropLeft(0), 71 mCropTop(0), 72 mCropWidth(mWidth), 73 mCropHeight(mHeight), 74 mFirstPicture(NULL), 75 mFirstPictureId(-1), 76 mPicId(0), 77 mHeadersDecoded(false), 78 mEOSStatus(INPUT_DATA_AVAILABLE), 79 mOutputPortSettingsChange(NONE), 80 mSignalledError(false) { 81 initPorts(); 82 CHECK_EQ(initDecoder(), (status_t)OK); 83 } 84 85 SoftAVC::~SoftAVC() { 86 H264SwDecRelease(mHandle); 87 mHandle = NULL; 88 89 while (mPicToHeaderMap.size() != 0) { 90 OMX_BUFFERHEADERTYPE *header = mPicToHeaderMap.editValueAt(0); 91 mPicToHeaderMap.removeItemsAt(0); 92 delete header; 93 header = NULL; 94 } 95 List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex); 96 List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex); 97 CHECK(outQueue.empty()); 98 CHECK(inQueue.empty()); 99 100 delete[] mFirstPicture; 101 } 102 103 void SoftAVC::initPorts() { 104 OMX_PARAM_PORTDEFINITIONTYPE def; 105 InitOMXParams(&def); 106 107 def.nPortIndex = kInputPortIndex; 108 def.eDir = OMX_DirInput; 109 def.nBufferCountMin = kNumInputBuffers; 110 def.nBufferCountActual = def.nBufferCountMin; 111 def.nBufferSize = 8192; 112 def.bEnabled = OMX_TRUE; 113 def.bPopulated = OMX_FALSE; 114 def.eDomain = OMX_PortDomainVideo; 115 def.bBuffersContiguous = OMX_FALSE; 116 def.nBufferAlignment = 1; 117 118 def.format.video.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_VIDEO_AVC); 119 def.format.video.pNativeRender = NULL; 120 def.format.video.nFrameWidth = mWidth; 121 def.format.video.nFrameHeight = mHeight; 122 def.format.video.nStride = def.format.video.nFrameWidth; 123 def.format.video.nSliceHeight = def.format.video.nFrameHeight; 124 def.format.video.nBitrate = 0; 125 def.format.video.xFramerate = 0; 126 def.format.video.bFlagErrorConcealment = OMX_FALSE; 127 def.format.video.eCompressionFormat = OMX_VIDEO_CodingAVC; 128 def.format.video.eColorFormat = OMX_COLOR_FormatUnused; 129 def.format.video.pNativeWindow = NULL; 130 131 addPort(def); 132 133 def.nPortIndex = kOutputPortIndex; 134 def.eDir = OMX_DirOutput; 135 def.nBufferCountMin = kNumOutputBuffers; 136 def.nBufferCountActual = def.nBufferCountMin; 137 def.bEnabled = OMX_TRUE; 138 def.bPopulated = OMX_FALSE; 139 def.eDomain = OMX_PortDomainVideo; 140 def.bBuffersContiguous = OMX_FALSE; 141 def.nBufferAlignment = 2; 142 143 def.format.video.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_VIDEO_RAW); 144 def.format.video.pNativeRender = NULL; 145 def.format.video.nFrameWidth = mWidth; 146 def.format.video.nFrameHeight = mHeight; 147 def.format.video.nStride = def.format.video.nFrameWidth; 148 def.format.video.nSliceHeight = def.format.video.nFrameHeight; 149 def.format.video.nBitrate = 0; 150 def.format.video.xFramerate = 0; 151 def.format.video.bFlagErrorConcealment = OMX_FALSE; 152 def.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused; 153 def.format.video.eColorFormat = OMX_COLOR_FormatYUV420Planar; 154 def.format.video.pNativeWindow = NULL; 155 156 def.nBufferSize = 157 (def.format.video.nFrameWidth * def.format.video.nFrameHeight * 3) / 2; 158 159 addPort(def); 160 } 161 162 status_t SoftAVC::initDecoder() { 163 // Force decoder to output buffers in display order. 164 if (H264SwDecInit(&mHandle, 0) == H264SWDEC_OK) { 165 return OK; 166 } 167 return UNKNOWN_ERROR; 168 } 169 170 OMX_ERRORTYPE SoftAVC::internalGetParameter( 171 OMX_INDEXTYPE index, OMX_PTR params) { 172 switch (index) { 173 case OMX_IndexParamVideoPortFormat: 174 { 175 OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams = 176 (OMX_VIDEO_PARAM_PORTFORMATTYPE *)params; 177 178 if (formatParams->nPortIndex > kOutputPortIndex) { 179 return OMX_ErrorUndefined; 180 } 181 182 if (formatParams->nIndex != 0) { 183 return OMX_ErrorNoMore; 184 } 185 186 if (formatParams->nPortIndex == kInputPortIndex) { 187 formatParams->eCompressionFormat = OMX_VIDEO_CodingAVC; 188 formatParams->eColorFormat = OMX_COLOR_FormatUnused; 189 formatParams->xFramerate = 0; 190 } else { 191 CHECK(formatParams->nPortIndex == kOutputPortIndex); 192 193 formatParams->eCompressionFormat = OMX_VIDEO_CodingUnused; 194 formatParams->eColorFormat = OMX_COLOR_FormatYUV420Planar; 195 formatParams->xFramerate = 0; 196 } 197 198 return OMX_ErrorNone; 199 } 200 201 case OMX_IndexParamVideoProfileLevelQuerySupported: 202 { 203 OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileLevel = 204 (OMX_VIDEO_PARAM_PROFILELEVELTYPE *) params; 205 206 if (profileLevel->nPortIndex != kInputPortIndex) { 207 ALOGE("Invalid port index: %ld", profileLevel->nPortIndex); 208 return OMX_ErrorUnsupportedIndex; 209 } 210 211 size_t index = profileLevel->nProfileIndex; 212 size_t nProfileLevels = 213 sizeof(kProfileLevels) / sizeof(kProfileLevels[0]); 214 if (index >= nProfileLevels) { 215 return OMX_ErrorNoMore; 216 } 217 218 profileLevel->eProfile = kProfileLevels[index].mProfile; 219 profileLevel->eLevel = kProfileLevels[index].mLevel; 220 return OMX_ErrorNone; 221 } 222 223 default: 224 return SimpleSoftOMXComponent::internalGetParameter(index, params); 225 } 226 } 227 228 OMX_ERRORTYPE SoftAVC::internalSetParameter( 229 OMX_INDEXTYPE index, const OMX_PTR params) { 230 switch (index) { 231 case OMX_IndexParamStandardComponentRole: 232 { 233 const OMX_PARAM_COMPONENTROLETYPE *roleParams = 234 (const OMX_PARAM_COMPONENTROLETYPE *)params; 235 236 if (strncmp((const char *)roleParams->cRole, 237 "video_decoder.avc", 238 OMX_MAX_STRINGNAME_SIZE - 1)) { 239 return OMX_ErrorUndefined; 240 } 241 242 return OMX_ErrorNone; 243 } 244 245 case OMX_IndexParamVideoPortFormat: 246 { 247 OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams = 248 (OMX_VIDEO_PARAM_PORTFORMATTYPE *)params; 249 250 if (formatParams->nPortIndex > kOutputPortIndex) { 251 return OMX_ErrorUndefined; 252 } 253 254 if (formatParams->nIndex != 0) { 255 return OMX_ErrorNoMore; 256 } 257 258 return OMX_ErrorNone; 259 } 260 261 default: 262 return SimpleSoftOMXComponent::internalSetParameter(index, params); 263 } 264 } 265 266 OMX_ERRORTYPE SoftAVC::getConfig( 267 OMX_INDEXTYPE index, OMX_PTR params) { 268 switch (index) { 269 case OMX_IndexConfigCommonOutputCrop: 270 { 271 OMX_CONFIG_RECTTYPE *rectParams = (OMX_CONFIG_RECTTYPE *)params; 272 273 if (rectParams->nPortIndex != 1) { 274 return OMX_ErrorUndefined; 275 } 276 277 rectParams->nLeft = mCropLeft; 278 rectParams->nTop = mCropTop; 279 rectParams->nWidth = mCropWidth; 280 rectParams->nHeight = mCropHeight; 281 282 return OMX_ErrorNone; 283 } 284 285 default: 286 return OMX_ErrorUnsupportedIndex; 287 } 288 } 289 290 void SoftAVC::onQueueFilled(OMX_U32 portIndex) { 291 if (mSignalledError || mOutputPortSettingsChange != NONE) { 292 return; 293 } 294 295 if (mEOSStatus == OUTPUT_FRAMES_FLUSHED) { 296 return; 297 } 298 299 List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex); 300 List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex); 301 H264SwDecRet ret = H264SWDEC_PIC_RDY; 302 bool portSettingsChanged = false; 303 while ((mEOSStatus != INPUT_DATA_AVAILABLE || !inQueue.empty()) 304 && outQueue.size() == kNumOutputBuffers) { 305 306 if (mEOSStatus == INPUT_EOS_SEEN) { 307 drainAllOutputBuffers(); 308 return; 309 } 310 311 BufferInfo *inInfo = *inQueue.begin(); 312 OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; 313 ++mPicId; 314 315 OMX_BUFFERHEADERTYPE *header = new OMX_BUFFERHEADERTYPE; 316 memset(header, 0, sizeof(OMX_BUFFERHEADERTYPE)); 317 header->nTimeStamp = inHeader->nTimeStamp; 318 header->nFlags = inHeader->nFlags; 319 if (header->nFlags & OMX_BUFFERFLAG_EOS) { 320 mEOSStatus = INPUT_EOS_SEEN; 321 } 322 mPicToHeaderMap.add(mPicId, header); 323 inQueue.erase(inQueue.begin()); 324 325 H264SwDecInput inPicture; 326 H264SwDecOutput outPicture; 327 memset(&inPicture, 0, sizeof(inPicture)); 328 inPicture.dataLen = inHeader->nFilledLen; 329 inPicture.pStream = inHeader->pBuffer + inHeader->nOffset; 330 inPicture.picId = mPicId; 331 inPicture.intraConcealmentMethod = 1; 332 H264SwDecPicture decodedPicture; 333 334 while (inPicture.dataLen > 0) { 335 ret = H264SwDecDecode(mHandle, &inPicture, &outPicture); 336 if (ret == H264SWDEC_HDRS_RDY_BUFF_NOT_EMPTY || 337 ret == H264SWDEC_PIC_RDY_BUFF_NOT_EMPTY) { 338 inPicture.dataLen -= (u32)(outPicture.pStrmCurrPos - inPicture.pStream); 339 inPicture.pStream = outPicture.pStrmCurrPos; 340 if (ret == H264SWDEC_HDRS_RDY_BUFF_NOT_EMPTY) { 341 mHeadersDecoded = true; 342 H264SwDecInfo decoderInfo; 343 CHECK(H264SwDecGetInfo(mHandle, &decoderInfo) == H264SWDEC_OK); 344 345 if (handlePortSettingChangeEvent(&decoderInfo)) { 346 portSettingsChanged = true; 347 } 348 349 if (decoderInfo.croppingFlag && 350 handleCropRectEvent(&decoderInfo.cropParams)) { 351 portSettingsChanged = true; 352 } 353 } 354 } else { 355 if (portSettingsChanged) { 356 if (H264SwDecNextPicture(mHandle, &decodedPicture, 0) 357 == H264SWDEC_PIC_RDY) { 358 359 // Save this output buffer; otherwise, it will be 360 // lost during dynamic port reconfiguration because 361 // OpenMAX client will delete _all_ output buffers 362 // in the process. 363 saveFirstOutputBuffer( 364 decodedPicture.picId, 365 (uint8_t *)decodedPicture.pOutputPicture); 366 } 367 } 368 inPicture.dataLen = 0; 369 if (ret < 0) { 370 ALOGE("Decoder failed: %d", ret); 371 372 notify(OMX_EventError, OMX_ErrorUndefined, 373 ERROR_MALFORMED, NULL); 374 375 mSignalledError = true; 376 return; 377 } 378 } 379 } 380 inInfo->mOwnedByUs = false; 381 notifyEmptyBufferDone(inHeader); 382 383 if (portSettingsChanged) { 384 portSettingsChanged = false; 385 return; 386 } 387 388 if (mFirstPicture && !outQueue.empty()) { 389 drainOneOutputBuffer(mFirstPictureId, mFirstPicture); 390 delete[] mFirstPicture; 391 mFirstPicture = NULL; 392 mFirstPictureId = -1; 393 } 394 395 while (!outQueue.empty() && 396 mHeadersDecoded && 397 H264SwDecNextPicture(mHandle, &decodedPicture, 0) 398 == H264SWDEC_PIC_RDY) { 399 400 int32_t picId = decodedPicture.picId; 401 uint8_t *data = (uint8_t *) decodedPicture.pOutputPicture; 402 drainOneOutputBuffer(picId, data); 403 } 404 } 405 } 406 407 bool SoftAVC::handlePortSettingChangeEvent(const H264SwDecInfo *info) { 408 if (mWidth != info->picWidth || mHeight != info->picHeight) { 409 mWidth = info->picWidth; 410 mHeight = info->picHeight; 411 mPictureSize = mWidth * mHeight * 3 / 2; 412 mCropWidth = mWidth; 413 mCropHeight = mHeight; 414 updatePortDefinitions(); 415 notify(OMX_EventPortSettingsChanged, 1, 0, NULL); 416 mOutputPortSettingsChange = AWAITING_DISABLED; 417 return true; 418 } 419 420 return false; 421 } 422 423 bool SoftAVC::handleCropRectEvent(const CropParams *crop) { 424 if (mCropLeft != crop->cropLeftOffset || 425 mCropTop != crop->cropTopOffset || 426 mCropWidth != crop->cropOutWidth || 427 mCropHeight != crop->cropOutHeight) { 428 mCropLeft = crop->cropLeftOffset; 429 mCropTop = crop->cropTopOffset; 430 mCropWidth = crop->cropOutWidth; 431 mCropHeight = crop->cropOutHeight; 432 433 notify(OMX_EventPortSettingsChanged, 1, 434 OMX_IndexConfigCommonOutputCrop, NULL); 435 436 return true; 437 } 438 return false; 439 } 440 441 void SoftAVC::saveFirstOutputBuffer(int32_t picId, uint8_t *data) { 442 CHECK(mFirstPicture == NULL); 443 mFirstPictureId = picId; 444 445 mFirstPicture = new uint8_t[mPictureSize]; 446 memcpy(mFirstPicture, data, mPictureSize); 447 } 448 449 void SoftAVC::drainOneOutputBuffer(int32_t picId, uint8_t* data) { 450 List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex); 451 BufferInfo *outInfo = *outQueue.begin(); 452 outQueue.erase(outQueue.begin()); 453 OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; 454 OMX_BUFFERHEADERTYPE *header = mPicToHeaderMap.valueFor(picId); 455 outHeader->nTimeStamp = header->nTimeStamp; 456 outHeader->nFlags = header->nFlags; 457 outHeader->nFilledLen = mPictureSize; 458 memcpy(outHeader->pBuffer + outHeader->nOffset, 459 data, mPictureSize); 460 mPicToHeaderMap.removeItem(picId); 461 delete header; 462 outInfo->mOwnedByUs = false; 463 notifyFillBufferDone(outHeader); 464 } 465 466 bool SoftAVC::drainAllOutputBuffers() { 467 List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex); 468 H264SwDecPicture decodedPicture; 469 470 while (!outQueue.empty()) { 471 BufferInfo *outInfo = *outQueue.begin(); 472 outQueue.erase(outQueue.begin()); 473 OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; 474 if (mHeadersDecoded && 475 H264SWDEC_PIC_RDY == 476 H264SwDecNextPicture(mHandle, &decodedPicture, 1 /* flush */)) { 477 478 int32_t picId = decodedPicture.picId; 479 CHECK(mPicToHeaderMap.indexOfKey(picId) >= 0); 480 481 memcpy(outHeader->pBuffer + outHeader->nOffset, 482 decodedPicture.pOutputPicture, 483 mPictureSize); 484 485 OMX_BUFFERHEADERTYPE *header = mPicToHeaderMap.valueFor(picId); 486 outHeader->nTimeStamp = header->nTimeStamp; 487 outHeader->nFlags = header->nFlags; 488 outHeader->nFilledLen = mPictureSize; 489 mPicToHeaderMap.removeItem(picId); 490 delete header; 491 } else { 492 outHeader->nTimeStamp = 0; 493 outHeader->nFilledLen = 0; 494 outHeader->nFlags = OMX_BUFFERFLAG_EOS; 495 mEOSStatus = OUTPUT_FRAMES_FLUSHED; 496 } 497 498 outInfo->mOwnedByUs = false; 499 notifyFillBufferDone(outHeader); 500 } 501 502 return true; 503 } 504 505 void SoftAVC::onPortFlushCompleted(OMX_U32 portIndex) { 506 if (portIndex == kInputPortIndex) { 507 mEOSStatus = INPUT_DATA_AVAILABLE; 508 } 509 } 510 511 void SoftAVC::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) { 512 switch (mOutputPortSettingsChange) { 513 case NONE: 514 break; 515 516 case AWAITING_DISABLED: 517 { 518 CHECK(!enabled); 519 mOutputPortSettingsChange = AWAITING_ENABLED; 520 break; 521 } 522 523 default: 524 { 525 CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED); 526 CHECK(enabled); 527 mOutputPortSettingsChange = NONE; 528 break; 529 } 530 } 531 } 532 533 void SoftAVC::updatePortDefinitions() { 534 OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(0)->mDef; 535 def->format.video.nFrameWidth = mWidth; 536 def->format.video.nFrameHeight = mHeight; 537 def->format.video.nStride = def->format.video.nFrameWidth; 538 def->format.video.nSliceHeight = def->format.video.nFrameHeight; 539 540 def = &editPortInfo(1)->mDef; 541 def->format.video.nFrameWidth = mWidth; 542 def->format.video.nFrameHeight = mHeight; 543 def->format.video.nStride = def->format.video.nFrameWidth; 544 def->format.video.nSliceHeight = def->format.video.nFrameHeight; 545 546 def->nBufferSize = 547 (def->format.video.nFrameWidth 548 * def->format.video.nFrameHeight * 3) / 2; 549 } 550 551 } // namespace android 552 553 android::SoftOMXComponent *createSoftOMXComponent( 554 const char *name, const OMX_CALLBACKTYPE *callbacks, 555 OMX_PTR appData, OMX_COMPONENTTYPE **component) { 556 return new android::SoftAVC(name, callbacks, appData, component); 557 } 558