blob: 62ea0fc4a904b8ef5648a4caebd3a283347fa4ec [file] [log] [blame]
[email protected]85a37afd2013-05-30 22:51:151// Copyright 2013 The Chromium Authors. All rights reserved.
[email protected]891acc92009-04-27 19:56:412// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
[email protected]ec9212f2008-12-18 21:40:364
acolwell9e0840d2014-09-06 19:01:325#include "media/blink/webmediaplayer_impl.h"
[email protected]8931c41a2009-07-07 17:31:496
[email protected]c2a45e242013-02-15 20:24:587#include <algorithm>
mateuszs3371ab02015-04-24 13:20:238#include <cmath>
[email protected]47b06ceb2010-08-04 22:41:119#include <limits>
Gyuyoung Kim62a5de42018-01-10 09:48:4210#include <memory>
guidouc7babef2015-10-22 00:42:3511#include <string>
dcheng652f5ff2015-12-27 08:54:0012#include <utility>
[email protected]47b06ceb2010-08-04 22:41:1113
[email protected]08273c7b2011-09-17 00:33:5114#include "base/bind.h"
sandersd1c0bba02016-03-04 23:14:0815#include "base/bind_helpers.h"
[email protected]2041cf342010-02-19 03:15:5916#include "base/callback.h"
[email protected]7502ef12014-01-25 01:19:2717#include "base/callback_helpers.h"
sandersd1e49fb62015-12-12 01:18:0618#include "base/command_line.h"
[email protected]ca04095f2014-02-07 10:23:5619#include "base/debug/alias.h"
[email protected]926f8fd2013-04-12 20:27:5320#include "base/debug/crash_logging.h"
fdoraydb3ef7d2016-06-09 15:42:3821#include "base/location.h"
Dale Curtis3899090ea2018-01-12 00:10:3522#include "base/metrics/histogram_functions.h"
asvitkine30330812016-08-30 04:01:0823#include "base/metrics/histogram_macros.h"
acolwellb4034942014-08-28 15:42:4324#include "base/single_thread_task_runner.h"
servolka233f832016-06-10 20:39:0425#include "base/strings/string_number_conversions.h"
Gabriel Charette44db1422018-08-06 11:19:3326#include "base/task/post_task.h"
wdzierzanowskifd4cd91c52015-12-02 23:50:2027#include "base/task_runner_util.h"
gabba14a442016-05-11 20:10:2028#include "base/threading/thread_task_runner_handle.h"
ssid9525f4672015-01-28 12:13:1529#include "base/trace_event/trace_event.h"
sandersd1e49fb62015-12-12 01:18:0630#include "build/build_config.h"
[email protected]21c3f7502013-03-23 03:29:5131#include "cc/layers/video_layer.h"
CJ DiMeglioc60a5cf2017-09-27 20:08:4132#include "components/viz/common/gpu/context_provider.h"
[email protected]e4fc09e2012-04-06 03:17:4433#include "media/audio/null_audio_sink.h"
[email protected]2eccbed2014-01-10 05:15:5334#include "media/base/bind_to_current_loop.h"
xhwang0ad11e512014-11-25 23:43:0935#include "media/base/cdm_context.h"
John Rummelldb5a7ef2018-05-16 00:28:0136#include "media/base/encryption_scheme.h"
[email protected]32da1002010-03-03 21:57:3537#include "media/base/limits.h"
zqzhang5d8eab72016-08-26 20:34:3038#include "media/base/media_content_type.h"
[email protected]090f7312011-08-05 23:26:4039#include "media/base/media_log.h"
sandersd1e49fb62015-12-12 01:18:0640#include "media/base/media_switches.h"
tguilbert25a4d112016-10-13 21:56:5141#include "media/base/media_url_demuxer.h"
[email protected]8a561062013-11-22 01:19:3142#include "media/base/text_renderer.h"
watk9f9dfdc92015-09-04 21:33:2943#include "media/base/timestamp_constants.h"
[email protected]e81283bb2010-08-31 18:01:2144#include "media/base/video_frame.h"
acolwell9e0840d2014-09-06 19:01:3245#include "media/blink/texttrack_impl.h"
Chris Cunninghamd9df58e2017-08-29 00:04:2346#include "media/blink/video_decode_stats_reporter.h"
dalecurtis04bdb582016-08-17 22:15:2347#include "media/blink/watch_time_reporter.h"
acolwell9e0840d2014-09-06 19:01:3248#include "media/blink/webaudiosourceprovider_impl.h"
xhwang97de4202014-11-25 08:44:0149#include "media/blink/webcontentdecryptionmodule_impl.h"
acolwell9e0840d2014-09-06 19:01:3250#include "media/blink/webinbandtexttrack_impl.h"
51#include "media/blink/webmediaplayer_delegate.h"
acolwell9e0840d2014-09-06 19:01:3252#include "media/blink/webmediaplayer_util.h"
53#include "media/blink/webmediasource_impl.h"
[email protected]efe7cd22012-09-12 23:55:0154#include "media/filters/chunk_demuxer.h"
[email protected]ddbc6ff2013-04-19 15:28:3355#include "media/filters/ffmpeg_demuxer.h"
Scott Violeta35f9a42018-03-22 22:00:4456#include "media/media_buildflags.h"
sawtellee19d11aa2018-08-10 03:47:5057#include "third_party/blink/public/common/picture_in_picture/picture_in_picture_control_info.h"
Blink Reformata30d4232018-04-07 15:31:0658#include "third_party/blink/public/platform/web_encrypted_media_types.h"
59#include "third_party/blink/public/platform/web_localized_string.h"
60#include "third_party/blink/public/platform/web_media_player_client.h"
61#include "third_party/blink/public/platform/web_media_player_encrypted_media_client.h"
62#include "third_party/blink/public/platform/web_media_player_source.h"
63#include "third_party/blink/public/platform/web_media_source.h"
64#include "third_party/blink/public/platform/web_rect.h"
65#include "third_party/blink/public/platform/web_runtime_features.h"
66#include "third_party/blink/public/platform/web_security_origin.h"
67#include "third_party/blink/public/platform/web_size.h"
68#include "third_party/blink/public/platform/web_string.h"
69#include "third_party/blink/public/platform/web_surface_layer_bridge.h"
70#include "third_party/blink/public/platform/web_url.h"
71#include "third_party/blink/public/web/web_document.h"
72#include "third_party/blink/public/web/web_frame.h"
73#include "third_party/blink/public/web/web_local_frame.h"
74#include "third_party/blink/public/web/web_user_gesture_indicator.h"
75#include "third_party/blink/public/web/web_view.h"
[email protected]b3f2b912009-04-09 16:18:5276
dalecurtisea27a3ed2016-06-24 01:41:3077#if defined(OS_ANDROID)
78#include "media/base/android/media_codec_util.h"
79#endif
80
[email protected]180ef242013-11-07 06:50:4681using blink::WebMediaPlayer;
82using blink::WebRect;
83using blink::WebSize;
84using blink::WebString;
hubbed5f36882016-01-15 22:40:3785using gpu::gles2::GLES2Interface;
86
danakj365175c2016-02-06 00:37:3787#define STATIC_ASSERT_ENUM(a, b) \
88 static_assert(static_cast<int>(a) == static_cast<int>(b), \
89 "mismatching enums: " #a)
90
hubbed5f36882016-01-15 22:40:3791namespace media {
[email protected]ec9212f2008-12-18 21:40:3692
[email protected]8931c41a2009-07-07 17:31:4993namespace {
94
hubbed5f36882016-01-15 22:40:3795void SetSinkIdOnMediaThread(scoped_refptr<WebAudioSourceProviderImpl> sink,
96 const std::string& device_id,
olka68b69392016-04-01 11:42:1297 const OutputDeviceStatusCB& callback) {
Max Morinf506af592018-04-17 12:23:3298 sink->SwitchOutputDevice(device_id, callback);
guidouc7babef2015-10-22 00:42:3599}
100
Luke Halliwell7a8a8982018-07-25 01:07:05101bool IsBackgroundSuspendEnabled(WebMediaPlayerDelegate* delegate) {
102 // TODO(crbug.com/867146): remove these switches.
103 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
104 switches::kDisableMediaSuspend))
105 return false;
106 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
107 switches::kEnableMediaSuspend))
108 return true;
109
110 return delegate->IsBackgroundMediaSuspendEnabled();
dalecurtis0431cbf2016-03-12 01:19:43111}
112
avayvod48a8be52016-08-04 19:52:50113bool IsResumeBackgroundVideosEnabled() {
114 return base::FeatureList::IsEnabled(kResumeBackgroundVideo);
115}
116
avayvod39c102402016-11-23 21:43:13117bool IsBackgroundVideoTrackOptimizationEnabled() {
118 return base::FeatureList::IsEnabled(kBackgroundVideoTrackOptimization);
119}
120
avayvod01201332017-04-14 00:27:15121bool IsBackgroundVideoPauseOptimizationEnabled() {
122 return base::FeatureList::IsEnabled(kBackgroundVideoPauseOptimization);
123}
124
avayvod82729272017-05-29 21:58:39125bool IsNewRemotePlaybackPipelineEnabled() {
126 return base::FeatureList::IsEnabled(kNewRemotePlaybackPipeline);
127}
128
sandersd50a635e2016-04-04 22:50:09129bool IsNetworkStateError(blink::WebMediaPlayer::NetworkState state) {
Blink Reformat1c4d759e2017-04-09 16:34:54130 bool result = state == blink::WebMediaPlayer::kNetworkStateFormatError ||
131 state == blink::WebMediaPlayer::kNetworkStateNetworkError ||
132 state == blink::WebMediaPlayer::kNetworkStateDecodeError;
133 DCHECK_EQ(state > blink::WebMediaPlayer::kNetworkStateLoaded, result);
sandersd50a635e2016-04-04 22:50:09134 return result;
135}
136
sandersd2c478422016-08-02 01:19:25137gfx::Size GetRotatedVideoSize(VideoRotation rotation, gfx::Size natural_size) {
138 if (rotation == VIDEO_ROTATION_90 || rotation == VIDEO_ROTATION_270)
139 return gfx::Size(natural_size.height(), natural_size.width());
140 return natural_size;
141}
142
Xiaohan Wangf63505d2017-10-21 08:00:53143void RecordEncryptedEvent(bool encrypted_event_fired) {
144 UMA_HISTOGRAM_BOOLEAN("Media.EME.EncryptedEvent", encrypted_event_fired);
145}
146
sandersd35d2c3f2017-01-14 02:04:42147// How much time must have elapsed since loading last progressed before we
148// assume that the decoder will have had time to complete preroll.
149constexpr base::TimeDelta kPrerollAttemptTimeout =
watkd026f792016-11-05 00:28:51150 base::TimeDelta::FromSeconds(3);
151
Matt Wolenetz6010f6c2017-10-18 00:44:36152// Maximum number, per-WMPI, of media logs of playback rate changes.
153constexpr int kMaxNumPlaybackRateLogs = 10;
154
Xiangjun Zhang5e20cba42018-01-10 19:54:56155blink::WebLocalizedString::Name GetSwitchToLocalMessage(
156 MediaObserverClient::ReasonToSwitchToLocal reason) {
157 switch (reason) {
158 case MediaObserverClient::ReasonToSwitchToLocal::NORMAL:
159 return blink::WebLocalizedString::kMediaRemotingStopText;
160 case MediaObserverClient::ReasonToSwitchToLocal::POOR_PLAYBACK_QUALITY:
161 return blink::WebLocalizedString::kMediaRemotingStopByPlaybackQualityText;
162 case MediaObserverClient::ReasonToSwitchToLocal::PIPELINE_ERROR:
163 return blink::WebLocalizedString::kMediaRemotingStopByErrorText;
164 case MediaObserverClient::ReasonToSwitchToLocal::ROUTE_TERMINATED:
165 return blink::WebLocalizedString::kMediaRemotingStopNoText;
166 }
167 NOTREACHED();
168 // To suppress compiler warning on Windows.
169 return blink::WebLocalizedString::kMediaRemotingStopNoText;
170}
171
John Rummelldb5a7ef2018-05-16 00:28:01172// These values are persisted to UMA. Entries should not be renumbered and
173// numeric values should never be reused.
174// TODO(crbug.com/825041): This should use EncryptionMode when kUnencrypted
175// removed.
176enum class EncryptionSchemeUMA { kCenc = 0, kCbcs = 1, kCount };
177
178EncryptionSchemeUMA DetermineEncryptionSchemeUMAValue(
179 const EncryptionScheme& encryption_scheme) {
180 if (encryption_scheme.mode() == EncryptionScheme::CIPHER_MODE_AES_CBC)
181 return EncryptionSchemeUMA::kCbcs;
182
183 DCHECK_EQ(encryption_scheme.mode(), EncryptionScheme::CIPHER_MODE_AES_CTR);
184 return EncryptionSchemeUMA::kCenc;
185}
186
Pavel Feldman023c3e62018-08-28 17:59:47187#if BUILDFLAG(ENABLE_FFMPEG)
Dale Curtisb8139f72018-08-27 23:28:48188// Returns true if |url| represents (or is likely to) a local file.
189bool IsLocalFile(const GURL& url) {
190 return url.SchemeIsFile() || url.SchemeIsFileSystem() ||
191 url.SchemeIs(url::kContentScheme) ||
192 url.SchemeIs(url::kContentIDScheme) ||
193 url.SchemeIs("chrome-extension");
194}
Pavel Feldman023c3e62018-08-28 17:59:47195#endif
Dale Curtisb8139f72018-08-27 23:28:48196
[email protected]8931c41a2009-07-07 17:31:49197} // namespace
198
[email protected]6683e1b2014-04-10 01:45:38199class BufferedDataSourceHostImpl;
200
Blink Reformat1c4d759e2017-04-09 16:34:54201STATIC_ASSERT_ENUM(WebMediaPlayer::kCORSModeUnspecified,
danakj365175c2016-02-06 00:37:37202 UrlData::CORS_UNSPECIFIED);
Blink Reformat1c4d759e2017-04-09 16:34:54203STATIC_ASSERT_ENUM(WebMediaPlayer::kCORSModeAnonymous, UrlData::CORS_ANONYMOUS);
204STATIC_ASSERT_ENUM(WebMediaPlayer::kCORSModeUseCredentials,
danakj365175c2016-02-06 00:37:37205 UrlData::CORS_USE_CREDENTIALS);
[email protected]a5a01102012-06-06 17:01:24206
[email protected]5b5bb9d2010-10-22 19:57:36207WebMediaPlayerImpl::WebMediaPlayerImpl(
[email protected]35b2a972014-04-04 15:50:22208 blink::WebLocalFrame* frame,
[email protected]180ef242013-11-07 06:50:46209 blink::WebMediaPlayerClient* client,
srirama.m26f864d02015-07-14 05:21:46210 blink::WebMediaPlayerEncryptedMediaClient* encrypted_client,
tguilbert1bb1c782017-01-23 21:15:11211 WebMediaPlayerDelegate* delegate,
tguilbert70d2a00a2017-04-25 00:30:44212 std::unique_ptr<RendererFactorySelector> renderer_factory_selector,
Alok Priyadarshi7166d4d2017-07-29 04:04:25213 UrlIndex* url_index,
CJ DiMegliod7ac6772017-11-10 00:19:06214 std::unique_ptr<VideoFrameCompositor> compositor,
dalecurtis9cddc0b2017-04-19 21:23:38215 std::unique_ptr<WebMediaPlayerParams> params)
[email protected]f6af7592014-02-28 10:09:11216 : frame_(frame),
Alexander Timin310368112017-09-13 10:01:44217 main_task_runner_(
218 frame->GetTaskRunner(blink::TaskType::kMediaElementEvent)),
dalecurtis9cddc0b2017-04-19 21:23:38219 media_task_runner_(params->media_task_runner()),
220 worker_task_runner_(params->worker_task_runner()),
221 media_log_(params->take_media_log()),
sandersd1c0bba02016-03-04 23:14:08222 pipeline_controller_(
Hajime Hoshidb0761a42018-01-18 08:10:19223 std::make_unique<PipelineImpl>(media_task_runner_,
224 main_task_runner_,
225 media_log_.get()),
sandersd1c0bba02016-03-04 23:14:08226 base::Bind(&WebMediaPlayerImpl::CreateRenderer,
227 base::Unretained(this)),
228 base::Bind(&WebMediaPlayerImpl::OnPipelineSeeked, AsWeakPtr()),
229 base::Bind(&WebMediaPlayerImpl::OnPipelineSuspended, AsWeakPtr()),
avayvod2135a642017-01-13 00:17:14230 base::Bind(&WebMediaPlayerImpl::OnBeforePipelineResume, AsWeakPtr()),
231 base::Bind(&WebMediaPlayerImpl::OnPipelineResumed, AsWeakPtr()),
alokp967c902452016-05-06 05:21:37232 base::Bind(&WebMediaPlayerImpl::OnError, AsWeakPtr())),
[email protected]5badb082010-06-11 17:40:15233 client_(client),
srirama.m26f864d02015-07-14 05:21:46234 encrypted_client_(encrypted_client),
[email protected]baff4512011-10-19 18:21:07235 delegate_(delegate),
dalecurtis9cddc0b2017-04-19 21:23:38236 defer_load_cb_(params->defer_load_cb()),
dalecurtis9cddc0b2017-04-19 21:23:38237 adjust_allocated_memory_cb_(params->adjust_allocated_memory_cb()),
tzik2c963b872017-12-07 06:57:24238 tick_clock_(base::DefaultTickClock::GetInstance()),
hubbeb2d3efd2017-05-05 23:26:38239 buffered_data_source_host_(
240 base::Bind(&WebMediaPlayerImpl::OnProgress, AsWeakPtr()),
tzik2c963b872017-12-07 06:57:24241 tick_clock_),
hubbe5f0ad43b2015-12-14 20:57:26242 url_index_(url_index),
CJ DiMeglioc60a5cf2017-09-27 20:08:41243 context_provider_(params->context_provider()),
CJ DiMegliod7ac6772017-11-10 00:19:06244 vfc_task_runner_(params->video_frame_compositor_task_runner()),
245 compositor_(std::move(compositor)),
hubbed5f36882016-01-15 22:40:37246#if defined(OS_ANDROID) // WMPI_CAST
CJ DiMeglioc60a5cf2017-09-27 20:08:41247 cast_impl_(this, client_, params->context_provider()),
hubbed5f36882016-01-15 22:40:37248#endif
tguilbert70d2a00a2017-04-25 00:30:44249 renderer_factory_selector_(std::move(renderer_factory_selector)),
dalecurtis9cddc0b2017-04-19 21:23:38250 observer_(params->media_observer()),
avayvod590011e32017-01-20 02:01:00251 max_keyframe_distance_to_disable_background_video_(
dalecurtis9cddc0b2017-04-19 21:23:38252 params->max_keyframe_distance_to_disable_background_video()),
avayvode85ec422017-04-14 00:11:33253 max_keyframe_distance_to_disable_background_video_mse_(
dalecurtis9cddc0b2017-04-19 21:23:38254 params->max_keyframe_distance_to_disable_background_video_mse()),
servolkf94b4602017-01-31 16:44:27255 enable_instant_source_buffer_gc_(
dalecurtis9cddc0b2017-04-19 21:23:38256 params->enable_instant_source_buffer_gc()),
shaktisahu24189c12017-03-11 17:42:55257 embedded_media_experience_enabled_(
liberato2ff93ad2017-05-17 07:28:24258 params->embedded_media_experience_enabled()),
CJ DiMegliodb88a672018-02-22 18:48:14259 surface_layer_for_video_enabled_(params->use_surface_layer_for_video()),
CJ DiMeglio96c18b692018-07-04 03:39:06260 create_bridge_callback_(params->create_bridge_callback()),
liberato2ff93ad2017-05-17 07:28:24261 request_routing_token_cb_(params->request_routing_token_cb()),
Dale Curtis1adbe6a2017-08-02 02:09:13262 overlay_routing_token_(OverlayInfo::RoutingToken()),
Mounir Lamourife756e32018-05-22 23:19:08263 media_metrics_provider_(params->take_metrics_provider()) {
xhwang51139732017-02-24 19:36:08264 DVLOG(1) << __func__;
dalecurtis83266c72015-10-29 18:43:20265 DCHECK(!adjust_allocated_memory_cb_.is_null());
tguilbert70d2a00a2017-04-25 00:30:44266 DCHECK(renderer_factory_selector_);
servolkef1e5ef2016-03-25 04:55:26267 DCHECK(client_);
tguilbert1bb1c782017-01-23 21:15:11268 DCHECK(delegate_);
dalecurtis83266c72015-10-29 18:43:20269
[email protected]c8d574722017-08-30 20:53:43270 // If we're supposed to force video overlays, then make sure that they're
271 // enabled all the time.
272 always_enable_overlays_ = base::CommandLine::ForCurrentProcess()->HasSwitch(
tsunghungee562e92016-07-20 18:03:31273 switches::kForceVideoOverlays);
274
liberato2ff93ad2017-05-17 07:28:24275 if (base::FeatureList::IsEnabled(media::kOverlayFullscreenVideo)) {
276 bool use_android_overlay =
277 base::FeatureList::IsEnabled(media::kUseAndroidOverlay);
278 overlay_mode_ = use_android_overlay ? OverlayMode::kUseAndroidOverlay
279 : OverlayMode::kUseContentVideoView;
280 } else {
281 overlay_mode_ = OverlayMode::kNoOverlays;
282 }
ampea73f792017-01-19 04:05:39283
tguilbert1bb1c782017-01-23 21:15:11284 delegate_id_ = delegate_->AddObserver(this);
285 delegate_->SetIdle(delegate_id_, true);
sandersd1e49fb62015-12-12 01:18:06286
dalecurtis2cff7f372017-05-24 08:30:08287 media_log_->AddEvent(media_log_->CreateCreatedEvent(
288 url::Origin(frame_->GetSecurityOrigin()).GetURL().spec()));
sandersd72683f252017-07-07 23:20:46289 media_log_->SetStringProperty("frame_url",
290 frame_->GetDocument().Url().GetString().Utf8());
291 media_log_->SetStringProperty("frame_title",
292 frame_->GetDocument().Title().Utf8());
[email protected]4e6be3f2009-05-07 02:24:44293
dalecurtis9cddc0b2017-04-19 21:23:38294 if (params->initial_cdm())
295 SetCdm(params->initial_cdm());
xhwang0ad11e512014-11-25 23:43:09296
Xiaohan Wangf63505d2017-10-21 08:00:53297 // Report a false "EncrytpedEvent" here as a baseline.
298 RecordEncryptedEvent(false);
299
xhwangf94a634d2014-10-22 22:07:27300 // TODO(xhwang): When we use an external Renderer, many methods won't work,
xhwang6fa356202014-12-11 00:44:12301 // e.g. GetCurrentFrameFromCompositor(). See http://crbug.com/434861
dalecurtis9cddc0b2017-04-19 21:23:38302 audio_source_provider_ = new WebAudioSourceProviderImpl(
303 params->audio_renderer_sink(), media_log_.get());
xjz4e5d4bf32017-02-15 21:26:35304
305 if (observer_)
306 observer_->SetClient(this);
Hajime Hoshi8bb37dc2017-12-19 09:35:10307
308 memory_usage_reporting_timer_.SetTaskRunner(
Hajime Hoshib5a26ee2018-05-14 12:47:51309 frame_->GetTaskRunner(blink::TaskType::kInternalMedia));
[email protected]ec9212f2008-12-18 21:40:36310}
311
[email protected]4e6be3f2009-05-07 02:24:44312WebMediaPlayerImpl::~WebMediaPlayerImpl() {
xhwang51139732017-02-24 19:36:08313 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:43314 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53315
xhwang51139732017-02-24 19:36:08316 if (set_cdm_result_) {
317 DVLOG(2) << "Resolve pending SetCdm() when media player is destroyed.";
Blink Reformat1c4d759e2017-04-09 16:34:54318 set_cdm_result_->Complete();
xhwang51139732017-02-24 19:36:08319 set_cdm_result_.reset();
320 }
321
alokp1116967f2016-06-11 17:30:56322 suppress_destruction_errors_ = true;
tguilbert1bb1c782017-01-23 21:15:11323
324 delegate_->PlayerGone(delegate_id_);
325 delegate_->RemoveObserver(delegate_id_);
[email protected]baff4512011-10-19 18:21:07326
dalecurtis04bdb582016-08-17 22:15:23327 // Finalize any watch time metrics before destroying the pipeline.
328 watch_time_reporter_.reset();
329
tguilbert350936ff2017-02-24 05:39:27330 // The underlying Pipeline must be stopped before it is destroyed.
331 pipeline_controller_.Stop();
[email protected]f6af7592014-02-28 10:09:11332
dalecurtis83266c72015-10-29 18:43:20333 if (last_reported_memory_usage_)
334 adjust_allocated_memory_cb_.Run(-last_reported_memory_usage_);
335
dalecurtise1edb312016-06-22 02:33:21336 // Destruct compositor resources in the proper order.
danakj8d204a42018-05-18 18:05:35337 client_->SetCcLayer(nullptr);
CJ DiMeglio2302d202017-08-31 08:38:04338
Xiangjun Zhang5e20cba42018-01-10 19:54:56339 client_->MediaRemotingStopped(
340 blink::WebLocalizedString::kMediaRemotingStopNoText);
Xiangjun Zhang87299142017-09-13 20:35:03341
danakj25f030112018-05-11 18:26:54342 if (!surface_layer_for_video_enabled_ && video_layer_) {
343 video_layer_->StopUsingProvider();
lethalantidote7f6009d2017-07-07 21:47:39344 }
CJ DiMeglio2302d202017-08-31 08:38:04345
346 vfc_task_runner_->DeleteSoon(FROM_HERE, std::move(compositor_));
xhwangea8bb3562015-06-08 21:18:37347
Matt Wolenetz95af6362018-01-04 20:23:42348 if (chunk_demuxer_) {
349 // Continue destruction of |chunk_demuxer_| on the |media_task_runner_| to
350 // avoid racing other pending tasks on |chunk_demuxer_| on that runner while
351 // not further blocking |main_task_runner_| to perform the destruction.
352 media_task_runner_->PostTask(
353 FROM_HERE, base::BindOnce(&WebMediaPlayerImpl::DemuxerDestructionHelper,
354 media_task_runner_, std::move(demuxer_)));
355 }
356
xhwangea8bb3562015-06-08 21:18:37357 media_log_->AddEvent(
358 media_log_->CreateEvent(MediaLogEvent::WEBMEDIAPLAYER_DESTROYED));
[email protected]ec9212f2008-12-18 21:40:36359}
360
Matt Wolenetz95af6362018-01-04 20:23:42361// static
362void WebMediaPlayerImpl::DemuxerDestructionHelper(
363 scoped_refptr<base::SingleThreadTaskRunner> task_runner,
364 std::unique_ptr<Demuxer> demuxer) {
365 DCHECK(task_runner->BelongsToCurrentThread());
366 // ChunkDemuxer's streams may contain much buffered, compressed media that may
367 // need to be paged back in during destruction. Paging delay may exceed the
368 // renderer hang monitor's threshold on at least Windows while also blocking
369 // other work on the renderer main thread, so we do the actual destruction in
370 // the background without blocking WMPI destruction or |task_runner|. On
371 // advice of task_scheduler OWNERS, MayBlock() is not used because virtual
372 // memory overhead is not considered blocking I/O; and CONTINUE_ON_SHUTDOWN is
373 // used to allow process termination to not block on completing the task.
374 base::PostTaskWithTraits(
375 FROM_HERE,
Gabriel Charetteb10aeebc2018-07-26 20:15:00376 {base::TaskPriority::BEST_EFFORT,
Matt Wolenetz95af6362018-01-04 20:23:42377 base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
378 base::BindOnce(
379 [](std::unique_ptr<Demuxer> demuxer_to_destroy) {
380 SCOPED_UMA_HISTOGRAM_TIMER("Media.MSE.DemuxerDestructionTime");
381 demuxer_to_destroy.reset();
382 },
383 std::move(demuxer)));
384}
385
chcunningham707b821e2018-05-29 08:42:19386WebMediaPlayer::LoadTiming WebMediaPlayerImpl::Load(
387 LoadType load_type,
388 const blink::WebMediaPlayerSource& source,
389 CORSMode cors_mode) {
xhwang51139732017-02-24 19:36:08390 DVLOG(1) << __func__;
guidou9bfe4e2f2016-04-09 08:31:19391 // Only URL or MSE blob URL is supported.
Blink Reformat1c4d759e2017-04-09 16:34:54392 DCHECK(source.IsURL());
393 blink::WebURL url = source.GetAsURL();
Xiaohan Wang81fd0022017-07-11 17:45:24394 DVLOG(1) << __func__ << "(" << load_type << ", " << GURL(url) << ", "
395 << cors_mode << ")";
chcunningham707b821e2018-05-29 08:42:19396
397 bool is_deferred = false;
398
[email protected]d726eddc2013-07-02 22:25:55399 if (!defer_load_cb_.is_null()) {
chcunningham707b821e2018-05-29 08:42:19400 is_deferred = defer_load_cb_.Run(base::BindOnce(
401 &WebMediaPlayerImpl::DoLoad, AsWeakPtr(), load_type, url, cors_mode));
402 } else {
403 DoLoad(load_type, url, cors_mode);
[email protected]d726eddc2013-07-02 22:25:55404 }
chcunningham707b821e2018-05-29 08:42:19405
406 return is_deferred ? LoadTiming::kDeferred : LoadTiming::kImmediate;
[email protected]62e5e682013-03-07 23:53:24407}
408
CJ DiMeglio013d4c472017-11-21 03:27:30409void WebMediaPlayerImpl::OnWebLayerUpdated() {}
410
danakj6a062b112018-05-17 16:25:45411void WebMediaPlayerImpl::RegisterContentsLayer(cc::Layer* layer) {
CJ DiMeglio2302d202017-08-31 08:38:04412 DCHECK(bridge_);
CJ DiMeglioa2b13fbc2018-06-27 00:50:59413 bridge_->SetContentsOpaque(opaque_);
danakj8d204a42018-05-18 18:05:35414 client_->SetCcLayer(layer);
CJ DiMeglio013d4c472017-11-21 03:27:30415}
416
danakj6a062b112018-05-17 16:25:45417void WebMediaPlayerImpl::UnregisterContentsLayer(cc::Layer* layer) {
418 // |client_| will unregister its cc::Layer if given a nullptr.
danakj8d204a42018-05-18 18:05:35419 client_->SetCcLayer(nullptr);
CJ DiMeglio2302d202017-08-31 08:38:04420}
421
Jennifer Apaciblec45fd052018-02-25 12:04:55422void WebMediaPlayerImpl::OnSurfaceIdUpdated(viz::SurfaceId surface_id) {
Jennifer Apaciblec45fd052018-02-25 12:04:55423 // TODO(726619): Handle the behavior when Picture-in-Picture mode is
424 // disabled.
Jennifer Apacible2b1dc5eb2018-04-27 16:23:28425 // The viz::SurfaceId may be updated when the video begins playback or when
426 // the size of the video changes.
Mounir Lamouri0484f40a2018-07-25 03:03:26427 if (client_ && IsInPictureInPicture() && !client_->IsInAutoPIP()) {
Mounir Lamourife756e32018-05-22 23:19:08428 delegate_->DidPictureInPictureSurfaceChange(
429 delegate_id_, surface_id, pipeline_metadata_.natural_size);
430 }
Jennifer Apaciblec45fd052018-02-25 12:04:55431}
432
Blink Reformat1c4d759e2017-04-09 16:34:54433bool WebMediaPlayerImpl::SupportsOverlayFullscreenVideo() {
watk9c87c6fa2016-05-06 20:36:51434#if defined(OS_ANDROID)
[email protected]68ec57f2017-06-27 22:10:05435 return !using_media_player_renderer_ &&
436 overlay_mode_ == OverlayMode::kUseContentVideoView;
watk9c87c6fa2016-05-06 20:36:51437#else
438 return false;
439#endif
440}
441
tsunghungee562e92016-07-20 18:03:31442void WebMediaPlayerImpl::EnableOverlay() {
443 overlay_enabled_ = true;
[email protected]f7df5b342018-07-13 20:22:13444 if (request_routing_token_cb_ &&
445 overlay_mode_ == OverlayMode::kUseAndroidOverlay) {
liberatofe8f9692017-06-08 19:17:36446 overlay_routing_token_is_pending_ = true;
liberato2ff93ad2017-05-17 07:28:24447 token_available_cb_.Reset(
448 base::Bind(&WebMediaPlayerImpl::OnOverlayRoutingToken, AsWeakPtr()));
449 request_routing_token_cb_.Run(token_available_cb_.callback());
watkf835a792016-06-24 23:24:40450 }
tsunghungee562e92016-07-20 18:03:31451
liberato2ff93ad2017-05-17 07:28:24452 // We have requested (and maybe already have) overlay information. If the
453 // restarted decoder requests overlay information, then we'll defer providing
454 // it if it hasn't arrived yet. Otherwise, this would be a race, since we
455 // don't know if the request for overlay info or restart will complete first.
tsunghungee562e92016-07-20 18:03:31456 if (decoder_requires_restart_for_overlay_)
watkdee516f2016-02-18 02:22:19457 ScheduleRestart();
458}
459
tsunghungee562e92016-07-20 18:03:31460void WebMediaPlayerImpl::DisableOverlay() {
461 overlay_enabled_ = false;
liberato2ff93ad2017-05-17 07:28:24462 if (overlay_mode_ == OverlayMode::kUseContentVideoView) {
463 surface_created_cb_.Cancel();
liberato2ff93ad2017-05-17 07:28:24464 } else if (overlay_mode_ == OverlayMode::kUseAndroidOverlay) {
465 token_available_cb_.Cancel();
liberatofe8f9692017-06-08 19:17:36466 overlay_routing_token_is_pending_ = false;
467 overlay_routing_token_ = OverlayInfo::RoutingToken();
liberato2ff93ad2017-05-17 07:28:24468 }
tsunghungee562e92016-07-20 18:03:31469
470 if (decoder_requires_restart_for_overlay_)
watkdee516f2016-02-18 02:22:19471 ScheduleRestart();
liberato2ff93ad2017-05-17 07:28:24472 else
473 MaybeSendOverlayInfoToDecoder();
watkdee516f2016-02-18 02:22:19474}
475
Blink Reformat1c4d759e2017-04-09 16:34:54476void WebMediaPlayerImpl::EnteredFullscreen() {
liberatofe8f9692017-06-08 19:17:36477 overlay_info_.is_fullscreen = true;
478
[email protected]c8d574722017-08-30 20:53:43479 // |always_enable_overlays_| implies that we're already in overlay mode, so
480 // take no action here. Otherwise, switch to an overlay if it's allowed and
481 // if it will display properly.
482 if (!always_enable_overlays_ && overlay_mode_ != OverlayMode::kNoOverlays &&
liberato2fd111be2017-01-04 00:25:06483 DoesOverlaySupportMetadata()) {
tsunghungee562e92016-07-20 18:03:31484 EnableOverlay();
liberato2fd111be2017-01-04 00:25:06485 }
liberato2ff93ad2017-05-17 07:28:24486
liberatofe8f9692017-06-08 19:17:36487 // We send this only if we can send multiple calls. Otherwise, either (a)
488 // we already sent it and we don't have a callback anyway (we reset it when
489 // it's called in restart mode), or (b) we'll send this later when the surface
490 // actually arrives. GVD assumes that the first overlay info will have the
491 // routing information. Note that we set |is_fullscreen_| earlier, so that
492 // if EnableOverlay() can include fullscreen info in case it sends the overlay
493 // info before returning.
494 if (!decoder_requires_restart_for_overlay_)
495 MaybeSendOverlayInfoToDecoder();
tsunghungee562e92016-07-20 18:03:31496}
497
Blink Reformat1c4d759e2017-04-09 16:34:54498void WebMediaPlayerImpl::ExitedFullscreen() {
liberatofe8f9692017-06-08 19:17:36499 overlay_info_.is_fullscreen = false;
500
[email protected]c8d574722017-08-30 20:53:43501 // If we're in overlay mode, then exit it unless we're supposed to allow
502 // overlays all the time.
503 if (!always_enable_overlays_ && overlay_enabled_)
tsunghungee562e92016-07-20 18:03:31504 DisableOverlay();
liberato2ff93ad2017-05-17 07:28:24505
liberatofe8f9692017-06-08 19:17:36506 // See EnteredFullscreen for why we do this.
507 if (!decoder_requires_restart_for_overlay_)
508 MaybeSendOverlayInfoToDecoder();
tsunghungee562e92016-07-20 18:03:31509}
510
Blink Reformat1c4d759e2017-04-09 16:34:54511void WebMediaPlayerImpl::BecameDominantVisibleContent(bool isDominant) {
xjzcdbbe732016-12-03 20:47:42512 if (observer_)
513 observer_->OnBecameDominantVisibleContent(isDominant);
514}
515
Blink Reformat1c4d759e2017-04-09 16:34:54516void WebMediaPlayerImpl::SetIsEffectivelyFullscreen(
François Beaufortad6c5232018-02-26 11:00:44517 blink::WebFullscreenVideoStatus fullscreen_video_status) {
518 delegate_->SetIsEffectivelyFullscreen(delegate_id_, fullscreen_video_status);
zqzhangabc08242017-03-02 16:07:14519}
520
Mounir Lamouri41a79c62017-06-06 12:53:16521void WebMediaPlayerImpl::OnHasNativeControlsChanged(bool has_native_controls) {
522 if (!watch_time_reporter_)
523 return;
524
525 if (has_native_controls)
526 watch_time_reporter_->OnNativeControlsEnabled();
527 else
528 watch_time_reporter_->OnNativeControlsDisabled();
529}
530
Mounir Lamourif9af74e72017-06-19 19:31:45531void WebMediaPlayerImpl::OnDisplayTypeChanged(
532 WebMediaPlayer::DisplayType display_type) {
Mounir Lamouri0484f40a2018-07-25 03:03:26533 if (surface_layer_for_video_enabled_) {
534 vfc_task_runner_->PostTask(
535 FROM_HERE,
536 base::BindOnce(
537 &VideoFrameCompositor::SetForceSubmit,
538 base::Unretained(compositor_.get()),
539 display_type == WebMediaPlayer::DisplayType::kPictureInPicture));
540 }
541
Mounir Lamourif9af74e72017-06-19 19:31:45542 if (!watch_time_reporter_)
543 return;
544
545 switch (display_type) {
546 case WebMediaPlayer::DisplayType::kInline:
547 watch_time_reporter_->OnDisplayTypeInline();
548 break;
549 case WebMediaPlayer::DisplayType::kFullscreen:
550 watch_time_reporter_->OnDisplayTypeFullscreen();
551 break;
552 case WebMediaPlayer::DisplayType::kPictureInPicture:
553 watch_time_reporter_->OnDisplayTypePictureInPicture();
554 break;
555 }
556}
557
[email protected]ef8394c2013-08-21 20:26:30558void WebMediaPlayerImpl::DoLoad(LoadType load_type,
[email protected]180ef242013-11-07 06:50:46559 const blink::WebURL& url,
[email protected]d726eddc2013-07-02 22:25:55560 CORSMode cors_mode) {
John Chen5b164a02017-11-01 00:36:09561 TRACE_EVENT1("media", "WebMediaPlayerImpl::DoLoad", "id", media_log_->id());
pkastingf5279482016-07-27 02:18:20562 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:43563 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d726eddc2013-07-02 22:25:55564
[email protected]62e5e682013-03-07 23:53:24565 GURL gurl(url);
dalecurtis9cddc0b2017-04-19 21:23:38566 ReportMetrics(load_type, gurl, frame_->GetSecurityOrigin(), media_log_.get());
[email protected]62e5e682013-03-07 23:53:24567
Dan Sanderscd8981c2017-08-31 22:37:02568 // Report poster availability for SRC=.
569 if (load_type == kLoadTypeURL) {
570 if (preload_ == MultibufferDataSource::METADATA) {
571 UMA_HISTOGRAM_BOOLEAN("Media.SRC.PreloadMetaDataHasPoster", has_poster_);
572 } else if (preload_ == MultibufferDataSource::AUTO) {
573 UMA_HISTOGRAM_BOOLEAN("Media.SRC.PreloadAutoHasPoster", has_poster_);
574 }
575 }
576
[email protected]926f8fd2013-04-12 20:27:53577 // Set subresource URL for crash reporting.
Robert Sesekc5e91df2017-12-12 21:11:03578 static base::debug::CrashKeyString* subresource_url =
579 base::debug::AllocateCrashKeyString("subresource_url",
580 base::debug::CrashKeySize::Size256);
581 base::debug::SetCrashKeyString(subresource_url, gurl.spec());
[email protected]926f8fd2013-04-12 20:27:53582
tguilbert75e2bf62017-04-26 20:13:12583 // Used for HLS playback.
584 loaded_url_ = gurl;
tguilbert25a4d112016-10-13 21:56:51585
[email protected]ef8394c2013-08-21 20:26:30586 load_type_ = load_type;
587
Blink Reformat1c4d759e2017-04-09 16:34:54588 SetNetworkState(WebMediaPlayer::kNetworkStateLoading);
589 SetReadyState(WebMediaPlayer::kReadyStateHaveNothing);
590 media_log_->AddEvent(media_log_->CreateLoadEvent(url.GetString().Utf8()));
Dale Curtis3899090ea2018-01-12 00:10:35591 load_start_time_ = base::TimeTicks::Now();
[email protected]d726eddc2013-07-02 22:25:55592
Dale Curtisd131da1e2018-08-30 02:09:53593 media_metrics_provider_->Initialize(load_type == kLoadTypeMediaSource,
594 load_type == kLoadTypeURL
595 ? GetMediaURLScheme(loaded_url_)
596 : mojom::MediaURLScheme::kUnknown);
Dale Curtis74612b72017-12-14 20:56:19597
[email protected]d726eddc2013-07-02 22:25:55598 // Media source pipelines can start immediately.
Blink Reformat1c4d759e2017-04-09 16:34:54599 if (load_type == kLoadTypeMediaSource) {
[email protected]ef8394c2013-08-21 20:26:30600 StartPipeline();
hubbe5f0ad43b2015-12-14 20:57:26601 } else {
dalecurtisb6e052f52016-08-25 00:35:55602 data_source_.reset(new MultibufferDataSource(
Alok Priyadarshib8f30542017-07-22 00:16:25603 main_task_runner_,
604 url_index_->GetByUrl(url, static_cast<UrlData::CORSMode>(cors_mode)),
605 media_log_.get(), &buffered_data_source_host_,
dalecurtisb6e052f52016-08-25 00:35:55606 base::Bind(&WebMediaPlayerImpl::NotifyDownloading, AsWeakPtr())));
avayvode46d7bef2016-03-30 23:18:26607 data_source_->SetPreload(preload_);
Yoav Weissc34fb0d2018-01-08 05:37:27608 data_source_->SetIsClientAudioElement(client_->IsAudioElement());
avayvode46d7bef2016-03-30 23:18:26609 data_source_->Initialize(
610 base::Bind(&WebMediaPlayerImpl::DataSourceInitialized, AsWeakPtr()));
hubbe5f0ad43b2015-12-14 20:57:26611 }
hubbed5f36882016-01-15 22:40:37612
613#if defined(OS_ANDROID) // WMPI_CAST
dalecurtisbb3eaac2016-01-27 21:10:25614 cast_impl_.Initialize(url, frame_, delegate_id_);
hubbed5f36882016-01-15 22:40:37615#endif
[email protected]62e5e682013-03-07 23:53:24616}
617
Blink Reformat1c4d759e2017-04-09 16:34:54618void WebMediaPlayerImpl::Play() {
pkastingf5279482016-07-27 02:18:20619 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:43620 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53621
avayvod65fad272017-02-24 01:00:48622 // User initiated play unlocks background video playback.
Mustaq Ahmede473e4352017-11-04 01:04:25623 if (blink::WebUserGestureIndicator::IsProcessingUserGesture(frame_))
avayvod65fad272017-02-24 01:00:48624 video_locked_when_paused_when_hidden_ = false;
625
hubbed5f36882016-01-15 22:40:37626#if defined(OS_ANDROID) // WMPI_CAST
Blink Reformat1c4d759e2017-04-09 16:34:54627 if (IsRemote()) {
dalecurtis6e2716d2016-01-21 04:49:15628 cast_impl_.play();
hubbed5f36882016-01-15 22:40:37629 return;
630 }
631#endif
sandersd35d2c3f2017-01-14 02:04:42632 // TODO(sandersd): Do we want to reset the idle timer here?
tguilbert1bb1c782017-01-23 21:15:11633 delegate_->SetIdle(delegate_id_, false);
[email protected]49480902009-07-14 20:23:43634 paused_ = false;
tguilbert350936ff2017-02-24 05:39:27635 pipeline_controller_.SetPlaybackRate(playback_rate_);
dalecurtis4619cd02016-09-22 21:39:10636 background_pause_timer_.Stop();
sandersd1c0bba02016-03-04 23:14:08637
[email protected]039b7542013-10-17 22:06:25638 if (data_source_)
639 data_source_->MediaIsPlaying();
[email protected]090f7312011-08-05 23:26:40640
xjz48a9cb72016-12-20 04:02:49641 if (observer_)
642 observer_->OnPlaying();
643
Mounir Lamouri89c0a1b2018-03-01 15:00:44644 watch_time_reporter_->SetAutoplayInitiated(client_->WasAutoplayInitiated());
645
Dale Curtis051fdf62017-08-05 00:21:13646 // If we're seeking we'll trigger the watch time reporter upon seek completed;
647 // we don't want to start it here since the seek time is unstable. E.g., when
648 // playing content with a positive start time we would have a zero seek time.
649 if (!Seeking()) {
650 DCHECK(watch_time_reporter_);
651 watch_time_reporter_->OnPlaying();
652 }
653
Chris Cunninghamd9df58e2017-08-29 00:04:23654 if (video_decode_stats_reporter_)
655 video_decode_stats_reporter_->OnPlaying();
656
acolwell9e0840d2014-09-06 19:01:32657 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PLAY));
sandersd50a635e2016-04-04 22:50:09658 UpdatePlayState();
[email protected]ec9212f2008-12-18 21:40:36659}
660
Blink Reformat1c4d759e2017-04-09 16:34:54661void WebMediaPlayerImpl::Pause() {
pkastingf5279482016-07-27 02:18:20662 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:43663 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53664
sandersd50a635e2016-04-04 22:50:09665 // We update the paused state even when casting, since we expect pause() to be
666 // called when casting begins, and when we exit casting we should end up in a
667 // paused state.
[email protected]49480902009-07-14 20:23:43668 paused_ = true;
hubbed5f36882016-01-15 22:40:37669
avayvodeb9098d2017-01-07 00:33:03670 // No longer paused because it was hidden.
671 paused_when_hidden_ = false;
672
avayvod65fad272017-02-24 01:00:48673 // User initiated pause locks background videos.
Mustaq Ahmede473e4352017-11-04 01:04:25674 if (blink::WebUserGestureIndicator::IsProcessingUserGesture(frame_))
avayvod65fad272017-02-24 01:00:48675 video_locked_when_paused_when_hidden_ = true;
676
hubbed5f36882016-01-15 22:40:37677#if defined(OS_ANDROID) // WMPI_CAST
Blink Reformat1c4d759e2017-04-09 16:34:54678 if (IsRemote()) {
dalecurtis6e2716d2016-01-21 04:49:15679 cast_impl_.pause();
hubbed5f36882016-01-15 22:40:37680 return;
681 }
682#endif
683
tguilbert350936ff2017-02-24 05:39:27684 pipeline_controller_.SetPlaybackRate(0.0);
Dale Curtisdc5d47c2018-02-15 11:15:19685 paused_time_ = pipeline_controller_.GetMediaTime();
[email protected]090f7312011-08-05 23:26:40686
xjz48a9cb72016-12-20 04:02:49687 if (observer_)
688 observer_->OnPaused();
689
dalecurtis04bdb582016-08-17 22:15:23690 DCHECK(watch_time_reporter_);
691 watch_time_reporter_->OnPaused();
Chris Cunninghamd9df58e2017-08-29 00:04:23692
693 if (video_decode_stats_reporter_)
694 video_decode_stats_reporter_->OnPaused();
695
acolwell9e0840d2014-09-06 19:01:32696 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PAUSE));
avayvod2135a642017-01-13 00:17:14697
sandersd50a635e2016-04-04 22:50:09698 UpdatePlayState();
[email protected]ec9212f2008-12-18 21:40:36699}
700
Blink Reformat1c4d759e2017-04-09 16:34:54701void WebMediaPlayerImpl::Seek(double seconds) {
pkastingf5279482016-07-27 02:18:20702 DVLOG(1) << __func__ << "(" << seconds << "s)";
acolwellb4034942014-08-28 15:42:43703 DCHECK(main_task_runner_->BelongsToCurrentThread());
servolk86b3d88fb2017-03-18 02:50:28704 media_log_->AddEvent(media_log_->CreateSeekEvent(seconds));
sandersd1c0bba02016-03-04 23:14:08705 DoSeek(base::TimeDelta::FromSecondsD(seconds), true);
706}
707
708void WebMediaPlayerImpl::DoSeek(base::TimeDelta time, bool time_updated) {
709 DCHECK(main_task_runner_->BelongsToCurrentThread());
John Chen5b164a02017-11-01 00:36:09710 TRACE_EVENT2("media", "WebMediaPlayerImpl::DoSeek", "target",
711 time.InSecondsF(), "id", media_log_->id());
[email protected]d43ed912009-02-03 04:52:53712
hubbed5f36882016-01-15 22:40:37713#if defined(OS_ANDROID) // WMPI_CAST
Blink Reformat1c4d759e2017-04-09 16:34:54714 if (IsRemote()) {
sandersd1c0bba02016-03-04 23:14:08715 cast_impl_.seek(time);
hubbed5f36882016-01-15 22:40:37716 return;
717 }
718#endif
719
srirama.mccf671812015-01-08 11:59:13720 ReadyState old_state = ready_state_;
Blink Reformat1c4d759e2017-04-09 16:34:54721 if (ready_state_ > WebMediaPlayer::kReadyStateHaveMetadata)
722 SetReadyState(WebMediaPlayer::kReadyStateHaveMetadata);
[email protected]1bb666802013-11-28 06:12:08723
Dale Curtis051fdf62017-08-05 00:21:13724 // When paused or ended, we know exactly what the current time is and can
725 // elide seeks to it. However, there are two cases that are not elided:
sandersd1c0bba02016-03-04 23:14:08726 // 1) When the pipeline state is not stable.
727 // In this case we just let |pipeline_controller_| decide what to do, as
728 // it has complete information.
729 // 2) For MSE.
730 // Because the buffers may have changed between seeks, MSE seeks are
731 // never elided.
Dale Curtis051fdf62017-08-05 00:21:13732 if (paused_ && pipeline_controller_.IsStable() &&
733 (paused_time_ == time ||
734 (ended_ && time == base::TimeDelta::FromSecondsD(Duration()))) &&
sandersd1c0bba02016-03-04 23:14:08735 !chunk_demuxer_) {
736 // If the ready state was high enough before, we can indicate that the seek
737 // completed just by restoring it. Otherwise we will just wait for the real
738 // ready state change to eventually happen.
Blink Reformat1c4d759e2017-04-09 16:34:54739 if (old_state == kReadyStateHaveEnoughData) {
srirama.m8f4a37562014-12-13 08:16:18740 main_task_runner_->PostTask(
alokp967c902452016-05-06 05:21:37741 FROM_HERE, base::Bind(&WebMediaPlayerImpl::OnBufferingStateChange,
742 AsWeakPtr(), BUFFERING_HAVE_ENOUGH));
srirama.m36ab2682014-12-11 04:20:01743 }
sandersd1c0bba02016-03-04 23:14:08744 return;
srirama.m36ab2682014-12-11 04:20:01745 }
[email protected]44ff37c02009-10-24 01:03:03746
dalecurtis04bdb582016-08-17 22:15:23747 // Call this before setting |seeking_| so that the current media time can be
748 // recorded by the reporter.
749 if (watch_time_reporter_)
750 watch_time_reporter_->OnSeeking();
751
dalecurtis1af3c1a2017-04-11 00:53:49752 // Clear any new frame processed callbacks on seek; otherwise we'll end up
753 // logging a time long after the seek completes.
754 frame_time_report_cb_.Cancel();
755
sandersd35d2c3f2017-01-14 02:04:42756 // TODO(sandersd): Move |seeking_| to PipelineController.
757 // TODO(sandersd): Do we want to reset the idle timer here?
tguilbert1bb1c782017-01-23 21:15:11758 delegate_->SetIdle(delegate_id_, false);
sandersd50a635e2016-04-04 22:50:09759 ended_ = false;
[email protected]b3766a22010-12-22 17:34:13760 seeking_ = true;
sandersd1c0bba02016-03-04 23:14:08761 seek_time_ = time;
762 if (paused_)
763 paused_time_ = time;
764 pipeline_controller_.Seek(time, time_updated);
[email protected]b3766a22010-12-22 17:34:13765
sandersd50a635e2016-04-04 22:50:09766 // This needs to be called after Seek() so that if a resume is triggered, it
767 // is to the correct time.
768 UpdatePlayState();
[email protected]ec9212f2008-12-18 21:40:36769}
770
Blink Reformat1c4d759e2017-04-09 16:34:54771void WebMediaPlayerImpl::SetRate(double rate) {
pkastingf5279482016-07-27 02:18:20772 DVLOG(1) << __func__ << "(" << rate << ")";
acolwellb4034942014-08-28 15:42:43773 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53774
Matt Wolenetz6010f6c2017-10-18 00:44:36775 if (rate != playback_rate_) {
776 LIMITED_MEDIA_LOG(INFO, media_log_.get(), num_playback_rate_logs_,
777 kMaxNumPlaybackRateLogs)
778 << "Effective playback rate changed from " << playback_rate_ << " to "
779 << rate;
780 }
781
[email protected]49480902009-07-14 20:23:43782 playback_rate_ = rate;
783 if (!paused_) {
tguilbert350936ff2017-02-24 05:39:27784 pipeline_controller_.SetPlaybackRate(rate);
[email protected]039b7542013-10-17 22:06:25785 if (data_source_)
786 data_source_->MediaPlaybackRateChanged(rate);
[email protected]49480902009-07-14 20:23:43787 }
[email protected]ec9212f2008-12-18 21:40:36788}
789
Blink Reformat1c4d759e2017-04-09 16:34:54790void WebMediaPlayerImpl::SetVolume(double volume) {
pkastingf5279482016-07-27 02:18:20791 DVLOG(1) << __func__ << "(" << volume << ")";
acolwellb4034942014-08-28 15:42:43792 DCHECK(main_task_runner_->BelongsToCurrentThread());
dalecurtisbb3eaac2016-01-27 21:10:25793 volume_ = volume;
tguilbert350936ff2017-02-24 05:39:27794 pipeline_controller_.SetVolume(volume_ * volume_multiplier_);
dalecurtis04bdb582016-08-17 22:15:23795 if (watch_time_reporter_)
796 watch_time_reporter_->OnVolumeChange(volume);
Becca Hughes9f6fd4b82017-06-15 10:01:40797 delegate_->DidPlayerMutedStatusChange(delegate_id_, volume == 0.0);
mlamouri910111362016-11-04 11:28:24798
799 // The play state is updated because the player might have left the autoplay
800 // muted state.
801 UpdatePlayState();
[email protected]ec9212f2008-12-18 21:40:36802}
[email protected]f0a51fb52009-03-05 12:46:38803
François Beaufort9290aab2018-05-07 21:18:47804void WebMediaPlayerImpl::EnterPictureInPicture(
Mounir Lamouri917143af2018-05-24 21:19:57805 blink::WebMediaPlayer::PipWindowOpenedCallback callback) {
Mounir Lamourib642a3c2018-07-09 15:45:31806 DCHECK(bridge_);
Mounir Lamouri37e8ae82018-05-31 02:38:46807
Mounir Lamourib642a3c2018-07-09 15:45:31808 const viz::SurfaceId& surface_id = bridge_->GetSurfaceId();
809 DCHECK(surface_id.is_valid());
Jennifer Apaciblec45fd052018-02-25 12:04:55810
Mounir Lamouri11e9ef42018-05-22 03:10:16811 // Notifies the browser process that the player should now be in
812 // Picture-in-Picture mode.
Mounir Lamourib642a3c2018-07-09 15:45:31813 delegate_->DidPictureInPictureModeStart(delegate_id_, surface_id,
Mounir Lamouri11e9ef42018-05-22 03:10:16814 pipeline_metadata_.natural_size,
815 std::move(callback));
Jennifer Apacible3f0489102018-01-19 20:10:31816}
817
François Beaufort9290aab2018-05-07 21:18:47818void WebMediaPlayerImpl::ExitPictureInPicture(
819 blink::WebMediaPlayer::PipWindowClosedCallback callback) {
Mounir Lamouri6d759e12018-05-16 20:01:30820 // Notifies the browser process that Picture-in-Picture has ended. It will
821 // clear out the states and close the window.
822 delegate_->DidPictureInPictureModeEnd(delegate_id_, std::move(callback));
Jennifer Apacible02897b72018-04-01 01:00:49823
Mounir Lamouri6d759e12018-05-16 20:01:30824 // Internal cleanups.
Jennifer Apacible5cd9a7e2018-04-17 03:08:06825 OnPictureInPictureModeEnded();
Jennifer Apacible02897b72018-04-01 01:00:49826}
827
sawtellee19d11aa2018-08-10 03:47:50828void WebMediaPlayerImpl::SetPictureInPictureCustomControls(
829 const std::vector<blink::PictureInPictureControlInfo>& controls) {
830 delegate_->DidSetPictureInPictureCustomControls(delegate_id_, controls);
831}
832
Mounir Lamouri917143af2018-05-24 21:19:57833void WebMediaPlayerImpl::RegisterPictureInPictureWindowResizeCallback(
834 blink::WebMediaPlayer::PipWindowResizedCallback callback) {
Mounir Lamouri0484f40a2018-07-25 03:03:26835 DCHECK(IsInPictureInPicture() && !client_->IsInAutoPIP());
Mounir Lamouri917143af2018-05-24 21:19:57836
837 delegate_->RegisterPictureInPictureWindowResizeCallback(delegate_id_,
838 std::move(callback));
839}
840
Dale Curtis5bba03232018-08-30 17:57:38841void WebMediaPlayerImpl::SetSinkId(const blink::WebString& sink_id,
842 blink::WebSetSinkIdCallbacks* web_callback) {
guidou69223ce2015-06-16 10:36:19843 DCHECK(main_task_runner_->BelongsToCurrentThread());
pkastingf5279482016-07-27 02:18:20844 DVLOG(1) << __func__;
guidouc7babef2015-10-22 00:42:35845
olka68b69392016-04-01 11:42:12846 media::OutputDeviceStatusCB callback =
847 media::ConvertToOutputDeviceStatusCB(web_callback);
guidouc7babef2015-10-22 00:42:35848 media_task_runner_->PostTask(
Max Morinf506af592018-04-17 12:23:32849 FROM_HERE, base::Bind(&SetSinkIdOnMediaThread, audio_source_provider_,
850 sink_id.Utf8(), callback));
guidou69223ce2015-06-16 10:36:19851}
852
Blink Reformat1c4d759e2017-04-09 16:34:54853STATIC_ASSERT_ENUM(WebMediaPlayer::kPreloadNone, MultibufferDataSource::NONE);
854STATIC_ASSERT_ENUM(WebMediaPlayer::kPreloadMetaData,
dalecurtisb6e052f52016-08-25 00:35:55855 MultibufferDataSource::METADATA);
Blink Reformat1c4d759e2017-04-09 16:34:54856STATIC_ASSERT_ENUM(WebMediaPlayer::kPreloadAuto, MultibufferDataSource::AUTO);
[email protected]23a8b1d82011-04-05 16:28:20857
Blink Reformat1c4d759e2017-04-09 16:34:54858void WebMediaPlayerImpl::SetPreload(WebMediaPlayer::Preload preload) {
pkastingf5279482016-07-27 02:18:20859 DVLOG(1) << __func__ << "(" << preload << ")";
acolwellb4034942014-08-28 15:42:43860 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]4e6be3f2009-05-07 02:24:44861
dalecurtisb6e052f52016-08-25 00:35:55862 preload_ = static_cast<MultibufferDataSource::Preload>(preload);
[email protected]b49beeb2013-03-01 20:04:00863 if (data_source_)
[email protected]09c60222014-08-07 16:42:31864 data_source_->SetPreload(preload_);
[email protected]4e6be3f2009-05-07 02:24:44865}
866
Blink Reformat1c4d759e2017-04-09 16:34:54867bool WebMediaPlayerImpl::HasVideo() const {
acolwellb4034942014-08-28 15:42:43868 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53869
[email protected]b8877772014-03-26 20:17:15870 return pipeline_metadata_.has_video;
[email protected]d43ed912009-02-03 04:52:53871}
872
Blink Reformat1c4d759e2017-04-09 16:34:54873bool WebMediaPlayerImpl::HasAudio() const {
acolwellb4034942014-08-28 15:42:43874 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]fc367af2009-08-14 23:06:35875
[email protected]b8877772014-03-26 20:17:15876 return pipeline_metadata_.has_audio;
[email protected]fc367af2009-08-14 23:06:35877}
878
Blink Reformat1c4d759e2017-04-09 16:34:54879void WebMediaPlayerImpl::EnabledAudioTracksChanged(
servolkf25ceed2016-07-01 03:44:38880 const blink::WebVector<blink::WebMediaPlayer::TrackId>& enabledTrackIds) {
881 DCHECK(main_task_runner_->BelongsToCurrentThread());
882
883 std::ostringstream logstr;
884 std::vector<MediaTrack::Id> enabledMediaTrackIds;
885 for (const auto& blinkTrackId : enabledTrackIds) {
Blink Reformat1c4d759e2017-04-09 16:34:54886 MediaTrack::Id track_id = blinkTrackId.Utf8().data();
servolkf25ceed2016-07-01 03:44:38887 logstr << track_id << " ";
888 enabledMediaTrackIds.push_back(track_id);
889 }
dalecurtis9cddc0b2017-04-19 21:23:38890 MEDIA_LOG(INFO, media_log_.get())
891 << "Enabled audio tracks: [" << logstr.str() << "]";
tguilbert350936ff2017-02-24 05:39:27892 pipeline_controller_.OnEnabledAudioTracksChanged(enabledMediaTrackIds);
servolkf25ceed2016-07-01 03:44:38893}
894
Blink Reformat1c4d759e2017-04-09 16:34:54895void WebMediaPlayerImpl::SelectedVideoTrackChanged(
servolkf25ceed2016-07-01 03:44:38896 blink::WebMediaPlayer::TrackId* selectedTrackId) {
897 DCHECK(main_task_runner_->BelongsToCurrentThread());
898
servolk9bed6602017-02-24 01:20:11899 base::Optional<MediaTrack::Id> selected_video_track_id;
900 if (selectedTrackId && !video_track_disabled_)
Blink Reformat1c4d759e2017-04-09 16:34:54901 selected_video_track_id = MediaTrack::Id(selectedTrackId->Utf8().data());
dalecurtis9cddc0b2017-04-19 21:23:38902 MEDIA_LOG(INFO, media_log_.get())
903 << "Selected video track: [" << selected_video_track_id.value_or("")
904 << "]";
tguilbert350936ff2017-02-24 05:39:27905 pipeline_controller_.OnSelectedVideoTrackChanged(selected_video_track_id);
servolkf25ceed2016-07-01 03:44:38906}
907
Blink Reformat1c4d759e2017-04-09 16:34:54908blink::WebSize WebMediaPlayerImpl::NaturalSize() const {
acolwellb4034942014-08-28 15:42:43909 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53910
[email protected]b8877772014-03-26 20:17:15911 return blink::WebSize(pipeline_metadata_.natural_size);
[email protected]d43ed912009-02-03 04:52:53912}
913
Jiajia Qin82acdc02017-07-31 09:55:14914blink::WebSize WebMediaPlayerImpl::VisibleRect() const {
915 DCHECK(main_task_runner_->BelongsToCurrentThread());
916 scoped_refptr<VideoFrame> video_frame = GetCurrentFrameFromCompositor();
917 if (!video_frame)
918 return blink::WebSize();
919
920 const gfx::Rect& visible_rect = video_frame->visible_rect();
921 return blink::WebSize(visible_rect.width(), visible_rect.height());
922}
923
Blink Reformat1c4d759e2017-04-09 16:34:54924bool WebMediaPlayerImpl::Paused() const {
acolwellb4034942014-08-28 15:42:43925 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53926
hubbed5f36882016-01-15 22:40:37927#if defined(OS_ANDROID) // WMPI_CAST
Blink Reformat1c4d759e2017-04-09 16:34:54928 if (IsRemote())
danakj4f1fd6a2017-01-06 21:15:17929 return cast_impl_.IsPaused();
hubbed5f36882016-01-15 22:40:37930#endif
sandersd50a635e2016-04-04 22:50:09931
tguilbert350936ff2017-02-24 05:39:27932 return pipeline_controller_.GetPlaybackRate() == 0.0f;
[email protected]d43ed912009-02-03 04:52:53933}
934
Blink Reformat1c4d759e2017-04-09 16:34:54935bool WebMediaPlayerImpl::Seeking() const {
acolwellb4034942014-08-28 15:42:43936 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53937
Blink Reformat1c4d759e2017-04-09 16:34:54938 if (ready_state_ == WebMediaPlayer::kReadyStateHaveNothing)
[email protected]0acebfa2009-08-21 22:45:40939 return false;
[email protected]67cd5052009-09-10 21:53:22940
[email protected]b3766a22010-12-22 17:34:13941 return seeking_;
[email protected]ec9212f2008-12-18 21:40:36942}
943
Blink Reformat1c4d759e2017-04-09 16:34:54944double WebMediaPlayerImpl::Duration() const {
acolwellb4034942014-08-28 15:42:43945 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]39bdde32013-04-17 17:44:20946
Blink Reformat1c4d759e2017-04-09 16:34:54947 if (ready_state_ == WebMediaPlayer::kReadyStateHaveNothing)
[email protected]39bdde32013-04-17 17:44:20948 return std::numeric_limits<double>::quiet_NaN();
949
chcunninghamb92d5062017-01-10 21:50:22950 // Use duration from ChunkDemuxer when present. MSE allows users to specify
951 // duration as a double. This propagates to the rest of the pipeline as a
952 // TimeDelta with potentially reduced precision (limited to Microseconds).
953 // ChunkDemuxer returns the full-precision user-specified double. This ensures
954 // users can "get" the exact duration they "set".
955 if (chunk_demuxer_)
956 return chunk_demuxer_->GetDuration();
957
avayvodcc273dd2017-01-19 19:35:12958 base::TimeDelta pipeline_duration = GetPipelineMediaDuration();
chcunninghamb92d5062017-01-10 21:50:22959 return pipeline_duration == kInfiniteDuration
960 ? std::numeric_limits<double>::infinity()
961 : pipeline_duration.InSecondsF();
[email protected]d43ed912009-02-03 04:52:53962}
963
[email protected]db66d0092014-04-16 07:15:12964double WebMediaPlayerImpl::timelineOffset() const {
acolwellb4034942014-08-28 15:42:43965 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]db66d0092014-04-16 07:15:12966
967 if (pipeline_metadata_.timeline_offset.is_null())
968 return std::numeric_limits<double>::quiet_NaN();
969
970 return pipeline_metadata_.timeline_offset.ToJsTime();
971}
972
Dale Curtis051fdf62017-08-05 00:21:13973base::TimeDelta WebMediaPlayerImpl::GetCurrentTimeInternal() const {
974 DCHECK(main_task_runner_->BelongsToCurrentThread());
975 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
976
977 base::TimeDelta current_time;
978 if (Seeking())
979 current_time = seek_time_;
980#if defined(OS_ANDROID) // WMPI_CAST
981 else if (IsRemote())
982 current_time = cast_impl_.currentTime();
983#endif
984 else if (paused_)
985 current_time = paused_time_;
986 else
987 current_time = pipeline_controller_.GetMediaTime();
988
989 DCHECK_NE(current_time, kInfiniteDuration);
990 DCHECK_GE(current_time, base::TimeDelta());
991 return current_time;
992}
993
Blink Reformat1c4d759e2017-04-09 16:34:54994double WebMediaPlayerImpl::CurrentTime() const {
acolwellb4034942014-08-28 15:42:43995 DCHECK(main_task_runner_->BelongsToCurrentThread());
Blink Reformat1c4d759e2017-04-09 16:34:54996 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
scherkusd2c745b2014-09-04 05:03:40997
998 // TODO(scherkus): Replace with an explicit ended signal to HTMLMediaElement,
999 // see http://crbug.com/409280
Dale Curtis051fdf62017-08-05 00:21:131000 // Note: Duration() may be infinity.
josephlolak918863bc2017-11-15 08:54:331001 return (ended_ && !std::isinf(Duration()))
1002 ? Duration()
1003 : GetCurrentTimeInternal().InSecondsF();
[email protected]d43ed912009-02-03 04:52:531004}
1005
Blink Reformat1c4d759e2017-04-09 16:34:541006WebMediaPlayer::NetworkState WebMediaPlayerImpl::GetNetworkState() const {
acolwellb4034942014-08-28 15:42:431007 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]ddb1e5a2010-12-13 20:10:451008 return network_state_;
1009}
1010
Blink Reformat1c4d759e2017-04-09 16:34:541011WebMediaPlayer::ReadyState WebMediaPlayerImpl::GetReadyState() const {
acolwellb4034942014-08-28 15:42:431012 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]ddb1e5a2010-12-13 20:10:451013 return ready_state_;
1014}
1015
wolenetzed8e7092017-04-21 16:28:591016blink::WebString WebMediaPlayerImpl::GetErrorMessage() const {
wolenetz4d39cc02016-04-05 19:54:411017 DCHECK(main_task_runner_->BelongsToCurrentThread());
wolenetzed8e7092017-04-21 16:28:591018 return blink::WebString::FromUTF8(media_log_->GetErrorMessage());
wolenetz4d39cc02016-04-05 19:54:411019}
1020
Blink Reformat1c4d759e2017-04-09 16:34:541021blink::WebTimeRanges WebMediaPlayerImpl::Buffered() const {
acolwellb4034942014-08-28 15:42:431022 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]779a8322014-08-22 21:28:371023
acolwell9e0840d2014-09-06 19:01:321024 Ranges<base::TimeDelta> buffered_time_ranges =
tguilbert350936ff2017-02-24 05:39:271025 pipeline_controller_.GetBufferedTimeRanges();
[email protected]779a8322014-08-22 21:28:371026
avayvodcc273dd2017-01-19 19:35:121027 const base::TimeDelta duration = GetPipelineMediaDuration();
dalecurtis39a7f932016-07-19 18:34:591028 if (duration != kInfiniteDuration) {
tguilbert350936ff2017-02-24 05:39:271029 buffered_data_source_host_.AddBufferedTimeRanges(&buffered_time_ranges,
1030 duration);
[email protected]779a8322014-08-22 21:28:371031 }
[email protected]02022fc2014-05-16 00:05:311032 return ConvertToWebTimeRanges(buffered_time_ranges);
1033}
1034
Blink Reformat1c4d759e2017-04-09 16:34:541035blink::WebTimeRanges WebMediaPlayerImpl::Seekable() const {
acolwellb4034942014-08-28 15:42:431036 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]39bdde32013-04-17 17:44:201037
Blink Reformat1c4d759e2017-04-09 16:34:541038 if (ready_state_ < WebMediaPlayer::kReadyStateHaveMetadata)
philipjb0e6f3f2014-09-30 09:51:531039 return blink::WebTimeRanges();
1040
Blink Reformat1c4d759e2017-04-09 16:34:541041 const double seekable_end = Duration();
dalecurtis56359cb2014-10-28 00:06:291042
1043 // Allow a special exception for seeks to zero for streaming sources with a
1044 // finite duration; this allows looping to work.
tguilbertade2bcb2017-01-07 02:57:451045 const bool is_finite_stream = data_source_ && data_source_->IsStreaming() &&
1046 std::isfinite(seekable_end);
1047
tguilbert75e2bf62017-04-26 20:13:121048 // Do not change the seekable range when using the MediaPlayerRenderer. It
1049 // will take care of dropping invalid seeks.
1050 const bool force_seeks_to_zero =
1051 !using_media_player_renderer_ && is_finite_stream;
dalecurtis56359cb2014-10-28 00:06:291052
1053 // TODO(dalecurtis): Technically this allows seeking on media which return an
tguilbertade2bcb2017-01-07 02:57:451054 // infinite duration so long as DataSource::IsStreaming() is false. While not
dalecurtis56359cb2014-10-28 00:06:291055 // expected, disabling this breaks semi-live players, http://crbug.com/427412.
1056 const blink::WebTimeRange seekable_range(
tguilbertade2bcb2017-01-07 02:57:451057 0.0, force_seeks_to_zero ? 0.0 : seekable_end);
philipjb0e6f3f2014-09-30 09:51:531058 return blink::WebTimeRanges(&seekable_range, 1);
[email protected]ec9212f2008-12-18 21:40:361059}
1060
sandersd35d2c3f2017-01-14 02:04:421061bool WebMediaPlayerImpl::IsPrerollAttemptNeeded() {
1062 // TODO(sandersd): Replace with |highest_ready_state_since_seek_| if we need
1063 // to ensure that preroll always gets a chance to complete.
1064 // See http://crbug.com/671525.
Blink Reformat1c4d759e2017-04-09 16:34:541065 if (highest_ready_state_ >= ReadyState::kReadyStateHaveFutureData)
sandersd35d2c3f2017-01-14 02:04:421066 return false;
1067
Fredrik Hubinette4cfb4412017-08-23 00:03:071068 // To suspend before we reach kReadyStateHaveCurrentData is only ok
1069 // if we know we're going to get woken up when we get more data, which
1070 // will only happen if the network is in the "Loading" state.
1071 // This happens when the network is fast, but multiple videos are loading
1072 // and multiplexing gets held up waiting for available threads.
1073 if (highest_ready_state_ <= ReadyState::kReadyStateHaveMetadata &&
1074 network_state_ != WebMediaPlayer::kNetworkStateLoading) {
1075 return true;
1076 }
1077
sandersd35d2c3f2017-01-14 02:04:421078 if (preroll_attempt_pending_)
1079 return true;
1080
1081 // Freshly initialized; there has never been any loading progress. (Otherwise
1082 // |preroll_attempt_pending_| would be true when the start time is null.)
1083 if (preroll_attempt_start_time_.is_null())
1084 return false;
1085
1086 base::TimeDelta preroll_attempt_duration =
1087 tick_clock_->NowTicks() - preroll_attempt_start_time_;
1088 return preroll_attempt_duration < kPrerollAttemptTimeout;
1089}
1090
Blink Reformat1c4d759e2017-04-09 16:34:541091bool WebMediaPlayerImpl::DidLoadingProgress() {
acolwellb4034942014-08-28 15:42:431092 DCHECK(main_task_runner_->BelongsToCurrentThread());
dalecurtise7120dc2016-09-03 02:54:351093
1094 // Note: Separate variables used to ensure both methods are called every time.
tguilbert350936ff2017-02-24 05:39:271095 const bool pipeline_progress = pipeline_controller_.DidLoadingProgress();
dalecurtise7120dc2016-09-03 02:54:351096 const bool data_progress = buffered_data_source_host_.DidLoadingProgress();
hubbeb2d3efd2017-05-05 23:26:381097 return pipeline_progress || data_progress;
[email protected]d43ed912009-02-03 04:52:531098}
1099
danakjff6a0262018-06-26 19:50:311100void WebMediaPlayerImpl::Paint(cc::PaintCanvas* canvas,
[email protected]dd5c7972014-08-21 15:00:371101 const blink::WebRect& rect,
Kai Ninomiya9e8ae29b2017-09-06 23:45:161102 cc::PaintFlags& flags,
1103 int already_uploaded_id,
1104 VideoFrameUploadMetadata* out_metadata) {
acolwellb4034942014-08-28 15:42:431105 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]dd061e12014-05-06 19:21:221106 TRACE_EVENT0("media", "WebMediaPlayerImpl:paint");
[email protected]4e6be3f2009-05-07 02:24:441107
watkd16bb3e2017-04-25 01:18:311108 // We can't copy from protected frames.
Xiaohan Wang24cfe2c2018-01-22 23:16:001109 if (cdm_context_ref_)
xhwang80739452016-01-13 00:48:001110 return;
1111
mcasasf1236fc22015-05-29 22:38:561112 scoped_refptr<VideoFrame> video_frame = GetCurrentFrameFromCompositor();
[email protected]0fe5d43b2014-01-24 23:32:451113
[email protected]b49beeb2013-03-01 20:04:001114 gfx::Rect gfx_rect(rect);
dongseong.hwang0c4e9d82015-01-08 20:11:131115 Context3D context_3d;
mcasas265bdbf82015-06-12 18:44:071116 if (video_frame.get() && video_frame->HasTextures()) {
CJ DiMeglioc60a5cf2017-09-27 20:08:411117 if (context_provider_) {
1118 context_3d = Context3D(context_provider_->ContextGL(),
1119 context_provider_->GrContext());
1120 }
dongseong.hwang0c4e9d82015-01-08 20:11:131121 if (!context_3d.gl)
danakj53f7ec902016-05-21 01:30:101122 return; // Unable to get/create a shared main thread context.
1123 if (!context_3d.gr_context)
1124 return; // The context has been lost since and can't setup a GrContext.
dongseong.hwang0c4e9d82015-01-08 20:11:131125 }
Kai Ninomiyaef8c9e02017-09-27 04:07:401126 if (out_metadata && video_frame) {
Kai Ninomiya9e8ae29b2017-09-06 23:45:161127 // WebGL last-uploaded-frame-metadata API enabled. https://crbug.com/639174
1128 ComputeFrameUploadMetadata(video_frame.get(), already_uploaded_id,
1129 out_metadata);
1130 if (out_metadata->skipped) {
1131 // Skip uploading this frame.
1132 return;
1133 }
1134 }
zhuoyu.qian4689dde22017-10-16 04:11:481135 video_renderer_.Paint(
Julien Isorce6c83d8de2017-10-12 13:11:291136 video_frame, canvas, gfx::RectF(gfx_rect), flags,
1137 pipeline_metadata_.video_decoder_config.video_rotation(), context_3d);
[email protected]ec9212f2008-12-18 21:40:361138}
[email protected]5df51652009-01-17 00:03:001139
Matt Falkenhagenb147c5f2018-02-02 03:17:351140bool WebMediaPlayerImpl::DidGetOpaqueResponseFromServiceWorker() const {
1141 if (data_source_)
1142 return data_source_->DidGetOpaqueResponseViaServiceWorker();
1143 return false;
1144}
1145
Blink Reformat1c4d759e2017-04-09 16:34:541146bool WebMediaPlayerImpl::HasSingleSecurityOrigin() const {
Thomas Guilbert153f84572018-07-19 05:03:581147 if (demuxer_found_hls_) {
1148 // HLS manifests might pull segments from a different origin. We can't know
1149 // for sure, so we conservatively say no here.
1150 return false;
1151 }
1152
[email protected]b49beeb2013-03-01 20:04:001153 if (data_source_)
1154 return data_source_->HasSingleOrigin();
[email protected]fcdb7462009-10-21 21:05:111155 return true;
[email protected]38259a7a82009-07-29 21:49:491156}
1157
Blink Reformat1c4d759e2017-04-09 16:34:541158bool WebMediaPlayerImpl::DidPassCORSAccessCheck() const {
[email protected]b49beeb2013-03-01 20:04:001159 if (data_source_)
1160 return data_source_->DidPassCORSAccessCheck();
1161 return false;
[email protected]3fe27112012-06-07 04:00:011162}
1163
Blink Reformat1c4d759e2017-04-09 16:34:541164double WebMediaPlayerImpl::MediaTimeForTimeValue(double timeValue) const {
qinminb4c39782015-08-10 18:43:241165 return base::TimeDelta::FromSecondsD(timeValue).InSecondsF();
[email protected]e06e16d82011-05-26 22:13:331166}
1167
Blink Reformat1c4d759e2017-04-09 16:34:541168unsigned WebMediaPlayerImpl::DecodedFrameCount() const {
acolwellb4034942014-08-28 15:42:431169 DCHECK(main_task_runner_->BelongsToCurrentThread());
Dale Curtisc7d2a7d22018-01-11 20:01:051170 return GetPipelineStatistics().video_frames_decoded;
[email protected]4c51bc662011-02-16 02:03:161171}
1172
Blink Reformat1c4d759e2017-04-09 16:34:541173unsigned WebMediaPlayerImpl::DroppedFrameCount() const {
acolwellb4034942014-08-28 15:42:431174 DCHECK(main_task_runner_->BelongsToCurrentThread());
Dale Curtisc7d2a7d22018-01-11 20:01:051175 return GetPipelineStatistics().video_frames_dropped;
[email protected]4c51bc662011-02-16 02:03:161176}
1177
Dave Tapuska6c7154912018-07-30 20:39:001178uint64_t WebMediaPlayerImpl::AudioDecodedByteCount() const {
acolwellb4034942014-08-28 15:42:431179 DCHECK(main_task_runner_->BelongsToCurrentThread());
Dale Curtisc7d2a7d22018-01-11 20:01:051180 return GetPipelineStatistics().audio_bytes_decoded;
[email protected]4c51bc662011-02-16 02:03:161181}
1182
Dave Tapuska6c7154912018-07-30 20:39:001183uint64_t WebMediaPlayerImpl::VideoDecodedByteCount() const {
acolwellb4034942014-08-28 15:42:431184 DCHECK(main_task_runner_->BelongsToCurrentThread());
Dale Curtisc7d2a7d22018-01-11 20:01:051185 return GetPipelineStatistics().video_bytes_decoded;
[email protected]4c51bc662011-02-16 02:03:161186}
1187
Blink Reformat1c4d759e2017-04-09 16:34:541188bool WebMediaPlayerImpl::CopyVideoTextureToPlatformTexture(
danakj46070b02016-03-28 21:54:111189 gpu::gles2::GLES2Interface* gl,
jiajia.qinc2943162017-05-12 01:34:391190 unsigned int target,
zmo57d577a2015-10-30 18:28:591191 unsigned int texture,
kbr0986e622017-04-13 02:34:581192 unsigned internal_format,
1193 unsigned format,
1194 unsigned type,
jiajia.qinc2943162017-05-12 01:34:391195 int level,
zmo57d577a2015-10-30 18:28:591196 bool premultiply_alpha,
Kai Ninomiya9e8ae29b2017-09-06 23:45:161197 bool flip_y,
1198 int already_uploaded_id,
1199 VideoFrameUploadMetadata* out_metadata) {
xhwang213e50c2016-10-10 23:56:311200 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]bfc05f22013-10-19 17:55:161201 TRACE_EVENT0("media", "WebMediaPlayerImpl:copyVideoTextureToPlatformTexture");
1202
watkd16bb3e2017-04-25 01:18:311203 // We can't copy from protected frames.
Xiaohan Wang24cfe2c2018-01-22 23:16:001204 if (cdm_context_ref_)
xhwang213e50c2016-10-10 23:56:311205 return false;
[email protected]dd061e12014-05-06 19:21:221206
xhwang213e50c2016-10-10 23:56:311207 scoped_refptr<VideoFrame> video_frame = GetCurrentFrameFromCompositor();
jbauman581d041c2016-07-21 01:01:031208 if (!video_frame.get() || !video_frame->HasTextures()) {
[email protected]e56f88c72013-06-25 22:31:291209 return false;
dongseong.hwang0c4e9d82015-01-08 20:11:131210 }
Kai Ninomiya9e8ae29b2017-09-06 23:45:161211 if (out_metadata) {
1212 // WebGL last-uploaded-frame-metadata API is enabled.
1213 // https://crbug.com/639174
1214 ComputeFrameUploadMetadata(video_frame.get(), already_uploaded_id,
1215 out_metadata);
1216 if (out_metadata->skipped) {
1217 // Skip uploading this frame.
1218 return true;
1219 }
1220 }
[email protected]df41e252014-02-03 23:39:501221
jbauman581d041c2016-07-21 01:01:031222 Context3D context_3d;
CJ DiMeglioc60a5cf2017-09-27 20:08:411223 if (context_provider_) {
1224 context_3d = Context3D(context_provider_->ContextGL(),
1225 context_provider_->GrContext());
1226 }
zhuoyu.qian4689dde22017-10-16 04:11:481227 return video_renderer_.CopyVideoFrameTexturesToGLTexture(
jiajia.qinc2943162017-05-12 01:34:391228 context_3d, gl, video_frame.get(), target, texture, internal_format,
1229 format, type, level, premultiply_alpha, flip_y);
[email protected]6523b242013-03-13 11:10:071230}
1231
Matt Wolenetz95af6362018-01-04 20:23:421232// static
Kai Ninomiya9e8ae29b2017-09-06 23:45:161233void WebMediaPlayerImpl::ComputeFrameUploadMetadata(
1234 VideoFrame* frame,
1235 int already_uploaded_id,
1236 VideoFrameUploadMetadata* out_metadata) {
1237 DCHECK(out_metadata);
Kai Ninomiyaef8c9e02017-09-27 04:07:401238 DCHECK(frame);
Kai Ninomiya9e8ae29b2017-09-06 23:45:161239 out_metadata->frame_id = frame->unique_id();
1240 out_metadata->visible_rect = frame->visible_rect();
1241 out_metadata->timestamp = frame->timestamp();
1242 bool skip_possible = already_uploaded_id != -1;
1243 bool same_frame_id = frame->unique_id() == already_uploaded_id;
1244 out_metadata->skipped = skip_possible && same_frame_id;
1245}
1246
Blink Reformat1c4d759e2017-04-09 16:34:541247void WebMediaPlayerImpl::SetContentDecryptionModule(
[email protected]9ebc3b03f2014-08-13 04:01:231248 blink::WebContentDecryptionModule* cdm,
1249 blink::WebContentDecryptionModuleResult result) {
xhwang51139732017-02-24 19:36:081250 DVLOG(1) << __func__ << ": cdm = " << cdm;
acolwellb4034942014-08-28 15:42:431251 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]9ebc3b03f2014-08-13 04:01:231252
jrummell06f27072015-06-08 18:12:381253 // Once the CDM is set it can't be cleared as there may be frames being
1254 // decrypted on other threads. So fail this request.
1255 // http://crbug.com/462365#c7.
xhwang97de4202014-11-25 08:44:011256 if (!cdm) {
Blink Reformat1c4d759e2017-04-09 16:34:541257 result.CompleteWithError(
1258 blink::kWebContentDecryptionModuleExceptionInvalidStateError, 0,
xhwang79b193042016-12-13 18:52:431259 "The existing ContentDecryptionModule object cannot be removed at this "
1260 "time.");
xhwang97de4202014-11-25 08:44:011261 return;
1262 }
1263
jrummell89e61d82015-07-23 20:03:341264 // Create a local copy of |result| to avoid problems with the callback
1265 // getting passed to the media thread and causing |result| to be destructed
jrummell4acbec912016-02-27 02:45:031266 // on the wrong thread in some failure conditions. Blink should prevent
1267 // multiple simultaneous calls.
1268 DCHECK(!set_cdm_result_);
jrummell89e61d82015-07-23 20:03:341269 set_cdm_result_.reset(new blink::WebContentDecryptionModuleResult(result));
1270
dalecurtis04bdb582016-08-17 22:15:231271 // Recreate the watch time reporter if necessary.
1272 const bool was_encrypted = is_encrypted_;
1273 is_encrypted_ = true;
Dale Curtis3899090ea2018-01-12 00:10:351274 if (!was_encrypted) {
1275 media_metrics_provider_->SetIsEME();
1276 if (watch_time_reporter_)
1277 CreateWatchTimeReporter();
1278 }
dalecurtis04bdb582016-08-17 22:15:231279
Chris Cunninghamd9df58e2017-08-29 00:04:231280 // For now MediaCapabilities only handles clear content.
1281 video_decode_stats_reporter_.reset();
1282
jrummelle616ee92016-10-08 02:15:441283 SetCdm(cdm);
xhwang97de4202014-11-25 08:44:011284}
1285
xhwange8c4181a2014-12-06 08:10:011286void WebMediaPlayerImpl::OnEncryptedMediaInitData(
jrummellcf78967c2015-04-03 05:03:581287 EmeInitDataType init_data_type,
Avi Drissman97785ea2015-12-19 01:11:311288 const std::vector<uint8_t>& init_data) {
jrummellcf78967c2015-04-03 05:03:581289 DCHECK(init_data_type != EmeInitDataType::UNKNOWN);
xhwangbab66f52014-12-02 23:49:501290
Xiaohan Wangf63505d2017-10-21 08:00:531291 RecordEncryptedEvent(true);
xhwangbab66f52014-12-02 23:49:501292
dalecurtis04bdb582016-08-17 22:15:231293 // Recreate the watch time reporter if necessary.
1294 const bool was_encrypted = is_encrypted_;
1295 is_encrypted_ = true;
Dale Curtis3899090ea2018-01-12 00:10:351296 if (!was_encrypted) {
1297 media_metrics_provider_->SetIsEME();
1298 if (watch_time_reporter_)
1299 CreateWatchTimeReporter();
1300 }
dalecurtis04bdb582016-08-17 22:15:231301
Chris Cunninghamd9df58e2017-08-29 00:04:231302 // For now MediaCapabilities only handles clear content.
1303 video_decode_stats_reporter_.reset();
1304
Blink Reformat1c4d759e2017-04-09 16:34:541305 encrypted_client_->Encrypted(
davidbenb50f00c2015-12-01 00:01:501306 ConvertToWebInitDataType(init_data_type), init_data.data(),
srirama.m26f864d02015-07-14 05:21:461307 base::saturated_cast<unsigned int>(init_data.size()));
xhwangbab66f52014-12-02 23:49:501308}
1309
servolk81e01e02016-03-05 03:29:151310void WebMediaPlayerImpl::OnFFmpegMediaTracksUpdated(
dcheng3076abbf2016-04-22 20:42:391311 std::unique_ptr<MediaTracks> tracks) {
servolk81e01e02016-03-05 03:29:151312 // For MSE/chunk_demuxer case the media track updates are handled by
1313 // WebSourceBufferImpl.
1314 DCHECK(demuxer_.get());
1315 DCHECK(!chunk_demuxer_);
servolkef1e5ef2016-03-25 04:55:261316
servolk16e8bdf82017-04-11 17:00:391317 // Report the media track information to blink. Only the first audio track and
1318 // the first video track are enabled by default to match blink logic.
1319 bool is_first_audio_track = true;
1320 bool is_first_video_track = true;
servolkef1e5ef2016-03-25 04:55:261321 for (const auto& track : tracks->tracks()) {
1322 if (track->type() == MediaTrack::Audio) {
Blink Reformat1c4d759e2017-04-09 16:34:541323 client_->AddAudioTrack(blink::WebString::FromUTF8(track->id()),
1324 blink::WebMediaPlayerClient::kAudioTrackKindMain,
1325 blink::WebString::FromUTF8(track->label()),
1326 blink::WebString::FromUTF8(track->language()),
servolk16e8bdf82017-04-11 17:00:391327 is_first_audio_track);
1328 is_first_audio_track = false;
servolkef1e5ef2016-03-25 04:55:261329 } else if (track->type() == MediaTrack::Video) {
Blink Reformat1c4d759e2017-04-09 16:34:541330 client_->AddVideoTrack(blink::WebString::FromUTF8(track->id()),
1331 blink::WebMediaPlayerClient::kVideoTrackKindMain,
1332 blink::WebString::FromUTF8(track->label()),
1333 blink::WebString::FromUTF8(track->language()),
servolk16e8bdf82017-04-11 17:00:391334 is_first_video_track);
1335 is_first_video_track = false;
servolkef1e5ef2016-03-25 04:55:261336 } else {
1337 // Text tracks are not supported through this code path yet.
1338 NOTREACHED();
1339 }
1340 }
servolk81e01e02016-03-05 03:29:151341}
1342
jrummelle616ee92016-10-08 02:15:441343void WebMediaPlayerImpl::SetCdm(blink::WebContentDecryptionModule* cdm) {
1344 DCHECK(main_task_runner_->BelongsToCurrentThread());
1345 DCHECK(cdm);
Xiaohan Wang24cfe2c2018-01-22 23:16:001346
1347 auto cdm_context_ref =
1348 ToWebContentDecryptionModuleImpl(cdm)->GetCdmContextRef();
1349 if (!cdm_context_ref) {
jrummelle616ee92016-10-08 02:15:441350 NOTREACHED();
1351 OnCdmAttached(false);
xhwang80739452016-01-13 00:48:001352 return;
1353 }
1354
Xiaohan Wang24cfe2c2018-01-22 23:16:001355 CdmContext* cdm_context = cdm_context_ref->GetCdmContext();
1356 DCHECK(cdm_context);
jrummelle616ee92016-10-08 02:15:441357
1358 // Keep the reference to the CDM, as it shouldn't be destroyed until
1359 // after the pipeline is done with the |cdm_context|.
Xiaohan Wang24cfe2c2018-01-22 23:16:001360 pending_cdm_context_ref_ = std::move(cdm_context_ref);
tguilbert350936ff2017-02-24 05:39:271361 pipeline_controller_.SetCdm(
1362 cdm_context, base::Bind(&WebMediaPlayerImpl::OnCdmAttached, AsWeakPtr()));
xhwang97de4202014-11-25 08:44:011363}
1364
jrummell89e61d82015-07-23 20:03:341365void WebMediaPlayerImpl::OnCdmAttached(bool success) {
xhwang51139732017-02-24 19:36:081366 DVLOG(1) << __func__ << ": success = " << success;
jrummelle616ee92016-10-08 02:15:441367 DCHECK(main_task_runner_->BelongsToCurrentThread());
Xiaohan Wang24cfe2c2018-01-22 23:16:001368 DCHECK(pending_cdm_context_ref_);
jrummelle616ee92016-10-08 02:15:441369
1370 // If the CDM is set from the constructor there is no promise
1371 // (|set_cdm_result_|) to fulfill.
xhwang97de4202014-11-25 08:44:011372 if (success) {
xhwang29c5ad202017-04-14 07:02:191373 media_log_->SetBooleanProperty("has_cdm", true);
1374
jrummelle616ee92016-10-08 02:15:441375 // This will release the previously attached CDM (if any).
Xiaohan Wang24cfe2c2018-01-22 23:16:001376 cdm_context_ref_ = std::move(pending_cdm_context_ref_);
jrummelle616ee92016-10-08 02:15:441377 if (set_cdm_result_) {
Blink Reformat1c4d759e2017-04-09 16:34:541378 set_cdm_result_->Complete();
jrummelle616ee92016-10-08 02:15:441379 set_cdm_result_.reset();
1380 }
1381
xhwang97de4202014-11-25 08:44:011382 return;
1383 }
1384
Xiaohan Wang24cfe2c2018-01-22 23:16:001385 pending_cdm_context_ref_.reset();
jrummelle616ee92016-10-08 02:15:441386 if (set_cdm_result_) {
Blink Reformat1c4d759e2017-04-09 16:34:541387 set_cdm_result_->CompleteWithError(
1388 blink::kWebContentDecryptionModuleExceptionNotSupportedError, 0,
xhwang79b193042016-12-13 18:52:431389 "Unable to set ContentDecryptionModule object");
jrummelle616ee92016-10-08 02:15:441390 set_cdm_result_.reset();
1391 }
[email protected]9ebc3b03f2014-08-13 04:01:231392}
1393
sandersd1c0bba02016-03-04 23:14:081394void WebMediaPlayerImpl::OnPipelineSeeked(bool time_updated) {
John Chen5b164a02017-11-01 00:36:091395 TRACE_EVENT2("media", "WebMediaPlayerImpl::OnPipelineSeeked", "target",
1396 seek_time_.InSecondsF(), "id", media_log_->id());
[email protected]5d11eff2011-09-15 00:06:061397 seeking_ = false;
wolenetz1b2ae7d2015-06-10 00:44:211398 seek_time_ = base::TimeDelta();
avayvod2135a642017-01-13 00:17:141399
hubbe5a2dec022016-03-17 01:14:231400 if (paused_) {
1401#if defined(OS_ANDROID) // WMPI_CAST
Blink Reformat1c4d759e2017-04-09 16:34:541402 if (IsRemote()) {
Dale Curtis051fdf62017-08-05 00:21:131403 paused_time_ = cast_impl_.currentTime();
hubbe5a2dec022016-03-17 01:14:231404 } else {
tguilbert350936ff2017-02-24 05:39:271405 paused_time_ = pipeline_controller_.GetMediaTime();
hubbe5a2dec022016-03-17 01:14:231406 }
1407#else
tguilbert350936ff2017-02-24 05:39:271408 paused_time_ = pipeline_controller_.GetMediaTime();
hubbe5a2dec022016-03-17 01:14:231409#endif
dalecurtis04bdb582016-08-17 22:15:231410 } else {
1411 DCHECK(watch_time_reporter_);
1412 watch_time_reporter_->OnPlaying();
hubbe5a2dec022016-03-17 01:14:231413 }
sandersd1c0bba02016-03-04 23:14:081414 if (time_updated)
1415 should_notify_time_changed_ = true;
dalecurtisaf34d8712016-09-20 04:32:261416
dalecurtis4f6d14d2017-02-22 17:42:221417 // Reset underflow duration upon seek; this prevents looping videos and user
1418 // actions from artificially inflating the duration.
1419 underflow_timer_.reset();
avayvod56e1f3942017-01-21 02:06:311420
1421 // Background video optimizations are delayed when shown/hidden if pipeline
1422 // is seeking.
1423 UpdateBackgroundVideoOptimizationState();
Dale Curtis2dc6089a2018-03-26 16:47:581424
1425 // If we successfully completed a suspended startup, lie about our buffering
1426 // state for the time being. While ultimately we want to avoid lying about the
1427 // buffering state, for the initial test of true preload=metadata, signal
1428 // BUFFERING_HAVE_ENOUGH so that canplay and canplaythrough fire correctly.
1429 //
1430 // Later we can experiment with the impact of removing this lie; initial data
1431 // suggests high disruption since we've also made preload=metadata the
1432 // default. Most sites are not prepared for a lack of canplay; even many of
1433 // our own tests don't function correctly. See https://crbug.com/694855.
1434 //
1435 // Note: This call is dual purpose, it is also responsible for triggering an
1436 // UpdatePlayState() call which may need to resume the pipeline once Blink
1437 // has been told about the ReadyState change.
1438 if (attempting_suspended_start_ &&
1439 pipeline_controller_.IsPipelineSuspended()) {
Dale Curtisff576552018-03-30 02:32:441440 skip_metrics_due_to_startup_suspend_ = true;
Dale Curtis2dc6089a2018-03-26 16:47:581441 OnBufferingStateChangeInternal(BUFFERING_HAVE_ENOUGH, true);
Dale Curtisff576552018-03-30 02:32:441442
1443 // If |skip_metrics_due_to_startup_suspend_| is unset by a resume started by
1444 // the OnBufferingStateChangeInternal() call, record a histogram of it here.
1445 //
1446 // If the value is unset, that means we should not have suspended and we've
1447 // likely incurred some cost to TimeToFirstFrame and TimeToPlayReady which
1448 // will be reflected in those statistics.
1449 base::UmaHistogramBoolean(
1450 std::string("Media.PreloadMetadataSuspendWasIdeal.") +
1451 ((HasVideo() && HasAudio()) ? "AudioVideo"
1452 : (HasVideo() ? "Video" : "Audio")),
1453 skip_metrics_due_to_startup_suspend_);
Dale Curtis2dc6089a2018-03-26 16:47:581454 }
1455
1456 attempting_suspended_start_ = false;
[email protected]8931c41a2009-07-07 17:31:491457}
1458
sandersd1c0bba02016-03-04 23:14:081459void WebMediaPlayerImpl::OnPipelineSuspended() {
hubbed5f36882016-01-15 22:40:371460#if defined(OS_ANDROID)
avayvod82729272017-05-29 21:58:391461 if (IsRemote() && !IsNewRemotePlaybackPipelineEnabled()) {
hubbed5f36882016-01-15 22:40:371462 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner();
sandersd50a635e2016-04-04 22:50:091463 if (frame)
dalecurtise9c89e92016-05-20 19:38:001464 compositor_->PaintSingleFrame(frame);
hubbed5f36882016-01-15 22:40:371465 }
1466#endif
1467
sandersd2f5bb6152017-03-29 22:57:531468 // Tell the data source we have enough data so that it may release the
1469 // connection.
1470 if (data_source_)
1471 data_source_->OnBufferingHaveEnough(true);
dalecurtis37fe5862016-03-15 19:29:091472
sandersd50a635e2016-04-04 22:50:091473 ReportMemoryUsage();
1474
sandersd1c0bba02016-03-04 23:14:081475 if (pending_suspend_resume_cycle_) {
watkdee516f2016-02-18 02:22:191476 pending_suspend_resume_cycle_ = false;
sandersd50a635e2016-04-04 22:50:091477 UpdatePlayState();
dalecurtis0431cbf2016-03-12 01:19:431478 }
sandersd1c0bba02016-03-04 23:14:081479}
1480
avayvod2135a642017-01-13 00:17:141481void WebMediaPlayerImpl::OnBeforePipelineResume() {
Dale Curtisff576552018-03-30 02:32:441482 // We went through suspended startup, so the player is only just now spooling
1483 // up for playback. As such adjust |load_start_time_| so it reports the same
1484 // metric as what would be reported if we had not suspended at startup.
1485 if (skip_metrics_due_to_startup_suspend_) {
1486 // In the event that the call to SetReadyState() initiated after pipeline
1487 // startup immediately tries to start playback, we should not update
1488 // |load_start_time_| to avoid losing visibility into the impact of a
1489 // suspended startup on the time until first frame / play ready for cases
1490 // where suspended startup was applied incorrectly.
1491 if (!attempting_suspended_start_)
1492 load_start_time_ = base::TimeTicks::Now() - time_to_metadata_;
1493 skip_metrics_due_to_startup_suspend_ = false;
1494 }
1495
avayvod2135a642017-01-13 00:17:141496 // Enable video track if we disabled it in the background - this way the new
1497 // renderer will attach its callbacks to the video stream properly.
1498 // TODO(avayvod): Remove this when disabling and enabling video tracks in
1499 // non-playing state works correctly. See https://crbug.com/678374.
1500 EnableVideoTrackIfNeeded();
1501 is_pipeline_resuming_ = true;
1502}
1503
1504void WebMediaPlayerImpl::OnPipelineResumed() {
1505 is_pipeline_resuming_ = false;
1506
avayvod56e1f3942017-01-21 02:06:311507 UpdateBackgroundVideoOptimizationState();
avayvod2135a642017-01-13 00:17:141508}
1509
alokp967c902452016-05-06 05:21:371510void WebMediaPlayerImpl::OnDemuxerOpened() {
1511 DCHECK(main_task_runner_->BelongsToCurrentThread());
dalecurtis9cddc0b2017-04-19 21:23:381512 client_->MediaSourceOpened(new WebMediaSourceImpl(chunk_demuxer_));
alokp967c902452016-05-06 05:21:371513}
1514
servolkf94b4602017-01-31 16:44:271515void WebMediaPlayerImpl::OnMemoryPressure(
1516 base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
1517 DVLOG(2) << __func__ << " memory_pressure_level=" << memory_pressure_level;
1518 DCHECK(main_task_runner_->BelongsToCurrentThread());
1519 DCHECK(base::FeatureList::IsEnabled(kMemoryPressureBasedSourceBufferGC));
1520 DCHECK(chunk_demuxer_);
1521
1522 // The new value of |memory_pressure_level| will take effect on the next
1523 // garbage collection. Typically this means the next SourceBuffer append()
1524 // operation, since per MSE spec, the garbage collection must only occur
1525 // during SourceBuffer append(). But if memory pressure is critical it might
1526 // be better to perform GC immediately rather than wait for the next append
1527 // and potentially get killed due to out-of-memory.
1528 // So if this experiment is enabled and pressure level is critical, we'll pass
1529 // down force_instant_gc==true, which will force immediate GC on
1530 // SourceBufferStreams.
1531 bool force_instant_gc =
1532 (enable_instant_source_buffer_gc_ &&
1533 memory_pressure_level ==
1534 base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
1535
Matt Wolenetz95af6362018-01-04 20:23:421536 // base::Unretained is safe, since |chunk_demuxer_| is actually owned by
1537 // |this| via this->demuxer_. Note the destruction of |chunk_demuxer_| is done
1538 // from ~WMPI by first hopping to |media_task_runner_| to prevent race with
1539 // this task.
servolkf94b4602017-01-31 16:44:271540 media_task_runner_->PostTask(
1541 FROM_HERE, base::Bind(&ChunkDemuxer::OnMemoryPressure,
1542 base::Unretained(chunk_demuxer_),
Blink Reformat1c4d759e2017-04-09 16:34:541543 base::TimeDelta::FromSecondsD(CurrentTime()),
servolkf94b4602017-01-31 16:44:271544 memory_pressure_level, force_instant_gc));
1545}
1546
alokp967c902452016-05-06 05:21:371547void WebMediaPlayerImpl::OnError(PipelineStatus status) {
pkastingf5279482016-07-27 02:18:201548 DVLOG(1) << __func__;
alokp967c902452016-05-06 05:21:371549 DCHECK(main_task_runner_->BelongsToCurrentThread());
1550 DCHECK_NE(status, PIPELINE_OK);
1551
1552 if (suppress_destruction_errors_)
1553 return;
1554
Thomas Guilbert6b6be3d2017-08-18 03:17:271555#if defined(OS_ANDROID)
1556 if (status == PipelineStatus::DEMUXER_ERROR_DETECTED_HLS) {
Thomas Guilbert153f84572018-07-19 05:03:581557 demuxer_found_hls_ = true;
1558
Thomas Guilbert6b6be3d2017-08-18 03:17:271559 renderer_factory_selector_->SetUseMediaPlayer(true);
1560
1561 pipeline_controller_.Stop();
Dale Curtis8a6281322017-08-31 00:35:531562 SetMemoryReportingState(false);
Thomas Guilbert6b6be3d2017-08-18 03:17:271563
1564 main_task_runner_->PostTask(
1565 FROM_HERE, base::Bind(&WebMediaPlayerImpl::StartPipeline, AsWeakPtr()));
1566 return;
1567 }
1568#endif
1569
Dale Curtis5bba03232018-08-30 17:57:381570 MaybeSetContainerName();
dalecurtis9cddc0b2017-04-19 21:23:381571 ReportPipelineError(load_type_, status, media_log_.get());
alokp967c902452016-05-06 05:21:371572 media_log_->AddEvent(media_log_->CreatePipelineErrorEvent(status));
Dale Curtis74612b72017-12-14 20:56:191573 media_metrics_provider_->OnError(status);
Dale Curtisccfd0cca2017-08-31 01:27:561574 if (watch_time_reporter_)
1575 watch_time_reporter_->OnError(status);
alokp967c902452016-05-06 05:21:371576
Blink Reformat1c4d759e2017-04-09 16:34:541577 if (ready_state_ == WebMediaPlayer::kReadyStateHaveNothing) {
alokp967c902452016-05-06 05:21:371578 // Any error that occurs before reaching ReadyStateHaveMetadata should
1579 // be considered a format error.
Blink Reformat1c4d759e2017-04-09 16:34:541580 SetNetworkState(WebMediaPlayer::kNetworkStateFormatError);
alokp967c902452016-05-06 05:21:371581 } else {
1582 SetNetworkState(PipelineErrorToNetworkState(status));
1583 }
1584
Thomas Guilbert2e591392017-08-12 00:56:381585 // PipelineController::Stop() is idempotent.
1586 pipeline_controller_.Stop();
1587
alokp967c902452016-05-06 05:21:371588 UpdatePlayState();
1589}
1590
1591void WebMediaPlayerImpl::OnEnded() {
John Chen5b164a02017-11-01 00:36:091592 TRACE_EVENT2("media", "WebMediaPlayerImpl::OnEnded", "duration", Duration(),
1593 "id", media_log_->id());
pkastingf5279482016-07-27 02:18:201594 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:431595 DCHECK(main_task_runner_->BelongsToCurrentThread());
scherkusd2c745b2014-09-04 05:03:401596
sandersd1c0bba02016-03-04 23:14:081597 // Ignore state changes until we've completed all outstanding operations.
1598 if (!pipeline_controller_.IsStable())
scherkusd2c745b2014-09-04 05:03:401599 return;
1600
1601 ended_ = true;
Blink Reformat1c4d759e2017-04-09 16:34:541602 client_->TimeChanged();
sandersd50a635e2016-04-04 22:50:091603
dalecurtis1af3c1a2017-04-11 00:53:491604 // Clear any new frame processed callbacks on end; otherwise we'll end up
1605 // logging a time long after playback ends.
1606 frame_time_report_cb_.Cancel();
1607
sandersd50a635e2016-04-04 22:50:091608 // We don't actually want this to run until |client_| calls seek() or pause(),
1609 // but that should have already happened in timeChanged() and so this is
1610 // expected to be a no-op.
1611 UpdatePlayState();
[email protected]576537842009-08-12 23:52:051612}
1613
alokp967c902452016-05-06 05:21:371614void WebMediaPlayerImpl::OnMetadata(PipelineMetadata metadata) {
pkastingf5279482016-07-27 02:18:201615 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:431616 DCHECK(main_task_runner_->BelongsToCurrentThread());
Dale Curtisff576552018-03-30 02:32:441617
1618 // Cache the |time_to_metadata_| to use for adjusting the TimeToFirstFrame and
1619 // TimeToPlayReady metrics later if we end up doing a suspended startup.
1620 time_to_metadata_ = base::TimeTicks::Now() - load_start_time_;
1621 media_metrics_provider_->SetTimeToMetadata(time_to_metadata_);
1622 RecordTimingUMA("Media.TimeToMetadata", time_to_metadata_);
[email protected]a8e2cb82012-08-17 00:02:391623
Dale Curtis5bba03232018-08-30 17:57:381624 MaybeSetContainerName();
1625
[email protected]b8877772014-03-26 20:17:151626 pipeline_metadata_ = metadata;
[email protected]739847c02014-01-16 00:12:251627
Blink Reformat1c4d759e2017-04-09 16:34:541628 SetReadyState(WebMediaPlayer::kReadyStateHaveMetadata);
Julien Isorce6c83d8de2017-10-12 13:11:291629 UMA_HISTOGRAM_ENUMERATION("Media.VideoRotation",
1630 metadata.video_decoder_config.video_rotation(),
acolwell9e0840d2014-09-06 19:01:321631 VIDEO_ROTATION_MAX + 1);
[email protected]21c3f7502013-03-23 03:29:511632
John Rummelldb5a7ef2018-05-16 00:28:011633 if (HasAudio()) {
1634 RecordEncryptionScheme("Audio",
1635 metadata.audio_decoder_config.encryption_scheme());
1636 }
1637
Blink Reformat1c4d759e2017-04-09 16:34:541638 if (HasVideo()) {
John Rummelldb5a7ef2018-05-16 00:28:011639 RecordEncryptionScheme("Video",
1640 metadata.video_decoder_config.encryption_scheme());
1641
liberato2fd111be2017-01-04 00:25:061642 if (overlay_enabled_) {
1643 // SurfaceView doesn't support rotated video, so transition back if
[email protected]c8d574722017-08-30 20:53:431644 // the video is now rotated. If |always_enable_overlays_|, we keep the
liberato2fd111be2017-01-04 00:25:061645 // overlay anyway so that the state machine keeps working.
[email protected]c8d574722017-08-30 20:53:431646 // TODO(liberato): verify if compositor feedback catches this. If so,
1647 // then we don't need this check.
1648 if (!always_enable_overlays_ && !DoesOverlaySupportMetadata())
liberato2fd111be2017-01-04 00:25:061649 DisableOverlay();
liberato2fd111be2017-01-04 00:25:061650 }
watkf835a792016-06-24 23:24:401651
lethalantidote7f6009d2017-07-07 21:47:391652 if (!surface_layer_for_video_enabled_) {
danakj6e669e782018-05-16 16:57:171653 DCHECK(!video_layer_);
danakj25f030112018-05-11 18:26:541654 video_layer_ = cc::VideoLayer::Create(
Julien Isorce6c83d8de2017-10-12 13:11:291655 compositor_.get(),
danakj25f030112018-05-11 18:26:541656 pipeline_metadata_.video_decoder_config.video_rotation());
danakj8bc61c72018-05-16 13:55:061657 video_layer_->SetContentsOpaque(opaque_);
danakj8d204a42018-05-18 18:05:351658 client_->SetCcLayer(video_layer_.get());
CJ DiMeglio7b8b5b6e2018-02-07 01:58:421659 } else {
CJ DiMeglio96c18b692018-07-04 03:39:061660 DCHECK(!bridge_);
1661
CJ DiMeglio3f2ddfe62018-07-17 23:03:371662 bridge_ = std::move(create_bridge_callback_)
1663 .Run(this, compositor_->GetUpdateSubmissionStateCallback());
CJ DiMeglio96c18b692018-07-04 03:39:061664 bridge_->CreateSurfaceLayer();
CJ DiMeglio3f2ddfe62018-07-17 23:03:371665
CJ DiMeglio7b8b5b6e2018-02-07 01:58:421666 vfc_task_runner_->PostTask(
1667 FROM_HERE,
1668 base::BindOnce(
1669 &VideoFrameCompositor::EnableSubmission,
CJ DiMeglio3f2ddfe62018-07-17 23:03:371670 base::Unretained(compositor_.get()), bridge_->GetSurfaceId(),
CJ DiMegliodf92bfe2018-05-11 20:11:001671 pipeline_metadata_.video_decoder_config.video_rotation(),
CJ DiMeglio27211372018-07-27 23:17:441672 IsInPictureInPicture(), opaque_,
CJ DiMegliodf92bfe2018-05-11 20:11:001673 BindToCurrentLoop(base::BindRepeating(
1674 &WebMediaPlayerImpl::OnFrameSinkDestroyed, AsWeakPtr()))));
CJ DiMeglioa2b13fbc2018-06-27 00:50:591675 bridge_->SetContentsOpaque(opaque_);
Mounir Lamourie8bd6852018-08-09 03:49:221676
1677 // If the element is already in Picture-in-Picture mode, it means that it
1678 // was set in this mode prior to this load, with a different
1679 // WebMediaPlayerImpl. The new player needs to send its id, size and
1680 // surface id to the browser process to make sure the states are properly
1681 // updated.
1682 // TODO(872056): the surface should be activated but for some reasons, it
1683 // does not. It is possible that this will no longer be neded after 872056
1684 // is fixed.
1685 if (client_->DisplayType() ==
1686 WebMediaPlayer::DisplayType::kPictureInPicture) {
1687 OnSurfaceIdUpdated(bridge_->GetSurfaceId());
1688 }
lethalantidote7f6009d2017-07-07 21:47:391689 }
[email protected]a8e2cb82012-08-17 00:02:391690 }
dalecurtis8e4dc682016-03-15 02:30:301691
xjzd3fe45a2016-10-12 18:26:371692 if (observer_)
xjz15b483f2017-01-12 00:21:361693 observer_->OnMetadataChanged(pipeline_metadata_);
xjzd3fe45a2016-10-12 18:26:371694
Dale Curtisc7d2a7d22018-01-11 20:01:051695 // TODO(dalecurtis): Don't create these until kReadyStateHaveFutureData; when
1696 // we create them early we just increase the chances of needing to throw them
1697 // away unnecessarily.
dalecurtis04bdb582016-08-17 22:15:231698 CreateWatchTimeReporter();
Chris Cunninghamd9df58e2017-08-29 00:04:231699 CreateVideoDecodeStatsReporter();
Dale Curtisc7d2a7d22018-01-11 20:01:051700
sandersd50a635e2016-04-04 22:50:091701 UpdatePlayState();
[email protected]a8e2cb82012-08-17 00:02:391702}
1703
CJ DiMegliodf92bfe2018-05-11 20:11:001704void WebMediaPlayerImpl::OnFrameSinkDestroyed() {
1705 bridge_->ClearSurfaceId();
1706}
1707
Dale Curtis2dc6089a2018-03-26 16:47:581708void WebMediaPlayerImpl::OnBufferingStateChange(BufferingState state) {
1709 OnBufferingStateChangeInternal(state, false);
1710}
1711
Chris Cunninghamd9df58e2017-08-29 00:04:231712void WebMediaPlayerImpl::CreateVideoDecodeStatsReporter() {
1713 // TODO(chcunningham): destroy reporter if we initially have video but the
1714 // track gets disabled. Currently not possible in default desktop Chrome.
1715 if (!HasVideo())
1716 return;
1717
1718 // Stats reporter requires a valid config. We may not have one for HLS cases
1719 // where URL demuxer doesn't know details of the stream.
1720 if (!pipeline_metadata_.video_decoder_config.IsValidConfig())
1721 return;
1722
1723 // For now MediaCapabilities only handles clear content.
1724 // TODO(chcunningham): Report encrypted stats.
1725 if (is_encrypted_)
1726 return;
1727
Dale Curtis7e8a510d2017-12-14 19:19:481728 mojom::VideoDecodeStatsRecorderPtr recorder;
1729 media_metrics_provider_->AcquireVideoDecodeStatsRecorder(
Dale Curtis7e8a510d2017-12-14 19:19:481730 mojo::MakeRequest(&recorder));
Chris Cunninghamc7c6a6d2017-11-23 14:06:451731
Chris Cunninghamd9df58e2017-08-29 00:04:231732 // Create capabilities reporter and synchronize its initial state.
1733 video_decode_stats_reporter_.reset(new VideoDecodeStatsReporter(
Chris Cunninghamc7c6a6d2017-11-23 14:06:451734 std::move(recorder),
Chris Cunninghamd9df58e2017-08-29 00:04:231735 base::Bind(&WebMediaPlayerImpl::GetPipelineStatistics,
1736 base::Unretained(this)),
Hajime Hoshi6c3194b52017-12-15 03:02:111737 pipeline_metadata_.video_decoder_config,
Hajime Hoshib5a26ee2018-05-14 12:47:511738 frame_->GetTaskRunner(blink::TaskType::kInternalMedia)));
Chris Cunninghamd9df58e2017-08-29 00:04:231739
1740 if (delegate_->IsFrameHidden())
1741 video_decode_stats_reporter_->OnHidden();
1742 else
1743 video_decode_stats_reporter_->OnShown();
1744
1745 if (paused_)
1746 video_decode_stats_reporter_->OnPaused();
1747 else
1748 video_decode_stats_reporter_->OnPlaying();
1749}
1750
hubbeb2d3efd2017-05-05 23:26:381751void WebMediaPlayerImpl::OnProgress() {
Chris Watkins1ffabc5f2017-05-10 20:52:091752 DVLOG(4) << __func__;
hubbeb2d3efd2017-05-05 23:26:381753 if (highest_ready_state_ < ReadyState::kReadyStateHaveFutureData) {
1754 // Reset the preroll attempt clock.
1755 preroll_attempt_pending_ = true;
1756 preroll_attempt_start_time_ = base::TimeTicks();
1757
1758 // Clear any 'stale' flag and give the pipeline a chance to resume. If we
1759 // are already resumed, this will cause |preroll_attempt_start_time_| to
1760 // be set.
1761 delegate_->ClearStaleFlag(delegate_id_);
1762 UpdatePlayState();
1763 } else if (ready_state_ == ReadyState::kReadyStateHaveFutureData &&
1764 CanPlayThrough()) {
1765 SetReadyState(WebMediaPlayer::kReadyStateHaveEnoughData);
1766 }
1767}
1768
1769bool WebMediaPlayerImpl::CanPlayThrough() {
1770 if (!base::FeatureList::IsEnabled(kSpecCompliantCanPlayThrough))
1771 return true;
1772 if (chunk_demuxer_)
1773 return true;
1774 if (data_source_ && data_source_->assume_fully_buffered())
1775 return true;
1776 // If we're not currently downloading, we have as much buffer as
1777 // we're ever going to get, which means we say we can play through.
1778 if (network_state_ == WebMediaPlayer::kNetworkStateIdle)
1779 return true;
1780 return buffered_data_source_host_.CanPlayThrough(
1781 base::TimeDelta::FromSecondsD(CurrentTime()),
1782 base::TimeDelta::FromSecondsD(Duration()),
1783 playback_rate_ == 0.0 ? 1.0 : playback_rate_);
1784}
1785
Dale Curtisff576552018-03-30 02:32:441786void WebMediaPlayerImpl::OnBufferingStateChangeInternal(
1787 BufferingState state,
1788 bool for_suspended_start) {
pkastingf5279482016-07-27 02:18:201789 DVLOG(1) << __func__ << "(" << state << ")";
alokp967c902452016-05-06 05:21:371790 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]b8877772014-03-26 20:17:151791
Ted Meyer742212b82018-08-22 17:21:421792 // Ignore buffering state changes caused by back-to-back seeking, so as not
1793 // to assume the second seek has finished when it was only the first seek.
1794 if (pipeline_controller_.IsPendingSeek())
[email protected]ba7d5f92014-06-24 05:37:401795 return;
[email protected]b8877772014-03-26 20:17:151796
Dale Curtisff576552018-03-30 02:32:441797 auto log_event = media_log_->CreateBufferingStateChangedEvent(
1798 "pipeline_buffering_state", state);
1799 log_event->params.SetBoolean("for_suspended_start", for_suspended_start);
1800 media_log_->AddEvent(std::move(log_event));
dalecurtis869bf2f2017-01-10 18:01:101801
chcunninghameb270c92016-07-15 01:00:451802 if (state == BUFFERING_HAVE_ENOUGH) {
John Chen5b164a02017-11-01 00:36:091803 TRACE_EVENT1("media", "WebMediaPlayerImpl::BufferingHaveEnough", "id",
1804 media_log_->id());
Dale Curtisff576552018-03-30 02:32:441805 // The SetReadyState() call below may clear
1806 // |skip_metrics_due_to_startup_suspend_| so report this first.
1807 if (!have_reported_time_to_play_ready_ &&
1808 !skip_metrics_due_to_startup_suspend_) {
1809 DCHECK(!for_suspended_start);
Dale Curtis3899090ea2018-01-12 00:10:351810 have_reported_time_to_play_ready_ = true;
1811 const base::TimeDelta elapsed = base::TimeTicks::Now() - load_start_time_;
1812 media_metrics_provider_->SetTimeToPlayReady(elapsed);
1813 RecordTimingUMA("Media.TimeToPlayReady", elapsed);
1814 }
[email protected]ba7d5f92014-06-24 05:37:401815
Dale Curtisff576552018-03-30 02:32:441816 // Warning: This call may be re-entrant.
1817 SetReadyState(CanPlayThrough() ? WebMediaPlayer::kReadyStateHaveEnoughData
1818 : WebMediaPlayer::kReadyStateHaveFutureData);
1819
chcunninghameb270c92016-07-15 01:00:451820 // Let the DataSource know we have enough data. It may use this information
1821 // to release unused network connections.
Fredrik Hubinette6dd3f3222018-05-24 01:00:511822 if (data_source_ && !client_->CouldPlayIfEnoughData())
chcunninghameb270c92016-07-15 01:00:451823 data_source_->OnBufferingHaveEnough(false);
dalecurtis849cf4b22015-03-27 18:35:451824
chcunninghameb270c92016-07-15 01:00:451825 // Blink expects a timeChanged() in response to a seek().
sandersd35d2c3f2017-01-14 02:04:421826 if (should_notify_time_changed_) {
1827 should_notify_time_changed_ = false;
Blink Reformat1c4d759e2017-04-09 16:34:541828 client_->TimeChanged();
sandersd35d2c3f2017-01-14 02:04:421829 }
dalecurtis0f0097a2015-12-01 17:40:471830
chcunninghameb270c92016-07-15 01:00:451831 // Once we have enough, start reporting the total memory usage. We'll also
1832 // report once playback starts.
1833 ReportMemoryUsage();
dalecurtis9d638a12016-08-30 06:20:551834
dalecurtis4f6d14d2017-02-22 17:42:221835 // Report the amount of time it took to leave the underflow state.
1836 if (underflow_timer_) {
1837 RecordUnderflowDuration(underflow_timer_->Elapsed());
dalecurtis9d638a12016-08-30 06:20:551838 underflow_timer_.reset();
1839 }
chcunninghameb270c92016-07-15 01:00:451840 } else {
1841 // Buffering has underflowed.
1842 DCHECK_EQ(state, BUFFERING_HAVE_NOTHING);
dalecurtisacd77d62016-09-09 23:23:141843
dalecurtisd06eabc2017-02-24 23:43:291844 // Report the number of times we've entered the underflow state. Ensure we
1845 // only report the value when transitioning from HAVE_ENOUGH to
1846 // HAVE_NOTHING.
Dale Curtis6995b862017-05-31 22:20:081847 if (ready_state_ == WebMediaPlayer::kReadyStateHaveEnoughData &&
1848 !seeking_) {
dalecurtisacd77d62016-09-09 23:23:141849 underflow_timer_.reset(new base::ElapsedTimer());
Dale Curtis6995b862017-05-31 22:20:081850 watch_time_reporter_->OnUnderflow();
1851 }
dalecurtisacd77d62016-09-09 23:23:141852
chcunninghameb270c92016-07-15 01:00:451853 // It shouldn't be possible to underflow if we've not advanced past
1854 // HAVE_CURRENT_DATA.
Blink Reformat1c4d759e2017-04-09 16:34:541855 DCHECK_GT(highest_ready_state_, WebMediaPlayer::kReadyStateHaveCurrentData);
1856 SetReadyState(WebMediaPlayer::kReadyStateHaveCurrentData);
chcunninghameb270c92016-07-15 01:00:451857 }
sandersd50a635e2016-04-04 22:50:091858
1859 UpdatePlayState();
[email protected]b8877772014-03-26 20:17:151860}
1861
alokp967c902452016-05-06 05:21:371862void WebMediaPlayerImpl::OnDurationChange() {
acolwellb4034942014-08-28 15:42:431863 DCHECK(main_task_runner_->BelongsToCurrentThread());
alokp967c902452016-05-06 05:21:371864
1865 // TODO(sandersd): We should call delegate_->DidPlay() with the new duration,
1866 // especially if it changed from <5s to >5s.
Blink Reformat1c4d759e2017-04-09 16:34:541867 if (ready_state_ == WebMediaPlayer::kReadyStateHaveNothing)
alokp967c902452016-05-06 05:21:371868 return;
1869
Blink Reformat1c4d759e2017-04-09 16:34:541870 client_->DurationChanged();
Dale Curtisaebaeea2018-07-19 23:42:111871 if (watch_time_reporter_)
1872 watch_time_reporter_->OnDurationChanged(GetPipelineMediaDuration());
[email protected]81bb3322011-07-21 15:55:501873}
1874
alokp967c902452016-05-06 05:21:371875void WebMediaPlayerImpl::OnAddTextTrack(const TextTrackConfig& config,
1876 const AddTextTrackDoneCB& done_cb) {
acolwellb4034942014-08-28 15:42:431877 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]71537722013-05-23 06:47:531878
[email protected]8a561062013-11-22 01:19:311879 const WebInbandTextTrackImpl::Kind web_kind =
1880 static_cast<WebInbandTextTrackImpl::Kind>(config.kind());
Blink Reformat1c4d759e2017-04-09 16:34:541881 const blink::WebString web_label = blink::WebString::FromUTF8(config.label());
[email protected]8a561062013-11-22 01:19:311882 const blink::WebString web_language =
Blink Reformat1c4d759e2017-04-09 16:34:541883 blink::WebString::FromUTF8(config.language());
1884 const blink::WebString web_id = blink::WebString::FromUTF8(config.id());
[email protected]71537722013-05-23 06:47:531885
dcheng3076abbf2016-04-22 20:42:391886 std::unique_ptr<WebInbandTextTrackImpl> web_inband_text_track(
henriks9cce5fa2014-12-12 09:35:301887 new WebInbandTextTrackImpl(web_kind, web_label, web_language, web_id));
[email protected]8a561062013-11-22 01:19:311888
dcheng3076abbf2016-04-22 20:42:391889 std::unique_ptr<media::TextTrack> text_track(new TextTrackImpl(
dcheng652f5ff2015-12-27 08:54:001890 main_task_runner_, client_, std::move(web_inband_text_track)));
[email protected]8a561062013-11-22 01:19:311891
dcheng652f5ff2015-12-27 08:54:001892 done_cb.Run(std::move(text_track));
[email protected]71537722013-05-23 06:47:531893}
1894
alokp967c902452016-05-06 05:21:371895void WebMediaPlayerImpl::OnWaitingForDecryptionKey() {
1896 DCHECK(main_task_runner_->BelongsToCurrentThread());
1897
Blink Reformat1c4d759e2017-04-09 16:34:541898 encrypted_client_->DidBlockPlaybackWaitingForKey();
alokp967c902452016-05-06 05:21:371899 // TODO(jrummell): didResumePlaybackBlockedForKey() should only be called
1900 // when a key has been successfully added (e.g. OnSessionKeysChange() with
1901 // |has_additional_usable_key| = true). http://crbug.com/461903
Blink Reformat1c4d759e2017-04-09 16:34:541902 encrypted_client_->DidResumePlaybackBlockedForKey();
alokp967c902452016-05-06 05:21:371903}
1904
alokp5d86e9b2016-05-17 20:20:411905void WebMediaPlayerImpl::OnVideoNaturalSizeChange(const gfx::Size& size) {
1906 DCHECK(main_task_runner_->BelongsToCurrentThread());
Blink Reformat1c4d759e2017-04-09 16:34:541907 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
alokp5d86e9b2016-05-17 20:20:411908
Chris Cunningham038548b2017-07-10 22:36:301909 TRACE_EVENT0("media", "WebMediaPlayerImpl::OnVideoNaturalSizeChange");
xhwang60802652017-04-19 07:29:581910
xjz15b483f2017-01-12 00:21:361911 // The input |size| is from the decoded video frame, which is the original
1912 // natural size and need to be rotated accordingly.
Julien Isorce6c83d8de2017-10-12 13:11:291913 gfx::Size rotated_size = GetRotatedVideoSize(
1914 pipeline_metadata_.video_decoder_config.video_rotation(), size);
sandersd2c478422016-08-02 01:19:251915
xhwang60802652017-04-19 07:29:581916 RecordVideoNaturalSize(rotated_size);
1917
1918 gfx::Size old_size = pipeline_metadata_.natural_size;
1919 if (rotated_size == old_size)
alokp5d86e9b2016-05-17 20:20:411920 return;
1921
xjz516ef6d2017-01-07 00:23:061922 pipeline_metadata_.natural_size = rotated_size;
Dale Curtis96d6e9382018-07-18 18:01:071923 UpdateSecondaryProperties();
dalecurtis25405562017-04-14 23:35:111924
Chris Cunninghamd9df58e2017-08-29 00:04:231925 if (video_decode_stats_reporter_)
1926 video_decode_stats_reporter_->OnNaturalSizeChanged(rotated_size);
1927
Blink Reformat1c4d759e2017-04-09 16:34:541928 client_->SizeChanged();
xjz516ef6d2017-01-07 00:23:061929
xjz15b483f2017-01-12 00:21:361930 if (observer_)
1931 observer_->OnMetadataChanged(pipeline_metadata_);
peconn257951522017-06-09 18:24:591932
1933 delegate_->DidPlayerSizeChange(delegate_id_, NaturalSize());
alokp5d86e9b2016-05-17 20:20:411934}
1935
1936void WebMediaPlayerImpl::OnVideoOpacityChange(bool opaque) {
1937 DCHECK(main_task_runner_->BelongsToCurrentThread());
Blink Reformat1c4d759e2017-04-09 16:34:541938 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
alokp5d86e9b2016-05-17 20:20:411939
1940 opaque_ = opaque;
lethalantidote7f6009d2017-07-07 21:47:391941 if (!surface_layer_for_video_enabled_) {
danakj8bc61c72018-05-16 13:55:061942 if (video_layer_)
1943 video_layer_->SetContentsOpaque(opaque_);
danakj8d204a42018-05-18 18:05:351944 } else if (bridge_->GetCcLayer()) {
CJ DiMeglioa2b13fbc2018-06-27 00:50:591945 bridge_->SetContentsOpaque(opaque_);
CJ DiMeglio27211372018-07-27 23:17:441946 vfc_task_runner_->PostTask(
1947 FROM_HERE,
1948 base::BindOnce(&VideoFrameCompositor::UpdateIsOpaque,
1949 base::Unretained(compositor_.get()), opaque_));
lethalantidote7f6009d2017-07-07 21:47:391950 }
alokp5d86e9b2016-05-17 20:20:411951}
1952
Chris Cunningham038548b2017-07-10 22:36:301953void WebMediaPlayerImpl::OnAudioConfigChange(const AudioDecoderConfig& config) {
1954 DCHECK(main_task_runner_->BelongsToCurrentThread());
1955 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
1956
Dale Curtisccfd0cca2017-08-31 01:27:561957 const bool codec_change =
1958 pipeline_metadata_.audio_decoder_config.codec() != config.codec();
Chris Cunningham038548b2017-07-10 22:36:301959 pipeline_metadata_.audio_decoder_config = config;
1960
1961 if (observer_)
1962 observer_->OnMetadataChanged(pipeline_metadata_);
Dale Curtisccfd0cca2017-08-31 01:27:561963
1964 if (codec_change)
Dale Curtis96d6e9382018-07-18 18:01:071965 UpdateSecondaryProperties();
Chris Cunningham038548b2017-07-10 22:36:301966}
1967
1968void WebMediaPlayerImpl::OnVideoConfigChange(const VideoDecoderConfig& config) {
1969 DCHECK(main_task_runner_->BelongsToCurrentThread());
1970 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
1971
Dale Curtisccfd0cca2017-08-31 01:27:561972 const bool codec_change =
1973 pipeline_metadata_.video_decoder_config.codec() != config.codec();
1974
Chris Cunningham038548b2017-07-10 22:36:301975 // TODO(chcunningham): Observe changes to video codec profile to signal
1976 // beginning of a new Media Capabilities playback report.
1977 pipeline_metadata_.video_decoder_config = config;
1978
1979 if (observer_)
1980 observer_->OnMetadataChanged(pipeline_metadata_);
Chris Cunninghamd9df58e2017-08-29 00:04:231981
1982 if (video_decode_stats_reporter_)
1983 video_decode_stats_reporter_->OnVideoConfigChanged(config);
Dale Curtisccfd0cca2017-08-31 01:27:561984
1985 if (codec_change)
Dale Curtis96d6e9382018-07-18 18:01:071986 UpdateSecondaryProperties();
Chris Cunningham038548b2017-07-10 22:36:301987}
1988
avayvodeecec52c2017-02-14 01:25:091989void WebMediaPlayerImpl::OnVideoAverageKeyframeDistanceUpdate() {
1990 UpdateBackgroundVideoOptimizationState();
1991}
1992
Dale Curtisc7d2a7d22018-01-11 20:01:051993void WebMediaPlayerImpl::OnAudioDecoderChange(const std::string& name) {
1994 if (name == audio_decoder_name_)
1995 return;
1996
Dale Curtisc7d2a7d22018-01-11 20:01:051997 audio_decoder_name_ = name;
1998
1999 // If there's no current reporter, there's nothing to be done.
2000 if (!watch_time_reporter_)
2001 return;
2002
Dale Curtis96d6e9382018-07-18 18:01:072003 UpdateSecondaryProperties();
Dale Curtisc7d2a7d22018-01-11 20:01:052004}
2005
2006void WebMediaPlayerImpl::OnVideoDecoderChange(const std::string& name) {
2007 if (name == video_decoder_name_)
2008 return;
2009
Dale Curtisc7d2a7d22018-01-11 20:01:052010 video_decoder_name_ = name;
2011
2012 // If there's no current reporter, there's nothing to be done.
2013 if (!watch_time_reporter_)
2014 return;
2015
Dale Curtis96d6e9382018-07-18 18:01:072016 UpdateSecondaryProperties();
Dale Curtisc7d2a7d22018-01-11 20:01:052017}
2018
sandersd35d2c3f2017-01-14 02:04:422019void WebMediaPlayerImpl::OnFrameHidden() {
sandersd1e49fb62015-12-12 01:18:062020 DCHECK(main_task_runner_->BelongsToCurrentThread());
avayvod39c102402016-11-23 21:43:132021
avayvod65fad272017-02-24 01:00:482022 // Backgrounding a video requires a user gesture to resume playback.
2023 if (IsHidden())
2024 video_locked_when_paused_when_hidden_ = true;
2025
dalecurtis04bdb582016-08-17 22:15:232026 if (watch_time_reporter_)
2027 watch_time_reporter_->OnHidden();
avayvod48a8be52016-08-04 19:52:502028
Chris Cunninghamd9df58e2017-08-29 00:04:232029 if (video_decode_stats_reporter_)
2030 video_decode_stats_reporter_->OnHidden();
2031
avayvod65fad272017-02-24 01:00:482032 UpdateBackgroundVideoOptimizationState();
sandersd50a635e2016-04-04 22:50:092033 UpdatePlayState();
dalecurtis8b8505e72016-06-10 21:59:172034
2035 // Schedule suspended playing media to be paused if the user doesn't come back
2036 // to it within some timeout period to avoid any autoplay surprises.
2037 ScheduleIdlePauseTimer();
sandersd1e49fb62015-12-12 01:18:062038}
2039
sandersd35d2c3f2017-01-14 02:04:422040void WebMediaPlayerImpl::OnFrameClosed() {
sandersd1e49fb62015-12-12 01:18:062041 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]28347e72017-06-27 17:30:112042
sandersd35d2c3f2017-01-14 02:04:422043 UpdatePlayState();
2044}
2045
2046void WebMediaPlayerImpl::OnFrameShown() {
2047 DCHECK(main_task_runner_->BelongsToCurrentThread());
2048 background_pause_timer_.Stop();
2049
avayvod65fad272017-02-24 01:00:482050 // Foreground videos don't require user gesture to continue playback.
2051 video_locked_when_paused_when_hidden_ = false;
2052
dalecurtis04bdb582016-08-17 22:15:232053 if (watch_time_reporter_)
2054 watch_time_reporter_->OnShown();
2055
Chris Cunninghamd9df58e2017-08-29 00:04:232056 if (video_decode_stats_reporter_)
2057 video_decode_stats_reporter_->OnShown();
2058
avayvodcc273dd2017-01-19 19:35:122059 // Only track the time to the first frame if playing or about to play because
2060 // of being shown and only for videos we would optimize background playback
2061 // for.
2062 if ((!paused_ && IsBackgroundOptimizationCandidate()) ||
2063 paused_when_hidden_) {
Dale Curtis3899090ea2018-01-12 00:10:352064 frame_time_report_cb_.Reset(base::BindOnce(
2065 &WebMediaPlayerImpl::ReportTimeFromForegroundToFirstFrame, AsWeakPtr(),
2066 base::TimeTicks::Now()));
CJ DiMeglio2302d202017-08-31 08:38:042067 vfc_task_runner_->PostTask(
avayvodcc273dd2017-01-19 19:35:122068 FROM_HERE,
Dale Curtis3899090ea2018-01-12 00:10:352069 base::BindOnce(&VideoFrameCompositor::SetOnNewProcessedFrameCallback,
2070 base::Unretained(compositor_.get()),
2071 BindToCurrentLoop(frame_time_report_cb_.callback())));
avayvodcc273dd2017-01-19 19:35:122072 }
avayvodac607d652017-01-06 03:16:432073
Dale Curtisdcbb81a2017-08-18 01:06:122074 UpdateBackgroundVideoOptimizationState();
avayvod65fad272017-02-24 01:00:482075
avayvod2135a642017-01-13 00:17:142076 if (paused_when_hidden_) {
2077 paused_when_hidden_ = false;
2078 OnPlay(); // Calls UpdatePlayState() so return afterwards.
2079 return;
2080 }
2081
sandersd50a635e2016-04-04 22:50:092082 UpdatePlayState();
sandersd1e49fb62015-12-12 01:18:062083}
2084
sandersd35d2c3f2017-01-14 02:04:422085void WebMediaPlayerImpl::OnIdleTimeout() {
dalecurtis0431cbf2016-03-12 01:19:432086 DCHECK(main_task_runner_->BelongsToCurrentThread());
2087
Dale Curtis99a9b482018-02-01 02:23:282088 // This should never be called when stale state testing overrides are used.
2089 DCHECK(!stale_state_override_for_testing_.has_value());
2090
sandersd35d2c3f2017-01-14 02:04:422091 // If we are attempting preroll, clear the stale flag.
2092 if (IsPrerollAttemptNeeded()) {
tguilbert1bb1c782017-01-23 21:15:112093 delegate_->ClearStaleFlag(delegate_id_);
sandersd35d2c3f2017-01-14 02:04:422094 return;
watkd026f792016-11-05 00:28:512095 }
sandersd50a635e2016-04-04 22:50:092096
sandersd35d2c3f2017-01-14 02:04:422097 UpdatePlayState();
dalecurtis0431cbf2016-03-12 01:19:432098}
2099
dalecurtisbb3eaac2016-01-27 21:10:252100void WebMediaPlayerImpl::OnPlay() {
Mounir Lamouri703106e2018-05-30 14:31:092101 client_->RequestPlay();
dalecurtisbb3eaac2016-01-27 21:10:252102}
2103
2104void WebMediaPlayerImpl::OnPause() {
Mounir Lamouri703106e2018-05-30 14:31:092105 client_->RequestPause();
dalecurtisbb3eaac2016-01-27 21:10:252106}
2107
Alec Douglas316cce42017-10-31 13:28:082108void WebMediaPlayerImpl::OnSeekForward(double seconds) {
2109 DCHECK_GE(seconds, 0) << "Attempted to seek by a negative number of seconds";
2110 client_->RequestSeek(CurrentTime() + seconds);
2111}
2112
2113void WebMediaPlayerImpl::OnSeekBackward(double seconds) {
2114 DCHECK_GE(seconds, 0) << "Attempted to seek by a negative number of seconds";
2115 client_->RequestSeek(CurrentTime() - seconds);
2116}
2117
dalecurtisbb3eaac2016-01-27 21:10:252118void WebMediaPlayerImpl::OnVolumeMultiplierUpdate(double multiplier) {
2119 volume_multiplier_ = multiplier;
Blink Reformat1c4d759e2017-04-09 16:34:542120 SetVolume(volume_);
dalecurtisbb3eaac2016-01-27 21:10:252121}
2122
zqzhang8ac49002017-03-16 21:51:352123void WebMediaPlayerImpl::OnBecamePersistentVideo(bool value) {
Blink Reformat1c4d759e2017-04-09 16:34:542124 client_->OnBecamePersistentVideo(value);
zqzhang8ac49002017-03-16 21:51:352125}
2126
Jennifer Apacible009f29842018-04-16 23:07:372127void WebMediaPlayerImpl::OnPictureInPictureModeEnded() {
Mounir Lamourib642a3c2018-07-09 15:45:312128 // It is possible for this method to be called when the player is no longer in
2129 // Picture-in-Picture mode.
Mounir Lamouri0484f40a2018-07-25 03:03:262130 if (!client_ || !IsInPictureInPicture())
Mounir Lamourib642a3c2018-07-09 15:45:312131 return;
Mounir Lamourib642a3c2018-07-09 15:45:312132
2133 client_->PictureInPictureStopped();
Jennifer Apacible009f29842018-04-16 23:07:372134}
2135
sawtelle82e4b752018-07-19 04:33:122136void WebMediaPlayerImpl::OnPictureInPictureControlClicked(
2137 const std::string& control_id) {
Mounir Lamouri0484f40a2018-07-25 03:03:262138 if (client_ && IsInPictureInPicture()) {
sawtelle82e4b752018-07-19 04:33:122139 client_->PictureInPictureControlClicked(
2140 blink::WebString::FromUTF8(control_id));
sawtelle42eac6a2018-06-26 03:22:012141 }
2142}
2143
watkdee516f2016-02-18 02:22:192144void WebMediaPlayerImpl::ScheduleRestart() {
sandersd50a635e2016-04-04 22:50:092145 // TODO(watk): All restart logic should be moved into PipelineController.
tguilbert350936ff2017-02-24 05:39:272146 if (pipeline_controller_.IsPipelineRunning() &&
2147 !pipeline_controller_.IsPipelineSuspended()) {
watkdee516f2016-02-18 02:22:192148 pending_suspend_resume_cycle_ = true;
sandersd50a635e2016-04-04 22:50:092149 UpdatePlayState();
watkdee516f2016-02-18 02:22:192150 }
2151}
2152
Blink Reformat1c4d759e2017-04-09 16:34:542153void WebMediaPlayerImpl::RequestRemotePlaybackDisabled(bool disabled) {
miu77f914c2016-11-19 23:56:182154 if (observer_)
2155 observer_->OnRemotePlaybackDisabled(disabled);
2156}
2157
hubbed5f36882016-01-15 22:40:372158#if defined(OS_ANDROID) // WMPI_CAST
Blink Reformat1c4d759e2017-04-09 16:34:542159bool WebMediaPlayerImpl::IsRemote() const {
hubbed5f36882016-01-15 22:40:372160 return cast_impl_.isRemote();
2161}
2162
2163void WebMediaPlayerImpl::SetMediaPlayerManager(
2164 RendererMediaPlayerManagerInterface* media_player_manager) {
2165 cast_impl_.SetMediaPlayerManager(media_player_manager);
2166}
2167
Blink Reformat1c4d759e2017-04-09 16:34:542168void WebMediaPlayerImpl::RequestRemotePlayback() {
hubbed5f36882016-01-15 22:40:372169 cast_impl_.requestRemotePlayback();
2170}
2171
Blink Reformat1c4d759e2017-04-09 16:34:542172void WebMediaPlayerImpl::RequestRemotePlaybackControl() {
hubbed5f36882016-01-15 22:40:372173 cast_impl_.requestRemotePlaybackControl();
2174}
2175
Blink Reformat1c4d759e2017-04-09 16:34:542176void WebMediaPlayerImpl::RequestRemotePlaybackStop() {
avayvod8d8c53b2016-11-04 16:10:302177 cast_impl_.requestRemotePlaybackStop();
2178}
2179
hubbed5f36882016-01-15 22:40:372180void WebMediaPlayerImpl::OnRemotePlaybackEnded() {
pkastingf5279482016-07-27 02:18:202181 DVLOG(1) << __func__;
hubbed5f36882016-01-15 22:40:372182 DCHECK(main_task_runner_->BelongsToCurrentThread());
2183
2184 ended_ = true;
Blink Reformat1c4d759e2017-04-09 16:34:542185 client_->TimeChanged();
hubbed5f36882016-01-15 22:40:372186}
2187
Thomas Guilbertb341bae02018-05-09 00:02:132188void WebMediaPlayerImpl::FlingingStarted() {
2189 DCHECK(main_task_runner_->BelongsToCurrentThread());
2190 DCHECK(!disable_pipeline_auto_suspend_);
2191 disable_pipeline_auto_suspend_ = true;
2192
2193 // Capabilities reporting should only be performed for local playbacks.
2194 video_decode_stats_reporter_.reset();
2195
2196 // Requests to restart media pipeline. A flinging renderer will be created via
2197 // the |renderer_factory_selector_|.
2198 ScheduleRestart();
2199}
2200
2201void WebMediaPlayerImpl::FlingingStopped() {
2202 DCHECK(main_task_runner_->BelongsToCurrentThread());
2203 DCHECK(disable_pipeline_auto_suspend_);
2204 disable_pipeline_auto_suspend_ = false;
2205
2206 CreateVideoDecodeStatsReporter();
2207
2208 ScheduleRestart();
2209}
2210
hubbed5f36882016-01-15 22:40:372211void WebMediaPlayerImpl::OnDisconnectedFromRemoteDevice(double t) {
sandersd1c0bba02016-03-04 23:14:082212 DoSeek(base::TimeDelta::FromSecondsD(t), false);
hubbed5f36882016-01-15 22:40:372213
Chris Cunninghamd9df58e2017-08-29 00:04:232214 // Capabilities reporting can resume now that playback is local.
2215 CreateVideoDecodeStatsReporter();
2216
Anton Vayvodfad2f3ea2017-07-19 21:45:272217 // |client_| might destroy us in methods below.
2218 UpdatePlayState();
2219
hubbed5f36882016-01-15 22:40:372220 // We already told the delegate we're paused when remoting started.
Mounir Lamouri703106e2018-05-30 14:31:092221 client_->RequestPause();
Blink Reformat1c4d759e2017-04-09 16:34:542222 client_->DisconnectedFromRemoteDevice();
hubbed5f36882016-01-15 22:40:372223}
2224
2225void WebMediaPlayerImpl::SuspendForRemote() {
Chris Cunninghamd9df58e2017-08-29 00:04:232226 // Capabilities reporting should only be performed for local playbacks.
2227 video_decode_stats_reporter_.reset();
2228
avayvod82729272017-05-29 21:58:392229 if (pipeline_controller_.IsPipelineSuspended() &&
2230 !IsNewRemotePlaybackPipelineEnabled()) {
hubbed5f36882016-01-15 22:40:372231 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner();
sandersd50a635e2016-04-04 22:50:092232 if (frame)
dalecurtise9c89e92016-05-20 19:38:002233 compositor_->PaintSingleFrame(frame);
hubbed5f36882016-01-15 22:40:372234 }
sandersd50a635e2016-04-04 22:50:092235
2236 UpdatePlayState();
hubbed5f36882016-01-15 22:40:372237}
2238
2239gfx::Size WebMediaPlayerImpl::GetCanvasSize() const {
lethalantidote7f6009d2017-07-07 21:47:392240 if (!surface_layer_for_video_enabled_) {
danakj6e669e782018-05-16 16:57:172241 if (!video_layer_)
lethalantidote7f6009d2017-07-07 21:47:392242 return pipeline_metadata_.natural_size;
2243
danakj6e669e782018-05-16 16:57:172244 return video_layer_->bounds();
lethalantidote7f6009d2017-07-07 21:47:392245 }
danakj8d204a42018-05-18 18:05:352246 if (!bridge_->GetCcLayer())
hubbed5f36882016-01-15 22:40:372247 return pipeline_metadata_.natural_size;
2248
danakj8d204a42018-05-18 18:05:352249 return bridge_->GetCcLayer()->bounds();
hubbed5f36882016-01-15 22:40:372250}
2251
2252void WebMediaPlayerImpl::SetDeviceScaleFactor(float scale_factor) {
2253 cast_impl_.SetDeviceScaleFactor(scale_factor);
2254}
Dan Sanderscd8981c2017-08-31 22:37:022255#endif // defined(OS_ANDROID) // WMPI_CAST
hubbee4027f92016-05-19 05:18:132256
Blink Reformat1c4d759e2017-04-09 16:34:542257void WebMediaPlayerImpl::SetPoster(const blink::WebURL& poster) {
Dan Sanderscd8981c2017-08-31 22:37:022258 has_poster_ = !poster.IsEmpty();
2259#if defined(OS_ANDROID) // WMPI_CAST
xjzc102fd82017-01-04 20:13:532260 cast_impl_.setPoster(poster);
xjz2504c4da2017-04-18 18:50:142261#endif // defined(OS_ANDROID) // WMPI_CAST
Dan Sanderscd8981c2017-08-31 22:37:022262}
xjzc102fd82017-01-04 20:13:532263
[email protected]fee8a902014-06-03 13:43:362264void WebMediaPlayerImpl::DataSourceInitialized(bool success) {
pkastingf5279482016-07-27 02:18:202265 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:432266 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]a9415292012-01-19 19:55:202267
Anton Vayvod09fa66e2017-07-20 23:02:122268 if (observer_ && IsNewRemotePlaybackPipelineEnabled() && data_source_)
2269 observer_->OnDataSourceInitialized(data_source_->GetUrlAfterRedirects());
2270
[email protected]d250190da3b2012-07-23 22:57:302271 if (!success) {
Blink Reformat1c4d759e2017-04-09 16:34:542272 SetNetworkState(WebMediaPlayer::kNetworkStateFormatError);
Dale Curtis74612b72017-12-14 20:56:192273 media_metrics_provider_->OnError(PIPELINE_ERROR_NETWORK);
sandersd50a635e2016-04-04 22:50:092274
2275 // Not really necessary, since the pipeline was never started, but it at
2276 // least this makes sure that the error handling code is in sync.
2277 UpdatePlayState();
2278
[email protected]a9415292012-01-19 19:55:202279 return;
2280 }
2281
hubbee2cc88c092017-07-14 23:10:412282 // No point in preloading data as we'll probably just throw it away anyways.
2283 if (IsStreaming() && preload_ > MultibufferDataSource::METADATA) {
2284 data_source_->SetPreload(MultibufferDataSource::METADATA);
2285 }
2286
[email protected]ef8394c2013-08-21 20:26:302287 StartPipeline();
[email protected]a9415292012-01-19 19:55:202288}
2289
[email protected]122f40252012-06-12 05:01:562290void WebMediaPlayerImpl::NotifyDownloading(bool is_downloading) {
hubbeb2d3efd2017-05-05 23:26:382291 DVLOG(1) << __func__ << "(" << is_downloading << ")";
Blink Reformat1c4d759e2017-04-09 16:34:542292 if (!is_downloading && network_state_ == WebMediaPlayer::kNetworkStateLoading)
2293 SetNetworkState(WebMediaPlayer::kNetworkStateIdle);
2294 else if (is_downloading &&
2295 network_state_ == WebMediaPlayer::kNetworkStateIdle)
2296 SetNetworkState(WebMediaPlayer::kNetworkStateLoading);
hubbeb2d3efd2017-05-05 23:26:382297 if (ready_state_ == ReadyState::kReadyStateHaveFutureData && !is_downloading)
2298 SetReadyState(WebMediaPlayer::kReadyStateHaveEnoughData);
[email protected]122f40252012-06-12 05:01:562299}
2300
liberato2ff93ad2017-05-17 07:28:242301void WebMediaPlayerImpl::OnOverlayRoutingToken(
2302 const base::UnguessableToken& token) {
2303 DCHECK(overlay_mode_ == OverlayMode::kUseAndroidOverlay);
liberatofe8f9692017-06-08 19:17:362304 // TODO(liberato): |token| should already be a RoutingToken.
2305 overlay_routing_token_is_pending_ = false;
2306 overlay_routing_token_ = OverlayInfo::RoutingToken(token);
liberato2ff93ad2017-05-17 07:28:242307 MaybeSendOverlayInfoToDecoder();
2308}
2309
2310void WebMediaPlayerImpl::OnOverlayInfoRequested(
dalecurtis4b632fce22016-11-10 00:52:172311 bool decoder_requires_restart_for_overlay,
liberato2ff93ad2017-05-17 07:28:242312 const ProvideOverlayInfoCB& provide_overlay_info_cb) {
watkdee516f2016-02-18 02:22:192313 DCHECK(main_task_runner_->BelongsToCurrentThread());
watkdee516f2016-02-18 02:22:192314
Chris Watkins557f84d2017-09-16 02:31:462315 // If we get a non-null cb, a decoder is initializing and requires overlay
2316 // info. If we get a null cb, a previously initialized decoder is
2317 // unregistering for overlay info updates.
liberato2ff93ad2017-05-17 07:28:242318 if (provide_overlay_info_cb.is_null()) {
tsunghungee562e92016-07-20 18:03:312319 decoder_requires_restart_for_overlay_ = false;
liberato2ff93ad2017-05-17 07:28:242320 provide_overlay_info_cb_.Reset();
watkdee516f2016-02-18 02:22:192321 return;
2322 }
2323
dalecurtis4b632fce22016-11-10 00:52:172324 // If |decoder_requires_restart_for_overlay| is true, we must restart the
2325 // pipeline for fullscreen transitions. The decoder is unable to switch
2326 // surfaces otherwise. If false, we simply need to tell the decoder about the
2327 // new surface and it will handle things seamlessly.
Chris Watkins557f84d2017-09-16 02:31:462328 // For encrypted video we pretend that the decoder doesn't require a restart
2329 // because it needs an overlay all the time anyway. We'll switch into
2330 // |always_enable_overlays_| mode below.
2331 decoder_requires_restart_for_overlay_ =
2332 (overlay_mode_ == OverlayMode::kUseAndroidOverlay && is_encrypted_)
2333 ? false
2334 : decoder_requires_restart_for_overlay;
liberato2ff93ad2017-05-17 07:28:242335 provide_overlay_info_cb_ = provide_overlay_info_cb;
dalecurtis4b632fce22016-11-10 00:52:172336
Chris Watkins557f84d2017-09-16 02:31:462337 // If the decoder doesn't require restarts for surface transitions, and we're
2338 // using AndroidOverlay mode, we can always enable the overlay and the decoder
2339 // can choose whether or not to use it. Otherwise, we'll restart the decoder
2340 // and enable the overlay on fullscreen transitions.
[email protected]77568482017-06-21 21:16:522341 if (overlay_mode_ == OverlayMode::kUseAndroidOverlay &&
Chris Watkins557f84d2017-09-16 02:31:462342 !decoder_requires_restart_for_overlay_) {
[email protected]c8d574722017-08-30 20:53:432343 always_enable_overlays_ = true;
[email protected]77568482017-06-21 21:16:522344 if (!overlay_enabled_)
2345 EnableOverlay();
2346 }
2347
Chris Watkins557f84d2017-09-16 02:31:462348 // Send the overlay info if we already have it. If not, it will be sent later.
liberato2ff93ad2017-05-17 07:28:242349 MaybeSendOverlayInfoToDecoder();
2350}
2351
2352void WebMediaPlayerImpl::MaybeSendOverlayInfoToDecoder() {
2353 // If the decoder didn't request overlay info, then don't send it.
2354 if (!provide_overlay_info_cb_)
dalecurtis4b632fce22016-11-10 00:52:172355 return;
2356
liberato2ff93ad2017-05-17 07:28:242357 // We should send the overlay info as long as we know it. This includes the
2358 // case where |!overlay_enabled_|, since we want to tell the decoder to avoid
2359 // using overlays. Assuming that the decoder has requested info, the only
2360 // case in which we don't want to send something is if we've requested the
2361 // info but not received it yet. Then, we should wait until we do.
liberatofe8f9692017-06-08 19:17:362362 //
2363 // Initialization requires this; AVDA should start with enough info to make an
2364 // overlay, so that (pre-M) the initial codec is created with the right output
2365 // surface; it can't switch later.
[email protected]f7df5b342018-07-13 20:22:132366 if (overlay_mode_ == OverlayMode::kUseAndroidOverlay) {
liberatofe8f9692017-06-08 19:17:362367 if (overlay_routing_token_is_pending_)
liberato2ff93ad2017-05-17 07:28:242368 return;
liberatofe8f9692017-06-08 19:17:362369
2370 overlay_info_.routing_token = overlay_routing_token_;
liberato2ff93ad2017-05-17 07:28:242371 }
2372
liberato2ff93ad2017-05-17 07:28:242373 // If restart is required, the callback is one-shot only.
2374 if (decoder_requires_restart_for_overlay_) {
liberatofe8f9692017-06-08 19:17:362375 base::ResetAndReturn(&provide_overlay_info_cb_).Run(overlay_info_);
liberato2ff93ad2017-05-17 07:28:242376 } else {
liberatofe8f9692017-06-08 19:17:362377 provide_overlay_info_cb_.Run(overlay_info_);
liberato2ff93ad2017-05-17 07:28:242378 }
watkdee516f2016-02-18 02:22:192379}
2380
dcheng3076abbf2016-04-22 20:42:392381std::unique_ptr<Renderer> WebMediaPlayerImpl::CreateRenderer() {
dcheng37b415b92017-01-27 20:17:432382 DCHECK(main_task_runner_->BelongsToCurrentThread());
2383
[email protected]c8d574722017-08-30 20:53:432384 // Make sure that overlays are enabled if they're always allowed.
2385 if (always_enable_overlays_)
tsunghungee562e92016-07-20 18:03:312386 EnableOverlay();
2387
liberato2ff93ad2017-05-17 07:28:242388 RequestOverlayInfoCB request_overlay_info_cb;
watkdee516f2016-02-18 02:22:192389#if defined(OS_ANDROID)
liberato2ff93ad2017-05-17 07:28:242390 request_overlay_info_cb = BindToCurrentLoop(
2391 base::Bind(&WebMediaPlayerImpl::OnOverlayInfoRequested, AsWeakPtr()));
watkdee516f2016-02-18 02:22:192392#endif
tguilbert70d2a00a2017-04-25 00:30:442393 return renderer_factory_selector_->GetCurrentFactory()->CreateRenderer(
sandersd1e49fb62015-12-12 01:18:062394 media_task_runner_, worker_task_runner_, audio_source_provider_.get(),
CJ DiMeglio2302d202017-08-31 08:38:042395 compositor_.get(), request_overlay_info_cb, client_->TargetColorSpace());
sandersd1e49fb62015-12-12 01:18:062396}
2397
[email protected]ef8394c2013-08-21 20:26:302398void WebMediaPlayerImpl::StartPipeline() {
acolwellb4034942014-08-28 15:42:432399 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]ddbc6ff2013-04-19 15:28:332400
xhwange8c4181a2014-12-06 08:10:012401 Demuxer::EncryptedMediaInitDataCB encrypted_media_init_data_cb =
dcheng37b415b92017-01-27 20:17:432402 BindToCurrentLoop(base::Bind(
2403 &WebMediaPlayerImpl::OnEncryptedMediaInitData, AsWeakPtr()));
[email protected]2b57e2e2014-05-09 11:07:252404
Dale Curtis3899090ea2018-01-12 00:10:352405 vfc_task_runner_->PostTask(
2406 FROM_HERE,
2407 base::BindOnce(&VideoFrameCompositor::SetOnNewProcessedFrameCallback,
2408 base::Unretained(compositor_.get()),
2409 BindToCurrentLoop(base::BindOnce(
2410 &WebMediaPlayerImpl::OnFirstFrame, AsWeakPtr()))));
2411
tguilbert75e2bf62017-04-26 20:13:122412 if (renderer_factory_selector_->GetCurrentFactory()
2413 ->GetRequiredMediaResourceType() == MediaResource::Type::URL) {
2414 if (data_source_)
2415 loaded_url_ = data_source_->GetUrlAfterRedirects();
2416
2417 // MediaPlayerRendererClient factory is the only factory that a
2418 // MediaResource::Type::URL for the moment. This might no longer be true
2419 // when we remove WebMediaPlayerCast.
2420 //
2421 // TODO(tguilbert/avayvod): Update this flag when removing |cast_impl_|.
2422 using_media_player_renderer_ = true;
2423
Chris Cunninghamd9df58e2017-08-29 00:04:232424 // MediaPlayerRenderer does not provide pipeline stats, so nuke capabilities
2425 // reporter.
2426 video_decode_stats_reporter_.reset();
2427
Mike Westb85da8ed2017-08-10 14:16:462428 demuxer_.reset(new MediaUrlDemuxer(media_task_runner_, loaded_url_,
2429 frame_->GetDocument().SiteForCookies()));
Dale Curtisc00d56482018-02-09 20:55:062430 pipeline_controller_.Start(Pipeline::StartType::kNormal, demuxer_.get(),
2431 this, false, false);
tguilbert25a4d112016-10-13 21:56:512432 return;
2433 }
2434
[email protected]ddbc6ff2013-04-19 15:28:332435 // Figure out which demuxer to use.
Blink Reformat1c4d759e2017-04-09 16:34:542436 if (load_type_ != kLoadTypeMediaSource) {
[email protected]ddbc6ff2013-04-19 15:28:332437 DCHECK(!chunk_demuxer_);
[email protected]f5443ef72013-04-22 04:03:382438 DCHECK(data_source_);
2439
Dale Curtisbcf523b2018-01-17 02:59:012440#if BUILDFLAG(ENABLE_FFMPEG)
servolk81e01e02016-03-05 03:29:152441 Demuxer::MediaTracksUpdatedCB media_tracks_updated_cb =
dcheng37b415b92017-01-27 20:17:432442 BindToCurrentLoop(base::Bind(
2443 &WebMediaPlayerImpl::OnFFmpegMediaTracksUpdated, AsWeakPtr()));
servolk81e01e02016-03-05 03:29:152444
dalecurtis9cddc0b2017-04-19 21:23:382445 demuxer_.reset(new FFmpegDemuxer(
2446 media_task_runner_, data_source_.get(), encrypted_media_init_data_cb,
Dale Curtisb8139f72018-08-27 23:28:482447 media_tracks_updated_cb, media_log_.get(), IsLocalFile(loaded_url_)));
j.isorcef6778e652015-11-16 17:14:252448#else
alokp967c902452016-05-06 05:21:372449 OnError(PipelineStatus::DEMUXER_ERROR_COULD_NOT_OPEN);
j.isorcef6778e652015-11-16 17:14:252450 return;
2451#endif
[email protected]ddbc6ff2013-04-19 15:28:332452 } else {
[email protected]f5443ef72013-04-22 04:03:382453 DCHECK(!chunk_demuxer_);
2454 DCHECK(!data_source_);
2455
acolwell9e0840d2014-09-06 19:01:322456 chunk_demuxer_ = new ChunkDemuxer(
dcheng37b415b92017-01-27 20:17:432457 BindToCurrentLoop(
2458 base::Bind(&WebMediaPlayerImpl::OnDemuxerOpened, AsWeakPtr())),
Dan Sanders42311b52017-08-10 23:41:032459 BindToCurrentLoop(
2460 base::Bind(&WebMediaPlayerImpl::OnProgress, AsWeakPtr())),
dalecurtis9cddc0b2017-04-19 21:23:382461 encrypted_media_init_data_cb, media_log_.get());
[email protected]f5443ef72013-04-22 04:03:382462 demuxer_.reset(chunk_demuxer_);
servolkf94b4602017-01-31 16:44:272463
2464 if (base::FeatureList::IsEnabled(kMemoryPressureBasedSourceBufferGC)) {
2465 // base::Unretained is safe because |this| owns memory_pressure_listener_.
2466 memory_pressure_listener_ =
Gyuyoung Kim62a5de42018-01-10 09:48:422467 std::make_unique<base::MemoryPressureListener>(base::Bind(
servolkf94b4602017-01-31 16:44:272468 &WebMediaPlayerImpl::OnMemoryPressure, base::Unretained(this)));
2469 }
[email protected]ddbc6ff2013-04-19 15:28:332470 }
2471
sandersdb5e21462016-03-09 01:49:072472 // TODO(sandersd): FileSystem objects may also be non-static, but due to our
2473 // caching layer such situations are broken already. http://crbug.com/593159
2474 bool is_static = !chunk_demuxer_;
avayvod102cdb62017-01-07 03:11:092475 bool is_streaming = IsStreaming();
sandersdb8eb5f1d2016-11-19 04:04:022476 UMA_HISTOGRAM_BOOLEAN("Media.IsStreaming", is_streaming);
sandersdb5e21462016-03-09 01:49:072477
Dale Curtis2dc6089a2018-03-26 16:47:582478 // If possible attempt to avoid decoder spool up until playback starts.
2479 Pipeline::StartType start_type = Pipeline::StartType::kNormal;
2480 if (base::FeatureList::IsEnabled(kPreloadMetadataSuspend) &&
Dale Curtisf5a7c9212018-04-10 21:57:342481 !chunk_demuxer_ && preload_ == MultibufferDataSource::METADATA &&
2482 !client_->CouldPlayIfEnoughData()) {
Dale Curtis2dc6089a2018-03-26 16:47:582483 start_type = has_poster_
2484 ? Pipeline::StartType::kSuspendAfterMetadata
2485 : Pipeline::StartType::kSuspendAfterMetadataForAudioOnly;
2486 attempting_suspended_start_ = true;
2487 }
2488
[email protected]f5443ef72013-04-22 04:03:382489 // ... and we're ready to go!
sandersd1e49fb62015-12-12 01:18:062490 // TODO(sandersd): On Android, defer Start() if the tab is not visible.
sandersdb8eb5f1d2016-11-19 04:04:022491 seeking_ = true;
Dale Curtis2dc6089a2018-03-26 16:47:582492 pipeline_controller_.Start(start_type, demuxer_.get(), this, is_streaming,
2493 is_static);
[email protected]f5443ef72013-04-22 04:03:382494}
2495
2496void WebMediaPlayerImpl::SetNetworkState(WebMediaPlayer::NetworkState state) {
pkastingf5279482016-07-27 02:18:202497 DVLOG(1) << __func__ << "(" << state << ")";
acolwellb4034942014-08-28 15:42:432498 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]f5443ef72013-04-22 04:03:382499 network_state_ = state;
2500 // Always notify to ensure client has the latest value.
Blink Reformat1c4d759e2017-04-09 16:34:542501 client_->NetworkStateChanged();
[email protected]f5443ef72013-04-22 04:03:382502}
2503
2504void WebMediaPlayerImpl::SetReadyState(WebMediaPlayer::ReadyState state) {
pkastingf5279482016-07-27 02:18:202505 DVLOG(1) << __func__ << "(" << state << ")";
acolwellb4034942014-08-28 15:42:432506 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]f5443ef72013-04-22 04:03:382507
Blink Reformat1c4d759e2017-04-09 16:34:542508 if (state == WebMediaPlayer::kReadyStateHaveEnoughData && data_source_ &&
[email protected]fee8a902014-06-03 13:43:362509 data_source_->assume_fully_buffered() &&
Blink Reformat1c4d759e2017-04-09 16:34:542510 network_state_ == WebMediaPlayer::kNetworkStateLoading)
2511 SetNetworkState(WebMediaPlayer::kNetworkStateLoaded);
[email protected]f5443ef72013-04-22 04:03:382512
2513 ready_state_ = state;
sandersd50a635e2016-04-04 22:50:092514 highest_ready_state_ = std::max(highest_ready_state_, ready_state_);
2515
[email protected]f5443ef72013-04-22 04:03:382516 // Always notify to ensure client has the latest value.
Blink Reformat1c4d759e2017-04-09 16:34:542517 client_->ReadyStateChanged();
[email protected]f5443ef72013-04-22 04:03:382518}
2519
Blink Reformat1c4d759e2017-04-09 16:34:542520blink::WebAudioSourceProvider* WebMediaPlayerImpl::GetAudioSourceProvider() {
[email protected]ff875be52013-06-02 23:47:382521 return audio_source_provider_.get();
[email protected]f5443ef72013-04-22 04:03:382522}
2523
Jiajia Qin82acdc02017-07-31 09:55:142524scoped_refptr<VideoFrame> WebMediaPlayerImpl::GetCurrentFrameFromCompositor()
2525 const {
xhwang213e50c2016-10-10 23:56:312526 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]dd061e12014-05-06 19:21:222527 TRACE_EVENT0("media", "WebMediaPlayerImpl::GetCurrentFrameFromCompositor");
xhwang213e50c2016-10-10 23:56:312528
Thomas Guilbertd85407412017-11-08 05:03:462529 // Can be null.
2530 scoped_refptr<VideoFrame> video_frame =
2531 compositor_->GetCurrentFrameOnAnyThread();
[email protected]dd061e12014-05-06 19:21:222532
Thomas Guilbertd85407412017-11-08 05:03:462533 // base::Unretained is safe here because |compositor_| is destroyed on
2534 // |vfc_task_runner_|. The destruction is queued from |this|' destructor,
2535 // which also runs on |main_task_runner_|, which makes it impossible for
2536 // UpdateCurrentFrameIfStale() to be queued after |compositor_|'s dtor.
CJ DiMeglio2302d202017-08-31 08:38:042537 vfc_task_runner_->PostTask(
Thomas Guilbertd85407412017-11-08 05:03:462538 FROM_HERE, base::Bind(&VideoFrameCompositor::UpdateCurrentFrameIfStale,
2539 base::Unretained(compositor_.get())));
kainino36eeff82017-03-30 00:55:302540
[email protected]dd061e12014-05-06 19:21:222541 return video_frame;
2542}
2543
sandersd50a635e2016-04-04 22:50:092544void WebMediaPlayerImpl::UpdatePlayState() {
xhwang213e50c2016-10-10 23:56:312545 DCHECK(main_task_runner_->BelongsToCurrentThread());
2546
hubbed5f36882016-01-15 22:40:372547#if defined(OS_ANDROID) // WMPI_CAST
Blink Reformat1c4d759e2017-04-09 16:34:542548 bool is_remote = IsRemote();
xjz4e5d4bf32017-02-15 21:26:352549 bool can_auto_suspend = true;
sandersd50a635e2016-04-04 22:50:092550#else
2551 bool is_remote = false;
hubbee2cc88c092017-07-14 23:10:412552 bool can_auto_suspend = !disable_pipeline_auto_suspend_;
2553 // For streaming videos, we only allow suspending at the very beginning of the
2554 // video, and only if we know the length of the video. (If we don't know
2555 // the length, it might be a dynamically generated video, and suspending
2556 // will not work at all.)
2557 if (IsStreaming()) {
2558 bool at_beginning =
2559 ready_state_ == WebMediaPlayer::kReadyStateHaveNothing ||
2560 CurrentTime() == 0.0;
2561 if (!at_beginning || GetPipelineMediaDuration() == kInfiniteDuration)
2562 can_auto_suspend = false;
2563 }
hubbed5f36882016-01-15 22:40:372564#endif
xhwang213e50c2016-10-10 23:56:312565
dalecurtis8b8505e72016-06-10 21:59:172566 bool is_suspended = pipeline_controller_.IsSuspended();
Luke Halliwell7a8a8982018-07-25 01:07:052567 bool is_backgrounded = IsBackgroundSuspendEnabled(delegate_) && IsHidden();
sandersdaaff1a652016-11-17 01:47:252568 PlayState state = UpdatePlayState_ComputePlayState(
xjz4e5d4bf32017-02-15 21:26:352569 is_remote, can_auto_suspend, is_suspended, is_backgrounded);
sandersd35d2c3f2017-01-14 02:04:422570 SetDelegateState(state.delegate_state, state.is_idle);
sandersd50a635e2016-04-04 22:50:092571 SetMemoryReportingState(state.is_memory_reporting_enabled);
2572 SetSuspendState(state.is_suspended || pending_suspend_resume_cycle_);
2573}
dalecurtis5bbc487e2016-02-27 04:15:052574
sandersd35d2c3f2017-01-14 02:04:422575void WebMediaPlayerImpl::SetDelegateState(DelegateState new_state,
2576 bool is_idle) {
tguilbert1bb1c782017-01-23 21:15:112577 DCHECK(delegate_);
Dale Curtis779ed842018-03-10 06:20:132578 DVLOG(2) << __func__ << "(" << static_cast<int>(new_state) << ", " << is_idle
2579 << ")";
dalecurtis5bbc487e2016-02-27 04:15:052580
sandersd35d2c3f2017-01-14 02:04:422581 // Prevent duplicate delegate calls.
2582 // TODO(sandersd): Move this deduplication into the delegate itself.
2583 // TODO(sandersd): WebContentsObserverSanityChecker does not allow sending the
2584 // 'playing' IPC more than once in a row, even if the metadata has changed.
2585 // Figure out whether it should.
Mounir Lamouri366dd8472018-06-19 17:20:042586 // Pretend that the media has no audio if it never played unmuted. This is to
2587 // avoid any action related to audible media such as taking audio focus or
2588 // showing a media notification. To preserve a consistent experience, it does
2589 // not apply if a media was audible so the system states do not flicker
2590 // depending on whether the user muted the player.
2591 bool has_audio = HasAudio() && !client_->WasAlwaysMuted();
sandersd35d2c3f2017-01-14 02:04:422592 if (delegate_state_ == new_state &&
2593 (delegate_state_ != DelegateState::PLAYING ||
2594 delegate_has_audio_ == has_audio)) {
2595 return;
mlamouri910111362016-11-04 11:28:242596 }
sandersd50a635e2016-04-04 22:50:092597 delegate_state_ = new_state;
sandersd35d2c3f2017-01-14 02:04:422598 delegate_has_audio_ = has_audio;
sandersd50a635e2016-04-04 22:50:092599
sandersd35d2c3f2017-01-14 02:04:422600 switch (new_state) {
sandersd50a635e2016-04-04 22:50:092601 case DelegateState::GONE:
2602 delegate_->PlayerGone(delegate_id_);
2603 break;
mlamouri910111362016-11-04 11:28:242604 case DelegateState::PLAYING: {
peconn257951522017-06-09 18:24:592605 if (HasVideo())
2606 delegate_->DidPlayerSizeChange(delegate_id_, NaturalSize());
zqzhang5d8eab72016-08-26 20:34:302607 delegate_->DidPlay(
Blink Reformat1c4d759e2017-04-09 16:34:542608 delegate_id_, HasVideo(), has_audio,
avayvodcc273dd2017-01-19 19:35:122609 media::DurationToMediaContentType(GetPipelineMediaDuration()));
sandersd50a635e2016-04-04 22:50:092610 break;
mlamouri910111362016-11-04 11:28:242611 }
sandersd50a635e2016-04-04 22:50:092612 case DelegateState::PAUSED:
sandersd35d2c3f2017-01-14 02:04:422613 delegate_->DidPause(delegate_id_);
sandersd50a635e2016-04-04 22:50:092614 break;
dalecurtis0f0097a2015-12-01 17:40:472615 }
sandersd35d2c3f2017-01-14 02:04:422616
2617 delegate_->SetIdle(delegate_id_, is_idle);
dalecurtis0f0097a2015-12-01 17:40:472618}
2619
sandersd50a635e2016-04-04 22:50:092620void WebMediaPlayerImpl::SetMemoryReportingState(
2621 bool is_memory_reporting_enabled) {
2622 if (memory_usage_reporting_timer_.IsRunning() ==
2623 is_memory_reporting_enabled) {
hubbed5f36882016-01-15 22:40:372624 return;
sandersd50a635e2016-04-04 22:50:092625 }
sandersd1c0bba02016-03-04 23:14:082626
sandersd50a635e2016-04-04 22:50:092627 if (is_memory_reporting_enabled) {
2628 memory_usage_reporting_timer_.Start(FROM_HERE,
2629 base::TimeDelta::FromSeconds(2), this,
2630 &WebMediaPlayerImpl::ReportMemoryUsage);
2631 } else {
2632 memory_usage_reporting_timer_.Stop();
2633 ReportMemoryUsage();
2634 }
2635}
2636
2637void WebMediaPlayerImpl::SetSuspendState(bool is_suspended) {
xhwang213e50c2016-10-10 23:56:312638 DCHECK(main_task_runner_->BelongsToCurrentThread());
Dale Curtis779ed842018-03-10 06:20:132639 DVLOG(2) << __func__ << "(" << is_suspended << ")";
xhwang213e50c2016-10-10 23:56:312640
sandersd50a635e2016-04-04 22:50:092641 // Do not change the state after an error has occurred.
2642 // TODO(sandersd): Update PipelineController to remove the need for this.
2643 if (IsNetworkStateError(network_state_))
sandersd1c0bba02016-03-04 23:14:082644 return;
2645
jameswest451a5bb2017-01-27 03:59:392646 if (is_suspended) {
sandersd35d2c3f2017-01-14 02:04:422647 // If we were not resumed for long enough to satisfy the preroll attempt,
2648 // reset the clock.
2649 if (!preroll_attempt_pending_ && IsPrerollAttemptNeeded()) {
2650 preroll_attempt_pending_ = true;
2651 preroll_attempt_start_time_ = base::TimeTicks();
2652 }
sandersd50a635e2016-04-04 22:50:092653 pipeline_controller_.Suspend();
2654 } else {
sandersd35d2c3f2017-01-14 02:04:422655 // When resuming, start the preroll attempt clock.
2656 if (preroll_attempt_pending_) {
2657 preroll_attempt_pending_ = false;
2658 preroll_attempt_start_time_ = tick_clock_->NowTicks();
2659 }
sandersd50a635e2016-04-04 22:50:092660 pipeline_controller_.Resume();
2661 }
2662}
2663
2664WebMediaPlayerImpl::PlayState
2665WebMediaPlayerImpl::UpdatePlayState_ComputePlayState(bool is_remote,
xjz4e5d4bf32017-02-15 21:26:352666 bool can_auto_suspend,
dalecurtis8b8505e72016-06-10 21:59:172667 bool is_suspended,
sandersd50a635e2016-04-04 22:50:092668 bool is_backgrounded) {
2669 PlayState result;
2670
tguilbert1bb1c782017-01-23 21:15:112671 bool must_suspend = delegate_->IsFrameClosed();
Dale Curtis6438cf12018-03-29 02:34:012672 bool is_stale = delegate_->IsStale(delegate_id_);
2673
2674 if (stale_state_override_for_testing_.has_value() &&
2675 ready_state_ >= stale_state_override_for_testing_.value()) {
2676 is_stale = true;
2677 }
sandersd35d2c3f2017-01-14 02:04:422678
sandersd50a635e2016-04-04 22:50:092679 // This includes both data source (before pipeline startup) and pipeline
2680 // errors.
2681 bool has_error = IsNetworkStateError(network_state_);
2682
dalecurtiscc8baf72016-10-27 01:49:442683 // After HaveFutureData, Blink will call play() if the state is not paused;
2684 // prior to this point |paused_| is not accurate.
sandersd50a635e2016-04-04 22:50:092685 bool have_future_data =
Blink Reformat1c4d759e2017-04-09 16:34:542686 highest_ready_state_ >= WebMediaPlayer::kReadyStateHaveFutureData;
sandersd50a635e2016-04-04 22:50:092687
avayvod65fad272017-02-24 01:00:482688 // Background suspend is only enabled for paused players.
2689 // In the case of players with audio the session should be kept.
2690 bool background_suspended =
xjz4e5d4bf32017-02-15 21:26:352691 can_auto_suspend && is_backgrounded && paused_ && have_future_data;
sandersd50a635e2016-04-04 22:50:092692
dalecurtiscc8baf72016-10-27 01:49:442693 // Idle suspension is allowed prior to have future data since there exist
2694 // mechanisms to exit the idle state when the player is capable of reaching
2695 // the have future data state; see didLoadingProgress().
2696 //
sandersd50a635e2016-04-04 22:50:092697 // TODO(sandersd): Make the delegate suspend idle players immediately when
2698 // hidden.
sandersdaaff1a652016-11-17 01:47:252699 bool idle_suspended =
xjz4e5d4bf32017-02-15 21:26:352700 can_auto_suspend && is_stale && paused_ && !seeking_ && !overlay_enabled_;
dalecurtise7120dc2016-09-03 02:54:352701
2702 // If we're already suspended, see if we can wait for user interaction. Prior
sandersd35d2c3f2017-01-14 02:04:422703 // to HaveFutureData, we require |is_stale| to remain suspended. |is_stale|
dalecurtise7120dc2016-09-03 02:54:352704 // will be cleared when we receive data which may take us to HaveFutureData.
2705 bool can_stay_suspended =
sandersd35d2c3f2017-01-14 02:04:422706 (is_stale || have_future_data) && is_suspended && paused_ && !seeking_;
sandersd50a635e2016-04-04 22:50:092707
2708 // Combined suspend state.
sandersd35d2c3f2017-01-14 02:04:422709 result.is_suspended = is_remote || must_suspend || idle_suspended ||
avayvod65fad272017-02-24 01:00:482710 background_suspended || can_stay_suspended;
sandersd50a635e2016-04-04 22:50:092711
Dale Curtis779ed842018-03-10 06:20:132712 DVLOG(3) << __func__ << ": is_remote=" << is_remote
2713 << ", must_suspend=" << must_suspend
2714 << ", idle_suspended=" << idle_suspended
2715 << ", background_suspended=" << background_suspended
2716 << ", can_stay_suspended=" << can_stay_suspended
2717 << ", is_stale=" << is_stale
2718 << ", have_future_data=" << have_future_data
2719 << ", paused_=" << paused_ << ", seeking_=" << seeking_;
2720
sandersd50a635e2016-04-04 22:50:092721 // We do not treat |playback_rate_| == 0 as paused. For the media session,
2722 // being paused implies displaying a play button, which is incorrect in this
2723 // case. For memory usage reporting, we just use the same definition (but we
2724 // don't have to).
2725 //
2726 // Similarly, we don't consider |ended_| to be paused. Blink will immediately
2727 // call pause() or seek(), so |ended_| should not affect the computation.
2728 // Despite that, |ended_| does result in a separate paused state, to simplfy
2729 // the contract for SetDelegateState().
2730 //
avayvod65fad272017-02-24 01:00:482731 // |has_remote_controls| indicates if the player can be controlled outside the
2732 // page (e.g. via the notification controls or by audio focus events). Idle
sandersd50a635e2016-04-04 22:50:092733 // suspension does not destroy the media session, because we expect that the
avayvod5f34b642017-03-23 03:14:042734 // notification controls (and audio focus) remain. With some exceptions for
2735 // background videos, the player only needs to have audio to have controls
2736 // (requires |have_future_data|).
2737 //
2738 // |alive| indicates if the player should be present (not |GONE|) to the
2739 // delegate, either paused or playing. The following must be true for the
2740 // player:
sandersd50a635e2016-04-04 22:50:092741 // - |have_future_data|, since we need to know whether we are paused to
avayvod65fad272017-02-24 01:00:482742 // correctly configure the session and also because the tracks and
avayvod5f34b642017-03-23 03:14:042743 // duration are passed to DidPlay(),
2744 // - |is_remote| is false as remote playback is not handled by the delegate,
2745 // - |has_error| is false as player should have no errors,
2746 // - |background_suspended| is false, otherwise |has_remote_controls| must
2747 // be true.
sandersd50a635e2016-04-04 22:50:092748 //
avayvod65fad272017-02-24 01:00:482749 // TODO(sandersd): If Blink told us the paused state sooner, we could detect
2750 // if the remote controls are available sooner.
2751
2752 // Background videos with audio don't have remote controls if background
2753 // suspend is enabled and resuming background videos is not (original Android
2754 // behavior).
2755 bool backgrounded_video_has_no_remote_controls =
Luke Halliwell7a8a8982018-07-25 01:07:052756 IsBackgroundSuspendEnabled(delegate_) &&
2757 !IsResumeBackgroundVideosEnabled() && is_backgrounded && HasVideo();
sandersd50a635e2016-04-04 22:50:092758 bool can_play = !has_error && !is_remote && have_future_data;
avayvod5f34b642017-03-23 03:14:042759 bool has_remote_controls =
Blink Reformat1c4d759e2017-04-09 16:34:542760 HasAudio() && !backgrounded_video_has_no_remote_controls;
avayvod5f34b642017-03-23 03:14:042761 bool alive = can_play && !must_suspend &&
2762 (!background_suspended || has_remote_controls);
2763 if (!alive) {
sandersd50a635e2016-04-04 22:50:092764 result.delegate_state = DelegateState::GONE;
tguilbert1bb1c782017-01-23 21:15:112765 result.is_idle = delegate_->IsIdle(delegate_id_);
avayvod65fad272017-02-24 01:00:482766 } else if (paused_) {
sandersd35d2c3f2017-01-14 02:04:422767 // TODO(sandersd): Is it possible to have a suspended session, be ended,
2768 // and not be paused? If so we should be in a PLAYING state.
dalecurtise7120dc2016-09-03 02:54:352769 result.delegate_state =
sandersd35d2c3f2017-01-14 02:04:422770 ended_ ? DelegateState::GONE : DelegateState::PAUSED;
2771 result.is_idle = !seeking_;
sandersd50a635e2016-04-04 22:50:092772 } else {
2773 result.delegate_state = DelegateState::PLAYING;
sandersd35d2c3f2017-01-14 02:04:422774 result.is_idle = false;
sandersd50a635e2016-04-04 22:50:092775 }
2776
dalecurtis8b8505e72016-06-10 21:59:172777 // It's not critical if some cases where memory usage can change are missed,
sandersd50a635e2016-04-04 22:50:092778 // since media memory changes are usually gradual.
2779 result.is_memory_reporting_enabled =
Dale Curtis8a6281322017-08-31 00:35:532780 !has_error && can_play && !result.is_suspended && (!paused_ || seeking_);
sandersd50a635e2016-04-04 22:50:092781
2782 return result;
dalecurtis0f0097a2015-12-01 17:40:472783}
2784
dalecurtis83266c72015-10-29 18:43:202785void WebMediaPlayerImpl::ReportMemoryUsage() {
2786 DCHECK(main_task_runner_->BelongsToCurrentThread());
2787
wdzierzanowskifd4cd91c52015-12-02 23:50:202788 // About base::Unretained() usage below: We destroy |demuxer_| on the main
2789 // thread. Before that, however, ~WebMediaPlayerImpl() posts a task to the
2790 // media thread and waits for it to finish. Hence, the GetMemoryUsage() task
2791 // posted here must finish earlier.
Dale Curtis8a6281322017-08-31 00:35:532792 //
2793 // The exception to the above is when OnError() has been called. If we're in
2794 // the error state we've already shut down the pipeline and can't rely on it
2795 // to cycle the media thread before we destroy |demuxer_|. In this case skip
2796 // collection of the demuxer memory stats.
2797 if (demuxer_ && !IsNetworkStateError(network_state_)) {
wdzierzanowskifd4cd91c52015-12-02 23:50:202798 base::PostTaskAndReplyWithResult(
2799 media_task_runner_.get(), FROM_HERE,
2800 base::Bind(&Demuxer::GetMemoryUsage, base::Unretained(demuxer_.get())),
2801 base::Bind(&WebMediaPlayerImpl::FinishMemoryUsageReport, AsWeakPtr()));
2802 } else {
2803 FinishMemoryUsageReport(0);
2804 }
2805}
2806
2807void WebMediaPlayerImpl::FinishMemoryUsageReport(int64_t demuxer_memory_usage) {
2808 DCHECK(main_task_runner_->BelongsToCurrentThread());
2809
avayvodc4bfb0e62017-01-13 01:07:012810 const PipelineStatistics stats = GetPipelineStatistics();
servolk639473e492016-12-15 04:14:202811 const int64_t data_source_memory_usage =
2812 data_source_ ? data_source_->GetMemoryUsage() : 0;
dalecurtisecc76612017-04-19 00:31:202813
Dale Curtisc2c5dcb12018-04-16 23:21:292814 // If we have video and no video memory usage and we've rendered the first
2815 // frame, assume the VideoFrameCompositor is holding onto the last frame after
2816 // we've suspended the pipeline; which thus reports zero memory usage from the
2817 // video renderer.
dalecurtisecc76612017-04-19 00:31:202818 //
2819 // Technically this should use the coded size, but that requires us to hop to
2820 // the compositor to get and byte-perfect accuracy isn't important here.
2821 const int64_t video_memory_usage =
2822 stats.video_memory_usage +
Dale Curtisc2c5dcb12018-04-16 23:21:292823 ((pipeline_metadata_.has_video && !stats.video_memory_usage &&
2824 has_first_frame_)
Miguel Casas9e7766022018-01-08 16:13:132825 ? VideoFrame::AllocationSize(PIXEL_FORMAT_I420,
dalecurtisecc76612017-04-19 00:31:202826 pipeline_metadata_.natural_size)
2827 : 0);
2828
dalecurtis83266c72015-10-29 18:43:202829 const int64_t current_memory_usage =
dalecurtisecc76612017-04-19 00:31:202830 stats.audio_memory_usage + video_memory_usage + data_source_memory_usage +
2831 demuxer_memory_usage;
dalecurtis83266c72015-10-29 18:43:202832
dalecurtisecc76612017-04-19 00:31:202833 DVLOG(2) << "Memory Usage -- Total: " << current_memory_usage
2834 << " Audio: " << stats.audio_memory_usage
2835 << ", Video: " << video_memory_usage
servolk639473e492016-12-15 04:14:202836 << ", DataSource: " << data_source_memory_usage
wdzierzanowskifd4cd91c52015-12-02 23:50:202837 << ", Demuxer: " << demuxer_memory_usage;
dalecurtis83266c72015-10-29 18:43:202838
2839 const int64_t delta = current_memory_usage - last_reported_memory_usage_;
2840 last_reported_memory_usage_ = current_memory_usage;
2841 adjust_allocated_memory_cb_.Run(delta);
servolk639473e492016-12-15 04:14:202842
Blink Reformat1c4d759e2017-04-09 16:34:542843 if (HasAudio()) {
servolk639473e492016-12-15 04:14:202844 UMA_HISTOGRAM_MEMORY_KB("Media.WebMediaPlayerImpl.Memory.Audio",
2845 stats.audio_memory_usage / 1024);
2846 }
Blink Reformat1c4d759e2017-04-09 16:34:542847 if (HasVideo()) {
servolk639473e492016-12-15 04:14:202848 UMA_HISTOGRAM_MEMORY_KB("Media.WebMediaPlayerImpl.Memory.Video",
dalecurtisecc76612017-04-19 00:31:202849 video_memory_usage / 1024);
servolk639473e492016-12-15 04:14:202850 }
2851 if (data_source_) {
2852 UMA_HISTOGRAM_MEMORY_KB("Media.WebMediaPlayerImpl.Memory.DataSource",
2853 data_source_memory_usage / 1024);
2854 }
2855 if (demuxer_) {
2856 UMA_HISTOGRAM_MEMORY_KB("Media.WebMediaPlayerImpl.Memory.Demuxer",
2857 demuxer_memory_usage / 1024);
2858 }
dalecurtis83266c72015-10-29 18:43:202859}
2860
dalecurtis8b8505e72016-06-10 21:59:172861void WebMediaPlayerImpl::ScheduleIdlePauseTimer() {
avayvod65fad272017-02-24 01:00:482862 // Only schedule the pause timer if we're not paused or paused but going to
avayvod52efd282017-03-07 21:13:042863 // resume when foregrounded, and are suspended and have audio.
2864 if ((paused_ && !paused_when_hidden_) ||
Blink Reformat1c4d759e2017-04-09 16:34:542865 !pipeline_controller_.IsSuspended() || !HasAudio()) {
dalecurtis8b8505e72016-06-10 21:59:172866 return;
avayvod52efd282017-03-07 21:13:042867 }
dalecurtis8b8505e72016-06-10 21:59:172868
2869#if defined(OS_ANDROID)
2870 // Remote players will be suspended and locally paused.
Blink Reformat1c4d759e2017-04-09 16:34:542871 if (IsRemote())
dalecurtis8b8505e72016-06-10 21:59:172872 return;
2873#endif
2874
2875 // Idle timeout chosen arbitrarily.
2876 background_pause_timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(5),
2877 this, &WebMediaPlayerImpl::OnPause);
2878}
2879
dalecurtis04bdb582016-08-17 22:15:232880void WebMediaPlayerImpl::CreateWatchTimeReporter() {
wdzierzanowskia78fa9b2017-06-13 18:12:102881 if (!HasVideo() && !HasAudio())
2882 return;
2883
dalecurtis04bdb582016-08-17 22:15:232884 // Create the watch time reporter and synchronize its initial state.
Dale Curtis1adbe6a2017-08-02 02:09:132885 watch_time_reporter_.reset(new WatchTimeReporter(
Dale Curtis96d6e9382018-07-18 18:01:072886 mojom::PlaybackProperties::New(pipeline_metadata_.has_audio,
2887 pipeline_metadata_.has_video, false, false,
2888 !!chunk_demuxer_, is_encrypted_,
2889 embedded_media_experience_enabled_),
2890 pipeline_metadata_.natural_size,
Dale Curtis051fdf62017-08-05 00:21:132891 base::BindRepeating(&WebMediaPlayerImpl::GetCurrentTimeInternal,
2892 base::Unretained(this)),
Hajime Hoshi8bb37dc2017-12-19 09:35:102893 media_metrics_provider_.get(),
Hajime Hoshib5a26ee2018-05-14 12:47:512894 frame_->GetTaskRunner(blink::TaskType::kInternalMedia)));
dalecurtis04bdb582016-08-17 22:15:232895 watch_time_reporter_->OnVolumeChange(volume_);
Dale Curtisaebaeea2018-07-19 23:42:112896 watch_time_reporter_->OnDurationChanged(GetPipelineMediaDuration());
Mounir Lamourif9af74e72017-06-19 19:31:452897
tguilbert1bb1c782017-01-23 21:15:112898 if (delegate_->IsFrameHidden())
dalecurtis04bdb582016-08-17 22:15:232899 watch_time_reporter_->OnHidden();
2900 else
2901 watch_time_reporter_->OnShown();
Mounir Lamourif9af74e72017-06-19 19:31:452902
Mounir Lamouri41a79c62017-06-06 12:53:162903 if (client_->HasNativeControls())
2904 watch_time_reporter_->OnNativeControlsEnabled();
2905 else
2906 watch_time_reporter_->OnNativeControlsDisabled();
Mounir Lamourif9af74e72017-06-19 19:31:452907
2908 switch (client_->DisplayType()) {
2909 case WebMediaPlayer::DisplayType::kInline:
2910 watch_time_reporter_->OnDisplayTypeInline();
2911 break;
2912 case WebMediaPlayer::DisplayType::kFullscreen:
2913 watch_time_reporter_->OnDisplayTypeFullscreen();
2914 break;
2915 case WebMediaPlayer::DisplayType::kPictureInPicture:
2916 watch_time_reporter_->OnDisplayTypePictureInPicture();
2917 break;
2918 }
Dale Curtis96d6e9382018-07-18 18:01:072919
2920 UpdateSecondaryProperties();
Dale Curtis7fd27c4b2018-07-30 22:14:212921
2922 // If the WatchTimeReporter was recreated in the middle of playback, we want
2923 // to resume playback here too since we won't get another play() call. When
2924 // seeking, the seek completion will restart it if necessary.
2925 if (!paused_ && !seeking_)
2926 watch_time_reporter_->OnPlaying();
Dale Curtis96d6e9382018-07-18 18:01:072927}
2928
2929void WebMediaPlayerImpl::UpdateSecondaryProperties() {
2930 watch_time_reporter_->UpdateSecondaryProperties(
2931 mojom::SecondaryPlaybackProperties::New(
2932 pipeline_metadata_.audio_decoder_config.codec(),
2933 pipeline_metadata_.video_decoder_config.codec(), audio_decoder_name_,
2934 video_decoder_name_, pipeline_metadata_.natural_size));
dalecurtis04bdb582016-08-17 22:15:232935}
2936
avayvod39c102402016-11-23 21:43:132937bool WebMediaPlayerImpl::IsHidden() const {
2938 DCHECK(main_task_runner_->BelongsToCurrentThread());
2939
tguilbert1bb1c782017-01-23 21:15:112940 return delegate_->IsFrameHidden() && !delegate_->IsFrameClosed();
avayvod39c102402016-11-23 21:43:132941}
2942
avayvod102cdb62017-01-07 03:11:092943bool WebMediaPlayerImpl::IsStreaming() const {
2944 return data_source_ && data_source_->IsStreaming();
2945}
2946
liberato2fd111be2017-01-04 00:25:062947bool WebMediaPlayerImpl::DoesOverlaySupportMetadata() const {
Julien Isorce6c83d8de2017-10-12 13:11:292948 return pipeline_metadata_.video_decoder_config.video_rotation() ==
2949 VIDEO_ROTATION_0;
liberato2fd111be2017-01-04 00:25:062950}
2951
xjzaf29d4182016-12-16 01:52:322952void WebMediaPlayerImpl::ActivateViewportIntersectionMonitoring(bool activate) {
2953 DCHECK(main_task_runner_->BelongsToCurrentThread());
2954
Blink Reformat1c4d759e2017-04-09 16:34:542955 client_->ActivateViewportIntersectionMonitoring(activate);
xjzaf29d4182016-12-16 01:52:322956}
2957
Anton Vayvod09fa66e2017-07-20 23:02:122958void WebMediaPlayerImpl::UpdateRemotePlaybackCompatibility(bool is_compatible) {
2959 DCHECK(main_task_runner_->BelongsToCurrentThread());
2960
2961 client_->RemotePlaybackCompatibilityChanged(loaded_url_, is_compatible);
2962}
2963
Dale Curtis6438cf12018-03-29 02:34:012964void WebMediaPlayerImpl::ForceStaleStateForTesting(ReadyState target_state) {
2965 stale_state_override_for_testing_.emplace(target_state);
Dale Curtis99a9b482018-02-01 02:23:282966 UpdatePlayState();
2967}
2968
2969bool WebMediaPlayerImpl::IsSuspendedForTesting() {
2970 // This intentionally uses IsPipelineSuspended since we need to know when the
2971 // pipeline has reached the suspended state, not when it's in suspending.
2972 return pipeline_controller_.IsPipelineSuspended();
2973}
2974
avayvodcc273dd2017-01-19 19:35:122975bool WebMediaPlayerImpl::ShouldPauseVideoWhenHidden() const {
avayvod65fad272017-02-24 01:00:482976 // If suspending background video, pause any video that's not remoted or
2977 // not unlocked to play in the background.
Luke Halliwell7a8a8982018-07-25 01:07:052978 if (IsBackgroundSuspendEnabled(delegate_)) {
Blink Reformat1c4d759e2017-04-09 16:34:542979 if (!HasVideo())
avayvod65fad272017-02-24 01:00:482980 return false;
2981
2982#if defined(OS_ANDROID)
Blink Reformat1c4d759e2017-04-09 16:34:542983 if (IsRemote())
avayvod65fad272017-02-24 01:00:482984 return false;
avayvodcc273dd2017-01-19 19:35:122985#endif
avayvodeb9098d2017-01-07 00:33:032986
Blink Reformat1c4d759e2017-04-09 16:34:542987 return !HasAudio() || (IsResumeBackgroundVideosEnabled() &&
2988 video_locked_when_paused_when_hidden_);
avayvod65fad272017-02-24 01:00:482989 }
2990
2991 // Otherwise only pause if the optimization is on and it's a video-only
2992 // optimization candidate.
avayvod01201332017-04-14 00:27:152993 return IsBackgroundVideoPauseOptimizationEnabled() && !HasAudio() &&
avayvod65fad272017-02-24 01:00:482994 IsBackgroundOptimizationCandidate();
avayvodeb9098d2017-01-07 00:33:032995}
2996
avayvod2135a642017-01-13 00:17:142997bool WebMediaPlayerImpl::ShouldDisableVideoWhenHidden() const {
avayvodcc273dd2017-01-19 19:35:122998 // This optimization is behind the flag on all platforms.
2999 if (!IsBackgroundVideoTrackOptimizationEnabled())
avayvodc4bfb0e62017-01-13 01:07:013000 return false;
avayvodc4bfb0e62017-01-13 01:07:013001
avayvodcc273dd2017-01-19 19:35:123002 // Disable video track only for players with audio that match the criteria for
3003 // being optimized.
Blink Reformat1c4d759e2017-04-09 16:34:543004 return HasAudio() && IsBackgroundOptimizationCandidate();
avayvodcc273dd2017-01-19 19:35:123005}
3006
3007bool WebMediaPlayerImpl::IsBackgroundOptimizationCandidate() const {
3008 DCHECK(main_task_runner_->BelongsToCurrentThread());
3009
François Beaufort664c3ca72018-04-13 07:24:513010 // Don't optimize Picture-in-Picture players.
Mounir Lamouri0484f40a2018-07-25 03:03:263011 if (IsInPictureInPicture())
François Beaufort664c3ca72018-04-13 07:24:513012 return false;
3013
avayvodcc273dd2017-01-19 19:35:123014#if defined(OS_ANDROID) // WMPI_CAST
avayvodac1a8522017-01-20 19:02:503015 // Don't optimize players being Cast.
Blink Reformat1c4d759e2017-04-09 16:34:543016 if (IsRemote())
avayvodcc273dd2017-01-19 19:35:123017 return false;
3018#endif // defined(OS_ANDROID)
3019
3020 // Don't optimize audio-only or streaming players.
Blink Reformat1c4d759e2017-04-09 16:34:543021 if (!HasVideo() || IsStreaming())
avayvodcc273dd2017-01-19 19:35:123022 return false;
3023
Dale Curtis3f4935b2017-09-09 00:11:593024 // Video-only players are always optimized (paused).
3025 // Don't check the keyframe distance and duration.
3026 if (!HasAudio() && HasVideo())
3027 return true;
3028
avayvodcc273dd2017-01-19 19:35:123029 // Videos shorter than the maximum allowed keyframe distance can be optimized.
3030 base::TimeDelta duration = GetPipelineMediaDuration();
avayvode85ec422017-04-14 00:11:333031 base::TimeDelta max_keyframe_distance =
3032 (load_type_ == kLoadTypeMediaSource)
3033 ? max_keyframe_distance_to_disable_background_video_mse_
3034 : max_keyframe_distance_to_disable_background_video_;
3035 if (duration < max_keyframe_distance)
avayvodcc273dd2017-01-19 19:35:123036 return true;
3037
3038 // Otherwise, only optimize videos with shorter average keyframe distance.
avayvodc4bfb0e62017-01-13 01:07:013039 PipelineStatistics stats = GetPipelineStatistics();
avayvode85ec422017-04-14 00:11:333040 return stats.video_keyframe_distance_average < max_keyframe_distance;
avayvod2135a642017-01-13 00:17:143041}
3042
avayvod56e1f3942017-01-21 02:06:313043void WebMediaPlayerImpl::UpdateBackgroundVideoOptimizationState() {
3044 if (IsHidden()) {
Dale Curtisa75a7892017-08-09 20:21:513045 if (ShouldPauseVideoWhenHidden()) {
avayvod56e1f3942017-01-21 02:06:313046 PauseVideoIfNeeded();
Dale Curtisa75a7892017-08-09 20:21:513047 } else if (update_background_status_cb_.IsCancelled()) {
3048 // Only trigger updates when we don't have one already scheduled.
3049 update_background_status_cb_.Reset(
3050 base::Bind(&WebMediaPlayerImpl::DisableVideoTrackIfNeeded,
3051 base::Unretained(this)));
3052
3053 // Defer disable track until we're sure the clip will be backgrounded for
3054 // some time. Resuming may take half a second, so frequent tab switches
3055 // will yield a poor user experience otherwise. http://crbug.com/709302
3056 // may also cause AV sync issues if disable/enable happens too fast.
3057 main_task_runner_->PostDelayedTask(
3058 FROM_HERE, update_background_status_cb_.callback(),
3059 base::TimeDelta::FromSeconds(10));
3060 }
avayvod56e1f3942017-01-21 02:06:313061 } else {
Dale Curtisa75a7892017-08-09 20:21:513062 update_background_status_cb_.Cancel();
avayvod56e1f3942017-01-21 02:06:313063 EnableVideoTrackIfNeeded();
3064 }
3065}
3066
3067void WebMediaPlayerImpl::PauseVideoIfNeeded() {
3068 DCHECK(IsHidden());
3069
3070 // Don't pause video while the pipeline is stopped, resuming or seeking.
3071 // Also if the video is paused already.
tguilbert350936ff2017-02-24 05:39:273072 if (!pipeline_controller_.IsPipelineRunning() || is_pipeline_resuming_ ||
3073 seeking_ || paused_)
avayvod56e1f3942017-01-21 02:06:313074 return;
3075
3076 // OnPause() will set |paused_when_hidden_| to false and call
3077 // UpdatePlayState(), so set the flag to true after and then return.
3078 OnPause();
3079 paused_when_hidden_ = true;
3080}
3081
avayvod2135a642017-01-13 00:17:143082void WebMediaPlayerImpl::EnableVideoTrackIfNeeded() {
avayvod56e1f3942017-01-21 02:06:313083 // Don't change video track while the pipeline is stopped, resuming or
3084 // seeking.
tguilbert350936ff2017-02-24 05:39:273085 if (!pipeline_controller_.IsPipelineRunning() || is_pipeline_resuming_ ||
3086 seeking_)
avayvod2135a642017-01-13 00:17:143087 return;
3088
3089 if (video_track_disabled_) {
3090 video_track_disabled_ = false;
Blink Reformat1c4d759e2017-04-09 16:34:543091 if (client_->HasSelectedVideoTrack()) {
3092 WebMediaPlayer::TrackId trackId = client_->GetSelectedVideoTrackId();
3093 SelectedVideoTrackChanged(&trackId);
avayvod2135a642017-01-13 00:17:143094 }
3095 }
3096}
3097
3098void WebMediaPlayerImpl::DisableVideoTrackIfNeeded() {
3099 DCHECK(IsHidden());
3100
3101 // Don't change video track while the pipeline is resuming or seeking.
3102 if (is_pipeline_resuming_ || seeking_)
3103 return;
3104
3105 if (!video_track_disabled_ && ShouldDisableVideoWhenHidden()) {
3106 video_track_disabled_ = true;
Blink Reformat1c4d759e2017-04-09 16:34:543107 SelectedVideoTrackChanged(nullptr);
avayvod2135a642017-01-13 00:17:143108 }
3109}
3110
avayvodc4bfb0e62017-01-13 01:07:013111void WebMediaPlayerImpl::SetPipelineStatisticsForTest(
3112 const PipelineStatistics& stats) {
3113 pipeline_statistics_for_test_ = base::make_optional(stats);
3114}
3115
3116PipelineStatistics WebMediaPlayerImpl::GetPipelineStatistics() const {
3117 DCHECK(main_task_runner_->BelongsToCurrentThread());
3118
tguilbert350936ff2017-02-24 05:39:273119 return pipeline_statistics_for_test_.value_or(
3120 pipeline_controller_.GetStatistics());
avayvodc4bfb0e62017-01-13 01:07:013121}
3122
avayvodcc273dd2017-01-19 19:35:123123void WebMediaPlayerImpl::SetPipelineMediaDurationForTest(
3124 base::TimeDelta duration) {
3125 pipeline_media_duration_for_test_ = base::make_optional(duration);
3126}
3127
3128base::TimeDelta WebMediaPlayerImpl::GetPipelineMediaDuration() const {
3129 DCHECK(main_task_runner_->BelongsToCurrentThread());
3130
3131 return pipeline_media_duration_for_test_.value_or(
tguilbert350936ff2017-02-24 05:39:273132 pipeline_controller_.GetMediaDuration());
avayvodcc273dd2017-01-19 19:35:123133}
3134
3135void WebMediaPlayerImpl::ReportTimeFromForegroundToFirstFrame(
3136 base::TimeTicks foreground_time,
3137 base::TimeTicks new_frame_time) {
3138 base::TimeDelta time_to_first_frame = new_frame_time - foreground_time;
Blink Reformat1c4d759e2017-04-09 16:34:543139 if (HasAudio()) {
avayvodcc273dd2017-01-19 19:35:123140 UMA_HISTOGRAM_TIMES(
3141 "Media.Video.TimeFromForegroundToFirstFrame.DisableTrack",
3142 time_to_first_frame);
3143 } else {
3144 UMA_HISTOGRAM_TIMES("Media.Video.TimeFromForegroundToFirstFrame.Paused",
3145 time_to_first_frame);
3146 }
3147}
Xiangjun Zhangba8724f482017-08-03 06:43:253148
3149void WebMediaPlayerImpl::SwitchToRemoteRenderer(
3150 const std::string& remote_device_friendly_name) {
xjz4e5d4bf32017-02-15 21:26:353151 DCHECK(main_task_runner_->BelongsToCurrentThread());
Thomas Guilbertb341bae02018-05-09 00:02:133152 DCHECK(!disable_pipeline_auto_suspend_);
Xiangjun Zhangba8724f482017-08-03 06:43:253153 disable_pipeline_auto_suspend_ = true;
Chris Cunninghamd9df58e2017-08-29 00:04:233154
3155 // Capabilities reporting should only be performed for local playbacks.
3156 video_decode_stats_reporter_.reset();
3157
Xiangjun Zhangba8724f482017-08-03 06:43:253158 // Requests to restart media pipeline. A remote renderer will be created via
3159 // the |renderer_factory_selector_|.
xjz4e5d4bf32017-02-15 21:26:353160 ScheduleRestart();
xjzdf9b67e2017-04-13 23:28:253161 if (client_) {
Xiangjun Zhangba8724f482017-08-03 06:43:253162 client_->MediaRemotingStarted(
3163 WebString::FromUTF8(remote_device_friendly_name));
xjzdf9b67e2017-04-13 23:28:253164 }
xjz4e5d4bf32017-02-15 21:26:353165}
3166
Xiangjun Zhang5e20cba42018-01-10 19:54:563167void WebMediaPlayerImpl::SwitchToLocalRenderer(
3168 MediaObserverClient::ReasonToSwitchToLocal reason) {
Xiangjun Zhangba8724f482017-08-03 06:43:253169 DCHECK(main_task_runner_->BelongsToCurrentThread());
Xiangjun Zhang12f55272018-07-30 23:19:373170 if (!disable_pipeline_auto_suspend_)
3171 return; // Is currently with local renderer.
Xiangjun Zhangba8724f482017-08-03 06:43:253172 disable_pipeline_auto_suspend_ = false;
Chris Cunninghamd9df58e2017-08-29 00:04:233173
3174 // Capabilities reporting may resume now that playback is local.
3175 CreateVideoDecodeStatsReporter();
3176
Xiangjun Zhangba8724f482017-08-03 06:43:253177 // Requests to restart media pipeline. A local renderer will be created via
3178 // the |renderer_factory_selector_|.
3179 ScheduleRestart();
3180 if (client_)
Xiangjun Zhang5e20cba42018-01-10 19:54:563181 client_->MediaRemotingStopped(GetSwitchToLocalMessage(reason));
Xiangjun Zhangba8724f482017-08-03 06:43:253182}
3183
dalecurtis4f6d14d2017-02-22 17:42:223184void WebMediaPlayerImpl::RecordUnderflowDuration(base::TimeDelta duration) {
3185 DCHECK(data_source_ || chunk_demuxer_);
xhwang68b3fab82017-05-17 21:31:463186
dalecurtis4f6d14d2017-02-22 17:42:223187 if (data_source_)
Jennifer Apacible82e25c92017-08-07 18:15:273188 UMA_HISTOGRAM_TIMES("Media.UnderflowDuration2.SRC", duration);
dalecurtis4f6d14d2017-02-22 17:42:223189 else
Jennifer Apacible82e25c92017-08-07 18:15:273190 UMA_HISTOGRAM_TIMES("Media.UnderflowDuration2.MSE", duration);
xhwang68b3fab82017-05-17 21:31:463191
3192 if (is_encrypted_)
Jennifer Apacible82e25c92017-08-07 18:15:273193 UMA_HISTOGRAM_TIMES("Media.UnderflowDuration2.EME", duration);
dalecurtis4f6d14d2017-02-22 17:42:223194}
3195
xhwang60802652017-04-19 07:29:583196#define UMA_HISTOGRAM_VIDEO_HEIGHT(name, sample) \
3197 UMA_HISTOGRAM_CUSTOM_COUNTS(name, sample, 100, 10000, 50)
3198
3199void WebMediaPlayerImpl::RecordVideoNaturalSize(const gfx::Size& natural_size) {
3200 // Always report video natural size to MediaLog.
3201 media_log_->AddEvent(media_log_->CreateVideoSizeSetEvent(
3202 natural_size.width(), natural_size.height()));
3203
3204 if (initial_video_height_recorded_)
3205 return;
3206
3207 initial_video_height_recorded_ = true;
3208
3209 int height = natural_size.height();
3210
3211 if (load_type_ == kLoadTypeURL)
3212 UMA_HISTOGRAM_VIDEO_HEIGHT("Media.VideoHeight.Initial.SRC", height);
3213 else if (load_type_ == kLoadTypeMediaSource)
3214 UMA_HISTOGRAM_VIDEO_HEIGHT("Media.VideoHeight.Initial.MSE", height);
3215
3216 if (is_encrypted_)
3217 UMA_HISTOGRAM_VIDEO_HEIGHT("Media.VideoHeight.Initial.EME", height);
3218
3219 UMA_HISTOGRAM_VIDEO_HEIGHT("Media.VideoHeight.Initial.All", height);
3220}
3221
3222#undef UMA_HISTOGRAM_VIDEO_HEIGHT
3223
Greg Thompsonaa48ce8d2018-04-03 06:11:433224void WebMediaPlayerImpl::SetTickClockForTest(
3225 const base::TickClock* tick_clock) {
tzik2c963b872017-12-07 06:57:243226 tick_clock_ = tick_clock;
hubbeb2d3efd2017-05-05 23:26:383227 buffered_data_source_host_.SetTickClockForTest(tick_clock);
3228}
3229
Dale Curtis3899090ea2018-01-12 00:10:353230void WebMediaPlayerImpl::OnFirstFrame(base::TimeTicks frame_time) {
3231 DCHECK(!load_start_time_.is_null());
Dale Curtisff576552018-03-30 02:32:443232 DCHECK(!skip_metrics_due_to_startup_suspend_);
Dale Curtisc2c5dcb12018-04-16 23:21:293233 has_first_frame_ = true;
Dale Curtis3899090ea2018-01-12 00:10:353234 const base::TimeDelta elapsed = frame_time - load_start_time_;
3235 media_metrics_provider_->SetTimeToFirstFrame(elapsed);
3236 RecordTimingUMA("Media.TimeToFirstFrame", elapsed);
3237}
3238
3239void WebMediaPlayerImpl::RecordTimingUMA(const std::string& key,
3240 base::TimeDelta elapsed) {
3241 if (chunk_demuxer_)
3242 base::UmaHistogramMediumTimes(key + ".MSE", elapsed);
3243 else
3244 base::UmaHistogramMediumTimes(key + ".SRC", elapsed);
3245 if (is_encrypted_)
3246 base::UmaHistogramMediumTimes(key + ".EME", elapsed);
3247}
3248
John Rummelldb5a7ef2018-05-16 00:28:013249void WebMediaPlayerImpl::RecordEncryptionScheme(
3250 const std::string& stream_name,
3251 const EncryptionScheme& encryption_scheme) {
3252 DCHECK(stream_name == "Audio" || stream_name == "Video");
3253
3254 // If the stream is not encrypted, don't record it.
3255 if (encryption_scheme.mode() == EncryptionScheme::CIPHER_MODE_UNENCRYPTED)
3256 return;
3257
3258 base::UmaHistogramEnumeration(
3259 "Media.EME.EncryptionScheme.Initial." + stream_name,
3260 DetermineEncryptionSchemeUMAValue(encryption_scheme),
3261 EncryptionSchemeUMA::kCount);
3262}
3263
Mounir Lamouri0484f40a2018-07-25 03:03:263264bool WebMediaPlayerImpl::IsInPictureInPicture() const {
3265 DCHECK(client_);
3266 return client_->DisplayType() ==
3267 WebMediaPlayer::DisplayType::kPictureInPicture;
3268}
3269
Dale Curtis5bba03232018-08-30 17:57:383270void WebMediaPlayerImpl::MaybeSetContainerName() {
Dale Curtisf01c8262018-09-04 23:50:433271 // MSE nor MediaPlayerRenderer provide container information.
3272 if (chunk_demuxer_ || using_media_player_renderer_)
Dale Curtis5bba03232018-08-30 17:57:383273 return;
3274
3275 // Pipeline startup failed before even getting a demuxer setup.
3276 if (!demuxer_)
3277 return;
3278
3279 // Container has already been set.
3280 if (highest_ready_state_ >= WebMediaPlayer::kReadyStateHaveMetadata)
3281 return;
3282
3283// If ffmpeg isn't enabled, we can't get the container name.
3284#if BUILDFLAG(ENABLE_FFMPEG)
3285 media_metrics_provider_->SetContainerName(
3286 static_cast<FFmpegDemuxer*>(demuxer_.get())->container());
3287#endif
3288}
3289
acolwell9e0840d2014-09-06 19:01:323290} // namespace media