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