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