// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef MEDIA_GPU_CHROMEOS_PLATFORM_VIDEO_FRAME_UTILS_H_
#define MEDIA_GPU_CHROMEOS_PLATFORM_VIDEO_FRAME_UTILS_H_

#include <optional>
#include <set>

#include "base/memory/scoped_refptr.h"
#include "base/unguessable_token.h"
#include "media/base/video_frame.h"
#include "media/gpu/media_gpu_export.h"
#include "ui/gfx/buffer_types.h"
#include "ui/gfx/gpu_memory_buffer_handle.h"
#include "ui/gfx/linux/native_pixmap_dmabuf.h"

namespace gpu {
class SharedImageInterface;
}  // namespace gpu

namespace media {

// Used to create UnguessableTokens that are guaranteed to be unique with
// respect to others that are generated by this class.
class UniqueTrackingTokenHelper {
 public:
  UniqueTrackingTokenHelper();
  UniqueTrackingTokenHelper(const UniqueTrackingTokenHelper&) = delete;
  UniqueTrackingTokenHelper& operator=(const UniqueTrackingTokenHelper&) =
      delete;
  ~UniqueTrackingTokenHelper();

  // Clears all tokens. Used when releasing all frames.
  void ClearTokens();

  // Clears a token from the helper. Called when a token is no longer used to
  // ensure the helper does not leak tokens.
  void ClearToken(const base::UnguessableToken& token);

  // SetUniqueTrackingToken sets a unique |tracking_token| in |metadata|. Note
  // that this operation is not idempotent. Subsequent calls will always
  // produce a new, unique tracking token.
  void SetUniqueTrackingToken(VideoFrameMetadata& metadata);

 private:
  // Initializes |tokens_| with an empty UnguessableToken. This ensures that
  // users cannot insert an empty token.
  void Initialize();

  // Generates a unique UnguessableToken.
  base::UnguessableToken GenerateToken();

  // The expectation is that this class will be used for frame pools where the
  // number of tokens will be relatively small. I.e. tens of tokens at most.
  // If this is not true, then we should figure out why, so crashing Chrome is
  // reasonable.
  static constexpr size_t kMaxNumberOfTokens = 1000;

  std::set<base::UnguessableToken> tokens_;
};

// Creates a GpuMemoryBufferHandle. This function is thread safe.
gfx::GpuMemoryBufferHandle AllocateGpuMemoryBufferHandle(
    VideoPixelFormat pixel_format,
    const gfx::Size& coded_size,
    gfx::BufferUsage buffer_usage);

// Creates a STORAGE_MAPPABLE_SHARED_IMAGE VideoFrame backed by a Mappable
// SharedImage allocated with |buffer_usage|.
// See //media/base/video_frame.h for the other parameters. This function is
// thread-safe.
MEDIA_GPU_EXPORT scoped_refptr<VideoFrame> CreateMappableSharedImageVideoFrame(
    VideoPixelFormat pixel_format,
    const gfx::ColorSpace& color_space,
    const gfx::Size& coded_size,
    const gfx::Rect& visible_rect,
    const gfx::Size& natural_size,
    base::TimeDelta timestamp,
    gfx::BufferUsage buffer_usage,
    gpu::SharedImageInterface* sii);

// Creates a STORAGE_MAPPABLE_SHARED_IMAGE VideoFrame from a
// GpuMemoryBufferHandle. See //media/base/video_frame.h for the other
// parameters. This function is thread-safe.
scoped_refptr<VideoFrame> CreateVideoFrameFromGpuMemoryBufferHandle(
    gfx::GpuMemoryBufferHandle gmb_handle,
    VideoPixelFormat pixel_format,
    const gfx::ColorSpace& color_space,
    const gfx::Size& coded_size,
    const gfx::Rect& visible_rect,
    const gfx::Size& natural_size,
    base::TimeDelta timestamp,
    gfx::BufferUsage buffer_usage,
    gpu::SharedImageInterface* sii);

// Creates a STORAGE_DMABUFS VideoFrame whose buffer is allocated with
// |buffer_usage|. See //media/base/video_frame.h for the other parameters. This
// function is thread-safe.
MEDIA_GPU_EXPORT scoped_refptr<VideoFrame> CreatePlatformVideoFrame(
    VideoPixelFormat pixel_format,
    const gfx::Size& coded_size,
    const gfx::Rect& visible_rect,
    const gfx::Size& natural_size,
    base::TimeDelta timestamp,
    gfx::BufferUsage buffer_usage);

// Returns the VideoFrameLayout of a VideoFrame allocated with
// CreatePlatformVideoFrame(), i.e., all parameters are forwarded to that
// function (|visible_rect| is set to gfx::Rect(|coded_size|), |natural_size| is
// set to |coded_size|, and |timestamp| is set to base::TimeDelta()). This
// function is not cheap as it allocates a buffer. Returns std::nullopt if the
// buffer allocation fails. This function is thread-safe.
MEDIA_GPU_EXPORT std::optional<VideoFrameLayout> GetPlatformVideoFrameLayout(
    VideoPixelFormat pixel_format,
    const gfx::Size& coded_size,
    gfx::BufferUsage buffer_usage);

// Create a shared GPU memory handle to the |video_frame|'s data.
MEDIA_GPU_EXPORT gfx::GpuMemoryBufferHandle CreateGpuMemoryBufferHandle(
    const VideoFrame* video_frame);

// Create a NativePixmap that references the DMA Bufs of |video_frame|. The
// returned pixmap is only a DMA Buf container and should not be used for
// compositing/scanout.
MEDIA_GPU_EXPORT scoped_refptr<gfx::NativePixmapDmaBuf>
CreateNativePixmapDmaBuf(const VideoFrame* video_frame);

}  // namespace media

#endif  // MEDIA_GPU_CHROMEOS_PLATFORM_VIDEO_FRAME_UTILS_H_
