1 // Copyright 2017 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 //#define LOG_NDEBUG 0 6 #define LOG_TAG "C2VDAComponent" 7 8 #ifdef V4L2_CODEC2_ARC 9 #include <C2VDAAdaptorProxy.h> 10 #else 11 #include <C2VDAAdaptor.h> 12 #endif 13 14 #define __C2_GENERATE_GLOBAL_VARS__ 15 #include <C2VDAAllocatorStore.h> 16 #include <C2VDAComponent.h> 17 #include <C2VDAPixelFormat.h> 18 #include <C2VDASupport.h> // to getParamReflector from vda store 19 #include <C2VdaBqBlockPool.h> 20 #include <C2VdaPooledBlockPool.h> 21 22 #include <h264_parser.h> 23 24 #include <C2AllocatorGralloc.h> 25 #include <C2ComponentFactory.h> 26 #include <C2PlatformSupport.h> 27 #include <Codec2Mapper.h> 28 29 #include <base/bind.h> 30 #include <base/bind_helpers.h> 31 32 #include <media/stagefright/MediaDefs.h> 33 #include <media/stagefright/foundation/ColorUtils.h> 34 #include <utils/Log.h> 35 #include <utils/misc.h> 36 37 #include <inttypes.h> 38 #include <string.h> 39 #include <algorithm> 40 #include <string> 41 42 #define UNUSED(expr) \ 43 do { \ 44 (void)(expr); \ 45 } while (0) 46 47 namespace android { 48 49 namespace { 50 51 // Mask against 30 bits to avoid (undefined) wraparound on signed integer. 52 int32_t frameIndexToBitstreamId(c2_cntr64_t frameIndex) { 53 return static_cast<int32_t>(frameIndex.peeku() & 0x3FFFFFFF); 54 } 55 56 // Use basic graphic block pool/allocator as default. 57 const C2BlockPool::local_id_t kDefaultOutputBlockPool = C2BlockPool::BASIC_GRAPHIC; 58 59 const C2String kH264DecoderName = "c2.vda.avc.decoder"; 60 const C2String kVP8DecoderName = "c2.vda.vp8.decoder"; 61 const C2String kVP9DecoderName = "c2.vda.vp9.decoder"; 62 const C2String kH264SecureDecoderName = "c2.vda.avc.decoder.secure"; 63 const C2String kVP8SecureDecoderName = "c2.vda.vp8.decoder.secure"; 64 const C2String kVP9SecureDecoderName = "c2.vda.vp9.decoder.secure"; 65 66 const uint32_t kDpbOutputBufferExtraCount = 3; // Use the same number as ACodec. 67 const int kDequeueRetryDelayUs = 10000; // Wait time of dequeue buffer retry in microseconds. 68 const int32_t kAllocateBufferMaxRetries = 10; // Max retry time for fetchGraphicBlock timeout. 69 } // namespace 70 71 static c2_status_t adaptorResultToC2Status(VideoDecodeAcceleratorAdaptor::Result result) { 72 switch (result) { 73 case VideoDecodeAcceleratorAdaptor::Result::SUCCESS: 74 return C2_OK; 75 case VideoDecodeAcceleratorAdaptor::Result::ILLEGAL_STATE: 76 ALOGE("Got error: ILLEGAL_STATE"); 77 return C2_BAD_STATE; 78 case VideoDecodeAcceleratorAdaptor::Result::INVALID_ARGUMENT: 79 ALOGE("Got error: INVALID_ARGUMENT"); 80 return C2_BAD_VALUE; 81 case VideoDecodeAcceleratorAdaptor::Result::UNREADABLE_INPUT: 82 ALOGE("Got error: UNREADABLE_INPUT"); 83 return C2_BAD_VALUE; 84 case VideoDecodeAcceleratorAdaptor::Result::PLATFORM_FAILURE: 85 ALOGE("Got error: PLATFORM_FAILURE"); 86 return C2_CORRUPTED; 87 case VideoDecodeAcceleratorAdaptor::Result::INSUFFICIENT_RESOURCES: 88 ALOGE("Got error: INSUFFICIENT_RESOURCES"); 89 return C2_NO_MEMORY; 90 default: 91 ALOGE("Unrecognizable adaptor result (value = %d)...", result); 92 return C2_CORRUPTED; 93 } 94 } 95 96 // static 97 C2R C2VDAComponent::IntfImpl::ProfileLevelSetter(bool mayBlock, 98 C2P<C2StreamProfileLevelInfo::input>& info) { 99 (void)mayBlock; 100 return info.F(info.v.profile) 101 .validatePossible(info.v.profile) 102 .plus(info.F(info.v.level).validatePossible(info.v.level)); 103 } 104 105 // static 106 C2R C2VDAComponent::IntfImpl::SizeSetter(bool mayBlock, 107 C2P<C2StreamPictureSizeInfo::output>& videoSize) { 108 (void)mayBlock; 109 // TODO: maybe apply block limit? 110 return videoSize.F(videoSize.v.width) 111 .validatePossible(videoSize.v.width) 112 .plus(videoSize.F(videoSize.v.height).validatePossible(videoSize.v.height)); 113 } 114 115 // static 116 template <typename T> 117 C2R C2VDAComponent::IntfImpl::DefaultColorAspectsSetter(bool mayBlock, C2P<T>& def) { 118 (void)mayBlock; 119 if (def.v.range > C2Color::RANGE_OTHER) { 120 def.set().range = C2Color::RANGE_OTHER; 121 } 122 if (def.v.primaries > C2Color::PRIMARIES_OTHER) { 123 def.set().primaries = C2Color::PRIMARIES_OTHER; 124 } 125 if (def.v.transfer > C2Color::TRANSFER_OTHER) { 126 def.set().transfer = C2Color::TRANSFER_OTHER; 127 } 128 if (def.v.matrix > C2Color::MATRIX_OTHER) { 129 def.set().matrix = C2Color::MATRIX_OTHER; 130 } 131 return C2R::Ok(); 132 } 133 134 // static 135 C2R C2VDAComponent::IntfImpl::MergedColorAspectsSetter( 136 bool mayBlock, C2P<C2StreamColorAspectsInfo::output>& merged, 137 const C2P<C2StreamColorAspectsTuning::output>& def, 138 const C2P<C2StreamColorAspectsInfo::input>& coded) { 139 (void)mayBlock; 140 // Take coded values for all specified fields, and default values for unspecified ones. 141 merged.set().range = coded.v.range == RANGE_UNSPECIFIED ? def.v.range : coded.v.range; 142 merged.set().primaries = 143 coded.v.primaries == PRIMARIES_UNSPECIFIED ? def.v.primaries : coded.v.primaries; 144 merged.set().transfer = 145 coded.v.transfer == TRANSFER_UNSPECIFIED ? def.v.transfer : coded.v.transfer; 146 merged.set().matrix = coded.v.matrix == MATRIX_UNSPECIFIED ? def.v.matrix : coded.v.matrix; 147 return C2R::Ok(); 148 } 149 150 C2VDAComponent::IntfImpl::IntfImpl(C2String name, const std::shared_ptr<C2ReflectorHelper>& helper) 151 : C2InterfaceHelper(helper), mInitStatus(C2_OK) { 152 setDerivedInstance(this); 153 154 // TODO(johnylin): use factory function to determine whether V4L2 stream or slice API is. 155 char inputMime[128]; 156 if (name == kH264DecoderName || name == kH264SecureDecoderName) { 157 strcpy(inputMime, MEDIA_MIMETYPE_VIDEO_AVC); 158 mInputCodec = InputCodec::H264; 159 addParameter( 160 DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL) 161 .withDefault(new C2StreamProfileLevelInfo::input( 162 0u, C2Config::PROFILE_AVC_MAIN, C2Config::LEVEL_AVC_4)) 163 .withFields( 164 {C2F(mProfileLevel, profile) 165 .oneOf({C2Config::PROFILE_AVC_BASELINE, 166 C2Config::PROFILE_AVC_CONSTRAINED_BASELINE, 167 C2Config::PROFILE_AVC_MAIN, 168 C2Config::PROFILE_AVC_HIGH, 169 C2Config::PROFILE_AVC_CONSTRAINED_HIGH}), 170 C2F(mProfileLevel, level) 171 .oneOf({C2Config::LEVEL_AVC_1, C2Config::LEVEL_AVC_1B, 172 C2Config::LEVEL_AVC_1_1, C2Config::LEVEL_AVC_1_2, 173 C2Config::LEVEL_AVC_1_3, C2Config::LEVEL_AVC_2, 174 C2Config::LEVEL_AVC_2_1, C2Config::LEVEL_AVC_2_2, 175 C2Config::LEVEL_AVC_3, C2Config::LEVEL_AVC_3_1, 176 C2Config::LEVEL_AVC_3_2, C2Config::LEVEL_AVC_4, 177 C2Config::LEVEL_AVC_4_1, C2Config::LEVEL_AVC_4_2, 178 C2Config::LEVEL_AVC_5, C2Config::LEVEL_AVC_5_1, 179 C2Config::LEVEL_AVC_5_2})}) 180 .withSetter(ProfileLevelSetter) 181 .build()); 182 } else if (name == kVP8DecoderName || name == kVP8SecureDecoderName) { 183 strcpy(inputMime, MEDIA_MIMETYPE_VIDEO_VP8); 184 mInputCodec = InputCodec::VP8; 185 addParameter(DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL) 186 .withConstValue(new C2StreamProfileLevelInfo::input( 187 0u, C2Config::PROFILE_UNUSED, C2Config::LEVEL_UNUSED)) 188 .build()); 189 } else if (name == kVP9DecoderName || name == kVP9SecureDecoderName) { 190 strcpy(inputMime, MEDIA_MIMETYPE_VIDEO_VP9); 191 mInputCodec = InputCodec::VP9; 192 addParameter( 193 DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL) 194 .withDefault(new C2StreamProfileLevelInfo::input( 195 0u, C2Config::PROFILE_VP9_0, C2Config::LEVEL_VP9_5)) 196 .withFields({C2F(mProfileLevel, profile).oneOf({C2Config::PROFILE_VP9_0}), 197 C2F(mProfileLevel, level) 198 .oneOf({C2Config::LEVEL_VP9_1, C2Config::LEVEL_VP9_1_1, 199 C2Config::LEVEL_VP9_2, C2Config::LEVEL_VP9_2_1, 200 C2Config::LEVEL_VP9_3, C2Config::LEVEL_VP9_3_1, 201 C2Config::LEVEL_VP9_4, C2Config::LEVEL_VP9_4_1, 202 C2Config::LEVEL_VP9_5})}) 203 .withSetter(ProfileLevelSetter) 204 .build()); 205 } else { 206 ALOGE("Invalid component name: %s", name.c_str()); 207 mInitStatus = C2_BAD_VALUE; 208 return; 209 } 210 // Get supported profiles from VDA. 211 // TODO: re-think the suitable method of getting supported profiles for both pure Android and 212 // ARC++. 213 media::VideoDecodeAccelerator::SupportedProfiles supportedProfiles; 214 #ifdef V4L2_CODEC2_ARC 215 supportedProfiles = arc::C2VDAAdaptorProxy::GetSupportedProfiles(mInputCodec); 216 #else 217 supportedProfiles = C2VDAAdaptor::GetSupportedProfiles(mInputCodec); 218 #endif 219 if (supportedProfiles.empty()) { 220 ALOGE("No supported profile from input codec: %d", mInputCodec); 221 mInitStatus = C2_BAD_VALUE; 222 return; 223 } 224 225 mCodecProfile = supportedProfiles[0].profile; 226 227 auto minSize = supportedProfiles[0].min_resolution; 228 auto maxSize = supportedProfiles[0].max_resolution; 229 230 addParameter( 231 DefineParam(mInputFormat, C2_PARAMKEY_INPUT_STREAM_BUFFER_TYPE) 232 .withConstValue(new C2StreamBufferTypeSetting::input(0u, C2FormatCompressed)) 233 .build()); 234 235 addParameter(DefineParam(mOutputFormat, C2_PARAMKEY_OUTPUT_STREAM_BUFFER_TYPE) 236 .withConstValue(new C2StreamBufferTypeSetting::output(0u, C2FormatVideo)) 237 .build()); 238 239 addParameter( 240 DefineParam(mInputMediaType, C2_PARAMKEY_INPUT_MEDIA_TYPE) 241 .withConstValue(AllocSharedString<C2PortMediaTypeSetting::input>(inputMime)) 242 .build()); 243 244 addParameter(DefineParam(mOutputMediaType, C2_PARAMKEY_OUTPUT_MEDIA_TYPE) 245 .withConstValue(AllocSharedString<C2PortMediaTypeSetting::output>( 246 MEDIA_MIMETYPE_VIDEO_RAW)) 247 .build()); 248 249 addParameter(DefineParam(mSize, C2_PARAMKEY_STREAM_PICTURE_SIZE) 250 .withDefault(new C2StreamPictureSizeInfo::output(0u, 176, 144)) 251 .withFields({ 252 C2F(mSize, width).inRange(minSize.width(), maxSize.width(), 16), 253 C2F(mSize, height).inRange(minSize.height(), maxSize.height(), 16), 254 }) 255 .withSetter(SizeSetter) 256 .build()); 257 258 // App may set a smaller value for maximum of input buffer size than actually required 259 // by mistake. C2VDAComponent overrides it if the value specified by app is smaller than 260 // the calculated value in MaxSizeCalculator(). 261 // This value is the default maximum of linear buffer size (kLinearBufferSize) in 262 // CCodecBufferChannel.cpp. 263 constexpr static size_t kLinearBufferSize = 1048576; 264 struct LocalCalculator { 265 static C2R MaxSizeCalculator(bool mayBlock, C2P<C2StreamMaxBufferSizeInfo::input>& me, 266 const C2P<C2StreamPictureSizeInfo::output>& size) { 267 (void)mayBlock; 268 // TODO: Need larger size? 269 me.set().value = kLinearBufferSize; 270 const uint32_t width = size.v.width; 271 const uint32_t height = size.v.height; 272 // Enlarge the input buffer for 4k video 273 if ((width > 1920 && height > 1080)) { 274 me.set().value = 4 * kLinearBufferSize; 275 } 276 return C2R::Ok(); 277 } 278 }; 279 addParameter(DefineParam(mMaxInputSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE) 280 .withDefault(new C2StreamMaxBufferSizeInfo::input(0u, kLinearBufferSize)) 281 .withFields({ 282 C2F(mMaxInputSize, value).any(), 283 }) 284 .calculatedAs(LocalCalculator::MaxSizeCalculator, mSize) 285 .build()); 286 287 bool secureMode = name.find(".secure") != std::string::npos; 288 C2Allocator::id_t inputAllocators[] = {secureMode ? C2VDAAllocatorStore::SECURE_LINEAR 289 : C2PlatformAllocatorStore::ION}; 290 291 C2Allocator::id_t outputAllocators[] = {C2VDAAllocatorStore::V4L2_BUFFERPOOL}; 292 293 C2Allocator::id_t surfaceAllocator = secureMode ? C2VDAAllocatorStore::SECURE_GRAPHIC 294 : C2VDAAllocatorStore::V4L2_BUFFERQUEUE; 295 296 addParameter( 297 DefineParam(mInputAllocatorIds, C2_PARAMKEY_INPUT_ALLOCATORS) 298 .withConstValue(C2PortAllocatorsTuning::input::AllocShared(inputAllocators)) 299 .build()); 300 301 addParameter( 302 DefineParam(mOutputAllocatorIds, C2_PARAMKEY_OUTPUT_ALLOCATORS) 303 .withConstValue(C2PortAllocatorsTuning::output::AllocShared(outputAllocators)) 304 .build()); 305 306 addParameter(DefineParam(mOutputSurfaceAllocatorId, C2_PARAMKEY_OUTPUT_SURFACE_ALLOCATOR) 307 .withConstValue(new C2PortSurfaceAllocatorTuning::output(surfaceAllocator)) 308 .build()); 309 310 C2BlockPool::local_id_t outputBlockPools[] = {kDefaultOutputBlockPool}; 311 312 addParameter( 313 DefineParam(mOutputBlockPoolIds, C2_PARAMKEY_OUTPUT_BLOCK_POOLS) 314 .withDefault(C2PortBlockPoolsTuning::output::AllocShared(outputBlockPools)) 315 .withFields({C2F(mOutputBlockPoolIds, m.values[0]).any(), 316 C2F(mOutputBlockPoolIds, m.values).inRange(0, 1)}) 317 .withSetter(Setter<C2PortBlockPoolsTuning::output>::NonStrictValuesWithNoDeps) 318 .build()); 319 320 addParameter( 321 DefineParam(mDefaultColorAspects, C2_PARAMKEY_DEFAULT_COLOR_ASPECTS) 322 .withDefault(new C2StreamColorAspectsTuning::output( 323 0u, C2Color::RANGE_UNSPECIFIED, C2Color::PRIMARIES_UNSPECIFIED, 324 C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED)) 325 .withFields( 326 {C2F(mDefaultColorAspects, range) 327 .inRange(C2Color::RANGE_UNSPECIFIED, C2Color::RANGE_OTHER), 328 C2F(mDefaultColorAspects, primaries) 329 .inRange(C2Color::PRIMARIES_UNSPECIFIED, 330 C2Color::PRIMARIES_OTHER), 331 C2F(mDefaultColorAspects, transfer) 332 .inRange(C2Color::TRANSFER_UNSPECIFIED, 333 C2Color::TRANSFER_OTHER), 334 C2F(mDefaultColorAspects, matrix) 335 .inRange(C2Color::MATRIX_UNSPECIFIED, C2Color::MATRIX_OTHER)}) 336 .withSetter(DefaultColorAspectsSetter) 337 .build()); 338 339 addParameter( 340 DefineParam(mCodedColorAspects, C2_PARAMKEY_VUI_COLOR_ASPECTS) 341 .withDefault(new C2StreamColorAspectsInfo::input( 342 0u, C2Color::RANGE_LIMITED, C2Color::PRIMARIES_UNSPECIFIED, 343 C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED)) 344 .withFields( 345 {C2F(mCodedColorAspects, range) 346 .inRange(C2Color::RANGE_UNSPECIFIED, C2Color::RANGE_OTHER), 347 C2F(mCodedColorAspects, primaries) 348 .inRange(C2Color::PRIMARIES_UNSPECIFIED, 349 C2Color::PRIMARIES_OTHER), 350 C2F(mCodedColorAspects, transfer) 351 .inRange(C2Color::TRANSFER_UNSPECIFIED, 352 C2Color::TRANSFER_OTHER), 353 C2F(mCodedColorAspects, matrix) 354 .inRange(C2Color::MATRIX_UNSPECIFIED, C2Color::MATRIX_OTHER)}) 355 .withSetter(DefaultColorAspectsSetter) 356 .build()); 357 358 addParameter( 359 DefineParam(mColorAspects, C2_PARAMKEY_COLOR_ASPECTS) 360 .withDefault(new C2StreamColorAspectsInfo::output( 361 0u, C2Color::RANGE_UNSPECIFIED, C2Color::PRIMARIES_UNSPECIFIED, 362 C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED)) 363 .withFields( 364 {C2F(mColorAspects, range) 365 .inRange(C2Color::RANGE_UNSPECIFIED, C2Color::RANGE_OTHER), 366 C2F(mColorAspects, primaries) 367 .inRange(C2Color::PRIMARIES_UNSPECIFIED, 368 C2Color::PRIMARIES_OTHER), 369 C2F(mColorAspects, transfer) 370 .inRange(C2Color::TRANSFER_UNSPECIFIED, 371 C2Color::TRANSFER_OTHER), 372 C2F(mColorAspects, matrix) 373 .inRange(C2Color::MATRIX_UNSPECIFIED, C2Color::MATRIX_OTHER)}) 374 .withSetter(MergedColorAspectsSetter, mDefaultColorAspects, mCodedColorAspects) 375 .build()); 376 } 377 378 //////////////////////////////////////////////////////////////////////////////// 379 #define EXPECT_STATE_OR_RETURN_ON_ERROR(x) \ 380 do { \ 381 if (mComponentState == ComponentState::ERROR) return; \ 382 CHECK_EQ(mComponentState, ComponentState::x); \ 383 } while (0) 384 385 #define EXPECT_RUNNING_OR_RETURN_ON_ERROR() \ 386 do { \ 387 if (mComponentState == ComponentState::ERROR) return; \ 388 CHECK_NE(mComponentState, ComponentState::UNINITIALIZED); \ 389 } while (0) 390 391 C2VDAComponent::VideoFormat::VideoFormat(HalPixelFormat pixelFormat, uint32_t minNumBuffers, 392 media::Size codedSize, media::Rect visibleRect) 393 : mPixelFormat(pixelFormat), 394 mMinNumBuffers(minNumBuffers), 395 mCodedSize(codedSize), 396 mVisibleRect(visibleRect) {} 397 398 C2VDAComponent::C2VDAComponent(C2String name, c2_node_id_t id, 399 const std::shared_ptr<C2ReflectorHelper>& helper) 400 : mIntfImpl(std::make_shared<IntfImpl>(name, helper)), 401 mIntf(std::make_shared<SimpleInterface<IntfImpl>>(name.c_str(), id, mIntfImpl)), 402 mThread("C2VDAComponentThread"), 403 mDequeueThread("C2VDAComponentDequeueThread"), 404 mVDAInitResult(VideoDecodeAcceleratorAdaptor::Result::ILLEGAL_STATE), 405 mComponentState(ComponentState::UNINITIALIZED), 406 mPendingOutputEOS(false), 407 mPendingColorAspectsChange(false), 408 mPendingColorAspectsChangeFrameIndex(0), 409 mCodecProfile(media::VIDEO_CODEC_PROFILE_UNKNOWN), 410 mState(State::UNLOADED), 411 mWeakThisFactory(this) { 412 // TODO(johnylin): the client may need to know if init is failed. 413 if (mIntfImpl->status() != C2_OK) { 414 ALOGE("Component interface init failed (err code = %d)", mIntfImpl->status()); 415 return; 416 } 417 418 mSecureMode = name.find(".secure") != std::string::npos; 419 if (!mThread.Start()) { 420 ALOGE("Component thread failed to start."); 421 return; 422 } 423 mTaskRunner = mThread.task_runner(); 424 mState.store(State::LOADED); 425 } 426 427 C2VDAComponent::~C2VDAComponent() { 428 if (mThread.IsRunning()) { 429 mTaskRunner->PostTask(FROM_HERE, 430 ::base::Bind(&C2VDAComponent::onDestroy, ::base::Unretained(this))); 431 mThread.Stop(); 432 } 433 } 434 435 void C2VDAComponent::onDestroy() { 436 DCHECK(mTaskRunner->BelongsToCurrentThread()); 437 ALOGV("onDestroy"); 438 if (mVDAAdaptor.get()) { 439 mVDAAdaptor->destroy(); 440 mVDAAdaptor.reset(nullptr); 441 } 442 stopDequeueThread(); 443 } 444 445 void C2VDAComponent::onStart(media::VideoCodecProfile profile, ::base::WaitableEvent* done) { 446 DCHECK(mTaskRunner->BelongsToCurrentThread()); 447 ALOGV("onStart"); 448 CHECK_EQ(mComponentState, ComponentState::UNINITIALIZED); 449 450 #ifdef V4L2_CODEC2_ARC 451 mVDAAdaptor.reset(new arc::C2VDAAdaptorProxy()); 452 #else 453 mVDAAdaptor.reset(new C2VDAAdaptor()); 454 #endif 455 456 mVDAInitResult = mVDAAdaptor->initialize(profile, mSecureMode, this); 457 if (mVDAInitResult == VideoDecodeAcceleratorAdaptor::Result::SUCCESS) { 458 mComponentState = ComponentState::STARTED; 459 } 460 461 if (!mSecureMode && mIntfImpl->getInputCodec() == InputCodec::H264) { 462 // Get default color aspects on start. 463 updateColorAspects(); 464 mPendingColorAspectsChange = false; 465 } 466 467 done->Signal(); 468 } 469 470 void C2VDAComponent::onQueueWork(std::unique_ptr<C2Work> work) { 471 DCHECK(mTaskRunner->BelongsToCurrentThread()); 472 ALOGV("onQueueWork: flags=0x%x, index=%llu, timestamp=%llu", work->input.flags, 473 work->input.ordinal.frameIndex.peekull(), work->input.ordinal.timestamp.peekull()); 474 EXPECT_RUNNING_OR_RETURN_ON_ERROR(); 475 476 uint32_t drainMode = NO_DRAIN; 477 if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) { 478 drainMode = DRAIN_COMPONENT_WITH_EOS; 479 } 480 mQueue.push({std::move(work), drainMode}); 481 // TODO(johnylin): set a maximum size of mQueue and check if mQueue is already full. 482 483 mTaskRunner->PostTask(FROM_HERE, 484 ::base::Bind(&C2VDAComponent::onDequeueWork, ::base::Unretained(this))); 485 } 486 487 void C2VDAComponent::onDequeueWork() { 488 DCHECK(mTaskRunner->BelongsToCurrentThread()); 489 ALOGV("onDequeueWork"); 490 EXPECT_RUNNING_OR_RETURN_ON_ERROR(); 491 if (mQueue.empty()) { 492 return; 493 } 494 if (mComponentState == ComponentState::DRAINING || 495 mComponentState == ComponentState::FLUSHING) { 496 ALOGV("Temporarily stop dequeueing works since component is draining/flushing."); 497 return; 498 } 499 if (mComponentState != ComponentState::STARTED) { 500 ALOGE("Work queue should be empty if the component is not in STARTED state."); 501 return; 502 } 503 504 // Dequeue a work from mQueue. 505 std::unique_ptr<C2Work> work(std::move(mQueue.front().mWork)); 506 auto drainMode = mQueue.front().mDrainMode; 507 mQueue.pop(); 508 509 CHECK_LE(work->input.buffers.size(), 1u); 510 bool isEmptyCSDWork = false; 511 // Use frameIndex as bitstreamId. 512 int32_t bitstreamId = frameIndexToBitstreamId(work->input.ordinal.frameIndex); 513 if (work->input.buffers.empty()) { 514 // Client may queue a work with no input buffer for either it's EOS or empty CSD, otherwise 515 // every work must have one input buffer. 516 isEmptyCSDWork = work->input.flags & C2FrameData::FLAG_CODEC_CONFIG; 517 CHECK(drainMode != NO_DRAIN || isEmptyCSDWork); 518 // Emplace a nullptr to unify the check for work done. 519 ALOGV("Got a work with no input buffer! Emplace a nullptr inside."); 520 work->input.buffers.emplace_back(nullptr); 521 } else { 522 // If input.buffers is not empty, the buffer should have meaningful content inside. 523 C2ConstLinearBlock linearBlock = work->input.buffers.front()->data().linearBlocks().front(); 524 CHECK_GT(linearBlock.size(), 0u); 525 526 // Call parseCodedColorAspects() to try to parse color aspects from bitstream only if: 527 // 1) This is non-secure decoding. 528 // 2) This is H264 codec. 529 // 3) This input is CSD buffer (with flags FLAG_CODEC_CONFIG). 530 if (!mSecureMode && (mIntfImpl->getInputCodec() == InputCodec::H264) && 531 (work->input.flags & C2FrameData::FLAG_CODEC_CONFIG)) { 532 if (parseCodedColorAspects(linearBlock)) { 533 // Record current frame index, color aspects should be updated only for output 534 // buffers whose frame indices are not less than this one. 535 mPendingColorAspectsChange = true; 536 mPendingColorAspectsChangeFrameIndex = work->input.ordinal.frameIndex.peeku(); 537 } 538 } 539 // Send input buffer to VDA for decode. 540 sendInputBufferToAccelerator(linearBlock, bitstreamId); 541 } 542 543 CHECK_EQ(work->worklets.size(), 1u); 544 work->worklets.front()->output.flags = static_cast<C2FrameData::flags_t>(0); 545 work->worklets.front()->output.buffers.clear(); 546 work->worklets.front()->output.ordinal = work->input.ordinal; 547 548 if (drainMode != NO_DRAIN) { 549 mVDAAdaptor->flush(); 550 mComponentState = ComponentState::DRAINING; 551 mPendingOutputEOS = drainMode == DRAIN_COMPONENT_WITH_EOS; 552 } 553 554 // Put work to mPendingWorks. 555 mPendingWorks.emplace_back(std::move(work)); 556 if (isEmptyCSDWork) { 557 // Directly report the empty CSD work as finished. 558 reportWorkIfFinished(bitstreamId); 559 } 560 561 if (!mQueue.empty()) { 562 mTaskRunner->PostTask(FROM_HERE, ::base::Bind(&C2VDAComponent::onDequeueWork, 563 ::base::Unretained(this))); 564 } 565 } 566 567 void C2VDAComponent::onInputBufferDone(int32_t bitstreamId) { 568 DCHECK(mTaskRunner->BelongsToCurrentThread()); 569 ALOGV("onInputBufferDone: bitstream id=%d", bitstreamId); 570 EXPECT_RUNNING_OR_RETURN_ON_ERROR(); 571 572 C2Work* work = getPendingWorkByBitstreamId(bitstreamId); 573 if (!work) { 574 reportError(C2_CORRUPTED); 575 return; 576 } 577 578 // When the work is done, the input buffer shall be reset by component. 579 work->input.buffers.front().reset(); 580 581 reportWorkIfFinished(bitstreamId); 582 } 583 584 void C2VDAComponent::onOutputBufferReturned(std::shared_ptr<C2GraphicBlock> block, 585 uint32_t poolId) { 586 DCHECK(mTaskRunner->BelongsToCurrentThread()); 587 ALOGV("onOutputBufferReturned: pool id=%u", poolId); 588 if (mComponentState == ComponentState::UNINITIALIZED) { 589 // Output buffer is returned from client after component is stopped. Just let the buffer be 590 // released. 591 return; 592 } 593 594 if (block->width() != static_cast<uint32_t>(mOutputFormat.mCodedSize.width()) || 595 block->height() != static_cast<uint32_t>(mOutputFormat.mCodedSize.height())) { 596 // Output buffer is returned after we changed output resolution. Just let the buffer be 597 // released. 598 ALOGV("Discard obsolete graphic block: pool id=%u", poolId); 599 return; 600 } 601 602 GraphicBlockInfo* info = getGraphicBlockByPoolId(poolId); 603 if (!info) { 604 reportError(C2_CORRUPTED); 605 return; 606 } 607 CHECK_EQ(info->mState, GraphicBlockInfo::State::OWNED_BY_CLIENT); 608 info->mGraphicBlock = std::move(block); 609 info->mState = GraphicBlockInfo::State::OWNED_BY_COMPONENT; 610 611 if (mPendingOutputFormat) { 612 tryChangeOutputFormat(); 613 } else { 614 // Do not pass the ownership to accelerator if this buffer will still be reused under 615 // |mPendingBuffersToWork|. 616 auto existingFrame = std::find_if( 617 mPendingBuffersToWork.begin(), mPendingBuffersToWork.end(), 618 [id = info->mBlockId](const OutputBufferInfo& o) { return o.mBlockId == id; }); 619 bool ownByAccelerator = existingFrame == mPendingBuffersToWork.end(); 620 sendOutputBufferToAccelerator(info, ownByAccelerator); 621 sendOutputBufferToWorkIfAny(false /* dropIfUnavailable */); 622 } 623 } 624 625 void C2VDAComponent::onOutputBufferDone(int32_t pictureBufferId, int32_t bitstreamId) { 626 DCHECK(mTaskRunner->BelongsToCurrentThread()); 627 ALOGV("onOutputBufferDone: picture id=%d, bitstream id=%d", pictureBufferId, bitstreamId); 628 EXPECT_RUNNING_OR_RETURN_ON_ERROR(); 629 630 GraphicBlockInfo* info = getGraphicBlockById(pictureBufferId); 631 if (!info) { 632 reportError(C2_CORRUPTED); 633 return; 634 } 635 636 if (info->mState == GraphicBlockInfo::State::OWNED_BY_ACCELERATOR) { 637 info->mState = GraphicBlockInfo::State::OWNED_BY_COMPONENT; 638 } 639 mPendingBuffersToWork.push_back({bitstreamId, pictureBufferId}); 640 sendOutputBufferToWorkIfAny(false /* dropIfUnavailable */); 641 } 642 643 void C2VDAComponent::sendOutputBufferToWorkIfAny(bool dropIfUnavailable) { 644 DCHECK(mTaskRunner->BelongsToCurrentThread()); 645 646 while (!mPendingBuffersToWork.empty()) { 647 auto nextBuffer = mPendingBuffersToWork.front(); 648 GraphicBlockInfo* info = getGraphicBlockById(nextBuffer.mBlockId); 649 CHECK_NE(info->mState, GraphicBlockInfo::State::OWNED_BY_ACCELERATOR); 650 651 C2Work* work = getPendingWorkByBitstreamId(nextBuffer.mBitstreamId); 652 if (!work) { 653 reportError(C2_CORRUPTED); 654 return; 655 } 656 657 if (info->mState == GraphicBlockInfo::State::OWNED_BY_CLIENT) { 658 // This buffer is the existing frame and still owned by client. 659 if (!dropIfUnavailable && 660 std::find(mUndequeuedBlockIds.begin(), mUndequeuedBlockIds.end(), 661 nextBuffer.mBlockId) == mUndequeuedBlockIds.end()) { 662 ALOGV("Still waiting for existing frame returned from client..."); 663 return; 664 } 665 ALOGV("Drop this frame..."); 666 sendOutputBufferToAccelerator(info, false /* ownByAccelerator */); 667 work->worklets.front()->output.flags = C2FrameData::FLAG_DROP_FRAME; 668 } else { 669 // This buffer is ready to push into the corresponding work. 670 // Output buffer will be passed to client soon along with mListener->onWorkDone_nb(). 671 info->mState = GraphicBlockInfo::State::OWNED_BY_CLIENT; 672 mBuffersInClient++; 673 updateUndequeuedBlockIds(info->mBlockId); 674 675 // Attach output buffer to the work corresponded to bitstreamId. 676 C2ConstGraphicBlock constBlock = info->mGraphicBlock->share( 677 C2Rect(mOutputFormat.mVisibleRect.width(), 678 mOutputFormat.mVisibleRect.height()), 679 C2Fence()); 680 MarkBlockPoolDataAsShared(constBlock); 681 682 std::shared_ptr<C2Buffer> buffer = C2Buffer::CreateGraphicBuffer(std::move(constBlock)); 683 if (mPendingColorAspectsChange && 684 work->input.ordinal.frameIndex.peeku() >= mPendingColorAspectsChangeFrameIndex) { 685 updateColorAspects(); 686 mPendingColorAspectsChange = false; 687 } 688 if (mCurrentColorAspects) { 689 buffer->setInfo(mCurrentColorAspects); 690 } 691 work->worklets.front()->output.buffers.emplace_back(std::move(buffer)); 692 info->mGraphicBlock.reset(); 693 } 694 reportWorkIfFinished(nextBuffer.mBitstreamId); 695 mPendingBuffersToWork.pop_front(); 696 } 697 } 698 699 void C2VDAComponent::updateUndequeuedBlockIds(int32_t blockId) { 700 // The size of |mUndequedBlockIds| will always be the minimum buffer count for display. 701 mUndequeuedBlockIds.push_back(blockId); 702 mUndequeuedBlockIds.pop_front(); 703 } 704 705 void C2VDAComponent::onDrain(uint32_t drainMode) { 706 DCHECK(mTaskRunner->BelongsToCurrentThread()); 707 ALOGV("onDrain: mode = %u", drainMode); 708 EXPECT_RUNNING_OR_RETURN_ON_ERROR(); 709 710 if (!mQueue.empty()) { 711 // Mark last queued work as "drain-till-here" by setting drainMode. Do not change drainMode 712 // if last work already has one. 713 if (mQueue.back().mDrainMode == NO_DRAIN) { 714 mQueue.back().mDrainMode = drainMode; 715 } 716 } else if (!mPendingWorks.empty()) { 717 // Neglect drain request if component is not in STARTED mode. Otherwise, enters DRAINING 718 // mode and signal VDA flush immediately. 719 if (mComponentState == ComponentState::STARTED) { 720 mVDAAdaptor->flush(); 721 mComponentState = ComponentState::DRAINING; 722 mPendingOutputEOS = drainMode == DRAIN_COMPONENT_WITH_EOS; 723 } else { 724 ALOGV("Neglect drain. Component in state: %d", mComponentState); 725 } 726 } else { 727 // Do nothing. 728 ALOGV("No buffers in VDA, drain takes no effect."); 729 } 730 } 731 732 void C2VDAComponent::onDrainDone() { 733 DCHECK(mTaskRunner->BelongsToCurrentThread()); 734 ALOGV("onDrainDone"); 735 if (mComponentState == ComponentState::DRAINING) { 736 mComponentState = ComponentState::STARTED; 737 } else if (mComponentState == ComponentState::STOPPING) { 738 // The client signals stop right before VDA notifies drain done. Let stop process goes. 739 return; 740 } else if (mComponentState != ComponentState::FLUSHING) { 741 // It is reasonable to get onDrainDone in FLUSHING, which means flush is already signaled 742 // and component should still expect onFlushDone callback from VDA. 743 ALOGE("Unexpected state while onDrainDone(). State=%d", mComponentState); 744 reportError(C2_BAD_STATE); 745 return; 746 } 747 748 // Drop all pending existing frames and return all finished works before drain done. 749 sendOutputBufferToWorkIfAny(true /* dropIfUnavailable */); 750 CHECK(mPendingBuffersToWork.empty()); 751 752 if (mPendingOutputEOS) { 753 // Return EOS work. 754 reportEOSWork(); 755 } 756 // mPendingWorks must be empty after draining is finished. 757 CHECK(mPendingWorks.empty()); 758 759 // Work dequeueing was stopped while component draining. Restart it. 760 mTaskRunner->PostTask(FROM_HERE, 761 ::base::Bind(&C2VDAComponent::onDequeueWork, ::base::Unretained(this))); 762 } 763 764 void C2VDAComponent::onFlush() { 765 DCHECK(mTaskRunner->BelongsToCurrentThread()); 766 ALOGV("onFlush"); 767 if (mComponentState == ComponentState::FLUSHING || 768 mComponentState == ComponentState::STOPPING) { 769 return; // Ignore other flush request when component is flushing or stopping. 770 } 771 EXPECT_RUNNING_OR_RETURN_ON_ERROR(); 772 773 mVDAAdaptor->reset(); 774 // Pop all works in mQueue and put into mAbandonedWorks. 775 while (!mQueue.empty()) { 776 mAbandonedWorks.emplace_back(std::move(mQueue.front().mWork)); 777 mQueue.pop(); 778 } 779 mComponentState = ComponentState::FLUSHING; 780 } 781 782 void C2VDAComponent::onStop(::base::WaitableEvent* done) { 783 DCHECK(mTaskRunner->BelongsToCurrentThread()); 784 ALOGV("onStop"); 785 EXPECT_RUNNING_OR_RETURN_ON_ERROR(); 786 787 // Do not request VDA reset again before the previous one is done. If reset is already sent by 788 // onFlush(), just regard the following NotifyResetDone callback as for stopping. 789 if (mComponentState != ComponentState::FLUSHING) { 790 mVDAAdaptor->reset(); 791 } 792 793 // Pop all works in mQueue and put into mAbandonedWorks. 794 while (!mQueue.empty()) { 795 mAbandonedWorks.emplace_back(std::move(mQueue.front().mWork)); 796 mQueue.pop(); 797 } 798 799 mStopDoneEvent = done; // restore done event which shoud be signaled in onStopDone(). 800 mComponentState = ComponentState::STOPPING; 801 } 802 803 void C2VDAComponent::onResetDone() { 804 DCHECK(mTaskRunner->BelongsToCurrentThread()); 805 if (mComponentState == ComponentState::ERROR) { 806 return; 807 } 808 if (mComponentState == ComponentState::FLUSHING) { 809 onFlushDone(); 810 } else if (mComponentState == ComponentState::STOPPING) { 811 onStopDone(); 812 } else { 813 reportError(C2_CORRUPTED); 814 } 815 } 816 817 void C2VDAComponent::onFlushDone() { 818 ALOGV("onFlushDone"); 819 reportAbandonedWorks(); 820 mPendingBuffersToWork.clear(); 821 mComponentState = ComponentState::STARTED; 822 823 // Work dequeueing was stopped while component flushing. Restart it. 824 mTaskRunner->PostTask(FROM_HERE, 825 ::base::Bind(&C2VDAComponent::onDequeueWork, ::base::Unretained(this))); 826 } 827 828 void C2VDAComponent::onStopDone() { 829 ALOGV("onStopDone"); 830 CHECK(mStopDoneEvent); 831 832 // TODO(johnylin): At this moment, there may be C2Buffer still owned by client, do we need to 833 // do something for them? 834 reportAbandonedWorks(); 835 mPendingOutputFormat.reset(); 836 mPendingBuffersToWork.clear(); 837 if (mVDAAdaptor.get()) { 838 mVDAAdaptor->destroy(); 839 mVDAAdaptor.reset(nullptr); 840 } 841 842 stopDequeueThread(); 843 mGraphicBlocks.clear(); 844 845 mStopDoneEvent->Signal(); 846 mStopDoneEvent = nullptr; 847 mComponentState = ComponentState::UNINITIALIZED; 848 } 849 850 c2_status_t C2VDAComponent::setListener_vb(const std::shared_ptr<C2Component::Listener>& listener, 851 c2_blocking_t mayBlock) { 852 UNUSED(mayBlock); 853 // TODO(johnylin): API says this method must be supported in all states, however I'm quite not 854 // sure what is the use case. 855 if (mState.load() != State::LOADED) { 856 return C2_BAD_STATE; 857 } 858 mListener = listener; 859 return C2_OK; 860 } 861 862 void C2VDAComponent::sendInputBufferToAccelerator(const C2ConstLinearBlock& input, 863 int32_t bitstreamId) { 864 ALOGV("sendInputBufferToAccelerator"); 865 int dupFd = dup(input.handle()->data[0]); 866 if (dupFd < 0) { 867 ALOGE("Failed to dup(%d) input buffer (bitstreamId=%d), errno=%d", input.handle()->data[0], 868 bitstreamId, errno); 869 reportError(C2_CORRUPTED); 870 return; 871 } 872 ALOGV("Decode bitstream ID: %d, offset: %u size: %u", bitstreamId, input.offset(), 873 input.size()); 874 mVDAAdaptor->decode(bitstreamId, dupFd, input.offset(), input.size()); 875 } 876 877 std::deque<std::unique_ptr<C2Work>>::iterator C2VDAComponent::findPendingWorkByBitstreamId( 878 int32_t bitstreamId) { 879 return std::find_if(mPendingWorks.begin(), mPendingWorks.end(), 880 [bitstreamId](const std::unique_ptr<C2Work>& w) { 881 return frameIndexToBitstreamId(w->input.ordinal.frameIndex) == 882 bitstreamId; 883 }); 884 } 885 886 C2Work* C2VDAComponent::getPendingWorkByBitstreamId(int32_t bitstreamId) { 887 auto workIter = findPendingWorkByBitstreamId(bitstreamId); 888 if (workIter == mPendingWorks.end()) { 889 ALOGE("Can't find pending work by bitstream ID: %d", bitstreamId); 890 return nullptr; 891 } 892 return workIter->get(); 893 } 894 895 C2VDAComponent::GraphicBlockInfo* C2VDAComponent::getGraphicBlockById(int32_t blockId) { 896 if (blockId < 0 || blockId >= static_cast<int32_t>(mGraphicBlocks.size())) { 897 ALOGE("getGraphicBlockById failed: id=%d", blockId); 898 return nullptr; 899 } 900 return &mGraphicBlocks[blockId]; 901 } 902 903 C2VDAComponent::GraphicBlockInfo* C2VDAComponent::getGraphicBlockByPoolId(uint32_t poolId) { 904 auto blockIter = std::find_if(mGraphicBlocks.begin(), mGraphicBlocks.end(), 905 [poolId](const GraphicBlockInfo& gb) { 906 return gb.mPoolId == poolId; 907 }); 908 909 if (blockIter == mGraphicBlocks.end()) { 910 ALOGE("getGraphicBlockByPoolId failed: poolId=%u", poolId); 911 return nullptr; 912 } 913 return &(*blockIter); 914 } 915 916 void C2VDAComponent::onOutputFormatChanged(std::unique_ptr<VideoFormat> format) { 917 DCHECK(mTaskRunner->BelongsToCurrentThread()); 918 ALOGV("onOutputFormatChanged"); 919 EXPECT_RUNNING_OR_RETURN_ON_ERROR(); 920 921 ALOGV("New output format(pixel_format=0x%x, min_num_buffers=%u, coded_size=%s, crop_rect=%s)", 922 static_cast<uint32_t>(format->mPixelFormat), format->mMinNumBuffers, 923 format->mCodedSize.ToString().c_str(), format->mVisibleRect.ToString().c_str()); 924 925 for (auto& info : mGraphicBlocks) { 926 if (info.mState == GraphicBlockInfo::State::OWNED_BY_ACCELERATOR) 927 info.mState = GraphicBlockInfo::State::OWNED_BY_COMPONENT; 928 } 929 930 CHECK(!mPendingOutputFormat); 931 mPendingOutputFormat = std::move(format); 932 tryChangeOutputFormat(); 933 } 934 935 void C2VDAComponent::tryChangeOutputFormat() { 936 DCHECK(mTaskRunner->BelongsToCurrentThread()); 937 ALOGV("tryChangeOutputFormat"); 938 CHECK(mPendingOutputFormat); 939 940 // At this point, all output buffers should not be owned by accelerator. The component is not 941 // able to know when a client will release all owned output buffers by now. But it is ok to 942 // leave them to client since componenet won't own those buffers anymore. 943 // TODO(johnylin): we may also set a parameter for component to keep dequeueing buffers and 944 // change format only after the component owns most buffers. This may prevent 945 // too many buffers are still on client's hand while component starts to 946 // allocate more buffers. However, it leads latency on output format change. 947 for (const auto& info : mGraphicBlocks) { 948 CHECK(info.mState != GraphicBlockInfo::State::OWNED_BY_ACCELERATOR); 949 } 950 951 // Drop all pending existing frames and return all finished works before changing output format. 952 sendOutputBufferToWorkIfAny(true /* dropIfUnavailable */); 953 CHECK(mPendingBuffersToWork.empty()); 954 955 CHECK_EQ(mPendingOutputFormat->mPixelFormat, HalPixelFormat::YCbCr_420_888); 956 957 mOutputFormat.mPixelFormat = mPendingOutputFormat->mPixelFormat; 958 mOutputFormat.mMinNumBuffers = mPendingOutputFormat->mMinNumBuffers; 959 mOutputFormat.mCodedSize = mPendingOutputFormat->mCodedSize; 960 961 setOutputFormatCrop(mPendingOutputFormat->mVisibleRect); 962 963 c2_status_t err = allocateBuffersFromBlockAllocator( 964 mPendingOutputFormat->mCodedSize, 965 static_cast<uint32_t>(mPendingOutputFormat->mPixelFormat)); 966 if (err != C2_OK) { 967 reportError(err); 968 return; 969 } 970 971 for (auto& info : mGraphicBlocks) { 972 sendOutputBufferToAccelerator(&info, true /* ownByAccelerator */); 973 } 974 mPendingOutputFormat.reset(); 975 } 976 977 c2_status_t C2VDAComponent::allocateBuffersFromBlockAllocator(const media::Size& size, 978 uint32_t pixelFormat) { 979 ALOGV("allocateBuffersFromBlockAllocator(%s, 0x%x)", size.ToString().c_str(), pixelFormat); 980 981 stopDequeueThread(); 982 983 size_t bufferCount = mOutputFormat.mMinNumBuffers + kDpbOutputBufferExtraCount; 984 985 // Allocate the output buffers. 986 mVDAAdaptor->assignPictureBuffers(bufferCount); 987 988 // Get block pool ID configured from the client. 989 std::shared_ptr<C2BlockPool> blockPool; 990 auto poolId = mIntfImpl->getBlockPoolId(); 991 ALOGI("Using C2BlockPool ID = %" PRIu64 " for allocating output buffers", poolId); 992 auto err = GetCodec2BlockPool(poolId, shared_from_this(), &blockPool); 993 if (err != C2_OK) { 994 ALOGE("Graphic block allocator is invalid"); 995 reportError(err); 996 return err; 997 } 998 999 mGraphicBlocks.clear(); 1000 1001 bool useBufferQueue = blockPool->getAllocatorId() == C2PlatformAllocatorStore::BUFFERQUEUE; 1002 size_t minBuffersForDisplay = 0; 1003 if (useBufferQueue) { 1004 ALOGV("Bufferqueue-backed block pool is used."); 1005 // Set requested buffer count to C2VdaBqBlockPool. 1006 std::shared_ptr<C2VdaBqBlockPool> bqPool = 1007 std::static_pointer_cast<C2VdaBqBlockPool>(blockPool); 1008 if (bqPool) { 1009 err = bqPool->requestNewBufferSet(static_cast<int32_t>(bufferCount)); 1010 if (err != C2_OK) { 1011 ALOGE("failed to request new buffer set to block pool: %d", err); 1012 reportError(err); 1013 return err; 1014 } 1015 err = bqPool->getMinBuffersForDisplay(&minBuffersForDisplay); 1016 if (err != C2_OK) { 1017 ALOGE("failed to query minimum undequeued buffer count from block pool: %d", err); 1018 reportError(err); 1019 return err; 1020 } 1021 } else { 1022 ALOGE("static_pointer_cast C2VdaBqBlockPool failed..."); 1023 reportError(C2_CORRUPTED); 1024 return C2_CORRUPTED; 1025 } 1026 } else { 1027 ALOGV("Bufferpool-backed block pool is used."); 1028 // Set requested buffer count to C2VdaPooledBlockPool. 1029 std::shared_ptr<C2VdaPooledBlockPool> bpPool = 1030 std::static_pointer_cast<C2VdaPooledBlockPool>(blockPool); 1031 if (bpPool) { 1032 err = bpPool->requestNewBufferSet(static_cast<int32_t>(bufferCount)); 1033 if (err != C2_OK) { 1034 ALOGE("failed to request new buffer set to block pool: %d", err); 1035 reportError(err); 1036 return err; 1037 } 1038 minBuffersForDisplay = 0; // no undequeued buffer restriction for bufferpool. 1039 } else { 1040 ALOGE("static_pointer_cast C2VdaPooledBlockPool failed..."); 1041 reportError(C2_CORRUPTED); 1042 return C2_CORRUPTED; 1043 } 1044 } 1045 1046 ALOGV("Minimum undequeued buffer count = %zu", minBuffersForDisplay); 1047 mUndequeuedBlockIds.resize(minBuffersForDisplay, -1); 1048 1049 for (size_t i = 0; i < bufferCount; ++i) { 1050 std::shared_ptr<C2GraphicBlock> block; 1051 C2MemoryUsage usage = { 1052 mSecureMode ? C2MemoryUsage::READ_PROTECTED : C2MemoryUsage::CPU_READ, 0}; 1053 1054 int32_t retries_left = kAllocateBufferMaxRetries; 1055 err = C2_NO_INIT; 1056 while (err != C2_OK) { 1057 err = blockPool->fetchGraphicBlock(size.width(), size.height(), pixelFormat, usage, 1058 &block); 1059 if (err == C2_TIMED_OUT && retries_left > 0) { 1060 ALOGD("allocate buffer timeout, %d retry time(s) left...", retries_left); 1061 retries_left--; 1062 } else if (err != C2_OK) { 1063 mGraphicBlocks.clear(); 1064 ALOGE("failed to allocate buffer: %d", err); 1065 reportError(err); 1066 return err; 1067 } 1068 } 1069 1070 uint32_t poolId; 1071 if (useBufferQueue) { 1072 err = C2VdaBqBlockPool::getPoolIdFromGraphicBlock(block, &poolId); 1073 } else { // use bufferpool 1074 err = C2VdaPooledBlockPool::getPoolIdFromGraphicBlock(block, &poolId); 1075 } 1076 if (err != C2_OK) { 1077 mGraphicBlocks.clear(); 1078 ALOGE("failed to getPoolIdFromGraphicBlock: %d", err); 1079 reportError(err); 1080 return err; 1081 } 1082 if (mSecureMode) { 1083 appendSecureOutputBuffer(std::move(block), poolId); 1084 } else { 1085 appendOutputBuffer(std::move(block), poolId); 1086 } 1087 } 1088 mOutputFormat.mMinNumBuffers = bufferCount; 1089 1090 if (!startDequeueThread(size, pixelFormat, std::move(blockPool), 1091 true /* resetBuffersInClient */)) { 1092 reportError(C2_CORRUPTED); 1093 return C2_CORRUPTED; 1094 } 1095 return C2_OK; 1096 } 1097 1098 void C2VDAComponent::appendOutputBuffer(std::shared_ptr<C2GraphicBlock> block, uint32_t poolId) { 1099 GraphicBlockInfo info; 1100 info.mBlockId = static_cast<int32_t>(mGraphicBlocks.size()); 1101 info.mGraphicBlock = std::move(block); 1102 info.mPoolId = poolId; 1103 1104 C2ConstGraphicBlock constBlock = info.mGraphicBlock->share( 1105 C2Rect(info.mGraphicBlock->width(), info.mGraphicBlock->height()), C2Fence()); 1106 1107 const C2GraphicView& view = constBlock.map().get(); 1108 const uint8_t* const* data = view.data(); 1109 CHECK_NE(data, nullptr); 1110 const C2PlanarLayout& layout = view.layout(); 1111 1112 ALOGV("allocate graphic buffer: %p, id: %d, size: %dx%d", info.mGraphicBlock->handle(), 1113 info.mBlockId, info.mGraphicBlock->width(), info.mGraphicBlock->height()); 1114 1115 // get offset from data pointers 1116 uint32_t offsets[C2PlanarLayout::MAX_NUM_PLANES]; 1117 auto baseAddress = reinterpret_cast<intptr_t>(data[0]); 1118 for (uint32_t i = 0; i < layout.numPlanes; ++i) { 1119 auto planeAddress = reinterpret_cast<intptr_t>(data[i]); 1120 offsets[i] = static_cast<uint32_t>(planeAddress - baseAddress); 1121 } 1122 1123 bool crcb = false; 1124 if (layout.numPlanes == 3 && 1125 offsets[C2PlanarLayout::PLANE_U] > offsets[C2PlanarLayout::PLANE_V]) { 1126 // YCrCb format 1127 std::swap(offsets[C2PlanarLayout::PLANE_U], offsets[C2PlanarLayout::PLANE_V]); 1128 crcb = true; 1129 } 1130 1131 bool semiplanar = false; 1132 uint32_t passedNumPlanes = layout.numPlanes; 1133 if (layout.planes[C2PlanarLayout::PLANE_U].colInc == 2) { // chroma_step 1134 // Semi-planar format 1135 passedNumPlanes--; 1136 semiplanar = true; 1137 } 1138 1139 for (uint32_t i = 0; i < passedNumPlanes; ++i) { 1140 ALOGV("plane %u: stride: %d, offset: %u", i, layout.planes[i].rowInc, offsets[i]); 1141 } 1142 info.mPixelFormat = resolveBufferFormat(crcb, semiplanar); 1143 ALOGV("HAL pixel format: 0x%x", static_cast<uint32_t>(info.mPixelFormat)); 1144 1145 ::base::ScopedFD passedHandle(dup(info.mGraphicBlock->handle()->data[0])); 1146 if (!passedHandle.is_valid()) { 1147 ALOGE("Failed to dup(%d), errno=%d", info.mGraphicBlock->handle()->data[0], errno); 1148 reportError(C2_CORRUPTED); 1149 return; 1150 } 1151 std::vector<VideoFramePlane> passedPlanes; 1152 for (uint32_t i = 0; i < passedNumPlanes; ++i) { 1153 CHECK_GT(layout.planes[i].rowInc, 0); 1154 passedPlanes.push_back({offsets[i], static_cast<uint32_t>(layout.planes[i].rowInc)}); 1155 } 1156 info.mHandle = std::move(passedHandle); 1157 info.mPlanes = std::move(passedPlanes); 1158 1159 mGraphicBlocks.push_back(std::move(info)); 1160 } 1161 1162 void C2VDAComponent::appendSecureOutputBuffer(std::shared_ptr<C2GraphicBlock> block, 1163 uint32_t poolId) { 1164 #ifdef V4L2_CODEC2_ARC 1165 const C2Handle* const handle = block->handle(); 1166 const int handleFd = handle->data[0]; 1167 ::base::ScopedFD passedHandle(dup(handleFd)); 1168 if (!passedHandle.is_valid()) { 1169 ALOGE("Failed to dup(%d), errno=%d", handleFd, errno); 1170 reportError(C2_CORRUPTED); 1171 return; 1172 } 1173 1174 android::HalPixelFormat pixelFormat = getPlatformPixelFormat(); 1175 if (pixelFormat == android::HalPixelFormat::UNKNOWN) { 1176 ALOGE("Failed to get pixel format on platform."); 1177 reportError(C2_CORRUPTED); 1178 return; 1179 } 1180 CHECK(pixelFormat == android::HalPixelFormat::YV12 || 1181 pixelFormat == android::HalPixelFormat::NV12); 1182 ALOGV("HAL pixel format: 0x%x", static_cast<uint32_t>(pixelFormat)); 1183 1184 GraphicBlockInfo info; 1185 info.mBlockId = static_cast<int32_t>(mGraphicBlocks.size()); 1186 info.mGraphicBlock = std::move(block); 1187 info.mPoolId = poolId; 1188 info.mHandle = std::move(passedHandle); 1189 info.mPixelFormat = pixelFormat; 1190 // In secure mode, since planes are not referred in Chrome side, empty plane is valid. 1191 info.mPlanes.clear(); 1192 mGraphicBlocks.push_back(std::move(info)); 1193 #else 1194 ALOGE("appendSecureOutputBuffer() is not supported..."); 1195 reportError(C2_OMITTED); 1196 #endif // V4L2_CODEC2_ARC 1197 } 1198 1199 void C2VDAComponent::sendOutputBufferToAccelerator(GraphicBlockInfo* info, bool ownByAccelerator) { 1200 DCHECK(mTaskRunner->BelongsToCurrentThread()); 1201 ALOGV("sendOutputBufferToAccelerator index=%d ownByAccelerator=%d", info->mBlockId, 1202 ownByAccelerator); 1203 1204 if (ownByAccelerator) { 1205 CHECK_EQ(info->mState, GraphicBlockInfo::State::OWNED_BY_COMPONENT); 1206 info->mState = GraphicBlockInfo::State::OWNED_BY_ACCELERATOR; 1207 } 1208 1209 // is_valid() is true for the first time the buffer is passed to VDA. In that case, VDA needs to 1210 // import the buffer first. 1211 if (info->mHandle.is_valid()) { 1212 mVDAAdaptor->importBufferForPicture(info->mBlockId, info->mPixelFormat, 1213 info->mHandle.release(), info->mPlanes); 1214 } else { 1215 mVDAAdaptor->reusePictureBuffer(info->mBlockId); 1216 } 1217 } 1218 1219 bool C2VDAComponent::parseCodedColorAspects(const C2ConstLinearBlock& input) { 1220 C2ReadView view = input.map().get(); 1221 const uint8_t* data = view.data(); 1222 const uint32_t size = view.capacity(); 1223 1224 std::unique_ptr<media::H264Parser> h264Parser = std::make_unique<media::H264Parser>(); 1225 h264Parser->SetStream(data, static_cast<off_t>(size)); 1226 media::H264NALU nalu; 1227 media::H264Parser::Result parRes = h264Parser->AdvanceToNextNALU(&nalu); 1228 if (parRes != media::H264Parser::kEOStream && parRes != media::H264Parser::kOk) { 1229 ALOGE("H264 AdvanceToNextNALU error: %d", static_cast<int>(parRes)); 1230 return false; 1231 } 1232 if (nalu.nal_unit_type != media::H264NALU::kSPS) { 1233 ALOGV("NALU is not SPS"); 1234 return false; 1235 } 1236 1237 int spsId; 1238 parRes = h264Parser->ParseSPS(&spsId); 1239 if (parRes != media::H264Parser::kEOStream && parRes != media::H264Parser::kOk) { 1240 ALOGE("H264 ParseSPS error: %d", static_cast<int>(parRes)); 1241 return false; 1242 } 1243 1244 // Parse ISO color aspects from H264 SPS bitstream. 1245 const media::H264SPS* sps = h264Parser->GetSPS(spsId); 1246 if (!sps->colour_description_present_flag) { 1247 ALOGV("No Color Description in SPS"); 1248 return false; 1249 } 1250 int32_t primaries = sps->colour_primaries; 1251 int32_t transfer = sps->transfer_characteristics; 1252 int32_t coeffs = sps->matrix_coefficients; 1253 bool fullRange = sps->video_full_range_flag; 1254 1255 // Convert ISO color aspects to ColorUtils::ColorAspects. 1256 ColorAspects colorAspects; 1257 ColorUtils::convertIsoColorAspectsToCodecAspects(primaries, transfer, coeffs, fullRange, 1258 colorAspects); 1259 ALOGV("Parsed ColorAspects from bitstream: (R:%d, P:%d, M:%d, T:%d)", colorAspects.mRange, 1260 colorAspects.mPrimaries, colorAspects.mMatrixCoeffs, colorAspects.mTransfer); 1261 1262 // Map ColorUtils::ColorAspects to C2StreamColorAspectsInfo::input parameter. 1263 C2StreamColorAspectsInfo::input codedAspects = {0u}; 1264 if (!C2Mapper::map(colorAspects.mPrimaries, &codedAspects.primaries)) { 1265 codedAspects.primaries = C2Color::PRIMARIES_UNSPECIFIED; 1266 } 1267 if (!C2Mapper::map(colorAspects.mRange, &codedAspects.range)) { 1268 codedAspects.range = C2Color::RANGE_UNSPECIFIED; 1269 } 1270 if (!C2Mapper::map(colorAspects.mMatrixCoeffs, &codedAspects.matrix)) { 1271 codedAspects.matrix = C2Color::MATRIX_UNSPECIFIED; 1272 } 1273 if (!C2Mapper::map(colorAspects.mTransfer, &codedAspects.transfer)) { 1274 codedAspects.transfer = C2Color::TRANSFER_UNSPECIFIED; 1275 } 1276 // Configure to interface. 1277 std::vector<std::unique_ptr<C2SettingResult>> failures; 1278 c2_status_t status = mIntfImpl->config({&codedAspects}, C2_MAY_BLOCK, &failures); 1279 if (status != C2_OK) { 1280 ALOGE("Failed to config color aspects to interface, error: %d", status); 1281 return false; 1282 } 1283 return true; 1284 } 1285 1286 c2_status_t C2VDAComponent::updateColorAspects() { 1287 ALOGV("updateColorAspects"); 1288 std::unique_ptr<C2StreamColorAspectsInfo::output> colorAspects = 1289 std::make_unique<C2StreamColorAspectsInfo::output>( 1290 0u, C2Color::RANGE_UNSPECIFIED, C2Color::PRIMARIES_UNSPECIFIED, 1291 C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED); 1292 c2_status_t status = mIntfImpl->query({colorAspects.get()}, {}, C2_DONT_BLOCK, nullptr); 1293 if (status != C2_OK) { 1294 ALOGE("Failed to query color aspects, error: %d", status); 1295 return status; 1296 } 1297 mCurrentColorAspects = std::move(colorAspects); 1298 return C2_OK; 1299 } 1300 1301 void C2VDAComponent::onVisibleRectChanged(const media::Rect& cropRect) { 1302 DCHECK(mTaskRunner->BelongsToCurrentThread()); 1303 ALOGV("onVisibleRectChanged"); 1304 EXPECT_RUNNING_OR_RETURN_ON_ERROR(); 1305 1306 // We should make sure there is no pending output format change. That is, the input cropRect is 1307 // corresponding to current output format. 1308 CHECK(mPendingOutputFormat == nullptr); 1309 setOutputFormatCrop(cropRect); 1310 } 1311 1312 void C2VDAComponent::setOutputFormatCrop(const media::Rect& cropRect) { 1313 ALOGV("setOutputFormatCrop(%dx%d)", cropRect.width(), cropRect.height()); 1314 // This visible rect should be set as crop window for each C2ConstGraphicBlock passed to 1315 // framework. 1316 mOutputFormat.mVisibleRect = cropRect; 1317 } 1318 1319 void C2VDAComponent::onSurfaceChanged() { 1320 DCHECK(mTaskRunner->BelongsToCurrentThread()); 1321 ALOGV("onSurfaceChanged"); 1322 1323 if (mComponentState == ComponentState::UNINITIALIZED) { 1324 return; // Component is already stopped, no need to update graphic blocks. 1325 } 1326 1327 stopDequeueThread(); 1328 1329 // Get block pool ID configured from the client. 1330 std::shared_ptr<C2BlockPool> blockPool; 1331 auto blockPoolId = mIntfImpl->getBlockPoolId(); 1332 ALOGI("Retrieving C2BlockPool ID = %" PRIu64 " for updating output buffers", blockPoolId); 1333 auto err = GetCodec2BlockPool(blockPoolId, shared_from_this(), &blockPool); 1334 if (err != C2_OK) { 1335 ALOGE("Graphic block allocator is invalid"); 1336 reportError(err); 1337 return; 1338 } 1339 if (blockPool->getAllocatorId() != C2PlatformAllocatorStore::BUFFERQUEUE) { 1340 ALOGE("Only Bufferqueue-backed block pool would need to change surface."); 1341 reportError(C2_CORRUPTED); 1342 return; 1343 } 1344 1345 std::shared_ptr<C2VdaBqBlockPool> bqPool = 1346 std::static_pointer_cast<C2VdaBqBlockPool>(blockPool); 1347 if (!bqPool) { 1348 ALOGE("static_pointer_cast C2VdaBqBlockPool failed..."); 1349 reportError(C2_CORRUPTED); 1350 return; 1351 } 1352 1353 size_t minBuffersForDisplay = 0; 1354 err = bqPool->getMinBuffersForDisplay(&minBuffersForDisplay); 1355 if (err != C2_OK) { 1356 ALOGE("failed to query minimum undequeued buffer count from block pool: %d", err); 1357 reportError(err); 1358 return; 1359 } 1360 ALOGV("Minimum undequeued buffer count = %zu", minBuffersForDisplay); 1361 mUndequeuedBlockIds.resize(minBuffersForDisplay, -1); 1362 1363 for (auto& info : mGraphicBlocks) { 1364 bool willCancel = (info.mGraphicBlock == nullptr); 1365 uint32_t oldSlot = info.mPoolId; 1366 ALOGV("Updating graphic block #%d: slot = %u, willCancel = %d", info.mBlockId, oldSlot, 1367 willCancel); 1368 uint32_t newSlot; 1369 std::shared_ptr<C2GraphicBlock> block; 1370 err = bqPool->updateGraphicBlock(willCancel, oldSlot, &newSlot, &block); 1371 if (err == C2_CANCELED) { 1372 // There may be a chance that a task in task runner before onSurfaceChange triggers 1373 // output format change. If so, block pool will return C2_CANCELED and no need to 1374 // updateGraphicBlock anymore. 1375 return; 1376 } 1377 if (err != C2_OK) { 1378 ALOGE("failed to update graphic block from block pool: %d", err); 1379 reportError(err); 1380 return; 1381 } 1382 1383 // Update slot index. 1384 info.mPoolId = newSlot; 1385 // Update C2GraphicBlock if |willCancel| is false. Note that although the old C2GraphicBlock 1386 // will be released, the block pool data destructor won't do detachBuffer to new surface 1387 // because the producer ID is not matched. 1388 if (!willCancel) { 1389 info.mGraphicBlock = std::move(block); 1390 } 1391 } 1392 1393 if (!startDequeueThread(mOutputFormat.mCodedSize, 1394 static_cast<uint32_t>(mOutputFormat.mPixelFormat), std::move(blockPool), 1395 false /* resetBuffersInClient */)) { 1396 reportError(C2_CORRUPTED); 1397 } 1398 } 1399 1400 c2_status_t C2VDAComponent::queue_nb(std::list<std::unique_ptr<C2Work>>* const items) { 1401 if (mState.load() != State::RUNNING) { 1402 return C2_BAD_STATE; 1403 } 1404 while (!items->empty()) { 1405 mTaskRunner->PostTask(FROM_HERE, 1406 ::base::Bind(&C2VDAComponent::onQueueWork, ::base::Unretained(this), 1407 ::base::Passed(&items->front()))); 1408 items->pop_front(); 1409 } 1410 return C2_OK; 1411 } 1412 1413 c2_status_t C2VDAComponent::announce_nb(const std::vector<C2WorkOutline>& items) { 1414 UNUSED(items); 1415 return C2_OMITTED; // Tunneling is not supported by now 1416 } 1417 1418 c2_status_t C2VDAComponent::flush_sm(flush_mode_t mode, 1419 std::list<std::unique_ptr<C2Work>>* const flushedWork) { 1420 if (mode != FLUSH_COMPONENT) { 1421 return C2_OMITTED; // Tunneling is not supported by now 1422 } 1423 if (mState.load() != State::RUNNING) { 1424 return C2_BAD_STATE; 1425 } 1426 mTaskRunner->PostTask(FROM_HERE, ::base::Bind(&C2VDAComponent::onFlush, 1427 ::base::Unretained(this))); 1428 // Instead of |flushedWork|, abandoned works will be returned via onWorkDone_nb() callback. 1429 return C2_OK; 1430 } 1431 1432 c2_status_t C2VDAComponent::drain_nb(drain_mode_t mode) { 1433 if (mode != DRAIN_COMPONENT_WITH_EOS && mode != DRAIN_COMPONENT_NO_EOS) { 1434 return C2_OMITTED; // Tunneling is not supported by now 1435 } 1436 if (mState.load() != State::RUNNING) { 1437 return C2_BAD_STATE; 1438 } 1439 mTaskRunner->PostTask(FROM_HERE, 1440 ::base::Bind(&C2VDAComponent::onDrain, ::base::Unretained(this), 1441 static_cast<uint32_t>(mode))); 1442 return C2_OK; 1443 } 1444 1445 c2_status_t C2VDAComponent::start() { 1446 // Use mStartStopLock to block other asynchronously start/stop calls. 1447 std::lock_guard<std::mutex> lock(mStartStopLock); 1448 1449 if (mState.load() != State::LOADED) { 1450 return C2_BAD_STATE; // start() is only supported when component is in LOADED state. 1451 } 1452 1453 mCodecProfile = mIntfImpl->getCodecProfile(); 1454 ALOGI("get parameter: mCodecProfile = %d", static_cast<int>(mCodecProfile)); 1455 1456 ::base::WaitableEvent done(::base::WaitableEvent::ResetPolicy::AUTOMATIC, 1457 ::base::WaitableEvent::InitialState::NOT_SIGNALED); 1458 mTaskRunner->PostTask(FROM_HERE, 1459 ::base::Bind(&C2VDAComponent::onStart, ::base::Unretained(this), 1460 mCodecProfile, &done)); 1461 done.Wait(); 1462 c2_status_t c2Status = adaptorResultToC2Status(mVDAInitResult); 1463 if (c2Status != C2_OK) { 1464 ALOGE("Failed to start component due to VDA error..."); 1465 return c2Status; 1466 } 1467 mState.store(State::RUNNING); 1468 return C2_OK; 1469 } 1470 1471 c2_status_t C2VDAComponent::stop() { 1472 // Use mStartStopLock to block other asynchronously start/stop calls. 1473 std::lock_guard<std::mutex> lock(mStartStopLock); 1474 1475 auto state = mState.load(); 1476 if (!(state == State::RUNNING || state == State::ERROR)) { 1477 return C2_OK; // Component is already in stopped state. 1478 } 1479 1480 ::base::WaitableEvent done(::base::WaitableEvent::ResetPolicy::AUTOMATIC, 1481 ::base::WaitableEvent::InitialState::NOT_SIGNALED); 1482 mTaskRunner->PostTask(FROM_HERE, 1483 ::base::Bind(&C2VDAComponent::onStop, ::base::Unretained(this), &done)); 1484 done.Wait(); 1485 mState.store(State::LOADED); 1486 return C2_OK; 1487 } 1488 1489 c2_status_t C2VDAComponent::reset() { 1490 return stop(); 1491 // TODO(johnylin): reset is different than stop that it could be called in any state. 1492 // TODO(johnylin): when reset is called, set ComponentInterface to default values. 1493 } 1494 1495 c2_status_t C2VDAComponent::release() { 1496 return reset(); 1497 } 1498 1499 std::shared_ptr<C2ComponentInterface> C2VDAComponent::intf() { 1500 return mIntf; 1501 } 1502 1503 void C2VDAComponent::providePictureBuffers(uint32_t minNumBuffers, const media::Size& codedSize) { 1504 // Always use fexible pixel 420 format YCbCr_420_888 in Android. 1505 // Uses coded size for crop rect while it is not available. 1506 auto format = std::make_unique<VideoFormat>(HalPixelFormat::YCbCr_420_888, minNumBuffers, 1507 codedSize, media::Rect(codedSize)); 1508 1509 // Set mRequestedVisibleRect to default. 1510 mRequestedVisibleRect = media::Rect(); 1511 1512 mTaskRunner->PostTask(FROM_HERE, ::base::Bind(&C2VDAComponent::onOutputFormatChanged, 1513 ::base::Unretained(this), 1514 ::base::Passed(&format))); 1515 } 1516 1517 void C2VDAComponent::dismissPictureBuffer(int32_t pictureBufferId) { 1518 UNUSED(pictureBufferId); 1519 // no ops 1520 } 1521 1522 void C2VDAComponent::pictureReady(int32_t pictureBufferId, int32_t bitstreamId, 1523 const media::Rect& cropRect) { 1524 UNUSED(pictureBufferId); 1525 UNUSED(bitstreamId); 1526 1527 if (mRequestedVisibleRect != cropRect) { 1528 mRequestedVisibleRect = cropRect; 1529 mTaskRunner->PostTask(FROM_HERE, ::base::Bind(&C2VDAComponent::onVisibleRectChanged, 1530 ::base::Unretained(this), cropRect)); 1531 } 1532 1533 mTaskRunner->PostTask(FROM_HERE, ::base::Bind(&C2VDAComponent::onOutputBufferDone, 1534 ::base::Unretained(this), 1535 pictureBufferId, bitstreamId)); 1536 } 1537 1538 void C2VDAComponent::notifyEndOfBitstreamBuffer(int32_t bitstreamId) { 1539 mTaskRunner->PostTask(FROM_HERE, ::base::Bind(&C2VDAComponent::onInputBufferDone, 1540 ::base::Unretained(this), bitstreamId)); 1541 } 1542 1543 void C2VDAComponent::notifyFlushDone() { 1544 mTaskRunner->PostTask(FROM_HERE, 1545 ::base::Bind(&C2VDAComponent::onDrainDone, ::base::Unretained(this))); 1546 } 1547 1548 void C2VDAComponent::notifyResetDone() { 1549 mTaskRunner->PostTask(FROM_HERE, 1550 ::base::Bind(&C2VDAComponent::onResetDone, ::base::Unretained(this))); 1551 } 1552 1553 void C2VDAComponent::notifyError(VideoDecodeAcceleratorAdaptor::Result error) { 1554 ALOGE("Got notifyError from VDA..."); 1555 c2_status_t err = adaptorResultToC2Status(error); 1556 if (err == C2_OK) { 1557 ALOGW("Shouldn't get SUCCESS err code in NotifyError(). Skip it..."); 1558 return; 1559 } 1560 reportError(err); 1561 } 1562 1563 void C2VDAComponent::reportWorkIfFinished(int32_t bitstreamId) { 1564 DCHECK(mTaskRunner->BelongsToCurrentThread()); 1565 1566 auto workIter = findPendingWorkByBitstreamId(bitstreamId); 1567 if (workIter == mPendingWorks.end()) { 1568 reportError(C2_CORRUPTED); 1569 return; 1570 } 1571 1572 // EOS work will not be reported here. reportEOSWork() does it. 1573 auto work = workIter->get(); 1574 if (isWorkDone(work)) { 1575 if (work->worklets.front()->output.flags & C2FrameData::FLAG_DROP_FRAME) { 1576 // TODO: actually framework does not handle FLAG_DROP_FRAME, use C2_NOT_FOUND result to 1577 // let framework treat this as flushed work. 1578 work->result = C2_NOT_FOUND; 1579 } else { 1580 work->result = C2_OK; 1581 } 1582 work->workletsProcessed = static_cast<uint32_t>(work->worklets.size()); 1583 1584 ALOGV("Reported finished work index=%llu", work->input.ordinal.frameIndex.peekull()); 1585 std::list<std::unique_ptr<C2Work>> finishedWorks; 1586 finishedWorks.emplace_back(std::move(*workIter)); 1587 mListener->onWorkDone_nb(shared_from_this(), std::move(finishedWorks)); 1588 mPendingWorks.erase(workIter); 1589 } 1590 } 1591 1592 bool C2VDAComponent::isWorkDone(const C2Work* work) const { 1593 if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) { 1594 // This is EOS work and should be processed by reportEOSWork(). 1595 return false; 1596 } 1597 if (work->input.buffers.front()) { 1598 // Input buffer is still owned by VDA. 1599 return false; 1600 } 1601 if (mPendingOutputEOS && mPendingWorks.size() == 1u) { 1602 // If mPendingOutputEOS is true, the last returned work should be marked EOS flag and 1603 // returned by reportEOSWork() instead. 1604 return false; 1605 } 1606 if (!(work->input.flags & C2FrameData::FLAG_CODEC_CONFIG) && 1607 !(work->worklets.front()->output.flags & C2FrameData::FLAG_DROP_FRAME) && 1608 work->worklets.front()->output.buffers.empty()) { 1609 // Unless the input is CSD or the output is dropped, this work is not done because the 1610 // output buffer is not returned from VDA yet. 1611 return false; 1612 } 1613 return true; // This work is done. 1614 } 1615 1616 void C2VDAComponent::reportEOSWork() { 1617 ALOGV("reportEOSWork"); 1618 DCHECK(mTaskRunner->BelongsToCurrentThread()); 1619 // In this moment all works prior to EOS work should be done and returned to listener. 1620 if (mPendingWorks.size() != 1u) { // only EOS work left 1621 ALOGE("It shouldn't have remaining works in mPendingWorks except EOS work."); 1622 reportError(C2_CORRUPTED); 1623 return; 1624 } 1625 1626 mPendingOutputEOS = false; 1627 1628 std::unique_ptr<C2Work> eosWork(std::move(mPendingWorks.front())); 1629 mPendingWorks.pop_front(); 1630 if (!eosWork->input.buffers.empty()) { 1631 eosWork->input.buffers.front().reset(); 1632 } 1633 eosWork->result = C2_OK; 1634 eosWork->workletsProcessed = static_cast<uint32_t>(eosWork->worklets.size()); 1635 eosWork->worklets.front()->output.flags = C2FrameData::FLAG_END_OF_STREAM; 1636 1637 std::list<std::unique_ptr<C2Work>> finishedWorks; 1638 finishedWorks.emplace_back(std::move(eosWork)); 1639 mListener->onWorkDone_nb(shared_from_this(), std::move(finishedWorks)); 1640 } 1641 1642 void C2VDAComponent::reportAbandonedWorks() { 1643 DCHECK(mTaskRunner->BelongsToCurrentThread()); 1644 std::list<std::unique_ptr<C2Work>> abandonedWorks; 1645 1646 while (!mPendingWorks.empty()) { 1647 std::unique_ptr<C2Work> work(std::move(mPendingWorks.front())); 1648 mPendingWorks.pop_front(); 1649 1650 // TODO: correlate the definition of flushed work result to framework. 1651 work->result = C2_NOT_FOUND; 1652 // When the work is abandoned, buffer in input.buffers shall reset by component. 1653 if (!work->input.buffers.empty()) { 1654 work->input.buffers.front().reset(); 1655 } 1656 abandonedWorks.emplace_back(std::move(work)); 1657 } 1658 1659 for (auto& work : mAbandonedWorks) { 1660 // TODO: correlate the definition of flushed work result to framework. 1661 work->result = C2_NOT_FOUND; 1662 // When the work is abandoned, buffer in input.buffers shall reset by component. 1663 if (!work->input.buffers.empty()) { 1664 work->input.buffers.front().reset(); 1665 } 1666 abandonedWorks.emplace_back(std::move(work)); 1667 } 1668 mAbandonedWorks.clear(); 1669 1670 // Pending EOS work will be abandoned here due to component flush if any. 1671 mPendingOutputEOS = false; 1672 1673 if (!abandonedWorks.empty()) { 1674 mListener->onWorkDone_nb(shared_from_this(), std::move(abandonedWorks)); 1675 } 1676 } 1677 1678 void C2VDAComponent::reportError(c2_status_t error) { 1679 mListener->onError_nb(shared_from_this(), static_cast<uint32_t>(error)); 1680 } 1681 1682 bool C2VDAComponent::startDequeueThread(const media::Size& size, uint32_t pixelFormat, 1683 std::shared_ptr<C2BlockPool> blockPool, 1684 bool resetBuffersInClient) { 1685 CHECK(!mDequeueThread.IsRunning()); 1686 if (!mDequeueThread.Start()) { 1687 ALOGE("failed to start dequeue thread!!"); 1688 return false; 1689 } 1690 mDequeueLoopStop.store(false); 1691 if (resetBuffersInClient) { 1692 mBuffersInClient.store(0u); 1693 } 1694 mDequeueThread.task_runner()->PostTask( 1695 FROM_HERE, ::base::Bind(&C2VDAComponent::dequeueThreadLoop, ::base::Unretained(this), 1696 size, pixelFormat, std::move(blockPool))); 1697 return true; 1698 } 1699 1700 void C2VDAComponent::stopDequeueThread() { 1701 if (mDequeueThread.IsRunning()) { 1702 mDequeueLoopStop.store(true); 1703 mDequeueThread.Stop(); 1704 } 1705 } 1706 1707 void C2VDAComponent::dequeueThreadLoop(const media::Size& size, uint32_t pixelFormat, 1708 std::shared_ptr<C2BlockPool> blockPool) { 1709 ALOGV("dequeueThreadLoop starts"); 1710 DCHECK(mDequeueThread.task_runner()->BelongsToCurrentThread()); 1711 1712 while (!mDequeueLoopStop.load()) { 1713 if (mBuffersInClient.load() == 0) { 1714 ::usleep(kDequeueRetryDelayUs); // wait for retry 1715 continue; 1716 } 1717 std::shared_ptr<C2GraphicBlock> block; 1718 C2MemoryUsage usage = { 1719 mSecureMode ? C2MemoryUsage::READ_PROTECTED : C2MemoryUsage::CPU_READ, 0}; 1720 auto err = blockPool->fetchGraphicBlock(size.width(), size.height(), pixelFormat, usage, 1721 &block); 1722 if (err == C2_TIMED_OUT) { 1723 // Mutexes often do not care for FIFO. Practically the thread who is locking the mutex 1724 // usually will be granted to lock again right thereafter. To make this loop not too 1725 // bossy, the simpliest way is to add a short delay to the next time acquiring the 1726 // lock. TODO (b/118354314): replace this if there is better solution. 1727 ::usleep(1); 1728 continue; // wait for retry 1729 } 1730 if (err == C2_BAD_STATE) { 1731 ALOGV("Got informed from block pool surface is changed."); 1732 mTaskRunner->PostTask(FROM_HERE, ::base::Bind(&C2VDAComponent::onSurfaceChanged, 1733 ::base::Unretained(this))); 1734 break; // terminate the loop, will be resumed after onSurfaceChanged(). 1735 } 1736 if (err == C2_OK) { 1737 uint32_t poolId; 1738 if (blockPool->getAllocatorId() == C2PlatformAllocatorStore::BUFFERQUEUE) { 1739 err = C2VdaBqBlockPool::getPoolIdFromGraphicBlock(block, &poolId); 1740 } else { // bufferpool 1741 err = C2VdaPooledBlockPool::getPoolIdFromGraphicBlock(block, &poolId); 1742 } 1743 1744 if (err != C2_OK) { 1745 ALOGE("dequeueThreadLoop got error on getPoolIdFromGraphicBlock: %d", err); 1746 break; 1747 } 1748 mTaskRunner->PostTask(FROM_HERE, 1749 ::base::Bind(&C2VDAComponent::onOutputBufferReturned, 1750 ::base::Unretained(this), std::move(block), poolId)); 1751 mBuffersInClient--; 1752 } else { 1753 ALOGE("dequeueThreadLoop got error: %d", err); 1754 break; 1755 } 1756 } 1757 ALOGV("dequeueThreadLoop terminates"); 1758 } 1759 1760 class C2VDAComponentFactory : public C2ComponentFactory { 1761 public: 1762 C2VDAComponentFactory(C2String decoderName) 1763 : mDecoderName(decoderName), 1764 mReflector(std::static_pointer_cast<C2ReflectorHelper>( 1765 GetCodec2VDAComponentStore()->getParamReflector())){}; 1766 1767 c2_status_t createComponent(c2_node_id_t id, std::shared_ptr<C2Component>* const component, 1768 ComponentDeleter deleter) override { 1769 UNUSED(deleter); 1770 *component = std::shared_ptr<C2Component>(new C2VDAComponent(mDecoderName, id, mReflector)); 1771 return C2_OK; 1772 } 1773 c2_status_t createInterface(c2_node_id_t id, 1774 std::shared_ptr<C2ComponentInterface>* const interface, 1775 InterfaceDeleter deleter) override { 1776 UNUSED(deleter); 1777 *interface = 1778 std::shared_ptr<C2ComponentInterface>(new SimpleInterface<C2VDAComponent::IntfImpl>( 1779 mDecoderName.c_str(), id, 1780 std::make_shared<C2VDAComponent::IntfImpl>(mDecoderName, mReflector))); 1781 return C2_OK; 1782 } 1783 ~C2VDAComponentFactory() override = default; 1784 1785 private: 1786 const C2String mDecoderName; 1787 std::shared_ptr<C2ReflectorHelper> mReflector; 1788 }; 1789 } // namespace android 1790 1791 extern "C" ::C2ComponentFactory* CreateC2VDAH264Factory(bool secureMode) { 1792 ALOGV("in %s (secureMode=%d)", __func__, secureMode); 1793 return secureMode ? new ::android::C2VDAComponentFactory(android::kH264SecureDecoderName) 1794 : new ::android::C2VDAComponentFactory(android::kH264DecoderName); 1795 } 1796 1797 extern "C" void DestroyC2VDAH264Factory(::C2ComponentFactory* factory) { 1798 ALOGV("in %s", __func__); 1799 delete factory; 1800 } 1801 1802 extern "C" ::C2ComponentFactory* CreateC2VDAVP8Factory(bool secureMode) { 1803 ALOGV("in %s (secureMode=%d)", __func__, secureMode); 1804 return secureMode ? new ::android::C2VDAComponentFactory(android::kVP8SecureDecoderName) 1805 : new ::android::C2VDAComponentFactory(android::kVP8DecoderName); 1806 } 1807 1808 extern "C" void DestroyC2VDAVP8Factory(::C2ComponentFactory* factory) { 1809 ALOGV("in %s", __func__); 1810 delete factory; 1811 } 1812 1813 extern "C" ::C2ComponentFactory* CreateC2VDAVP9Factory(bool secureMode) { 1814 ALOGV("in %s (secureMode=%d)", __func__, secureMode); 1815 return secureMode ? new ::android::C2VDAComponentFactory(android::kVP9SecureDecoderName) 1816 : new ::android::C2VDAComponentFactory(android::kVP9DecoderName); 1817 } 1818 1819 extern "C" void DestroyC2VDAVP9Factory(::C2ComponentFactory* factory) { 1820 ALOGV("in %s", __func__); 1821 delete factory; 1822 } 1823