blob: 72d1d88c2019f2cb6d7261afead4ce5a67aca064 [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"
wdzierzanowskifd4cd91c52015-12-02 23:50:2026#include "base/task_runner_util.h"
Matt Wolenetz95af6362018-01-04 20:23:4227#include "base/task_scheduler/post_task.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"
Blink Reformata30d4232018-04-07 15:31:0657#include "third_party/blink/public/platform/web_encrypted_media_types.h"
Blink Reformata30d4232018-04-07 15:31:0658#include "third_party/blink/public/platform/web_localized_string.h"
59#include "third_party/blink/public/platform/web_media_player_client.h"
60#include "third_party/blink/public/platform/web_media_player_encrypted_media_client.h"
61#include "third_party/blink/public/platform/web_media_player_source.h"
62#include "third_party/blink/public/platform/web_media_source.h"
63#include "third_party/blink/public/platform/web_rect.h"
64#include "third_party/blink/public/platform/web_runtime_features.h"
65#include "third_party/blink/public/platform/web_security_origin.h"
66#include "third_party/blink/public/platform/web_size.h"
67#include "third_party/blink/public/platform/web_string.h"
68#include "third_party/blink/public/platform/web_surface_layer_bridge.h"
69#include "third_party/blink/public/platform/web_url.h"
70#include "third_party/blink/public/web/web_document.h"
71#include "third_party/blink/public/web/web_frame.h"
72#include "third_party/blink/public/web/web_local_frame.h"
73#include "third_party/blink/public/web/web_user_gesture_indicator.h"
74#include "third_party/blink/public/web/web_view.h"
[email protected]b3f2b912009-04-09 16:18:5275
dalecurtisea27a3ed2016-06-24 01:41:3076#if defined(OS_ANDROID)
77#include "media/base/android/media_codec_util.h"
78#endif
79
[email protected]180ef242013-11-07 06:50:4680using blink::WebCanvas;
81using 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
sandersd50a635e2016-04-04 22:50:09101bool IsBackgroundedSuspendEnabled() {
dalecurtis0431cbf2016-03-12 01:19:43102#if !defined(OS_ANDROID)
103 // Suspend/Resume is only enabled by default on Android.
104 return base::CommandLine::ForCurrentProcess()->HasSwitch(
105 switches::kEnableMediaSuspend);
106#else
107 return !base::CommandLine::ForCurrentProcess()->HasSwitch(
108 switches::kDisableMediaSuspend);
109#endif
110}
111
avayvod48a8be52016-08-04 19:52:50112bool IsResumeBackgroundVideosEnabled() {
113 return base::FeatureList::IsEnabled(kResumeBackgroundVideo);
114}
115
avayvod39c102402016-11-23 21:43:13116bool IsBackgroundVideoTrackOptimizationEnabled() {
117 return base::FeatureList::IsEnabled(kBackgroundVideoTrackOptimization);
118}
119
avayvod01201332017-04-14 00:27:15120bool IsBackgroundVideoPauseOptimizationEnabled() {
121 return base::FeatureList::IsEnabled(kBackgroundVideoPauseOptimization);
122}
123
avayvod82729272017-05-29 21:58:39124bool IsNewRemotePlaybackPipelineEnabled() {
125 return base::FeatureList::IsEnabled(kNewRemotePlaybackPipeline);
126}
127
sandersd50a635e2016-04-04 22:50:09128bool IsNetworkStateError(blink::WebMediaPlayer::NetworkState state) {
Blink Reformat1c4d759e2017-04-09 16:34:54129 bool result = state == blink::WebMediaPlayer::kNetworkStateFormatError ||
130 state == blink::WebMediaPlayer::kNetworkStateNetworkError ||
131 state == blink::WebMediaPlayer::kNetworkStateDecodeError;
132 DCHECK_EQ(state > blink::WebMediaPlayer::kNetworkStateLoaded, result);
sandersd50a635e2016-04-04 22:50:09133 return result;
134}
135
sandersd2c478422016-08-02 01:19:25136gfx::Size GetRotatedVideoSize(VideoRotation rotation, gfx::Size natural_size) {
137 if (rotation == VIDEO_ROTATION_90 || rotation == VIDEO_ROTATION_270)
138 return gfx::Size(natural_size.height(), natural_size.width());
139 return natural_size;
140}
141
Xiaohan Wangf63505d2017-10-21 08:00:53142void RecordEncryptedEvent(bool encrypted_event_fired) {
143 UMA_HISTOGRAM_BOOLEAN("Media.EME.EncryptedEvent", encrypted_event_fired);
144}
145
sandersd35d2c3f2017-01-14 02:04:42146// How much time must have elapsed since loading last progressed before we
147// assume that the decoder will have had time to complete preroll.
148constexpr base::TimeDelta kPrerollAttemptTimeout =
watkd026f792016-11-05 00:28:51149 base::TimeDelta::FromSeconds(3);
150
Matt Wolenetz6010f6c2017-10-18 00:44:36151// Maximum number, per-WMPI, of media logs of playback rate changes.
152constexpr int kMaxNumPlaybackRateLogs = 10;
153
Xiangjun Zhang5e20cba42018-01-10 19:54:56154blink::WebLocalizedString::Name GetSwitchToLocalMessage(
155 MediaObserverClient::ReasonToSwitchToLocal reason) {
156 switch (reason) {
157 case MediaObserverClient::ReasonToSwitchToLocal::NORMAL:
158 return blink::WebLocalizedString::kMediaRemotingStopText;
159 case MediaObserverClient::ReasonToSwitchToLocal::POOR_PLAYBACK_QUALITY:
160 return blink::WebLocalizedString::kMediaRemotingStopByPlaybackQualityText;
161 case MediaObserverClient::ReasonToSwitchToLocal::PIPELINE_ERROR:
162 return blink::WebLocalizedString::kMediaRemotingStopByErrorText;
163 case MediaObserverClient::ReasonToSwitchToLocal::ROUTE_TERMINATED:
164 return blink::WebLocalizedString::kMediaRemotingStopNoText;
165 }
166 NOTREACHED();
167 // To suppress compiler warning on Windows.
168 return blink::WebLocalizedString::kMediaRemotingStopNoText;
169}
170
John Rummelldb5a7ef2018-05-16 00:28:01171// These values are persisted to UMA. Entries should not be renumbered and
172// numeric values should never be reused.
173// TODO(crbug.com/825041): This should use EncryptionMode when kUnencrypted
174// removed.
175enum class EncryptionSchemeUMA { kCenc = 0, kCbcs = 1, kCount };
176
177EncryptionSchemeUMA DetermineEncryptionSchemeUMAValue(
178 const EncryptionScheme& encryption_scheme) {
179 if (encryption_scheme.mode() == EncryptionScheme::CIPHER_MODE_AES_CBC)
180 return EncryptionSchemeUMA::kCbcs;
181
182 DCHECK_EQ(encryption_scheme.mode(), EncryptionScheme::CIPHER_MODE_AES_CTR);
183 return EncryptionSchemeUMA::kCenc;
184}
185
[email protected]8931c41a2009-07-07 17:31:49186} // namespace
187
[email protected]6683e1b2014-04-10 01:45:38188class BufferedDataSourceHostImpl;
189
Blink Reformat1c4d759e2017-04-09 16:34:54190STATIC_ASSERT_ENUM(WebMediaPlayer::kCORSModeUnspecified,
danakj365175c2016-02-06 00:37:37191 UrlData::CORS_UNSPECIFIED);
Blink Reformat1c4d759e2017-04-09 16:34:54192STATIC_ASSERT_ENUM(WebMediaPlayer::kCORSModeAnonymous, UrlData::CORS_ANONYMOUS);
193STATIC_ASSERT_ENUM(WebMediaPlayer::kCORSModeUseCredentials,
danakj365175c2016-02-06 00:37:37194 UrlData::CORS_USE_CREDENTIALS);
[email protected]a5a01102012-06-06 17:01:24195
[email protected]5b5bb9d2010-10-22 19:57:36196WebMediaPlayerImpl::WebMediaPlayerImpl(
[email protected]35b2a972014-04-04 15:50:22197 blink::WebLocalFrame* frame,
[email protected]180ef242013-11-07 06:50:46198 blink::WebMediaPlayerClient* client,
srirama.m26f864d02015-07-14 05:21:46199 blink::WebMediaPlayerEncryptedMediaClient* encrypted_client,
tguilbert1bb1c782017-01-23 21:15:11200 WebMediaPlayerDelegate* delegate,
tguilbert70d2a00a2017-04-25 00:30:44201 std::unique_ptr<RendererFactorySelector> renderer_factory_selector,
Alok Priyadarshi7166d4d2017-07-29 04:04:25202 UrlIndex* url_index,
CJ DiMegliod7ac6772017-11-10 00:19:06203 std::unique_ptr<VideoFrameCompositor> compositor,
dalecurtis9cddc0b2017-04-19 21:23:38204 std::unique_ptr<WebMediaPlayerParams> params)
[email protected]f6af7592014-02-28 10:09:11205 : frame_(frame),
Alexander Timin310368112017-09-13 10:01:44206 main_task_runner_(
207 frame->GetTaskRunner(blink::TaskType::kMediaElementEvent)),
dalecurtis9cddc0b2017-04-19 21:23:38208 media_task_runner_(params->media_task_runner()),
209 worker_task_runner_(params->worker_task_runner()),
210 media_log_(params->take_media_log()),
sandersd1c0bba02016-03-04 23:14:08211 pipeline_controller_(
Hajime Hoshidb0761a42018-01-18 08:10:19212 std::make_unique<PipelineImpl>(media_task_runner_,
213 main_task_runner_,
214 media_log_.get()),
sandersd1c0bba02016-03-04 23:14:08215 base::Bind(&WebMediaPlayerImpl::CreateRenderer,
216 base::Unretained(this)),
217 base::Bind(&WebMediaPlayerImpl::OnPipelineSeeked, AsWeakPtr()),
218 base::Bind(&WebMediaPlayerImpl::OnPipelineSuspended, AsWeakPtr()),
avayvod2135a642017-01-13 00:17:14219 base::Bind(&WebMediaPlayerImpl::OnBeforePipelineResume, AsWeakPtr()),
220 base::Bind(&WebMediaPlayerImpl::OnPipelineResumed, AsWeakPtr()),
alokp967c902452016-05-06 05:21:37221 base::Bind(&WebMediaPlayerImpl::OnError, AsWeakPtr())),
[email protected]5badb082010-06-11 17:40:15222 client_(client),
srirama.m26f864d02015-07-14 05:21:46223 encrypted_client_(encrypted_client),
[email protected]baff4512011-10-19 18:21:07224 delegate_(delegate),
dalecurtis9cddc0b2017-04-19 21:23:38225 defer_load_cb_(params->defer_load_cb()),
dalecurtis9cddc0b2017-04-19 21:23:38226 adjust_allocated_memory_cb_(params->adjust_allocated_memory_cb()),
tzik2c963b872017-12-07 06:57:24227 tick_clock_(base::DefaultTickClock::GetInstance()),
hubbeb2d3efd2017-05-05 23:26:38228 buffered_data_source_host_(
229 base::Bind(&WebMediaPlayerImpl::OnProgress, AsWeakPtr()),
tzik2c963b872017-12-07 06:57:24230 tick_clock_),
hubbe5f0ad43b2015-12-14 20:57:26231 url_index_(url_index),
CJ DiMeglioc60a5cf2017-09-27 20:08:41232 context_provider_(params->context_provider()),
CJ DiMegliod7ac6772017-11-10 00:19:06233 vfc_task_runner_(params->video_frame_compositor_task_runner()),
234 compositor_(std::move(compositor)),
hubbed5f36882016-01-15 22:40:37235#if defined(OS_ANDROID) // WMPI_CAST
CJ DiMeglioc60a5cf2017-09-27 20:08:41236 cast_impl_(this, client_, params->context_provider()),
hubbed5f36882016-01-15 22:40:37237#endif
tguilbert70d2a00a2017-04-25 00:30:44238 renderer_factory_selector_(std::move(renderer_factory_selector)),
dalecurtis9cddc0b2017-04-19 21:23:38239 surface_manager_(params->surface_manager()),
dalecurtis9cddc0b2017-04-19 21:23:38240 observer_(params->media_observer()),
avayvod590011e32017-01-20 02:01:00241 max_keyframe_distance_to_disable_background_video_(
dalecurtis9cddc0b2017-04-19 21:23:38242 params->max_keyframe_distance_to_disable_background_video()),
avayvode85ec422017-04-14 00:11:33243 max_keyframe_distance_to_disable_background_video_mse_(
dalecurtis9cddc0b2017-04-19 21:23:38244 params->max_keyframe_distance_to_disable_background_video_mse()),
servolkf94b4602017-01-31 16:44:27245 enable_instant_source_buffer_gc_(
dalecurtis9cddc0b2017-04-19 21:23:38246 params->enable_instant_source_buffer_gc()),
shaktisahu24189c12017-03-11 17:42:55247 embedded_media_experience_enabled_(
liberato2ff93ad2017-05-17 07:28:24248 params->embedded_media_experience_enabled()),
CJ DiMegliodb88a672018-02-22 18:48:14249 surface_layer_for_video_enabled_(params->use_surface_layer_for_video()),
liberato2ff93ad2017-05-17 07:28:24250 request_routing_token_cb_(params->request_routing_token_cb()),
Dale Curtis1adbe6a2017-08-02 02:09:13251 overlay_routing_token_(OverlayInfo::RoutingToken()),
Jennifer Apaciblec45fd052018-02-25 12:04:55252 media_metrics_provider_(params->take_metrics_provider()),
Mounir Lamouri6d759e12018-05-16 20:01:30253 pip_surface_info_cb_(params->pip_surface_info_cb()) {
xhwang51139732017-02-24 19:36:08254 DVLOG(1) << __func__;
dalecurtis83266c72015-10-29 18:43:20255 DCHECK(!adjust_allocated_memory_cb_.is_null());
tguilbert70d2a00a2017-04-25 00:30:44256 DCHECK(renderer_factory_selector_);
servolkef1e5ef2016-03-25 04:55:26257 DCHECK(client_);
tguilbert1bb1c782017-01-23 21:15:11258 DCHECK(delegate_);
dalecurtis83266c72015-10-29 18:43:20259
CJ DiMegliod7ac6772017-11-10 00:19:06260 if (surface_layer_for_video_enabled_)
CJ DiMeglio2302d202017-08-31 08:38:04261 bridge_ = params->create_bridge_callback().Run(this);
CJ DiMeglio2302d202017-08-31 08:38:04262
[email protected]c8d574722017-08-30 20:53:43263 // If we're supposed to force video overlays, then make sure that they're
264 // enabled all the time.
265 always_enable_overlays_ = base::CommandLine::ForCurrentProcess()->HasSwitch(
tsunghungee562e92016-07-20 18:03:31266 switches::kForceVideoOverlays);
267
liberato2ff93ad2017-05-17 07:28:24268 if (base::FeatureList::IsEnabled(media::kOverlayFullscreenVideo)) {
269 bool use_android_overlay =
270 base::FeatureList::IsEnabled(media::kUseAndroidOverlay);
271 overlay_mode_ = use_android_overlay ? OverlayMode::kUseAndroidOverlay
272 : OverlayMode::kUseContentVideoView;
273 } else {
274 overlay_mode_ = OverlayMode::kNoOverlays;
275 }
ampea73f792017-01-19 04:05:39276
tguilbert1bb1c782017-01-23 21:15:11277 delegate_id_ = delegate_->AddObserver(this);
278 delegate_->SetIdle(delegate_id_, true);
sandersd1e49fb62015-12-12 01:18:06279
dalecurtis2cff7f372017-05-24 08:30:08280 media_log_->AddEvent(media_log_->CreateCreatedEvent(
281 url::Origin(frame_->GetSecurityOrigin()).GetURL().spec()));
sandersd72683f252017-07-07 23:20:46282 media_log_->SetStringProperty("frame_url",
283 frame_->GetDocument().Url().GetString().Utf8());
284 media_log_->SetStringProperty("frame_title",
285 frame_->GetDocument().Title().Utf8());
[email protected]4e6be3f2009-05-07 02:24:44286
dalecurtis9cddc0b2017-04-19 21:23:38287 if (params->initial_cdm())
288 SetCdm(params->initial_cdm());
xhwang0ad11e512014-11-25 23:43:09289
Xiaohan Wangf63505d2017-10-21 08:00:53290 // Report a false "EncrytpedEvent" here as a baseline.
291 RecordEncryptedEvent(false);
292
xhwangf94a634d2014-10-22 22:07:27293 // TODO(xhwang): When we use an external Renderer, many methods won't work,
xhwang6fa356202014-12-11 00:44:12294 // e.g. GetCurrentFrameFromCompositor(). See http://crbug.com/434861
dalecurtis9cddc0b2017-04-19 21:23:38295 audio_source_provider_ = new WebAudioSourceProviderImpl(
296 params->audio_renderer_sink(), media_log_.get());
xjz4e5d4bf32017-02-15 21:26:35297
298 if (observer_)
299 observer_->SetClient(this);
Hajime Hoshi8bb37dc2017-12-19 09:35:10300
301 memory_usage_reporting_timer_.SetTaskRunner(
Hajime Hoshib5a26ee2018-05-14 12:47:51302 frame_->GetTaskRunner(blink::TaskType::kInternalMedia));
[email protected]ec9212f2008-12-18 21:40:36303}
304
[email protected]4e6be3f2009-05-07 02:24:44305WebMediaPlayerImpl::~WebMediaPlayerImpl() {
xhwang51139732017-02-24 19:36:08306 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:43307 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53308
xhwang51139732017-02-24 19:36:08309 if (set_cdm_result_) {
310 DVLOG(2) << "Resolve pending SetCdm() when media player is destroyed.";
Blink Reformat1c4d759e2017-04-09 16:34:54311 set_cdm_result_->Complete();
xhwang51139732017-02-24 19:36:08312 set_cdm_result_.reset();
313 }
314
alokp1116967f2016-06-11 17:30:56315 suppress_destruction_errors_ = true;
tguilbert1bb1c782017-01-23 21:15:11316
317 delegate_->PlayerGone(delegate_id_);
318 delegate_->RemoveObserver(delegate_id_);
[email protected]baff4512011-10-19 18:21:07319
dalecurtis04bdb582016-08-17 22:15:23320 // Finalize any watch time metrics before destroying the pipeline.
321 watch_time_reporter_.reset();
322
tguilbert350936ff2017-02-24 05:39:27323 // The underlying Pipeline must be stopped before it is destroyed.
324 pipeline_controller_.Stop();
[email protected]f6af7592014-02-28 10:09:11325
dalecurtis83266c72015-10-29 18:43:20326 if (last_reported_memory_usage_)
327 adjust_allocated_memory_cb_.Run(-last_reported_memory_usage_);
328
dalecurtise1edb312016-06-22 02:33:21329 // Destruct compositor resources in the proper order.
danakj8d204a42018-05-18 18:05:35330 client_->SetCcLayer(nullptr);
CJ DiMeglio2302d202017-08-31 08:38:04331
Xiangjun Zhang5e20cba42018-01-10 19:54:56332 client_->MediaRemotingStopped(
333 blink::WebLocalizedString::kMediaRemotingStopNoText);
Xiangjun Zhang87299142017-09-13 20:35:03334
Mounir Lamouri6d759e12018-05-16 20:01:30335 if (client_->IsInPictureInPictureMode())
336 ExitPictureInPicture(base::DoNothing());
Jennifer Apacible302ad412018-03-23 07:05:04337
danakj25f030112018-05-11 18:26:54338 if (!surface_layer_for_video_enabled_ && video_layer_) {
339 video_layer_->StopUsingProvider();
lethalantidote7f6009d2017-07-07 21:47:39340 }
CJ DiMeglio2302d202017-08-31 08:38:04341
342 vfc_task_runner_->DeleteSoon(FROM_HERE, std::move(compositor_));
xhwangea8bb3562015-06-08 21:18:37343
Matt Wolenetz95af6362018-01-04 20:23:42344 if (chunk_demuxer_) {
345 // Continue destruction of |chunk_demuxer_| on the |media_task_runner_| to
346 // avoid racing other pending tasks on |chunk_demuxer_| on that runner while
347 // not further blocking |main_task_runner_| to perform the destruction.
348 media_task_runner_->PostTask(
349 FROM_HERE, base::BindOnce(&WebMediaPlayerImpl::DemuxerDestructionHelper,
350 media_task_runner_, std::move(demuxer_)));
351 }
352
xhwangea8bb3562015-06-08 21:18:37353 media_log_->AddEvent(
354 media_log_->CreateEvent(MediaLogEvent::WEBMEDIAPLAYER_DESTROYED));
[email protected]ec9212f2008-12-18 21:40:36355}
356
Matt Wolenetz95af6362018-01-04 20:23:42357// static
358void WebMediaPlayerImpl::DemuxerDestructionHelper(
359 scoped_refptr<base::SingleThreadTaskRunner> task_runner,
360 std::unique_ptr<Demuxer> demuxer) {
361 DCHECK(task_runner->BelongsToCurrentThread());
362 // ChunkDemuxer's streams may contain much buffered, compressed media that may
363 // need to be paged back in during destruction. Paging delay may exceed the
364 // renderer hang monitor's threshold on at least Windows while also blocking
365 // other work on the renderer main thread, so we do the actual destruction in
366 // the background without blocking WMPI destruction or |task_runner|. On
367 // advice of task_scheduler OWNERS, MayBlock() is not used because virtual
368 // memory overhead is not considered blocking I/O; and CONTINUE_ON_SHUTDOWN is
369 // used to allow process termination to not block on completing the task.
370 base::PostTaskWithTraits(
371 FROM_HERE,
372 {base::TaskPriority::BACKGROUND,
373 base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
374 base::BindOnce(
375 [](std::unique_ptr<Demuxer> demuxer_to_destroy) {
376 SCOPED_UMA_HISTOGRAM_TIMER("Media.MSE.DemuxerDestructionTime");
377 demuxer_to_destroy.reset();
378 },
379 std::move(demuxer)));
380}
381
Blink Reformat1c4d759e2017-04-09 16:34:54382void WebMediaPlayerImpl::Load(LoadType load_type,
guidou9bfe4e2f2016-04-09 08:31:19383 const blink::WebMediaPlayerSource& source,
[email protected]62e5e682013-03-07 23:53:24384 CORSMode cors_mode) {
xhwang51139732017-02-24 19:36:08385 DVLOG(1) << __func__;
guidou9bfe4e2f2016-04-09 08:31:19386 // Only URL or MSE blob URL is supported.
Blink Reformat1c4d759e2017-04-09 16:34:54387 DCHECK(source.IsURL());
388 blink::WebURL url = source.GetAsURL();
Xiaohan Wang81fd0022017-07-11 17:45:24389 DVLOG(1) << __func__ << "(" << load_type << ", " << GURL(url) << ", "
390 << cors_mode << ")";
[email protected]d726eddc2013-07-02 22:25:55391 if (!defer_load_cb_.is_null()) {
tguilbert350936ff2017-02-24 05:39:27392 defer_load_cb_.Run(base::Bind(&WebMediaPlayerImpl::DoLoad, AsWeakPtr(),
393 load_type, url, cors_mode));
[email protected]d726eddc2013-07-02 22:25:55394 return;
395 }
[email protected]ef8394c2013-08-21 20:26:30396 DoLoad(load_type, url, cors_mode);
[email protected]62e5e682013-03-07 23:53:24397}
398
CJ DiMeglio013d4c472017-11-21 03:27:30399void WebMediaPlayerImpl::OnWebLayerUpdated() {}
400
danakj6a062b112018-05-17 16:25:45401void WebMediaPlayerImpl::RegisterContentsLayer(cc::Layer* layer) {
CJ DiMeglio2302d202017-08-31 08:38:04402 DCHECK(bridge_);
danakj8d204a42018-05-18 18:05:35403 bridge_->GetCcLayer()->SetContentsOpaque(opaque_);
404 client_->SetCcLayer(layer);
CJ DiMeglio013d4c472017-11-21 03:27:30405}
406
danakj6a062b112018-05-17 16:25:45407void WebMediaPlayerImpl::UnregisterContentsLayer(cc::Layer* layer) {
408 // |client_| will unregister its cc::Layer if given a nullptr.
danakj8d204a42018-05-18 18:05:35409 client_->SetCcLayer(nullptr);
CJ DiMeglio2302d202017-08-31 08:38:04410}
411
Jennifer Apaciblec45fd052018-02-25 12:04:55412void WebMediaPlayerImpl::OnSurfaceIdUpdated(viz::SurfaceId surface_id) {
413 pip_surface_id_ = surface_id;
414
415 // TODO(726619): Handle the behavior when Picture-in-Picture mode is
416 // disabled.
Jennifer Apacible2b1dc5eb2018-04-27 16:23:28417 // The viz::SurfaceId may be updated when the video begins playback or when
418 // the size of the video changes.
Jennifer Apaciblec45fd052018-02-25 12:04:55419 if (client_ && client_->IsInPictureInPictureMode())
Jennifer Apacibleb1c9ca12018-04-12 07:49:38420 pip_surface_info_cb_.Run(pip_surface_id_, pipeline_metadata_.natural_size);
Jennifer Apaciblec45fd052018-02-25 12:04:55421}
422
Blink Reformat1c4d759e2017-04-09 16:34:54423bool WebMediaPlayerImpl::SupportsOverlayFullscreenVideo() {
watk9c87c6fa2016-05-06 20:36:51424#if defined(OS_ANDROID)
[email protected]68ec57f2017-06-27 22:10:05425 return !using_media_player_renderer_ &&
426 overlay_mode_ == OverlayMode::kUseContentVideoView;
watk9c87c6fa2016-05-06 20:36:51427#else
428 return false;
429#endif
430}
431
tsunghungee562e92016-07-20 18:03:31432void WebMediaPlayerImpl::EnableOverlay() {
433 overlay_enabled_ = true;
liberato2ff93ad2017-05-17 07:28:24434 if (surface_manager_ && overlay_mode_ == OverlayMode::kUseContentVideoView) {
liberatoe8e3f43d2017-05-01 22:23:11435 overlay_surface_id_.reset();
watkf835a792016-06-24 23:24:40436 surface_created_cb_.Reset(
437 base::Bind(&WebMediaPlayerImpl::OnSurfaceCreated, AsWeakPtr()));
438 surface_manager_->CreateFullscreenSurface(pipeline_metadata_.natural_size,
439 surface_created_cb_.callback());
liberato2ff93ad2017-05-17 07:28:24440 } else if (request_routing_token_cb_ &&
441 overlay_mode_ == OverlayMode::kUseAndroidOverlay) {
liberatofe8f9692017-06-08 19:17:36442 overlay_routing_token_is_pending_ = true;
liberato2ff93ad2017-05-17 07:28:24443 token_available_cb_.Reset(
444 base::Bind(&WebMediaPlayerImpl::OnOverlayRoutingToken, AsWeakPtr()));
445 request_routing_token_cb_.Run(token_available_cb_.callback());
watkf835a792016-06-24 23:24:40446 }
tsunghungee562e92016-07-20 18:03:31447
liberato2ff93ad2017-05-17 07:28:24448 // We have requested (and maybe already have) overlay information. If the
449 // restarted decoder requests overlay information, then we'll defer providing
450 // it if it hasn't arrived yet. Otherwise, this would be a race, since we
451 // don't know if the request for overlay info or restart will complete first.
tsunghungee562e92016-07-20 18:03:31452 if (decoder_requires_restart_for_overlay_)
watkdee516f2016-02-18 02:22:19453 ScheduleRestart();
454}
455
tsunghungee562e92016-07-20 18:03:31456void WebMediaPlayerImpl::DisableOverlay() {
457 overlay_enabled_ = false;
liberato2ff93ad2017-05-17 07:28:24458 if (overlay_mode_ == OverlayMode::kUseContentVideoView) {
459 surface_created_cb_.Cancel();
460 overlay_surface_id_ = SurfaceManager::kNoSurfaceID;
461 } else if (overlay_mode_ == OverlayMode::kUseAndroidOverlay) {
462 token_available_cb_.Cancel();
liberatofe8f9692017-06-08 19:17:36463 overlay_routing_token_is_pending_ = false;
464 overlay_routing_token_ = OverlayInfo::RoutingToken();
liberato2ff93ad2017-05-17 07:28:24465 }
tsunghungee562e92016-07-20 18:03:31466
467 if (decoder_requires_restart_for_overlay_)
watkdee516f2016-02-18 02:22:19468 ScheduleRestart();
liberato2ff93ad2017-05-17 07:28:24469 else
470 MaybeSendOverlayInfoToDecoder();
watkdee516f2016-02-18 02:22:19471}
472
Blink Reformat1c4d759e2017-04-09 16:34:54473void WebMediaPlayerImpl::EnteredFullscreen() {
liberatofe8f9692017-06-08 19:17:36474 overlay_info_.is_fullscreen = true;
475
[email protected]c8d574722017-08-30 20:53:43476 // |always_enable_overlays_| implies that we're already in overlay mode, so
477 // take no action here. Otherwise, switch to an overlay if it's allowed and
478 // if it will display properly.
479 if (!always_enable_overlays_ && overlay_mode_ != OverlayMode::kNoOverlays &&
liberato2fd111be2017-01-04 00:25:06480 DoesOverlaySupportMetadata()) {
tsunghungee562e92016-07-20 18:03:31481 EnableOverlay();
liberato2fd111be2017-01-04 00:25:06482 }
liberato2ff93ad2017-05-17 07:28:24483
liberatofe8f9692017-06-08 19:17:36484 // We send this only if we can send multiple calls. Otherwise, either (a)
485 // we already sent it and we don't have a callback anyway (we reset it when
486 // it's called in restart mode), or (b) we'll send this later when the surface
487 // actually arrives. GVD assumes that the first overlay info will have the
488 // routing information. Note that we set |is_fullscreen_| earlier, so that
489 // if EnableOverlay() can include fullscreen info in case it sends the overlay
490 // info before returning.
491 if (!decoder_requires_restart_for_overlay_)
492 MaybeSendOverlayInfoToDecoder();
tsunghungee562e92016-07-20 18:03:31493}
494
Blink Reformat1c4d759e2017-04-09 16:34:54495void WebMediaPlayerImpl::ExitedFullscreen() {
liberatofe8f9692017-06-08 19:17:36496 overlay_info_.is_fullscreen = false;
497
[email protected]c8d574722017-08-30 20:53:43498 // If we're in overlay mode, then exit it unless we're supposed to allow
499 // overlays all the time.
500 if (!always_enable_overlays_ && overlay_enabled_)
tsunghungee562e92016-07-20 18:03:31501 DisableOverlay();
liberato2ff93ad2017-05-17 07:28:24502
liberatofe8f9692017-06-08 19:17:36503 // See EnteredFullscreen for why we do this.
504 if (!decoder_requires_restart_for_overlay_)
505 MaybeSendOverlayInfoToDecoder();
tsunghungee562e92016-07-20 18:03:31506}
507
Blink Reformat1c4d759e2017-04-09 16:34:54508void WebMediaPlayerImpl::BecameDominantVisibleContent(bool isDominant) {
xjzcdbbe732016-12-03 20:47:42509 if (observer_)
510 observer_->OnBecameDominantVisibleContent(isDominant);
511}
512
Blink Reformat1c4d759e2017-04-09 16:34:54513void WebMediaPlayerImpl::SetIsEffectivelyFullscreen(
François Beaufortad6c5232018-02-26 11:00:44514 blink::WebFullscreenVideoStatus fullscreen_video_status) {
515 delegate_->SetIsEffectivelyFullscreen(delegate_id_, fullscreen_video_status);
zqzhangabc08242017-03-02 16:07:14516}
517
Mounir Lamouri41a79c62017-06-06 12:53:16518void WebMediaPlayerImpl::OnHasNativeControlsChanged(bool has_native_controls) {
519 if (!watch_time_reporter_)
520 return;
521
522 if (has_native_controls)
523 watch_time_reporter_->OnNativeControlsEnabled();
524 else
525 watch_time_reporter_->OnNativeControlsDisabled();
526}
527
Mounir Lamourif9af74e72017-06-19 19:31:45528void WebMediaPlayerImpl::OnDisplayTypeChanged(
529 WebMediaPlayer::DisplayType display_type) {
530 if (!watch_time_reporter_)
531 return;
532
533 switch (display_type) {
534 case WebMediaPlayer::DisplayType::kInline:
535 watch_time_reporter_->OnDisplayTypeInline();
536 break;
537 case WebMediaPlayer::DisplayType::kFullscreen:
538 watch_time_reporter_->OnDisplayTypeFullscreen();
539 break;
540 case WebMediaPlayer::DisplayType::kPictureInPicture:
541 watch_time_reporter_->OnDisplayTypePictureInPicture();
542 break;
543 }
544}
545
[email protected]ef8394c2013-08-21 20:26:30546void WebMediaPlayerImpl::DoLoad(LoadType load_type,
[email protected]180ef242013-11-07 06:50:46547 const blink::WebURL& url,
[email protected]d726eddc2013-07-02 22:25:55548 CORSMode cors_mode) {
John Chen5b164a02017-11-01 00:36:09549 TRACE_EVENT1("media", "WebMediaPlayerImpl::DoLoad", "id", media_log_->id());
pkastingf5279482016-07-27 02:18:20550 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:43551 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d726eddc2013-07-02 22:25:55552
[email protected]62e5e682013-03-07 23:53:24553 GURL gurl(url);
dalecurtis9cddc0b2017-04-19 21:23:38554 ReportMetrics(load_type, gurl, frame_->GetSecurityOrigin(), media_log_.get());
[email protected]62e5e682013-03-07 23:53:24555
Dan Sanderscd8981c2017-08-31 22:37:02556 // Report poster availability for SRC=.
557 if (load_type == kLoadTypeURL) {
558 if (preload_ == MultibufferDataSource::METADATA) {
559 UMA_HISTOGRAM_BOOLEAN("Media.SRC.PreloadMetaDataHasPoster", has_poster_);
560 } else if (preload_ == MultibufferDataSource::AUTO) {
561 UMA_HISTOGRAM_BOOLEAN("Media.SRC.PreloadAutoHasPoster", has_poster_);
562 }
563 }
564
[email protected]926f8fd2013-04-12 20:27:53565 // Set subresource URL for crash reporting.
Robert Sesekc5e91df2017-12-12 21:11:03566 static base::debug::CrashKeyString* subresource_url =
567 base::debug::AllocateCrashKeyString("subresource_url",
568 base::debug::CrashKeySize::Size256);
569 base::debug::SetCrashKeyString(subresource_url, gurl.spec());
[email protected]926f8fd2013-04-12 20:27:53570
tguilbert75e2bf62017-04-26 20:13:12571 // Used for HLS playback.
572 loaded_url_ = gurl;
tguilbert25a4d112016-10-13 21:56:51573
[email protected]ef8394c2013-08-21 20:26:30574 load_type_ = load_type;
575
Blink Reformat1c4d759e2017-04-09 16:34:54576 SetNetworkState(WebMediaPlayer::kNetworkStateLoading);
577 SetReadyState(WebMediaPlayer::kReadyStateHaveNothing);
578 media_log_->AddEvent(media_log_->CreateLoadEvent(url.GetString().Utf8()));
Dale Curtis3899090ea2018-01-12 00:10:35579 load_start_time_ = base::TimeTicks::Now();
[email protected]d726eddc2013-07-02 22:25:55580
Dale Curtis74612b72017-12-14 20:56:19581 // URL is used for UKM reporting. Privacy requires we only report origin of
582 // the top frame. |is_top_frame| signals how to interpret the origin.
583 // TODO(crbug.com/787209): Stop getting origin from the renderer.
584 media_metrics_provider_->Initialize(load_type == kLoadTypeMediaSource,
585 frame_ == frame_->Top(),
586 frame_->Top()->GetSecurityOrigin());
587
[email protected]d726eddc2013-07-02 22:25:55588 // Media source pipelines can start immediately.
Blink Reformat1c4d759e2017-04-09 16:34:54589 if (load_type == kLoadTypeMediaSource) {
[email protected]ef8394c2013-08-21 20:26:30590 StartPipeline();
hubbe5f0ad43b2015-12-14 20:57:26591 } else {
dalecurtisb6e052f52016-08-25 00:35:55592 data_source_.reset(new MultibufferDataSource(
Alok Priyadarshib8f30542017-07-22 00:16:25593 main_task_runner_,
594 url_index_->GetByUrl(url, static_cast<UrlData::CORSMode>(cors_mode)),
595 media_log_.get(), &buffered_data_source_host_,
dalecurtisb6e052f52016-08-25 00:35:55596 base::Bind(&WebMediaPlayerImpl::NotifyDownloading, AsWeakPtr())));
avayvode46d7bef2016-03-30 23:18:26597 data_source_->SetPreload(preload_);
Yoav Weissc34fb0d2018-01-08 05:37:27598 data_source_->SetIsClientAudioElement(client_->IsAudioElement());
avayvode46d7bef2016-03-30 23:18:26599 data_source_->Initialize(
600 base::Bind(&WebMediaPlayerImpl::DataSourceInitialized, AsWeakPtr()));
hubbe5f0ad43b2015-12-14 20:57:26601 }
hubbed5f36882016-01-15 22:40:37602
603#if defined(OS_ANDROID) // WMPI_CAST
dalecurtisbb3eaac2016-01-27 21:10:25604 cast_impl_.Initialize(url, frame_, delegate_id_);
hubbed5f36882016-01-15 22:40:37605#endif
[email protected]62e5e682013-03-07 23:53:24606}
607
Blink Reformat1c4d759e2017-04-09 16:34:54608void WebMediaPlayerImpl::Play() {
pkastingf5279482016-07-27 02:18:20609 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:43610 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53611
avayvod65fad272017-02-24 01:00:48612 // User initiated play unlocks background video playback.
Mustaq Ahmede473e4352017-11-04 01:04:25613 if (blink::WebUserGestureIndicator::IsProcessingUserGesture(frame_))
avayvod65fad272017-02-24 01:00:48614 video_locked_when_paused_when_hidden_ = false;
615
hubbed5f36882016-01-15 22:40:37616#if defined(OS_ANDROID) // WMPI_CAST
Blink Reformat1c4d759e2017-04-09 16:34:54617 if (IsRemote()) {
dalecurtis6e2716d2016-01-21 04:49:15618 cast_impl_.play();
hubbed5f36882016-01-15 22:40:37619 return;
620 }
621#endif
sandersd35d2c3f2017-01-14 02:04:42622 // TODO(sandersd): Do we want to reset the idle timer here?
tguilbert1bb1c782017-01-23 21:15:11623 delegate_->SetIdle(delegate_id_, false);
[email protected]49480902009-07-14 20:23:43624 paused_ = false;
tguilbert350936ff2017-02-24 05:39:27625 pipeline_controller_.SetPlaybackRate(playback_rate_);
dalecurtis4619cd02016-09-22 21:39:10626 background_pause_timer_.Stop();
sandersd1c0bba02016-03-04 23:14:08627
[email protected]039b7542013-10-17 22:06:25628 if (data_source_)
629 data_source_->MediaIsPlaying();
[email protected]090f7312011-08-05 23:26:40630
xjz48a9cb72016-12-20 04:02:49631 if (observer_)
632 observer_->OnPlaying();
633
Mounir Lamouri89c0a1b2018-03-01 15:00:44634 watch_time_reporter_->SetAutoplayInitiated(client_->WasAutoplayInitiated());
635
Dale Curtis051fdf62017-08-05 00:21:13636 // If we're seeking we'll trigger the watch time reporter upon seek completed;
637 // we don't want to start it here since the seek time is unstable. E.g., when
638 // playing content with a positive start time we would have a zero seek time.
639 if (!Seeking()) {
640 DCHECK(watch_time_reporter_);
641 watch_time_reporter_->OnPlaying();
642 }
643
Chris Cunninghamd9df58e2017-08-29 00:04:23644 if (video_decode_stats_reporter_)
645 video_decode_stats_reporter_->OnPlaying();
646
acolwell9e0840d2014-09-06 19:01:32647 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PLAY));
sandersd50a635e2016-04-04 22:50:09648 UpdatePlayState();
[email protected]ec9212f2008-12-18 21:40:36649}
650
Blink Reformat1c4d759e2017-04-09 16:34:54651void WebMediaPlayerImpl::Pause() {
pkastingf5279482016-07-27 02:18:20652 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:43653 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53654
sandersd50a635e2016-04-04 22:50:09655 // We update the paused state even when casting, since we expect pause() to be
656 // called when casting begins, and when we exit casting we should end up in a
657 // paused state.
[email protected]49480902009-07-14 20:23:43658 paused_ = true;
hubbed5f36882016-01-15 22:40:37659
avayvodeb9098d2017-01-07 00:33:03660 // No longer paused because it was hidden.
661 paused_when_hidden_ = false;
662
avayvod65fad272017-02-24 01:00:48663 // User initiated pause locks background videos.
Mustaq Ahmede473e4352017-11-04 01:04:25664 if (blink::WebUserGestureIndicator::IsProcessingUserGesture(frame_))
avayvod65fad272017-02-24 01:00:48665 video_locked_when_paused_when_hidden_ = true;
666
hubbed5f36882016-01-15 22:40:37667#if defined(OS_ANDROID) // WMPI_CAST
Blink Reformat1c4d759e2017-04-09 16:34:54668 if (IsRemote()) {
dalecurtis6e2716d2016-01-21 04:49:15669 cast_impl_.pause();
hubbed5f36882016-01-15 22:40:37670 return;
671 }
672#endif
673
tguilbert350936ff2017-02-24 05:39:27674 pipeline_controller_.SetPlaybackRate(0.0);
Dale Curtisdc5d47c2018-02-15 11:15:19675 paused_time_ = pipeline_controller_.GetMediaTime();
[email protected]090f7312011-08-05 23:26:40676
xjz48a9cb72016-12-20 04:02:49677 if (observer_)
678 observer_->OnPaused();
679
dalecurtis04bdb582016-08-17 22:15:23680 DCHECK(watch_time_reporter_);
681 watch_time_reporter_->OnPaused();
Chris Cunninghamd9df58e2017-08-29 00:04:23682
683 if (video_decode_stats_reporter_)
684 video_decode_stats_reporter_->OnPaused();
685
acolwell9e0840d2014-09-06 19:01:32686 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PAUSE));
avayvod2135a642017-01-13 00:17:14687
sandersd50a635e2016-04-04 22:50:09688 UpdatePlayState();
[email protected]ec9212f2008-12-18 21:40:36689}
690
Blink Reformat1c4d759e2017-04-09 16:34:54691void WebMediaPlayerImpl::Seek(double seconds) {
pkastingf5279482016-07-27 02:18:20692 DVLOG(1) << __func__ << "(" << seconds << "s)";
acolwellb4034942014-08-28 15:42:43693 DCHECK(main_task_runner_->BelongsToCurrentThread());
servolk86b3d88fb2017-03-18 02:50:28694 media_log_->AddEvent(media_log_->CreateSeekEvent(seconds));
sandersd1c0bba02016-03-04 23:14:08695 DoSeek(base::TimeDelta::FromSecondsD(seconds), true);
696}
697
698void WebMediaPlayerImpl::DoSeek(base::TimeDelta time, bool time_updated) {
699 DCHECK(main_task_runner_->BelongsToCurrentThread());
John Chen5b164a02017-11-01 00:36:09700 TRACE_EVENT2("media", "WebMediaPlayerImpl::DoSeek", "target",
701 time.InSecondsF(), "id", media_log_->id());
[email protected]d43ed912009-02-03 04:52:53702
hubbed5f36882016-01-15 22:40:37703#if defined(OS_ANDROID) // WMPI_CAST
Blink Reformat1c4d759e2017-04-09 16:34:54704 if (IsRemote()) {
sandersd1c0bba02016-03-04 23:14:08705 cast_impl_.seek(time);
hubbed5f36882016-01-15 22:40:37706 return;
707 }
708#endif
709
srirama.mccf671812015-01-08 11:59:13710 ReadyState old_state = ready_state_;
Blink Reformat1c4d759e2017-04-09 16:34:54711 if (ready_state_ > WebMediaPlayer::kReadyStateHaveMetadata)
712 SetReadyState(WebMediaPlayer::kReadyStateHaveMetadata);
[email protected]1bb666802013-11-28 06:12:08713
Dale Curtis051fdf62017-08-05 00:21:13714 // When paused or ended, we know exactly what the current time is and can
715 // elide seeks to it. However, there are two cases that are not elided:
sandersd1c0bba02016-03-04 23:14:08716 // 1) When the pipeline state is not stable.
717 // In this case we just let |pipeline_controller_| decide what to do, as
718 // it has complete information.
719 // 2) For MSE.
720 // Because the buffers may have changed between seeks, MSE seeks are
721 // never elided.
Dale Curtis051fdf62017-08-05 00:21:13722 if (paused_ && pipeline_controller_.IsStable() &&
723 (paused_time_ == time ||
724 (ended_ && time == base::TimeDelta::FromSecondsD(Duration()))) &&
sandersd1c0bba02016-03-04 23:14:08725 !chunk_demuxer_) {
726 // If the ready state was high enough before, we can indicate that the seek
727 // completed just by restoring it. Otherwise we will just wait for the real
728 // ready state change to eventually happen.
Blink Reformat1c4d759e2017-04-09 16:34:54729 if (old_state == kReadyStateHaveEnoughData) {
srirama.m8f4a37562014-12-13 08:16:18730 main_task_runner_->PostTask(
alokp967c902452016-05-06 05:21:37731 FROM_HERE, base::Bind(&WebMediaPlayerImpl::OnBufferingStateChange,
732 AsWeakPtr(), BUFFERING_HAVE_ENOUGH));
srirama.m36ab2682014-12-11 04:20:01733 }
sandersd1c0bba02016-03-04 23:14:08734 return;
srirama.m36ab2682014-12-11 04:20:01735 }
[email protected]44ff37c02009-10-24 01:03:03736
dalecurtis04bdb582016-08-17 22:15:23737 // Call this before setting |seeking_| so that the current media time can be
738 // recorded by the reporter.
739 if (watch_time_reporter_)
740 watch_time_reporter_->OnSeeking();
741
dalecurtis1af3c1a2017-04-11 00:53:49742 // Clear any new frame processed callbacks on seek; otherwise we'll end up
743 // logging a time long after the seek completes.
744 frame_time_report_cb_.Cancel();
745
sandersd35d2c3f2017-01-14 02:04:42746 // TODO(sandersd): Move |seeking_| to PipelineController.
747 // TODO(sandersd): Do we want to reset the idle timer here?
tguilbert1bb1c782017-01-23 21:15:11748 delegate_->SetIdle(delegate_id_, false);
sandersd50a635e2016-04-04 22:50:09749 ended_ = false;
[email protected]b3766a22010-12-22 17:34:13750 seeking_ = true;
sandersd1c0bba02016-03-04 23:14:08751 seek_time_ = time;
752 if (paused_)
753 paused_time_ = time;
754 pipeline_controller_.Seek(time, time_updated);
[email protected]b3766a22010-12-22 17:34:13755
sandersd50a635e2016-04-04 22:50:09756 // This needs to be called after Seek() so that if a resume is triggered, it
757 // is to the correct time.
758 UpdatePlayState();
[email protected]ec9212f2008-12-18 21:40:36759}
760
Blink Reformat1c4d759e2017-04-09 16:34:54761void WebMediaPlayerImpl::SetRate(double rate) {
pkastingf5279482016-07-27 02:18:20762 DVLOG(1) << __func__ << "(" << rate << ")";
acolwellb4034942014-08-28 15:42:43763 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53764
Matt Wolenetz6010f6c2017-10-18 00:44:36765 if (rate != playback_rate_) {
766 LIMITED_MEDIA_LOG(INFO, media_log_.get(), num_playback_rate_logs_,
767 kMaxNumPlaybackRateLogs)
768 << "Effective playback rate changed from " << playback_rate_ << " to "
769 << rate;
770 }
771
[email protected]49480902009-07-14 20:23:43772 playback_rate_ = rate;
773 if (!paused_) {
tguilbert350936ff2017-02-24 05:39:27774 pipeline_controller_.SetPlaybackRate(rate);
[email protected]039b7542013-10-17 22:06:25775 if (data_source_)
776 data_source_->MediaPlaybackRateChanged(rate);
[email protected]49480902009-07-14 20:23:43777 }
[email protected]ec9212f2008-12-18 21:40:36778}
779
Blink Reformat1c4d759e2017-04-09 16:34:54780void WebMediaPlayerImpl::SetVolume(double volume) {
pkastingf5279482016-07-27 02:18:20781 DVLOG(1) << __func__ << "(" << volume << ")";
acolwellb4034942014-08-28 15:42:43782 DCHECK(main_task_runner_->BelongsToCurrentThread());
dalecurtisbb3eaac2016-01-27 21:10:25783 volume_ = volume;
tguilbert350936ff2017-02-24 05:39:27784 pipeline_controller_.SetVolume(volume_ * volume_multiplier_);
dalecurtis04bdb582016-08-17 22:15:23785 if (watch_time_reporter_)
786 watch_time_reporter_->OnVolumeChange(volume);
Becca Hughes9f6fd4b82017-06-15 10:01:40787 delegate_->DidPlayerMutedStatusChange(delegate_id_, volume == 0.0);
mlamouri910111362016-11-04 11:28:24788
789 // The play state is updated because the player might have left the autoplay
790 // muted state.
791 UpdatePlayState();
[email protected]ec9212f2008-12-18 21:40:36792}
[email protected]f0a51fb52009-03-05 12:46:38793
François Beaufort9290aab2018-05-07 21:18:47794void WebMediaPlayerImpl::EnterPictureInPicture(
795 blink::WebMediaPlayer::PipWindowSizeCallback callback) {
Mounir Lamouri6d759e12018-05-16 20:01:30796 if (!pip_surface_id_.is_valid()) {
797 // TODO(crbug.com/806249): Use Picture-in-Picture window size.
798 // TODO(mlamouri): should this be a DCHECK?
799 std::move(callback).Run(WebSize(pipeline_metadata_.natural_size));
Jennifer Apaciblec45fd052018-02-25 12:04:55800 return;
Mounir Lamouri6d759e12018-05-16 20:01:30801 }
Jennifer Apaciblec45fd052018-02-25 12:04:55802
Jennifer Apacibleee4c468a2018-03-24 06:57:19803 // Updates the MediaWebContentsObserver with |delegate_id_| to track which
804 // media player is in Picture-in-Picture mode.
Jennifer Apacible4081cb6b2018-05-04 01:34:45805 // This must be called before |pip_surface_info_cb_| to ensure the
806 // Picture-in-Picture media player id is set before the controller is set up.
Jennifer Apacibleee4c468a2018-03-24 06:57:19807 delegate_->DidPictureInPictureSourceChange(delegate_id_);
808
Jennifer Apacible4081cb6b2018-05-04 01:34:45809 pip_surface_info_cb_.Run(pip_surface_id_, pipeline_metadata_.natural_size);
810
Jennifer Apacible1a78cd02018-01-20 00:28:51811 if (client_)
Jennifer Apacible3f0489102018-01-19 20:10:31812 client_->PictureInPictureStarted();
Mounir Lamouri6d759e12018-05-16 20:01:30813
814 // TODO(crbug.com/806249): Use Picture-in-Picture window size.
815 std::move(callback).Run(WebSize(pipeline_metadata_.natural_size));
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 DCHECK(pip_surface_id_.is_valid());
François Beaufort9290aab2018-05-07 21:18:47821
Mounir Lamouri6d759e12018-05-16 20:01:30822 // Notifies the browser process that Picture-in-Picture has ended. It will
823 // clear out the states and close the window.
824 delegate_->DidPictureInPictureModeEnd(delegate_id_, std::move(callback));
Jennifer Apacible02897b72018-04-01 01:00:49825
Mounir Lamouri6d759e12018-05-16 20:01:30826 // Internal cleanups.
Jennifer Apacible5cd9a7e2018-04-17 03:08:06827 OnPictureInPictureModeEnded();
Jennifer Apacible02897b72018-04-01 01:00:49828}
829
Blink Reformat1c4d759e2017-04-09 16:34:54830void WebMediaPlayerImpl::SetSinkId(
guidouc7babef2015-10-22 00:42:35831 const blink::WebString& sink_id,
guidouc7babef2015-10-22 00:42:35832 blink::WebSetSinkIdCallbacks* web_callback) {
guidou69223ce2015-06-16 10:36:19833 DCHECK(main_task_runner_->BelongsToCurrentThread());
pkastingf5279482016-07-27 02:18:20834 DVLOG(1) << __func__;
guidouc7babef2015-10-22 00:42:35835
olka68b69392016-04-01 11:42:12836 media::OutputDeviceStatusCB callback =
837 media::ConvertToOutputDeviceStatusCB(web_callback);
guidouc7babef2015-10-22 00:42:35838 media_task_runner_->PostTask(
Max Morinf506af592018-04-17 12:23:32839 FROM_HERE, base::Bind(&SetSinkIdOnMediaThread, audio_source_provider_,
840 sink_id.Utf8(), callback));
guidou69223ce2015-06-16 10:36:19841}
842
Blink Reformat1c4d759e2017-04-09 16:34:54843STATIC_ASSERT_ENUM(WebMediaPlayer::kPreloadNone, MultibufferDataSource::NONE);
844STATIC_ASSERT_ENUM(WebMediaPlayer::kPreloadMetaData,
dalecurtisb6e052f52016-08-25 00:35:55845 MultibufferDataSource::METADATA);
Blink Reformat1c4d759e2017-04-09 16:34:54846STATIC_ASSERT_ENUM(WebMediaPlayer::kPreloadAuto, MultibufferDataSource::AUTO);
[email protected]23a8b1d82011-04-05 16:28:20847
Blink Reformat1c4d759e2017-04-09 16:34:54848void WebMediaPlayerImpl::SetPreload(WebMediaPlayer::Preload preload) {
pkastingf5279482016-07-27 02:18:20849 DVLOG(1) << __func__ << "(" << preload << ")";
acolwellb4034942014-08-28 15:42:43850 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]4e6be3f2009-05-07 02:24:44851
dalecurtisb6e052f52016-08-25 00:35:55852 preload_ = static_cast<MultibufferDataSource::Preload>(preload);
[email protected]b49beeb2013-03-01 20:04:00853 if (data_source_)
[email protected]09c60222014-08-07 16:42:31854 data_source_->SetPreload(preload_);
[email protected]4e6be3f2009-05-07 02:24:44855}
856
Blink Reformat1c4d759e2017-04-09 16:34:54857bool WebMediaPlayerImpl::HasVideo() const {
acolwellb4034942014-08-28 15:42:43858 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53859
[email protected]b8877772014-03-26 20:17:15860 return pipeline_metadata_.has_video;
[email protected]d43ed912009-02-03 04:52:53861}
862
Blink Reformat1c4d759e2017-04-09 16:34:54863bool WebMediaPlayerImpl::HasAudio() const {
acolwellb4034942014-08-28 15:42:43864 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]fc367af2009-08-14 23:06:35865
[email protected]b8877772014-03-26 20:17:15866 return pipeline_metadata_.has_audio;
[email protected]fc367af2009-08-14 23:06:35867}
868
Blink Reformat1c4d759e2017-04-09 16:34:54869void WebMediaPlayerImpl::EnabledAudioTracksChanged(
servolkf25ceed2016-07-01 03:44:38870 const blink::WebVector<blink::WebMediaPlayer::TrackId>& enabledTrackIds) {
871 DCHECK(main_task_runner_->BelongsToCurrentThread());
872
873 std::ostringstream logstr;
874 std::vector<MediaTrack::Id> enabledMediaTrackIds;
875 for (const auto& blinkTrackId : enabledTrackIds) {
Blink Reformat1c4d759e2017-04-09 16:34:54876 MediaTrack::Id track_id = blinkTrackId.Utf8().data();
servolkf25ceed2016-07-01 03:44:38877 logstr << track_id << " ";
878 enabledMediaTrackIds.push_back(track_id);
879 }
dalecurtis9cddc0b2017-04-19 21:23:38880 MEDIA_LOG(INFO, media_log_.get())
881 << "Enabled audio tracks: [" << logstr.str() << "]";
tguilbert350936ff2017-02-24 05:39:27882 pipeline_controller_.OnEnabledAudioTracksChanged(enabledMediaTrackIds);
servolkf25ceed2016-07-01 03:44:38883}
884
Blink Reformat1c4d759e2017-04-09 16:34:54885void WebMediaPlayerImpl::SelectedVideoTrackChanged(
servolkf25ceed2016-07-01 03:44:38886 blink::WebMediaPlayer::TrackId* selectedTrackId) {
887 DCHECK(main_task_runner_->BelongsToCurrentThread());
888
servolk9bed6602017-02-24 01:20:11889 base::Optional<MediaTrack::Id> selected_video_track_id;
890 if (selectedTrackId && !video_track_disabled_)
Blink Reformat1c4d759e2017-04-09 16:34:54891 selected_video_track_id = MediaTrack::Id(selectedTrackId->Utf8().data());
dalecurtis9cddc0b2017-04-19 21:23:38892 MEDIA_LOG(INFO, media_log_.get())
893 << "Selected video track: [" << selected_video_track_id.value_or("")
894 << "]";
tguilbert350936ff2017-02-24 05:39:27895 pipeline_controller_.OnSelectedVideoTrackChanged(selected_video_track_id);
servolkf25ceed2016-07-01 03:44:38896}
897
Blink Reformat1c4d759e2017-04-09 16:34:54898blink::WebSize WebMediaPlayerImpl::NaturalSize() const {
acolwellb4034942014-08-28 15:42:43899 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53900
[email protected]b8877772014-03-26 20:17:15901 return blink::WebSize(pipeline_metadata_.natural_size);
[email protected]d43ed912009-02-03 04:52:53902}
903
Jiajia Qin82acdc02017-07-31 09:55:14904blink::WebSize WebMediaPlayerImpl::VisibleRect() const {
905 DCHECK(main_task_runner_->BelongsToCurrentThread());
906 scoped_refptr<VideoFrame> video_frame = GetCurrentFrameFromCompositor();
907 if (!video_frame)
908 return blink::WebSize();
909
910 const gfx::Rect& visible_rect = video_frame->visible_rect();
911 return blink::WebSize(visible_rect.width(), visible_rect.height());
912}
913
Blink Reformat1c4d759e2017-04-09 16:34:54914bool WebMediaPlayerImpl::Paused() const {
acolwellb4034942014-08-28 15:42:43915 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53916
hubbed5f36882016-01-15 22:40:37917#if defined(OS_ANDROID) // WMPI_CAST
Blink Reformat1c4d759e2017-04-09 16:34:54918 if (IsRemote())
danakj4f1fd6a2017-01-06 21:15:17919 return cast_impl_.IsPaused();
hubbed5f36882016-01-15 22:40:37920#endif
sandersd50a635e2016-04-04 22:50:09921
tguilbert350936ff2017-02-24 05:39:27922 return pipeline_controller_.GetPlaybackRate() == 0.0f;
[email protected]d43ed912009-02-03 04:52:53923}
924
Blink Reformat1c4d759e2017-04-09 16:34:54925bool WebMediaPlayerImpl::Seeking() const {
acolwellb4034942014-08-28 15:42:43926 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53927
Blink Reformat1c4d759e2017-04-09 16:34:54928 if (ready_state_ == WebMediaPlayer::kReadyStateHaveNothing)
[email protected]0acebfa2009-08-21 22:45:40929 return false;
[email protected]67cd5052009-09-10 21:53:22930
[email protected]b3766a22010-12-22 17:34:13931 return seeking_;
[email protected]ec9212f2008-12-18 21:40:36932}
933
Blink Reformat1c4d759e2017-04-09 16:34:54934double WebMediaPlayerImpl::Duration() const {
acolwellb4034942014-08-28 15:42:43935 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]39bdde32013-04-17 17:44:20936
Blink Reformat1c4d759e2017-04-09 16:34:54937 if (ready_state_ == WebMediaPlayer::kReadyStateHaveNothing)
[email protected]39bdde32013-04-17 17:44:20938 return std::numeric_limits<double>::quiet_NaN();
939
chcunninghamb92d5062017-01-10 21:50:22940 // Use duration from ChunkDemuxer when present. MSE allows users to specify
941 // duration as a double. This propagates to the rest of the pipeline as a
942 // TimeDelta with potentially reduced precision (limited to Microseconds).
943 // ChunkDemuxer returns the full-precision user-specified double. This ensures
944 // users can "get" the exact duration they "set".
945 if (chunk_demuxer_)
946 return chunk_demuxer_->GetDuration();
947
avayvodcc273dd2017-01-19 19:35:12948 base::TimeDelta pipeline_duration = GetPipelineMediaDuration();
chcunninghamb92d5062017-01-10 21:50:22949 return pipeline_duration == kInfiniteDuration
950 ? std::numeric_limits<double>::infinity()
951 : pipeline_duration.InSecondsF();
[email protected]d43ed912009-02-03 04:52:53952}
953
[email protected]db66d0092014-04-16 07:15:12954double WebMediaPlayerImpl::timelineOffset() const {
acolwellb4034942014-08-28 15:42:43955 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]db66d0092014-04-16 07:15:12956
957 if (pipeline_metadata_.timeline_offset.is_null())
958 return std::numeric_limits<double>::quiet_NaN();
959
960 return pipeline_metadata_.timeline_offset.ToJsTime();
961}
962
Dale Curtis051fdf62017-08-05 00:21:13963base::TimeDelta WebMediaPlayerImpl::GetCurrentTimeInternal() const {
964 DCHECK(main_task_runner_->BelongsToCurrentThread());
965 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
966
967 base::TimeDelta current_time;
968 if (Seeking())
969 current_time = seek_time_;
970#if defined(OS_ANDROID) // WMPI_CAST
971 else if (IsRemote())
972 current_time = cast_impl_.currentTime();
973#endif
974 else if (paused_)
975 current_time = paused_time_;
976 else
977 current_time = pipeline_controller_.GetMediaTime();
978
979 DCHECK_NE(current_time, kInfiniteDuration);
980 DCHECK_GE(current_time, base::TimeDelta());
981 return current_time;
982}
983
Blink Reformat1c4d759e2017-04-09 16:34:54984double WebMediaPlayerImpl::CurrentTime() const {
acolwellb4034942014-08-28 15:42:43985 DCHECK(main_task_runner_->BelongsToCurrentThread());
Blink Reformat1c4d759e2017-04-09 16:34:54986 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
scherkusd2c745b2014-09-04 05:03:40987
988 // TODO(scherkus): Replace with an explicit ended signal to HTMLMediaElement,
989 // see http://crbug.com/409280
Dale Curtis051fdf62017-08-05 00:21:13990 // Note: Duration() may be infinity.
josephlolak918863bc2017-11-15 08:54:33991 return (ended_ && !std::isinf(Duration()))
992 ? Duration()
993 : GetCurrentTimeInternal().InSecondsF();
[email protected]d43ed912009-02-03 04:52:53994}
995
Blink Reformat1c4d759e2017-04-09 16:34:54996WebMediaPlayer::NetworkState WebMediaPlayerImpl::GetNetworkState() const {
acolwellb4034942014-08-28 15:42:43997 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]ddb1e5a2010-12-13 20:10:45998 return network_state_;
999}
1000
Blink Reformat1c4d759e2017-04-09 16:34:541001WebMediaPlayer::ReadyState WebMediaPlayerImpl::GetReadyState() const {
acolwellb4034942014-08-28 15:42:431002 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]ddb1e5a2010-12-13 20:10:451003 return ready_state_;
1004}
1005
wolenetzed8e7092017-04-21 16:28:591006blink::WebString WebMediaPlayerImpl::GetErrorMessage() const {
wolenetz4d39cc02016-04-05 19:54:411007 DCHECK(main_task_runner_->BelongsToCurrentThread());
wolenetzed8e7092017-04-21 16:28:591008 return blink::WebString::FromUTF8(media_log_->GetErrorMessage());
wolenetz4d39cc02016-04-05 19:54:411009}
1010
Blink Reformat1c4d759e2017-04-09 16:34:541011blink::WebTimeRanges WebMediaPlayerImpl::Buffered() const {
acolwellb4034942014-08-28 15:42:431012 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]779a8322014-08-22 21:28:371013
acolwell9e0840d2014-09-06 19:01:321014 Ranges<base::TimeDelta> buffered_time_ranges =
tguilbert350936ff2017-02-24 05:39:271015 pipeline_controller_.GetBufferedTimeRanges();
[email protected]779a8322014-08-22 21:28:371016
avayvodcc273dd2017-01-19 19:35:121017 const base::TimeDelta duration = GetPipelineMediaDuration();
dalecurtis39a7f932016-07-19 18:34:591018 if (duration != kInfiniteDuration) {
tguilbert350936ff2017-02-24 05:39:271019 buffered_data_source_host_.AddBufferedTimeRanges(&buffered_time_ranges,
1020 duration);
[email protected]779a8322014-08-22 21:28:371021 }
[email protected]02022fc2014-05-16 00:05:311022 return ConvertToWebTimeRanges(buffered_time_ranges);
1023}
1024
Blink Reformat1c4d759e2017-04-09 16:34:541025blink::WebTimeRanges WebMediaPlayerImpl::Seekable() const {
acolwellb4034942014-08-28 15:42:431026 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]39bdde32013-04-17 17:44:201027
Blink Reformat1c4d759e2017-04-09 16:34:541028 if (ready_state_ < WebMediaPlayer::kReadyStateHaveMetadata)
philipjb0e6f3f2014-09-30 09:51:531029 return blink::WebTimeRanges();
1030
Blink Reformat1c4d759e2017-04-09 16:34:541031 const double seekable_end = Duration();
dalecurtis56359cb2014-10-28 00:06:291032
1033 // Allow a special exception for seeks to zero for streaming sources with a
1034 // finite duration; this allows looping to work.
tguilbertade2bcb2017-01-07 02:57:451035 const bool is_finite_stream = data_source_ && data_source_->IsStreaming() &&
1036 std::isfinite(seekable_end);
1037
tguilbert75e2bf62017-04-26 20:13:121038 // Do not change the seekable range when using the MediaPlayerRenderer. It
1039 // will take care of dropping invalid seeks.
1040 const bool force_seeks_to_zero =
1041 !using_media_player_renderer_ && is_finite_stream;
dalecurtis56359cb2014-10-28 00:06:291042
1043 // TODO(dalecurtis): Technically this allows seeking on media which return an
tguilbertade2bcb2017-01-07 02:57:451044 // infinite duration so long as DataSource::IsStreaming() is false. While not
dalecurtis56359cb2014-10-28 00:06:291045 // expected, disabling this breaks semi-live players, http://crbug.com/427412.
1046 const blink::WebTimeRange seekable_range(
tguilbertade2bcb2017-01-07 02:57:451047 0.0, force_seeks_to_zero ? 0.0 : seekable_end);
philipjb0e6f3f2014-09-30 09:51:531048 return blink::WebTimeRanges(&seekable_range, 1);
[email protected]ec9212f2008-12-18 21:40:361049}
1050
sandersd35d2c3f2017-01-14 02:04:421051bool WebMediaPlayerImpl::IsPrerollAttemptNeeded() {
1052 // TODO(sandersd): Replace with |highest_ready_state_since_seek_| if we need
1053 // to ensure that preroll always gets a chance to complete.
1054 // See http://crbug.com/671525.
Blink Reformat1c4d759e2017-04-09 16:34:541055 if (highest_ready_state_ >= ReadyState::kReadyStateHaveFutureData)
sandersd35d2c3f2017-01-14 02:04:421056 return false;
1057
Fredrik Hubinette4cfb4412017-08-23 00:03:071058 // To suspend before we reach kReadyStateHaveCurrentData is only ok
1059 // if we know we're going to get woken up when we get more data, which
1060 // will only happen if the network is in the "Loading" state.
1061 // This happens when the network is fast, but multiple videos are loading
1062 // and multiplexing gets held up waiting for available threads.
1063 if (highest_ready_state_ <= ReadyState::kReadyStateHaveMetadata &&
1064 network_state_ != WebMediaPlayer::kNetworkStateLoading) {
1065 return true;
1066 }
1067
sandersd35d2c3f2017-01-14 02:04:421068 if (preroll_attempt_pending_)
1069 return true;
1070
1071 // Freshly initialized; there has never been any loading progress. (Otherwise
1072 // |preroll_attempt_pending_| would be true when the start time is null.)
1073 if (preroll_attempt_start_time_.is_null())
1074 return false;
1075
1076 base::TimeDelta preroll_attempt_duration =
1077 tick_clock_->NowTicks() - preroll_attempt_start_time_;
1078 return preroll_attempt_duration < kPrerollAttemptTimeout;
1079}
1080
Blink Reformat1c4d759e2017-04-09 16:34:541081bool WebMediaPlayerImpl::DidLoadingProgress() {
acolwellb4034942014-08-28 15:42:431082 DCHECK(main_task_runner_->BelongsToCurrentThread());
dalecurtise7120dc2016-09-03 02:54:351083
1084 // Note: Separate variables used to ensure both methods are called every time.
tguilbert350936ff2017-02-24 05:39:271085 const bool pipeline_progress = pipeline_controller_.DidLoadingProgress();
dalecurtise7120dc2016-09-03 02:54:351086 const bool data_progress = buffered_data_source_host_.DidLoadingProgress();
hubbeb2d3efd2017-05-05 23:26:381087 return pipeline_progress || data_progress;
[email protected]d43ed912009-02-03 04:52:531088}
1089
Blink Reformat1c4d759e2017-04-09 16:34:541090void WebMediaPlayerImpl::Paint(blink::WebCanvas* canvas,
[email protected]dd5c7972014-08-21 15:00:371091 const blink::WebRect& rect,
Kai Ninomiya9e8ae29b2017-09-06 23:45:161092 cc::PaintFlags& flags,
1093 int already_uploaded_id,
1094 VideoFrameUploadMetadata* out_metadata) {
acolwellb4034942014-08-28 15:42:431095 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]dd061e12014-05-06 19:21:221096 TRACE_EVENT0("media", "WebMediaPlayerImpl:paint");
[email protected]4e6be3f2009-05-07 02:24:441097
watkd16bb3e2017-04-25 01:18:311098 // We can't copy from protected frames.
Xiaohan Wang24cfe2c2018-01-22 23:16:001099 if (cdm_context_ref_)
xhwang80739452016-01-13 00:48:001100 return;
1101
mcasasf1236fc22015-05-29 22:38:561102 scoped_refptr<VideoFrame> video_frame = GetCurrentFrameFromCompositor();
[email protected]0fe5d43b2014-01-24 23:32:451103
[email protected]b49beeb2013-03-01 20:04:001104 gfx::Rect gfx_rect(rect);
dongseong.hwang0c4e9d82015-01-08 20:11:131105 Context3D context_3d;
mcasas265bdbf82015-06-12 18:44:071106 if (video_frame.get() && video_frame->HasTextures()) {
CJ DiMeglioc60a5cf2017-09-27 20:08:411107 if (context_provider_) {
1108 context_3d = Context3D(context_provider_->ContextGL(),
1109 context_provider_->GrContext());
1110 }
dongseong.hwang0c4e9d82015-01-08 20:11:131111 if (!context_3d.gl)
danakj53f7ec902016-05-21 01:30:101112 return; // Unable to get/create a shared main thread context.
1113 if (!context_3d.gr_context)
1114 return; // The context has been lost since and can't setup a GrContext.
dongseong.hwang0c4e9d82015-01-08 20:11:131115 }
Kai Ninomiyaef8c9e02017-09-27 04:07:401116 if (out_metadata && video_frame) {
Kai Ninomiya9e8ae29b2017-09-06 23:45:161117 // WebGL last-uploaded-frame-metadata API enabled. https://crbug.com/639174
1118 ComputeFrameUploadMetadata(video_frame.get(), already_uploaded_id,
1119 out_metadata);
1120 if (out_metadata->skipped) {
1121 // Skip uploading this frame.
1122 return;
1123 }
1124 }
zhuoyu.qian4689dde22017-10-16 04:11:481125 video_renderer_.Paint(
Julien Isorce6c83d8de2017-10-12 13:11:291126 video_frame, canvas, gfx::RectF(gfx_rect), flags,
1127 pipeline_metadata_.video_decoder_config.video_rotation(), context_3d);
[email protected]ec9212f2008-12-18 21:40:361128}
[email protected]5df51652009-01-17 00:03:001129
Matt Falkenhagenb147c5f2018-02-02 03:17:351130bool WebMediaPlayerImpl::DidGetOpaqueResponseFromServiceWorker() const {
1131 if (data_source_)
1132 return data_source_->DidGetOpaqueResponseViaServiceWorker();
1133 return false;
1134}
1135
Blink Reformat1c4d759e2017-04-09 16:34:541136bool WebMediaPlayerImpl::HasSingleSecurityOrigin() const {
[email protected]b49beeb2013-03-01 20:04:001137 if (data_source_)
1138 return data_source_->HasSingleOrigin();
[email protected]fcdb7462009-10-21 21:05:111139 return true;
[email protected]38259a7a82009-07-29 21:49:491140}
1141
Blink Reformat1c4d759e2017-04-09 16:34:541142bool WebMediaPlayerImpl::DidPassCORSAccessCheck() const {
[email protected]b49beeb2013-03-01 20:04:001143 if (data_source_)
1144 return data_source_->DidPassCORSAccessCheck();
1145 return false;
[email protected]3fe27112012-06-07 04:00:011146}
1147
Blink Reformat1c4d759e2017-04-09 16:34:541148double WebMediaPlayerImpl::MediaTimeForTimeValue(double timeValue) const {
qinminb4c39782015-08-10 18:43:241149 return base::TimeDelta::FromSecondsD(timeValue).InSecondsF();
[email protected]e06e16d82011-05-26 22:13:331150}
1151
Blink Reformat1c4d759e2017-04-09 16:34:541152unsigned WebMediaPlayerImpl::DecodedFrameCount() const {
acolwellb4034942014-08-28 15:42:431153 DCHECK(main_task_runner_->BelongsToCurrentThread());
Dale Curtisc7d2a7d22018-01-11 20:01:051154 return GetPipelineStatistics().video_frames_decoded;
[email protected]4c51bc662011-02-16 02:03:161155}
1156
Blink Reformat1c4d759e2017-04-09 16:34:541157unsigned WebMediaPlayerImpl::DroppedFrameCount() const {
acolwellb4034942014-08-28 15:42:431158 DCHECK(main_task_runner_->BelongsToCurrentThread());
Dale Curtisc7d2a7d22018-01-11 20:01:051159 return GetPipelineStatistics().video_frames_dropped;
[email protected]4c51bc662011-02-16 02:03:161160}
1161
Blink Reformat1c4d759e2017-04-09 16:34:541162size_t WebMediaPlayerImpl::AudioDecodedByteCount() const {
acolwellb4034942014-08-28 15:42:431163 DCHECK(main_task_runner_->BelongsToCurrentThread());
Dale Curtisc7d2a7d22018-01-11 20:01:051164 return GetPipelineStatistics().audio_bytes_decoded;
[email protected]4c51bc662011-02-16 02:03:161165}
1166
Blink Reformat1c4d759e2017-04-09 16:34:541167size_t WebMediaPlayerImpl::VideoDecodedByteCount() const {
acolwellb4034942014-08-28 15:42:431168 DCHECK(main_task_runner_->BelongsToCurrentThread());
Dale Curtisc7d2a7d22018-01-11 20:01:051169 return GetPipelineStatistics().video_bytes_decoded;
[email protected]4c51bc662011-02-16 02:03:161170}
1171
Blink Reformat1c4d759e2017-04-09 16:34:541172bool WebMediaPlayerImpl::CopyVideoTextureToPlatformTexture(
danakj46070b02016-03-28 21:54:111173 gpu::gles2::GLES2Interface* gl,
jiajia.qinc2943162017-05-12 01:34:391174 unsigned int target,
zmo57d577a2015-10-30 18:28:591175 unsigned int texture,
kbr0986e622017-04-13 02:34:581176 unsigned internal_format,
1177 unsigned format,
1178 unsigned type,
jiajia.qinc2943162017-05-12 01:34:391179 int level,
zmo57d577a2015-10-30 18:28:591180 bool premultiply_alpha,
Kai Ninomiya9e8ae29b2017-09-06 23:45:161181 bool flip_y,
1182 int already_uploaded_id,
1183 VideoFrameUploadMetadata* out_metadata) {
xhwang213e50c2016-10-10 23:56:311184 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]bfc05f22013-10-19 17:55:161185 TRACE_EVENT0("media", "WebMediaPlayerImpl:copyVideoTextureToPlatformTexture");
1186
watkd16bb3e2017-04-25 01:18:311187 // We can't copy from protected frames.
Xiaohan Wang24cfe2c2018-01-22 23:16:001188 if (cdm_context_ref_)
xhwang213e50c2016-10-10 23:56:311189 return false;
[email protected]dd061e12014-05-06 19:21:221190
xhwang213e50c2016-10-10 23:56:311191 scoped_refptr<VideoFrame> video_frame = GetCurrentFrameFromCompositor();
jbauman581d041c2016-07-21 01:01:031192 if (!video_frame.get() || !video_frame->HasTextures()) {
[email protected]e56f88c72013-06-25 22:31:291193 return false;
dongseong.hwang0c4e9d82015-01-08 20:11:131194 }
Kai Ninomiya9e8ae29b2017-09-06 23:45:161195 if (out_metadata) {
1196 // WebGL last-uploaded-frame-metadata API is enabled.
1197 // https://crbug.com/639174
1198 ComputeFrameUploadMetadata(video_frame.get(), already_uploaded_id,
1199 out_metadata);
1200 if (out_metadata->skipped) {
1201 // Skip uploading this frame.
1202 return true;
1203 }
1204 }
[email protected]df41e252014-02-03 23:39:501205
jbauman581d041c2016-07-21 01:01:031206 Context3D context_3d;
CJ DiMeglioc60a5cf2017-09-27 20:08:411207 if (context_provider_) {
1208 context_3d = Context3D(context_provider_->ContextGL(),
1209 context_provider_->GrContext());
1210 }
zhuoyu.qian4689dde22017-10-16 04:11:481211 return video_renderer_.CopyVideoFrameTexturesToGLTexture(
jiajia.qinc2943162017-05-12 01:34:391212 context_3d, gl, video_frame.get(), target, texture, internal_format,
1213 format, type, level, premultiply_alpha, flip_y);
[email protected]6523b242013-03-13 11:10:071214}
1215
Matt Wolenetz95af6362018-01-04 20:23:421216// static
Kai Ninomiya9e8ae29b2017-09-06 23:45:161217void WebMediaPlayerImpl::ComputeFrameUploadMetadata(
1218 VideoFrame* frame,
1219 int already_uploaded_id,
1220 VideoFrameUploadMetadata* out_metadata) {
1221 DCHECK(out_metadata);
Kai Ninomiyaef8c9e02017-09-27 04:07:401222 DCHECK(frame);
Kai Ninomiya9e8ae29b2017-09-06 23:45:161223 out_metadata->frame_id = frame->unique_id();
1224 out_metadata->visible_rect = frame->visible_rect();
1225 out_metadata->timestamp = frame->timestamp();
1226 bool skip_possible = already_uploaded_id != -1;
1227 bool same_frame_id = frame->unique_id() == already_uploaded_id;
1228 out_metadata->skipped = skip_possible && same_frame_id;
1229}
1230
Blink Reformat1c4d759e2017-04-09 16:34:541231void WebMediaPlayerImpl::SetContentDecryptionModule(
[email protected]9ebc3b03f2014-08-13 04:01:231232 blink::WebContentDecryptionModule* cdm,
1233 blink::WebContentDecryptionModuleResult result) {
xhwang51139732017-02-24 19:36:081234 DVLOG(1) << __func__ << ": cdm = " << cdm;
acolwellb4034942014-08-28 15:42:431235 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]9ebc3b03f2014-08-13 04:01:231236
jrummell06f27072015-06-08 18:12:381237 // Once the CDM is set it can't be cleared as there may be frames being
1238 // decrypted on other threads. So fail this request.
1239 // http://crbug.com/462365#c7.
xhwang97de4202014-11-25 08:44:011240 if (!cdm) {
Blink Reformat1c4d759e2017-04-09 16:34:541241 result.CompleteWithError(
1242 blink::kWebContentDecryptionModuleExceptionInvalidStateError, 0,
xhwang79b193042016-12-13 18:52:431243 "The existing ContentDecryptionModule object cannot be removed at this "
1244 "time.");
xhwang97de4202014-11-25 08:44:011245 return;
1246 }
1247
jrummell89e61d82015-07-23 20:03:341248 // Create a local copy of |result| to avoid problems with the callback
1249 // getting passed to the media thread and causing |result| to be destructed
jrummell4acbec912016-02-27 02:45:031250 // on the wrong thread in some failure conditions. Blink should prevent
1251 // multiple simultaneous calls.
1252 DCHECK(!set_cdm_result_);
jrummell89e61d82015-07-23 20:03:341253 set_cdm_result_.reset(new blink::WebContentDecryptionModuleResult(result));
1254
dalecurtis04bdb582016-08-17 22:15:231255 // Recreate the watch time reporter if necessary.
1256 const bool was_encrypted = is_encrypted_;
1257 is_encrypted_ = true;
Dale Curtis3899090ea2018-01-12 00:10:351258 if (!was_encrypted) {
1259 media_metrics_provider_->SetIsEME();
1260 if (watch_time_reporter_)
1261 CreateWatchTimeReporter();
1262 }
dalecurtis04bdb582016-08-17 22:15:231263
Chris Cunninghamd9df58e2017-08-29 00:04:231264 // For now MediaCapabilities only handles clear content.
1265 video_decode_stats_reporter_.reset();
1266
jrummelle616ee92016-10-08 02:15:441267 SetCdm(cdm);
xhwang97de4202014-11-25 08:44:011268}
1269
xhwange8c4181a2014-12-06 08:10:011270void WebMediaPlayerImpl::OnEncryptedMediaInitData(
jrummellcf78967c2015-04-03 05:03:581271 EmeInitDataType init_data_type,
Avi Drissman97785ea2015-12-19 01:11:311272 const std::vector<uint8_t>& init_data) {
jrummellcf78967c2015-04-03 05:03:581273 DCHECK(init_data_type != EmeInitDataType::UNKNOWN);
xhwangbab66f52014-12-02 23:49:501274
Xiaohan Wangf63505d2017-10-21 08:00:531275 RecordEncryptedEvent(true);
xhwangbab66f52014-12-02 23:49:501276
dalecurtis04bdb582016-08-17 22:15:231277 // Recreate the watch time reporter if necessary.
1278 const bool was_encrypted = is_encrypted_;
1279 is_encrypted_ = true;
Dale Curtis3899090ea2018-01-12 00:10:351280 if (!was_encrypted) {
1281 media_metrics_provider_->SetIsEME();
1282 if (watch_time_reporter_)
1283 CreateWatchTimeReporter();
1284 }
dalecurtis04bdb582016-08-17 22:15:231285
Chris Cunninghamd9df58e2017-08-29 00:04:231286 // For now MediaCapabilities only handles clear content.
1287 video_decode_stats_reporter_.reset();
1288
Blink Reformat1c4d759e2017-04-09 16:34:541289 encrypted_client_->Encrypted(
davidbenb50f00c2015-12-01 00:01:501290 ConvertToWebInitDataType(init_data_type), init_data.data(),
srirama.m26f864d02015-07-14 05:21:461291 base::saturated_cast<unsigned int>(init_data.size()));
xhwangbab66f52014-12-02 23:49:501292}
1293
servolk81e01e02016-03-05 03:29:151294void WebMediaPlayerImpl::OnFFmpegMediaTracksUpdated(
dcheng3076abbf2016-04-22 20:42:391295 std::unique_ptr<MediaTracks> tracks) {
servolk81e01e02016-03-05 03:29:151296 // For MSE/chunk_demuxer case the media track updates are handled by
1297 // WebSourceBufferImpl.
1298 DCHECK(demuxer_.get());
1299 DCHECK(!chunk_demuxer_);
servolkef1e5ef2016-03-25 04:55:261300
servolk16e8bdf82017-04-11 17:00:391301 // Report the media track information to blink. Only the first audio track and
1302 // the first video track are enabled by default to match blink logic.
1303 bool is_first_audio_track = true;
1304 bool is_first_video_track = true;
servolkef1e5ef2016-03-25 04:55:261305 for (const auto& track : tracks->tracks()) {
1306 if (track->type() == MediaTrack::Audio) {
Blink Reformat1c4d759e2017-04-09 16:34:541307 client_->AddAudioTrack(blink::WebString::FromUTF8(track->id()),
1308 blink::WebMediaPlayerClient::kAudioTrackKindMain,
1309 blink::WebString::FromUTF8(track->label()),
1310 blink::WebString::FromUTF8(track->language()),
servolk16e8bdf82017-04-11 17:00:391311 is_first_audio_track);
1312 is_first_audio_track = false;
servolkef1e5ef2016-03-25 04:55:261313 } else if (track->type() == MediaTrack::Video) {
Blink Reformat1c4d759e2017-04-09 16:34:541314 client_->AddVideoTrack(blink::WebString::FromUTF8(track->id()),
1315 blink::WebMediaPlayerClient::kVideoTrackKindMain,
1316 blink::WebString::FromUTF8(track->label()),
1317 blink::WebString::FromUTF8(track->language()),
servolk16e8bdf82017-04-11 17:00:391318 is_first_video_track);
1319 is_first_video_track = false;
servolkef1e5ef2016-03-25 04:55:261320 } else {
1321 // Text tracks are not supported through this code path yet.
1322 NOTREACHED();
1323 }
1324 }
servolk81e01e02016-03-05 03:29:151325}
1326
jrummelle616ee92016-10-08 02:15:441327void WebMediaPlayerImpl::SetCdm(blink::WebContentDecryptionModule* cdm) {
1328 DCHECK(main_task_runner_->BelongsToCurrentThread());
1329 DCHECK(cdm);
Xiaohan Wang24cfe2c2018-01-22 23:16:001330
1331 auto cdm_context_ref =
1332 ToWebContentDecryptionModuleImpl(cdm)->GetCdmContextRef();
1333 if (!cdm_context_ref) {
jrummelle616ee92016-10-08 02:15:441334 NOTREACHED();
1335 OnCdmAttached(false);
xhwang80739452016-01-13 00:48:001336 return;
1337 }
1338
Xiaohan Wang24cfe2c2018-01-22 23:16:001339 CdmContext* cdm_context = cdm_context_ref->GetCdmContext();
1340 DCHECK(cdm_context);
jrummelle616ee92016-10-08 02:15:441341
1342 // Keep the reference to the CDM, as it shouldn't be destroyed until
1343 // after the pipeline is done with the |cdm_context|.
Xiaohan Wang24cfe2c2018-01-22 23:16:001344 pending_cdm_context_ref_ = std::move(cdm_context_ref);
tguilbert350936ff2017-02-24 05:39:271345 pipeline_controller_.SetCdm(
1346 cdm_context, base::Bind(&WebMediaPlayerImpl::OnCdmAttached, AsWeakPtr()));
xhwang97de4202014-11-25 08:44:011347}
1348
jrummell89e61d82015-07-23 20:03:341349void WebMediaPlayerImpl::OnCdmAttached(bool success) {
xhwang51139732017-02-24 19:36:081350 DVLOG(1) << __func__ << ": success = " << success;
jrummelle616ee92016-10-08 02:15:441351 DCHECK(main_task_runner_->BelongsToCurrentThread());
Xiaohan Wang24cfe2c2018-01-22 23:16:001352 DCHECK(pending_cdm_context_ref_);
jrummelle616ee92016-10-08 02:15:441353
1354 // If the CDM is set from the constructor there is no promise
1355 // (|set_cdm_result_|) to fulfill.
xhwang97de4202014-11-25 08:44:011356 if (success) {
xhwang29c5ad202017-04-14 07:02:191357 media_log_->SetBooleanProperty("has_cdm", true);
1358
jrummelle616ee92016-10-08 02:15:441359 // This will release the previously attached CDM (if any).
Xiaohan Wang24cfe2c2018-01-22 23:16:001360 cdm_context_ref_ = std::move(pending_cdm_context_ref_);
jrummelle616ee92016-10-08 02:15:441361 if (set_cdm_result_) {
Blink Reformat1c4d759e2017-04-09 16:34:541362 set_cdm_result_->Complete();
jrummelle616ee92016-10-08 02:15:441363 set_cdm_result_.reset();
1364 }
1365
xhwang97de4202014-11-25 08:44:011366 return;
1367 }
1368
Xiaohan Wang24cfe2c2018-01-22 23:16:001369 pending_cdm_context_ref_.reset();
jrummelle616ee92016-10-08 02:15:441370 if (set_cdm_result_) {
Blink Reformat1c4d759e2017-04-09 16:34:541371 set_cdm_result_->CompleteWithError(
1372 blink::kWebContentDecryptionModuleExceptionNotSupportedError, 0,
xhwang79b193042016-12-13 18:52:431373 "Unable to set ContentDecryptionModule object");
jrummelle616ee92016-10-08 02:15:441374 set_cdm_result_.reset();
1375 }
[email protected]9ebc3b03f2014-08-13 04:01:231376}
1377
sandersd1c0bba02016-03-04 23:14:081378void WebMediaPlayerImpl::OnPipelineSeeked(bool time_updated) {
John Chen5b164a02017-11-01 00:36:091379 TRACE_EVENT2("media", "WebMediaPlayerImpl::OnPipelineSeeked", "target",
1380 seek_time_.InSecondsF(), "id", media_log_->id());
[email protected]5d11eff2011-09-15 00:06:061381 seeking_ = false;
wolenetz1b2ae7d2015-06-10 00:44:211382 seek_time_ = base::TimeDelta();
avayvod2135a642017-01-13 00:17:141383
hubbe5a2dec022016-03-17 01:14:231384 if (paused_) {
1385#if defined(OS_ANDROID) // WMPI_CAST
Blink Reformat1c4d759e2017-04-09 16:34:541386 if (IsRemote()) {
Dale Curtis051fdf62017-08-05 00:21:131387 paused_time_ = cast_impl_.currentTime();
hubbe5a2dec022016-03-17 01:14:231388 } else {
tguilbert350936ff2017-02-24 05:39:271389 paused_time_ = pipeline_controller_.GetMediaTime();
hubbe5a2dec022016-03-17 01:14:231390 }
1391#else
tguilbert350936ff2017-02-24 05:39:271392 paused_time_ = pipeline_controller_.GetMediaTime();
hubbe5a2dec022016-03-17 01:14:231393#endif
dalecurtis04bdb582016-08-17 22:15:231394 } else {
1395 DCHECK(watch_time_reporter_);
1396 watch_time_reporter_->OnPlaying();
hubbe5a2dec022016-03-17 01:14:231397 }
sandersd1c0bba02016-03-04 23:14:081398 if (time_updated)
1399 should_notify_time_changed_ = true;
dalecurtisaf34d8712016-09-20 04:32:261400
dalecurtis4f6d14d2017-02-22 17:42:221401 // Reset underflow duration upon seek; this prevents looping videos and user
1402 // actions from artificially inflating the duration.
1403 underflow_timer_.reset();
avayvod56e1f3942017-01-21 02:06:311404
1405 // Background video optimizations are delayed when shown/hidden if pipeline
1406 // is seeking.
1407 UpdateBackgroundVideoOptimizationState();
Dale Curtis2dc6089a2018-03-26 16:47:581408
1409 // If we successfully completed a suspended startup, lie about our buffering
1410 // state for the time being. While ultimately we want to avoid lying about the
1411 // buffering state, for the initial test of true preload=metadata, signal
1412 // BUFFERING_HAVE_ENOUGH so that canplay and canplaythrough fire correctly.
1413 //
1414 // Later we can experiment with the impact of removing this lie; initial data
1415 // suggests high disruption since we've also made preload=metadata the
1416 // default. Most sites are not prepared for a lack of canplay; even many of
1417 // our own tests don't function correctly. See https://crbug.com/694855.
1418 //
1419 // Note: This call is dual purpose, it is also responsible for triggering an
1420 // UpdatePlayState() call which may need to resume the pipeline once Blink
1421 // has been told about the ReadyState change.
1422 if (attempting_suspended_start_ &&
1423 pipeline_controller_.IsPipelineSuspended()) {
Dale Curtisff576552018-03-30 02:32:441424 skip_metrics_due_to_startup_suspend_ = true;
Dale Curtis2dc6089a2018-03-26 16:47:581425 OnBufferingStateChangeInternal(BUFFERING_HAVE_ENOUGH, true);
Dale Curtisff576552018-03-30 02:32:441426
1427 // If |skip_metrics_due_to_startup_suspend_| is unset by a resume started by
1428 // the OnBufferingStateChangeInternal() call, record a histogram of it here.
1429 //
1430 // If the value is unset, that means we should not have suspended and we've
1431 // likely incurred some cost to TimeToFirstFrame and TimeToPlayReady which
1432 // will be reflected in those statistics.
1433 base::UmaHistogramBoolean(
1434 std::string("Media.PreloadMetadataSuspendWasIdeal.") +
1435 ((HasVideo() && HasAudio()) ? "AudioVideo"
1436 : (HasVideo() ? "Video" : "Audio")),
1437 skip_metrics_due_to_startup_suspend_);
Dale Curtis2dc6089a2018-03-26 16:47:581438 }
1439
1440 attempting_suspended_start_ = false;
[email protected]8931c41a2009-07-07 17:31:491441}
1442
sandersd1c0bba02016-03-04 23:14:081443void WebMediaPlayerImpl::OnPipelineSuspended() {
hubbed5f36882016-01-15 22:40:371444#if defined(OS_ANDROID)
avayvod82729272017-05-29 21:58:391445 if (IsRemote() && !IsNewRemotePlaybackPipelineEnabled()) {
hubbed5f36882016-01-15 22:40:371446 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner();
sandersd50a635e2016-04-04 22:50:091447 if (frame)
dalecurtise9c89e92016-05-20 19:38:001448 compositor_->PaintSingleFrame(frame);
hubbed5f36882016-01-15 22:40:371449 }
1450#endif
1451
sandersd2f5bb6152017-03-29 22:57:531452 // Tell the data source we have enough data so that it may release the
1453 // connection.
1454 if (data_source_)
1455 data_source_->OnBufferingHaveEnough(true);
dalecurtis37fe5862016-03-15 19:29:091456
sandersd50a635e2016-04-04 22:50:091457 ReportMemoryUsage();
1458
sandersd1c0bba02016-03-04 23:14:081459 if (pending_suspend_resume_cycle_) {
watkdee516f2016-02-18 02:22:191460 pending_suspend_resume_cycle_ = false;
sandersd50a635e2016-04-04 22:50:091461 UpdatePlayState();
dalecurtis0431cbf2016-03-12 01:19:431462 }
sandersd1c0bba02016-03-04 23:14:081463}
1464
avayvod2135a642017-01-13 00:17:141465void WebMediaPlayerImpl::OnBeforePipelineResume() {
Dale Curtisff576552018-03-30 02:32:441466 // We went through suspended startup, so the player is only just now spooling
1467 // up for playback. As such adjust |load_start_time_| so it reports the same
1468 // metric as what would be reported if we had not suspended at startup.
1469 if (skip_metrics_due_to_startup_suspend_) {
1470 // In the event that the call to SetReadyState() initiated after pipeline
1471 // startup immediately tries to start playback, we should not update
1472 // |load_start_time_| to avoid losing visibility into the impact of a
1473 // suspended startup on the time until first frame / play ready for cases
1474 // where suspended startup was applied incorrectly.
1475 if (!attempting_suspended_start_)
1476 load_start_time_ = base::TimeTicks::Now() - time_to_metadata_;
1477 skip_metrics_due_to_startup_suspend_ = false;
1478 }
1479
avayvod2135a642017-01-13 00:17:141480 // Enable video track if we disabled it in the background - this way the new
1481 // renderer will attach its callbacks to the video stream properly.
1482 // TODO(avayvod): Remove this when disabling and enabling video tracks in
1483 // non-playing state works correctly. See https://crbug.com/678374.
1484 EnableVideoTrackIfNeeded();
1485 is_pipeline_resuming_ = true;
1486}
1487
1488void WebMediaPlayerImpl::OnPipelineResumed() {
1489 is_pipeline_resuming_ = false;
1490
avayvod56e1f3942017-01-21 02:06:311491 UpdateBackgroundVideoOptimizationState();
avayvod2135a642017-01-13 00:17:141492}
1493
alokp967c902452016-05-06 05:21:371494void WebMediaPlayerImpl::OnDemuxerOpened() {
1495 DCHECK(main_task_runner_->BelongsToCurrentThread());
dalecurtis9cddc0b2017-04-19 21:23:381496 client_->MediaSourceOpened(new WebMediaSourceImpl(chunk_demuxer_));
alokp967c902452016-05-06 05:21:371497}
1498
servolkf94b4602017-01-31 16:44:271499void WebMediaPlayerImpl::OnMemoryPressure(
1500 base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
1501 DVLOG(2) << __func__ << " memory_pressure_level=" << memory_pressure_level;
1502 DCHECK(main_task_runner_->BelongsToCurrentThread());
1503 DCHECK(base::FeatureList::IsEnabled(kMemoryPressureBasedSourceBufferGC));
1504 DCHECK(chunk_demuxer_);
1505
1506 // The new value of |memory_pressure_level| will take effect on the next
1507 // garbage collection. Typically this means the next SourceBuffer append()
1508 // operation, since per MSE spec, the garbage collection must only occur
1509 // during SourceBuffer append(). But if memory pressure is critical it might
1510 // be better to perform GC immediately rather than wait for the next append
1511 // and potentially get killed due to out-of-memory.
1512 // So if this experiment is enabled and pressure level is critical, we'll pass
1513 // down force_instant_gc==true, which will force immediate GC on
1514 // SourceBufferStreams.
1515 bool force_instant_gc =
1516 (enable_instant_source_buffer_gc_ &&
1517 memory_pressure_level ==
1518 base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
1519
Matt Wolenetz95af6362018-01-04 20:23:421520 // base::Unretained is safe, since |chunk_demuxer_| is actually owned by
1521 // |this| via this->demuxer_. Note the destruction of |chunk_demuxer_| is done
1522 // from ~WMPI by first hopping to |media_task_runner_| to prevent race with
1523 // this task.
servolkf94b4602017-01-31 16:44:271524 media_task_runner_->PostTask(
1525 FROM_HERE, base::Bind(&ChunkDemuxer::OnMemoryPressure,
1526 base::Unretained(chunk_demuxer_),
Blink Reformat1c4d759e2017-04-09 16:34:541527 base::TimeDelta::FromSecondsD(CurrentTime()),
servolkf94b4602017-01-31 16:44:271528 memory_pressure_level, force_instant_gc));
1529}
1530
alokp967c902452016-05-06 05:21:371531void WebMediaPlayerImpl::OnError(PipelineStatus status) {
pkastingf5279482016-07-27 02:18:201532 DVLOG(1) << __func__;
alokp967c902452016-05-06 05:21:371533 DCHECK(main_task_runner_->BelongsToCurrentThread());
1534 DCHECK_NE(status, PIPELINE_OK);
1535
1536 if (suppress_destruction_errors_)
1537 return;
1538
Thomas Guilbert6b6be3d2017-08-18 03:17:271539#if defined(OS_ANDROID)
1540 if (status == PipelineStatus::DEMUXER_ERROR_DETECTED_HLS) {
1541 renderer_factory_selector_->SetUseMediaPlayer(true);
1542
1543 pipeline_controller_.Stop();
Dale Curtis8a6281322017-08-31 00:35:531544 SetMemoryReportingState(false);
Thomas Guilbert6b6be3d2017-08-18 03:17:271545
1546 main_task_runner_->PostTask(
1547 FROM_HERE, base::Bind(&WebMediaPlayerImpl::StartPipeline, AsWeakPtr()));
1548 return;
1549 }
1550#endif
1551
dalecurtis9cddc0b2017-04-19 21:23:381552 ReportPipelineError(load_type_, status, media_log_.get());
alokp967c902452016-05-06 05:21:371553 media_log_->AddEvent(media_log_->CreatePipelineErrorEvent(status));
Dale Curtis74612b72017-12-14 20:56:191554 media_metrics_provider_->OnError(status);
Dale Curtisccfd0cca2017-08-31 01:27:561555 if (watch_time_reporter_)
1556 watch_time_reporter_->OnError(status);
alokp967c902452016-05-06 05:21:371557
Blink Reformat1c4d759e2017-04-09 16:34:541558 if (ready_state_ == WebMediaPlayer::kReadyStateHaveNothing) {
alokp967c902452016-05-06 05:21:371559 // Any error that occurs before reaching ReadyStateHaveMetadata should
1560 // be considered a format error.
Blink Reformat1c4d759e2017-04-09 16:34:541561 SetNetworkState(WebMediaPlayer::kNetworkStateFormatError);
alokp967c902452016-05-06 05:21:371562 } else {
1563 SetNetworkState(PipelineErrorToNetworkState(status));
1564 }
1565
Thomas Guilbert2e591392017-08-12 00:56:381566 // PipelineController::Stop() is idempotent.
1567 pipeline_controller_.Stop();
1568
alokp967c902452016-05-06 05:21:371569 UpdatePlayState();
1570}
1571
1572void WebMediaPlayerImpl::OnEnded() {
John Chen5b164a02017-11-01 00:36:091573 TRACE_EVENT2("media", "WebMediaPlayerImpl::OnEnded", "duration", Duration(),
1574 "id", media_log_->id());
pkastingf5279482016-07-27 02:18:201575 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:431576 DCHECK(main_task_runner_->BelongsToCurrentThread());
scherkusd2c745b2014-09-04 05:03:401577
sandersd1c0bba02016-03-04 23:14:081578 // Ignore state changes until we've completed all outstanding operations.
1579 if (!pipeline_controller_.IsStable())
scherkusd2c745b2014-09-04 05:03:401580 return;
1581
1582 ended_ = true;
Blink Reformat1c4d759e2017-04-09 16:34:541583 client_->TimeChanged();
sandersd50a635e2016-04-04 22:50:091584
dalecurtis1af3c1a2017-04-11 00:53:491585 // Clear any new frame processed callbacks on end; otherwise we'll end up
1586 // logging a time long after playback ends.
1587 frame_time_report_cb_.Cancel();
1588
sandersd50a635e2016-04-04 22:50:091589 // We don't actually want this to run until |client_| calls seek() or pause(),
1590 // but that should have already happened in timeChanged() and so this is
1591 // expected to be a no-op.
1592 UpdatePlayState();
[email protected]576537842009-08-12 23:52:051593}
1594
alokp967c902452016-05-06 05:21:371595void WebMediaPlayerImpl::OnMetadata(PipelineMetadata metadata) {
pkastingf5279482016-07-27 02:18:201596 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:431597 DCHECK(main_task_runner_->BelongsToCurrentThread());
Dale Curtisff576552018-03-30 02:32:441598
1599 // Cache the |time_to_metadata_| to use for adjusting the TimeToFirstFrame and
1600 // TimeToPlayReady metrics later if we end up doing a suspended startup.
1601 time_to_metadata_ = base::TimeTicks::Now() - load_start_time_;
1602 media_metrics_provider_->SetTimeToMetadata(time_to_metadata_);
1603 RecordTimingUMA("Media.TimeToMetadata", time_to_metadata_);
[email protected]a8e2cb82012-08-17 00:02:391604
[email protected]b8877772014-03-26 20:17:151605 pipeline_metadata_ = metadata;
[email protected]739847c02014-01-16 00:12:251606
Blink Reformat1c4d759e2017-04-09 16:34:541607 SetReadyState(WebMediaPlayer::kReadyStateHaveMetadata);
Julien Isorce6c83d8de2017-10-12 13:11:291608 UMA_HISTOGRAM_ENUMERATION("Media.VideoRotation",
1609 metadata.video_decoder_config.video_rotation(),
acolwell9e0840d2014-09-06 19:01:321610 VIDEO_ROTATION_MAX + 1);
[email protected]21c3f7502013-03-23 03:29:511611
John Rummelldb5a7ef2018-05-16 00:28:011612 if (HasAudio()) {
1613 RecordEncryptionScheme("Audio",
1614 metadata.audio_decoder_config.encryption_scheme());
1615 }
1616
Blink Reformat1c4d759e2017-04-09 16:34:541617 if (HasVideo()) {
John Rummelldb5a7ef2018-05-16 00:28:011618 RecordEncryptionScheme("Video",
1619 metadata.video_decoder_config.encryption_scheme());
1620
liberato2fd111be2017-01-04 00:25:061621 if (overlay_enabled_) {
1622 // SurfaceView doesn't support rotated video, so transition back if
[email protected]c8d574722017-08-30 20:53:431623 // the video is now rotated. If |always_enable_overlays_|, we keep the
liberato2fd111be2017-01-04 00:25:061624 // overlay anyway so that the state machine keeps working.
[email protected]c8d574722017-08-30 20:53:431625 // TODO(liberato): verify if compositor feedback catches this. If so,
1626 // then we don't need this check.
1627 if (!always_enable_overlays_ && !DoesOverlaySupportMetadata())
liberato2fd111be2017-01-04 00:25:061628 DisableOverlay();
1629 else if (surface_manager_)
1630 surface_manager_->NaturalSizeChanged(pipeline_metadata_.natural_size);
1631 }
watkf835a792016-06-24 23:24:401632
lethalantidote7f6009d2017-07-07 21:47:391633 if (!surface_layer_for_video_enabled_) {
danakj6e669e782018-05-16 16:57:171634 DCHECK(!video_layer_);
danakj25f030112018-05-11 18:26:541635 video_layer_ = cc::VideoLayer::Create(
Julien Isorce6c83d8de2017-10-12 13:11:291636 compositor_.get(),
danakj25f030112018-05-11 18:26:541637 pipeline_metadata_.video_decoder_config.video_rotation());
danakj8bc61c72018-05-16 13:55:061638 video_layer_->SetContentsOpaque(opaque_);
danakj8d204a42018-05-18 18:05:351639 client_->SetCcLayer(video_layer_.get());
CJ DiMeglio7b8b5b6e2018-02-07 01:58:421640 } else {
1641 vfc_task_runner_->PostTask(
1642 FROM_HERE,
1643 base::BindOnce(
1644 &VideoFrameCompositor::EnableSubmission,
1645 base::Unretained(compositor_.get()), bridge_->GetFrameSinkId(),
CJ DiMegliodf92bfe2018-05-11 20:11:001646 pipeline_metadata_.video_decoder_config.video_rotation(),
1647 BindToCurrentLoop(base::BindRepeating(
1648 &WebMediaPlayerImpl::OnFrameSinkDestroyed, AsWeakPtr()))));
lethalantidote7f6009d2017-07-07 21:47:391649 }
[email protected]a8e2cb82012-08-17 00:02:391650 }
dalecurtis8e4dc682016-03-15 02:30:301651
xjzd3fe45a2016-10-12 18:26:371652 if (observer_)
xjz15b483f2017-01-12 00:21:361653 observer_->OnMetadataChanged(pipeline_metadata_);
xjzd3fe45a2016-10-12 18:26:371654
Dale Curtisc7d2a7d22018-01-11 20:01:051655 // TODO(dalecurtis): Don't create these until kReadyStateHaveFutureData; when
1656 // we create them early we just increase the chances of needing to throw them
1657 // away unnecessarily.
dalecurtis04bdb582016-08-17 22:15:231658 CreateWatchTimeReporter();
Chris Cunninghamd9df58e2017-08-29 00:04:231659 CreateVideoDecodeStatsReporter();
Dale Curtisc7d2a7d22018-01-11 20:01:051660
sandersd50a635e2016-04-04 22:50:091661 UpdatePlayState();
[email protected]a8e2cb82012-08-17 00:02:391662}
1663
CJ DiMegliodf92bfe2018-05-11 20:11:001664void WebMediaPlayerImpl::OnFrameSinkDestroyed() {
1665 bridge_->ClearSurfaceId();
1666}
1667
Dale Curtis2dc6089a2018-03-26 16:47:581668void WebMediaPlayerImpl::OnBufferingStateChange(BufferingState state) {
1669 OnBufferingStateChangeInternal(state, false);
1670}
1671
Chris Cunninghamd9df58e2017-08-29 00:04:231672void WebMediaPlayerImpl::CreateVideoDecodeStatsReporter() {
1673 // TODO(chcunningham): destroy reporter if we initially have video but the
1674 // track gets disabled. Currently not possible in default desktop Chrome.
1675 if (!HasVideo())
1676 return;
1677
1678 // Stats reporter requires a valid config. We may not have one for HLS cases
1679 // where URL demuxer doesn't know details of the stream.
1680 if (!pipeline_metadata_.video_decoder_config.IsValidConfig())
1681 return;
1682
1683 // For now MediaCapabilities only handles clear content.
1684 // TODO(chcunningham): Report encrypted stats.
1685 if (is_encrypted_)
1686 return;
1687
Dale Curtis7e8a510d2017-12-14 19:19:481688 mojom::VideoDecodeStatsRecorderPtr recorder;
1689 media_metrics_provider_->AcquireVideoDecodeStatsRecorder(
Dale Curtis7e8a510d2017-12-14 19:19:481690 mojo::MakeRequest(&recorder));
Chris Cunninghamc7c6a6d2017-11-23 14:06:451691
Chris Cunninghamd9df58e2017-08-29 00:04:231692 // Create capabilities reporter and synchronize its initial state.
1693 video_decode_stats_reporter_.reset(new VideoDecodeStatsReporter(
Chris Cunninghamc7c6a6d2017-11-23 14:06:451694 std::move(recorder),
Chris Cunninghamd9df58e2017-08-29 00:04:231695 base::Bind(&WebMediaPlayerImpl::GetPipelineStatistics,
1696 base::Unretained(this)),
Hajime Hoshi6c3194b52017-12-15 03:02:111697 pipeline_metadata_.video_decoder_config,
Hajime Hoshib5a26ee2018-05-14 12:47:511698 frame_->GetTaskRunner(blink::TaskType::kInternalMedia)));
Chris Cunninghamd9df58e2017-08-29 00:04:231699
1700 if (delegate_->IsFrameHidden())
1701 video_decode_stats_reporter_->OnHidden();
1702 else
1703 video_decode_stats_reporter_->OnShown();
1704
1705 if (paused_)
1706 video_decode_stats_reporter_->OnPaused();
1707 else
1708 video_decode_stats_reporter_->OnPlaying();
1709}
1710
hubbeb2d3efd2017-05-05 23:26:381711void WebMediaPlayerImpl::OnProgress() {
Chris Watkins1ffabc5f2017-05-10 20:52:091712 DVLOG(4) << __func__;
hubbeb2d3efd2017-05-05 23:26:381713 if (highest_ready_state_ < ReadyState::kReadyStateHaveFutureData) {
1714 // Reset the preroll attempt clock.
1715 preroll_attempt_pending_ = true;
1716 preroll_attempt_start_time_ = base::TimeTicks();
1717
1718 // Clear any 'stale' flag and give the pipeline a chance to resume. If we
1719 // are already resumed, this will cause |preroll_attempt_start_time_| to
1720 // be set.
1721 delegate_->ClearStaleFlag(delegate_id_);
1722 UpdatePlayState();
1723 } else if (ready_state_ == ReadyState::kReadyStateHaveFutureData &&
1724 CanPlayThrough()) {
1725 SetReadyState(WebMediaPlayer::kReadyStateHaveEnoughData);
1726 }
1727}
1728
1729bool WebMediaPlayerImpl::CanPlayThrough() {
1730 if (!base::FeatureList::IsEnabled(kSpecCompliantCanPlayThrough))
1731 return true;
1732 if (chunk_demuxer_)
1733 return true;
1734 if (data_source_ && data_source_->assume_fully_buffered())
1735 return true;
1736 // If we're not currently downloading, we have as much buffer as
1737 // we're ever going to get, which means we say we can play through.
1738 if (network_state_ == WebMediaPlayer::kNetworkStateIdle)
1739 return true;
1740 return buffered_data_source_host_.CanPlayThrough(
1741 base::TimeDelta::FromSecondsD(CurrentTime()),
1742 base::TimeDelta::FromSecondsD(Duration()),
1743 playback_rate_ == 0.0 ? 1.0 : playback_rate_);
1744}
1745
Dale Curtisff576552018-03-30 02:32:441746void WebMediaPlayerImpl::OnBufferingStateChangeInternal(
1747 BufferingState state,
1748 bool for_suspended_start) {
pkastingf5279482016-07-27 02:18:201749 DVLOG(1) << __func__ << "(" << state << ")";
alokp967c902452016-05-06 05:21:371750 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]b8877772014-03-26 20:17:151751
sandersd1c0bba02016-03-04 23:14:081752 // Ignore buffering state changes until we've completed all outstanding
Dale Curtisff576552018-03-30 02:32:441753 // operations unless this is a buffering update for a suspended startup.
1754 if (!pipeline_controller_.IsStable() && !for_suspended_start)
[email protected]ba7d5f92014-06-24 05:37:401755 return;
[email protected]b8877772014-03-26 20:17:151756
Dale Curtisff576552018-03-30 02:32:441757 auto log_event = media_log_->CreateBufferingStateChangedEvent(
1758 "pipeline_buffering_state", state);
1759 log_event->params.SetBoolean("for_suspended_start", for_suspended_start);
1760 media_log_->AddEvent(std::move(log_event));
dalecurtis869bf2f2017-01-10 18:01:101761
chcunninghameb270c92016-07-15 01:00:451762 if (state == BUFFERING_HAVE_ENOUGH) {
John Chen5b164a02017-11-01 00:36:091763 TRACE_EVENT1("media", "WebMediaPlayerImpl::BufferingHaveEnough", "id",
1764 media_log_->id());
Dale Curtisff576552018-03-30 02:32:441765 // The SetReadyState() call below may clear
1766 // |skip_metrics_due_to_startup_suspend_| so report this first.
1767 if (!have_reported_time_to_play_ready_ &&
1768 !skip_metrics_due_to_startup_suspend_) {
1769 DCHECK(!for_suspended_start);
Dale Curtis3899090ea2018-01-12 00:10:351770 have_reported_time_to_play_ready_ = true;
1771 const base::TimeDelta elapsed = base::TimeTicks::Now() - load_start_time_;
1772 media_metrics_provider_->SetTimeToPlayReady(elapsed);
1773 RecordTimingUMA("Media.TimeToPlayReady", elapsed);
1774 }
[email protected]ba7d5f92014-06-24 05:37:401775
Dale Curtisff576552018-03-30 02:32:441776 // Warning: This call may be re-entrant.
1777 SetReadyState(CanPlayThrough() ? WebMediaPlayer::kReadyStateHaveEnoughData
1778 : WebMediaPlayer::kReadyStateHaveFutureData);
1779
chcunninghameb270c92016-07-15 01:00:451780 // Let the DataSource know we have enough data. It may use this information
1781 // to release unused network connections.
1782 if (data_source_)
1783 data_source_->OnBufferingHaveEnough(false);
dalecurtis849cf4b22015-03-27 18:35:451784
chcunninghameb270c92016-07-15 01:00:451785 // Blink expects a timeChanged() in response to a seek().
sandersd35d2c3f2017-01-14 02:04:421786 if (should_notify_time_changed_) {
1787 should_notify_time_changed_ = false;
Blink Reformat1c4d759e2017-04-09 16:34:541788 client_->TimeChanged();
sandersd35d2c3f2017-01-14 02:04:421789 }
dalecurtis0f0097a2015-12-01 17:40:471790
chcunninghameb270c92016-07-15 01:00:451791 // Once we have enough, start reporting the total memory usage. We'll also
1792 // report once playback starts.
1793 ReportMemoryUsage();
dalecurtis9d638a12016-08-30 06:20:551794
dalecurtis4f6d14d2017-02-22 17:42:221795 // Report the amount of time it took to leave the underflow state.
1796 if (underflow_timer_) {
1797 RecordUnderflowDuration(underflow_timer_->Elapsed());
dalecurtis9d638a12016-08-30 06:20:551798 underflow_timer_.reset();
1799 }
chcunninghameb270c92016-07-15 01:00:451800 } else {
1801 // Buffering has underflowed.
1802 DCHECK_EQ(state, BUFFERING_HAVE_NOTHING);
dalecurtisacd77d62016-09-09 23:23:141803
dalecurtisd06eabc2017-02-24 23:43:291804 // Report the number of times we've entered the underflow state. Ensure we
1805 // only report the value when transitioning from HAVE_ENOUGH to
1806 // HAVE_NOTHING.
Dale Curtis6995b862017-05-31 22:20:081807 if (ready_state_ == WebMediaPlayer::kReadyStateHaveEnoughData &&
1808 !seeking_) {
dalecurtisacd77d62016-09-09 23:23:141809 underflow_timer_.reset(new base::ElapsedTimer());
Dale Curtis6995b862017-05-31 22:20:081810 watch_time_reporter_->OnUnderflow();
1811 }
dalecurtisacd77d62016-09-09 23:23:141812
chcunninghameb270c92016-07-15 01:00:451813 // It shouldn't be possible to underflow if we've not advanced past
1814 // HAVE_CURRENT_DATA.
Blink Reformat1c4d759e2017-04-09 16:34:541815 DCHECK_GT(highest_ready_state_, WebMediaPlayer::kReadyStateHaveCurrentData);
1816 SetReadyState(WebMediaPlayer::kReadyStateHaveCurrentData);
chcunninghameb270c92016-07-15 01:00:451817 }
sandersd50a635e2016-04-04 22:50:091818
1819 UpdatePlayState();
[email protected]b8877772014-03-26 20:17:151820}
1821
alokp967c902452016-05-06 05:21:371822void WebMediaPlayerImpl::OnDurationChange() {
acolwellb4034942014-08-28 15:42:431823 DCHECK(main_task_runner_->BelongsToCurrentThread());
alokp967c902452016-05-06 05:21:371824
1825 // TODO(sandersd): We should call delegate_->DidPlay() with the new duration,
1826 // especially if it changed from <5s to >5s.
Blink Reformat1c4d759e2017-04-09 16:34:541827 if (ready_state_ == WebMediaPlayer::kReadyStateHaveNothing)
alokp967c902452016-05-06 05:21:371828 return;
1829
Blink Reformat1c4d759e2017-04-09 16:34:541830 client_->DurationChanged();
[email protected]81bb3322011-07-21 15:55:501831}
1832
alokp967c902452016-05-06 05:21:371833void WebMediaPlayerImpl::OnAddTextTrack(const TextTrackConfig& config,
1834 const AddTextTrackDoneCB& done_cb) {
acolwellb4034942014-08-28 15:42:431835 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]71537722013-05-23 06:47:531836
[email protected]8a561062013-11-22 01:19:311837 const WebInbandTextTrackImpl::Kind web_kind =
1838 static_cast<WebInbandTextTrackImpl::Kind>(config.kind());
Blink Reformat1c4d759e2017-04-09 16:34:541839 const blink::WebString web_label = blink::WebString::FromUTF8(config.label());
[email protected]8a561062013-11-22 01:19:311840 const blink::WebString web_language =
Blink Reformat1c4d759e2017-04-09 16:34:541841 blink::WebString::FromUTF8(config.language());
1842 const blink::WebString web_id = blink::WebString::FromUTF8(config.id());
[email protected]71537722013-05-23 06:47:531843
dcheng3076abbf2016-04-22 20:42:391844 std::unique_ptr<WebInbandTextTrackImpl> web_inband_text_track(
henriks9cce5fa2014-12-12 09:35:301845 new WebInbandTextTrackImpl(web_kind, web_label, web_language, web_id));
[email protected]8a561062013-11-22 01:19:311846
dcheng3076abbf2016-04-22 20:42:391847 std::unique_ptr<media::TextTrack> text_track(new TextTrackImpl(
dcheng652f5ff2015-12-27 08:54:001848 main_task_runner_, client_, std::move(web_inband_text_track)));
[email protected]8a561062013-11-22 01:19:311849
dcheng652f5ff2015-12-27 08:54:001850 done_cb.Run(std::move(text_track));
[email protected]71537722013-05-23 06:47:531851}
1852
alokp967c902452016-05-06 05:21:371853void WebMediaPlayerImpl::OnWaitingForDecryptionKey() {
1854 DCHECK(main_task_runner_->BelongsToCurrentThread());
1855
Blink Reformat1c4d759e2017-04-09 16:34:541856 encrypted_client_->DidBlockPlaybackWaitingForKey();
alokp967c902452016-05-06 05:21:371857 // TODO(jrummell): didResumePlaybackBlockedForKey() should only be called
1858 // when a key has been successfully added (e.g. OnSessionKeysChange() with
1859 // |has_additional_usable_key| = true). http://crbug.com/461903
Blink Reformat1c4d759e2017-04-09 16:34:541860 encrypted_client_->DidResumePlaybackBlockedForKey();
alokp967c902452016-05-06 05:21:371861}
1862
alokp5d86e9b2016-05-17 20:20:411863void WebMediaPlayerImpl::OnVideoNaturalSizeChange(const gfx::Size& size) {
1864 DCHECK(main_task_runner_->BelongsToCurrentThread());
Blink Reformat1c4d759e2017-04-09 16:34:541865 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
alokp5d86e9b2016-05-17 20:20:411866
Chris Cunningham038548b2017-07-10 22:36:301867 TRACE_EVENT0("media", "WebMediaPlayerImpl::OnVideoNaturalSizeChange");
xhwang60802652017-04-19 07:29:581868
xjz15b483f2017-01-12 00:21:361869 // The input |size| is from the decoded video frame, which is the original
1870 // natural size and need to be rotated accordingly.
Julien Isorce6c83d8de2017-10-12 13:11:291871 gfx::Size rotated_size = GetRotatedVideoSize(
1872 pipeline_metadata_.video_decoder_config.video_rotation(), size);
sandersd2c478422016-08-02 01:19:251873
xhwang60802652017-04-19 07:29:581874 RecordVideoNaturalSize(rotated_size);
1875
1876 gfx::Size old_size = pipeline_metadata_.natural_size;
1877 if (rotated_size == old_size)
alokp5d86e9b2016-05-17 20:20:411878 return;
1879
xjz516ef6d2017-01-07 00:23:061880 pipeline_metadata_.natural_size = rotated_size;
Dale Curtisccfd0cca2017-08-31 01:27:561881 CreateWatchTimeReporter();
dalecurtis25405562017-04-14 23:35:111882
Chris Cunninghamd9df58e2017-08-29 00:04:231883 if (video_decode_stats_reporter_)
1884 video_decode_stats_reporter_->OnNaturalSizeChanged(rotated_size);
1885
liberato2ff93ad2017-05-17 07:28:241886 if (overlay_enabled_ && surface_manager_ &&
1887 overlay_mode_ == OverlayMode::kUseContentVideoView) {
xhwang60802652017-04-19 07:29:581888 surface_manager_->NaturalSizeChanged(rotated_size);
liberato2ff93ad2017-05-17 07:28:241889 }
xhwang60802652017-04-19 07:29:581890
Blink Reformat1c4d759e2017-04-09 16:34:541891 client_->SizeChanged();
xjz516ef6d2017-01-07 00:23:061892
xjz15b483f2017-01-12 00:21:361893 if (observer_)
1894 observer_->OnMetadataChanged(pipeline_metadata_);
peconn257951522017-06-09 18:24:591895
1896 delegate_->DidPlayerSizeChange(delegate_id_, NaturalSize());
alokp5d86e9b2016-05-17 20:20:411897}
1898
1899void WebMediaPlayerImpl::OnVideoOpacityChange(bool opaque) {
1900 DCHECK(main_task_runner_->BelongsToCurrentThread());
Blink Reformat1c4d759e2017-04-09 16:34:541901 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
alokp5d86e9b2016-05-17 20:20:411902
1903 opaque_ = opaque;
lethalantidote7f6009d2017-07-07 21:47:391904 if (!surface_layer_for_video_enabled_) {
danakj8bc61c72018-05-16 13:55:061905 if (video_layer_)
1906 video_layer_->SetContentsOpaque(opaque_);
danakj8d204a42018-05-18 18:05:351907 } else if (bridge_->GetCcLayer()) {
1908 bridge_->GetCcLayer()->SetContentsOpaque(opaque_);
lethalantidote7f6009d2017-07-07 21:47:391909 }
alokp5d86e9b2016-05-17 20:20:411910}
1911
Chris Cunningham038548b2017-07-10 22:36:301912void WebMediaPlayerImpl::OnAudioConfigChange(const AudioDecoderConfig& config) {
1913 DCHECK(main_task_runner_->BelongsToCurrentThread());
1914 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
1915
Dale Curtisccfd0cca2017-08-31 01:27:561916 const bool codec_change =
1917 pipeline_metadata_.audio_decoder_config.codec() != config.codec();
Chris Cunningham038548b2017-07-10 22:36:301918 pipeline_metadata_.audio_decoder_config = config;
1919
1920 if (observer_)
1921 observer_->OnMetadataChanged(pipeline_metadata_);
Dale Curtisccfd0cca2017-08-31 01:27:561922
1923 if (codec_change)
1924 CreateWatchTimeReporter();
Chris Cunningham038548b2017-07-10 22:36:301925}
1926
1927void WebMediaPlayerImpl::OnVideoConfigChange(const VideoDecoderConfig& config) {
1928 DCHECK(main_task_runner_->BelongsToCurrentThread());
1929 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
1930
Dale Curtisccfd0cca2017-08-31 01:27:561931 const bool codec_change =
1932 pipeline_metadata_.video_decoder_config.codec() != config.codec();
1933
Chris Cunningham038548b2017-07-10 22:36:301934 // TODO(chcunningham): Observe changes to video codec profile to signal
1935 // beginning of a new Media Capabilities playback report.
1936 pipeline_metadata_.video_decoder_config = config;
1937
1938 if (observer_)
1939 observer_->OnMetadataChanged(pipeline_metadata_);
Chris Cunninghamd9df58e2017-08-29 00:04:231940
1941 if (video_decode_stats_reporter_)
1942 video_decode_stats_reporter_->OnVideoConfigChanged(config);
Dale Curtisccfd0cca2017-08-31 01:27:561943
1944 if (codec_change)
1945 CreateWatchTimeReporter();
Chris Cunningham038548b2017-07-10 22:36:301946}
1947
avayvodeecec52c2017-02-14 01:25:091948void WebMediaPlayerImpl::OnVideoAverageKeyframeDistanceUpdate() {
1949 UpdateBackgroundVideoOptimizationState();
1950}
1951
Dale Curtisc7d2a7d22018-01-11 20:01:051952void WebMediaPlayerImpl::OnAudioDecoderChange(const std::string& name) {
1953 if (name == audio_decoder_name_)
1954 return;
1955
1956 const bool is_decoder_change = !audio_decoder_name_.empty();
1957 audio_decoder_name_ = name;
1958
1959 // If there's no current reporter, there's nothing to be done.
1960 if (!watch_time_reporter_)
1961 return;
1962
1963 if (is_decoder_change)
1964 CreateWatchTimeReporter();
1965 else
1966 watch_time_reporter_->SetAudioDecoderName(name);
1967}
1968
1969void WebMediaPlayerImpl::OnVideoDecoderChange(const std::string& name) {
1970 if (name == video_decoder_name_)
1971 return;
1972
1973 const bool is_decoder_change = !video_decoder_name_.empty();
1974 video_decoder_name_ = name;
1975
1976 // If there's no current reporter, there's nothing to be done.
1977 if (!watch_time_reporter_)
1978 return;
1979
1980 if (is_decoder_change)
1981 CreateWatchTimeReporter();
1982 else
1983 watch_time_reporter_->SetVideoDecoderName(name);
1984}
1985
sandersd35d2c3f2017-01-14 02:04:421986void WebMediaPlayerImpl::OnFrameHidden() {
sandersd1e49fb62015-12-12 01:18:061987 DCHECK(main_task_runner_->BelongsToCurrentThread());
avayvod39c102402016-11-23 21:43:131988
avayvod65fad272017-02-24 01:00:481989 // Backgrounding a video requires a user gesture to resume playback.
1990 if (IsHidden())
1991 video_locked_when_paused_when_hidden_ = true;
1992
dalecurtis04bdb582016-08-17 22:15:231993 if (watch_time_reporter_)
1994 watch_time_reporter_->OnHidden();
avayvod48a8be52016-08-04 19:52:501995
Chris Cunninghamd9df58e2017-08-29 00:04:231996 if (video_decode_stats_reporter_)
1997 video_decode_stats_reporter_->OnHidden();
1998
avayvod65fad272017-02-24 01:00:481999 UpdateBackgroundVideoOptimizationState();
sandersd50a635e2016-04-04 22:50:092000 UpdatePlayState();
dalecurtis8b8505e72016-06-10 21:59:172001
2002 // Schedule suspended playing media to be paused if the user doesn't come back
2003 // to it within some timeout period to avoid any autoplay surprises.
2004 ScheduleIdlePauseTimer();
sandersd1e49fb62015-12-12 01:18:062005}
2006
sandersd35d2c3f2017-01-14 02:04:422007void WebMediaPlayerImpl::OnFrameClosed() {
sandersd1e49fb62015-12-12 01:18:062008 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]28347e72017-06-27 17:30:112009
sandersd35d2c3f2017-01-14 02:04:422010 UpdatePlayState();
2011}
2012
2013void WebMediaPlayerImpl::OnFrameShown() {
2014 DCHECK(main_task_runner_->BelongsToCurrentThread());
2015 background_pause_timer_.Stop();
2016
avayvod65fad272017-02-24 01:00:482017 // Foreground videos don't require user gesture to continue playback.
2018 video_locked_when_paused_when_hidden_ = false;
2019
dalecurtis04bdb582016-08-17 22:15:232020 if (watch_time_reporter_)
2021 watch_time_reporter_->OnShown();
2022
Chris Cunninghamd9df58e2017-08-29 00:04:232023 if (video_decode_stats_reporter_)
2024 video_decode_stats_reporter_->OnShown();
2025
avayvodcc273dd2017-01-19 19:35:122026 // Only track the time to the first frame if playing or about to play because
2027 // of being shown and only for videos we would optimize background playback
2028 // for.
2029 if ((!paused_ && IsBackgroundOptimizationCandidate()) ||
2030 paused_when_hidden_) {
Dale Curtis3899090ea2018-01-12 00:10:352031 frame_time_report_cb_.Reset(base::BindOnce(
2032 &WebMediaPlayerImpl::ReportTimeFromForegroundToFirstFrame, AsWeakPtr(),
2033 base::TimeTicks::Now()));
CJ DiMeglio2302d202017-08-31 08:38:042034 vfc_task_runner_->PostTask(
avayvodcc273dd2017-01-19 19:35:122035 FROM_HERE,
Dale Curtis3899090ea2018-01-12 00:10:352036 base::BindOnce(&VideoFrameCompositor::SetOnNewProcessedFrameCallback,
2037 base::Unretained(compositor_.get()),
2038 BindToCurrentLoop(frame_time_report_cb_.callback())));
avayvodcc273dd2017-01-19 19:35:122039 }
avayvodac607d652017-01-06 03:16:432040
Dale Curtisdcbb81a2017-08-18 01:06:122041 UpdateBackgroundVideoOptimizationState();
avayvod65fad272017-02-24 01:00:482042
avayvod2135a642017-01-13 00:17:142043 if (paused_when_hidden_) {
2044 paused_when_hidden_ = false;
2045 OnPlay(); // Calls UpdatePlayState() so return afterwards.
2046 return;
2047 }
2048
sandersd50a635e2016-04-04 22:50:092049 UpdatePlayState();
sandersd1e49fb62015-12-12 01:18:062050}
2051
sandersd35d2c3f2017-01-14 02:04:422052void WebMediaPlayerImpl::OnIdleTimeout() {
dalecurtis0431cbf2016-03-12 01:19:432053 DCHECK(main_task_runner_->BelongsToCurrentThread());
2054
Dale Curtis99a9b482018-02-01 02:23:282055 // This should never be called when stale state testing overrides are used.
2056 DCHECK(!stale_state_override_for_testing_.has_value());
2057
sandersd35d2c3f2017-01-14 02:04:422058 // If we are attempting preroll, clear the stale flag.
2059 if (IsPrerollAttemptNeeded()) {
tguilbert1bb1c782017-01-23 21:15:112060 delegate_->ClearStaleFlag(delegate_id_);
sandersd35d2c3f2017-01-14 02:04:422061 return;
watkd026f792016-11-05 00:28:512062 }
sandersd50a635e2016-04-04 22:50:092063
sandersd35d2c3f2017-01-14 02:04:422064 UpdatePlayState();
dalecurtis0431cbf2016-03-12 01:19:432065}
2066
dalecurtisbb3eaac2016-01-27 21:10:252067void WebMediaPlayerImpl::OnPlay() {
Blink Reformat1c4d759e2017-04-09 16:34:542068 Play();
2069 client_->PlaybackStateChanged();
dalecurtisbb3eaac2016-01-27 21:10:252070}
2071
2072void WebMediaPlayerImpl::OnPause() {
Blink Reformat1c4d759e2017-04-09 16:34:542073 Pause();
2074 client_->PlaybackStateChanged();
dalecurtisbb3eaac2016-01-27 21:10:252075}
2076
Alec Douglas316cce42017-10-31 13:28:082077void WebMediaPlayerImpl::OnSeekForward(double seconds) {
2078 DCHECK_GE(seconds, 0) << "Attempted to seek by a negative number of seconds";
2079 client_->RequestSeek(CurrentTime() + seconds);
2080}
2081
2082void WebMediaPlayerImpl::OnSeekBackward(double seconds) {
2083 DCHECK_GE(seconds, 0) << "Attempted to seek by a negative number of seconds";
2084 client_->RequestSeek(CurrentTime() - seconds);
2085}
2086
dalecurtisbb3eaac2016-01-27 21:10:252087void WebMediaPlayerImpl::OnVolumeMultiplierUpdate(double multiplier) {
2088 volume_multiplier_ = multiplier;
Blink Reformat1c4d759e2017-04-09 16:34:542089 SetVolume(volume_);
dalecurtisbb3eaac2016-01-27 21:10:252090}
2091
zqzhang8ac49002017-03-16 21:51:352092void WebMediaPlayerImpl::OnBecamePersistentVideo(bool value) {
Blink Reformat1c4d759e2017-04-09 16:34:542093 client_->OnBecamePersistentVideo(value);
zqzhang8ac49002017-03-16 21:51:352094}
2095
Jennifer Apacible009f29842018-04-16 23:07:372096void WebMediaPlayerImpl::OnPictureInPictureModeEnded() {
Jennifer Apacible5cd9a7e2018-04-17 03:08:062097 // This should never be called if |pip_surface_id_| is invalid. This is either
2098 // called from the Picture-in-Picture window side by a user gesture to end
2099 // Picture-in-Picture mode, or in ExitPictureInPicture(), which already checks
2100 // for validity.
2101 DCHECK(pip_surface_id_.is_valid());
2102
Jennifer Apacible5cd9a7e2018-04-17 03:08:062103 if (client_)
2104 client_->PictureInPictureStopped();
Jennifer Apacible009f29842018-04-16 23:07:372105}
2106
watkdee516f2016-02-18 02:22:192107void WebMediaPlayerImpl::ScheduleRestart() {
sandersd50a635e2016-04-04 22:50:092108 // TODO(watk): All restart logic should be moved into PipelineController.
tguilbert350936ff2017-02-24 05:39:272109 if (pipeline_controller_.IsPipelineRunning() &&
2110 !pipeline_controller_.IsPipelineSuspended()) {
watkdee516f2016-02-18 02:22:192111 pending_suspend_resume_cycle_ = true;
sandersd50a635e2016-04-04 22:50:092112 UpdatePlayState();
watkdee516f2016-02-18 02:22:192113 }
2114}
2115
Blink Reformat1c4d759e2017-04-09 16:34:542116void WebMediaPlayerImpl::RequestRemotePlaybackDisabled(bool disabled) {
miu77f914c2016-11-19 23:56:182117 if (observer_)
2118 observer_->OnRemotePlaybackDisabled(disabled);
2119}
2120
hubbed5f36882016-01-15 22:40:372121#if defined(OS_ANDROID) // WMPI_CAST
Blink Reformat1c4d759e2017-04-09 16:34:542122bool WebMediaPlayerImpl::IsRemote() const {
hubbed5f36882016-01-15 22:40:372123 return cast_impl_.isRemote();
2124}
2125
2126void WebMediaPlayerImpl::SetMediaPlayerManager(
2127 RendererMediaPlayerManagerInterface* media_player_manager) {
2128 cast_impl_.SetMediaPlayerManager(media_player_manager);
2129}
2130
Blink Reformat1c4d759e2017-04-09 16:34:542131void WebMediaPlayerImpl::RequestRemotePlayback() {
hubbed5f36882016-01-15 22:40:372132 cast_impl_.requestRemotePlayback();
2133}
2134
Blink Reformat1c4d759e2017-04-09 16:34:542135void WebMediaPlayerImpl::RequestRemotePlaybackControl() {
hubbed5f36882016-01-15 22:40:372136 cast_impl_.requestRemotePlaybackControl();
2137}
2138
Blink Reformat1c4d759e2017-04-09 16:34:542139void WebMediaPlayerImpl::RequestRemotePlaybackStop() {
avayvod8d8c53b2016-11-04 16:10:302140 cast_impl_.requestRemotePlaybackStop();
2141}
2142
hubbed5f36882016-01-15 22:40:372143void WebMediaPlayerImpl::OnRemotePlaybackEnded() {
pkastingf5279482016-07-27 02:18:202144 DVLOG(1) << __func__;
hubbed5f36882016-01-15 22:40:372145 DCHECK(main_task_runner_->BelongsToCurrentThread());
2146
2147 ended_ = true;
Blink Reformat1c4d759e2017-04-09 16:34:542148 client_->TimeChanged();
hubbed5f36882016-01-15 22:40:372149}
2150
Thomas Guilbertb341bae02018-05-09 00:02:132151void WebMediaPlayerImpl::FlingingStarted() {
2152 DCHECK(main_task_runner_->BelongsToCurrentThread());
2153 DCHECK(!disable_pipeline_auto_suspend_);
2154 disable_pipeline_auto_suspend_ = true;
2155
2156 // Capabilities reporting should only be performed for local playbacks.
2157 video_decode_stats_reporter_.reset();
2158
2159 // Requests to restart media pipeline. A flinging renderer will be created via
2160 // the |renderer_factory_selector_|.
2161 ScheduleRestart();
2162}
2163
2164void WebMediaPlayerImpl::FlingingStopped() {
2165 DCHECK(main_task_runner_->BelongsToCurrentThread());
2166 DCHECK(disable_pipeline_auto_suspend_);
2167 disable_pipeline_auto_suspend_ = false;
2168
2169 CreateVideoDecodeStatsReporter();
2170
2171 ScheduleRestart();
2172}
2173
hubbed5f36882016-01-15 22:40:372174void WebMediaPlayerImpl::OnDisconnectedFromRemoteDevice(double t) {
sandersd1c0bba02016-03-04 23:14:082175 DoSeek(base::TimeDelta::FromSecondsD(t), false);
hubbed5f36882016-01-15 22:40:372176
Chris Cunninghamd9df58e2017-08-29 00:04:232177 // Capabilities reporting can resume now that playback is local.
2178 CreateVideoDecodeStatsReporter();
2179
Anton Vayvodfad2f3ea2017-07-19 21:45:272180 // |client_| might destroy us in methods below.
2181 UpdatePlayState();
2182
hubbed5f36882016-01-15 22:40:372183 // We already told the delegate we're paused when remoting started.
Blink Reformat1c4d759e2017-04-09 16:34:542184 client_->PlaybackStateChanged();
2185 client_->DisconnectedFromRemoteDevice();
hubbed5f36882016-01-15 22:40:372186}
2187
2188void WebMediaPlayerImpl::SuspendForRemote() {
Chris Cunninghamd9df58e2017-08-29 00:04:232189 // Capabilities reporting should only be performed for local playbacks.
2190 video_decode_stats_reporter_.reset();
2191
avayvod82729272017-05-29 21:58:392192 if (pipeline_controller_.IsPipelineSuspended() &&
2193 !IsNewRemotePlaybackPipelineEnabled()) {
hubbed5f36882016-01-15 22:40:372194 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner();
sandersd50a635e2016-04-04 22:50:092195 if (frame)
dalecurtise9c89e92016-05-20 19:38:002196 compositor_->PaintSingleFrame(frame);
hubbed5f36882016-01-15 22:40:372197 }
sandersd50a635e2016-04-04 22:50:092198
2199 UpdatePlayState();
hubbed5f36882016-01-15 22:40:372200}
2201
2202gfx::Size WebMediaPlayerImpl::GetCanvasSize() const {
lethalantidote7f6009d2017-07-07 21:47:392203 if (!surface_layer_for_video_enabled_) {
danakj6e669e782018-05-16 16:57:172204 if (!video_layer_)
lethalantidote7f6009d2017-07-07 21:47:392205 return pipeline_metadata_.natural_size;
2206
danakj6e669e782018-05-16 16:57:172207 return video_layer_->bounds();
lethalantidote7f6009d2017-07-07 21:47:392208 }
danakj8d204a42018-05-18 18:05:352209 if (!bridge_->GetCcLayer())
hubbed5f36882016-01-15 22:40:372210 return pipeline_metadata_.natural_size;
2211
danakj8d204a42018-05-18 18:05:352212 return bridge_->GetCcLayer()->bounds();
hubbed5f36882016-01-15 22:40:372213}
2214
2215void WebMediaPlayerImpl::SetDeviceScaleFactor(float scale_factor) {
2216 cast_impl_.SetDeviceScaleFactor(scale_factor);
2217}
Dan Sanderscd8981c2017-08-31 22:37:022218#endif // defined(OS_ANDROID) // WMPI_CAST
hubbee4027f92016-05-19 05:18:132219
Blink Reformat1c4d759e2017-04-09 16:34:542220void WebMediaPlayerImpl::SetPoster(const blink::WebURL& poster) {
Dan Sanderscd8981c2017-08-31 22:37:022221 has_poster_ = !poster.IsEmpty();
2222#if defined(OS_ANDROID) // WMPI_CAST
xjzc102fd82017-01-04 20:13:532223 cast_impl_.setPoster(poster);
xjz2504c4da2017-04-18 18:50:142224#endif // defined(OS_ANDROID) // WMPI_CAST
Dan Sanderscd8981c2017-08-31 22:37:022225}
xjzc102fd82017-01-04 20:13:532226
[email protected]fee8a902014-06-03 13:43:362227void WebMediaPlayerImpl::DataSourceInitialized(bool success) {
pkastingf5279482016-07-27 02:18:202228 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:432229 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]a9415292012-01-19 19:55:202230
Anton Vayvod09fa66e2017-07-20 23:02:122231 if (observer_ && IsNewRemotePlaybackPipelineEnabled() && data_source_)
2232 observer_->OnDataSourceInitialized(data_source_->GetUrlAfterRedirects());
2233
[email protected]d250190da3b2012-07-23 22:57:302234 if (!success) {
Blink Reformat1c4d759e2017-04-09 16:34:542235 SetNetworkState(WebMediaPlayer::kNetworkStateFormatError);
Dale Curtis74612b72017-12-14 20:56:192236 media_metrics_provider_->OnError(PIPELINE_ERROR_NETWORK);
sandersd50a635e2016-04-04 22:50:092237
2238 // Not really necessary, since the pipeline was never started, but it at
2239 // least this makes sure that the error handling code is in sync.
2240 UpdatePlayState();
2241
[email protected]a9415292012-01-19 19:55:202242 return;
2243 }
2244
hubbee2cc88c092017-07-14 23:10:412245 // No point in preloading data as we'll probably just throw it away anyways.
2246 if (IsStreaming() && preload_ > MultibufferDataSource::METADATA) {
2247 data_source_->SetPreload(MultibufferDataSource::METADATA);
2248 }
2249
[email protected]ef8394c2013-08-21 20:26:302250 StartPipeline();
[email protected]a9415292012-01-19 19:55:202251}
2252
[email protected]122f40252012-06-12 05:01:562253void WebMediaPlayerImpl::NotifyDownloading(bool is_downloading) {
hubbeb2d3efd2017-05-05 23:26:382254 DVLOG(1) << __func__ << "(" << is_downloading << ")";
Blink Reformat1c4d759e2017-04-09 16:34:542255 if (!is_downloading && network_state_ == WebMediaPlayer::kNetworkStateLoading)
2256 SetNetworkState(WebMediaPlayer::kNetworkStateIdle);
2257 else if (is_downloading &&
2258 network_state_ == WebMediaPlayer::kNetworkStateIdle)
2259 SetNetworkState(WebMediaPlayer::kNetworkStateLoading);
hubbeb2d3efd2017-05-05 23:26:382260 if (ready_state_ == ReadyState::kReadyStateHaveFutureData && !is_downloading)
2261 SetReadyState(WebMediaPlayer::kReadyStateHaveEnoughData);
[email protected]122f40252012-06-12 05:01:562262}
2263
watkf835a792016-06-24 23:24:402264void WebMediaPlayerImpl::OnSurfaceCreated(int surface_id) {
liberato2ff93ad2017-05-17 07:28:242265 DCHECK(overlay_mode_ == OverlayMode::kUseContentVideoView);
tsunghungee562e92016-07-20 18:03:312266 overlay_surface_id_ = surface_id;
liberato2ff93ad2017-05-17 07:28:242267 MaybeSendOverlayInfoToDecoder();
watkf835a792016-06-24 23:24:402268}
2269
liberato2ff93ad2017-05-17 07:28:242270void WebMediaPlayerImpl::OnOverlayRoutingToken(
2271 const base::UnguessableToken& token) {
2272 DCHECK(overlay_mode_ == OverlayMode::kUseAndroidOverlay);
liberatofe8f9692017-06-08 19:17:362273 // TODO(liberato): |token| should already be a RoutingToken.
2274 overlay_routing_token_is_pending_ = false;
2275 overlay_routing_token_ = OverlayInfo::RoutingToken(token);
liberato2ff93ad2017-05-17 07:28:242276 MaybeSendOverlayInfoToDecoder();
2277}
2278
2279void WebMediaPlayerImpl::OnOverlayInfoRequested(
dalecurtis4b632fce22016-11-10 00:52:172280 bool decoder_requires_restart_for_overlay,
liberato2ff93ad2017-05-17 07:28:242281 const ProvideOverlayInfoCB& provide_overlay_info_cb) {
watkdee516f2016-02-18 02:22:192282 DCHECK(main_task_runner_->BelongsToCurrentThread());
2283 DCHECK(surface_manager_);
2284
Chris Watkins557f84d2017-09-16 02:31:462285 // If we get a non-null cb, a decoder is initializing and requires overlay
2286 // info. If we get a null cb, a previously initialized decoder is
2287 // unregistering for overlay info updates.
liberato2ff93ad2017-05-17 07:28:242288 if (provide_overlay_info_cb.is_null()) {
tsunghungee562e92016-07-20 18:03:312289 decoder_requires_restart_for_overlay_ = false;
liberato2ff93ad2017-05-17 07:28:242290 provide_overlay_info_cb_.Reset();
watkdee516f2016-02-18 02:22:192291 return;
2292 }
2293
dalecurtis4b632fce22016-11-10 00:52:172294 // If |decoder_requires_restart_for_overlay| is true, we must restart the
2295 // pipeline for fullscreen transitions. The decoder is unable to switch
2296 // surfaces otherwise. If false, we simply need to tell the decoder about the
2297 // new surface and it will handle things seamlessly.
Chris Watkins557f84d2017-09-16 02:31:462298 // For encrypted video we pretend that the decoder doesn't require a restart
2299 // because it needs an overlay all the time anyway. We'll switch into
2300 // |always_enable_overlays_| mode below.
2301 decoder_requires_restart_for_overlay_ =
2302 (overlay_mode_ == OverlayMode::kUseAndroidOverlay && is_encrypted_)
2303 ? false
2304 : decoder_requires_restart_for_overlay;
liberato2ff93ad2017-05-17 07:28:242305 provide_overlay_info_cb_ = provide_overlay_info_cb;
dalecurtis4b632fce22016-11-10 00:52:172306
Chris Watkins557f84d2017-09-16 02:31:462307 // If the decoder doesn't require restarts for surface transitions, and we're
2308 // using AndroidOverlay mode, we can always enable the overlay and the decoder
2309 // can choose whether or not to use it. Otherwise, we'll restart the decoder
2310 // and enable the overlay on fullscreen transitions.
[email protected]77568482017-06-21 21:16:522311 if (overlay_mode_ == OverlayMode::kUseAndroidOverlay &&
Chris Watkins557f84d2017-09-16 02:31:462312 !decoder_requires_restart_for_overlay_) {
[email protected]c8d574722017-08-30 20:53:432313 always_enable_overlays_ = true;
[email protected]77568482017-06-21 21:16:522314 if (!overlay_enabled_)
2315 EnableOverlay();
2316 }
2317
Chris Watkins557f84d2017-09-16 02:31:462318 // Send the overlay info if we already have it. If not, it will be sent later.
liberato2ff93ad2017-05-17 07:28:242319 MaybeSendOverlayInfoToDecoder();
2320}
2321
2322void WebMediaPlayerImpl::MaybeSendOverlayInfoToDecoder() {
2323 // If the decoder didn't request overlay info, then don't send it.
2324 if (!provide_overlay_info_cb_)
dalecurtis4b632fce22016-11-10 00:52:172325 return;
2326
liberato2ff93ad2017-05-17 07:28:242327 // We should send the overlay info as long as we know it. This includes the
2328 // case where |!overlay_enabled_|, since we want to tell the decoder to avoid
2329 // using overlays. Assuming that the decoder has requested info, the only
2330 // case in which we don't want to send something is if we've requested the
2331 // info but not received it yet. Then, we should wait until we do.
liberatofe8f9692017-06-08 19:17:362332 //
2333 // Initialization requires this; AVDA should start with enough info to make an
2334 // overlay, so that (pre-M) the initial codec is created with the right output
2335 // surface; it can't switch later.
liberato2ff93ad2017-05-17 07:28:242336 if (overlay_mode_ == OverlayMode::kUseContentVideoView) {
2337 if (!overlay_surface_id_.has_value())
2338 return;
liberatofe8f9692017-06-08 19:17:362339
2340 overlay_info_.surface_id = *overlay_surface_id_;
liberato2ff93ad2017-05-17 07:28:242341 } else if (overlay_mode_ == OverlayMode::kUseAndroidOverlay) {
liberatofe8f9692017-06-08 19:17:362342 if (overlay_routing_token_is_pending_)
liberato2ff93ad2017-05-17 07:28:242343 return;
liberatofe8f9692017-06-08 19:17:362344
2345 overlay_info_.routing_token = overlay_routing_token_;
liberato2ff93ad2017-05-17 07:28:242346 }
2347
liberato2ff93ad2017-05-17 07:28:242348 // If restart is required, the callback is one-shot only.
2349 if (decoder_requires_restart_for_overlay_) {
liberatofe8f9692017-06-08 19:17:362350 base::ResetAndReturn(&provide_overlay_info_cb_).Run(overlay_info_);
liberato2ff93ad2017-05-17 07:28:242351 } else {
liberatofe8f9692017-06-08 19:17:362352 provide_overlay_info_cb_.Run(overlay_info_);
liberato2ff93ad2017-05-17 07:28:242353 }
watkdee516f2016-02-18 02:22:192354}
2355
dcheng3076abbf2016-04-22 20:42:392356std::unique_ptr<Renderer> WebMediaPlayerImpl::CreateRenderer() {
dcheng37b415b92017-01-27 20:17:432357 DCHECK(main_task_runner_->BelongsToCurrentThread());
2358
[email protected]c8d574722017-08-30 20:53:432359 // Make sure that overlays are enabled if they're always allowed.
2360 if (always_enable_overlays_)
tsunghungee562e92016-07-20 18:03:312361 EnableOverlay();
2362
liberato2ff93ad2017-05-17 07:28:242363 RequestOverlayInfoCB request_overlay_info_cb;
watkdee516f2016-02-18 02:22:192364#if defined(OS_ANDROID)
liberato2ff93ad2017-05-17 07:28:242365 request_overlay_info_cb = BindToCurrentLoop(
2366 base::Bind(&WebMediaPlayerImpl::OnOverlayInfoRequested, AsWeakPtr()));
watkdee516f2016-02-18 02:22:192367#endif
tguilbert70d2a00a2017-04-25 00:30:442368 return renderer_factory_selector_->GetCurrentFactory()->CreateRenderer(
sandersd1e49fb62015-12-12 01:18:062369 media_task_runner_, worker_task_runner_, audio_source_provider_.get(),
CJ DiMeglio2302d202017-08-31 08:38:042370 compositor_.get(), request_overlay_info_cb, client_->TargetColorSpace());
sandersd1e49fb62015-12-12 01:18:062371}
2372
[email protected]ef8394c2013-08-21 20:26:302373void WebMediaPlayerImpl::StartPipeline() {
acolwellb4034942014-08-28 15:42:432374 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]ddbc6ff2013-04-19 15:28:332375
xhwange8c4181a2014-12-06 08:10:012376 Demuxer::EncryptedMediaInitDataCB encrypted_media_init_data_cb =
dcheng37b415b92017-01-27 20:17:432377 BindToCurrentLoop(base::Bind(
2378 &WebMediaPlayerImpl::OnEncryptedMediaInitData, AsWeakPtr()));
[email protected]2b57e2e2014-05-09 11:07:252379
Dale Curtis3899090ea2018-01-12 00:10:352380 vfc_task_runner_->PostTask(
2381 FROM_HERE,
2382 base::BindOnce(&VideoFrameCompositor::SetOnNewProcessedFrameCallback,
2383 base::Unretained(compositor_.get()),
2384 BindToCurrentLoop(base::BindOnce(
2385 &WebMediaPlayerImpl::OnFirstFrame, AsWeakPtr()))));
2386
tguilbert75e2bf62017-04-26 20:13:122387 if (renderer_factory_selector_->GetCurrentFactory()
2388 ->GetRequiredMediaResourceType() == MediaResource::Type::URL) {
2389 if (data_source_)
2390 loaded_url_ = data_source_->GetUrlAfterRedirects();
2391
2392 // MediaPlayerRendererClient factory is the only factory that a
2393 // MediaResource::Type::URL for the moment. This might no longer be true
2394 // when we remove WebMediaPlayerCast.
2395 //
2396 // TODO(tguilbert/avayvod): Update this flag when removing |cast_impl_|.
2397 using_media_player_renderer_ = true;
2398
Chris Cunninghamd9df58e2017-08-29 00:04:232399 // MediaPlayerRenderer does not provide pipeline stats, so nuke capabilities
2400 // reporter.
2401 video_decode_stats_reporter_.reset();
2402
Mike Westb85da8ed2017-08-10 14:16:462403 demuxer_.reset(new MediaUrlDemuxer(media_task_runner_, loaded_url_,
2404 frame_->GetDocument().SiteForCookies()));
Dale Curtisc00d56482018-02-09 20:55:062405 pipeline_controller_.Start(Pipeline::StartType::kNormal, demuxer_.get(),
2406 this, false, false);
tguilbert25a4d112016-10-13 21:56:512407 return;
2408 }
2409
[email protected]ddbc6ff2013-04-19 15:28:332410 // Figure out which demuxer to use.
Blink Reformat1c4d759e2017-04-09 16:34:542411 if (load_type_ != kLoadTypeMediaSource) {
[email protected]ddbc6ff2013-04-19 15:28:332412 DCHECK(!chunk_demuxer_);
[email protected]f5443ef72013-04-22 04:03:382413 DCHECK(data_source_);
2414
Dale Curtisbcf523b2018-01-17 02:59:012415#if BUILDFLAG(ENABLE_FFMPEG)
servolk81e01e02016-03-05 03:29:152416 Demuxer::MediaTracksUpdatedCB media_tracks_updated_cb =
dcheng37b415b92017-01-27 20:17:432417 BindToCurrentLoop(base::Bind(
2418 &WebMediaPlayerImpl::OnFFmpegMediaTracksUpdated, AsWeakPtr()));
servolk81e01e02016-03-05 03:29:152419
dalecurtis9cddc0b2017-04-19 21:23:382420 demuxer_.reset(new FFmpegDemuxer(
2421 media_task_runner_, data_source_.get(), encrypted_media_init_data_cb,
2422 media_tracks_updated_cb, media_log_.get()));
j.isorcef6778e652015-11-16 17:14:252423#else
alokp967c902452016-05-06 05:21:372424 OnError(PipelineStatus::DEMUXER_ERROR_COULD_NOT_OPEN);
j.isorcef6778e652015-11-16 17:14:252425 return;
2426#endif
[email protected]ddbc6ff2013-04-19 15:28:332427 } else {
[email protected]f5443ef72013-04-22 04:03:382428 DCHECK(!chunk_demuxer_);
2429 DCHECK(!data_source_);
2430
acolwell9e0840d2014-09-06 19:01:322431 chunk_demuxer_ = new ChunkDemuxer(
dcheng37b415b92017-01-27 20:17:432432 BindToCurrentLoop(
2433 base::Bind(&WebMediaPlayerImpl::OnDemuxerOpened, AsWeakPtr())),
Dan Sanders42311b52017-08-10 23:41:032434 BindToCurrentLoop(
2435 base::Bind(&WebMediaPlayerImpl::OnProgress, AsWeakPtr())),
dalecurtis9cddc0b2017-04-19 21:23:382436 encrypted_media_init_data_cb, media_log_.get());
[email protected]f5443ef72013-04-22 04:03:382437 demuxer_.reset(chunk_demuxer_);
servolkf94b4602017-01-31 16:44:272438
2439 if (base::FeatureList::IsEnabled(kMemoryPressureBasedSourceBufferGC)) {
2440 // base::Unretained is safe because |this| owns memory_pressure_listener_.
2441 memory_pressure_listener_ =
Gyuyoung Kim62a5de42018-01-10 09:48:422442 std::make_unique<base::MemoryPressureListener>(base::Bind(
servolkf94b4602017-01-31 16:44:272443 &WebMediaPlayerImpl::OnMemoryPressure, base::Unretained(this)));
2444 }
[email protected]ddbc6ff2013-04-19 15:28:332445 }
2446
sandersdb5e21462016-03-09 01:49:072447 // TODO(sandersd): FileSystem objects may also be non-static, but due to our
2448 // caching layer such situations are broken already. http://crbug.com/593159
2449 bool is_static = !chunk_demuxer_;
avayvod102cdb62017-01-07 03:11:092450 bool is_streaming = IsStreaming();
sandersdb8eb5f1d2016-11-19 04:04:022451 UMA_HISTOGRAM_BOOLEAN("Media.IsStreaming", is_streaming);
sandersdb5e21462016-03-09 01:49:072452
Dale Curtis2dc6089a2018-03-26 16:47:582453 // If possible attempt to avoid decoder spool up until playback starts.
2454 Pipeline::StartType start_type = Pipeline::StartType::kNormal;
2455 if (base::FeatureList::IsEnabled(kPreloadMetadataSuspend) &&
Dale Curtisf5a7c9212018-04-10 21:57:342456 !chunk_demuxer_ && preload_ == MultibufferDataSource::METADATA &&
2457 !client_->CouldPlayIfEnoughData()) {
Dale Curtis2dc6089a2018-03-26 16:47:582458 start_type = has_poster_
2459 ? Pipeline::StartType::kSuspendAfterMetadata
2460 : Pipeline::StartType::kSuspendAfterMetadataForAudioOnly;
2461 attempting_suspended_start_ = true;
2462 }
2463
[email protected]f5443ef72013-04-22 04:03:382464 // ... and we're ready to go!
sandersd1e49fb62015-12-12 01:18:062465 // TODO(sandersd): On Android, defer Start() if the tab is not visible.
sandersdb8eb5f1d2016-11-19 04:04:022466 seeking_ = true;
Dale Curtis2dc6089a2018-03-26 16:47:582467 pipeline_controller_.Start(start_type, demuxer_.get(), this, is_streaming,
2468 is_static);
[email protected]f5443ef72013-04-22 04:03:382469}
2470
2471void WebMediaPlayerImpl::SetNetworkState(WebMediaPlayer::NetworkState state) {
pkastingf5279482016-07-27 02:18:202472 DVLOG(1) << __func__ << "(" << state << ")";
acolwellb4034942014-08-28 15:42:432473 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]f5443ef72013-04-22 04:03:382474 network_state_ = state;
2475 // Always notify to ensure client has the latest value.
Blink Reformat1c4d759e2017-04-09 16:34:542476 client_->NetworkStateChanged();
[email protected]f5443ef72013-04-22 04:03:382477}
2478
2479void WebMediaPlayerImpl::SetReadyState(WebMediaPlayer::ReadyState state) {
pkastingf5279482016-07-27 02:18:202480 DVLOG(1) << __func__ << "(" << state << ")";
acolwellb4034942014-08-28 15:42:432481 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]f5443ef72013-04-22 04:03:382482
Blink Reformat1c4d759e2017-04-09 16:34:542483 if (state == WebMediaPlayer::kReadyStateHaveEnoughData && data_source_ &&
[email protected]fee8a902014-06-03 13:43:362484 data_source_->assume_fully_buffered() &&
Blink Reformat1c4d759e2017-04-09 16:34:542485 network_state_ == WebMediaPlayer::kNetworkStateLoading)
2486 SetNetworkState(WebMediaPlayer::kNetworkStateLoaded);
[email protected]f5443ef72013-04-22 04:03:382487
2488 ready_state_ = state;
sandersd50a635e2016-04-04 22:50:092489 highest_ready_state_ = std::max(highest_ready_state_, ready_state_);
2490
[email protected]f5443ef72013-04-22 04:03:382491 // Always notify to ensure client has the latest value.
Blink Reformat1c4d759e2017-04-09 16:34:542492 client_->ReadyStateChanged();
[email protected]f5443ef72013-04-22 04:03:382493}
2494
Blink Reformat1c4d759e2017-04-09 16:34:542495blink::WebAudioSourceProvider* WebMediaPlayerImpl::GetAudioSourceProvider() {
[email protected]ff875be52013-06-02 23:47:382496 return audio_source_provider_.get();
[email protected]f5443ef72013-04-22 04:03:382497}
2498
Jiajia Qin82acdc02017-07-31 09:55:142499scoped_refptr<VideoFrame> WebMediaPlayerImpl::GetCurrentFrameFromCompositor()
2500 const {
xhwang213e50c2016-10-10 23:56:312501 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]dd061e12014-05-06 19:21:222502 TRACE_EVENT0("media", "WebMediaPlayerImpl::GetCurrentFrameFromCompositor");
xhwang213e50c2016-10-10 23:56:312503
Thomas Guilbertd85407412017-11-08 05:03:462504 // Can be null.
2505 scoped_refptr<VideoFrame> video_frame =
2506 compositor_->GetCurrentFrameOnAnyThread();
[email protected]dd061e12014-05-06 19:21:222507
Thomas Guilbertd85407412017-11-08 05:03:462508 // base::Unretained is safe here because |compositor_| is destroyed on
2509 // |vfc_task_runner_|. The destruction is queued from |this|' destructor,
2510 // which also runs on |main_task_runner_|, which makes it impossible for
2511 // UpdateCurrentFrameIfStale() to be queued after |compositor_|'s dtor.
CJ DiMeglio2302d202017-08-31 08:38:042512 vfc_task_runner_->PostTask(
Thomas Guilbertd85407412017-11-08 05:03:462513 FROM_HERE, base::Bind(&VideoFrameCompositor::UpdateCurrentFrameIfStale,
2514 base::Unretained(compositor_.get())));
kainino36eeff82017-03-30 00:55:302515
[email protected]dd061e12014-05-06 19:21:222516 return video_frame;
2517}
2518
sandersd50a635e2016-04-04 22:50:092519void WebMediaPlayerImpl::UpdatePlayState() {
xhwang213e50c2016-10-10 23:56:312520 DCHECK(main_task_runner_->BelongsToCurrentThread());
2521
hubbed5f36882016-01-15 22:40:372522#if defined(OS_ANDROID) // WMPI_CAST
Blink Reformat1c4d759e2017-04-09 16:34:542523 bool is_remote = IsRemote();
xjz4e5d4bf32017-02-15 21:26:352524 bool can_auto_suspend = true;
sandersd50a635e2016-04-04 22:50:092525#else
2526 bool is_remote = false;
hubbee2cc88c092017-07-14 23:10:412527 bool can_auto_suspend = !disable_pipeline_auto_suspend_;
2528 // For streaming videos, we only allow suspending at the very beginning of the
2529 // video, and only if we know the length of the video. (If we don't know
2530 // the length, it might be a dynamically generated video, and suspending
2531 // will not work at all.)
2532 if (IsStreaming()) {
2533 bool at_beginning =
2534 ready_state_ == WebMediaPlayer::kReadyStateHaveNothing ||
2535 CurrentTime() == 0.0;
2536 if (!at_beginning || GetPipelineMediaDuration() == kInfiniteDuration)
2537 can_auto_suspend = false;
2538 }
hubbed5f36882016-01-15 22:40:372539#endif
xhwang213e50c2016-10-10 23:56:312540
dalecurtis8b8505e72016-06-10 21:59:172541 bool is_suspended = pipeline_controller_.IsSuspended();
avayvod39c102402016-11-23 21:43:132542 bool is_backgrounded = IsBackgroundedSuspendEnabled() && IsHidden();
sandersdaaff1a652016-11-17 01:47:252543 PlayState state = UpdatePlayState_ComputePlayState(
xjz4e5d4bf32017-02-15 21:26:352544 is_remote, can_auto_suspend, is_suspended, is_backgrounded);
sandersd35d2c3f2017-01-14 02:04:422545 SetDelegateState(state.delegate_state, state.is_idle);
sandersd50a635e2016-04-04 22:50:092546 SetMemoryReportingState(state.is_memory_reporting_enabled);
2547 SetSuspendState(state.is_suspended || pending_suspend_resume_cycle_);
2548}
dalecurtis5bbc487e2016-02-27 04:15:052549
sandersd35d2c3f2017-01-14 02:04:422550void WebMediaPlayerImpl::SetDelegateState(DelegateState new_state,
2551 bool is_idle) {
tguilbert1bb1c782017-01-23 21:15:112552 DCHECK(delegate_);
Dale Curtis779ed842018-03-10 06:20:132553 DVLOG(2) << __func__ << "(" << static_cast<int>(new_state) << ", " << is_idle
2554 << ")";
dalecurtis5bbc487e2016-02-27 04:15:052555
sandersd35d2c3f2017-01-14 02:04:422556 // Prevent duplicate delegate calls.
2557 // TODO(sandersd): Move this deduplication into the delegate itself.
2558 // TODO(sandersd): WebContentsObserverSanityChecker does not allow sending the
2559 // 'playing' IPC more than once in a row, even if the metadata has changed.
2560 // Figure out whether it should.
Blink Reformat1c4d759e2017-04-09 16:34:542561 bool has_audio = HasAudio() && !client_->IsAutoplayingMuted();
sandersd35d2c3f2017-01-14 02:04:422562 if (delegate_state_ == new_state &&
2563 (delegate_state_ != DelegateState::PLAYING ||
2564 delegate_has_audio_ == has_audio)) {
2565 return;
mlamouri910111362016-11-04 11:28:242566 }
sandersd50a635e2016-04-04 22:50:092567 delegate_state_ = new_state;
sandersd35d2c3f2017-01-14 02:04:422568 delegate_has_audio_ = has_audio;
sandersd50a635e2016-04-04 22:50:092569
sandersd35d2c3f2017-01-14 02:04:422570 switch (new_state) {
sandersd50a635e2016-04-04 22:50:092571 case DelegateState::GONE:
2572 delegate_->PlayerGone(delegate_id_);
2573 break;
mlamouri910111362016-11-04 11:28:242574 case DelegateState::PLAYING: {
peconn257951522017-06-09 18:24:592575 if (HasVideo())
2576 delegate_->DidPlayerSizeChange(delegate_id_, NaturalSize());
zqzhang5d8eab72016-08-26 20:34:302577 delegate_->DidPlay(
Blink Reformat1c4d759e2017-04-09 16:34:542578 delegate_id_, HasVideo(), has_audio,
avayvodcc273dd2017-01-19 19:35:122579 media::DurationToMediaContentType(GetPipelineMediaDuration()));
sandersd50a635e2016-04-04 22:50:092580 break;
mlamouri910111362016-11-04 11:28:242581 }
sandersd50a635e2016-04-04 22:50:092582 case DelegateState::PAUSED:
sandersd35d2c3f2017-01-14 02:04:422583 delegate_->DidPause(delegate_id_);
sandersd50a635e2016-04-04 22:50:092584 break;
dalecurtis0f0097a2015-12-01 17:40:472585 }
sandersd35d2c3f2017-01-14 02:04:422586
2587 delegate_->SetIdle(delegate_id_, is_idle);
dalecurtis0f0097a2015-12-01 17:40:472588}
2589
sandersd50a635e2016-04-04 22:50:092590void WebMediaPlayerImpl::SetMemoryReportingState(
2591 bool is_memory_reporting_enabled) {
2592 if (memory_usage_reporting_timer_.IsRunning() ==
2593 is_memory_reporting_enabled) {
hubbed5f36882016-01-15 22:40:372594 return;
sandersd50a635e2016-04-04 22:50:092595 }
sandersd1c0bba02016-03-04 23:14:082596
sandersd50a635e2016-04-04 22:50:092597 if (is_memory_reporting_enabled) {
2598 memory_usage_reporting_timer_.Start(FROM_HERE,
2599 base::TimeDelta::FromSeconds(2), this,
2600 &WebMediaPlayerImpl::ReportMemoryUsage);
2601 } else {
2602 memory_usage_reporting_timer_.Stop();
2603 ReportMemoryUsage();
2604 }
2605}
2606
2607void WebMediaPlayerImpl::SetSuspendState(bool is_suspended) {
xhwang213e50c2016-10-10 23:56:312608 DCHECK(main_task_runner_->BelongsToCurrentThread());
Dale Curtis779ed842018-03-10 06:20:132609 DVLOG(2) << __func__ << "(" << is_suspended << ")";
xhwang213e50c2016-10-10 23:56:312610
sandersd50a635e2016-04-04 22:50:092611 // Do not change the state after an error has occurred.
2612 // TODO(sandersd): Update PipelineController to remove the need for this.
2613 if (IsNetworkStateError(network_state_))
sandersd1c0bba02016-03-04 23:14:082614 return;
2615
jameswest451a5bb2017-01-27 03:59:392616 if (is_suspended) {
sandersd35d2c3f2017-01-14 02:04:422617 // If we were not resumed for long enough to satisfy the preroll attempt,
2618 // reset the clock.
2619 if (!preroll_attempt_pending_ && IsPrerollAttemptNeeded()) {
2620 preroll_attempt_pending_ = true;
2621 preroll_attempt_start_time_ = base::TimeTicks();
2622 }
sandersd50a635e2016-04-04 22:50:092623 pipeline_controller_.Suspend();
2624 } else {
sandersd35d2c3f2017-01-14 02:04:422625 // When resuming, start the preroll attempt clock.
2626 if (preroll_attempt_pending_) {
2627 preroll_attempt_pending_ = false;
2628 preroll_attempt_start_time_ = tick_clock_->NowTicks();
2629 }
sandersd50a635e2016-04-04 22:50:092630 pipeline_controller_.Resume();
2631 }
2632}
2633
2634WebMediaPlayerImpl::PlayState
2635WebMediaPlayerImpl::UpdatePlayState_ComputePlayState(bool is_remote,
xjz4e5d4bf32017-02-15 21:26:352636 bool can_auto_suspend,
dalecurtis8b8505e72016-06-10 21:59:172637 bool is_suspended,
sandersd50a635e2016-04-04 22:50:092638 bool is_backgrounded) {
2639 PlayState result;
2640
tguilbert1bb1c782017-01-23 21:15:112641 bool must_suspend = delegate_->IsFrameClosed();
Dale Curtis6438cf12018-03-29 02:34:012642 bool is_stale = delegate_->IsStale(delegate_id_);
2643
2644 if (stale_state_override_for_testing_.has_value() &&
2645 ready_state_ >= stale_state_override_for_testing_.value()) {
2646 is_stale = true;
2647 }
sandersd35d2c3f2017-01-14 02:04:422648
sandersd50a635e2016-04-04 22:50:092649 // This includes both data source (before pipeline startup) and pipeline
2650 // errors.
2651 bool has_error = IsNetworkStateError(network_state_);
2652
dalecurtiscc8baf72016-10-27 01:49:442653 // After HaveFutureData, Blink will call play() if the state is not paused;
2654 // prior to this point |paused_| is not accurate.
sandersd50a635e2016-04-04 22:50:092655 bool have_future_data =
Blink Reformat1c4d759e2017-04-09 16:34:542656 highest_ready_state_ >= WebMediaPlayer::kReadyStateHaveFutureData;
sandersd50a635e2016-04-04 22:50:092657
avayvod65fad272017-02-24 01:00:482658 // Background suspend is only enabled for paused players.
2659 // In the case of players with audio the session should be kept.
2660 bool background_suspended =
xjz4e5d4bf32017-02-15 21:26:352661 can_auto_suspend && is_backgrounded && paused_ && have_future_data;
sandersd50a635e2016-04-04 22:50:092662
dalecurtiscc8baf72016-10-27 01:49:442663 // Idle suspension is allowed prior to have future data since there exist
2664 // mechanisms to exit the idle state when the player is capable of reaching
2665 // the have future data state; see didLoadingProgress().
2666 //
sandersd50a635e2016-04-04 22:50:092667 // TODO(sandersd): Make the delegate suspend idle players immediately when
2668 // hidden.
sandersdaaff1a652016-11-17 01:47:252669 bool idle_suspended =
xjz4e5d4bf32017-02-15 21:26:352670 can_auto_suspend && is_stale && paused_ && !seeking_ && !overlay_enabled_;
dalecurtise7120dc2016-09-03 02:54:352671
2672 // If we're already suspended, see if we can wait for user interaction. Prior
sandersd35d2c3f2017-01-14 02:04:422673 // to HaveFutureData, we require |is_stale| to remain suspended. |is_stale|
dalecurtise7120dc2016-09-03 02:54:352674 // will be cleared when we receive data which may take us to HaveFutureData.
2675 bool can_stay_suspended =
sandersd35d2c3f2017-01-14 02:04:422676 (is_stale || have_future_data) && is_suspended && paused_ && !seeking_;
sandersd50a635e2016-04-04 22:50:092677
2678 // Combined suspend state.
sandersd35d2c3f2017-01-14 02:04:422679 result.is_suspended = is_remote || must_suspend || idle_suspended ||
avayvod65fad272017-02-24 01:00:482680 background_suspended || can_stay_suspended;
sandersd50a635e2016-04-04 22:50:092681
Dale Curtis779ed842018-03-10 06:20:132682 DVLOG(3) << __func__ << ": is_remote=" << is_remote
2683 << ", must_suspend=" << must_suspend
2684 << ", idle_suspended=" << idle_suspended
2685 << ", background_suspended=" << background_suspended
2686 << ", can_stay_suspended=" << can_stay_suspended
2687 << ", is_stale=" << is_stale
2688 << ", have_future_data=" << have_future_data
2689 << ", paused_=" << paused_ << ", seeking_=" << seeking_;
2690
sandersd50a635e2016-04-04 22:50:092691 // We do not treat |playback_rate_| == 0 as paused. For the media session,
2692 // being paused implies displaying a play button, which is incorrect in this
2693 // case. For memory usage reporting, we just use the same definition (but we
2694 // don't have to).
2695 //
2696 // Similarly, we don't consider |ended_| to be paused. Blink will immediately
2697 // call pause() or seek(), so |ended_| should not affect the computation.
2698 // Despite that, |ended_| does result in a separate paused state, to simplfy
2699 // the contract for SetDelegateState().
2700 //
avayvod65fad272017-02-24 01:00:482701 // |has_remote_controls| indicates if the player can be controlled outside the
2702 // page (e.g. via the notification controls or by audio focus events). Idle
sandersd50a635e2016-04-04 22:50:092703 // suspension does not destroy the media session, because we expect that the
avayvod5f34b642017-03-23 03:14:042704 // notification controls (and audio focus) remain. With some exceptions for
2705 // background videos, the player only needs to have audio to have controls
2706 // (requires |have_future_data|).
2707 //
2708 // |alive| indicates if the player should be present (not |GONE|) to the
2709 // delegate, either paused or playing. The following must be true for the
2710 // player:
sandersd50a635e2016-04-04 22:50:092711 // - |have_future_data|, since we need to know whether we are paused to
avayvod65fad272017-02-24 01:00:482712 // correctly configure the session and also because the tracks and
avayvod5f34b642017-03-23 03:14:042713 // duration are passed to DidPlay(),
2714 // - |is_remote| is false as remote playback is not handled by the delegate,
2715 // - |has_error| is false as player should have no errors,
2716 // - |background_suspended| is false, otherwise |has_remote_controls| must
2717 // be true.
sandersd50a635e2016-04-04 22:50:092718 //
avayvod65fad272017-02-24 01:00:482719 // TODO(sandersd): If Blink told us the paused state sooner, we could detect
2720 // if the remote controls are available sooner.
2721
2722 // Background videos with audio don't have remote controls if background
2723 // suspend is enabled and resuming background videos is not (original Android
2724 // behavior).
2725 bool backgrounded_video_has_no_remote_controls =
2726 IsBackgroundedSuspendEnabled() && !IsResumeBackgroundVideosEnabled() &&
Blink Reformat1c4d759e2017-04-09 16:34:542727 is_backgrounded && HasVideo();
sandersd50a635e2016-04-04 22:50:092728 bool can_play = !has_error && !is_remote && have_future_data;
avayvod5f34b642017-03-23 03:14:042729 bool has_remote_controls =
Blink Reformat1c4d759e2017-04-09 16:34:542730 HasAudio() && !backgrounded_video_has_no_remote_controls;
avayvod5f34b642017-03-23 03:14:042731 bool alive = can_play && !must_suspend &&
2732 (!background_suspended || has_remote_controls);
2733 if (!alive) {
sandersd50a635e2016-04-04 22:50:092734 result.delegate_state = DelegateState::GONE;
tguilbert1bb1c782017-01-23 21:15:112735 result.is_idle = delegate_->IsIdle(delegate_id_);
avayvod65fad272017-02-24 01:00:482736 } else if (paused_) {
sandersd35d2c3f2017-01-14 02:04:422737 // TODO(sandersd): Is it possible to have a suspended session, be ended,
2738 // and not be paused? If so we should be in a PLAYING state.
dalecurtise7120dc2016-09-03 02:54:352739 result.delegate_state =
sandersd35d2c3f2017-01-14 02:04:422740 ended_ ? DelegateState::GONE : DelegateState::PAUSED;
2741 result.is_idle = !seeking_;
sandersd50a635e2016-04-04 22:50:092742 } else {
2743 result.delegate_state = DelegateState::PLAYING;
sandersd35d2c3f2017-01-14 02:04:422744 result.is_idle = false;
sandersd50a635e2016-04-04 22:50:092745 }
2746
dalecurtis8b8505e72016-06-10 21:59:172747 // It's not critical if some cases where memory usage can change are missed,
sandersd50a635e2016-04-04 22:50:092748 // since media memory changes are usually gradual.
2749 result.is_memory_reporting_enabled =
Dale Curtis8a6281322017-08-31 00:35:532750 !has_error && can_play && !result.is_suspended && (!paused_ || seeking_);
sandersd50a635e2016-04-04 22:50:092751
2752 return result;
dalecurtis0f0097a2015-12-01 17:40:472753}
2754
dalecurtis83266c72015-10-29 18:43:202755void WebMediaPlayerImpl::ReportMemoryUsage() {
2756 DCHECK(main_task_runner_->BelongsToCurrentThread());
2757
wdzierzanowskifd4cd91c52015-12-02 23:50:202758 // About base::Unretained() usage below: We destroy |demuxer_| on the main
2759 // thread. Before that, however, ~WebMediaPlayerImpl() posts a task to the
2760 // media thread and waits for it to finish. Hence, the GetMemoryUsage() task
2761 // posted here must finish earlier.
Dale Curtis8a6281322017-08-31 00:35:532762 //
2763 // The exception to the above is when OnError() has been called. If we're in
2764 // the error state we've already shut down the pipeline and can't rely on it
2765 // to cycle the media thread before we destroy |demuxer_|. In this case skip
2766 // collection of the demuxer memory stats.
2767 if (demuxer_ && !IsNetworkStateError(network_state_)) {
wdzierzanowskifd4cd91c52015-12-02 23:50:202768 base::PostTaskAndReplyWithResult(
2769 media_task_runner_.get(), FROM_HERE,
2770 base::Bind(&Demuxer::GetMemoryUsage, base::Unretained(demuxer_.get())),
2771 base::Bind(&WebMediaPlayerImpl::FinishMemoryUsageReport, AsWeakPtr()));
2772 } else {
2773 FinishMemoryUsageReport(0);
2774 }
2775}
2776
2777void WebMediaPlayerImpl::FinishMemoryUsageReport(int64_t demuxer_memory_usage) {
2778 DCHECK(main_task_runner_->BelongsToCurrentThread());
2779
avayvodc4bfb0e62017-01-13 01:07:012780 const PipelineStatistics stats = GetPipelineStatistics();
servolk639473e492016-12-15 04:14:202781 const int64_t data_source_memory_usage =
2782 data_source_ ? data_source_->GetMemoryUsage() : 0;
dalecurtisecc76612017-04-19 00:31:202783
Dale Curtisc2c5dcb12018-04-16 23:21:292784 // If we have video and no video memory usage and we've rendered the first
2785 // frame, assume the VideoFrameCompositor is holding onto the last frame after
2786 // we've suspended the pipeline; which thus reports zero memory usage from the
2787 // video renderer.
dalecurtisecc76612017-04-19 00:31:202788 //
2789 // Technically this should use the coded size, but that requires us to hop to
2790 // the compositor to get and byte-perfect accuracy isn't important here.
2791 const int64_t video_memory_usage =
2792 stats.video_memory_usage +
Dale Curtisc2c5dcb12018-04-16 23:21:292793 ((pipeline_metadata_.has_video && !stats.video_memory_usage &&
2794 has_first_frame_)
Miguel Casas9e7766022018-01-08 16:13:132795 ? VideoFrame::AllocationSize(PIXEL_FORMAT_I420,
dalecurtisecc76612017-04-19 00:31:202796 pipeline_metadata_.natural_size)
2797 : 0);
2798
dalecurtis83266c72015-10-29 18:43:202799 const int64_t current_memory_usage =
dalecurtisecc76612017-04-19 00:31:202800 stats.audio_memory_usage + video_memory_usage + data_source_memory_usage +
2801 demuxer_memory_usage;
dalecurtis83266c72015-10-29 18:43:202802
dalecurtisecc76612017-04-19 00:31:202803 DVLOG(2) << "Memory Usage -- Total: " << current_memory_usage
2804 << " Audio: " << stats.audio_memory_usage
2805 << ", Video: " << video_memory_usage
servolk639473e492016-12-15 04:14:202806 << ", DataSource: " << data_source_memory_usage
wdzierzanowskifd4cd91c52015-12-02 23:50:202807 << ", Demuxer: " << demuxer_memory_usage;
dalecurtis83266c72015-10-29 18:43:202808
2809 const int64_t delta = current_memory_usage - last_reported_memory_usage_;
2810 last_reported_memory_usage_ = current_memory_usage;
2811 adjust_allocated_memory_cb_.Run(delta);
servolk639473e492016-12-15 04:14:202812
Blink Reformat1c4d759e2017-04-09 16:34:542813 if (HasAudio()) {
servolk639473e492016-12-15 04:14:202814 UMA_HISTOGRAM_MEMORY_KB("Media.WebMediaPlayerImpl.Memory.Audio",
2815 stats.audio_memory_usage / 1024);
2816 }
Blink Reformat1c4d759e2017-04-09 16:34:542817 if (HasVideo()) {
servolk639473e492016-12-15 04:14:202818 UMA_HISTOGRAM_MEMORY_KB("Media.WebMediaPlayerImpl.Memory.Video",
dalecurtisecc76612017-04-19 00:31:202819 video_memory_usage / 1024);
servolk639473e492016-12-15 04:14:202820 }
2821 if (data_source_) {
2822 UMA_HISTOGRAM_MEMORY_KB("Media.WebMediaPlayerImpl.Memory.DataSource",
2823 data_source_memory_usage / 1024);
2824 }
2825 if (demuxer_) {
2826 UMA_HISTOGRAM_MEMORY_KB("Media.WebMediaPlayerImpl.Memory.Demuxer",
2827 demuxer_memory_usage / 1024);
2828 }
dalecurtis83266c72015-10-29 18:43:202829}
2830
dalecurtis8b8505e72016-06-10 21:59:172831void WebMediaPlayerImpl::ScheduleIdlePauseTimer() {
avayvod65fad272017-02-24 01:00:482832 // Only schedule the pause timer if we're not paused or paused but going to
avayvod52efd282017-03-07 21:13:042833 // resume when foregrounded, and are suspended and have audio.
2834 if ((paused_ && !paused_when_hidden_) ||
Blink Reformat1c4d759e2017-04-09 16:34:542835 !pipeline_controller_.IsSuspended() || !HasAudio()) {
dalecurtis8b8505e72016-06-10 21:59:172836 return;
avayvod52efd282017-03-07 21:13:042837 }
dalecurtis8b8505e72016-06-10 21:59:172838
2839#if defined(OS_ANDROID)
2840 // Remote players will be suspended and locally paused.
Blink Reformat1c4d759e2017-04-09 16:34:542841 if (IsRemote())
dalecurtis8b8505e72016-06-10 21:59:172842 return;
2843#endif
2844
2845 // Idle timeout chosen arbitrarily.
2846 background_pause_timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(5),
2847 this, &WebMediaPlayerImpl::OnPause);
2848}
2849
dalecurtis04bdb582016-08-17 22:15:232850void WebMediaPlayerImpl::CreateWatchTimeReporter() {
wdzierzanowskia78fa9b2017-06-13 18:12:102851 if (!HasVideo() && !HasAudio())
2852 return;
2853
dalecurtis04bdb582016-08-17 22:15:232854 // Create the watch time reporter and synchronize its initial state.
Dale Curtis1adbe6a2017-08-02 02:09:132855 watch_time_reporter_.reset(new WatchTimeReporter(
2856 mojom::PlaybackProperties::New(
2857 pipeline_metadata_.audio_decoder_config.codec(),
2858 pipeline_metadata_.video_decoder_config.codec(),
Dale Curtisef3893f2017-12-06 23:28:102859 pipeline_metadata_.has_audio, pipeline_metadata_.has_video, false,
Dale Curtis1adbe6a2017-08-02 02:09:132860 !!chunk_demuxer_, is_encrypted_, embedded_media_experience_enabled_,
Dale Curtis74612b72017-12-14 20:56:192861 pipeline_metadata_.natural_size),
Dale Curtis051fdf62017-08-05 00:21:132862 base::BindRepeating(&WebMediaPlayerImpl::GetCurrentTimeInternal,
2863 base::Unretained(this)),
Hajime Hoshi8bb37dc2017-12-19 09:35:102864 media_metrics_provider_.get(),
Hajime Hoshib5a26ee2018-05-14 12:47:512865 frame_->GetTaskRunner(blink::TaskType::kInternalMedia)));
dalecurtis04bdb582016-08-17 22:15:232866 watch_time_reporter_->OnVolumeChange(volume_);
Mounir Lamourif9af74e72017-06-19 19:31:452867
tguilbert1bb1c782017-01-23 21:15:112868 if (delegate_->IsFrameHidden())
dalecurtis04bdb582016-08-17 22:15:232869 watch_time_reporter_->OnHidden();
2870 else
2871 watch_time_reporter_->OnShown();
Mounir Lamourif9af74e72017-06-19 19:31:452872
Mounir Lamouri41a79c62017-06-06 12:53:162873 if (client_->HasNativeControls())
2874 watch_time_reporter_->OnNativeControlsEnabled();
2875 else
2876 watch_time_reporter_->OnNativeControlsDisabled();
Mounir Lamourif9af74e72017-06-19 19:31:452877
Dale Curtisc7d2a7d22018-01-11 20:01:052878 if (!audio_decoder_name_.empty())
2879 watch_time_reporter_->SetAudioDecoderName(audio_decoder_name_);
2880 if (!video_decoder_name_.empty())
2881 watch_time_reporter_->SetVideoDecoderName(video_decoder_name_);
2882
Mounir Lamourif9af74e72017-06-19 19:31:452883 switch (client_->DisplayType()) {
2884 case WebMediaPlayer::DisplayType::kInline:
2885 watch_time_reporter_->OnDisplayTypeInline();
2886 break;
2887 case WebMediaPlayer::DisplayType::kFullscreen:
2888 watch_time_reporter_->OnDisplayTypeFullscreen();
2889 break;
2890 case WebMediaPlayer::DisplayType::kPictureInPicture:
2891 watch_time_reporter_->OnDisplayTypePictureInPicture();
2892 break;
2893 }
dalecurtis04bdb582016-08-17 22:15:232894}
2895
avayvod39c102402016-11-23 21:43:132896bool WebMediaPlayerImpl::IsHidden() const {
2897 DCHECK(main_task_runner_->BelongsToCurrentThread());
2898
tguilbert1bb1c782017-01-23 21:15:112899 return delegate_->IsFrameHidden() && !delegate_->IsFrameClosed();
avayvod39c102402016-11-23 21:43:132900}
2901
avayvod102cdb62017-01-07 03:11:092902bool WebMediaPlayerImpl::IsStreaming() const {
2903 return data_source_ && data_source_->IsStreaming();
2904}
2905
liberato2fd111be2017-01-04 00:25:062906bool WebMediaPlayerImpl::DoesOverlaySupportMetadata() const {
Julien Isorce6c83d8de2017-10-12 13:11:292907 return pipeline_metadata_.video_decoder_config.video_rotation() ==
2908 VIDEO_ROTATION_0;
liberato2fd111be2017-01-04 00:25:062909}
2910
xjzaf29d4182016-12-16 01:52:322911void WebMediaPlayerImpl::ActivateViewportIntersectionMonitoring(bool activate) {
2912 DCHECK(main_task_runner_->BelongsToCurrentThread());
2913
Blink Reformat1c4d759e2017-04-09 16:34:542914 client_->ActivateViewportIntersectionMonitoring(activate);
xjzaf29d4182016-12-16 01:52:322915}
2916
Anton Vayvod09fa66e2017-07-20 23:02:122917void WebMediaPlayerImpl::UpdateRemotePlaybackCompatibility(bool is_compatible) {
2918 DCHECK(main_task_runner_->BelongsToCurrentThread());
2919
2920 client_->RemotePlaybackCompatibilityChanged(loaded_url_, is_compatible);
2921}
2922
Dale Curtis6438cf12018-03-29 02:34:012923void WebMediaPlayerImpl::ForceStaleStateForTesting(ReadyState target_state) {
2924 stale_state_override_for_testing_.emplace(target_state);
Dale Curtis99a9b482018-02-01 02:23:282925 UpdatePlayState();
2926}
2927
2928bool WebMediaPlayerImpl::IsSuspendedForTesting() {
2929 // This intentionally uses IsPipelineSuspended since we need to know when the
2930 // pipeline has reached the suspended state, not when it's in suspending.
2931 return pipeline_controller_.IsPipelineSuspended();
2932}
2933
avayvodcc273dd2017-01-19 19:35:122934bool WebMediaPlayerImpl::ShouldPauseVideoWhenHidden() const {
avayvod65fad272017-02-24 01:00:482935 // If suspending background video, pause any video that's not remoted or
2936 // not unlocked to play in the background.
2937 if (IsBackgroundedSuspendEnabled()) {
Blink Reformat1c4d759e2017-04-09 16:34:542938 if (!HasVideo())
avayvod65fad272017-02-24 01:00:482939 return false;
2940
2941#if defined(OS_ANDROID)
Blink Reformat1c4d759e2017-04-09 16:34:542942 if (IsRemote())
avayvod65fad272017-02-24 01:00:482943 return false;
avayvodcc273dd2017-01-19 19:35:122944#endif
avayvodeb9098d2017-01-07 00:33:032945
Blink Reformat1c4d759e2017-04-09 16:34:542946 return !HasAudio() || (IsResumeBackgroundVideosEnabled() &&
2947 video_locked_when_paused_when_hidden_);
avayvod65fad272017-02-24 01:00:482948 }
2949
2950 // Otherwise only pause if the optimization is on and it's a video-only
2951 // optimization candidate.
avayvod01201332017-04-14 00:27:152952 return IsBackgroundVideoPauseOptimizationEnabled() && !HasAudio() &&
avayvod65fad272017-02-24 01:00:482953 IsBackgroundOptimizationCandidate();
avayvodeb9098d2017-01-07 00:33:032954}
2955
avayvod2135a642017-01-13 00:17:142956bool WebMediaPlayerImpl::ShouldDisableVideoWhenHidden() const {
avayvodcc273dd2017-01-19 19:35:122957 // This optimization is behind the flag on all platforms.
2958 if (!IsBackgroundVideoTrackOptimizationEnabled())
avayvodc4bfb0e62017-01-13 01:07:012959 return false;
avayvodc4bfb0e62017-01-13 01:07:012960
avayvodcc273dd2017-01-19 19:35:122961 // Disable video track only for players with audio that match the criteria for
2962 // being optimized.
Blink Reformat1c4d759e2017-04-09 16:34:542963 return HasAudio() && IsBackgroundOptimizationCandidate();
avayvodcc273dd2017-01-19 19:35:122964}
2965
2966bool WebMediaPlayerImpl::IsBackgroundOptimizationCandidate() const {
2967 DCHECK(main_task_runner_->BelongsToCurrentThread());
2968
François Beaufort664c3ca72018-04-13 07:24:512969 // Don't optimize Picture-in-Picture players.
2970 if (client_->IsInPictureInPictureMode())
2971 return false;
2972
avayvodcc273dd2017-01-19 19:35:122973#if defined(OS_ANDROID) // WMPI_CAST
avayvodac1a8522017-01-20 19:02:502974 // Don't optimize players being Cast.
Blink Reformat1c4d759e2017-04-09 16:34:542975 if (IsRemote())
avayvodcc273dd2017-01-19 19:35:122976 return false;
2977#endif // defined(OS_ANDROID)
2978
2979 // Don't optimize audio-only or streaming players.
Blink Reformat1c4d759e2017-04-09 16:34:542980 if (!HasVideo() || IsStreaming())
avayvodcc273dd2017-01-19 19:35:122981 return false;
2982
Dale Curtis3f4935b2017-09-09 00:11:592983 // Video-only players are always optimized (paused).
2984 // Don't check the keyframe distance and duration.
2985 if (!HasAudio() && HasVideo())
2986 return true;
2987
avayvodcc273dd2017-01-19 19:35:122988 // Videos shorter than the maximum allowed keyframe distance can be optimized.
2989 base::TimeDelta duration = GetPipelineMediaDuration();
avayvode85ec422017-04-14 00:11:332990 base::TimeDelta max_keyframe_distance =
2991 (load_type_ == kLoadTypeMediaSource)
2992 ? max_keyframe_distance_to_disable_background_video_mse_
2993 : max_keyframe_distance_to_disable_background_video_;
2994 if (duration < max_keyframe_distance)
avayvodcc273dd2017-01-19 19:35:122995 return true;
2996
2997 // Otherwise, only optimize videos with shorter average keyframe distance.
avayvodc4bfb0e62017-01-13 01:07:012998 PipelineStatistics stats = GetPipelineStatistics();
avayvode85ec422017-04-14 00:11:332999 return stats.video_keyframe_distance_average < max_keyframe_distance;
avayvod2135a642017-01-13 00:17:143000}
3001
avayvod56e1f3942017-01-21 02:06:313002void WebMediaPlayerImpl::UpdateBackgroundVideoOptimizationState() {
3003 if (IsHidden()) {
Dale Curtisa75a7892017-08-09 20:21:513004 if (ShouldPauseVideoWhenHidden()) {
avayvod56e1f3942017-01-21 02:06:313005 PauseVideoIfNeeded();
Dale Curtisa75a7892017-08-09 20:21:513006 } else if (update_background_status_cb_.IsCancelled()) {
3007 // Only trigger updates when we don't have one already scheduled.
3008 update_background_status_cb_.Reset(
3009 base::Bind(&WebMediaPlayerImpl::DisableVideoTrackIfNeeded,
3010 base::Unretained(this)));
3011
3012 // Defer disable track until we're sure the clip will be backgrounded for
3013 // some time. Resuming may take half a second, so frequent tab switches
3014 // will yield a poor user experience otherwise. http://crbug.com/709302
3015 // may also cause AV sync issues if disable/enable happens too fast.
3016 main_task_runner_->PostDelayedTask(
3017 FROM_HERE, update_background_status_cb_.callback(),
3018 base::TimeDelta::FromSeconds(10));
3019 }
avayvod56e1f3942017-01-21 02:06:313020 } else {
Dale Curtisa75a7892017-08-09 20:21:513021 update_background_status_cb_.Cancel();
avayvod56e1f3942017-01-21 02:06:313022 EnableVideoTrackIfNeeded();
3023 }
3024}
3025
3026void WebMediaPlayerImpl::PauseVideoIfNeeded() {
3027 DCHECK(IsHidden());
3028
3029 // Don't pause video while the pipeline is stopped, resuming or seeking.
3030 // Also if the video is paused already.
tguilbert350936ff2017-02-24 05:39:273031 if (!pipeline_controller_.IsPipelineRunning() || is_pipeline_resuming_ ||
3032 seeking_ || paused_)
avayvod56e1f3942017-01-21 02:06:313033 return;
3034
3035 // OnPause() will set |paused_when_hidden_| to false and call
3036 // UpdatePlayState(), so set the flag to true after and then return.
3037 OnPause();
3038 paused_when_hidden_ = true;
3039}
3040
avayvod2135a642017-01-13 00:17:143041void WebMediaPlayerImpl::EnableVideoTrackIfNeeded() {
avayvod56e1f3942017-01-21 02:06:313042 // Don't change video track while the pipeline is stopped, resuming or
3043 // seeking.
tguilbert350936ff2017-02-24 05:39:273044 if (!pipeline_controller_.IsPipelineRunning() || is_pipeline_resuming_ ||
3045 seeking_)
avayvod2135a642017-01-13 00:17:143046 return;
3047
3048 if (video_track_disabled_) {
3049 video_track_disabled_ = false;
Blink Reformat1c4d759e2017-04-09 16:34:543050 if (client_->HasSelectedVideoTrack()) {
3051 WebMediaPlayer::TrackId trackId = client_->GetSelectedVideoTrackId();
3052 SelectedVideoTrackChanged(&trackId);
avayvod2135a642017-01-13 00:17:143053 }
3054 }
3055}
3056
3057void WebMediaPlayerImpl::DisableVideoTrackIfNeeded() {
3058 DCHECK(IsHidden());
3059
3060 // Don't change video track while the pipeline is resuming or seeking.
3061 if (is_pipeline_resuming_ || seeking_)
3062 return;
3063
3064 if (!video_track_disabled_ && ShouldDisableVideoWhenHidden()) {
3065 video_track_disabled_ = true;
Blink Reformat1c4d759e2017-04-09 16:34:543066 SelectedVideoTrackChanged(nullptr);
avayvod2135a642017-01-13 00:17:143067 }
3068}
3069
avayvodc4bfb0e62017-01-13 01:07:013070void WebMediaPlayerImpl::SetPipelineStatisticsForTest(
3071 const PipelineStatistics& stats) {
3072 pipeline_statistics_for_test_ = base::make_optional(stats);
3073}
3074
3075PipelineStatistics WebMediaPlayerImpl::GetPipelineStatistics() const {
3076 DCHECK(main_task_runner_->BelongsToCurrentThread());
3077
tguilbert350936ff2017-02-24 05:39:273078 return pipeline_statistics_for_test_.value_or(
3079 pipeline_controller_.GetStatistics());
avayvodc4bfb0e62017-01-13 01:07:013080}
3081
avayvodcc273dd2017-01-19 19:35:123082void WebMediaPlayerImpl::SetPipelineMediaDurationForTest(
3083 base::TimeDelta duration) {
3084 pipeline_media_duration_for_test_ = base::make_optional(duration);
3085}
3086
3087base::TimeDelta WebMediaPlayerImpl::GetPipelineMediaDuration() const {
3088 DCHECK(main_task_runner_->BelongsToCurrentThread());
3089
3090 return pipeline_media_duration_for_test_.value_or(
tguilbert350936ff2017-02-24 05:39:273091 pipeline_controller_.GetMediaDuration());
avayvodcc273dd2017-01-19 19:35:123092}
3093
3094void WebMediaPlayerImpl::ReportTimeFromForegroundToFirstFrame(
3095 base::TimeTicks foreground_time,
3096 base::TimeTicks new_frame_time) {
3097 base::TimeDelta time_to_first_frame = new_frame_time - foreground_time;
Blink Reformat1c4d759e2017-04-09 16:34:543098 if (HasAudio()) {
avayvodcc273dd2017-01-19 19:35:123099 UMA_HISTOGRAM_TIMES(
3100 "Media.Video.TimeFromForegroundToFirstFrame.DisableTrack",
3101 time_to_first_frame);
3102 } else {
3103 UMA_HISTOGRAM_TIMES("Media.Video.TimeFromForegroundToFirstFrame.Paused",
3104 time_to_first_frame);
3105 }
3106}
Xiangjun Zhangba8724f482017-08-03 06:43:253107
3108void WebMediaPlayerImpl::SwitchToRemoteRenderer(
3109 const std::string& remote_device_friendly_name) {
xjz4e5d4bf32017-02-15 21:26:353110 DCHECK(main_task_runner_->BelongsToCurrentThread());
Thomas Guilbertb341bae02018-05-09 00:02:133111 DCHECK(!disable_pipeline_auto_suspend_);
Xiangjun Zhangba8724f482017-08-03 06:43:253112 disable_pipeline_auto_suspend_ = true;
Chris Cunninghamd9df58e2017-08-29 00:04:233113
3114 // Capabilities reporting should only be performed for local playbacks.
3115 video_decode_stats_reporter_.reset();
3116
Xiangjun Zhangba8724f482017-08-03 06:43:253117 // Requests to restart media pipeline. A remote renderer will be created via
3118 // the |renderer_factory_selector_|.
xjz4e5d4bf32017-02-15 21:26:353119 ScheduleRestart();
xjzdf9b67e2017-04-13 23:28:253120 if (client_) {
Xiangjun Zhangba8724f482017-08-03 06:43:253121 client_->MediaRemotingStarted(
3122 WebString::FromUTF8(remote_device_friendly_name));
xjzdf9b67e2017-04-13 23:28:253123 }
xjz4e5d4bf32017-02-15 21:26:353124}
3125
Xiangjun Zhang5e20cba42018-01-10 19:54:563126void WebMediaPlayerImpl::SwitchToLocalRenderer(
3127 MediaObserverClient::ReasonToSwitchToLocal reason) {
Xiangjun Zhangba8724f482017-08-03 06:43:253128 DCHECK(main_task_runner_->BelongsToCurrentThread());
Thomas Guilbertb341bae02018-05-09 00:02:133129 DCHECK(disable_pipeline_auto_suspend_);
Xiangjun Zhangba8724f482017-08-03 06:43:253130 disable_pipeline_auto_suspend_ = false;
Chris Cunninghamd9df58e2017-08-29 00:04:233131
3132 // Capabilities reporting may resume now that playback is local.
3133 CreateVideoDecodeStatsReporter();
3134
Xiangjun Zhangba8724f482017-08-03 06:43:253135 // Requests to restart media pipeline. A local renderer will be created via
3136 // the |renderer_factory_selector_|.
3137 ScheduleRestart();
3138 if (client_)
Xiangjun Zhang5e20cba42018-01-10 19:54:563139 client_->MediaRemotingStopped(GetSwitchToLocalMessage(reason));
Xiangjun Zhangba8724f482017-08-03 06:43:253140}
3141
dalecurtis4f6d14d2017-02-22 17:42:223142void WebMediaPlayerImpl::RecordUnderflowDuration(base::TimeDelta duration) {
3143 DCHECK(data_source_ || chunk_demuxer_);
xhwang68b3fab82017-05-17 21:31:463144
dalecurtis4f6d14d2017-02-22 17:42:223145 if (data_source_)
Jennifer Apacible82e25c92017-08-07 18:15:273146 UMA_HISTOGRAM_TIMES("Media.UnderflowDuration2.SRC", duration);
dalecurtis4f6d14d2017-02-22 17:42:223147 else
Jennifer Apacible82e25c92017-08-07 18:15:273148 UMA_HISTOGRAM_TIMES("Media.UnderflowDuration2.MSE", duration);
xhwang68b3fab82017-05-17 21:31:463149
3150 if (is_encrypted_)
Jennifer Apacible82e25c92017-08-07 18:15:273151 UMA_HISTOGRAM_TIMES("Media.UnderflowDuration2.EME", duration);
dalecurtis4f6d14d2017-02-22 17:42:223152}
3153
xhwang60802652017-04-19 07:29:583154#define UMA_HISTOGRAM_VIDEO_HEIGHT(name, sample) \
3155 UMA_HISTOGRAM_CUSTOM_COUNTS(name, sample, 100, 10000, 50)
3156
3157void WebMediaPlayerImpl::RecordVideoNaturalSize(const gfx::Size& natural_size) {
3158 // Always report video natural size to MediaLog.
3159 media_log_->AddEvent(media_log_->CreateVideoSizeSetEvent(
3160 natural_size.width(), natural_size.height()));
3161
3162 if (initial_video_height_recorded_)
3163 return;
3164
3165 initial_video_height_recorded_ = true;
3166
3167 int height = natural_size.height();
3168
3169 if (load_type_ == kLoadTypeURL)
3170 UMA_HISTOGRAM_VIDEO_HEIGHT("Media.VideoHeight.Initial.SRC", height);
3171 else if (load_type_ == kLoadTypeMediaSource)
3172 UMA_HISTOGRAM_VIDEO_HEIGHT("Media.VideoHeight.Initial.MSE", height);
3173
3174 if (is_encrypted_)
3175 UMA_HISTOGRAM_VIDEO_HEIGHT("Media.VideoHeight.Initial.EME", height);
3176
3177 UMA_HISTOGRAM_VIDEO_HEIGHT("Media.VideoHeight.Initial.All", height);
3178}
3179
3180#undef UMA_HISTOGRAM_VIDEO_HEIGHT
3181
Greg Thompsonaa48ce8d2018-04-03 06:11:433182void WebMediaPlayerImpl::SetTickClockForTest(
3183 const base::TickClock* tick_clock) {
tzik2c963b872017-12-07 06:57:243184 tick_clock_ = tick_clock;
hubbeb2d3efd2017-05-05 23:26:383185 buffered_data_source_host_.SetTickClockForTest(tick_clock);
3186}
3187
Dale Curtis3899090ea2018-01-12 00:10:353188void WebMediaPlayerImpl::OnFirstFrame(base::TimeTicks frame_time) {
3189 DCHECK(!load_start_time_.is_null());
Dale Curtisff576552018-03-30 02:32:443190 DCHECK(!skip_metrics_due_to_startup_suspend_);
Dale Curtisc2c5dcb12018-04-16 23:21:293191 has_first_frame_ = true;
Dale Curtis3899090ea2018-01-12 00:10:353192 const base::TimeDelta elapsed = frame_time - load_start_time_;
3193 media_metrics_provider_->SetTimeToFirstFrame(elapsed);
3194 RecordTimingUMA("Media.TimeToFirstFrame", elapsed);
3195}
3196
3197void WebMediaPlayerImpl::RecordTimingUMA(const std::string& key,
3198 base::TimeDelta elapsed) {
3199 if (chunk_demuxer_)
3200 base::UmaHistogramMediumTimes(key + ".MSE", elapsed);
3201 else
3202 base::UmaHistogramMediumTimes(key + ".SRC", elapsed);
3203 if (is_encrypted_)
3204 base::UmaHistogramMediumTimes(key + ".EME", elapsed);
3205}
3206
John Rummelldb5a7ef2018-05-16 00:28:013207void WebMediaPlayerImpl::RecordEncryptionScheme(
3208 const std::string& stream_name,
3209 const EncryptionScheme& encryption_scheme) {
3210 DCHECK(stream_name == "Audio" || stream_name == "Video");
3211
3212 // If the stream is not encrypted, don't record it.
3213 if (encryption_scheme.mode() == EncryptionScheme::CIPHER_MODE_UNENCRYPTED)
3214 return;
3215
3216 base::UmaHistogramEnumeration(
3217 "Media.EME.EncryptionScheme.Initial." + stream_name,
3218 DetermineEncryptionSchemeUMAValue(encryption_scheme),
3219 EncryptionSchemeUMA::kCount);
3220}
3221
acolwell9e0840d2014-09-06 19:01:323222} // namespace media