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-InputBufferManager"
     19 #include <android-base/logging.h>
     20 
     21 #include <codec2/hidl/1.0/InputBufferManager.h>
     22 #include <codec2/hidl/1.0/types.h>
     23 
     24 #include <android/hardware/media/c2/1.0/IComponentListener.h>
     25 #include <android-base/logging.h>
     26 
     27 #include <C2Buffer.h>
     28 #include <C2Work.h>
     29 
     30 #include <chrono>
     31 
     32 namespace android {
     33 namespace hardware {
     34 namespace media {
     35 namespace c2 {
     36 namespace V1_0 {
     37 namespace utils {
     38 
     39 using namespace ::android;
     40 
     41 void InputBufferManager::registerFrameData(
     42         const sp<IComponentListener>& listener,
     43         const C2FrameData& input) {
     44     getInstance()._registerFrameData(listener, input);
     45 }
     46 
     47 void InputBufferManager::unregisterFrameData(
     48         const wp<IComponentListener>& listener,
     49         const C2FrameData& input) {
     50     getInstance()._unregisterFrameData(listener, input);
     51 }
     52 
     53 void InputBufferManager::unregisterFrameData(
     54         const wp<IComponentListener>& listener) {
     55     getInstance()._unregisterFrameData(listener);
     56 }
     57 
     58 void InputBufferManager::setNotificationInterval(
     59         nsecs_t notificationIntervalNs) {
     60     getInstance()._setNotificationInterval(notificationIntervalNs);
     61 }
     62 
     63 void InputBufferManager::_registerFrameData(
     64         const sp<IComponentListener>& listener,
     65         const C2FrameData& input) {
     66     uint64_t frameIndex = input.ordinal.frameIndex.peeku();
     67     LOG(VERBOSE) << "InputBufferManager::_registerFrameData -- called with "
     68                  << "listener @ 0x" << std::hex << listener.get()
     69                  << ", frameIndex = " << std::dec << frameIndex
     70                  << ".";
     71     std::lock_guard<std::mutex> lock(mMutex);
     72 
     73     std::set<TrackedBuffer> &bufferIds =
     74             mTrackedBuffersMap[listener][frameIndex];
     75 
     76     for (size_t i = 0; i < input.buffers.size(); ++i) {
     77         if (!input.buffers[i]) {
     78             LOG(VERBOSE) << "InputBufferManager::_registerFrameData -- "
     79                          << "Input buffer at index " << i << " is null.";
     80             continue;
     81         }
     82         const TrackedBuffer &bufferId =
     83                 *bufferIds.emplace(listener, frameIndex, i, input.buffers[i]).
     84                 first;
     85 
     86         c2_status_t status = input.buffers[i]->registerOnDestroyNotify(
     87                 onBufferDestroyed,
     88                 const_cast<void*>(reinterpret_cast<const void*>(&bufferId)));
     89         if (status != C2_OK) {
     90             LOG(DEBUG) << "InputBufferManager::_registerFrameData -- "
     91                        << "registerOnDestroyNotify() failed "
     92                        << "(listener @ 0x" << std::hex << listener.get()
     93                        << ", frameIndex = " << std::dec << frameIndex
     94                        << ", bufferIndex = " << i
     95                        << ") => status = " << status
     96                        << ".";
     97         }
     98     }
     99 
    100     mDeathNotifications.emplace(
    101             listener,
    102             DeathNotifications(
    103                 mNotificationIntervalNs.load(std::memory_order_relaxed)));
    104 }
    105 
    106 // Remove a pair (listener, frameIndex) from mTrackedBuffersMap and
    107 // mDeathNotifications. This implies all bufferIndices are removed.
    108 //
    109 // This is called from onWorkDone() and flush().
    110 void InputBufferManager::_unregisterFrameData(
    111         const wp<IComponentListener>& listener,
    112         const C2FrameData& input) {
    113     uint64_t frameIndex = input.ordinal.frameIndex.peeku();
    114     LOG(VERBOSE) << "InputBufferManager::_unregisterFrameData -- called with "
    115                  << "listener @ 0x" << std::hex << listener.unsafe_get()
    116                  << ", frameIndex = " << std::dec << frameIndex
    117                  << ".";
    118     std::lock_guard<std::mutex> lock(mMutex);
    119 
    120     auto findListener = mTrackedBuffersMap.find(listener);
    121     if (findListener != mTrackedBuffersMap.end()) {
    122         std::map<uint64_t, std::set<TrackedBuffer>> &frameIndex2BufferIds
    123                 = findListener->second;
    124         auto findFrameIndex = frameIndex2BufferIds.find(frameIndex);
    125         if (findFrameIndex != frameIndex2BufferIds.end()) {
    126             std::set<TrackedBuffer> &bufferIds = findFrameIndex->second;
    127             for (const TrackedBuffer& bufferId : bufferIds) {
    128                 std::shared_ptr<C2Buffer> buffer = bufferId.buffer.lock();
    129                 if (buffer) {
    130                     c2_status_t status = buffer->unregisterOnDestroyNotify(
    131                             onBufferDestroyed,
    132                             const_cast<void*>(
    133                             reinterpret_cast<const void*>(&bufferId)));
    134                     if (status != C2_OK) {
    135                         LOG(DEBUG) << "InputBufferManager::_unregisterFrameData "
    136                                    << "-- unregisterOnDestroyNotify() failed "
    137                                    << "(listener @ 0x"
    138                                         << std::hex
    139                                         << bufferId.listener.unsafe_get()
    140                                    << ", frameIndex = "
    141                                         << std::dec << bufferId.frameIndex
    142                                    << ", bufferIndex = " << bufferId.bufferIndex
    143                                    << ") => status = " << status
    144                                    << ".";
    145                     }
    146                 }
    147             }
    148 
    149             frameIndex2BufferIds.erase(findFrameIndex);
    150             if (frameIndex2BufferIds.empty()) {
    151                 mTrackedBuffersMap.erase(findListener);
    152             }
    153         }
    154     }
    155 
    156     auto findListenerD = mDeathNotifications.find(listener);
    157     if (findListenerD != mDeathNotifications.end()) {
    158         DeathNotifications &deathNotifications = findListenerD->second;
    159         auto findFrameIndex = deathNotifications.indices.find(frameIndex);
    160         if (findFrameIndex != deathNotifications.indices.end()) {
    161             std::vector<size_t> &bufferIndices = findFrameIndex->second;
    162             deathNotifications.count -= bufferIndices.size();
    163             deathNotifications.indices.erase(findFrameIndex);
    164         }
    165     }
    166 }
    167 
    168 // Remove listener from mTrackedBuffersMap and mDeathNotifications. This implies
    169 // all frameIndices and bufferIndices are removed.
    170 //
    171 // This is called when the component cleans up all input buffers, i.e., when
    172 // reset(), release(), stop() or ~Component() is called.
    173 void InputBufferManager::_unregisterFrameData(
    174         const wp<IComponentListener>& listener) {
    175     LOG(VERBOSE) << "InputBufferManager::_unregisterFrameData -- called with "
    176                  << "listener @ 0x" << std::hex << listener.unsafe_get()
    177                  << std::dec << ".";
    178     std::lock_guard<std::mutex> lock(mMutex);
    179 
    180     auto findListener = mTrackedBuffersMap.find(listener);
    181     if (findListener != mTrackedBuffersMap.end()) {
    182         std::map<uint64_t, std::set<TrackedBuffer>> &frameIndex2BufferIds =
    183                 findListener->second;
    184         for (auto findFrameIndex = frameIndex2BufferIds.begin();
    185                 findFrameIndex != frameIndex2BufferIds.end();
    186                 ++findFrameIndex) {
    187             std::set<TrackedBuffer> &bufferIds = findFrameIndex->second;
    188             for (const TrackedBuffer& bufferId : bufferIds) {
    189                 std::shared_ptr<C2Buffer> buffer = bufferId.buffer.lock();
    190                 if (buffer) {
    191                     c2_status_t status = buffer->unregisterOnDestroyNotify(
    192                             onBufferDestroyed,
    193                             const_cast<void*>(
    194                             reinterpret_cast<const void*>(&bufferId)));
    195                     if (status != C2_OK) {
    196                         LOG(DEBUG) << "InputBufferManager::_unregisterFrameData "
    197                                    << "-- unregisterOnDestroyNotify() failed "
    198                                    << "(listener @ 0x"
    199                                         << std::hex
    200                                         << bufferId.listener.unsafe_get()
    201                                    << ", frameIndex = "
    202                                         << std::dec << bufferId.frameIndex
    203                                    << ", bufferIndex = " << bufferId.bufferIndex
    204                                    << ") => status = " << status
    205                                    << ".";
    206                     }
    207                 }
    208             }
    209         }
    210         mTrackedBuffersMap.erase(findListener);
    211     }
    212 
    213     mDeathNotifications.erase(listener);
    214 }
    215 
    216 // Set mNotificationIntervalNs.
    217 void InputBufferManager::_setNotificationInterval(
    218         nsecs_t notificationIntervalNs) {
    219     mNotificationIntervalNs.store(
    220             notificationIntervalNs,
    221             std::memory_order_relaxed);
    222 }
    223 
    224 // Move a buffer from mTrackedBuffersMap to mDeathNotifications.
    225 // This is called when a registered C2Buffer object is destroyed.
    226 void InputBufferManager::onBufferDestroyed(const C2Buffer* buf, void* arg) {
    227     getInstance()._onBufferDestroyed(buf, arg);
    228 }
    229 
    230 void InputBufferManager::_onBufferDestroyed(const C2Buffer* buf, void* arg) {
    231     if (!buf || !arg) {
    232         LOG(WARNING) << "InputBufferManager::_onBufferDestroyed -- called with "
    233                      << "null argument (s): "
    234                      << "buf @ 0x" << std::hex << buf
    235                      << ", arg @ 0x" << std::hex << arg
    236                      << std::dec << ".";
    237         return;
    238     }
    239     TrackedBuffer id(*reinterpret_cast<TrackedBuffer*>(arg));
    240     LOG(VERBOSE) << "InputBufferManager::_onBufferDestroyed -- called with "
    241                  << "buf @ 0x" << std::hex << buf
    242                  << ", arg @ 0x" << std::hex << arg
    243                  << std::dec << " -- "
    244                  << "listener @ 0x" << std::hex << id.listener.unsafe_get()
    245                  << ", frameIndex = " << std::dec << id.frameIndex
    246                  << ", bufferIndex = " << id.bufferIndex
    247                  << ".";
    248 
    249     std::lock_guard<std::mutex> lock(mMutex);
    250 
    251     auto findListener = mTrackedBuffersMap.find(id.listener);
    252     if (findListener == mTrackedBuffersMap.end()) {
    253         LOG(DEBUG) << "InputBufferManager::_onBufferDestroyed -- "
    254                    << "received invalid listener: "
    255                    << "listener @ 0x" << std::hex << id.listener.unsafe_get()
    256                    << " (frameIndex = " << std::dec << id.frameIndex
    257                    << ", bufferIndex = " << id.bufferIndex
    258                    << ").";
    259         return;
    260     }
    261 
    262     std::map<uint64_t, std::set<TrackedBuffer>> &frameIndex2BufferIds
    263             = findListener->second;
    264     auto findFrameIndex = frameIndex2BufferIds.find(id.frameIndex);
    265     if (findFrameIndex == frameIndex2BufferIds.end()) {
    266         LOG(DEBUG) << "InputBufferManager::_onBufferDestroyed -- "
    267                    << "received invalid frame index: "
    268                    << "frameIndex = " << id.frameIndex
    269                    << " (listener @ 0x" << std::hex << id.listener.unsafe_get()
    270                    << ", bufferIndex = " << std::dec << id.bufferIndex
    271                    << ").";
    272         return;
    273     }
    274 
    275     std::set<TrackedBuffer> &bufferIds = findFrameIndex->second;
    276     auto findBufferId = bufferIds.find(id);
    277     if (findBufferId == bufferIds.end()) {
    278         LOG(DEBUG) << "InputBufferManager::_onBufferDestroyed -- "
    279                    << "received invalid buffer index: "
    280                    << "bufferIndex = " << id.bufferIndex
    281                    << " (frameIndex = " << id.frameIndex
    282                    << ", listener @ 0x" << std::hex << id.listener.unsafe_get()
    283                    << std::dec << ").";
    284         return;
    285     }
    286 
    287     bufferIds.erase(findBufferId);
    288     if (bufferIds.empty()) {
    289         frameIndex2BufferIds.erase(findFrameIndex);
    290         if (frameIndex2BufferIds.empty()) {
    291             mTrackedBuffersMap.erase(findListener);
    292         }
    293     }
    294 
    295     DeathNotifications &deathNotifications = mDeathNotifications[id.listener];
    296     deathNotifications.indices[id.frameIndex].emplace_back(id.bufferIndex);
    297     ++deathNotifications.count;
    298     mOnBufferDestroyed.notify_one();
    299 }
    300 
    301 // Notify the clients about buffer destructions.
    302 // Return false if all destructions have been notified.
    303 // Return true and set timeToRetry to the time point to wait for before
    304 // retrying if some destructions have not been notified.
    305 bool InputBufferManager::processNotifications(nsecs_t* timeToRetryNs) {
    306 
    307     struct Notification {
    308         sp<IComponentListener> listener;
    309         hidl_vec<IComponentListener::InputBuffer> inputBuffers;
    310         Notification(const sp<IComponentListener>& l, size_t s)
    311               : listener(l), inputBuffers(s) {}
    312     };
    313     std::list<Notification> notifications;
    314     nsecs_t notificationIntervalNs =
    315             mNotificationIntervalNs.load(std::memory_order_relaxed);
    316 
    317     bool retry = false;
    318     {
    319         std::lock_guard<std::mutex> lock(mMutex);
    320         *timeToRetryNs = notificationIntervalNs;
    321         nsecs_t timeNowNs = systemTime();
    322         for (auto it = mDeathNotifications.begin();
    323                 it != mDeathNotifications.end(); ) {
    324             sp<IComponentListener> listener = it->first.promote();
    325             if (!listener) {
    326                 ++it;
    327                 continue;
    328             }
    329             DeathNotifications &deathNotifications = it->second;
    330 
    331             nsecs_t timeSinceLastNotifiedNs =
    332                     timeNowNs - deathNotifications.lastSentNs;
    333             // If not enough time has passed since the last callback, leave the
    334             // notifications for this listener untouched for now and retry
    335             // later.
    336             if (timeSinceLastNotifiedNs < notificationIntervalNs) {
    337                 retry = true;
    338                 *timeToRetryNs = std::min(*timeToRetryNs,
    339                         notificationIntervalNs - timeSinceLastNotifiedNs);
    340                 LOG(VERBOSE) << "InputBufferManager::processNotifications -- "
    341                              << "Notifications for listener @ "
    342                                  << std::hex << listener.get()
    343                              << " will be postponed.";
    344                 ++it;
    345                 continue;
    346             }
    347 
    348             // If enough time has passed since the last notification to this
    349             // listener but there are currently no pending notifications, the
    350             // listener can be removed from mDeathNotifications---there is no
    351             // need to keep track of the last notification time anymore.
    352             if (deathNotifications.count == 0) {
    353                 it = mDeathNotifications.erase(it);
    354                 continue;
    355             }
    356 
    357             // Create the argument for the callback.
    358             notifications.emplace_back(listener, deathNotifications.count);
    359             hidl_vec<IComponentListener::InputBuffer> &inputBuffers =
    360                     notifications.back().inputBuffers;
    361             size_t i = 0;
    362             for (std::pair<const uint64_t, std::vector<size_t>>& p :
    363                     deathNotifications.indices) {
    364                 uint64_t frameIndex = p.first;
    365                 const std::vector<size_t> &bufferIndices = p.second;
    366                 for (const size_t& bufferIndex : bufferIndices) {
    367                     IComponentListener::InputBuffer &inputBuffer
    368                             = inputBuffers[i++];
    369                     inputBuffer.arrayIndex = bufferIndex;
    370                     inputBuffer.frameIndex = frameIndex;
    371                 }
    372             }
    373 
    374             // Clear deathNotifications for this listener and set retry to true
    375             // so processNotifications will be called again. This will
    376             // guarantee that a listener with no pending notifications will
    377             // eventually be removed from mDeathNotifications after
    378             // mNotificationIntervalNs nanoseconds has passed.
    379             retry = true;
    380             deathNotifications.indices.clear();
    381             deathNotifications.count = 0;
    382             deathNotifications.lastSentNs = timeNowNs;
    383             ++it;
    384         }
    385     }
    386 
    387     // Call onInputBuffersReleased() outside the lock to avoid deadlock.
    388     for (const Notification& notification : notifications) {
    389         if (!notification.listener->onInputBuffersReleased(
    390                 notification.inputBuffers).isOk()) {
    391             // This may trigger if the client has died.
    392             LOG(DEBUG) << "InputBufferManager::processNotifications -- "
    393                        << "failed to send death notifications to "
    394                        << "listener @ 0x" << std::hex
    395                                           << notification.listener.get()
    396                        << std::dec << ".";
    397         } else {
    398 #if LOG_NDEBUG == 0
    399             std::stringstream inputBufferLog;
    400             for (const IComponentListener::InputBuffer& inputBuffer :
    401                     notification.inputBuffers) {
    402                 inputBufferLog << " (" << inputBuffer.frameIndex
    403                                << ", " << inputBuffer.arrayIndex
    404                                << ")";
    405             }
    406             LOG(VERBOSE) << "InputBufferManager::processNotifications -- "
    407                          << "death notifications sent to "
    408                          << "listener @ 0x" << std::hex
    409                                             << notification.listener.get()
    410                                             << std::dec
    411                          << " with these (frameIndex, bufferIndex) pairs:"
    412                          << inputBufferLog.str();
    413 #endif
    414         }
    415     }
    416 #if LOG_NDEBUG == 0
    417     if (retry) {
    418         LOG(VERBOSE) << "InputBufferManager::processNotifications -- "
    419                      << "will retry again in " << *timeToRetryNs << "ns.";
    420     } else {
    421         LOG(VERBOSE) << "InputBufferManager::processNotifications -- "
    422                      << "no pending death notifications.";
    423     }
    424 #endif
    425     return retry;
    426 }
    427 
    428 void InputBufferManager::main() {
    429     LOG(VERBOSE) << "InputBufferManager main -- started.";
    430     nsecs_t timeToRetryNs;
    431     while (true) {
    432         std::unique_lock<std::mutex> lock(mMutex);
    433         while (mDeathNotifications.empty()) {
    434             mOnBufferDestroyed.wait(lock);
    435         }
    436         lock.unlock();
    437         while (processNotifications(&timeToRetryNs)) {
    438             std::this_thread::sleep_for(
    439                     std::chrono::nanoseconds(timeToRetryNs));
    440         }
    441     }
    442 }
    443 
    444 InputBufferManager::InputBufferManager()
    445       : mMainThread{&InputBufferManager::main, this} {
    446 }
    447 
    448 InputBufferManager& InputBufferManager::getInstance() {
    449     static InputBufferManager instance{};
    450     return instance;
    451 }
    452 
    453 }  // namespace utils
    454 }  // namespace V1_0
    455 }  // namespace c2
    456 }  // namespace media
    457 }  // namespace hardware
    458 }  // namespace android
    459 
    460 
    461 
    462