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

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: Created 8 years, 2 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 hardware video decoder present on Intel CPUs.
Ami GONE FROM CHROMIUM 2012/10/18 08:30:26 no it doesn't ;)
sheu 2012/10/30 09:05:03 Done.
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 "media/base/video_decoder_config.h"
19 #include "media/video/video_decode_accelerator.h"
20 #include "third_party/angle/include/EGL/egl.h"
21 #include "third_party/angle/include/EGL/eglext.h"
22
23 namespace base {
24 class MessageLoopProxy;
25 }
26
27 namespace gfx {
28 class GLContext;
29 }
30
31 // This class handls Exynos video acceleration directly through the V4L2 devices
32 // 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 API thread, which is the main GPU process thread which calls the
Ami GONE FROM CHROMIUM 2012/10/29 23:30:16 Chromium terminology calls this thread the ChildTh
sheu 2012/10/30 09:05:03 Done.
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 as well as
46 // device events. Pretty much all state modification is done on this thread.
47 // * The device_thread_, owned by this class. All it does is epoll() on the
48 // V4L2 device and notify the decoder_thread_ when something interesting
49 // happens.
50 //
51 // Note that this class has no locks! Everything's serviced on the
52 // decoder_thread_, so there are no synchronization issues.
53 // ... well, there are, but it's a matter of getting messages posted in the
54 // right order, not fiddling with locks.
55 class ExynosVideoDecodeAccelerator : public media::VideoDecodeAccelerator {
56 public:
57 ExynosVideoDecodeAccelerator(gfx::GLContext* gl_context,
Ami GONE FROM CHROMIUM 2012/10/29 23:30:16 style: here & elsewhere, arg lists should be eithe
sheu 2012/10/30 09:05:03 Done.
58 Client* client,
59 const base::Callback<bool(void)>& make_context_current);
60 virtual ~ExynosVideoDecodeAccelerator();
61
62 // media::VideoDecodeAccelerator implementation.
63 // Note: Initialize() and Destroy() are synchronous.
64 virtual bool Initialize(media::VideoCodecProfile profile) OVERRIDE;
65 virtual void Decode(const media::BitstreamBuffer& bitstream_buffer) OVERRIDE;
66 virtual void AssignPictureBuffers(
67 const std::vector<media::PictureBuffer>& buffers) OVERRIDE;
68 virtual void ReusePictureBuffer(int32 picture_buffer_id) OVERRIDE;
69 virtual void Flush() OVERRIDE;
70 virtual void Reset() OVERRIDE;
71 virtual void Destroy() OVERRIDE;
72
73 // Do any necessary initialization before the sandbox is enabled.
74 static void PreSandboxInitialization();
75
76 // Lazily initialize static data after sandbox is enabled. Return false on
77 // init failure.
78 static bool PostSandboxInitialization();
79
80 // Call through the static function pointers we hold.
Ami GONE FROM CHROMIUM 2012/10/29 23:30:16 Can't these be private? For that matter, they seem
sheu 2012/10/30 09:05:03 Done.
81 static EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type,
82 const EGLint* attrib_list);
83 static EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync);
84 static EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync,
85 EGLint flags, EGLTimeKHR timeout);
86
87 private:
88 // These are rather subjectively tuned.
Ami GONE FROM CHROMIUM 2012/10/29 23:30:16 Have you tested flash? ihf@ found he needed 6-8 o
sheu 2012/10/30 09:05:03 I tested flash. Over and over again. I can turn
89 enum {
90 kMfcInputBufferCount = 4,
91 kMfcOutputBufferExtraCount = 2,
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.
Ami GONE FROM CHROMIUM 2012/10/29 23:30:16 I believe the only diff between this and kInitiali
sheu 2012/10/30 09:05:03 I think the kInitialized/kDecoding/kAfterReset sta
104 kError, // Error in kDecoding state.
105 };
106
107 // Record for decoder input buffers.
Ami GONE FROM CHROMIUM 2012/10/29 23:30:16 Comments that apply to each of the structs defined
sheu 2012/10/30 09:05:03 I suppose I could move BitstreamBufferRecord, but
108 struct BitstreamBufferRecord {
109 BitstreamBufferRecord();
110 scoped_ptr<base::SharedMemory> shm;
111 size_t size;
112 int32 input_id;
113 };
114
115 // Record for MFC input buffers.
116 struct MfcInputRecord {
117 MfcInputRecord();
118 bool queued : 1; // queued to device.
Ami GONE FROM CHROMIUM 2012/10/29 23:30:16 here and below: why bother with the :1? If the com
Ami GONE FROM CHROMIUM 2012/10/29 23:30:16 s/queued/at_device/ ? (ditto for other "queued" fi
sheu 2012/10/30 09:05:03 Done.
119 void* offset; // mmap() offset.
120 size_t length; // mmap() length.
121 off_t bytes_used; // bytes filled in the mmap() segment.
122 int32 input_id; // triggering input_id as given to Decode().
123 };
124
125 // Record for MFC output buffers.
126 struct MfcOutputRecord {
127 MfcOutputRecord();
128 bool queued : 1; // queued to device.
129 size_t bytes_used[2]; // bytes used in each dmabuf.
130 void* offset[2]; // mmap() offset for each plane.
131 size_t length[2]; // mmap() length for each plane.
Ami GONE FROM CHROMIUM 2012/10/29 23:30:16 what are these dmabufs/planes?
sheu 2012/10/30 09:05:03 It's hardware-specific business; I'm not sure that
132 int32 input_id; // triggering input_id as given to Decode().
133 };
134
135 // Record for GSC input buffers.
136 struct GscInputRecord {
137 GscInputRecord();
138 bool queued : 1; // queued to device.
139 int mfc_output; // MFC output to recycle when this input is complete
Ami GONE FROM CHROMIUM 2012/10/29 23:30:16 s/MFC output/MfcOutputRecord/
sheu 2012/10/30 09:05:03 Well, we're tracking the buffer index here, not re
sheu 2012/10/30 09:05:03 We're tracking the output buffer itself, not the r
140 };
141
142 // Record for GSC output buffers.
143 struct GscOutputRecord {
144 GscOutputRecord();
145 bool queued : 1; // queued to device.
146 bool in_vda : 1; // held by VDA.
Ami GONE FROM CHROMIUM 2012/10/29 23:30:16 _this_ is the VDA :) Do you mean at_client?
sheu 2012/10/30 09:05:03 Done.
147 int fd; // file descriptor from backing EGLImage.
148 EGLImageKHR egl_image; // backing EGLImage.
149 EGLSyncKHR egl_sync; // sync the compositor's use of the EGLImage.
150 int32 picture_id; // picture ID as returned to PictureReady().
151 };
152
153 // Auto-destruction reference for an array of EGLImage (for message-passing)
154 struct EGLImageKHRArrayRef {
155 EGLImageKHRArrayRef();
156 ~EGLImageKHRArrayRef();
157 EGLDisplay egl_display;
158 scoped_array<EGLImageKHR> egl_images;
159 scoped_array<int> egl_image_fds;
160 int egl_images_count;
161 };
162
163 // Auto-destruction reference for EGLSync (for message-passing)
164 struct EGLSyncKHRRef {
165 EGLSyncKHRRef();
166 ~EGLSyncKHRRef();
167 EGLDisplay egl_display;
168 EGLSyncKHR egl_sync;
169 };
170
171 //
172 // Decoding tasks, to be run on decode_thread_.
173 //
174
175 // Enqueue a BitstreamBuffer to decode. This will enqueue a
176 // DecodeBufferTask() to actually decoe the buffer.
Ami GONE FROM CHROMIUM 2012/10/29 23:30:16 typo: decoe
sheu 2012/10/30 09:05:03 Done.
177 void DecodeTask(scoped_ptr<BitstreamBufferRecord> bitstream_record);
Ami GONE FROM CHROMIUM 2012/10/29 23:30:16 I think you can improve function naming here. WDY
sheu 2012/10/30 09:05:03 Generally I'm matching each "Foo" call from the AP
178
179 // Decode from the queued BitstreamBuffers. Calls DecodeBufferInitial()
180 // or DecodeBufferContinue().
181 void DecodeBufferTask();
Ami GONE FROM CHROMIUM 2012/10/29 23:30:16 ...and rename: DoSomeDecodeWork (and below)
sheu 2012/10/30 09:05:03 They're pretty closely associated with DecodeBuffe
182 bool DecodeBufferInitial(const void* data, size_t size);
183 bool DecodeBufferContinue(const void* data, size_t size);
184 // Helpers: accumulate and flush data for one decoded frame.
185 bool AppendToInputFrame(const void* data, size_t size);
186 bool FlushInputFrame();
187
188 // Process an AssignPictureBuffers() API call. After this, the device_thread_
189 // can be started safely, since we have all our buffers.
190 void AssignPictureBuffersTask(scoped_ptr<EGLImageKHRArrayRef> egl_images_ref);
191
192 // Service I/O on the V4L2 devices.
193 void ServiceDeviceTask();
194 // Handle the various device queues.
195 void EnqueueMfc();
196 void DequeueMfc();
197 void EnqueueGsc();
198 void DequeueGsc();
199
200 // Process a ReusePictureBuffer() API call. The API call create an EGLSync
201 // object on the main (GPU process) thread; we will record this object so we
202 // can wait on it before reusing the buffer.
203 void ReusePictureBufferTask(int32 picture_buffer_id,
204 scoped_ptr<EGLSyncKHRRef> egl_sync_ref);
205
206 // Flush() task. API thread should not submit any more buffers until it
207 // receives the NotifyFlushDone callback.
Ami GONE FROM CHROMIUM 2012/10/29 23:30:16 this is fine, but make sure you can deal with a Re
sheu 2012/10/30 09:05:03 Yep, that case should work. It just sets a flag a
208 void FlushTask();
209
210 // Reset() task. This task will schedule a ResetDoneTask() that will send
211 // the NotifyResetDone callback.
212 void ResetTask();
213 void ResetDoneTask();
214
215 // Device destruction task.
216 void DestroyTask();
217
218 // Cleanup() task, mostly used on the error path.
219 void CleanupTask();
220
221 // Start/stop DeviceTask() running on device_thread_.
222 bool StartDevice();
223 bool StopDevice();
Ami GONE FROM CHROMIUM 2012/10/29 23:30:16 You should doco the return value of these methods,
sheu 2012/10/30 09:05:03 Done.
224
225 //
226 // Device tasks, to be run on device_thread_.
227 //
228
229 // The device task.
230 void DeviceTask();
231
232 //
233 // Safe from any thread (uses PostTask() to API thread).
234 //
235
236 // Error notification.
237 void NotifyError(Error error);
238
239 //
240 // Other utility functions
241 //
242
243 // Create the buffers we need.
244 bool CreateMfcInputBuffers();
245 bool CreateMfcOutputBuffers();
246 bool CreateGscInputBuffers();
247 bool CreateGscOutputBuffers();
248
249 // Destroy these buffers.
250 bool DestroyMfcInputBuffers();
251 bool DestroyMfcOutputBuffers();
252 bool DestroyGscInputBuffers();
253 bool DestroyGscOutputBuffers();
Ami GONE FROM CHROMIUM 2012/10/29 23:30:16 Again, return values seem to be silently ignored s
sheu 2012/10/30 09:05:03 Done.
254
255 // Our original calling message loop for the API thread.
256 scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
Ami GONE FROM CHROMIUM 2012/10/29 23:30:16 name it something more distinct, like {main,child}
sheu 2012/10/30 09:05:03 Done.
257
258 // WeakPtr<> pointing to |this| for use in posting tasks from the decoder
259 // thread back to the API thread. Because the decoder thread is a member of
260 // this class, any task running on the decoder thread is guaranteed that this
261 // object is still alive. As a result, tasks posted from API thread to
262 // decoder thread should use base::Unretained(this), and tasks posted from the
263 // decoder thread to the API thread should use |weak_this_|.
Ami GONE FROM CHROMIUM 2012/10/29 23:30:16 Comment that |device_thread_| follows the same log
sheu 2012/10/30 09:05:03 Done.
264 base::WeakPtr<ExynosVideoDecodeAccelerator> weak_this_;
265
266 // To expose client callbacks from VideoDecodeAccelerator.
267 // NOTE: all calls to these objects *MUST* be executed on message_loop_proxy_.
268 base::WeakPtrFactory<Client> client_ptr_factory_;
269 base::WeakPtr<Client> client_;
270
271 // This thread handles VDA API entry points and callbacks.
Ami GONE FROM CHROMIUM 2012/10/29 23:30:16 I think this comment is misleading.
sheu 2012/10/30 09:05:03 Done.
272 base::Thread decoder_thread_;
273 // Decoder state. Owned by decoder_thread_.
Ami GONE FROM CHROMIUM 2012/10/29 23:30:16 Replace "Owned by..." with a blanket comment at l.
sheu 2012/10/30 09:05:03 Done. I did some declaration moving-around to hop
274 State decoder_state_;
Ami GONE FROM CHROMIUM 2012/10/29 23:30:16 ...except this seems to be read from both the deco
sheu 2012/10/30 09:05:03 Probably the trickiest bit of state. It's only re
Ami GONE FROM CHROMIUM 2012/10/31 01:06:50 If you wanted to be super-XTREME about it, you cou
275 // Bitstream buffer we're presently reading.
276 scoped_ptr<BitstreamBufferRecord> decoder_current_bitstream_buffer_;
Ami GONE FROM CHROMIUM 2012/10/29 23:30:16 s/decoder_//
277 // MFC input buffer we're presently filling.
278 int decoder_current_input_buffer_;
Ami GONE FROM CHROMIUM 2012/10/29 23:30:16 ditto s/decoder_// here and below.
sheu 2012/10/30 09:05:03 I was trying to mark these as more closely "decode
279 // We track the number of buffer decode tasks we have scheduled, since each
280 // task execution should complete one buffer. If we fall behind (due to
281 // resource backpressure, etc.), we'll have to schedule more to catch up.
282 int decoder_decode_buffer_tasks_scheduled_;
283 // Buffers in the pipe, five-by-five.
Ami GONE FROM CHROMIUM 2012/10/29 23:30:16 lolwat?
sheu 2012/10/30 09:05:03 http://www.youtube.com/watch?v=fOZk--oZdQk (My re
284 int decoder_frames_inflight_;
285 // Buffers unreturned by the VDA
286 int decoder_frames_unreturned_;
287 // Are we waiting for a flush notification?
288 bool decoder_notify_flush_;
Ami GONE FROM CHROMIUM 2012/10/29 23:30:16 Can you make a pass and align these variable names
sheu 2012/10/30 09:05:03 Done.
289
290 // This thread handles notifications of V4L2 device changes.
291 base::Thread device_thread_;
292
293 // GL state
294 gfx::GLContext* gl_context_;
295
296 // Make our context current before running any EGL entry points.
297 base::Callback<bool(void)> make_context_current_;
298
299 // The codec we'll be decoding for.
300 media::VideoCodecProfile video_codec_;
Ami GONE FROM CHROMIUM 2012/10/29 23:30:16 if you passed this to CreateMfcInputBuffers as a p
Ami GONE FROM CHROMIUM 2012/10/29 23:30:16 it's a profile, not a codec.
sheu 2012/10/30 09:05:03 Done.
301
302 // EGL state
303 EGLContext egl_context_;
Ami GONE FROM CHROMIUM 2012/10/29 23:30:16 you could assign these in the ctor and avoid the n
sheu 2012/10/30 09:05:03 A little forward-thinking: I'd like to standardize
304 EGLDisplay egl_display_;
305
306 // Input queue for decoder_thread_: BitstreamBuffers in.
307 std::deque<linked_ptr<BitstreamBufferRecord> > decode_input_queue_;
308
309 // Completed decode buffers, waiting for MSC.
Ami GONE FROM CHROMIUM 2012/10/29 23:30:16 typo: MSC
Ami GONE FROM CHROMIUM 2012/10/29 23:30:16 I'm a bit confused about what makes an input decod
sheu 2012/10/30 09:05:03 Done. The bit about "decode_output_mfc_input_queu
310 std::deque<int> decode_output_mfc_input_queue_;
311
312 // MFC decode device.
313 int mfc_fd_;
Ami GONE FROM CHROMIUM 2012/10/29 23:30:16 Use base::ScopedFD, per IM convo.
sheu 2012/10/30 09:05:03 Done.
314 // MFC input buffer state.
315 bool mfc_input_streamon_;
316 int mfc_input_buffer_count_;
317 std::deque<int> mfc_free_input_buffers_;
318 // Mapping to track MFC input buffers.
Ami GONE FROM CHROMIUM 2012/10/29 23:30:16 There's a lot of "map" commentary/variable-naming
sheu 2012/10/30 09:05:03 I tweaked the comment a bit. I think the fact tha
319 std::vector<MfcInputRecord> mfc_input_buffer_map_;
320
321 // MFC output buffer state.
322 bool mfc_output_streamon_;
323 int mfc_output_buffer_count_;
324 std::deque<int> mfc_free_output_buffers_;
325 // Mapping to track MFC output buffers.
326 std::vector<MfcOutputRecord> mfc_output_buffer_map_;
327 size_t mfc_output_buffer_size_[2];
Ami GONE FROM CHROMIUM 2012/10/29 23:30:16 doco what the [2] is about.
sheu 2012/10/30 09:05:03 Done.
328 uint32 mfc_output_buffer_pixelformat_;
329
330 // Completed MFC outputs, waiting for GSC.
331 std::deque<int> mfc_output_gsc_input_queue_;
332
333 // GSC decode device.
334 int gsc_fd_;
Ami GONE FROM CHROMIUM 2012/10/29 23:30:16 scoped
sheu 2012/10/30 09:05:03 Done.
335
336 // GSC input buffer state.
337 bool gsc_input_streamon_;
338 int gsc_input_buffer_count_;
339 std::deque<int> gsc_free_input_buffers_;
Ami GONE FROM CHROMIUM 2012/10/29 23:30:16 does this really need to be a FIFO or could it jus
sheu 2012/10/30 09:05:03 Done.
340 // Mapping to track GSC input buffers.
341 std::vector<GscInputRecord> gsc_input_buffer_map_;
342
343 // GSC output buffer state.
344 bool gsc_output_streamon_;
345 int gsc_output_buffer_count_;
346 // GSC output buffers enqueued to device and ready, but not yet in use.
347 int gsc_output_buffer_prepared_count_;
348 // GSC output buffers enqueued to device, total.
349 int gsc_output_buffer_queued_count_;
350 std::deque<int> gsc_free_output_buffers_;
Ami GONE FROM CHROMIUM 2012/10/29 23:30:16 ditto
sheu 2012/10/30 09:05:03 This one does have to be a FIFO -- before we can r
351 // Mapping to track GSC output buffers.
352 std::vector<GscOutputRecord> gsc_output_buffer_map_;
353
Ami GONE FROM CHROMIUM 2012/10/29 23:30:16 ISTM there's a ton of repetition among the above 4
sheu 2012/10/30 09:05:03 The only things really common to them are *_stream
354 // Output picture size.
355 unsigned int frame_width_;
Ami GONE FROM CHROMIUM 2012/10/29 23:30:16 gfx::Size
sheu 2012/10/30 09:05:03 Done.
356 unsigned int frame_height_;
357
358 // "private" API pointers as exported by libmali, that we require.
Ami GONE FROM CHROMIUM 2012/10/29 23:30:16 see above; l.358-369 belong only in the .cc file I
sheu 2012/10/30 09:05:03 Done.
359 static void* libmali_handle;
360 static EGLBoolean(*mali_egl_image_get_buffer_ext_phandle)(
361 EGLImageKHR image, EGLint *attribs, void *phandle);
362
363 // Entry points for uncommon EGL extensions we use.
364 static EGLSyncKHR (*egl_create_sync_khr)(
365 EGLDisplay dpy, EGLenum type, const EGLint* attrib_list);
366 static EGLBoolean (*egl_destroy_sync_khr)(
367 EGLDisplay dpy, EGLSyncKHR sync);
368 static EGLint (*egl_client_wait_sync_khr)(
369 EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout);
370
371 DISALLOW_COPY_AND_ASSIGN(ExynosVideoDecodeAccelerator);
372 };
373
374 #endif // CONTENT_COMMON_GPU_MEDIA_EXYNOS_VIDEO_DECODE_ACCELERATOR_H_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698