blob: 0b87ac2b52454e08f2c61f218f360109299d9415 [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"
Dale Curtis4841c712018-12-13 18:14:0557#include "media/filters/memory_data_source.h"
Scott Violeta35f9a42018-03-22 22:00:4458#include "media/media_buildflags.h"
Dale Curtis4841c712018-12-13 18:14:0559#include "net/base/data_url.h"
sawtellee19d11aa2018-08-10 03:47:5060#include "third_party/blink/public/common/picture_in_picture/picture_in_picture_control_info.h"
Blink Reformata30d4232018-04-07 15:31:0661#include "third_party/blink/public/platform/web_encrypted_media_types.h"
62#include "third_party/blink/public/platform/web_localized_string.h"
63#include "third_party/blink/public/platform/web_media_player_client.h"
64#include "third_party/blink/public/platform/web_media_player_encrypted_media_client.h"
65#include "third_party/blink/public/platform/web_media_player_source.h"
66#include "third_party/blink/public/platform/web_media_source.h"
67#include "third_party/blink/public/platform/web_rect.h"
68#include "third_party/blink/public/platform/web_runtime_features.h"
69#include "third_party/blink/public/platform/web_security_origin.h"
70#include "third_party/blink/public/platform/web_size.h"
71#include "third_party/blink/public/platform/web_string.h"
72#include "third_party/blink/public/platform/web_surface_layer_bridge.h"
73#include "third_party/blink/public/platform/web_url.h"
74#include "third_party/blink/public/web/web_document.h"
75#include "third_party/blink/public/web/web_frame.h"
76#include "third_party/blink/public/web/web_local_frame.h"
77#include "third_party/blink/public/web/web_user_gesture_indicator.h"
78#include "third_party/blink/public/web/web_view.h"
[email protected]b3f2b912009-04-09 16:18:5279
dalecurtisea27a3ed2016-06-24 01:41:3080#if defined(OS_ANDROID)
81#include "media/base/android/media_codec_util.h"
82#endif
83
[email protected]180ef242013-11-07 06:50:4684using blink::WebMediaPlayer;
85using blink::WebRect;
86using blink::WebSize;
87using blink::WebString;
hubbed5f36882016-01-15 22:40:3788using gpu::gles2::GLES2Interface;
89
danakj365175c2016-02-06 00:37:3790#define STATIC_ASSERT_ENUM(a, b) \
91 static_assert(static_cast<int>(a) == static_cast<int>(b), \
92 "mismatching enums: " #a)
93
hubbed5f36882016-01-15 22:40:3794namespace media {
[email protected]ec9212f2008-12-18 21:40:3695
[email protected]8931c41a2009-07-07 17:31:4996namespace {
97
hubbed5f36882016-01-15 22:40:3798void SetSinkIdOnMediaThread(scoped_refptr<WebAudioSourceProviderImpl> sink,
99 const std::string& device_id,
Daniel Chengc1710b52018-10-24 03:12:28100 OutputDeviceStatusCB callback) {
101 sink->SwitchOutputDevice(device_id, std::move(callback));
guidouc7babef2015-10-22 00:42:35102}
103
Sergey Volk8b09c2c52018-12-12 23:20:40104bool IsBackgroundSuspendEnabled(const WebMediaPlayerImpl* wmpi) {
Luke Halliwell7a8a8982018-07-25 01:07:05105 // TODO(crbug.com/867146): remove these switches.
106 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
107 switches::kDisableMediaSuspend))
108 return false;
109 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
110 switches::kEnableMediaSuspend))
111 return true;
112
Sergey Volk8b09c2c52018-12-12 23:20:40113 return wmpi->IsBackgroundMediaSuspendEnabled();
dalecurtis0431cbf2016-03-12 01:19:43114}
115
avayvod48a8be52016-08-04 19:52:50116bool IsResumeBackgroundVideosEnabled() {
117 return base::FeatureList::IsEnabled(kResumeBackgroundVideo);
118}
119
Ted Meyera918e592018-09-08 00:16:20120bool IsBackgroundVideoTrackOptimizationEnabled(
121 WebMediaPlayer::LoadType load_type) {
122 // Background video track optimization is always enabled for MSE videos.
123 return load_type == WebMediaPlayer::LoadType::kLoadTypeMediaSource ||
124 base::FeatureList::IsEnabled(kBackgroundSrcVideoTrackOptimization);
avayvod39c102402016-11-23 21:43:13125}
126
avayvod01201332017-04-14 00:27:15127bool IsBackgroundVideoPauseOptimizationEnabled() {
128 return base::FeatureList::IsEnabled(kBackgroundVideoPauseOptimization);
129}
130
avayvod82729272017-05-29 21:58:39131bool IsNewRemotePlaybackPipelineEnabled() {
132 return base::FeatureList::IsEnabled(kNewRemotePlaybackPipeline);
133}
134
sandersd50a635e2016-04-04 22:50:09135bool IsNetworkStateError(blink::WebMediaPlayer::NetworkState state) {
Blink Reformat1c4d759e2017-04-09 16:34:54136 bool result = state == blink::WebMediaPlayer::kNetworkStateFormatError ||
137 state == blink::WebMediaPlayer::kNetworkStateNetworkError ||
138 state == blink::WebMediaPlayer::kNetworkStateDecodeError;
139 DCHECK_EQ(state > blink::WebMediaPlayer::kNetworkStateLoaded, result);
sandersd50a635e2016-04-04 22:50:09140 return result;
141}
142
sandersd2c478422016-08-02 01:19:25143gfx::Size GetRotatedVideoSize(VideoRotation rotation, gfx::Size natural_size) {
144 if (rotation == VIDEO_ROTATION_90 || rotation == VIDEO_ROTATION_270)
145 return gfx::Size(natural_size.height(), natural_size.width());
146 return natural_size;
147}
148
Xiaohan Wangf63505d2017-10-21 08:00:53149void RecordEncryptedEvent(bool encrypted_event_fired) {
150 UMA_HISTOGRAM_BOOLEAN("Media.EME.EncryptedEvent", encrypted_event_fired);
151}
152
sandersd35d2c3f2017-01-14 02:04:42153// How much time must have elapsed since loading last progressed before we
154// assume that the decoder will have had time to complete preroll.
155constexpr base::TimeDelta kPrerollAttemptTimeout =
watkd026f792016-11-05 00:28:51156 base::TimeDelta::FromSeconds(3);
157
Matt Wolenetz6010f6c2017-10-18 00:44:36158// Maximum number, per-WMPI, of media logs of playback rate changes.
159constexpr int kMaxNumPlaybackRateLogs = 10;
160
Xiangjun Zhang5e20cba42018-01-10 19:54:56161blink::WebLocalizedString::Name GetSwitchToLocalMessage(
162 MediaObserverClient::ReasonToSwitchToLocal reason) {
163 switch (reason) {
164 case MediaObserverClient::ReasonToSwitchToLocal::NORMAL:
165 return blink::WebLocalizedString::kMediaRemotingStopText;
166 case MediaObserverClient::ReasonToSwitchToLocal::POOR_PLAYBACK_QUALITY:
167 return blink::WebLocalizedString::kMediaRemotingStopByPlaybackQualityText;
168 case MediaObserverClient::ReasonToSwitchToLocal::PIPELINE_ERROR:
169 return blink::WebLocalizedString::kMediaRemotingStopByErrorText;
170 case MediaObserverClient::ReasonToSwitchToLocal::ROUTE_TERMINATED:
171 return blink::WebLocalizedString::kMediaRemotingStopNoText;
172 }
173 NOTREACHED();
174 // To suppress compiler warning on Windows.
175 return blink::WebLocalizedString::kMediaRemotingStopNoText;
176}
177
John Rummelldb5a7ef2018-05-16 00:28:01178// These values are persisted to UMA. Entries should not be renumbered and
179// numeric values should never be reused.
180// TODO(crbug.com/825041): This should use EncryptionMode when kUnencrypted
181// removed.
182enum class EncryptionSchemeUMA { kCenc = 0, kCbcs = 1, kCount };
183
184EncryptionSchemeUMA DetermineEncryptionSchemeUMAValue(
185 const EncryptionScheme& encryption_scheme) {
186 if (encryption_scheme.mode() == EncryptionScheme::CIPHER_MODE_AES_CBC)
187 return EncryptionSchemeUMA::kCbcs;
188
189 DCHECK_EQ(encryption_scheme.mode(), EncryptionScheme::CIPHER_MODE_AES_CTR);
190 return EncryptionSchemeUMA::kCenc;
191}
192
John Rummelld30555352018-09-21 20:47:25193EncryptionMode DetermineEncryptionMode(
194 const EncryptionScheme& encryption_scheme) {
195 switch (encryption_scheme.mode()) {
196 case EncryptionScheme::CIPHER_MODE_UNENCRYPTED:
197 return EncryptionMode::kUnencrypted;
198 case EncryptionScheme::CIPHER_MODE_AES_CTR:
199 return EncryptionMode::kCenc;
200 case EncryptionScheme::CIPHER_MODE_AES_CBC:
201 return EncryptionMode::kCbcs;
202 }
203}
204
Pavel Feldman023c3e62018-08-28 17:59:47205#if BUILDFLAG(ENABLE_FFMPEG)
Dale Curtisb8139f72018-08-27 23:28:48206// Returns true if |url| represents (or is likely to) a local file.
207bool IsLocalFile(const GURL& url) {
208 return url.SchemeIsFile() || url.SchemeIsFileSystem() ||
209 url.SchemeIs(url::kContentScheme) ||
210 url.SchemeIs(url::kContentIDScheme) ||
211 url.SchemeIs("chrome-extension");
212}
Pavel Feldman023c3e62018-08-28 17:59:47213#endif
Dale Curtisb8139f72018-08-27 23:28:48214
Dale Curtisf273f8f2018-12-13 23:40:33215// Handles destruction of media::Renderer dependent components after the
216// renderer has been destructed on the media thread.
217void DestructionHelper(
218 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
219 scoped_refptr<base::SingleThreadTaskRunner> vfc_task_runner,
220 std::unique_ptr<Demuxer> demuxer,
221 std::unique_ptr<DataSource> data_source,
222 std::unique_ptr<VideoFrameCompositor> compositor,
223 std::unique_ptr<CdmContextRef> cdm_context_1,
224 std::unique_ptr<CdmContextRef> cdm_context_2,
225 std::unique_ptr<MediaLog> media_log,
226 std::unique_ptr<RendererFactorySelector> renderer_factory_selector,
227 std::unique_ptr<blink::WebSurfaceLayerBridge> bridge,
228 bool is_chunk_demuxer) {
229 // We release |bridge| after pipeline stop to ensure layout tests receive
230 // painted video frames before test harness exit.
231 main_task_runner->DeleteSoon(FROM_HERE, std::move(bridge));
232
233 // Since the media::Renderer is gone we can now destroy the compositor and
234 // renderer factory selector.
235 vfc_task_runner->DeleteSoon(FROM_HERE, std::move(compositor));
236 main_task_runner->DeleteSoon(FROM_HERE, std::move(renderer_factory_selector));
237
238 // ChunkDemuxer can be deleted on any thread, but other demuxers are bound to
239 // the main thread and must be deleted there now that the renderer is gone.
240 if (!is_chunk_demuxer) {
241 main_task_runner->DeleteSoon(FROM_HERE, std::move(demuxer));
242 main_task_runner->DeleteSoon(FROM_HERE, std::move(data_source));
243 main_task_runner->DeleteSoon(FROM_HERE, std::move(cdm_context_1));
244 main_task_runner->DeleteSoon(FROM_HERE, std::move(cdm_context_2));
245 main_task_runner->DeleteSoon(FROM_HERE, std::move(media_log));
246 return;
247 }
248
249 // ChunkDemuxer's streams may contain much buffered, compressed media that
250 // may need to be paged back in during destruction. Paging delay may exceed
251 // the renderer hang monitor's threshold on at least Windows while also
252 // blocking other work on the renderer main thread, so we do the actual
253 // destruction in the background without blocking WMPI destruction or
254 // |task_runner|. On advice of task_scheduler OWNERS, MayBlock() is not
255 // used because virtual memory overhead is not considered blocking I/O; and
256 // CONTINUE_ON_SHUTDOWN is used to allow process termination to not block on
257 // completing the task.
258 base::PostTaskWithTraits(
259 FROM_HERE,
260 {base::TaskPriority::BEST_EFFORT,
261 base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
262 base::BindOnce(
263 [](scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
264 std::unique_ptr<Demuxer> demuxer_to_destroy,
265 std::unique_ptr<CdmContextRef> cdm_context_1,
266 std::unique_ptr<CdmContextRef> cdm_context_2,
267 std::unique_ptr<MediaLog> media_log) {
268 SCOPED_UMA_HISTOGRAM_TIMER("Media.MSE.DemuxerDestructionTime");
269 demuxer_to_destroy.reset();
270 main_task_runner->DeleteSoon(FROM_HERE, std::move(cdm_context_1));
271 main_task_runner->DeleteSoon(FROM_HERE, std::move(cdm_context_2));
272 main_task_runner->DeleteSoon(FROM_HERE, std::move(media_log));
273 },
274 std::move(main_task_runner), std::move(demuxer),
275 std::move(cdm_context_1), std::move(cdm_context_2),
276 std::move(media_log)));
277}
278
[email protected]8931c41a2009-07-07 17:31:49279} // namespace
280
[email protected]6683e1b2014-04-10 01:45:38281class BufferedDataSourceHostImpl;
282
Takashi Toyoshima2e01e692018-11-16 03:23:27283STATIC_ASSERT_ENUM(WebMediaPlayer::kCorsModeUnspecified,
danakj365175c2016-02-06 00:37:37284 UrlData::CORS_UNSPECIFIED);
Takashi Toyoshima2e01e692018-11-16 03:23:27285STATIC_ASSERT_ENUM(WebMediaPlayer::kCorsModeAnonymous, UrlData::CORS_ANONYMOUS);
286STATIC_ASSERT_ENUM(WebMediaPlayer::kCorsModeUseCredentials,
danakj365175c2016-02-06 00:37:37287 UrlData::CORS_USE_CREDENTIALS);
[email protected]a5a01102012-06-06 17:01:24288
[email protected]5b5bb9d2010-10-22 19:57:36289WebMediaPlayerImpl::WebMediaPlayerImpl(
[email protected]35b2a972014-04-04 15:50:22290 blink::WebLocalFrame* frame,
[email protected]180ef242013-11-07 06:50:46291 blink::WebMediaPlayerClient* client,
srirama.m26f864d02015-07-14 05:21:46292 blink::WebMediaPlayerEncryptedMediaClient* encrypted_client,
tguilbert1bb1c782017-01-23 21:15:11293 WebMediaPlayerDelegate* delegate,
tguilbert70d2a00a2017-04-25 00:30:44294 std::unique_ptr<RendererFactorySelector> renderer_factory_selector,
Alok Priyadarshi7166d4d2017-07-29 04:04:25295 UrlIndex* url_index,
CJ DiMegliod7ac6772017-11-10 00:19:06296 std::unique_ptr<VideoFrameCompositor> compositor,
dalecurtis9cddc0b2017-04-19 21:23:38297 std::unique_ptr<WebMediaPlayerParams> params)
[email protected]f6af7592014-02-28 10:09:11298 : frame_(frame),
Alexander Timin310368112017-09-13 10:01:44299 main_task_runner_(
300 frame->GetTaskRunner(blink::TaskType::kMediaElementEvent)),
dalecurtis9cddc0b2017-04-19 21:23:38301 media_task_runner_(params->media_task_runner()),
302 worker_task_runner_(params->worker_task_runner()),
303 media_log_(params->take_media_log()),
sandersd1c0bba02016-03-04 23:14:08304 pipeline_controller_(
Hajime Hoshidb0761a42018-01-18 08:10:19305 std::make_unique<PipelineImpl>(media_task_runner_,
306 main_task_runner_,
307 media_log_.get()),
sandersd1c0bba02016-03-04 23:14:08308 base::Bind(&WebMediaPlayerImpl::CreateRenderer,
309 base::Unretained(this)),
310 base::Bind(&WebMediaPlayerImpl::OnPipelineSeeked, AsWeakPtr()),
311 base::Bind(&WebMediaPlayerImpl::OnPipelineSuspended, AsWeakPtr()),
avayvod2135a642017-01-13 00:17:14312 base::Bind(&WebMediaPlayerImpl::OnBeforePipelineResume, AsWeakPtr()),
313 base::Bind(&WebMediaPlayerImpl::OnPipelineResumed, AsWeakPtr()),
alokp967c902452016-05-06 05:21:37314 base::Bind(&WebMediaPlayerImpl::OnError, AsWeakPtr())),
[email protected]5badb082010-06-11 17:40:15315 client_(client),
srirama.m26f864d02015-07-14 05:21:46316 encrypted_client_(encrypted_client),
[email protected]baff4512011-10-19 18:21:07317 delegate_(delegate),
dalecurtis9cddc0b2017-04-19 21:23:38318 defer_load_cb_(params->defer_load_cb()),
dalecurtis9cddc0b2017-04-19 21:23:38319 adjust_allocated_memory_cb_(params->adjust_allocated_memory_cb()),
tzik2c963b872017-12-07 06:57:24320 tick_clock_(base::DefaultTickClock::GetInstance()),
hubbeb2d3efd2017-05-05 23:26:38321 buffered_data_source_host_(
322 base::Bind(&WebMediaPlayerImpl::OnProgress, AsWeakPtr()),
tzik2c963b872017-12-07 06:57:24323 tick_clock_),
hubbe5f0ad43b2015-12-14 20:57:26324 url_index_(url_index),
CJ DiMeglioc60a5cf2017-09-27 20:08:41325 context_provider_(params->context_provider()),
CJ DiMegliod7ac6772017-11-10 00:19:06326 vfc_task_runner_(params->video_frame_compositor_task_runner()),
327 compositor_(std::move(compositor)),
hubbed5f36882016-01-15 22:40:37328#if defined(OS_ANDROID) // WMPI_CAST
CJ DiMeglioc60a5cf2017-09-27 20:08:41329 cast_impl_(this, client_, params->context_provider()),
hubbed5f36882016-01-15 22:40:37330#endif
tguilbert70d2a00a2017-04-25 00:30:44331 renderer_factory_selector_(std::move(renderer_factory_selector)),
dalecurtis9cddc0b2017-04-19 21:23:38332 observer_(params->media_observer()),
servolkf94b4602017-01-31 16:44:27333 enable_instant_source_buffer_gc_(
dalecurtis9cddc0b2017-04-19 21:23:38334 params->enable_instant_source_buffer_gc()),
shaktisahu24189c12017-03-11 17:42:55335 embedded_media_experience_enabled_(
liberato2ff93ad2017-05-17 07:28:24336 params->embedded_media_experience_enabled()),
[email protected]69db58f2018-09-26 20:27:56337 surface_layer_mode_(params->use_surface_layer_for_video()),
CJ DiMeglio96c18b692018-07-04 03:39:06338 create_bridge_callback_(params->create_bridge_callback()),
liberato2ff93ad2017-05-17 07:28:24339 request_routing_token_cb_(params->request_routing_token_cb()),
Dale Curtis1adbe6a2017-08-02 02:09:13340 overlay_routing_token_(OverlayInfo::RoutingToken()),
Sergey Volk8b09c2c52018-12-12 23:20:40341 media_metrics_provider_(params->take_metrics_provider()),
342 is_background_suspend_enabled_(params->IsBackgroundSuspendEnabled()),
Junbo Kefba620b2019-01-16 02:54:36343 is_background_video_playback_enabled_(
344 params->IsBackgroundVideoPlaybackEnabled()),
Sergey Volk8b09c2c52018-12-12 23:20:40345 is_background_video_track_optimization_supported_(
346 params->IsBackgroundVideoTrackOptimizationSupported()) {
xhwang51139732017-02-24 19:36:08347 DVLOG(1) << __func__;
Dale Curtise25163812018-09-21 22:13:39348 DCHECK(adjust_allocated_memory_cb_);
tguilbert70d2a00a2017-04-25 00:30:44349 DCHECK(renderer_factory_selector_);
servolkef1e5ef2016-03-25 04:55:26350 DCHECK(client_);
tguilbert1bb1c782017-01-23 21:15:11351 DCHECK(delegate_);
dalecurtis83266c72015-10-29 18:43:20352
[email protected]c8d574722017-08-30 20:53:43353 // If we're supposed to force video overlays, then make sure that they're
354 // enabled all the time.
355 always_enable_overlays_ = base::CommandLine::ForCurrentProcess()->HasSwitch(
tsunghungee562e92016-07-20 18:03:31356 switches::kForceVideoOverlays);
357
Dale Curtisca1b78f2019-01-15 03:11:26358 if (base::FeatureList::IsEnabled(kOverlayFullscreenVideo)) {
359 bool use_android_overlay = base::FeatureList::IsEnabled(kUseAndroidOverlay);
liberato2ff93ad2017-05-17 07:28:24360 overlay_mode_ = use_android_overlay ? OverlayMode::kUseAndroidOverlay
361 : OverlayMode::kUseContentVideoView;
362 } else {
363 overlay_mode_ = OverlayMode::kNoOverlays;
364 }
ampea73f792017-01-19 04:05:39365
tguilbert1bb1c782017-01-23 21:15:11366 delegate_id_ = delegate_->AddObserver(this);
367 delegate_->SetIdle(delegate_id_, true);
sandersd1e49fb62015-12-12 01:18:06368
dalecurtis2cff7f372017-05-24 08:30:08369 media_log_->AddEvent(media_log_->CreateCreatedEvent(
370 url::Origin(frame_->GetSecurityOrigin()).GetURL().spec()));
sandersd72683f252017-07-07 23:20:46371 media_log_->SetStringProperty("frame_url",
372 frame_->GetDocument().Url().GetString().Utf8());
373 media_log_->SetStringProperty("frame_title",
374 frame_->GetDocument().Title().Utf8());
[email protected]4e6be3f2009-05-07 02:24:44375
[email protected]52b0b212018-10-10 05:25:28376 // To make manual testing easier, include |surface_layer_mode_| in the log.
377 // TODO(liberato): Move this into media_factory.cc, so that it can be shared
378 // with the MediaStream startup.
379 const char* surface_layer_mode_name = "(unset)";
380 switch (surface_layer_mode_) {
CJ DiMeglio89240472018-10-18 18:21:10381 case SurfaceLayerMode::kAlways:
[email protected]52b0b212018-10-10 05:25:28382 surface_layer_mode_name = "kAlways";
383 break;
CJ DiMeglio89240472018-10-18 18:21:10384 case SurfaceLayerMode::kOnDemand:
[email protected]52b0b212018-10-10 05:25:28385 surface_layer_mode_name = "kOnDemand";
386 break;
CJ DiMeglio89240472018-10-18 18:21:10387 case SurfaceLayerMode::kNever:
[email protected]52b0b212018-10-10 05:25:28388 surface_layer_mode_name = "kNever";
389 break;
390 }
391 media_log_->SetStringProperty("surface_layer_mode", surface_layer_mode_name);
392
dalecurtis9cddc0b2017-04-19 21:23:38393 if (params->initial_cdm())
394 SetCdm(params->initial_cdm());
xhwang0ad11e512014-11-25 23:43:09395
Xiaohan Wangf63505d2017-10-21 08:00:53396 // Report a false "EncrytpedEvent" here as a baseline.
397 RecordEncryptedEvent(false);
398
xhwangf94a634d2014-10-22 22:07:27399 // TODO(xhwang): When we use an external Renderer, many methods won't work,
xhwang6fa356202014-12-11 00:44:12400 // e.g. GetCurrentFrameFromCompositor(). See http://crbug.com/434861
dalecurtis9cddc0b2017-04-19 21:23:38401 audio_source_provider_ = new WebAudioSourceProviderImpl(
402 params->audio_renderer_sink(), media_log_.get());
xjz4e5d4bf32017-02-15 21:26:35403
404 if (observer_)
405 observer_->SetClient(this);
Hajime Hoshi8bb37dc2017-12-19 09:35:10406
407 memory_usage_reporting_timer_.SetTaskRunner(
Hajime Hoshib5a26ee2018-05-14 12:47:51408 frame_->GetTaskRunner(blink::TaskType::kInternalMedia));
John Delaney6c8ecc1b2018-10-21 19:07:29409
410 if (frame_->IsAdSubframe())
411 media_metrics_provider_->SetIsAdMedia();
[email protected]ec9212f2008-12-18 21:40:36412}
413
[email protected]4e6be3f2009-05-07 02:24:44414WebMediaPlayerImpl::~WebMediaPlayerImpl() {
xhwang51139732017-02-24 19:36:08415 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:43416 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53417
xhwang51139732017-02-24 19:36:08418 if (set_cdm_result_) {
419 DVLOG(2) << "Resolve pending SetCdm() when media player is destroyed.";
Blink Reformat1c4d759e2017-04-09 16:34:54420 set_cdm_result_->Complete();
xhwang51139732017-02-24 19:36:08421 set_cdm_result_.reset();
422 }
423
alokp1116967f2016-06-11 17:30:56424 suppress_destruction_errors_ = true;
tguilbert1bb1c782017-01-23 21:15:11425
426 delegate_->PlayerGone(delegate_id_);
427 delegate_->RemoveObserver(delegate_id_);
[email protected]baff4512011-10-19 18:21:07428
dalecurtis04bdb582016-08-17 22:15:23429 // Finalize any watch time metrics before destroying the pipeline.
430 watch_time_reporter_.reset();
431
tguilbert350936ff2017-02-24 05:39:27432 // The underlying Pipeline must be stopped before it is destroyed.
Dale Curtisf273f8f2018-12-13 23:40:33433 //
434 // Note: This destruction happens synchronously on the media thread and
435 // |demuxer_|, |data_source_|, |compositor_|, and |media_log_| must outlive
436 // this process. They will be destructed by the DestructionHelper below
437 // after trampolining through the media thread.
tguilbert350936ff2017-02-24 05:39:27438 pipeline_controller_.Stop();
[email protected]f6af7592014-02-28 10:09:11439
dalecurtis83266c72015-10-29 18:43:20440 if (last_reported_memory_usage_)
441 adjust_allocated_memory_cb_.Run(-last_reported_memory_usage_);
442
dalecurtise1edb312016-06-22 02:33:21443 // Destruct compositor resources in the proper order.
danakj8d204a42018-05-18 18:05:35444 client_->SetCcLayer(nullptr);
CJ DiMeglio2302d202017-08-31 08:38:04445
Xiangjun Zhang5e20cba42018-01-10 19:54:56446 client_->MediaRemotingStopped(
447 blink::WebLocalizedString::kMediaRemotingStopNoText);
Xiangjun Zhang87299142017-09-13 20:35:03448
Dale Curtisf273f8f2018-12-13 23:40:33449 if (!surface_layer_for_video_enabled_ && video_layer_)
danakj25f030112018-05-11 18:26:54450 video_layer_->StopUsingProvider();
Matt Wolenetz95af6362018-01-04 20:23:42451
xhwangea8bb3562015-06-08 21:18:37452 media_log_->AddEvent(
453 media_log_->CreateEvent(MediaLogEvent::WEBMEDIAPLAYER_DESTROYED));
[email protected]ec9212f2008-12-18 21:40:36454
Dale Curtisf273f8f2018-12-13 23:40:33455 if (data_source_)
456 data_source_->Stop();
457
458 // Disconnect from the surface layer. We still preserve the |bridge_| until
459 // after pipeline shutdown to ensure any pending frames are painted for tests.
460 if (bridge_)
461 bridge_->ClearObserver();
462
Dale Curtisc96a3542018-12-17 22:15:23463 // Disconnect from the MediaObserver implementation since it's lifetime is
464 // tied to the RendererFactorySelector which can't be destroyed until after
465 // the Pipeline stops.
466 //
467 // Note: We can't use a WeakPtr with the RendererFactory because its methods
468 // are called on the media thread and this destruction takes place on the
469 // renderer thread.
470 if (observer_)
471 observer_->SetClient(nullptr);
472
Dale Curtisf273f8f2018-12-13 23:40:33473 // Handle destruction of things that need to be destructed after the pipeline
474 // completes stopping on the media thread.
475 media_task_runner_->PostTask(
Matt Wolenetz95af6362018-01-04 20:23:42476 FROM_HERE,
Dale Curtisf273f8f2018-12-13 23:40:33477 base::BindOnce(&DestructionHelper, std::move(main_task_runner_),
478 std::move(vfc_task_runner_), std::move(demuxer_),
479 std::move(data_source_), std::move(compositor_),
480 std::move(cdm_context_ref_),
481 std::move(pending_cdm_context_ref_), std::move(media_log_),
482 std::move(renderer_factory_selector_), std::move(bridge_),
483 !!chunk_demuxer_));
Matt Wolenetz95af6362018-01-04 20:23:42484}
485
chcunningham707b821e2018-05-29 08:42:19486WebMediaPlayer::LoadTiming WebMediaPlayerImpl::Load(
487 LoadType load_type,
488 const blink::WebMediaPlayerSource& source,
Takashi Toyoshima2e01e692018-11-16 03:23:27489 CorsMode cors_mode) {
xhwang51139732017-02-24 19:36:08490 DVLOG(1) << __func__;
guidou9bfe4e2f2016-04-09 08:31:19491 // Only URL or MSE blob URL is supported.
Blink Reformat1c4d759e2017-04-09 16:34:54492 DCHECK(source.IsURL());
493 blink::WebURL url = source.GetAsURL();
Xiaohan Wang81fd0022017-07-11 17:45:24494 DVLOG(1) << __func__ << "(" << load_type << ", " << GURL(url) << ", "
495 << cors_mode << ")";
chcunningham707b821e2018-05-29 08:42:19496
497 bool is_deferred = false;
498
Dale Curtise25163812018-09-21 22:13:39499 if (defer_load_cb_) {
chcunningham707b821e2018-05-29 08:42:19500 is_deferred = defer_load_cb_.Run(base::BindOnce(
501 &WebMediaPlayerImpl::DoLoad, AsWeakPtr(), load_type, url, cors_mode));
502 } else {
503 DoLoad(load_type, url, cors_mode);
[email protected]d726eddc2013-07-02 22:25:55504 }
chcunningham707b821e2018-05-29 08:42:19505
506 return is_deferred ? LoadTiming::kDeferred : LoadTiming::kImmediate;
[email protected]62e5e682013-03-07 23:53:24507}
508
CJ DiMeglio013d4c472017-11-21 03:27:30509void WebMediaPlayerImpl::OnWebLayerUpdated() {}
510
danakj6a062b112018-05-17 16:25:45511void WebMediaPlayerImpl::RegisterContentsLayer(cc::Layer* layer) {
CJ DiMeglio2302d202017-08-31 08:38:04512 DCHECK(bridge_);
CJ DiMeglioa2b13fbc2018-06-27 00:50:59513 bridge_->SetContentsOpaque(opaque_);
danakj8d204a42018-05-18 18:05:35514 client_->SetCcLayer(layer);
CJ DiMeglio013d4c472017-11-21 03:27:30515}
516
danakj6a062b112018-05-17 16:25:45517void WebMediaPlayerImpl::UnregisterContentsLayer(cc::Layer* layer) {
518 // |client_| will unregister its cc::Layer if given a nullptr.
danakj8d204a42018-05-18 18:05:35519 client_->SetCcLayer(nullptr);
CJ DiMeglio2302d202017-08-31 08:38:04520}
521
Jennifer Apaciblec45fd052018-02-25 12:04:55522void WebMediaPlayerImpl::OnSurfaceIdUpdated(viz::SurfaceId surface_id) {
Jennifer Apaciblec45fd052018-02-25 12:04:55523 // TODO(726619): Handle the behavior when Picture-in-Picture mode is
524 // disabled.
Jennifer Apacible2b1dc5eb2018-04-27 16:23:28525 // The viz::SurfaceId may be updated when the video begins playback or when
526 // the size of the video changes.
Mounir Lamouri0484f40a2018-07-25 03:03:26527 if (client_ && IsInPictureInPicture() && !client_->IsInAutoPIP()) {
Mounir Lamourife756e32018-05-22 23:19:08528 delegate_->DidPictureInPictureSurfaceChange(
François Beauforta22026d2018-09-25 08:51:11529 delegate_id_, surface_id, pipeline_metadata_.natural_size,
François Beaufortbb68c43e2018-11-20 20:12:03530 ShouldShowPlayPauseButtonInPictureInPictureWindow());
Mounir Lamourife756e32018-05-22 23:19:08531 }
Jennifer Apaciblec45fd052018-02-25 12:04:55532}
533
Blink Reformat1c4d759e2017-04-09 16:34:54534bool WebMediaPlayerImpl::SupportsOverlayFullscreenVideo() {
watk9c87c6fa2016-05-06 20:36:51535#if defined(OS_ANDROID)
[email protected]68ec57f2017-06-27 22:10:05536 return !using_media_player_renderer_ &&
537 overlay_mode_ == OverlayMode::kUseContentVideoView;
watk9c87c6fa2016-05-06 20:36:51538#else
539 return false;
540#endif
541}
542
tsunghungee562e92016-07-20 18:03:31543void WebMediaPlayerImpl::EnableOverlay() {
544 overlay_enabled_ = true;
[email protected]f7df5b342018-07-13 20:22:13545 if (request_routing_token_cb_ &&
546 overlay_mode_ == OverlayMode::kUseAndroidOverlay) {
liberatofe8f9692017-06-08 19:17:36547 overlay_routing_token_is_pending_ = true;
liberato2ff93ad2017-05-17 07:28:24548 token_available_cb_.Reset(
549 base::Bind(&WebMediaPlayerImpl::OnOverlayRoutingToken, AsWeakPtr()));
550 request_routing_token_cb_.Run(token_available_cb_.callback());
watkf835a792016-06-24 23:24:40551 }
tsunghungee562e92016-07-20 18:03:31552
liberato2ff93ad2017-05-17 07:28:24553 // We have requested (and maybe already have) overlay information. If the
554 // restarted decoder requests overlay information, then we'll defer providing
555 // it if it hasn't arrived yet. Otherwise, this would be a race, since we
556 // don't know if the request for overlay info or restart will complete first.
tsunghungee562e92016-07-20 18:03:31557 if (decoder_requires_restart_for_overlay_)
watkdee516f2016-02-18 02:22:19558 ScheduleRestart();
559}
560
tsunghungee562e92016-07-20 18:03:31561void WebMediaPlayerImpl::DisableOverlay() {
562 overlay_enabled_ = false;
liberato2ff93ad2017-05-17 07:28:24563 if (overlay_mode_ == OverlayMode::kUseContentVideoView) {
564 surface_created_cb_.Cancel();
liberato2ff93ad2017-05-17 07:28:24565 } else if (overlay_mode_ == OverlayMode::kUseAndroidOverlay) {
566 token_available_cb_.Cancel();
liberatofe8f9692017-06-08 19:17:36567 overlay_routing_token_is_pending_ = false;
568 overlay_routing_token_ = OverlayInfo::RoutingToken();
liberato2ff93ad2017-05-17 07:28:24569 }
tsunghungee562e92016-07-20 18:03:31570
571 if (decoder_requires_restart_for_overlay_)
watkdee516f2016-02-18 02:22:19572 ScheduleRestart();
liberato2ff93ad2017-05-17 07:28:24573 else
574 MaybeSendOverlayInfoToDecoder();
watkdee516f2016-02-18 02:22:19575}
576
Blink Reformat1c4d759e2017-04-09 16:34:54577void WebMediaPlayerImpl::EnteredFullscreen() {
liberatofe8f9692017-06-08 19:17:36578 overlay_info_.is_fullscreen = true;
579
[email protected]c8d574722017-08-30 20:53:43580 // |always_enable_overlays_| implies that we're already in overlay mode, so
581 // take no action here. Otherwise, switch to an overlay if it's allowed and
582 // if it will display properly.
583 if (!always_enable_overlays_ && overlay_mode_ != OverlayMode::kNoOverlays &&
liberato2fd111be2017-01-04 00:25:06584 DoesOverlaySupportMetadata()) {
tsunghungee562e92016-07-20 18:03:31585 EnableOverlay();
liberato2fd111be2017-01-04 00:25:06586 }
liberato2ff93ad2017-05-17 07:28:24587
liberatofe8f9692017-06-08 19:17:36588 // We send this only if we can send multiple calls. Otherwise, either (a)
589 // we already sent it and we don't have a callback anyway (we reset it when
590 // it's called in restart mode), or (b) we'll send this later when the surface
591 // actually arrives. GVD assumes that the first overlay info will have the
592 // routing information. Note that we set |is_fullscreen_| earlier, so that
593 // if EnableOverlay() can include fullscreen info in case it sends the overlay
594 // info before returning.
595 if (!decoder_requires_restart_for_overlay_)
596 MaybeSendOverlayInfoToDecoder();
tsunghungee562e92016-07-20 18:03:31597}
598
Blink Reformat1c4d759e2017-04-09 16:34:54599void WebMediaPlayerImpl::ExitedFullscreen() {
liberatofe8f9692017-06-08 19:17:36600 overlay_info_.is_fullscreen = false;
601
[email protected]c8d574722017-08-30 20:53:43602 // If we're in overlay mode, then exit it unless we're supposed to allow
603 // overlays all the time.
604 if (!always_enable_overlays_ && overlay_enabled_)
tsunghungee562e92016-07-20 18:03:31605 DisableOverlay();
liberato2ff93ad2017-05-17 07:28:24606
liberatofe8f9692017-06-08 19:17:36607 // See EnteredFullscreen for why we do this.
608 if (!decoder_requires_restart_for_overlay_)
609 MaybeSendOverlayInfoToDecoder();
tsunghungee562e92016-07-20 18:03:31610}
611
Blink Reformat1c4d759e2017-04-09 16:34:54612void WebMediaPlayerImpl::BecameDominantVisibleContent(bool isDominant) {
xjzcdbbe732016-12-03 20:47:42613 if (observer_)
614 observer_->OnBecameDominantVisibleContent(isDominant);
615}
616
Blink Reformat1c4d759e2017-04-09 16:34:54617void WebMediaPlayerImpl::SetIsEffectivelyFullscreen(
François Beaufortad6c5232018-02-26 11:00:44618 blink::WebFullscreenVideoStatus fullscreen_video_status) {
619 delegate_->SetIsEffectivelyFullscreen(delegate_id_, fullscreen_video_status);
zqzhangabc08242017-03-02 16:07:14620}
621
Mounir Lamouri41a79c62017-06-06 12:53:16622void WebMediaPlayerImpl::OnHasNativeControlsChanged(bool has_native_controls) {
623 if (!watch_time_reporter_)
624 return;
625
626 if (has_native_controls)
627 watch_time_reporter_->OnNativeControlsEnabled();
628 else
629 watch_time_reporter_->OnNativeControlsDisabled();
630}
631
Mounir Lamourif9af74e72017-06-19 19:31:45632void WebMediaPlayerImpl::OnDisplayTypeChanged(
633 WebMediaPlayer::DisplayType display_type) {
Mounir Lamouri0484f40a2018-07-25 03:03:26634 if (surface_layer_for_video_enabled_) {
635 vfc_task_runner_->PostTask(
636 FROM_HERE,
637 base::BindOnce(
638 &VideoFrameCompositor::SetForceSubmit,
639 base::Unretained(compositor_.get()),
640 display_type == WebMediaPlayer::DisplayType::kPictureInPicture));
641 }
642
Mounir Lamourif9af74e72017-06-19 19:31:45643 if (!watch_time_reporter_)
644 return;
645
646 switch (display_type) {
647 case WebMediaPlayer::DisplayType::kInline:
648 watch_time_reporter_->OnDisplayTypeInline();
649 break;
650 case WebMediaPlayer::DisplayType::kFullscreen:
651 watch_time_reporter_->OnDisplayTypeFullscreen();
652 break;
653 case WebMediaPlayer::DisplayType::kPictureInPicture:
654 watch_time_reporter_->OnDisplayTypePictureInPicture();
655 break;
656 }
657}
658
[email protected]ef8394c2013-08-21 20:26:30659void WebMediaPlayerImpl::DoLoad(LoadType load_type,
[email protected]180ef242013-11-07 06:50:46660 const blink::WebURL& url,
Takashi Toyoshima2e01e692018-11-16 03:23:27661 CorsMode cors_mode) {
John Chen5b164a02017-11-01 00:36:09662 TRACE_EVENT1("media", "WebMediaPlayerImpl::DoLoad", "id", media_log_->id());
pkastingf5279482016-07-27 02:18:20663 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:43664 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d726eddc2013-07-02 22:25:55665
Dale Curtis4841c712018-12-13 18:14:05666 // Note: |url| may be very large, take care when making copies.
667 loaded_url_ = GURL(url);
668 load_type_ = load_type;
669
670 ReportMetrics(load_type, loaded_url_, *frame_, media_log_.get());
[email protected]62e5e682013-03-07 23:53:24671
Dan Sanderscd8981c2017-08-31 22:37:02672 // Report poster availability for SRC=.
673 if (load_type == kLoadTypeURL) {
674 if (preload_ == MultibufferDataSource::METADATA) {
675 UMA_HISTOGRAM_BOOLEAN("Media.SRC.PreloadMetaDataHasPoster", has_poster_);
676 } else if (preload_ == MultibufferDataSource::AUTO) {
677 UMA_HISTOGRAM_BOOLEAN("Media.SRC.PreloadAutoHasPoster", has_poster_);
678 }
679 }
680
Dale Curtis4841c712018-12-13 18:14:05681 // Set subresource URL for crash reporting; will be truncated to 256 bytes.
Robert Sesekc5e91df2017-12-12 21:11:03682 static base::debug::CrashKeyString* subresource_url =
683 base::debug::AllocateCrashKeyString("subresource_url",
684 base::debug::CrashKeySize::Size256);
Dale Curtis4841c712018-12-13 18:14:05685 base::debug::SetCrashKeyString(subresource_url, loaded_url_.spec());
[email protected]ef8394c2013-08-21 20:26:30686
Blink Reformat1c4d759e2017-04-09 16:34:54687 SetNetworkState(WebMediaPlayer::kNetworkStateLoading);
688 SetReadyState(WebMediaPlayer::kReadyStateHaveNothing);
689 media_log_->AddEvent(media_log_->CreateLoadEvent(url.GetString().Utf8()));
Dale Curtis3899090ea2018-01-12 00:10:35690 load_start_time_ = base::TimeTicks::Now();
[email protected]d726eddc2013-07-02 22:25:55691
Dale Curtisd131da1e2018-08-30 02:09:53692 media_metrics_provider_->Initialize(load_type == kLoadTypeMediaSource,
693 load_type == kLoadTypeURL
694 ? GetMediaURLScheme(loaded_url_)
695 : mojom::MediaURLScheme::kUnknown);
Dale Curtis74612b72017-12-14 20:56:19696
[email protected]d726eddc2013-07-02 22:25:55697 // Media source pipelines can start immediately.
Blink Reformat1c4d759e2017-04-09 16:34:54698 if (load_type == kLoadTypeMediaSource) {
[email protected]ef8394c2013-08-21 20:26:30699 StartPipeline();
hubbe5f0ad43b2015-12-14 20:57:26700 } else {
Dale Curtis4841c712018-12-13 18:14:05701 // Short circuit the more complex loading path for data:// URLs. Sending
702 // them through the network based loading path just wastes memory and causes
703 // worse performance since reads become asynchronous.
704 if (loaded_url_.SchemeIs(url::kDataScheme)) {
705 std::string mime_type, charset, data;
706 if (!net::DataURL::Parse(loaded_url_, &mime_type, &charset, &data)) {
707 DataSourceInitialized(false);
708 return;
709 }
710
711 // Replace |loaded_url_| with an empty data:// URL since it may be large.
712 loaded_url_ = GURL("data:,");
713
714 // Mark all the data as buffered.
715 buffered_data_source_host_.SetTotalBytes(data.size());
716 buffered_data_source_host_.AddBufferedByteRange(0, data.size());
717
718 DCHECK(!mb_data_source_);
719 data_source_.reset(new MemoryDataSource(std::move(data)));
720 DataSourceInitialized(true);
721 return;
722 }
723
John Delaneyb933391602018-10-17 21:50:47724 auto url_data =
Takashi Toyoshima2e01e692018-11-16 03:23:27725 url_index_->GetByUrl(url, static_cast<UrlData::CorsMode>(cors_mode));
John Delaneyb933391602018-10-17 21:50:47726 // Notify |this| of bytes received by the network.
727 url_data->AddBytesReceivedCallback(BindToCurrentLoop(base::BindRepeating(
728 &WebMediaPlayerImpl::OnBytesReceived, AsWeakPtr())));
Dale Curtis4841c712018-12-13 18:14:05729 mb_data_source_ = new MultibufferDataSource(
John Delaneyb933391602018-10-17 21:50:47730 main_task_runner_, std::move(url_data), media_log_.get(),
731 &buffered_data_source_host_,
Dale Curtis4841c712018-12-13 18:14:05732 base::BindRepeating(&WebMediaPlayerImpl::NotifyDownloading,
733 AsWeakPtr()));
734 data_source_.reset(mb_data_source_);
735 mb_data_source_->SetPreload(preload_);
736 mb_data_source_->SetIsClientAudioElement(client_->IsAudioElement());
737 mb_data_source_->Initialize(
avayvode46d7bef2016-03-30 23:18:26738 base::Bind(&WebMediaPlayerImpl::DataSourceInitialized, AsWeakPtr()));
hubbe5f0ad43b2015-12-14 20:57:26739 }
hubbed5f36882016-01-15 22:40:37740
741#if defined(OS_ANDROID) // WMPI_CAST
dalecurtisbb3eaac2016-01-27 21:10:25742 cast_impl_.Initialize(url, frame_, delegate_id_);
hubbed5f36882016-01-15 22:40:37743#endif
[email protected]62e5e682013-03-07 23:53:24744}
745
Blink Reformat1c4d759e2017-04-09 16:34:54746void WebMediaPlayerImpl::Play() {
pkastingf5279482016-07-27 02:18:20747 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:43748 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53749
avayvod65fad272017-02-24 01:00:48750 // User initiated play unlocks background video playback.
Mustaq Ahmede473e4352017-11-04 01:04:25751 if (blink::WebUserGestureIndicator::IsProcessingUserGesture(frame_))
avayvod65fad272017-02-24 01:00:48752 video_locked_when_paused_when_hidden_ = false;
753
hubbed5f36882016-01-15 22:40:37754#if defined(OS_ANDROID) // WMPI_CAST
Blink Reformat1c4d759e2017-04-09 16:34:54755 if (IsRemote()) {
dalecurtis6e2716d2016-01-21 04:49:15756 cast_impl_.play();
hubbed5f36882016-01-15 22:40:37757 return;
758 }
759#endif
sandersd35d2c3f2017-01-14 02:04:42760 // TODO(sandersd): Do we want to reset the idle timer here?
tguilbert1bb1c782017-01-23 21:15:11761 delegate_->SetIdle(delegate_id_, false);
[email protected]49480902009-07-14 20:23:43762 paused_ = false;
tguilbert350936ff2017-02-24 05:39:27763 pipeline_controller_.SetPlaybackRate(playback_rate_);
dalecurtis4619cd02016-09-22 21:39:10764 background_pause_timer_.Stop();
sandersd1c0bba02016-03-04 23:14:08765
Dale Curtis4841c712018-12-13 18:14:05766 if (mb_data_source_)
767 mb_data_source_->MediaIsPlaying();
[email protected]090f7312011-08-05 23:26:40768
xjz48a9cb72016-12-20 04:02:49769 if (observer_)
770 observer_->OnPlaying();
771
Mounir Lamouri89c0a1b2018-03-01 15:00:44772 watch_time_reporter_->SetAutoplayInitiated(client_->WasAutoplayInitiated());
773
Dale Curtis051fdf62017-08-05 00:21:13774 // If we're seeking we'll trigger the watch time reporter upon seek completed;
775 // we don't want to start it here since the seek time is unstable. E.g., when
776 // playing content with a positive start time we would have a zero seek time.
777 if (!Seeking()) {
778 DCHECK(watch_time_reporter_);
779 watch_time_reporter_->OnPlaying();
780 }
781
Chris Cunninghamd9df58e2017-08-29 00:04:23782 if (video_decode_stats_reporter_)
783 video_decode_stats_reporter_->OnPlaying();
784
acolwell9e0840d2014-09-06 19:01:32785 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PLAY));
sandersd50a635e2016-04-04 22:50:09786 UpdatePlayState();
[email protected]ec9212f2008-12-18 21:40:36787}
788
Blink Reformat1c4d759e2017-04-09 16:34:54789void WebMediaPlayerImpl::Pause() {
pkastingf5279482016-07-27 02:18:20790 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:43791 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53792
sandersd50a635e2016-04-04 22:50:09793 // We update the paused state even when casting, since we expect pause() to be
794 // called when casting begins, and when we exit casting we should end up in a
795 // paused state.
[email protected]49480902009-07-14 20:23:43796 paused_ = true;
hubbed5f36882016-01-15 22:40:37797
avayvodeb9098d2017-01-07 00:33:03798 // No longer paused because it was hidden.
799 paused_when_hidden_ = false;
800
avayvod65fad272017-02-24 01:00:48801 // User initiated pause locks background videos.
Mustaq Ahmede473e4352017-11-04 01:04:25802 if (blink::WebUserGestureIndicator::IsProcessingUserGesture(frame_))
avayvod65fad272017-02-24 01:00:48803 video_locked_when_paused_when_hidden_ = true;
804
hubbed5f36882016-01-15 22:40:37805#if defined(OS_ANDROID) // WMPI_CAST
Blink Reformat1c4d759e2017-04-09 16:34:54806 if (IsRemote()) {
dalecurtis6e2716d2016-01-21 04:49:15807 cast_impl_.pause();
hubbed5f36882016-01-15 22:40:37808 return;
809 }
810#endif
811
tguilbert350936ff2017-02-24 05:39:27812 pipeline_controller_.SetPlaybackRate(0.0);
Dale Curtisdc5d47c2018-02-15 11:15:19813 paused_time_ = pipeline_controller_.GetMediaTime();
[email protected]090f7312011-08-05 23:26:40814
xjz48a9cb72016-12-20 04:02:49815 if (observer_)
816 observer_->OnPaused();
817
dalecurtis04bdb582016-08-17 22:15:23818 DCHECK(watch_time_reporter_);
819 watch_time_reporter_->OnPaused();
Chris Cunninghamd9df58e2017-08-29 00:04:23820
821 if (video_decode_stats_reporter_)
822 video_decode_stats_reporter_->OnPaused();
823
acolwell9e0840d2014-09-06 19:01:32824 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PAUSE));
avayvod2135a642017-01-13 00:17:14825
sandersd50a635e2016-04-04 22:50:09826 UpdatePlayState();
[email protected]ec9212f2008-12-18 21:40:36827}
828
Blink Reformat1c4d759e2017-04-09 16:34:54829void WebMediaPlayerImpl::Seek(double seconds) {
pkastingf5279482016-07-27 02:18:20830 DVLOG(1) << __func__ << "(" << seconds << "s)";
acolwellb4034942014-08-28 15:42:43831 DCHECK(main_task_runner_->BelongsToCurrentThread());
servolk86b3d88fb2017-03-18 02:50:28832 media_log_->AddEvent(media_log_->CreateSeekEvent(seconds));
sandersd1c0bba02016-03-04 23:14:08833 DoSeek(base::TimeDelta::FromSecondsD(seconds), true);
834}
835
836void WebMediaPlayerImpl::DoSeek(base::TimeDelta time, bool time_updated) {
837 DCHECK(main_task_runner_->BelongsToCurrentThread());
John Chen5b164a02017-11-01 00:36:09838 TRACE_EVENT2("media", "WebMediaPlayerImpl::DoSeek", "target",
839 time.InSecondsF(), "id", media_log_->id());
[email protected]d43ed912009-02-03 04:52:53840
hubbed5f36882016-01-15 22:40:37841#if defined(OS_ANDROID) // WMPI_CAST
Blink Reformat1c4d759e2017-04-09 16:34:54842 if (IsRemote()) {
sandersd1c0bba02016-03-04 23:14:08843 cast_impl_.seek(time);
hubbed5f36882016-01-15 22:40:37844 return;
845 }
846#endif
847
srirama.mccf671812015-01-08 11:59:13848 ReadyState old_state = ready_state_;
Blink Reformat1c4d759e2017-04-09 16:34:54849 if (ready_state_ > WebMediaPlayer::kReadyStateHaveMetadata)
850 SetReadyState(WebMediaPlayer::kReadyStateHaveMetadata);
[email protected]1bb666802013-11-28 06:12:08851
Dale Curtis051fdf62017-08-05 00:21:13852 // When paused or ended, we know exactly what the current time is and can
853 // elide seeks to it. However, there are two cases that are not elided:
sandersd1c0bba02016-03-04 23:14:08854 // 1) When the pipeline state is not stable.
855 // In this case we just let |pipeline_controller_| decide what to do, as
856 // it has complete information.
857 // 2) For MSE.
858 // Because the buffers may have changed between seeks, MSE seeks are
859 // never elided.
Dale Curtis051fdf62017-08-05 00:21:13860 if (paused_ && pipeline_controller_.IsStable() &&
861 (paused_time_ == time ||
862 (ended_ && time == base::TimeDelta::FromSecondsD(Duration()))) &&
sandersd1c0bba02016-03-04 23:14:08863 !chunk_demuxer_) {
864 // If the ready state was high enough before, we can indicate that the seek
865 // completed just by restoring it. Otherwise we will just wait for the real
866 // ready state change to eventually happen.
Blink Reformat1c4d759e2017-04-09 16:34:54867 if (old_state == kReadyStateHaveEnoughData) {
srirama.m8f4a37562014-12-13 08:16:18868 main_task_runner_->PostTask(
Dale Curtisee9be30012018-09-21 22:21:51869 FROM_HERE, base::BindOnce(&WebMediaPlayerImpl::OnBufferingStateChange,
870 AsWeakPtr(), BUFFERING_HAVE_ENOUGH));
srirama.m36ab2682014-12-11 04:20:01871 }
sandersd1c0bba02016-03-04 23:14:08872 return;
srirama.m36ab2682014-12-11 04:20:01873 }
[email protected]44ff37c02009-10-24 01:03:03874
dalecurtis04bdb582016-08-17 22:15:23875 // Call this before setting |seeking_| so that the current media time can be
876 // recorded by the reporter.
877 if (watch_time_reporter_)
878 watch_time_reporter_->OnSeeking();
879
dalecurtis1af3c1a2017-04-11 00:53:49880 // Clear any new frame processed callbacks on seek; otherwise we'll end up
881 // logging a time long after the seek completes.
882 frame_time_report_cb_.Cancel();
883
sandersd35d2c3f2017-01-14 02:04:42884 // TODO(sandersd): Move |seeking_| to PipelineController.
885 // TODO(sandersd): Do we want to reset the idle timer here?
tguilbert1bb1c782017-01-23 21:15:11886 delegate_->SetIdle(delegate_id_, false);
sandersd50a635e2016-04-04 22:50:09887 ended_ = false;
[email protected]b3766a22010-12-22 17:34:13888 seeking_ = true;
sandersd1c0bba02016-03-04 23:14:08889 seek_time_ = time;
890 if (paused_)
891 paused_time_ = time;
892 pipeline_controller_.Seek(time, time_updated);
[email protected]b3766a22010-12-22 17:34:13893
sandersd50a635e2016-04-04 22:50:09894 // This needs to be called after Seek() so that if a resume is triggered, it
895 // is to the correct time.
896 UpdatePlayState();
[email protected]ec9212f2008-12-18 21:40:36897}
898
Blink Reformat1c4d759e2017-04-09 16:34:54899void WebMediaPlayerImpl::SetRate(double rate) {
pkastingf5279482016-07-27 02:18:20900 DVLOG(1) << __func__ << "(" << rate << ")";
acolwellb4034942014-08-28 15:42:43901 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53902
Matt Wolenetz6010f6c2017-10-18 00:44:36903 if (rate != playback_rate_) {
904 LIMITED_MEDIA_LOG(INFO, media_log_.get(), num_playback_rate_logs_,
905 kMaxNumPlaybackRateLogs)
906 << "Effective playback rate changed from " << playback_rate_ << " to "
907 << rate;
908 }
909
[email protected]49480902009-07-14 20:23:43910 playback_rate_ = rate;
911 if (!paused_) {
tguilbert350936ff2017-02-24 05:39:27912 pipeline_controller_.SetPlaybackRate(rate);
Dale Curtis4841c712018-12-13 18:14:05913 if (mb_data_source_)
914 mb_data_source_->MediaPlaybackRateChanged(rate);
[email protected]49480902009-07-14 20:23:43915 }
[email protected]ec9212f2008-12-18 21:40:36916}
917
Blink Reformat1c4d759e2017-04-09 16:34:54918void WebMediaPlayerImpl::SetVolume(double volume) {
pkastingf5279482016-07-27 02:18:20919 DVLOG(1) << __func__ << "(" << volume << ")";
acolwellb4034942014-08-28 15:42:43920 DCHECK(main_task_runner_->BelongsToCurrentThread());
dalecurtisbb3eaac2016-01-27 21:10:25921 volume_ = volume;
tguilbert350936ff2017-02-24 05:39:27922 pipeline_controller_.SetVolume(volume_ * volume_multiplier_);
dalecurtis04bdb582016-08-17 22:15:23923 if (watch_time_reporter_)
924 watch_time_reporter_->OnVolumeChange(volume);
Becca Hughes9f6fd4b82017-06-15 10:01:40925 delegate_->DidPlayerMutedStatusChange(delegate_id_, volume == 0.0);
mlamouri910111362016-11-04 11:28:24926
927 // The play state is updated because the player might have left the autoplay
928 // muted state.
929 UpdatePlayState();
[email protected]ec9212f2008-12-18 21:40:36930}
[email protected]f0a51fb52009-03-05 12:46:38931
François Beaufort9290aab2018-05-07 21:18:47932void WebMediaPlayerImpl::EnterPictureInPicture(
Mounir Lamouri917143af2018-05-24 21:19:57933 blink::WebMediaPlayer::PipWindowOpenedCallback callback) {
[email protected]69db58f2018-09-26 20:27:56934 if (!surface_layer_for_video_enabled_)
935 ActivateSurfaceLayerForVideo();
936
Mounir Lamourib642a3c2018-07-09 15:45:31937 DCHECK(bridge_);
Mounir Lamouri37e8ae82018-05-31 02:38:46938
Mounir Lamourib642a3c2018-07-09 15:45:31939 const viz::SurfaceId& surface_id = bridge_->GetSurfaceId();
940 DCHECK(surface_id.is_valid());
Jennifer Apaciblec45fd052018-02-25 12:04:55941
Mounir Lamouri11e9ef42018-05-22 03:10:16942 // Notifies the browser process that the player should now be in
943 // Picture-in-Picture mode.
François Beauforta22026d2018-09-25 08:51:11944 delegate_->DidPictureInPictureModeStart(
945 delegate_id_, surface_id, pipeline_metadata_.natural_size,
François Beaufortbb68c43e2018-11-20 20:12:03946 std::move(callback), ShouldShowPlayPauseButtonInPictureInPictureWindow());
Jennifer Apacible3f0489102018-01-19 20:10:31947}
948
François Beaufort9290aab2018-05-07 21:18:47949void WebMediaPlayerImpl::ExitPictureInPicture(
950 blink::WebMediaPlayer::PipWindowClosedCallback callback) {
Mounir Lamouri6d759e12018-05-16 20:01:30951 // Notifies the browser process that Picture-in-Picture has ended. It will
952 // clear out the states and close the window.
953 delegate_->DidPictureInPictureModeEnd(delegate_id_, std::move(callback));
Jennifer Apacible02897b72018-04-01 01:00:49954
Mounir Lamouri6d759e12018-05-16 20:01:30955 // Internal cleanups.
Jennifer Apacible5cd9a7e2018-04-17 03:08:06956 OnPictureInPictureModeEnded();
Jennifer Apacible02897b72018-04-01 01:00:49957}
958
sawtellee19d11aa2018-08-10 03:47:50959void WebMediaPlayerImpl::SetPictureInPictureCustomControls(
960 const std::vector<blink::PictureInPictureControlInfo>& controls) {
961 delegate_->DidSetPictureInPictureCustomControls(delegate_id_, controls);
962}
963
Mounir Lamouri917143af2018-05-24 21:19:57964void WebMediaPlayerImpl::RegisterPictureInPictureWindowResizeCallback(
965 blink::WebMediaPlayer::PipWindowResizedCallback callback) {
Mounir Lamouri0484f40a2018-07-25 03:03:26966 DCHECK(IsInPictureInPicture() && !client_->IsInAutoPIP());
Mounir Lamouri917143af2018-05-24 21:19:57967
968 delegate_->RegisterPictureInPictureWindowResizeCallback(delegate_id_,
969 std::move(callback));
970}
971
Daniel Chengc1710b52018-10-24 03:12:28972void WebMediaPlayerImpl::SetSinkId(
973 const blink::WebString& sink_id,
974 std::unique_ptr<blink::WebSetSinkIdCallbacks> web_callback) {
guidou69223ce2015-06-16 10:36:19975 DCHECK(main_task_runner_->BelongsToCurrentThread());
pkastingf5279482016-07-27 02:18:20976 DVLOG(1) << __func__;
guidouc7babef2015-10-22 00:42:35977
Dale Curtisca1b78f2019-01-15 03:11:26978 OutputDeviceStatusCB callback =
979 ConvertToOutputDeviceStatusCB(std::move(web_callback));
guidouc7babef2015-10-22 00:42:35980 media_task_runner_->PostTask(
Dale Curtisee9be30012018-09-21 22:21:51981 FROM_HERE, base::BindOnce(&SetSinkIdOnMediaThread, audio_source_provider_,
Daniel Chengc1710b52018-10-24 03:12:28982 sink_id.Utf8(), std::move(callback)));
guidou69223ce2015-06-16 10:36:19983}
984
Blink Reformat1c4d759e2017-04-09 16:34:54985STATIC_ASSERT_ENUM(WebMediaPlayer::kPreloadNone, MultibufferDataSource::NONE);
986STATIC_ASSERT_ENUM(WebMediaPlayer::kPreloadMetaData,
dalecurtisb6e052f52016-08-25 00:35:55987 MultibufferDataSource::METADATA);
Blink Reformat1c4d759e2017-04-09 16:34:54988STATIC_ASSERT_ENUM(WebMediaPlayer::kPreloadAuto, MultibufferDataSource::AUTO);
[email protected]23a8b1d82011-04-05 16:28:20989
Blink Reformat1c4d759e2017-04-09 16:34:54990void WebMediaPlayerImpl::SetPreload(WebMediaPlayer::Preload preload) {
pkastingf5279482016-07-27 02:18:20991 DVLOG(1) << __func__ << "(" << preload << ")";
acolwellb4034942014-08-28 15:42:43992 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]4e6be3f2009-05-07 02:24:44993
dalecurtisb6e052f52016-08-25 00:35:55994 preload_ = static_cast<MultibufferDataSource::Preload>(preload);
Dale Curtis4841c712018-12-13 18:14:05995 if (mb_data_source_)
996 mb_data_source_->SetPreload(preload_);
[email protected]4e6be3f2009-05-07 02:24:44997}
998
Blink Reformat1c4d759e2017-04-09 16:34:54999bool WebMediaPlayerImpl::HasVideo() const {
acolwellb4034942014-08-28 15:42:431000 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:531001
[email protected]b8877772014-03-26 20:17:151002 return pipeline_metadata_.has_video;
[email protected]d43ed912009-02-03 04:52:531003}
1004
Blink Reformat1c4d759e2017-04-09 16:34:541005bool WebMediaPlayerImpl::HasAudio() const {
acolwellb4034942014-08-28 15:42:431006 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]fc367af2009-08-14 23:06:351007
[email protected]b8877772014-03-26 20:17:151008 return pipeline_metadata_.has_audio;
[email protected]fc367af2009-08-14 23:06:351009}
1010
Blink Reformat1c4d759e2017-04-09 16:34:541011void WebMediaPlayerImpl::EnabledAudioTracksChanged(
servolkf25ceed2016-07-01 03:44:381012 const blink::WebVector<blink::WebMediaPlayer::TrackId>& enabledTrackIds) {
1013 DCHECK(main_task_runner_->BelongsToCurrentThread());
1014
1015 std::ostringstream logstr;
1016 std::vector<MediaTrack::Id> enabledMediaTrackIds;
1017 for (const auto& blinkTrackId : enabledTrackIds) {
Blink Reformat1c4d759e2017-04-09 16:34:541018 MediaTrack::Id track_id = blinkTrackId.Utf8().data();
servolkf25ceed2016-07-01 03:44:381019 logstr << track_id << " ";
1020 enabledMediaTrackIds.push_back(track_id);
1021 }
dalecurtis9cddc0b2017-04-19 21:23:381022 MEDIA_LOG(INFO, media_log_.get())
1023 << "Enabled audio tracks: [" << logstr.str() << "]";
tguilbert350936ff2017-02-24 05:39:271024 pipeline_controller_.OnEnabledAudioTracksChanged(enabledMediaTrackIds);
servolkf25ceed2016-07-01 03:44:381025}
1026
Blink Reformat1c4d759e2017-04-09 16:34:541027void WebMediaPlayerImpl::SelectedVideoTrackChanged(
servolkf25ceed2016-07-01 03:44:381028 blink::WebMediaPlayer::TrackId* selectedTrackId) {
1029 DCHECK(main_task_runner_->BelongsToCurrentThread());
1030
servolk9bed6602017-02-24 01:20:111031 base::Optional<MediaTrack::Id> selected_video_track_id;
1032 if (selectedTrackId && !video_track_disabled_)
Blink Reformat1c4d759e2017-04-09 16:34:541033 selected_video_track_id = MediaTrack::Id(selectedTrackId->Utf8().data());
dalecurtis9cddc0b2017-04-19 21:23:381034 MEDIA_LOG(INFO, media_log_.get())
1035 << "Selected video track: [" << selected_video_track_id.value_or("")
1036 << "]";
tguilbert350936ff2017-02-24 05:39:271037 pipeline_controller_.OnSelectedVideoTrackChanged(selected_video_track_id);
servolkf25ceed2016-07-01 03:44:381038}
1039
Blink Reformat1c4d759e2017-04-09 16:34:541040blink::WebSize WebMediaPlayerImpl::NaturalSize() const {
acolwellb4034942014-08-28 15:42:431041 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:531042
[email protected]b8877772014-03-26 20:17:151043 return blink::WebSize(pipeline_metadata_.natural_size);
[email protected]d43ed912009-02-03 04:52:531044}
1045
Jiajia Qin82acdc02017-07-31 09:55:141046blink::WebSize WebMediaPlayerImpl::VisibleRect() const {
1047 DCHECK(main_task_runner_->BelongsToCurrentThread());
1048 scoped_refptr<VideoFrame> video_frame = GetCurrentFrameFromCompositor();
1049 if (!video_frame)
1050 return blink::WebSize();
1051
1052 const gfx::Rect& visible_rect = video_frame->visible_rect();
1053 return blink::WebSize(visible_rect.width(), visible_rect.height());
1054}
1055
Blink Reformat1c4d759e2017-04-09 16:34:541056bool WebMediaPlayerImpl::Paused() const {
acolwellb4034942014-08-28 15:42:431057 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:531058
hubbed5f36882016-01-15 22:40:371059#if defined(OS_ANDROID) // WMPI_CAST
Blink Reformat1c4d759e2017-04-09 16:34:541060 if (IsRemote())
danakj4f1fd6a2017-01-06 21:15:171061 return cast_impl_.IsPaused();
hubbed5f36882016-01-15 22:40:371062#endif
sandersd50a635e2016-04-04 22:50:091063
tguilbert350936ff2017-02-24 05:39:271064 return pipeline_controller_.GetPlaybackRate() == 0.0f;
[email protected]d43ed912009-02-03 04:52:531065}
1066
Blink Reformat1c4d759e2017-04-09 16:34:541067bool WebMediaPlayerImpl::Seeking() const {
acolwellb4034942014-08-28 15:42:431068 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:531069
Blink Reformat1c4d759e2017-04-09 16:34:541070 if (ready_state_ == WebMediaPlayer::kReadyStateHaveNothing)
[email protected]0acebfa2009-08-21 22:45:401071 return false;
[email protected]67cd5052009-09-10 21:53:221072
[email protected]b3766a22010-12-22 17:34:131073 return seeking_;
[email protected]ec9212f2008-12-18 21:40:361074}
1075
Blink Reformat1c4d759e2017-04-09 16:34:541076double WebMediaPlayerImpl::Duration() const {
acolwellb4034942014-08-28 15:42:431077 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]39bdde32013-04-17 17:44:201078
Blink Reformat1c4d759e2017-04-09 16:34:541079 if (ready_state_ == WebMediaPlayer::kReadyStateHaveNothing)
[email protected]39bdde32013-04-17 17:44:201080 return std::numeric_limits<double>::quiet_NaN();
1081
chcunninghamb92d5062017-01-10 21:50:221082 // Use duration from ChunkDemuxer when present. MSE allows users to specify
1083 // duration as a double. This propagates to the rest of the pipeline as a
1084 // TimeDelta with potentially reduced precision (limited to Microseconds).
1085 // ChunkDemuxer returns the full-precision user-specified double. This ensures
1086 // users can "get" the exact duration they "set".
1087 if (chunk_demuxer_)
1088 return chunk_demuxer_->GetDuration();
1089
avayvodcc273dd2017-01-19 19:35:121090 base::TimeDelta pipeline_duration = GetPipelineMediaDuration();
chcunninghamb92d5062017-01-10 21:50:221091 return pipeline_duration == kInfiniteDuration
1092 ? std::numeric_limits<double>::infinity()
1093 : pipeline_duration.InSecondsF();
[email protected]d43ed912009-02-03 04:52:531094}
1095
[email protected]db66d0092014-04-16 07:15:121096double WebMediaPlayerImpl::timelineOffset() const {
acolwellb4034942014-08-28 15:42:431097 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]db66d0092014-04-16 07:15:121098
1099 if (pipeline_metadata_.timeline_offset.is_null())
1100 return std::numeric_limits<double>::quiet_NaN();
1101
1102 return pipeline_metadata_.timeline_offset.ToJsTime();
1103}
1104
Dale Curtis051fdf62017-08-05 00:21:131105base::TimeDelta WebMediaPlayerImpl::GetCurrentTimeInternal() const {
1106 DCHECK(main_task_runner_->BelongsToCurrentThread());
1107 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
1108
1109 base::TimeDelta current_time;
1110 if (Seeking())
1111 current_time = seek_time_;
1112#if defined(OS_ANDROID) // WMPI_CAST
1113 else if (IsRemote())
1114 current_time = cast_impl_.currentTime();
1115#endif
1116 else if (paused_)
1117 current_time = paused_time_;
1118 else
1119 current_time = pipeline_controller_.GetMediaTime();
1120
1121 DCHECK_NE(current_time, kInfiniteDuration);
1122 DCHECK_GE(current_time, base::TimeDelta());
1123 return current_time;
1124}
1125
Blink Reformat1c4d759e2017-04-09 16:34:541126double WebMediaPlayerImpl::CurrentTime() const {
acolwellb4034942014-08-28 15:42:431127 DCHECK(main_task_runner_->BelongsToCurrentThread());
Blink Reformat1c4d759e2017-04-09 16:34:541128 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
scherkusd2c745b2014-09-04 05:03:401129
1130 // TODO(scherkus): Replace with an explicit ended signal to HTMLMediaElement,
1131 // see http://crbug.com/409280
Dale Curtis051fdf62017-08-05 00:21:131132 // Note: Duration() may be infinity.
josephlolak918863bc2017-11-15 08:54:331133 return (ended_ && !std::isinf(Duration()))
1134 ? Duration()
1135 : GetCurrentTimeInternal().InSecondsF();
[email protected]d43ed912009-02-03 04:52:531136}
1137
Blink Reformat1c4d759e2017-04-09 16:34:541138WebMediaPlayer::NetworkState WebMediaPlayerImpl::GetNetworkState() const {
acolwellb4034942014-08-28 15:42:431139 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]ddb1e5a2010-12-13 20:10:451140 return network_state_;
1141}
1142
Blink Reformat1c4d759e2017-04-09 16:34:541143WebMediaPlayer::ReadyState WebMediaPlayerImpl::GetReadyState() const {
acolwellb4034942014-08-28 15:42:431144 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]ddb1e5a2010-12-13 20:10:451145 return ready_state_;
1146}
1147
CJ DiMeglio89240472018-10-18 18:21:101148blink::WebMediaPlayer::SurfaceLayerMode
1149WebMediaPlayerImpl::GetVideoSurfaceLayerMode() const {
1150 return surface_layer_mode_;
1151}
1152
wolenetzed8e7092017-04-21 16:28:591153blink::WebString WebMediaPlayerImpl::GetErrorMessage() const {
wolenetz4d39cc02016-04-05 19:54:411154 DCHECK(main_task_runner_->BelongsToCurrentThread());
wolenetzed8e7092017-04-21 16:28:591155 return blink::WebString::FromUTF8(media_log_->GetErrorMessage());
wolenetz4d39cc02016-04-05 19:54:411156}
1157
Blink Reformat1c4d759e2017-04-09 16:34:541158blink::WebTimeRanges WebMediaPlayerImpl::Buffered() const {
acolwellb4034942014-08-28 15:42:431159 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]779a8322014-08-22 21:28:371160
acolwell9e0840d2014-09-06 19:01:321161 Ranges<base::TimeDelta> buffered_time_ranges =
tguilbert350936ff2017-02-24 05:39:271162 pipeline_controller_.GetBufferedTimeRanges();
[email protected]779a8322014-08-22 21:28:371163
avayvodcc273dd2017-01-19 19:35:121164 const base::TimeDelta duration = GetPipelineMediaDuration();
dalecurtis39a7f932016-07-19 18:34:591165 if (duration != kInfiniteDuration) {
tguilbert350936ff2017-02-24 05:39:271166 buffered_data_source_host_.AddBufferedTimeRanges(&buffered_time_ranges,
1167 duration);
[email protected]779a8322014-08-22 21:28:371168 }
[email protected]02022fc2014-05-16 00:05:311169 return ConvertToWebTimeRanges(buffered_time_ranges);
1170}
1171
Blink Reformat1c4d759e2017-04-09 16:34:541172blink::WebTimeRanges WebMediaPlayerImpl::Seekable() const {
acolwellb4034942014-08-28 15:42:431173 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]39bdde32013-04-17 17:44:201174
Blink Reformat1c4d759e2017-04-09 16:34:541175 if (ready_state_ < WebMediaPlayer::kReadyStateHaveMetadata)
philipjb0e6f3f2014-09-30 09:51:531176 return blink::WebTimeRanges();
1177
Blink Reformat1c4d759e2017-04-09 16:34:541178 const double seekable_end = Duration();
dalecurtis56359cb2014-10-28 00:06:291179
1180 // Allow a special exception for seeks to zero for streaming sources with a
1181 // finite duration; this allows looping to work.
Dale Curtis4841c712018-12-13 18:14:051182 const bool is_finite_stream = mb_data_source_ &&
1183 mb_data_source_->IsStreaming() &&
tguilbertade2bcb2017-01-07 02:57:451184 std::isfinite(seekable_end);
1185
tguilbert75e2bf62017-04-26 20:13:121186 // Do not change the seekable range when using the MediaPlayerRenderer. It
1187 // will take care of dropping invalid seeks.
1188 const bool force_seeks_to_zero =
1189 !using_media_player_renderer_ && is_finite_stream;
dalecurtis56359cb2014-10-28 00:06:291190
1191 // TODO(dalecurtis): Technically this allows seeking on media which return an
tguilbertade2bcb2017-01-07 02:57:451192 // infinite duration so long as DataSource::IsStreaming() is false. While not
dalecurtis56359cb2014-10-28 00:06:291193 // expected, disabling this breaks semi-live players, http://crbug.com/427412.
1194 const blink::WebTimeRange seekable_range(
tguilbertade2bcb2017-01-07 02:57:451195 0.0, force_seeks_to_zero ? 0.0 : seekable_end);
philipjb0e6f3f2014-09-30 09:51:531196 return blink::WebTimeRanges(&seekable_range, 1);
[email protected]ec9212f2008-12-18 21:40:361197}
1198
sandersd35d2c3f2017-01-14 02:04:421199bool WebMediaPlayerImpl::IsPrerollAttemptNeeded() {
1200 // TODO(sandersd): Replace with |highest_ready_state_since_seek_| if we need
1201 // to ensure that preroll always gets a chance to complete.
1202 // See http://crbug.com/671525.
Blink Reformat1c4d759e2017-04-09 16:34:541203 if (highest_ready_state_ >= ReadyState::kReadyStateHaveFutureData)
sandersd35d2c3f2017-01-14 02:04:421204 return false;
1205
Fredrik Hubinette4cfb4412017-08-23 00:03:071206 // To suspend before we reach kReadyStateHaveCurrentData is only ok
1207 // if we know we're going to get woken up when we get more data, which
1208 // will only happen if the network is in the "Loading" state.
1209 // This happens when the network is fast, but multiple videos are loading
1210 // and multiplexing gets held up waiting for available threads.
1211 if (highest_ready_state_ <= ReadyState::kReadyStateHaveMetadata &&
1212 network_state_ != WebMediaPlayer::kNetworkStateLoading) {
1213 return true;
1214 }
1215
sandersd35d2c3f2017-01-14 02:04:421216 if (preroll_attempt_pending_)
1217 return true;
1218
1219 // Freshly initialized; there has never been any loading progress. (Otherwise
1220 // |preroll_attempt_pending_| would be true when the start time is null.)
1221 if (preroll_attempt_start_time_.is_null())
1222 return false;
1223
1224 base::TimeDelta preroll_attempt_duration =
1225 tick_clock_->NowTicks() - preroll_attempt_start_time_;
1226 return preroll_attempt_duration < kPrerollAttemptTimeout;
1227}
1228
Blink Reformat1c4d759e2017-04-09 16:34:541229bool WebMediaPlayerImpl::DidLoadingProgress() {
acolwellb4034942014-08-28 15:42:431230 DCHECK(main_task_runner_->BelongsToCurrentThread());
dalecurtise7120dc2016-09-03 02:54:351231
1232 // Note: Separate variables used to ensure both methods are called every time.
tguilbert350936ff2017-02-24 05:39:271233 const bool pipeline_progress = pipeline_controller_.DidLoadingProgress();
dalecurtise7120dc2016-09-03 02:54:351234 const bool data_progress = buffered_data_source_host_.DidLoadingProgress();
hubbeb2d3efd2017-05-05 23:26:381235 return pipeline_progress || data_progress;
[email protected]d43ed912009-02-03 04:52:531236}
1237
danakjff6a0262018-06-26 19:50:311238void WebMediaPlayerImpl::Paint(cc::PaintCanvas* canvas,
[email protected]dd5c7972014-08-21 15:00:371239 const blink::WebRect& rect,
Kai Ninomiya9e8ae29b2017-09-06 23:45:161240 cc::PaintFlags& flags,
1241 int already_uploaded_id,
1242 VideoFrameUploadMetadata* out_metadata) {
acolwellb4034942014-08-28 15:42:431243 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]dd061e12014-05-06 19:21:221244 TRACE_EVENT0("media", "WebMediaPlayerImpl:paint");
[email protected]4e6be3f2009-05-07 02:24:441245
watkd16bb3e2017-04-25 01:18:311246 // We can't copy from protected frames.
Xiaohan Wang24cfe2c2018-01-22 23:16:001247 if (cdm_context_ref_)
xhwang80739452016-01-13 00:48:001248 return;
1249
mcasasf1236fc22015-05-29 22:38:561250 scoped_refptr<VideoFrame> video_frame = GetCurrentFrameFromCompositor();
[email protected]0fe5d43b2014-01-24 23:32:451251
[email protected]b49beeb2013-03-01 20:04:001252 gfx::Rect gfx_rect(rect);
dongseong.hwang0c4e9d82015-01-08 20:11:131253 Context3D context_3d;
Dan Sanders930cc1d2018-10-03 00:45:081254 gpu::ContextSupport* context_support = nullptr;
mcasas265bdbf82015-06-12 18:44:071255 if (video_frame.get() && video_frame->HasTextures()) {
CJ DiMeglioc60a5cf2017-09-27 20:08:411256 if (context_provider_) {
1257 context_3d = Context3D(context_provider_->ContextGL(),
1258 context_provider_->GrContext());
Dan Sanders930cc1d2018-10-03 00:45:081259 context_support = context_provider_->ContextSupport();
CJ DiMeglioc60a5cf2017-09-27 20:08:411260 }
dongseong.hwang0c4e9d82015-01-08 20:11:131261 if (!context_3d.gl)
danakj53f7ec902016-05-21 01:30:101262 return; // Unable to get/create a shared main thread context.
1263 if (!context_3d.gr_context)
1264 return; // The context has been lost since and can't setup a GrContext.
dongseong.hwang0c4e9d82015-01-08 20:11:131265 }
Kai Ninomiyaef8c9e02017-09-27 04:07:401266 if (out_metadata && video_frame) {
Kai Ninomiya9e8ae29b2017-09-06 23:45:161267 // WebGL last-uploaded-frame-metadata API enabled. https://crbug.com/639174
1268 ComputeFrameUploadMetadata(video_frame.get(), already_uploaded_id,
1269 out_metadata);
1270 if (out_metadata->skipped) {
1271 // Skip uploading this frame.
1272 return;
1273 }
1274 }
zhuoyu.qian4689dde22017-10-16 04:11:481275 video_renderer_.Paint(
Julien Isorce6c83d8de2017-10-12 13:11:291276 video_frame, canvas, gfx::RectF(gfx_rect), flags,
Dan Sanders930cc1d2018-10-03 00:45:081277 pipeline_metadata_.video_decoder_config.video_rotation(), context_3d,
1278 context_support);
[email protected]ec9212f2008-12-18 21:40:361279}
[email protected]5df51652009-01-17 00:03:001280
Yutaka Hirano657a0552018-11-09 00:52:551281bool WebMediaPlayerImpl::WouldTaintOrigin() const {
Thomas Guilbert153f84572018-07-19 05:03:581282 if (demuxer_found_hls_) {
1283 // HLS manifests might pull segments from a different origin. We can't know
1284 // for sure, so we conservatively say no here.
Yutaka Hiranoa9cbaa72018-10-10 08:35:221285 return true;
1286 }
1287
Dale Curtis4841c712018-12-13 18:14:051288 if (!mb_data_source_)
Yutaka Hirano657a0552018-11-09 00:52:551289 return false;
1290
1291 // When the resource is redirected to another origin we think it as
1292 // tainted. This is actually not specified, and is under discussion.
1293 // See https://github.com/whatwg/fetch/issues/737.
Dale Curtis4841c712018-12-13 18:14:051294 if (!mb_data_source_->HasSingleOrigin() &&
1295 mb_data_source_->cors_mode() == UrlData::CORS_UNSPECIFIED) {
Yutaka Hirano657a0552018-11-09 00:52:551296 return true;
1297 }
1298
Dale Curtis4841c712018-12-13 18:14:051299 return mb_data_source_->IsCorsCrossOrigin();
[email protected]3fe27112012-06-07 04:00:011300}
1301
Blink Reformat1c4d759e2017-04-09 16:34:541302double WebMediaPlayerImpl::MediaTimeForTimeValue(double timeValue) const {
qinminb4c39782015-08-10 18:43:241303 return base::TimeDelta::FromSecondsD(timeValue).InSecondsF();
[email protected]e06e16d82011-05-26 22:13:331304}
1305
Blink Reformat1c4d759e2017-04-09 16:34:541306unsigned WebMediaPlayerImpl::DecodedFrameCount() const {
acolwellb4034942014-08-28 15:42:431307 DCHECK(main_task_runner_->BelongsToCurrentThread());
Dale Curtisc7d2a7d22018-01-11 20:01:051308 return GetPipelineStatistics().video_frames_decoded;
[email protected]4c51bc662011-02-16 02:03:161309}
1310
Blink Reformat1c4d759e2017-04-09 16:34:541311unsigned WebMediaPlayerImpl::DroppedFrameCount() const {
acolwellb4034942014-08-28 15:42:431312 DCHECK(main_task_runner_->BelongsToCurrentThread());
Dale Curtisc7d2a7d22018-01-11 20:01:051313 return GetPipelineStatistics().video_frames_dropped;
[email protected]4c51bc662011-02-16 02:03:161314}
1315
Dave Tapuska6c7154912018-07-30 20:39:001316uint64_t WebMediaPlayerImpl::AudioDecodedByteCount() const {
acolwellb4034942014-08-28 15:42:431317 DCHECK(main_task_runner_->BelongsToCurrentThread());
Dale Curtisc7d2a7d22018-01-11 20:01:051318 return GetPipelineStatistics().audio_bytes_decoded;
[email protected]4c51bc662011-02-16 02:03:161319}
1320
Dave Tapuska6c7154912018-07-30 20:39:001321uint64_t WebMediaPlayerImpl::VideoDecodedByteCount() const {
acolwellb4034942014-08-28 15:42:431322 DCHECK(main_task_runner_->BelongsToCurrentThread());
Dale Curtisc7d2a7d22018-01-11 20:01:051323 return GetPipelineStatistics().video_bytes_decoded;
[email protected]4c51bc662011-02-16 02:03:161324}
1325
Blink Reformat1c4d759e2017-04-09 16:34:541326bool WebMediaPlayerImpl::CopyVideoTextureToPlatformTexture(
danakj46070b02016-03-28 21:54:111327 gpu::gles2::GLES2Interface* gl,
jiajia.qinc2943162017-05-12 01:34:391328 unsigned int target,
zmo57d577a2015-10-30 18:28:591329 unsigned int texture,
kbr0986e622017-04-13 02:34:581330 unsigned internal_format,
1331 unsigned format,
1332 unsigned type,
jiajia.qinc2943162017-05-12 01:34:391333 int level,
zmo57d577a2015-10-30 18:28:591334 bool premultiply_alpha,
Kai Ninomiya9e8ae29b2017-09-06 23:45:161335 bool flip_y,
1336 int already_uploaded_id,
1337 VideoFrameUploadMetadata* out_metadata) {
xhwang213e50c2016-10-10 23:56:311338 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]bfc05f22013-10-19 17:55:161339 TRACE_EVENT0("media", "WebMediaPlayerImpl:copyVideoTextureToPlatformTexture");
1340
watkd16bb3e2017-04-25 01:18:311341 // We can't copy from protected frames.
Xiaohan Wang24cfe2c2018-01-22 23:16:001342 if (cdm_context_ref_)
xhwang213e50c2016-10-10 23:56:311343 return false;
[email protected]dd061e12014-05-06 19:21:221344
xhwang213e50c2016-10-10 23:56:311345 scoped_refptr<VideoFrame> video_frame = GetCurrentFrameFromCompositor();
jbauman581d041c2016-07-21 01:01:031346 if (!video_frame.get() || !video_frame->HasTextures()) {
[email protected]e56f88c72013-06-25 22:31:291347 return false;
dongseong.hwang0c4e9d82015-01-08 20:11:131348 }
Kai Ninomiya9e8ae29b2017-09-06 23:45:161349 if (out_metadata) {
1350 // WebGL last-uploaded-frame-metadata API is enabled.
1351 // https://crbug.com/639174
1352 ComputeFrameUploadMetadata(video_frame.get(), already_uploaded_id,
1353 out_metadata);
1354 if (out_metadata->skipped) {
1355 // Skip uploading this frame.
1356 return true;
1357 }
1358 }
[email protected]df41e252014-02-03 23:39:501359
jbauman581d041c2016-07-21 01:01:031360 Context3D context_3d;
Dan Sanders930cc1d2018-10-03 00:45:081361 gpu::ContextSupport* context_support = nullptr;
CJ DiMeglioc60a5cf2017-09-27 20:08:411362 if (context_provider_) {
1363 context_3d = Context3D(context_provider_->ContextGL(),
1364 context_provider_->GrContext());
Dan Sanders930cc1d2018-10-03 00:45:081365 context_support = context_provider_->ContextSupport();
CJ DiMeglioc60a5cf2017-09-27 20:08:411366 }
zhuoyu.qian4689dde22017-10-16 04:11:481367 return video_renderer_.CopyVideoFrameTexturesToGLTexture(
Dan Sanders930cc1d2018-10-03 00:45:081368 context_3d, context_support, gl, video_frame.get(), target, texture,
1369 internal_format, format, type, level, premultiply_alpha, flip_y);
[email protected]6523b242013-03-13 11:10:071370}
1371
Matt Wolenetz95af6362018-01-04 20:23:421372// static
Kai Ninomiya9e8ae29b2017-09-06 23:45:161373void WebMediaPlayerImpl::ComputeFrameUploadMetadata(
1374 VideoFrame* frame,
1375 int already_uploaded_id,
1376 VideoFrameUploadMetadata* out_metadata) {
1377 DCHECK(out_metadata);
Kai Ninomiyaef8c9e02017-09-27 04:07:401378 DCHECK(frame);
Kai Ninomiya9e8ae29b2017-09-06 23:45:161379 out_metadata->frame_id = frame->unique_id();
1380 out_metadata->visible_rect = frame->visible_rect();
1381 out_metadata->timestamp = frame->timestamp();
1382 bool skip_possible = already_uploaded_id != -1;
1383 bool same_frame_id = frame->unique_id() == already_uploaded_id;
1384 out_metadata->skipped = skip_possible && same_frame_id;
1385}
1386
Blink Reformat1c4d759e2017-04-09 16:34:541387void WebMediaPlayerImpl::SetContentDecryptionModule(
[email protected]9ebc3b03f2014-08-13 04:01:231388 blink::WebContentDecryptionModule* cdm,
1389 blink::WebContentDecryptionModuleResult result) {
xhwang51139732017-02-24 19:36:081390 DVLOG(1) << __func__ << ": cdm = " << cdm;
acolwellb4034942014-08-28 15:42:431391 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]9ebc3b03f2014-08-13 04:01:231392
jrummell06f27072015-06-08 18:12:381393 // Once the CDM is set it can't be cleared as there may be frames being
1394 // decrypted on other threads. So fail this request.
1395 // http://crbug.com/462365#c7.
xhwang97de4202014-11-25 08:44:011396 if (!cdm) {
Blink Reformat1c4d759e2017-04-09 16:34:541397 result.CompleteWithError(
1398 blink::kWebContentDecryptionModuleExceptionInvalidStateError, 0,
xhwang79b193042016-12-13 18:52:431399 "The existing ContentDecryptionModule object cannot be removed at this "
1400 "time.");
xhwang97de4202014-11-25 08:44:011401 return;
1402 }
1403
jrummell89e61d82015-07-23 20:03:341404 // Create a local copy of |result| to avoid problems with the callback
1405 // getting passed to the media thread and causing |result| to be destructed
jrummell4acbec912016-02-27 02:45:031406 // on the wrong thread in some failure conditions. Blink should prevent
1407 // multiple simultaneous calls.
1408 DCHECK(!set_cdm_result_);
jrummell89e61d82015-07-23 20:03:341409 set_cdm_result_.reset(new blink::WebContentDecryptionModuleResult(result));
1410
dalecurtis04bdb582016-08-17 22:15:231411 // Recreate the watch time reporter if necessary.
1412 const bool was_encrypted = is_encrypted_;
1413 is_encrypted_ = true;
Dale Curtis3899090ea2018-01-12 00:10:351414 if (!was_encrypted) {
1415 media_metrics_provider_->SetIsEME();
1416 if (watch_time_reporter_)
1417 CreateWatchTimeReporter();
1418 }
dalecurtis04bdb582016-08-17 22:15:231419
Chris Cunninghamd9df58e2017-08-29 00:04:231420 // For now MediaCapabilities only handles clear content.
1421 video_decode_stats_reporter_.reset();
1422
jrummelle616ee92016-10-08 02:15:441423 SetCdm(cdm);
xhwang97de4202014-11-25 08:44:011424}
1425
xhwange8c4181a2014-12-06 08:10:011426void WebMediaPlayerImpl::OnEncryptedMediaInitData(
jrummellcf78967c2015-04-03 05:03:581427 EmeInitDataType init_data_type,
Avi Drissman97785ea2015-12-19 01:11:311428 const std::vector<uint8_t>& init_data) {
jrummellcf78967c2015-04-03 05:03:581429 DCHECK(init_data_type != EmeInitDataType::UNKNOWN);
xhwangbab66f52014-12-02 23:49:501430
Xiaohan Wangf63505d2017-10-21 08:00:531431 RecordEncryptedEvent(true);
xhwangbab66f52014-12-02 23:49:501432
dalecurtis04bdb582016-08-17 22:15:231433 // Recreate the watch time reporter if necessary.
1434 const bool was_encrypted = is_encrypted_;
1435 is_encrypted_ = true;
Dale Curtis3899090ea2018-01-12 00:10:351436 if (!was_encrypted) {
1437 media_metrics_provider_->SetIsEME();
1438 if (watch_time_reporter_)
1439 CreateWatchTimeReporter();
1440 }
dalecurtis04bdb582016-08-17 22:15:231441
Chris Cunninghamd9df58e2017-08-29 00:04:231442 // For now MediaCapabilities only handles clear content.
1443 video_decode_stats_reporter_.reset();
1444
Blink Reformat1c4d759e2017-04-09 16:34:541445 encrypted_client_->Encrypted(
davidbenb50f00c2015-12-01 00:01:501446 ConvertToWebInitDataType(init_data_type), init_data.data(),
srirama.m26f864d02015-07-14 05:21:461447 base::saturated_cast<unsigned int>(init_data.size()));
xhwangbab66f52014-12-02 23:49:501448}
1449
servolk81e01e02016-03-05 03:29:151450void WebMediaPlayerImpl::OnFFmpegMediaTracksUpdated(
dcheng3076abbf2016-04-22 20:42:391451 std::unique_ptr<MediaTracks> tracks) {
servolk81e01e02016-03-05 03:29:151452 // For MSE/chunk_demuxer case the media track updates are handled by
1453 // WebSourceBufferImpl.
1454 DCHECK(demuxer_.get());
1455 DCHECK(!chunk_demuxer_);
servolkef1e5ef2016-03-25 04:55:261456
servolk16e8bdf82017-04-11 17:00:391457 // Report the media track information to blink. Only the first audio track and
1458 // the first video track are enabled by default to match blink logic.
1459 bool is_first_audio_track = true;
1460 bool is_first_video_track = true;
servolkef1e5ef2016-03-25 04:55:261461 for (const auto& track : tracks->tracks()) {
1462 if (track->type() == MediaTrack::Audio) {
Blink Reformat1c4d759e2017-04-09 16:34:541463 client_->AddAudioTrack(blink::WebString::FromUTF8(track->id()),
1464 blink::WebMediaPlayerClient::kAudioTrackKindMain,
1465 blink::WebString::FromUTF8(track->label()),
1466 blink::WebString::FromUTF8(track->language()),
servolk16e8bdf82017-04-11 17:00:391467 is_first_audio_track);
1468 is_first_audio_track = false;
servolkef1e5ef2016-03-25 04:55:261469 } else if (track->type() == MediaTrack::Video) {
Blink Reformat1c4d759e2017-04-09 16:34:541470 client_->AddVideoTrack(blink::WebString::FromUTF8(track->id()),
1471 blink::WebMediaPlayerClient::kVideoTrackKindMain,
1472 blink::WebString::FromUTF8(track->label()),
1473 blink::WebString::FromUTF8(track->language()),
servolk16e8bdf82017-04-11 17:00:391474 is_first_video_track);
1475 is_first_video_track = false;
servolkef1e5ef2016-03-25 04:55:261476 } else {
1477 // Text tracks are not supported through this code path yet.
1478 NOTREACHED();
1479 }
1480 }
servolk81e01e02016-03-05 03:29:151481}
1482
jrummelle616ee92016-10-08 02:15:441483void WebMediaPlayerImpl::SetCdm(blink::WebContentDecryptionModule* cdm) {
1484 DCHECK(main_task_runner_->BelongsToCurrentThread());
1485 DCHECK(cdm);
Xiaohan Wang24cfe2c2018-01-22 23:16:001486
1487 auto cdm_context_ref =
1488 ToWebContentDecryptionModuleImpl(cdm)->GetCdmContextRef();
1489 if (!cdm_context_ref) {
jrummelle616ee92016-10-08 02:15:441490 NOTREACHED();
1491 OnCdmAttached(false);
xhwang80739452016-01-13 00:48:001492 return;
1493 }
1494
Xiaohan Wang24cfe2c2018-01-22 23:16:001495 CdmContext* cdm_context = cdm_context_ref->GetCdmContext();
1496 DCHECK(cdm_context);
jrummelle616ee92016-10-08 02:15:441497
1498 // Keep the reference to the CDM, as it shouldn't be destroyed until
1499 // after the pipeline is done with the |cdm_context|.
Xiaohan Wang24cfe2c2018-01-22 23:16:001500 pending_cdm_context_ref_ = std::move(cdm_context_ref);
tguilbert350936ff2017-02-24 05:39:271501 pipeline_controller_.SetCdm(
1502 cdm_context, base::Bind(&WebMediaPlayerImpl::OnCdmAttached, AsWeakPtr()));
xhwang97de4202014-11-25 08:44:011503}
1504
jrummell89e61d82015-07-23 20:03:341505void WebMediaPlayerImpl::OnCdmAttached(bool success) {
xhwang51139732017-02-24 19:36:081506 DVLOG(1) << __func__ << ": success = " << success;
jrummelle616ee92016-10-08 02:15:441507 DCHECK(main_task_runner_->BelongsToCurrentThread());
Xiaohan Wang24cfe2c2018-01-22 23:16:001508 DCHECK(pending_cdm_context_ref_);
jrummelle616ee92016-10-08 02:15:441509
1510 // If the CDM is set from the constructor there is no promise
1511 // (|set_cdm_result_|) to fulfill.
xhwang97de4202014-11-25 08:44:011512 if (success) {
xhwang29c5ad202017-04-14 07:02:191513 media_log_->SetBooleanProperty("has_cdm", true);
1514
jrummelle616ee92016-10-08 02:15:441515 // This will release the previously attached CDM (if any).
Xiaohan Wang24cfe2c2018-01-22 23:16:001516 cdm_context_ref_ = std::move(pending_cdm_context_ref_);
jrummelle616ee92016-10-08 02:15:441517 if (set_cdm_result_) {
Blink Reformat1c4d759e2017-04-09 16:34:541518 set_cdm_result_->Complete();
jrummelle616ee92016-10-08 02:15:441519 set_cdm_result_.reset();
1520 }
1521
xhwang97de4202014-11-25 08:44:011522 return;
1523 }
1524
Xiaohan Wang24cfe2c2018-01-22 23:16:001525 pending_cdm_context_ref_.reset();
jrummelle616ee92016-10-08 02:15:441526 if (set_cdm_result_) {
Blink Reformat1c4d759e2017-04-09 16:34:541527 set_cdm_result_->CompleteWithError(
1528 blink::kWebContentDecryptionModuleExceptionNotSupportedError, 0,
xhwang79b193042016-12-13 18:52:431529 "Unable to set ContentDecryptionModule object");
jrummelle616ee92016-10-08 02:15:441530 set_cdm_result_.reset();
1531 }
[email protected]9ebc3b03f2014-08-13 04:01:231532}
1533
sandersd1c0bba02016-03-04 23:14:081534void WebMediaPlayerImpl::OnPipelineSeeked(bool time_updated) {
John Chen5b164a02017-11-01 00:36:091535 TRACE_EVENT2("media", "WebMediaPlayerImpl::OnPipelineSeeked", "target",
1536 seek_time_.InSecondsF(), "id", media_log_->id());
[email protected]5d11eff2011-09-15 00:06:061537 seeking_ = false;
wolenetz1b2ae7d2015-06-10 00:44:211538 seek_time_ = base::TimeDelta();
avayvod2135a642017-01-13 00:17:141539
hubbe5a2dec022016-03-17 01:14:231540 if (paused_) {
1541#if defined(OS_ANDROID) // WMPI_CAST
Blink Reformat1c4d759e2017-04-09 16:34:541542 if (IsRemote()) {
Dale Curtis051fdf62017-08-05 00:21:131543 paused_time_ = cast_impl_.currentTime();
hubbe5a2dec022016-03-17 01:14:231544 } else {
tguilbert350936ff2017-02-24 05:39:271545 paused_time_ = pipeline_controller_.GetMediaTime();
hubbe5a2dec022016-03-17 01:14:231546 }
1547#else
tguilbert350936ff2017-02-24 05:39:271548 paused_time_ = pipeline_controller_.GetMediaTime();
hubbe5a2dec022016-03-17 01:14:231549#endif
dalecurtis04bdb582016-08-17 22:15:231550 } else {
1551 DCHECK(watch_time_reporter_);
1552 watch_time_reporter_->OnPlaying();
hubbe5a2dec022016-03-17 01:14:231553 }
sandersd1c0bba02016-03-04 23:14:081554 if (time_updated)
1555 should_notify_time_changed_ = true;
dalecurtisaf34d8712016-09-20 04:32:261556
dalecurtis4f6d14d2017-02-22 17:42:221557 // Reset underflow duration upon seek; this prevents looping videos and user
1558 // actions from artificially inflating the duration.
1559 underflow_timer_.reset();
avayvod56e1f3942017-01-21 02:06:311560
1561 // Background video optimizations are delayed when shown/hidden if pipeline
1562 // is seeking.
1563 UpdateBackgroundVideoOptimizationState();
Dale Curtis2dc6089a2018-03-26 16:47:581564
1565 // If we successfully completed a suspended startup, lie about our buffering
1566 // state for the time being. While ultimately we want to avoid lying about the
1567 // buffering state, for the initial test of true preload=metadata, signal
1568 // BUFFERING_HAVE_ENOUGH so that canplay and canplaythrough fire correctly.
1569 //
1570 // Later we can experiment with the impact of removing this lie; initial data
1571 // suggests high disruption since we've also made preload=metadata the
1572 // default. Most sites are not prepared for a lack of canplay; even many of
1573 // our own tests don't function correctly. See https://crbug.com/694855.
1574 //
1575 // Note: This call is dual purpose, it is also responsible for triggering an
1576 // UpdatePlayState() call which may need to resume the pipeline once Blink
1577 // has been told about the ReadyState change.
1578 if (attempting_suspended_start_ &&
1579 pipeline_controller_.IsPipelineSuspended()) {
Dale Curtis7c63f2e22018-09-19 21:06:271580 did_lazy_load_ = !has_poster_ && HasVideo();
1581 if (did_lazy_load_)
1582 DCHECK(base::FeatureList::IsEnabled(kPreloadMetadataLazyLoad));
1583
Dale Curtisff576552018-03-30 02:32:441584 skip_metrics_due_to_startup_suspend_ = true;
Dale Curtis2dc6089a2018-03-26 16:47:581585 OnBufferingStateChangeInternal(BUFFERING_HAVE_ENOUGH, true);
Dale Curtisff576552018-03-30 02:32:441586
1587 // If |skip_metrics_due_to_startup_suspend_| is unset by a resume started by
1588 // the OnBufferingStateChangeInternal() call, record a histogram of it here.
1589 //
1590 // If the value is unset, that means we should not have suspended and we've
1591 // likely incurred some cost to TimeToFirstFrame and TimeToPlayReady which
1592 // will be reflected in those statistics.
1593 base::UmaHistogramBoolean(
1594 std::string("Media.PreloadMetadataSuspendWasIdeal.") +
1595 ((HasVideo() && HasAudio()) ? "AudioVideo"
1596 : (HasVideo() ? "Video" : "Audio")),
1597 skip_metrics_due_to_startup_suspend_);
Dale Curtis2dc6089a2018-03-26 16:47:581598 }
1599
1600 attempting_suspended_start_ = false;
[email protected]8931c41a2009-07-07 17:31:491601}
1602
sandersd1c0bba02016-03-04 23:14:081603void WebMediaPlayerImpl::OnPipelineSuspended() {
Dale Curtis83321152018-12-01 01:22:061604 // Add a log event so the player shows up as "SUSPENDED" in media-internals.
1605 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::SUSPENDED));
1606
hubbed5f36882016-01-15 22:40:371607#if defined(OS_ANDROID)
avayvod82729272017-05-29 21:58:391608 if (IsRemote() && !IsNewRemotePlaybackPipelineEnabled()) {
hubbed5f36882016-01-15 22:40:371609 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner();
sandersd50a635e2016-04-04 22:50:091610 if (frame)
dalecurtise9c89e92016-05-20 19:38:001611 compositor_->PaintSingleFrame(frame);
hubbed5f36882016-01-15 22:40:371612 }
1613#endif
1614
sandersd2f5bb6152017-03-29 22:57:531615 // Tell the data source we have enough data so that it may release the
1616 // connection.
Dale Curtis4841c712018-12-13 18:14:051617 if (mb_data_source_)
1618 mb_data_source_->OnBufferingHaveEnough(true);
dalecurtis37fe5862016-03-15 19:29:091619
sandersd50a635e2016-04-04 22:50:091620 ReportMemoryUsage();
1621
sandersd1c0bba02016-03-04 23:14:081622 if (pending_suspend_resume_cycle_) {
watkdee516f2016-02-18 02:22:191623 pending_suspend_resume_cycle_ = false;
sandersd50a635e2016-04-04 22:50:091624 UpdatePlayState();
dalecurtis0431cbf2016-03-12 01:19:431625 }
sandersd1c0bba02016-03-04 23:14:081626}
1627
avayvod2135a642017-01-13 00:17:141628void WebMediaPlayerImpl::OnBeforePipelineResume() {
Dale Curtisff576552018-03-30 02:32:441629 // We went through suspended startup, so the player is only just now spooling
1630 // up for playback. As such adjust |load_start_time_| so it reports the same
1631 // metric as what would be reported if we had not suspended at startup.
1632 if (skip_metrics_due_to_startup_suspend_) {
1633 // In the event that the call to SetReadyState() initiated after pipeline
1634 // startup immediately tries to start playback, we should not update
1635 // |load_start_time_| to avoid losing visibility into the impact of a
1636 // suspended startup on the time until first frame / play ready for cases
1637 // where suspended startup was applied incorrectly.
1638 if (!attempting_suspended_start_)
1639 load_start_time_ = base::TimeTicks::Now() - time_to_metadata_;
1640 skip_metrics_due_to_startup_suspend_ = false;
1641 }
1642
avayvod2135a642017-01-13 00:17:141643 // Enable video track if we disabled it in the background - this way the new
1644 // renderer will attach its callbacks to the video stream properly.
1645 // TODO(avayvod): Remove this when disabling and enabling video tracks in
1646 // non-playing state works correctly. See https://crbug.com/678374.
1647 EnableVideoTrackIfNeeded();
1648 is_pipeline_resuming_ = true;
1649}
1650
1651void WebMediaPlayerImpl::OnPipelineResumed() {
1652 is_pipeline_resuming_ = false;
1653
avayvod56e1f3942017-01-21 02:06:311654 UpdateBackgroundVideoOptimizationState();
avayvod2135a642017-01-13 00:17:141655}
1656
alokp967c902452016-05-06 05:21:371657void WebMediaPlayerImpl::OnDemuxerOpened() {
1658 DCHECK(main_task_runner_->BelongsToCurrentThread());
dalecurtis9cddc0b2017-04-19 21:23:381659 client_->MediaSourceOpened(new WebMediaSourceImpl(chunk_demuxer_));
alokp967c902452016-05-06 05:21:371660}
1661
servolkf94b4602017-01-31 16:44:271662void WebMediaPlayerImpl::OnMemoryPressure(
1663 base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
1664 DVLOG(2) << __func__ << " memory_pressure_level=" << memory_pressure_level;
1665 DCHECK(main_task_runner_->BelongsToCurrentThread());
1666 DCHECK(base::FeatureList::IsEnabled(kMemoryPressureBasedSourceBufferGC));
1667 DCHECK(chunk_demuxer_);
1668
1669 // The new value of |memory_pressure_level| will take effect on the next
1670 // garbage collection. Typically this means the next SourceBuffer append()
1671 // operation, since per MSE spec, the garbage collection must only occur
1672 // during SourceBuffer append(). But if memory pressure is critical it might
1673 // be better to perform GC immediately rather than wait for the next append
1674 // and potentially get killed due to out-of-memory.
1675 // So if this experiment is enabled and pressure level is critical, we'll pass
1676 // down force_instant_gc==true, which will force immediate GC on
1677 // SourceBufferStreams.
1678 bool force_instant_gc =
1679 (enable_instant_source_buffer_gc_ &&
1680 memory_pressure_level ==
1681 base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
1682
Matt Wolenetz95af6362018-01-04 20:23:421683 // base::Unretained is safe, since |chunk_demuxer_| is actually owned by
1684 // |this| via this->demuxer_. Note the destruction of |chunk_demuxer_| is done
1685 // from ~WMPI by first hopping to |media_task_runner_| to prevent race with
1686 // this task.
servolkf94b4602017-01-31 16:44:271687 media_task_runner_->PostTask(
Dale Curtisee9be30012018-09-21 22:21:511688 FROM_HERE, base::BindOnce(&ChunkDemuxer::OnMemoryPressure,
1689 base::Unretained(chunk_demuxer_),
1690 base::TimeDelta::FromSecondsD(CurrentTime()),
1691 memory_pressure_level, force_instant_gc));
servolkf94b4602017-01-31 16:44:271692}
1693
alokp967c902452016-05-06 05:21:371694void WebMediaPlayerImpl::OnError(PipelineStatus status) {
pkastingf5279482016-07-27 02:18:201695 DVLOG(1) << __func__;
alokp967c902452016-05-06 05:21:371696 DCHECK(main_task_runner_->BelongsToCurrentThread());
1697 DCHECK_NE(status, PIPELINE_OK);
1698
1699 if (suppress_destruction_errors_)
1700 return;
1701
Thomas Guilbert6b6be3d2017-08-18 03:17:271702#if defined(OS_ANDROID)
Dale Curtisf273f8f2018-12-13 23:40:331703 // |mb_data_source_| may be nullptr if someone passes in a m3u8 as a data://
1704 // URL, since MediaPlayer doesn't support data:// URLs, fail playback now.
1705 const bool found_hls = status == PipelineStatus::DEMUXER_ERROR_DETECTED_HLS;
1706 if (found_hls && mb_data_source_) {
1707 demuxer_found_hls_ = found_hls;
Thomas Guilbert153f84572018-07-19 05:03:581708
Thomas Guilbert6b6be3d2017-08-18 03:17:271709 renderer_factory_selector_->SetUseMediaPlayer(true);
1710
Dale Curtisf273f8f2018-12-13 23:40:331711 loaded_url_ = mb_data_source_->GetUrlAfterRedirects();
1712 DCHECK(data_source_);
1713 data_source_->Stop();
1714 mb_data_source_ = nullptr;
1715
Thomas Guilbert6b6be3d2017-08-18 03:17:271716 pipeline_controller_.Stop();
Dale Curtis8a6281322017-08-31 00:35:531717 SetMemoryReportingState(false);
Thomas Guilbert6b6be3d2017-08-18 03:17:271718
Dale Curtisf273f8f2018-12-13 23:40:331719 // Trampoline through the media task runner to destruct the demuxer and
1720 // data source now that we're switching to HLS playback.
1721 media_task_runner_->PostTask(
Dale Curtisee9be30012018-09-21 22:21:511722 FROM_HERE,
Dale Curtisf273f8f2018-12-13 23:40:331723 BindToCurrentLoop(base::BindOnce(
1724 [](std::unique_ptr<Demuxer> demuxer,
1725 std::unique_ptr<DataSource> data_source,
1726 base::OnceClosure start_pipeline_cb) {
1727 // Release resources before starting HLS.
1728 demuxer.reset();
1729 data_source.reset();
1730
1731 std::move(start_pipeline_cb).Run();
1732 },
1733 std::move(demuxer_), std::move(data_source_),
1734 base::BindOnce(&WebMediaPlayerImpl::StartPipeline, AsWeakPtr()))));
1735
Thomas Guilbert6b6be3d2017-08-18 03:17:271736 return;
1737 }
Dale Curtisf273f8f2018-12-13 23:40:331738
1739 // We found hls in a data:// URL, fail immediately.
1740 if (found_hls)
1741 status = PIPELINE_ERROR_EXTERNAL_RENDERER_FAILED;
Thomas Guilbert6b6be3d2017-08-18 03:17:271742#endif
1743
Dale Curtis5bba03232018-08-30 17:57:381744 MaybeSetContainerName();
dalecurtis9cddc0b2017-04-19 21:23:381745 ReportPipelineError(load_type_, status, media_log_.get());
alokp967c902452016-05-06 05:21:371746 media_log_->AddEvent(media_log_->CreatePipelineErrorEvent(status));
Dale Curtis74612b72017-12-14 20:56:191747 media_metrics_provider_->OnError(status);
Dale Curtisccfd0cca2017-08-31 01:27:561748 if (watch_time_reporter_)
1749 watch_time_reporter_->OnError(status);
alokp967c902452016-05-06 05:21:371750
Blink Reformat1c4d759e2017-04-09 16:34:541751 if (ready_state_ == WebMediaPlayer::kReadyStateHaveNothing) {
alokp967c902452016-05-06 05:21:371752 // Any error that occurs before reaching ReadyStateHaveMetadata should
1753 // be considered a format error.
Blink Reformat1c4d759e2017-04-09 16:34:541754 SetNetworkState(WebMediaPlayer::kNetworkStateFormatError);
alokp967c902452016-05-06 05:21:371755 } else {
1756 SetNetworkState(PipelineErrorToNetworkState(status));
1757 }
1758
Thomas Guilbert2e591392017-08-12 00:56:381759 // PipelineController::Stop() is idempotent.
1760 pipeline_controller_.Stop();
1761
alokp967c902452016-05-06 05:21:371762 UpdatePlayState();
1763}
1764
1765void WebMediaPlayerImpl::OnEnded() {
John Chen5b164a02017-11-01 00:36:091766 TRACE_EVENT2("media", "WebMediaPlayerImpl::OnEnded", "duration", Duration(),
1767 "id", media_log_->id());
pkastingf5279482016-07-27 02:18:201768 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:431769 DCHECK(main_task_runner_->BelongsToCurrentThread());
scherkusd2c745b2014-09-04 05:03:401770
sandersd1c0bba02016-03-04 23:14:081771 // Ignore state changes until we've completed all outstanding operations.
1772 if (!pipeline_controller_.IsStable())
scherkusd2c745b2014-09-04 05:03:401773 return;
1774
1775 ended_ = true;
Blink Reformat1c4d759e2017-04-09 16:34:541776 client_->TimeChanged();
sandersd50a635e2016-04-04 22:50:091777
dalecurtis1af3c1a2017-04-11 00:53:491778 // Clear any new frame processed callbacks on end; otherwise we'll end up
1779 // logging a time long after playback ends.
1780 frame_time_report_cb_.Cancel();
1781
sandersd50a635e2016-04-04 22:50:091782 // We don't actually want this to run until |client_| calls seek() or pause(),
1783 // but that should have already happened in timeChanged() and so this is
1784 // expected to be a no-op.
1785 UpdatePlayState();
[email protected]576537842009-08-12 23:52:051786}
1787
alokp967c902452016-05-06 05:21:371788void WebMediaPlayerImpl::OnMetadata(PipelineMetadata metadata) {
pkastingf5279482016-07-27 02:18:201789 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:431790 DCHECK(main_task_runner_->BelongsToCurrentThread());
Dale Curtisff576552018-03-30 02:32:441791
1792 // Cache the |time_to_metadata_| to use for adjusting the TimeToFirstFrame and
1793 // TimeToPlayReady metrics later if we end up doing a suspended startup.
1794 time_to_metadata_ = base::TimeTicks::Now() - load_start_time_;
1795 media_metrics_provider_->SetTimeToMetadata(time_to_metadata_);
1796 RecordTimingUMA("Media.TimeToMetadata", time_to_metadata_);
[email protected]a8e2cb82012-08-17 00:02:391797
Dale Curtis5bba03232018-08-30 17:57:381798 MaybeSetContainerName();
1799
[email protected]b8877772014-03-26 20:17:151800 pipeline_metadata_ = metadata;
[email protected]739847c02014-01-16 00:12:251801
Blink Reformat1c4d759e2017-04-09 16:34:541802 SetReadyState(WebMediaPlayer::kReadyStateHaveMetadata);
Julien Isorce6c83d8de2017-10-12 13:11:291803 UMA_HISTOGRAM_ENUMERATION("Media.VideoRotation",
1804 metadata.video_decoder_config.video_rotation(),
acolwell9e0840d2014-09-06 19:01:321805 VIDEO_ROTATION_MAX + 1);
[email protected]21c3f7502013-03-23 03:29:511806
John Rummelldb5a7ef2018-05-16 00:28:011807 if (HasAudio()) {
1808 RecordEncryptionScheme("Audio",
1809 metadata.audio_decoder_config.encryption_scheme());
1810 }
1811
Blink Reformat1c4d759e2017-04-09 16:34:541812 if (HasVideo()) {
John Rummelldb5a7ef2018-05-16 00:28:011813 RecordEncryptionScheme("Video",
1814 metadata.video_decoder_config.encryption_scheme());
1815
liberato2fd111be2017-01-04 00:25:061816 if (overlay_enabled_) {
1817 // SurfaceView doesn't support rotated video, so transition back if
[email protected]c8d574722017-08-30 20:53:431818 // the video is now rotated. If |always_enable_overlays_|, we keep the
liberato2fd111be2017-01-04 00:25:061819 // overlay anyway so that the state machine keeps working.
[email protected]c8d574722017-08-30 20:53:431820 // TODO(liberato): verify if compositor feedback catches this. If so,
1821 // then we don't need this check.
1822 if (!always_enable_overlays_ && !DoesOverlaySupportMetadata())
liberato2fd111be2017-01-04 00:25:061823 DisableOverlay();
liberato2fd111be2017-01-04 00:25:061824 }
watkf835a792016-06-24 23:24:401825
[email protected]702d721d2018-10-25 21:55:271826 if (surface_layer_mode_ ==
1827 blink::WebMediaPlayer::SurfaceLayerMode::kAlways ||
1828 (surface_layer_mode_ ==
1829 blink::WebMediaPlayer::SurfaceLayerMode::kOnDemand &&
1830 client_->DisplayType() ==
1831 WebMediaPlayer::DisplayType::kPictureInPicture)) {
1832 ActivateSurfaceLayerForVideo();
1833 } else {
danakj6e669e782018-05-16 16:57:171834 DCHECK(!video_layer_);
danakj25f030112018-05-11 18:26:541835 video_layer_ = cc::VideoLayer::Create(
Julien Isorce6c83d8de2017-10-12 13:11:291836 compositor_.get(),
danakj25f030112018-05-11 18:26:541837 pipeline_metadata_.video_decoder_config.video_rotation());
danakj8bc61c72018-05-16 13:55:061838 video_layer_->SetContentsOpaque(opaque_);
danakj8d204a42018-05-18 18:05:351839 client_->SetCcLayer(video_layer_.get());
lethalantidote7f6009d2017-07-07 21:47:391840 }
[email protected]a8e2cb82012-08-17 00:02:391841 }
dalecurtis8e4dc682016-03-15 02:30:301842
xjzd3fe45a2016-10-12 18:26:371843 if (observer_)
xjz15b483f2017-01-12 00:21:361844 observer_->OnMetadataChanged(pipeline_metadata_);
xjzd3fe45a2016-10-12 18:26:371845
Dale Curtisc7d2a7d22018-01-11 20:01:051846 // TODO(dalecurtis): Don't create these until kReadyStateHaveFutureData; when
1847 // we create them early we just increase the chances of needing to throw them
1848 // away unnecessarily.
dalecurtis04bdb582016-08-17 22:15:231849 CreateWatchTimeReporter();
Chris Cunninghamd9df58e2017-08-29 00:04:231850 CreateVideoDecodeStatsReporter();
Dale Curtisc7d2a7d22018-01-11 20:01:051851
sandersd50a635e2016-04-04 22:50:091852 UpdatePlayState();
[email protected]a8e2cb82012-08-17 00:02:391853}
1854
[email protected]69db58f2018-09-26 20:27:561855void WebMediaPlayerImpl::ActivateSurfaceLayerForVideo() {
1856 // Note that we might or might not already be in VideoLayer mode.
1857 DCHECK(!bridge_);
1858
1859 surface_layer_for_video_enabled_ = true;
1860
1861 // If we're in VideoLayer mode, then get rid of the layer.
1862 if (video_layer_) {
1863 client_->SetCcLayer(nullptr);
1864 video_layer_ = nullptr;
1865 }
1866
1867 bridge_ = std::move(create_bridge_callback_)
1868 .Run(this, compositor_->GetUpdateSubmissionStateCallback());
1869 bridge_->CreateSurfaceLayer();
1870
1871 vfc_task_runner_->PostTask(
1872 FROM_HERE,
1873 base::BindOnce(
1874 &VideoFrameCompositor::EnableSubmission,
1875 base::Unretained(compositor_.get()), bridge_->GetSurfaceId(),
jonross180dc482018-10-23 21:22:091876 bridge_->GetLocalSurfaceIdAllocationTime(),
[email protected]69db58f2018-09-26 20:27:561877 pipeline_metadata_.video_decoder_config.video_rotation(),
1878 IsInPictureInPicture(), opaque_,
1879 BindToCurrentLoop(base::BindRepeating(
1880 &WebMediaPlayerImpl::OnFrameSinkDestroyed, AsWeakPtr()))));
1881 bridge_->SetContentsOpaque(opaque_);
1882
1883 // If the element is already in Picture-in-Picture mode, it means that it
1884 // was set in this mode prior to this load, with a different
1885 // WebMediaPlayerImpl. The new player needs to send its id, size and
1886 // surface id to the browser process to make sure the states are properly
1887 // updated.
1888 // TODO(872056): the surface should be activated but for some reasons, it
1889 // does not. It is possible that this will no longer be needed after 872056
1890 // is fixed.
Dale Curtisca1b78f2019-01-15 03:11:261891 if (IsInPictureInPicture())
[email protected]69db58f2018-09-26 20:27:561892 OnSurfaceIdUpdated(bridge_->GetSurfaceId());
[email protected]69db58f2018-09-26 20:27:561893}
1894
CJ DiMegliodf92bfe2018-05-11 20:11:001895void WebMediaPlayerImpl::OnFrameSinkDestroyed() {
1896 bridge_->ClearSurfaceId();
1897}
1898
Dale Curtis2dc6089a2018-03-26 16:47:581899void WebMediaPlayerImpl::OnBufferingStateChange(BufferingState state) {
1900 OnBufferingStateChangeInternal(state, false);
1901}
1902
Chris Cunninghamd9df58e2017-08-29 00:04:231903void WebMediaPlayerImpl::CreateVideoDecodeStatsReporter() {
1904 // TODO(chcunningham): destroy reporter if we initially have video but the
1905 // track gets disabled. Currently not possible in default desktop Chrome.
1906 if (!HasVideo())
1907 return;
1908
1909 // Stats reporter requires a valid config. We may not have one for HLS cases
1910 // where URL demuxer doesn't know details of the stream.
1911 if (!pipeline_metadata_.video_decoder_config.IsValidConfig())
1912 return;
1913
1914 // For now MediaCapabilities only handles clear content.
1915 // TODO(chcunningham): Report encrypted stats.
1916 if (is_encrypted_)
1917 return;
1918
Dale Curtis7e8a510d2017-12-14 19:19:481919 mojom::VideoDecodeStatsRecorderPtr recorder;
1920 media_metrics_provider_->AcquireVideoDecodeStatsRecorder(
Dale Curtis7e8a510d2017-12-14 19:19:481921 mojo::MakeRequest(&recorder));
Chris Cunninghamc7c6a6d2017-11-23 14:06:451922
Chris Cunninghamd9df58e2017-08-29 00:04:231923 // Create capabilities reporter and synchronize its initial state.
1924 video_decode_stats_reporter_.reset(new VideoDecodeStatsReporter(
Chris Cunninghamc7c6a6d2017-11-23 14:06:451925 std::move(recorder),
Chris Cunninghamd9df58e2017-08-29 00:04:231926 base::Bind(&WebMediaPlayerImpl::GetPipelineStatistics,
1927 base::Unretained(this)),
Hajime Hoshi6c3194b52017-12-15 03:02:111928 pipeline_metadata_.video_decoder_config,
Hajime Hoshib5a26ee2018-05-14 12:47:511929 frame_->GetTaskRunner(blink::TaskType::kInternalMedia)));
Chris Cunninghamd9df58e2017-08-29 00:04:231930
1931 if (delegate_->IsFrameHidden())
1932 video_decode_stats_reporter_->OnHidden();
1933 else
1934 video_decode_stats_reporter_->OnShown();
1935
1936 if (paused_)
1937 video_decode_stats_reporter_->OnPaused();
1938 else
1939 video_decode_stats_reporter_->OnPlaying();
1940}
1941
hubbeb2d3efd2017-05-05 23:26:381942void WebMediaPlayerImpl::OnProgress() {
Chris Watkins1ffabc5f2017-05-10 20:52:091943 DVLOG(4) << __func__;
hubbeb2d3efd2017-05-05 23:26:381944 if (highest_ready_state_ < ReadyState::kReadyStateHaveFutureData) {
1945 // Reset the preroll attempt clock.
1946 preroll_attempt_pending_ = true;
1947 preroll_attempt_start_time_ = base::TimeTicks();
1948
1949 // Clear any 'stale' flag and give the pipeline a chance to resume. If we
1950 // are already resumed, this will cause |preroll_attempt_start_time_| to
1951 // be set.
1952 delegate_->ClearStaleFlag(delegate_id_);
1953 UpdatePlayState();
1954 } else if (ready_state_ == ReadyState::kReadyStateHaveFutureData &&
1955 CanPlayThrough()) {
1956 SetReadyState(WebMediaPlayer::kReadyStateHaveEnoughData);
1957 }
1958}
1959
1960bool WebMediaPlayerImpl::CanPlayThrough() {
1961 if (!base::FeatureList::IsEnabled(kSpecCompliantCanPlayThrough))
1962 return true;
1963 if (chunk_demuxer_)
1964 return true;
Dale Curtis4841c712018-12-13 18:14:051965 if (data_source_ && data_source_->AssumeFullyBuffered())
hubbeb2d3efd2017-05-05 23:26:381966 return true;
1967 // If we're not currently downloading, we have as much buffer as
1968 // we're ever going to get, which means we say we can play through.
1969 if (network_state_ == WebMediaPlayer::kNetworkStateIdle)
1970 return true;
1971 return buffered_data_source_host_.CanPlayThrough(
1972 base::TimeDelta::FromSecondsD(CurrentTime()),
1973 base::TimeDelta::FromSecondsD(Duration()),
1974 playback_rate_ == 0.0 ? 1.0 : playback_rate_);
1975}
1976
Dale Curtisff576552018-03-30 02:32:441977void WebMediaPlayerImpl::OnBufferingStateChangeInternal(
1978 BufferingState state,
1979 bool for_suspended_start) {
pkastingf5279482016-07-27 02:18:201980 DVLOG(1) << __func__ << "(" << state << ")";
alokp967c902452016-05-06 05:21:371981 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]b8877772014-03-26 20:17:151982
Ted Meyer742212b82018-08-22 17:21:421983 // Ignore buffering state changes caused by back-to-back seeking, so as not
1984 // to assume the second seek has finished when it was only the first seek.
1985 if (pipeline_controller_.IsPendingSeek())
[email protected]ba7d5f92014-06-24 05:37:401986 return;
[email protected]b8877772014-03-26 20:17:151987
Dale Curtisff576552018-03-30 02:32:441988 auto log_event = media_log_->CreateBufferingStateChangedEvent(
1989 "pipeline_buffering_state", state);
1990 log_event->params.SetBoolean("for_suspended_start", for_suspended_start);
1991 media_log_->AddEvent(std::move(log_event));
dalecurtis869bf2f2017-01-10 18:01:101992
chcunninghameb270c92016-07-15 01:00:451993 if (state == BUFFERING_HAVE_ENOUGH) {
John Chen5b164a02017-11-01 00:36:091994 TRACE_EVENT1("media", "WebMediaPlayerImpl::BufferingHaveEnough", "id",
1995 media_log_->id());
Dale Curtisff576552018-03-30 02:32:441996 // The SetReadyState() call below may clear
1997 // |skip_metrics_due_to_startup_suspend_| so report this first.
1998 if (!have_reported_time_to_play_ready_ &&
1999 !skip_metrics_due_to_startup_suspend_) {
2000 DCHECK(!for_suspended_start);
Dale Curtis3899090ea2018-01-12 00:10:352001 have_reported_time_to_play_ready_ = true;
2002 const base::TimeDelta elapsed = base::TimeTicks::Now() - load_start_time_;
2003 media_metrics_provider_->SetTimeToPlayReady(elapsed);
2004 RecordTimingUMA("Media.TimeToPlayReady", elapsed);
2005 }
[email protected]ba7d5f92014-06-24 05:37:402006
Dale Curtisff576552018-03-30 02:32:442007 // Warning: This call may be re-entrant.
2008 SetReadyState(CanPlayThrough() ? WebMediaPlayer::kReadyStateHaveEnoughData
2009 : WebMediaPlayer::kReadyStateHaveFutureData);
2010
chcunninghameb270c92016-07-15 01:00:452011 // Let the DataSource know we have enough data. It may use this information
2012 // to release unused network connections.
Dale Curtis4841c712018-12-13 18:14:052013 if (mb_data_source_ && !client_->CouldPlayIfEnoughData())
2014 mb_data_source_->OnBufferingHaveEnough(false);
dalecurtis849cf4b22015-03-27 18:35:452015
chcunninghameb270c92016-07-15 01:00:452016 // Blink expects a timeChanged() in response to a seek().
sandersd35d2c3f2017-01-14 02:04:422017 if (should_notify_time_changed_) {
2018 should_notify_time_changed_ = false;
Blink Reformat1c4d759e2017-04-09 16:34:542019 client_->TimeChanged();
sandersd35d2c3f2017-01-14 02:04:422020 }
dalecurtis0f0097a2015-12-01 17:40:472021
chcunninghameb270c92016-07-15 01:00:452022 // Once we have enough, start reporting the total memory usage. We'll also
2023 // report once playback starts.
2024 ReportMemoryUsage();
dalecurtis9d638a12016-08-30 06:20:552025
dalecurtis4f6d14d2017-02-22 17:42:222026 // Report the amount of time it took to leave the underflow state.
2027 if (underflow_timer_) {
2028 RecordUnderflowDuration(underflow_timer_->Elapsed());
dalecurtis9d638a12016-08-30 06:20:552029 underflow_timer_.reset();
2030 }
chcunninghameb270c92016-07-15 01:00:452031 } else {
2032 // Buffering has underflowed.
2033 DCHECK_EQ(state, BUFFERING_HAVE_NOTHING);
dalecurtisacd77d62016-09-09 23:23:142034
dalecurtisd06eabc2017-02-24 23:43:292035 // Report the number of times we've entered the underflow state. Ensure we
2036 // only report the value when transitioning from HAVE_ENOUGH to
2037 // HAVE_NOTHING.
Dale Curtis6995b862017-05-31 22:20:082038 if (ready_state_ == WebMediaPlayer::kReadyStateHaveEnoughData &&
2039 !seeking_) {
dalecurtisacd77d62016-09-09 23:23:142040 underflow_timer_.reset(new base::ElapsedTimer());
Dale Curtis6995b862017-05-31 22:20:082041 watch_time_reporter_->OnUnderflow();
2042 }
dalecurtisacd77d62016-09-09 23:23:142043
chcunninghameb270c92016-07-15 01:00:452044 // It shouldn't be possible to underflow if we've not advanced past
2045 // HAVE_CURRENT_DATA.
Blink Reformat1c4d759e2017-04-09 16:34:542046 DCHECK_GT(highest_ready_state_, WebMediaPlayer::kReadyStateHaveCurrentData);
2047 SetReadyState(WebMediaPlayer::kReadyStateHaveCurrentData);
chcunninghameb270c92016-07-15 01:00:452048 }
sandersd50a635e2016-04-04 22:50:092049
2050 UpdatePlayState();
[email protected]b8877772014-03-26 20:17:152051}
2052
alokp967c902452016-05-06 05:21:372053void WebMediaPlayerImpl::OnDurationChange() {
acolwellb4034942014-08-28 15:42:432054 DCHECK(main_task_runner_->BelongsToCurrentThread());
alokp967c902452016-05-06 05:21:372055
John Delaney2371b452018-12-13 04:30:332056 if (frame_->IsAdSubframe()) {
2057 UMA_HISTOGRAM_CUSTOM_TIMES("Ads.Media.Duration", GetPipelineMediaDuration(),
2058 base::TimeDelta::FromMilliseconds(1),
2059 base::TimeDelta::FromDays(1),
2060 50 /* bucket_count */);
2061 }
2062
alokp967c902452016-05-06 05:21:372063 // TODO(sandersd): We should call delegate_->DidPlay() with the new duration,
2064 // especially if it changed from <5s to >5s.
Blink Reformat1c4d759e2017-04-09 16:34:542065 if (ready_state_ == WebMediaPlayer::kReadyStateHaveNothing)
alokp967c902452016-05-06 05:21:372066 return;
2067
Blink Reformat1c4d759e2017-04-09 16:34:542068 client_->DurationChanged();
Dale Curtisaebaeea2018-07-19 23:42:112069 if (watch_time_reporter_)
2070 watch_time_reporter_->OnDurationChanged(GetPipelineMediaDuration());
[email protected]81bb3322011-07-21 15:55:502071}
2072
alokp967c902452016-05-06 05:21:372073void WebMediaPlayerImpl::OnAddTextTrack(const TextTrackConfig& config,
2074 const AddTextTrackDoneCB& done_cb) {
acolwellb4034942014-08-28 15:42:432075 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]71537722013-05-23 06:47:532076
[email protected]8a561062013-11-22 01:19:312077 const WebInbandTextTrackImpl::Kind web_kind =
2078 static_cast<WebInbandTextTrackImpl::Kind>(config.kind());
Blink Reformat1c4d759e2017-04-09 16:34:542079 const blink::WebString web_label = blink::WebString::FromUTF8(config.label());
[email protected]8a561062013-11-22 01:19:312080 const blink::WebString web_language =
Blink Reformat1c4d759e2017-04-09 16:34:542081 blink::WebString::FromUTF8(config.language());
2082 const blink::WebString web_id = blink::WebString::FromUTF8(config.id());
[email protected]71537722013-05-23 06:47:532083
dcheng3076abbf2016-04-22 20:42:392084 std::unique_ptr<WebInbandTextTrackImpl> web_inband_text_track(
henriks9cce5fa2014-12-12 09:35:302085 new WebInbandTextTrackImpl(web_kind, web_label, web_language, web_id));
[email protected]8a561062013-11-22 01:19:312086
Dale Curtisca1b78f2019-01-15 03:11:262087 std::unique_ptr<TextTrack> text_track(new TextTrackImpl(
dcheng652f5ff2015-12-27 08:54:002088 main_task_runner_, client_, std::move(web_inband_text_track)));
[email protected]8a561062013-11-22 01:19:312089
dcheng652f5ff2015-12-27 08:54:002090 done_cb.Run(std::move(text_track));
[email protected]71537722013-05-23 06:47:532091}
2092
Xiaohan Wang640b41d2018-12-18 19:00:462093void WebMediaPlayerImpl::OnWaiting(WaitingReason reason) {
alokp967c902452016-05-06 05:21:372094 DCHECK(main_task_runner_->BelongsToCurrentThread());
2095
Xiaohan Wang640b41d2018-12-18 19:00:462096 switch (reason) {
2097 case WaitingReason::kNoDecryptionKey:
2098 encrypted_client_->DidBlockPlaybackWaitingForKey();
2099 // TODO(jrummell): didResumePlaybackBlockedForKey() should only be called
2100 // when a key has been successfully added (e.g. OnSessionKeysChange() with
2101 // |has_additional_usable_key| = true). http://crbug.com/461903
2102 encrypted_client_->DidResumePlaybackBlockedForKey();
2103 return;
Xiaohan Wang640b41d2018-12-18 19:00:462104
Xiaohan Wanga7224d62019-01-04 22:22:302105 // Ideally this should be handled by PipelineController directly without
2106 // being proxied here. But currently Pipeline::Client (|this|) is passed to
2107 // PipelineImpl directly without going through |pipeline_controller_|,
2108 // making it difficult to do.
2109 // TODO(xhwang): Handle this in PipelineController when we have a clearer
2110 // picture on how to refactor WebMediaPlayerImpl, PipelineController and
2111 // PipelineImpl.
2112 case WaitingReason::kDecoderStateLost:
2113 pipeline_controller_.OnDecoderStateLost();
2114 return;
2115 }
alokp967c902452016-05-06 05:21:372116}
2117
alokp5d86e9b2016-05-17 20:20:412118void WebMediaPlayerImpl::OnVideoNaturalSizeChange(const gfx::Size& size) {
2119 DCHECK(main_task_runner_->BelongsToCurrentThread());
Blink Reformat1c4d759e2017-04-09 16:34:542120 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
alokp5d86e9b2016-05-17 20:20:412121
Chris Cunningham038548b2017-07-10 22:36:302122 TRACE_EVENT0("media", "WebMediaPlayerImpl::OnVideoNaturalSizeChange");
xhwang60802652017-04-19 07:29:582123
xjz15b483f2017-01-12 00:21:362124 // The input |size| is from the decoded video frame, which is the original
2125 // natural size and need to be rotated accordingly.
Julien Isorce6c83d8de2017-10-12 13:11:292126 gfx::Size rotated_size = GetRotatedVideoSize(
2127 pipeline_metadata_.video_decoder_config.video_rotation(), size);
sandersd2c478422016-08-02 01:19:252128
xhwang60802652017-04-19 07:29:582129 RecordVideoNaturalSize(rotated_size);
2130
2131 gfx::Size old_size = pipeline_metadata_.natural_size;
2132 if (rotated_size == old_size)
alokp5d86e9b2016-05-17 20:20:412133 return;
2134
xjz516ef6d2017-01-07 00:23:062135 pipeline_metadata_.natural_size = rotated_size;
Dale Curtis96d6e9382018-07-18 18:01:072136 UpdateSecondaryProperties();
dalecurtis25405562017-04-14 23:35:112137
Chris Cunninghamd9df58e2017-08-29 00:04:232138 if (video_decode_stats_reporter_)
2139 video_decode_stats_reporter_->OnNaturalSizeChanged(rotated_size);
2140
Blink Reformat1c4d759e2017-04-09 16:34:542141 client_->SizeChanged();
xjz516ef6d2017-01-07 00:23:062142
xjz15b483f2017-01-12 00:21:362143 if (observer_)
2144 observer_->OnMetadataChanged(pipeline_metadata_);
peconn257951522017-06-09 18:24:592145
2146 delegate_->DidPlayerSizeChange(delegate_id_, NaturalSize());
alokp5d86e9b2016-05-17 20:20:412147}
2148
2149void WebMediaPlayerImpl::OnVideoOpacityChange(bool opaque) {
2150 DCHECK(main_task_runner_->BelongsToCurrentThread());
Blink Reformat1c4d759e2017-04-09 16:34:542151 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
alokp5d86e9b2016-05-17 20:20:412152
2153 opaque_ = opaque;
lethalantidote7f6009d2017-07-07 21:47:392154 if (!surface_layer_for_video_enabled_) {
danakj8bc61c72018-05-16 13:55:062155 if (video_layer_)
2156 video_layer_->SetContentsOpaque(opaque_);
danakj8d204a42018-05-18 18:05:352157 } else if (bridge_->GetCcLayer()) {
CJ DiMeglioa2b13fbc2018-06-27 00:50:592158 bridge_->SetContentsOpaque(opaque_);
CJ DiMeglio27211372018-07-27 23:17:442159 vfc_task_runner_->PostTask(
2160 FROM_HERE,
2161 base::BindOnce(&VideoFrameCompositor::UpdateIsOpaque,
2162 base::Unretained(compositor_.get()), opaque_));
lethalantidote7f6009d2017-07-07 21:47:392163 }
alokp5d86e9b2016-05-17 20:20:412164}
2165
Chris Cunningham038548b2017-07-10 22:36:302166void WebMediaPlayerImpl::OnAudioConfigChange(const AudioDecoderConfig& config) {
2167 DCHECK(main_task_runner_->BelongsToCurrentThread());
2168 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
2169
Dale Curtisccfd0cca2017-08-31 01:27:562170 const bool codec_change =
2171 pipeline_metadata_.audio_decoder_config.codec() != config.codec();
Chris Cunningham038548b2017-07-10 22:36:302172 pipeline_metadata_.audio_decoder_config = config;
2173
2174 if (observer_)
2175 observer_->OnMetadataChanged(pipeline_metadata_);
Dale Curtisccfd0cca2017-08-31 01:27:562176
2177 if (codec_change)
Dale Curtis96d6e9382018-07-18 18:01:072178 UpdateSecondaryProperties();
Chris Cunningham038548b2017-07-10 22:36:302179}
2180
2181void WebMediaPlayerImpl::OnVideoConfigChange(const VideoDecoderConfig& config) {
2182 DCHECK(main_task_runner_->BelongsToCurrentThread());
2183 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
2184
Dale Curtisccfd0cca2017-08-31 01:27:562185 const bool codec_change =
2186 pipeline_metadata_.video_decoder_config.codec() != config.codec();
2187
Chris Cunningham038548b2017-07-10 22:36:302188 // TODO(chcunningham): Observe changes to video codec profile to signal
2189 // beginning of a new Media Capabilities playback report.
2190 pipeline_metadata_.video_decoder_config = config;
2191
2192 if (observer_)
2193 observer_->OnMetadataChanged(pipeline_metadata_);
Chris Cunninghamd9df58e2017-08-29 00:04:232194
2195 if (video_decode_stats_reporter_)
2196 video_decode_stats_reporter_->OnVideoConfigChanged(config);
Dale Curtisccfd0cca2017-08-31 01:27:562197
2198 if (codec_change)
Dale Curtis96d6e9382018-07-18 18:01:072199 UpdateSecondaryProperties();
Chris Cunningham038548b2017-07-10 22:36:302200}
2201
avayvodeecec52c2017-02-14 01:25:092202void WebMediaPlayerImpl::OnVideoAverageKeyframeDistanceUpdate() {
2203 UpdateBackgroundVideoOptimizationState();
2204}
2205
Dale Curtisc7d2a7d22018-01-11 20:01:052206void WebMediaPlayerImpl::OnAudioDecoderChange(const std::string& name) {
2207 if (name == audio_decoder_name_)
2208 return;
2209
Dale Curtisc7d2a7d22018-01-11 20:01:052210 audio_decoder_name_ = name;
2211
2212 // If there's no current reporter, there's nothing to be done.
2213 if (!watch_time_reporter_)
2214 return;
2215
Dale Curtis96d6e9382018-07-18 18:01:072216 UpdateSecondaryProperties();
Dale Curtisc7d2a7d22018-01-11 20:01:052217}
2218
2219void WebMediaPlayerImpl::OnVideoDecoderChange(const std::string& name) {
2220 if (name == video_decoder_name_)
2221 return;
2222
Dale Curtisc7d2a7d22018-01-11 20:01:052223 video_decoder_name_ = name;
2224
2225 // If there's no current reporter, there's nothing to be done.
2226 if (!watch_time_reporter_)
2227 return;
2228
Dale Curtis96d6e9382018-07-18 18:01:072229 UpdateSecondaryProperties();
Dale Curtisc7d2a7d22018-01-11 20:01:052230}
2231
sandersd35d2c3f2017-01-14 02:04:422232void WebMediaPlayerImpl::OnFrameHidden() {
sandersd1e49fb62015-12-12 01:18:062233 DCHECK(main_task_runner_->BelongsToCurrentThread());
avayvod39c102402016-11-23 21:43:132234
avayvod65fad272017-02-24 01:00:482235 // Backgrounding a video requires a user gesture to resume playback.
2236 if (IsHidden())
2237 video_locked_when_paused_when_hidden_ = true;
2238
dalecurtis04bdb582016-08-17 22:15:232239 if (watch_time_reporter_)
2240 watch_time_reporter_->OnHidden();
avayvod48a8be52016-08-04 19:52:502241
Chris Cunninghamd9df58e2017-08-29 00:04:232242 if (video_decode_stats_reporter_)
2243 video_decode_stats_reporter_->OnHidden();
2244
avayvod65fad272017-02-24 01:00:482245 UpdateBackgroundVideoOptimizationState();
sandersd50a635e2016-04-04 22:50:092246 UpdatePlayState();
dalecurtis8b8505e72016-06-10 21:59:172247
2248 // Schedule suspended playing media to be paused if the user doesn't come back
2249 // to it within some timeout period to avoid any autoplay surprises.
2250 ScheduleIdlePauseTimer();
Dale Curtisca1b78f2019-01-15 03:11:262251
2252 // Notify the compositor of our page visibility status.
2253 vfc_task_runner_->PostTask(
2254 FROM_HERE,
2255 base::BindOnce(&VideoFrameCompositor::SetIsPageVisible,
2256 base::Unretained(compositor_.get()), !IsHidden()));
sandersd1e49fb62015-12-12 01:18:062257}
2258
sandersd35d2c3f2017-01-14 02:04:422259void WebMediaPlayerImpl::OnFrameClosed() {
sandersd1e49fb62015-12-12 01:18:062260 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]28347e72017-06-27 17:30:112261
sandersd35d2c3f2017-01-14 02:04:422262 UpdatePlayState();
2263}
2264
2265void WebMediaPlayerImpl::OnFrameShown() {
2266 DCHECK(main_task_runner_->BelongsToCurrentThread());
2267 background_pause_timer_.Stop();
2268
avayvod65fad272017-02-24 01:00:482269 // Foreground videos don't require user gesture to continue playback.
2270 video_locked_when_paused_when_hidden_ = false;
2271
dalecurtis04bdb582016-08-17 22:15:232272 if (watch_time_reporter_)
2273 watch_time_reporter_->OnShown();
2274
Chris Cunninghamd9df58e2017-08-29 00:04:232275 if (video_decode_stats_reporter_)
2276 video_decode_stats_reporter_->OnShown();
2277
Dale Curtisca1b78f2019-01-15 03:11:262278 // Notify the compositor of our page visibility status.
2279 vfc_task_runner_->PostTask(
2280 FROM_HERE,
2281 base::BindOnce(&VideoFrameCompositor::SetIsPageVisible,
2282 base::Unretained(compositor_.get()), !IsHidden()));
2283
avayvodcc273dd2017-01-19 19:35:122284 // Only track the time to the first frame if playing or about to play because
2285 // of being shown and only for videos we would optimize background playback
2286 // for.
2287 if ((!paused_ && IsBackgroundOptimizationCandidate()) ||
2288 paused_when_hidden_) {
Dale Curtis3899090ea2018-01-12 00:10:352289 frame_time_report_cb_.Reset(base::BindOnce(
2290 &WebMediaPlayerImpl::ReportTimeFromForegroundToFirstFrame, AsWeakPtr(),
2291 base::TimeTicks::Now()));
CJ DiMeglio2302d202017-08-31 08:38:042292 vfc_task_runner_->PostTask(
avayvodcc273dd2017-01-19 19:35:122293 FROM_HERE,
Dale Curtis3899090ea2018-01-12 00:10:352294 base::BindOnce(&VideoFrameCompositor::SetOnNewProcessedFrameCallback,
2295 base::Unretained(compositor_.get()),
2296 BindToCurrentLoop(frame_time_report_cb_.callback())));
avayvodcc273dd2017-01-19 19:35:122297 }
avayvodac607d652017-01-06 03:16:432298
Dale Curtisdcbb81a2017-08-18 01:06:122299 UpdateBackgroundVideoOptimizationState();
avayvod65fad272017-02-24 01:00:482300
avayvod2135a642017-01-13 00:17:142301 if (paused_when_hidden_) {
2302 paused_when_hidden_ = false;
2303 OnPlay(); // Calls UpdatePlayState() so return afterwards.
2304 return;
2305 }
2306
sandersd50a635e2016-04-04 22:50:092307 UpdatePlayState();
sandersd1e49fb62015-12-12 01:18:062308}
2309
sandersd35d2c3f2017-01-14 02:04:422310void WebMediaPlayerImpl::OnIdleTimeout() {
dalecurtis0431cbf2016-03-12 01:19:432311 DCHECK(main_task_runner_->BelongsToCurrentThread());
2312
Dale Curtis99a9b482018-02-01 02:23:282313 // This should never be called when stale state testing overrides are used.
2314 DCHECK(!stale_state_override_for_testing_.has_value());
2315
sandersd35d2c3f2017-01-14 02:04:422316 // If we are attempting preroll, clear the stale flag.
2317 if (IsPrerollAttemptNeeded()) {
tguilbert1bb1c782017-01-23 21:15:112318 delegate_->ClearStaleFlag(delegate_id_);
sandersd35d2c3f2017-01-14 02:04:422319 return;
watkd026f792016-11-05 00:28:512320 }
sandersd50a635e2016-04-04 22:50:092321
sandersd35d2c3f2017-01-14 02:04:422322 UpdatePlayState();
dalecurtis0431cbf2016-03-12 01:19:432323}
2324
dalecurtisbb3eaac2016-01-27 21:10:252325void WebMediaPlayerImpl::OnPlay() {
Mounir Lamouri703106e2018-05-30 14:31:092326 client_->RequestPlay();
dalecurtisbb3eaac2016-01-27 21:10:252327}
2328
2329void WebMediaPlayerImpl::OnPause() {
Mounir Lamouri703106e2018-05-30 14:31:092330 client_->RequestPause();
dalecurtisbb3eaac2016-01-27 21:10:252331}
2332
Alec Douglas316cce42017-10-31 13:28:082333void WebMediaPlayerImpl::OnSeekForward(double seconds) {
2334 DCHECK_GE(seconds, 0) << "Attempted to seek by a negative number of seconds";
2335 client_->RequestSeek(CurrentTime() + seconds);
2336}
2337
2338void WebMediaPlayerImpl::OnSeekBackward(double seconds) {
2339 DCHECK_GE(seconds, 0) << "Attempted to seek by a negative number of seconds";
2340 client_->RequestSeek(CurrentTime() - seconds);
2341}
2342
dalecurtisbb3eaac2016-01-27 21:10:252343void WebMediaPlayerImpl::OnVolumeMultiplierUpdate(double multiplier) {
2344 volume_multiplier_ = multiplier;
Blink Reformat1c4d759e2017-04-09 16:34:542345 SetVolume(volume_);
dalecurtisbb3eaac2016-01-27 21:10:252346}
2347
zqzhang8ac49002017-03-16 21:51:352348void WebMediaPlayerImpl::OnBecamePersistentVideo(bool value) {
Blink Reformat1c4d759e2017-04-09 16:34:542349 client_->OnBecamePersistentVideo(value);
[email protected]6490e2d12019-01-14 19:18:372350 overlay_info_.is_persistent_video = value;
2351 MaybeSendOverlayInfoToDecoder();
zqzhang8ac49002017-03-16 21:51:352352}
2353
Jennifer Apacible009f29842018-04-16 23:07:372354void WebMediaPlayerImpl::OnPictureInPictureModeEnded() {
Mounir Lamourib642a3c2018-07-09 15:45:312355 // It is possible for this method to be called when the player is no longer in
2356 // Picture-in-Picture mode.
Mounir Lamouri0484f40a2018-07-25 03:03:262357 if (!client_ || !IsInPictureInPicture())
Mounir Lamourib642a3c2018-07-09 15:45:312358 return;
Mounir Lamourib642a3c2018-07-09 15:45:312359
2360 client_->PictureInPictureStopped();
Jennifer Apacible009f29842018-04-16 23:07:372361}
2362
sawtelle82e4b752018-07-19 04:33:122363void WebMediaPlayerImpl::OnPictureInPictureControlClicked(
2364 const std::string& control_id) {
Mounir Lamouri0484f40a2018-07-25 03:03:262365 if (client_ && IsInPictureInPicture()) {
sawtelle82e4b752018-07-19 04:33:122366 client_->PictureInPictureControlClicked(
2367 blink::WebString::FromUTF8(control_id));
sawtelle42eac6a2018-06-26 03:22:012368 }
2369}
2370
John Delaneyc9abf4a2018-10-31 00:39:162371void WebMediaPlayerImpl::SendBytesReceivedUpdate() {
2372 media_metrics_provider_->AddBytesReceived(bytes_received_since_last_update_);
2373 bytes_received_since_last_update_ = 0;
2374}
2375
John Delaneyb933391602018-10-17 21:50:472376void WebMediaPlayerImpl::OnBytesReceived(uint64_t data_length) {
John Delaneyc9abf4a2018-10-31 00:39:162377 bytes_received_since_last_update_ += data_length;
2378 constexpr base::TimeDelta kBytesReceivedUpdateInterval =
2379 base::TimeDelta::FromMilliseconds(500);
2380 auto current_time = base::TimeTicks::Now();
2381 if (earliest_time_next_bytes_received_update_.is_null() ||
2382 earliest_time_next_bytes_received_update_ <= current_time) {
2383 report_bytes_received_timer_.Stop();
2384 SendBytesReceivedUpdate();
2385 earliest_time_next_bytes_received_update_ =
2386 current_time + kBytesReceivedUpdateInterval;
2387 } else {
2388 report_bytes_received_timer_.Start(
2389 FROM_HERE, kBytesReceivedUpdateInterval, this,
2390 &WebMediaPlayerImpl::SendBytesReceivedUpdate);
2391 }
John Delaneyb933391602018-10-17 21:50:472392}
2393
watkdee516f2016-02-18 02:22:192394void WebMediaPlayerImpl::ScheduleRestart() {
sandersd50a635e2016-04-04 22:50:092395 // TODO(watk): All restart logic should be moved into PipelineController.
tguilbert350936ff2017-02-24 05:39:272396 if (pipeline_controller_.IsPipelineRunning() &&
2397 !pipeline_controller_.IsPipelineSuspended()) {
watkdee516f2016-02-18 02:22:192398 pending_suspend_resume_cycle_ = true;
sandersd50a635e2016-04-04 22:50:092399 UpdatePlayState();
watkdee516f2016-02-18 02:22:192400 }
2401}
2402
Blink Reformat1c4d759e2017-04-09 16:34:542403void WebMediaPlayerImpl::RequestRemotePlaybackDisabled(bool disabled) {
miu77f914c2016-11-19 23:56:182404 if (observer_)
2405 observer_->OnRemotePlaybackDisabled(disabled);
2406}
2407
hubbed5f36882016-01-15 22:40:372408#if defined(OS_ANDROID) // WMPI_CAST
Blink Reformat1c4d759e2017-04-09 16:34:542409bool WebMediaPlayerImpl::IsRemote() const {
hubbed5f36882016-01-15 22:40:372410 return cast_impl_.isRemote();
2411}
2412
2413void WebMediaPlayerImpl::SetMediaPlayerManager(
2414 RendererMediaPlayerManagerInterface* media_player_manager) {
2415 cast_impl_.SetMediaPlayerManager(media_player_manager);
2416}
2417
Blink Reformat1c4d759e2017-04-09 16:34:542418void WebMediaPlayerImpl::RequestRemotePlayback() {
hubbed5f36882016-01-15 22:40:372419 cast_impl_.requestRemotePlayback();
2420}
2421
Blink Reformat1c4d759e2017-04-09 16:34:542422void WebMediaPlayerImpl::RequestRemotePlaybackControl() {
hubbed5f36882016-01-15 22:40:372423 cast_impl_.requestRemotePlaybackControl();
2424}
2425
Blink Reformat1c4d759e2017-04-09 16:34:542426void WebMediaPlayerImpl::RequestRemotePlaybackStop() {
avayvod8d8c53b2016-11-04 16:10:302427 cast_impl_.requestRemotePlaybackStop();
2428}
2429
hubbed5f36882016-01-15 22:40:372430void WebMediaPlayerImpl::OnRemotePlaybackEnded() {
pkastingf5279482016-07-27 02:18:202431 DVLOG(1) << __func__;
hubbed5f36882016-01-15 22:40:372432 DCHECK(main_task_runner_->BelongsToCurrentThread());
2433
2434 ended_ = true;
Blink Reformat1c4d759e2017-04-09 16:34:542435 client_->TimeChanged();
hubbed5f36882016-01-15 22:40:372436}
2437
Thomas Guilbertb341bae02018-05-09 00:02:132438void WebMediaPlayerImpl::FlingingStarted() {
2439 DCHECK(main_task_runner_->BelongsToCurrentThread());
2440 DCHECK(!disable_pipeline_auto_suspend_);
2441 disable_pipeline_auto_suspend_ = true;
2442
Thomas Guilbert29ae1a902018-10-20 01:53:382443 is_flinging_ = true;
2444
Thomas Guilbertb341bae02018-05-09 00:02:132445 // Capabilities reporting should only be performed for local playbacks.
2446 video_decode_stats_reporter_.reset();
2447
2448 // Requests to restart media pipeline. A flinging renderer will be created via
2449 // the |renderer_factory_selector_|.
2450 ScheduleRestart();
2451}
2452
2453void WebMediaPlayerImpl::FlingingStopped() {
2454 DCHECK(main_task_runner_->BelongsToCurrentThread());
2455 DCHECK(disable_pipeline_auto_suspend_);
2456 disable_pipeline_auto_suspend_ = false;
2457
Thomas Guilbert29ae1a902018-10-20 01:53:382458 is_flinging_ = false;
2459
Thomas Guilbertb341bae02018-05-09 00:02:132460 CreateVideoDecodeStatsReporter();
2461
2462 ScheduleRestart();
2463}
2464
hubbed5f36882016-01-15 22:40:372465void WebMediaPlayerImpl::OnDisconnectedFromRemoteDevice(double t) {
sandersd1c0bba02016-03-04 23:14:082466 DoSeek(base::TimeDelta::FromSecondsD(t), false);
hubbed5f36882016-01-15 22:40:372467
Chris Cunninghamd9df58e2017-08-29 00:04:232468 // Capabilities reporting can resume now that playback is local.
2469 CreateVideoDecodeStatsReporter();
2470
Anton Vayvodfad2f3ea2017-07-19 21:45:272471 // |client_| might destroy us in methods below.
2472 UpdatePlayState();
2473
hubbed5f36882016-01-15 22:40:372474 // We already told the delegate we're paused when remoting started.
Mounir Lamouri703106e2018-05-30 14:31:092475 client_->RequestPause();
Blink Reformat1c4d759e2017-04-09 16:34:542476 client_->DisconnectedFromRemoteDevice();
hubbed5f36882016-01-15 22:40:372477}
2478
2479void WebMediaPlayerImpl::SuspendForRemote() {
Chris Cunninghamd9df58e2017-08-29 00:04:232480 // Capabilities reporting should only be performed for local playbacks.
2481 video_decode_stats_reporter_.reset();
2482
avayvod82729272017-05-29 21:58:392483 if (pipeline_controller_.IsPipelineSuspended() &&
2484 !IsNewRemotePlaybackPipelineEnabled()) {
hubbed5f36882016-01-15 22:40:372485 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner();
sandersd50a635e2016-04-04 22:50:092486 if (frame)
dalecurtise9c89e92016-05-20 19:38:002487 compositor_->PaintSingleFrame(frame);
hubbed5f36882016-01-15 22:40:372488 }
sandersd50a635e2016-04-04 22:50:092489
2490 UpdatePlayState();
hubbed5f36882016-01-15 22:40:372491}
2492
2493gfx::Size WebMediaPlayerImpl::GetCanvasSize() const {
lethalantidote7f6009d2017-07-07 21:47:392494 if (!surface_layer_for_video_enabled_) {
danakj6e669e782018-05-16 16:57:172495 if (!video_layer_)
lethalantidote7f6009d2017-07-07 21:47:392496 return pipeline_metadata_.natural_size;
2497
danakj6e669e782018-05-16 16:57:172498 return video_layer_->bounds();
lethalantidote7f6009d2017-07-07 21:47:392499 }
danakj8d204a42018-05-18 18:05:352500 if (!bridge_->GetCcLayer())
hubbed5f36882016-01-15 22:40:372501 return pipeline_metadata_.natural_size;
2502
danakj8d204a42018-05-18 18:05:352503 return bridge_->GetCcLayer()->bounds();
hubbed5f36882016-01-15 22:40:372504}
2505
2506void WebMediaPlayerImpl::SetDeviceScaleFactor(float scale_factor) {
2507 cast_impl_.SetDeviceScaleFactor(scale_factor);
2508}
Dan Sanderscd8981c2017-08-31 22:37:022509#endif // defined(OS_ANDROID) // WMPI_CAST
hubbee4027f92016-05-19 05:18:132510
Blink Reformat1c4d759e2017-04-09 16:34:542511void WebMediaPlayerImpl::SetPoster(const blink::WebURL& poster) {
Dan Sanderscd8981c2017-08-31 22:37:022512 has_poster_ = !poster.IsEmpty();
2513#if defined(OS_ANDROID) // WMPI_CAST
xjzc102fd82017-01-04 20:13:532514 cast_impl_.setPoster(poster);
xjz2504c4da2017-04-18 18:50:142515#endif // defined(OS_ANDROID) // WMPI_CAST
Dan Sanderscd8981c2017-08-31 22:37:022516}
xjzc102fd82017-01-04 20:13:532517
[email protected]fee8a902014-06-03 13:43:362518void WebMediaPlayerImpl::DataSourceInitialized(bool success) {
pkastingf5279482016-07-27 02:18:202519 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:432520 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]a9415292012-01-19 19:55:202521
Dale Curtis4841c712018-12-13 18:14:052522 if (observer_ && IsNewRemotePlaybackPipelineEnabled() && mb_data_source_)
2523 observer_->OnDataSourceInitialized(mb_data_source_->GetUrlAfterRedirects());
Anton Vayvod09fa66e2017-07-20 23:02:122524
[email protected]d250190da3b2012-07-23 22:57:302525 if (!success) {
Blink Reformat1c4d759e2017-04-09 16:34:542526 SetNetworkState(WebMediaPlayer::kNetworkStateFormatError);
Dale Curtis74612b72017-12-14 20:56:192527 media_metrics_provider_->OnError(PIPELINE_ERROR_NETWORK);
sandersd50a635e2016-04-04 22:50:092528
2529 // Not really necessary, since the pipeline was never started, but it at
2530 // least this makes sure that the error handling code is in sync.
2531 UpdatePlayState();
2532
[email protected]a9415292012-01-19 19:55:202533 return;
2534 }
2535
hubbee2cc88c092017-07-14 23:10:412536 // No point in preloading data as we'll probably just throw it away anyways.
Dale Curtis4841c712018-12-13 18:14:052537 if (IsStreaming() && preload_ > MultibufferDataSource::METADATA &&
2538 mb_data_source_) {
2539 mb_data_source_->SetPreload(MultibufferDataSource::METADATA);
hubbee2cc88c092017-07-14 23:10:412540 }
2541
[email protected]ef8394c2013-08-21 20:26:302542 StartPipeline();
[email protected]a9415292012-01-19 19:55:202543}
2544
[email protected]122f40252012-06-12 05:01:562545void WebMediaPlayerImpl::NotifyDownloading(bool is_downloading) {
hubbeb2d3efd2017-05-05 23:26:382546 DVLOG(1) << __func__ << "(" << is_downloading << ")";
Blink Reformat1c4d759e2017-04-09 16:34:542547 if (!is_downloading && network_state_ == WebMediaPlayer::kNetworkStateLoading)
2548 SetNetworkState(WebMediaPlayer::kNetworkStateIdle);
2549 else if (is_downloading &&
2550 network_state_ == WebMediaPlayer::kNetworkStateIdle)
2551 SetNetworkState(WebMediaPlayer::kNetworkStateLoading);
hubbeb2d3efd2017-05-05 23:26:382552 if (ready_state_ == ReadyState::kReadyStateHaveFutureData && !is_downloading)
2553 SetReadyState(WebMediaPlayer::kReadyStateHaveEnoughData);
[email protected]122f40252012-06-12 05:01:562554}
2555
liberato2ff93ad2017-05-17 07:28:242556void WebMediaPlayerImpl::OnOverlayRoutingToken(
2557 const base::UnguessableToken& token) {
2558 DCHECK(overlay_mode_ == OverlayMode::kUseAndroidOverlay);
liberatofe8f9692017-06-08 19:17:362559 // TODO(liberato): |token| should already be a RoutingToken.
2560 overlay_routing_token_is_pending_ = false;
2561 overlay_routing_token_ = OverlayInfo::RoutingToken(token);
liberato2ff93ad2017-05-17 07:28:242562 MaybeSendOverlayInfoToDecoder();
2563}
2564
2565void WebMediaPlayerImpl::OnOverlayInfoRequested(
dalecurtis4b632fce22016-11-10 00:52:172566 bool decoder_requires_restart_for_overlay,
liberato2ff93ad2017-05-17 07:28:242567 const ProvideOverlayInfoCB& provide_overlay_info_cb) {
watkdee516f2016-02-18 02:22:192568 DCHECK(main_task_runner_->BelongsToCurrentThread());
watkdee516f2016-02-18 02:22:192569
Chris Watkins557f84d2017-09-16 02:31:462570 // If we get a non-null cb, a decoder is initializing and requires overlay
2571 // info. If we get a null cb, a previously initialized decoder is
2572 // unregistering for overlay info updates.
Dale Curtise25163812018-09-21 22:13:392573 if (!provide_overlay_info_cb) {
tsunghungee562e92016-07-20 18:03:312574 decoder_requires_restart_for_overlay_ = false;
liberato2ff93ad2017-05-17 07:28:242575 provide_overlay_info_cb_.Reset();
watkdee516f2016-02-18 02:22:192576 return;
2577 }
2578
dalecurtis4b632fce22016-11-10 00:52:172579 // If |decoder_requires_restart_for_overlay| is true, we must restart the
2580 // pipeline for fullscreen transitions. The decoder is unable to switch
2581 // surfaces otherwise. If false, we simply need to tell the decoder about the
2582 // new surface and it will handle things seamlessly.
Chris Watkins557f84d2017-09-16 02:31:462583 // For encrypted video we pretend that the decoder doesn't require a restart
2584 // because it needs an overlay all the time anyway. We'll switch into
2585 // |always_enable_overlays_| mode below.
2586 decoder_requires_restart_for_overlay_ =
2587 (overlay_mode_ == OverlayMode::kUseAndroidOverlay && is_encrypted_)
2588 ? false
2589 : decoder_requires_restart_for_overlay;
liberato2ff93ad2017-05-17 07:28:242590 provide_overlay_info_cb_ = provide_overlay_info_cb;
dalecurtis4b632fce22016-11-10 00:52:172591
Chris Watkins557f84d2017-09-16 02:31:462592 // If the decoder doesn't require restarts for surface transitions, and we're
2593 // using AndroidOverlay mode, we can always enable the overlay and the decoder
2594 // can choose whether or not to use it. Otherwise, we'll restart the decoder
2595 // and enable the overlay on fullscreen transitions.
[email protected]77568482017-06-21 21:16:522596 if (overlay_mode_ == OverlayMode::kUseAndroidOverlay &&
Chris Watkins557f84d2017-09-16 02:31:462597 !decoder_requires_restart_for_overlay_) {
[email protected]c8d574722017-08-30 20:53:432598 always_enable_overlays_ = true;
[email protected]77568482017-06-21 21:16:522599 if (!overlay_enabled_)
2600 EnableOverlay();
2601 }
2602
Chris Watkins557f84d2017-09-16 02:31:462603 // Send the overlay info if we already have it. If not, it will be sent later.
liberato2ff93ad2017-05-17 07:28:242604 MaybeSendOverlayInfoToDecoder();
2605}
2606
2607void WebMediaPlayerImpl::MaybeSendOverlayInfoToDecoder() {
2608 // If the decoder didn't request overlay info, then don't send it.
2609 if (!provide_overlay_info_cb_)
dalecurtis4b632fce22016-11-10 00:52:172610 return;
2611
liberato2ff93ad2017-05-17 07:28:242612 // We should send the overlay info as long as we know it. This includes the
2613 // case where |!overlay_enabled_|, since we want to tell the decoder to avoid
2614 // using overlays. Assuming that the decoder has requested info, the only
2615 // case in which we don't want to send something is if we've requested the
2616 // info but not received it yet. Then, we should wait until we do.
liberatofe8f9692017-06-08 19:17:362617 //
2618 // Initialization requires this; AVDA should start with enough info to make an
2619 // overlay, so that (pre-M) the initial codec is created with the right output
2620 // surface; it can't switch later.
[email protected]f7df5b342018-07-13 20:22:132621 if (overlay_mode_ == OverlayMode::kUseAndroidOverlay) {
liberatofe8f9692017-06-08 19:17:362622 if (overlay_routing_token_is_pending_)
liberato2ff93ad2017-05-17 07:28:242623 return;
liberatofe8f9692017-06-08 19:17:362624
2625 overlay_info_.routing_token = overlay_routing_token_;
liberato2ff93ad2017-05-17 07:28:242626 }
2627
liberato2ff93ad2017-05-17 07:28:242628 // If restart is required, the callback is one-shot only.
2629 if (decoder_requires_restart_for_overlay_) {
Dale Curtise25163812018-09-21 22:13:392630 std::move(provide_overlay_info_cb_).Run(overlay_info_);
liberato2ff93ad2017-05-17 07:28:242631 } else {
liberatofe8f9692017-06-08 19:17:362632 provide_overlay_info_cb_.Run(overlay_info_);
liberato2ff93ad2017-05-17 07:28:242633 }
watkdee516f2016-02-18 02:22:192634}
2635
dcheng3076abbf2016-04-22 20:42:392636std::unique_ptr<Renderer> WebMediaPlayerImpl::CreateRenderer() {
dcheng37b415b92017-01-27 20:17:432637 DCHECK(main_task_runner_->BelongsToCurrentThread());
2638
[email protected]c8d574722017-08-30 20:53:432639 // Make sure that overlays are enabled if they're always allowed.
2640 if (always_enable_overlays_)
tsunghungee562e92016-07-20 18:03:312641 EnableOverlay();
2642
liberato2ff93ad2017-05-17 07:28:242643 RequestOverlayInfoCB request_overlay_info_cb;
watkdee516f2016-02-18 02:22:192644#if defined(OS_ANDROID)
liberato2ff93ad2017-05-17 07:28:242645 request_overlay_info_cb = BindToCurrentLoop(
2646 base::Bind(&WebMediaPlayerImpl::OnOverlayInfoRequested, AsWeakPtr()));
watkdee516f2016-02-18 02:22:192647#endif
tguilbert70d2a00a2017-04-25 00:30:442648 return renderer_factory_selector_->GetCurrentFactory()->CreateRenderer(
sandersd1e49fb62015-12-12 01:18:062649 media_task_runner_, worker_task_runner_, audio_source_provider_.get(),
CJ DiMeglio2302d202017-08-31 08:38:042650 compositor_.get(), request_overlay_info_cb, client_->TargetColorSpace());
sandersd1e49fb62015-12-12 01:18:062651}
2652
[email protected]ef8394c2013-08-21 20:26:302653void WebMediaPlayerImpl::StartPipeline() {
acolwellb4034942014-08-28 15:42:432654 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]ddbc6ff2013-04-19 15:28:332655
xhwange8c4181a2014-12-06 08:10:012656 Demuxer::EncryptedMediaInitDataCB encrypted_media_init_data_cb =
dcheng37b415b92017-01-27 20:17:432657 BindToCurrentLoop(base::Bind(
2658 &WebMediaPlayerImpl::OnEncryptedMediaInitData, AsWeakPtr()));
[email protected]2b57e2e2014-05-09 11:07:252659
Dale Curtis3899090ea2018-01-12 00:10:352660 vfc_task_runner_->PostTask(
2661 FROM_HERE,
2662 base::BindOnce(&VideoFrameCompositor::SetOnNewProcessedFrameCallback,
2663 base::Unretained(compositor_.get()),
2664 BindToCurrentLoop(base::BindOnce(
2665 &WebMediaPlayerImpl::OnFirstFrame, AsWeakPtr()))));
2666
tguilbert75e2bf62017-04-26 20:13:122667 if (renderer_factory_selector_->GetCurrentFactory()
2668 ->GetRequiredMediaResourceType() == MediaResource::Type::URL) {
tguilbert75e2bf62017-04-26 20:13:122669 // MediaPlayerRendererClient factory is the only factory that a
2670 // MediaResource::Type::URL for the moment. This might no longer be true
2671 // when we remove WebMediaPlayerCast.
2672 //
2673 // TODO(tguilbert/avayvod): Update this flag when removing |cast_impl_|.
2674 using_media_player_renderer_ = true;
2675
Chris Cunninghamd9df58e2017-08-29 00:04:232676 // MediaPlayerRenderer does not provide pipeline stats, so nuke capabilities
2677 // reporter.
2678 video_decode_stats_reporter_.reset();
2679
Mike Westb85da8ed2017-08-10 14:16:462680 demuxer_.reset(new MediaUrlDemuxer(media_task_runner_, loaded_url_,
2681 frame_->GetDocument().SiteForCookies()));
Dale Curtisc00d56482018-02-09 20:55:062682 pipeline_controller_.Start(Pipeline::StartType::kNormal, demuxer_.get(),
2683 this, false, false);
tguilbert25a4d112016-10-13 21:56:512684 return;
2685 }
2686
[email protected]ddbc6ff2013-04-19 15:28:332687 // Figure out which demuxer to use.
Blink Reformat1c4d759e2017-04-09 16:34:542688 if (load_type_ != kLoadTypeMediaSource) {
[email protected]ddbc6ff2013-04-19 15:28:332689 DCHECK(!chunk_demuxer_);
[email protected]f5443ef72013-04-22 04:03:382690 DCHECK(data_source_);
2691
Dale Curtisbcf523b2018-01-17 02:59:012692#if BUILDFLAG(ENABLE_FFMPEG)
servolk81e01e02016-03-05 03:29:152693 Demuxer::MediaTracksUpdatedCB media_tracks_updated_cb =
dcheng37b415b92017-01-27 20:17:432694 BindToCurrentLoop(base::Bind(
2695 &WebMediaPlayerImpl::OnFFmpegMediaTracksUpdated, AsWeakPtr()));
servolk81e01e02016-03-05 03:29:152696
dalecurtis9cddc0b2017-04-19 21:23:382697 demuxer_.reset(new FFmpegDemuxer(
2698 media_task_runner_, data_source_.get(), encrypted_media_init_data_cb,
Dale Curtisb8139f72018-08-27 23:28:482699 media_tracks_updated_cb, media_log_.get(), IsLocalFile(loaded_url_)));
j.isorcef6778e652015-11-16 17:14:252700#else
alokp967c902452016-05-06 05:21:372701 OnError(PipelineStatus::DEMUXER_ERROR_COULD_NOT_OPEN);
j.isorcef6778e652015-11-16 17:14:252702 return;
2703#endif
[email protected]ddbc6ff2013-04-19 15:28:332704 } else {
[email protected]f5443ef72013-04-22 04:03:382705 DCHECK(!chunk_demuxer_);
2706 DCHECK(!data_source_);
2707
acolwell9e0840d2014-09-06 19:01:322708 chunk_demuxer_ = new ChunkDemuxer(
dcheng37b415b92017-01-27 20:17:432709 BindToCurrentLoop(
2710 base::Bind(&WebMediaPlayerImpl::OnDemuxerOpened, AsWeakPtr())),
Dan Sanders42311b52017-08-10 23:41:032711 BindToCurrentLoop(
2712 base::Bind(&WebMediaPlayerImpl::OnProgress, AsWeakPtr())),
dalecurtis9cddc0b2017-04-19 21:23:382713 encrypted_media_init_data_cb, media_log_.get());
John Delaneyb933391602018-10-17 21:50:472714 // Notify |this| of bytes that are received via MSE.
2715 chunk_demuxer_->AddBytesReceivedCallback(
2716 BindToCurrentLoop(base::BindRepeating(
2717 &WebMediaPlayerImpl::OnBytesReceived, AsWeakPtr())));
[email protected]f5443ef72013-04-22 04:03:382718 demuxer_.reset(chunk_demuxer_);
servolkf94b4602017-01-31 16:44:272719
2720 if (base::FeatureList::IsEnabled(kMemoryPressureBasedSourceBufferGC)) {
2721 // base::Unretained is safe because |this| owns memory_pressure_listener_.
2722 memory_pressure_listener_ =
Gyuyoung Kim62a5de42018-01-10 09:48:422723 std::make_unique<base::MemoryPressureListener>(base::Bind(
servolkf94b4602017-01-31 16:44:272724 &WebMediaPlayerImpl::OnMemoryPressure, base::Unretained(this)));
2725 }
[email protected]ddbc6ff2013-04-19 15:28:332726 }
2727
sandersdb5e21462016-03-09 01:49:072728 // TODO(sandersd): FileSystem objects may also be non-static, but due to our
2729 // caching layer such situations are broken already. http://crbug.com/593159
2730 bool is_static = !chunk_demuxer_;
avayvod102cdb62017-01-07 03:11:092731 bool is_streaming = IsStreaming();
sandersdb8eb5f1d2016-11-19 04:04:022732 UMA_HISTOGRAM_BOOLEAN("Media.IsStreaming", is_streaming);
sandersdb5e21462016-03-09 01:49:072733
Dale Curtis2dc6089a2018-03-26 16:47:582734 // If possible attempt to avoid decoder spool up until playback starts.
2735 Pipeline::StartType start_type = Pipeline::StartType::kNormal;
Dale Curtis7c63f2e22018-09-19 21:06:272736 if (!chunk_demuxer_ && preload_ == MultibufferDataSource::METADATA &&
Dale Curtisf5a7c9212018-04-10 21:57:342737 !client_->CouldPlayIfEnoughData()) {
Dale Curtis7c63f2e22018-09-19 21:06:272738 start_type =
2739 (has_poster_ || base::FeatureList::IsEnabled(kPreloadMetadataLazyLoad))
2740 ? Pipeline::StartType::kSuspendAfterMetadata
2741 : Pipeline::StartType::kSuspendAfterMetadataForAudioOnly;
Dale Curtis2dc6089a2018-03-26 16:47:582742 attempting_suspended_start_ = true;
2743 }
2744
[email protected]f5443ef72013-04-22 04:03:382745 // ... and we're ready to go!
sandersd1e49fb62015-12-12 01:18:062746 // TODO(sandersd): On Android, defer Start() if the tab is not visible.
sandersdb8eb5f1d2016-11-19 04:04:022747 seeking_ = true;
Dale Curtis2dc6089a2018-03-26 16:47:582748 pipeline_controller_.Start(start_type, demuxer_.get(), this, is_streaming,
2749 is_static);
[email protected]f5443ef72013-04-22 04:03:382750}
2751
2752void WebMediaPlayerImpl::SetNetworkState(WebMediaPlayer::NetworkState state) {
pkastingf5279482016-07-27 02:18:202753 DVLOG(1) << __func__ << "(" << state << ")";
acolwellb4034942014-08-28 15:42:432754 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]f5443ef72013-04-22 04:03:382755 network_state_ = state;
2756 // Always notify to ensure client has the latest value.
Blink Reformat1c4d759e2017-04-09 16:34:542757 client_->NetworkStateChanged();
[email protected]f5443ef72013-04-22 04:03:382758}
2759
2760void WebMediaPlayerImpl::SetReadyState(WebMediaPlayer::ReadyState state) {
pkastingf5279482016-07-27 02:18:202761 DVLOG(1) << __func__ << "(" << state << ")";
acolwellb4034942014-08-28 15:42:432762 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]f5443ef72013-04-22 04:03:382763
Blink Reformat1c4d759e2017-04-09 16:34:542764 if (state == WebMediaPlayer::kReadyStateHaveEnoughData && data_source_ &&
Dale Curtis4841c712018-12-13 18:14:052765 data_source_->AssumeFullyBuffered() &&
2766 network_state_ == WebMediaPlayer::kNetworkStateLoading) {
Blink Reformat1c4d759e2017-04-09 16:34:542767 SetNetworkState(WebMediaPlayer::kNetworkStateLoaded);
Dale Curtis4841c712018-12-13 18:14:052768 }
[email protected]f5443ef72013-04-22 04:03:382769
2770 ready_state_ = state;
sandersd50a635e2016-04-04 22:50:092771 highest_ready_state_ = std::max(highest_ready_state_, ready_state_);
2772
[email protected]f5443ef72013-04-22 04:03:382773 // Always notify to ensure client has the latest value.
Blink Reformat1c4d759e2017-04-09 16:34:542774 client_->ReadyStateChanged();
[email protected]f5443ef72013-04-22 04:03:382775}
2776
Blink Reformat1c4d759e2017-04-09 16:34:542777blink::WebAudioSourceProvider* WebMediaPlayerImpl::GetAudioSourceProvider() {
[email protected]ff875be52013-06-02 23:47:382778 return audio_source_provider_.get();
[email protected]f5443ef72013-04-22 04:03:382779}
2780
Jiajia Qin82acdc02017-07-31 09:55:142781scoped_refptr<VideoFrame> WebMediaPlayerImpl::GetCurrentFrameFromCompositor()
2782 const {
xhwang213e50c2016-10-10 23:56:312783 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]dd061e12014-05-06 19:21:222784 TRACE_EVENT0("media", "WebMediaPlayerImpl::GetCurrentFrameFromCompositor");
xhwang213e50c2016-10-10 23:56:312785
Thomas Guilbertd85407412017-11-08 05:03:462786 // Can be null.
2787 scoped_refptr<VideoFrame> video_frame =
2788 compositor_->GetCurrentFrameOnAnyThread();
[email protected]dd061e12014-05-06 19:21:222789
Thomas Guilbertd85407412017-11-08 05:03:462790 // base::Unretained is safe here because |compositor_| is destroyed on
2791 // |vfc_task_runner_|. The destruction is queued from |this|' destructor,
2792 // which also runs on |main_task_runner_|, which makes it impossible for
2793 // UpdateCurrentFrameIfStale() to be queued after |compositor_|'s dtor.
CJ DiMeglio2302d202017-08-31 08:38:042794 vfc_task_runner_->PostTask(
Dale Curtisee9be30012018-09-21 22:21:512795 FROM_HERE,
2796 base::BindOnce(&VideoFrameCompositor::UpdateCurrentFrameIfStale,
2797 base::Unretained(compositor_.get())));
kainino36eeff82017-03-30 00:55:302798
[email protected]dd061e12014-05-06 19:21:222799 return video_frame;
2800}
2801
sandersd50a635e2016-04-04 22:50:092802void WebMediaPlayerImpl::UpdatePlayState() {
xhwang213e50c2016-10-10 23:56:312803 DCHECK(main_task_runner_->BelongsToCurrentThread());
2804
hubbed5f36882016-01-15 22:40:372805#if defined(OS_ANDROID) // WMPI_CAST
Blink Reformat1c4d759e2017-04-09 16:34:542806 bool is_remote = IsRemote();
xjz4e5d4bf32017-02-15 21:26:352807 bool can_auto_suspend = true;
sandersd50a635e2016-04-04 22:50:092808#else
2809 bool is_remote = false;
hubbee2cc88c092017-07-14 23:10:412810 bool can_auto_suspend = !disable_pipeline_auto_suspend_;
2811 // For streaming videos, we only allow suspending at the very beginning of the
2812 // video, and only if we know the length of the video. (If we don't know
2813 // the length, it might be a dynamically generated video, and suspending
2814 // will not work at all.)
2815 if (IsStreaming()) {
2816 bool at_beginning =
2817 ready_state_ == WebMediaPlayer::kReadyStateHaveNothing ||
2818 CurrentTime() == 0.0;
2819 if (!at_beginning || GetPipelineMediaDuration() == kInfiniteDuration)
2820 can_auto_suspend = false;
2821 }
hubbed5f36882016-01-15 22:40:372822#endif
xhwang213e50c2016-10-10 23:56:312823
dalecurtis8b8505e72016-06-10 21:59:172824 bool is_suspended = pipeline_controller_.IsSuspended();
Sergey Volk8b09c2c52018-12-12 23:20:402825 bool is_backgrounded = IsBackgroundSuspendEnabled(this) && IsHidden();
sandersdaaff1a652016-11-17 01:47:252826 PlayState state = UpdatePlayState_ComputePlayState(
Thomas Guilbert4c6feff2018-11-09 19:53:322827 is_remote, is_flinging_, can_auto_suspend, is_suspended, is_backgrounded);
sandersd35d2c3f2017-01-14 02:04:422828 SetDelegateState(state.delegate_state, state.is_idle);
sandersd50a635e2016-04-04 22:50:092829 SetMemoryReportingState(state.is_memory_reporting_enabled);
2830 SetSuspendState(state.is_suspended || pending_suspend_resume_cycle_);
2831}
dalecurtis5bbc487e2016-02-27 04:15:052832
sandersd35d2c3f2017-01-14 02:04:422833void WebMediaPlayerImpl::SetDelegateState(DelegateState new_state,
2834 bool is_idle) {
tguilbert1bb1c782017-01-23 21:15:112835 DCHECK(delegate_);
Dale Curtis779ed842018-03-10 06:20:132836 DVLOG(2) << __func__ << "(" << static_cast<int>(new_state) << ", " << is_idle
2837 << ")";
dalecurtis5bbc487e2016-02-27 04:15:052838
sandersd35d2c3f2017-01-14 02:04:422839 // Prevent duplicate delegate calls.
2840 // TODO(sandersd): Move this deduplication into the delegate itself.
2841 // TODO(sandersd): WebContentsObserverSanityChecker does not allow sending the
2842 // 'playing' IPC more than once in a row, even if the metadata has changed.
2843 // Figure out whether it should.
Mounir Lamouri366dd8472018-06-19 17:20:042844 // Pretend that the media has no audio if it never played unmuted. This is to
2845 // avoid any action related to audible media such as taking audio focus or
2846 // showing a media notification. To preserve a consistent experience, it does
2847 // not apply if a media was audible so the system states do not flicker
2848 // depending on whether the user muted the player.
2849 bool has_audio = HasAudio() && !client_->WasAlwaysMuted();
sandersd35d2c3f2017-01-14 02:04:422850 if (delegate_state_ == new_state &&
2851 (delegate_state_ != DelegateState::PLAYING ||
2852 delegate_has_audio_ == has_audio)) {
2853 return;
mlamouri910111362016-11-04 11:28:242854 }
sandersd50a635e2016-04-04 22:50:092855 delegate_state_ = new_state;
sandersd35d2c3f2017-01-14 02:04:422856 delegate_has_audio_ = has_audio;
sandersd50a635e2016-04-04 22:50:092857
sandersd35d2c3f2017-01-14 02:04:422858 switch (new_state) {
sandersd50a635e2016-04-04 22:50:092859 case DelegateState::GONE:
2860 delegate_->PlayerGone(delegate_id_);
2861 break;
mlamouri910111362016-11-04 11:28:242862 case DelegateState::PLAYING: {
peconn257951522017-06-09 18:24:592863 if (HasVideo())
2864 delegate_->DidPlayerSizeChange(delegate_id_, NaturalSize());
zqzhang5d8eab72016-08-26 20:34:302865 delegate_->DidPlay(
Blink Reformat1c4d759e2017-04-09 16:34:542866 delegate_id_, HasVideo(), has_audio,
Dale Curtisca1b78f2019-01-15 03:11:262867 DurationToMediaContentType(GetPipelineMediaDuration()));
sandersd50a635e2016-04-04 22:50:092868 break;
mlamouri910111362016-11-04 11:28:242869 }
sandersd50a635e2016-04-04 22:50:092870 case DelegateState::PAUSED:
sandersd35d2c3f2017-01-14 02:04:422871 delegate_->DidPause(delegate_id_);
sandersd50a635e2016-04-04 22:50:092872 break;
dalecurtis0f0097a2015-12-01 17:40:472873 }
sandersd35d2c3f2017-01-14 02:04:422874
2875 delegate_->SetIdle(delegate_id_, is_idle);
dalecurtis0f0097a2015-12-01 17:40:472876}
2877
sandersd50a635e2016-04-04 22:50:092878void WebMediaPlayerImpl::SetMemoryReportingState(
2879 bool is_memory_reporting_enabled) {
2880 if (memory_usage_reporting_timer_.IsRunning() ==
2881 is_memory_reporting_enabled) {
hubbed5f36882016-01-15 22:40:372882 return;
sandersd50a635e2016-04-04 22:50:092883 }
sandersd1c0bba02016-03-04 23:14:082884
sandersd50a635e2016-04-04 22:50:092885 if (is_memory_reporting_enabled) {
2886 memory_usage_reporting_timer_.Start(FROM_HERE,
2887 base::TimeDelta::FromSeconds(2), this,
2888 &WebMediaPlayerImpl::ReportMemoryUsage);
2889 } else {
2890 memory_usage_reporting_timer_.Stop();
2891 ReportMemoryUsage();
2892 }
2893}
2894
2895void WebMediaPlayerImpl::SetSuspendState(bool is_suspended) {
xhwang213e50c2016-10-10 23:56:312896 DCHECK(main_task_runner_->BelongsToCurrentThread());
Dale Curtis779ed842018-03-10 06:20:132897 DVLOG(2) << __func__ << "(" << is_suspended << ")";
xhwang213e50c2016-10-10 23:56:312898
sandersd50a635e2016-04-04 22:50:092899 // Do not change the state after an error has occurred.
2900 // TODO(sandersd): Update PipelineController to remove the need for this.
2901 if (IsNetworkStateError(network_state_))
sandersd1c0bba02016-03-04 23:14:082902 return;
2903
jameswest451a5bb2017-01-27 03:59:392904 if (is_suspended) {
sandersd35d2c3f2017-01-14 02:04:422905 // If we were not resumed for long enough to satisfy the preroll attempt,
2906 // reset the clock.
2907 if (!preroll_attempt_pending_ && IsPrerollAttemptNeeded()) {
2908 preroll_attempt_pending_ = true;
2909 preroll_attempt_start_time_ = base::TimeTicks();
2910 }
sandersd50a635e2016-04-04 22:50:092911 pipeline_controller_.Suspend();
2912 } else {
sandersd35d2c3f2017-01-14 02:04:422913 // When resuming, start the preroll attempt clock.
2914 if (preroll_attempt_pending_) {
2915 preroll_attempt_pending_ = false;
2916 preroll_attempt_start_time_ = tick_clock_->NowTicks();
2917 }
sandersd50a635e2016-04-04 22:50:092918 pipeline_controller_.Resume();
2919 }
2920}
2921
Thomas Guilbert4c6feff2018-11-09 19:53:322922// NOTE: |is_remote| and |is_flinging| both indicate that we are in a remote
2923// playback session, with the following differences:
2924// - |is_remote| : we are using |cast_impl_|, and most of WMPI's functions
2925// are forwarded to it. This method of remote playback is scheduled
2926// for deprecation soon, in favor of the |is_flinging| path.
2927// - |is_flinging| : we are using the FlingingRenderer, and WMPI should
2928// behave exactly if we are using the DefaultRenderer, except for the
2929// disabling of certain optimizations.
2930// See https://crbug.com/790766.
sandersd50a635e2016-04-04 22:50:092931WebMediaPlayerImpl::PlayState
2932WebMediaPlayerImpl::UpdatePlayState_ComputePlayState(bool is_remote,
Thomas Guilbert4c6feff2018-11-09 19:53:322933 bool is_flinging,
xjz4e5d4bf32017-02-15 21:26:352934 bool can_auto_suspend,
dalecurtis8b8505e72016-06-10 21:59:172935 bool is_suspended,
sandersd50a635e2016-04-04 22:50:092936 bool is_backgrounded) {
2937 PlayState result;
2938
tguilbert1bb1c782017-01-23 21:15:112939 bool must_suspend = delegate_->IsFrameClosed();
Dale Curtis6438cf12018-03-29 02:34:012940 bool is_stale = delegate_->IsStale(delegate_id_);
2941
2942 if (stale_state_override_for_testing_.has_value() &&
2943 ready_state_ >= stale_state_override_for_testing_.value()) {
2944 is_stale = true;
2945 }
sandersd35d2c3f2017-01-14 02:04:422946
sandersd50a635e2016-04-04 22:50:092947 // This includes both data source (before pipeline startup) and pipeline
2948 // errors.
2949 bool has_error = IsNetworkStateError(network_state_);
2950
dalecurtiscc8baf72016-10-27 01:49:442951 // After HaveFutureData, Blink will call play() if the state is not paused;
2952 // prior to this point |paused_| is not accurate.
sandersd50a635e2016-04-04 22:50:092953 bool have_future_data =
Blink Reformat1c4d759e2017-04-09 16:34:542954 highest_ready_state_ >= WebMediaPlayer::kReadyStateHaveFutureData;
sandersd50a635e2016-04-04 22:50:092955
avayvod65fad272017-02-24 01:00:482956 // Background suspend is only enabled for paused players.
2957 // In the case of players with audio the session should be kept.
2958 bool background_suspended =
xjz4e5d4bf32017-02-15 21:26:352959 can_auto_suspend && is_backgrounded && paused_ && have_future_data;
sandersd50a635e2016-04-04 22:50:092960
dalecurtiscc8baf72016-10-27 01:49:442961 // Idle suspension is allowed prior to have future data since there exist
2962 // mechanisms to exit the idle state when the player is capable of reaching
2963 // the have future data state; see didLoadingProgress().
2964 //
sandersd50a635e2016-04-04 22:50:092965 // TODO(sandersd): Make the delegate suspend idle players immediately when
2966 // hidden.
Dale Curtis7c63f2e22018-09-19 21:06:272967 bool idle_suspended = can_auto_suspend && is_stale && paused_ && !seeking_ &&
2968 !overlay_enabled_ && !needs_first_frame_;
dalecurtise7120dc2016-09-03 02:54:352969
2970 // If we're already suspended, see if we can wait for user interaction. Prior
sandersd35d2c3f2017-01-14 02:04:422971 // to HaveFutureData, we require |is_stale| to remain suspended. |is_stale|
dalecurtise7120dc2016-09-03 02:54:352972 // will be cleared when we receive data which may take us to HaveFutureData.
Dale Curtis7c63f2e22018-09-19 21:06:272973 bool can_stay_suspended = (is_stale || have_future_data) && is_suspended &&
2974 paused_ && !seeking_ && !needs_first_frame_;
sandersd50a635e2016-04-04 22:50:092975
2976 // Combined suspend state.
sandersd35d2c3f2017-01-14 02:04:422977 result.is_suspended = is_remote || must_suspend || idle_suspended ||
avayvod65fad272017-02-24 01:00:482978 background_suspended || can_stay_suspended;
sandersd50a635e2016-04-04 22:50:092979
Dale Curtis779ed842018-03-10 06:20:132980 DVLOG(3) << __func__ << ": is_remote=" << is_remote
2981 << ", must_suspend=" << must_suspend
2982 << ", idle_suspended=" << idle_suspended
2983 << ", background_suspended=" << background_suspended
2984 << ", can_stay_suspended=" << can_stay_suspended
2985 << ", is_stale=" << is_stale
2986 << ", have_future_data=" << have_future_data
2987 << ", paused_=" << paused_ << ", seeking_=" << seeking_;
2988
sandersd50a635e2016-04-04 22:50:092989 // We do not treat |playback_rate_| == 0 as paused. For the media session,
2990 // being paused implies displaying a play button, which is incorrect in this
2991 // case. For memory usage reporting, we just use the same definition (but we
2992 // don't have to).
2993 //
2994 // Similarly, we don't consider |ended_| to be paused. Blink will immediately
2995 // call pause() or seek(), so |ended_| should not affect the computation.
2996 // Despite that, |ended_| does result in a separate paused state, to simplfy
2997 // the contract for SetDelegateState().
2998 //
avayvod65fad272017-02-24 01:00:482999 // |has_remote_controls| indicates if the player can be controlled outside the
3000 // page (e.g. via the notification controls or by audio focus events). Idle
sandersd50a635e2016-04-04 22:50:093001 // suspension does not destroy the media session, because we expect that the
avayvod5f34b642017-03-23 03:14:043002 // notification controls (and audio focus) remain. With some exceptions for
3003 // background videos, the player only needs to have audio to have controls
3004 // (requires |have_future_data|).
3005 //
3006 // |alive| indicates if the player should be present (not |GONE|) to the
3007 // delegate, either paused or playing. The following must be true for the
3008 // player:
sandersd50a635e2016-04-04 22:50:093009 // - |have_future_data|, since we need to know whether we are paused to
avayvod65fad272017-02-24 01:00:483010 // correctly configure the session and also because the tracks and
avayvod5f34b642017-03-23 03:14:043011 // duration are passed to DidPlay(),
Thomas Guilbert4c6feff2018-11-09 19:53:323012 // - |is_remote| and |is_flinging| are false as remote playback is not
3013 // handled by the delegate,
avayvod5f34b642017-03-23 03:14:043014 // - |has_error| is false as player should have no errors,
3015 // - |background_suspended| is false, otherwise |has_remote_controls| must
3016 // be true.
sandersd50a635e2016-04-04 22:50:093017 //
avayvod65fad272017-02-24 01:00:483018 // TODO(sandersd): If Blink told us the paused state sooner, we could detect
3019 // if the remote controls are available sooner.
3020
3021 // Background videos with audio don't have remote controls if background
3022 // suspend is enabled and resuming background videos is not (original Android
3023 // behavior).
3024 bool backgrounded_video_has_no_remote_controls =
Sergey Volk8b09c2c52018-12-12 23:20:403025 IsBackgroundSuspendEnabled(this) && !IsResumeBackgroundVideosEnabled() &&
3026 is_backgrounded && HasVideo();
Thomas Guilbert4c6feff2018-11-09 19:53:323027 bool can_play = !has_error && have_future_data;
avayvod5f34b642017-03-23 03:14:043028 bool has_remote_controls =
Blink Reformat1c4d759e2017-04-09 16:34:543029 HasAudio() && !backgrounded_video_has_no_remote_controls;
Thomas Guilbert4c6feff2018-11-09 19:53:323030 bool in_remote_playback = is_remote || is_flinging;
3031 bool alive = can_play && !in_remote_playback && !must_suspend &&
avayvod5f34b642017-03-23 03:14:043032 (!background_suspended || has_remote_controls);
3033 if (!alive) {
Thomas Guilbert4c6feff2018-11-09 19:53:323034 // Do not mark players as idle when flinging.
sandersd50a635e2016-04-04 22:50:093035 result.delegate_state = DelegateState::GONE;
Thomas Guilbert4c6feff2018-11-09 19:53:323036 result.is_idle = delegate_->IsIdle(delegate_id_) && !is_flinging;
avayvod65fad272017-02-24 01:00:483037 } else if (paused_) {
sandersd35d2c3f2017-01-14 02:04:423038 // TODO(sandersd): Is it possible to have a suspended session, be ended,
3039 // and not be paused? If so we should be in a PLAYING state.
dalecurtise7120dc2016-09-03 02:54:353040 result.delegate_state =
sandersd35d2c3f2017-01-14 02:04:423041 ended_ ? DelegateState::GONE : DelegateState::PAUSED;
3042 result.is_idle = !seeking_;
sandersd50a635e2016-04-04 22:50:093043 } else {
3044 result.delegate_state = DelegateState::PLAYING;
sandersd35d2c3f2017-01-14 02:04:423045 result.is_idle = false;
sandersd50a635e2016-04-04 22:50:093046 }
3047
dalecurtis8b8505e72016-06-10 21:59:173048 // It's not critical if some cases where memory usage can change are missed,
sandersd50a635e2016-04-04 22:50:093049 // since media memory changes are usually gradual.
3050 result.is_memory_reporting_enabled =
Thomas Guilbert4c6feff2018-11-09 19:53:323051 !has_error && can_play && !in_remote_playback && !result.is_suspended &&
3052 (!paused_ || seeking_);
sandersd50a635e2016-04-04 22:50:093053
3054 return result;
dalecurtis0f0097a2015-12-01 17:40:473055}
3056
dalecurtis83266c72015-10-29 18:43:203057void WebMediaPlayerImpl::ReportMemoryUsage() {
3058 DCHECK(main_task_runner_->BelongsToCurrentThread());
3059
wdzierzanowskifd4cd91c52015-12-02 23:50:203060 // About base::Unretained() usage below: We destroy |demuxer_| on the main
3061 // thread. Before that, however, ~WebMediaPlayerImpl() posts a task to the
3062 // media thread and waits for it to finish. Hence, the GetMemoryUsage() task
3063 // posted here must finish earlier.
Dale Curtis8a6281322017-08-31 00:35:533064 //
3065 // The exception to the above is when OnError() has been called. If we're in
3066 // the error state we've already shut down the pipeline and can't rely on it
3067 // to cycle the media thread before we destroy |demuxer_|. In this case skip
3068 // collection of the demuxer memory stats.
3069 if (demuxer_ && !IsNetworkStateError(network_state_)) {
wdzierzanowskifd4cd91c52015-12-02 23:50:203070 base::PostTaskAndReplyWithResult(
3071 media_task_runner_.get(), FROM_HERE,
3072 base::Bind(&Demuxer::GetMemoryUsage, base::Unretained(demuxer_.get())),
3073 base::Bind(&WebMediaPlayerImpl::FinishMemoryUsageReport, AsWeakPtr()));
3074 } else {
3075 FinishMemoryUsageReport(0);
3076 }
3077}
3078
3079void WebMediaPlayerImpl::FinishMemoryUsageReport(int64_t demuxer_memory_usage) {
3080 DCHECK(main_task_runner_->BelongsToCurrentThread());
3081
avayvodc4bfb0e62017-01-13 01:07:013082 const PipelineStatistics stats = GetPipelineStatistics();
servolk639473e492016-12-15 04:14:203083 const int64_t data_source_memory_usage =
3084 data_source_ ? data_source_->GetMemoryUsage() : 0;
dalecurtisecc76612017-04-19 00:31:203085
Dale Curtisc2c5dcb12018-04-16 23:21:293086 // If we have video and no video memory usage and we've rendered the first
3087 // frame, assume the VideoFrameCompositor is holding onto the last frame after
3088 // we've suspended the pipeline; which thus reports zero memory usage from the
3089 // video renderer.
dalecurtisecc76612017-04-19 00:31:203090 //
3091 // Technically this should use the coded size, but that requires us to hop to
3092 // the compositor to get and byte-perfect accuracy isn't important here.
3093 const int64_t video_memory_usage =
3094 stats.video_memory_usage +
Dale Curtisc2c5dcb12018-04-16 23:21:293095 ((pipeline_metadata_.has_video && !stats.video_memory_usage &&
3096 has_first_frame_)
Miguel Casas9e7766022018-01-08 16:13:133097 ? VideoFrame::AllocationSize(PIXEL_FORMAT_I420,
dalecurtisecc76612017-04-19 00:31:203098 pipeline_metadata_.natural_size)
3099 : 0);
3100
dalecurtis83266c72015-10-29 18:43:203101 const int64_t current_memory_usage =
dalecurtisecc76612017-04-19 00:31:203102 stats.audio_memory_usage + video_memory_usage + data_source_memory_usage +
3103 demuxer_memory_usage;
dalecurtis83266c72015-10-29 18:43:203104
dalecurtisecc76612017-04-19 00:31:203105 DVLOG(2) << "Memory Usage -- Total: " << current_memory_usage
3106 << " Audio: " << stats.audio_memory_usage
3107 << ", Video: " << video_memory_usage
servolk639473e492016-12-15 04:14:203108 << ", DataSource: " << data_source_memory_usage
wdzierzanowskifd4cd91c52015-12-02 23:50:203109 << ", Demuxer: " << demuxer_memory_usage;
dalecurtis83266c72015-10-29 18:43:203110
3111 const int64_t delta = current_memory_usage - last_reported_memory_usage_;
3112 last_reported_memory_usage_ = current_memory_usage;
3113 adjust_allocated_memory_cb_.Run(delta);
servolk639473e492016-12-15 04:14:203114
Blink Reformat1c4d759e2017-04-09 16:34:543115 if (HasAudio()) {
servolk639473e492016-12-15 04:14:203116 UMA_HISTOGRAM_MEMORY_KB("Media.WebMediaPlayerImpl.Memory.Audio",
3117 stats.audio_memory_usage / 1024);
3118 }
Blink Reformat1c4d759e2017-04-09 16:34:543119 if (HasVideo()) {
servolk639473e492016-12-15 04:14:203120 UMA_HISTOGRAM_MEMORY_KB("Media.WebMediaPlayerImpl.Memory.Video",
dalecurtisecc76612017-04-19 00:31:203121 video_memory_usage / 1024);
servolk639473e492016-12-15 04:14:203122 }
3123 if (data_source_) {
3124 UMA_HISTOGRAM_MEMORY_KB("Media.WebMediaPlayerImpl.Memory.DataSource",
3125 data_source_memory_usage / 1024);
3126 }
3127 if (demuxer_) {
3128 UMA_HISTOGRAM_MEMORY_KB("Media.WebMediaPlayerImpl.Memory.Demuxer",
3129 demuxer_memory_usage / 1024);
3130 }
dalecurtis83266c72015-10-29 18:43:203131}
3132
dalecurtis8b8505e72016-06-10 21:59:173133void WebMediaPlayerImpl::ScheduleIdlePauseTimer() {
avayvod65fad272017-02-24 01:00:483134 // Only schedule the pause timer if we're not paused or paused but going to
avayvod52efd282017-03-07 21:13:043135 // resume when foregrounded, and are suspended and have audio.
3136 if ((paused_ && !paused_when_hidden_) ||
Blink Reformat1c4d759e2017-04-09 16:34:543137 !pipeline_controller_.IsSuspended() || !HasAudio()) {
dalecurtis8b8505e72016-06-10 21:59:173138 return;
avayvod52efd282017-03-07 21:13:043139 }
dalecurtis8b8505e72016-06-10 21:59:173140
3141#if defined(OS_ANDROID)
3142 // Remote players will be suspended and locally paused.
Blink Reformat1c4d759e2017-04-09 16:34:543143 if (IsRemote())
dalecurtis8b8505e72016-06-10 21:59:173144 return;
3145#endif
3146
3147 // Idle timeout chosen arbitrarily.
3148 background_pause_timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(5),
3149 this, &WebMediaPlayerImpl::OnPause);
3150}
3151
dalecurtis04bdb582016-08-17 22:15:233152void WebMediaPlayerImpl::CreateWatchTimeReporter() {
wdzierzanowskia78fa9b2017-06-13 18:12:103153 if (!HasVideo() && !HasAudio())
3154 return;
3155
dalecurtis04bdb582016-08-17 22:15:233156 // Create the watch time reporter and synchronize its initial state.
Dale Curtis1adbe6a2017-08-02 02:09:133157 watch_time_reporter_.reset(new WatchTimeReporter(
Dale Curtis96d6e9382018-07-18 18:01:073158 mojom::PlaybackProperties::New(pipeline_metadata_.has_audio,
3159 pipeline_metadata_.has_video, false, false,
3160 !!chunk_demuxer_, is_encrypted_,
3161 embedded_media_experience_enabled_),
3162 pipeline_metadata_.natural_size,
Dale Curtis051fdf62017-08-05 00:21:133163 base::BindRepeating(&WebMediaPlayerImpl::GetCurrentTimeInternal,
3164 base::Unretained(this)),
Hajime Hoshi8bb37dc2017-12-19 09:35:103165 media_metrics_provider_.get(),
Hajime Hoshib5a26ee2018-05-14 12:47:513166 frame_->GetTaskRunner(blink::TaskType::kInternalMedia)));
dalecurtis04bdb582016-08-17 22:15:233167 watch_time_reporter_->OnVolumeChange(volume_);
Dale Curtisaebaeea2018-07-19 23:42:113168 watch_time_reporter_->OnDurationChanged(GetPipelineMediaDuration());
Mounir Lamourif9af74e72017-06-19 19:31:453169
tguilbert1bb1c782017-01-23 21:15:113170 if (delegate_->IsFrameHidden())
dalecurtis04bdb582016-08-17 22:15:233171 watch_time_reporter_->OnHidden();
3172 else
3173 watch_time_reporter_->OnShown();
Mounir Lamourif9af74e72017-06-19 19:31:453174
Mounir Lamouri41a79c62017-06-06 12:53:163175 if (client_->HasNativeControls())
3176 watch_time_reporter_->OnNativeControlsEnabled();
3177 else
3178 watch_time_reporter_->OnNativeControlsDisabled();
Mounir Lamourif9af74e72017-06-19 19:31:453179
3180 switch (client_->DisplayType()) {
3181 case WebMediaPlayer::DisplayType::kInline:
3182 watch_time_reporter_->OnDisplayTypeInline();
3183 break;
3184 case WebMediaPlayer::DisplayType::kFullscreen:
3185 watch_time_reporter_->OnDisplayTypeFullscreen();
3186 break;
3187 case WebMediaPlayer::DisplayType::kPictureInPicture:
3188 watch_time_reporter_->OnDisplayTypePictureInPicture();
3189 break;
3190 }
Dale Curtis96d6e9382018-07-18 18:01:073191
3192 UpdateSecondaryProperties();
Dale Curtis7fd27c4b2018-07-30 22:14:213193
3194 // If the WatchTimeReporter was recreated in the middle of playback, we want
3195 // to resume playback here too since we won't get another play() call. When
3196 // seeking, the seek completion will restart it if necessary.
3197 if (!paused_ && !seeking_)
3198 watch_time_reporter_->OnPlaying();
Dale Curtis96d6e9382018-07-18 18:01:073199}
3200
3201void WebMediaPlayerImpl::UpdateSecondaryProperties() {
3202 watch_time_reporter_->UpdateSecondaryProperties(
3203 mojom::SecondaryPlaybackProperties::New(
3204 pipeline_metadata_.audio_decoder_config.codec(),
3205 pipeline_metadata_.video_decoder_config.codec(), audio_decoder_name_,
John Rummelld30555352018-09-21 20:47:253206 video_decoder_name_,
3207 DetermineEncryptionMode(
3208 pipeline_metadata_.audio_decoder_config.encryption_scheme()),
3209 DetermineEncryptionMode(
3210 pipeline_metadata_.video_decoder_config.encryption_scheme()),
3211 pipeline_metadata_.natural_size));
dalecurtis04bdb582016-08-17 22:15:233212}
3213
avayvod39c102402016-11-23 21:43:133214bool WebMediaPlayerImpl::IsHidden() const {
3215 DCHECK(main_task_runner_->BelongsToCurrentThread());
3216
tguilbert1bb1c782017-01-23 21:15:113217 return delegate_->IsFrameHidden() && !delegate_->IsFrameClosed();
avayvod39c102402016-11-23 21:43:133218}
3219
avayvod102cdb62017-01-07 03:11:093220bool WebMediaPlayerImpl::IsStreaming() const {
3221 return data_source_ && data_source_->IsStreaming();
3222}
3223
liberato2fd111be2017-01-04 00:25:063224bool WebMediaPlayerImpl::DoesOverlaySupportMetadata() const {
Julien Isorce6c83d8de2017-10-12 13:11:293225 return pipeline_metadata_.video_decoder_config.video_rotation() ==
3226 VIDEO_ROTATION_0;
liberato2fd111be2017-01-04 00:25:063227}
3228
xjzaf29d4182016-12-16 01:52:323229void WebMediaPlayerImpl::ActivateViewportIntersectionMonitoring(bool activate) {
3230 DCHECK(main_task_runner_->BelongsToCurrentThread());
3231
Blink Reformat1c4d759e2017-04-09 16:34:543232 client_->ActivateViewportIntersectionMonitoring(activate);
xjzaf29d4182016-12-16 01:52:323233}
3234
Anton Vayvod09fa66e2017-07-20 23:02:123235void WebMediaPlayerImpl::UpdateRemotePlaybackCompatibility(bool is_compatible) {
3236 DCHECK(main_task_runner_->BelongsToCurrentThread());
3237
3238 client_->RemotePlaybackCompatibilityChanged(loaded_url_, is_compatible);
3239}
3240
Dale Curtis6438cf12018-03-29 02:34:013241void WebMediaPlayerImpl::ForceStaleStateForTesting(ReadyState target_state) {
3242 stale_state_override_for_testing_.emplace(target_state);
Dale Curtis99a9b482018-02-01 02:23:283243 UpdatePlayState();
3244}
3245
3246bool WebMediaPlayerImpl::IsSuspendedForTesting() {
3247 // This intentionally uses IsPipelineSuspended since we need to know when the
3248 // pipeline has reached the suspended state, not when it's in suspending.
3249 return pipeline_controller_.IsPipelineSuspended();
3250}
3251
Dale Curtis7c63f2e22018-09-19 21:06:273252bool WebMediaPlayerImpl::DidLazyLoad() const {
3253 return did_lazy_load_;
3254}
3255
3256void WebMediaPlayerImpl::OnBecameVisible() {
3257 needs_first_frame_ = !has_first_frame_;
3258 UpdatePlayState();
3259}
3260
Miguel Casasfb63a5792018-12-04 23:50:413261bool WebMediaPlayerImpl::IsOpaque() const {
3262 return opaque_;
3263}
3264
avayvodcc273dd2017-01-19 19:35:123265bool WebMediaPlayerImpl::ShouldPauseVideoWhenHidden() const {
Junbo Kefba620b2019-01-16 02:54:363266 if (!is_background_video_playback_enabled_)
3267 return true;
3268
avayvod65fad272017-02-24 01:00:483269 // If suspending background video, pause any video that's not remoted or
3270 // not unlocked to play in the background.
Sergey Volk8b09c2c52018-12-12 23:20:403271 if (IsBackgroundSuspendEnabled(this)) {
Blink Reformat1c4d759e2017-04-09 16:34:543272 if (!HasVideo())
avayvod65fad272017-02-24 01:00:483273 return false;
3274
3275#if defined(OS_ANDROID)
Thomas Guilbert29ae1a902018-10-20 01:53:383276 if (IsRemote() || is_flinging_)
avayvod65fad272017-02-24 01:00:483277 return false;
avayvodcc273dd2017-01-19 19:35:123278#endif
avayvodeb9098d2017-01-07 00:33:033279
Blink Reformat1c4d759e2017-04-09 16:34:543280 return !HasAudio() || (IsResumeBackgroundVideosEnabled() &&
3281 video_locked_when_paused_when_hidden_);
avayvod65fad272017-02-24 01:00:483282 }
3283
3284 // Otherwise only pause if the optimization is on and it's a video-only
3285 // optimization candidate.
avayvod01201332017-04-14 00:27:153286 return IsBackgroundVideoPauseOptimizationEnabled() && !HasAudio() &&
Thomas Guilbert29ae1a902018-10-20 01:53:383287 IsBackgroundOptimizationCandidate() && !is_flinging_;
avayvodeb9098d2017-01-07 00:33:033288}
3289
avayvod2135a642017-01-13 00:17:143290bool WebMediaPlayerImpl::ShouldDisableVideoWhenHidden() const {
Ted Meyera918e592018-09-08 00:16:203291 // This optimization is behind the flag on all platforms, only for non-mse
3292 // video. MSE video track switching on hide has gone through a field test.
3293 // TODO(tmathmeyer): Passing load_type_ won't be needed after src= field
3294 // testing is finished. see: http://crbug.com/709302
Sergey Volk8b09c2c52018-12-12 23:20:403295 if (!is_background_video_track_optimization_supported_ ||
3296 !IsBackgroundVideoTrackOptimizationEnabled(load_type_))
avayvodc4bfb0e62017-01-13 01:07:013297 return false;
avayvodc4bfb0e62017-01-13 01:07:013298
avayvodcc273dd2017-01-19 19:35:123299 // Disable video track only for players with audio that match the criteria for
3300 // being optimized.
Blink Reformat1c4d759e2017-04-09 16:34:543301 return HasAudio() && IsBackgroundOptimizationCandidate();
avayvodcc273dd2017-01-19 19:35:123302}
3303
3304bool WebMediaPlayerImpl::IsBackgroundOptimizationCandidate() const {
3305 DCHECK(main_task_runner_->BelongsToCurrentThread());
3306
François Beaufort664c3ca72018-04-13 07:24:513307 // Don't optimize Picture-in-Picture players.
Mounir Lamouri0484f40a2018-07-25 03:03:263308 if (IsInPictureInPicture())
François Beaufort664c3ca72018-04-13 07:24:513309 return false;
3310
avayvodcc273dd2017-01-19 19:35:123311#if defined(OS_ANDROID) // WMPI_CAST
avayvodac1a8522017-01-20 19:02:503312 // Don't optimize players being Cast.
Blink Reformat1c4d759e2017-04-09 16:34:543313 if (IsRemote())
avayvodcc273dd2017-01-19 19:35:123314 return false;
3315#endif // defined(OS_ANDROID)
3316
3317 // Don't optimize audio-only or streaming players.
Blink Reformat1c4d759e2017-04-09 16:34:543318 if (!HasVideo() || IsStreaming())
avayvodcc273dd2017-01-19 19:35:123319 return false;
3320
Dale Curtis3f4935b2017-09-09 00:11:593321 // Video-only players are always optimized (paused).
3322 // Don't check the keyframe distance and duration.
3323 if (!HasAudio() && HasVideo())
3324 return true;
3325
avayvodcc273dd2017-01-19 19:35:123326 // Videos shorter than the maximum allowed keyframe distance can be optimized.
3327 base::TimeDelta duration = GetPipelineMediaDuration();
Ted Meyera918e592018-09-08 00:16:203328
Dale Curtis456808a2018-10-23 17:50:213329 constexpr base::TimeDelta kMaxKeyframeDistanceToDisableBackgroundVideo =
3330 base::TimeDelta::FromMilliseconds(
3331 kMaxKeyframeDistanceToDisableBackgroundVideoMs);
3332 if (duration < kMaxKeyframeDistanceToDisableBackgroundVideo)
avayvodcc273dd2017-01-19 19:35:123333 return true;
3334
3335 // Otherwise, only optimize videos with shorter average keyframe distance.
avayvodc4bfb0e62017-01-13 01:07:013336 PipelineStatistics stats = GetPipelineStatistics();
Dale Curtis456808a2018-10-23 17:50:213337 return stats.video_keyframe_distance_average <
3338 kMaxKeyframeDistanceToDisableBackgroundVideo;
avayvod2135a642017-01-13 00:17:143339}
3340
avayvod56e1f3942017-01-21 02:06:313341void WebMediaPlayerImpl::UpdateBackgroundVideoOptimizationState() {
3342 if (IsHidden()) {
Dale Curtisa75a7892017-08-09 20:21:513343 if (ShouldPauseVideoWhenHidden()) {
avayvod56e1f3942017-01-21 02:06:313344 PauseVideoIfNeeded();
Dale Curtisa75a7892017-08-09 20:21:513345 } else if (update_background_status_cb_.IsCancelled()) {
3346 // Only trigger updates when we don't have one already scheduled.
3347 update_background_status_cb_.Reset(
3348 base::Bind(&WebMediaPlayerImpl::DisableVideoTrackIfNeeded,
3349 base::Unretained(this)));
3350
3351 // Defer disable track until we're sure the clip will be backgrounded for
3352 // some time. Resuming may take half a second, so frequent tab switches
3353 // will yield a poor user experience otherwise. http://crbug.com/709302
3354 // may also cause AV sync issues if disable/enable happens too fast.
3355 main_task_runner_->PostDelayedTask(
3356 FROM_HERE, update_background_status_cb_.callback(),
3357 base::TimeDelta::FromSeconds(10));
3358 }
avayvod56e1f3942017-01-21 02:06:313359 } else {
Dale Curtisa75a7892017-08-09 20:21:513360 update_background_status_cb_.Cancel();
avayvod56e1f3942017-01-21 02:06:313361 EnableVideoTrackIfNeeded();
3362 }
3363}
3364
3365void WebMediaPlayerImpl::PauseVideoIfNeeded() {
3366 DCHECK(IsHidden());
3367
3368 // Don't pause video while the pipeline is stopped, resuming or seeking.
3369 // Also if the video is paused already.
tguilbert350936ff2017-02-24 05:39:273370 if (!pipeline_controller_.IsPipelineRunning() || is_pipeline_resuming_ ||
3371 seeking_ || paused_)
avayvod56e1f3942017-01-21 02:06:313372 return;
3373
3374 // OnPause() will set |paused_when_hidden_| to false and call
3375 // UpdatePlayState(), so set the flag to true after and then return.
3376 OnPause();
3377 paused_when_hidden_ = true;
3378}
3379
avayvod2135a642017-01-13 00:17:143380void WebMediaPlayerImpl::EnableVideoTrackIfNeeded() {
avayvod56e1f3942017-01-21 02:06:313381 // Don't change video track while the pipeline is stopped, resuming or
3382 // seeking.
tguilbert350936ff2017-02-24 05:39:273383 if (!pipeline_controller_.IsPipelineRunning() || is_pipeline_resuming_ ||
3384 seeking_)
avayvod2135a642017-01-13 00:17:143385 return;
3386
3387 if (video_track_disabled_) {
3388 video_track_disabled_ = false;
Blink Reformat1c4d759e2017-04-09 16:34:543389 if (client_->HasSelectedVideoTrack()) {
3390 WebMediaPlayer::TrackId trackId = client_->GetSelectedVideoTrackId();
3391 SelectedVideoTrackChanged(&trackId);
avayvod2135a642017-01-13 00:17:143392 }
3393 }
3394}
3395
3396void WebMediaPlayerImpl::DisableVideoTrackIfNeeded() {
3397 DCHECK(IsHidden());
3398
3399 // Don't change video track while the pipeline is resuming or seeking.
3400 if (is_pipeline_resuming_ || seeking_)
3401 return;
3402
3403 if (!video_track_disabled_ && ShouldDisableVideoWhenHidden()) {
3404 video_track_disabled_ = true;
Blink Reformat1c4d759e2017-04-09 16:34:543405 SelectedVideoTrackChanged(nullptr);
avayvod2135a642017-01-13 00:17:143406 }
3407}
3408
avayvodc4bfb0e62017-01-13 01:07:013409void WebMediaPlayerImpl::SetPipelineStatisticsForTest(
3410 const PipelineStatistics& stats) {
3411 pipeline_statistics_for_test_ = base::make_optional(stats);
3412}
3413
3414PipelineStatistics WebMediaPlayerImpl::GetPipelineStatistics() const {
3415 DCHECK(main_task_runner_->BelongsToCurrentThread());
3416
tguilbert350936ff2017-02-24 05:39:273417 return pipeline_statistics_for_test_.value_or(
3418 pipeline_controller_.GetStatistics());
avayvodc4bfb0e62017-01-13 01:07:013419}
3420
avayvodcc273dd2017-01-19 19:35:123421void WebMediaPlayerImpl::SetPipelineMediaDurationForTest(
3422 base::TimeDelta duration) {
3423 pipeline_media_duration_for_test_ = base::make_optional(duration);
3424}
3425
3426base::TimeDelta WebMediaPlayerImpl::GetPipelineMediaDuration() const {
3427 DCHECK(main_task_runner_->BelongsToCurrentThread());
3428
3429 return pipeline_media_duration_for_test_.value_or(
tguilbert350936ff2017-02-24 05:39:273430 pipeline_controller_.GetMediaDuration());
avayvodcc273dd2017-01-19 19:35:123431}
3432
3433void WebMediaPlayerImpl::ReportTimeFromForegroundToFirstFrame(
3434 base::TimeTicks foreground_time,
3435 base::TimeTicks new_frame_time) {
3436 base::TimeDelta time_to_first_frame = new_frame_time - foreground_time;
Blink Reformat1c4d759e2017-04-09 16:34:543437 if (HasAudio()) {
avayvodcc273dd2017-01-19 19:35:123438 UMA_HISTOGRAM_TIMES(
3439 "Media.Video.TimeFromForegroundToFirstFrame.DisableTrack",
3440 time_to_first_frame);
3441 } else {
3442 UMA_HISTOGRAM_TIMES("Media.Video.TimeFromForegroundToFirstFrame.Paused",
3443 time_to_first_frame);
3444 }
3445}
Xiangjun Zhangba8724f482017-08-03 06:43:253446
3447void WebMediaPlayerImpl::SwitchToRemoteRenderer(
3448 const std::string& remote_device_friendly_name) {
xjz4e5d4bf32017-02-15 21:26:353449 DCHECK(main_task_runner_->BelongsToCurrentThread());
Thomas Guilbertb341bae02018-05-09 00:02:133450 DCHECK(!disable_pipeline_auto_suspend_);
Xiangjun Zhangba8724f482017-08-03 06:43:253451 disable_pipeline_auto_suspend_ = true;
Chris Cunninghamd9df58e2017-08-29 00:04:233452
3453 // Capabilities reporting should only be performed for local playbacks.
3454 video_decode_stats_reporter_.reset();
3455
Xiangjun Zhangba8724f482017-08-03 06:43:253456 // Requests to restart media pipeline. A remote renderer will be created via
3457 // the |renderer_factory_selector_|.
xjz4e5d4bf32017-02-15 21:26:353458 ScheduleRestart();
xjzdf9b67e2017-04-13 23:28:253459 if (client_) {
Xiangjun Zhangba8724f482017-08-03 06:43:253460 client_->MediaRemotingStarted(
3461 WebString::FromUTF8(remote_device_friendly_name));
xjzdf9b67e2017-04-13 23:28:253462 }
xjz4e5d4bf32017-02-15 21:26:353463}
3464
Xiangjun Zhang5e20cba42018-01-10 19:54:563465void WebMediaPlayerImpl::SwitchToLocalRenderer(
3466 MediaObserverClient::ReasonToSwitchToLocal reason) {
Xiangjun Zhangba8724f482017-08-03 06:43:253467 DCHECK(main_task_runner_->BelongsToCurrentThread());
Xiangjun Zhang12f55272018-07-30 23:19:373468 if (!disable_pipeline_auto_suspend_)
3469 return; // Is currently with local renderer.
Xiangjun Zhangba8724f482017-08-03 06:43:253470 disable_pipeline_auto_suspend_ = false;
Chris Cunninghamd9df58e2017-08-29 00:04:233471
3472 // Capabilities reporting may resume now that playback is local.
3473 CreateVideoDecodeStatsReporter();
3474
Xiangjun Zhangba8724f482017-08-03 06:43:253475 // Requests to restart media pipeline. A local renderer will be created via
3476 // the |renderer_factory_selector_|.
3477 ScheduleRestart();
3478 if (client_)
Xiangjun Zhang5e20cba42018-01-10 19:54:563479 client_->MediaRemotingStopped(GetSwitchToLocalMessage(reason));
Xiangjun Zhangba8724f482017-08-03 06:43:253480}
3481
dalecurtis4f6d14d2017-02-22 17:42:223482void WebMediaPlayerImpl::RecordUnderflowDuration(base::TimeDelta duration) {
3483 DCHECK(data_source_ || chunk_demuxer_);
xhwang68b3fab82017-05-17 21:31:463484
dalecurtis4f6d14d2017-02-22 17:42:223485 if (data_source_)
Jennifer Apacible82e25c92017-08-07 18:15:273486 UMA_HISTOGRAM_TIMES("Media.UnderflowDuration2.SRC", duration);
dalecurtis4f6d14d2017-02-22 17:42:223487 else
Jennifer Apacible82e25c92017-08-07 18:15:273488 UMA_HISTOGRAM_TIMES("Media.UnderflowDuration2.MSE", duration);
xhwang68b3fab82017-05-17 21:31:463489
3490 if (is_encrypted_)
Jennifer Apacible82e25c92017-08-07 18:15:273491 UMA_HISTOGRAM_TIMES("Media.UnderflowDuration2.EME", duration);
dalecurtis4f6d14d2017-02-22 17:42:223492}
3493
xhwang60802652017-04-19 07:29:583494#define UMA_HISTOGRAM_VIDEO_HEIGHT(name, sample) \
3495 UMA_HISTOGRAM_CUSTOM_COUNTS(name, sample, 100, 10000, 50)
3496
3497void WebMediaPlayerImpl::RecordVideoNaturalSize(const gfx::Size& natural_size) {
3498 // Always report video natural size to MediaLog.
3499 media_log_->AddEvent(media_log_->CreateVideoSizeSetEvent(
3500 natural_size.width(), natural_size.height()));
3501
3502 if (initial_video_height_recorded_)
3503 return;
3504
3505 initial_video_height_recorded_ = true;
3506
3507 int height = natural_size.height();
3508
3509 if (load_type_ == kLoadTypeURL)
3510 UMA_HISTOGRAM_VIDEO_HEIGHT("Media.VideoHeight.Initial.SRC", height);
3511 else if (load_type_ == kLoadTypeMediaSource)
3512 UMA_HISTOGRAM_VIDEO_HEIGHT("Media.VideoHeight.Initial.MSE", height);
3513
3514 if (is_encrypted_)
3515 UMA_HISTOGRAM_VIDEO_HEIGHT("Media.VideoHeight.Initial.EME", height);
3516
3517 UMA_HISTOGRAM_VIDEO_HEIGHT("Media.VideoHeight.Initial.All", height);
3518}
3519
3520#undef UMA_HISTOGRAM_VIDEO_HEIGHT
3521
Greg Thompsonaa48ce8d2018-04-03 06:11:433522void WebMediaPlayerImpl::SetTickClockForTest(
3523 const base::TickClock* tick_clock) {
tzik2c963b872017-12-07 06:57:243524 tick_clock_ = tick_clock;
hubbeb2d3efd2017-05-05 23:26:383525 buffered_data_source_host_.SetTickClockForTest(tick_clock);
3526}
3527
Dale Curtis3899090ea2018-01-12 00:10:353528void WebMediaPlayerImpl::OnFirstFrame(base::TimeTicks frame_time) {
3529 DCHECK(!load_start_time_.is_null());
Dale Curtisff576552018-03-30 02:32:443530 DCHECK(!skip_metrics_due_to_startup_suspend_);
Dale Curtisc2c5dcb12018-04-16 23:21:293531 has_first_frame_ = true;
Dale Curtis7c63f2e22018-09-19 21:06:273532 needs_first_frame_ = false;
Dale Curtis3899090ea2018-01-12 00:10:353533 const base::TimeDelta elapsed = frame_time - load_start_time_;
3534 media_metrics_provider_->SetTimeToFirstFrame(elapsed);
3535 RecordTimingUMA("Media.TimeToFirstFrame", elapsed);
3536}
3537
3538void WebMediaPlayerImpl::RecordTimingUMA(const std::string& key,
3539 base::TimeDelta elapsed) {
3540 if (chunk_demuxer_)
3541 base::UmaHistogramMediumTimes(key + ".MSE", elapsed);
3542 else
3543 base::UmaHistogramMediumTimes(key + ".SRC", elapsed);
3544 if (is_encrypted_)
3545 base::UmaHistogramMediumTimes(key + ".EME", elapsed);
3546}
3547
John Rummelldb5a7ef2018-05-16 00:28:013548void WebMediaPlayerImpl::RecordEncryptionScheme(
3549 const std::string& stream_name,
3550 const EncryptionScheme& encryption_scheme) {
3551 DCHECK(stream_name == "Audio" || stream_name == "Video");
3552
3553 // If the stream is not encrypted, don't record it.
3554 if (encryption_scheme.mode() == EncryptionScheme::CIPHER_MODE_UNENCRYPTED)
3555 return;
3556
3557 base::UmaHistogramEnumeration(
3558 "Media.EME.EncryptionScheme.Initial." + stream_name,
3559 DetermineEncryptionSchemeUMAValue(encryption_scheme),
3560 EncryptionSchemeUMA::kCount);
3561}
3562
Mounir Lamouri0484f40a2018-07-25 03:03:263563bool WebMediaPlayerImpl::IsInPictureInPicture() const {
3564 DCHECK(client_);
3565 return client_->DisplayType() ==
3566 WebMediaPlayer::DisplayType::kPictureInPicture;
3567}
3568
François Beaufortbb68c43e2018-11-20 20:12:033569bool WebMediaPlayerImpl::ShouldShowPlayPauseButtonInPictureInPictureWindow()
3570 const {
3571 return Duration() != std::numeric_limits<double>::infinity();
3572}
3573
Dale Curtis5bba03232018-08-30 17:57:383574void WebMediaPlayerImpl::MaybeSetContainerName() {
Dale Curtisf01c8262018-09-04 23:50:433575 // MSE nor MediaPlayerRenderer provide container information.
3576 if (chunk_demuxer_ || using_media_player_renderer_)
Dale Curtis5bba03232018-08-30 17:57:383577 return;
3578
3579 // Pipeline startup failed before even getting a demuxer setup.
3580 if (!demuxer_)
3581 return;
3582
3583 // Container has already been set.
3584 if (highest_ready_state_ >= WebMediaPlayer::kReadyStateHaveMetadata)
3585 return;
3586
3587// If ffmpeg isn't enabled, we can't get the container name.
3588#if BUILDFLAG(ENABLE_FFMPEG)
3589 media_metrics_provider_->SetContainerName(
3590 static_cast<FFmpegDemuxer*>(demuxer_.get())->container());
3591#endif
3592}
3593
acolwell9e0840d2014-09-06 19:01:323594} // namespace media