Skip to content

Commit

Permalink
Implement a video detector in Viz
Browse files Browse the repository at this point in the history
Current video detector is broken with Viz enabled. Move parts of
ash::VideoDetector that need to be run in Viz process into
viz::VideoDetector and notify ash::VideoDetector over mojo.
I don't expect any regressions in behaviour. One improvement is that
when the video activity is happening in an occluded window, the new
video detector does not report that activity, whereas the old video
detector did.

Test: There are unit tests. I also tried --mash, --mus,--enable-viz,
and no flags manually for a chromeos build on my workstation. Also
tried --mash and --mus and no flags manually on a link chromebook.

BUG=775035

Change-Id: I5098492edaf5cce08f9ba6c50a5d7482eb739426
Reviewed-on: https://chromium-review.googlesource.com/702044
Reviewed-by: kylechar <kylechar@chromium.org>
Reviewed-by: Scott Violet <sky@chromium.org>
Reviewed-by: Yuzhu Shen <yzshen@chromium.org>
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Reviewed-by: Dan Erat <derat@chromium.org>
Commit-Queue: Saman Sami <samans@chromium.org>
Cr-Commit-Position: refs/heads/master@{#515186}
  • Loading branch information
Saman Sami authored and Commit Bot committed Nov 9, 2017
1 parent bc34fae commit 3fb310d
Show file tree
Hide file tree
Showing 45 changed files with 875 additions and 336 deletions.
1 change: 1 addition & 0 deletions ash/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -972,6 +972,7 @@ component("ash") {
"//components/strings",
"//components/user_manager",
"//components/vector_icons",
"//components/viz/host",
"//components/viz/service",
"//components/wallpaper",
"//device/bluetooth",
Expand Down
2 changes: 2 additions & 0 deletions ash/DEPS
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,15 @@ include_rules = [
"+components/user_manager",
"+components/vector_icons",
"+components/viz/common",
"+components/viz/host",
"+components/wallpaper",
"+gpu/config",
"+media",
"+mojo/public",
"+services/preferences/public",
"+services/service_manager/public",
"+services/ui/public",
"+services/viz/public",
"+skia/ext",
"+third_party/cros_system_api",
"+third_party/icu",
Expand Down
2 changes: 1 addition & 1 deletion ash/mus/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
"*": [ "accessibility", "app" ],
"ash_pref_connector": [ "pref_connector" ],
"local_state": [ "pref_client" ],
"ui": [ "display_dev", "window_manager" ],
"ui": [ "display_dev", "window_manager", "video_detector" ],
"touch_hud": [ "mash:launchable" ]
}
}
Expand Down
13 changes: 13 additions & 0 deletions ash/mus/shell_port_mus.cc
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include "ash/wm/workspace/workspace_event_handler_classic.h"
#include "base/memory/ptr_util.h"
#include "services/ui/public/interfaces/constants.mojom.h"
#include "services/ui/public/interfaces/video_detector.mojom.h"
#include "ui/aura/env.h"
#include "ui/aura/mus/focus_synchronizer.h"
#include "ui/aura/mus/window_tree_client.h"
Expand Down Expand Up @@ -262,5 +263,17 @@ ShellPortMus::CreateAcceleratorController() {
accelerator_controller_delegate_.get(), nullptr);
}

void ShellPortMus::AddVideoDetectorObserver(
viz::mojom::VideoDetectorObserverPtr observer) {
// We may not have access to the connector in unit tests.
if (!window_manager_->connector())
return;

ui::mojom::VideoDetectorPtr video_detector;
window_manager_->connector()->BindInterface(ui::mojom::kServiceName,
&video_detector);
video_detector->AddObserver(std::move(observer));
}

} // namespace mus
} // namespace ash
2 changes: 2 additions & 0 deletions ash/mus/shell_port_mus.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ class ShellPortMus : public ShellPort {
std::unique_ptr<display::NativeDisplayDelegate> CreateNativeDisplayDelegate()
override;
std::unique_ptr<AcceleratorController> CreateAcceleratorController() override;
void AddVideoDetectorObserver(
viz::mojom::VideoDetectorObserverPtr observer) override;

protected:
WindowManager* window_manager_;
Expand Down
7 changes: 6 additions & 1 deletion ash/shell.cc
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@
#include "chromeos/system/devicemode.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "components/viz/host/host_frame_sink_manager.h"
#include "services/preferences/public/cpp/pref_service_factory.h"
#include "services/preferences/public/interfaces/preferences.mojom.h"
#include "services/service_manager/public/cpp/connector.h"
Expand Down Expand Up @@ -1068,7 +1069,11 @@ void Shell::Init(const ShellInitParams& init_params) {
autoclick_controller_.reset(AutoclickController::CreateInstance());

high_contrast_controller_.reset(new HighContrastController);
video_detector_.reset(new VideoDetector);

viz::mojom::VideoDetectorObserverPtr observer;
video_detector_ =
std::make_unique<VideoDetector>(mojo::MakeRequest(&observer));
shell_port_->AddVideoDetectorObserver(std::move(observer));

tooltip_controller_.reset(new views::corewm::TooltipController(
std::unique_ptr<views::corewm::Tooltip>(new views::corewm::TooltipAura)));
Expand Down
5 changes: 5 additions & 0 deletions ash/shell_port.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "ash/wm/lock_state_observer.h"
#include "base/observer_list.h"
#include "base/optional.h"
#include "services/viz/public/interfaces/compositing/video_detector_observer.mojom.h"
#include "ui/aura/client/window_types.h"
#include "ui/base/cursor/cursor_data.h"
#include "ui/base/ui_base_types.h"
Expand Down Expand Up @@ -168,6 +169,10 @@ class ASH_EXPORT ShellPort {
// sent to the server.
virtual void UpdateSystemModalAndBlockingContainers() = 0;

// Adds an observer for viz::VideoDetector.
virtual void AddVideoDetectorObserver(
viz::mojom::VideoDetectorObserverPtr observer) = 0;

protected:
ShellPort();

Expand Down
9 changes: 9 additions & 0 deletions ash/shell_port_classic.cc
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "ash/wm/window_util.h"
#include "ash/wm/workspace/workspace_event_handler_classic.h"
#include "base/memory/ptr_util.h"
#include "components/viz/host/host_frame_sink_manager.h"
#include "ui/aura/env.h"
#include "ui/display/manager/chromeos/default_touch_transform_setter.h"
#include "ui/display/types/native_display_delegate.h"
Expand Down Expand Up @@ -171,4 +172,12 @@ ShellPortClassic::CreateAcceleratorController() {
accelerator_controller_delegate_.get(), nullptr);
}

void ShellPortClassic::AddVideoDetectorObserver(
viz::mojom::VideoDetectorObserverPtr observer) {
aura::Env::GetInstance()
->context_factory_private()
->GetHostFrameSinkManager()
->AddVideoDetectorObserver(std::move(observer));
}

} // namespace ash
2 changes: 2 additions & 0 deletions ash/shell_port_classic.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ class ASH_EXPORT ShellPortClassic : public ShellPort {
std::unique_ptr<display::NativeDisplayDelegate> CreateNativeDisplayDelegate()
override;
std::unique_ptr<AcceleratorController> CreateAcceleratorController() override;
void AddVideoDetectorObserver(
viz::mojom::VideoDetectorObserverPtr observer) override;

private:
std::unique_ptr<PointerWatcherAdapterClassic> pointer_watcher_adapter_;
Expand Down
3 changes: 2 additions & 1 deletion ash/system/power/video_activity_notifier_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ class VideoActivityNotifierTest : public AshTestBase {
AshTestBase::SetUp();
power_client_ = static_cast<chromeos::FakePowerManagerClient*>(
chromeos::DBusThreadManager::Get()->GetPowerManagerClient());
detector_.reset(new VideoDetector());
detector_ = std::make_unique<VideoDetector>(
viz::mojom::VideoDetectorObserverRequest());
notifier_.reset(new VideoActivityNotifier(detector_.get()));
}

Expand Down
123 changes: 15 additions & 108 deletions ash/wm/video_detector.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,72 +15,13 @@

namespace ash {

const int VideoDetector::kMinUpdateWidth = 333;
const int VideoDetector::kMinUpdateHeight = 250;
const int VideoDetector::kMinFramesPerSecond = 15;
const int VideoDetector::kVideoTimeoutMs = 1000;
const int VideoDetector::kMinVideoDurationMs = 3000;

// Stores information about updates to a window and determines whether it's
// likely that a video is playing in it.
class VideoDetector::WindowInfo {
public:
WindowInfo() : buffer_start_(0), buffer_size_(0) {}

// Handles an update within a window, returning true if it appears that
// video is currently playing in the window.
bool RecordUpdateAndCheckForVideo(const gfx::Rect& region,
base::TimeTicks now) {
if (region.width() < kMinUpdateWidth || region.height() < kMinUpdateHeight)
return false;

// If the buffer is full, drop the first timestamp.
if (buffer_size_ == static_cast<size_t>(kMinFramesPerSecond)) {
buffer_start_ = (buffer_start_ + 1) % kMinFramesPerSecond;
buffer_size_--;
}

update_times_[(buffer_start_ + buffer_size_) % kMinFramesPerSecond] = now;
buffer_size_++;

const bool in_video =
(buffer_size_ == static_cast<size_t>(kMinFramesPerSecond)) &&
((now - update_times_[buffer_start_]).InSecondsF() <= 1.0);

if (in_video && video_start_time_.is_null())
video_start_time_ = update_times_[buffer_start_];
else if (!in_video && !video_start_time_.is_null())
video_start_time_ = base::TimeTicks();

const base::TimeDelta elapsed = now - video_start_time_;
return in_video &&
elapsed >= base::TimeDelta::FromMilliseconds(kMinVideoDurationMs);
}

private:
// Circular buffer containing update times of the last (up to
// |kMinFramesPerSecond|) video-sized updates to this window.
base::TimeTicks update_times_[kMinFramesPerSecond];

// Time at which the current sequence of updates that looks like video
// started. Empty if video isn't currently playing.
base::TimeTicks video_start_time_;

// Index into |update_times_| of the oldest update.
size_t buffer_start_;

// Number of updates stored in |update_times_|.
size_t buffer_size_;

DISALLOW_COPY_AND_ASSIGN(WindowInfo);
};

VideoDetector::VideoDetector()
VideoDetector::VideoDetector(viz::mojom::VideoDetectorObserverRequest request)
: state_(State::NOT_PLAYING),
video_is_playing_(false),
window_observer_manager_(this),
scoped_session_observer_(this),
is_shutting_down_(false) {
is_shutting_down_(false),
binding_(this, std::move(request)) {
aura::Env::GetInstance()->AddObserver(this);
Shell::Get()->AddShellObserver(this);
}
Expand All @@ -98,34 +39,10 @@ void VideoDetector::RemoveObserver(Observer* observer) {
observers_.RemoveObserver(observer);
}

bool VideoDetector::TriggerTimeoutForTest() {
if (!video_inactive_timer_.IsRunning())
return false;

video_inactive_timer_.Stop();
HandleVideoInactive();
return true;
}

void VideoDetector::OnWindowInitialized(aura::Window* window) {
window_observer_manager_.Add(window);
}

void VideoDetector::OnDelegatedFrameDamage(
aura::Window* window,
const gfx::Rect& damage_rect_in_dip) {
if (is_shutting_down_)
return;
std::unique_ptr<WindowInfo>& info = window_infos_[window];
if (!info.get())
info.reset(new WindowInfo);

base::TimeTicks now =
!now_for_test_.is_null() ? now_for_test_ : base::TimeTicks::Now();
if (info->RecordUpdateAndCheckForVideo(damage_rect_in_dip, now))
HandleVideoActivity(window, now);
}

void VideoDetector::OnWindowDestroying(aura::Window* window) {
if (fullscreen_root_windows_.count(window)) {
window_observer_manager_.Remove(window);
Expand All @@ -135,7 +52,6 @@ void VideoDetector::OnWindowDestroying(aura::Window* window) {
}

void VideoDetector::OnWindowDestroyed(aura::Window* window) {
window_infos_.erase(window);
window_observer_manager_.Remove(window);
}

Expand All @@ -159,27 +75,6 @@ void VideoDetector::OnFullscreenStateChanged(bool is_fullscreen,
}
}

void VideoDetector::HandleVideoActivity(aura::Window* window,
base::TimeTicks now) {
if (!window->IsVisible())
return;

gfx::Rect root_bounds = window->GetRootWindow()->bounds();
if (!window->GetBoundsInRootWindow().Intersects(root_bounds))
return;

video_is_playing_ = true;
video_inactive_timer_.Start(
FROM_HERE, base::TimeDelta::FromMilliseconds(kVideoTimeoutMs), this,
&VideoDetector::HandleVideoInactive);
UpdateState();
}

void VideoDetector::HandleVideoInactive() {
video_is_playing_ = false;
UpdateState();
}

void VideoDetector::UpdateState() {
State new_state = State::NOT_PLAYING;
if (video_is_playing_) {
Expand All @@ -194,4 +89,16 @@ void VideoDetector::UpdateState() {
}
}

void VideoDetector::OnVideoActivityStarted() {
if (is_shutting_down_)
return;
video_is_playing_ = true;
UpdateState();
}

void VideoDetector::OnVideoActivityEnded() {
video_is_playing_ = false;
UpdateState();
}

} // namespace ash
Loading

0 comments on commit 3fb310d

Please sign in to comment.