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

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

Powered by Google App Engine
This is Rietveld 408576698