1 /*
2  * Copyright (C) 2017 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 SIMPLE_C2_COMPONENT_H_
18 #define SIMPLE_C2_COMPONENT_H_
19 
20 #include <list>
21 #include <thread>
22 #include <unordered_map>
23 
24 #include <C2Component.h>
25 
26 #include <media/stagefright/foundation/Mutexed.h>
27 
28 namespace android {
29 
30 class SimpleC2Component
31         : public C2Component, public std::enable_shared_from_this<SimpleC2Component> {
32 public:
33     explicit SimpleC2Component(
34             const std::shared_ptr<C2ComponentInterface> &intf);
35     virtual ~SimpleC2Component() = default;
36 
37     // C2Component
38     // From C2Component
39     virtual c2_status_t setListener_vb(
40             const std::shared_ptr<Listener> &listener, c2_blocking_t mayBlock) override;
41     virtual c2_status_t queue_nb(std::list<std::unique_ptr<C2Work>>* const items) override;
42     virtual c2_status_t announce_nb(const std::vector<C2WorkOutline> &items) override;
43     virtual c2_status_t flush_sm(
44             flush_mode_t mode, std::list<std::unique_ptr<C2Work>>* const flushedWork) override;
45     virtual c2_status_t drain_nb(drain_mode_t mode) override;
46     virtual c2_status_t start() override;
47     virtual c2_status_t stop() override;
48     virtual c2_status_t reset() override;
49     virtual c2_status_t release() override;
50     virtual std::shared_ptr<C2ComponentInterface> intf() override;
51 
52     // for thread
exitRequested()53     inline bool exitRequested() { return mExitRequested; }
54     void processQueue();
55     void signalExit();
56 
57 protected:
58     /**
59      * Initialize internal states of the component according to the config set
60      * in the interface.
61      *
62      * This method is called during start(), but only at the first invocation or
63      * after reset().
64      */
65     virtual c2_status_t onInit() = 0;
66 
67     /**
68      * Stop the component.
69      */
70     virtual c2_status_t onStop() = 0;
71 
72     /**
73      * Reset the component.
74      */
75     virtual void onReset() = 0;
76 
77     /**
78      * Release the component.
79      */
80     virtual void onRelease() = 0;
81 
82     /**
83      * Flush the component.
84      */
85     virtual c2_status_t onFlush_sm() = 0;
86 
87     /**
88      * Process the given work and finish pending work using finish().
89      *
90      * \param[in,out]   work    the work to process
91      * \param[in]       pool    the pool to use for allocating output blocks.
92      */
93     virtual void process(
94             const std::unique_ptr<C2Work> &work,
95             const std::shared_ptr<C2BlockPool> &pool) = 0;
96 
97     /**
98      * Drain the component and finish pending work using finish().
99      *
100      * \param[in]   drainMode   mode of drain.
101      * \param[in]   pool        the pool to use for allocating output blocks.
102      *
103      * \retval C2_OK            The component has drained all pending output
104      *                          work.
105      * \retval C2_OMITTED       Unsupported mode (e.g. DRAIN_CHAIN)
106      */
107     virtual c2_status_t drain(
108             uint32_t drainMode,
109             const std::shared_ptr<C2BlockPool> &pool) = 0;
110 
111     // for derived classes
112     /**
113      * Finish pending work.
114      *
115      * This method will retrieve the pending work according to |frameIndex| and
116      * feed the work into |fillWork| function. |fillWork| must be
117      * "non-blocking". Once |fillWork| returns the filled work will be returned
118      * to the client.
119      *
120      * \param[in]   frameIndex    the index of the pending work
121      * \param[in]   fillWork      the function to fill the retrieved work.
122      */
123     void finish(uint64_t frameIndex, std::function<void(const std::unique_ptr<C2Work> &)> fillWork);
124 
125     std::shared_ptr<C2Buffer> createLinearBuffer(
126             const std::shared_ptr<C2LinearBlock> &block);
127 
128     std::shared_ptr<C2Buffer> createLinearBuffer(
129             const std::shared_ptr<C2LinearBlock> &block, size_t offset, size_t size);
130 
131     std::shared_ptr<C2Buffer> createGraphicBuffer(
132             const std::shared_ptr<C2GraphicBlock> &block);
133 
134     std::shared_ptr<C2Buffer> createGraphicBuffer(
135             const std::shared_ptr<C2GraphicBlock> &block,
136             const C2Rect &crop);
137 
138     static constexpr uint32_t NO_DRAIN = ~0u;
139 
140     C2ReadView mDummyReadView;
141 
142 private:
143     const std::shared_ptr<C2ComponentInterface> mIntf;
144     std::atomic_bool mExitRequested;
145 
146     enum {
147         UNINITIALIZED,
148         STOPPED,
149         RUNNING,
150     };
151 
152     struct ExecState {
ExecStateExecState153         ExecState() : mState(UNINITIALIZED) {}
154 
155         int mState;
156         std::thread mThread;
157         std::shared_ptr<C2Component::Listener> mListener;
158     };
159     Mutexed<ExecState> mExecState;
160 
161     class WorkQueue {
162     public:
WorkQueue()163         inline WorkQueue() : mFlush(false), mGeneration(0ul) {}
164 
generation()165         inline uint64_t generation() const { return mGeneration; }
incGeneration()166         inline void incGeneration() { ++mGeneration; mFlush = true; }
167 
168         std::unique_ptr<C2Work> pop_front();
169         void push_back(std::unique_ptr<C2Work> work);
170         bool empty() const;
171         uint32_t drainMode() const;
172         void markDrain(uint32_t drainMode);
popPendingFlush()173         inline bool popPendingFlush() {
174             bool flush = mFlush;
175             mFlush = false;
176             return flush;
177         }
178         void clear();
179 
180         Condition mCondition;
181 
182     private:
183         struct Entry {
184             std::unique_ptr<C2Work> work;
185             uint32_t drainMode;
186         };
187 
188         bool mFlush;
189         uint64_t mGeneration;
190         std::list<Entry> mQueue;
191     };
192     Mutexed<WorkQueue> mWorkQueue;
193 
194     typedef std::unordered_map<uint64_t, std::unique_ptr<C2Work>> PendingWork;
195     Mutexed<PendingWork> mPendingWork;
196 
197     struct ExitMonitor {
ExitMonitorExitMonitor198         inline ExitMonitor() : mExited(false) {}
199         Condition mCondition;
200         bool mExited;
201     };
202     Mutexed<ExitMonitor> mExitMonitor;
203 
204     std::shared_ptr<C2BlockPool> mOutputBlockPool;
205 
206     SimpleC2Component() = delete;
207 
208     void requestExitAndWait(std::function<void()> job);
209 };
210 
211 }  // namespace android
212 
213 #endif  // SIMPLE_C2_COMPONENT_H_
214