1/* 2 * Copyright (C) 2018 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 "C2SoftMpeg2Dec" 19#include <log/log.h> 20 21#include <media/stagefright/foundation/MediaDefs.h> 22 23#include <C2Debug.h> 24#include <C2PlatformSupport.h> 25#include <SimpleC2Interface.h> 26 27#include "C2SoftMpeg2Dec.h" 28#include "impeg2d.h" 29 30namespace android { 31 32constexpr char COMPONENT_NAME[] = "c2.android.mpeg2.decoder"; 33 34class C2SoftMpeg2Dec::IntfImpl : public SimpleInterface<void>::BaseParams { 35public: 36 explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper> &helper) 37 : SimpleInterface<void>::BaseParams( 38 helper, 39 COMPONENT_NAME, 40 C2Component::KIND_DECODER, 41 C2Component::DOMAIN_VIDEO, 42 MEDIA_MIMETYPE_VIDEO_MPEG2) { 43 noPrivateBuffers(); // TODO: account for our buffers here 44 noInputReferences(); 45 noOutputReferences(); 46 noInputLatency(); 47 noTimeStretch(); 48 49 // TODO: output latency and reordering 50 51 addParameter( 52 DefineParam(mAttrib, C2_PARAMKEY_COMPONENT_ATTRIBUTES) 53 .withConstValue(new C2ComponentAttributesSetting(C2Component::ATTRIB_IS_TEMPORAL)) 54 .build()); 55 56 addParameter( 57 DefineParam(mSize, C2_PARAMKEY_PICTURE_SIZE) 58 .withDefault(new C2StreamPictureSizeInfo::output(0u, 320, 240)) 59 .withFields({ 60 C2F(mSize, width).inRange(16, 1920, 4), 61 C2F(mSize, height).inRange(16, 1088, 4), 62 }) 63 .withSetter(SizeSetter) 64 .build()); 65 66 addParameter( 67 DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL) 68 .withDefault(new C2StreamProfileLevelInfo::input(0u, 69 C2Config::PROFILE_MP2V_SIMPLE, C2Config::LEVEL_MP2V_HIGH)) 70 .withFields({ 71 C2F(mProfileLevel, profile).oneOf({ 72 C2Config::PROFILE_MP2V_SIMPLE, 73 C2Config::PROFILE_MP2V_MAIN}), 74 C2F(mProfileLevel, level).oneOf({ 75 C2Config::LEVEL_MP2V_LOW, 76 C2Config::LEVEL_MP2V_MAIN, 77 C2Config::LEVEL_MP2V_HIGH_1440, 78 C2Config::LEVEL_MP2V_HIGH}) 79 }) 80 .withSetter(ProfileLevelSetter, mSize) 81 .build()); 82 83 C2ChromaOffsetStruct locations[1] = { C2ChromaOffsetStruct::ITU_YUV_420_0() }; 84 std::shared_ptr<C2StreamColorInfo::output> defaultColorInfo = 85 C2StreamColorInfo::output::AllocShared( 86 1u, 0u, 8u /* bitDepth */, C2Color::YUV_420); 87 memcpy(defaultColorInfo->m.locations, locations, sizeof(locations)); 88 89 defaultColorInfo = 90 C2StreamColorInfo::output::AllocShared( 91 { C2ChromaOffsetStruct::ITU_YUV_420_0() }, 92 0u, 8u /* bitDepth */, C2Color::YUV_420); 93 helper->addStructDescriptors<C2ChromaOffsetStruct>(); 94 95 addParameter( 96 DefineParam(mColorInfo, C2_PARAMKEY_CODED_COLOR_INFO) 97 .withConstValue(defaultColorInfo) 98 .build()); 99 100 addParameter( 101 DefineParam(mDefaultColorAspects, C2_PARAMKEY_DEFAULT_COLOR_ASPECTS) 102 .withDefault(new C2StreamColorAspectsTuning::input( 103 0u, C2Color::RANGE_UNSPECIFIED, C2Color::PRIMARIES_UNSPECIFIED, 104 C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED)) 105 .withFields({ 106 C2F(mDefaultColorAspects, range).inRange( 107 C2Color::RANGE_UNSPECIFIED, C2Color::RANGE_OTHER), 108 C2F(mDefaultColorAspects, primaries).inRange( 109 C2Color::PRIMARIES_UNSPECIFIED, C2Color::PRIMARIES_OTHER), 110 C2F(mDefaultColorAspects, transfer).inRange( 111 C2Color::TRANSFER_UNSPECIFIED, C2Color::TRANSFER_OTHER), 112 C2F(mDefaultColorAspects, matrix).inRange( 113 C2Color::MATRIX_UNSPECIFIED, C2Color::MATRIX_OTHER) 114 }) 115 .withSetter(DefaultColorAspectsSetter) 116 .build()); 117 118 addParameter( 119 DefineParam(mCodedColorAspects, C2_PARAMKEY_DEFAULT_COLOR_ASPECTS) 120 .withDefault(new C2StreamColorAspectsInfo::input( 121 0u, C2Color::RANGE_UNSPECIFIED, C2Color::PRIMARIES_UNSPECIFIED, 122 C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED)) 123 .withFields({ 124 C2F(mCodedColorAspects, range).inRange( 125 C2Color::RANGE_UNSPECIFIED, C2Color::RANGE_OTHER), 126 C2F(mCodedColorAspects, primaries).inRange( 127 C2Color::PRIMARIES_UNSPECIFIED, C2Color::PRIMARIES_OTHER), 128 C2F(mCodedColorAspects, transfer).inRange( 129 C2Color::TRANSFER_UNSPECIFIED, C2Color::TRANSFER_OTHER), 130 C2F(mCodedColorAspects, matrix).inRange( 131 C2Color::MATRIX_UNSPECIFIED, C2Color::MATRIX_OTHER) 132 }) 133 .withSetter(CodedColorAspectsSetter) 134 .build()); 135 136 addParameter( 137 DefineParam(mColorAspects, C2_PARAMKEY_COLOR_ASPECTS) 138 .withDefault(new C2StreamColorAspectsInfo::output( 139 0u, C2Color::RANGE_UNSPECIFIED, C2Color::PRIMARIES_UNSPECIFIED, 140 C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED)) 141 .withFields({ 142 C2F(mColorAspects, range).inRange( 143 C2Color::RANGE_UNSPECIFIED, C2Color::RANGE_OTHER), 144 C2F(mColorAspects, primaries).inRange( 145 C2Color::PRIMARIES_UNSPECIFIED, C2Color::PRIMARIES_OTHER), 146 C2F(mColorAspects, transfer).inRange( 147 C2Color::TRANSFER_UNSPECIFIED, C2Color::TRANSFER_OTHER), 148 C2F(mColorAspects, matrix).inRange( 149 C2Color::MATRIX_UNSPECIFIED, C2Color::MATRIX_OTHER) 150 }) 151 .withSetter(ColorAspectsSetter, mDefaultColorAspects, mCodedColorAspects) 152 .build()); 153 154 // TODO: support more formats? 155 addParameter( 156 DefineParam(mPixelFormat, C2_PARAMKEY_PIXEL_FORMAT) 157 .withConstValue(new C2StreamPixelFormatInfo::output( 158 0u, HAL_PIXEL_FORMAT_YCBCR_420_888)) 159 .build()); 160 } 161 162 static C2R SizeSetter(bool mayBlock, const C2P<C2VideoSizeStreamInfo::output> &oldMe, 163 C2P<C2VideoSizeStreamInfo::output> &me) { 164 (void)mayBlock; 165 C2R res = C2R::Ok(); 166 if (!me.F(me.v.width).supportsAtAll(me.v.width)) { 167 res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.width))); 168 me.set().width = oldMe.v.width; 169 } 170 if (!me.F(me.v.height).supportsAtAll(me.v.height)) { 171 res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.height))); 172 me.set().height = oldMe.v.height; 173 } 174 return res; 175 } 176 177 static C2R ProfileLevelSetter(bool mayBlock, C2P<C2StreamProfileLevelInfo::input> &me, 178 const C2P<C2StreamPictureSizeInfo::output> &size) { 179 (void)mayBlock; 180 (void)size; 181 (void)me; // TODO: validate 182 return C2R::Ok(); 183 } 184 185 static C2R DefaultColorAspectsSetter(bool mayBlock, C2P<C2StreamColorAspectsTuning::input> &me) { 186 (void)mayBlock; 187 (void)me; 188 // take all values 189 return C2R::Ok(); 190 } 191 192 static C2R CodedColorAspectsSetter(bool mayBlock, C2P<C2StreamColorAspectsInfo::input> &me) { 193 (void)mayBlock; 194 (void)me; 195 // take all values 196 return C2R::Ok(); 197 } 198 199 static C2R ColorAspectsSetter(bool mayBlock, C2P<C2StreamColorAspectsInfo::output> &me, 200 const C2P<C2StreamColorAspectsTuning::input> &def, 201 const C2P<C2StreamColorAspectsInfo::input> &coded) { 202 (void)mayBlock; 203 // take default values for all unspecified fields, and coded values for specified ones 204 me.set().range = coded.v.range == RANGE_UNSPECIFIED ? def.v.range : coded.v.range; 205 me.set().primaries = coded.v.primaries == PRIMARIES_UNSPECIFIED ? def.v.primaries : coded.v.primaries; 206 me.set().transfer = coded.v.transfer == TRANSFER_UNSPECIFIED ? def.v.transfer : coded.v.transfer; 207 me.set().matrix = coded.v.matrix == MATRIX_UNSPECIFIED ? def.v.matrix : coded.v.matrix; 208 // TODO: validate 209 return C2R::Ok(); 210 } 211 212private: 213 std::shared_ptr<C2StreamProfileLevelInfo::input> mProfileLevel; 214 std::shared_ptr<C2VideoSizeStreamInfo::output> mSize; 215 std::shared_ptr<C2StreamColorInfo::output> mColorInfo; 216 std::shared_ptr<C2StreamColorAspectsTuning::input> mDefaultColorAspects; 217 std::shared_ptr<C2StreamColorAspectsInfo::input> mCodedColorAspects; 218 std::shared_ptr<C2StreamColorAspectsInfo::output> mColorAspects; 219 std::shared_ptr<C2StreamPixelFormatInfo::output> mPixelFormat; 220}; 221 222static size_t getCpuCoreCount() { 223 long cpuCoreCount = 1; 224#if defined(_SC_NPROCESSORS_ONLN) 225 cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN); 226#else 227 // _SC_NPROC_ONLN must be defined... 228 cpuCoreCount = sysconf(_SC_NPROC_ONLN); 229#endif 230 CHECK(cpuCoreCount >= 1); 231 ALOGV("Number of CPU cores: %ld", cpuCoreCount); 232 return (size_t)cpuCoreCount; 233} 234 235static void *ivd_aligned_malloc(WORD32 alignment, WORD32 size) { 236 return memalign(alignment, size); 237} 238 239static void ivd_aligned_free(void *mem) { 240 free(mem); 241} 242 243C2SoftMpeg2Dec::C2SoftMpeg2Dec( 244 const char *name, 245 c2_node_id_t id, 246 const std::shared_ptr<IntfImpl> &intfImpl) 247 : SimpleC2Component(std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)), 248 mIntf(intfImpl), 249 mDecHandle(nullptr), 250 mMemRecords(nullptr), 251 mOutBufferDrain(nullptr), 252 mIvColorformat(IV_YUV_420P), 253 mWidth(320), 254 mHeight(240) { 255 // If input dump is enabled, then open create an empty file 256 GENERATE_FILE_NAMES(); 257 CREATE_DUMP_FILE(mInFile); 258} 259 260C2SoftMpeg2Dec::~C2SoftMpeg2Dec() { 261 onRelease(); 262} 263 264c2_status_t C2SoftMpeg2Dec::onInit() { 265 status_t err = initDecoder(); 266 return err == OK ? C2_OK : C2_CORRUPTED; 267} 268 269c2_status_t C2SoftMpeg2Dec::onStop() { 270 if (OK != resetDecoder()) return C2_CORRUPTED; 271 resetPlugin(); 272 return C2_OK; 273} 274 275void C2SoftMpeg2Dec::onReset() { 276 (void) onStop(); 277} 278 279void C2SoftMpeg2Dec::onRelease() { 280 (void) deleteDecoder(); 281 if (mOutBufferDrain) { 282 ivd_aligned_free(mOutBufferDrain); 283 mOutBufferDrain = nullptr; 284 } 285 if (mOutBlock) { 286 mOutBlock.reset(); 287 } 288 if (mMemRecords) { 289 ivd_aligned_free(mMemRecords); 290 mMemRecords = nullptr; 291 } 292} 293 294c2_status_t C2SoftMpeg2Dec::onFlush_sm() { 295 if (OK != setFlushMode()) return C2_CORRUPTED; 296 297 uint32_t displayStride = mStride; 298 uint32_t displayHeight = mHeight; 299 uint32_t bufferSize = displayStride * displayHeight * 3 / 2; 300 mOutBufferDrain = (uint8_t *)ivd_aligned_malloc(128, bufferSize); 301 if (!mOutBufferDrain) { 302 ALOGE("could not allocate tmp output buffer (for flush) of size %u ", bufferSize); 303 return C2_NO_MEMORY; 304 } 305 306 while (true) { 307 ivd_video_decode_ip_t s_decode_ip; 308 ivd_video_decode_op_t s_decode_op; 309 310 setDecodeArgs(&s_decode_ip, &s_decode_op, nullptr, nullptr, 0, 0, 0); 311 (void) ivdec_api_function(mDecHandle, &s_decode_ip, &s_decode_op); 312 if (0 == s_decode_op.u4_output_present) { 313 resetPlugin(); 314 break; 315 } 316 } 317 318 ivd_aligned_free(mOutBufferDrain); 319 mOutBufferDrain = nullptr; 320 321 return C2_OK; 322} 323 324status_t C2SoftMpeg2Dec::getNumMemRecords() { 325 iv_num_mem_rec_ip_t s_num_mem_rec_ip; 326 iv_num_mem_rec_op_t s_num_mem_rec_op; 327 328 s_num_mem_rec_ip.u4_size = sizeof(s_num_mem_rec_ip); 329 s_num_mem_rec_ip.e_cmd = IV_CMD_GET_NUM_MEM_REC; 330 s_num_mem_rec_op.u4_size = sizeof(s_num_mem_rec_op); 331 332 IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle, 333 &s_num_mem_rec_ip, 334 &s_num_mem_rec_op); 335 if (IV_SUCCESS != status) { 336 ALOGE("Error in getting mem records: 0x%x", s_num_mem_rec_op.u4_error_code); 337 return UNKNOWN_ERROR; 338 } 339 mNumMemRecords = s_num_mem_rec_op.u4_num_mem_rec; 340 341 return OK; 342} 343 344status_t C2SoftMpeg2Dec::fillMemRecords() { 345 iv_mem_rec_t *ps_mem_rec = (iv_mem_rec_t *) ivd_aligned_malloc( 346 128, mNumMemRecords * sizeof(iv_mem_rec_t)); 347 if (!ps_mem_rec) { 348 ALOGE("Allocation failure"); 349 return NO_MEMORY; 350 } 351 memset(ps_mem_rec, 0, mNumMemRecords * sizeof(iv_mem_rec_t)); 352 for (size_t i = 0; i < mNumMemRecords; i++) 353 ps_mem_rec[i].u4_size = sizeof(iv_mem_rec_t); 354 mMemRecords = ps_mem_rec; 355 356 ivdext_fill_mem_rec_ip_t s_fill_mem_ip; 357 ivdext_fill_mem_rec_op_t s_fill_mem_op; 358 359 s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_size = sizeof(ivdext_fill_mem_rec_ip_t); 360 s_fill_mem_ip.u4_share_disp_buf = 0; 361 s_fill_mem_ip.e_output_format = mIvColorformat; 362 s_fill_mem_ip.u4_deinterlace = 1; 363 s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.e_cmd = IV_CMD_FILL_NUM_MEM_REC; 364 s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.pv_mem_rec_location = mMemRecords; 365 s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_wd = mWidth; 366 s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_ht = mHeight; 367 s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_size = sizeof(ivdext_fill_mem_rec_op_t); 368 IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle, 369 &s_fill_mem_ip, 370 &s_fill_mem_op); 371 if (IV_SUCCESS != status) { 372 ALOGE("Error in filling mem records: 0x%x", 373 s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_error_code); 374 return UNKNOWN_ERROR; 375 } 376 377 CHECK_EQ(mNumMemRecords, s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_num_mem_rec_filled); 378 for (size_t i = 0; i < mNumMemRecords; i++, ps_mem_rec++) { 379 ps_mem_rec->pv_base = ivd_aligned_malloc( 380 ps_mem_rec->u4_mem_alignment, ps_mem_rec->u4_mem_size); 381 if (!ps_mem_rec->pv_base) { 382 ALOGE("Allocation failure for memory record #%zu of size %u", 383 i, ps_mem_rec->u4_mem_size); 384 return NO_MEMORY; 385 } 386 } 387 388 return OK; 389} 390 391status_t C2SoftMpeg2Dec::createDecoder() { 392 ivdext_init_ip_t s_init_ip; 393 ivdext_init_op_t s_init_op; 394 395 s_init_ip.s_ivd_init_ip_t.u4_size = sizeof(ivdext_init_ip_t); 396 s_init_ip.s_ivd_init_ip_t.e_cmd = (IVD_API_COMMAND_TYPE_T)IV_CMD_INIT; 397 s_init_ip.s_ivd_init_ip_t.pv_mem_rec_location = mMemRecords; 398 s_init_ip.s_ivd_init_ip_t.u4_frm_max_wd = mWidth; 399 s_init_ip.s_ivd_init_ip_t.u4_frm_max_ht = mHeight; 400 s_init_ip.u4_share_disp_buf = 0; 401 s_init_ip.u4_deinterlace = 1; 402 s_init_ip.s_ivd_init_ip_t.u4_num_mem_rec = mNumMemRecords; 403 s_init_ip.s_ivd_init_ip_t.e_output_format = mIvColorformat; 404 s_init_op.s_ivd_init_op_t.u4_size = sizeof(ivdext_init_op_t); 405 406 mDecHandle = (iv_obj_t *)mMemRecords[0].pv_base; 407 mDecHandle->pv_fxns = (void *)ivdec_api_function; 408 mDecHandle->u4_size = sizeof(iv_obj_t); 409 410 IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle, 411 &s_init_ip, 412 &s_init_op); 413 if (status != IV_SUCCESS) { 414 ALOGE("error in %s: 0x%x", __func__, 415 s_init_op.s_ivd_init_op_t.u4_error_code); 416 return UNKNOWN_ERROR; 417 } 418 419 return OK; 420} 421 422status_t C2SoftMpeg2Dec::setNumCores() { 423 ivdext_ctl_set_num_cores_ip_t s_set_num_cores_ip; 424 ivdext_ctl_set_num_cores_op_t s_set_num_cores_op; 425 426 s_set_num_cores_ip.u4_size = sizeof(ivdext_ctl_set_num_cores_ip_t); 427 s_set_num_cores_ip.e_cmd = IVD_CMD_VIDEO_CTL; 428 s_set_num_cores_ip.e_sub_cmd = IVDEXT_CMD_CTL_SET_NUM_CORES; 429 s_set_num_cores_ip.u4_num_cores = mNumCores; 430 s_set_num_cores_op.u4_size = sizeof(ivdext_ctl_set_num_cores_op_t); 431 IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle, 432 &s_set_num_cores_ip, 433 &s_set_num_cores_op); 434 if (status != IV_SUCCESS) { 435 ALOGD("error in %s: 0x%x", __func__, s_set_num_cores_op.u4_error_code); 436 return UNKNOWN_ERROR; 437 } 438 439 return OK; 440} 441 442status_t C2SoftMpeg2Dec::setParams(size_t stride) { 443 ivd_ctl_set_config_ip_t s_set_dyn_params_ip; 444 ivd_ctl_set_config_op_t s_set_dyn_params_op; 445 446 s_set_dyn_params_ip.u4_size = sizeof(ivd_ctl_set_config_ip_t); 447 s_set_dyn_params_ip.e_cmd = IVD_CMD_VIDEO_CTL; 448 s_set_dyn_params_ip.e_sub_cmd = IVD_CMD_CTL_SETPARAMS; 449 s_set_dyn_params_ip.u4_disp_wd = (UWORD32) stride; 450 s_set_dyn_params_ip.e_frm_skip_mode = IVD_SKIP_NONE; 451 s_set_dyn_params_ip.e_frm_out_mode = IVD_DISPLAY_FRAME_OUT; 452 s_set_dyn_params_ip.e_vid_dec_mode = IVD_DECODE_FRAME; 453 s_set_dyn_params_op.u4_size = sizeof(ivd_ctl_set_config_op_t); 454 IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle, 455 &s_set_dyn_params_ip, 456 &s_set_dyn_params_op); 457 if (status != IV_SUCCESS) { 458 ALOGE("error in %s: 0x%x", __func__, s_set_dyn_params_op.u4_error_code); 459 return UNKNOWN_ERROR; 460 } 461 462 return OK; 463} 464 465status_t C2SoftMpeg2Dec::getVersion() { 466 ivd_ctl_getversioninfo_ip_t s_get_versioninfo_ip; 467 ivd_ctl_getversioninfo_op_t s_get_versioninfo_op; 468 UWORD8 au1_buf[512]; 469 470 s_get_versioninfo_ip.u4_size = sizeof(ivd_ctl_getversioninfo_ip_t); 471 s_get_versioninfo_ip.e_cmd = IVD_CMD_VIDEO_CTL; 472 s_get_versioninfo_ip.e_sub_cmd = IVD_CMD_CTL_GETVERSION; 473 s_get_versioninfo_ip.pv_version_buffer = au1_buf; 474 s_get_versioninfo_ip.u4_version_buffer_size = sizeof(au1_buf); 475 s_get_versioninfo_op.u4_size = sizeof(ivd_ctl_getversioninfo_op_t); 476 IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle, 477 &s_get_versioninfo_ip, 478 &s_get_versioninfo_op); 479 if (status != IV_SUCCESS) { 480 ALOGD("error in %s: 0x%x", __func__, 481 s_get_versioninfo_op.u4_error_code); 482 } else { 483 ALOGV("ittiam decoder version number: %s", 484 (char *) s_get_versioninfo_ip.pv_version_buffer); 485 } 486 487 return OK; 488} 489 490status_t C2SoftMpeg2Dec::initDecoder() { 491 status_t ret = getNumMemRecords(); 492 if (OK != ret) return ret; 493 494 ret = fillMemRecords(); 495 if (OK != ret) return ret; 496 497 if (OK != createDecoder()) return UNKNOWN_ERROR; 498 499 mNumCores = MIN(getCpuCoreCount(), MAX_NUM_CORES); 500 mStride = ALIGN64(mWidth); 501 mSignalledError = false; 502 mPreference = kPreferBitstream; 503 memset(&mDefaultColorAspects, 0, sizeof(ColorAspects)); 504 memset(&mBitstreamColorAspects, 0, sizeof(ColorAspects)); 505 memset(&mFinalColorAspects, 0, sizeof(ColorAspects)); 506 mUpdateColorAspects = false; 507 resetPlugin(); 508 (void) setNumCores(); 509 if (OK != setParams(mStride)) return UNKNOWN_ERROR; 510 (void) getVersion(); 511 512 return OK; 513} 514 515bool C2SoftMpeg2Dec::setDecodeArgs(ivd_video_decode_ip_t *ps_decode_ip, 516 ivd_video_decode_op_t *ps_decode_op, 517 C2ReadView *inBuffer, 518 C2GraphicView *outBuffer, 519 size_t inOffset, 520 size_t inSize, 521 uint32_t tsMarker) { 522 uint32_t displayStride = mStride; 523 uint32_t displayHeight = mHeight; 524 size_t lumaSize = displayStride * displayHeight; 525 size_t chromaSize = lumaSize >> 2; 526 527 ps_decode_ip->u4_size = sizeof(ivd_video_decode_ip_t); 528 ps_decode_ip->e_cmd = IVD_CMD_VIDEO_DECODE; 529 if (inBuffer) { 530 ps_decode_ip->u4_ts = tsMarker; 531 ps_decode_ip->pv_stream_buffer = const_cast<uint8_t *>(inBuffer->data() + inOffset); 532 ps_decode_ip->u4_num_Bytes = inSize; 533 } else { 534 ps_decode_ip->u4_ts = 0; 535 ps_decode_ip->pv_stream_buffer = nullptr; 536 ps_decode_ip->u4_num_Bytes = 0; 537 } 538 ps_decode_ip->s_out_buffer.u4_min_out_buf_size[0] = lumaSize; 539 ps_decode_ip->s_out_buffer.u4_min_out_buf_size[1] = chromaSize; 540 ps_decode_ip->s_out_buffer.u4_min_out_buf_size[2] = chromaSize; 541 if (outBuffer) { 542 if (outBuffer->width() < displayStride || outBuffer->height() < displayHeight) { 543 ALOGE("Output buffer too small: provided (%dx%d) required (%ux%u)", 544 outBuffer->width(), outBuffer->height(), displayStride, displayHeight); 545 return false; 546 } 547 ps_decode_ip->s_out_buffer.pu1_bufs[0] = outBuffer->data()[C2PlanarLayout::PLANE_Y]; 548 ps_decode_ip->s_out_buffer.pu1_bufs[1] = outBuffer->data()[C2PlanarLayout::PLANE_U]; 549 ps_decode_ip->s_out_buffer.pu1_bufs[2] = outBuffer->data()[C2PlanarLayout::PLANE_V]; 550 } else { 551 ps_decode_ip->s_out_buffer.pu1_bufs[0] = mOutBufferDrain; 552 ps_decode_ip->s_out_buffer.pu1_bufs[1] = mOutBufferDrain + lumaSize; 553 ps_decode_ip->s_out_buffer.pu1_bufs[2] = mOutBufferDrain + lumaSize + chromaSize; 554 } 555 ps_decode_ip->s_out_buffer.u4_num_bufs = 3; 556 ps_decode_op->u4_size = sizeof(ivd_video_decode_op_t); 557 558 return true; 559} 560 561bool C2SoftMpeg2Dec::colorAspectsDiffer( 562 const ColorAspects &a, const ColorAspects &b) { 563 if (a.mRange != b.mRange 564 || a.mPrimaries != b.mPrimaries 565 || a.mTransfer != b.mTransfer 566 || a.mMatrixCoeffs != b.mMatrixCoeffs) { 567 return true; 568 } 569 return false; 570} 571 572void C2SoftMpeg2Dec::updateFinalColorAspects( 573 const ColorAspects &otherAspects, const ColorAspects &preferredAspects) { 574 Mutex::Autolock autoLock(mColorAspectsLock); 575 ColorAspects newAspects; 576 newAspects.mRange = preferredAspects.mRange != ColorAspects::RangeUnspecified ? 577 preferredAspects.mRange : otherAspects.mRange; 578 newAspects.mPrimaries = preferredAspects.mPrimaries != ColorAspects::PrimariesUnspecified ? 579 preferredAspects.mPrimaries : otherAspects.mPrimaries; 580 newAspects.mTransfer = preferredAspects.mTransfer != ColorAspects::TransferUnspecified ? 581 preferredAspects.mTransfer : otherAspects.mTransfer; 582 newAspects.mMatrixCoeffs = preferredAspects.mMatrixCoeffs != ColorAspects::MatrixUnspecified ? 583 preferredAspects.mMatrixCoeffs : otherAspects.mMatrixCoeffs; 584 585 // Check to see if need update mFinalColorAspects. 586 if (colorAspectsDiffer(mFinalColorAspects, newAspects)) { 587 mFinalColorAspects = newAspects; 588 mUpdateColorAspects = true; 589 } 590} 591 592status_t C2SoftMpeg2Dec::handleColorAspectsChange() { 593 if (mPreference == kPreferBitstream) { 594 updateFinalColorAspects(mDefaultColorAspects, mBitstreamColorAspects); 595 } else if (mPreference == kPreferContainer) { 596 updateFinalColorAspects(mBitstreamColorAspects, mDefaultColorAspects); 597 } else { 598 return C2_CORRUPTED; 599 } 600 return C2_OK; 601} 602 603bool C2SoftMpeg2Dec::getSeqInfo() { 604 ivdext_ctl_get_seq_info_ip_t s_ctl_get_seq_info_ip; 605 ivdext_ctl_get_seq_info_op_t s_ctl_get_seq_info_op; 606 607 s_ctl_get_seq_info_ip.u4_size = sizeof(ivdext_ctl_get_seq_info_ip_t); 608 s_ctl_get_seq_info_ip.e_cmd = IVD_CMD_VIDEO_CTL; 609 s_ctl_get_seq_info_ip.e_sub_cmd = 610 (IVD_CONTROL_API_COMMAND_TYPE_T)IMPEG2D_CMD_CTL_GET_SEQ_INFO; 611 s_ctl_get_seq_info_op.u4_size = sizeof(ivdext_ctl_get_seq_info_op_t); 612 IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle, 613 &s_ctl_get_seq_info_ip, 614 &s_ctl_get_seq_info_op); 615 if (status != IV_SUCCESS) { 616 ALOGW("Error in getting Sequence info: 0x%x", s_ctl_get_seq_info_op.u4_error_code); 617 return false; 618 } 619 620 int32_t primaries = s_ctl_get_seq_info_op.u1_colour_primaries; 621 int32_t transfer = s_ctl_get_seq_info_op.u1_transfer_characteristics; 622 int32_t coeffs = s_ctl_get_seq_info_op.u1_matrix_coefficients; 623 bool full_range = false; // mpeg2 video has limited range. 624 625 ColorAspects colorAspects; 626 ColorUtils::convertIsoColorAspectsToCodecAspects( 627 primaries, transfer, coeffs, full_range, colorAspects); 628 // Update color aspects if necessary. 629 if (colorAspectsDiffer(colorAspects, mBitstreamColorAspects)) { 630 mBitstreamColorAspects = colorAspects; 631 status_t err = handleColorAspectsChange(); 632 CHECK(err == OK); 633 } 634 635 return true; 636} 637 638status_t C2SoftMpeg2Dec::setFlushMode() { 639 ivd_ctl_flush_ip_t s_set_flush_ip; 640 ivd_ctl_flush_op_t s_set_flush_op; 641 642 s_set_flush_ip.u4_size = sizeof(ivd_ctl_flush_ip_t); 643 s_set_flush_ip.e_cmd = IVD_CMD_VIDEO_CTL; 644 s_set_flush_ip.e_sub_cmd = IVD_CMD_CTL_FLUSH; 645 s_set_flush_op.u4_size = sizeof(ivd_ctl_flush_op_t); 646 IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle, 647 &s_set_flush_ip, 648 &s_set_flush_op); 649 if (status != IV_SUCCESS) { 650 ALOGE("error in %s: 0x%x", __func__, s_set_flush_op.u4_error_code); 651 return UNKNOWN_ERROR; 652 } 653 654 return OK; 655} 656 657status_t C2SoftMpeg2Dec::resetDecoder() { 658 ivd_ctl_reset_ip_t s_reset_ip; 659 ivd_ctl_reset_op_t s_reset_op; 660 661 s_reset_ip.u4_size = sizeof(ivd_ctl_reset_ip_t); 662 s_reset_ip.e_cmd = IVD_CMD_VIDEO_CTL; 663 s_reset_ip.e_sub_cmd = IVD_CMD_CTL_RESET; 664 s_reset_op.u4_size = sizeof(ivd_ctl_reset_op_t); 665 IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle, 666 &s_reset_ip, 667 &s_reset_op); 668 if (IV_SUCCESS != status) { 669 ALOGE("error in %s: 0x%x", __func__, s_reset_op.u4_error_code); 670 return UNKNOWN_ERROR; 671 } 672 (void) setNumCores(); 673 mStride = 0; 674 mSignalledError = false; 675 676 return OK; 677} 678 679void C2SoftMpeg2Dec::resetPlugin() { 680 mSignalledOutputEos = false; 681 gettimeofday(&mTimeStart, nullptr); 682 gettimeofday(&mTimeEnd, nullptr); 683} 684 685status_t C2SoftMpeg2Dec::deleteDecoder() { 686 if (mMemRecords) { 687 iv_mem_rec_t *ps_mem_rec = mMemRecords; 688 689 for (size_t i = 0; i < mNumMemRecords; i++, ps_mem_rec++) { 690 if (ps_mem_rec->pv_base) { 691 ivd_aligned_free(ps_mem_rec->pv_base); 692 } 693 } 694 ivd_aligned_free(mMemRecords); 695 mMemRecords = nullptr; 696 } 697 mDecHandle = nullptr; 698 699 return OK; 700} 701 702status_t C2SoftMpeg2Dec::reInitDecoder() { 703 deleteDecoder(); 704 705 status_t ret = initDecoder(); 706 if (OK != ret) { 707 ALOGE("Failed to initialize decoder"); 708 deleteDecoder(); 709 return ret; 710 } 711 return OK; 712} 713 714void fillEmptyWork(const std::unique_ptr<C2Work> &work) { 715 uint32_t flags = 0; 716 if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) { 717 flags |= C2FrameData::FLAG_END_OF_STREAM; 718 ALOGV("signalling eos"); 719 } 720 work->worklets.front()->output.flags = (C2FrameData::flags_t)flags; 721 work->worklets.front()->output.buffers.clear(); 722 work->worklets.front()->output.ordinal = work->input.ordinal; 723 work->workletsProcessed = 1u; 724} 725 726void C2SoftMpeg2Dec::finishWork(uint64_t index, const std::unique_ptr<C2Work> &work) { 727 std::shared_ptr<C2Buffer> buffer = createGraphicBuffer(std::move(mOutBlock), 728 C2Rect(mWidth, mHeight)); 729 mOutBlock = nullptr; 730 auto fillWork = [buffer, index](const std::unique_ptr<C2Work> &work) { 731 uint32_t flags = 0; 732 if ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) && 733 (c2_cntr64_t(index) == work->input.ordinal.frameIndex)) { 734 flags |= C2FrameData::FLAG_END_OF_STREAM; 735 ALOGV("signalling eos"); 736 } 737 work->worklets.front()->output.flags = (C2FrameData::flags_t)flags; 738 work->worklets.front()->output.buffers.clear(); 739 work->worklets.front()->output.buffers.push_back(buffer); 740 work->worklets.front()->output.ordinal = work->input.ordinal; 741 work->workletsProcessed = 1u; 742 }; 743 if (work && c2_cntr64_t(index) == work->input.ordinal.frameIndex) { 744 fillWork(work); 745 } else { 746 finish(index, fillWork); 747 } 748} 749 750c2_status_t C2SoftMpeg2Dec::ensureDecoderState(const std::shared_ptr<C2BlockPool> &pool) { 751 if (!mDecHandle) { 752 ALOGE("not supposed to be here, invalid decoder context"); 753 return C2_CORRUPTED; 754 } 755 if (mStride != ALIGN64(mWidth)) { 756 mStride = ALIGN64(mWidth); 757 if (OK != setParams(mStride)) return C2_CORRUPTED; 758 } 759 if (mOutBlock && 760 (mOutBlock->width() != mStride || mOutBlock->height() != mHeight)) { 761 mOutBlock.reset(); 762 } 763 if (!mOutBlock) { 764 uint32_t format = HAL_PIXEL_FORMAT_YV12; 765 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE }; 766 c2_status_t err = pool->fetchGraphicBlock(mStride, mHeight, format, usage, &mOutBlock); 767 if (err != C2_OK) { 768 ALOGE("fetchGraphicBlock for Output failed with status %d", err); 769 return err; 770 } 771 ALOGV("provided (%dx%d) required (%dx%d)", 772 mOutBlock->width(), mOutBlock->height(), mStride, mHeight); 773 } 774 775 return C2_OK; 776} 777 778// TODO: can overall error checking be improved? 779// TODO: allow configuration of color format and usage for graphic buffers instead 780// of hard coding them to HAL_PIXEL_FORMAT_YV12 781// TODO: pass coloraspects information to surface 782// TODO: test support for dynamic change in resolution 783// TODO: verify if the decoder sent back all frames 784void C2SoftMpeg2Dec::process( 785 const std::unique_ptr<C2Work> &work, 786 const std::shared_ptr<C2BlockPool> &pool) { 787 work->result = C2_OK; 788 work->workletsProcessed = 0u; 789 work->worklets.front()->output.configUpdate.clear(); 790 if (mSignalledError || mSignalledOutputEos) { 791 work->result = C2_BAD_VALUE; 792 return; 793 } 794 795 size_t inOffset = 0u; 796 size_t inSize = 0u; 797 uint32_t workIndex = work->input.ordinal.frameIndex.peeku() & 0xFFFFFFFF; 798 C2ReadView rView = mDummyReadView; 799 if (work->input.buffers.empty()) { 800 rView = work->input.buffers[0]->data().linearBlocks().front().map().get(); 801 inSize = rView.capacity(); 802 if (inSize && rView.error()) { 803 ALOGE("read view map failed %d", rView.error()); 804 work->result = C2_CORRUPTED; 805 return; 806 } 807 } 808 bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0); 809 bool hasPicture = false; 810 811 ALOGV("in buffer attr. size %zu timestamp %d frameindex %d, flags %x", 812 inSize, (int)work->input.ordinal.timestamp.peeku(), 813 (int)work->input.ordinal.frameIndex.peeku(), work->input.flags); 814 size_t inPos = 0; 815 while (inPos < inSize) { 816 if (C2_OK != ensureDecoderState(pool)) { 817 mSignalledError = true; 818 work->result = C2_CORRUPTED; 819 return; 820 } 821 C2GraphicView wView = mOutBlock->map().get(); 822 if (wView.error()) { 823 ALOGE("graphic view map failed %d", wView.error()); 824 work->result = C2_CORRUPTED; 825 return; 826 } 827 828 ivd_video_decode_ip_t s_decode_ip; 829 ivd_video_decode_op_t s_decode_op; 830 if (!setDecodeArgs(&s_decode_ip, &s_decode_op, &rView, &wView, 831 inOffset + inPos, inSize - inPos, workIndex)) { 832 mSignalledError = true; 833 work->result = C2_CORRUPTED; 834 return; 835 } 836 // If input dump is enabled, then write to file 837 DUMP_TO_FILE(mInFile, s_decode_ip.pv_stream_buffer, s_decode_ip.u4_num_Bytes); 838 WORD32 delay; 839 GETTIME(&mTimeStart, NULL); 840 TIME_DIFF(mTimeEnd, mTimeStart, delay); 841 (void) ivdec_api_function(mDecHandle, &s_decode_ip, &s_decode_op); 842 WORD32 decodeTime; 843 GETTIME(&mTimeEnd, nullptr); 844 TIME_DIFF(mTimeStart, mTimeEnd, decodeTime); 845 ALOGV("decodeTime=%6d delay=%6d numBytes=%6d ", decodeTime, delay, 846 s_decode_op.u4_num_bytes_consumed); 847 if (IMPEG2D_UNSUPPORTED_DIMENSIONS == s_decode_op.u4_error_code) { 848 ALOGV("unsupported resolution : %dx%d", s_decode_op.u4_pic_wd, s_decode_op.u4_pic_ht); 849 drainInternal(DRAIN_COMPONENT_NO_EOS, pool, work); 850 resetPlugin(); 851 mWidth = s_decode_op.u4_pic_wd; 852 mHeight = s_decode_op.u4_pic_ht; 853 854 ALOGI("Configuring decoder: mWidth %d , mHeight %d ", 855 mWidth, mHeight); 856 C2VideoSizeStreamInfo::output size(0u, mWidth, mHeight); 857 std::vector<std::unique_ptr<C2SettingResult>> failures; 858 c2_status_t err = 859 mIntf->config({&size}, C2_MAY_BLOCK, &failures); 860 if (err == OK) { 861 work->worklets.front()->output.configUpdate.push_back( 862 C2Param::Copy(size)); 863 } else { 864 ALOGE("Cannot set width and height"); 865 mSignalledError = true; 866 work->result = C2_CORRUPTED; 867 return; 868 } 869 870 if (OK != reInitDecoder()) { 871 ALOGE("Failed to reinitialize decoder"); 872 mSignalledError = true; 873 work->result = C2_CORRUPTED; 874 return; 875 } 876 continue; 877 } else if (IVD_RES_CHANGED == (s_decode_op.u4_error_code & 0xFF)) { 878 ALOGV("resolution changed"); 879 drainInternal(DRAIN_COMPONENT_NO_EOS, pool, work); 880 resetDecoder(); 881 resetPlugin(); 882 continue; 883 } 884 if (0 < s_decode_op.u4_pic_wd && 0 < s_decode_op.u4_pic_ht) { 885 if (s_decode_op.u4_pic_wd != mWidth || s_decode_op.u4_pic_ht != mHeight) { 886 mWidth = s_decode_op.u4_pic_wd; 887 mHeight = s_decode_op.u4_pic_ht; 888 CHECK_EQ(0u, s_decode_op.u4_output_present); 889 890 ALOGI("Configuring decoder out: mWidth %d , mHeight %d ", 891 mWidth, mHeight); 892 C2VideoSizeStreamInfo::output size(0u, mWidth, mHeight); 893 std::vector<std::unique_ptr<C2SettingResult>> failures; 894 c2_status_t err = 895 mIntf->config({&size}, C2_MAY_BLOCK, &failures); 896 if (err == OK) { 897 work->worklets.front()->output.configUpdate.push_back( 898 C2Param::Copy(size)); 899 } else { 900 ALOGE("Cannot set width and height"); 901 mSignalledError = true; 902 work->result = C2_CORRUPTED; 903 return; 904 } 905 } 906 } 907 908 (void) getSeqInfo(); 909 if (mUpdateColorAspects) { 910 mUpdateColorAspects = false; 911 } 912 hasPicture |= (1 == s_decode_op.u4_frame_decoded_flag); 913 if (s_decode_op.u4_output_present) { 914 finishWork(s_decode_op.u4_ts, work); 915 } 916 inPos += s_decode_op.u4_num_bytes_consumed; 917 if (hasPicture && (inSize - inPos) != 0) { 918 ALOGD("decoded frame in current access nal, ignoring further trailing bytes %d", 919 (int)inSize - (int)inPos); 920 break; 921 } 922 } 923 924 if (eos) { 925 drainInternal(DRAIN_COMPONENT_WITH_EOS, pool, work); 926 mSignalledOutputEos = true; 927 } else if (!hasPicture) { 928 fillEmptyWork(work); 929 } 930} 931 932c2_status_t C2SoftMpeg2Dec::drainInternal( 933 uint32_t drainMode, 934 const std::shared_ptr<C2BlockPool> &pool, 935 const std::unique_ptr<C2Work> &work) { 936 if (drainMode == NO_DRAIN) { 937 ALOGW("drain with NO_DRAIN: no-op"); 938 return C2_OK; 939 } 940 if (drainMode == DRAIN_CHAIN) { 941 ALOGW("DRAIN_CHAIN not supported"); 942 return C2_OMITTED; 943 } 944 945 if (OK != setFlushMode()) return C2_CORRUPTED; 946 while (true) { 947 if (C2_OK != ensureDecoderState(pool)) { 948 mSignalledError = true; 949 work->result = C2_CORRUPTED; 950 return C2_CORRUPTED; 951 } 952 C2GraphicView wView = mOutBlock->map().get(); 953 if (wView.error()) { 954 ALOGE("graphic view map failed %d", wView.error()); 955 return C2_CORRUPTED; 956 } 957 ivd_video_decode_ip_t s_decode_ip; 958 ivd_video_decode_op_t s_decode_op; 959 if (!setDecodeArgs(&s_decode_ip, &s_decode_op, nullptr, &wView, 0, 0, 0)) { 960 mSignalledError = true; 961 return C2_CORRUPTED; 962 } 963 (void) ivdec_api_function(mDecHandle, &s_decode_ip, &s_decode_op); 964 if (s_decode_op.u4_output_present) { 965 finishWork(s_decode_op.u4_ts, work); 966 } else { 967 break; 968 } 969 } 970 if (drainMode == DRAIN_COMPONENT_WITH_EOS && 971 work && work->workletsProcessed == 0u) { 972 fillEmptyWork(work); 973 } 974 975 return C2_OK; 976} 977 978c2_status_t C2SoftMpeg2Dec::drain( 979 uint32_t drainMode, 980 const std::shared_ptr<C2BlockPool> &pool) { 981 return drainInternal(drainMode, pool, nullptr); 982} 983 984class C2SoftMpeg2DecFactory : public C2ComponentFactory { 985public: 986 C2SoftMpeg2DecFactory() : mHelper(std::static_pointer_cast<C2ReflectorHelper>( 987 GetCodec2PlatformComponentStore()->getParamReflector())) { 988 } 989 990 virtual c2_status_t createComponent( 991 c2_node_id_t id, 992 std::shared_ptr<C2Component>* const component, 993 std::function<void(C2Component*)> deleter) override { 994 *component = std::shared_ptr<C2Component>( 995 new C2SoftMpeg2Dec(COMPONENT_NAME, 996 id, 997 std::make_shared<C2SoftMpeg2Dec::IntfImpl>(mHelper)), 998 deleter); 999 return C2_OK; 1000 } 1001 1002 virtual c2_status_t createInterface( 1003 c2_node_id_t id, 1004 std::shared_ptr<C2ComponentInterface>* const interface, 1005 std::function<void(C2ComponentInterface*)> deleter) override { 1006 *interface = std::shared_ptr<C2ComponentInterface>( 1007 new SimpleInterface<C2SoftMpeg2Dec::IntfImpl>( 1008 COMPONENT_NAME, id, std::make_shared<C2SoftMpeg2Dec::IntfImpl>(mHelper)), 1009 deleter); 1010 return C2_OK; 1011 } 1012 1013 virtual ~C2SoftMpeg2DecFactory() override = default; 1014 1015private: 1016 std::shared_ptr<C2ReflectorHelper> mHelper; 1017}; 1018 1019} // namespace android 1020 1021extern "C" ::C2ComponentFactory* CreateCodec2Factory() { 1022 ALOGV("in %s", __func__); 1023 return new ::android::C2SoftMpeg2DecFactory(); 1024} 1025 1026extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) { 1027 ALOGV("in %s", __func__); 1028 delete factory; 1029} 1030