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 #ifndef CODEC2_AIDL_UTILS_INPUT_BUFFER_MANAGER_H 18 #define CODEC2_AIDL_UTILS_INPUT_BUFFER_MANAGER_H 19 20 #include <aidl/android/hardware/media/c2/IComponentListener.h> 21 #include <utils/Timers.h> 22 23 #include <C2Buffer.h> 24 #include <C2Work.h> 25 26 #include <set> 27 #include <map> 28 #include <thread> 29 30 namespace aidl { 31 namespace android { 32 namespace hardware { 33 namespace media { 34 namespace c2 { 35 namespace utils { 36 37 /** 38 * InputBufferManager 39 * ================== 40 * 41 * InputBufferManager presents a way to track and untrack input buffers in this 42 * (codec) process and send a notification to a listener, possibly in a 43 * different process, when a tracked buffer no longer has any references in this 44 * process. 45 * 46 * InputBufferManager holds a collection of records representing tracked buffers 47 * and their callback listeners. Conceptually, one record is a triple (listener, 48 * frameIndex, bufferIndex) where 49 * 50 * - (frameIndex, bufferIndex) is a pair of indices used to identify the buffer. 51 * - listener is of type IComponentListener. Its onInputBuffersReleased() 52 * function will be called after the associated buffer dies. The argument of 53 * onInputBuffersReleased() is a list of InputBuffer objects, each of which 54 * has the following members: 55 * 56 * uint64_t frameIndex 57 * uint32_t arrayIndex 58 * 59 * When a tracked buffer associated to the triple (listener, frameIndex, 60 * bufferIndex) goes out of scope, listener->onInputBuffersReleased() will be 61 * called with an InputBuffer object whose members are set as follows: 62 * 63 * inputBuffer.frameIndex = frameIndex 64 * inputBuffer.arrayIndex = bufferIndex 65 * 66 * IPC Optimization 67 * ---------------- 68 * 69 * Since onInputBuffersReleased() is an IPC call, InputBufferManager tries not 70 * to call it too often. Any two calls to the same listener are at least 71 * mNotificationIntervalNs nanoseconds apart, where mNotificationIntervalNs is 72 * configurable via calling setNotificationInterval(). The default value of 73 * mNotificationIntervalNs is kDefaultNotificationInternalNs. 74 * 75 * Public Member Functions 76 * ----------------------- 77 * 78 * InputBufferManager is a singleton class. Its only instance is accessible via 79 * the following public functions: 80 * 81 * - registerFrameData(const sp<IComponentListener>& listener, 82 * const C2FrameData& input) 83 * 84 * - unregisterFrameData(const sp<IComponentListener>& listener, 85 * const C2FrameData& input) 86 * 87 * - unregisterFrameData(const sp<IComponentListener>& listener) 88 * 89 * - setNotificationInterval(nsecs_t notificationIntervalNs) 90 * 91 */ 92 93 struct InputBufferManager { 94 95 /** 96 * The default value for the time interval between 2 subsequent IPCs. 97 */ 98 static constexpr nsecs_t kDefaultNotificationIntervalNs = 1000000; /* 1ms */ 99 100 /** 101 * Track all buffers in a C2FrameData object. 102 * 103 * input (C2FrameData) has the following two members that are of interest: 104 * 105 * C2WorkOrdinal ordinal 106 * vector<shared_ptr<C2Buffer>> buffers 107 * 108 * Calling registerFrameData(listener, input) will register multiple 109 * triples (listener, frameIndex, bufferIndex) where frameIndex is equal to 110 * input.ordinal.frameIndex and bufferIndex runs through the indices of 111 * input.buffers such that input.buffers[bufferIndex] is not null. 112 * 113 * This should be called from queue(). 114 * 115 * \param listener Listener of death notifications. 116 * \param input Input frame data whose input buffers are to be tracked. 117 */ 118 static void registerFrameData( 119 const std::shared_ptr<IComponentListener>& listener, 120 const C2FrameData& input); 121 122 /** 123 * Untrack all buffers in a C2FrameData object. 124 * 125 * Calling unregisterFrameData(listener, input) will unregister and remove 126 * pending notifications for all triples (l, fi, bufferIndex) such that 127 * l = listener and fi = input.ordinal.frameIndex. 128 * 129 * This should be called from onWorkDone() and flush(). 130 * 131 * \param listener Previously registered listener. 132 * \param input Previously registered frame data. 133 */ 134 static void unregisterFrameData( 135 const std::weak_ptr<IComponentListener>& listener, 136 const C2FrameData& input); 137 138 /** 139 * Untrack all buffers associated to a given listener. 140 * 141 * Calling unregisterFrameData(listener) will unregister and remove 142 * pending notifications for all triples (l, frameIndex, bufferIndex) such 143 * that l = listener. 144 * 145 * This should be called when the component cleans up all input buffers, 146 * i.e., when reset(), release(), stop() or ~Component() is called. 147 * 148 * \param listener Previously registered listener. 149 */ 150 static void unregisterFrameData( 151 const std::weak_ptr<IComponentListener>& listener); 152 153 /** 154 * Set the notification interval. 155 * 156 * \param notificationIntervalNs New notification interval, in nanoseconds. 157 */ 158 static void setNotificationInterval(nsecs_t notificationIntervalNs); 159 160 private: 161 void _registerFrameData( 162 const std::shared_ptr<IComponentListener>& listener, 163 const C2FrameData& input); 164 void _unregisterFrameData( 165 const std::weak_ptr<IComponentListener>& listener, 166 const C2FrameData& input); 167 void _unregisterFrameData( 168 const std::weak_ptr<IComponentListener>& listener); 169 void _setNotificationInterval(nsecs_t notificationIntervalNs); 170 171 // The callback function tied to C2Buffer objects. 172 // 173 // Note: This function assumes that sInstance is the only instance of this 174 // class. 175 static void onBufferDestroyed(const C2Buffer* buf, void* arg); 176 void _onBufferDestroyed(const C2Buffer* buf, void* arg); 177 178 // Persistent data to be passed as "arg" in onBufferDestroyed(). 179 // This is essentially the triple (listener, frameIndex, bufferIndex) plus a 180 // weak pointer to the C2Buffer object. 181 // 182 // Note that the "key" is bufferIndex according to operator<(). This is 183 // designed to work with TrackedBuffersMap defined below. 184 struct TrackedBuffer { 185 std::weak_ptr<IComponentListener> listener; 186 uint64_t frameIndex; 187 size_t bufferIndex; 188 std::weak_ptr<C2Buffer> buffer; TrackedBufferInputBufferManager::TrackedBuffer189 TrackedBuffer(const std::weak_ptr<IComponentListener>& listener, 190 uint64_t frameIndex, 191 size_t bufferIndex, 192 const std::shared_ptr<C2Buffer>& buffer) 193 : listener(listener), 194 frameIndex(frameIndex), 195 bufferIndex(bufferIndex), 196 buffer(buffer) {} 197 }; 198 199 // Map: listener -> frameIndex -> set<TrackedBuffer*>. 200 // Essentially, this is used to store triples (listener, frameIndex, 201 // bufferIndex) that's searchable by listener and (listener, frameIndex). 202 // However, the value of the innermost map is TrackedBuffer, which also 203 // contains an extra copy of listener and frameIndex. This is needed 204 // because onBufferDestroyed() needs to know listener and frameIndex too. 205 typedef std::map<std::weak_ptr<IComponentListener>, 206 std::map<uint64_t, 207 std::set<TrackedBuffer*>>, 208 std::owner_less<std::weak_ptr<IComponentListener>>> TrackedBuffersMap; 209 210 // Storage for pending (unsent) death notifications for one listener. 211 // Each pair in member named "indices" are (frameIndex, bufferIndex) from 212 // the (listener, frameIndex, bufferIndex) triple. 213 struct DeathNotifications { 214 215 // The number of pending notifications for this listener. 216 // count may be 0, in which case the DeathNotifications object will 217 // remain valid for only a small period (specified 218 // nanoseconds). 219 size_t count; 220 221 // The timestamp of the most recent callback on this listener. This is 222 // used to guarantee that callbacks do not occur too frequently, and 223 // also to trigger expiration of a DeathNotifications object that has 224 // count = 0. 225 nsecs_t lastSentNs; 226 227 // Map: frameIndex -> vector of bufferIndices 228 // This is essentially a collection of (framdeIndex, bufferIndex). 229 std::map<uint64_t, std::vector<size_t>> indices; 230 231 DeathNotifications( 232 nsecs_t notificationIntervalNs = kDefaultNotificationIntervalNs) 233 : count(0), 234 lastSentNs(systemTime() - notificationIntervalNs), 235 indices() {} 236 }; 237 238 // The minimum time period between IPC calls to notify the client about the 239 // destruction of input buffers. 240 std::atomic<nsecs_t> mNotificationIntervalNs{kDefaultNotificationIntervalNs}; 241 242 // Mutex for the management of all input buffers. 243 std::mutex mMutex; 244 245 // Cache for all TrackedBuffers. 246 // 247 // Whenever registerOnDestroyNotify() is called, an argument of type 248 // TrackedBuffer is created and stored into this cache. 249 // Whenever unregisterOnDestroyNotify() or onBufferDestroyed() is called, 250 // the TrackedBuffer is removed from this cache. 251 // 252 // mTrackedBuffersMap stores references to TrackedBuffers inside this cache. 253 std::set<TrackedBuffer*> mTrackedBufferCache; 254 255 // Tracked input buffers. 256 TrackedBuffersMap mTrackedBuffersMap; 257 258 // Death notifications to be sent. 259 // 260 // A DeathNotifications object is associated to each listener. An entry in 261 // this map will be removed if its associated DeathNotifications has count = 262 // 0 and lastSentNs < systemTime() - mNotificationIntervalNs. 263 std::map<std::weak_ptr<IComponentListener>, 264 DeathNotifications, 265 std::owner_less<std::weak_ptr<IComponentListener>>> mDeathNotifications; 266 267 // Condition variable signaled when an entry is added to mDeathNotifications. 268 std::condition_variable mOnBufferDestroyed; 269 270 // Notify the clients about buffer destructions. 271 // Return false if all destructions have been notified. 272 // Return true and set timeToRetry to the duration to wait for before 273 // retrying if some destructions have not been notified. 274 bool processNotifications(nsecs_t* timeToRetryNs); 275 276 // Main function for the input buffer manager thread. 277 void main(); 278 279 // The thread that manages notifications. 280 // 281 // Note: This variable is declared last so its initialization will happen 282 // after all other member variables have been initialized. 283 std::thread mMainThread; 284 285 // Private constructor. 286 InputBufferManager(); 287 288 // The only instance of this class. 289 static InputBufferManager& getInstance(); 290 291 }; 292 293 } // namespace utils 294 } // namespace c2 295 } // namespace media 296 } // namespace hardware 297 } // namespace android 298 } // namespace aidl 299 300 #endif // CODEC2_AIDL_UTILS_INPUT_BUFFER_MANAGER_H 301 302