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