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 <queue> | |
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 "content/common/gpu/media/video_decode_accelerator_impl.h" | |
20 #include "media/base/limits.h" | |
21 #include "media/base/video_decoder_config.h" | |
22 #include "media/video/picture.h" | |
23 #include "ui/gfx/size.h" | |
24 #include "ui/gl/gl_bindings.h" | |
25 | |
26 namespace base { | |
27 class MessageLoopProxy; | |
28 } | |
29 | |
30 namespace content { | |
31 class H264Parser; | |
32 | |
33 // This class handles Exynos video acceleration directly through the V4L2 | |
34 // device exported by the Multi Format Codec hardware block. | |
35 // | |
36 // The threading model of this class is driven by the fact that it needs to | |
37 // interface two fundamentally different event queues -- the one Chromium | |
38 // provides through MessageLoop, and the one driven by the V4L2 devices which | |
39 // is waited on with epoll(). There are three threads involved in this class: | |
40 // | |
41 // * The child thread, which is the main GPU process thread which calls the | |
42 // media::VideoDecodeAccelerator entry points. Calls from this thread | |
43 // generally do not block (with the exception of Initialize() and Destroy()). | |
44 // They post tasks to the decoder_thread_, which actually services the task | |
45 // and calls back when complete through the | |
46 // media::VideoDecodeAccelerator::Client interface. | |
47 // * The decoder_thread_, owned by this class. It services API tasks, through | |
48 // the *Task() routines, as well as V4L2 device events, through | |
49 // ServiceDeviceTask(). Almost all state modification is done on this thread. | |
50 // * The device_poll_thread_, owned by this class. All it does is epoll() on | |
51 // the V4L2 in DevicePollTask() and schedule a ServiceDeviceTask() on the | |
52 // decoder_thread_ when something interesting happens. | |
53 // TODO(sheu): replace this thread with an TYPE_IO decoder_thread_. | |
54 // | |
55 // Note that this class has no locks! Everything's serviced on the | |
56 // decoder_thread_, so there are no synchronization issues. | |
57 // ... well, there are, but it's a matter of getting messages posted in the | |
58 // right order, not fiddling with locks. | |
59 class CONTENT_EXPORT ExynosVideoDecodeAccelerator | |
60 : public VideoDecodeAcceleratorImpl { | |
61 public: | |
62 ExynosVideoDecodeAccelerator( | |
63 EGLDisplay egl_display, | |
64 Client* client, | |
65 const base::WeakPtr<Client>& io_client_, | |
66 const base::Callback<bool(void)>& make_context_current, | |
67 const scoped_refptr<base::MessageLoopProxy>& io_message_loop_proxy); | |
68 virtual ~ExynosVideoDecodeAccelerator(); | |
69 | |
70 // media::VideoDecodeAccelerator implementation. | |
71 // Note: Initialize() and Destroy() are synchronous. | |
72 virtual bool Initialize(media::VideoCodecProfile profile) OVERRIDE; | |
73 virtual void Decode(const media::BitstreamBuffer& bitstream_buffer) OVERRIDE; | |
74 virtual void AssignPictureBuffers( | |
75 const std::vector<media::PictureBuffer>& buffers) OVERRIDE; | |
76 virtual void ReusePictureBuffer(int32 picture_buffer_id) OVERRIDE; | |
77 virtual void Flush() OVERRIDE; | |
78 virtual void Reset() OVERRIDE; | |
79 virtual void Destroy() OVERRIDE; | |
80 | |
81 // VideoDecodeAcceleratorImpl implementation. | |
82 virtual bool CanDecodeOnIOThread() OVERRIDE; | |
83 | |
84 private: | |
85 // These are rather subjectively tuned. | |
86 enum { | |
87 kMfcInputBufferCount = 8, | |
88 // TODO(posciak): determine MFC input buffer size based on level limits. | |
89 // See http://crbug.com/255116. | |
90 kMfcInputBufferMaxSize = 1024 * 1024, | |
91 // Number of output buffers to use for each VDA stage above what's required | |
92 // by the decoder (e.g. DPB size, in H264). We need | |
93 // media::limits::kMaxVideoFrames to fill up the GpuVideoDecode pipeline, | |
94 // and +1 for a frame in transit. | |
95 kDpbOutputBufferExtraCount = media::limits::kMaxVideoFrames + 1, | |
96 }; | |
97 | |
98 // Internal state of the decoder. | |
99 enum State { | |
100 kUninitialized, // Initialize() not yet called. | |
101 kInitialized, // Initialize() returned true; ready to start decoding. | |
102 kDecoding, // DecodeBufferInitial() successful; decoding frames. | |
103 kResetting, // Presently resetting. | |
104 kAfterReset, // After Reset(), ready to start decoding again. | |
105 kChangingResolution, // Performing resolution change, all remaining | |
106 // pre-change frames decoded and processed. | |
107 kError, // Error in kDecoding state. | |
108 }; | |
109 | |
110 enum BufferId { | |
111 kFlushBufferId = -2 // Buffer id for flush buffer, queued by FlushTask(). | |
112 }; | |
113 | |
114 // File descriptors we need to poll. | |
115 enum PollFds { | |
116 kPollMfc = (1 << 0), | |
117 }; | |
118 | |
119 // Auto-destruction reference for BitstreamBuffer, for message-passing from | |
120 // Decode() to DecodeTask(). | |
121 struct BitstreamBufferRef; | |
122 | |
123 // Auto-destruction reference for an array of PictureBuffer, for | |
124 // message-passing from AssignPictureBuffers() to AssignPictureBuffersTask(). | |
125 struct PictureBufferArrayRef; | |
126 | |
127 // Auto-destruction reference for EGLSync (for message-passing). | |
128 struct EGLSyncKHRRef; | |
129 | |
130 // Record for decoded pictures that can be sent to PictureReady. | |
131 struct PictureRecord; | |
132 | |
133 // Record for MFC input buffers. | |
134 struct MfcInputRecord { | |
135 MfcInputRecord(); | |
136 ~MfcInputRecord(); | |
137 bool at_device; // held by device. | |
138 void* address; // mmap() address. | |
139 size_t length; // mmap() length. | |
140 off_t bytes_used; // bytes filled in the mmap() segment. | |
141 int32 input_id; // triggering input_id as given to Decode(). | |
142 }; | |
143 | |
144 // Record for MFC output buffers. | |
145 struct MfcOutputRecord { | |
146 MfcOutputRecord(); | |
147 ~MfcOutputRecord(); | |
148 bool at_device; // held by device. | |
149 bool at_client; // held by client. | |
150 int fds[2]; // file descriptors for each plane. | |
151 EGLImageKHR egl_image; // EGLImageKHR for the output buffer. | |
152 EGLSyncKHR egl_sync; // sync the compositor's use of the EGLImage. | |
153 int32 picture_id; // picture buffer id as returned to PictureReady(). | |
154 bool cleared; // Whether the texture is cleared and safe to render | |
155 // from. See TextureManager for details. | |
156 }; | |
157 | |
158 // | |
159 // Decoding tasks, to be run on decode_thread_. | |
160 // | |
161 | |
162 // Enqueue a BitstreamBuffer to decode. This will enqueue a buffer to the | |
163 // decoder_input_queue_, then queue a DecodeBufferTask() to actually decode | |
164 // the buffer. | |
165 void DecodeTask(const media::BitstreamBuffer& bitstream_buffer); | |
166 | |
167 // Decode from the buffers queued in decoder_input_queue_. Calls | |
168 // DecodeBufferInitial() or DecodeBufferContinue() as appropriate. | |
169 void DecodeBufferTask(); | |
170 // Advance to the next fragment that begins a frame. | |
171 bool AdvanceFrameFragment(const uint8* data, size_t size, size_t* endpos); | |
172 // Schedule another DecodeBufferTask() if we're behind. | |
173 void ScheduleDecodeBufferTaskIfNeeded(); | |
174 | |
175 // Return true if we should continue to schedule DecodeBufferTask()s after | |
176 // completion. Store the amount of input actually consumed in |endpos|. | |
177 bool DecodeBufferInitial(const void* data, size_t size, size_t* endpos); | |
178 bool DecodeBufferContinue(const void* data, size_t size); | |
179 | |
180 // Accumulate data for the next frame to decode. May return false in | |
181 // non-error conditions; for example when pipeline is full and should be | |
182 // retried later. | |
183 bool AppendToInputFrame(const void* data, size_t size); | |
184 // Flush data for one decoded frame. | |
185 bool FlushInputFrame(); | |
186 | |
187 // Process an AssignPictureBuffers() API call. After this, the | |
188 // device_poll_thread_ can be started safely, since we have all our | |
189 // buffers. | |
190 void AssignPictureBuffersTask(scoped_ptr<PictureBufferArrayRef> pic_buffers); | |
191 | |
192 // Service I/O on the V4L2 devices. This task should only be scheduled from | |
193 // DevicePollTask(). If |mfc_event_pending| is true, one or more events | |
194 // on MFC file descriptor are pending. | |
195 void ServiceDeviceTask(bool mfc_event_pending); | |
196 // Handle the various device queues. | |
197 void EnqueueMfc(); | |
198 void DequeueMfc(); | |
199 // Handle incoming MFC events. | |
200 void DequeueMfcEvents(); | |
201 // Enqueue a buffer on the corresponding queue. | |
202 bool EnqueueMfcInputRecord(); | |
203 bool EnqueueMfcOutputRecord(); | |
204 | |
205 // Process a ReusePictureBuffer() API call. The API call create an EGLSync | |
206 // object on the main (GPU process) thread; we will record this object so we | |
207 // can wait on it before reusing the buffer. | |
208 void ReusePictureBufferTask(int32 picture_buffer_id, | |
209 scoped_ptr<EGLSyncKHRRef> egl_sync_ref); | |
210 | |
211 // Flush() task. Child thread should not submit any more buffers until it | |
212 // receives the NotifyFlushDone callback. This task will schedule an empty | |
213 // BitstreamBufferRef (with input_id == kFlushBufferId) to perform the flush. | |
214 void FlushTask(); | |
215 // Notify the client of a flush completion, if required. This should be | |
216 // called any time a relevant queue could potentially be emptied: see | |
217 // function definition. | |
218 void NotifyFlushDoneIfNeeded(); | |
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 // ResetDoneTask() will set the decoder state back to kAfterReset, so | |
225 // subsequent decoding can continue. | |
226 void ResetDoneTask(); | |
227 | |
228 // Device destruction task. | |
229 void DestroyTask(); | |
230 | |
231 // Attempt to start/stop device_poll_thread_. | |
232 bool StartDevicePoll(); | |
233 // If |keep_mfc_input_state| is true, don't reset MFC input state; used during | |
234 // resolution change. | |
235 bool StopDevicePoll(bool keep_mfc_input_state); | |
236 // Set/clear the device poll interrupt (using device_poll_interrupt_fd_). | |
237 bool SetDevicePollInterrupt(); | |
238 bool ClearDevicePollInterrupt(); | |
239 | |
240 void StartResolutionChangeIfNeeded(); | |
241 void FinishResolutionChange(); | |
242 void ResumeAfterResolutionChange(); | |
243 | |
244 // Try to get output format from MFC, detected after parsing the beginning | |
245 // of the stream. Sets |again| to true if more parsing is needed. | |
246 bool GetFormatInfo(struct v4l2_format* format, bool* again); | |
247 // Create MFC output buffers for the given |format|. | |
248 bool CreateBuffersForFormat(const struct v4l2_format& format); | |
249 | |
250 // | |
251 // Device tasks, to be run on device_poll_thread_. | |
252 // | |
253 | |
254 // The device task. | |
255 void DevicePollTask(unsigned int poll_fds); | |
256 | |
257 // | |
258 // Safe from any thread. | |
259 // | |
260 | |
261 // Error notification (using PostTask() to child thread, if necessary). | |
262 void NotifyError(Error error); | |
263 | |
264 // Set the decoder_thread_ state (using PostTask to decoder thread, if | |
265 // necessary). | |
266 void SetDecoderState(State state); | |
267 | |
268 // | |
269 // Other utility functions. Called on decoder_thread_, unless | |
270 // decoder_thread_ is not yet started, in which case the child thread can call | |
271 // these (e.g. in Initialize() or Destroy()). | |
272 // | |
273 | |
274 // Create the buffers we need. | |
275 bool CreateMfcInputBuffers(); | |
276 bool CreateMfcOutputBuffers(); | |
277 | |
278 // | |
279 // Methods run on child thread. | |
280 // | |
281 | |
282 // Destroy buffers. | |
283 void DestroyMfcInputBuffers(); | |
284 void DestroyMfcOutputBuffers(); | |
285 void ResolutionChangeDestroyBuffers(); | |
286 | |
287 // Send decoded pictures to PictureReady. | |
288 void SendPictureReady(); | |
289 | |
290 // Callback that indicates a picture has been cleared. | |
291 void PictureCleared(); | |
292 | |
293 // Our original calling message loop for the child thread. | |
294 scoped_refptr<base::MessageLoopProxy> child_message_loop_proxy_; | |
295 | |
296 // Message loop of the IO thread. | |
297 scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy_; | |
298 | |
299 // WeakPtr<> pointing to |this| for use in posting tasks from the decoder or | |
300 // device worker threads back to the child thread. Because the worker threads | |
301 // are members of this class, any task running on those threads is guaranteed | |
302 // that this object is still alive. As a result, tasks posted from the child | |
303 // thread to the decoder or device thread should use base::Unretained(this), | |
304 // and tasks posted the other way should use |weak_this_|. | |
305 base::WeakPtr<ExynosVideoDecodeAccelerator> weak_this_; | |
306 | |
307 // To expose client callbacks from VideoDecodeAccelerator. | |
308 // NOTE: all calls to these objects *MUST* be executed on | |
309 // child_message_loop_proxy_. | |
310 base::WeakPtrFactory<Client> client_ptr_factory_; | |
311 base::WeakPtr<Client> client_; | |
312 // Callbacks to |io_client_| must be executed on |io_message_loop_proxy_|. | |
313 base::WeakPtr<Client> io_client_; | |
314 | |
315 // | |
316 // Decoder state, owned and operated by decoder_thread_. | |
317 // Before decoder_thread_ has started, the decoder state is managed by | |
318 // the child (main) thread. After decoder_thread_ has started, the decoder | |
319 // thread should be the only one managing these. | |
320 // | |
321 | |
322 // This thread services tasks posted from the VDA API entry points by the | |
323 // child thread and device service callbacks posted from the device thread. | |
324 base::Thread decoder_thread_; | |
325 // Decoder state machine state. | |
326 State decoder_state_; | |
327 // BitstreamBuffer we're presently reading. | |
328 scoped_ptr<BitstreamBufferRef> decoder_current_bitstream_buffer_; | |
329 // FlushTask() and ResetTask() should not affect buffers that have been | |
330 // queued afterwards. For flushing or resetting the pipeline then, we will | |
331 // delay these buffers until after the flush or reset completes. | |
332 int decoder_delay_bitstream_buffer_id_; | |
333 // MFC input buffer we're presently filling. | |
334 int decoder_current_input_buffer_; | |
335 // We track the number of buffer decode tasks we have scheduled, since each | |
336 // task execution should complete one buffer. If we fall behind (due to | |
337 // resource backpressure, etc.), we'll have to schedule more to catch up. | |
338 int decoder_decode_buffer_tasks_scheduled_; | |
339 // Picture buffers held by the client. | |
340 int decoder_frames_at_client_; | |
341 // Are we flushing? | |
342 bool decoder_flushing_; | |
343 // Got a notification from driver that it reached resolution change point | |
344 // in the stream. | |
345 bool resolution_change_pending_; | |
346 // Got a reset request while we were performing resolution change. | |
347 bool resolution_change_reset_pending_; | |
348 // Input queue for decoder_thread_: BitstreamBuffers in. | |
349 std::queue<linked_ptr<BitstreamBufferRef> > decoder_input_queue_; | |
350 // For H264 decode, hardware requires that we send it frame-sized chunks. | |
351 // We'll need to parse the stream. | |
352 scoped_ptr<content::H264Parser> decoder_h264_parser_; | |
353 // Set if the decoder has a pending incomplete frame in an input buffer. | |
354 bool decoder_partial_frame_pending_; | |
355 | |
356 // | |
357 // Hardware state and associated queues. Since decoder_thread_ services | |
358 // the hardware, decoder_thread_ owns these too. | |
359 // | |
360 | |
361 // Completed decode buffers, waiting for MFC. | |
362 std::queue<int> mfc_input_ready_queue_; | |
363 | |
364 // MFC decode device. | |
365 int mfc_fd_; | |
366 | |
367 // MFC input buffer state. | |
368 bool mfc_input_streamon_; | |
369 // MFC input buffers enqueued to device. | |
370 int mfc_input_buffer_queued_count_; | |
371 // Input buffers ready to use, as a LIFO since we don't care about ordering. | |
372 std::vector<int> mfc_free_input_buffers_; | |
373 // Mapping of int index to MFC input buffer record. | |
374 std::vector<MfcInputRecord> mfc_input_buffer_map_; | |
375 | |
376 // MFC output buffer state. | |
377 bool mfc_output_streamon_; | |
378 // MFC output buffers enqueued to device. | |
379 int mfc_output_buffer_queued_count_; | |
380 // Output buffers ready to use, as a FIFO since we want oldest-first to hide | |
381 // synchronization latency with GL. | |
382 std::queue<int> mfc_free_output_buffers_; | |
383 // Mapping of int index to MFC output buffer record. | |
384 std::vector<MfcOutputRecord> mfc_output_buffer_map_; | |
385 // MFC output pixel format. | |
386 uint32 mfc_output_buffer_pixelformat_; | |
387 // Required size of DPB for decoding. | |
388 int mfc_output_dpb_size_; | |
389 | |
390 // Pictures that are ready but not sent to PictureReady yet. | |
391 std::queue<PictureRecord> pending_picture_ready_; | |
392 | |
393 // The number of pictures that are sent to PictureReady and will be cleared. | |
394 int picture_clearing_count_; | |
395 | |
396 // Output picture size. | |
397 gfx::Size frame_buffer_size_; | |
398 | |
399 // | |
400 // The device polling thread handles notifications of V4L2 device changes. | |
401 // | |
402 | |
403 // The thread. | |
404 base::Thread device_poll_thread_; | |
405 // eventfd fd to signal device poll thread when its poll() should be | |
406 // interrupted. | |
407 int device_poll_interrupt_fd_; | |
408 | |
409 // | |
410 // Other state, held by the child (main) thread. | |
411 // | |
412 | |
413 // Make our context current before running any EGL entry points. | |
414 base::Callback<bool(void)> make_context_current_; | |
415 | |
416 // EGL state | |
417 EGLDisplay egl_display_; | |
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 |