chromium/chromecast/media/base/video_plane_controller.h

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

#ifndef CHROMECAST_MEDIA_BASE_VIDEO_PLANE_CONTROLLER_H_
#define CHROMECAST_MEDIA_BASE_VIDEO_PLANE_CONTROLLER_H_

#include "base/memory/ref_counted.h"
#include "base/memory/singleton.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/thread_checker.h"
#include "chromecast/public/graphics_types.h"
#include "chromecast/public/video_plane.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/overlay_transform.h"

namespace base {
class SingleThreadTaskRunner;
}  // namespace base

namespace gfx {
class Rect;
}  // namespace gfx

namespace media {
struct VideoTransformation;
}  // namespace media

namespace chromecast {
namespace media {

// Provides main interface for setting video plane geometry.  All callsites
// should use this over VideoPlane::SetGeometry.  Reasons for this:
// * provides conversion between graphics plane coordinates and screen
//   resolution coordinates
// * updates VideoPlane when screen resolution changes
// * handles threading correctly (posting SetGeometry to media thread).
// * coalesces multiple calls in short space of time to prevent flooding the
//   media thread with SetGeometry calls (which are expensive on many
//   platforms).
// All public methods should be called from the same thread that the class was
// constructed on.
class VideoPlaneController {
 public:
  VideoPlaneController(
      const Size& graphics_resolution,
      scoped_refptr<base::SingleThreadTaskRunner> media_task_runner);

  VideoPlaneController(const VideoPlaneController&) = delete;
  VideoPlaneController& operator=(const VideoPlaneController&) = delete;

  ~VideoPlaneController();

  // Sets the video plane geometry in *graphics plane coordinates*. If there is
  // no change to video plane parameters from the last call to this method, it
  // is a no-op.
  void SetGeometry(const gfx::RectF& display_rect,
                   gfx::OverlayTransform transform);
  void SetGeometryFromMediaType(const gfx::Rect& display_rect,
                                const ::media::VideoTransformation& transform);

  // Sets physical screen resolution. This must be called at least once when
  // the final output resolution (HDMI signal or panel resolution) is known,
  // then later when it changes. If there is no change to the screen resolution
  // from the last call to this method, it is a no-op.
  void SetScreenResolution(const Size& resolution);

  // After Pause is called, no further calls to VideoPlane::SetGeometry will be
  // made except for any pending calls already scheduled on the media thread.
  // The Set methods will however update cached parameters that will take
  // effect once the class is resumed. Safe to call multiple times.
  // TODO(esum): Handle the case where there are pending calls already on the
  // media thread. When this returns, the caller needs to know that absolutely
  // no more SetGeometry calls will be made.
  void Pause();
  // Makes class active again, and clears any cached video plane geometry
  // parameters. Safe to call multiple times.
  void Resume();
  bool is_paused() const;

 private:
  class RateLimitedSetVideoPlaneGeometry;
  friend struct base::DefaultSingletonTraits<VideoPlaneController>;

  void SetGeometryInternal(const gfx::RectF& display_rect,
                           VideoPlane::Transform transform);

  // Check if HaveDataForSetGeometry. If not, this method is a no-op. Otherwise
  // it scales the display rect from graphics to device resolution coordinates.
  // Then posts task to media thread for VideoPlane::SetGeometry.
  void MaybeRunSetGeometry();
  // Checks if all data has been collected to make calls to
  // VideoPlane::SetGeometry.
  bool HaveDataForSetGeometry() const;
  // Clears any cached video plane geometry parameters.
  void ClearVideoPlaneGeometry();

  bool is_paused_;

  // Current resolutions
  bool have_screen_res_;
  Size screen_res_;
  const Size graphics_plane_res_;

  // Which coordinates to use for transforms (e.g. graphics coordinates or
  // screen coordinates).
  const VideoPlane::Coordinates coordinates_;

  // Saved video plane parameters (in graphics plane coordinates)
  // for use when screen resolution changes.
  bool have_video_plane_geometry_;
  RectF video_plane_display_rect_;
  VideoPlane::Transform video_plane_transform_;

  scoped_refptr<base::SingleThreadTaskRunner> media_task_runner_;
  scoped_refptr<RateLimitedSetVideoPlaneGeometry> video_plane_wrapper_;

  base::ThreadChecker thread_checker_;
  base::WeakPtrFactory<VideoPlaneController> weak_factory_{this};
};

}  // namespace media
}  // namespace chromecast

#endif  // CHROMECAST_MEDIA_BASE_VIDEO_PLANE_CONTROLLER_H_