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