/*=========================================================================

  Program:   ParaView
  Module:    vtkPVImageDelivery.h

  Copyright (c) Kitware, Inc.
  All rights reserved.
  See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
/**
 * @class vtkPVImageDelivery
 * @brief Uses image/video compression techniques to stream vtkRenderWindow display framebuffer
 *
 */
#ifndef vtkPVImageDelivery_h
#define vtkPVImageDelivery_h

#include "vtkObject.h"

#include "vtkCompressedVideoPacket.h"            // for arg
#include "vtkPacket.h"                           // for return
#include "vtkPixelFormatTypes.h"                 // for ivar
#include "vtkRawVideoFrame.h"                    // for slice order
#include "vtkRemoteViewResultItem.h"             // for return
#include "vtkRemoteViewStatsItem.h"              // for return
#include "vtkRemotingServerManagerViewsModule.h" // for export macro
#include "vtkSmartPointer.h"                     // for arg
#include "vtkUnsignedCharArray.h"                // for arg

#include <memory> // for ivar

class vtkVideoEncoder;
class vtkRenderWindow;

class VTKREMOTINGSERVERMANAGERVIEWS_EXPORT vtkPVImageDelivery : public vtkObject
{
public:
  static vtkPVImageDelivery* New();
  vtkTypeMacro(vtkPVImageDelivery, vtkObject);
  void PrintSelf(ostream& os, vtkIndent indent) override;

  enum class EncoderQuality
  {
    LOW,
    HIGH
  };

  ///@{
  /**
   * Each image delivery class is assigned a unique id.
   */
  void SetGlobalID(vtkTypeUInt32 gid);
  vtkTypeUInt32 GetGlobalID() const;
  ///@}

  ///@{
  /**
   * Set lossless image transmission mode.
   */
  void SetLosslessMode(bool value);
  void SetLosslessPixelFormat(VTKPixelFormatType pixFmt);
  void SetLosslessPictureSliceOrder(vtkRawVideoFrame::SliceOrderType sliceOrder);
  void SetLosslessPixelFormat(int pixFmt);
  void SetLosslessPictureSliceOrder(int sliceOrder);
  ///@}

  /**
   * Jpeg image transmission mode and relevant options
   */
  void SetJpegMode(bool value);

  ///@{
  /**
   * Quality control 0-100. 0: worst quality, 100: best quality
   */
  //  quality of stream for StillRender
  void SetStillStreamQuality(int quality);
  //  quality of stream for InteractiveRender
  void SetInteractiveStreamQuality(int quality);
  ///@}

  /**
   * Set the target bitrate for video encoders in kbps
   */
  void SetTargetBitrate(int bitrate);

  /**
   * Set/Get video encoder used for frame compression.
   */
  void SetVideoEncoder(vtkVideoEncoder* encoder);
  ///@}

  ///@{
  /**
   * Multiplex video packets into media segments of a standard container (vp9 -> webm)
   * (av1 -> avif), (h.26x -> mp4). At the moment, the server handles vp9 -> webm.
   *
   * Initialization segment: https://www.w3.org/TR/media-source/#init-segment
   * Media segment: https://www.w3.org/TR/media-source/#media-segment
   */
  void SetMediaSegmentsMode(bool value);
  void SetRequestMediaInitializationSegment(bool value);
  ///@}

  /**
   * Packs the contents of the render window's display framebuffer.
   * It can optionally use image compression or advanced video
   * codecs for high compression ratio.
   */
  vtkPacket PackageDisplayFramebuffer(
    vtkRenderWindow* window, vtkRemoteViewStatsItem& stats, bool prefer_low_quality = false);

  VTKPixelFormatType GetOptimalStreamPixelFormat() const;
  vtkRawVideoFrame::SliceOrderType GetOptimalSliceOrder() const;

protected:
  vtkPVImageDelivery();
  ~vtkPVImageDelivery() override;

  /**
   * Convenient function to get mime, codec types as universally recognized strings.
   */
  const char* GetMimeType() const;
  const char* GetCodecLongName() const;
  bool GetUseVideoEncoders() const;

  /**
   * Implements logic for compression and serializes the
   * result into vtkRemoteViewResultItem
   */
  vtkRemoteViewResultItem SerializeDisplayFrameBuffer(vtkRenderWindow* window,
    vtkRemoteViewStatsItem& stats, vtkSmartPointer<vtkUnsignedCharArray>& content,
    bool prefer_low_quality = false);

  /**
   * Captures the current output of the render view.
   * The destination is in GPU storage (OpenGL texture).
   */
  void Capture(vtkRenderWindow* window);
  void DoImageEncode(vtkRemoteViewResultItem& result,
    vtkSmartPointer<vtkUnsignedCharArray>& content, EncoderQuality qualityMode);
  void DoVideoEncode(vtkRemoteViewResultItem& result,
    vtkSmartPointer<vtkUnsignedCharArray>& content, EncoderQuality qualityMode);
  vtkSmartPointer<vtkCompressedVideoPacket> GenerateMediaSegments(
    vtkSmartPointer<vtkCompressedVideoPacket> encodedVideoChunk);

  bool NeedKeyFrame(EncoderQuality qualityMode);

private:
  vtkPVImageDelivery(const vtkPVImageDelivery&) = delete;
  void operator=(const vtkPVImageDelivery&) = delete;

  class vtkInternals;
  std::unique_ptr<vtkInternals> Internals;
};

#endif
