SoftHEVC.cpp revision 3b5a6b9fa6c6825a1d0b441429e2bb365b259827
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 CODEC_MAX_WIDTH /* width */, CODEC_MAX_HEIGHT /* 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 107status_t SoftHEVC::getVersion() { 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 OK; 131} 132 133status_t SoftHEVC::setParams(WORD32 stride, IVD_VIDEO_DECODE_MODE_T decMode) { 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 = 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 = decMode; 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, IVD_DECODE_FRAME); 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 254 /* Initialize number of ref and reorder modes (for HEVC) */ 255 u4_num_reorder_frames = 16; 256 u4_num_ref_frames = 16; 257 u4_share_disp_buf = 0; 258 259 if ((mWidth * mHeight) > (1920 * 1088)) { 260 i4_level = 50; 261 } else if ((mWidth * mHeight) > (1280 * 720)) { 262 i4_level = 41; 263 } else { 264 i4_level = 31; 265 } 266 267 { 268 iv_num_mem_rec_ip_t s_num_mem_rec_ip; 269 iv_num_mem_rec_op_t s_num_mem_rec_op; 270 271 s_num_mem_rec_ip.u4_size = sizeof(s_num_mem_rec_ip); 272 s_num_mem_rec_op.u4_size = sizeof(s_num_mem_rec_op); 273 s_num_mem_rec_ip.e_cmd = IV_CMD_GET_NUM_MEM_REC; 274 275 ALOGV("Get number of mem records"); 276 status = ivdec_api_function(mCodecCtx, (void*)&s_num_mem_rec_ip, 277 (void*)&s_num_mem_rec_op); 278 if (IV_SUCCESS != status) { 279 ALOGE("Error in getting mem records: 0x%x", 280 s_num_mem_rec_op.u4_error_code); 281 return UNKNOWN_ERROR; 282 } 283 284 mNumMemRecords = s_num_mem_rec_op.u4_num_mem_rec; 285 } 286 287 mMemRecords = (iv_mem_rec_t*)ivd_aligned_malloc( 288 128, mNumMemRecords * sizeof(iv_mem_rec_t)); 289 if (mMemRecords == NULL) { 290 ALOGE("Allocation failure"); 291 return NO_MEMORY; 292 } 293 294 { 295 size_t i; 296 ivdext_fill_mem_rec_ip_t s_fill_mem_ip; 297 ivdext_fill_mem_rec_op_t s_fill_mem_op; 298 iv_mem_rec_t *ps_mem_rec; 299 300 s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_size = 301 sizeof(ivdext_fill_mem_rec_ip_t); 302 s_fill_mem_ip.i4_level = i4_level; 303 s_fill_mem_ip.u4_num_reorder_frames = u4_num_reorder_frames; 304 s_fill_mem_ip.u4_num_ref_frames = u4_num_ref_frames; 305 s_fill_mem_ip.u4_share_disp_buf = u4_share_disp_buf; 306 s_fill_mem_ip.u4_num_extra_disp_buf = 0; 307 s_fill_mem_ip.e_output_format = mIvColorFormat; 308 309 s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.e_cmd = IV_CMD_FILL_NUM_MEM_REC; 310 s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.pv_mem_rec_location = mMemRecords; 311 s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_wd = mWidth; 312 s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_ht = mHeight; 313 s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_size = 314 sizeof(ivdext_fill_mem_rec_op_t); 315 316 ps_mem_rec = mMemRecords; 317 for (i = 0; i < mNumMemRecords; i++) 318 ps_mem_rec[i].u4_size = sizeof(iv_mem_rec_t); 319 320 status = ivdec_api_function(mCodecCtx, (void *)&s_fill_mem_ip, 321 (void *)&s_fill_mem_op); 322 323 if (IV_SUCCESS != status) { 324 ALOGE("Error in filling mem records: 0x%x", 325 s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_error_code); 326 return UNKNOWN_ERROR; 327 } 328 mNumMemRecords = 329 s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_num_mem_rec_filled; 330 331 ps_mem_rec = mMemRecords; 332 333 for (i = 0; i < mNumMemRecords; i++) { 334 ps_mem_rec->pv_base = ivd_aligned_malloc( 335 ps_mem_rec->u4_mem_alignment, ps_mem_rec->u4_mem_size); 336 if (ps_mem_rec->pv_base == NULL) { 337 ALOGE("Allocation failure for memory record #%zu of size %u", 338 i, ps_mem_rec->u4_mem_size); 339 status = IV_FAIL; 340 return NO_MEMORY; 341 } 342 343 ps_mem_rec++; 344 } 345 } 346 347 /* Initialize the decoder */ 348 { 349 ivdext_init_ip_t s_init_ip; 350 ivdext_init_op_t s_init_op; 351 352 void *dec_fxns = (void *)ivdec_api_function; 353 354 s_init_ip.s_ivd_init_ip_t.u4_size = sizeof(ivdext_init_ip_t); 355 s_init_ip.s_ivd_init_ip_t.e_cmd = (IVD_API_COMMAND_TYPE_T)IV_CMD_INIT; 356 s_init_ip.s_ivd_init_ip_t.pv_mem_rec_location = mMemRecords; 357 s_init_ip.s_ivd_init_ip_t.u4_frm_max_wd = mWidth; 358 s_init_ip.s_ivd_init_ip_t.u4_frm_max_ht = mHeight; 359 360 s_init_ip.i4_level = i4_level; 361 s_init_ip.u4_num_reorder_frames = u4_num_reorder_frames; 362 s_init_ip.u4_num_ref_frames = u4_num_ref_frames; 363 s_init_ip.u4_share_disp_buf = u4_share_disp_buf; 364 s_init_ip.u4_num_extra_disp_buf = 0; 365 366 s_init_op.s_ivd_init_op_t.u4_size = sizeof(s_init_op); 367 368 s_init_ip.s_ivd_init_ip_t.u4_num_mem_rec = mNumMemRecords; 369 s_init_ip.s_ivd_init_ip_t.e_output_format = mIvColorFormat; 370 371 mCodecCtx = (iv_obj_t*)mMemRecords[0].pv_base; 372 mCodecCtx->pv_fxns = dec_fxns; 373 mCodecCtx->u4_size = sizeof(iv_obj_t); 374 375 ALOGD("Initializing decoder"); 376 status = ivdec_api_function(mCodecCtx, (void *)&s_init_ip, 377 (void *)&s_init_op); 378 if (status != IV_SUCCESS) { 379 ALOGE("Error in init: 0x%x", 380 s_init_op.s_ivd_init_op_t.u4_error_code); 381 return UNKNOWN_ERROR; 382 } 383 } 384 385 /* Reset the plugin state */ 386 resetPlugin(); 387 388 /* Set the run time (dynamic) parameters */ 389 setParams(0, IVD_DECODE_FRAME); 390 391 /* Set number of cores/threads to be used by the codec */ 392 setNumCores(); 393 394 /* Get codec version */ 395 getVersion(); 396 397 /* Allocate internal picture buffer */ 398 mFlushOutBuffer = (uint8_t *)ivd_aligned_malloc(128, mStride * mHeight * 3 / 2); 399 if (NULL == mFlushOutBuffer) { 400 ALOGE("Could not allocate flushOutputBuffer of size %zu", mStride * mHeight * 3 / 2); 401 return NO_MEMORY; 402 } 403 404 return OK; 405} 406 407status_t SoftHEVC::deInitDecoder() { 408 size_t i; 409 iv_mem_rec_t *ps_mem_rec; 410 ps_mem_rec = mMemRecords; 411 ALOGD("Freeing codec memory"); 412 for (i = 0; i < mNumMemRecords; i++) { 413 ivd_aligned_free(ps_mem_rec->pv_base); 414 ps_mem_rec++; 415 } 416 417 ivd_aligned_free(mMemRecords); 418 ivd_aligned_free(mFlushOutBuffer); 419 return OK; 420} 421 422void SoftHEVC::onReset() { 423 ALOGD("onReset called"); 424 SoftVideoDecoderOMXComponent::onReset(); 425 426 resetDecoder(); 427 resetPlugin(); 428} 429 430void SoftHEVC::onPortFlushCompleted(OMX_U32 portIndex) { 431 ALOGD("onPortFlushCompleted on port %d", portIndex); 432 433 /* Once the output buffers are flushed, ignore any buffers that are held in decoder */ 434 if (kOutputPortIndex == portIndex) { 435 setFlushMode(); 436 437 /* Reset the time stamp arrays */ 438 memset(mTimeStamps, 0, sizeof(mTimeStamps)); 439 memset(mTimeStampsValid, 0, sizeof(mTimeStampsValid)); 440 441 while (true) { 442 ivd_video_decode_ip_t s_dec_ip; 443 ivd_video_decode_op_t s_dec_op; 444 IV_API_CALL_STATUS_T status; 445 size_t sizeY, sizeUV; 446 447 s_dec_ip.e_cmd = IVD_CMD_VIDEO_DECODE; 448 449 s_dec_ip.u4_ts = 0; 450 s_dec_ip.pv_stream_buffer = NULL; 451 s_dec_ip.u4_num_Bytes = 0; 452 453 s_dec_ip.u4_size = sizeof(ivd_video_decode_ip_t); 454 s_dec_op.u4_size = sizeof(ivd_video_decode_op_t); 455 456 sizeY = mStride * mHeight; 457 sizeUV = sizeY / 4; 458 s_dec_ip.s_out_buffer.u4_min_out_buf_size[0] = sizeY; 459 s_dec_ip.s_out_buffer.u4_min_out_buf_size[1] = sizeUV; 460 s_dec_ip.s_out_buffer.u4_min_out_buf_size[2] = sizeUV; 461 462 s_dec_ip.s_out_buffer.pu1_bufs[0] = mFlushOutBuffer; 463 s_dec_ip.s_out_buffer.pu1_bufs[1] = 464 s_dec_ip.s_out_buffer.pu1_bufs[0] + sizeY; 465 s_dec_ip.s_out_buffer.pu1_bufs[2] = 466 s_dec_ip.s_out_buffer.pu1_bufs[1] + sizeUV; 467 s_dec_ip.s_out_buffer.u4_num_bufs = 3; 468 469 status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, 470 (void *)&s_dec_op); 471 if (0 == s_dec_op.u4_output_present) { 472 resetPlugin(); 473 break; 474 } 475 } 476 } 477} 478 479void SoftHEVC::onQueueFilled(OMX_U32 portIndex) { 480 IV_API_CALL_STATUS_T status; 481 482 UNUSED(portIndex); 483 484 if (mOutputPortSettingsChange != NONE) { 485 return; 486 } 487 488 List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex); 489 List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex); 490 491 /* If input EOS is seen and decoder is not in flush mode, 492 * set the decoder in flush mode. 493 * There can be a case where EOS is sent along with last picture data 494 * In that case, only after decoding that input data, decoder has to be 495 * put in flush. This case is handled here */ 496 497 if (mReceivedEOS && !mIsInFlush) { 498 setFlushMode(); 499 } 500 501 while (outQueue.size() == kNumBuffers) { 502 BufferInfo *inInfo; 503 OMX_BUFFERHEADERTYPE *inHeader; 504 505 BufferInfo *outInfo; 506 OMX_BUFFERHEADERTYPE *outHeader; 507 size_t timeStampIx; 508 509 inInfo = NULL; 510 inHeader = NULL; 511 512 if (!mIsInFlush) { 513 if (!inQueue.empty()) { 514 inInfo = *inQueue.begin(); 515 inHeader = inInfo->mHeader; 516 } else { 517 break; 518 } 519 } 520 521 outInfo = *outQueue.begin(); 522 outHeader = outInfo->mHeader; 523 outHeader->nFlags = 0; 524 outHeader->nTimeStamp = 0; 525 outHeader->nOffset = 0; 526 527 if (inHeader != NULL && (inHeader->nFlags & OMX_BUFFERFLAG_EOS)) { 528 ALOGD("EOS seen on input"); 529 mReceivedEOS = true; 530 if (inHeader->nFilledLen == 0) { 531 inQueue.erase(inQueue.begin()); 532 inInfo->mOwnedByUs = false; 533 notifyEmptyBufferDone(inHeader); 534 inHeader = NULL; 535 setFlushMode(); 536 } 537 } 538 539 /* Get a free slot in timestamp array to hold input timestamp */ 540 { 541 size_t i; 542 timeStampIx = 0; 543 for (i = 0; i < MAX_TIME_STAMPS; i++) { 544 if (!mTimeStampsValid[i]) { 545 timeStampIx = i; 546 break; 547 } 548 } 549 if (inHeader != NULL) { 550 mTimeStampsValid[timeStampIx] = true; 551 mTimeStamps[timeStampIx] = inHeader->nTimeStamp; 552 } 553 } 554 555 { 556 ivd_video_decode_ip_t s_dec_ip; 557 ivd_video_decode_op_t s_dec_op; 558 WORD32 timeDelay, timeTaken; 559 size_t sizeY, sizeUV; 560 561 s_dec_ip.e_cmd = IVD_CMD_VIDEO_DECODE; 562 563 /* When in flush and after EOS with zero byte input, 564 * inHeader is set to zero. Hence check for non-null */ 565 if (inHeader != NULL) { 566 s_dec_ip.u4_ts = timeStampIx; 567 s_dec_ip.pv_stream_buffer = inHeader->pBuffer 568 + inHeader->nOffset; 569 s_dec_ip.u4_num_Bytes = inHeader->nFilledLen; 570 } else { 571 s_dec_ip.u4_ts = 0; 572 s_dec_ip.pv_stream_buffer = NULL; 573 s_dec_ip.u4_num_Bytes = 0; 574 } 575 576 s_dec_ip.u4_size = sizeof(ivd_video_decode_ip_t); 577 s_dec_op.u4_size = sizeof(ivd_video_decode_op_t); 578 579 sizeY = mStride * mHeight; 580 sizeUV = sizeY / 4; 581 s_dec_ip.s_out_buffer.u4_min_out_buf_size[0] = sizeY; 582 s_dec_ip.s_out_buffer.u4_min_out_buf_size[1] = sizeUV; 583 s_dec_ip.s_out_buffer.u4_min_out_buf_size[2] = sizeUV; 584 585 s_dec_ip.s_out_buffer.pu1_bufs[0] = outHeader->pBuffer; 586 s_dec_ip.s_out_buffer.pu1_bufs[1] = 587 s_dec_ip.s_out_buffer.pu1_bufs[0] + sizeY; 588 s_dec_ip.s_out_buffer.pu1_bufs[2] = 589 s_dec_ip.s_out_buffer.pu1_bufs[1] + sizeUV; 590 s_dec_ip.s_out_buffer.u4_num_bufs = 3; 591 592 GETTIME(&mTimeStart, NULL); 593 /* Compute time elapsed between end of previous decode() 594 * to start of current decode() */ 595 TIME_DIFF(mTimeEnd, mTimeStart, timeDelay); 596 597 status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, 598 (void *)&s_dec_op); 599 600 GETTIME(&mTimeEnd, NULL); 601 /* Compute time taken for decode() */ 602 TIME_DIFF(mTimeStart, mTimeEnd, timeTaken); 603 604 ALOGD("timeTaken=%6d delay=%6d numBytes=%6d", timeTaken, timeDelay, 605 s_dec_op.u4_num_bytes_consumed); 606 607 if ((inHeader != NULL) && (1 != s_dec_op.u4_frame_decoded_flag)) { 608 /* If the input did not contain picture data, then ignore 609 * the associated timestamp */ 610 mTimeStampsValid[timeStampIx] = false; 611 } 612 613 /* If valid height and width are decoded, 614 * then look at change in resolution */ 615 if ((0 < s_dec_op.u4_pic_wd) && (0 < s_dec_op.u4_pic_ht)) { 616 uint32_t width = s_dec_op.u4_pic_wd; 617 uint32_t height = s_dec_op.u4_pic_ht; 618 619 if ((width != mWidth || height != mHeight)) { 620 mWidth = width; 621 mHeight = height; 622 mStride = mWidth; 623 624 /* If width and height are greater than the 625 * the dimensions used during codec create, then 626 * delete the current instance and recreate an instance with 627 * new dimensions */ 628 /* TODO: The following does not work currently, since the decoder 629 * currently returns 0 x 0 as width height when it is not supported 630 * Once the decoder is updated to return actual width and height, 631 * then this can be validated*/ 632 633 if ((mWidth * mHeight) > (mInitWidth * mInitHeight)) { 634 status_t ret; 635 ALOGD("Trying reInit"); 636 ret = deInitDecoder(); 637 if (OK != ret) { 638 // TODO: Handle graceful exit 639 ALOGE("Create failure"); 640 return; 641 } 642 643 mInitWidth = mWidth; 644 mInitHeight = mHeight; 645 646 ret = initDecoder(); 647 if (OK != ret) { 648 // TODO: Handle graceful exit 649 ALOGE("Create failure"); 650 return; 651 } 652 } 653 updatePortDefinitions(); 654 655 notify(OMX_EventPortSettingsChanged, 1, 0, NULL); 656 mOutputPortSettingsChange = AWAITING_DISABLED; 657 return; 658 } 659 } 660 661 if (s_dec_op.u4_output_present) { 662 outHeader->nFilledLen = (mStride * mHeight * 3) / 2; 663 664 outHeader->nTimeStamp = mTimeStamps[s_dec_op.u4_ts]; 665 mTimeStampsValid[s_dec_op.u4_ts] = false; 666 667 outInfo->mOwnedByUs = false; 668 outQueue.erase(outQueue.begin()); 669 outInfo = NULL; 670 notifyFillBufferDone(outHeader); 671 outHeader = NULL; 672 } else { 673 /* If in flush mode and no output is returned by the codec, 674 * then come out of flush mode */ 675 mIsInFlush = false; 676 677 /* If EOS was recieved on input port and there is no output 678 * from the codec, then signal EOS on output port */ 679 if (mReceivedEOS) { 680 outHeader->nFilledLen = 0; 681 outHeader->nFlags |= OMX_BUFFERFLAG_EOS; 682 683 outInfo->mOwnedByUs = false; 684 outQueue.erase(outQueue.begin()); 685 outInfo = NULL; 686 notifyFillBufferDone(outHeader); 687 outHeader = NULL; 688 resetPlugin(); 689 } 690 } 691 } 692 693 // TODO: Handle more than one picture data 694 if (inHeader != NULL) { 695 inInfo->mOwnedByUs = false; 696 inQueue.erase(inQueue.begin()); 697 inInfo = NULL; 698 notifyEmptyBufferDone(inHeader); 699 inHeader = NULL; 700 } 701 } 702} 703 704} // namespace android 705 706android::SoftOMXComponent *createSoftOMXComponent(const char *name, 707 const OMX_CALLBACKTYPE *callbacks, OMX_PTR appData, 708 OMX_COMPONENTTYPE **component) { 709 return new android::SoftHEVC(name, callbacks, appData, component); 710} 711