123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353 |
- // Copyright 2020 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.
- #include "ash/services/recording/video_capture_params.h"
- #include "ash/services/recording/recording_service_constants.h"
- #include "base/check.h"
- #include "components/viz/common/surfaces/subtree_capture_id.h"
- #include "media/base/video_types.h"
- #include "services/viz/privileged/mojom/compositing/frame_sink_video_capture.mojom.h"
- #include "ui/gfx/geometry/dip_util.h"
- #include "ui/gfx/geometry/rect.h"
- #include "ui/gfx/geometry/rect_conversions.h"
- #include "ui/gfx/geometry/size_conversions.h"
- namespace recording {
- namespace {
- // Returns a rect that is the result of intersecting the given two rects.
- gfx::Rect GetIntersectionRect(const gfx::Rect& rect_a,
- const gfx::Rect& rect_b) {
- auto result = rect_a;
- result.Intersect(rect_b);
- return result;
- }
- inline gfx::Size GetSizeInPixels(const gfx::Size& size_dips, float dsf) {
- return gfx::ToFlooredSize(gfx::ConvertSizeToPixels(size_dips, dsf));
- }
- // -----------------------------------------------------------------------------
- // FullscreenCaptureParams:
- class FullscreenCaptureParams : public VideoCaptureParams {
- public:
- FullscreenCaptureParams(viz::FrameSinkId frame_sink_id,
- const gfx::Size& frame_sink_size_dip,
- float device_scale_factor)
- : VideoCaptureParams(frame_sink_id,
- viz::SubtreeCaptureId(),
- frame_sink_size_dip,
- device_scale_factor),
- initial_frame_sink_size_pixels_(current_frame_sink_size_pixels_) {}
- FullscreenCaptureParams(const FullscreenCaptureParams&) = delete;
- FullscreenCaptureParams& operator=(const FullscreenCaptureParams&) = delete;
- ~FullscreenCaptureParams() override = default;
- // VideoCaptureParams:
- gfx::Size GetVideoSize() const override {
- return initial_frame_sink_size_pixels_;
- }
- protected:
- void SetCapturerResolutionConstraints(
- mojo::Remote<viz::mojom::FrameSinkVideoCapturer>& capturer)
- const override {
- DCHECK(capturer);
- capturer->SetResolutionConstraints(
- /*min_size=*/initial_frame_sink_size_pixels_,
- /*max_size=*/initial_frame_sink_size_pixels_,
- /*use_fixed_aspect_ratio=*/true);
- }
- bool OnVideoSizeMayHaveChanged(
- mojo::Remote<viz::mojom::FrameSinkVideoCapturer>& capturer) override {
- // We override the default behavior, as we want the video size to remain at
- // the original requested size. This gives a nice indication of display
- // rotations. The new video frames will letterbox to adhere to
- // the original requested resolution constraints.
- return false;
- }
- private:
- // We chose not to change the video size for fullscreen recording and let the
- // capturer letterbox the content in the initial size we gave it. This gives
- // a nice effect especially when rotating the display. See
- // OnVideoSizeMayHaveChanged() above.
- const gfx::Size initial_frame_sink_size_pixels_;
- };
- // -----------------------------------------------------------------------------
- // WindowCaptureParams:
- class WindowCaptureParams : public VideoCaptureParams {
- public:
- WindowCaptureParams(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)
- : VideoCaptureParams(frame_sink_id,
- subtree_capture_id,
- frame_sink_size_dip,
- device_scale_factor),
- current_window_size_dips_(window_size_dip),
- current_window_size_pixels_(CalculateWindowSizeInPixels()) {}
- WindowCaptureParams(const WindowCaptureParams&) = delete;
- WindowCaptureParams& operator=(const WindowCaptureParams&) = delete;
- ~WindowCaptureParams() override = default;
- // VideoCaptureParams:
- gfx::Rect GetVideoFrameVisibleRect(
- const gfx::Rect& original_frame_visible_rect_pixels) const override {
- return GetIntersectionRect(original_frame_visible_rect_pixels,
- gfx::Rect(current_window_size_pixels_));
- }
- gfx::Size GetVideoSize() const override {
- return current_window_size_pixels_;
- }
- 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) override {
- DCHECK(new_frame_sink_id.is_valid());
- DCHECK_NE(frame_sink_id_, new_frame_sink_id);
- frame_sink_id_ = new_frame_sink_id;
- capturer->ChangeTarget(
- viz::VideoCaptureTarget(frame_sink_id_, subtree_capture_id_),
- /*crop_version=*/0);
- // If the movement to another display results in changes in the frame sink
- // size or DSF, OnVideoSizeMayHaveChanged() will be called by the below
- // OnFrameSinkSizeChanged().
- return OnFrameSinkSizeChanged(capturer, new_frame_sink_size_dip,
- new_device_scale_factor);
- }
- bool OnRecordedWindowSizeChanged(
- mojo::Remote<viz::mojom::FrameSinkVideoCapturer>& capturer,
- const gfx::Size& new_window_size_dip) override {
- current_window_size_dips_ = new_window_size_dip;
- return OnVideoSizeMayHaveChanged(capturer);
- }
- protected:
- void SetCapturerResolutionConstraints(
- mojo::Remote<viz::mojom::FrameSinkVideoCapturer>& capturer)
- const override {
- DCHECK(capturer);
- // To avoid receiving letterboxed video frames from the capturer, we ask it
- // to give us an exact resolution matching the window's size in pixels.
- capturer->SetResolutionConstraints(/*min_size=*/current_window_size_pixels_,
- /*max_size=*/current_window_size_pixels_,
- /*use_fixed_aspect_ratio=*/true);
- }
- bool OnVideoSizeMayHaveChanged(
- mojo::Remote<viz::mojom::FrameSinkVideoCapturer>& capturer) override {
- const auto new_window_size_pixels = CalculateWindowSizeInPixels();
- if (new_window_size_pixels == current_window_size_pixels_)
- return false;
- current_window_size_pixels_ = new_window_size_pixels;
- SetCapturerResolutionConstraints(capturer);
- return true;
- }
- private:
- gfx::Size CalculateWindowSizeInPixels() const {
- return GetSizeInPixels(current_window_size_dips_,
- current_device_scale_factor_);
- }
- gfx::Size current_window_size_dips_;
- gfx::Size current_window_size_pixels_;
- };
- // -----------------------------------------------------------------------------
- // RegionCaptureParams:
- class RegionCaptureParams : public VideoCaptureParams {
- public:
- RegionCaptureParams(viz::FrameSinkId frame_sink_id,
- const gfx::Size& frame_sink_size_dip,
- float device_scale_factor,
- const gfx::Rect& crop_region_dip)
- : VideoCaptureParams(frame_sink_id,
- viz::SubtreeCaptureId(),
- frame_sink_size_dip,
- device_scale_factor),
- crop_region_dips_(crop_region_dip),
- crop_region_pixels_(CalculateCropRegionInPixels()) {
- DCHECK(!crop_region_dips_.IsEmpty());
- DCHECK(!crop_region_pixels_.IsEmpty());
- }
- RegionCaptureParams(const RegionCaptureParams&) = delete;
- RegionCaptureParams& operator=(const RegionCaptureParams&) = delete;
- ~RegionCaptureParams() override = default;
- // VideoCaptureParams:
- gfx::Rect GetVideoFrameVisibleRect(
- const gfx::Rect& original_frame_visible_rect_pixels) const override {
- // We can't crop the video frame by an invalid bounds. The crop bounds must
- // be contained within the original frame bounds.
- gfx::Rect visible_rect = crop_region_pixels_;
- visible_rect.AdjustToFit(original_frame_visible_rect_pixels);
- return visible_rect;
- }
- gfx::Size GetVideoSize() const override {
- return GetVideoFrameVisibleRect(gfx::Rect(current_frame_sink_size_pixels_))
- .size();
- }
- protected:
- void SetCapturerResolutionConstraints(
- mojo::Remote<viz::mojom::FrameSinkVideoCapturer>& capturer)
- const override {
- DCHECK(capturer);
- capturer->SetResolutionConstraints(
- /*min_size=*/current_frame_sink_size_pixels_,
- /*max_size=*/current_frame_sink_size_pixels_,
- /*use_fixed_aspect_ratio=*/true);
- }
- bool OnVideoSizeMayHaveChanged(
- mojo::Remote<viz::mojom::FrameSinkVideoCapturer>& capturer) override {
- SetCapturerResolutionConstraints(capturer);
- const auto new_crop_region_pixels = CalculateCropRegionInPixels();
- if (new_crop_region_pixels == crop_region_pixels_)
- return false;
- crop_region_pixels_ = new_crop_region_pixels;
- return true;
- }
- private:
- // Computes and returns the crop region bounds in pixels, according to the
- // |crop_region_dips_| and the |current_device_scale_factor_|.
- gfx::Rect CalculateCropRegionInPixels() const {
- return gfx::ToRoundedRect(gfx::ConvertRectToPixels(
- crop_region_dips_, current_device_scale_factor_));
- }
- const gfx::Rect crop_region_dips_;
- gfx::Rect crop_region_pixels_;
- };
- } // namespace
- // -----------------------------------------------------------------------------
- // VideoCaptureParams:
- // static
- std::unique_ptr<VideoCaptureParams>
- VideoCaptureParams::CreateForFullscreenCapture(
- viz::FrameSinkId frame_sink_id,
- const gfx::Size& frame_sink_size_dip,
- float device_scale_factor) {
- return std::make_unique<FullscreenCaptureParams>(
- frame_sink_id, frame_sink_size_dip, device_scale_factor);
- }
- // static
- std::unique_ptr<VideoCaptureParams> 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) {
- return std::make_unique<WindowCaptureParams>(
- frame_sink_id, subtree_capture_id, frame_sink_size_dip,
- device_scale_factor, window_size_dip);
- }
- // static
- std::unique_ptr<VideoCaptureParams> VideoCaptureParams::CreateForRegionCapture(
- viz::FrameSinkId frame_sink_id,
- const gfx::Size& full_capture_size,
- float device_scale_factor,
- const gfx::Rect& crop_region_dip) {
- return std::make_unique<RegionCaptureParams>(
- frame_sink_id, full_capture_size, device_scale_factor, crop_region_dip);
- }
- void VideoCaptureParams::InitializeVideoCapturer(
- mojo::Remote<viz::mojom::FrameSinkVideoCapturer>& capturer) const {
- DCHECK(capturer);
- capturer->SetMinCapturePeriod(kMinCapturePeriod);
- capturer->SetMinSizeChangePeriod(kMinPeriodForResizeThrottling);
- SetCapturerResolutionConstraints(capturer);
- capturer->SetAutoThrottlingEnabled(false);
- // TODO(afakhry): Discuss with //media/ team the implications of color space
- // conversions.
- capturer->SetFormat(media::PIXEL_FORMAT_I420);
- capturer->ChangeTarget(
- viz::VideoCaptureTarget(frame_sink_id_, subtree_capture_id_),
- /*crop_version=*/0);
- }
- gfx::Rect VideoCaptureParams::GetVideoFrameVisibleRect(
- const gfx::Rect& original_frame_visible_rect_pixels) const {
- return original_frame_visible_rect_pixels;
- }
- bool VideoCaptureParams::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) {
- CHECK(false) << "This can only be called when recording a window";
- return false;
- }
- bool VideoCaptureParams::OnRecordedWindowSizeChanged(
- mojo::Remote<viz::mojom::FrameSinkVideoCapturer>& capturer,
- const gfx::Size& new_window_size_dip) {
- CHECK(false) << "This can only be called when recording a window";
- return false;
- }
- bool VideoCaptureParams::OnFrameSinkSizeChanged(
- mojo::Remote<viz::mojom::FrameSinkVideoCapturer>& capturer,
- const gfx::Size& new_frame_sink_size_dip,
- float new_device_scale_factor) {
- if (current_frame_sink_size_dips_ == new_frame_sink_size_dip &&
- current_device_scale_factor_ == new_device_scale_factor) {
- return false;
- }
- current_frame_sink_size_dips_ = new_frame_sink_size_dip;
- current_device_scale_factor_ = new_device_scale_factor;
- current_frame_sink_size_pixels_ = CalculateFrameSinkSizeInPixels();
- return OnVideoSizeMayHaveChanged(capturer);
- }
- VideoCaptureParams::VideoCaptureParams(viz::FrameSinkId frame_sink_id,
- viz::SubtreeCaptureId subtree_capture_id,
- const gfx::Size& current_frame_sink_size,
- float device_scale_factor)
- : frame_sink_id_(frame_sink_id),
- subtree_capture_id_(subtree_capture_id),
- current_frame_sink_size_dips_(current_frame_sink_size),
- current_device_scale_factor_(device_scale_factor),
- current_frame_sink_size_pixels_(CalculateFrameSinkSizeInPixels()) {
- DCHECK(frame_sink_id_.is_valid());
- }
- gfx::Size VideoCaptureParams::CalculateFrameSinkSizeInPixels() const {
- return GetSizeInPixels(current_frame_sink_size_dips_,
- current_device_scale_factor_);
- }
- } // namespace recording
|