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

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: Added H264 parsing for frame boundaries. 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 = 8,
88 kMfcOutputBufferExtraCount = 2, // number of buffers above request by V4L2.
89 kMfcInputBufferMaxSize = 512 * 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 off_t bytes_used;
118 const int32 input_id;
119 };
120
121 // Auto-destruction reference for an array of EGLImage (for message-passing).
122 struct EGLImageKHRArrayRef {
123 EGLImageKHRArrayRef(EGLDisplay egl_display, EGLImageKHR egl_images[],
124 int egl_image_fds[], int egl_images_count);
125 ~EGLImageKHRArrayRef();
126 EGLDisplay const egl_display;
127 const scoped_array<EGLImageKHR> egl_images;
128 const scoped_array<int> egl_image_fds;
129 const int egl_images_count;
130 };
131
132 // Auto-destruction reference for EGLSync (for message-passing).
133 struct EGLSyncKHRRef {
134 EGLSyncKHRRef(EGLDisplay egl_display, EGLSyncKHR egl_sync);
135 ~EGLSyncKHRRef();
136 EGLDisplay const egl_display;
137 EGLSyncKHR egl_sync;
138 };
139 // Record for MFC input buffers.
140 struct MfcInputRecord {
141 MfcInputRecord();
142 ~MfcInputRecord();
143 bool at_device; // held by device.
144 void* address; // mmap() address.
145 size_t length; // mmap() length.
146 off_t bytes_used; // bytes filled in the mmap() segment.
147 int32 input_id; // triggering input_id as given to Decode().
148 };
149
150 // Record for MFC output buffers.
151 struct MfcOutputRecord {
152 MfcOutputRecord();
153 ~MfcOutputRecord();
154 bool at_device; // held by device.
155 size_t bytes_used[2]; // bytes used in each dmabuf.
156 void* address[2]; // mmap() address for each plane.
157 size_t length[2]; // mmap() length for each plane.
158 int32 input_id; // triggering input_id as given to Decode().
159 };
160
161 // Record for GSC input buffers.
162 struct GscInputRecord {
163 GscInputRecord();
164 ~GscInputRecord();
165 bool at_device; // held by device.
166 int mfc_output; // MFC output buffer index to recycle when this input
167 // is complete
168 };
169
170 // Record for GSC output buffers.
171 struct GscOutputRecord {
172 GscOutputRecord();
173 ~GscOutputRecord();
174 bool at_device; // held by device.
175 bool at_client; // held by client.
176 int fd; // file descriptor from backing EGLImage.
177 EGLImageKHR egl_image; // backing EGLImage.
178 EGLSyncKHR egl_sync; // sync the compositor's use of the EGLImage.
179 int32 picture_id; // picture ID as returned to PictureReady().
180 };
181
182 //
183 // Decoding tasks, to be run on decode_thread_.
184 //
185
186 // Enqueue a BitstreamBuffer to decode. This will enqueue a
187 // DecodeBufferTask() to actually decode the buffer.
188 void DecodeTask(scoped_ptr<BitstreamBufferRef> bitstream_record);
189
190 // Decode from the queued BitstreamBuffers. Calls DecodeBufferInitial()
191 // or DecodeBufferContinue().
192 void DecodeBufferTask();
193 // Find the extents of one frame fragment to push to HW.
194 bool FindFrameFragment(const void* data, size_t size, size_t* endpos);
195 // Schedule another DecodeBufferTask() if we're behind.
196 void ScheduleDecodeBufferTaskIfNeeded();
197
198 // Return true if an input buffer is consumed. It may not be an error
199 // condition not to consume a buffer.
200 bool DecodeBufferInitial(const void* data, size_t size);
201 bool DecodeBufferContinue(const void* data, size_t size);
202
203 // Helpers: accumulate and flush data for one decoded frame.
204 bool AppendToInputFrame(const void* data, size_t size);
205 bool FlushInputFrame();
206
207 // Process an AssignPictureBuffers() API call. After this, the
208 // device_poll_thread_ can be started safely, since we have all our
209 // buffers.
210 void AssignPictureBuffersTask(scoped_ptr<EGLImageKHRArrayRef> egl_images_ref);
211
212 // Service I/O on the V4L2 devices. This task should only be scheduled from
213 // DevicePollTask().
214 void ServiceDeviceTask();
215 // Handle the various device queues.
216 void EnqueueMfc();
217 void DequeueMfc();
218 void EnqueueGsc();
219 void DequeueGsc();
220 // Enqueue a buffer on the corresponding queue.
221 bool EnqueueMfcInputRecord();
222 bool EnqueueMfcOutputRecord();
223 bool EnqueueGscInputRecord();
224 bool EnqueueGscOutputRecord();
225
226 // Process a ReusePictureBuffer() API call. The API call create an EGLSync
227 // object on the main (GPU process) thread; we will record this object so we
228 // can wait on it before reusing the buffer.
229 void ReusePictureBufferTask(int32 picture_buffer_id,
230 scoped_ptr<EGLSyncKHRRef> egl_sync_ref);
231
232 // Flush() task. Child thread should not submit any more buffers until it
233 // receives the NotifyFlushDone callback.
234 void FlushTask();
235 // Is our decode pipeline empty?
236 bool IsPipelineEmpty();
237
238 // Reset() task. This task will schedule a ResetDoneTask() that will send
239 // the NotifyResetDone callback, then set the decoder state to kResetting so
240 // that all intervening tasks will drain.
241 void ResetTask();
242 void ResetDoneTask();
243
244 // Device destruction task.
245 void DestroyTask();
246
247 // Attempt to start/stop device_poll_thread_.
248 bool StartDevicePoll();
249 bool StopDevicePoll();
250 // Set/clear the device poll interrupt (using device_poll_interrupt_fd_).
251 bool SetDevicePollInterrupt();
252 bool ClearDevicePollInterrupt();
253
254 //
255 // Device tasks, to be run on device_poll_thread_.
256 //
257
258 // The device task.
259 void DevicePollTask();
260
261 //
262 // Safe from any thread.
263 //
264
265 // Error notification (using PostTask() to child thread, if necessary).
266 void NotifyError(Error error);
267
268 // Set the decoder_thread_ state (using PostTask to decoder thread, if
269 // necessary).
270 void SetDecoderState(State state);
271
272 //
273 // Other utility functions. Called on decoder_thread_, unless
274 // decoder_thread_ is not yet started, in which case the child thread can call
275 // these (e.g. in Initialize() or Destroy()).
276 //
277
278 // Create the buffers we need.
279 bool CreateMfcInputBuffers();
280 bool CreateMfcOutputBuffers();
281 bool CreateGscInputBuffers();
282 bool CreateGscOutputBuffers();
283
284 // Destroy these buffers.
285 void DestroyMfcInputBuffers();
286 void DestroyMfcOutputBuffers();
287 void DestroyGscInputBuffers();
288 void DestroyGscOutputBuffers();
289
290 // Our original calling message loop for the child thread.
291 scoped_refptr<base::MessageLoopProxy> child_message_loop_proxy_;
292
293 // WeakPtr<> pointing to |this| for use in posting tasks from the decoder or
294 // device worker threads back to the child thread. Because the worker threads
295 // are members of this class, any task running on those threads is guaranteed
296 // that this object is still alive. As a result, tasks posted from the child
297 // thread to the decoder or device thread should use base::Unretained(this),
298 // and tasks posted the other way should use |weak_this_|.
299 base::WeakPtr<ExynosVideoDecodeAccelerator> weak_this_;
300
301 // To expose client callbacks from VideoDecodeAccelerator.
302 // NOTE: all calls to these objects *MUST* be executed on
303 // child_message_loop_proxy_.
304 base::WeakPtrFactory<Client> client_ptr_factory_;
305 base::WeakPtr<Client> client_;
306
307 //
308 // Decoder state, owned and operated by decoder_thread_.
309 // Before decoder_thread_ has started, the decoder state is managed by
310 // the child (main) thread. After decoder_thread_ has started, the decoder
311 // thread should be the only one managing these.
312 //
313
314 // This thread services tasks posted from the VDA API entry points by the
315 // child thread and device service callbacks posted from the device thread.
316 base::Thread decoder_thread_;
317 // Decoder state machine state.
318 State decoder_state_;
319 // Bitstream buffer we're presently reading.
320 scoped_ptr<BitstreamBufferRef> decoder_current_bitstream_buffer_;
321 // MFC input buffer we're presently filling.
322 int decoder_current_input_buffer_;
323 // We track the number of buffer decode tasks we have scheduled, since each
324 // task execution should complete one buffer. If we fall behind (due to
325 // resource backpressure, etc.), we'll have to schedule more to catch up.
326 int decoder_decode_buffer_tasks_scheduled_;
327 // Buffers held by the client.
328 int decoder_frames_at_client_;
329 // Are we waiting for a flush notification?
330 bool decoder_flush_notify_requested_;
331 // Input queue for decoder_thread_: BitstreamBuffers in.
332 std::deque<linked_ptr<BitstreamBufferRef> > decoder_input_queue_;
333
334 //
335 // Hardware state and associated queues. Since decoder_thread_ services
336 // the hardware, decoder_thread_ owns these too.
337 //
338
339 // Completed decode buffers, waiting for MFC.
340 std::deque<int> mfc_input_ready_queue_;
341
342 // MFC decode device.
343 int mfc_fd_;
344
345 // MFC input buffer state.
346 bool mfc_input_streamon_;
347 // MFC input buffers, total.
348 int mfc_input_buffer_count_;
349 // MFC input buffers enqueued to device.
350 int mfc_input_buffer_queued_count_;
351 // Input buffers ready to use, as a FIFO since we don't care about ordering.
352 std::vector<int> mfc_free_input_buffers_;
353 // Mapping of int index to MFC input buffer record.
354 std::vector<MfcInputRecord> mfc_input_buffer_map_;
355
356 // MFC output buffer state.
357 bool mfc_output_streamon_;
358 // MFC output buffers, total.
359 int mfc_output_buffer_count_;
360 // MFC output buffers enqueued to device.
361 int mfc_output_buffer_queued_count_;
362 // Output buffers ready to use, as a FIFO since we don't care about ordering.
363 std::vector<int> mfc_free_output_buffers_;
364 // Mapping of int index to MFC output buffer record.
365 std::vector<MfcOutputRecord> mfc_output_buffer_map_;
366 // Required size of MFC output buffers. Two sizes for two planes.
367 size_t mfc_output_buffer_size_[2];
368 uint32 mfc_output_buffer_pixelformat_;
369
370 // Completed MFC outputs, waiting for GSC.
371 std::deque<int> mfc_output_gsc_input_queue_;
372
373 // GSC decode device.
374 int gsc_fd_;
375
376 // GSC input buffer state.
377 bool gsc_input_streamon_;
378 // GSC input buffers, total.
379 int gsc_input_buffer_count_;
380 // GSC input buffers enqueued to device.
381 int gsc_input_buffer_queued_count_;
382 // Input buffers ready to use, as a FIFO since we don't care about ordering.
383 std::vector<int> gsc_free_input_buffers_;
384 // Mapping of int index to GSC input buffer record.
385 std::vector<GscInputRecord> gsc_input_buffer_map_;
386
387 // GSC output buffer state.
388 bool gsc_output_streamon_;
389 // GSC output buffers, total.
390 int gsc_output_buffer_count_;
391 // GSC output buffers enqueued to device.
392 int gsc_output_buffer_queued_count_;
393 // Output buffers ready to use. We need a LIFO here.
394 std::deque<int> gsc_free_output_buffers_;
395 // Mapping of int index to GSC output buffer record.
396 std::vector<GscOutputRecord> gsc_output_buffer_map_;
397
398 // Output picture size.
399 gfx::Size frame_buffer_size_;
400
401 //
402 // The device polling thread handles notifications of V4L2 device changes.
403 //
404
405 // The thread.
406 base::Thread device_poll_thread_;
407 // epoll fd that the device poll thread will epoll() on. This FD is set up by
408 // the decoder thread every time before it schedules a device wait on the
409 // device poll thread.
410 int device_poll_epoll_fd_;
411 // eventfd fd to signal device poll thread when its epoll() should be
412 // interrupted.
413 int device_poll_interrupt_fd_;
414
415 //
416 // Other state, held by the child (main) thread.
417 //
418
419 // Make our context current before running any EGL entry points.
420 base::Callback<bool(void)> make_context_current_;
421
422 // EGL state
423 EGLDisplay egl_display_;
424 EGLContext egl_context_;
425
426 // The codec we'll be decoding for.
427 media::VideoCodecProfile video_profile_;
428
429 DISALLOW_COPY_AND_ASSIGN(ExynosVideoDecodeAccelerator);
430 };
431
432 } // namespace content
433
434 #endif // CONTENT_COMMON_GPU_MEDIA_EXYNOS_VIDEO_DECODE_ACCELERATOR_H_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698