chromium/chromeos/ash/services/recording/video_capture_params.h

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

#ifndef CHROMEOS_ASH_SERVICES_RECORDING_VIDEO_CAPTURE_PARAMS_H_
#define CHROMEOS_ASH_SERVICES_RECORDING_VIDEO_CAPTURE_PARAMS_H_

#include <memory>

#include "components/viz/common/surfaces/frame_sink_id.h"
#include "components/viz/common/surfaces/subtree_capture_id.h"
#include "media/base/video_types.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/viz/privileged/mojom/compositing/frame_sink_video_capture.mojom-forward.h"
#include "ui/gfx/geometry/size.h"

namespace gfx {
class Rect;
class Size;
}  // namespace gfx

namespace recording {

// Encapsulates the parameters for an ongoing video capture, and knows how to
// initialize a video capturer according to the requested capture source
// (fullscreen, window, or region).
class VideoCaptureParams {
 public:
  VideoCaptureParams(const VideoCaptureParams&) = delete;
  VideoCaptureParams& operator=(const VideoCaptureParams&) = delete;
  virtual ~VideoCaptureParams() = default;

  // Returns a capture params instance for a fullscreen recording of a root
  // window which has the given |frame_sink_id|. Using the given
  // |frame_sink_size_dip| and |device_scale_factor|, the resulting video will
  // have a resolution equal to the pixel size of the recorded frame sink.
  // |frame_sink_id| must be valid.
  static std::unique_ptr<VideoCaptureParams> CreateForFullscreenCapture(
      viz::FrameSinkId frame_sink_id,
      const gfx::Size& frame_sink_size_dip,
      float device_scale_factor);

  // Returns a capture params instance for a recording of a window. The given
  // |frame_sink_id| is either of that window (if it submits compositor frames
  // independently), or of the root window it descends from (if it doesn't
  // submit its compositor frames). In the latter case, the window must be
  // identifiable by a valid |subtree_capture_id| (created by calling
  // aura::window::MakeWindowCapturable() before recording starts).
  // |window_size_dip| is the initial size of the recorded window, and
  // |frame_sink_size_dip| is the current size of the frame sink.
  // |device_scale_factor| will be used to compute and perform the capture at
  // the pixel size of the window.
  // |frame_sink_id| must be valid.
  static std::unique_ptr<VideoCaptureParams> CreateForWindowCapture(
      viz::FrameSinkId frame_sink_id,
      viz::SubtreeCaptureId subtree_capture_id,
      const gfx::Size& frame_sink_size_dip,
      float device_scale_factor,
      const gfx::Size& window_size_dip);

  // Returns a capture params instance for a recording of a partial region of a
  // root window which has the given |frame_sink_id|. Using the given
  // |frame_sink_size_dip| and |device_scale_factor|, the video will be captured
  // at a resolution equal to the size of the frame sink in pixels, but the
  // resulting video frames will be cropped to the pixel bounds that corresponds
  // to the given |crop_region_dip|. |frame_sink_id| must be valid.
  static std::unique_ptr<VideoCaptureParams> CreateForRegionCapture(
      viz::FrameSinkId frame_sink_id,
      const gfx::Size& frame_sink_size_dip,
      float device_scale_factor,
      const gfx::Rect& crop_region_dip);

  const viz::FrameSinkId& frame_sink_id() const { return frame_sink_id_; }
  float current_device_scale_factor() const {
    return current_device_scale_factor_;
  }
  gfx::Size current_frame_sink_size_pixels() const {
    return current_frame_sink_size_pixels_;
  }

  // Initializes the given `capturer` (passed by ref) according to the capture
  // parameters. The given `capturer` must be bound before calling this.
  // The given `supported_pixel_format` will be used to initialize `capturer`.
  void InitializeVideoCapturer(
      mojo::Remote<viz::mojom::FrameSinkVideoCapturer>& capturer,
      media::VideoPixelFormat supported_pixel_format) const;

  // Returns the bounds to which a video frame, whose
  // |original_frame_visible_rect_pixels| is given, should be cropped. If no
  // cropping is desired, |original_frame_visible_rect_pixels| is returned.
  virtual gfx::Rect GetVideoFrameVisibleRect(
      const gfx::Rect& original_frame_visible_rect_pixels) const;

  // Returns the size in pixels with which the video encoder will be
  // initialized.
  virtual gfx::Size GetVideoSize() const = 0;

  // Called when a window, being recorded by the given |capturer|, is moved to
  // a different display whose root window has the given |new_frame_sink_id|,
  // |new_frame_sink_size_dip|, and |new_device_scale_factor|.
  // The default implementation is to *crash* the service, as this is only valid
  // when recording a window.
  // Returns true if the video encoder needs to be reconfigured, which happens
  // when the pixel size of the window changes, resulting in a change in the
  // size of the video. Returns false otherwise.
  [[nodiscard]] virtual bool OnRecordedWindowChangingRoot(
      mojo::Remote<viz::mojom::FrameSinkVideoCapturer>& capturer,
      viz::FrameSinkId new_frame_sink_id,
      const gfx::Size& new_frame_sink_size_dip,
      float new_device_scale_factor);

  // Called when a window being recorded by the given |capturer| is resized
  // (e.g. due to snapping, maximizing, user resizing, ... etc.) to
  // |new_window_size_dip|.
  // The default implementation is to *crash* the service, as this is only valid
  // when recording a window.
  // Returns true if the video encoder needs to be reconfigured, indicating that
  // there's a change in the pixel size of the recorded window, resulting in a
  // change in the video size. False otherwise.
  [[nodiscard]] virtual bool OnRecordedWindowSizeChanged(
      mojo::Remote<viz::mojom::FrameSinkVideoCapturer>& capturer,
      const gfx::Size& new_window_size_dip);

  // Called when the frame sink being recorded changes its size or device scale
  // factor to |new_frame_sink_size_dip| or |new_device_scale_factor|
  // respectively. The |current_frame_sink_size_pixels_| will be updated, and
  // OnVideoSizeMayHaveChanged() will be called. Subclasses should implement
  // OnVideoSizeMayHaveChanged() to handle possible changes in the pixel size
  // of the recorded surface, and hence a change in the output video size, which
  // would require a video encoder reconfiguration.
  // Returns true if the video encoder needs to be reconfigured. False
  // otherwise.
  [[nodiscard]] bool OnFrameSinkSizeChanged(
      mojo::Remote<viz::mojom::FrameSinkVideoCapturer>& capturer,
      const gfx::Size& new_frame_sink_size_dip,
      float new_device_scale_factor);

 protected:
  VideoCaptureParams(viz::FrameSinkId frame_sink_id,
                     viz::SubtreeCaptureId subtree_capture_id,
                     const gfx::Size& current_frame_sink_size,
                     float device_scale_factor);

  // Sets the desired resolution constraints on the given |capturer|. Subclasses
  // should override this to request a resolution from |capturer| that matches
  // the pixel size of the recorded surface.
  virtual void SetCapturerResolutionConstraints(
      mojo::Remote<viz::mojom::FrameSinkVideoCapturer>& capturer) const = 0;

  // Called when an event occurs that may lead to changing the size of the
  // video (such as changing the device scale factor, or resizing a recorded
  // window). Implementations should recompute the video size, and return true
  // if there was actually a change in the video size that the video encoder
  // needs to be reconfigured. Returns false otherwise.
  virtual bool OnVideoSizeMayHaveChanged(
      mojo::Remote<viz::mojom::FrameSinkVideoCapturer>& capturer) = 0;

  // Computes and returns the pixel size of the frame sink according to the
  // current values of |current_frame_sink_size_dips_| and
  // |current_device_scale_factor_|.
  gfx::Size CalculateFrameSinkSizeInPixels() const;

  viz::FrameSinkId frame_sink_id_;
  const viz::SubtreeCaptureId subtree_capture_id_;
  gfx::Size current_frame_sink_size_dips_;
  float current_device_scale_factor_;
  gfx::Size current_frame_sink_size_pixels_;
};

}  // namespace recording

#endif  // CHROMEOS_ASH_SERVICES_RECORDING_VIDEO_CAPTURE_PARAMS_H_