Index: content/common/gpu/media/exynos_video_encode_accelerator.h |
diff --git a/content/common/gpu/media/exynos_video_encode_accelerator.h b/content/common/gpu/media/exynos_video_encode_accelerator.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..75b97b6621bfa12fd6d324271c28ae058787adf5 |
--- /dev/null |
+++ b/content/common/gpu/media/exynos_video_encode_accelerator.h |
@@ -0,0 +1,360 @@ |
+// Copyright (c) 2013 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#ifndef CONTENT_COMMON_GPU_MEDIA_EXYNOS_VIDEO_ENCODE_ACCELERATOR_H_ |
+#define CONTENT_COMMON_GPU_MEDIA_EXYNOS_VIDEO_ENCODE_ACCELERATOR_H_ |
+ |
+#include <list> |
+#include <vector> |
+ |
+#include "base/callback_forward.h" |
+#include "base/memory/linked_ptr.h" |
+#include "base/memory/weak_ptr.h" |
+#include "base/threading/thread.h" |
+#include "content/common/gpu/gl_surface_encoder.h" |
+#include "media/base/video_decoder_config.h" |
+#include "media/video/video_encode_accelerator.h" |
+#include "ui/gfx/size.h" |
+#include "ui/gl/gl_bindings.h" |
+ |
+namespace base { |
+ |
+class MessageLoopProxy; |
+ |
+} // namespace base |
+ |
+namespace gfx { |
+ |
+class GLSurface; |
+ |
+} // namespace gfx |
+ |
+namespace media { |
+ |
+class BitstreamBuffer; |
+ |
+} // namespace media |
+ |
+namespace content { |
+ |
+// This class handles Exynos video encode acceleration by interfacing with the |
+// V4L2 devices exported by the Multi Format Codec and GScaler hardware blocks |
+// on the Exynos platform. |
+// |
+// The threading model of this class is the same as the |
+// ExynosVideoDecodeAccelerator (from which class this was designed). The one |
+// notable difference is in the thread "ownership" of the GSC free input buffers |
+// queue (gsc_free_input_buffers_). As this queue needs to be queried and |
+// dequeued from the child thread (to obtain a texture to copy the backbuffer |
+// to in Encode()), it is owned by the child thread. |
+class ExynosVideoEncodeAccelerator : public media::VideoEncodeAccelerator { |
+ public: |
+ ExynosVideoEncodeAccelerator( |
+ EGLDisplay egl_display, |
+ media::VideoEncodeAccelerator::Client* client, |
+ const base::Callback<bool(void)>& make_context_current, |
+ bool encode_from_backbuffer); |
+ ~ExynosVideoEncodeAccelerator(); |
+ |
+ // media::VideoEncodeAccelerator implementation. |
+ virtual void Initialize(media::VideoCodecProfile profile, |
+ const gfx::Size& input_resolution, |
+ const gfx::Size& output_resolution, |
+ int32 initial_bitrate) OVERRIDE; |
+ virtual void Encode( |
+ const scoped_refptr<media::VideoFrame>& frame, |
+ int32 frame_id, |
+ bool force_keyframe) OVERRIDE; |
+ virtual void UseBitstreamBuffer( |
+ const media::BitstreamBuffer& buffer) OVERRIDE; |
+ virtual void RequestEncodingParameterChange(int32 bitrate) OVERRIDE; |
+ virtual void Destroy() OVERRIDE; |
+ |
+ private: |
+ // Auto-destroy reference for BitstreamBuffer, for tracking buffers passed as |
+ // input to UseBitstreamBuffer. |
+ struct BitstreamBufferRef; |
+ |
+ // Record for GSC input buffers. |
+ struct GscInputRecord { |
+ GscInputRecord(); |
+ bool at_device; |
+ int frame_id; |
+ EGLSyncKHR egl_sync; |
+ EGLImageKHR egl_image; |
+ GLuint texture_id; |
+ void* address; |
+ size_t length; |
+ }; |
+ |
+ // Record for GSC output buffers. |
+ struct GscOutputRecord { |
+ GscOutputRecord(); |
+ bool at_device; |
+ int mfc_input; |
+ void* address[3]; |
+ size_t length[3]; |
+ size_t bytes_used[3]; |
+ }; |
+ |
+ // Record for MFC input buffers. |
+ struct MfcInputRecord { |
+ MfcInputRecord(); |
+ bool at_device; |
+ int fd[2]; |
+ }; |
+ |
+ // Record for MFC output buffers. |
+ struct MfcOutputRecord { |
+ MfcOutputRecord(); |
+ bool at_device; |
+ void* address; |
+ size_t length; |
+ size_t bytes_used; |
+ }; |
+ |
+ enum { |
+ // These are rather subjectively tuned. |
+ kGscInputBufferCount = 2, |
+ kGscOutputBufferCount = 2, |
+ kMfcOutputBufferCount = 3, |
+ // MFC hardware does not report required output buffer size correctly. |
+ // Use maximum theoretical size to avoid hanging the hardware. |
+ kMfcOutputBufferSize = (2 * 1024 * 1024), |
+ }; |
+ |
+ // Internal state of the encoder. |
+ enum State { |
+ kUninitialized, // Initialize() not yet called. |
+ kInitialized, // Initialize() returned true; ready to start decoding. |
+ kEncoding, // Encoding frames. |
+ kError, // Error in kEncoding state. |
+ }; |
+ |
+ // File descriptors we need to poll. |
+ enum PollFds { |
+ kPollGsc = (1 << 0), |
+ kPollMfc = (1 << 1), |
+ }; |
+ |
+ // |
+ // Child thread utility functions, supporting API entry points. |
+ // |
+ |
+ // Return a buffer to gsc_free_input_buffers_. |
+ void ReturnFreeGscInputBuffer(int index); |
+ |
+ // |
+ // Decoding tasks, to be run on encode_thread_. |
+ // |
+ |
+ // Encode a GSC input buffer. |
+ void EncodeTask(int gsc_input_index); |
+ |
+ // Copy a media::VideoFrame to the GSC input buffer, then encode it. |
+ void CopyFrameAndEncodeTask(const scoped_refptr<media::VideoFrame>& frame, |
+ int gsc_input_index); |
+ |
+ // Add a BitstreamBuffer to out queue of buffers ready to be used for client |
+ // output. |
+ void UseBitstreamBufferTask(scoped_ptr<BitstreamBufferRef> buffer_ref); |
+ |
+ // Device destruction task. |
+ void DestroyTask(); |
+ |
+ // Service I/O on the V4L2 devices. This task should only be scheduled from |
+ // DevicePollTask(). |
+ void ServiceDeviceTask(); |
+ // Handle the various device queues. |
+ void EnqueueGsc(); |
+ void DequeueGsc(); |
+ void EnqueueMfc(); |
+ void DequeueMfc(); |
+ // Enqueue a buffer on the corresponding queue. |
+ bool EnqueueGscInputRecord(); |
+ bool EnqueueGscOutputRecord(); |
+ bool EnqueueMfcInputRecord(); |
+ bool EnqueueMfcOutputRecord(); |
+ // Return completed buffers to the client. |
+ void ReturnCompleteBuffers(); |
+ |
+ // Attempt to start/stop device_poll_thread_. |
+ bool StartDevicePoll(); |
+ bool StopDevicePoll(); |
+ // Set/clear the device poll interrupt (using device_ooll_interrupt_fd_). |
+ bool SetDevicePollInterrupt(); |
+ bool ClearDevicePollInterrupt(); |
+ |
+ // |
+ // Device tasks, to be run on device_poll_thread_. |
+ // |
+ |
+ // The device task. |
+ void DevicePollTask(unsigned int poll_fds); |
+ |
+ // |
+ // Safe from any thread. |
+ // |
+ |
+ // Error notification (using PostTask() to child thread, if necessary). |
+ void NotifyError(Error error); |
+ |
+ // Set the encoder_thread_ state (using PostTask to encoder thread, if |
+ // necessary). |
+ void SetEncoderState(State state); |
+ |
+ // |
+ // Other utility functions. Called on encoder_thread_, unless |
+ // encoder_thread_ is not yet started, in which case the child thread can call |
+ // these (e.g. in Initialize() or Destroy()). |
+ // |
+ |
+ // Create the buffers we need. |
+ bool CreateGscInputBuffers(); |
+ bool CreateGscOutputBuffers(); |
+ bool SetMfcFormats(); |
+ bool CreateMfcInputBuffers(); |
+ bool CreateMfcOutputBuffers(); |
+ |
+ // Set encoding parameters. |
+ void SetBitrate(int32 bitrate); |
+ |
+ // Destroy these buffers. |
+ void DestroyGscInputBuffers(); |
+ void DestroyGscOutputBuffers(); |
+ void DestroyMfcInputBuffers(); |
+ void DestroyMfcOutputBuffers(); |
+ |
+ // Our original calling message loop for the child thread. |
+ const scoped_refptr<base::MessageLoopProxy> child_message_loop_proxy_; |
+ |
+ // WeakPtr<> pointing to |this| for use in posting tasks from the encoder or |
+ // device worker threads back to the child thread. Because the worker threads |
+ // are members of this class, any task running on those threads is guaranteed |
+ // that this object is still alive. As a result, tasks posted from the child |
+ // thread to the encoder or device thread should use base::Unretained(this), |
+ // and tasks posted the other way should use |weak_this_|. |
+ base::WeakPtrFactory<ExynosVideoEncodeAccelerator> weak_this_ptr_factory_; |
+ base::WeakPtr<ExynosVideoEncodeAccelerator> weak_this_; |
+ |
+ // To expose client callbacks from VideoEncodeAccelerator. |
+ // NOTE: all calls to these objects *MUST* be executed on |
+ // child_message_loop_proxy_. |
+ base::WeakPtrFactory<Client> client_ptr_factory_; |
+ base::WeakPtr<Client> client_; |
+ |
+ // |
+ // Encoder state, owned and operated by encoder_thread_. |
+ // Before encoder_thread_ has started, the encoder state is managed by |
+ // the child (main) thread. After encoder_thread_ has started, the encoder |
+ // thread should be the only one managing these. |
+ // |
+ |
+ // This thread services tasks posted from the VEA API entry points by the |
+ // child thread and device service callbacks posted from the device thread. |
+ base::Thread encoder_thread_; |
+ // Encoder state machine state. |
+ State encoder_state_; |
+ // The visible/allocated sizes of the input frame. |
+ gfx::Size input_visible_size_; |
+ gfx::Size input_allocated_size_; |
+ // The visible/allocated sizes of the color-converted frame. |
+ gfx::Size converted_visible_size_; |
+ gfx::Size converted_allocated_size_; |
+ // The visible/allocated sizes of the output frame. |
+ gfx::Size output_visible_size_; |
+ // The required byte size of output BitstreamBuffers. |
+ size_t output_buffer_byte_size_; |
+ |
+ // Cached stream header. |
+ scoped_ptr<uint8[]> stream_header_; |
+ size_t stream_header_size_; |
+ |
+ // Bitstream buffers ready to be used to return encoded output. |
+ std::vector<linked_ptr<BitstreamBufferRef> > encoder_bitstream_buffers_; |
+ |
+ // Buffers ready to be encoded. |
+ std::list<int> encoder_input_queue_; |
+ |
+ // Encoded buffers ready to return to the client. |
+ std::list<int> encoder_output_queue_; |
+ |
+ // Flag if we are encoding the output (and using MFC). |
+ bool do_output_encoding_; |
+ |
+ // Flag if we are encoding from the backbuffer (instead of a CPU allocation). |
+ const bool do_encode_from_backbuffer_; |
+ |
+ // GSC color conversion device. |
+ int gsc_fd_; |
+ // GSC input buffer state. |
+ bool gsc_input_streamon_; |
+ // GSC input buffers enqueued to device. |
+ int gsc_input_buffer_queued_count_; |
+ // Mapping of int index to GSC input buffer record. |
+ std::vector<GscInputRecord> gsc_input_buffer_map_; |
+ |
+ // GSC output buffer state. |
+ bool gsc_output_streamon_; |
+ // GSC output buffers enqueued to device. |
+ int gsc_output_buffer_queued_count_; |
+ // Output buffers ready to use, as a LIFO since we don't care about ordering. |
+ std::vector<int> gsc_free_output_buffers_; |
+ // Mapping of int index to GSC output buffer record. |
+ std::vector<GscOutputRecord> gsc_output_buffer_map_; |
+ |
+ // Completed GSC outputs, waiting for GSC. |
+ std::list<int> gsc_output_mfc_input_queue_; |
+ |
+ // MFC video encoding device. |
+ int mfc_fd_; |
+ |
+ // MFC input buffer state. |
+ bool mfc_input_streamon_; |
+ // MFC input buffers enqueued to device. |
+ int mfc_input_buffer_queued_count_; |
+ // Input buffers ready to use, as a LIFO since we don't care about ordering. |
+ std::vector<int> mfc_free_input_buffers_; |
+ // Mapping of int index to MFC input buffer record. |
+ std::vector<MfcInputRecord> mfc_input_buffer_map_; |
+ |
+ // MFC output buffer state. |
+ bool mfc_output_streamon_; |
+ // MFC output buffers enqueued to device. |
+ int mfc_output_buffer_queued_count_; |
+ // Output buffers ready to use, as a LIFO since we don't care about ordering. |
+ std::vector<int> mfc_free_output_buffers_; |
+ // Mapping of int index to MFC output buffer record. |
+ std::vector<MfcOutputRecord> mfc_output_buffer_map_; |
+ |
+ // |
+ // The device polling thread handles notifications of V4L2 device changes. |
+ // |
+ |
+ // The thread. |
+ base::Thread device_poll_thread_; |
+ // eventfd fd to signal device poll thread when its poll() should be |
+ // interrupted. |
+ int device_poll_interrupt_fd_; |
+ |
+ // |
+ // Other state, held by child (main) thread. |
+ // |
+ |
+ // Make our context current before running any EGL entry points. |
+ base::Callback<bool(void)> make_context_current_; |
+ |
+ // Input buffers ready to use, as a LIFO since we don't care about ordering. |
+ std::vector<int> gsc_free_input_buffers_; |
+ |
+ // EGL state |
+ const EGLDisplay egl_display_; |
+ |
+ // The codec we'll be decoding for. |
+ media::VideoCodecProfile video_profile_; |
+}; |
+ |
+} // namespace content |
+ |
+#endif // CONTENT_COMMON_GPU_MEDIA_EXYNOS_VIDEO_ENCODE_ACCELERATOR_H_ |