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

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

Powered by Google App Engine
This is Rietveld 408576698