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