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