SoftAVC.cpp revision 9a8ded7348c5b2302dd27b285b395416bc842c49
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 29namespace android { 30 31static 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 50template<class T> 51static 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 59SoftAVC::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 85SoftAVC::~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 103void 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 162status_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 170OMX_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 228OMX_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 266OMX_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 290void 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 if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { 315 inQueue.erase(inQueue.begin()); 316 inInfo->mOwnedByUs = false; 317 notifyEmptyBufferDone(inHeader); 318 mEOSStatus = INPUT_EOS_SEEN; 319 continue; 320 } 321 322 OMX_BUFFERHEADERTYPE *header = new OMX_BUFFERHEADERTYPE; 323 memset(header, 0, sizeof(OMX_BUFFERHEADERTYPE)); 324 header->nTimeStamp = inHeader->nTimeStamp; 325 header->nFlags = inHeader->nFlags; 326 mPicToHeaderMap.add(mPicId, header); 327 inQueue.erase(inQueue.begin()); 328 329 H264SwDecInput inPicture; 330 H264SwDecOutput outPicture; 331 memset(&inPicture, 0, sizeof(inPicture)); 332 inPicture.dataLen = inHeader->nFilledLen; 333 inPicture.pStream = inHeader->pBuffer + inHeader->nOffset; 334 inPicture.picId = mPicId; 335 inPicture.intraConcealmentMethod = 1; 336 H264SwDecPicture decodedPicture; 337 338 while (inPicture.dataLen > 0) { 339 ret = H264SwDecDecode(mHandle, &inPicture, &outPicture); 340 if (ret == H264SWDEC_HDRS_RDY_BUFF_NOT_EMPTY || 341 ret == H264SWDEC_PIC_RDY_BUFF_NOT_EMPTY) { 342 inPicture.dataLen -= (u32)(outPicture.pStrmCurrPos - inPicture.pStream); 343 inPicture.pStream = outPicture.pStrmCurrPos; 344 if (ret == H264SWDEC_HDRS_RDY_BUFF_NOT_EMPTY) { 345 mHeadersDecoded = true; 346 H264SwDecInfo decoderInfo; 347 CHECK(H264SwDecGetInfo(mHandle, &decoderInfo) == H264SWDEC_OK); 348 349 if (handlePortSettingChangeEvent(&decoderInfo)) { 350 portSettingsChanged = true; 351 } 352 353 if (decoderInfo.croppingFlag && 354 handleCropRectEvent(&decoderInfo.cropParams)) { 355 portSettingsChanged = true; 356 } 357 } 358 } else { 359 if (portSettingsChanged) { 360 if (H264SwDecNextPicture(mHandle, &decodedPicture, 0) 361 == H264SWDEC_PIC_RDY) { 362 363 // Save this output buffer; otherwise, it will be 364 // lost during dynamic port reconfiguration because 365 // OpenMAX client will delete _all_ output buffers 366 // in the process. 367 saveFirstOutputBuffer( 368 decodedPicture.picId, 369 (uint8_t *)decodedPicture.pOutputPicture); 370 } 371 } 372 inPicture.dataLen = 0; 373 if (ret < 0) { 374 ALOGE("Decoder failed: %d", ret); 375 376 notify(OMX_EventError, OMX_ErrorUndefined, 377 ERROR_MALFORMED, NULL); 378 379 mSignalledError = true; 380 return; 381 } 382 } 383 } 384 inInfo->mOwnedByUs = false; 385 notifyEmptyBufferDone(inHeader); 386 387 if (portSettingsChanged) { 388 portSettingsChanged = false; 389 return; 390 } 391 392 if (mFirstPicture && !outQueue.empty()) { 393 drainOneOutputBuffer(mFirstPictureId, mFirstPicture); 394 delete[] mFirstPicture; 395 mFirstPicture = NULL; 396 mFirstPictureId = -1; 397 } 398 399 while (!outQueue.empty() && 400 mHeadersDecoded && 401 H264SwDecNextPicture(mHandle, &decodedPicture, 0) 402 == H264SWDEC_PIC_RDY) { 403 404 int32_t picId = decodedPicture.picId; 405 uint8_t *data = (uint8_t *) decodedPicture.pOutputPicture; 406 drainOneOutputBuffer(picId, data); 407 } 408 } 409} 410 411bool SoftAVC::handlePortSettingChangeEvent(const H264SwDecInfo *info) { 412 if (mWidth != info->picWidth || mHeight != info->picHeight) { 413 mWidth = info->picWidth; 414 mHeight = info->picHeight; 415 mPictureSize = mWidth * mHeight * 3 / 2; 416 mCropWidth = mWidth; 417 mCropHeight = mHeight; 418 updatePortDefinitions(); 419 notify(OMX_EventPortSettingsChanged, 1, 0, NULL); 420 mOutputPortSettingsChange = AWAITING_DISABLED; 421 return true; 422 } 423 424 return false; 425} 426 427bool SoftAVC::handleCropRectEvent(const CropParams *crop) { 428 if (mCropLeft != crop->cropLeftOffset || 429 mCropTop != crop->cropTopOffset || 430 mCropWidth != crop->cropOutWidth || 431 mCropHeight != crop->cropOutHeight) { 432 mCropLeft = crop->cropLeftOffset; 433 mCropTop = crop->cropTopOffset; 434 mCropWidth = crop->cropOutWidth; 435 mCropHeight = crop->cropOutHeight; 436 437 notify(OMX_EventPortSettingsChanged, 1, 438 OMX_IndexConfigCommonOutputCrop, NULL); 439 440 return true; 441 } 442 return false; 443} 444 445void SoftAVC::saveFirstOutputBuffer(int32_t picId, uint8_t *data) { 446 CHECK(mFirstPicture == NULL); 447 mFirstPictureId = picId; 448 449 mFirstPicture = new uint8_t[mPictureSize]; 450 memcpy(mFirstPicture, data, mPictureSize); 451} 452 453void SoftAVC::drainOneOutputBuffer(int32_t picId, uint8_t* data) { 454 List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex); 455 BufferInfo *outInfo = *outQueue.begin(); 456 outQueue.erase(outQueue.begin()); 457 OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; 458 OMX_BUFFERHEADERTYPE *header = mPicToHeaderMap.valueFor(picId); 459 outHeader->nTimeStamp = header->nTimeStamp; 460 outHeader->nFlags = header->nFlags; 461 outHeader->nFilledLen = mPictureSize; 462 memcpy(outHeader->pBuffer + outHeader->nOffset, 463 data, mPictureSize); 464 mPicToHeaderMap.removeItem(picId); 465 delete header; 466 outInfo->mOwnedByUs = false; 467 notifyFillBufferDone(outHeader); 468} 469 470bool SoftAVC::drainAllOutputBuffers() { 471 List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex); 472 H264SwDecPicture decodedPicture; 473 474 while (!outQueue.empty()) { 475 BufferInfo *outInfo = *outQueue.begin(); 476 outQueue.erase(outQueue.begin()); 477 OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; 478 if (mHeadersDecoded && 479 H264SWDEC_PIC_RDY == 480 H264SwDecNextPicture(mHandle, &decodedPicture, 1 /* flush */)) { 481 482 int32_t picId = decodedPicture.picId; 483 CHECK(mPicToHeaderMap.indexOfKey(picId) >= 0); 484 485 memcpy(outHeader->pBuffer + outHeader->nOffset, 486 decodedPicture.pOutputPicture, 487 mPictureSize); 488 489 OMX_BUFFERHEADERTYPE *header = mPicToHeaderMap.valueFor(picId); 490 outHeader->nTimeStamp = header->nTimeStamp; 491 outHeader->nFlags = header->nFlags; 492 outHeader->nFilledLen = mPictureSize; 493 mPicToHeaderMap.removeItem(picId); 494 delete header; 495 } else { 496 outHeader->nTimeStamp = 0; 497 outHeader->nFilledLen = 0; 498 outHeader->nFlags = OMX_BUFFERFLAG_EOS; 499 mEOSStatus = OUTPUT_FRAMES_FLUSHED; 500 } 501 502 outInfo->mOwnedByUs = false; 503 notifyFillBufferDone(outHeader); 504 } 505 506 return true; 507} 508 509void SoftAVC::onPortFlushCompleted(OMX_U32 portIndex) { 510 if (portIndex == kInputPortIndex) { 511 mEOSStatus = INPUT_DATA_AVAILABLE; 512 } 513} 514 515void SoftAVC::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) { 516 switch (mOutputPortSettingsChange) { 517 case NONE: 518 break; 519 520 case AWAITING_DISABLED: 521 { 522 CHECK(!enabled); 523 mOutputPortSettingsChange = AWAITING_ENABLED; 524 break; 525 } 526 527 default: 528 { 529 CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED); 530 CHECK(enabled); 531 mOutputPortSettingsChange = NONE; 532 break; 533 } 534 } 535} 536 537void SoftAVC::updatePortDefinitions() { 538 OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(0)->mDef; 539 def->format.video.nFrameWidth = mWidth; 540 def->format.video.nFrameHeight = mHeight; 541 def->format.video.nStride = def->format.video.nFrameWidth; 542 def->format.video.nSliceHeight = def->format.video.nFrameHeight; 543 544 def = &editPortInfo(1)->mDef; 545 def->format.video.nFrameWidth = mWidth; 546 def->format.video.nFrameHeight = mHeight; 547 def->format.video.nStride = def->format.video.nFrameWidth; 548 def->format.video.nSliceHeight = def->format.video.nFrameHeight; 549 550 def->nBufferSize = 551 (def->format.video.nFrameWidth 552 * def->format.video.nFrameHeight * 3) / 2; 553} 554 555} // namespace android 556 557android::SoftOMXComponent *createSoftOMXComponent( 558 const char *name, const OMX_CALLBACKTYPE *callbacks, 559 OMX_PTR appData, OMX_COMPONENTTYPE **component) { 560 return new android::SoftAVC(name, callbacks, appData, component); 561} 562