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