1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
media / gpu / android / surface_chooser_helper.cc [blame]
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "media/gpu/android/surface_chooser_helper.h"
#include <memory>
#include "base/time/default_tick_clock.h"
#include "base/time/tick_clock.h"
#include "media/gpu/android/android_video_surface_chooser.h"
#include "media/gpu/android/promotion_hint_aggregator_impl.h"
namespace media {
namespace {
// Number of frames to defer overlays for when entering fullscreen. This lets
// blink relayout settle down a bit. If overlay positions were synchronous,
// then we wouldn't need this.
enum { kFrameDelayForFullscreenLayout = 15 };
// How often do we let the surface chooser try for an overlay? While we'll
// retry if some relevant state changes on our side (e.g., fullscreen state),
// there's plenty of state that we don't know about (e.g., power efficiency,
// memory pressure => cancelling an old overlay, etc.). We just let the chooser
// retry every once in a while for those things.
constexpr base::TimeDelta RetryChooserTimeout = base::Seconds(5);
} // namespace
SurfaceChooserHelper::SurfaceChooserHelper(
std::unique_ptr<AndroidVideoSurfaceChooser> surface_chooser,
bool is_overlay_required,
bool promote_secure_only,
bool always_use_texture_owner,
std::unique_ptr<PromotionHintAggregator> promotion_hint_aggregator,
const base::TickClock* tick_clock)
: surface_chooser_(std::move(surface_chooser)),
is_overlay_required_(is_overlay_required),
promotion_hint_aggregator_(
promotion_hint_aggregator
? std::move(promotion_hint_aggregator)
: std::make_unique<PromotionHintAggregatorImpl>()),
tick_clock_(tick_clock ? tick_clock
: base::DefaultTickClock::GetInstance()) {
surface_chooser_state_.is_required = is_overlay_required_;
surface_chooser_state_.promote_secure_only = promote_secure_only;
surface_chooser_state_.always_use_texture_owner = always_use_texture_owner;
}
SurfaceChooserHelper::~SurfaceChooserHelper() {}
void SurfaceChooserHelper::SetSecureSurfaceMode(SecureSurfaceMode mode) {
bool is_secure = false;
requires_secure_video_surface_ = false;
switch (mode) {
case SecureSurfaceMode::kInsecure:
break;
case SecureSurfaceMode::kRequested:
is_secure = true;
break;
case SecureSurfaceMode::kRequired:
is_secure = true;
requires_secure_video_surface_ = true;
break;
}
surface_chooser_state_.is_secure = is_secure;
surface_chooser_state_.is_required =
requires_secure_video_surface_ || is_overlay_required_;
}
void SurfaceChooserHelper::SetIsFullscreen(bool is_fullscreen) {
// TODO(liberato): AVDA previously only set is_expecting_relayout when
// getting overlay info, not when checking fullscreen for the first time.
// This might affect pre-M devices. I think the pre-M path doesn't care.
if (is_fullscreen && !surface_chooser_state_.is_fullscreen) {
// It would be nice if we could just delay until we get a hint from an
// overlay that's "in fullscreen" in the sense that the CompositorFrame it
// came from had some flag set to indicate that the renderer was in
// fullscreen mode when it was generated. However, even that's hard, since
// there's no real connection between "renderer finds out about fullscreen"
// and "blink has completed layouts for it". The latter is what we really
// want to know.
surface_chooser_state_.is_expecting_relayout = true;
hints_until_clear_relayout_flag_ = kFrameDelayForFullscreenLayout;
}
surface_chooser_state_.is_fullscreen = is_fullscreen;
}
void SurfaceChooserHelper::SetVideoRotation(VideoRotation video_rotation) {
surface_chooser_state_.video_rotation = video_rotation;
}
void SurfaceChooserHelper::SetIsPersistentVideo(bool is_persistent_video) {
surface_chooser_state_.is_persistent_video = is_persistent_video;
}
void SurfaceChooserHelper::UpdateChooserState(
std::optional<AndroidOverlayFactoryCB> new_factory) {
surface_chooser_->UpdateState(std::move(new_factory), surface_chooser_state_);
}
void SurfaceChooserHelper::NotifyPromotionHintAndUpdateChooser(
const PromotionHintAggregator::Hint& hint,
bool is_using_overlay) {
bool update_state = false;
promotion_hint_aggregator_->NotifyPromotionHint(hint);
// If we're expecting a full screen relayout, then also use this hint as a
// notification that another frame has happened.
if (hints_until_clear_relayout_flag_ > 0) {
hints_until_clear_relayout_flag_--;
if (hints_until_clear_relayout_flag_ == 0) {
surface_chooser_state_.is_expecting_relayout = false;
update_state = true;
}
}
surface_chooser_state_.initial_position = hint.screen_rect;
bool promotable = promotion_hint_aggregator_->IsSafeToPromote();
if (promotable != surface_chooser_state_.is_compositor_promotable) {
surface_chooser_state_.is_compositor_promotable = promotable;
update_state = true;
}
// If we've been provided with enough new frames, then update the state even
// if it hasn't changed. This lets |surface_chooser_| retry for an overlay.
// It's especially helpful for power-efficient overlays, since we don't know
// when an overlay becomes power efficient. It also helps retry any failure
// that's not accompanied by a state change, such as if android destroys the
// overlay asynchronously for a transient reason.
//
// If we're already using an overlay, then there's no need to do this.
base::TimeTicks now = tick_clock_->NowTicks();
if (!is_using_overlay &&
now - most_recent_chooser_retry_ >= RetryChooserTimeout) {
update_state = true;
}
if (update_state) {
most_recent_chooser_retry_ = now;
UpdateChooserState(std::optional<AndroidOverlayFactoryCB>());
}
}
SurfaceChooserHelper::FrameInformation
SurfaceChooserHelper::ComputeFrameInformation(bool is_using_overlay) {
if (!is_using_overlay) {
// Not an overlay.
return surface_chooser_state_.is_secure
? FrameInformation::NON_OVERLAY_L3
: FrameInformation::NON_OVERLAY_INSECURE;
}
// Overlay.
if (surface_chooser_state_.is_secure) {
return surface_chooser_state_.is_required ? FrameInformation::OVERLAY_L1
: FrameInformation::OVERLAY_L3;
}
return surface_chooser_state_.is_fullscreen
? FrameInformation::OVERLAY_INSECURE_PLAYER_ELEMENT_FULLSCREEN
: FrameInformation::OVERLAY_INSECURE_NON_PLAYER_ELEMENT_FULLSCREEN;
}
} // namespace media