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