1 /* 2 * Copyright 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 "Codec2-Component" 19 #include <android-base/logging.h> 20 21 #include <codec2/hidl/1.0/Component.h> 22 #include <codec2/hidl/1.0/ComponentStore.h> 23 #include <codec2/hidl/1.0/InputBufferManager.h> 24 25 #include <hidl/HidlBinderSupport.h> 26 #include <utils/Timers.h> 27 28 #include <C2BqBufferPriv.h> 29 #include <C2Debug.h> 30 #include <C2PlatformSupport.h> 31 32 #include <chrono> 33 #include <thread> 34 35 namespace android { 36 namespace hardware { 37 namespace media { 38 namespace c2 { 39 namespace V1_0 { 40 namespace utils { 41 42 using namespace ::android; 43 44 // ComponentListener wrapper 45 struct Component::Listener : public C2Component::Listener { 46 47 Listener(const sp<Component>& component) : 48 mComponent(component), 49 mListener(component->mListener) { 50 } 51 52 virtual void onError_nb( 53 std::weak_ptr<C2Component> /* c2component */, 54 uint32_t errorCode) override { 55 sp<IComponentListener> listener = mListener.promote(); 56 if (listener) { 57 Return<void> transStatus = listener->onError(Status::OK, errorCode); 58 if (!transStatus.isOk()) { 59 LOG(ERROR) << "Component::Listener::onError_nb -- " 60 << "transaction failed."; 61 } 62 } 63 } 64 65 virtual void onTripped_nb( 66 std::weak_ptr<C2Component> /* c2component */, 67 std::vector<std::shared_ptr<C2SettingResult>> c2settingResult 68 ) override { 69 sp<IComponentListener> listener = mListener.promote(); 70 if (listener) { 71 hidl_vec<SettingResult> settingResults(c2settingResult.size()); 72 size_t ix = 0; 73 for (const std::shared_ptr<C2SettingResult> &c2result : 74 c2settingResult) { 75 if (c2result) { 76 if (!objcpy(&settingResults[ix++], *c2result)) { 77 break; 78 } 79 } 80 } 81 settingResults.resize(ix); 82 Return<void> transStatus = listener->onTripped(settingResults); 83 if (!transStatus.isOk()) { 84 LOG(ERROR) << "Component::Listener::onTripped_nb -- " 85 << "transaction failed."; 86 } 87 } 88 } 89 90 virtual void onWorkDone_nb( 91 std::weak_ptr<C2Component> /* c2component */, 92 std::list<std::unique_ptr<C2Work>> c2workItems) override { 93 for (const std::unique_ptr<C2Work>& work : c2workItems) { 94 if (work) { 95 if (work->worklets.empty() 96 || !work->worklets.back() 97 || (work->worklets.back()->output.flags & 98 C2FrameData::FLAG_INCOMPLETE) == 0) { 99 InputBufferManager:: 100 unregisterFrameData(mListener, work->input); 101 } 102 } 103 } 104 105 sp<IComponentListener> listener = mListener.promote(); 106 if (listener) { 107 WorkBundle workBundle; 108 109 sp<Component> strongComponent = mComponent.promote(); 110 beginTransferBufferQueueBlocks(c2workItems, true); 111 if (!objcpy(&workBundle, c2workItems, strongComponent ? 112 &strongComponent->mBufferPoolSender : nullptr)) { 113 LOG(ERROR) << "Component::Listener::onWorkDone_nb -- " 114 << "received corrupted work items."; 115 endTransferBufferQueueBlocks(c2workItems, false, true); 116 return; 117 } 118 Return<void> transStatus = listener->onWorkDone(workBundle); 119 if (!transStatus.isOk()) { 120 LOG(ERROR) << "Component::Listener::onWorkDone_nb -- " 121 << "transaction failed."; 122 endTransferBufferQueueBlocks(c2workItems, false, true); 123 return; 124 } 125 endTransferBufferQueueBlocks(c2workItems, true, true); 126 } 127 } 128 129 protected: 130 wp<Component> mComponent; 131 wp<IComponentListener> mListener; 132 }; 133 134 // Component::Sink 135 struct Component::Sink : public IInputSink { 136 std::shared_ptr<Component> mComponent; 137 sp<IConfigurable> mConfigurable; 138 139 virtual Return<Status> queue(const WorkBundle& workBundle) override { 140 return mComponent->queue(workBundle); 141 } 142 143 virtual Return<sp<IConfigurable>> getConfigurable() override { 144 return mConfigurable; 145 } 146 147 Sink(const std::shared_ptr<Component>& component); 148 virtual ~Sink() override; 149 150 // Process-wide map: Component::Sink -> C2Component. 151 static std::mutex sSink2ComponentMutex; 152 static std::map<IInputSink*, std::weak_ptr<C2Component>> sSink2Component; 153 154 static std::shared_ptr<C2Component> findLocalComponent( 155 const sp<IInputSink>& sink); 156 }; 157 158 std::mutex 159 Component::Sink::sSink2ComponentMutex{}; 160 std::map<IInputSink*, std::weak_ptr<C2Component>> 161 Component::Sink::sSink2Component{}; 162 163 Component::Sink::Sink(const std::shared_ptr<Component>& component) 164 : mComponent{component}, 165 mConfigurable{[&component]() -> sp<IConfigurable> { 166 Return<sp<IComponentInterface>> ret1 = component->getInterface(); 167 if (!ret1.isOk()) { 168 LOG(ERROR) << "Sink::Sink -- component's transaction failed."; 169 return nullptr; 170 } 171 Return<sp<IConfigurable>> ret2 = 172 static_cast<sp<IComponentInterface>>(ret1)-> 173 getConfigurable(); 174 if (!ret2.isOk()) { 175 LOG(ERROR) << "Sink::Sink -- interface's transaction failed."; 176 return nullptr; 177 } 178 return static_cast<sp<IConfigurable>>(ret2); 179 }()} { 180 std::lock_guard<std::mutex> lock(sSink2ComponentMutex); 181 sSink2Component.emplace(this, component->mComponent); 182 } 183 184 Component::Sink::~Sink() { 185 std::lock_guard<std::mutex> lock(sSink2ComponentMutex); 186 sSink2Component.erase(this); 187 } 188 189 std::shared_ptr<C2Component> Component::Sink::findLocalComponent( 190 const sp<IInputSink>& sink) { 191 std::lock_guard<std::mutex> lock(sSink2ComponentMutex); 192 auto i = sSink2Component.find(sink.get()); 193 if (i == sSink2Component.end()) { 194 return nullptr; 195 } 196 return i->second.lock(); 197 } 198 199 // Component 200 Component::Component( 201 const std::shared_ptr<C2Component>& component, 202 const sp<IComponentListener>& listener, 203 const sp<ComponentStore>& store, 204 const sp<::android::hardware::media::bufferpool::V2_0:: 205 IClientManager>& clientPoolManager) 206 : mComponent{component}, 207 mInterface{new ComponentInterface(component->intf(), store.get())}, 208 mListener{listener}, 209 mStore{store}, 210 mBufferPoolSender{clientPoolManager} { 211 // Retrieve supported parameters from store 212 // TODO: We could cache this per component/interface type 213 mInit = mInterface->status(); 214 } 215 216 c2_status_t Component::status() const { 217 return mInit; 218 } 219 220 // Methods from ::android::hardware::media::c2::V1_0::IComponent 221 Return<Status> Component::queue(const WorkBundle& workBundle) { 222 std::list<std::unique_ptr<C2Work>> c2works; 223 224 if (!objcpy(&c2works, workBundle)) { 225 return Status::CORRUPTED; 226 } 227 228 // Register input buffers. 229 for (const std::unique_ptr<C2Work>& work : c2works) { 230 if (work) { 231 InputBufferManager:: 232 registerFrameData(mListener, work->input); 233 } 234 } 235 236 return static_cast<Status>(mComponent->queue_nb(&c2works)); 237 } 238 239 Return<void> Component::flush(flush_cb _hidl_cb) { 240 std::list<std::unique_ptr<C2Work>> c2flushedWorks; 241 c2_status_t c2res = mComponent->flush_sm( 242 C2Component::FLUSH_COMPONENT, 243 &c2flushedWorks); 244 245 // Unregister input buffers. 246 for (const std::unique_ptr<C2Work>& work : c2flushedWorks) { 247 if (work) { 248 if (work->worklets.empty() 249 || !work->worklets.back() 250 || (work->worklets.back()->output.flags & 251 C2FrameData::FLAG_INCOMPLETE) == 0) { 252 InputBufferManager:: 253 unregisterFrameData(mListener, work->input); 254 } 255 } 256 } 257 258 WorkBundle flushedWorkBundle; 259 Status res = static_cast<Status>(c2res); 260 beginTransferBufferQueueBlocks(c2flushedWorks, true); 261 if (c2res == C2_OK) { 262 if (!objcpy(&flushedWorkBundle, c2flushedWorks, &mBufferPoolSender)) { 263 res = Status::CORRUPTED; 264 } 265 } 266 _hidl_cb(res, flushedWorkBundle); 267 endTransferBufferQueueBlocks(c2flushedWorks, true, true); 268 return Void(); 269 } 270 271 Return<Status> Component::drain(bool withEos) { 272 return static_cast<Status>(mComponent->drain_nb(withEos ? 273 C2Component::DRAIN_COMPONENT_WITH_EOS : 274 C2Component::DRAIN_COMPONENT_NO_EOS)); 275 } 276 277 Return<Status> Component::setOutputSurface( 278 uint64_t blockPoolId, 279 const sp<HGraphicBufferProducer2>& surface) { 280 std::shared_ptr<C2BlockPool> pool; 281 GetCodec2BlockPool(blockPoolId, mComponent, &pool); 282 if (pool && pool->getAllocatorId() == C2PlatformAllocatorStore::BUFFERQUEUE) { 283 std::shared_ptr<C2BufferQueueBlockPool> bqPool = 284 std::static_pointer_cast<C2BufferQueueBlockPool>(pool); 285 C2BufferQueueBlockPool::OnRenderCallback cb = 286 [this](uint64_t producer, int32_t slot, int64_t nsecs) { 287 // TODO: batch this 288 hidl_vec<IComponentListener::RenderedFrame> rendered; 289 rendered.resize(1); 290 rendered[0] = { producer, slot, nsecs }; 291 (void)mListener->onFramesRendered(rendered).isOk(); 292 }; 293 if (bqPool) { 294 bqPool->setRenderCallback(cb); 295 bqPool->configureProducer(surface); 296 } 297 } 298 return Status::OK; 299 } 300 301 Return<void> Component::connectToInputSurface( 302 const sp<IInputSurface>& inputSurface, 303 connectToInputSurface_cb _hidl_cb) { 304 Status status; 305 sp<IInputSurfaceConnection> connection; 306 auto transStatus = inputSurface->connect( 307 asInputSink(), 308 [&status, &connection]( 309 Status s, const sp<IInputSurfaceConnection>& c) { 310 status = s; 311 connection = c; 312 } 313 ); 314 _hidl_cb(status, connection); 315 return Void(); 316 } 317 318 Return<void> Component::connectToOmxInputSurface( 319 const sp<HGraphicBufferProducer1>& producer, 320 const sp<::android::hardware::media::omx::V1_0:: 321 IGraphicBufferSource>& source, 322 connectToOmxInputSurface_cb _hidl_cb) { 323 (void)producer; 324 (void)source; 325 (void)_hidl_cb; 326 return Void(); 327 } 328 329 Return<Status> Component::disconnectFromInputSurface() { 330 // TODO implement 331 return Status::OK; 332 } 333 334 namespace /* unnamed */ { 335 336 struct BlockPoolIntf : public ConfigurableC2Intf { 337 BlockPoolIntf(const std::shared_ptr<C2BlockPool>& pool) 338 : ConfigurableC2Intf{ 339 "C2BlockPool:" + 340 (pool ? std::to_string(pool->getLocalId()) : "null"), 341 0}, 342 mPool{pool} { 343 } 344 345 virtual c2_status_t config( 346 const std::vector<C2Param*>& params, 347 c2_blocking_t mayBlock, 348 std::vector<std::unique_ptr<C2SettingResult>>* const failures 349 ) override { 350 (void)params; 351 (void)mayBlock; 352 (void)failures; 353 return C2_OK; 354 } 355 356 virtual c2_status_t query( 357 const std::vector<C2Param::Index>& indices, 358 c2_blocking_t mayBlock, 359 std::vector<std::unique_ptr<C2Param>>* const params 360 ) const override { 361 (void)indices; 362 (void)mayBlock; 363 (void)params; 364 return C2_OK; 365 } 366 367 virtual c2_status_t querySupportedParams( 368 std::vector<std::shared_ptr<C2ParamDescriptor>>* const params 369 ) const override { 370 (void)params; 371 return C2_OK; 372 } 373 374 virtual c2_status_t querySupportedValues( 375 std::vector<C2FieldSupportedValuesQuery>& fields, 376 c2_blocking_t mayBlock) const override { 377 (void)fields; 378 (void)mayBlock; 379 return C2_OK; 380 } 381 382 protected: 383 std::shared_ptr<C2BlockPool> mPool; 384 }; 385 386 } // unnamed namespace 387 388 Return<void> Component::createBlockPool( 389 uint32_t allocatorId, 390 createBlockPool_cb _hidl_cb) { 391 std::shared_ptr<C2BlockPool> blockPool; 392 c2_status_t status = CreateCodec2BlockPool( 393 static_cast<C2PlatformAllocatorStore::id_t>(allocatorId), 394 mComponent, 395 &blockPool); 396 if (status != C2_OK) { 397 blockPool = nullptr; 398 } 399 if (blockPool) { 400 mBlockPoolsMutex.lock(); 401 mBlockPools.emplace(blockPool->getLocalId(), blockPool); 402 mBlockPoolsMutex.unlock(); 403 } else if (status == C2_OK) { 404 status = C2_CORRUPTED; 405 } 406 407 _hidl_cb(static_cast<Status>(status), 408 blockPool ? blockPool->getLocalId() : 0, 409 new CachedConfigurable( 410 std::make_unique<BlockPoolIntf>(blockPool))); 411 return Void(); 412 } 413 414 Return<Status> Component::destroyBlockPool(uint64_t blockPoolId) { 415 std::lock_guard<std::mutex> lock(mBlockPoolsMutex); 416 return mBlockPools.erase(blockPoolId) == 1 ? 417 Status::OK : Status::CORRUPTED; 418 } 419 420 Return<Status> Component::start() { 421 return static_cast<Status>(mComponent->start()); 422 } 423 424 Return<Status> Component::stop() { 425 InputBufferManager::unregisterFrameData(mListener); 426 return static_cast<Status>(mComponent->stop()); 427 } 428 429 Return<Status> Component::reset() { 430 Status status = static_cast<Status>(mComponent->reset()); 431 { 432 std::lock_guard<std::mutex> lock(mBlockPoolsMutex); 433 mBlockPools.clear(); 434 } 435 InputBufferManager::unregisterFrameData(mListener); 436 return status; 437 } 438 439 Return<Status> Component::release() { 440 Status status = static_cast<Status>(mComponent->release()); 441 { 442 std::lock_guard<std::mutex> lock(mBlockPoolsMutex); 443 mBlockPools.clear(); 444 } 445 InputBufferManager::unregisterFrameData(mListener); 446 return status; 447 } 448 449 Return<sp<IComponentInterface>> Component::getInterface() { 450 return sp<IComponentInterface>(mInterface); 451 } 452 453 Return<sp<IInputSink>> Component::asInputSink() { 454 std::lock_guard<std::mutex> lock(mSinkMutex); 455 if (!mSink) { 456 mSink = new Sink(shared_from_this()); 457 } 458 return {mSink}; 459 } 460 461 std::shared_ptr<C2Component> Component::findLocalComponent( 462 const sp<IInputSink>& sink) { 463 return Component::Sink::findLocalComponent(sink); 464 } 465 466 void Component::initListener(const sp<Component>& self) { 467 std::shared_ptr<C2Component::Listener> c2listener = 468 std::make_shared<Listener>(self); 469 c2_status_t res = mComponent->setListener_vb(c2listener, C2_DONT_BLOCK); 470 if (res != C2_OK) { 471 mInit = res; 472 } 473 } 474 475 Component::~Component() { 476 InputBufferManager::unregisterFrameData(mListener); 477 mStore->reportComponentDeath(this); 478 } 479 480 } // namespace utils 481 } // namespace V1_0 482 } // namespace c2 483 } // namespace media 484 } // namespace hardware 485 } // namespace android 486 487