Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(38)

Side by Side Diff: content/common/gpu/media/exynos_video_decode_accelerator.h

Issue 11198060: VDA implementation for Exynos, using V4L2 (Closed) Base URL: https://git.chromium.org/git/chromium/src@git-svn
Patch Set: Flush() path rework. Created 7 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698