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