root/content/common/gpu/media/exynos_video_encode_accelerator.h

/* [<][>][^][v][top][bottom][index][help] */

INCLUDED FROM


// Copyright 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/memory/linked_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/thread.h"
#include "content/common/content_export.h"
#include "media/video/video_encode_accelerator.h"
#include "ui/gfx/size.h"

namespace base {

class MessageLoopProxy;

}  // namespace base

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).
class CONTENT_EXPORT ExynosVideoEncodeAccelerator
    : public media::VideoEncodeAccelerator {
 public:
  ExynosVideoEncodeAccelerator();
  virtual ~ExynosVideoEncodeAccelerator();

  // media::VideoEncodeAccelerator implementation.
  virtual bool Initialize(media::VideoFrame::Format format,
                          const gfx::Size& input_visible_size,
                          media::VideoCodecProfile output_profile,
                          uint32 initial_bitrate,
                          Client* client) OVERRIDE;
  virtual void Encode(const scoped_refptr<media::VideoFrame>& frame,
                      bool force_keyframe) OVERRIDE;
  virtual void UseOutputBitstreamBuffer(
      const media::BitstreamBuffer& buffer) OVERRIDE;
  virtual void RequestEncodingParametersChange(uint32 bitrate,
                                               uint32 framerate) OVERRIDE;
  virtual void Destroy() OVERRIDE;

  static std::vector<media::VideoEncodeAccelerator::SupportedProfile>
      GetSupportedProfiles();

 private:
  // Auto-destroy reference for BitstreamBuffer, for tracking buffers passed to
  // this instance.
  struct BitstreamBufferRef;

  // Record for GSC input buffers.
  struct GscInputRecord {
    GscInputRecord();
    bool at_device;
    scoped_refptr<media::VideoFrame> frame;
  };

  // Record for GSC output buffers.
  struct GscOutputRecord {
    GscOutputRecord();
    bool at_device;
    int mfc_input;
  };

  // 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;
    linked_ptr<BitstreamBufferRef> buffer_ref;
    void* address;
    size_t length;
  };

  enum {
    kInitialFramerate = 30,
    // These are rather subjectively tuned.
    kGscInputBufferCount = 2,
    kGscOutputBufferCount = 2,
    kMfcOutputBufferCount = 2,
    // 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 encoding.
    kEncoding,       // Encoding frames.
    kError,          // Error in encoder state.
  };

  //
  // Encoding tasks, to be run on encode_thread_.
  //

  // Encode a GSC input buffer.
  void EncodeTask(const scoped_refptr<media::VideoFrame>& frame,
                  bool force_keyframe);

  // Add a BitstreamBuffer to the queue of buffers ready to be used for encoder
  // output.
  void UseOutputBitstreamBufferTask(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.  Returns false on fatal error.
  bool EnqueueGscInputRecord();
  bool EnqueueGscOutputRecord();
  bool EnqueueMfcInputRecord();
  bool EnqueueMfcOutputRecord();

  // Attempt to start/stop device_poll_thread_.
  bool StartDevicePoll();
  bool StopDevicePoll();
  // Set/clear the device poll interrupt (using device_poll_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()).
  //

  // Change the parameters of encoding.
  void RequestEncodingParametersChangeTask(uint32 bitrate, uint32 framerate);

  // Create the buffers we need.
  bool CreateGscInputBuffers();
  bool CreateGscOutputBuffers();
  bool SetMfcFormats();
  bool InitMfcControls();
  bool CreateMfcInputBuffers();
  bool CreateMfcOutputBuffers();

  // 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_.
  scoped_ptr<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.
  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 intermediate frame.
  gfx::Size converted_visible_size_;
  gfx::Size converted_allocated_size_;
  // The logical visible size of the output frame.
  gfx::Size output_visible_size_;
  // The required byte size of output BitstreamBuffers.
  size_t output_buffer_byte_size_;

  // We need to provide the stream header with every keyframe, to allow
  // midstream decoding restarts.  Store it here.
  scoped_ptr<uint8[]> stream_header_;
  size_t stream_header_size_;

  // V4L2 formats for input frames and the output stream.
  uint32 input_format_fourcc_;
  uint32 output_format_fourcc_;

  // Video frames ready to be encoded.
  std::list<scoped_refptr<media::VideoFrame> > encoder_input_queue_;

  // GSC color conversion device.
  int gsc_fd_;
  // GSC input queue state.
  bool gsc_input_streamon_;
  // GSC input buffers enqueued to device.
  int gsc_input_buffer_queued_count_;
  // GSC input buffers ready to use; LIFO since we don't care about ordering.
  std::vector<int> gsc_free_input_buffers_;
  // Mapping of int index to GSC input buffer record.
  std::vector<GscInputRecord> gsc_input_buffer_map_;

  // GSC output queue state.
  bool gsc_output_streamon_;
  // GSC output buffers enqueued to device.
  int gsc_output_buffer_queued_count_;
  // GSC output buffers ready to use; 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_;

  // MFC input buffers filled by GSC, waiting to be queued to MFC.
  std::list<int> mfc_ready_input_buffers_;

  // MFC video encoding device.
  int mfc_fd_;

  // MFC input queue state.
  bool mfc_input_streamon_;
  // MFC input buffers enqueued to device.
  int mfc_input_buffer_queued_count_;
  // MFC input buffers ready to use; 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 queue state.
  bool mfc_output_streamon_;
  // MFC output buffers enqueued to device.
  int mfc_output_buffer_queued_count_;
  // MFC output buffers ready to use; 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_;

  // Bitstream buffers ready to be used to return encoded output, as a LIFO
  // since we don't care about ordering.
  std::vector<linked_ptr<BitstreamBufferRef> > encoder_output_queue_;

  //
  // The device polling thread handles notifications of V4L2 device changes.
  // TODO(sheu): replace this thread with an TYPE_IO encoder_thread_.
  //

  // 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_;

  DISALLOW_COPY_AND_ASSIGN(ExynosVideoEncodeAccelerator);
};

}  // namespace content

#endif  // CONTENT_COMMON_GPU_MEDIA_EXYNOS_VIDEO_ENCODE_ACCELERATOR_H_

/* [<][>][^][v][top][bottom][index][help] */