xref: /aosp_15_r20/frameworks/av/media/codec2/hal/aidl/include/codec2/aidl/InputBufferManager.h (revision ec779b8e0859a360c3d303172224686826e6e0e1)
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