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