summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorhalliwell <halliwell@chromium.org>2015-07-10 13:18:24 -0700
committerCommit bot <commit-bot@chromium.org>2015-07-10 20:19:10 +0000
commiteae1a9bbc57f3e7c53ae6fa94ad86c240cfd5237 (patch)
tree073954a4e4f20951253c294ae32ab06e54034f9f
parentab1a2dc33561303b1aab4a6e77a47bff749e58ce (diff)
downloadchromium_src-eae1a9bbc57f3e7c53ae6fa94ad86c240cfd5237.zip
chromium_src-eae1a9bbc57f3e7c53ae6fa94ad86c240cfd5237.tar.gz
chromium_src-eae1a9bbc57f3e7c53ae6fa94ad86c240cfd5237.tar.bz2
Limit rate of posted VideoPlane::SetGeometry calls from Cast overlays
Some VideoPlane::SetGeometry implementations are slow (on the order of 100ms). The overlay path can end up posting a task as fast as the graphics system is producing frames. So at 20fps, the media thread ends up backing up with SetGeometry tasks. The new implementation measures the time taken by SetGeometry to adaptively determine a reasonable rate at which to call it. It then coalesces multiple SetGeometry calls within this frequency into one. BUG=469374 Review URL: https://codereview.chromium.org/1228423003 Cr-Commit-Position: refs/heads/master@{#338343}
-rw-r--r--ui/ozone/platform/cast/overlay_manager_cast.cc116
1 files changed, 105 insertions, 11 deletions
diff --git a/ui/ozone/platform/cast/overlay_manager_cast.cc b/ui/ozone/platform/cast/overlay_manager_cast.cc
index 9d17300..a46bb55 100644
--- a/ui/ozone/platform/cast/overlay_manager_cast.cc
+++ b/ui/ozone/platform/cast/overlay_manager_cast.cc
@@ -18,15 +18,105 @@
namespace ui {
namespace {
-void SetVideoPlaneGeometry(
- const chromecast::RectF& display_rect,
- chromecast::media::VideoPlane::CoordinateType coordinate_type,
- chromecast::media::VideoPlane::Transform transform) {
- chromecast::media::VideoPlane* video_plane =
- chromecast::media::CastMediaShlib::GetVideoPlane();
- CHECK(video_plane);
- video_plane->SetGeometry(display_rect, coordinate_type, transform);
-}
+// Helper class for calling VideoPlane::SetGeometry with rate-limiting.
+// SetGeometry can take on the order of 100ms to run in some implementations
+// and can be called on the order of 20x / second (as fast as graphics frames
+// are produced). This creates an ever-growing backlog of tasks on the media
+// thread.
+// This class measures the time taken to run SetGeometry to determine a
+// reasonable frequency at which to call it. Excess calls are coalesced
+// to just set the most recent geometry.
+class RateLimitedSetVideoPlaneGeometry
+ : public base::RefCountedThreadSafe<RateLimitedSetVideoPlaneGeometry> {
+ public:
+ RateLimitedSetVideoPlaneGeometry(
+ const scoped_refptr<base::SingleThreadTaskRunner>& task_runner)
+ : pending_display_rect_(0, 0, 0, 0),
+ pending_set_geometry_(false),
+ min_calling_interval_ms_(0),
+ sample_counter_(0),
+ task_runner_(task_runner) {}
+
+ void SetGeometry(
+ const chromecast::RectF& display_rect,
+ chromecast::media::VideoPlane::CoordinateType coordinate_type,
+ chromecast::media::VideoPlane::Transform transform) {
+ DCHECK(task_runner_->BelongsToCurrentThread());
+
+ base::TimeTicks now = base::TimeTicks::Now();
+ base::TimeDelta elapsed = now - last_set_geometry_time_;
+
+ if (elapsed < base::TimeDelta::FromMilliseconds(min_calling_interval_ms_)) {
+ if (!pending_set_geometry_) {
+ pending_set_geometry_ = true;
+
+ task_runner_->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(
+ &RateLimitedSetVideoPlaneGeometry::ApplyPendingSetGeometry,
+ this),
+ base::TimeDelta::FromMilliseconds(2 * min_calling_interval_ms_));
+ }
+
+ pending_display_rect_ = display_rect;
+ pending_coordinate_type_ = coordinate_type;
+ pending_transform_ = transform;
+ return;
+ }
+ last_set_geometry_time_ = now;
+
+ chromecast::media::VideoPlane* video_plane =
+ chromecast::media::CastMediaShlib::GetVideoPlane();
+ CHECK(video_plane);
+ base::TimeTicks start = base::TimeTicks::Now();
+ video_plane->SetGeometry(display_rect, coordinate_type, transform);
+
+ base::TimeDelta set_geometry_time = base::TimeTicks::Now() - start;
+ UpdateAverageTime(set_geometry_time.InMilliseconds());
+ }
+
+ private:
+ friend class base::RefCountedThreadSafe<RateLimitedSetVideoPlaneGeometry>;
+ ~RateLimitedSetVideoPlaneGeometry() {}
+
+ void UpdateAverageTime(int64 sample) {
+ const size_t kSampleCount = 5;
+ if (samples_.size() < kSampleCount)
+ samples_.push_back(sample);
+ else
+ samples_[sample_counter_++ % kSampleCount] = sample;
+ int64 total = 0;
+ for (int64 s : samples_)
+ total += s;
+ min_calling_interval_ms_ = 2 * total / samples_.size();
+ }
+
+ void ApplyPendingSetGeometry() {
+ if (pending_set_geometry_) {
+ pending_set_geometry_ = false;
+ SetGeometry(pending_display_rect_, pending_coordinate_type_,
+ pending_transform_);
+ }
+ }
+
+ chromecast::RectF pending_display_rect_;
+ chromecast::media::VideoPlane::CoordinateType pending_coordinate_type_;
+ chromecast::media::VideoPlane::Transform pending_transform_;
+ bool pending_set_geometry_;
+ base::TimeTicks last_set_geometry_time_;
+
+ // Don't call SetGeometry faster than this interval.
+ int64 min_calling_interval_ms_;
+
+ // Min calling interval is computed as double average of last few time samples
+ // (i.e. allow at least as much time between calls as the call itself takes).
+ std::vector<int64> samples_;
+ size_t sample_counter_;
+
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+
+ DISALLOW_COPY_AND_ASSIGN(RateLimitedSetVideoPlaneGeometry);
+};
// Translates a gfx::OverlayTransform into a VideoPlane::Transform.
// Could be just a lookup table once we have unit tests for this code
@@ -63,7 +153,9 @@ class OverlayCandidatesCast : public OverlayCandidatesOzone {
: media_task_runner_(
chromecast::media::MediaMessageLoop::GetTaskRunner()),
transform_(gfx::OVERLAY_TRANSFORM_INVALID),
- display_rect_(0, 0, 0, 0) {}
+ display_rect_(0, 0, 0, 0),
+ video_plane_wrapper_(
+ new RateLimitedSetVideoPlaneGeometry(media_task_runner_)) {}
void CheckOverlaySupport(OverlaySurfaceCandidateList* surfaces) override;
@@ -71,6 +163,7 @@ class OverlayCandidatesCast : public OverlayCandidatesOzone {
scoped_refptr<base::SingleThreadTaskRunner> media_task_runner_;
gfx::OverlayTransform transform_;
chromecast::RectF display_rect_;
+ scoped_refptr<RateLimitedSetVideoPlaneGeometry> video_plane_wrapper_;
};
void OverlayCandidatesCast::CheckOverlaySupport(
@@ -99,7 +192,8 @@ void OverlayCandidatesCast::CheckOverlaySupport(
media_task_runner_->PostTask(
FROM_HERE,
base::Bind(
- &SetVideoPlaneGeometry, display_rect,
+ &RateLimitedSetVideoPlaneGeometry::SetGeometry,
+ video_plane_wrapper_, display_rect,
chromecast::media::VideoPlane::COORDINATE_TYPE_GRAPHICS_PLANE,
ConvertTransform(candidate.transform)));
}