OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2012 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 // This file contains an implementation of VideoDecoderAccelerator | |
6 // that utilizes hardware video decoder present on the Exynos SoC. | |
7 | |
8 #ifndef CONTENT_COMMON_GPU_MEDIA_EXYNOS_VIDEO_DECODE_ACCELERATOR_H_ | |
9 #define CONTENT_COMMON_GPU_MEDIA_EXYNOS_VIDEO_DECODE_ACCELERATOR_H_ | |
10 | |
11 #include <deque> | |
12 #include <vector> | |
13 | |
14 #include "base/callback_forward.h" | |
15 #include "base/file_util.h" | |
16 #include "base/memory/linked_ptr.h" | |
17 #include "base/memory/scoped_ptr.h" | |
18 #include "base/threading/thread.h" | |
19 #include "content/common/content_export.h" | |
20 #include "media/base/video_decoder_config.h" | |
21 #include "media/video/video_decode_accelerator.h" | |
22 #include "third_party/angle/include/EGL/egl.h" | |
23 #include "third_party/angle/include/EGL/eglext.h" | |
24 #include "ui/gfx/size.h" | |
25 | |
26 namespace base { | |
27 class MessageLoopProxy; | |
28 } | |
29 | |
30 namespace gfx { | |
31 class GLContext; | |
32 } | |
33 | |
34 namespace content { | |
35 | |
36 // This class handls Exynos video acceleration directly through the V4L2 devices | |
37 // exported by the Multi Format Codec and GScaler hardware blocks. | |
38 // | |
39 // The threading model of this class is driven by the fact that it needs to | |
40 // interface two fundamentally different event queues -- the one Chromium | |
41 // provides through MessageLoop, and the one driven by the V4L2 devices which | |
42 // is waited on with epoll(). There are three threads involved in this class: | |
43 // | |
44 // * The child thread, which is the main GPU process thread which calls the | |
45 // media::VideoDecodeAccelerator entry points. Calls from this thread | |
46 // generally do not block (with the exception of Initialize() and Destroy()). | |
47 // They post tasks to the decoder_thread_, which actually services the task | |
48 // and calls back when complete through the | |
49 // media::VideoDecodeAccelerator::Client interface. | |
50 // * The decoder_thread_, owned by this class. It services API tasks as well as | |
51 // device events. Pretty much all state modification is done on this thread. | |
52 // * The device_poll_thread_, owned by this class. All it does is epoll() on | |
53 // the V4L2 device and notify the decoder_thread_ when something interesting | |
54 // happens. | |
55 // | |
56 // Note that this class has no locks! Everything's serviced on the | |
57 // decoder_thread_, so there are no synchronization issues. | |
58 // ... well, there are, but it's a matter of getting messages posted in the | |
59 // right order, not fiddling with locks. | |
60 class CONTENT_EXPORT ExynosVideoDecodeAccelerator : | |
61 public media::VideoDecodeAccelerator { | |
62 public: | |
63 ExynosVideoDecodeAccelerator( | |
64 gfx::GLContext* gl_context, | |
65 Client* client, | |
66 const base::Callback<bool(void)>& make_context_current); | |
67 virtual ~ExynosVideoDecodeAccelerator(); | |
68 | |
69 // media::VideoDecodeAccelerator implementation. | |
70 // Note: Initialize() and Destroy() are synchronous. | |
71 virtual bool Initialize(media::VideoCodecProfile profile) OVERRIDE; | |
72 virtual void Decode(const media::BitstreamBuffer& bitstream_buffer) OVERRIDE; | |
73 virtual void AssignPictureBuffers( | |
74 const std::vector<media::PictureBuffer>& buffers) OVERRIDE; | |
75 virtual void ReusePictureBuffer(int32 picture_buffer_id) OVERRIDE; | |
76 virtual void Flush() OVERRIDE; | |
77 virtual void Reset() OVERRIDE; | |
78 virtual void Destroy() OVERRIDE; | |
79 | |
80 // Do any necessary initialization before the sandbox is enabled. | |
81 static void PreSandboxInitialization(); | |
82 | |
83 // Lazily initialize static data after sandbox is enabled. Return false on | |
84 // init failure. | |
85 static bool PostSandboxInitialization(); | |
86 | |
87 private: | |
88 // These are rather subjectively tuned. | |
89 enum { | |
90 kMfcInputBufferCount = 4, | |
91 kMfcOutputBufferExtraCount = 2, | |
92 kMfcInputBufferMaxSize = 1024 * 1024, | |
93 kGscInputBufferCount = 4, | |
94 kGscOutputBufferCount = 6, | |
95 }; | |
96 | |
97 // Internal state of the decoder. | |
98 enum State { | |
99 kUninitialized, // Initialize() not yet called. | |
100 kInitialized, // Initialize() called. Ready to start decoding. | |
101 kDecoding, // DecodeBufferInitial() successful; decoding frames. | |
102 kResetting, // Presently resetting. | |
103 kAfterReset, // After Reset(), ready to start decoding again. | |
104 kError, // Error in kDecoding state. | |
105 }; | |
106 | |
107 // Record for decoder input buffers. | |
108 struct BitstreamBufferRecord { | |
109 BitstreamBufferRecord(base::SharedMemory* shm, size_t size, int32 input_id); | |
110 ~BitstreamBufferRecord(); | |
111 const scoped_ptr<base::SharedMemory> shm; | |
112 const size_t size; | |
113 const int32 input_id; | |
114 }; | |
115 | |
116 // Record for MFC input buffers. | |
117 struct MfcInputRecord { | |
118 MfcInputRecord(); | |
119 ~MfcInputRecord(); | |
120 bool at_device; // held by device. | |
121 void* offset; // mmap() offset. | |
122 size_t length; // mmap() length. | |
123 off_t bytes_used; // bytes filled in the mmap() segment. | |
124 int32 input_id; // triggering input_id as given to Decode(). | |
125 }; | |
126 | |
127 // Record for MFC output buffers. | |
128 struct MfcOutputRecord { | |
129 MfcOutputRecord(); | |
130 ~MfcOutputRecord(); | |
131 bool at_device; // held by device. | |
132 size_t bytes_used[2]; // bytes used in each dmabuf. | |
133 void* offset[2]; // mmap() offset for each plane. | |
134 size_t length[2]; // mmap() length for each plane. | |
135 int32 input_id; // triggering input_id as given to Decode(). | |
136 }; | |
137 | |
138 // Record for GSC input buffers. | |
139 struct GscInputRecord { | |
140 GscInputRecord(); | |
141 ~GscInputRecord(); | |
142 bool at_device; // held by device. | |
143 int mfc_output; // MFC output buffer index to recycle when this input | |
144 // is complete | |
145 }; | |
146 | |
147 // Record for GSC output buffers. | |
148 struct GscOutputRecord { | |
149 GscOutputRecord(); | |
150 ~GscOutputRecord(); | |
151 bool at_device; // held by device. | |
152 bool at_client; // held by client. | |
153 int fd; // file descriptor from backing EGLImage. | |
154 EGLImageKHR egl_image; // backing EGLImage. | |
155 EGLSyncKHR egl_sync; // sync the compositor's use of the EGLImage. | |
156 int32 picture_id; // picture ID as returned to PictureReady(). | |
157 }; | |
158 | |
159 // Auto-destruction reference for an array of EGLImage (for message-passing) | |
160 struct EGLImageKHRArrayRef { | |
161 EGLImageKHRArrayRef(EGLDisplay egl_display, EGLImageKHR egl_images[], | |
162 int egl_image_fds[], int egl_images_count); | |
163 ~EGLImageKHRArrayRef(); | |
164 EGLDisplay const egl_display; | |
165 const scoped_array<EGLImageKHR> egl_images; | |
166 const scoped_array<int> egl_image_fds; | |
167 const int egl_images_count; | |
168 }; | |
169 | |
170 // Auto-destruction reference for EGLSync (for message-passing) | |
171 struct EGLSyncKHRRef { | |
172 EGLSyncKHRRef(EGLDisplay egl_display, EGLSyncKHR egl_sync); | |
173 ~EGLSyncKHRRef(); | |
174 EGLDisplay const egl_display; | |
175 EGLSyncKHR egl_sync; | |
176 }; | |
177 | |
178 // | |
179 // Decoding tasks, to be run on decode_thread_. | |
180 // | |
181 | |
182 // Enqueue a BitstreamBuffer to decode. This will enqueue a | |
183 // DecodeBufferTask() to actually decode the buffer. | |
184 void DecodeTask(scoped_ptr<BitstreamBufferRecord> bitstream_record); | |
185 | |
186 // Decode from the queued BitstreamBuffers. Calls DecodeBufferInitial() | |
187 // or DecodeBufferContinue(). | |
188 void DecodeBufferTask(); | |
189 // There return true if an input buffer is consumed, otherwise false. It may | |
Ami GONE FROM CHROMIUM
2012/11/02 17:57:06
s/There/These/ but more stylish to use the active
sheu
2012/11/03 00:37:14
Done.
| |
190 // not be an error condition not to consume a buffer. | |
191 bool DecodeBufferInitial(const void* data, size_t size); | |
192 bool DecodeBufferContinue(const void* data, size_t size); | |
193 // Helpers: accumulate and flush data for one decoded frame. | |
194 bool AppendToInputFrame(const void* data, size_t size); | |
195 bool FlushInputFrame(); | |
196 | |
197 // Process an AssignPictureBuffers() API call. After this, the | |
198 // device_poll_thread_ can be started safely, since we have all our | |
199 // buffers. | |
200 void AssignPictureBuffersTask(scoped_ptr<EGLImageKHRArrayRef> egl_images_ref); | |
201 | |
202 // Service I/O on the V4L2 devices. | |
203 void ServiceDeviceTask(); | |
204 // Handle the various device queues. | |
205 void EnqueueMfc(); | |
206 void DequeueMfc(); | |
207 void EnqueueGsc(); | |
208 void DequeueGsc(); | |
209 | |
210 // Process a ReusePictureBuffer() API call. The API call create an EGLSync | |
211 // object on the main (GPU process) thread; we will record this object so we | |
212 // can wait on it before reusing the buffer. | |
213 void ReusePictureBufferTask(int32 picture_buffer_id, | |
214 scoped_ptr<EGLSyncKHRRef> egl_sync_ref); | |
215 | |
216 // Flush() task. Child thread should not submit any more buffers until it | |
217 // receives the NotifyFlushDone callback. | |
218 void FlushTask(); | |
219 | |
220 // Reset() task. This task will schedule a ResetDoneTask() that will send | |
221 // the NotifyResetDone callback, then set the decoder state to kResetting so | |
222 // that all intervening tasks will drain. | |
223 void ResetTask(); | |
224 void ResetDoneTask(); | |
225 | |
226 // Device destruction task. | |
227 void DestroyTask(); | |
228 | |
229 // Start/stop DevicePollLoop() running on device_monitor_thread_. | |
Ami GONE FROM CHROMIUM
2012/11/02 21:11:08
doco return value. in particular ISTM Start() can
sheu
2012/11/03 00:37:14
Done.
| |
230 bool StartDevicePoll(); | |
231 bool StopDevicePoll(); | |
232 | |
233 // | |
234 // Device tasks, to be run on device_poll_thread_. | |
235 // | |
236 | |
237 // The device task. | |
238 void DevicePollLoop(); | |
239 | |
240 // | |
241 // Safe from any thread (uses PostTask() to child thread). | |
242 // | |
243 | |
244 // Error notification. | |
245 void NotifyError(Error error); | |
246 | |
247 // | |
248 // Other utility functions | |
Ami GONE FROM CHROMIUM
2012/11/02 17:57:06
doco which thread they run on?
sheu
2012/11/03 00:37:14
Done.
| |
249 // | |
250 | |
251 // Create the buffers we need. | |
252 bool CreateMfcInputBuffers(); | |
253 bool CreateMfcOutputBuffers(); | |
254 bool CreateGscInputBuffers(); | |
255 bool CreateGscOutputBuffers(); | |
256 | |
257 // Destroy these buffers. | |
258 void DestroyMfcInputBuffers(); | |
259 void DestroyMfcOutputBuffers(); | |
260 void DestroyGscInputBuffers(); | |
261 void DestroyGscOutputBuffers(); | |
262 | |
263 // Our original calling message loop for the child thread. | |
264 scoped_refptr<base::MessageLoopProxy> child_message_loop_proxy_; | |
265 | |
266 // WeakPtr<> pointing to |this| for use in posting tasks from the decoder or | |
267 // device worker threads back to the child thread. Because the worker threads | |
268 // are members of this class, any task running on those threads is guaranteed | |
269 // that this object is still alive. As a result, tasks posted from the child | |
270 // thread to the decoder or device thread should use base::Unretained(this), | |
271 // and tasks posted the other way should use |weak_this_|. | |
272 base::WeakPtr<ExynosVideoDecodeAccelerator> weak_this_; | |
273 | |
274 // To expose client callbacks from VideoDecodeAccelerator. | |
275 // NOTE: all calls to these objects *MUST* be executed on | |
276 // child_message_loop_proxy_. | |
277 base::WeakPtrFactory<Client> client_ptr_factory_; | |
278 base::WeakPtr<Client> client_; | |
279 | |
280 // | |
281 // Decoder state, owned and operated by decoder_thread_. | |
282 // Before decoder_thread_ has started, the decoder state is managed by | |
283 // the child (main) thread. After decoder_thread_ has started, the decoder | |
284 // thread should be the only one managing these. | |
285 // | |
286 | |
287 // This thread services tasks posted from the VDA API entry points by the | |
288 // child thread and device service callbacks posted from the device thread. | |
289 base::Thread decoder_thread_; | |
290 // Decoder state machine state. | |
291 State decoder_state_; | |
292 // Bitstream buffer we're presently reading. | |
293 scoped_ptr<BitstreamBufferRecord> decoder_current_bitstream_buffer_; | |
294 // MFC input buffer we're presently filling. | |
295 int decoder_current_input_buffer_; | |
296 // We track the number of buffer decode tasks we have scheduled, since each | |
297 // task execution should complete one buffer. If we fall behind (due to | |
298 // resource backpressure, etc.), we'll have to schedule more to catch up. | |
299 int decoder_decode_buffer_tasks_scheduled_; | |
300 // Buffers in the pipe, five-by-five. | |
301 int decoder_frames_inflight_; | |
302 // Buffers held by the client. | |
303 int decoder_frames_at_client_; | |
304 // Are we waiting for a flush notification? | |
305 bool decoder_flush_notify_requested_; | |
306 // Input queue for decoder_thread_: BitstreamBuffers in. | |
307 std::deque<linked_ptr<BitstreamBufferRecord> > decoder_input_queue_; | |
308 | |
309 // | |
310 // Hardware state and associated queues. Since decoder_thread_ services | |
311 // the hardware, decoder_thread_ owns these too. | |
312 // | |
313 | |
314 // Completed decode buffers, waiting for MFC. | |
315 std::deque<int> mfc_input_ready_queue_; | |
316 | |
317 // MFC decode device. | |
318 int mfc_fd_; | |
319 file_util::ScopedFD mfc_fd_closer_; | |
320 | |
321 // MFC input buffer state. | |
322 bool mfc_input_streamon_; | |
323 int mfc_input_buffer_count_; | |
324 // MFC input buffes enqueued to device, total. | |
325 int mfc_input_buffer_queued_count_; | |
326 // Input buffers ready to use, as a FIFO since we don't care about ordering. | |
327 std::vector<int> mfc_free_input_buffers_; | |
328 // Mapping of int index to MFC input buffer record. | |
329 std::vector<MfcInputRecord> mfc_input_buffer_map_; | |
330 | |
331 // MFC output buffer state. | |
332 bool mfc_output_streamon_; | |
333 int mfc_output_buffer_count_; | |
334 // Output buffers ready to use, as a FIFO since we don't care about ordering. | |
335 std::vector<int> mfc_free_output_buffers_; | |
336 // Mapping of int index to MFC output buffer record. | |
337 std::vector<MfcOutputRecord> mfc_output_buffer_map_; | |
338 // Required size of MFC output buffers. Two sizes for two planes. | |
339 size_t mfc_output_buffer_size_[2]; | |
340 uint32 mfc_output_buffer_pixelformat_; | |
341 | |
342 // Completed MFC outputs, waiting for GSC. | |
343 std::deque<int> mfc_output_gsc_input_queue_; | |
344 | |
345 // GSC decode device. | |
346 int gsc_fd_; | |
347 file_util::ScopedFD gsc_fd_closer_; | |
348 | |
349 // GSC input buffer state. | |
350 bool gsc_input_streamon_; | |
351 int gsc_input_buffer_count_; | |
352 // Input buffers ready to use, as a FIFO since we don't care about ordering. | |
353 std::vector<int> gsc_free_input_buffers_; | |
354 // Mapping of int index to GSC input buffer record. | |
355 std::vector<GscInputRecord> gsc_input_buffer_map_; | |
356 | |
357 // GSC output buffer state. | |
358 bool gsc_output_streamon_; | |
359 int gsc_output_buffer_count_; | |
360 // GSC output buffers enqueued to device and ready, but not yet in use. | |
361 int gsc_output_buffer_prepared_count_; | |
362 // GSC output buffers enqueued to device, total. | |
363 int gsc_output_buffer_queued_count_; | |
364 // Output buffers ready to use. We need a LIFO here. | |
365 std::deque<int> gsc_free_output_buffers_; | |
366 // Mapping of int index to GSC output buffer record. | |
367 std::vector<GscOutputRecord> gsc_output_buffer_map_; | |
368 | |
369 // Output picture size. | |
370 gfx::Size frame_buffer_size_; | |
371 | |
372 // | |
373 // The device polling thread handles notifications of V4L2 device changes. | |
374 // | |
375 | |
376 // The thread. | |
377 base::Thread device_poll_thread_; | |
378 | |
379 // | |
380 // Other state, held by the child (main) thread. | |
381 // | |
382 | |
383 // GL state | |
384 gfx::GLContext* gl_context_; | |
385 // Make our context current before running any EGL entry points. | |
386 base::Callback<bool(void)> make_context_current_; | |
387 | |
388 // EGL state | |
389 EGLContext egl_context_; | |
390 EGLDisplay egl_display_; | |
391 | |
392 // The codec we'll be decoding for. | |
393 media::VideoCodecProfile video_profile_; | |
394 | |
395 DISALLOW_COPY_AND_ASSIGN(ExynosVideoDecodeAccelerator); | |
396 }; | |
397 | |
398 } // namespace content | |
399 | |
400 #endif // CONTENT_COMMON_GPU_MEDIA_EXYNOS_VIDEO_DECODE_ACCELERATOR_H_ | |
OLD | NEW |