/media/gpu/android/surface_chooser_helper.cc
C++ | 171 lines | 110 code | 28 blank | 33 comment | 13 complexity | b1cdd867c3f44b83564f5167208e19d8 MD5 | raw file
Possible License(s): Apache-2.0, LGPL-2.0, BSD-2-Clause, LGPL-2.1, MPL-2.0, 0BSD, EPL-1.0, MPL-2.0-no-copyleft-exception, GPL-2.0, BitTorrent-1.0, CPL-1.0, LGPL-3.0, Unlicense, BSD-3-Clause, CC0-1.0, JSON, MIT, GPL-3.0, CC-BY-SA-3.0, AGPL-1.0
- // Copyright 2017 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 "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::TimeDelta::FromSeconds(5);
- } // namespace
- SurfaceChooserHelper::SurfaceChooserHelper(
- std::unique_ptr<AndroidVideoSurfaceChooser> surface_chooser,
- bool is_overlay_required,
- bool promote_aggressively,
- 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_aggressively = promote_aggressively;
- 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(
- base::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(base::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