1 /* 2 * Copyright (C) 2014 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 "SoftHEVC" 19 #include <utils/Log.h> 20 21 #include "ihevc_typedefs.h" 22 #include "iv.h" 23 #include "ivd.h" 24 #include "ihevcd_cxa.h" 25 #include "SoftHEVC.h" 26 27 #include <media/stagefright/foundation/ADebug.h> 28 #include <media/stagefright/foundation/AUtils.h> 29 #include <media/stagefright/MediaDefs.h> 30 #include <OMX_VideoExt.h> 31 32 namespace android { 33 34 #define componentName "video_decoder.hevc" 35 #define codingType OMX_VIDEO_CodingHEVC 36 #define CODEC_MIME_TYPE MEDIA_MIMETYPE_VIDEO_HEVC 37 38 /** Function and structure definitions to keep code similar for each codec */ 39 #define ivdec_api_function ihevcd_cxa_api_function 40 #define ivdext_create_ip_t ihevcd_cxa_create_ip_t 41 #define ivdext_create_op_t ihevcd_cxa_create_op_t 42 #define ivdext_delete_ip_t ihevcd_cxa_delete_ip_t 43 #define ivdext_delete_op_t ihevcd_cxa_delete_op_t 44 #define ivdext_ctl_set_num_cores_ip_t ihevcd_cxa_ctl_set_num_cores_ip_t 45 #define ivdext_ctl_set_num_cores_op_t ihevcd_cxa_ctl_set_num_cores_op_t 46 47 #define IVDEXT_CMD_CTL_SET_NUM_CORES \ 48 (IVD_CONTROL_API_COMMAND_TYPE_T)IHEVCD_CXA_CMD_CTL_SET_NUM_CORES 49 50 static const CodecProfileLevel kProfileLevels[] = { 51 { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel51 }, 52 }; 53 54 SoftHEVC::SoftHEVC( 55 const char *name, 56 const OMX_CALLBACKTYPE *callbacks, 57 OMX_PTR appData, 58 OMX_COMPONENTTYPE **component) 59 : SoftVideoDecoderOMXComponent(name, componentName, codingType, 60 kProfileLevels, ARRAY_SIZE(kProfileLevels), 61 320 /* width */, 240 /* height */, callbacks, 62 appData, component), 63 mCodecCtx(NULL), 64 mFlushOutBuffer(NULL), 65 mOmxColorFormat(OMX_COLOR_FormatYUV420Planar), 66 mIvColorFormat(IV_YUV_420P), 67 mChangingResolution(false), 68 mSignalledError(false), 69 mStride(mWidth) { 70 const size_t kMinCompressionRatio = 4 /* compressionRatio (for Level 4+) */; 71 const size_t kMaxOutputBufferSize = 2048 * 2048 * 3 / 2; 72 // INPUT_BUF_SIZE is given by HEVC codec as minimum input size 73 initPorts( 74 kNumBuffers, max(kMaxOutputBufferSize / kMinCompressionRatio, (size_t)INPUT_BUF_SIZE), 75 kNumBuffers, CODEC_MIME_TYPE, kMinCompressionRatio); 76 } 77 78 status_t SoftHEVC::init() { 79 return initDecoder(); 80 } 81 82 SoftHEVC::~SoftHEVC() { 83 ALOGV("In SoftHEVC::~SoftHEVC"); 84 CHECK_EQ(deInitDecoder(), (status_t)OK); 85 } 86 87 static void *ivd_aligned_malloc(void *ctxt, WORD32 alignment, WORD32 size) { 88 UNUSED(ctxt); 89 return memalign(alignment, size); 90 } 91 92 static void ivd_aligned_free(void *ctxt, void *buf) { 93 UNUSED(ctxt); 94 free(buf); 95 return; 96 } 97 98 static size_t GetCPUCoreCount() { 99 long cpuCoreCount = 1; 100 #if defined(_SC_NPROCESSORS_ONLN) 101 cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN); 102 #else 103 // _SC_NPROC_ONLN must be defined... 104 cpuCoreCount = sysconf(_SC_NPROC_ONLN); 105 #endif 106 CHECK(cpuCoreCount >= 1); 107 ALOGV("Number of CPU cores: %ld", cpuCoreCount); 108 return (size_t)cpuCoreCount; 109 } 110 111 void SoftHEVC::logVersion() { 112 ivd_ctl_getversioninfo_ip_t s_ctl_ip; 113 ivd_ctl_getversioninfo_op_t s_ctl_op; 114 UWORD8 au1_buf[512]; 115 IV_API_CALL_STATUS_T status; 116 117 s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL; 118 s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_GETVERSION; 119 s_ctl_ip.u4_size = sizeof(ivd_ctl_getversioninfo_ip_t); 120 s_ctl_op.u4_size = sizeof(ivd_ctl_getversioninfo_op_t); 121 s_ctl_ip.pv_version_buffer = au1_buf; 122 s_ctl_ip.u4_version_buffer_size = sizeof(au1_buf); 123 124 status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip, 125 (void *)&s_ctl_op); 126 127 if (status != IV_SUCCESS) { 128 ALOGE("Error in getting version number: 0x%x", 129 s_ctl_op.u4_error_code); 130 } else { 131 ALOGV("Ittiam decoder version number: %s", 132 (char *)s_ctl_ip.pv_version_buffer); 133 } 134 return; 135 } 136 137 status_t SoftHEVC::setParams(size_t stride) { 138 ivd_ctl_set_config_ip_t s_ctl_ip; 139 ivd_ctl_set_config_op_t s_ctl_op; 140 IV_API_CALL_STATUS_T status; 141 s_ctl_ip.u4_disp_wd = (UWORD32)stride; 142 s_ctl_ip.e_frm_skip_mode = IVD_SKIP_NONE; 143 144 s_ctl_ip.e_frm_out_mode = IVD_DISPLAY_FRAME_OUT; 145 s_ctl_ip.e_vid_dec_mode = IVD_DECODE_FRAME; 146 s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL; 147 s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_SETPARAMS; 148 s_ctl_ip.u4_size = sizeof(ivd_ctl_set_config_ip_t); 149 s_ctl_op.u4_size = sizeof(ivd_ctl_set_config_op_t); 150 151 ALOGV("Set the run-time (dynamic) parameters stride = %zu", stride); 152 status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip, 153 (void *)&s_ctl_op); 154 155 if (status != IV_SUCCESS) { 156 ALOGE("Error in setting the run-time parameters: 0x%x", 157 s_ctl_op.u4_error_code); 158 159 return UNKNOWN_ERROR; 160 } 161 return OK; 162 } 163 164 status_t SoftHEVC::resetPlugin() { 165 mIsInFlush = false; 166 mReceivedEOS = false; 167 memset(mTimeStamps, 0, sizeof(mTimeStamps)); 168 memset(mTimeStampsValid, 0, sizeof(mTimeStampsValid)); 169 170 /* Initialize both start and end times */ 171 gettimeofday(&mTimeStart, NULL); 172 gettimeofday(&mTimeEnd, NULL); 173 174 return OK; 175 } 176 177 bool SoftHEVC::getVUIParams() { 178 IV_API_CALL_STATUS_T status; 179 ihevcd_cxa_ctl_get_vui_params_ip_t s_ctl_get_vui_params_ip; 180 ihevcd_cxa_ctl_get_vui_params_op_t s_ctl_get_vui_params_op; 181 182 s_ctl_get_vui_params_ip.e_cmd = IVD_CMD_VIDEO_CTL; 183 s_ctl_get_vui_params_ip.e_sub_cmd = 184 (IVD_CONTROL_API_COMMAND_TYPE_T)IHEVCD_CXA_CMD_CTL_GET_VUI_PARAMS; 185 186 s_ctl_get_vui_params_ip.u4_size = 187 sizeof(ihevcd_cxa_ctl_get_vui_params_ip_t); 188 189 s_ctl_get_vui_params_op.u4_size = sizeof(ihevcd_cxa_ctl_get_vui_params_op_t); 190 191 status = ivdec_api_function( 192 (iv_obj_t *)mCodecCtx, (void *)&s_ctl_get_vui_params_ip, 193 (void *)&s_ctl_get_vui_params_op); 194 195 if (status != IV_SUCCESS) { 196 ALOGW("Error in getting VUI params: 0x%x", 197 s_ctl_get_vui_params_op.u4_error_code); 198 return false; 199 } 200 201 int32_t primaries = s_ctl_get_vui_params_op.u1_colour_primaries; 202 int32_t transfer = s_ctl_get_vui_params_op.u1_transfer_characteristics; 203 int32_t coeffs = s_ctl_get_vui_params_op.u1_matrix_coefficients; 204 bool fullRange = s_ctl_get_vui_params_op.u1_video_full_range_flag; 205 206 ColorAspects colorAspects; 207 ColorUtils::convertIsoColorAspectsToCodecAspects( 208 primaries, transfer, coeffs, fullRange, colorAspects); 209 210 // Update color aspects if necessary. 211 if (colorAspectsDiffer(colorAspects, mBitstreamColorAspects)) { 212 mBitstreamColorAspects = colorAspects; 213 status_t err = handleColorAspectsChange(); 214 CHECK(err == OK); 215 } 216 return true; 217 } 218 219 status_t SoftHEVC::resetDecoder() { 220 ivd_ctl_reset_ip_t s_ctl_ip; 221 ivd_ctl_reset_op_t s_ctl_op; 222 IV_API_CALL_STATUS_T status; 223 224 s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL; 225 s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_RESET; 226 s_ctl_ip.u4_size = sizeof(ivd_ctl_reset_ip_t); 227 s_ctl_op.u4_size = sizeof(ivd_ctl_reset_op_t); 228 229 status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip, 230 (void *)&s_ctl_op); 231 if (IV_SUCCESS != status) { 232 ALOGE("Error in reset: 0x%x", s_ctl_op.u4_error_code); 233 return UNKNOWN_ERROR; 234 } 235 mSignalledError = false; 236 237 /* Set number of cores/threads to be used by the codec */ 238 setNumCores(); 239 240 mStride = 0; 241 return OK; 242 } 243 244 status_t SoftHEVC::setNumCores() { 245 ivdext_ctl_set_num_cores_ip_t s_set_cores_ip; 246 ivdext_ctl_set_num_cores_op_t s_set_cores_op; 247 IV_API_CALL_STATUS_T status; 248 s_set_cores_ip.e_cmd = IVD_CMD_VIDEO_CTL; 249 s_set_cores_ip.e_sub_cmd = IVDEXT_CMD_CTL_SET_NUM_CORES; 250 s_set_cores_ip.u4_num_cores = MIN(mNumCores, CODEC_MAX_NUM_CORES); 251 s_set_cores_ip.u4_size = sizeof(ivdext_ctl_set_num_cores_ip_t); 252 s_set_cores_op.u4_size = sizeof(ivdext_ctl_set_num_cores_op_t); 253 ALOGV("Set number of cores to %u", s_set_cores_ip.u4_num_cores); 254 status = ivdec_api_function(mCodecCtx, (void *)&s_set_cores_ip, 255 (void *)&s_set_cores_op); 256 if (IV_SUCCESS != status) { 257 ALOGE("Error in setting number of cores: 0x%x", 258 s_set_cores_op.u4_error_code); 259 return UNKNOWN_ERROR; 260 } 261 return OK; 262 } 263 264 status_t SoftHEVC::setFlushMode() { 265 IV_API_CALL_STATUS_T status; 266 ivd_ctl_flush_ip_t s_video_flush_ip; 267 ivd_ctl_flush_op_t s_video_flush_op; 268 269 s_video_flush_ip.e_cmd = IVD_CMD_VIDEO_CTL; 270 s_video_flush_ip.e_sub_cmd = IVD_CMD_CTL_FLUSH; 271 s_video_flush_ip.u4_size = sizeof(ivd_ctl_flush_ip_t); 272 s_video_flush_op.u4_size = sizeof(ivd_ctl_flush_op_t); 273 ALOGV("Set the decoder in flush mode "); 274 275 /* Set the decoder in Flush mode, subsequent decode() calls will flush */ 276 status = ivdec_api_function(mCodecCtx, (void *)&s_video_flush_ip, 277 (void *)&s_video_flush_op); 278 279 if (status != IV_SUCCESS) { 280 ALOGE("Error in setting the decoder in flush mode: (%d) 0x%x", status, 281 s_video_flush_op.u4_error_code); 282 return UNKNOWN_ERROR; 283 } 284 285 mIsInFlush = true; 286 return OK; 287 } 288 289 status_t SoftHEVC::initDecoder() { 290 IV_API_CALL_STATUS_T status; 291 292 mNumCores = GetCPUCoreCount(); 293 mCodecCtx = NULL; 294 295 mStride = outputBufferWidth(); 296 297 /* Initialize the decoder */ 298 { 299 ivdext_create_ip_t s_create_ip; 300 ivdext_create_op_t s_create_op; 301 302 void *dec_fxns = (void *)ivdec_api_function; 303 304 s_create_ip.s_ivd_create_ip_t.u4_size = sizeof(ivdext_create_ip_t); 305 s_create_ip.s_ivd_create_ip_t.e_cmd = IVD_CMD_CREATE; 306 s_create_ip.s_ivd_create_ip_t.u4_share_disp_buf = 0; 307 s_create_op.s_ivd_create_op_t.u4_size = sizeof(ivdext_create_op_t); 308 s_create_ip.s_ivd_create_ip_t.e_output_format = mIvColorFormat; 309 s_create_ip.s_ivd_create_ip_t.pf_aligned_alloc = ivd_aligned_malloc; 310 s_create_ip.s_ivd_create_ip_t.pf_aligned_free = ivd_aligned_free; 311 s_create_ip.s_ivd_create_ip_t.pv_mem_ctxt = NULL; 312 313 status = ivdec_api_function(mCodecCtx, (void *)&s_create_ip, (void *)&s_create_op); 314 315 mCodecCtx = (iv_obj_t*)s_create_op.s_ivd_create_op_t.pv_handle; 316 mCodecCtx->pv_fxns = dec_fxns; 317 mCodecCtx->u4_size = sizeof(iv_obj_t); 318 319 if (status != IV_SUCCESS) { 320 ALOGE("Error in create: 0x%x", 321 s_create_op.s_ivd_create_op_t.u4_error_code); 322 deInitDecoder(); 323 mCodecCtx = NULL; 324 return UNKNOWN_ERROR; 325 } 326 } 327 328 /* Reset the plugin state */ 329 resetPlugin(); 330 331 /* Set the run time (dynamic) parameters */ 332 setParams(mStride); 333 334 /* Set number of cores/threads to be used by the codec */ 335 setNumCores(); 336 337 /* Get codec version */ 338 logVersion(); 339 340 mFlushNeeded = false; 341 return OK; 342 } 343 344 status_t SoftHEVC::deInitDecoder() { 345 size_t i; 346 IV_API_CALL_STATUS_T status; 347 348 if (mCodecCtx) { 349 ivdext_delete_ip_t s_delete_ip; 350 ivdext_delete_op_t s_delete_op; 351 352 s_delete_ip.s_ivd_delete_ip_t.u4_size = sizeof(ivdext_delete_ip_t); 353 s_delete_ip.s_ivd_delete_ip_t.e_cmd = IVD_CMD_DELETE; 354 355 s_delete_op.s_ivd_delete_op_t.u4_size = sizeof(ivdext_delete_op_t); 356 357 status = ivdec_api_function(mCodecCtx, (void *)&s_delete_ip, (void *)&s_delete_op); 358 if (status != IV_SUCCESS) { 359 ALOGE("Error in delete: 0x%x", 360 s_delete_op.s_ivd_delete_op_t.u4_error_code); 361 return UNKNOWN_ERROR; 362 } 363 } 364 365 366 mChangingResolution = false; 367 368 return OK; 369 } 370 371 void SoftHEVC::onReset() { 372 ALOGV("onReset called"); 373 SoftVideoDecoderOMXComponent::onReset(); 374 375 mSignalledError = false; 376 resetDecoder(); 377 resetPlugin(); 378 } 379 380 bool SoftHEVC::setDecodeArgs(ivd_video_decode_ip_t *ps_dec_ip, 381 ivd_video_decode_op_t *ps_dec_op, 382 OMX_BUFFERHEADERTYPE *inHeader, 383 OMX_BUFFERHEADERTYPE *outHeader, 384 size_t timeStampIx) { 385 size_t sizeY = outputBufferWidth() * outputBufferHeight(); 386 size_t sizeUV; 387 388 ps_dec_ip->u4_size = sizeof(ivd_video_decode_ip_t); 389 ps_dec_op->u4_size = sizeof(ivd_video_decode_op_t); 390 391 ps_dec_ip->e_cmd = IVD_CMD_VIDEO_DECODE; 392 393 /* When in flush and after EOS with zero byte input, 394 * inHeader is set to zero. Hence check for non-null */ 395 if (inHeader) { 396 ps_dec_ip->u4_ts = timeStampIx; 397 ps_dec_ip->pv_stream_buffer = inHeader->pBuffer 398 + inHeader->nOffset; 399 ps_dec_ip->u4_num_Bytes = inHeader->nFilledLen; 400 } else { 401 ps_dec_ip->u4_ts = 0; 402 ps_dec_ip->pv_stream_buffer = NULL; 403 ps_dec_ip->u4_num_Bytes = 0; 404 } 405 406 sizeUV = sizeY / 4; 407 ps_dec_ip->s_out_buffer.u4_min_out_buf_size[0] = sizeY; 408 ps_dec_ip->s_out_buffer.u4_min_out_buf_size[1] = sizeUV; 409 ps_dec_ip->s_out_buffer.u4_min_out_buf_size[2] = sizeUV; 410 411 uint8_t *pBuf; 412 if (outHeader) { 413 if (outHeader->nAllocLen < sizeY + (sizeUV * 2)) { 414 android_errorWriteLog(0x534e4554, "27833616"); 415 return false; 416 } 417 pBuf = outHeader->pBuffer; 418 } else { 419 // mFlushOutBuffer always has the right size. 420 pBuf = mFlushOutBuffer; 421 } 422 423 ps_dec_ip->s_out_buffer.pu1_bufs[0] = pBuf; 424 ps_dec_ip->s_out_buffer.pu1_bufs[1] = pBuf + sizeY; 425 ps_dec_ip->s_out_buffer.pu1_bufs[2] = pBuf + sizeY + sizeUV; 426 ps_dec_ip->s_out_buffer.u4_num_bufs = 3; 427 return true; 428 } 429 void SoftHEVC::onPortFlushCompleted(OMX_U32 portIndex) { 430 /* Once the output buffers are flushed, ignore any buffers that are held in decoder */ 431 if (kOutputPortIndex == portIndex) { 432 setFlushMode(); 433 434 /* Allocate a picture buffer to flushed data */ 435 uint32_t displayStride = outputBufferWidth(); 436 uint32_t displayHeight = outputBufferHeight(); 437 438 uint32_t bufferSize = displayStride * displayHeight * 3 / 2; 439 mFlushOutBuffer = (uint8_t *)memalign(128, bufferSize); 440 if (NULL == mFlushOutBuffer) { 441 ALOGE("Could not allocate flushOutputBuffer of size %u", bufferSize); 442 return; 443 } 444 445 while (true) { 446 ivd_video_decode_ip_t s_dec_ip; 447 ivd_video_decode_op_t s_dec_op; 448 IV_API_CALL_STATUS_T status; 449 size_t sizeY, sizeUV; 450 451 setDecodeArgs(&s_dec_ip, &s_dec_op, NULL, NULL, 0); 452 453 status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, 454 (void *)&s_dec_op); 455 if (0 == s_dec_op.u4_output_present) { 456 resetPlugin(); 457 break; 458 } 459 } 460 461 if (mFlushOutBuffer) { 462 free(mFlushOutBuffer); 463 mFlushOutBuffer = NULL; 464 } 465 466 } 467 } 468 469 void SoftHEVC::onQueueFilled(OMX_U32 portIndex) { 470 UNUSED(portIndex); 471 472 if (mSignalledError) { 473 return; 474 } 475 if (mOutputPortSettingsChange != NONE) { 476 return; 477 } 478 479 if (NULL == mCodecCtx) { 480 if (OK != initDecoder()) { 481 ALOGE("Failed to initialize decoder"); 482 notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL); 483 mSignalledError = true; 484 return; 485 } 486 } 487 if (outputBufferWidth() != mStride) { 488 /* Set the run-time (dynamic) parameters */ 489 mStride = outputBufferWidth(); 490 setParams(mStride); 491 } 492 493 List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex); 494 List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex); 495 496 while (!outQueue.empty()) { 497 BufferInfo *inInfo; 498 OMX_BUFFERHEADERTYPE *inHeader; 499 500 BufferInfo *outInfo; 501 OMX_BUFFERHEADERTYPE *outHeader; 502 size_t timeStampIx; 503 504 inInfo = NULL; 505 inHeader = NULL; 506 507 if (!mIsInFlush) { 508 if (!inQueue.empty()) { 509 inInfo = *inQueue.begin(); 510 inHeader = inInfo->mHeader; 511 } else { 512 break; 513 } 514 } 515 516 outInfo = *outQueue.begin(); 517 outHeader = outInfo->mHeader; 518 outHeader->nFlags = 0; 519 outHeader->nTimeStamp = 0; 520 outHeader->nOffset = 0; 521 522 if (inHeader != NULL && (inHeader->nFlags & OMX_BUFFERFLAG_EOS)) { 523 mReceivedEOS = true; 524 if (inHeader->nFilledLen == 0) { 525 inQueue.erase(inQueue.begin()); 526 inInfo->mOwnedByUs = false; 527 notifyEmptyBufferDone(inHeader); 528 inHeader = NULL; 529 setFlushMode(); 530 } 531 } 532 533 /* Get a free slot in timestamp array to hold input timestamp */ 534 { 535 size_t i; 536 timeStampIx = 0; 537 for (i = 0; i < MAX_TIME_STAMPS; i++) { 538 if (!mTimeStampsValid[i]) { 539 timeStampIx = i; 540 break; 541 } 542 } 543 if (inHeader != NULL) { 544 mTimeStampsValid[timeStampIx] = true; 545 mTimeStamps[timeStampIx] = inHeader->nTimeStamp; 546 } 547 } 548 549 { 550 ivd_video_decode_ip_t s_dec_ip; 551 ivd_video_decode_op_t s_dec_op; 552 WORD32 timeDelay, timeTaken; 553 size_t sizeY, sizeUV; 554 555 if (!setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx)) { 556 ALOGE("Decoder arg setup failed"); 557 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); 558 mSignalledError = true; 559 return; 560 } 561 562 GETTIME(&mTimeStart, NULL); 563 /* Compute time elapsed between end of previous decode() 564 * to start of current decode() */ 565 TIME_DIFF(mTimeEnd, mTimeStart, timeDelay); 566 567 IV_API_CALL_STATUS_T status; 568 status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op); 569 570 bool unsupportedResolution = 571 (IVD_STREAM_WIDTH_HEIGHT_NOT_SUPPORTED == (s_dec_op.u4_error_code & 0xFF)); 572 573 /* Check for unsupported dimensions */ 574 if (unsupportedResolution) { 575 ALOGE("Unsupported resolution : %dx%d", mWidth, mHeight); 576 notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL); 577 mSignalledError = true; 578 return; 579 } 580 581 bool allocationFailed = (IVD_MEM_ALLOC_FAILED == (s_dec_op.u4_error_code & 0xFF)); 582 if (allocationFailed) { 583 ALOGE("Allocation failure in decoder"); 584 notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL); 585 mSignalledError = true; 586 return; 587 } 588 589 bool resChanged = (IVD_RES_CHANGED == (s_dec_op.u4_error_code & 0xFF)); 590 591 getVUIParams(); 592 593 GETTIME(&mTimeEnd, NULL); 594 /* Compute time taken for decode() */ 595 TIME_DIFF(mTimeStart, mTimeEnd, timeTaken); 596 597 ALOGV("timeTaken=%6d delay=%6d numBytes=%6d", timeTaken, timeDelay, 598 s_dec_op.u4_num_bytes_consumed); 599 if (s_dec_op.u4_frame_decoded_flag && !mFlushNeeded) { 600 mFlushNeeded = true; 601 } 602 603 if ((inHeader != NULL) && (1 != s_dec_op.u4_frame_decoded_flag)) { 604 /* If the input did not contain picture data, then ignore 605 * the associated timestamp */ 606 mTimeStampsValid[timeStampIx] = false; 607 } 608 609 // If the decoder is in the changing resolution mode and there is no output present, 610 // that means the switching is done and it's ready to reset the decoder and the plugin. 611 if (mChangingResolution && !s_dec_op.u4_output_present) { 612 mChangingResolution = false; 613 resetDecoder(); 614 resetPlugin(); 615 mStride = outputBufferWidth(); 616 setParams(mStride); 617 continue; 618 } 619 620 if (resChanged) { 621 mChangingResolution = true; 622 if (mFlushNeeded) { 623 setFlushMode(); 624 } 625 continue; 626 } 627 628 // Combine the resolution change and coloraspects change in one PortSettingChange event 629 // if necessary. 630 if ((0 < s_dec_op.u4_pic_wd) && (0 < s_dec_op.u4_pic_ht)) { 631 uint32_t width = s_dec_op.u4_pic_wd; 632 uint32_t height = s_dec_op.u4_pic_ht; 633 bool portWillReset = false; 634 handlePortSettingsChange(&portWillReset, width, height); 635 636 if (portWillReset) { 637 resetDecoder(); 638 resetPlugin(); 639 return; 640 } 641 } else if (mUpdateColorAspects) { 642 notify(OMX_EventPortSettingsChanged, kOutputPortIndex, 643 kDescribeColorAspectsIndex, NULL); 644 mUpdateColorAspects = false; 645 return; 646 } 647 648 if (s_dec_op.u4_output_present) { 649 outHeader->nFilledLen = (outputBufferWidth() * outputBufferHeight() * 3) / 2; 650 651 outHeader->nTimeStamp = mTimeStamps[s_dec_op.u4_ts]; 652 mTimeStampsValid[s_dec_op.u4_ts] = false; 653 654 outInfo->mOwnedByUs = false; 655 outQueue.erase(outQueue.begin()); 656 outInfo = NULL; 657 notifyFillBufferDone(outHeader); 658 outHeader = NULL; 659 } else if (mIsInFlush) { 660 /* If in flush mode and no output is returned by the codec, 661 * then come out of flush mode */ 662 mIsInFlush = false; 663 664 /* If EOS was recieved on input port and there is no output 665 * from the codec, then signal EOS on output port */ 666 if (mReceivedEOS) { 667 outHeader->nFilledLen = 0; 668 outHeader->nFlags |= OMX_BUFFERFLAG_EOS; 669 670 outInfo->mOwnedByUs = false; 671 outQueue.erase(outQueue.begin()); 672 outInfo = NULL; 673 notifyFillBufferDone(outHeader); 674 outHeader = NULL; 675 resetPlugin(); 676 } 677 } 678 } 679 680 /* If input EOS is seen and decoder is not in flush mode, 681 * set the decoder in flush mode. 682 * There can be a case where EOS is sent along with last picture data 683 * In that case, only after decoding that input data, decoder has to be 684 * put in flush. This case is handled here */ 685 686 if (mReceivedEOS && !mIsInFlush) { 687 setFlushMode(); 688 } 689 690 // TODO: Handle more than one picture data 691 if (inHeader != NULL) { 692 inInfo->mOwnedByUs = false; 693 inQueue.erase(inQueue.begin()); 694 inInfo = NULL; 695 notifyEmptyBufferDone(inHeader); 696 inHeader = NULL; 697 } 698 } 699 } 700 701 int SoftHEVC::getColorAspectPreference() { 702 return kPreferBitstream; 703 } 704 705 } // namespace android 706 707 android::SoftOMXComponent *createSoftOMXComponent(const char *name, 708 const OMX_CALLBACKTYPE *callbacks, OMX_PTR appData, 709 OMX_COMPONENTTYPE **component) { 710 android::SoftHEVC *codec = new android::SoftHEVC(name, callbacks, appData, component); 711 if (codec->init() != android::OK) { 712 android::sp<android::SoftOMXComponent> release = codec; 713 return NULL; 714 } 715 return codec; 716 } 717