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 "ithread.h" 25 #include "ihevcd_cxa.h" 26 #include "SoftHEVC.h" 27 28 #include <media/stagefright/foundation/ADebug.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_init_ip_t ihevcd_cxa_init_ip_t 41 #define ivdext_init_op_t ihevcd_cxa_init_op_t 42 #define ivdext_fill_mem_rec_ip_t ihevcd_cxa_fill_mem_rec_ip_t 43 #define ivdext_fill_mem_rec_op_t ihevcd_cxa_fill_mem_rec_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_HEVCMainTierLevel1 }, 52 { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel2 }, 53 { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel21 }, 54 { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel3 }, 55 { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel31 }, 56 { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel4 }, 57 { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel41 }, 58 { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel5 }, 59 { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel51 }, 60 }; 61 62 SoftHEVC::SoftHEVC( 63 const char *name, 64 const OMX_CALLBACKTYPE *callbacks, 65 OMX_PTR appData, 66 OMX_COMPONENTTYPE **component) 67 : SoftVideoDecoderOMXComponent(name, componentName, codingType, 68 kProfileLevels, ARRAY_SIZE(kProfileLevels), 69 320 /* width */, 240 /* height */, callbacks, 70 appData, component), 71 mMemRecords(NULL), 72 mFlushOutBuffer(NULL), 73 mOmxColorFormat(OMX_COLOR_FormatYUV420Planar), 74 mIvColorFormat(IV_YUV_420P), 75 mNewWidth(mWidth), 76 mNewHeight(mHeight), 77 mChangingResolution(false) { 78 initPorts(kNumBuffers, INPUT_BUF_SIZE, kNumBuffers, 79 CODEC_MIME_TYPE); 80 CHECK_EQ(initDecoder(), (status_t)OK); 81 } 82 83 SoftHEVC::~SoftHEVC() { 84 ALOGD("In SoftHEVC::~SoftHEVC"); 85 CHECK_EQ(deInitDecoder(), (status_t)OK); 86 } 87 88 static size_t GetCPUCoreCount() { 89 long cpuCoreCount = 1; 90 #if defined(_SC_NPROCESSORS_ONLN) 91 cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN); 92 #else 93 // _SC_NPROC_ONLN must be defined... 94 cpuCoreCount = sysconf(_SC_NPROC_ONLN); 95 #endif 96 CHECK(cpuCoreCount >= 1); 97 ALOGD("Number of CPU cores: %ld", cpuCoreCount); 98 return (size_t)cpuCoreCount; 99 } 100 101 void SoftHEVC::logVersion() { 102 ivd_ctl_getversioninfo_ip_t s_ctl_ip; 103 ivd_ctl_getversioninfo_op_t s_ctl_op; 104 UWORD8 au1_buf[512]; 105 IV_API_CALL_STATUS_T status; 106 107 s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL; 108 s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_GETVERSION; 109 s_ctl_ip.u4_size = sizeof(ivd_ctl_getversioninfo_ip_t); 110 s_ctl_op.u4_size = sizeof(ivd_ctl_getversioninfo_op_t); 111 s_ctl_ip.pv_version_buffer = au1_buf; 112 s_ctl_ip.u4_version_buffer_size = sizeof(au1_buf); 113 114 status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip, 115 (void *)&s_ctl_op); 116 117 if (status != IV_SUCCESS) { 118 ALOGE("Error in getting version number: 0x%x", 119 s_ctl_op.u4_error_code); 120 } else { 121 ALOGD("Ittiam decoder version number: %s", 122 (char *)s_ctl_ip.pv_version_buffer); 123 } 124 return; 125 } 126 127 status_t SoftHEVC::setParams(size_t stride) { 128 ivd_ctl_set_config_ip_t s_ctl_ip; 129 ivd_ctl_set_config_op_t s_ctl_op; 130 IV_API_CALL_STATUS_T status; 131 s_ctl_ip.u4_disp_wd = (UWORD32)stride; 132 s_ctl_ip.e_frm_skip_mode = IVD_SKIP_NONE; 133 134 s_ctl_ip.e_frm_out_mode = IVD_DISPLAY_FRAME_OUT; 135 s_ctl_ip.e_vid_dec_mode = IVD_DECODE_FRAME; 136 s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL; 137 s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_SETPARAMS; 138 s_ctl_ip.u4_size = sizeof(ivd_ctl_set_config_ip_t); 139 s_ctl_op.u4_size = sizeof(ivd_ctl_set_config_op_t); 140 141 ALOGV("Set the run-time (dynamic) parameters stride = %u", stride); 142 status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip, 143 (void *)&s_ctl_op); 144 145 if (status != IV_SUCCESS) { 146 ALOGE("Error in setting the run-time parameters: 0x%x", 147 s_ctl_op.u4_error_code); 148 149 return UNKNOWN_ERROR; 150 } 151 return OK; 152 } 153 154 status_t SoftHEVC::resetPlugin() { 155 mIsInFlush = false; 156 mReceivedEOS = false; 157 memset(mTimeStamps, 0, sizeof(mTimeStamps)); 158 memset(mTimeStampsValid, 0, sizeof(mTimeStampsValid)); 159 160 /* Initialize both start and end times */ 161 gettimeofday(&mTimeStart, NULL); 162 gettimeofday(&mTimeEnd, NULL); 163 164 return OK; 165 } 166 167 status_t SoftHEVC::resetDecoder() { 168 ivd_ctl_reset_ip_t s_ctl_ip; 169 ivd_ctl_reset_op_t s_ctl_op; 170 IV_API_CALL_STATUS_T status; 171 172 s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL; 173 s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_RESET; 174 s_ctl_ip.u4_size = sizeof(ivd_ctl_reset_ip_t); 175 s_ctl_op.u4_size = sizeof(ivd_ctl_reset_op_t); 176 177 status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip, 178 (void *)&s_ctl_op); 179 if (IV_SUCCESS != status) { 180 ALOGE("Error in reset: 0x%x", s_ctl_op.u4_error_code); 181 return UNKNOWN_ERROR; 182 } 183 184 /* Set the run-time (dynamic) parameters */ 185 setParams(outputBufferWidth()); 186 187 /* Set number of cores/threads to be used by the codec */ 188 setNumCores(); 189 190 return OK; 191 } 192 193 status_t SoftHEVC::setNumCores() { 194 ivdext_ctl_set_num_cores_ip_t s_set_cores_ip; 195 ivdext_ctl_set_num_cores_op_t s_set_cores_op; 196 IV_API_CALL_STATUS_T status; 197 s_set_cores_ip.e_cmd = IVD_CMD_VIDEO_CTL; 198 s_set_cores_ip.e_sub_cmd = IVDEXT_CMD_CTL_SET_NUM_CORES; 199 s_set_cores_ip.u4_num_cores = MIN(mNumCores, CODEC_MAX_NUM_CORES); 200 s_set_cores_ip.u4_size = sizeof(ivdext_ctl_set_num_cores_ip_t); 201 s_set_cores_op.u4_size = sizeof(ivdext_ctl_set_num_cores_op_t); 202 ALOGD("Set number of cores to %u", s_set_cores_ip.u4_num_cores); 203 status = ivdec_api_function(mCodecCtx, (void *)&s_set_cores_ip, 204 (void *)&s_set_cores_op); 205 if (IV_SUCCESS != status) { 206 ALOGE("Error in setting number of cores: 0x%x", 207 s_set_cores_op.u4_error_code); 208 return UNKNOWN_ERROR; 209 } 210 return OK; 211 } 212 213 status_t SoftHEVC::setFlushMode() { 214 IV_API_CALL_STATUS_T status; 215 ivd_ctl_flush_ip_t s_video_flush_ip; 216 ivd_ctl_flush_op_t s_video_flush_op; 217 218 s_video_flush_ip.e_cmd = IVD_CMD_VIDEO_CTL; 219 s_video_flush_ip.e_sub_cmd = IVD_CMD_CTL_FLUSH; 220 s_video_flush_ip.u4_size = sizeof(ivd_ctl_flush_ip_t); 221 s_video_flush_op.u4_size = sizeof(ivd_ctl_flush_op_t); 222 ALOGD("Set the decoder in flush mode "); 223 224 /* Set the decoder in Flush mode, subsequent decode() calls will flush */ 225 status = ivdec_api_function(mCodecCtx, (void *)&s_video_flush_ip, 226 (void *)&s_video_flush_op); 227 228 if (status != IV_SUCCESS) { 229 ALOGE("Error in setting the decoder in flush mode: (%d) 0x%x", status, 230 s_video_flush_op.u4_error_code); 231 return UNKNOWN_ERROR; 232 } 233 234 mIsInFlush = true; 235 return OK; 236 } 237 238 status_t SoftHEVC::initDecoder() { 239 IV_API_CALL_STATUS_T status; 240 241 UWORD32 u4_num_reorder_frames; 242 UWORD32 u4_num_ref_frames; 243 UWORD32 u4_share_disp_buf; 244 WORD32 i4_level; 245 246 mNumCores = GetCPUCoreCount(); 247 248 /* Initialize number of ref and reorder modes (for HEVC) */ 249 u4_num_reorder_frames = 16; 250 u4_num_ref_frames = 16; 251 u4_share_disp_buf = 0; 252 253 uint32_t displayStride = outputBufferWidth(); 254 uint32_t displayHeight = outputBufferHeight(); 255 uint32_t displaySizeY = displayStride * displayHeight; 256 257 if (displaySizeY > (1920 * 1088)) { 258 i4_level = 50; 259 } else if (displaySizeY > (1280 * 720)) { 260 i4_level = 40; 261 } else if (displaySizeY > (960 * 540)) { 262 i4_level = 31; 263 } else if (displaySizeY > (640 * 360)) { 264 i4_level = 30; 265 } else if (displaySizeY > (352 * 288)) { 266 i4_level = 21; 267 } else { 268 i4_level = 20; 269 } 270 { 271 iv_num_mem_rec_ip_t s_num_mem_rec_ip; 272 iv_num_mem_rec_op_t s_num_mem_rec_op; 273 274 s_num_mem_rec_ip.u4_size = sizeof(s_num_mem_rec_ip); 275 s_num_mem_rec_op.u4_size = sizeof(s_num_mem_rec_op); 276 s_num_mem_rec_ip.e_cmd = IV_CMD_GET_NUM_MEM_REC; 277 278 ALOGV("Get number of mem records"); 279 status = ivdec_api_function(mCodecCtx, (void*)&s_num_mem_rec_ip, 280 (void*)&s_num_mem_rec_op); 281 if (IV_SUCCESS != status) { 282 ALOGE("Error in getting mem records: 0x%x", 283 s_num_mem_rec_op.u4_error_code); 284 return UNKNOWN_ERROR; 285 } 286 287 mNumMemRecords = s_num_mem_rec_op.u4_num_mem_rec; 288 } 289 290 mMemRecords = (iv_mem_rec_t*)ivd_aligned_malloc( 291 128, mNumMemRecords * sizeof(iv_mem_rec_t)); 292 if (mMemRecords == NULL) { 293 ALOGE("Allocation failure"); 294 return NO_MEMORY; 295 } 296 297 memset(mMemRecords, 0, mNumMemRecords * sizeof(iv_mem_rec_t)); 298 299 { 300 size_t i; 301 ivdext_fill_mem_rec_ip_t s_fill_mem_ip; 302 ivdext_fill_mem_rec_op_t s_fill_mem_op; 303 iv_mem_rec_t *ps_mem_rec; 304 305 s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_size = 306 sizeof(ivdext_fill_mem_rec_ip_t); 307 s_fill_mem_ip.i4_level = i4_level; 308 s_fill_mem_ip.u4_num_reorder_frames = u4_num_reorder_frames; 309 s_fill_mem_ip.u4_num_ref_frames = u4_num_ref_frames; 310 s_fill_mem_ip.u4_share_disp_buf = u4_share_disp_buf; 311 s_fill_mem_ip.u4_num_extra_disp_buf = 0; 312 s_fill_mem_ip.e_output_format = mIvColorFormat; 313 314 s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.e_cmd = IV_CMD_FILL_NUM_MEM_REC; 315 s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.pv_mem_rec_location = mMemRecords; 316 s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_wd = displayStride; 317 s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_ht = displayHeight; 318 s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_size = 319 sizeof(ivdext_fill_mem_rec_op_t); 320 321 ps_mem_rec = mMemRecords; 322 for (i = 0; i < mNumMemRecords; i++) 323 ps_mem_rec[i].u4_size = sizeof(iv_mem_rec_t); 324 325 status = ivdec_api_function(mCodecCtx, (void *)&s_fill_mem_ip, 326 (void *)&s_fill_mem_op); 327 328 if (IV_SUCCESS != status) { 329 ALOGE("Error in filling mem records: 0x%x", 330 s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_error_code); 331 return UNKNOWN_ERROR; 332 } 333 mNumMemRecords = 334 s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_num_mem_rec_filled; 335 336 ps_mem_rec = mMemRecords; 337 338 for (i = 0; i < mNumMemRecords; i++) { 339 ps_mem_rec->pv_base = ivd_aligned_malloc( 340 ps_mem_rec->u4_mem_alignment, ps_mem_rec->u4_mem_size); 341 if (ps_mem_rec->pv_base == NULL) { 342 ALOGE("Allocation failure for memory record #%zu of size %u", 343 i, ps_mem_rec->u4_mem_size); 344 status = IV_FAIL; 345 return NO_MEMORY; 346 } 347 348 ps_mem_rec++; 349 } 350 } 351 352 /* Initialize the decoder */ 353 { 354 ivdext_init_ip_t s_init_ip; 355 ivdext_init_op_t s_init_op; 356 357 void *dec_fxns = (void *)ivdec_api_function; 358 359 s_init_ip.s_ivd_init_ip_t.u4_size = sizeof(ivdext_init_ip_t); 360 s_init_ip.s_ivd_init_ip_t.e_cmd = (IVD_API_COMMAND_TYPE_T)IV_CMD_INIT; 361 s_init_ip.s_ivd_init_ip_t.pv_mem_rec_location = mMemRecords; 362 s_init_ip.s_ivd_init_ip_t.u4_frm_max_wd = displayStride; 363 s_init_ip.s_ivd_init_ip_t.u4_frm_max_ht = displayHeight; 364 365 s_init_ip.i4_level = i4_level; 366 s_init_ip.u4_num_reorder_frames = u4_num_reorder_frames; 367 s_init_ip.u4_num_ref_frames = u4_num_ref_frames; 368 s_init_ip.u4_share_disp_buf = u4_share_disp_buf; 369 s_init_ip.u4_num_extra_disp_buf = 0; 370 371 s_init_op.s_ivd_init_op_t.u4_size = sizeof(s_init_op); 372 373 s_init_ip.s_ivd_init_ip_t.u4_num_mem_rec = mNumMemRecords; 374 s_init_ip.s_ivd_init_ip_t.e_output_format = mIvColorFormat; 375 376 mCodecCtx = (iv_obj_t*)mMemRecords[0].pv_base; 377 mCodecCtx->pv_fxns = dec_fxns; 378 mCodecCtx->u4_size = sizeof(iv_obj_t); 379 380 ALOGD("Initializing decoder"); 381 status = ivdec_api_function(mCodecCtx, (void *)&s_init_ip, 382 (void *)&s_init_op); 383 if (status != IV_SUCCESS) { 384 ALOGE("Error in init: 0x%x", 385 s_init_op.s_ivd_init_op_t.u4_error_code); 386 return UNKNOWN_ERROR; 387 } 388 } 389 390 /* Reset the plugin state */ 391 resetPlugin(); 392 393 /* Set the run time (dynamic) parameters */ 394 setParams(displayStride); 395 396 /* Set number of cores/threads to be used by the codec */ 397 setNumCores(); 398 399 /* Get codec version */ 400 logVersion(); 401 402 /* Allocate internal picture buffer */ 403 uint32_t bufferSize = displaySizeY * 3 / 2; 404 mFlushOutBuffer = (uint8_t *)ivd_aligned_malloc(128, bufferSize); 405 if (NULL == mFlushOutBuffer) { 406 ALOGE("Could not allocate flushOutputBuffer of size %zu", bufferSize); 407 return NO_MEMORY; 408 } 409 410 mInitNeeded = false; 411 mFlushNeeded = false; 412 return OK; 413 } 414 415 status_t SoftHEVC::deInitDecoder() { 416 size_t i; 417 418 if (mMemRecords) { 419 iv_mem_rec_t *ps_mem_rec; 420 421 ps_mem_rec = mMemRecords; 422 ALOGD("Freeing codec memory"); 423 for (i = 0; i < mNumMemRecords; i++) { 424 if(ps_mem_rec->pv_base) { 425 ivd_aligned_free(ps_mem_rec->pv_base); 426 } 427 ps_mem_rec++; 428 } 429 ivd_aligned_free(mMemRecords); 430 mMemRecords = NULL; 431 } 432 433 if(mFlushOutBuffer) { 434 ivd_aligned_free(mFlushOutBuffer); 435 mFlushOutBuffer = NULL; 436 } 437 438 mInitNeeded = true; 439 mChangingResolution = false; 440 441 return OK; 442 } 443 444 status_t SoftHEVC::reInitDecoder() { 445 status_t ret; 446 447 deInitDecoder(); 448 449 ret = initDecoder(); 450 if (OK != ret) { 451 ALOGE("Create failure"); 452 deInitDecoder(); 453 return NO_MEMORY; 454 } 455 return OK; 456 } 457 458 void SoftHEVC::onReset() { 459 ALOGD("onReset called"); 460 SoftVideoDecoderOMXComponent::onReset(); 461 462 resetDecoder(); 463 resetPlugin(); 464 } 465 466 OMX_ERRORTYPE SoftHEVC::internalSetParameter(OMX_INDEXTYPE index, const OMX_PTR params) { 467 const uint32_t oldWidth = mWidth; 468 const uint32_t oldHeight = mHeight; 469 OMX_ERRORTYPE ret = SoftVideoDecoderOMXComponent::internalSetParameter(index, params); 470 if (mWidth != oldWidth || mHeight != oldHeight) { 471 reInitDecoder(); 472 } 473 return ret; 474 } 475 476 void SoftHEVC::setDecodeArgs(ivd_video_decode_ip_t *ps_dec_ip, 477 ivd_video_decode_op_t *ps_dec_op, 478 OMX_BUFFERHEADERTYPE *inHeader, 479 OMX_BUFFERHEADERTYPE *outHeader, 480 size_t timeStampIx) { 481 size_t sizeY = outputBufferWidth() * outputBufferHeight(); 482 size_t sizeUV; 483 uint8_t *pBuf; 484 485 ps_dec_ip->u4_size = sizeof(ivd_video_decode_ip_t); 486 ps_dec_op->u4_size = sizeof(ivd_video_decode_op_t); 487 488 ps_dec_ip->e_cmd = IVD_CMD_VIDEO_DECODE; 489 490 /* When in flush and after EOS with zero byte input, 491 * inHeader is set to zero. Hence check for non-null */ 492 if (inHeader) { 493 ps_dec_ip->u4_ts = timeStampIx; 494 ps_dec_ip->pv_stream_buffer = inHeader->pBuffer 495 + inHeader->nOffset; 496 ps_dec_ip->u4_num_Bytes = inHeader->nFilledLen; 497 } else { 498 ps_dec_ip->u4_ts = 0; 499 ps_dec_ip->pv_stream_buffer = NULL; 500 ps_dec_ip->u4_num_Bytes = 0; 501 } 502 503 if (outHeader) { 504 pBuf = outHeader->pBuffer; 505 } else { 506 pBuf = mFlushOutBuffer; 507 } 508 509 sizeUV = sizeY / 4; 510 ps_dec_ip->s_out_buffer.u4_min_out_buf_size[0] = sizeY; 511 ps_dec_ip->s_out_buffer.u4_min_out_buf_size[1] = sizeUV; 512 ps_dec_ip->s_out_buffer.u4_min_out_buf_size[2] = sizeUV; 513 514 ps_dec_ip->s_out_buffer.pu1_bufs[0] = pBuf; 515 ps_dec_ip->s_out_buffer.pu1_bufs[1] = pBuf + sizeY; 516 ps_dec_ip->s_out_buffer.pu1_bufs[2] = pBuf + sizeY + sizeUV; 517 ps_dec_ip->s_out_buffer.u4_num_bufs = 3; 518 return; 519 } 520 void SoftHEVC::onPortFlushCompleted(OMX_U32 portIndex) { 521 /* Once the output buffers are flushed, ignore any buffers that are held in decoder */ 522 if (kOutputPortIndex == portIndex) { 523 setFlushMode(); 524 525 while (true) { 526 ivd_video_decode_ip_t s_dec_ip; 527 ivd_video_decode_op_t s_dec_op; 528 IV_API_CALL_STATUS_T status; 529 size_t sizeY, sizeUV; 530 531 setDecodeArgs(&s_dec_ip, &s_dec_op, NULL, NULL, 0); 532 533 status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, 534 (void *)&s_dec_op); 535 if (0 == s_dec_op.u4_output_present) { 536 resetPlugin(); 537 break; 538 } 539 } 540 } 541 } 542 543 void SoftHEVC::onQueueFilled(OMX_U32 portIndex) { 544 UNUSED(portIndex); 545 546 if (mOutputPortSettingsChange != NONE) { 547 return; 548 } 549 550 List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex); 551 List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex); 552 553 /* If input EOS is seen and decoder is not in flush mode, 554 * set the decoder in flush mode. 555 * There can be a case where EOS is sent along with last picture data 556 * In that case, only after decoding that input data, decoder has to be 557 * put in flush. This case is handled here */ 558 559 if (mReceivedEOS && !mIsInFlush) { 560 setFlushMode(); 561 } 562 563 while (!outQueue.empty()) { 564 BufferInfo *inInfo; 565 OMX_BUFFERHEADERTYPE *inHeader; 566 567 BufferInfo *outInfo; 568 OMX_BUFFERHEADERTYPE *outHeader; 569 size_t timeStampIx; 570 571 inInfo = NULL; 572 inHeader = NULL; 573 574 if (!mIsInFlush) { 575 if (!inQueue.empty()) { 576 inInfo = *inQueue.begin(); 577 inHeader = inInfo->mHeader; 578 } else { 579 break; 580 } 581 } 582 583 outInfo = *outQueue.begin(); 584 outHeader = outInfo->mHeader; 585 outHeader->nFlags = 0; 586 outHeader->nTimeStamp = 0; 587 outHeader->nOffset = 0; 588 589 if (inHeader != NULL && (inHeader->nFlags & OMX_BUFFERFLAG_EOS)) { 590 ALOGD("EOS seen on input"); 591 mReceivedEOS = true; 592 if (inHeader->nFilledLen == 0) { 593 inQueue.erase(inQueue.begin()); 594 inInfo->mOwnedByUs = false; 595 notifyEmptyBufferDone(inHeader); 596 inHeader = NULL; 597 setFlushMode(); 598 } 599 } 600 601 // When there is an init required and the decoder is not in flush mode, 602 // update output port's definition and reinitialize decoder. 603 if (mInitNeeded && !mIsInFlush) { 604 bool portWillReset = false; 605 handlePortSettingsChange(&portWillReset, mNewWidth, mNewHeight); 606 607 CHECK_EQ(reInitDecoder(), (status_t)OK); 608 return; 609 } 610 611 /* Get a free slot in timestamp array to hold input timestamp */ 612 { 613 size_t i; 614 timeStampIx = 0; 615 for (i = 0; i < MAX_TIME_STAMPS; i++) { 616 if (!mTimeStampsValid[i]) { 617 timeStampIx = i; 618 break; 619 } 620 } 621 if (inHeader != NULL) { 622 mTimeStampsValid[timeStampIx] = true; 623 mTimeStamps[timeStampIx] = inHeader->nTimeStamp; 624 } 625 } 626 627 { 628 ivd_video_decode_ip_t s_dec_ip; 629 ivd_video_decode_op_t s_dec_op; 630 WORD32 timeDelay, timeTaken; 631 size_t sizeY, sizeUV; 632 633 setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx); 634 635 GETTIME(&mTimeStart, NULL); 636 /* Compute time elapsed between end of previous decode() 637 * to start of current decode() */ 638 TIME_DIFF(mTimeEnd, mTimeStart, timeDelay); 639 640 IV_API_CALL_STATUS_T status; 641 status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op); 642 // FIXME: Compare |status| to IHEVCD_UNSUPPORTED_DIMENSIONS, which is not one of the 643 // IV_API_CALL_STATUS_T, seems be wrong. But this is what the decoder returns right now. 644 // The decoder should be fixed so that |u4_error_code| instead of |status| returns 645 // IHEVCD_UNSUPPORTED_DIMENSIONS. 646 bool unsupportedDimensions = 647 ((IHEVCD_UNSUPPORTED_DIMENSIONS == status) 648 || (IHEVCD_UNSUPPORTED_DIMENSIONS == s_dec_op.u4_error_code)); 649 bool resChanged = (IVD_RES_CHANGED == (s_dec_op.u4_error_code & 0xFF)); 650 651 GETTIME(&mTimeEnd, NULL); 652 /* Compute time taken for decode() */ 653 TIME_DIFF(mTimeStart, mTimeEnd, timeTaken); 654 655 ALOGV("timeTaken=%6d delay=%6d numBytes=%6d", timeTaken, timeDelay, 656 s_dec_op.u4_num_bytes_consumed); 657 if (s_dec_op.u4_frame_decoded_flag && !mFlushNeeded) { 658 mFlushNeeded = true; 659 } 660 661 if ((inHeader != NULL) && (1 != s_dec_op.u4_frame_decoded_flag)) { 662 /* If the input did not contain picture data, then ignore 663 * the associated timestamp */ 664 mTimeStampsValid[timeStampIx] = false; 665 } 666 667 // This is needed to handle CTS DecoderTest testCodecResetsHEVCWithoutSurface, 668 // which is not sending SPS/PPS after port reconfiguration and flush to the codec. 669 if (unsupportedDimensions && !mFlushNeeded) { 670 bool portWillReset = false; 671 handlePortSettingsChange(&portWillReset, s_dec_op.u4_pic_wd, s_dec_op.u4_pic_ht); 672 673 CHECK_EQ(reInitDecoder(), (status_t)OK); 674 675 setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx); 676 677 ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op); 678 return; 679 } 680 681 // If the decoder is in the changing resolution mode and there is no output present, 682 // that means the switching is done and it's ready to reset the decoder and the plugin. 683 if (mChangingResolution && !s_dec_op.u4_output_present) { 684 mChangingResolution = false; 685 resetDecoder(); 686 resetPlugin(); 687 continue; 688 } 689 690 if (unsupportedDimensions || resChanged) { 691 mChangingResolution = true; 692 if (mFlushNeeded) { 693 setFlushMode(); 694 } 695 696 if (unsupportedDimensions) { 697 mNewWidth = s_dec_op.u4_pic_wd; 698 mNewHeight = s_dec_op.u4_pic_ht; 699 mInitNeeded = true; 700 } 701 continue; 702 } 703 704 if ((0 < s_dec_op.u4_pic_wd) && (0 < s_dec_op.u4_pic_ht)) { 705 uint32_t width = s_dec_op.u4_pic_wd; 706 uint32_t height = s_dec_op.u4_pic_ht; 707 bool portWillReset = false; 708 handlePortSettingsChange(&portWillReset, width, height); 709 710 if (portWillReset) { 711 resetDecoder(); 712 return; 713 } 714 } 715 716 if (s_dec_op.u4_output_present) { 717 outHeader->nFilledLen = (mWidth * mHeight * 3) / 2; 718 719 outHeader->nTimeStamp = mTimeStamps[s_dec_op.u4_ts]; 720 mTimeStampsValid[s_dec_op.u4_ts] = false; 721 722 outInfo->mOwnedByUs = false; 723 outQueue.erase(outQueue.begin()); 724 outInfo = NULL; 725 notifyFillBufferDone(outHeader); 726 outHeader = NULL; 727 } else { 728 /* If in flush mode and no output is returned by the codec, 729 * then come out of flush mode */ 730 mIsInFlush = false; 731 732 /* If EOS was recieved on input port and there is no output 733 * from the codec, then signal EOS on output port */ 734 if (mReceivedEOS) { 735 outHeader->nFilledLen = 0; 736 outHeader->nFlags |= OMX_BUFFERFLAG_EOS; 737 738 outInfo->mOwnedByUs = false; 739 outQueue.erase(outQueue.begin()); 740 outInfo = NULL; 741 notifyFillBufferDone(outHeader); 742 outHeader = NULL; 743 resetPlugin(); 744 } 745 } 746 } 747 748 // TODO: Handle more than one picture data 749 if (inHeader != NULL) { 750 inInfo->mOwnedByUs = false; 751 inQueue.erase(inQueue.begin()); 752 inInfo = NULL; 753 notifyEmptyBufferDone(inHeader); 754 inHeader = NULL; 755 } 756 } 757 } 758 759 } // namespace android 760 761 android::SoftOMXComponent *createSoftOMXComponent(const char *name, 762 const OMX_CALLBACKTYPE *callbacks, OMX_PTR appData, 763 OMX_COMPONENTTYPE **component) { 764 return new android::SoftHEVC(name, callbacks, appData, component); 765 } 766