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