SoftHEVC.cpp revision 02fd609b7fd54c471ab1f5e77567d60c98e943d1
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_create_ip_t ihevcd_cxa_create_ip_t 41#define ivdext_create_op_t ihevcd_cxa_create_op_t 42#define ivdext_delete_ip_t ihevcd_cxa_delete_ip_t 43#define ivdext_delete_op_t ihevcd_cxa_delete_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 mCodecCtx(NULL), 72 mFlushOutBuffer(NULL), 73 mOmxColorFormat(OMX_COLOR_FormatYUV420Planar), 74 mIvColorFormat(IV_YUV_420P), 75 mChangingResolution(false), 76 mSignalledError(false), 77 mStride(mWidth) { 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 ALOGV("In SoftHEVC::~SoftHEVC"); 92 CHECK_EQ(deInitDecoder(), (status_t)OK); 93} 94 95static void *ivd_aligned_malloc(void *ctxt, WORD32 alignment, WORD32 size) { 96 UNUSED(ctxt); 97 return memalign(alignment, size); 98} 99 100static void ivd_aligned_free(void *ctxt, void *buf) { 101 UNUSED(ctxt); 102 free(buf); 103 return; 104} 105 106static size_t GetCPUCoreCount() { 107 long cpuCoreCount = 1; 108#if defined(_SC_NPROCESSORS_ONLN) 109 cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN); 110#else 111 // _SC_NPROC_ONLN must be defined... 112 cpuCoreCount = sysconf(_SC_NPROC_ONLN); 113#endif 114 CHECK(cpuCoreCount >= 1); 115 ALOGV("Number of CPU cores: %ld", cpuCoreCount); 116 return (size_t)cpuCoreCount; 117} 118 119void SoftHEVC::logVersion() { 120 ivd_ctl_getversioninfo_ip_t s_ctl_ip; 121 ivd_ctl_getversioninfo_op_t s_ctl_op; 122 UWORD8 au1_buf[512]; 123 IV_API_CALL_STATUS_T status; 124 125 s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL; 126 s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_GETVERSION; 127 s_ctl_ip.u4_size = sizeof(ivd_ctl_getversioninfo_ip_t); 128 s_ctl_op.u4_size = sizeof(ivd_ctl_getversioninfo_op_t); 129 s_ctl_ip.pv_version_buffer = au1_buf; 130 s_ctl_ip.u4_version_buffer_size = sizeof(au1_buf); 131 132 status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip, 133 (void *)&s_ctl_op); 134 135 if (status != IV_SUCCESS) { 136 ALOGE("Error in getting version number: 0x%x", 137 s_ctl_op.u4_error_code); 138 } else { 139 ALOGV("Ittiam decoder version number: %s", 140 (char *)s_ctl_ip.pv_version_buffer); 141 } 142 return; 143} 144 145status_t SoftHEVC::setParams(size_t stride) { 146 ivd_ctl_set_config_ip_t s_ctl_ip; 147 ivd_ctl_set_config_op_t s_ctl_op; 148 IV_API_CALL_STATUS_T status; 149 s_ctl_ip.u4_disp_wd = (UWORD32)stride; 150 s_ctl_ip.e_frm_skip_mode = IVD_SKIP_NONE; 151 152 s_ctl_ip.e_frm_out_mode = IVD_DISPLAY_FRAME_OUT; 153 s_ctl_ip.e_vid_dec_mode = IVD_DECODE_FRAME; 154 s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL; 155 s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_SETPARAMS; 156 s_ctl_ip.u4_size = sizeof(ivd_ctl_set_config_ip_t); 157 s_ctl_op.u4_size = sizeof(ivd_ctl_set_config_op_t); 158 159 ALOGV("Set the run-time (dynamic) parameters stride = %zu", stride); 160 status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip, 161 (void *)&s_ctl_op); 162 163 if (status != IV_SUCCESS) { 164 ALOGE("Error in setting the run-time parameters: 0x%x", 165 s_ctl_op.u4_error_code); 166 167 return UNKNOWN_ERROR; 168 } 169 return OK; 170} 171 172status_t SoftHEVC::resetPlugin() { 173 mIsInFlush = false; 174 mReceivedEOS = false; 175 memset(mTimeStamps, 0, sizeof(mTimeStamps)); 176 memset(mTimeStampsValid, 0, sizeof(mTimeStampsValid)); 177 178 /* Initialize both start and end times */ 179 gettimeofday(&mTimeStart, NULL); 180 gettimeofday(&mTimeEnd, NULL); 181 182 return OK; 183} 184 185status_t SoftHEVC::resetDecoder() { 186 ivd_ctl_reset_ip_t s_ctl_ip; 187 ivd_ctl_reset_op_t s_ctl_op; 188 IV_API_CALL_STATUS_T status; 189 190 s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL; 191 s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_RESET; 192 s_ctl_ip.u4_size = sizeof(ivd_ctl_reset_ip_t); 193 s_ctl_op.u4_size = sizeof(ivd_ctl_reset_op_t); 194 195 status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip, 196 (void *)&s_ctl_op); 197 if (IV_SUCCESS != status) { 198 ALOGE("Error in reset: 0x%x", s_ctl_op.u4_error_code); 199 return UNKNOWN_ERROR; 200 } 201 mSignalledError = false; 202 203 /* Set number of cores/threads to be used by the codec */ 204 setNumCores(); 205 206 mStride = 0; 207 return OK; 208} 209 210status_t SoftHEVC::setNumCores() { 211 ivdext_ctl_set_num_cores_ip_t s_set_cores_ip; 212 ivdext_ctl_set_num_cores_op_t s_set_cores_op; 213 IV_API_CALL_STATUS_T status; 214 s_set_cores_ip.e_cmd = IVD_CMD_VIDEO_CTL; 215 s_set_cores_ip.e_sub_cmd = IVDEXT_CMD_CTL_SET_NUM_CORES; 216 s_set_cores_ip.u4_num_cores = MIN(mNumCores, CODEC_MAX_NUM_CORES); 217 s_set_cores_ip.u4_size = sizeof(ivdext_ctl_set_num_cores_ip_t); 218 s_set_cores_op.u4_size = sizeof(ivdext_ctl_set_num_cores_op_t); 219 ALOGV("Set number of cores to %u", s_set_cores_ip.u4_num_cores); 220 status = ivdec_api_function(mCodecCtx, (void *)&s_set_cores_ip, 221 (void *)&s_set_cores_op); 222 if (IV_SUCCESS != status) { 223 ALOGE("Error in setting number of cores: 0x%x", 224 s_set_cores_op.u4_error_code); 225 return UNKNOWN_ERROR; 226 } 227 return OK; 228} 229 230status_t SoftHEVC::setFlushMode() { 231 IV_API_CALL_STATUS_T status; 232 ivd_ctl_flush_ip_t s_video_flush_ip; 233 ivd_ctl_flush_op_t s_video_flush_op; 234 235 s_video_flush_ip.e_cmd = IVD_CMD_VIDEO_CTL; 236 s_video_flush_ip.e_sub_cmd = IVD_CMD_CTL_FLUSH; 237 s_video_flush_ip.u4_size = sizeof(ivd_ctl_flush_ip_t); 238 s_video_flush_op.u4_size = sizeof(ivd_ctl_flush_op_t); 239 ALOGV("Set the decoder in flush mode "); 240 241 /* Set the decoder in Flush mode, subsequent decode() calls will flush */ 242 status = ivdec_api_function(mCodecCtx, (void *)&s_video_flush_ip, 243 (void *)&s_video_flush_op); 244 245 if (status != IV_SUCCESS) { 246 ALOGE("Error in setting the decoder in flush mode: (%d) 0x%x", status, 247 s_video_flush_op.u4_error_code); 248 return UNKNOWN_ERROR; 249 } 250 251 mIsInFlush = true; 252 return OK; 253} 254 255status_t SoftHEVC::initDecoder() { 256 IV_API_CALL_STATUS_T status; 257 258 mNumCores = GetCPUCoreCount(); 259 mCodecCtx = NULL; 260 261 mStride = outputBufferWidth(); 262 263 /* Initialize the decoder */ 264 { 265 ivdext_create_ip_t s_create_ip; 266 ivdext_create_op_t s_create_op; 267 268 void *dec_fxns = (void *)ivdec_api_function; 269 270 s_create_ip.s_ivd_create_ip_t.u4_size = sizeof(ivdext_create_ip_t); 271 s_create_ip.s_ivd_create_ip_t.e_cmd = IVD_CMD_CREATE; 272 s_create_ip.s_ivd_create_ip_t.u4_share_disp_buf = 0; 273 s_create_op.s_ivd_create_op_t.u4_size = sizeof(ivdext_create_op_t); 274 s_create_ip.s_ivd_create_ip_t.e_output_format = mIvColorFormat; 275 s_create_ip.s_ivd_create_ip_t.pf_aligned_alloc = ivd_aligned_malloc; 276 s_create_ip.s_ivd_create_ip_t.pf_aligned_free = ivd_aligned_free; 277 s_create_ip.s_ivd_create_ip_t.pv_mem_ctxt = NULL; 278 279 status = ivdec_api_function(mCodecCtx, (void *)&s_create_ip, (void *)&s_create_op); 280 281 mCodecCtx = (iv_obj_t*)s_create_op.s_ivd_create_op_t.pv_handle; 282 mCodecCtx->pv_fxns = dec_fxns; 283 mCodecCtx->u4_size = sizeof(iv_obj_t); 284 285 if (status != IV_SUCCESS) { 286 ALOGE("Error in create: 0x%x", 287 s_create_op.s_ivd_create_op_t.u4_error_code); 288 deInitDecoder(); 289 mCodecCtx = NULL; 290 return UNKNOWN_ERROR; 291 } 292 } 293 294 /* Reset the plugin state */ 295 resetPlugin(); 296 297 /* Set the run time (dynamic) parameters */ 298 setParams(mStride); 299 300 /* Set number of cores/threads to be used by the codec */ 301 setNumCores(); 302 303 /* Get codec version */ 304 logVersion(); 305 306 mFlushNeeded = false; 307 return OK; 308} 309 310status_t SoftHEVC::deInitDecoder() { 311 size_t i; 312 IV_API_CALL_STATUS_T status; 313 314 if (mCodecCtx) { 315 ivdext_delete_ip_t s_delete_ip; 316 ivdext_delete_op_t s_delete_op; 317 318 s_delete_ip.s_ivd_delete_ip_t.u4_size = sizeof(ivdext_delete_ip_t); 319 s_delete_ip.s_ivd_delete_ip_t.e_cmd = IVD_CMD_DELETE; 320 321 s_delete_op.s_ivd_delete_op_t.u4_size = sizeof(ivdext_delete_op_t); 322 323 status = ivdec_api_function(mCodecCtx, (void *)&s_delete_ip, (void *)&s_delete_op); 324 if (status != IV_SUCCESS) { 325 ALOGE("Error in delete: 0x%x", 326 s_delete_op.s_ivd_delete_op_t.u4_error_code); 327 return UNKNOWN_ERROR; 328 } 329 } 330 331 332 mChangingResolution = false; 333 334 return OK; 335} 336 337void SoftHEVC::onReset() { 338 ALOGV("onReset called"); 339 SoftVideoDecoderOMXComponent::onReset(); 340 341 mSignalledError = false; 342 resetDecoder(); 343 resetPlugin(); 344} 345 346bool SoftHEVC::setDecodeArgs(ivd_video_decode_ip_t *ps_dec_ip, 347 ivd_video_decode_op_t *ps_dec_op, 348 OMX_BUFFERHEADERTYPE *inHeader, 349 OMX_BUFFERHEADERTYPE *outHeader, 350 size_t timeStampIx) { 351 size_t sizeY = outputBufferWidth() * outputBufferHeight(); 352 size_t sizeUV; 353 354 ps_dec_ip->u4_size = sizeof(ivd_video_decode_ip_t); 355 ps_dec_op->u4_size = sizeof(ivd_video_decode_op_t); 356 357 ps_dec_ip->e_cmd = IVD_CMD_VIDEO_DECODE; 358 359 /* When in flush and after EOS with zero byte input, 360 * inHeader is set to zero. Hence check for non-null */ 361 if (inHeader) { 362 ps_dec_ip->u4_ts = timeStampIx; 363 ps_dec_ip->pv_stream_buffer = inHeader->pBuffer 364 + inHeader->nOffset; 365 ps_dec_ip->u4_num_Bytes = inHeader->nFilledLen; 366 } else { 367 ps_dec_ip->u4_ts = 0; 368 ps_dec_ip->pv_stream_buffer = NULL; 369 ps_dec_ip->u4_num_Bytes = 0; 370 } 371 372 sizeUV = sizeY / 4; 373 ps_dec_ip->s_out_buffer.u4_min_out_buf_size[0] = sizeY; 374 ps_dec_ip->s_out_buffer.u4_min_out_buf_size[1] = sizeUV; 375 ps_dec_ip->s_out_buffer.u4_min_out_buf_size[2] = sizeUV; 376 377 uint8_t *pBuf; 378 if (outHeader) { 379 if (outHeader->nAllocLen < sizeY + (sizeUV * 2)) { 380 android_errorWriteLog(0x534e4554, "27833616"); 381 return false; 382 } 383 pBuf = outHeader->pBuffer; 384 } else { 385 // mFlushOutBuffer always has the right size. 386 pBuf = mFlushOutBuffer; 387 } 388 389 ps_dec_ip->s_out_buffer.pu1_bufs[0] = pBuf; 390 ps_dec_ip->s_out_buffer.pu1_bufs[1] = pBuf + sizeY; 391 ps_dec_ip->s_out_buffer.pu1_bufs[2] = pBuf + sizeY + sizeUV; 392 ps_dec_ip->s_out_buffer.u4_num_bufs = 3; 393 return true; 394} 395void SoftHEVC::onPortFlushCompleted(OMX_U32 portIndex) { 396 /* Once the output buffers are flushed, ignore any buffers that are held in decoder */ 397 if (kOutputPortIndex == portIndex) { 398 setFlushMode(); 399 400 /* Allocate a picture buffer to flushed data */ 401 uint32_t displayStride = outputBufferWidth(); 402 uint32_t displayHeight = outputBufferHeight(); 403 404 uint32_t bufferSize = displayStride * displayHeight * 3 / 2; 405 mFlushOutBuffer = (uint8_t *)memalign(128, bufferSize); 406 if (NULL == mFlushOutBuffer) { 407 ALOGE("Could not allocate flushOutputBuffer of size %u", bufferSize); 408 return; 409 } 410 411 while (true) { 412 ivd_video_decode_ip_t s_dec_ip; 413 ivd_video_decode_op_t s_dec_op; 414 IV_API_CALL_STATUS_T status; 415 size_t sizeY, sizeUV; 416 417 setDecodeArgs(&s_dec_ip, &s_dec_op, NULL, NULL, 0); 418 419 status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, 420 (void *)&s_dec_op); 421 if (0 == s_dec_op.u4_output_present) { 422 resetPlugin(); 423 break; 424 } 425 } 426 427 if (mFlushOutBuffer) { 428 free(mFlushOutBuffer); 429 mFlushOutBuffer = NULL; 430 } 431 432 } 433} 434 435void SoftHEVC::onQueueFilled(OMX_U32 portIndex) { 436 UNUSED(portIndex); 437 438 if (mSignalledError) { 439 return; 440 } 441 if (mOutputPortSettingsChange != NONE) { 442 return; 443 } 444 445 if (NULL == mCodecCtx) { 446 if (OK != initDecoder()) { 447 return; 448 } 449 } 450 if (outputBufferWidth() != mStride) { 451 /* Set the run-time (dynamic) parameters */ 452 mStride = outputBufferWidth(); 453 setParams(mStride); 454 } 455 456 List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex); 457 List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex); 458 459 /* If input EOS is seen and decoder is not in flush mode, 460 * set the decoder in flush mode. 461 * There can be a case where EOS is sent along with last picture data 462 * In that case, only after decoding that input data, decoder has to be 463 * put in flush. This case is handled here */ 464 465 if (mReceivedEOS && !mIsInFlush) { 466 setFlushMode(); 467 } 468 469 while (!outQueue.empty()) { 470 BufferInfo *inInfo; 471 OMX_BUFFERHEADERTYPE *inHeader; 472 473 BufferInfo *outInfo; 474 OMX_BUFFERHEADERTYPE *outHeader; 475 size_t timeStampIx; 476 477 inInfo = NULL; 478 inHeader = NULL; 479 480 if (!mIsInFlush) { 481 if (!inQueue.empty()) { 482 inInfo = *inQueue.begin(); 483 inHeader = inInfo->mHeader; 484 } else { 485 break; 486 } 487 } 488 489 outInfo = *outQueue.begin(); 490 outHeader = outInfo->mHeader; 491 outHeader->nFlags = 0; 492 outHeader->nTimeStamp = 0; 493 outHeader->nOffset = 0; 494 495 if (inHeader != NULL && (inHeader->nFlags & OMX_BUFFERFLAG_EOS)) { 496 mReceivedEOS = true; 497 if (inHeader->nFilledLen == 0) { 498 inQueue.erase(inQueue.begin()); 499 inInfo->mOwnedByUs = false; 500 notifyEmptyBufferDone(inHeader); 501 inHeader = NULL; 502 setFlushMode(); 503 } 504 } 505 506 /* Get a free slot in timestamp array to hold input timestamp */ 507 { 508 size_t i; 509 timeStampIx = 0; 510 for (i = 0; i < MAX_TIME_STAMPS; i++) { 511 if (!mTimeStampsValid[i]) { 512 timeStampIx = i; 513 break; 514 } 515 } 516 if (inHeader != NULL) { 517 mTimeStampsValid[timeStampIx] = true; 518 mTimeStamps[timeStampIx] = inHeader->nTimeStamp; 519 } 520 } 521 522 { 523 ivd_video_decode_ip_t s_dec_ip; 524 ivd_video_decode_op_t s_dec_op; 525 WORD32 timeDelay, timeTaken; 526 size_t sizeY, sizeUV; 527 528 if (!setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx)) { 529 ALOGE("Decoder arg setup failed"); 530 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); 531 mSignalledError = true; 532 return; 533 } 534 535 GETTIME(&mTimeStart, NULL); 536 /* Compute time elapsed between end of previous decode() 537 * to start of current decode() */ 538 TIME_DIFF(mTimeEnd, mTimeStart, timeDelay); 539 540 IV_API_CALL_STATUS_T status; 541 status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op); 542 543 bool resChanged = (IVD_RES_CHANGED == (s_dec_op.u4_error_code & 0xFF)); 544 545 GETTIME(&mTimeEnd, NULL); 546 /* Compute time taken for decode() */ 547 TIME_DIFF(mTimeStart, mTimeEnd, timeTaken); 548 549 ALOGV("timeTaken=%6d delay=%6d numBytes=%6d", timeTaken, timeDelay, 550 s_dec_op.u4_num_bytes_consumed); 551 if (s_dec_op.u4_frame_decoded_flag && !mFlushNeeded) { 552 mFlushNeeded = true; 553 } 554 555 if ((inHeader != NULL) && (1 != s_dec_op.u4_frame_decoded_flag)) { 556 /* If the input did not contain picture data, then ignore 557 * the associated timestamp */ 558 mTimeStampsValid[timeStampIx] = false; 559 } 560 561 // If the decoder is in the changing resolution mode and there is no output present, 562 // that means the switching is done and it's ready to reset the decoder and the plugin. 563 if (mChangingResolution && !s_dec_op.u4_output_present) { 564 mChangingResolution = false; 565 resetDecoder(); 566 resetPlugin(); 567 mStride = outputBufferWidth(); 568 setParams(mStride); 569 continue; 570 } 571 572 if (resChanged) { 573 mChangingResolution = true; 574 if (mFlushNeeded) { 575 setFlushMode(); 576 } 577 continue; 578 } 579 580 if ((0 < s_dec_op.u4_pic_wd) && (0 < s_dec_op.u4_pic_ht)) { 581 uint32_t width = s_dec_op.u4_pic_wd; 582 uint32_t height = s_dec_op.u4_pic_ht; 583 bool portWillReset = false; 584 handlePortSettingsChange(&portWillReset, width, height); 585 586 if (portWillReset) { 587 resetDecoder(); 588 return; 589 } 590 } 591 592 if (s_dec_op.u4_output_present) { 593 outHeader->nFilledLen = (outputBufferWidth() * outputBufferHeight() * 3) / 2; 594 595 outHeader->nTimeStamp = mTimeStamps[s_dec_op.u4_ts]; 596 mTimeStampsValid[s_dec_op.u4_ts] = false; 597 598 outInfo->mOwnedByUs = false; 599 outQueue.erase(outQueue.begin()); 600 outInfo = NULL; 601 notifyFillBufferDone(outHeader); 602 outHeader = NULL; 603 } else { 604 /* If in flush mode and no output is returned by the codec, 605 * then come out of flush mode */ 606 mIsInFlush = false; 607 608 /* If EOS was recieved on input port and there is no output 609 * from the codec, then signal EOS on output port */ 610 if (mReceivedEOS) { 611 outHeader->nFilledLen = 0; 612 outHeader->nFlags |= OMX_BUFFERFLAG_EOS; 613 614 outInfo->mOwnedByUs = false; 615 outQueue.erase(outQueue.begin()); 616 outInfo = NULL; 617 notifyFillBufferDone(outHeader); 618 outHeader = NULL; 619 resetPlugin(); 620 } 621 } 622 } 623 624 // TODO: Handle more than one picture data 625 if (inHeader != NULL) { 626 inInfo->mOwnedByUs = false; 627 inQueue.erase(inQueue.begin()); 628 inInfo = NULL; 629 notifyEmptyBufferDone(inHeader); 630 inHeader = NULL; 631 } 632 } 633} 634 635} // namespace android 636 637android::SoftOMXComponent *createSoftOMXComponent(const char *name, 638 const OMX_CALLBACKTYPE *callbacks, OMX_PTR appData, 639 OMX_COMPONENTTYPE **component) { 640 android::SoftHEVC *codec = new android::SoftHEVC(name, callbacks, appData, component); 641 if (codec->init() != android::OK) { 642 android::sp<android::SoftOMXComponent> release = codec; 643 return NULL; 644 } 645 return codec; 646} 647