Home | History | Annotate | Download | only in utils
      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