blob: a6e0158890d2b43f90e26c206910917a163c7d7e [file] [log] [blame]
[email protected]85a37afd2013-05-30 22:51:151// Copyright 2013 The Chromium Authors. All rights reserved.
[email protected]891acc92009-04-27 19:56:412// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
[email protected]ec9212f2008-12-18 21:40:364
acolwell9e0840d2014-09-06 19:01:325#include "media/blink/webmediaplayer_impl.h"
[email protected]8931c41a2009-07-07 17:31:496
[email protected]c2a45e242013-02-15 20:24:587#include <algorithm>
mateuszs3371ab02015-04-24 13:20:238#include <cmath>
[email protected]47b06ceb2010-08-04 22:41:119#include <limits>
Gyuyoung Kim62a5de42018-01-10 09:48:4210#include <memory>
guidouc7babef2015-10-22 00:42:3511#include <string>
dcheng652f5ff2015-12-27 08:54:0012#include <utility>
[email protected]47b06ceb2010-08-04 22:41:1113
[email protected]08273c7b2011-09-17 00:33:5114#include "base/bind.h"
sandersd1c0bba02016-03-04 23:14:0815#include "base/bind_helpers.h"
[email protected]2041cf342010-02-19 03:15:5916#include "base/callback.h"
[email protected]7502ef12014-01-25 01:19:2717#include "base/callback_helpers.h"
sandersd1e49fb62015-12-12 01:18:0618#include "base/command_line.h"
[email protected]ca04095f2014-02-07 10:23:5619#include "base/debug/alias.h"
[email protected]926f8fd2013-04-12 20:27:5320#include "base/debug/crash_logging.h"
fdoraydb3ef7d2016-06-09 15:42:3821#include "base/location.h"
Dale Curtis3899090ea2018-01-12 00:10:3522#include "base/metrics/histogram_functions.h"
asvitkine30330812016-08-30 04:01:0823#include "base/metrics/histogram_macros.h"
acolwellb4034942014-08-28 15:42:4324#include "base/single_thread_task_runner.h"
servolka233f832016-06-10 20:39:0425#include "base/strings/string_number_conversions.h"
Gabriel Charette44db1422018-08-06 11:19:3326#include "base/task/post_task.h"
wdzierzanowskifd4cd91c52015-12-02 23:50:2027#include "base/task_runner_util.h"
gabba14a442016-05-11 20:10:2028#include "base/threading/thread_task_runner_handle.h"
ssid9525f4672015-01-28 12:13:1529#include "base/trace_event/trace_event.h"
sandersd1e49fb62015-12-12 01:18:0630#include "build/build_config.h"
[email protected]21c3f7502013-03-23 03:29:5131#include "cc/layers/video_layer.h"
CJ DiMeglioc60a5cf2017-09-27 20:08:4132#include "components/viz/common/gpu/context_provider.h"
[email protected]e4fc09e2012-04-06 03:17:4433#include "media/audio/null_audio_sink.h"
[email protected]2eccbed2014-01-10 05:15:5334#include "media/base/bind_to_current_loop.h"
xhwang0ad11e512014-11-25 23:43:0935#include "media/base/cdm_context.h"
John Rummelldb5a7ef2018-05-16 00:28:0136#include "media/base/encryption_scheme.h"
[email protected]32da1002010-03-03 21:57:3537#include "media/base/limits.h"
zqzhang5d8eab72016-08-26 20:34:3038#include "media/base/media_content_type.h"
[email protected]090f7312011-08-05 23:26:4039#include "media/base/media_log.h"
sandersd1e49fb62015-12-12 01:18:0640#include "media/base/media_switches.h"
tguilbert25a4d112016-10-13 21:56:5141#include "media/base/media_url_demuxer.h"
[email protected]8a561062013-11-22 01:19:3142#include "media/base/text_renderer.h"
watk9f9dfdc92015-09-04 21:33:2943#include "media/base/timestamp_constants.h"
[email protected]e81283bb2010-08-31 18:01:2144#include "media/base/video_frame.h"
acolwell9e0840d2014-09-06 19:01:3245#include "media/blink/texttrack_impl.h"
John Delaneyb933391602018-10-17 21:50:4746#include "media/blink/url_index.h"
Chris Cunninghamd9df58e2017-08-29 00:04:2347#include "media/blink/video_decode_stats_reporter.h"
dalecurtis04bdb582016-08-17 22:15:2348#include "media/blink/watch_time_reporter.h"
acolwell9e0840d2014-09-06 19:01:3249#include "media/blink/webaudiosourceprovider_impl.h"
xhwang97de4202014-11-25 08:44:0150#include "media/blink/webcontentdecryptionmodule_impl.h"
acolwell9e0840d2014-09-06 19:01:3251#include "media/blink/webinbandtexttrack_impl.h"
52#include "media/blink/webmediaplayer_delegate.h"
acolwell9e0840d2014-09-06 19:01:3253#include "media/blink/webmediaplayer_util.h"
54#include "media/blink/webmediasource_impl.h"
[email protected]efe7cd22012-09-12 23:55:0155#include "media/filters/chunk_demuxer.h"
[email protected]ddbc6ff2013-04-19 15:28:3356#include "media/filters/ffmpeg_demuxer.h"
Scott Violeta35f9a42018-03-22 22:00:4457#include "media/media_buildflags.h"
sawtellee19d11aa2018-08-10 03:47:5058#include "third_party/blink/public/common/picture_in_picture/picture_in_picture_control_info.h"
Blink Reformata30d4232018-04-07 15:31:0659#include "third_party/blink/public/platform/web_encrypted_media_types.h"
60#include "third_party/blink/public/platform/web_localized_string.h"
61#include "third_party/blink/public/platform/web_media_player_client.h"
62#include "third_party/blink/public/platform/web_media_player_encrypted_media_client.h"
63#include "third_party/blink/public/platform/web_media_player_source.h"
64#include "third_party/blink/public/platform/web_media_source.h"
65#include "third_party/blink/public/platform/web_rect.h"
66#include "third_party/blink/public/platform/web_runtime_features.h"
67#include "third_party/blink/public/platform/web_security_origin.h"
68#include "third_party/blink/public/platform/web_size.h"
69#include "third_party/blink/public/platform/web_string.h"
70#include "third_party/blink/public/platform/web_surface_layer_bridge.h"
71#include "third_party/blink/public/platform/web_url.h"
72#include "third_party/blink/public/web/web_document.h"
73#include "third_party/blink/public/web/web_frame.h"
74#include "third_party/blink/public/web/web_local_frame.h"
75#include "third_party/blink/public/web/web_user_gesture_indicator.h"
76#include "third_party/blink/public/web/web_view.h"
[email protected]b3f2b912009-04-09 16:18:5277
dalecurtisea27a3ed2016-06-24 01:41:3078#if defined(OS_ANDROID)
79#include "media/base/android/media_codec_util.h"
80#endif
81
[email protected]180ef242013-11-07 06:50:4682using blink::WebMediaPlayer;
83using blink::WebRect;
84using blink::WebSize;
85using blink::WebString;
hubbed5f36882016-01-15 22:40:3786using gpu::gles2::GLES2Interface;
87
danakj365175c2016-02-06 00:37:3788#define STATIC_ASSERT_ENUM(a, b) \
89 static_assert(static_cast<int>(a) == static_cast<int>(b), \
90 "mismatching enums: " #a)
91
hubbed5f36882016-01-15 22:40:3792namespace media {
[email protected]ec9212f2008-12-18 21:40:3693
[email protected]8931c41a2009-07-07 17:31:4994namespace {
95
hubbed5f36882016-01-15 22:40:3796void SetSinkIdOnMediaThread(scoped_refptr<WebAudioSourceProviderImpl> sink,
97 const std::string& device_id,
Daniel Chengc1710b52018-10-24 03:12:2898 OutputDeviceStatusCB callback) {
99 sink->SwitchOutputDevice(device_id, std::move(callback));
guidouc7babef2015-10-22 00:42:35100}
101
Sergey Volk8b09c2c52018-12-12 23:20:40102bool IsBackgroundSuspendEnabled(const WebMediaPlayerImpl* wmpi) {
Luke Halliwell7a8a8982018-07-25 01:07:05103 // TODO(crbug.com/867146): remove these switches.
104 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
105 switches::kDisableMediaSuspend))
106 return false;
107 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
108 switches::kEnableMediaSuspend))
109 return true;
110
Sergey Volk8b09c2c52018-12-12 23:20:40111 return wmpi->IsBackgroundMediaSuspendEnabled();
dalecurtis0431cbf2016-03-12 01:19:43112}
113
avayvod48a8be52016-08-04 19:52:50114bool IsResumeBackgroundVideosEnabled() {
115 return base::FeatureList::IsEnabled(kResumeBackgroundVideo);
116}
117
Ted Meyera918e592018-09-08 00:16:20118bool IsBackgroundVideoTrackOptimizationEnabled(
119 WebMediaPlayer::LoadType load_type) {
120 // Background video track optimization is always enabled for MSE videos.
121 return load_type == WebMediaPlayer::LoadType::kLoadTypeMediaSource ||
122 base::FeatureList::IsEnabled(kBackgroundSrcVideoTrackOptimization);
avayvod39c102402016-11-23 21:43:13123}
124
avayvod01201332017-04-14 00:27:15125bool IsBackgroundVideoPauseOptimizationEnabled() {
126 return base::FeatureList::IsEnabled(kBackgroundVideoPauseOptimization);
127}
128
avayvod82729272017-05-29 21:58:39129bool IsNewRemotePlaybackPipelineEnabled() {
130 return base::FeatureList::IsEnabled(kNewRemotePlaybackPipeline);
131}
132
sandersd50a635e2016-04-04 22:50:09133bool IsNetworkStateError(blink::WebMediaPlayer::NetworkState state) {
Blink Reformat1c4d759e2017-04-09 16:34:54134 bool result = state == blink::WebMediaPlayer::kNetworkStateFormatError ||
135 state == blink::WebMediaPlayer::kNetworkStateNetworkError ||
136 state == blink::WebMediaPlayer::kNetworkStateDecodeError;
137 DCHECK_EQ(state > blink::WebMediaPlayer::kNetworkStateLoaded, result);
sandersd50a635e2016-04-04 22:50:09138 return result;
139}
140
sandersd2c478422016-08-02 01:19:25141gfx::Size GetRotatedVideoSize(VideoRotation rotation, gfx::Size natural_size) {
142 if (rotation == VIDEO_ROTATION_90 || rotation == VIDEO_ROTATION_270)
143 return gfx::Size(natural_size.height(), natural_size.width());
144 return natural_size;
145}
146
Xiaohan Wangf63505d2017-10-21 08:00:53147void RecordEncryptedEvent(bool encrypted_event_fired) {
148 UMA_HISTOGRAM_BOOLEAN("Media.EME.EncryptedEvent", encrypted_event_fired);
149}
150
sandersd35d2c3f2017-01-14 02:04:42151// How much time must have elapsed since loading last progressed before we
152// assume that the decoder will have had time to complete preroll.
153constexpr base::TimeDelta kPrerollAttemptTimeout =
watkd026f792016-11-05 00:28:51154 base::TimeDelta::FromSeconds(3);
155
Matt Wolenetz6010f6c2017-10-18 00:44:36156// Maximum number, per-WMPI, of media logs of playback rate changes.
157constexpr int kMaxNumPlaybackRateLogs = 10;
158
Xiangjun Zhang5e20cba42018-01-10 19:54:56159blink::WebLocalizedString::Name GetSwitchToLocalMessage(
160 MediaObserverClient::ReasonToSwitchToLocal reason) {
161 switch (reason) {
162 case MediaObserverClient::ReasonToSwitchToLocal::NORMAL:
163 return blink::WebLocalizedString::kMediaRemotingStopText;
164 case MediaObserverClient::ReasonToSwitchToLocal::POOR_PLAYBACK_QUALITY:
165 return blink::WebLocalizedString::kMediaRemotingStopByPlaybackQualityText;
166 case MediaObserverClient::ReasonToSwitchToLocal::PIPELINE_ERROR:
167 return blink::WebLocalizedString::kMediaRemotingStopByErrorText;
168 case MediaObserverClient::ReasonToSwitchToLocal::ROUTE_TERMINATED:
169 return blink::WebLocalizedString::kMediaRemotingStopNoText;
170 }
171 NOTREACHED();
172 // To suppress compiler warning on Windows.
173 return blink::WebLocalizedString::kMediaRemotingStopNoText;
174}
175
John Rummelldb5a7ef2018-05-16 00:28:01176// These values are persisted to UMA. Entries should not be renumbered and
177// numeric values should never be reused.
178// TODO(crbug.com/825041): This should use EncryptionMode when kUnencrypted
179// removed.
180enum class EncryptionSchemeUMA { kCenc = 0, kCbcs = 1, kCount };
181
182EncryptionSchemeUMA DetermineEncryptionSchemeUMAValue(
183 const EncryptionScheme& encryption_scheme) {
184 if (encryption_scheme.mode() == EncryptionScheme::CIPHER_MODE_AES_CBC)
185 return EncryptionSchemeUMA::kCbcs;
186
187 DCHECK_EQ(encryption_scheme.mode(), EncryptionScheme::CIPHER_MODE_AES_CTR);
188 return EncryptionSchemeUMA::kCenc;
189}
190
John Rummelld30555352018-09-21 20:47:25191EncryptionMode DetermineEncryptionMode(
192 const EncryptionScheme& encryption_scheme) {
193 switch (encryption_scheme.mode()) {
194 case EncryptionScheme::CIPHER_MODE_UNENCRYPTED:
195 return EncryptionMode::kUnencrypted;
196 case EncryptionScheme::CIPHER_MODE_AES_CTR:
197 return EncryptionMode::kCenc;
198 case EncryptionScheme::CIPHER_MODE_AES_CBC:
199 return EncryptionMode::kCbcs;
200 }
201}
202
Pavel Feldman023c3e62018-08-28 17:59:47203#if BUILDFLAG(ENABLE_FFMPEG)
Dale Curtisb8139f72018-08-27 23:28:48204// Returns true if |url| represents (or is likely to) a local file.
205bool IsLocalFile(const GURL& url) {
206 return url.SchemeIsFile() || url.SchemeIsFileSystem() ||
207 url.SchemeIs(url::kContentScheme) ||
208 url.SchemeIs(url::kContentIDScheme) ||
209 url.SchemeIs("chrome-extension");
210}
Pavel Feldman023c3e62018-08-28 17:59:47211#endif
Dale Curtisb8139f72018-08-27 23:28:48212
[email protected]8931c41a2009-07-07 17:31:49213} // namespace
214
[email protected]6683e1b2014-04-10 01:45:38215class BufferedDataSourceHostImpl;
216
Takashi Toyoshima2e01e692018-11-16 03:23:27217STATIC_ASSERT_ENUM(WebMediaPlayer::kCorsModeUnspecified,
danakj365175c2016-02-06 00:37:37218 UrlData::CORS_UNSPECIFIED);
Takashi Toyoshima2e01e692018-11-16 03:23:27219STATIC_ASSERT_ENUM(WebMediaPlayer::kCorsModeAnonymous, UrlData::CORS_ANONYMOUS);
220STATIC_ASSERT_ENUM(WebMediaPlayer::kCorsModeUseCredentials,
danakj365175c2016-02-06 00:37:37221 UrlData::CORS_USE_CREDENTIALS);
[email protected]a5a01102012-06-06 17:01:24222
[email protected]5b5bb9d2010-10-22 19:57:36223WebMediaPlayerImpl::WebMediaPlayerImpl(
[email protected]35b2a972014-04-04 15:50:22224 blink::WebLocalFrame* frame,
[email protected]180ef242013-11-07 06:50:46225 blink::WebMediaPlayerClient* client,
srirama.m26f864d02015-07-14 05:21:46226 blink::WebMediaPlayerEncryptedMediaClient* encrypted_client,
tguilbert1bb1c782017-01-23 21:15:11227 WebMediaPlayerDelegate* delegate,
tguilbert70d2a00a2017-04-25 00:30:44228 std::unique_ptr<RendererFactorySelector> renderer_factory_selector,
Alok Priyadarshi7166d4d2017-07-29 04:04:25229 UrlIndex* url_index,
CJ DiMegliod7ac6772017-11-10 00:19:06230 std::unique_ptr<VideoFrameCompositor> compositor,
dalecurtis9cddc0b2017-04-19 21:23:38231 std::unique_ptr<WebMediaPlayerParams> params)
[email protected]f6af7592014-02-28 10:09:11232 : frame_(frame),
Alexander Timin310368112017-09-13 10:01:44233 main_task_runner_(
234 frame->GetTaskRunner(blink::TaskType::kMediaElementEvent)),
dalecurtis9cddc0b2017-04-19 21:23:38235 media_task_runner_(params->media_task_runner()),
236 worker_task_runner_(params->worker_task_runner()),
237 media_log_(params->take_media_log()),
sandersd1c0bba02016-03-04 23:14:08238 pipeline_controller_(
Hajime Hoshidb0761a42018-01-18 08:10:19239 std::make_unique<PipelineImpl>(media_task_runner_,
240 main_task_runner_,
241 media_log_.get()),
sandersd1c0bba02016-03-04 23:14:08242 base::Bind(&WebMediaPlayerImpl::CreateRenderer,
243 base::Unretained(this)),
244 base::Bind(&WebMediaPlayerImpl::OnPipelineSeeked, AsWeakPtr()),
245 base::Bind(&WebMediaPlayerImpl::OnPipelineSuspended, AsWeakPtr()),
avayvod2135a642017-01-13 00:17:14246 base::Bind(&WebMediaPlayerImpl::OnBeforePipelineResume, AsWeakPtr()),
247 base::Bind(&WebMediaPlayerImpl::OnPipelineResumed, AsWeakPtr()),
alokp967c902452016-05-06 05:21:37248 base::Bind(&WebMediaPlayerImpl::OnError, AsWeakPtr())),
[email protected]5badb082010-06-11 17:40:15249 client_(client),
srirama.m26f864d02015-07-14 05:21:46250 encrypted_client_(encrypted_client),
[email protected]baff4512011-10-19 18:21:07251 delegate_(delegate),
dalecurtis9cddc0b2017-04-19 21:23:38252 defer_load_cb_(params->defer_load_cb()),
dalecurtis9cddc0b2017-04-19 21:23:38253 adjust_allocated_memory_cb_(params->adjust_allocated_memory_cb()),
tzik2c963b872017-12-07 06:57:24254 tick_clock_(base::DefaultTickClock::GetInstance()),
hubbeb2d3efd2017-05-05 23:26:38255 buffered_data_source_host_(
256 base::Bind(&WebMediaPlayerImpl::OnProgress, AsWeakPtr()),
tzik2c963b872017-12-07 06:57:24257 tick_clock_),
hubbe5f0ad43b2015-12-14 20:57:26258 url_index_(url_index),
CJ DiMeglioc60a5cf2017-09-27 20:08:41259 context_provider_(params->context_provider()),
CJ DiMegliod7ac6772017-11-10 00:19:06260 vfc_task_runner_(params->video_frame_compositor_task_runner()),
261 compositor_(std::move(compositor)),
hubbed5f36882016-01-15 22:40:37262#if defined(OS_ANDROID) // WMPI_CAST
CJ DiMeglioc60a5cf2017-09-27 20:08:41263 cast_impl_(this, client_, params->context_provider()),
hubbed5f36882016-01-15 22:40:37264#endif
tguilbert70d2a00a2017-04-25 00:30:44265 renderer_factory_selector_(std::move(renderer_factory_selector)),
dalecurtis9cddc0b2017-04-19 21:23:38266 observer_(params->media_observer()),
servolkf94b4602017-01-31 16:44:27267 enable_instant_source_buffer_gc_(
dalecurtis9cddc0b2017-04-19 21:23:38268 params->enable_instant_source_buffer_gc()),
shaktisahu24189c12017-03-11 17:42:55269 embedded_media_experience_enabled_(
liberato2ff93ad2017-05-17 07:28:24270 params->embedded_media_experience_enabled()),
[email protected]69db58f2018-09-26 20:27:56271 surface_layer_mode_(params->use_surface_layer_for_video()),
CJ DiMeglio96c18b692018-07-04 03:39:06272 create_bridge_callback_(params->create_bridge_callback()),
liberato2ff93ad2017-05-17 07:28:24273 request_routing_token_cb_(params->request_routing_token_cb()),
Dale Curtis1adbe6a2017-08-02 02:09:13274 overlay_routing_token_(OverlayInfo::RoutingToken()),
Sergey Volk8b09c2c52018-12-12 23:20:40275 media_metrics_provider_(params->take_metrics_provider()),
276 is_background_suspend_enabled_(params->IsBackgroundSuspendEnabled()),
277 is_background_video_track_optimization_supported_(
278 params->IsBackgroundVideoTrackOptimizationSupported()) {
xhwang51139732017-02-24 19:36:08279 DVLOG(1) << __func__;
Dale Curtise25163812018-09-21 22:13:39280 DCHECK(adjust_allocated_memory_cb_);
tguilbert70d2a00a2017-04-25 00:30:44281 DCHECK(renderer_factory_selector_);
servolkef1e5ef2016-03-25 04:55:26282 DCHECK(client_);
tguilbert1bb1c782017-01-23 21:15:11283 DCHECK(delegate_);
dalecurtis83266c72015-10-29 18:43:20284
[email protected]c8d574722017-08-30 20:53:43285 // If we're supposed to force video overlays, then make sure that they're
286 // enabled all the time.
287 always_enable_overlays_ = base::CommandLine::ForCurrentProcess()->HasSwitch(
tsunghungee562e92016-07-20 18:03:31288 switches::kForceVideoOverlays);
289
liberato2ff93ad2017-05-17 07:28:24290 if (base::FeatureList::IsEnabled(media::kOverlayFullscreenVideo)) {
291 bool use_android_overlay =
292 base::FeatureList::IsEnabled(media::kUseAndroidOverlay);
293 overlay_mode_ = use_android_overlay ? OverlayMode::kUseAndroidOverlay
294 : OverlayMode::kUseContentVideoView;
295 } else {
296 overlay_mode_ = OverlayMode::kNoOverlays;
297 }
ampea73f792017-01-19 04:05:39298
tguilbert1bb1c782017-01-23 21:15:11299 delegate_id_ = delegate_->AddObserver(this);
300 delegate_->SetIdle(delegate_id_, true);
sandersd1e49fb62015-12-12 01:18:06301
dalecurtis2cff7f372017-05-24 08:30:08302 media_log_->AddEvent(media_log_->CreateCreatedEvent(
303 url::Origin(frame_->GetSecurityOrigin()).GetURL().spec()));
sandersd72683f252017-07-07 23:20:46304 media_log_->SetStringProperty("frame_url",
305 frame_->GetDocument().Url().GetString().Utf8());
306 media_log_->SetStringProperty("frame_title",
307 frame_->GetDocument().Title().Utf8());
[email protected]4e6be3f2009-05-07 02:24:44308
[email protected]52b0b212018-10-10 05:25:28309 // To make manual testing easier, include |surface_layer_mode_| in the log.
310 // TODO(liberato): Move this into media_factory.cc, so that it can be shared
311 // with the MediaStream startup.
312 const char* surface_layer_mode_name = "(unset)";
313 switch (surface_layer_mode_) {
CJ DiMeglio89240472018-10-18 18:21:10314 case SurfaceLayerMode::kAlways:
[email protected]52b0b212018-10-10 05:25:28315 surface_layer_mode_name = "kAlways";
316 break;
CJ DiMeglio89240472018-10-18 18:21:10317 case SurfaceLayerMode::kOnDemand:
[email protected]52b0b212018-10-10 05:25:28318 surface_layer_mode_name = "kOnDemand";
319 break;
CJ DiMeglio89240472018-10-18 18:21:10320 case SurfaceLayerMode::kNever:
[email protected]52b0b212018-10-10 05:25:28321 surface_layer_mode_name = "kNever";
322 break;
323 }
324 media_log_->SetStringProperty("surface_layer_mode", surface_layer_mode_name);
325
dalecurtis9cddc0b2017-04-19 21:23:38326 if (params->initial_cdm())
327 SetCdm(params->initial_cdm());
xhwang0ad11e512014-11-25 23:43:09328
Xiaohan Wangf63505d2017-10-21 08:00:53329 // Report a false "EncrytpedEvent" here as a baseline.
330 RecordEncryptedEvent(false);
331
xhwangf94a634d2014-10-22 22:07:27332 // TODO(xhwang): When we use an external Renderer, many methods won't work,
xhwang6fa356202014-12-11 00:44:12333 // e.g. GetCurrentFrameFromCompositor(). See http://crbug.com/434861
dalecurtis9cddc0b2017-04-19 21:23:38334 audio_source_provider_ = new WebAudioSourceProviderImpl(
335 params->audio_renderer_sink(), media_log_.get());
xjz4e5d4bf32017-02-15 21:26:35336
337 if (observer_)
338 observer_->SetClient(this);
Hajime Hoshi8bb37dc2017-12-19 09:35:10339
340 memory_usage_reporting_timer_.SetTaskRunner(
Hajime Hoshib5a26ee2018-05-14 12:47:51341 frame_->GetTaskRunner(blink::TaskType::kInternalMedia));
John Delaney6c8ecc1b2018-10-21 19:07:29342
343 if (frame_->IsAdSubframe())
344 media_metrics_provider_->SetIsAdMedia();
[email protected]ec9212f2008-12-18 21:40:36345}
346
[email protected]4e6be3f2009-05-07 02:24:44347WebMediaPlayerImpl::~WebMediaPlayerImpl() {
xhwang51139732017-02-24 19:36:08348 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:43349 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53350
xhwang51139732017-02-24 19:36:08351 if (set_cdm_result_) {
352 DVLOG(2) << "Resolve pending SetCdm() when media player is destroyed.";
Blink Reformat1c4d759e2017-04-09 16:34:54353 set_cdm_result_->Complete();
xhwang51139732017-02-24 19:36:08354 set_cdm_result_.reset();
355 }
356
alokp1116967f2016-06-11 17:30:56357 suppress_destruction_errors_ = true;
tguilbert1bb1c782017-01-23 21:15:11358
359 delegate_->PlayerGone(delegate_id_);
360 delegate_->RemoveObserver(delegate_id_);
[email protected]baff4512011-10-19 18:21:07361
dalecurtis04bdb582016-08-17 22:15:23362 // Finalize any watch time metrics before destroying the pipeline.
363 watch_time_reporter_.reset();
364
tguilbert350936ff2017-02-24 05:39:27365 // The underlying Pipeline must be stopped before it is destroyed.
tguilbert350936ff2017-02-24 05:39:27366 pipeline_controller_.Stop();
[email protected]f6af7592014-02-28 10:09:11367
dalecurtis83266c72015-10-29 18:43:20368 if (last_reported_memory_usage_)
369 adjust_allocated_memory_cb_.Run(-last_reported_memory_usage_);
370
dalecurtise1edb312016-06-22 02:33:21371 // Destruct compositor resources in the proper order.
danakj8d204a42018-05-18 18:05:35372 client_->SetCcLayer(nullptr);
CJ DiMeglio2302d202017-08-31 08:38:04373
Xiangjun Zhang5e20cba42018-01-10 19:54:56374 client_->MediaRemotingStopped(
375 blink::WebLocalizedString::kMediaRemotingStopNoText);
Xiangjun Zhang87299142017-09-13 20:35:03376
Tim Schumann964cc812018-11-28 08:47:03377 if (!surface_layer_for_video_enabled_ && video_layer_) {
danakj25f030112018-05-11 18:26:54378 video_layer_->StopUsingProvider();
Tim Schumann964cc812018-11-28 08:47:03379 }
380
381 vfc_task_runner_->DeleteSoon(FROM_HERE, std::move(compositor_));
382
383 if (chunk_demuxer_) {
384 // Continue destruction of |chunk_demuxer_| on the |media_task_runner_| to
385 // avoid racing other pending tasks on |chunk_demuxer_| on that runner while
386 // not further blocking |main_task_runner_| to perform the destruction.
387 media_task_runner_->PostTask(
388 FROM_HERE, base::BindOnce(&WebMediaPlayerImpl::DemuxerDestructionHelper,
389 media_task_runner_, std::move(demuxer_)));
390 }
Matt Wolenetz95af6362018-01-04 20:23:42391
xhwangea8bb3562015-06-08 21:18:37392 media_log_->AddEvent(
393 media_log_->CreateEvent(MediaLogEvent::WEBMEDIAPLAYER_DESTROYED));
Tim Schumann964cc812018-11-28 08:47:03394}
[email protected]ec9212f2008-12-18 21:40:36395
Tim Schumann964cc812018-11-28 08:47:03396// static
397void WebMediaPlayerImpl::DemuxerDestructionHelper(
398 scoped_refptr<base::SingleThreadTaskRunner> task_runner,
399 std::unique_ptr<Demuxer> demuxer) {
400 DCHECK(task_runner->BelongsToCurrentThread());
401 // ChunkDemuxer's streams may contain much buffered, compressed media that may
402 // need to be paged back in during destruction. Paging delay may exceed the
403 // renderer hang monitor's threshold on at least Windows while also blocking
404 // other work on the renderer main thread, so we do the actual destruction in
405 // the background without blocking WMPI destruction or |task_runner|. On
406 // advice of task_scheduler OWNERS, MayBlock() is not used because virtual
407 // memory overhead is not considered blocking I/O; and CONTINUE_ON_SHUTDOWN is
408 // used to allow process termination to not block on completing the task.
409 base::PostTaskWithTraits(
Matt Wolenetz95af6362018-01-04 20:23:42410 FROM_HERE,
Tim Schumann964cc812018-11-28 08:47:03411 {base::TaskPriority::BEST_EFFORT,
412 base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
413 base::BindOnce(
414 [](std::unique_ptr<Demuxer> demuxer_to_destroy) {
415 SCOPED_UMA_HISTOGRAM_TIMER("Media.MSE.DemuxerDestructionTime");
416 demuxer_to_destroy.reset();
417 },
418 std::move(demuxer)));
Matt Wolenetz95af6362018-01-04 20:23:42419}
420
chcunningham707b821e2018-05-29 08:42:19421WebMediaPlayer::LoadTiming WebMediaPlayerImpl::Load(
422 LoadType load_type,
423 const blink::WebMediaPlayerSource& source,
Takashi Toyoshima2e01e692018-11-16 03:23:27424 CorsMode cors_mode) {
xhwang51139732017-02-24 19:36:08425 DVLOG(1) << __func__;
guidou9bfe4e2f2016-04-09 08:31:19426 // Only URL or MSE blob URL is supported.
Blink Reformat1c4d759e2017-04-09 16:34:54427 DCHECK(source.IsURL());
428 blink::WebURL url = source.GetAsURL();
Xiaohan Wang81fd0022017-07-11 17:45:24429 DVLOG(1) << __func__ << "(" << load_type << ", " << GURL(url) << ", "
430 << cors_mode << ")";
chcunningham707b821e2018-05-29 08:42:19431
432 bool is_deferred = false;
433
Dale Curtise25163812018-09-21 22:13:39434 if (defer_load_cb_) {
chcunningham707b821e2018-05-29 08:42:19435 is_deferred = defer_load_cb_.Run(base::BindOnce(
436 &WebMediaPlayerImpl::DoLoad, AsWeakPtr(), load_type, url, cors_mode));
437 } else {
438 DoLoad(load_type, url, cors_mode);
[email protected]d726eddc2013-07-02 22:25:55439 }
chcunningham707b821e2018-05-29 08:42:19440
441 return is_deferred ? LoadTiming::kDeferred : LoadTiming::kImmediate;
[email protected]62e5e682013-03-07 23:53:24442}
443
CJ DiMeglio013d4c472017-11-21 03:27:30444void WebMediaPlayerImpl::OnWebLayerUpdated() {}
445
danakj6a062b112018-05-17 16:25:45446void WebMediaPlayerImpl::RegisterContentsLayer(cc::Layer* layer) {
CJ DiMeglio2302d202017-08-31 08:38:04447 DCHECK(bridge_);
CJ DiMeglioa2b13fbc2018-06-27 00:50:59448 bridge_->SetContentsOpaque(opaque_);
danakj8d204a42018-05-18 18:05:35449 client_->SetCcLayer(layer);
CJ DiMeglio013d4c472017-11-21 03:27:30450}
451
danakj6a062b112018-05-17 16:25:45452void WebMediaPlayerImpl::UnregisterContentsLayer(cc::Layer* layer) {
453 // |client_| will unregister its cc::Layer if given a nullptr.
danakj8d204a42018-05-18 18:05:35454 client_->SetCcLayer(nullptr);
CJ DiMeglio2302d202017-08-31 08:38:04455}
456
Jennifer Apaciblec45fd052018-02-25 12:04:55457void WebMediaPlayerImpl::OnSurfaceIdUpdated(viz::SurfaceId surface_id) {
Jennifer Apaciblec45fd052018-02-25 12:04:55458 // TODO(726619): Handle the behavior when Picture-in-Picture mode is
459 // disabled.
Jennifer Apacible2b1dc5eb2018-04-27 16:23:28460 // The viz::SurfaceId may be updated when the video begins playback or when
461 // the size of the video changes.
Mounir Lamouri0484f40a2018-07-25 03:03:26462 if (client_ && IsInPictureInPicture() && !client_->IsInAutoPIP()) {
Mounir Lamourife756e32018-05-22 23:19:08463 delegate_->DidPictureInPictureSurfaceChange(
François Beauforta22026d2018-09-25 08:51:11464 delegate_id_, surface_id, pipeline_metadata_.natural_size,
François Beaufortbb68c43e2018-11-20 20:12:03465 ShouldShowPlayPauseButtonInPictureInPictureWindow());
Mounir Lamourife756e32018-05-22 23:19:08466 }
Jennifer Apaciblec45fd052018-02-25 12:04:55467}
468
Blink Reformat1c4d759e2017-04-09 16:34:54469bool WebMediaPlayerImpl::SupportsOverlayFullscreenVideo() {
watk9c87c6fa2016-05-06 20:36:51470#if defined(OS_ANDROID)
[email protected]68ec57f2017-06-27 22:10:05471 return !using_media_player_renderer_ &&
472 overlay_mode_ == OverlayMode::kUseContentVideoView;
watk9c87c6fa2016-05-06 20:36:51473#else
474 return false;
475#endif
476}
477
tsunghungee562e92016-07-20 18:03:31478void WebMediaPlayerImpl::EnableOverlay() {
479 overlay_enabled_ = true;
[email protected]f7df5b342018-07-13 20:22:13480 if (request_routing_token_cb_ &&
481 overlay_mode_ == OverlayMode::kUseAndroidOverlay) {
liberatofe8f9692017-06-08 19:17:36482 overlay_routing_token_is_pending_ = true;
liberato2ff93ad2017-05-17 07:28:24483 token_available_cb_.Reset(
484 base::Bind(&WebMediaPlayerImpl::OnOverlayRoutingToken, AsWeakPtr()));
485 request_routing_token_cb_.Run(token_available_cb_.callback());
watkf835a792016-06-24 23:24:40486 }
tsunghungee562e92016-07-20 18:03:31487
liberato2ff93ad2017-05-17 07:28:24488 // We have requested (and maybe already have) overlay information. If the
489 // restarted decoder requests overlay information, then we'll defer providing
490 // it if it hasn't arrived yet. Otherwise, this would be a race, since we
491 // don't know if the request for overlay info or restart will complete first.
tsunghungee562e92016-07-20 18:03:31492 if (decoder_requires_restart_for_overlay_)
watkdee516f2016-02-18 02:22:19493 ScheduleRestart();
494}
495
tsunghungee562e92016-07-20 18:03:31496void WebMediaPlayerImpl::DisableOverlay() {
497 overlay_enabled_ = false;
liberato2ff93ad2017-05-17 07:28:24498 if (overlay_mode_ == OverlayMode::kUseContentVideoView) {
499 surface_created_cb_.Cancel();
liberato2ff93ad2017-05-17 07:28:24500 } else if (overlay_mode_ == OverlayMode::kUseAndroidOverlay) {
501 token_available_cb_.Cancel();
liberatofe8f9692017-06-08 19:17:36502 overlay_routing_token_is_pending_ = false;
503 overlay_routing_token_ = OverlayInfo::RoutingToken();
liberato2ff93ad2017-05-17 07:28:24504 }
tsunghungee562e92016-07-20 18:03:31505
506 if (decoder_requires_restart_for_overlay_)
watkdee516f2016-02-18 02:22:19507 ScheduleRestart();
liberato2ff93ad2017-05-17 07:28:24508 else
509 MaybeSendOverlayInfoToDecoder();
watkdee516f2016-02-18 02:22:19510}
511
Blink Reformat1c4d759e2017-04-09 16:34:54512void WebMediaPlayerImpl::EnteredFullscreen() {
liberatofe8f9692017-06-08 19:17:36513 overlay_info_.is_fullscreen = true;
514
[email protected]c8d574722017-08-30 20:53:43515 // |always_enable_overlays_| implies that we're already in overlay mode, so
516 // take no action here. Otherwise, switch to an overlay if it's allowed and
517 // if it will display properly.
518 if (!always_enable_overlays_ && overlay_mode_ != OverlayMode::kNoOverlays &&
liberato2fd111be2017-01-04 00:25:06519 DoesOverlaySupportMetadata()) {
tsunghungee562e92016-07-20 18:03:31520 EnableOverlay();
liberato2fd111be2017-01-04 00:25:06521 }
liberato2ff93ad2017-05-17 07:28:24522
liberatofe8f9692017-06-08 19:17:36523 // We send this only if we can send multiple calls. Otherwise, either (a)
524 // we already sent it and we don't have a callback anyway (we reset it when
525 // it's called in restart mode), or (b) we'll send this later when the surface
526 // actually arrives. GVD assumes that the first overlay info will have the
527 // routing information. Note that we set |is_fullscreen_| earlier, so that
528 // if EnableOverlay() can include fullscreen info in case it sends the overlay
529 // info before returning.
530 if (!decoder_requires_restart_for_overlay_)
531 MaybeSendOverlayInfoToDecoder();
tsunghungee562e92016-07-20 18:03:31532}
533
Blink Reformat1c4d759e2017-04-09 16:34:54534void WebMediaPlayerImpl::ExitedFullscreen() {
liberatofe8f9692017-06-08 19:17:36535 overlay_info_.is_fullscreen = false;
536
[email protected]c8d574722017-08-30 20:53:43537 // If we're in overlay mode, then exit it unless we're supposed to allow
538 // overlays all the time.
539 if (!always_enable_overlays_ && overlay_enabled_)
tsunghungee562e92016-07-20 18:03:31540 DisableOverlay();
liberato2ff93ad2017-05-17 07:28:24541
liberatofe8f9692017-06-08 19:17:36542 // See EnteredFullscreen for why we do this.
543 if (!decoder_requires_restart_for_overlay_)
544 MaybeSendOverlayInfoToDecoder();
tsunghungee562e92016-07-20 18:03:31545}
546
Blink Reformat1c4d759e2017-04-09 16:34:54547void WebMediaPlayerImpl::BecameDominantVisibleContent(bool isDominant) {
xjzcdbbe732016-12-03 20:47:42548 if (observer_)
549 observer_->OnBecameDominantVisibleContent(isDominant);
550}
551
Blink Reformat1c4d759e2017-04-09 16:34:54552void WebMediaPlayerImpl::SetIsEffectivelyFullscreen(
François Beaufortad6c5232018-02-26 11:00:44553 blink::WebFullscreenVideoStatus fullscreen_video_status) {
554 delegate_->SetIsEffectivelyFullscreen(delegate_id_, fullscreen_video_status);
zqzhangabc08242017-03-02 16:07:14555}
556
Mounir Lamouri41a79c62017-06-06 12:53:16557void WebMediaPlayerImpl::OnHasNativeControlsChanged(bool has_native_controls) {
558 if (!watch_time_reporter_)
559 return;
560
561 if (has_native_controls)
562 watch_time_reporter_->OnNativeControlsEnabled();
563 else
564 watch_time_reporter_->OnNativeControlsDisabled();
565}
566
Mounir Lamourif9af74e72017-06-19 19:31:45567void WebMediaPlayerImpl::OnDisplayTypeChanged(
568 WebMediaPlayer::DisplayType display_type) {
Mounir Lamouri0484f40a2018-07-25 03:03:26569 if (surface_layer_for_video_enabled_) {
570 vfc_task_runner_->PostTask(
571 FROM_HERE,
572 base::BindOnce(
573 &VideoFrameCompositor::SetForceSubmit,
574 base::Unretained(compositor_.get()),
575 display_type == WebMediaPlayer::DisplayType::kPictureInPicture));
576 }
577
Mounir Lamourif9af74e72017-06-19 19:31:45578 if (!watch_time_reporter_)
579 return;
580
581 switch (display_type) {
582 case WebMediaPlayer::DisplayType::kInline:
583 watch_time_reporter_->OnDisplayTypeInline();
584 break;
585 case WebMediaPlayer::DisplayType::kFullscreen:
586 watch_time_reporter_->OnDisplayTypeFullscreen();
587 break;
588 case WebMediaPlayer::DisplayType::kPictureInPicture:
589 watch_time_reporter_->OnDisplayTypePictureInPicture();
590 break;
591 }
592}
593
[email protected]ef8394c2013-08-21 20:26:30594void WebMediaPlayerImpl::DoLoad(LoadType load_type,
[email protected]180ef242013-11-07 06:50:46595 const blink::WebURL& url,
Takashi Toyoshima2e01e692018-11-16 03:23:27596 CorsMode cors_mode) {
John Chen5b164a02017-11-01 00:36:09597 TRACE_EVENT1("media", "WebMediaPlayerImpl::DoLoad", "id", media_log_->id());
pkastingf5279482016-07-27 02:18:20598 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:43599 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d726eddc2013-07-02 22:25:55600
[email protected]62e5e682013-03-07 23:53:24601 GURL gurl(url);
John Delaneybdcfc2112018-09-18 16:20:23602 ReportMetrics(load_type, gurl, *frame_, media_log_.get());
[email protected]62e5e682013-03-07 23:53:24603
Dan Sanderscd8981c2017-08-31 22:37:02604 // Report poster availability for SRC=.
605 if (load_type == kLoadTypeURL) {
606 if (preload_ == MultibufferDataSource::METADATA) {
607 UMA_HISTOGRAM_BOOLEAN("Media.SRC.PreloadMetaDataHasPoster", has_poster_);
608 } else if (preload_ == MultibufferDataSource::AUTO) {
609 UMA_HISTOGRAM_BOOLEAN("Media.SRC.PreloadAutoHasPoster", has_poster_);
610 }
611 }
612
[email protected]926f8fd2013-04-12 20:27:53613 // Set subresource URL for crash reporting.
Robert Sesekc5e91df2017-12-12 21:11:03614 static base::debug::CrashKeyString* subresource_url =
615 base::debug::AllocateCrashKeyString("subresource_url",
616 base::debug::CrashKeySize::Size256);
617 base::debug::SetCrashKeyString(subresource_url, gurl.spec());
[email protected]926f8fd2013-04-12 20:27:53618
tguilbert75e2bf62017-04-26 20:13:12619 // Used for HLS playback.
620 loaded_url_ = gurl;
tguilbert25a4d112016-10-13 21:56:51621
[email protected]ef8394c2013-08-21 20:26:30622 load_type_ = load_type;
623
Blink Reformat1c4d759e2017-04-09 16:34:54624 SetNetworkState(WebMediaPlayer::kNetworkStateLoading);
625 SetReadyState(WebMediaPlayer::kReadyStateHaveNothing);
626 media_log_->AddEvent(media_log_->CreateLoadEvent(url.GetString().Utf8()));
Dale Curtis3899090ea2018-01-12 00:10:35627 load_start_time_ = base::TimeTicks::Now();
[email protected]d726eddc2013-07-02 22:25:55628
Dale Curtisd131da1e2018-08-30 02:09:53629 media_metrics_provider_->Initialize(load_type == kLoadTypeMediaSource,
630 load_type == kLoadTypeURL
631 ? GetMediaURLScheme(loaded_url_)
632 : mojom::MediaURLScheme::kUnknown);
Dale Curtis74612b72017-12-14 20:56:19633
[email protected]d726eddc2013-07-02 22:25:55634 // Media source pipelines can start immediately.
Blink Reformat1c4d759e2017-04-09 16:34:54635 if (load_type == kLoadTypeMediaSource) {
[email protected]ef8394c2013-08-21 20:26:30636 StartPipeline();
hubbe5f0ad43b2015-12-14 20:57:26637 } else {
John Delaneyb933391602018-10-17 21:50:47638 auto url_data =
Takashi Toyoshima2e01e692018-11-16 03:23:27639 url_index_->GetByUrl(url, static_cast<UrlData::CorsMode>(cors_mode));
John Delaneyb933391602018-10-17 21:50:47640 // Notify |this| of bytes received by the network.
641 url_data->AddBytesReceivedCallback(BindToCurrentLoop(base::BindRepeating(
642 &WebMediaPlayerImpl::OnBytesReceived, AsWeakPtr())));
dalecurtisb6e052f52016-08-25 00:35:55643 data_source_.reset(new MultibufferDataSource(
John Delaneyb933391602018-10-17 21:50:47644 main_task_runner_, std::move(url_data), media_log_.get(),
645 &buffered_data_source_host_,
dalecurtisb6e052f52016-08-25 00:35:55646 base::Bind(&WebMediaPlayerImpl::NotifyDownloading, AsWeakPtr())));
avayvode46d7bef2016-03-30 23:18:26647 data_source_->SetPreload(preload_);
Yoav Weissc34fb0d2018-01-08 05:37:27648 data_source_->SetIsClientAudioElement(client_->IsAudioElement());
avayvode46d7bef2016-03-30 23:18:26649 data_source_->Initialize(
650 base::Bind(&WebMediaPlayerImpl::DataSourceInitialized, AsWeakPtr()));
hubbe5f0ad43b2015-12-14 20:57:26651 }
hubbed5f36882016-01-15 22:40:37652
653#if defined(OS_ANDROID) // WMPI_CAST
dalecurtisbb3eaac2016-01-27 21:10:25654 cast_impl_.Initialize(url, frame_, delegate_id_);
hubbed5f36882016-01-15 22:40:37655#endif
[email protected]62e5e682013-03-07 23:53:24656}
657
Blink Reformat1c4d759e2017-04-09 16:34:54658void WebMediaPlayerImpl::Play() {
pkastingf5279482016-07-27 02:18:20659 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:43660 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53661
avayvod65fad272017-02-24 01:00:48662 // User initiated play unlocks background video playback.
Mustaq Ahmede473e4352017-11-04 01:04:25663 if (blink::WebUserGestureIndicator::IsProcessingUserGesture(frame_))
avayvod65fad272017-02-24 01:00:48664 video_locked_when_paused_when_hidden_ = false;
665
hubbed5f36882016-01-15 22:40:37666#if defined(OS_ANDROID) // WMPI_CAST
Blink Reformat1c4d759e2017-04-09 16:34:54667 if (IsRemote()) {
dalecurtis6e2716d2016-01-21 04:49:15668 cast_impl_.play();
hubbed5f36882016-01-15 22:40:37669 return;
670 }
671#endif
sandersd35d2c3f2017-01-14 02:04:42672 // TODO(sandersd): Do we want to reset the idle timer here?
tguilbert1bb1c782017-01-23 21:15:11673 delegate_->SetIdle(delegate_id_, false);
[email protected]49480902009-07-14 20:23:43674 paused_ = false;
tguilbert350936ff2017-02-24 05:39:27675 pipeline_controller_.SetPlaybackRate(playback_rate_);
dalecurtis4619cd02016-09-22 21:39:10676 background_pause_timer_.Stop();
sandersd1c0bba02016-03-04 23:14:08677
[email protected]039b7542013-10-17 22:06:25678 if (data_source_)
679 data_source_->MediaIsPlaying();
[email protected]090f7312011-08-05 23:26:40680
xjz48a9cb72016-12-20 04:02:49681 if (observer_)
682 observer_->OnPlaying();
683
Mounir Lamouri89c0a1b2018-03-01 15:00:44684 watch_time_reporter_->SetAutoplayInitiated(client_->WasAutoplayInitiated());
685
Dale Curtis051fdf62017-08-05 00:21:13686 // If we're seeking we'll trigger the watch time reporter upon seek completed;
687 // we don't want to start it here since the seek time is unstable. E.g., when
688 // playing content with a positive start time we would have a zero seek time.
689 if (!Seeking()) {
690 DCHECK(watch_time_reporter_);
691 watch_time_reporter_->OnPlaying();
692 }
693
Chris Cunninghamd9df58e2017-08-29 00:04:23694 if (video_decode_stats_reporter_)
695 video_decode_stats_reporter_->OnPlaying();
696
acolwell9e0840d2014-09-06 19:01:32697 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PLAY));
sandersd50a635e2016-04-04 22:50:09698 UpdatePlayState();
[email protected]ec9212f2008-12-18 21:40:36699}
700
Blink Reformat1c4d759e2017-04-09 16:34:54701void WebMediaPlayerImpl::Pause() {
pkastingf5279482016-07-27 02:18:20702 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:43703 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53704
sandersd50a635e2016-04-04 22:50:09705 // We update the paused state even when casting, since we expect pause() to be
706 // called when casting begins, and when we exit casting we should end up in a
707 // paused state.
[email protected]49480902009-07-14 20:23:43708 paused_ = true;
hubbed5f36882016-01-15 22:40:37709
avayvodeb9098d2017-01-07 00:33:03710 // No longer paused because it was hidden.
711 paused_when_hidden_ = false;
712
avayvod65fad272017-02-24 01:00:48713 // User initiated pause locks background videos.
Mustaq Ahmede473e4352017-11-04 01:04:25714 if (blink::WebUserGestureIndicator::IsProcessingUserGesture(frame_))
avayvod65fad272017-02-24 01:00:48715 video_locked_when_paused_when_hidden_ = true;
716
hubbed5f36882016-01-15 22:40:37717#if defined(OS_ANDROID) // WMPI_CAST
Blink Reformat1c4d759e2017-04-09 16:34:54718 if (IsRemote()) {
dalecurtis6e2716d2016-01-21 04:49:15719 cast_impl_.pause();
hubbed5f36882016-01-15 22:40:37720 return;
721 }
722#endif
723
tguilbert350936ff2017-02-24 05:39:27724 pipeline_controller_.SetPlaybackRate(0.0);
Dale Curtisdc5d47c2018-02-15 11:15:19725 paused_time_ = pipeline_controller_.GetMediaTime();
[email protected]090f7312011-08-05 23:26:40726
xjz48a9cb72016-12-20 04:02:49727 if (observer_)
728 observer_->OnPaused();
729
dalecurtis04bdb582016-08-17 22:15:23730 DCHECK(watch_time_reporter_);
731 watch_time_reporter_->OnPaused();
Chris Cunninghamd9df58e2017-08-29 00:04:23732
733 if (video_decode_stats_reporter_)
734 video_decode_stats_reporter_->OnPaused();
735
acolwell9e0840d2014-09-06 19:01:32736 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PAUSE));
avayvod2135a642017-01-13 00:17:14737
sandersd50a635e2016-04-04 22:50:09738 UpdatePlayState();
[email protected]ec9212f2008-12-18 21:40:36739}
740
Blink Reformat1c4d759e2017-04-09 16:34:54741void WebMediaPlayerImpl::Seek(double seconds) {
pkastingf5279482016-07-27 02:18:20742 DVLOG(1) << __func__ << "(" << seconds << "s)";
acolwellb4034942014-08-28 15:42:43743 DCHECK(main_task_runner_->BelongsToCurrentThread());
servolk86b3d88fb2017-03-18 02:50:28744 media_log_->AddEvent(media_log_->CreateSeekEvent(seconds));
sandersd1c0bba02016-03-04 23:14:08745 DoSeek(base::TimeDelta::FromSecondsD(seconds), true);
746}
747
748void WebMediaPlayerImpl::DoSeek(base::TimeDelta time, bool time_updated) {
749 DCHECK(main_task_runner_->BelongsToCurrentThread());
John Chen5b164a02017-11-01 00:36:09750 TRACE_EVENT2("media", "WebMediaPlayerImpl::DoSeek", "target",
751 time.InSecondsF(), "id", media_log_->id());
[email protected]d43ed912009-02-03 04:52:53752
hubbed5f36882016-01-15 22:40:37753#if defined(OS_ANDROID) // WMPI_CAST
Blink Reformat1c4d759e2017-04-09 16:34:54754 if (IsRemote()) {
sandersd1c0bba02016-03-04 23:14:08755 cast_impl_.seek(time);
hubbed5f36882016-01-15 22:40:37756 return;
757 }
758#endif
759
srirama.mccf671812015-01-08 11:59:13760 ReadyState old_state = ready_state_;
Blink Reformat1c4d759e2017-04-09 16:34:54761 if (ready_state_ > WebMediaPlayer::kReadyStateHaveMetadata)
762 SetReadyState(WebMediaPlayer::kReadyStateHaveMetadata);
[email protected]1bb666802013-11-28 06:12:08763
Dale Curtis051fdf62017-08-05 00:21:13764 // When paused or ended, we know exactly what the current time is and can
765 // elide seeks to it. However, there are two cases that are not elided:
sandersd1c0bba02016-03-04 23:14:08766 // 1) When the pipeline state is not stable.
767 // In this case we just let |pipeline_controller_| decide what to do, as
768 // it has complete information.
769 // 2) For MSE.
770 // Because the buffers may have changed between seeks, MSE seeks are
771 // never elided.
Dale Curtis051fdf62017-08-05 00:21:13772 if (paused_ && pipeline_controller_.IsStable() &&
773 (paused_time_ == time ||
774 (ended_ && time == base::TimeDelta::FromSecondsD(Duration()))) &&
sandersd1c0bba02016-03-04 23:14:08775 !chunk_demuxer_) {
776 // If the ready state was high enough before, we can indicate that the seek
777 // completed just by restoring it. Otherwise we will just wait for the real
778 // ready state change to eventually happen.
Blink Reformat1c4d759e2017-04-09 16:34:54779 if (old_state == kReadyStateHaveEnoughData) {
srirama.m8f4a37562014-12-13 08:16:18780 main_task_runner_->PostTask(
Dale Curtisee9be30012018-09-21 22:21:51781 FROM_HERE, base::BindOnce(&WebMediaPlayerImpl::OnBufferingStateChange,
782 AsWeakPtr(), BUFFERING_HAVE_ENOUGH));
srirama.m36ab2682014-12-11 04:20:01783 }
sandersd1c0bba02016-03-04 23:14:08784 return;
srirama.m36ab2682014-12-11 04:20:01785 }
[email protected]44ff37c02009-10-24 01:03:03786
dalecurtis04bdb582016-08-17 22:15:23787 // Call this before setting |seeking_| so that the current media time can be
788 // recorded by the reporter.
789 if (watch_time_reporter_)
790 watch_time_reporter_->OnSeeking();
791
dalecurtis1af3c1a2017-04-11 00:53:49792 // Clear any new frame processed callbacks on seek; otherwise we'll end up
793 // logging a time long after the seek completes.
794 frame_time_report_cb_.Cancel();
795
sandersd35d2c3f2017-01-14 02:04:42796 // TODO(sandersd): Move |seeking_| to PipelineController.
797 // TODO(sandersd): Do we want to reset the idle timer here?
tguilbert1bb1c782017-01-23 21:15:11798 delegate_->SetIdle(delegate_id_, false);
sandersd50a635e2016-04-04 22:50:09799 ended_ = false;
[email protected]b3766a22010-12-22 17:34:13800 seeking_ = true;
sandersd1c0bba02016-03-04 23:14:08801 seek_time_ = time;
802 if (paused_)
803 paused_time_ = time;
804 pipeline_controller_.Seek(time, time_updated);
[email protected]b3766a22010-12-22 17:34:13805
sandersd50a635e2016-04-04 22:50:09806 // This needs to be called after Seek() so that if a resume is triggered, it
807 // is to the correct time.
808 UpdatePlayState();
[email protected]ec9212f2008-12-18 21:40:36809}
810
Blink Reformat1c4d759e2017-04-09 16:34:54811void WebMediaPlayerImpl::SetRate(double rate) {
pkastingf5279482016-07-27 02:18:20812 DVLOG(1) << __func__ << "(" << rate << ")";
acolwellb4034942014-08-28 15:42:43813 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53814
Matt Wolenetz6010f6c2017-10-18 00:44:36815 if (rate != playback_rate_) {
816 LIMITED_MEDIA_LOG(INFO, media_log_.get(), num_playback_rate_logs_,
817 kMaxNumPlaybackRateLogs)
818 << "Effective playback rate changed from " << playback_rate_ << " to "
819 << rate;
820 }
821
[email protected]49480902009-07-14 20:23:43822 playback_rate_ = rate;
823 if (!paused_) {
tguilbert350936ff2017-02-24 05:39:27824 pipeline_controller_.SetPlaybackRate(rate);
[email protected]039b7542013-10-17 22:06:25825 if (data_source_)
826 data_source_->MediaPlaybackRateChanged(rate);
[email protected]49480902009-07-14 20:23:43827 }
[email protected]ec9212f2008-12-18 21:40:36828}
829
Blink Reformat1c4d759e2017-04-09 16:34:54830void WebMediaPlayerImpl::SetVolume(double volume) {
pkastingf5279482016-07-27 02:18:20831 DVLOG(1) << __func__ << "(" << volume << ")";
acolwellb4034942014-08-28 15:42:43832 DCHECK(main_task_runner_->BelongsToCurrentThread());
dalecurtisbb3eaac2016-01-27 21:10:25833 volume_ = volume;
tguilbert350936ff2017-02-24 05:39:27834 pipeline_controller_.SetVolume(volume_ * volume_multiplier_);
dalecurtis04bdb582016-08-17 22:15:23835 if (watch_time_reporter_)
836 watch_time_reporter_->OnVolumeChange(volume);
Becca Hughes9f6fd4b82017-06-15 10:01:40837 delegate_->DidPlayerMutedStatusChange(delegate_id_, volume == 0.0);
mlamouri910111362016-11-04 11:28:24838
839 // The play state is updated because the player might have left the autoplay
840 // muted state.
841 UpdatePlayState();
[email protected]ec9212f2008-12-18 21:40:36842}
[email protected]f0a51fb52009-03-05 12:46:38843
François Beaufort9290aab2018-05-07 21:18:47844void WebMediaPlayerImpl::EnterPictureInPicture(
Mounir Lamouri917143af2018-05-24 21:19:57845 blink::WebMediaPlayer::PipWindowOpenedCallback callback) {
[email protected]69db58f2018-09-26 20:27:56846 if (!surface_layer_for_video_enabled_)
847 ActivateSurfaceLayerForVideo();
848
Mounir Lamourib642a3c2018-07-09 15:45:31849 DCHECK(bridge_);
Mounir Lamouri37e8ae82018-05-31 02:38:46850
Mounir Lamourib642a3c2018-07-09 15:45:31851 const viz::SurfaceId& surface_id = bridge_->GetSurfaceId();
852 DCHECK(surface_id.is_valid());
Jennifer Apaciblec45fd052018-02-25 12:04:55853
Mounir Lamouri11e9ef42018-05-22 03:10:16854 // Notifies the browser process that the player should now be in
855 // Picture-in-Picture mode.
François Beauforta22026d2018-09-25 08:51:11856 delegate_->DidPictureInPictureModeStart(
857 delegate_id_, surface_id, pipeline_metadata_.natural_size,
François Beaufortbb68c43e2018-11-20 20:12:03858 std::move(callback), ShouldShowPlayPauseButtonInPictureInPictureWindow());
Jennifer Apacible3f0489102018-01-19 20:10:31859}
860
François Beaufort9290aab2018-05-07 21:18:47861void WebMediaPlayerImpl::ExitPictureInPicture(
862 blink::WebMediaPlayer::PipWindowClosedCallback callback) {
Mounir Lamouri6d759e12018-05-16 20:01:30863 // Notifies the browser process that Picture-in-Picture has ended. It will
864 // clear out the states and close the window.
865 delegate_->DidPictureInPictureModeEnd(delegate_id_, std::move(callback));
Jennifer Apacible02897b72018-04-01 01:00:49866
Mounir Lamouri6d759e12018-05-16 20:01:30867 // Internal cleanups.
Jennifer Apacible5cd9a7e2018-04-17 03:08:06868 OnPictureInPictureModeEnded();
Jennifer Apacible02897b72018-04-01 01:00:49869}
870
sawtellee19d11aa2018-08-10 03:47:50871void WebMediaPlayerImpl::SetPictureInPictureCustomControls(
872 const std::vector<blink::PictureInPictureControlInfo>& controls) {
873 delegate_->DidSetPictureInPictureCustomControls(delegate_id_, controls);
874}
875
Mounir Lamouri917143af2018-05-24 21:19:57876void WebMediaPlayerImpl::RegisterPictureInPictureWindowResizeCallback(
877 blink::WebMediaPlayer::PipWindowResizedCallback callback) {
Mounir Lamouri0484f40a2018-07-25 03:03:26878 DCHECK(IsInPictureInPicture() && !client_->IsInAutoPIP());
Mounir Lamouri917143af2018-05-24 21:19:57879
880 delegate_->RegisterPictureInPictureWindowResizeCallback(delegate_id_,
881 std::move(callback));
882}
883
Daniel Chengc1710b52018-10-24 03:12:28884void WebMediaPlayerImpl::SetSinkId(
885 const blink::WebString& sink_id,
886 std::unique_ptr<blink::WebSetSinkIdCallbacks> web_callback) {
guidou69223ce2015-06-16 10:36:19887 DCHECK(main_task_runner_->BelongsToCurrentThread());
pkastingf5279482016-07-27 02:18:20888 DVLOG(1) << __func__;
guidouc7babef2015-10-22 00:42:35889
olka68b69392016-04-01 11:42:12890 media::OutputDeviceStatusCB callback =
Daniel Chengc1710b52018-10-24 03:12:28891 media::ConvertToOutputDeviceStatusCB(std::move(web_callback));
guidouc7babef2015-10-22 00:42:35892 media_task_runner_->PostTask(
Dale Curtisee9be30012018-09-21 22:21:51893 FROM_HERE, base::BindOnce(&SetSinkIdOnMediaThread, audio_source_provider_,
Daniel Chengc1710b52018-10-24 03:12:28894 sink_id.Utf8(), std::move(callback)));
guidou69223ce2015-06-16 10:36:19895}
896
Blink Reformat1c4d759e2017-04-09 16:34:54897STATIC_ASSERT_ENUM(WebMediaPlayer::kPreloadNone, MultibufferDataSource::NONE);
898STATIC_ASSERT_ENUM(WebMediaPlayer::kPreloadMetaData,
dalecurtisb6e052f52016-08-25 00:35:55899 MultibufferDataSource::METADATA);
Blink Reformat1c4d759e2017-04-09 16:34:54900STATIC_ASSERT_ENUM(WebMediaPlayer::kPreloadAuto, MultibufferDataSource::AUTO);
[email protected]23a8b1d82011-04-05 16:28:20901
Blink Reformat1c4d759e2017-04-09 16:34:54902void WebMediaPlayerImpl::SetPreload(WebMediaPlayer::Preload preload) {
pkastingf5279482016-07-27 02:18:20903 DVLOG(1) << __func__ << "(" << preload << ")";
acolwellb4034942014-08-28 15:42:43904 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]4e6be3f2009-05-07 02:24:44905
dalecurtisb6e052f52016-08-25 00:35:55906 preload_ = static_cast<MultibufferDataSource::Preload>(preload);
[email protected]b49beeb2013-03-01 20:04:00907 if (data_source_)
[email protected]09c60222014-08-07 16:42:31908 data_source_->SetPreload(preload_);
[email protected]4e6be3f2009-05-07 02:24:44909}
910
Blink Reformat1c4d759e2017-04-09 16:34:54911bool WebMediaPlayerImpl::HasVideo() const {
acolwellb4034942014-08-28 15:42:43912 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53913
[email protected]b8877772014-03-26 20:17:15914 return pipeline_metadata_.has_video;
[email protected]d43ed912009-02-03 04:52:53915}
916
Blink Reformat1c4d759e2017-04-09 16:34:54917bool WebMediaPlayerImpl::HasAudio() const {
acolwellb4034942014-08-28 15:42:43918 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]fc367af2009-08-14 23:06:35919
[email protected]b8877772014-03-26 20:17:15920 return pipeline_metadata_.has_audio;
[email protected]fc367af2009-08-14 23:06:35921}
922
Blink Reformat1c4d759e2017-04-09 16:34:54923void WebMediaPlayerImpl::EnabledAudioTracksChanged(
servolkf25ceed2016-07-01 03:44:38924 const blink::WebVector<blink::WebMediaPlayer::TrackId>& enabledTrackIds) {
925 DCHECK(main_task_runner_->BelongsToCurrentThread());
926
927 std::ostringstream logstr;
928 std::vector<MediaTrack::Id> enabledMediaTrackIds;
929 for (const auto& blinkTrackId : enabledTrackIds) {
Blink Reformat1c4d759e2017-04-09 16:34:54930 MediaTrack::Id track_id = blinkTrackId.Utf8().data();
servolkf25ceed2016-07-01 03:44:38931 logstr << track_id << " ";
932 enabledMediaTrackIds.push_back(track_id);
933 }
dalecurtis9cddc0b2017-04-19 21:23:38934 MEDIA_LOG(INFO, media_log_.get())
935 << "Enabled audio tracks: [" << logstr.str() << "]";
tguilbert350936ff2017-02-24 05:39:27936 pipeline_controller_.OnEnabledAudioTracksChanged(enabledMediaTrackIds);
servolkf25ceed2016-07-01 03:44:38937}
938
Blink Reformat1c4d759e2017-04-09 16:34:54939void WebMediaPlayerImpl::SelectedVideoTrackChanged(
servolkf25ceed2016-07-01 03:44:38940 blink::WebMediaPlayer::TrackId* selectedTrackId) {
941 DCHECK(main_task_runner_->BelongsToCurrentThread());
942
servolk9bed6602017-02-24 01:20:11943 base::Optional<MediaTrack::Id> selected_video_track_id;
944 if (selectedTrackId && !video_track_disabled_)
Blink Reformat1c4d759e2017-04-09 16:34:54945 selected_video_track_id = MediaTrack::Id(selectedTrackId->Utf8().data());
dalecurtis9cddc0b2017-04-19 21:23:38946 MEDIA_LOG(INFO, media_log_.get())
947 << "Selected video track: [" << selected_video_track_id.value_or("")
948 << "]";
tguilbert350936ff2017-02-24 05:39:27949 pipeline_controller_.OnSelectedVideoTrackChanged(selected_video_track_id);
servolkf25ceed2016-07-01 03:44:38950}
951
Blink Reformat1c4d759e2017-04-09 16:34:54952blink::WebSize WebMediaPlayerImpl::NaturalSize() const {
acolwellb4034942014-08-28 15:42:43953 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53954
[email protected]b8877772014-03-26 20:17:15955 return blink::WebSize(pipeline_metadata_.natural_size);
[email protected]d43ed912009-02-03 04:52:53956}
957
Jiajia Qin82acdc02017-07-31 09:55:14958blink::WebSize WebMediaPlayerImpl::VisibleRect() const {
959 DCHECK(main_task_runner_->BelongsToCurrentThread());
960 scoped_refptr<VideoFrame> video_frame = GetCurrentFrameFromCompositor();
961 if (!video_frame)
962 return blink::WebSize();
963
964 const gfx::Rect& visible_rect = video_frame->visible_rect();
965 return blink::WebSize(visible_rect.width(), visible_rect.height());
966}
967
Blink Reformat1c4d759e2017-04-09 16:34:54968bool WebMediaPlayerImpl::Paused() const {
acolwellb4034942014-08-28 15:42:43969 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53970
hubbed5f36882016-01-15 22:40:37971#if defined(OS_ANDROID) // WMPI_CAST
Blink Reformat1c4d759e2017-04-09 16:34:54972 if (IsRemote())
danakj4f1fd6a2017-01-06 21:15:17973 return cast_impl_.IsPaused();
hubbed5f36882016-01-15 22:40:37974#endif
sandersd50a635e2016-04-04 22:50:09975
tguilbert350936ff2017-02-24 05:39:27976 return pipeline_controller_.GetPlaybackRate() == 0.0f;
[email protected]d43ed912009-02-03 04:52:53977}
978
Blink Reformat1c4d759e2017-04-09 16:34:54979bool WebMediaPlayerImpl::Seeking() const {
acolwellb4034942014-08-28 15:42:43980 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53981
Blink Reformat1c4d759e2017-04-09 16:34:54982 if (ready_state_ == WebMediaPlayer::kReadyStateHaveNothing)
[email protected]0acebfa2009-08-21 22:45:40983 return false;
[email protected]67cd5052009-09-10 21:53:22984
[email protected]b3766a22010-12-22 17:34:13985 return seeking_;
[email protected]ec9212f2008-12-18 21:40:36986}
987
Blink Reformat1c4d759e2017-04-09 16:34:54988double WebMediaPlayerImpl::Duration() const {
acolwellb4034942014-08-28 15:42:43989 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]39bdde32013-04-17 17:44:20990
Blink Reformat1c4d759e2017-04-09 16:34:54991 if (ready_state_ == WebMediaPlayer::kReadyStateHaveNothing)
[email protected]39bdde32013-04-17 17:44:20992 return std::numeric_limits<double>::quiet_NaN();
993
chcunninghamb92d5062017-01-10 21:50:22994 // Use duration from ChunkDemuxer when present. MSE allows users to specify
995 // duration as a double. This propagates to the rest of the pipeline as a
996 // TimeDelta with potentially reduced precision (limited to Microseconds).
997 // ChunkDemuxer returns the full-precision user-specified double. This ensures
998 // users can "get" the exact duration they "set".
999 if (chunk_demuxer_)
1000 return chunk_demuxer_->GetDuration();
1001
avayvodcc273dd2017-01-19 19:35:121002 base::TimeDelta pipeline_duration = GetPipelineMediaDuration();
chcunninghamb92d5062017-01-10 21:50:221003 return pipeline_duration == kInfiniteDuration
1004 ? std::numeric_limits<double>::infinity()
1005 : pipeline_duration.InSecondsF();
[email protected]d43ed912009-02-03 04:52:531006}
1007
[email protected]db66d0092014-04-16 07:15:121008double WebMediaPlayerImpl::timelineOffset() const {
acolwellb4034942014-08-28 15:42:431009 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]db66d0092014-04-16 07:15:121010
1011 if (pipeline_metadata_.timeline_offset.is_null())
1012 return std::numeric_limits<double>::quiet_NaN();
1013
1014 return pipeline_metadata_.timeline_offset.ToJsTime();
1015}
1016
Dale Curtis051fdf62017-08-05 00:21:131017base::TimeDelta WebMediaPlayerImpl::GetCurrentTimeInternal() const {
1018 DCHECK(main_task_runner_->BelongsToCurrentThread());
1019 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
1020
1021 base::TimeDelta current_time;
1022 if (Seeking())
1023 current_time = seek_time_;
1024#if defined(OS_ANDROID) // WMPI_CAST
1025 else if (IsRemote())
1026 current_time = cast_impl_.currentTime();
1027#endif
1028 else if (paused_)
1029 current_time = paused_time_;
1030 else
1031 current_time = pipeline_controller_.GetMediaTime();
1032
1033 DCHECK_NE(current_time, kInfiniteDuration);
1034 DCHECK_GE(current_time, base::TimeDelta());
1035 return current_time;
1036}
1037
Blink Reformat1c4d759e2017-04-09 16:34:541038double WebMediaPlayerImpl::CurrentTime() const {
acolwellb4034942014-08-28 15:42:431039 DCHECK(main_task_runner_->BelongsToCurrentThread());
Blink Reformat1c4d759e2017-04-09 16:34:541040 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
scherkusd2c745b2014-09-04 05:03:401041
1042 // TODO(scherkus): Replace with an explicit ended signal to HTMLMediaElement,
1043 // see http://crbug.com/409280
Dale Curtis051fdf62017-08-05 00:21:131044 // Note: Duration() may be infinity.
josephlolak918863bc2017-11-15 08:54:331045 return (ended_ && !std::isinf(Duration()))
1046 ? Duration()
1047 : GetCurrentTimeInternal().InSecondsF();
[email protected]d43ed912009-02-03 04:52:531048}
1049
Blink Reformat1c4d759e2017-04-09 16:34:541050WebMediaPlayer::NetworkState WebMediaPlayerImpl::GetNetworkState() const {
acolwellb4034942014-08-28 15:42:431051 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]ddb1e5a2010-12-13 20:10:451052 return network_state_;
1053}
1054
Blink Reformat1c4d759e2017-04-09 16:34:541055WebMediaPlayer::ReadyState WebMediaPlayerImpl::GetReadyState() const {
acolwellb4034942014-08-28 15:42:431056 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]ddb1e5a2010-12-13 20:10:451057 return ready_state_;
1058}
1059
CJ DiMeglio89240472018-10-18 18:21:101060blink::WebMediaPlayer::SurfaceLayerMode
1061WebMediaPlayerImpl::GetVideoSurfaceLayerMode() const {
1062 return surface_layer_mode_;
1063}
1064
wolenetzed8e7092017-04-21 16:28:591065blink::WebString WebMediaPlayerImpl::GetErrorMessage() const {
wolenetz4d39cc02016-04-05 19:54:411066 DCHECK(main_task_runner_->BelongsToCurrentThread());
wolenetzed8e7092017-04-21 16:28:591067 return blink::WebString::FromUTF8(media_log_->GetErrorMessage());
wolenetz4d39cc02016-04-05 19:54:411068}
1069
Blink Reformat1c4d759e2017-04-09 16:34:541070blink::WebTimeRanges WebMediaPlayerImpl::Buffered() const {
acolwellb4034942014-08-28 15:42:431071 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]779a8322014-08-22 21:28:371072
acolwell9e0840d2014-09-06 19:01:321073 Ranges<base::TimeDelta> buffered_time_ranges =
tguilbert350936ff2017-02-24 05:39:271074 pipeline_controller_.GetBufferedTimeRanges();
[email protected]779a8322014-08-22 21:28:371075
avayvodcc273dd2017-01-19 19:35:121076 const base::TimeDelta duration = GetPipelineMediaDuration();
dalecurtis39a7f932016-07-19 18:34:591077 if (duration != kInfiniteDuration) {
tguilbert350936ff2017-02-24 05:39:271078 buffered_data_source_host_.AddBufferedTimeRanges(&buffered_time_ranges,
1079 duration);
[email protected]779a8322014-08-22 21:28:371080 }
[email protected]02022fc2014-05-16 00:05:311081 return ConvertToWebTimeRanges(buffered_time_ranges);
1082}
1083
Blink Reformat1c4d759e2017-04-09 16:34:541084blink::WebTimeRanges WebMediaPlayerImpl::Seekable() const {
acolwellb4034942014-08-28 15:42:431085 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]39bdde32013-04-17 17:44:201086
Blink Reformat1c4d759e2017-04-09 16:34:541087 if (ready_state_ < WebMediaPlayer::kReadyStateHaveMetadata)
philipjb0e6f3f2014-09-30 09:51:531088 return blink::WebTimeRanges();
1089
Blink Reformat1c4d759e2017-04-09 16:34:541090 const double seekable_end = Duration();
dalecurtis56359cb2014-10-28 00:06:291091
1092 // Allow a special exception for seeks to zero for streaming sources with a
1093 // finite duration; this allows looping to work.
tguilbertade2bcb2017-01-07 02:57:451094 const bool is_finite_stream = data_source_ && data_source_->IsStreaming() &&
1095 std::isfinite(seekable_end);
1096
tguilbert75e2bf62017-04-26 20:13:121097 // Do not change the seekable range when using the MediaPlayerRenderer. It
1098 // will take care of dropping invalid seeks.
1099 const bool force_seeks_to_zero =
1100 !using_media_player_renderer_ && is_finite_stream;
dalecurtis56359cb2014-10-28 00:06:291101
1102 // TODO(dalecurtis): Technically this allows seeking on media which return an
tguilbertade2bcb2017-01-07 02:57:451103 // infinite duration so long as DataSource::IsStreaming() is false. While not
dalecurtis56359cb2014-10-28 00:06:291104 // expected, disabling this breaks semi-live players, http://crbug.com/427412.
1105 const blink::WebTimeRange seekable_range(
tguilbertade2bcb2017-01-07 02:57:451106 0.0, force_seeks_to_zero ? 0.0 : seekable_end);
philipjb0e6f3f2014-09-30 09:51:531107 return blink::WebTimeRanges(&seekable_range, 1);
[email protected]ec9212f2008-12-18 21:40:361108}
1109
sandersd35d2c3f2017-01-14 02:04:421110bool WebMediaPlayerImpl::IsPrerollAttemptNeeded() {
1111 // TODO(sandersd): Replace with |highest_ready_state_since_seek_| if we need
1112 // to ensure that preroll always gets a chance to complete.
1113 // See http://crbug.com/671525.
Blink Reformat1c4d759e2017-04-09 16:34:541114 if (highest_ready_state_ >= ReadyState::kReadyStateHaveFutureData)
sandersd35d2c3f2017-01-14 02:04:421115 return false;
1116
Fredrik Hubinette4cfb4412017-08-23 00:03:071117 // To suspend before we reach kReadyStateHaveCurrentData is only ok
1118 // if we know we're going to get woken up when we get more data, which
1119 // will only happen if the network is in the "Loading" state.
1120 // This happens when the network is fast, but multiple videos are loading
1121 // and multiplexing gets held up waiting for available threads.
1122 if (highest_ready_state_ <= ReadyState::kReadyStateHaveMetadata &&
1123 network_state_ != WebMediaPlayer::kNetworkStateLoading) {
1124 return true;
1125 }
1126
sandersd35d2c3f2017-01-14 02:04:421127 if (preroll_attempt_pending_)
1128 return true;
1129
1130 // Freshly initialized; there has never been any loading progress. (Otherwise
1131 // |preroll_attempt_pending_| would be true when the start time is null.)
1132 if (preroll_attempt_start_time_.is_null())
1133 return false;
1134
1135 base::TimeDelta preroll_attempt_duration =
1136 tick_clock_->NowTicks() - preroll_attempt_start_time_;
1137 return preroll_attempt_duration < kPrerollAttemptTimeout;
1138}
1139
Blink Reformat1c4d759e2017-04-09 16:34:541140bool WebMediaPlayerImpl::DidLoadingProgress() {
acolwellb4034942014-08-28 15:42:431141 DCHECK(main_task_runner_->BelongsToCurrentThread());
dalecurtise7120dc2016-09-03 02:54:351142
1143 // Note: Separate variables used to ensure both methods are called every time.
tguilbert350936ff2017-02-24 05:39:271144 const bool pipeline_progress = pipeline_controller_.DidLoadingProgress();
dalecurtise7120dc2016-09-03 02:54:351145 const bool data_progress = buffered_data_source_host_.DidLoadingProgress();
hubbeb2d3efd2017-05-05 23:26:381146 return pipeline_progress || data_progress;
[email protected]d43ed912009-02-03 04:52:531147}
1148
danakjff6a0262018-06-26 19:50:311149void WebMediaPlayerImpl::Paint(cc::PaintCanvas* canvas,
[email protected]dd5c7972014-08-21 15:00:371150 const blink::WebRect& rect,
Kai Ninomiya9e8ae29b2017-09-06 23:45:161151 cc::PaintFlags& flags,
1152 int already_uploaded_id,
1153 VideoFrameUploadMetadata* out_metadata) {
acolwellb4034942014-08-28 15:42:431154 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]dd061e12014-05-06 19:21:221155 TRACE_EVENT0("media", "WebMediaPlayerImpl:paint");
[email protected]4e6be3f2009-05-07 02:24:441156
watkd16bb3e2017-04-25 01:18:311157 // We can't copy from protected frames.
Xiaohan Wang24cfe2c2018-01-22 23:16:001158 if (cdm_context_ref_)
xhwang80739452016-01-13 00:48:001159 return;
1160
mcasasf1236fc22015-05-29 22:38:561161 scoped_refptr<VideoFrame> video_frame = GetCurrentFrameFromCompositor();
[email protected]0fe5d43b2014-01-24 23:32:451162
[email protected]b49beeb2013-03-01 20:04:001163 gfx::Rect gfx_rect(rect);
dongseong.hwang0c4e9d82015-01-08 20:11:131164 Context3D context_3d;
Dan Sanders930cc1d2018-10-03 00:45:081165 gpu::ContextSupport* context_support = nullptr;
mcasas265bdbf82015-06-12 18:44:071166 if (video_frame.get() && video_frame->HasTextures()) {
CJ DiMeglioc60a5cf2017-09-27 20:08:411167 if (context_provider_) {
1168 context_3d = Context3D(context_provider_->ContextGL(),
1169 context_provider_->GrContext());
Dan Sanders930cc1d2018-10-03 00:45:081170 context_support = context_provider_->ContextSupport();
CJ DiMeglioc60a5cf2017-09-27 20:08:411171 }
dongseong.hwang0c4e9d82015-01-08 20:11:131172 if (!context_3d.gl)
danakj53f7ec902016-05-21 01:30:101173 return; // Unable to get/create a shared main thread context.
1174 if (!context_3d.gr_context)
1175 return; // The context has been lost since and can't setup a GrContext.
dongseong.hwang0c4e9d82015-01-08 20:11:131176 }
Kai Ninomiyaef8c9e02017-09-27 04:07:401177 if (out_metadata && video_frame) {
Kai Ninomiya9e8ae29b2017-09-06 23:45:161178 // WebGL last-uploaded-frame-metadata API enabled. https://crbug.com/639174
1179 ComputeFrameUploadMetadata(video_frame.get(), already_uploaded_id,
1180 out_metadata);
1181 if (out_metadata->skipped) {
1182 // Skip uploading this frame.
1183 return;
1184 }
1185 }
zhuoyu.qian4689dde22017-10-16 04:11:481186 video_renderer_.Paint(
Julien Isorce6c83d8de2017-10-12 13:11:291187 video_frame, canvas, gfx::RectF(gfx_rect), flags,
Dan Sanders930cc1d2018-10-03 00:45:081188 pipeline_metadata_.video_decoder_config.video_rotation(), context_3d,
1189 context_support);
[email protected]ec9212f2008-12-18 21:40:361190}
[email protected]5df51652009-01-17 00:03:001191
Yutaka Hirano657a0552018-11-09 00:52:551192bool WebMediaPlayerImpl::WouldTaintOrigin() const {
Thomas Guilbert153f84572018-07-19 05:03:581193 if (demuxer_found_hls_) {
1194 // HLS manifests might pull segments from a different origin. We can't know
1195 // for sure, so we conservatively say no here.
Yutaka Hiranoa9cbaa72018-10-10 08:35:221196 return true;
1197 }
1198
Yutaka Hirano657a0552018-11-09 00:52:551199 if (!data_source_)
1200 return false;
1201
1202 // When the resource is redirected to another origin we think it as
1203 // tainted. This is actually not specified, and is under discussion.
1204 // See https://github.com/whatwg/fetch/issues/737.
1205 if (!data_source_->HasSingleOrigin() &&
1206 data_source_->cors_mode() == UrlData::CORS_UNSPECIFIED) {
1207 return true;
1208 }
1209
1210 return data_source_->IsCorsCrossOrigin();
[email protected]3fe27112012-06-07 04:00:011211}
1212
Blink Reformat1c4d759e2017-04-09 16:34:541213double WebMediaPlayerImpl::MediaTimeForTimeValue(double timeValue) const {
qinminb4c39782015-08-10 18:43:241214 return base::TimeDelta::FromSecondsD(timeValue).InSecondsF();
[email protected]e06e16d82011-05-26 22:13:331215}
1216
Blink Reformat1c4d759e2017-04-09 16:34:541217unsigned WebMediaPlayerImpl::DecodedFrameCount() const {
acolwellb4034942014-08-28 15:42:431218 DCHECK(main_task_runner_->BelongsToCurrentThread());
Dale Curtisc7d2a7d22018-01-11 20:01:051219 return GetPipelineStatistics().video_frames_decoded;
[email protected]4c51bc662011-02-16 02:03:161220}
1221
Blink Reformat1c4d759e2017-04-09 16:34:541222unsigned WebMediaPlayerImpl::DroppedFrameCount() const {
acolwellb4034942014-08-28 15:42:431223 DCHECK(main_task_runner_->BelongsToCurrentThread());
Dale Curtisc7d2a7d22018-01-11 20:01:051224 return GetPipelineStatistics().video_frames_dropped;
[email protected]4c51bc662011-02-16 02:03:161225}
1226
Dave Tapuska6c7154912018-07-30 20:39:001227uint64_t WebMediaPlayerImpl::AudioDecodedByteCount() const {
acolwellb4034942014-08-28 15:42:431228 DCHECK(main_task_runner_->BelongsToCurrentThread());
Dale Curtisc7d2a7d22018-01-11 20:01:051229 return GetPipelineStatistics().audio_bytes_decoded;
[email protected]4c51bc662011-02-16 02:03:161230}
1231
Dave Tapuska6c7154912018-07-30 20:39:001232uint64_t WebMediaPlayerImpl::VideoDecodedByteCount() const {
acolwellb4034942014-08-28 15:42:431233 DCHECK(main_task_runner_->BelongsToCurrentThread());
Dale Curtisc7d2a7d22018-01-11 20:01:051234 return GetPipelineStatistics().video_bytes_decoded;
[email protected]4c51bc662011-02-16 02:03:161235}
1236
Blink Reformat1c4d759e2017-04-09 16:34:541237bool WebMediaPlayerImpl::CopyVideoTextureToPlatformTexture(
danakj46070b02016-03-28 21:54:111238 gpu::gles2::GLES2Interface* gl,
jiajia.qinc2943162017-05-12 01:34:391239 unsigned int target,
zmo57d577a2015-10-30 18:28:591240 unsigned int texture,
kbr0986e622017-04-13 02:34:581241 unsigned internal_format,
1242 unsigned format,
1243 unsigned type,
jiajia.qinc2943162017-05-12 01:34:391244 int level,
zmo57d577a2015-10-30 18:28:591245 bool premultiply_alpha,
Kai Ninomiya9e8ae29b2017-09-06 23:45:161246 bool flip_y,
1247 int already_uploaded_id,
1248 VideoFrameUploadMetadata* out_metadata) {
xhwang213e50c2016-10-10 23:56:311249 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]bfc05f22013-10-19 17:55:161250 TRACE_EVENT0("media", "WebMediaPlayerImpl:copyVideoTextureToPlatformTexture");
1251
watkd16bb3e2017-04-25 01:18:311252 // We can't copy from protected frames.
Xiaohan Wang24cfe2c2018-01-22 23:16:001253 if (cdm_context_ref_)
xhwang213e50c2016-10-10 23:56:311254 return false;
[email protected]dd061e12014-05-06 19:21:221255
xhwang213e50c2016-10-10 23:56:311256 scoped_refptr<VideoFrame> video_frame = GetCurrentFrameFromCompositor();
jbauman581d041c2016-07-21 01:01:031257 if (!video_frame.get() || !video_frame->HasTextures()) {
[email protected]e56f88c72013-06-25 22:31:291258 return false;
dongseong.hwang0c4e9d82015-01-08 20:11:131259 }
Kai Ninomiya9e8ae29b2017-09-06 23:45:161260 if (out_metadata) {
1261 // WebGL last-uploaded-frame-metadata API is enabled.
1262 // https://crbug.com/639174
1263 ComputeFrameUploadMetadata(video_frame.get(), already_uploaded_id,
1264 out_metadata);
1265 if (out_metadata->skipped) {
1266 // Skip uploading this frame.
1267 return true;
1268 }
1269 }
[email protected]df41e252014-02-03 23:39:501270
jbauman581d041c2016-07-21 01:01:031271 Context3D context_3d;
Dan Sanders930cc1d2018-10-03 00:45:081272 gpu::ContextSupport* context_support = nullptr;
CJ DiMeglioc60a5cf2017-09-27 20:08:411273 if (context_provider_) {
1274 context_3d = Context3D(context_provider_->ContextGL(),
1275 context_provider_->GrContext());
Dan Sanders930cc1d2018-10-03 00:45:081276 context_support = context_provider_->ContextSupport();
CJ DiMeglioc60a5cf2017-09-27 20:08:411277 }
zhuoyu.qian4689dde22017-10-16 04:11:481278 return video_renderer_.CopyVideoFrameTexturesToGLTexture(
Dan Sanders930cc1d2018-10-03 00:45:081279 context_3d, context_support, gl, video_frame.get(), target, texture,
1280 internal_format, format, type, level, premultiply_alpha, flip_y);
[email protected]6523b242013-03-13 11:10:071281}
1282
Matt Wolenetz95af6362018-01-04 20:23:421283// static
Kai Ninomiya9e8ae29b2017-09-06 23:45:161284void WebMediaPlayerImpl::ComputeFrameUploadMetadata(
1285 VideoFrame* frame,
1286 int already_uploaded_id,
1287 VideoFrameUploadMetadata* out_metadata) {
1288 DCHECK(out_metadata);
Kai Ninomiyaef8c9e02017-09-27 04:07:401289 DCHECK(frame);
Kai Ninomiya9e8ae29b2017-09-06 23:45:161290 out_metadata->frame_id = frame->unique_id();
1291 out_metadata->visible_rect = frame->visible_rect();
1292 out_metadata->timestamp = frame->timestamp();
1293 bool skip_possible = already_uploaded_id != -1;
1294 bool same_frame_id = frame->unique_id() == already_uploaded_id;
1295 out_metadata->skipped = skip_possible && same_frame_id;
1296}
1297
Blink Reformat1c4d759e2017-04-09 16:34:541298void WebMediaPlayerImpl::SetContentDecryptionModule(
[email protected]9ebc3b03f2014-08-13 04:01:231299 blink::WebContentDecryptionModule* cdm,
1300 blink::WebContentDecryptionModuleResult result) {
xhwang51139732017-02-24 19:36:081301 DVLOG(1) << __func__ << ": cdm = " << cdm;
acolwellb4034942014-08-28 15:42:431302 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]9ebc3b03f2014-08-13 04:01:231303
jrummell06f27072015-06-08 18:12:381304 // Once the CDM is set it can't be cleared as there may be frames being
1305 // decrypted on other threads. So fail this request.
1306 // http://crbug.com/462365#c7.
xhwang97de4202014-11-25 08:44:011307 if (!cdm) {
Blink Reformat1c4d759e2017-04-09 16:34:541308 result.CompleteWithError(
1309 blink::kWebContentDecryptionModuleExceptionInvalidStateError, 0,
xhwang79b193042016-12-13 18:52:431310 "The existing ContentDecryptionModule object cannot be removed at this "
1311 "time.");
xhwang97de4202014-11-25 08:44:011312 return;
1313 }
1314
jrummell89e61d82015-07-23 20:03:341315 // Create a local copy of |result| to avoid problems with the callback
1316 // getting passed to the media thread and causing |result| to be destructed
jrummell4acbec912016-02-27 02:45:031317 // on the wrong thread in some failure conditions. Blink should prevent
1318 // multiple simultaneous calls.
1319 DCHECK(!set_cdm_result_);
jrummell89e61d82015-07-23 20:03:341320 set_cdm_result_.reset(new blink::WebContentDecryptionModuleResult(result));
1321
dalecurtis04bdb582016-08-17 22:15:231322 // Recreate the watch time reporter if necessary.
1323 const bool was_encrypted = is_encrypted_;
1324 is_encrypted_ = true;
Dale Curtis3899090ea2018-01-12 00:10:351325 if (!was_encrypted) {
1326 media_metrics_provider_->SetIsEME();
1327 if (watch_time_reporter_)
1328 CreateWatchTimeReporter();
1329 }
dalecurtis04bdb582016-08-17 22:15:231330
Chris Cunninghamd9df58e2017-08-29 00:04:231331 // For now MediaCapabilities only handles clear content.
1332 video_decode_stats_reporter_.reset();
1333
jrummelle616ee92016-10-08 02:15:441334 SetCdm(cdm);
xhwang97de4202014-11-25 08:44:011335}
1336
xhwange8c4181a2014-12-06 08:10:011337void WebMediaPlayerImpl::OnEncryptedMediaInitData(
jrummellcf78967c2015-04-03 05:03:581338 EmeInitDataType init_data_type,
Avi Drissman97785ea2015-12-19 01:11:311339 const std::vector<uint8_t>& init_data) {
jrummellcf78967c2015-04-03 05:03:581340 DCHECK(init_data_type != EmeInitDataType::UNKNOWN);
xhwangbab66f52014-12-02 23:49:501341
Xiaohan Wangf63505d2017-10-21 08:00:531342 RecordEncryptedEvent(true);
xhwangbab66f52014-12-02 23:49:501343
dalecurtis04bdb582016-08-17 22:15:231344 // Recreate the watch time reporter if necessary.
1345 const bool was_encrypted = is_encrypted_;
1346 is_encrypted_ = true;
Dale Curtis3899090ea2018-01-12 00:10:351347 if (!was_encrypted) {
1348 media_metrics_provider_->SetIsEME();
1349 if (watch_time_reporter_)
1350 CreateWatchTimeReporter();
1351 }
dalecurtis04bdb582016-08-17 22:15:231352
Chris Cunninghamd9df58e2017-08-29 00:04:231353 // For now MediaCapabilities only handles clear content.
1354 video_decode_stats_reporter_.reset();
1355
Blink Reformat1c4d759e2017-04-09 16:34:541356 encrypted_client_->Encrypted(
davidbenb50f00c2015-12-01 00:01:501357 ConvertToWebInitDataType(init_data_type), init_data.data(),
srirama.m26f864d02015-07-14 05:21:461358 base::saturated_cast<unsigned int>(init_data.size()));
xhwangbab66f52014-12-02 23:49:501359}
1360
servolk81e01e02016-03-05 03:29:151361void WebMediaPlayerImpl::OnFFmpegMediaTracksUpdated(
dcheng3076abbf2016-04-22 20:42:391362 std::unique_ptr<MediaTracks> tracks) {
servolk81e01e02016-03-05 03:29:151363 // For MSE/chunk_demuxer case the media track updates are handled by
1364 // WebSourceBufferImpl.
1365 DCHECK(demuxer_.get());
1366 DCHECK(!chunk_demuxer_);
servolkef1e5ef2016-03-25 04:55:261367
servolk16e8bdf82017-04-11 17:00:391368 // Report the media track information to blink. Only the first audio track and
1369 // the first video track are enabled by default to match blink logic.
1370 bool is_first_audio_track = true;
1371 bool is_first_video_track = true;
servolkef1e5ef2016-03-25 04:55:261372 for (const auto& track : tracks->tracks()) {
1373 if (track->type() == MediaTrack::Audio) {
Blink Reformat1c4d759e2017-04-09 16:34:541374 client_->AddAudioTrack(blink::WebString::FromUTF8(track->id()),
1375 blink::WebMediaPlayerClient::kAudioTrackKindMain,
1376 blink::WebString::FromUTF8(track->label()),
1377 blink::WebString::FromUTF8(track->language()),
servolk16e8bdf82017-04-11 17:00:391378 is_first_audio_track);
1379 is_first_audio_track = false;
servolkef1e5ef2016-03-25 04:55:261380 } else if (track->type() == MediaTrack::Video) {
Blink Reformat1c4d759e2017-04-09 16:34:541381 client_->AddVideoTrack(blink::WebString::FromUTF8(track->id()),
1382 blink::WebMediaPlayerClient::kVideoTrackKindMain,
1383 blink::WebString::FromUTF8(track->label()),
1384 blink::WebString::FromUTF8(track->language()),
servolk16e8bdf82017-04-11 17:00:391385 is_first_video_track);
1386 is_first_video_track = false;
servolkef1e5ef2016-03-25 04:55:261387 } else {
1388 // Text tracks are not supported through this code path yet.
1389 NOTREACHED();
1390 }
1391 }
servolk81e01e02016-03-05 03:29:151392}
1393
jrummelle616ee92016-10-08 02:15:441394void WebMediaPlayerImpl::SetCdm(blink::WebContentDecryptionModule* cdm) {
1395 DCHECK(main_task_runner_->BelongsToCurrentThread());
1396 DCHECK(cdm);
Xiaohan Wang24cfe2c2018-01-22 23:16:001397
1398 auto cdm_context_ref =
1399 ToWebContentDecryptionModuleImpl(cdm)->GetCdmContextRef();
1400 if (!cdm_context_ref) {
jrummelle616ee92016-10-08 02:15:441401 NOTREACHED();
1402 OnCdmAttached(false);
xhwang80739452016-01-13 00:48:001403 return;
1404 }
1405
Xiaohan Wang24cfe2c2018-01-22 23:16:001406 CdmContext* cdm_context = cdm_context_ref->GetCdmContext();
1407 DCHECK(cdm_context);
jrummelle616ee92016-10-08 02:15:441408
1409 // Keep the reference to the CDM, as it shouldn't be destroyed until
1410 // after the pipeline is done with the |cdm_context|.
Xiaohan Wang24cfe2c2018-01-22 23:16:001411 pending_cdm_context_ref_ = std::move(cdm_context_ref);
tguilbert350936ff2017-02-24 05:39:271412 pipeline_controller_.SetCdm(
1413 cdm_context, base::Bind(&WebMediaPlayerImpl::OnCdmAttached, AsWeakPtr()));
xhwang97de4202014-11-25 08:44:011414}
1415
jrummell89e61d82015-07-23 20:03:341416void WebMediaPlayerImpl::OnCdmAttached(bool success) {
xhwang51139732017-02-24 19:36:081417 DVLOG(1) << __func__ << ": success = " << success;
jrummelle616ee92016-10-08 02:15:441418 DCHECK(main_task_runner_->BelongsToCurrentThread());
Xiaohan Wang24cfe2c2018-01-22 23:16:001419 DCHECK(pending_cdm_context_ref_);
jrummelle616ee92016-10-08 02:15:441420
1421 // If the CDM is set from the constructor there is no promise
1422 // (|set_cdm_result_|) to fulfill.
xhwang97de4202014-11-25 08:44:011423 if (success) {
xhwang29c5ad202017-04-14 07:02:191424 media_log_->SetBooleanProperty("has_cdm", true);
1425
jrummelle616ee92016-10-08 02:15:441426 // This will release the previously attached CDM (if any).
Xiaohan Wang24cfe2c2018-01-22 23:16:001427 cdm_context_ref_ = std::move(pending_cdm_context_ref_);
jrummelle616ee92016-10-08 02:15:441428 if (set_cdm_result_) {
Blink Reformat1c4d759e2017-04-09 16:34:541429 set_cdm_result_->Complete();
jrummelle616ee92016-10-08 02:15:441430 set_cdm_result_.reset();
1431 }
1432
xhwang97de4202014-11-25 08:44:011433 return;
1434 }
1435
Xiaohan Wang24cfe2c2018-01-22 23:16:001436 pending_cdm_context_ref_.reset();
jrummelle616ee92016-10-08 02:15:441437 if (set_cdm_result_) {
Blink Reformat1c4d759e2017-04-09 16:34:541438 set_cdm_result_->CompleteWithError(
1439 blink::kWebContentDecryptionModuleExceptionNotSupportedError, 0,
xhwang79b193042016-12-13 18:52:431440 "Unable to set ContentDecryptionModule object");
jrummelle616ee92016-10-08 02:15:441441 set_cdm_result_.reset();
1442 }
[email protected]9ebc3b03f2014-08-13 04:01:231443}
1444
sandersd1c0bba02016-03-04 23:14:081445void WebMediaPlayerImpl::OnPipelineSeeked(bool time_updated) {
John Chen5b164a02017-11-01 00:36:091446 TRACE_EVENT2("media", "WebMediaPlayerImpl::OnPipelineSeeked", "target",
1447 seek_time_.InSecondsF(), "id", media_log_->id());
[email protected]5d11eff2011-09-15 00:06:061448 seeking_ = false;
wolenetz1b2ae7d2015-06-10 00:44:211449 seek_time_ = base::TimeDelta();
avayvod2135a642017-01-13 00:17:141450
hubbe5a2dec022016-03-17 01:14:231451 if (paused_) {
1452#if defined(OS_ANDROID) // WMPI_CAST
Blink Reformat1c4d759e2017-04-09 16:34:541453 if (IsRemote()) {
Dale Curtis051fdf62017-08-05 00:21:131454 paused_time_ = cast_impl_.currentTime();
hubbe5a2dec022016-03-17 01:14:231455 } else {
tguilbert350936ff2017-02-24 05:39:271456 paused_time_ = pipeline_controller_.GetMediaTime();
hubbe5a2dec022016-03-17 01:14:231457 }
1458#else
tguilbert350936ff2017-02-24 05:39:271459 paused_time_ = pipeline_controller_.GetMediaTime();
hubbe5a2dec022016-03-17 01:14:231460#endif
dalecurtis04bdb582016-08-17 22:15:231461 } else {
1462 DCHECK(watch_time_reporter_);
1463 watch_time_reporter_->OnPlaying();
hubbe5a2dec022016-03-17 01:14:231464 }
sandersd1c0bba02016-03-04 23:14:081465 if (time_updated)
1466 should_notify_time_changed_ = true;
dalecurtisaf34d8712016-09-20 04:32:261467
dalecurtis4f6d14d2017-02-22 17:42:221468 // Reset underflow duration upon seek; this prevents looping videos and user
1469 // actions from artificially inflating the duration.
1470 underflow_timer_.reset();
avayvod56e1f3942017-01-21 02:06:311471
1472 // Background video optimizations are delayed when shown/hidden if pipeline
1473 // is seeking.
1474 UpdateBackgroundVideoOptimizationState();
Dale Curtis2dc6089a2018-03-26 16:47:581475
1476 // If we successfully completed a suspended startup, lie about our buffering
1477 // state for the time being. While ultimately we want to avoid lying about the
1478 // buffering state, for the initial test of true preload=metadata, signal
1479 // BUFFERING_HAVE_ENOUGH so that canplay and canplaythrough fire correctly.
1480 //
1481 // Later we can experiment with the impact of removing this lie; initial data
1482 // suggests high disruption since we've also made preload=metadata the
1483 // default. Most sites are not prepared for a lack of canplay; even many of
1484 // our own tests don't function correctly. See https://crbug.com/694855.
1485 //
1486 // Note: This call is dual purpose, it is also responsible for triggering an
1487 // UpdatePlayState() call which may need to resume the pipeline once Blink
1488 // has been told about the ReadyState change.
1489 if (attempting_suspended_start_ &&
1490 pipeline_controller_.IsPipelineSuspended()) {
Dale Curtis7c63f2e22018-09-19 21:06:271491 did_lazy_load_ = !has_poster_ && HasVideo();
1492 if (did_lazy_load_)
1493 DCHECK(base::FeatureList::IsEnabled(kPreloadMetadataLazyLoad));
1494
Dale Curtisff576552018-03-30 02:32:441495 skip_metrics_due_to_startup_suspend_ = true;
Dale Curtis2dc6089a2018-03-26 16:47:581496 OnBufferingStateChangeInternal(BUFFERING_HAVE_ENOUGH, true);
Dale Curtisff576552018-03-30 02:32:441497
1498 // If |skip_metrics_due_to_startup_suspend_| is unset by a resume started by
1499 // the OnBufferingStateChangeInternal() call, record a histogram of it here.
1500 //
1501 // If the value is unset, that means we should not have suspended and we've
1502 // likely incurred some cost to TimeToFirstFrame and TimeToPlayReady which
1503 // will be reflected in those statistics.
1504 base::UmaHistogramBoolean(
1505 std::string("Media.PreloadMetadataSuspendWasIdeal.") +
1506 ((HasVideo() && HasAudio()) ? "AudioVideo"
1507 : (HasVideo() ? "Video" : "Audio")),
1508 skip_metrics_due_to_startup_suspend_);
Dale Curtis2dc6089a2018-03-26 16:47:581509 }
1510
1511 attempting_suspended_start_ = false;
[email protected]8931c41a2009-07-07 17:31:491512}
1513
sandersd1c0bba02016-03-04 23:14:081514void WebMediaPlayerImpl::OnPipelineSuspended() {
Dale Curtis83321152018-12-01 01:22:061515 // Add a log event so the player shows up as "SUSPENDED" in media-internals.
1516 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::SUSPENDED));
1517
hubbed5f36882016-01-15 22:40:371518#if defined(OS_ANDROID)
avayvod82729272017-05-29 21:58:391519 if (IsRemote() && !IsNewRemotePlaybackPipelineEnabled()) {
hubbed5f36882016-01-15 22:40:371520 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner();
sandersd50a635e2016-04-04 22:50:091521 if (frame)
dalecurtise9c89e92016-05-20 19:38:001522 compositor_->PaintSingleFrame(frame);
hubbed5f36882016-01-15 22:40:371523 }
1524#endif
1525
sandersd2f5bb6152017-03-29 22:57:531526 // Tell the data source we have enough data so that it may release the
1527 // connection.
1528 if (data_source_)
1529 data_source_->OnBufferingHaveEnough(true);
dalecurtis37fe5862016-03-15 19:29:091530
sandersd50a635e2016-04-04 22:50:091531 ReportMemoryUsage();
1532
sandersd1c0bba02016-03-04 23:14:081533 if (pending_suspend_resume_cycle_) {
watkdee516f2016-02-18 02:22:191534 pending_suspend_resume_cycle_ = false;
sandersd50a635e2016-04-04 22:50:091535 UpdatePlayState();
dalecurtis0431cbf2016-03-12 01:19:431536 }
sandersd1c0bba02016-03-04 23:14:081537}
1538
avayvod2135a642017-01-13 00:17:141539void WebMediaPlayerImpl::OnBeforePipelineResume() {
Dale Curtisff576552018-03-30 02:32:441540 // We went through suspended startup, so the player is only just now spooling
1541 // up for playback. As such adjust |load_start_time_| so it reports the same
1542 // metric as what would be reported if we had not suspended at startup.
1543 if (skip_metrics_due_to_startup_suspend_) {
1544 // In the event that the call to SetReadyState() initiated after pipeline
1545 // startup immediately tries to start playback, we should not update
1546 // |load_start_time_| to avoid losing visibility into the impact of a
1547 // suspended startup on the time until first frame / play ready for cases
1548 // where suspended startup was applied incorrectly.
1549 if (!attempting_suspended_start_)
1550 load_start_time_ = base::TimeTicks::Now() - time_to_metadata_;
1551 skip_metrics_due_to_startup_suspend_ = false;
1552 }
1553
avayvod2135a642017-01-13 00:17:141554 // Enable video track if we disabled it in the background - this way the new
1555 // renderer will attach its callbacks to the video stream properly.
1556 // TODO(avayvod): Remove this when disabling and enabling video tracks in
1557 // non-playing state works correctly. See https://crbug.com/678374.
1558 EnableVideoTrackIfNeeded();
1559 is_pipeline_resuming_ = true;
1560}
1561
1562void WebMediaPlayerImpl::OnPipelineResumed() {
1563 is_pipeline_resuming_ = false;
1564
avayvod56e1f3942017-01-21 02:06:311565 UpdateBackgroundVideoOptimizationState();
avayvod2135a642017-01-13 00:17:141566}
1567
alokp967c902452016-05-06 05:21:371568void WebMediaPlayerImpl::OnDemuxerOpened() {
1569 DCHECK(main_task_runner_->BelongsToCurrentThread());
dalecurtis9cddc0b2017-04-19 21:23:381570 client_->MediaSourceOpened(new WebMediaSourceImpl(chunk_demuxer_));
alokp967c902452016-05-06 05:21:371571}
1572
servolkf94b4602017-01-31 16:44:271573void WebMediaPlayerImpl::OnMemoryPressure(
1574 base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
1575 DVLOG(2) << __func__ << " memory_pressure_level=" << memory_pressure_level;
1576 DCHECK(main_task_runner_->BelongsToCurrentThread());
1577 DCHECK(base::FeatureList::IsEnabled(kMemoryPressureBasedSourceBufferGC));
1578 DCHECK(chunk_demuxer_);
1579
1580 // The new value of |memory_pressure_level| will take effect on the next
1581 // garbage collection. Typically this means the next SourceBuffer append()
1582 // operation, since per MSE spec, the garbage collection must only occur
1583 // during SourceBuffer append(). But if memory pressure is critical it might
1584 // be better to perform GC immediately rather than wait for the next append
1585 // and potentially get killed due to out-of-memory.
1586 // So if this experiment is enabled and pressure level is critical, we'll pass
1587 // down force_instant_gc==true, which will force immediate GC on
1588 // SourceBufferStreams.
1589 bool force_instant_gc =
1590 (enable_instant_source_buffer_gc_ &&
1591 memory_pressure_level ==
1592 base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
1593
Matt Wolenetz95af6362018-01-04 20:23:421594 // base::Unretained is safe, since |chunk_demuxer_| is actually owned by
1595 // |this| via this->demuxer_. Note the destruction of |chunk_demuxer_| is done
1596 // from ~WMPI by first hopping to |media_task_runner_| to prevent race with
1597 // this task.
servolkf94b4602017-01-31 16:44:271598 media_task_runner_->PostTask(
Dale Curtisee9be30012018-09-21 22:21:511599 FROM_HERE, base::BindOnce(&ChunkDemuxer::OnMemoryPressure,
1600 base::Unretained(chunk_demuxer_),
1601 base::TimeDelta::FromSecondsD(CurrentTime()),
1602 memory_pressure_level, force_instant_gc));
servolkf94b4602017-01-31 16:44:271603}
1604
alokp967c902452016-05-06 05:21:371605void WebMediaPlayerImpl::OnError(PipelineStatus status) {
pkastingf5279482016-07-27 02:18:201606 DVLOG(1) << __func__;
alokp967c902452016-05-06 05:21:371607 DCHECK(main_task_runner_->BelongsToCurrentThread());
1608 DCHECK_NE(status, PIPELINE_OK);
1609
1610 if (suppress_destruction_errors_)
1611 return;
1612
Thomas Guilbert6b6be3d2017-08-18 03:17:271613#if defined(OS_ANDROID)
1614 if (status == PipelineStatus::DEMUXER_ERROR_DETECTED_HLS) {
Thomas Guilbert153f84572018-07-19 05:03:581615 demuxer_found_hls_ = true;
1616
Thomas Guilbert6b6be3d2017-08-18 03:17:271617 renderer_factory_selector_->SetUseMediaPlayer(true);
1618
1619 pipeline_controller_.Stop();
Dale Curtis8a6281322017-08-31 00:35:531620 SetMemoryReportingState(false);
Thomas Guilbert6b6be3d2017-08-18 03:17:271621
1622 main_task_runner_->PostTask(
Dale Curtisee9be30012018-09-21 22:21:511623 FROM_HERE,
1624 base::BindOnce(&WebMediaPlayerImpl::StartPipeline, AsWeakPtr()));
Thomas Guilbert6b6be3d2017-08-18 03:17:271625 return;
1626 }
1627#endif
1628
Dale Curtis5bba03232018-08-30 17:57:381629 MaybeSetContainerName();
dalecurtis9cddc0b2017-04-19 21:23:381630 ReportPipelineError(load_type_, status, media_log_.get());
alokp967c902452016-05-06 05:21:371631 media_log_->AddEvent(media_log_->CreatePipelineErrorEvent(status));
Dale Curtis74612b72017-12-14 20:56:191632 media_metrics_provider_->OnError(status);
Dale Curtisccfd0cca2017-08-31 01:27:561633 if (watch_time_reporter_)
1634 watch_time_reporter_->OnError(status);
alokp967c902452016-05-06 05:21:371635
Blink Reformat1c4d759e2017-04-09 16:34:541636 if (ready_state_ == WebMediaPlayer::kReadyStateHaveNothing) {
alokp967c902452016-05-06 05:21:371637 // Any error that occurs before reaching ReadyStateHaveMetadata should
1638 // be considered a format error.
Blink Reformat1c4d759e2017-04-09 16:34:541639 SetNetworkState(WebMediaPlayer::kNetworkStateFormatError);
alokp967c902452016-05-06 05:21:371640 } else {
1641 SetNetworkState(PipelineErrorToNetworkState(status));
1642 }
1643
Thomas Guilbert2e591392017-08-12 00:56:381644 // PipelineController::Stop() is idempotent.
1645 pipeline_controller_.Stop();
1646
alokp967c902452016-05-06 05:21:371647 UpdatePlayState();
1648}
1649
1650void WebMediaPlayerImpl::OnEnded() {
John Chen5b164a02017-11-01 00:36:091651 TRACE_EVENT2("media", "WebMediaPlayerImpl::OnEnded", "duration", Duration(),
1652 "id", media_log_->id());
pkastingf5279482016-07-27 02:18:201653 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:431654 DCHECK(main_task_runner_->BelongsToCurrentThread());
scherkusd2c745b2014-09-04 05:03:401655
sandersd1c0bba02016-03-04 23:14:081656 // Ignore state changes until we've completed all outstanding operations.
1657 if (!pipeline_controller_.IsStable())
scherkusd2c745b2014-09-04 05:03:401658 return;
1659
1660 ended_ = true;
Blink Reformat1c4d759e2017-04-09 16:34:541661 client_->TimeChanged();
sandersd50a635e2016-04-04 22:50:091662
dalecurtis1af3c1a2017-04-11 00:53:491663 // Clear any new frame processed callbacks on end; otherwise we'll end up
1664 // logging a time long after playback ends.
1665 frame_time_report_cb_.Cancel();
1666
sandersd50a635e2016-04-04 22:50:091667 // We don't actually want this to run until |client_| calls seek() or pause(),
1668 // but that should have already happened in timeChanged() and so this is
1669 // expected to be a no-op.
1670 UpdatePlayState();
[email protected]576537842009-08-12 23:52:051671}
1672
alokp967c902452016-05-06 05:21:371673void WebMediaPlayerImpl::OnMetadata(PipelineMetadata metadata) {
pkastingf5279482016-07-27 02:18:201674 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:431675 DCHECK(main_task_runner_->BelongsToCurrentThread());
Dale Curtisff576552018-03-30 02:32:441676
1677 // Cache the |time_to_metadata_| to use for adjusting the TimeToFirstFrame and
1678 // TimeToPlayReady metrics later if we end up doing a suspended startup.
1679 time_to_metadata_ = base::TimeTicks::Now() - load_start_time_;
1680 media_metrics_provider_->SetTimeToMetadata(time_to_metadata_);
1681 RecordTimingUMA("Media.TimeToMetadata", time_to_metadata_);
[email protected]a8e2cb82012-08-17 00:02:391682
Dale Curtis5bba03232018-08-30 17:57:381683 MaybeSetContainerName();
1684
[email protected]b8877772014-03-26 20:17:151685 pipeline_metadata_ = metadata;
[email protected]739847c02014-01-16 00:12:251686
Blink Reformat1c4d759e2017-04-09 16:34:541687 SetReadyState(WebMediaPlayer::kReadyStateHaveMetadata);
Julien Isorce6c83d8de2017-10-12 13:11:291688 UMA_HISTOGRAM_ENUMERATION("Media.VideoRotation",
1689 metadata.video_decoder_config.video_rotation(),
acolwell9e0840d2014-09-06 19:01:321690 VIDEO_ROTATION_MAX + 1);
[email protected]21c3f7502013-03-23 03:29:511691
John Rummelldb5a7ef2018-05-16 00:28:011692 if (HasAudio()) {
1693 RecordEncryptionScheme("Audio",
1694 metadata.audio_decoder_config.encryption_scheme());
1695 }
1696
Blink Reformat1c4d759e2017-04-09 16:34:541697 if (HasVideo()) {
John Rummelldb5a7ef2018-05-16 00:28:011698 RecordEncryptionScheme("Video",
1699 metadata.video_decoder_config.encryption_scheme());
1700
liberato2fd111be2017-01-04 00:25:061701 if (overlay_enabled_) {
1702 // SurfaceView doesn't support rotated video, so transition back if
[email protected]c8d574722017-08-30 20:53:431703 // the video is now rotated. If |always_enable_overlays_|, we keep the
liberato2fd111be2017-01-04 00:25:061704 // overlay anyway so that the state machine keeps working.
[email protected]c8d574722017-08-30 20:53:431705 // TODO(liberato): verify if compositor feedback catches this. If so,
1706 // then we don't need this check.
1707 if (!always_enable_overlays_ && !DoesOverlaySupportMetadata())
liberato2fd111be2017-01-04 00:25:061708 DisableOverlay();
liberato2fd111be2017-01-04 00:25:061709 }
watkf835a792016-06-24 23:24:401710
[email protected]702d721d2018-10-25 21:55:271711 if (surface_layer_mode_ ==
1712 blink::WebMediaPlayer::SurfaceLayerMode::kAlways ||
1713 (surface_layer_mode_ ==
1714 blink::WebMediaPlayer::SurfaceLayerMode::kOnDemand &&
1715 client_->DisplayType() ==
1716 WebMediaPlayer::DisplayType::kPictureInPicture)) {
1717 ActivateSurfaceLayerForVideo();
1718 } else {
danakj6e669e782018-05-16 16:57:171719 DCHECK(!video_layer_);
danakj25f030112018-05-11 18:26:541720 video_layer_ = cc::VideoLayer::Create(
Julien Isorce6c83d8de2017-10-12 13:11:291721 compositor_.get(),
danakj25f030112018-05-11 18:26:541722 pipeline_metadata_.video_decoder_config.video_rotation());
danakj8bc61c72018-05-16 13:55:061723 video_layer_->SetContentsOpaque(opaque_);
danakj8d204a42018-05-18 18:05:351724 client_->SetCcLayer(video_layer_.get());
lethalantidote7f6009d2017-07-07 21:47:391725 }
[email protected]a8e2cb82012-08-17 00:02:391726 }
dalecurtis8e4dc682016-03-15 02:30:301727
xjzd3fe45a2016-10-12 18:26:371728 if (observer_)
xjz15b483f2017-01-12 00:21:361729 observer_->OnMetadataChanged(pipeline_metadata_);
xjzd3fe45a2016-10-12 18:26:371730
Dale Curtisc7d2a7d22018-01-11 20:01:051731 // TODO(dalecurtis): Don't create these until kReadyStateHaveFutureData; when
1732 // we create them early we just increase the chances of needing to throw them
1733 // away unnecessarily.
dalecurtis04bdb582016-08-17 22:15:231734 CreateWatchTimeReporter();
Chris Cunninghamd9df58e2017-08-29 00:04:231735 CreateVideoDecodeStatsReporter();
Dale Curtisc7d2a7d22018-01-11 20:01:051736
sandersd50a635e2016-04-04 22:50:091737 UpdatePlayState();
[email protected]a8e2cb82012-08-17 00:02:391738}
1739
[email protected]69db58f2018-09-26 20:27:561740void WebMediaPlayerImpl::ActivateSurfaceLayerForVideo() {
1741 // Note that we might or might not already be in VideoLayer mode.
1742 DCHECK(!bridge_);
1743
1744 surface_layer_for_video_enabled_ = true;
1745
1746 // If we're in VideoLayer mode, then get rid of the layer.
1747 if (video_layer_) {
1748 client_->SetCcLayer(nullptr);
1749 video_layer_ = nullptr;
1750 }
1751
1752 bridge_ = std::move(create_bridge_callback_)
1753 .Run(this, compositor_->GetUpdateSubmissionStateCallback());
1754 bridge_->CreateSurfaceLayer();
1755
1756 vfc_task_runner_->PostTask(
1757 FROM_HERE,
1758 base::BindOnce(
1759 &VideoFrameCompositor::EnableSubmission,
1760 base::Unretained(compositor_.get()), bridge_->GetSurfaceId(),
jonross180dc482018-10-23 21:22:091761 bridge_->GetLocalSurfaceIdAllocationTime(),
[email protected]69db58f2018-09-26 20:27:561762 pipeline_metadata_.video_decoder_config.video_rotation(),
1763 IsInPictureInPicture(), opaque_,
1764 BindToCurrentLoop(base::BindRepeating(
1765 &WebMediaPlayerImpl::OnFrameSinkDestroyed, AsWeakPtr()))));
1766 bridge_->SetContentsOpaque(opaque_);
1767
1768 // If the element is already in Picture-in-Picture mode, it means that it
1769 // was set in this mode prior to this load, with a different
1770 // WebMediaPlayerImpl. The new player needs to send its id, size and
1771 // surface id to the browser process to make sure the states are properly
1772 // updated.
1773 // TODO(872056): the surface should be activated but for some reasons, it
1774 // does not. It is possible that this will no longer be needed after 872056
1775 // is fixed.
1776 if (client_->DisplayType() ==
1777 WebMediaPlayer::DisplayType::kPictureInPicture) {
1778 OnSurfaceIdUpdated(bridge_->GetSurfaceId());
1779 }
1780}
1781
CJ DiMegliodf92bfe2018-05-11 20:11:001782void WebMediaPlayerImpl::OnFrameSinkDestroyed() {
1783 bridge_->ClearSurfaceId();
1784}
1785
Dale Curtis2dc6089a2018-03-26 16:47:581786void WebMediaPlayerImpl::OnBufferingStateChange(BufferingState state) {
1787 OnBufferingStateChangeInternal(state, false);
1788}
1789
Chris Cunninghamd9df58e2017-08-29 00:04:231790void WebMediaPlayerImpl::CreateVideoDecodeStatsReporter() {
1791 // TODO(chcunningham): destroy reporter if we initially have video but the
1792 // track gets disabled. Currently not possible in default desktop Chrome.
1793 if (!HasVideo())
1794 return;
1795
1796 // Stats reporter requires a valid config. We may not have one for HLS cases
1797 // where URL demuxer doesn't know details of the stream.
1798 if (!pipeline_metadata_.video_decoder_config.IsValidConfig())
1799 return;
1800
1801 // For now MediaCapabilities only handles clear content.
1802 // TODO(chcunningham): Report encrypted stats.
1803 if (is_encrypted_)
1804 return;
1805
Dale Curtis7e8a510d2017-12-14 19:19:481806 mojom::VideoDecodeStatsRecorderPtr recorder;
1807 media_metrics_provider_->AcquireVideoDecodeStatsRecorder(
Dale Curtis7e8a510d2017-12-14 19:19:481808 mojo::MakeRequest(&recorder));
Chris Cunninghamc7c6a6d2017-11-23 14:06:451809
Chris Cunninghamd9df58e2017-08-29 00:04:231810 // Create capabilities reporter and synchronize its initial state.
1811 video_decode_stats_reporter_.reset(new VideoDecodeStatsReporter(
Chris Cunninghamc7c6a6d2017-11-23 14:06:451812 std::move(recorder),
Chris Cunninghamd9df58e2017-08-29 00:04:231813 base::Bind(&WebMediaPlayerImpl::GetPipelineStatistics,
1814 base::Unretained(this)),
Hajime Hoshi6c3194b52017-12-15 03:02:111815 pipeline_metadata_.video_decoder_config,
Hajime Hoshib5a26ee2018-05-14 12:47:511816 frame_->GetTaskRunner(blink::TaskType::kInternalMedia)));
Chris Cunninghamd9df58e2017-08-29 00:04:231817
1818 if (delegate_->IsFrameHidden())
1819 video_decode_stats_reporter_->OnHidden();
1820 else
1821 video_decode_stats_reporter_->OnShown();
1822
1823 if (paused_)
1824 video_decode_stats_reporter_->OnPaused();
1825 else
1826 video_decode_stats_reporter_->OnPlaying();
1827}
1828
hubbeb2d3efd2017-05-05 23:26:381829void WebMediaPlayerImpl::OnProgress() {
Chris Watkins1ffabc5f2017-05-10 20:52:091830 DVLOG(4) << __func__;
hubbeb2d3efd2017-05-05 23:26:381831 if (highest_ready_state_ < ReadyState::kReadyStateHaveFutureData) {
1832 // Reset the preroll attempt clock.
1833 preroll_attempt_pending_ = true;
1834 preroll_attempt_start_time_ = base::TimeTicks();
1835
1836 // Clear any 'stale' flag and give the pipeline a chance to resume. If we
1837 // are already resumed, this will cause |preroll_attempt_start_time_| to
1838 // be set.
1839 delegate_->ClearStaleFlag(delegate_id_);
1840 UpdatePlayState();
1841 } else if (ready_state_ == ReadyState::kReadyStateHaveFutureData &&
1842 CanPlayThrough()) {
1843 SetReadyState(WebMediaPlayer::kReadyStateHaveEnoughData);
1844 }
1845}
1846
1847bool WebMediaPlayerImpl::CanPlayThrough() {
1848 if (!base::FeatureList::IsEnabled(kSpecCompliantCanPlayThrough))
1849 return true;
1850 if (chunk_demuxer_)
1851 return true;
1852 if (data_source_ && data_source_->assume_fully_buffered())
1853 return true;
1854 // If we're not currently downloading, we have as much buffer as
1855 // we're ever going to get, which means we say we can play through.
1856 if (network_state_ == WebMediaPlayer::kNetworkStateIdle)
1857 return true;
1858 return buffered_data_source_host_.CanPlayThrough(
1859 base::TimeDelta::FromSecondsD(CurrentTime()),
1860 base::TimeDelta::FromSecondsD(Duration()),
1861 playback_rate_ == 0.0 ? 1.0 : playback_rate_);
1862}
1863
Dale Curtisff576552018-03-30 02:32:441864void WebMediaPlayerImpl::OnBufferingStateChangeInternal(
1865 BufferingState state,
1866 bool for_suspended_start) {
pkastingf5279482016-07-27 02:18:201867 DVLOG(1) << __func__ << "(" << state << ")";
alokp967c902452016-05-06 05:21:371868 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]b8877772014-03-26 20:17:151869
Ted Meyer742212b82018-08-22 17:21:421870 // Ignore buffering state changes caused by back-to-back seeking, so as not
1871 // to assume the second seek has finished when it was only the first seek.
1872 if (pipeline_controller_.IsPendingSeek())
[email protected]ba7d5f92014-06-24 05:37:401873 return;
[email protected]b8877772014-03-26 20:17:151874
Dale Curtisff576552018-03-30 02:32:441875 auto log_event = media_log_->CreateBufferingStateChangedEvent(
1876 "pipeline_buffering_state", state);
1877 log_event->params.SetBoolean("for_suspended_start", for_suspended_start);
1878 media_log_->AddEvent(std::move(log_event));
dalecurtis869bf2f2017-01-10 18:01:101879
chcunninghameb270c92016-07-15 01:00:451880 if (state == BUFFERING_HAVE_ENOUGH) {
John Chen5b164a02017-11-01 00:36:091881 TRACE_EVENT1("media", "WebMediaPlayerImpl::BufferingHaveEnough", "id",
1882 media_log_->id());
Dale Curtisff576552018-03-30 02:32:441883 // The SetReadyState() call below may clear
1884 // |skip_metrics_due_to_startup_suspend_| so report this first.
1885 if (!have_reported_time_to_play_ready_ &&
1886 !skip_metrics_due_to_startup_suspend_) {
1887 DCHECK(!for_suspended_start);
Dale Curtis3899090ea2018-01-12 00:10:351888 have_reported_time_to_play_ready_ = true;
1889 const base::TimeDelta elapsed = base::TimeTicks::Now() - load_start_time_;
1890 media_metrics_provider_->SetTimeToPlayReady(elapsed);
1891 RecordTimingUMA("Media.TimeToPlayReady", elapsed);
1892 }
[email protected]ba7d5f92014-06-24 05:37:401893
Dale Curtisff576552018-03-30 02:32:441894 // Warning: This call may be re-entrant.
1895 SetReadyState(CanPlayThrough() ? WebMediaPlayer::kReadyStateHaveEnoughData
1896 : WebMediaPlayer::kReadyStateHaveFutureData);
1897
chcunninghameb270c92016-07-15 01:00:451898 // Let the DataSource know we have enough data. It may use this information
1899 // to release unused network connections.
Fredrik Hubinette6dd3f3222018-05-24 01:00:511900 if (data_source_ && !client_->CouldPlayIfEnoughData())
chcunninghameb270c92016-07-15 01:00:451901 data_source_->OnBufferingHaveEnough(false);
dalecurtis849cf4b22015-03-27 18:35:451902
chcunninghameb270c92016-07-15 01:00:451903 // Blink expects a timeChanged() in response to a seek().
sandersd35d2c3f2017-01-14 02:04:421904 if (should_notify_time_changed_) {
1905 should_notify_time_changed_ = false;
Blink Reformat1c4d759e2017-04-09 16:34:541906 client_->TimeChanged();
sandersd35d2c3f2017-01-14 02:04:421907 }
dalecurtis0f0097a2015-12-01 17:40:471908
chcunninghameb270c92016-07-15 01:00:451909 // Once we have enough, start reporting the total memory usage. We'll also
1910 // report once playback starts.
1911 ReportMemoryUsage();
dalecurtis9d638a12016-08-30 06:20:551912
dalecurtis4f6d14d2017-02-22 17:42:221913 // Report the amount of time it took to leave the underflow state.
1914 if (underflow_timer_) {
1915 RecordUnderflowDuration(underflow_timer_->Elapsed());
dalecurtis9d638a12016-08-30 06:20:551916 underflow_timer_.reset();
1917 }
chcunninghameb270c92016-07-15 01:00:451918 } else {
1919 // Buffering has underflowed.
1920 DCHECK_EQ(state, BUFFERING_HAVE_NOTHING);
dalecurtisacd77d62016-09-09 23:23:141921
dalecurtisd06eabc2017-02-24 23:43:291922 // Report the number of times we've entered the underflow state. Ensure we
1923 // only report the value when transitioning from HAVE_ENOUGH to
1924 // HAVE_NOTHING.
Dale Curtis6995b862017-05-31 22:20:081925 if (ready_state_ == WebMediaPlayer::kReadyStateHaveEnoughData &&
1926 !seeking_) {
dalecurtisacd77d62016-09-09 23:23:141927 underflow_timer_.reset(new base::ElapsedTimer());
Dale Curtis6995b862017-05-31 22:20:081928 watch_time_reporter_->OnUnderflow();
1929 }
dalecurtisacd77d62016-09-09 23:23:141930
chcunninghameb270c92016-07-15 01:00:451931 // It shouldn't be possible to underflow if we've not advanced past
1932 // HAVE_CURRENT_DATA.
Blink Reformat1c4d759e2017-04-09 16:34:541933 DCHECK_GT(highest_ready_state_, WebMediaPlayer::kReadyStateHaveCurrentData);
1934 SetReadyState(WebMediaPlayer::kReadyStateHaveCurrentData);
chcunninghameb270c92016-07-15 01:00:451935 }
sandersd50a635e2016-04-04 22:50:091936
1937 UpdatePlayState();
[email protected]b8877772014-03-26 20:17:151938}
1939
alokp967c902452016-05-06 05:21:371940void WebMediaPlayerImpl::OnDurationChange() {
acolwellb4034942014-08-28 15:42:431941 DCHECK(main_task_runner_->BelongsToCurrentThread());
alokp967c902452016-05-06 05:21:371942
John Delaney2371b452018-12-13 04:30:331943 if (frame_->IsAdSubframe()) {
1944 UMA_HISTOGRAM_CUSTOM_TIMES("Ads.Media.Duration", GetPipelineMediaDuration(),
1945 base::TimeDelta::FromMilliseconds(1),
1946 base::TimeDelta::FromDays(1),
1947 50 /* bucket_count */);
1948 }
1949
alokp967c902452016-05-06 05:21:371950 // TODO(sandersd): We should call delegate_->DidPlay() with the new duration,
1951 // especially if it changed from <5s to >5s.
Blink Reformat1c4d759e2017-04-09 16:34:541952 if (ready_state_ == WebMediaPlayer::kReadyStateHaveNothing)
alokp967c902452016-05-06 05:21:371953 return;
1954
Blink Reformat1c4d759e2017-04-09 16:34:541955 client_->DurationChanged();
Dale Curtisaebaeea2018-07-19 23:42:111956 if (watch_time_reporter_)
1957 watch_time_reporter_->OnDurationChanged(GetPipelineMediaDuration());
[email protected]81bb3322011-07-21 15:55:501958}
1959
alokp967c902452016-05-06 05:21:371960void WebMediaPlayerImpl::OnAddTextTrack(const TextTrackConfig& config,
1961 const AddTextTrackDoneCB& done_cb) {
acolwellb4034942014-08-28 15:42:431962 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]71537722013-05-23 06:47:531963
[email protected]8a561062013-11-22 01:19:311964 const WebInbandTextTrackImpl::Kind web_kind =
1965 static_cast<WebInbandTextTrackImpl::Kind>(config.kind());
Blink Reformat1c4d759e2017-04-09 16:34:541966 const blink::WebString web_label = blink::WebString::FromUTF8(config.label());
[email protected]8a561062013-11-22 01:19:311967 const blink::WebString web_language =
Blink Reformat1c4d759e2017-04-09 16:34:541968 blink::WebString::FromUTF8(config.language());
1969 const blink::WebString web_id = blink::WebString::FromUTF8(config.id());
[email protected]71537722013-05-23 06:47:531970
dcheng3076abbf2016-04-22 20:42:391971 std::unique_ptr<WebInbandTextTrackImpl> web_inband_text_track(
henriks9cce5fa2014-12-12 09:35:301972 new WebInbandTextTrackImpl(web_kind, web_label, web_language, web_id));
[email protected]8a561062013-11-22 01:19:311973
dcheng3076abbf2016-04-22 20:42:391974 std::unique_ptr<media::TextTrack> text_track(new TextTrackImpl(
dcheng652f5ff2015-12-27 08:54:001975 main_task_runner_, client_, std::move(web_inband_text_track)));
[email protected]8a561062013-11-22 01:19:311976
dcheng652f5ff2015-12-27 08:54:001977 done_cb.Run(std::move(text_track));
[email protected]71537722013-05-23 06:47:531978}
1979
alokp967c902452016-05-06 05:21:371980void WebMediaPlayerImpl::OnWaitingForDecryptionKey() {
1981 DCHECK(main_task_runner_->BelongsToCurrentThread());
1982
Blink Reformat1c4d759e2017-04-09 16:34:541983 encrypted_client_->DidBlockPlaybackWaitingForKey();
alokp967c902452016-05-06 05:21:371984 // TODO(jrummell): didResumePlaybackBlockedForKey() should only be called
1985 // when a key has been successfully added (e.g. OnSessionKeysChange() with
1986 // |has_additional_usable_key| = true). http://crbug.com/461903
Blink Reformat1c4d759e2017-04-09 16:34:541987 encrypted_client_->DidResumePlaybackBlockedForKey();
alokp967c902452016-05-06 05:21:371988}
1989
alokp5d86e9b2016-05-17 20:20:411990void WebMediaPlayerImpl::OnVideoNaturalSizeChange(const gfx::Size& size) {
1991 DCHECK(main_task_runner_->BelongsToCurrentThread());
Blink Reformat1c4d759e2017-04-09 16:34:541992 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
alokp5d86e9b2016-05-17 20:20:411993
Chris Cunningham038548b2017-07-10 22:36:301994 TRACE_EVENT0("media", "WebMediaPlayerImpl::OnVideoNaturalSizeChange");
xhwang60802652017-04-19 07:29:581995
xjz15b483f2017-01-12 00:21:361996 // The input |size| is from the decoded video frame, which is the original
1997 // natural size and need to be rotated accordingly.
Julien Isorce6c83d8de2017-10-12 13:11:291998 gfx::Size rotated_size = GetRotatedVideoSize(
1999 pipeline_metadata_.video_decoder_config.video_rotation(), size);
sandersd2c478422016-08-02 01:19:252000
xhwang60802652017-04-19 07:29:582001 RecordVideoNaturalSize(rotated_size);
2002
2003 gfx::Size old_size = pipeline_metadata_.natural_size;
2004 if (rotated_size == old_size)
alokp5d86e9b2016-05-17 20:20:412005 return;
2006
xjz516ef6d2017-01-07 00:23:062007 pipeline_metadata_.natural_size = rotated_size;
Dale Curtis96d6e9382018-07-18 18:01:072008 UpdateSecondaryProperties();
dalecurtis25405562017-04-14 23:35:112009
Chris Cunninghamd9df58e2017-08-29 00:04:232010 if (video_decode_stats_reporter_)
2011 video_decode_stats_reporter_->OnNaturalSizeChanged(rotated_size);
2012
Blink Reformat1c4d759e2017-04-09 16:34:542013 client_->SizeChanged();
xjz516ef6d2017-01-07 00:23:062014
xjz15b483f2017-01-12 00:21:362015 if (observer_)
2016 observer_->OnMetadataChanged(pipeline_metadata_);
peconn257951522017-06-09 18:24:592017
2018 delegate_->DidPlayerSizeChange(delegate_id_, NaturalSize());
alokp5d86e9b2016-05-17 20:20:412019}
2020
2021void WebMediaPlayerImpl::OnVideoOpacityChange(bool opaque) {
2022 DCHECK(main_task_runner_->BelongsToCurrentThread());
Blink Reformat1c4d759e2017-04-09 16:34:542023 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
alokp5d86e9b2016-05-17 20:20:412024
2025 opaque_ = opaque;
lethalantidote7f6009d2017-07-07 21:47:392026 if (!surface_layer_for_video_enabled_) {
danakj8bc61c72018-05-16 13:55:062027 if (video_layer_)
2028 video_layer_->SetContentsOpaque(opaque_);
danakj8d204a42018-05-18 18:05:352029 } else if (bridge_->GetCcLayer()) {
CJ DiMeglioa2b13fbc2018-06-27 00:50:592030 bridge_->SetContentsOpaque(opaque_);
CJ DiMeglio27211372018-07-27 23:17:442031 vfc_task_runner_->PostTask(
2032 FROM_HERE,
2033 base::BindOnce(&VideoFrameCompositor::UpdateIsOpaque,
2034 base::Unretained(compositor_.get()), opaque_));
lethalantidote7f6009d2017-07-07 21:47:392035 }
alokp5d86e9b2016-05-17 20:20:412036}
2037
Chris Cunningham038548b2017-07-10 22:36:302038void WebMediaPlayerImpl::OnAudioConfigChange(const AudioDecoderConfig& config) {
2039 DCHECK(main_task_runner_->BelongsToCurrentThread());
2040 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
2041
Dale Curtisccfd0cca2017-08-31 01:27:562042 const bool codec_change =
2043 pipeline_metadata_.audio_decoder_config.codec() != config.codec();
Chris Cunningham038548b2017-07-10 22:36:302044 pipeline_metadata_.audio_decoder_config = config;
2045
2046 if (observer_)
2047 observer_->OnMetadataChanged(pipeline_metadata_);
Dale Curtisccfd0cca2017-08-31 01:27:562048
2049 if (codec_change)
Dale Curtis96d6e9382018-07-18 18:01:072050 UpdateSecondaryProperties();
Chris Cunningham038548b2017-07-10 22:36:302051}
2052
2053void WebMediaPlayerImpl::OnVideoConfigChange(const VideoDecoderConfig& config) {
2054 DCHECK(main_task_runner_->BelongsToCurrentThread());
2055 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
2056
Dale Curtisccfd0cca2017-08-31 01:27:562057 const bool codec_change =
2058 pipeline_metadata_.video_decoder_config.codec() != config.codec();
2059
Chris Cunningham038548b2017-07-10 22:36:302060 // TODO(chcunningham): Observe changes to video codec profile to signal
2061 // beginning of a new Media Capabilities playback report.
2062 pipeline_metadata_.video_decoder_config = config;
2063
2064 if (observer_)
2065 observer_->OnMetadataChanged(pipeline_metadata_);
Chris Cunninghamd9df58e2017-08-29 00:04:232066
2067 if (video_decode_stats_reporter_)
2068 video_decode_stats_reporter_->OnVideoConfigChanged(config);
Dale Curtisccfd0cca2017-08-31 01:27:562069
2070 if (codec_change)
Dale Curtis96d6e9382018-07-18 18:01:072071 UpdateSecondaryProperties();
Chris Cunningham038548b2017-07-10 22:36:302072}
2073
avayvodeecec52c2017-02-14 01:25:092074void WebMediaPlayerImpl::OnVideoAverageKeyframeDistanceUpdate() {
2075 UpdateBackgroundVideoOptimizationState();
2076}
2077
Dale Curtisc7d2a7d22018-01-11 20:01:052078void WebMediaPlayerImpl::OnAudioDecoderChange(const std::string& name) {
2079 if (name == audio_decoder_name_)
2080 return;
2081
Dale Curtisc7d2a7d22018-01-11 20:01:052082 audio_decoder_name_ = name;
2083
2084 // If there's no current reporter, there's nothing to be done.
2085 if (!watch_time_reporter_)
2086 return;
2087
Dale Curtis96d6e9382018-07-18 18:01:072088 UpdateSecondaryProperties();
Dale Curtisc7d2a7d22018-01-11 20:01:052089}
2090
2091void WebMediaPlayerImpl::OnVideoDecoderChange(const std::string& name) {
2092 if (name == video_decoder_name_)
2093 return;
2094
Dale Curtisc7d2a7d22018-01-11 20:01:052095 video_decoder_name_ = name;
2096
2097 // If there's no current reporter, there's nothing to be done.
2098 if (!watch_time_reporter_)
2099 return;
2100
Dale Curtis96d6e9382018-07-18 18:01:072101 UpdateSecondaryProperties();
Dale Curtisc7d2a7d22018-01-11 20:01:052102}
2103
sandersd35d2c3f2017-01-14 02:04:422104void WebMediaPlayerImpl::OnFrameHidden() {
sandersd1e49fb62015-12-12 01:18:062105 DCHECK(main_task_runner_->BelongsToCurrentThread());
avayvod39c102402016-11-23 21:43:132106
avayvod65fad272017-02-24 01:00:482107 // Backgrounding a video requires a user gesture to resume playback.
2108 if (IsHidden())
2109 video_locked_when_paused_when_hidden_ = true;
2110
dalecurtis04bdb582016-08-17 22:15:232111 if (watch_time_reporter_)
2112 watch_time_reporter_->OnHidden();
avayvod48a8be52016-08-04 19:52:502113
Chris Cunninghamd9df58e2017-08-29 00:04:232114 if (video_decode_stats_reporter_)
2115 video_decode_stats_reporter_->OnHidden();
2116
avayvod65fad272017-02-24 01:00:482117 UpdateBackgroundVideoOptimizationState();
sandersd50a635e2016-04-04 22:50:092118 UpdatePlayState();
dalecurtis8b8505e72016-06-10 21:59:172119
2120 // Schedule suspended playing media to be paused if the user doesn't come back
2121 // to it within some timeout period to avoid any autoplay surprises.
2122 ScheduleIdlePauseTimer();
sandersd1e49fb62015-12-12 01:18:062123}
2124
sandersd35d2c3f2017-01-14 02:04:422125void WebMediaPlayerImpl::OnFrameClosed() {
sandersd1e49fb62015-12-12 01:18:062126 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]28347e72017-06-27 17:30:112127
sandersd35d2c3f2017-01-14 02:04:422128 UpdatePlayState();
2129}
2130
2131void WebMediaPlayerImpl::OnFrameShown() {
2132 DCHECK(main_task_runner_->BelongsToCurrentThread());
2133 background_pause_timer_.Stop();
2134
avayvod65fad272017-02-24 01:00:482135 // Foreground videos don't require user gesture to continue playback.
2136 video_locked_when_paused_when_hidden_ = false;
2137
dalecurtis04bdb582016-08-17 22:15:232138 if (watch_time_reporter_)
2139 watch_time_reporter_->OnShown();
2140
Chris Cunninghamd9df58e2017-08-29 00:04:232141 if (video_decode_stats_reporter_)
2142 video_decode_stats_reporter_->OnShown();
2143
avayvodcc273dd2017-01-19 19:35:122144 // Only track the time to the first frame if playing or about to play because
2145 // of being shown and only for videos we would optimize background playback
2146 // for.
2147 if ((!paused_ && IsBackgroundOptimizationCandidate()) ||
2148 paused_when_hidden_) {
Dale Curtis3899090ea2018-01-12 00:10:352149 frame_time_report_cb_.Reset(base::BindOnce(
2150 &WebMediaPlayerImpl::ReportTimeFromForegroundToFirstFrame, AsWeakPtr(),
2151 base::TimeTicks::Now()));
CJ DiMeglio2302d202017-08-31 08:38:042152 vfc_task_runner_->PostTask(
avayvodcc273dd2017-01-19 19:35:122153 FROM_HERE,
Dale Curtis3899090ea2018-01-12 00:10:352154 base::BindOnce(&VideoFrameCompositor::SetOnNewProcessedFrameCallback,
2155 base::Unretained(compositor_.get()),
2156 BindToCurrentLoop(frame_time_report_cb_.callback())));
avayvodcc273dd2017-01-19 19:35:122157 }
avayvodac607d652017-01-06 03:16:432158
Dale Curtisdcbb81a2017-08-18 01:06:122159 UpdateBackgroundVideoOptimizationState();
avayvod65fad272017-02-24 01:00:482160
avayvod2135a642017-01-13 00:17:142161 if (paused_when_hidden_) {
2162 paused_when_hidden_ = false;
2163 OnPlay(); // Calls UpdatePlayState() so return afterwards.
2164 return;
2165 }
2166
sandersd50a635e2016-04-04 22:50:092167 UpdatePlayState();
sandersd1e49fb62015-12-12 01:18:062168}
2169
sandersd35d2c3f2017-01-14 02:04:422170void WebMediaPlayerImpl::OnIdleTimeout() {
dalecurtis0431cbf2016-03-12 01:19:432171 DCHECK(main_task_runner_->BelongsToCurrentThread());
2172
Dale Curtis99a9b482018-02-01 02:23:282173 // This should never be called when stale state testing overrides are used.
2174 DCHECK(!stale_state_override_for_testing_.has_value());
2175
sandersd35d2c3f2017-01-14 02:04:422176 // If we are attempting preroll, clear the stale flag.
2177 if (IsPrerollAttemptNeeded()) {
tguilbert1bb1c782017-01-23 21:15:112178 delegate_->ClearStaleFlag(delegate_id_);
sandersd35d2c3f2017-01-14 02:04:422179 return;
watkd026f792016-11-05 00:28:512180 }
sandersd50a635e2016-04-04 22:50:092181
sandersd35d2c3f2017-01-14 02:04:422182 UpdatePlayState();
dalecurtis0431cbf2016-03-12 01:19:432183}
2184
dalecurtisbb3eaac2016-01-27 21:10:252185void WebMediaPlayerImpl::OnPlay() {
Mounir Lamouri703106e2018-05-30 14:31:092186 client_->RequestPlay();
dalecurtisbb3eaac2016-01-27 21:10:252187}
2188
2189void WebMediaPlayerImpl::OnPause() {
Mounir Lamouri703106e2018-05-30 14:31:092190 client_->RequestPause();
dalecurtisbb3eaac2016-01-27 21:10:252191}
2192
Alec Douglas316cce42017-10-31 13:28:082193void WebMediaPlayerImpl::OnSeekForward(double seconds) {
2194 DCHECK_GE(seconds, 0) << "Attempted to seek by a negative number of seconds";
2195 client_->RequestSeek(CurrentTime() + seconds);
2196}
2197
2198void WebMediaPlayerImpl::OnSeekBackward(double seconds) {
2199 DCHECK_GE(seconds, 0) << "Attempted to seek by a negative number of seconds";
2200 client_->RequestSeek(CurrentTime() - seconds);
2201}
2202
dalecurtisbb3eaac2016-01-27 21:10:252203void WebMediaPlayerImpl::OnVolumeMultiplierUpdate(double multiplier) {
2204 volume_multiplier_ = multiplier;
Blink Reformat1c4d759e2017-04-09 16:34:542205 SetVolume(volume_);
dalecurtisbb3eaac2016-01-27 21:10:252206}
2207
zqzhang8ac49002017-03-16 21:51:352208void WebMediaPlayerImpl::OnBecamePersistentVideo(bool value) {
Blink Reformat1c4d759e2017-04-09 16:34:542209 client_->OnBecamePersistentVideo(value);
zqzhang8ac49002017-03-16 21:51:352210}
2211
Jennifer Apacible009f29842018-04-16 23:07:372212void WebMediaPlayerImpl::OnPictureInPictureModeEnded() {
Mounir Lamourib642a3c2018-07-09 15:45:312213 // It is possible for this method to be called when the player is no longer in
2214 // Picture-in-Picture mode.
Mounir Lamouri0484f40a2018-07-25 03:03:262215 if (!client_ || !IsInPictureInPicture())
Mounir Lamourib642a3c2018-07-09 15:45:312216 return;
Mounir Lamourib642a3c2018-07-09 15:45:312217
2218 client_->PictureInPictureStopped();
Jennifer Apacible009f29842018-04-16 23:07:372219}
2220
sawtelle82e4b752018-07-19 04:33:122221void WebMediaPlayerImpl::OnPictureInPictureControlClicked(
2222 const std::string& control_id) {
Mounir Lamouri0484f40a2018-07-25 03:03:262223 if (client_ && IsInPictureInPicture()) {
sawtelle82e4b752018-07-19 04:33:122224 client_->PictureInPictureControlClicked(
2225 blink::WebString::FromUTF8(control_id));
sawtelle42eac6a2018-06-26 03:22:012226 }
2227}
2228
John Delaneyc9abf4a2018-10-31 00:39:162229void WebMediaPlayerImpl::SendBytesReceivedUpdate() {
2230 media_metrics_provider_->AddBytesReceived(bytes_received_since_last_update_);
2231 bytes_received_since_last_update_ = 0;
2232}
2233
John Delaneyb933391602018-10-17 21:50:472234void WebMediaPlayerImpl::OnBytesReceived(uint64_t data_length) {
John Delaneyc9abf4a2018-10-31 00:39:162235 bytes_received_since_last_update_ += data_length;
2236 constexpr base::TimeDelta kBytesReceivedUpdateInterval =
2237 base::TimeDelta::FromMilliseconds(500);
2238 auto current_time = base::TimeTicks::Now();
2239 if (earliest_time_next_bytes_received_update_.is_null() ||
2240 earliest_time_next_bytes_received_update_ <= current_time) {
2241 report_bytes_received_timer_.Stop();
2242 SendBytesReceivedUpdate();
2243 earliest_time_next_bytes_received_update_ =
2244 current_time + kBytesReceivedUpdateInterval;
2245 } else {
2246 report_bytes_received_timer_.Start(
2247 FROM_HERE, kBytesReceivedUpdateInterval, this,
2248 &WebMediaPlayerImpl::SendBytesReceivedUpdate);
2249 }
John Delaneyb933391602018-10-17 21:50:472250}
2251
watkdee516f2016-02-18 02:22:192252void WebMediaPlayerImpl::ScheduleRestart() {
sandersd50a635e2016-04-04 22:50:092253 // TODO(watk): All restart logic should be moved into PipelineController.
tguilbert350936ff2017-02-24 05:39:272254 if (pipeline_controller_.IsPipelineRunning() &&
2255 !pipeline_controller_.IsPipelineSuspended()) {
watkdee516f2016-02-18 02:22:192256 pending_suspend_resume_cycle_ = true;
sandersd50a635e2016-04-04 22:50:092257 UpdatePlayState();
watkdee516f2016-02-18 02:22:192258 }
2259}
2260
Blink Reformat1c4d759e2017-04-09 16:34:542261void WebMediaPlayerImpl::RequestRemotePlaybackDisabled(bool disabled) {
miu77f914c2016-11-19 23:56:182262 if (observer_)
2263 observer_->OnRemotePlaybackDisabled(disabled);
2264}
2265
hubbed5f36882016-01-15 22:40:372266#if defined(OS_ANDROID) // WMPI_CAST
Blink Reformat1c4d759e2017-04-09 16:34:542267bool WebMediaPlayerImpl::IsRemote() const {
hubbed5f36882016-01-15 22:40:372268 return cast_impl_.isRemote();
2269}
2270
2271void WebMediaPlayerImpl::SetMediaPlayerManager(
2272 RendererMediaPlayerManagerInterface* media_player_manager) {
2273 cast_impl_.SetMediaPlayerManager(media_player_manager);
2274}
2275
Blink Reformat1c4d759e2017-04-09 16:34:542276void WebMediaPlayerImpl::RequestRemotePlayback() {
hubbed5f36882016-01-15 22:40:372277 cast_impl_.requestRemotePlayback();
2278}
2279
Blink Reformat1c4d759e2017-04-09 16:34:542280void WebMediaPlayerImpl::RequestRemotePlaybackControl() {
hubbed5f36882016-01-15 22:40:372281 cast_impl_.requestRemotePlaybackControl();
2282}
2283
Blink Reformat1c4d759e2017-04-09 16:34:542284void WebMediaPlayerImpl::RequestRemotePlaybackStop() {
avayvod8d8c53b2016-11-04 16:10:302285 cast_impl_.requestRemotePlaybackStop();
2286}
2287
hubbed5f36882016-01-15 22:40:372288void WebMediaPlayerImpl::OnRemotePlaybackEnded() {
pkastingf5279482016-07-27 02:18:202289 DVLOG(1) << __func__;
hubbed5f36882016-01-15 22:40:372290 DCHECK(main_task_runner_->BelongsToCurrentThread());
2291
2292 ended_ = true;
Blink Reformat1c4d759e2017-04-09 16:34:542293 client_->TimeChanged();
hubbed5f36882016-01-15 22:40:372294}
2295
Thomas Guilbertb341bae02018-05-09 00:02:132296void WebMediaPlayerImpl::FlingingStarted() {
2297 DCHECK(main_task_runner_->BelongsToCurrentThread());
2298 DCHECK(!disable_pipeline_auto_suspend_);
2299 disable_pipeline_auto_suspend_ = true;
2300
Thomas Guilbert29ae1a902018-10-20 01:53:382301 is_flinging_ = true;
2302
Thomas Guilbertb341bae02018-05-09 00:02:132303 // Capabilities reporting should only be performed for local playbacks.
2304 video_decode_stats_reporter_.reset();
2305
2306 // Requests to restart media pipeline. A flinging renderer will be created via
2307 // the |renderer_factory_selector_|.
2308 ScheduleRestart();
2309}
2310
2311void WebMediaPlayerImpl::FlingingStopped() {
2312 DCHECK(main_task_runner_->BelongsToCurrentThread());
2313 DCHECK(disable_pipeline_auto_suspend_);
2314 disable_pipeline_auto_suspend_ = false;
2315
Thomas Guilbert29ae1a902018-10-20 01:53:382316 is_flinging_ = false;
2317
Thomas Guilbertb341bae02018-05-09 00:02:132318 CreateVideoDecodeStatsReporter();
2319
2320 ScheduleRestart();
2321}
2322
hubbed5f36882016-01-15 22:40:372323void WebMediaPlayerImpl::OnDisconnectedFromRemoteDevice(double t) {
sandersd1c0bba02016-03-04 23:14:082324 DoSeek(base::TimeDelta::FromSecondsD(t), false);
hubbed5f36882016-01-15 22:40:372325
Chris Cunninghamd9df58e2017-08-29 00:04:232326 // Capabilities reporting can resume now that playback is local.
2327 CreateVideoDecodeStatsReporter();
2328
Anton Vayvodfad2f3ea2017-07-19 21:45:272329 // |client_| might destroy us in methods below.
2330 UpdatePlayState();
2331
hubbed5f36882016-01-15 22:40:372332 // We already told the delegate we're paused when remoting started.
Mounir Lamouri703106e2018-05-30 14:31:092333 client_->RequestPause();
Blink Reformat1c4d759e2017-04-09 16:34:542334 client_->DisconnectedFromRemoteDevice();
hubbed5f36882016-01-15 22:40:372335}
2336
2337void WebMediaPlayerImpl::SuspendForRemote() {
Chris Cunninghamd9df58e2017-08-29 00:04:232338 // Capabilities reporting should only be performed for local playbacks.
2339 video_decode_stats_reporter_.reset();
2340
avayvod82729272017-05-29 21:58:392341 if (pipeline_controller_.IsPipelineSuspended() &&
2342 !IsNewRemotePlaybackPipelineEnabled()) {
hubbed5f36882016-01-15 22:40:372343 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner();
sandersd50a635e2016-04-04 22:50:092344 if (frame)
dalecurtise9c89e92016-05-20 19:38:002345 compositor_->PaintSingleFrame(frame);
hubbed5f36882016-01-15 22:40:372346 }
sandersd50a635e2016-04-04 22:50:092347
2348 UpdatePlayState();
hubbed5f36882016-01-15 22:40:372349}
2350
2351gfx::Size WebMediaPlayerImpl::GetCanvasSize() const {
lethalantidote7f6009d2017-07-07 21:47:392352 if (!surface_layer_for_video_enabled_) {
danakj6e669e782018-05-16 16:57:172353 if (!video_layer_)
lethalantidote7f6009d2017-07-07 21:47:392354 return pipeline_metadata_.natural_size;
2355
danakj6e669e782018-05-16 16:57:172356 return video_layer_->bounds();
lethalantidote7f6009d2017-07-07 21:47:392357 }
danakj8d204a42018-05-18 18:05:352358 if (!bridge_->GetCcLayer())
hubbed5f36882016-01-15 22:40:372359 return pipeline_metadata_.natural_size;
2360
danakj8d204a42018-05-18 18:05:352361 return bridge_->GetCcLayer()->bounds();
hubbed5f36882016-01-15 22:40:372362}
2363
2364void WebMediaPlayerImpl::SetDeviceScaleFactor(float scale_factor) {
2365 cast_impl_.SetDeviceScaleFactor(scale_factor);
2366}
Dan Sanderscd8981c2017-08-31 22:37:022367#endif // defined(OS_ANDROID) // WMPI_CAST
hubbee4027f92016-05-19 05:18:132368
Blink Reformat1c4d759e2017-04-09 16:34:542369void WebMediaPlayerImpl::SetPoster(const blink::WebURL& poster) {
Dan Sanderscd8981c2017-08-31 22:37:022370 has_poster_ = !poster.IsEmpty();
2371#if defined(OS_ANDROID) // WMPI_CAST
xjzc102fd82017-01-04 20:13:532372 cast_impl_.setPoster(poster);
xjz2504c4da2017-04-18 18:50:142373#endif // defined(OS_ANDROID) // WMPI_CAST
Dan Sanderscd8981c2017-08-31 22:37:022374}
xjzc102fd82017-01-04 20:13:532375
[email protected]fee8a902014-06-03 13:43:362376void WebMediaPlayerImpl::DataSourceInitialized(bool success) {
pkastingf5279482016-07-27 02:18:202377 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:432378 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]a9415292012-01-19 19:55:202379
Anton Vayvod09fa66e2017-07-20 23:02:122380 if (observer_ && IsNewRemotePlaybackPipelineEnabled() && data_source_)
2381 observer_->OnDataSourceInitialized(data_source_->GetUrlAfterRedirects());
2382
[email protected]d250190da3b2012-07-23 22:57:302383 if (!success) {
Blink Reformat1c4d759e2017-04-09 16:34:542384 SetNetworkState(WebMediaPlayer::kNetworkStateFormatError);
Dale Curtis74612b72017-12-14 20:56:192385 media_metrics_provider_->OnError(PIPELINE_ERROR_NETWORK);
sandersd50a635e2016-04-04 22:50:092386
2387 // Not really necessary, since the pipeline was never started, but it at
2388 // least this makes sure that the error handling code is in sync.
2389 UpdatePlayState();
2390
[email protected]a9415292012-01-19 19:55:202391 return;
2392 }
2393
hubbee2cc88c092017-07-14 23:10:412394 // No point in preloading data as we'll probably just throw it away anyways.
2395 if (IsStreaming() && preload_ > MultibufferDataSource::METADATA) {
2396 data_source_->SetPreload(MultibufferDataSource::METADATA);
2397 }
2398
[email protected]ef8394c2013-08-21 20:26:302399 StartPipeline();
[email protected]a9415292012-01-19 19:55:202400}
2401
[email protected]122f40252012-06-12 05:01:562402void WebMediaPlayerImpl::NotifyDownloading(bool is_downloading) {
hubbeb2d3efd2017-05-05 23:26:382403 DVLOG(1) << __func__ << "(" << is_downloading << ")";
Blink Reformat1c4d759e2017-04-09 16:34:542404 if (!is_downloading && network_state_ == WebMediaPlayer::kNetworkStateLoading)
2405 SetNetworkState(WebMediaPlayer::kNetworkStateIdle);
2406 else if (is_downloading &&
2407 network_state_ == WebMediaPlayer::kNetworkStateIdle)
2408 SetNetworkState(WebMediaPlayer::kNetworkStateLoading);
hubbeb2d3efd2017-05-05 23:26:382409 if (ready_state_ == ReadyState::kReadyStateHaveFutureData && !is_downloading)
2410 SetReadyState(WebMediaPlayer::kReadyStateHaveEnoughData);
[email protected]122f40252012-06-12 05:01:562411}
2412
liberato2ff93ad2017-05-17 07:28:242413void WebMediaPlayerImpl::OnOverlayRoutingToken(
2414 const base::UnguessableToken& token) {
2415 DCHECK(overlay_mode_ == OverlayMode::kUseAndroidOverlay);
liberatofe8f9692017-06-08 19:17:362416 // TODO(liberato): |token| should already be a RoutingToken.
2417 overlay_routing_token_is_pending_ = false;
2418 overlay_routing_token_ = OverlayInfo::RoutingToken(token);
liberato2ff93ad2017-05-17 07:28:242419 MaybeSendOverlayInfoToDecoder();
2420}
2421
2422void WebMediaPlayerImpl::OnOverlayInfoRequested(
dalecurtis4b632fce22016-11-10 00:52:172423 bool decoder_requires_restart_for_overlay,
liberato2ff93ad2017-05-17 07:28:242424 const ProvideOverlayInfoCB& provide_overlay_info_cb) {
watkdee516f2016-02-18 02:22:192425 DCHECK(main_task_runner_->BelongsToCurrentThread());
watkdee516f2016-02-18 02:22:192426
Chris Watkins557f84d2017-09-16 02:31:462427 // If we get a non-null cb, a decoder is initializing and requires overlay
2428 // info. If we get a null cb, a previously initialized decoder is
2429 // unregistering for overlay info updates.
Dale Curtise25163812018-09-21 22:13:392430 if (!provide_overlay_info_cb) {
tsunghungee562e92016-07-20 18:03:312431 decoder_requires_restart_for_overlay_ = false;
liberato2ff93ad2017-05-17 07:28:242432 provide_overlay_info_cb_.Reset();
watkdee516f2016-02-18 02:22:192433 return;
2434 }
2435
dalecurtis4b632fce22016-11-10 00:52:172436 // If |decoder_requires_restart_for_overlay| is true, we must restart the
2437 // pipeline for fullscreen transitions. The decoder is unable to switch
2438 // surfaces otherwise. If false, we simply need to tell the decoder about the
2439 // new surface and it will handle things seamlessly.
Chris Watkins557f84d2017-09-16 02:31:462440 // For encrypted video we pretend that the decoder doesn't require a restart
2441 // because it needs an overlay all the time anyway. We'll switch into
2442 // |always_enable_overlays_| mode below.
2443 decoder_requires_restart_for_overlay_ =
2444 (overlay_mode_ == OverlayMode::kUseAndroidOverlay && is_encrypted_)
2445 ? false
2446 : decoder_requires_restart_for_overlay;
liberato2ff93ad2017-05-17 07:28:242447 provide_overlay_info_cb_ = provide_overlay_info_cb;
dalecurtis4b632fce22016-11-10 00:52:172448
Chris Watkins557f84d2017-09-16 02:31:462449 // If the decoder doesn't require restarts for surface transitions, and we're
2450 // using AndroidOverlay mode, we can always enable the overlay and the decoder
2451 // can choose whether or not to use it. Otherwise, we'll restart the decoder
2452 // and enable the overlay on fullscreen transitions.
[email protected]77568482017-06-21 21:16:522453 if (overlay_mode_ == OverlayMode::kUseAndroidOverlay &&
Chris Watkins557f84d2017-09-16 02:31:462454 !decoder_requires_restart_for_overlay_) {
[email protected]c8d574722017-08-30 20:53:432455 always_enable_overlays_ = true;
[email protected]77568482017-06-21 21:16:522456 if (!overlay_enabled_)
2457 EnableOverlay();
2458 }
2459
Chris Watkins557f84d2017-09-16 02:31:462460 // Send the overlay info if we already have it. If not, it will be sent later.
liberato2ff93ad2017-05-17 07:28:242461 MaybeSendOverlayInfoToDecoder();
2462}
2463
2464void WebMediaPlayerImpl::MaybeSendOverlayInfoToDecoder() {
2465 // If the decoder didn't request overlay info, then don't send it.
2466 if (!provide_overlay_info_cb_)
dalecurtis4b632fce22016-11-10 00:52:172467 return;
2468
liberato2ff93ad2017-05-17 07:28:242469 // We should send the overlay info as long as we know it. This includes the
2470 // case where |!overlay_enabled_|, since we want to tell the decoder to avoid
2471 // using overlays. Assuming that the decoder has requested info, the only
2472 // case in which we don't want to send something is if we've requested the
2473 // info but not received it yet. Then, we should wait until we do.
liberatofe8f9692017-06-08 19:17:362474 //
2475 // Initialization requires this; AVDA should start with enough info to make an
2476 // overlay, so that (pre-M) the initial codec is created with the right output
2477 // surface; it can't switch later.
[email protected]f7df5b342018-07-13 20:22:132478 if (overlay_mode_ == OverlayMode::kUseAndroidOverlay) {
liberatofe8f9692017-06-08 19:17:362479 if (overlay_routing_token_is_pending_)
liberato2ff93ad2017-05-17 07:28:242480 return;
liberatofe8f9692017-06-08 19:17:362481
2482 overlay_info_.routing_token = overlay_routing_token_;
liberato2ff93ad2017-05-17 07:28:242483 }
2484
liberato2ff93ad2017-05-17 07:28:242485 // If restart is required, the callback is one-shot only.
2486 if (decoder_requires_restart_for_overlay_) {
Dale Curtise25163812018-09-21 22:13:392487 std::move(provide_overlay_info_cb_).Run(overlay_info_);
liberato2ff93ad2017-05-17 07:28:242488 } else {
liberatofe8f9692017-06-08 19:17:362489 provide_overlay_info_cb_.Run(overlay_info_);
liberato2ff93ad2017-05-17 07:28:242490 }
watkdee516f2016-02-18 02:22:192491}
2492
dcheng3076abbf2016-04-22 20:42:392493std::unique_ptr<Renderer> WebMediaPlayerImpl::CreateRenderer() {
dcheng37b415b92017-01-27 20:17:432494 DCHECK(main_task_runner_->BelongsToCurrentThread());
2495
[email protected]c8d574722017-08-30 20:53:432496 // Make sure that overlays are enabled if they're always allowed.
2497 if (always_enable_overlays_)
tsunghungee562e92016-07-20 18:03:312498 EnableOverlay();
2499
liberato2ff93ad2017-05-17 07:28:242500 RequestOverlayInfoCB request_overlay_info_cb;
watkdee516f2016-02-18 02:22:192501#if defined(OS_ANDROID)
liberato2ff93ad2017-05-17 07:28:242502 request_overlay_info_cb = BindToCurrentLoop(
2503 base::Bind(&WebMediaPlayerImpl::OnOverlayInfoRequested, AsWeakPtr()));
watkdee516f2016-02-18 02:22:192504#endif
tguilbert70d2a00a2017-04-25 00:30:442505 return renderer_factory_selector_->GetCurrentFactory()->CreateRenderer(
sandersd1e49fb62015-12-12 01:18:062506 media_task_runner_, worker_task_runner_, audio_source_provider_.get(),
CJ DiMeglio2302d202017-08-31 08:38:042507 compositor_.get(), request_overlay_info_cb, client_->TargetColorSpace());
sandersd1e49fb62015-12-12 01:18:062508}
2509
[email protected]ef8394c2013-08-21 20:26:302510void WebMediaPlayerImpl::StartPipeline() {
acolwellb4034942014-08-28 15:42:432511 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]ddbc6ff2013-04-19 15:28:332512
xhwange8c4181a2014-12-06 08:10:012513 Demuxer::EncryptedMediaInitDataCB encrypted_media_init_data_cb =
dcheng37b415b92017-01-27 20:17:432514 BindToCurrentLoop(base::Bind(
2515 &WebMediaPlayerImpl::OnEncryptedMediaInitData, AsWeakPtr()));
[email protected]2b57e2e2014-05-09 11:07:252516
Dale Curtis3899090ea2018-01-12 00:10:352517 vfc_task_runner_->PostTask(
2518 FROM_HERE,
2519 base::BindOnce(&VideoFrameCompositor::SetOnNewProcessedFrameCallback,
2520 base::Unretained(compositor_.get()),
2521 BindToCurrentLoop(base::BindOnce(
2522 &WebMediaPlayerImpl::OnFirstFrame, AsWeakPtr()))));
2523
tguilbert75e2bf62017-04-26 20:13:122524 if (renderer_factory_selector_->GetCurrentFactory()
2525 ->GetRequiredMediaResourceType() == MediaResource::Type::URL) {
2526 if (data_source_)
2527 loaded_url_ = data_source_->GetUrlAfterRedirects();
2528
2529 // MediaPlayerRendererClient factory is the only factory that a
2530 // MediaResource::Type::URL for the moment. This might no longer be true
2531 // when we remove WebMediaPlayerCast.
2532 //
2533 // TODO(tguilbert/avayvod): Update this flag when removing |cast_impl_|.
2534 using_media_player_renderer_ = true;
2535
Chris Cunninghamd9df58e2017-08-29 00:04:232536 // MediaPlayerRenderer does not provide pipeline stats, so nuke capabilities
2537 // reporter.
2538 video_decode_stats_reporter_.reset();
2539
Mike Westb85da8ed2017-08-10 14:16:462540 demuxer_.reset(new MediaUrlDemuxer(media_task_runner_, loaded_url_,
2541 frame_->GetDocument().SiteForCookies()));
Dale Curtisc00d56482018-02-09 20:55:062542 pipeline_controller_.Start(Pipeline::StartType::kNormal, demuxer_.get(),
2543 this, false, false);
tguilbert25a4d112016-10-13 21:56:512544 return;
2545 }
2546
[email protected]ddbc6ff2013-04-19 15:28:332547 // Figure out which demuxer to use.
Blink Reformat1c4d759e2017-04-09 16:34:542548 if (load_type_ != kLoadTypeMediaSource) {
[email protected]ddbc6ff2013-04-19 15:28:332549 DCHECK(!chunk_demuxer_);
[email protected]f5443ef72013-04-22 04:03:382550 DCHECK(data_source_);
2551
Dale Curtisbcf523b2018-01-17 02:59:012552#if BUILDFLAG(ENABLE_FFMPEG)
servolk81e01e02016-03-05 03:29:152553 Demuxer::MediaTracksUpdatedCB media_tracks_updated_cb =
dcheng37b415b92017-01-27 20:17:432554 BindToCurrentLoop(base::Bind(
2555 &WebMediaPlayerImpl::OnFFmpegMediaTracksUpdated, AsWeakPtr()));
servolk81e01e02016-03-05 03:29:152556
dalecurtis9cddc0b2017-04-19 21:23:382557 demuxer_.reset(new FFmpegDemuxer(
2558 media_task_runner_, data_source_.get(), encrypted_media_init_data_cb,
Dale Curtisb8139f72018-08-27 23:28:482559 media_tracks_updated_cb, media_log_.get(), IsLocalFile(loaded_url_)));
j.isorcef6778e652015-11-16 17:14:252560#else
alokp967c902452016-05-06 05:21:372561 OnError(PipelineStatus::DEMUXER_ERROR_COULD_NOT_OPEN);
j.isorcef6778e652015-11-16 17:14:252562 return;
2563#endif
[email protected]ddbc6ff2013-04-19 15:28:332564 } else {
[email protected]f5443ef72013-04-22 04:03:382565 DCHECK(!chunk_demuxer_);
2566 DCHECK(!data_source_);
2567
acolwell9e0840d2014-09-06 19:01:322568 chunk_demuxer_ = new ChunkDemuxer(
dcheng37b415b92017-01-27 20:17:432569 BindToCurrentLoop(
2570 base::Bind(&WebMediaPlayerImpl::OnDemuxerOpened, AsWeakPtr())),
Dan Sanders42311b52017-08-10 23:41:032571 BindToCurrentLoop(
2572 base::Bind(&WebMediaPlayerImpl::OnProgress, AsWeakPtr())),
dalecurtis9cddc0b2017-04-19 21:23:382573 encrypted_media_init_data_cb, media_log_.get());
John Delaneyb933391602018-10-17 21:50:472574 // Notify |this| of bytes that are received via MSE.
2575 chunk_demuxer_->AddBytesReceivedCallback(
2576 BindToCurrentLoop(base::BindRepeating(
2577 &WebMediaPlayerImpl::OnBytesReceived, AsWeakPtr())));
[email protected]f5443ef72013-04-22 04:03:382578 demuxer_.reset(chunk_demuxer_);
servolkf94b4602017-01-31 16:44:272579
2580 if (base::FeatureList::IsEnabled(kMemoryPressureBasedSourceBufferGC)) {
2581 // base::Unretained is safe because |this| owns memory_pressure_listener_.
2582 memory_pressure_listener_ =
Gyuyoung Kim62a5de42018-01-10 09:48:422583 std::make_unique<base::MemoryPressureListener>(base::Bind(
servolkf94b4602017-01-31 16:44:272584 &WebMediaPlayerImpl::OnMemoryPressure, base::Unretained(this)));
2585 }
[email protected]ddbc6ff2013-04-19 15:28:332586 }
2587
sandersdb5e21462016-03-09 01:49:072588 // TODO(sandersd): FileSystem objects may also be non-static, but due to our
2589 // caching layer such situations are broken already. http://crbug.com/593159
2590 bool is_static = !chunk_demuxer_;
avayvod102cdb62017-01-07 03:11:092591 bool is_streaming = IsStreaming();
sandersdb8eb5f1d2016-11-19 04:04:022592 UMA_HISTOGRAM_BOOLEAN("Media.IsStreaming", is_streaming);
sandersdb5e21462016-03-09 01:49:072593
Dale Curtis2dc6089a2018-03-26 16:47:582594 // If possible attempt to avoid decoder spool up until playback starts.
2595 Pipeline::StartType start_type = Pipeline::StartType::kNormal;
Dale Curtis7c63f2e22018-09-19 21:06:272596 if (!chunk_demuxer_ && preload_ == MultibufferDataSource::METADATA &&
Dale Curtisf5a7c9212018-04-10 21:57:342597 !client_->CouldPlayIfEnoughData()) {
Dale Curtis7c63f2e22018-09-19 21:06:272598 start_type =
2599 (has_poster_ || base::FeatureList::IsEnabled(kPreloadMetadataLazyLoad))
2600 ? Pipeline::StartType::kSuspendAfterMetadata
2601 : Pipeline::StartType::kSuspendAfterMetadataForAudioOnly;
Dale Curtis2dc6089a2018-03-26 16:47:582602 attempting_suspended_start_ = true;
2603 }
2604
[email protected]f5443ef72013-04-22 04:03:382605 // ... and we're ready to go!
sandersd1e49fb62015-12-12 01:18:062606 // TODO(sandersd): On Android, defer Start() if the tab is not visible.
sandersdb8eb5f1d2016-11-19 04:04:022607 seeking_ = true;
Dale Curtis2dc6089a2018-03-26 16:47:582608 pipeline_controller_.Start(start_type, demuxer_.get(), this, is_streaming,
2609 is_static);
[email protected]f5443ef72013-04-22 04:03:382610}
2611
2612void WebMediaPlayerImpl::SetNetworkState(WebMediaPlayer::NetworkState state) {
pkastingf5279482016-07-27 02:18:202613 DVLOG(1) << __func__ << "(" << state << ")";
acolwellb4034942014-08-28 15:42:432614 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]f5443ef72013-04-22 04:03:382615 network_state_ = state;
2616 // Always notify to ensure client has the latest value.
Blink Reformat1c4d759e2017-04-09 16:34:542617 client_->NetworkStateChanged();
[email protected]f5443ef72013-04-22 04:03:382618}
2619
2620void WebMediaPlayerImpl::SetReadyState(WebMediaPlayer::ReadyState state) {
pkastingf5279482016-07-27 02:18:202621 DVLOG(1) << __func__ << "(" << state << ")";
acolwellb4034942014-08-28 15:42:432622 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]f5443ef72013-04-22 04:03:382623
Blink Reformat1c4d759e2017-04-09 16:34:542624 if (state == WebMediaPlayer::kReadyStateHaveEnoughData && data_source_ &&
[email protected]fee8a902014-06-03 13:43:362625 data_source_->assume_fully_buffered() &&
Blink Reformat1c4d759e2017-04-09 16:34:542626 network_state_ == WebMediaPlayer::kNetworkStateLoading)
2627 SetNetworkState(WebMediaPlayer::kNetworkStateLoaded);
[email protected]f5443ef72013-04-22 04:03:382628
2629 ready_state_ = state;
sandersd50a635e2016-04-04 22:50:092630 highest_ready_state_ = std::max(highest_ready_state_, ready_state_);
2631
[email protected]f5443ef72013-04-22 04:03:382632 // Always notify to ensure client has the latest value.
Blink Reformat1c4d759e2017-04-09 16:34:542633 client_->ReadyStateChanged();
[email protected]f5443ef72013-04-22 04:03:382634}
2635
Blink Reformat1c4d759e2017-04-09 16:34:542636blink::WebAudioSourceProvider* WebMediaPlayerImpl::GetAudioSourceProvider() {
[email protected]ff875be52013-06-02 23:47:382637 return audio_source_provider_.get();
[email protected]f5443ef72013-04-22 04:03:382638}
2639
Jiajia Qin82acdc02017-07-31 09:55:142640scoped_refptr<VideoFrame> WebMediaPlayerImpl::GetCurrentFrameFromCompositor()
2641 const {
xhwang213e50c2016-10-10 23:56:312642 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]dd061e12014-05-06 19:21:222643 TRACE_EVENT0("media", "WebMediaPlayerImpl::GetCurrentFrameFromCompositor");
xhwang213e50c2016-10-10 23:56:312644
Thomas Guilbertd85407412017-11-08 05:03:462645 // Can be null.
2646 scoped_refptr<VideoFrame> video_frame =
2647 compositor_->GetCurrentFrameOnAnyThread();
[email protected]dd061e12014-05-06 19:21:222648
Thomas Guilbertd85407412017-11-08 05:03:462649 // base::Unretained is safe here because |compositor_| is destroyed on
2650 // |vfc_task_runner_|. The destruction is queued from |this|' destructor,
2651 // which also runs on |main_task_runner_|, which makes it impossible for
2652 // UpdateCurrentFrameIfStale() to be queued after |compositor_|'s dtor.
CJ DiMeglio2302d202017-08-31 08:38:042653 vfc_task_runner_->PostTask(
Dale Curtisee9be30012018-09-21 22:21:512654 FROM_HERE,
2655 base::BindOnce(&VideoFrameCompositor::UpdateCurrentFrameIfStale,
2656 base::Unretained(compositor_.get())));
kainino36eeff82017-03-30 00:55:302657
[email protected]dd061e12014-05-06 19:21:222658 return video_frame;
2659}
2660
sandersd50a635e2016-04-04 22:50:092661void WebMediaPlayerImpl::UpdatePlayState() {
xhwang213e50c2016-10-10 23:56:312662 DCHECK(main_task_runner_->BelongsToCurrentThread());
2663
hubbed5f36882016-01-15 22:40:372664#if defined(OS_ANDROID) // WMPI_CAST
Blink Reformat1c4d759e2017-04-09 16:34:542665 bool is_remote = IsRemote();
xjz4e5d4bf32017-02-15 21:26:352666 bool can_auto_suspend = true;
sandersd50a635e2016-04-04 22:50:092667#else
2668 bool is_remote = false;
hubbee2cc88c092017-07-14 23:10:412669 bool can_auto_suspend = !disable_pipeline_auto_suspend_;
2670 // For streaming videos, we only allow suspending at the very beginning of the
2671 // video, and only if we know the length of the video. (If we don't know
2672 // the length, it might be a dynamically generated video, and suspending
2673 // will not work at all.)
2674 if (IsStreaming()) {
2675 bool at_beginning =
2676 ready_state_ == WebMediaPlayer::kReadyStateHaveNothing ||
2677 CurrentTime() == 0.0;
2678 if (!at_beginning || GetPipelineMediaDuration() == kInfiniteDuration)
2679 can_auto_suspend = false;
2680 }
hubbed5f36882016-01-15 22:40:372681#endif
xhwang213e50c2016-10-10 23:56:312682
dalecurtis8b8505e72016-06-10 21:59:172683 bool is_suspended = pipeline_controller_.IsSuspended();
Sergey Volk8b09c2c52018-12-12 23:20:402684 bool is_backgrounded = IsBackgroundSuspendEnabled(this) && IsHidden();
sandersdaaff1a652016-11-17 01:47:252685 PlayState state = UpdatePlayState_ComputePlayState(
Thomas Guilbert4c6feff2018-11-09 19:53:322686 is_remote, is_flinging_, can_auto_suspend, is_suspended, is_backgrounded);
sandersd35d2c3f2017-01-14 02:04:422687 SetDelegateState(state.delegate_state, state.is_idle);
sandersd50a635e2016-04-04 22:50:092688 SetMemoryReportingState(state.is_memory_reporting_enabled);
2689 SetSuspendState(state.is_suspended || pending_suspend_resume_cycle_);
2690}
dalecurtis5bbc487e2016-02-27 04:15:052691
sandersd35d2c3f2017-01-14 02:04:422692void WebMediaPlayerImpl::SetDelegateState(DelegateState new_state,
2693 bool is_idle) {
tguilbert1bb1c782017-01-23 21:15:112694 DCHECK(delegate_);
Dale Curtis779ed842018-03-10 06:20:132695 DVLOG(2) << __func__ << "(" << static_cast<int>(new_state) << ", " << is_idle
2696 << ")";
dalecurtis5bbc487e2016-02-27 04:15:052697
sandersd35d2c3f2017-01-14 02:04:422698 // Prevent duplicate delegate calls.
2699 // TODO(sandersd): Move this deduplication into the delegate itself.
2700 // TODO(sandersd): WebContentsObserverSanityChecker does not allow sending the
2701 // 'playing' IPC more than once in a row, even if the metadata has changed.
2702 // Figure out whether it should.
Mounir Lamouri366dd8472018-06-19 17:20:042703 // Pretend that the media has no audio if it never played unmuted. This is to
2704 // avoid any action related to audible media such as taking audio focus or
2705 // showing a media notification. To preserve a consistent experience, it does
2706 // not apply if a media was audible so the system states do not flicker
2707 // depending on whether the user muted the player.
2708 bool has_audio = HasAudio() && !client_->WasAlwaysMuted();
sandersd35d2c3f2017-01-14 02:04:422709 if (delegate_state_ == new_state &&
2710 (delegate_state_ != DelegateState::PLAYING ||
2711 delegate_has_audio_ == has_audio)) {
2712 return;
mlamouri910111362016-11-04 11:28:242713 }
sandersd50a635e2016-04-04 22:50:092714 delegate_state_ = new_state;
sandersd35d2c3f2017-01-14 02:04:422715 delegate_has_audio_ = has_audio;
sandersd50a635e2016-04-04 22:50:092716
sandersd35d2c3f2017-01-14 02:04:422717 switch (new_state) {
sandersd50a635e2016-04-04 22:50:092718 case DelegateState::GONE:
2719 delegate_->PlayerGone(delegate_id_);
2720 break;
mlamouri910111362016-11-04 11:28:242721 case DelegateState::PLAYING: {
peconn257951522017-06-09 18:24:592722 if (HasVideo())
2723 delegate_->DidPlayerSizeChange(delegate_id_, NaturalSize());
zqzhang5d8eab72016-08-26 20:34:302724 delegate_->DidPlay(
Blink Reformat1c4d759e2017-04-09 16:34:542725 delegate_id_, HasVideo(), has_audio,
avayvodcc273dd2017-01-19 19:35:122726 media::DurationToMediaContentType(GetPipelineMediaDuration()));
sandersd50a635e2016-04-04 22:50:092727 break;
mlamouri910111362016-11-04 11:28:242728 }
sandersd50a635e2016-04-04 22:50:092729 case DelegateState::PAUSED:
sandersd35d2c3f2017-01-14 02:04:422730 delegate_->DidPause(delegate_id_);
sandersd50a635e2016-04-04 22:50:092731 break;
dalecurtis0f0097a2015-12-01 17:40:472732 }
sandersd35d2c3f2017-01-14 02:04:422733
2734 delegate_->SetIdle(delegate_id_, is_idle);
dalecurtis0f0097a2015-12-01 17:40:472735}
2736
sandersd50a635e2016-04-04 22:50:092737void WebMediaPlayerImpl::SetMemoryReportingState(
2738 bool is_memory_reporting_enabled) {
2739 if (memory_usage_reporting_timer_.IsRunning() ==
2740 is_memory_reporting_enabled) {
hubbed5f36882016-01-15 22:40:372741 return;
sandersd50a635e2016-04-04 22:50:092742 }
sandersd1c0bba02016-03-04 23:14:082743
sandersd50a635e2016-04-04 22:50:092744 if (is_memory_reporting_enabled) {
2745 memory_usage_reporting_timer_.Start(FROM_HERE,
2746 base::TimeDelta::FromSeconds(2), this,
2747 &WebMediaPlayerImpl::ReportMemoryUsage);
2748 } else {
2749 memory_usage_reporting_timer_.Stop();
2750 ReportMemoryUsage();
2751 }
2752}
2753
2754void WebMediaPlayerImpl::SetSuspendState(bool is_suspended) {
xhwang213e50c2016-10-10 23:56:312755 DCHECK(main_task_runner_->BelongsToCurrentThread());
Dale Curtis779ed842018-03-10 06:20:132756 DVLOG(2) << __func__ << "(" << is_suspended << ")";
xhwang213e50c2016-10-10 23:56:312757
sandersd50a635e2016-04-04 22:50:092758 // Do not change the state after an error has occurred.
2759 // TODO(sandersd): Update PipelineController to remove the need for this.
2760 if (IsNetworkStateError(network_state_))
sandersd1c0bba02016-03-04 23:14:082761 return;
2762
jameswest451a5bb2017-01-27 03:59:392763 if (is_suspended) {
sandersd35d2c3f2017-01-14 02:04:422764 // If we were not resumed for long enough to satisfy the preroll attempt,
2765 // reset the clock.
2766 if (!preroll_attempt_pending_ && IsPrerollAttemptNeeded()) {
2767 preroll_attempt_pending_ = true;
2768 preroll_attempt_start_time_ = base::TimeTicks();
2769 }
sandersd50a635e2016-04-04 22:50:092770 pipeline_controller_.Suspend();
2771 } else {
sandersd35d2c3f2017-01-14 02:04:422772 // When resuming, start the preroll attempt clock.
2773 if (preroll_attempt_pending_) {
2774 preroll_attempt_pending_ = false;
2775 preroll_attempt_start_time_ = tick_clock_->NowTicks();
2776 }
sandersd50a635e2016-04-04 22:50:092777 pipeline_controller_.Resume();
2778 }
2779}
2780
Thomas Guilbert4c6feff2018-11-09 19:53:322781// NOTE: |is_remote| and |is_flinging| both indicate that we are in a remote
2782// playback session, with the following differences:
2783// - |is_remote| : we are using |cast_impl_|, and most of WMPI's functions
2784// are forwarded to it. This method of remote playback is scheduled
2785// for deprecation soon, in favor of the |is_flinging| path.
2786// - |is_flinging| : we are using the FlingingRenderer, and WMPI should
2787// behave exactly if we are using the DefaultRenderer, except for the
2788// disabling of certain optimizations.
2789// See https://crbug.com/790766.
sandersd50a635e2016-04-04 22:50:092790WebMediaPlayerImpl::PlayState
2791WebMediaPlayerImpl::UpdatePlayState_ComputePlayState(bool is_remote,
Thomas Guilbert4c6feff2018-11-09 19:53:322792 bool is_flinging,
xjz4e5d4bf32017-02-15 21:26:352793 bool can_auto_suspend,
dalecurtis8b8505e72016-06-10 21:59:172794 bool is_suspended,
sandersd50a635e2016-04-04 22:50:092795 bool is_backgrounded) {
2796 PlayState result;
2797
tguilbert1bb1c782017-01-23 21:15:112798 bool must_suspend = delegate_->IsFrameClosed();
Dale Curtis6438cf12018-03-29 02:34:012799 bool is_stale = delegate_->IsStale(delegate_id_);
2800
2801 if (stale_state_override_for_testing_.has_value() &&
2802 ready_state_ >= stale_state_override_for_testing_.value()) {
2803 is_stale = true;
2804 }
sandersd35d2c3f2017-01-14 02:04:422805
sandersd50a635e2016-04-04 22:50:092806 // This includes both data source (before pipeline startup) and pipeline
2807 // errors.
2808 bool has_error = IsNetworkStateError(network_state_);
2809
dalecurtiscc8baf72016-10-27 01:49:442810 // After HaveFutureData, Blink will call play() if the state is not paused;
2811 // prior to this point |paused_| is not accurate.
sandersd50a635e2016-04-04 22:50:092812 bool have_future_data =
Blink Reformat1c4d759e2017-04-09 16:34:542813 highest_ready_state_ >= WebMediaPlayer::kReadyStateHaveFutureData;
sandersd50a635e2016-04-04 22:50:092814
avayvod65fad272017-02-24 01:00:482815 // Background suspend is only enabled for paused players.
2816 // In the case of players with audio the session should be kept.
2817 bool background_suspended =
xjz4e5d4bf32017-02-15 21:26:352818 can_auto_suspend && is_backgrounded && paused_ && have_future_data;
sandersd50a635e2016-04-04 22:50:092819
dalecurtiscc8baf72016-10-27 01:49:442820 // Idle suspension is allowed prior to have future data since there exist
2821 // mechanisms to exit the idle state when the player is capable of reaching
2822 // the have future data state; see didLoadingProgress().
2823 //
sandersd50a635e2016-04-04 22:50:092824 // TODO(sandersd): Make the delegate suspend idle players immediately when
2825 // hidden.
Dale Curtis7c63f2e22018-09-19 21:06:272826 bool idle_suspended = can_auto_suspend && is_stale && paused_ && !seeking_ &&
2827 !overlay_enabled_ && !needs_first_frame_;
dalecurtise7120dc2016-09-03 02:54:352828
2829 // If we're already suspended, see if we can wait for user interaction. Prior
sandersd35d2c3f2017-01-14 02:04:422830 // to HaveFutureData, we require |is_stale| to remain suspended. |is_stale|
dalecurtise7120dc2016-09-03 02:54:352831 // will be cleared when we receive data which may take us to HaveFutureData.
Dale Curtis7c63f2e22018-09-19 21:06:272832 bool can_stay_suspended = (is_stale || have_future_data) && is_suspended &&
2833 paused_ && !seeking_ && !needs_first_frame_;
sandersd50a635e2016-04-04 22:50:092834
2835 // Combined suspend state.
sandersd35d2c3f2017-01-14 02:04:422836 result.is_suspended = is_remote || must_suspend || idle_suspended ||
avayvod65fad272017-02-24 01:00:482837 background_suspended || can_stay_suspended;
sandersd50a635e2016-04-04 22:50:092838
Dale Curtis779ed842018-03-10 06:20:132839 DVLOG(3) << __func__ << ": is_remote=" << is_remote
2840 << ", must_suspend=" << must_suspend
2841 << ", idle_suspended=" << idle_suspended
2842 << ", background_suspended=" << background_suspended
2843 << ", can_stay_suspended=" << can_stay_suspended
2844 << ", is_stale=" << is_stale
2845 << ", have_future_data=" << have_future_data
2846 << ", paused_=" << paused_ << ", seeking_=" << seeking_;
2847
sandersd50a635e2016-04-04 22:50:092848 // We do not treat |playback_rate_| == 0 as paused. For the media session,
2849 // being paused implies displaying a play button, which is incorrect in this
2850 // case. For memory usage reporting, we just use the same definition (but we
2851 // don't have to).
2852 //
2853 // Similarly, we don't consider |ended_| to be paused. Blink will immediately
2854 // call pause() or seek(), so |ended_| should not affect the computation.
2855 // Despite that, |ended_| does result in a separate paused state, to simplfy
2856 // the contract for SetDelegateState().
2857 //
avayvod65fad272017-02-24 01:00:482858 // |has_remote_controls| indicates if the player can be controlled outside the
2859 // page (e.g. via the notification controls or by audio focus events). Idle
sandersd50a635e2016-04-04 22:50:092860 // suspension does not destroy the media session, because we expect that the
avayvod5f34b642017-03-23 03:14:042861 // notification controls (and audio focus) remain. With some exceptions for
2862 // background videos, the player only needs to have audio to have controls
2863 // (requires |have_future_data|).
2864 //
2865 // |alive| indicates if the player should be present (not |GONE|) to the
2866 // delegate, either paused or playing. The following must be true for the
2867 // player:
sandersd50a635e2016-04-04 22:50:092868 // - |have_future_data|, since we need to know whether we are paused to
avayvod65fad272017-02-24 01:00:482869 // correctly configure the session and also because the tracks and
avayvod5f34b642017-03-23 03:14:042870 // duration are passed to DidPlay(),
Thomas Guilbert4c6feff2018-11-09 19:53:322871 // - |is_remote| and |is_flinging| are false as remote playback is not
2872 // handled by the delegate,
avayvod5f34b642017-03-23 03:14:042873 // - |has_error| is false as player should have no errors,
2874 // - |background_suspended| is false, otherwise |has_remote_controls| must
2875 // be true.
sandersd50a635e2016-04-04 22:50:092876 //
avayvod65fad272017-02-24 01:00:482877 // TODO(sandersd): If Blink told us the paused state sooner, we could detect
2878 // if the remote controls are available sooner.
2879
2880 // Background videos with audio don't have remote controls if background
2881 // suspend is enabled and resuming background videos is not (original Android
2882 // behavior).
2883 bool backgrounded_video_has_no_remote_controls =
Sergey Volk8b09c2c52018-12-12 23:20:402884 IsBackgroundSuspendEnabled(this) && !IsResumeBackgroundVideosEnabled() &&
2885 is_backgrounded && HasVideo();
Thomas Guilbert4c6feff2018-11-09 19:53:322886 bool can_play = !has_error && have_future_data;
avayvod5f34b642017-03-23 03:14:042887 bool has_remote_controls =
Blink Reformat1c4d759e2017-04-09 16:34:542888 HasAudio() && !backgrounded_video_has_no_remote_controls;
Thomas Guilbert4c6feff2018-11-09 19:53:322889 bool in_remote_playback = is_remote || is_flinging;
2890 bool alive = can_play && !in_remote_playback && !must_suspend &&
avayvod5f34b642017-03-23 03:14:042891 (!background_suspended || has_remote_controls);
2892 if (!alive) {
Thomas Guilbert4c6feff2018-11-09 19:53:322893 // Do not mark players as idle when flinging.
sandersd50a635e2016-04-04 22:50:092894 result.delegate_state = DelegateState::GONE;
Thomas Guilbert4c6feff2018-11-09 19:53:322895 result.is_idle = delegate_->IsIdle(delegate_id_) && !is_flinging;
avayvod65fad272017-02-24 01:00:482896 } else if (paused_) {
sandersd35d2c3f2017-01-14 02:04:422897 // TODO(sandersd): Is it possible to have a suspended session, be ended,
2898 // and not be paused? If so we should be in a PLAYING state.
dalecurtise7120dc2016-09-03 02:54:352899 result.delegate_state =
sandersd35d2c3f2017-01-14 02:04:422900 ended_ ? DelegateState::GONE : DelegateState::PAUSED;
2901 result.is_idle = !seeking_;
sandersd50a635e2016-04-04 22:50:092902 } else {
2903 result.delegate_state = DelegateState::PLAYING;
sandersd35d2c3f2017-01-14 02:04:422904 result.is_idle = false;
sandersd50a635e2016-04-04 22:50:092905 }
2906
dalecurtis8b8505e72016-06-10 21:59:172907 // It's not critical if some cases where memory usage can change are missed,
sandersd50a635e2016-04-04 22:50:092908 // since media memory changes are usually gradual.
2909 result.is_memory_reporting_enabled =
Thomas Guilbert4c6feff2018-11-09 19:53:322910 !has_error && can_play && !in_remote_playback && !result.is_suspended &&
2911 (!paused_ || seeking_);
sandersd50a635e2016-04-04 22:50:092912
2913 return result;
dalecurtis0f0097a2015-12-01 17:40:472914}
2915
dalecurtis83266c72015-10-29 18:43:202916void WebMediaPlayerImpl::ReportMemoryUsage() {
2917 DCHECK(main_task_runner_->BelongsToCurrentThread());
2918
wdzierzanowskifd4cd91c52015-12-02 23:50:202919 // About base::Unretained() usage below: We destroy |demuxer_| on the main
2920 // thread. Before that, however, ~WebMediaPlayerImpl() posts a task to the
2921 // media thread and waits for it to finish. Hence, the GetMemoryUsage() task
2922 // posted here must finish earlier.
Dale Curtis8a6281322017-08-31 00:35:532923 //
2924 // The exception to the above is when OnError() has been called. If we're in
2925 // the error state we've already shut down the pipeline and can't rely on it
2926 // to cycle the media thread before we destroy |demuxer_|. In this case skip
2927 // collection of the demuxer memory stats.
2928 if (demuxer_ && !IsNetworkStateError(network_state_)) {
wdzierzanowskifd4cd91c52015-12-02 23:50:202929 base::PostTaskAndReplyWithResult(
2930 media_task_runner_.get(), FROM_HERE,
2931 base::Bind(&Demuxer::GetMemoryUsage, base::Unretained(demuxer_.get())),
2932 base::Bind(&WebMediaPlayerImpl::FinishMemoryUsageReport, AsWeakPtr()));
2933 } else {
2934 FinishMemoryUsageReport(0);
2935 }
2936}
2937
2938void WebMediaPlayerImpl::FinishMemoryUsageReport(int64_t demuxer_memory_usage) {
2939 DCHECK(main_task_runner_->BelongsToCurrentThread());
2940
avayvodc4bfb0e62017-01-13 01:07:012941 const PipelineStatistics stats = GetPipelineStatistics();
servolk639473e492016-12-15 04:14:202942 const int64_t data_source_memory_usage =
2943 data_source_ ? data_source_->GetMemoryUsage() : 0;
dalecurtisecc76612017-04-19 00:31:202944
Dale Curtisc2c5dcb12018-04-16 23:21:292945 // If we have video and no video memory usage and we've rendered the first
2946 // frame, assume the VideoFrameCompositor is holding onto the last frame after
2947 // we've suspended the pipeline; which thus reports zero memory usage from the
2948 // video renderer.
dalecurtisecc76612017-04-19 00:31:202949 //
2950 // Technically this should use the coded size, but that requires us to hop to
2951 // the compositor to get and byte-perfect accuracy isn't important here.
2952 const int64_t video_memory_usage =
2953 stats.video_memory_usage +
Dale Curtisc2c5dcb12018-04-16 23:21:292954 ((pipeline_metadata_.has_video && !stats.video_memory_usage &&
2955 has_first_frame_)
Miguel Casas9e7766022018-01-08 16:13:132956 ? VideoFrame::AllocationSize(PIXEL_FORMAT_I420,
dalecurtisecc76612017-04-19 00:31:202957 pipeline_metadata_.natural_size)
2958 : 0);
2959
dalecurtis83266c72015-10-29 18:43:202960 const int64_t current_memory_usage =
dalecurtisecc76612017-04-19 00:31:202961 stats.audio_memory_usage + video_memory_usage + data_source_memory_usage +
2962 demuxer_memory_usage;
dalecurtis83266c72015-10-29 18:43:202963
dalecurtisecc76612017-04-19 00:31:202964 DVLOG(2) << "Memory Usage -- Total: " << current_memory_usage
2965 << " Audio: " << stats.audio_memory_usage
2966 << ", Video: " << video_memory_usage
servolk639473e492016-12-15 04:14:202967 << ", DataSource: " << data_source_memory_usage
wdzierzanowskifd4cd91c52015-12-02 23:50:202968 << ", Demuxer: " << demuxer_memory_usage;
dalecurtis83266c72015-10-29 18:43:202969
2970 const int64_t delta = current_memory_usage - last_reported_memory_usage_;
2971 last_reported_memory_usage_ = current_memory_usage;
2972 adjust_allocated_memory_cb_.Run(delta);
servolk639473e492016-12-15 04:14:202973
Blink Reformat1c4d759e2017-04-09 16:34:542974 if (HasAudio()) {
servolk639473e492016-12-15 04:14:202975 UMA_HISTOGRAM_MEMORY_KB("Media.WebMediaPlayerImpl.Memory.Audio",
2976 stats.audio_memory_usage / 1024);
2977 }
Blink Reformat1c4d759e2017-04-09 16:34:542978 if (HasVideo()) {
servolk639473e492016-12-15 04:14:202979 UMA_HISTOGRAM_MEMORY_KB("Media.WebMediaPlayerImpl.Memory.Video",
dalecurtisecc76612017-04-19 00:31:202980 video_memory_usage / 1024);
servolk639473e492016-12-15 04:14:202981 }
2982 if (data_source_) {
2983 UMA_HISTOGRAM_MEMORY_KB("Media.WebMediaPlayerImpl.Memory.DataSource",
2984 data_source_memory_usage / 1024);
2985 }
2986 if (demuxer_) {
2987 UMA_HISTOGRAM_MEMORY_KB("Media.WebMediaPlayerImpl.Memory.Demuxer",
2988 demuxer_memory_usage / 1024);
2989 }
dalecurtis83266c72015-10-29 18:43:202990}
2991
dalecurtis8b8505e72016-06-10 21:59:172992void WebMediaPlayerImpl::ScheduleIdlePauseTimer() {
avayvod65fad272017-02-24 01:00:482993 // Only schedule the pause timer if we're not paused or paused but going to
avayvod52efd282017-03-07 21:13:042994 // resume when foregrounded, and are suspended and have audio.
2995 if ((paused_ && !paused_when_hidden_) ||
Blink Reformat1c4d759e2017-04-09 16:34:542996 !pipeline_controller_.IsSuspended() || !HasAudio()) {
dalecurtis8b8505e72016-06-10 21:59:172997 return;
avayvod52efd282017-03-07 21:13:042998 }
dalecurtis8b8505e72016-06-10 21:59:172999
3000#if defined(OS_ANDROID)
3001 // Remote players will be suspended and locally paused.
Blink Reformat1c4d759e2017-04-09 16:34:543002 if (IsRemote())
dalecurtis8b8505e72016-06-10 21:59:173003 return;
3004#endif
3005
3006 // Idle timeout chosen arbitrarily.
3007 background_pause_timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(5),
3008 this, &WebMediaPlayerImpl::OnPause);
3009}
3010
dalecurtis04bdb582016-08-17 22:15:233011void WebMediaPlayerImpl::CreateWatchTimeReporter() {
wdzierzanowskia78fa9b2017-06-13 18:12:103012 if (!HasVideo() && !HasAudio())
3013 return;
3014
dalecurtis04bdb582016-08-17 22:15:233015 // Create the watch time reporter and synchronize its initial state.
Dale Curtis1adbe6a2017-08-02 02:09:133016 watch_time_reporter_.reset(new WatchTimeReporter(
Dale Curtis96d6e9382018-07-18 18:01:073017 mojom::PlaybackProperties::New(pipeline_metadata_.has_audio,
3018 pipeline_metadata_.has_video, false, false,
3019 !!chunk_demuxer_, is_encrypted_,
3020 embedded_media_experience_enabled_),
3021 pipeline_metadata_.natural_size,
Dale Curtis051fdf62017-08-05 00:21:133022 base::BindRepeating(&WebMediaPlayerImpl::GetCurrentTimeInternal,
3023 base::Unretained(this)),
Hajime Hoshi8bb37dc2017-12-19 09:35:103024 media_metrics_provider_.get(),
Hajime Hoshib5a26ee2018-05-14 12:47:513025 frame_->GetTaskRunner(blink::TaskType::kInternalMedia)));
dalecurtis04bdb582016-08-17 22:15:233026 watch_time_reporter_->OnVolumeChange(volume_);
Dale Curtisaebaeea2018-07-19 23:42:113027 watch_time_reporter_->OnDurationChanged(GetPipelineMediaDuration());
Mounir Lamourif9af74e72017-06-19 19:31:453028
tguilbert1bb1c782017-01-23 21:15:113029 if (delegate_->IsFrameHidden())
dalecurtis04bdb582016-08-17 22:15:233030 watch_time_reporter_->OnHidden();
3031 else
3032 watch_time_reporter_->OnShown();
Mounir Lamourif9af74e72017-06-19 19:31:453033
Mounir Lamouri41a79c62017-06-06 12:53:163034 if (client_->HasNativeControls())
3035 watch_time_reporter_->OnNativeControlsEnabled();
3036 else
3037 watch_time_reporter_->OnNativeControlsDisabled();
Mounir Lamourif9af74e72017-06-19 19:31:453038
3039 switch (client_->DisplayType()) {
3040 case WebMediaPlayer::DisplayType::kInline:
3041 watch_time_reporter_->OnDisplayTypeInline();
3042 break;
3043 case WebMediaPlayer::DisplayType::kFullscreen:
3044 watch_time_reporter_->OnDisplayTypeFullscreen();
3045 break;
3046 case WebMediaPlayer::DisplayType::kPictureInPicture:
3047 watch_time_reporter_->OnDisplayTypePictureInPicture();
3048 break;
3049 }
Dale Curtis96d6e9382018-07-18 18:01:073050
3051 UpdateSecondaryProperties();
Dale Curtis7fd27c4b2018-07-30 22:14:213052
3053 // If the WatchTimeReporter was recreated in the middle of playback, we want
3054 // to resume playback here too since we won't get another play() call. When
3055 // seeking, the seek completion will restart it if necessary.
3056 if (!paused_ && !seeking_)
3057 watch_time_reporter_->OnPlaying();
Dale Curtis96d6e9382018-07-18 18:01:073058}
3059
3060void WebMediaPlayerImpl::UpdateSecondaryProperties() {
3061 watch_time_reporter_->UpdateSecondaryProperties(
3062 mojom::SecondaryPlaybackProperties::New(
3063 pipeline_metadata_.audio_decoder_config.codec(),
3064 pipeline_metadata_.video_decoder_config.codec(), audio_decoder_name_,
John Rummelld30555352018-09-21 20:47:253065 video_decoder_name_,
3066 DetermineEncryptionMode(
3067 pipeline_metadata_.audio_decoder_config.encryption_scheme()),
3068 DetermineEncryptionMode(
3069 pipeline_metadata_.video_decoder_config.encryption_scheme()),
3070 pipeline_metadata_.natural_size));
dalecurtis04bdb582016-08-17 22:15:233071}
3072
avayvod39c102402016-11-23 21:43:133073bool WebMediaPlayerImpl::IsHidden() const {
3074 DCHECK(main_task_runner_->BelongsToCurrentThread());
3075
tguilbert1bb1c782017-01-23 21:15:113076 return delegate_->IsFrameHidden() && !delegate_->IsFrameClosed();
avayvod39c102402016-11-23 21:43:133077}
3078
avayvod102cdb62017-01-07 03:11:093079bool WebMediaPlayerImpl::IsStreaming() const {
3080 return data_source_ && data_source_->IsStreaming();
3081}
3082
liberato2fd111be2017-01-04 00:25:063083bool WebMediaPlayerImpl::DoesOverlaySupportMetadata() const {
Julien Isorce6c83d8de2017-10-12 13:11:293084 return pipeline_metadata_.video_decoder_config.video_rotation() ==
3085 VIDEO_ROTATION_0;
liberato2fd111be2017-01-04 00:25:063086}
3087
xjzaf29d4182016-12-16 01:52:323088void WebMediaPlayerImpl::ActivateViewportIntersectionMonitoring(bool activate) {
3089 DCHECK(main_task_runner_->BelongsToCurrentThread());
3090
Blink Reformat1c4d759e2017-04-09 16:34:543091 client_->ActivateViewportIntersectionMonitoring(activate);
xjzaf29d4182016-12-16 01:52:323092}
3093
Anton Vayvod09fa66e2017-07-20 23:02:123094void WebMediaPlayerImpl::UpdateRemotePlaybackCompatibility(bool is_compatible) {
3095 DCHECK(main_task_runner_->BelongsToCurrentThread());
3096
3097 client_->RemotePlaybackCompatibilityChanged(loaded_url_, is_compatible);
3098}
3099
Dale Curtis6438cf12018-03-29 02:34:013100void WebMediaPlayerImpl::ForceStaleStateForTesting(ReadyState target_state) {
3101 stale_state_override_for_testing_.emplace(target_state);
Dale Curtis99a9b482018-02-01 02:23:283102 UpdatePlayState();
3103}
3104
3105bool WebMediaPlayerImpl::IsSuspendedForTesting() {
3106 // This intentionally uses IsPipelineSuspended since we need to know when the
3107 // pipeline has reached the suspended state, not when it's in suspending.
3108 return pipeline_controller_.IsPipelineSuspended();
3109}
3110
Dale Curtis7c63f2e22018-09-19 21:06:273111bool WebMediaPlayerImpl::DidLazyLoad() const {
3112 return did_lazy_load_;
3113}
3114
3115void WebMediaPlayerImpl::OnBecameVisible() {
3116 needs_first_frame_ = !has_first_frame_;
3117 UpdatePlayState();
3118}
3119
Miguel Casasfb63a5792018-12-04 23:50:413120bool WebMediaPlayerImpl::IsOpaque() const {
3121 return opaque_;
3122}
3123
avayvodcc273dd2017-01-19 19:35:123124bool WebMediaPlayerImpl::ShouldPauseVideoWhenHidden() const {
avayvod65fad272017-02-24 01:00:483125 // If suspending background video, pause any video that's not remoted or
3126 // not unlocked to play in the background.
Sergey Volk8b09c2c52018-12-12 23:20:403127 if (IsBackgroundSuspendEnabled(this)) {
Blink Reformat1c4d759e2017-04-09 16:34:543128 if (!HasVideo())
avayvod65fad272017-02-24 01:00:483129 return false;
3130
3131#if defined(OS_ANDROID)
Thomas Guilbert29ae1a902018-10-20 01:53:383132 if (IsRemote() || is_flinging_)
avayvod65fad272017-02-24 01:00:483133 return false;
avayvodcc273dd2017-01-19 19:35:123134#endif
avayvodeb9098d2017-01-07 00:33:033135
Blink Reformat1c4d759e2017-04-09 16:34:543136 return !HasAudio() || (IsResumeBackgroundVideosEnabled() &&
3137 video_locked_when_paused_when_hidden_);
avayvod65fad272017-02-24 01:00:483138 }
3139
3140 // Otherwise only pause if the optimization is on and it's a video-only
3141 // optimization candidate.
avayvod01201332017-04-14 00:27:153142 return IsBackgroundVideoPauseOptimizationEnabled() && !HasAudio() &&
Thomas Guilbert29ae1a902018-10-20 01:53:383143 IsBackgroundOptimizationCandidate() && !is_flinging_;
avayvodeb9098d2017-01-07 00:33:033144}
3145
avayvod2135a642017-01-13 00:17:143146bool WebMediaPlayerImpl::ShouldDisableVideoWhenHidden() const {
Ted Meyera918e592018-09-08 00:16:203147 // This optimization is behind the flag on all platforms, only for non-mse
3148 // video. MSE video track switching on hide has gone through a field test.
3149 // TODO(tmathmeyer): Passing load_type_ won't be needed after src= field
3150 // testing is finished. see: http://crbug.com/709302
Sergey Volk8b09c2c52018-12-12 23:20:403151 if (!is_background_video_track_optimization_supported_ ||
3152 !IsBackgroundVideoTrackOptimizationEnabled(load_type_))
avayvodc4bfb0e62017-01-13 01:07:013153 return false;
avayvodc4bfb0e62017-01-13 01:07:013154
avayvodcc273dd2017-01-19 19:35:123155 // Disable video track only for players with audio that match the criteria for
3156 // being optimized.
Blink Reformat1c4d759e2017-04-09 16:34:543157 return HasAudio() && IsBackgroundOptimizationCandidate();
avayvodcc273dd2017-01-19 19:35:123158}
3159
3160bool WebMediaPlayerImpl::IsBackgroundOptimizationCandidate() const {
3161 DCHECK(main_task_runner_->BelongsToCurrentThread());
3162
François Beaufort664c3ca72018-04-13 07:24:513163 // Don't optimize Picture-in-Picture players.
Mounir Lamouri0484f40a2018-07-25 03:03:263164 if (IsInPictureInPicture())
François Beaufort664c3ca72018-04-13 07:24:513165 return false;
3166
avayvodcc273dd2017-01-19 19:35:123167#if defined(OS_ANDROID) // WMPI_CAST
avayvodac1a8522017-01-20 19:02:503168 // Don't optimize players being Cast.
Blink Reformat1c4d759e2017-04-09 16:34:543169 if (IsRemote())
avayvodcc273dd2017-01-19 19:35:123170 return false;
3171#endif // defined(OS_ANDROID)
3172
3173 // Don't optimize audio-only or streaming players.
Blink Reformat1c4d759e2017-04-09 16:34:543174 if (!HasVideo() || IsStreaming())
avayvodcc273dd2017-01-19 19:35:123175 return false;
3176
Dale Curtis3f4935b2017-09-09 00:11:593177 // Video-only players are always optimized (paused).
3178 // Don't check the keyframe distance and duration.
3179 if (!HasAudio() && HasVideo())
3180 return true;
3181
avayvodcc273dd2017-01-19 19:35:123182 // Videos shorter than the maximum allowed keyframe distance can be optimized.
3183 base::TimeDelta duration = GetPipelineMediaDuration();
Ted Meyera918e592018-09-08 00:16:203184
Dale Curtis456808a2018-10-23 17:50:213185 constexpr base::TimeDelta kMaxKeyframeDistanceToDisableBackgroundVideo =
3186 base::TimeDelta::FromMilliseconds(
3187 kMaxKeyframeDistanceToDisableBackgroundVideoMs);
3188 if (duration < kMaxKeyframeDistanceToDisableBackgroundVideo)
avayvodcc273dd2017-01-19 19:35:123189 return true;
3190
3191 // Otherwise, only optimize videos with shorter average keyframe distance.
avayvodc4bfb0e62017-01-13 01:07:013192 PipelineStatistics stats = GetPipelineStatistics();
Dale Curtis456808a2018-10-23 17:50:213193 return stats.video_keyframe_distance_average <
3194 kMaxKeyframeDistanceToDisableBackgroundVideo;
avayvod2135a642017-01-13 00:17:143195}
3196
avayvod56e1f3942017-01-21 02:06:313197void WebMediaPlayerImpl::UpdateBackgroundVideoOptimizationState() {
3198 if (IsHidden()) {
Dale Curtisa75a7892017-08-09 20:21:513199 if (ShouldPauseVideoWhenHidden()) {
avayvod56e1f3942017-01-21 02:06:313200 PauseVideoIfNeeded();
Dale Curtisa75a7892017-08-09 20:21:513201 } else if (update_background_status_cb_.IsCancelled()) {
3202 // Only trigger updates when we don't have one already scheduled.
3203 update_background_status_cb_.Reset(
3204 base::Bind(&WebMediaPlayerImpl::DisableVideoTrackIfNeeded,
3205 base::Unretained(this)));
3206
3207 // Defer disable track until we're sure the clip will be backgrounded for
3208 // some time. Resuming may take half a second, so frequent tab switches
3209 // will yield a poor user experience otherwise. http://crbug.com/709302
3210 // may also cause AV sync issues if disable/enable happens too fast.
3211 main_task_runner_->PostDelayedTask(
3212 FROM_HERE, update_background_status_cb_.callback(),
3213 base::TimeDelta::FromSeconds(10));
3214 }
avayvod56e1f3942017-01-21 02:06:313215 } else {
Dale Curtisa75a7892017-08-09 20:21:513216 update_background_status_cb_.Cancel();
avayvod56e1f3942017-01-21 02:06:313217 EnableVideoTrackIfNeeded();
3218 }
3219}
3220
3221void WebMediaPlayerImpl::PauseVideoIfNeeded() {
3222 DCHECK(IsHidden());
3223
3224 // Don't pause video while the pipeline is stopped, resuming or seeking.
3225 // Also if the video is paused already.
tguilbert350936ff2017-02-24 05:39:273226 if (!pipeline_controller_.IsPipelineRunning() || is_pipeline_resuming_ ||
3227 seeking_ || paused_)
avayvod56e1f3942017-01-21 02:06:313228 return;
3229
3230 // OnPause() will set |paused_when_hidden_| to false and call
3231 // UpdatePlayState(), so set the flag to true after and then return.
3232 OnPause();
3233 paused_when_hidden_ = true;
3234}
3235
avayvod2135a642017-01-13 00:17:143236void WebMediaPlayerImpl::EnableVideoTrackIfNeeded() {
avayvod56e1f3942017-01-21 02:06:313237 // Don't change video track while the pipeline is stopped, resuming or
3238 // seeking.
tguilbert350936ff2017-02-24 05:39:273239 if (!pipeline_controller_.IsPipelineRunning() || is_pipeline_resuming_ ||
3240 seeking_)
avayvod2135a642017-01-13 00:17:143241 return;
3242
3243 if (video_track_disabled_) {
3244 video_track_disabled_ = false;
Blink Reformat1c4d759e2017-04-09 16:34:543245 if (client_->HasSelectedVideoTrack()) {
3246 WebMediaPlayer::TrackId trackId = client_->GetSelectedVideoTrackId();
3247 SelectedVideoTrackChanged(&trackId);
avayvod2135a642017-01-13 00:17:143248 }
3249 }
3250}
3251
3252void WebMediaPlayerImpl::DisableVideoTrackIfNeeded() {
3253 DCHECK(IsHidden());
3254
3255 // Don't change video track while the pipeline is resuming or seeking.
3256 if (is_pipeline_resuming_ || seeking_)
3257 return;
3258
3259 if (!video_track_disabled_ && ShouldDisableVideoWhenHidden()) {
3260 video_track_disabled_ = true;
Blink Reformat1c4d759e2017-04-09 16:34:543261 SelectedVideoTrackChanged(nullptr);
avayvod2135a642017-01-13 00:17:143262 }
3263}
3264
avayvodc4bfb0e62017-01-13 01:07:013265void WebMediaPlayerImpl::SetPipelineStatisticsForTest(
3266 const PipelineStatistics& stats) {
3267 pipeline_statistics_for_test_ = base::make_optional(stats);
3268}
3269
3270PipelineStatistics WebMediaPlayerImpl::GetPipelineStatistics() const {
3271 DCHECK(main_task_runner_->BelongsToCurrentThread());
3272
tguilbert350936ff2017-02-24 05:39:273273 return pipeline_statistics_for_test_.value_or(
3274 pipeline_controller_.GetStatistics());
avayvodc4bfb0e62017-01-13 01:07:013275}
3276
avayvodcc273dd2017-01-19 19:35:123277void WebMediaPlayerImpl::SetPipelineMediaDurationForTest(
3278 base::TimeDelta duration) {
3279 pipeline_media_duration_for_test_ = base::make_optional(duration);
3280}
3281
3282base::TimeDelta WebMediaPlayerImpl::GetPipelineMediaDuration() const {
3283 DCHECK(main_task_runner_->BelongsToCurrentThread());
3284
3285 return pipeline_media_duration_for_test_.value_or(
tguilbert350936ff2017-02-24 05:39:273286 pipeline_controller_.GetMediaDuration());
avayvodcc273dd2017-01-19 19:35:123287}
3288
3289void WebMediaPlayerImpl::ReportTimeFromForegroundToFirstFrame(
3290 base::TimeTicks foreground_time,
3291 base::TimeTicks new_frame_time) {
3292 base::TimeDelta time_to_first_frame = new_frame_time - foreground_time;
Blink Reformat1c4d759e2017-04-09 16:34:543293 if (HasAudio()) {
avayvodcc273dd2017-01-19 19:35:123294 UMA_HISTOGRAM_TIMES(
3295 "Media.Video.TimeFromForegroundToFirstFrame.DisableTrack",
3296 time_to_first_frame);
3297 } else {
3298 UMA_HISTOGRAM_TIMES("Media.Video.TimeFromForegroundToFirstFrame.Paused",
3299 time_to_first_frame);
3300 }
3301}
Xiangjun Zhangba8724f482017-08-03 06:43:253302
3303void WebMediaPlayerImpl::SwitchToRemoteRenderer(
3304 const std::string& remote_device_friendly_name) {
xjz4e5d4bf32017-02-15 21:26:353305 DCHECK(main_task_runner_->BelongsToCurrentThread());
Thomas Guilbertb341bae02018-05-09 00:02:133306 DCHECK(!disable_pipeline_auto_suspend_);
Xiangjun Zhangba8724f482017-08-03 06:43:253307 disable_pipeline_auto_suspend_ = true;
Chris Cunninghamd9df58e2017-08-29 00:04:233308
3309 // Capabilities reporting should only be performed for local playbacks.
3310 video_decode_stats_reporter_.reset();
3311
Xiangjun Zhangba8724f482017-08-03 06:43:253312 // Requests to restart media pipeline. A remote renderer will be created via
3313 // the |renderer_factory_selector_|.
xjz4e5d4bf32017-02-15 21:26:353314 ScheduleRestart();
xjzdf9b67e2017-04-13 23:28:253315 if (client_) {
Xiangjun Zhangba8724f482017-08-03 06:43:253316 client_->MediaRemotingStarted(
3317 WebString::FromUTF8(remote_device_friendly_name));
xjzdf9b67e2017-04-13 23:28:253318 }
xjz4e5d4bf32017-02-15 21:26:353319}
3320
Xiangjun Zhang5e20cba42018-01-10 19:54:563321void WebMediaPlayerImpl::SwitchToLocalRenderer(
3322 MediaObserverClient::ReasonToSwitchToLocal reason) {
Xiangjun Zhangba8724f482017-08-03 06:43:253323 DCHECK(main_task_runner_->BelongsToCurrentThread());
Xiangjun Zhang12f55272018-07-30 23:19:373324 if (!disable_pipeline_auto_suspend_)
3325 return; // Is currently with local renderer.
Xiangjun Zhangba8724f482017-08-03 06:43:253326 disable_pipeline_auto_suspend_ = false;
Chris Cunninghamd9df58e2017-08-29 00:04:233327
3328 // Capabilities reporting may resume now that playback is local.
3329 CreateVideoDecodeStatsReporter();
3330
Xiangjun Zhangba8724f482017-08-03 06:43:253331 // Requests to restart media pipeline. A local renderer will be created via
3332 // the |renderer_factory_selector_|.
3333 ScheduleRestart();
3334 if (client_)
Xiangjun Zhang5e20cba42018-01-10 19:54:563335 client_->MediaRemotingStopped(GetSwitchToLocalMessage(reason));
Xiangjun Zhangba8724f482017-08-03 06:43:253336}
3337
dalecurtis4f6d14d2017-02-22 17:42:223338void WebMediaPlayerImpl::RecordUnderflowDuration(base::TimeDelta duration) {
3339 DCHECK(data_source_ || chunk_demuxer_);
xhwang68b3fab82017-05-17 21:31:463340
dalecurtis4f6d14d2017-02-22 17:42:223341 if (data_source_)
Jennifer Apacible82e25c92017-08-07 18:15:273342 UMA_HISTOGRAM_TIMES("Media.UnderflowDuration2.SRC", duration);
dalecurtis4f6d14d2017-02-22 17:42:223343 else
Jennifer Apacible82e25c92017-08-07 18:15:273344 UMA_HISTOGRAM_TIMES("Media.UnderflowDuration2.MSE", duration);
xhwang68b3fab82017-05-17 21:31:463345
3346 if (is_encrypted_)
Jennifer Apacible82e25c92017-08-07 18:15:273347 UMA_HISTOGRAM_TIMES("Media.UnderflowDuration2.EME", duration);
dalecurtis4f6d14d2017-02-22 17:42:223348}
3349
xhwang60802652017-04-19 07:29:583350#define UMA_HISTOGRAM_VIDEO_HEIGHT(name, sample) \
3351 UMA_HISTOGRAM_CUSTOM_COUNTS(name, sample, 100, 10000, 50)
3352
3353void WebMediaPlayerImpl::RecordVideoNaturalSize(const gfx::Size& natural_size) {
3354 // Always report video natural size to MediaLog.
3355 media_log_->AddEvent(media_log_->CreateVideoSizeSetEvent(
3356 natural_size.width(), natural_size.height()));
3357
3358 if (initial_video_height_recorded_)
3359 return;
3360
3361 initial_video_height_recorded_ = true;
3362
3363 int height = natural_size.height();
3364
3365 if (load_type_ == kLoadTypeURL)
3366 UMA_HISTOGRAM_VIDEO_HEIGHT("Media.VideoHeight.Initial.SRC", height);
3367 else if (load_type_ == kLoadTypeMediaSource)
3368 UMA_HISTOGRAM_VIDEO_HEIGHT("Media.VideoHeight.Initial.MSE", height);
3369
3370 if (is_encrypted_)
3371 UMA_HISTOGRAM_VIDEO_HEIGHT("Media.VideoHeight.Initial.EME", height);
3372
3373 UMA_HISTOGRAM_VIDEO_HEIGHT("Media.VideoHeight.Initial.All", height);
3374}
3375
3376#undef UMA_HISTOGRAM_VIDEO_HEIGHT
3377
Greg Thompsonaa48ce8d2018-04-03 06:11:433378void WebMediaPlayerImpl::SetTickClockForTest(
3379 const base::TickClock* tick_clock) {
tzik2c963b872017-12-07 06:57:243380 tick_clock_ = tick_clock;
hubbeb2d3efd2017-05-05 23:26:383381 buffered_data_source_host_.SetTickClockForTest(tick_clock);
3382}
3383
Dale Curtis3899090ea2018-01-12 00:10:353384void WebMediaPlayerImpl::OnFirstFrame(base::TimeTicks frame_time) {
3385 DCHECK(!load_start_time_.is_null());
Dale Curtisff576552018-03-30 02:32:443386 DCHECK(!skip_metrics_due_to_startup_suspend_);
Dale Curtisc2c5dcb12018-04-16 23:21:293387 has_first_frame_ = true;
Dale Curtis7c63f2e22018-09-19 21:06:273388 needs_first_frame_ = false;
Dale Curtis3899090ea2018-01-12 00:10:353389 const base::TimeDelta elapsed = frame_time - load_start_time_;
3390 media_metrics_provider_->SetTimeToFirstFrame(elapsed);
3391 RecordTimingUMA("Media.TimeToFirstFrame", elapsed);
Dale Curtis3899090ea2018-01-12 00:10:353392}
3393
3394void WebMediaPlayerImpl::RecordTimingUMA(const std::string& key,
3395 base::TimeDelta elapsed) {
3396 if (chunk_demuxer_)
3397 base::UmaHistogramMediumTimes(key + ".MSE", elapsed);
3398 else
3399 base::UmaHistogramMediumTimes(key + ".SRC", elapsed);
3400 if (is_encrypted_)
3401 base::UmaHistogramMediumTimes(key + ".EME", elapsed);
3402}
3403
John Rummelldb5a7ef2018-05-16 00:28:013404void WebMediaPlayerImpl::RecordEncryptionScheme(
3405 const std::string& stream_name,
3406 const EncryptionScheme& encryption_scheme) {
3407 DCHECK(stream_name == "Audio" || stream_name == "Video");
3408
3409 // If the stream is not encrypted, don't record it.
3410 if (encryption_scheme.mode() == EncryptionScheme::CIPHER_MODE_UNENCRYPTED)
3411 return;
3412
3413 base::UmaHistogramEnumeration(
3414 "Media.EME.EncryptionScheme.Initial." + stream_name,
3415 DetermineEncryptionSchemeUMAValue(encryption_scheme),
3416 EncryptionSchemeUMA::kCount);
3417}
3418
Mounir Lamouri0484f40a2018-07-25 03:03:263419bool WebMediaPlayerImpl::IsInPictureInPicture() const {
3420 DCHECK(client_);
3421 return client_->DisplayType() ==
3422 WebMediaPlayer::DisplayType::kPictureInPicture;
3423}
3424
François Beaufortbb68c43e2018-11-20 20:12:033425bool WebMediaPlayerImpl::ShouldShowPlayPauseButtonInPictureInPictureWindow()
3426 const {
3427 return Duration() != std::numeric_limits<double>::infinity();
3428}
3429
Dale Curtis5bba03232018-08-30 17:57:383430void WebMediaPlayerImpl::MaybeSetContainerName() {
Dale Curtisf01c8262018-09-04 23:50:433431 // MSE nor MediaPlayerRenderer provide container information.
3432 if (chunk_demuxer_ || using_media_player_renderer_)
Dale Curtis5bba03232018-08-30 17:57:383433 return;
3434
3435 // Pipeline startup failed before even getting a demuxer setup.
3436 if (!demuxer_)
3437 return;
3438
3439 // Container has already been set.
3440 if (highest_ready_state_ >= WebMediaPlayer::kReadyStateHaveMetadata)
3441 return;
3442
3443// If ffmpeg isn't enabled, we can't get the container name.
3444#if BUILDFLAG(ENABLE_FFMPEG)
3445 media_metrics_provider_->SetContainerName(
3446 static_cast<FFmpegDemuxer*>(demuxer_.get())->container());
3447#endif
3448}
3449
acolwell9e0840d2014-09-06 19:01:323450} // namespace media