• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef ANDROID_C2_VDA_COMPONENT_H
6 #define ANDROID_C2_VDA_COMPONENT_H
7 
8 #include <C2VDACommon.h>
9 #include <VideoDecodeAcceleratorAdaptor.h>
10 
11 #include <rect.h>
12 #include <size.h>
13 #include <video_codecs.h>
14 #include <video_decode_accelerator.h>
15 
16 #include <C2Component.h>
17 #include <C2Config.h>
18 #include <C2Enum.h>
19 #include <C2Param.h>
20 #include <C2ParamDef.h>
21 #include <SimpleC2Interface.h>
22 #include <util/C2InterfaceHelper.h>
23 
24 #include <base/macros.h>
25 #include <base/memory/ref_counted.h>
26 #include <base/single_thread_task_runner.h>
27 #include <base/synchronization/waitable_event.h>
28 #include <base/threading/thread.h>
29 
30 #include <atomic>
31 #include <deque>
32 #include <map>
33 #include <mutex>
34 #include <queue>
35 #include <unordered_map>
36 
37 namespace android {
38 
39 class C2VDAComponent : public C2Component,
40                        public VideoDecodeAcceleratorAdaptor::Client,
41                        public std::enable_shared_from_this<C2VDAComponent> {
42 public:
43     class IntfImpl : public C2InterfaceHelper {
44     public:
45         IntfImpl(C2String name, const std::shared_ptr<C2ReflectorHelper>& helper);
46 
47         // interfaces for C2VDAComponent
status()48         c2_status_t status() const { return mInitStatus; }
getCodecProfile()49         media::VideoCodecProfile getCodecProfile() const { return mCodecProfile; }
getBlockPoolId()50         C2BlockPool::local_id_t getBlockPoolId() const { return mOutputBlockPoolIds->m.values[0]; }
getInputCodec()51         InputCodec getInputCodec() const { return mInputCodec; }
52 
53     private:
54         // Configurable parameter setters.
55         static C2R ProfileLevelSetter(bool mayBlock, C2P<C2StreamProfileLevelInfo::input>& info);
56 
57         static C2R SizeSetter(bool mayBlock, C2P<C2StreamPictureSizeInfo::output>& videoSize);
58 
59         template <typename T>
60         static C2R DefaultColorAspectsSetter(bool mayBlock, C2P<T>& def);
61 
62         static C2R MergedColorAspectsSetter(bool mayBlock,
63                                             C2P<C2StreamColorAspectsInfo::output>& merged,
64                                             const C2P<C2StreamColorAspectsTuning::output>& def,
65                                             const C2P<C2StreamColorAspectsInfo::input>& coded);
66 
67         // The input format kind; should be C2FormatCompressed.
68         std::shared_ptr<C2StreamBufferTypeSetting::input> mInputFormat;
69         // The output format kind; should be C2FormatVideo.
70         std::shared_ptr<C2StreamBufferTypeSetting::output> mOutputFormat;
71         // The MIME type of input port.
72         std::shared_ptr<C2PortMediaTypeSetting::input> mInputMediaType;
73         // The MIME type of output port; should be MEDIA_MIMETYPE_VIDEO_RAW.
74         std::shared_ptr<C2PortMediaTypeSetting::output> mOutputMediaType;
75         // The input codec profile and level. For now configuring this parameter is useless since
76         // the component always uses fixed codec profile to initialize accelerator. It is only used
77         // for the client to query supported profile and level values.
78         // TODO: use configured profile/level to initialize accelerator.
79         std::shared_ptr<C2StreamProfileLevelInfo::input> mProfileLevel;
80         // Decoded video size for output.
81         std::shared_ptr<C2StreamPictureSizeInfo::output> mSize;
82         // Maximum size of one input buffer.
83         std::shared_ptr<C2StreamMaxBufferSizeInfo::input> mMaxInputSize;
84         // The suggested usage of input buffer allocator ID.
85         std::shared_ptr<C2PortAllocatorsTuning::input> mInputAllocatorIds;
86         // The suggested usage of output buffer allocator ID.
87         std::shared_ptr<C2PortAllocatorsTuning::output> mOutputAllocatorIds;
88         // The suggested usage of output buffer allocator ID with surface.
89         std::shared_ptr<C2PortSurfaceAllocatorTuning::output> mOutputSurfaceAllocatorId;
90         // Compnent uses this ID to fetch corresponding output block pool from platform.
91         std::shared_ptr<C2PortBlockPoolsTuning::output> mOutputBlockPoolIds;
92         // The color aspects parsed from input bitstream. This parameter should be configured by
93         // component while decoding.
94         std::shared_ptr<C2StreamColorAspectsInfo::input> mCodedColorAspects;
95         // The default color aspects specified by requested output format. This parameter should be
96         // configured by client.
97         std::shared_ptr<C2StreamColorAspectsTuning::output> mDefaultColorAspects;
98         // The combined color aspects by |mCodedColorAspects| and |mDefaultColorAspects|, and the
99         // former has higher priority. This parameter is used for component to provide color aspects
100         // as C2Info in decoded output buffers.
101         std::shared_ptr<C2StreamColorAspectsInfo::output> mColorAspects;
102 
103         c2_status_t mInitStatus;
104         media::VideoCodecProfile mCodecProfile;
105         InputCodec mInputCodec;
106     };
107 
108     C2VDAComponent(C2String name, c2_node_id_t id,
109                    const std::shared_ptr<C2ReflectorHelper>& helper);
110     virtual ~C2VDAComponent() override;
111 
112     // Implementation of C2Component interface
113     virtual c2_status_t setListener_vb(const std::shared_ptr<Listener>& listener,
114                                        c2_blocking_t mayBlock) override;
115     virtual c2_status_t queue_nb(std::list<std::unique_ptr<C2Work>>* const items) override;
116     virtual c2_status_t announce_nb(const std::vector<C2WorkOutline>& items) override;
117     virtual c2_status_t flush_sm(flush_mode_t mode,
118                                  std::list<std::unique_ptr<C2Work>>* const flushedWork) override;
119     virtual c2_status_t drain_nb(drain_mode_t mode) override;
120     virtual c2_status_t start() override;
121     virtual c2_status_t stop() override;
122     virtual c2_status_t reset() override;
123     virtual c2_status_t release() override;
124     virtual std::shared_ptr<C2ComponentInterface> intf() override;
125 
126     // Implementation of VideDecodeAcceleratorAdaptor::Client interface
127     virtual void providePictureBuffers(uint32_t minNumBuffers,
128                                        const media::Size& codedSize) override;
129     virtual void dismissPictureBuffer(int32_t pictureBufferId) override;
130     virtual void pictureReady(int32_t pictureBufferId, int32_t bitstreamId,
131                               const media::Rect& cropRect) override;
132     virtual void notifyEndOfBitstreamBuffer(int32_t bitstreamId) override;
133     virtual void notifyFlushDone() override;
134     virtual void notifyResetDone() override;
135     virtual void notifyError(VideoDecodeAcceleratorAdaptor::Result error) override;
136 
137 private:
138     // The state machine enumeration on parent thread.
139     enum class State : int32_t {
140         // The initial state of component. State will change to LOADED after the component is
141         // created.
142         UNLOADED,
143         // The component is stopped. State will change to RUNNING when start() is called by
144         // framework.
145         LOADED,
146         // The component is running, State will change to LOADED when stop() or reset() is called by
147         // framework.
148         RUNNING,
149         // The component is in error state.
150         ERROR,
151     };
152     // The state machine enumeration on component thread.
153     enum class ComponentState : int32_t {
154         // This is the initial state until VDA initialization returns successfully.
155         UNINITIALIZED,
156         // VDA initialization returns successfully. VDA is ready to make progress.
157         STARTED,
158         // onDrain() is called. VDA is draining. Component will hold on queueing works until
159         // onDrainDone().
160         DRAINING,
161         // onFlush() is called. VDA is flushing. State will change to STARTED after onFlushDone().
162         FLUSHING,
163         // onStop() is called. VDA is shutting down. State will change to UNINITIALIZED after
164         // onStopDone().
165         STOPPING,
166         // onError() is called.
167         ERROR,
168     };
169 
170     // This constant is used to tell apart from drain_mode_t enumerations in C2Component.h, which
171     // means no drain request.
172     // Note: this value must be different than all enumerations in drain_mode_t.
173     static constexpr uint32_t NO_DRAIN = ~0u;
174 
175     // Internal struct for work queue.
176     struct WorkEntry {
177         std::unique_ptr<C2Work> mWork;
178         uint32_t mDrainMode = NO_DRAIN;
179     };
180 
181     // Internal struct to keep the information of a specific graphic block.
182     struct GraphicBlockInfo {
183         enum class State {
184             OWNED_BY_COMPONENT,    // Owned by this component.
185             OWNED_BY_ACCELERATOR,  // Owned by video decode accelerator.
186             OWNED_BY_CLIENT,       // Owned by client.
187         };
188 
189         // The ID of this block used for accelerator.
190         int32_t mBlockId = -1;
191         // The ID of this block used in block pool. It indicates slot index for bufferqueue-backed
192         // block pool, and buffer ID of BufferPoolData for bufferpool block pool.
193         uint32_t mPoolId = 0;
194         State mState = State::OWNED_BY_COMPONENT;
195         // Graphic block buffer allocated from allocator. The graphic block should be owned until
196         // it is passed to client.
197         std::shared_ptr<C2GraphicBlock> mGraphicBlock;
198         // HAL pixel format used while importing to VDA.
199         HalPixelFormat mPixelFormat;
200         // The handle dupped from graphic block for importing to VDA.
201         ::base::ScopedFD mHandle;
202         // VideoFramePlane information for importing to VDA.
203         std::vector<VideoFramePlane> mPlanes;
204     };
205 
206     struct VideoFormat {
207         HalPixelFormat mPixelFormat = HalPixelFormat::UNKNOWN;
208         uint32_t mMinNumBuffers = 0;
209         media::Size mCodedSize;
210         media::Rect mVisibleRect;
211 
VideoFormatVideoFormat212         VideoFormat() {}
213         VideoFormat(HalPixelFormat pixelFormat, uint32_t minNumBuffers, media::Size codedSize,
214                     media::Rect visibleRect);
215     };
216 
217     // Internal struct for the information of output buffer returned from the accelerator.
218     struct OutputBufferInfo {
219         int32_t mBitstreamId;
220         int32_t mBlockId;
221     };
222 
223     // These tasks should be run on the component thread |mThread|.
224     void onDestroy();
225     void onStart(media::VideoCodecProfile profile, ::base::WaitableEvent* done);
226     void onQueueWork(std::unique_ptr<C2Work> work);
227     void onDequeueWork();
228     void onInputBufferDone(int32_t bitstreamId);
229     void onOutputBufferDone(int32_t pictureBufferId, int32_t bitstreamId);
230     void onDrain(uint32_t drainMode);
231     void onDrainDone();
232     void onFlush();
233     void onStop(::base::WaitableEvent* done);
234     void onResetDone();
235     void onFlushDone();
236     void onStopDone();
237     void onOutputFormatChanged(std::unique_ptr<VideoFormat> format);
238     void onVisibleRectChanged(const media::Rect& cropRect);
239     void onOutputBufferReturned(std::shared_ptr<C2GraphicBlock> block, uint32_t poolId);
240     void onSurfaceChanged();
241 
242     // Send input buffer to accelerator with specified bitstream id.
243     void sendInputBufferToAccelerator(const C2ConstLinearBlock& input, int32_t bitstreamId);
244     // Send output buffer to accelerator. If |passToAccelerator|, change the ownership to
245     // OWNED_BY_ACCELERATOR of this buffer.
246     void sendOutputBufferToAccelerator(GraphicBlockInfo* info, bool passToAccelerator);
247     // Set crop rectangle infomation to output format.
248     void setOutputFormatCrop(const media::Rect& cropRect);
249     // Helper function to get the specified GraphicBlockInfo object by its id.
250     GraphicBlockInfo* getGraphicBlockById(int32_t blockId);
251     // Helper function to get the specified GraphicBlockInfo object by its pool id.
252     GraphicBlockInfo* getGraphicBlockByPoolId(uint32_t poolId);
253     // Helper function to find the work iterator in |mPendingWorks| by bitstream id.
254     std::deque<std::unique_ptr<C2Work>>::iterator findPendingWorkByBitstreamId(int32_t bitstreamId);
255     // Helper function to get the specified work in |mPendingWorks| by bitstream id.
256     C2Work* getPendingWorkByBitstreamId(int32_t bitstreamId);
257     // Try to apply the output format change.
258     void tryChangeOutputFormat();
259     // Allocate output buffers (graphic blocks) from block allocator.
260     c2_status_t allocateBuffersFromBlockAllocator(const media::Size& size, uint32_t pixelFormat);
261     // Append allocated buffer (graphic block) to |mGraphicBlocks|.
262     void appendOutputBuffer(std::shared_ptr<C2GraphicBlock> block, uint32_t poolId);
263     // Append allocated buffer (graphic block) to |mGraphicBlocks| in secure mode.
264     void appendSecureOutputBuffer(std::shared_ptr<C2GraphicBlock> block, uint32_t poolId);
265     // Parse coded color aspects from bitstream and configs parameter if applicable.
266     bool parseCodedColorAspects(const C2ConstLinearBlock& input);
267     // Update color aspects for current output buffer.
268     c2_status_t updateColorAspects();
269     // Dequeue |mPendingBuffersToWork| to put output buffer to corresponding work and report if
270     // finished as many as possible. If |dropIfUnavailable|, drop all pending existing frames
271     // without blocking.
272     void sendOutputBufferToWorkIfAny(bool dropIfUnavailable);
273     // Update |mUndequeuedBlockIds| FIFO by pushing |blockId|.
274     void updateUndequeuedBlockIds(int32_t blockId);
275 
276     // Check if the corresponding work is finished by |bitstreamId|. If yes, make onWorkDone call to
277     // listener and erase the work from |mPendingWorks|.
278     void reportWorkIfFinished(int32_t bitstreamId);
279     // Make onWorkDone call to listener for reporting EOS work in |mPendingWorks|.
280     void reportEOSWork();
281     // Abandon all works in |mPendingWorks| and |mAbandonedWorks|.
282     void reportAbandonedWorks();
283     // Make onError call to listener for reporting errors.
284     void reportError(c2_status_t error);
285     // Helper function to determine if the work is finished.
286     bool isWorkDone(const C2Work* work) const;
287 
288     // Start dequeue thread, return true on success. If |resetBuffersInClient|, reset the counter
289     // |mBuffersInClient| on start.
290     bool startDequeueThread(const media::Size& size, uint32_t pixelFormat,
291                             std::shared_ptr<C2BlockPool> blockPool, bool resetBuffersInClient);
292     // Stop dequeue thread.
293     void stopDequeueThread();
294     // The rountine task running on dequeue thread.
295     void dequeueThreadLoop(const media::Size& size, uint32_t pixelFormat,
296                            std::shared_ptr<C2BlockPool> blockPool);
297 
298     // The pointer of component interface implementation.
299     std::shared_ptr<IntfImpl> mIntfImpl;
300     // The pointer of component interface.
301     const std::shared_ptr<C2ComponentInterface> mIntf;
302     // The pointer of component listener.
303     std::shared_ptr<Listener> mListener;
304 
305     // The main component thread.
306     ::base::Thread mThread;
307     // The task runner on component thread.
308     scoped_refptr<::base::SingleThreadTaskRunner> mTaskRunner;
309 
310     // The dequeue buffer loop thread.
311     ::base::Thread mDequeueThread;
312     // The stop signal for dequeue loop which should be atomic (toggled by main thread).
313     std::atomic<bool> mDequeueLoopStop;
314     // The count of buffers owned by client which should be atomic.
315     std::atomic<uint32_t> mBuffersInClient;
316 
317     // The following members should be utilized on component thread |mThread|.
318 
319     // The initialization result retrieved from VDA.
320     VideoDecodeAcceleratorAdaptor::Result mVDAInitResult;
321     // The pointer of VideoDecodeAcceleratorAdaptor.
322     std::unique_ptr<VideoDecodeAcceleratorAdaptor> mVDAAdaptor;
323     // The done event pointer of stop procedure. It should be restored in onStop() and signaled in
324     // onStopDone().
325     ::base::WaitableEvent* mStopDoneEvent;
326     // The state machine on component thread.
327     ComponentState mComponentState;
328     // The indicator of draining with EOS. This should be always set along with component going to
329     // DRAINING state, and will be unset either after reportEOSWork() (EOS is outputted), or
330     // reportAbandonedWorks() (drain is cancelled and works are abandoned).
331     bool mPendingOutputEOS;
332     // The vector of storing allocated output graphic block information.
333     std::vector<GraphicBlockInfo> mGraphicBlocks;
334     // The work queue. Works are queued along with drain mode from component API queue_nb and
335     // dequeued by the decode process of component.
336     std::queue<WorkEntry> mQueue;
337     // Store all pending works. The dequeued works are placed here until they are finished and then
338     // sent out by onWorkDone call to listener.
339     std::deque<std::unique_ptr<C2Work>> mPendingWorks;
340     // Store all abandoned works. When component gets flushed/stopped, remaining works in queue are
341     // dumped here and sent out by onWorkDone call to listener after flush/stop is finished.
342     std::vector<std::unique_ptr<C2Work>> mAbandonedWorks;
343     // Store the visible rect provided from VDA. If this is changed, component should issue a
344     // visible size change event.
345     media::Rect mRequestedVisibleRect;
346     // The current output format.
347     VideoFormat mOutputFormat;
348     // The pending output format. We need to wait until all buffers are returned back to apply the
349     // format change.
350     std::unique_ptr<VideoFormat> mPendingOutputFormat;
351     // The color aspects parameter for current decoded output buffers.
352     std::shared_ptr<C2StreamColorAspectsInfo::output> mCurrentColorAspects;
353     // The flag of pending color aspects change. This should be set once we have parsed color
354     // aspects from bitstream by parseCodedColorAspects(), at the same time recorded input frame
355     // index into |mPendingColorAspectsChangeFrameIndex|.
356     // When this flag is true and the corresponding frame index is not less than
357     // |mPendingColorAspectsChangeFrameIndex| for the output buffer in onOutputBufferDone(), update
358     // |mCurrentColorAspects| from component interface and reset the flag.
359     bool mPendingColorAspectsChange;
360     // The record of frame index to update color aspects. Details as above.
361     uint64_t mPendingColorAspectsChangeFrameIndex;
362     // The record of bitstream and block ID of pending output buffers returned from accelerator.
363     std::deque<OutputBufferInfo> mPendingBuffersToWork;
364     // A FIFO queue to record the block IDs which are currently undequequed for display. The size
365     // of this queue will be equal to the minimum number of undequeued buffers.
366     std::deque<int32_t> mUndequeuedBlockIds;
367 
368     // The indicator of whether component is in secure mode.
369     bool mSecureMode;
370 
371     // The following members should be utilized on parent thread.
372 
373     // The input codec profile which is configured in component interface.
374     media::VideoCodecProfile mCodecProfile;
375     // The state machine on parent thread which should be atomic.
376     std::atomic<State> mState;
377     // The mutex lock to synchronize start/stop/reset/release calls.
378     std::mutex mStartStopLock;
379 
380     // The WeakPtrFactory for getting weak pointer of this.
381     ::base::WeakPtrFactory<C2VDAComponent> mWeakThisFactory;
382 
383     DISALLOW_COPY_AND_ASSIGN(C2VDAComponent);
384 };
385 
386 }  // namespace android
387 
388 #endif  // ANDROID_C2_VDA_COMPONENT_H
389