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