OLD | NEW |
(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_ |
OLD | NEW |