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