// 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_CLIENT_GPU_VIDEO_ENCODE_ACCELERATOR_HOST_H_
#define CONTENT_COMMON_GPU_CLIENT_GPU_VIDEO_ENCODE_ACCELERATOR_HOST_H_

#include <stdint.h>

#include <vector>

#include "base/containers/hash_tables.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/non_thread_safe.h"
#include "content/common/gpu/client/command_buffer_proxy_impl.h"
#include "gpu/config/gpu_info.h"
#include "ipc/ipc_listener.h"
#include "media/video/video_encode_accelerator.h"

namespace gfx {
struct GpuMemoryBufferHandle;
class Size;
}  // namespace gfx

namespace media {
class VideoFrame;
}  // namespace media

namespace tracked_objects {
class Location;
}  // namespace tracked_objects

namespace content {
class GpuChannelHost;

// This class is the renderer-side host for the VideoEncodeAccelerator in the
// GPU process, coordinated over IPC.
class GpuVideoEncodeAcceleratorHost
    : public IPC::Listener,
      public media::VideoEncodeAccelerator,
      public CommandBufferProxyImpl::DeletionObserver,
      public base::NonThreadSafe {
 public:
  // |this| is guaranteed not to outlive |channel| and |impl|.  (See comments
  // for |channel_| and |impl_|.)
  GpuVideoEncodeAcceleratorHost(GpuChannelHost* channel,
                                CommandBufferProxyImpl* impl);

  // IPC::Listener implementation.
  bool OnMessageReceived(const IPC::Message& message) override;
  void OnChannelError() override;

  // media::VideoEncodeAccelerator implementation.
  SupportedProfiles GetSupportedProfiles() override;
  bool Initialize(media::VideoPixelFormat input_format,
                  const gfx::Size& input_visible_size,
                  media::VideoCodecProfile output_profile,
                  uint32_t initial_bitrate,
                  Client* client) override;
  void Encode(const scoped_refptr<media::VideoFrame>& frame,
              bool force_keyframe) override;
  void UseOutputBitstreamBuffer(const media::BitstreamBuffer& buffer) override;
  void RequestEncodingParametersChange(uint32_t bitrate,
                                       uint32_t framerate_num) override;
  void Destroy() override;

  // CommandBufferProxyImpl::DeletionObserver implementation.
  void OnWillDeleteImpl() override;

 private:
  // Only Destroy() should be deleting |this|.
  ~GpuVideoEncodeAcceleratorHost() override;

  // Encode specific video frame types.
  void EncodeGpuMemoryBufferFrame(const scoped_refptr<media::VideoFrame>& frame,
                                  bool force_keyframe);
  void EncodeSharedMemoryFrame(const scoped_refptr<media::VideoFrame>& frame,
                               bool force_keyframe);

  // Notify |client_| of an error.  Posts a task to avoid re-entrancy.
  void PostNotifyError(const tracked_objects::Location& location,
                       Error error, const std::string& message);

  void Send(IPC::Message* message);

  // IPC handlers, proxying media::VideoEncodeAccelerator::Client for the GPU
  // process.  Should not be called directly.
  void OnRequireBitstreamBuffers(uint32_t input_count,
                                 const gfx::Size& input_coded_size,
                                 uint32_t output_buffer_size);
  void OnNotifyInputDone(int32_t frame_id);
  void OnBitstreamBufferReady(int32_t bitstream_buffer_id,
                              uint32_t payload_size,
                              bool key_frame);
  void OnNotifyError(Error error);

  // Unowned reference to the GpuChannelHost to send IPC messages to the GPU
  // process.  |channel_| outlives |impl_|, so the reference is always valid as
  // long as it is not NULL.
  GpuChannelHost* channel_;

  // Route ID for the associated encoder in the GPU process.
  int32_t encoder_route_id_;

  // The client that will receive callbacks from the encoder.
  Client* client_;

  // Unowned reference to the CommandBufferProxyImpl that created us.  |this|
  // registers as a DeletionObserver of |impl_|, so the reference is always
  // valid as long as it is not NULL.
  CommandBufferProxyImpl* impl_;

  // media::VideoFrames sent to the encoder.
  // base::IDMap not used here, since that takes pointers, not scoped_refptr.
  typedef base::hash_map<int32_t, scoped_refptr<media::VideoFrame>> FrameMap;
  FrameMap frame_map_;

  // ID serial number for the next frame to send to the GPU process.
  int32_t next_frame_id_;

  // WeakPtr factory for posting tasks back to itself.
  base::WeakPtrFactory<GpuVideoEncodeAcceleratorHost> weak_this_factory_;

  DISALLOW_COPY_AND_ASSIGN(GpuVideoEncodeAcceleratorHost);
};

}  // namespace content

#endif  // CONTENT_COMMON_GPU_CLIENT_GPU_VIDEO_ENCODE_ACCELERATOR_HOST_H_
