blob: f9fd104843832ce043527c171f19be81ade4ba8e [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"
xhwang97de4202014-11-25 08:44:0149#include "media/blink/webcontentdecryptionmodule_impl.h"
acolwell9e0840d2014-09-06 19:01:3250#include "media/blink/webinbandtexttrack_impl.h"
acolwell9e0840d2014-09-06 19:01:3251#include "media/blink/webmediasource_impl.h"
[email protected]efe7cd22012-09-12 23:55:0152#include "media/filters/chunk_demuxer.h"
[email protected]ddbc6ff2013-04-19 15:28:3353#include "media/filters/ffmpeg_demuxer.h"
Dale Curtis4841c712018-12-13 18:14:0554#include "media/filters/memory_data_source.h"
Scott Violeta35f9a42018-03-22 22:00:4455#include "media/media_buildflags.h"
Dale Curtis4841c712018-12-13 18:14:0556#include "net/base/data_url.h"
Blink Reformata30d4232018-04-07 15:31:0657#include "third_party/blink/public/platform/web_encrypted_media_types.h"
58#include "third_party/blink/public/platform/web_localized_string.h"
59#include "third_party/blink/public/platform/web_media_player_client.h"
60#include "third_party/blink/public/platform/web_media_player_encrypted_media_client.h"
61#include "third_party/blink/public/platform/web_media_player_source.h"
62#include "third_party/blink/public/platform/web_media_source.h"
63#include "third_party/blink/public/platform/web_rect.h"
64#include "third_party/blink/public/platform/web_runtime_features.h"
65#include "third_party/blink/public/platform/web_security_origin.h"
66#include "third_party/blink/public/platform/web_size.h"
67#include "third_party/blink/public/platform/web_string.h"
68#include "third_party/blink/public/platform/web_surface_layer_bridge.h"
69#include "third_party/blink/public/platform/web_url.h"
Antonio Gomes3a858b52019-05-31 02:47:5270#include "third_party/blink/public/platform/webaudiosourceprovider_impl.h"
Antonio Gomesf01cfbd2019-07-12 08:53:1171#include "third_party/blink/public/web/modules/media/webmediaplayer_util.h"
Blink Reformata30d4232018-04-07 15:31:0672#include "third_party/blink/public/web/web_document.h"
73#include "third_party/blink/public/web/web_frame.h"
74#include "third_party/blink/public/web/web_local_frame.h"
75#include "third_party/blink/public/web/web_user_gesture_indicator.h"
76#include "third_party/blink/public/web/web_view.h"
[email protected]b3f2b912009-04-09 16:18:5277
dalecurtisea27a3ed2016-06-24 01:41:3078#if defined(OS_ANDROID)
79#include "media/base/android/media_codec_util.h"
80#endif
81
[email protected]180ef242013-11-07 06:50:4682using blink::WebMediaPlayer;
83using blink::WebRect;
84using blink::WebSize;
85using blink::WebString;
hubbed5f36882016-01-15 22:40:3786using gpu::gles2::GLES2Interface;
87
danakj365175c2016-02-06 00:37:3788#define STATIC_ASSERT_ENUM(a, b) \
89 static_assert(static_cast<int>(a) == static_cast<int>(b), \
90 "mismatching enums: " #a)
91
hubbed5f36882016-01-15 22:40:3792namespace media {
[email protected]ec9212f2008-12-18 21:40:3693
[email protected]8931c41a2009-07-07 17:31:4994namespace {
95
Antonio Gomes3a858b52019-05-31 02:47:5296void SetSinkIdOnMediaThread(
97 scoped_refptr<blink::WebAudioSourceProviderImpl> sink,
98 const std::string& device_id,
99 OutputDeviceStatusCB callback) {
Daniel Chengc1710b52018-10-24 03:12:28100 sink->SwitchOutputDevice(device_id, std::move(callback));
guidouc7babef2015-10-22 00:42:35101}
102
Sergey Volk8b09c2c52018-12-12 23:20:40103bool IsBackgroundSuspendEnabled(const WebMediaPlayerImpl* wmpi) {
Luke Halliwell7a8a8982018-07-25 01:07:05104 // TODO(crbug.com/867146): remove these switches.
105 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
106 switches::kDisableMediaSuspend))
107 return false;
108 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
109 switches::kEnableMediaSuspend))
110 return true;
111
Sergey Volk8b09c2c52018-12-12 23:20:40112 return wmpi->IsBackgroundMediaSuspendEnabled();
dalecurtis0431cbf2016-03-12 01:19:43113}
114
avayvod48a8be52016-08-04 19:52:50115bool IsResumeBackgroundVideosEnabled() {
116 return base::FeatureList::IsEnabled(kResumeBackgroundVideo);
117}
118
avayvod01201332017-04-14 00:27:15119bool IsBackgroundVideoPauseOptimizationEnabled() {
120 return base::FeatureList::IsEnabled(kBackgroundVideoPauseOptimization);
121}
122
sandersd50a635e2016-04-04 22:50:09123bool IsNetworkStateError(blink::WebMediaPlayer::NetworkState state) {
Blink Reformat1c4d759e2017-04-09 16:34:54124 bool result = state == blink::WebMediaPlayer::kNetworkStateFormatError ||
125 state == blink::WebMediaPlayer::kNetworkStateNetworkError ||
126 state == blink::WebMediaPlayer::kNetworkStateDecodeError;
127 DCHECK_EQ(state > blink::WebMediaPlayer::kNetworkStateLoaded, result);
sandersd50a635e2016-04-04 22:50:09128 return result;
129}
130
sandersd2c478422016-08-02 01:19:25131gfx::Size GetRotatedVideoSize(VideoRotation rotation, gfx::Size natural_size) {
132 if (rotation == VIDEO_ROTATION_90 || rotation == VIDEO_ROTATION_270)
133 return gfx::Size(natural_size.height(), natural_size.width());
134 return natural_size;
135}
136
Xiaohan Wangf63505d2017-10-21 08:00:53137void RecordEncryptedEvent(bool encrypted_event_fired) {
138 UMA_HISTOGRAM_BOOLEAN("Media.EME.EncryptedEvent", encrypted_event_fired);
139}
140
sandersd35d2c3f2017-01-14 02:04:42141// How much time must have elapsed since loading last progressed before we
142// assume that the decoder will have had time to complete preroll.
143constexpr base::TimeDelta kPrerollAttemptTimeout =
watkd026f792016-11-05 00:28:51144 base::TimeDelta::FromSeconds(3);
145
Matt Wolenetz6010f6c2017-10-18 00:44:36146// Maximum number, per-WMPI, of media logs of playback rate changes.
147constexpr int kMaxNumPlaybackRateLogs = 10;
148
Xiangjun Zhang5e20cba42018-01-10 19:54:56149blink::WebLocalizedString::Name GetSwitchToLocalMessage(
150 MediaObserverClient::ReasonToSwitchToLocal reason) {
151 switch (reason) {
152 case MediaObserverClient::ReasonToSwitchToLocal::NORMAL:
153 return blink::WebLocalizedString::kMediaRemotingStopText;
154 case MediaObserverClient::ReasonToSwitchToLocal::POOR_PLAYBACK_QUALITY:
155 return blink::WebLocalizedString::kMediaRemotingStopByPlaybackQualityText;
156 case MediaObserverClient::ReasonToSwitchToLocal::PIPELINE_ERROR:
157 return blink::WebLocalizedString::kMediaRemotingStopByErrorText;
158 case MediaObserverClient::ReasonToSwitchToLocal::ROUTE_TERMINATED:
159 return blink::WebLocalizedString::kMediaRemotingStopNoText;
160 }
161 NOTREACHED();
162 // To suppress compiler warning on Windows.
163 return blink::WebLocalizedString::kMediaRemotingStopNoText;
164}
165
John Rummelldb5a7ef2018-05-16 00:28:01166// These values are persisted to UMA. Entries should not be renumbered and
167// numeric values should never be reused.
168// TODO(crbug.com/825041): This should use EncryptionMode when kUnencrypted
169// removed.
170enum class EncryptionSchemeUMA { kCenc = 0, kCbcs = 1, kCount };
171
172EncryptionSchemeUMA DetermineEncryptionSchemeUMAValue(
173 const EncryptionScheme& encryption_scheme) {
174 if (encryption_scheme.mode() == EncryptionScheme::CIPHER_MODE_AES_CBC)
175 return EncryptionSchemeUMA::kCbcs;
176
177 DCHECK_EQ(encryption_scheme.mode(), EncryptionScheme::CIPHER_MODE_AES_CTR);
178 return EncryptionSchemeUMA::kCenc;
179}
180
John Rummelld30555352018-09-21 20:47:25181EncryptionMode DetermineEncryptionMode(
182 const EncryptionScheme& encryption_scheme) {
183 switch (encryption_scheme.mode()) {
184 case EncryptionScheme::CIPHER_MODE_UNENCRYPTED:
185 return EncryptionMode::kUnencrypted;
186 case EncryptionScheme::CIPHER_MODE_AES_CTR:
187 return EncryptionMode::kCenc;
188 case EncryptionScheme::CIPHER_MODE_AES_CBC:
189 return EncryptionMode::kCbcs;
190 }
191}
192
Pavel Feldman023c3e62018-08-28 17:59:47193#if BUILDFLAG(ENABLE_FFMPEG)
Dale Curtisb8139f72018-08-27 23:28:48194// Returns true if |url| represents (or is likely to) a local file.
195bool IsLocalFile(const GURL& url) {
196 return url.SchemeIsFile() || url.SchemeIsFileSystem() ||
197 url.SchemeIs(url::kContentScheme) ||
198 url.SchemeIs(url::kContentIDScheme) ||
199 url.SchemeIs("chrome-extension");
200}
Pavel Feldman023c3e62018-08-28 17:59:47201#endif
Dale Curtisb8139f72018-08-27 23:28:48202
Dale Curtisf273f8f2018-12-13 23:40:33203// Handles destruction of media::Renderer dependent components after the
204// renderer has been destructed on the media thread.
205void DestructionHelper(
206 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
207 scoped_refptr<base::SingleThreadTaskRunner> vfc_task_runner,
208 std::unique_ptr<Demuxer> demuxer,
209 std::unique_ptr<DataSource> data_source,
210 std::unique_ptr<VideoFrameCompositor> compositor,
211 std::unique_ptr<CdmContextRef> cdm_context_1,
212 std::unique_ptr<CdmContextRef> cdm_context_2,
213 std::unique_ptr<MediaLog> media_log,
214 std::unique_ptr<RendererFactorySelector> renderer_factory_selector,
215 std::unique_ptr<blink::WebSurfaceLayerBridge> bridge,
216 bool is_chunk_demuxer) {
217 // We release |bridge| after pipeline stop to ensure layout tests receive
218 // painted video frames before test harness exit.
219 main_task_runner->DeleteSoon(FROM_HERE, std::move(bridge));
220
221 // Since the media::Renderer is gone we can now destroy the compositor and
222 // renderer factory selector.
223 vfc_task_runner->DeleteSoon(FROM_HERE, std::move(compositor));
224 main_task_runner->DeleteSoon(FROM_HERE, std::move(renderer_factory_selector));
225
226 // ChunkDemuxer can be deleted on any thread, but other demuxers are bound to
227 // the main thread and must be deleted there now that the renderer is gone.
228 if (!is_chunk_demuxer) {
229 main_task_runner->DeleteSoon(FROM_HERE, std::move(demuxer));
230 main_task_runner->DeleteSoon(FROM_HERE, std::move(data_source));
231 main_task_runner->DeleteSoon(FROM_HERE, std::move(cdm_context_1));
232 main_task_runner->DeleteSoon(FROM_HERE, std::move(cdm_context_2));
233 main_task_runner->DeleteSoon(FROM_HERE, std::move(media_log));
234 return;
235 }
236
237 // ChunkDemuxer's streams may contain much buffered, compressed media that
238 // may need to be paged back in during destruction. Paging delay may exceed
239 // the renderer hang monitor's threshold on at least Windows while also
240 // blocking other work on the renderer main thread, so we do the actual
241 // destruction in the background without blocking WMPI destruction or
242 // |task_runner|. On advice of task_scheduler OWNERS, MayBlock() is not
243 // used because virtual memory overhead is not considered blocking I/O; and
244 // CONTINUE_ON_SHUTDOWN is used to allow process termination to not block on
245 // completing the task.
246 base::PostTaskWithTraits(
247 FROM_HERE,
248 {base::TaskPriority::BEST_EFFORT,
249 base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
250 base::BindOnce(
251 [](scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
252 std::unique_ptr<Demuxer> demuxer_to_destroy,
253 std::unique_ptr<CdmContextRef> cdm_context_1,
254 std::unique_ptr<CdmContextRef> cdm_context_2,
255 std::unique_ptr<MediaLog> media_log) {
256 SCOPED_UMA_HISTOGRAM_TIMER("Media.MSE.DemuxerDestructionTime");
257 demuxer_to_destroy.reset();
258 main_task_runner->DeleteSoon(FROM_HERE, std::move(cdm_context_1));
259 main_task_runner->DeleteSoon(FROM_HERE, std::move(cdm_context_2));
260 main_task_runner->DeleteSoon(FROM_HERE, std::move(media_log));
261 },
262 std::move(main_task_runner), std::move(demuxer),
263 std::move(cdm_context_1), std::move(cdm_context_2),
264 std::move(media_log)));
265}
266
[email protected]8931c41a2009-07-07 17:31:49267} // namespace
268
[email protected]6683e1b2014-04-10 01:45:38269class BufferedDataSourceHostImpl;
270
Takashi Toyoshima2e01e692018-11-16 03:23:27271STATIC_ASSERT_ENUM(WebMediaPlayer::kCorsModeUnspecified,
danakj365175c2016-02-06 00:37:37272 UrlData::CORS_UNSPECIFIED);
Takashi Toyoshima2e01e692018-11-16 03:23:27273STATIC_ASSERT_ENUM(WebMediaPlayer::kCorsModeAnonymous, UrlData::CORS_ANONYMOUS);
274STATIC_ASSERT_ENUM(WebMediaPlayer::kCorsModeUseCredentials,
danakj365175c2016-02-06 00:37:37275 UrlData::CORS_USE_CREDENTIALS);
[email protected]a5a01102012-06-06 17:01:24276
[email protected]5b5bb9d2010-10-22 19:57:36277WebMediaPlayerImpl::WebMediaPlayerImpl(
[email protected]35b2a972014-04-04 15:50:22278 blink::WebLocalFrame* frame,
[email protected]180ef242013-11-07 06:50:46279 blink::WebMediaPlayerClient* client,
srirama.m26f864d02015-07-14 05:21:46280 blink::WebMediaPlayerEncryptedMediaClient* encrypted_client,
Antonio Gomes423df612019-07-11 12:40:07281 blink::WebMediaPlayerDelegate* delegate,
tguilbert70d2a00a2017-04-25 00:30:44282 std::unique_ptr<RendererFactorySelector> renderer_factory_selector,
Alok Priyadarshi7166d4d2017-07-29 04:04:25283 UrlIndex* url_index,
CJ DiMegliod7ac6772017-11-10 00:19:06284 std::unique_ptr<VideoFrameCompositor> compositor,
dalecurtis9cddc0b2017-04-19 21:23:38285 std::unique_ptr<WebMediaPlayerParams> params)
[email protected]f6af7592014-02-28 10:09:11286 : frame_(frame),
Alexander Timin310368112017-09-13 10:01:44287 main_task_runner_(
288 frame->GetTaskRunner(blink::TaskType::kMediaElementEvent)),
dalecurtis9cddc0b2017-04-19 21:23:38289 media_task_runner_(params->media_task_runner()),
290 worker_task_runner_(params->worker_task_runner()),
291 media_log_(params->take_media_log()),
[email protected]5badb082010-06-11 17:40:15292 client_(client),
srirama.m26f864d02015-07-14 05:21:46293 encrypted_client_(encrypted_client),
[email protected]baff4512011-10-19 18:21:07294 delegate_(delegate),
dalecurtis9cddc0b2017-04-19 21:23:38295 defer_load_cb_(params->defer_load_cb()),
dalecurtis9cddc0b2017-04-19 21:23:38296 adjust_allocated_memory_cb_(params->adjust_allocated_memory_cb()),
tzik2c963b872017-12-07 06:57:24297 tick_clock_(base::DefaultTickClock::GetInstance()),
hubbe5f0ad43b2015-12-14 20:57:26298 url_index_(url_index),
CJ DiMeglioc60a5cf2017-09-27 20:08:41299 context_provider_(params->context_provider()),
CJ DiMegliod7ac6772017-11-10 00:19:06300 vfc_task_runner_(params->video_frame_compositor_task_runner()),
301 compositor_(std::move(compositor)),
tguilbert70d2a00a2017-04-25 00:30:44302 renderer_factory_selector_(std::move(renderer_factory_selector)),
dalecurtis9cddc0b2017-04-19 21:23:38303 observer_(params->media_observer()),
servolkf94b4602017-01-31 16:44:27304 enable_instant_source_buffer_gc_(
dalecurtis9cddc0b2017-04-19 21:23:38305 params->enable_instant_source_buffer_gc()),
shaktisahu24189c12017-03-11 17:42:55306 embedded_media_experience_enabled_(
liberato2ff93ad2017-05-17 07:28:24307 params->embedded_media_experience_enabled()),
[email protected]69db58f2018-09-26 20:27:56308 surface_layer_mode_(params->use_surface_layer_for_video()),
CJ DiMeglio96c18b692018-07-04 03:39:06309 create_bridge_callback_(params->create_bridge_callback()),
liberato2ff93ad2017-05-17 07:28:24310 request_routing_token_cb_(params->request_routing_token_cb()),
Dale Curtis1adbe6a2017-08-02 02:09:13311 overlay_routing_token_(OverlayInfo::RoutingToken()),
Sergey Volk8b09c2c52018-12-12 23:20:40312 media_metrics_provider_(params->take_metrics_provider()),
313 is_background_suspend_enabled_(params->IsBackgroundSuspendEnabled()),
Junbo Kefba620b2019-01-16 02:54:36314 is_background_video_playback_enabled_(
315 params->IsBackgroundVideoPlaybackEnabled()),
Sergey Volk8b09c2c52018-12-12 23:20:40316 is_background_video_track_optimization_supported_(
Jeremy Roman32948392019-07-09 18:34:37317 params->IsBackgroundVideoTrackOptimizationSupported()) {
xhwang51139732017-02-24 19:36:08318 DVLOG(1) << __func__;
Dale Curtise25163812018-09-21 22:13:39319 DCHECK(adjust_allocated_memory_cb_);
tguilbert70d2a00a2017-04-25 00:30:44320 DCHECK(renderer_factory_selector_);
servolkef1e5ef2016-03-25 04:55:26321 DCHECK(client_);
tguilbert1bb1c782017-01-23 21:15:11322 DCHECK(delegate_);
dalecurtis83266c72015-10-29 18:43:20323
Antonio Gomes142f32a2019-05-15 23:32:56324 weak_this_ = weak_factory_.GetWeakPtr();
325
Antonio Gomes81b56552019-05-15 22:15:28326 pipeline_controller_ = std::make_unique<PipelineController>(
327 std::make_unique<PipelineImpl>(media_task_runner_, main_task_runner_,
328 media_log_.get()),
329 base::BindRepeating(&WebMediaPlayerImpl::CreateRenderer,
330 base::Unretained(this)),
Antonio Gomes142f32a2019-05-15 23:32:56331 base::BindRepeating(&WebMediaPlayerImpl::OnPipelineSeeked, weak_this_),
332 base::BindRepeating(&WebMediaPlayerImpl::OnPipelineSuspended, weak_this_),
Antonio Gomes81b56552019-05-15 22:15:28333 base::BindRepeating(&WebMediaPlayerImpl::OnBeforePipelineResume,
Antonio Gomes142f32a2019-05-15 23:32:56334 weak_this_),
335 base::BindRepeating(&WebMediaPlayerImpl::OnPipelineResumed, weak_this_),
336 base::BindRepeating(&WebMediaPlayerImpl::OnError, weak_this_));
Antonio Gomes81b56552019-05-15 22:15:28337
338 buffered_data_source_host_ = std::make_unique<BufferedDataSourceHostImpl>(
Antonio Gomes142f32a2019-05-15 23:32:56339 base::BindRepeating(&WebMediaPlayerImpl::OnProgress, weak_this_),
Antonio Gomes81b56552019-05-15 22:15:28340 tick_clock_);
341
[email protected]c8d574722017-08-30 20:53:43342 // If we're supposed to force video overlays, then make sure that they're
343 // enabled all the time.
344 always_enable_overlays_ = base::CommandLine::ForCurrentProcess()->HasSwitch(
tsunghungee562e92016-07-20 18:03:31345 switches::kForceVideoOverlays);
346
Dale Curtisca1b78f2019-01-15 03:11:26347 if (base::FeatureList::IsEnabled(kOverlayFullscreenVideo)) {
348 bool use_android_overlay = base::FeatureList::IsEnabled(kUseAndroidOverlay);
liberato2ff93ad2017-05-17 07:28:24349 overlay_mode_ = use_android_overlay ? OverlayMode::kUseAndroidOverlay
350 : OverlayMode::kUseContentVideoView;
351 } else {
352 overlay_mode_ = OverlayMode::kNoOverlays;
353 }
ampea73f792017-01-19 04:05:39354
tguilbert1bb1c782017-01-23 21:15:11355 delegate_id_ = delegate_->AddObserver(this);
356 delegate_->SetIdle(delegate_id_, true);
sandersd1e49fb62015-12-12 01:18:06357
dalecurtis2cff7f372017-05-24 08:30:08358 media_log_->AddEvent(media_log_->CreateCreatedEvent(
359 url::Origin(frame_->GetSecurityOrigin()).GetURL().spec()));
sandersd72683f252017-07-07 23:20:46360 media_log_->SetStringProperty("frame_url",
361 frame_->GetDocument().Url().GetString().Utf8());
362 media_log_->SetStringProperty("frame_title",
363 frame_->GetDocument().Title().Utf8());
[email protected]4e6be3f2009-05-07 02:24:44364
[email protected]52b0b212018-10-10 05:25:28365 // To make manual testing easier, include |surface_layer_mode_| in the log.
366 // TODO(liberato): Move this into media_factory.cc, so that it can be shared
367 // with the MediaStream startup.
368 const char* surface_layer_mode_name = "(unset)";
369 switch (surface_layer_mode_) {
CJ DiMeglio89240472018-10-18 18:21:10370 case SurfaceLayerMode::kAlways:
[email protected]52b0b212018-10-10 05:25:28371 surface_layer_mode_name = "kAlways";
372 break;
CJ DiMeglio89240472018-10-18 18:21:10373 case SurfaceLayerMode::kOnDemand:
[email protected]52b0b212018-10-10 05:25:28374 surface_layer_mode_name = "kOnDemand";
375 break;
CJ DiMeglio89240472018-10-18 18:21:10376 case SurfaceLayerMode::kNever:
[email protected]52b0b212018-10-10 05:25:28377 surface_layer_mode_name = "kNever";
378 break;
379 }
380 media_log_->SetStringProperty("surface_layer_mode", surface_layer_mode_name);
381
dalecurtis9cddc0b2017-04-19 21:23:38382 if (params->initial_cdm())
Chris Cunninghamd4a00192019-03-21 20:02:49383 SetCdmInternal(params->initial_cdm());
xhwang0ad11e512014-11-25 23:43:09384
Xiaohan Wangf63505d2017-10-21 08:00:53385 // Report a false "EncrytpedEvent" here as a baseline.
386 RecordEncryptedEvent(false);
387
xhwangf94a634d2014-10-22 22:07:27388 // TODO(xhwang): When we use an external Renderer, many methods won't work,
xhwang6fa356202014-12-11 00:44:12389 // e.g. GetCurrentFrameFromCompositor(). See http://crbug.com/434861
Antonio Gomes3a858b52019-05-31 02:47:52390 audio_source_provider_ = new blink::WebAudioSourceProviderImpl(
dalecurtis9cddc0b2017-04-19 21:23:38391 params->audio_renderer_sink(), media_log_.get());
xjz4e5d4bf32017-02-15 21:26:35392
393 if (observer_)
394 observer_->SetClient(this);
Hajime Hoshi8bb37dc2017-12-19 09:35:10395
396 memory_usage_reporting_timer_.SetTaskRunner(
Hajime Hoshib5a26ee2018-05-14 12:47:51397 frame_->GetTaskRunner(blink::TaskType::kInternalMedia));
John Delaney6c8ecc1b2018-10-21 19:07:29398
399 if (frame_->IsAdSubframe())
400 media_metrics_provider_->SetIsAdMedia();
Thomas Guilbert901808982019-07-03 20:38:18401
402#if defined(OS_ANDROID)
403 renderer_factory_selector_->SetRemotePlayStateChangeCB(base::BindRepeating(
404 &WebMediaPlayerImpl::OnRemotePlayStateChange, weak_this_));
405#endif // defined (OS_ANDROID)
[email protected]ec9212f2008-12-18 21:40:36406}
407
[email protected]4e6be3f2009-05-07 02:24:44408WebMediaPlayerImpl::~WebMediaPlayerImpl() {
xhwang51139732017-02-24 19:36:08409 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:43410 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53411
xhwang51139732017-02-24 19:36:08412 if (set_cdm_result_) {
Chris Cunninghamd4a00192019-03-21 20:02:49413 DVLOG(2)
414 << "Resolve pending SetCdmInternal() when media player is destroyed.";
Blink Reformat1c4d759e2017-04-09 16:34:54415 set_cdm_result_->Complete();
xhwang51139732017-02-24 19:36:08416 set_cdm_result_.reset();
417 }
418
alokp1116967f2016-06-11 17:30:56419 suppress_destruction_errors_ = true;
tguilbert1bb1c782017-01-23 21:15:11420
421 delegate_->PlayerGone(delegate_id_);
422 delegate_->RemoveObserver(delegate_id_);
[email protected]baff4512011-10-19 18:21:07423
dalecurtis04bdb582016-08-17 22:15:23424 // Finalize any watch time metrics before destroying the pipeline.
425 watch_time_reporter_.reset();
426
tguilbert350936ff2017-02-24 05:39:27427 // The underlying Pipeline must be stopped before it is destroyed.
Dale Curtisf273f8f2018-12-13 23:40:33428 //
429 // Note: This destruction happens synchronously on the media thread and
430 // |demuxer_|, |data_source_|, |compositor_|, and |media_log_| must outlive
431 // this process. They will be destructed by the DestructionHelper below
432 // after trampolining through the media thread.
Antonio Gomes81b56552019-05-15 22:15:28433 pipeline_controller_->Stop();
[email protected]f6af7592014-02-28 10:09:11434
dalecurtis83266c72015-10-29 18:43:20435 if (last_reported_memory_usage_)
436 adjust_allocated_memory_cb_.Run(-last_reported_memory_usage_);
437
dalecurtise1edb312016-06-22 02:33:21438 // Destruct compositor resources in the proper order.
danakj8d204a42018-05-18 18:05:35439 client_->SetCcLayer(nullptr);
CJ DiMeglio2302d202017-08-31 08:38:04440
Xiangjun Zhang5e20cba42018-01-10 19:54:56441 client_->MediaRemotingStopped(
442 blink::WebLocalizedString::kMediaRemotingStopNoText);
Xiangjun Zhang87299142017-09-13 20:35:03443
Dale Curtisf273f8f2018-12-13 23:40:33444 if (!surface_layer_for_video_enabled_ && video_layer_)
danakj25f030112018-05-11 18:26:54445 video_layer_->StopUsingProvider();
Matt Wolenetz95af6362018-01-04 20:23:42446
xhwangea8bb3562015-06-08 21:18:37447 media_log_->AddEvent(
448 media_log_->CreateEvent(MediaLogEvent::WEBMEDIAPLAYER_DESTROYED));
[email protected]ec9212f2008-12-18 21:40:36449
Dale Curtisf273f8f2018-12-13 23:40:33450 if (data_source_)
451 data_source_->Stop();
452
453 // Disconnect from the surface layer. We still preserve the |bridge_| until
454 // after pipeline shutdown to ensure any pending frames are painted for tests.
455 if (bridge_)
456 bridge_->ClearObserver();
457
Dale Curtisc96a3542018-12-17 22:15:23458 // Disconnect from the MediaObserver implementation since it's lifetime is
459 // tied to the RendererFactorySelector which can't be destroyed until after
460 // the Pipeline stops.
461 //
462 // Note: We can't use a WeakPtr with the RendererFactory because its methods
463 // are called on the media thread and this destruction takes place on the
464 // renderer thread.
465 if (observer_)
466 observer_->SetClient(nullptr);
467
Dale Curtisf273f8f2018-12-13 23:40:33468 // Handle destruction of things that need to be destructed after the pipeline
469 // completes stopping on the media thread.
470 media_task_runner_->PostTask(
Matt Wolenetz95af6362018-01-04 20:23:42471 FROM_HERE,
Dale Curtisf273f8f2018-12-13 23:40:33472 base::BindOnce(&DestructionHelper, std::move(main_task_runner_),
473 std::move(vfc_task_runner_), std::move(demuxer_),
474 std::move(data_source_), std::move(compositor_),
475 std::move(cdm_context_ref_),
476 std::move(pending_cdm_context_ref_), std::move(media_log_),
477 std::move(renderer_factory_selector_), std::move(bridge_),
478 !!chunk_demuxer_));
Matt Wolenetz95af6362018-01-04 20:23:42479}
480
chcunningham707b821e2018-05-29 08:42:19481WebMediaPlayer::LoadTiming WebMediaPlayerImpl::Load(
482 LoadType load_type,
483 const blink::WebMediaPlayerSource& source,
Takashi Toyoshima2e01e692018-11-16 03:23:27484 CorsMode cors_mode) {
guidou9bfe4e2f2016-04-09 08:31:19485 // Only URL or MSE blob URL is supported.
Blink Reformat1c4d759e2017-04-09 16:34:54486 DCHECK(source.IsURL());
487 blink::WebURL url = source.GetAsURL();
Xiaohan Wang81fd0022017-07-11 17:45:24488 DVLOG(1) << __func__ << "(" << load_type << ", " << GURL(url) << ", "
489 << cors_mode << ")";
chcunningham707b821e2018-05-29 08:42:19490
491 bool is_deferred = false;
492
Dale Curtise25163812018-09-21 22:13:39493 if (defer_load_cb_) {
chcunningham707b821e2018-05-29 08:42:19494 is_deferred = defer_load_cb_.Run(base::BindOnce(
Antonio Gomes142f32a2019-05-15 23:32:56495 &WebMediaPlayerImpl::DoLoad, weak_this_, load_type, url, cors_mode));
chcunningham707b821e2018-05-29 08:42:19496 } else {
497 DoLoad(load_type, url, cors_mode);
[email protected]d726eddc2013-07-02 22:25:55498 }
chcunningham707b821e2018-05-29 08:42:19499
500 return is_deferred ? LoadTiming::kDeferred : LoadTiming::kImmediate;
[email protected]62e5e682013-03-07 23:53:24501}
502
CJ DiMeglio013d4c472017-11-21 03:27:30503void WebMediaPlayerImpl::OnWebLayerUpdated() {}
504
danakj6a062b112018-05-17 16:25:45505void WebMediaPlayerImpl::RegisterContentsLayer(cc::Layer* layer) {
CJ DiMeglio2302d202017-08-31 08:38:04506 DCHECK(bridge_);
CJ DiMeglioa2b13fbc2018-06-27 00:50:59507 bridge_->SetContentsOpaque(opaque_);
danakj8d204a42018-05-18 18:05:35508 client_->SetCcLayer(layer);
CJ DiMeglio013d4c472017-11-21 03:27:30509}
510
danakj6a062b112018-05-17 16:25:45511void WebMediaPlayerImpl::UnregisterContentsLayer(cc::Layer* layer) {
512 // |client_| will unregister its cc::Layer if given a nullptr.
danakj8d204a42018-05-18 18:05:35513 client_->SetCcLayer(nullptr);
CJ DiMeglio2302d202017-08-31 08:38:04514}
515
Jennifer Apaciblec45fd052018-02-25 12:04:55516void WebMediaPlayerImpl::OnSurfaceIdUpdated(viz::SurfaceId surface_id) {
Jennifer Apaciblec45fd052018-02-25 12:04:55517 // TODO(726619): Handle the behavior when Picture-in-Picture mode is
518 // disabled.
Jennifer Apacible2b1dc5eb2018-04-27 16:23:28519 // The viz::SurfaceId may be updated when the video begins playback or when
520 // the size of the video changes.
Mounir Lamouri99ba5a62019-02-12 01:27:47521 if (client_)
522 client_->OnPictureInPictureStateChange();
Jennifer Apaciblec45fd052018-02-25 12:04:55523}
524
Blink Reformat1c4d759e2017-04-09 16:34:54525bool WebMediaPlayerImpl::SupportsOverlayFullscreenVideo() {
watk9c87c6fa2016-05-06 20:36:51526#if defined(OS_ANDROID)
[email protected]68ec57f2017-06-27 22:10:05527 return !using_media_player_renderer_ &&
528 overlay_mode_ == OverlayMode::kUseContentVideoView;
watk9c87c6fa2016-05-06 20:36:51529#else
530 return false;
531#endif
532}
533
tsunghungee562e92016-07-20 18:03:31534void WebMediaPlayerImpl::EnableOverlay() {
535 overlay_enabled_ = true;
[email protected]f7df5b342018-07-13 20:22:13536 if (request_routing_token_cb_ &&
537 overlay_mode_ == OverlayMode::kUseAndroidOverlay) {
liberatofe8f9692017-06-08 19:17:36538 overlay_routing_token_is_pending_ = true;
liberato2ff93ad2017-05-17 07:28:24539 token_available_cb_.Reset(
Antonio Gomes142f32a2019-05-15 23:32:56540 base::Bind(&WebMediaPlayerImpl::OnOverlayRoutingToken, weak_this_));
liberato2ff93ad2017-05-17 07:28:24541 request_routing_token_cb_.Run(token_available_cb_.callback());
watkf835a792016-06-24 23:24:40542 }
tsunghungee562e92016-07-20 18:03:31543
liberato2ff93ad2017-05-17 07:28:24544 // We have requested (and maybe already have) overlay information. If the
545 // restarted decoder requests overlay information, then we'll defer providing
546 // it if it hasn't arrived yet. Otherwise, this would be a race, since we
547 // don't know if the request for overlay info or restart will complete first.
tsunghungee562e92016-07-20 18:03:31548 if (decoder_requires_restart_for_overlay_)
watkdee516f2016-02-18 02:22:19549 ScheduleRestart();
550}
551
tsunghungee562e92016-07-20 18:03:31552void WebMediaPlayerImpl::DisableOverlay() {
553 overlay_enabled_ = false;
liberato2ff93ad2017-05-17 07:28:24554 if (overlay_mode_ == OverlayMode::kUseContentVideoView) {
555 surface_created_cb_.Cancel();
liberato2ff93ad2017-05-17 07:28:24556 } else if (overlay_mode_ == OverlayMode::kUseAndroidOverlay) {
557 token_available_cb_.Cancel();
liberatofe8f9692017-06-08 19:17:36558 overlay_routing_token_is_pending_ = false;
559 overlay_routing_token_ = OverlayInfo::RoutingToken();
liberato2ff93ad2017-05-17 07:28:24560 }
tsunghungee562e92016-07-20 18:03:31561
562 if (decoder_requires_restart_for_overlay_)
watkdee516f2016-02-18 02:22:19563 ScheduleRestart();
liberato2ff93ad2017-05-17 07:28:24564 else
565 MaybeSendOverlayInfoToDecoder();
watkdee516f2016-02-18 02:22:19566}
567
Blink Reformat1c4d759e2017-04-09 16:34:54568void WebMediaPlayerImpl::EnteredFullscreen() {
liberatofe8f9692017-06-08 19:17:36569 overlay_info_.is_fullscreen = true;
570
[email protected]c8d574722017-08-30 20:53:43571 // |always_enable_overlays_| implies that we're already in overlay mode, so
572 // take no action here. Otherwise, switch to an overlay if it's allowed and
573 // if it will display properly.
574 if (!always_enable_overlays_ && overlay_mode_ != OverlayMode::kNoOverlays &&
liberato2fd111be2017-01-04 00:25:06575 DoesOverlaySupportMetadata()) {
tsunghungee562e92016-07-20 18:03:31576 EnableOverlay();
liberato2fd111be2017-01-04 00:25:06577 }
liberato2ff93ad2017-05-17 07:28:24578
liberatofe8f9692017-06-08 19:17:36579 // We send this only if we can send multiple calls. Otherwise, either (a)
580 // we already sent it and we don't have a callback anyway (we reset it when
581 // it's called in restart mode), or (b) we'll send this later when the surface
582 // actually arrives. GVD assumes that the first overlay info will have the
583 // routing information. Note that we set |is_fullscreen_| earlier, so that
584 // if EnableOverlay() can include fullscreen info in case it sends the overlay
585 // info before returning.
586 if (!decoder_requires_restart_for_overlay_)
587 MaybeSendOverlayInfoToDecoder();
tsunghungee562e92016-07-20 18:03:31588}
589
Blink Reformat1c4d759e2017-04-09 16:34:54590void WebMediaPlayerImpl::ExitedFullscreen() {
liberatofe8f9692017-06-08 19:17:36591 overlay_info_.is_fullscreen = false;
592
[email protected]c8d574722017-08-30 20:53:43593 // If we're in overlay mode, then exit it unless we're supposed to allow
594 // overlays all the time.
595 if (!always_enable_overlays_ && overlay_enabled_)
tsunghungee562e92016-07-20 18:03:31596 DisableOverlay();
liberato2ff93ad2017-05-17 07:28:24597
liberatofe8f9692017-06-08 19:17:36598 // See EnteredFullscreen for why we do this.
599 if (!decoder_requires_restart_for_overlay_)
600 MaybeSendOverlayInfoToDecoder();
tsunghungee562e92016-07-20 18:03:31601}
602
Blink Reformat1c4d759e2017-04-09 16:34:54603void WebMediaPlayerImpl::BecameDominantVisibleContent(bool isDominant) {
xjzcdbbe732016-12-03 20:47:42604 if (observer_)
605 observer_->OnBecameDominantVisibleContent(isDominant);
606}
607
Blink Reformat1c4d759e2017-04-09 16:34:54608void WebMediaPlayerImpl::SetIsEffectivelyFullscreen(
François Beaufortad6c5232018-02-26 11:00:44609 blink::WebFullscreenVideoStatus fullscreen_video_status) {
610 delegate_->SetIsEffectivelyFullscreen(delegate_id_, fullscreen_video_status);
zqzhangabc08242017-03-02 16:07:14611}
612
Mounir Lamouri41a79c62017-06-06 12:53:16613void WebMediaPlayerImpl::OnHasNativeControlsChanged(bool has_native_controls) {
614 if (!watch_time_reporter_)
615 return;
616
617 if (has_native_controls)
618 watch_time_reporter_->OnNativeControlsEnabled();
619 else
620 watch_time_reporter_->OnNativeControlsDisabled();
621}
622
Mounir Lamourif9af74e72017-06-19 19:31:45623void WebMediaPlayerImpl::OnDisplayTypeChanged(
624 WebMediaPlayer::DisplayType display_type) {
Mounir Lamouri0484f40a2018-07-25 03:03:26625 if (surface_layer_for_video_enabled_) {
626 vfc_task_runner_->PostTask(
627 FROM_HERE,
628 base::BindOnce(
629 &VideoFrameCompositor::SetForceSubmit,
630 base::Unretained(compositor_.get()),
631 display_type == WebMediaPlayer::DisplayType::kPictureInPicture));
632 }
633
Mounir Lamourif9af74e72017-06-19 19:31:45634 if (!watch_time_reporter_)
635 return;
636
637 switch (display_type) {
638 case WebMediaPlayer::DisplayType::kInline:
639 watch_time_reporter_->OnDisplayTypeInline();
640 break;
641 case WebMediaPlayer::DisplayType::kFullscreen:
642 watch_time_reporter_->OnDisplayTypeFullscreen();
643 break;
644 case WebMediaPlayer::DisplayType::kPictureInPicture:
645 watch_time_reporter_->OnDisplayTypePictureInPicture();
François Beaufort3f62f382019-01-18 15:05:17646
647 // Resumes playback if it was paused when hidden.
648 if (paused_when_hidden_) {
649 paused_when_hidden_ = false;
650 OnPlay();
651 }
Mounir Lamourif9af74e72017-06-19 19:31:45652 break;
653 }
654}
655
[email protected]ef8394c2013-08-21 20:26:30656void WebMediaPlayerImpl::DoLoad(LoadType load_type,
[email protected]180ef242013-11-07 06:50:46657 const blink::WebURL& url,
Takashi Toyoshima2e01e692018-11-16 03:23:27658 CorsMode cors_mode) {
John Chen5b164a02017-11-01 00:36:09659 TRACE_EVENT1("media", "WebMediaPlayerImpl::DoLoad", "id", media_log_->id());
pkastingf5279482016-07-27 02:18:20660 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:43661 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d726eddc2013-07-02 22:25:55662
Thomas Guilbert55b48d92019-03-25 23:16:54663#if defined(OS_ANDROID)
664 // Only allow credentials if the crossorigin attribute is unspecified
665 // (kCorsModeUnspecified) or "use-credentials" (kCorsModeUseCredentials).
666 // This value is only used by the MediaPlayerRenderer.
667 // See https://crbug.com/936566.
668 //
669 // The credentials mode also has repercussions in WouldTaintOrigin(), but we
670 // access what we need from |mb_data_source_|->cors_mode() directly, instead
671 // of storing it here.
672 allow_media_player_renderer_credentials_ = cors_mode != kCorsModeAnonymous;
673#endif // defined(OS_ANDROID)
674
Dale Curtis4841c712018-12-13 18:14:05675 // Note: |url| may be very large, take care when making copies.
676 loaded_url_ = GURL(url);
677 load_type_ = load_type;
678
679 ReportMetrics(load_type, loaded_url_, *frame_, media_log_.get());
[email protected]62e5e682013-03-07 23:53:24680
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
Antonio Gomesf01cfbd2019-07-12 08:53:11692 media_metrics_provider_->Initialize(
693 load_type == kLoadTypeMediaSource,
694 load_type == kLoadTypeURL ? blink::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;
Dale Curtis44eacb72019-06-10 20:41:28706 if (!net::DataURL::Parse(loaded_url_, &mime_type, &charset, &data) ||
707 data.empty()) {
Dale Curtis4841c712018-12-13 18:14:05708 DataSourceInitialized(false);
709 return;
710 }
711
712 // Replace |loaded_url_| with an empty data:// URL since it may be large.
713 loaded_url_ = GURL("data:,");
714
715 // Mark all the data as buffered.
Antonio Gomes81b56552019-05-15 22:15:28716 buffered_data_source_host_->SetTotalBytes(data.size());
717 buffered_data_source_host_->AddBufferedByteRange(0, data.size());
Dale Curtis4841c712018-12-13 18:14:05718
719 DCHECK(!mb_data_source_);
720 data_source_.reset(new MemoryDataSource(std::move(data)));
721 DataSourceInitialized(true);
722 return;
723 }
724
John Delaneyb933391602018-10-17 21:50:47725 auto url_data =
Takashi Toyoshima2e01e692018-11-16 03:23:27726 url_index_->GetByUrl(url, static_cast<UrlData::CorsMode>(cors_mode));
John Delaneyb933391602018-10-17 21:50:47727 // Notify |this| of bytes received by the network.
Antonio Gomes142f32a2019-05-15 23:32:56728 url_data->AddBytesReceivedCallback(BindToCurrentLoop(
729 base::BindRepeating(&WebMediaPlayerImpl::OnBytesReceived, weak_this_)));
Dale Curtis4841c712018-12-13 18:14:05730 mb_data_source_ = new MultibufferDataSource(
John Delaneyb933391602018-10-17 21:50:47731 main_task_runner_, std::move(url_data), media_log_.get(),
Antonio Gomes81b56552019-05-15 22:15:28732 buffered_data_source_host_.get(),
Dale Curtis4841c712018-12-13 18:14:05733 base::BindRepeating(&WebMediaPlayerImpl::NotifyDownloading,
Antonio Gomes142f32a2019-05-15 23:32:56734 weak_this_));
Dale Curtis4841c712018-12-13 18:14:05735 data_source_.reset(mb_data_source_);
736 mb_data_source_->SetPreload(preload_);
737 mb_data_source_->SetIsClientAudioElement(client_->IsAudioElement());
738 mb_data_source_->Initialize(
Antonio Gomes142f32a2019-05-15 23:32:56739 base::Bind(&WebMediaPlayerImpl::DataSourceInitialized, weak_this_));
hubbe5f0ad43b2015-12-14 20:57:26740 }
[email protected]62e5e682013-03-07 23:53:24741}
742
Blink Reformat1c4d759e2017-04-09 16:34:54743void WebMediaPlayerImpl::Play() {
pkastingf5279482016-07-27 02:18:20744 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:43745 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53746
avayvod65fad272017-02-24 01:00:48747 // User initiated play unlocks background video playback.
Mustaq Ahmede473e4352017-11-04 01:04:25748 if (blink::WebUserGestureIndicator::IsProcessingUserGesture(frame_))
avayvod65fad272017-02-24 01:00:48749 video_locked_when_paused_when_hidden_ = false;
750
sandersd35d2c3f2017-01-14 02:04:42751 // TODO(sandersd): Do we want to reset the idle timer here?
tguilbert1bb1c782017-01-23 21:15:11752 delegate_->SetIdle(delegate_id_, false);
[email protected]49480902009-07-14 20:23:43753 paused_ = false;
Antonio Gomes81b56552019-05-15 22:15:28754 pipeline_controller_->SetPlaybackRate(playback_rate_);
dalecurtis4619cd02016-09-22 21:39:10755 background_pause_timer_.Stop();
sandersd1c0bba02016-03-04 23:14:08756
xjz48a9cb72016-12-20 04:02:49757 if (observer_)
758 observer_->OnPlaying();
759
Mounir Lamouri89c0a1b2018-03-01 15:00:44760 watch_time_reporter_->SetAutoplayInitiated(client_->WasAutoplayInitiated());
761
Dale Curtis051fdf62017-08-05 00:21:13762 // If we're seeking we'll trigger the watch time reporter upon seek completed;
763 // we don't want to start it here since the seek time is unstable. E.g., when
764 // playing content with a positive start time we would have a zero seek time.
765 if (!Seeking()) {
766 DCHECK(watch_time_reporter_);
767 watch_time_reporter_->OnPlaying();
768 }
769
Chris Cunninghamd9df58e2017-08-29 00:04:23770 if (video_decode_stats_reporter_)
771 video_decode_stats_reporter_->OnPlaying();
772
Ted Meyerd5885f82019-07-16 19:19:17773 media_metrics_provider_->SetHasPlayed();
acolwell9e0840d2014-09-06 19:01:32774 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PLAY));
Dale Curtis18ad391b2019-05-30 23:25:09775
776 MaybeUpdateBufferSizesForPlayback();
sandersd50a635e2016-04-04 22:50:09777 UpdatePlayState();
[email protected]ec9212f2008-12-18 21:40:36778}
779
Blink Reformat1c4d759e2017-04-09 16:34:54780void WebMediaPlayerImpl::Pause() {
pkastingf5279482016-07-27 02:18:20781 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:43782 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53783
sandersd50a635e2016-04-04 22:50:09784 // We update the paused state even when casting, since we expect pause() to be
785 // called when casting begins, and when we exit casting we should end up in a
786 // paused state.
[email protected]49480902009-07-14 20:23:43787 paused_ = true;
hubbed5f36882016-01-15 22:40:37788
avayvodeb9098d2017-01-07 00:33:03789 // No longer paused because it was hidden.
790 paused_when_hidden_ = false;
791
avayvod65fad272017-02-24 01:00:48792 // User initiated pause locks background videos.
Mustaq Ahmede473e4352017-11-04 01:04:25793 if (blink::WebUserGestureIndicator::IsProcessingUserGesture(frame_))
avayvod65fad272017-02-24 01:00:48794 video_locked_when_paused_when_hidden_ = true;
795
Antonio Gomes81b56552019-05-15 22:15:28796 pipeline_controller_->SetPlaybackRate(0.0);
Dale Curtis2fc01cc2019-05-20 22:53:52797
798 // For states <= kReadyStateHaveMetadata, we may not have a renderer yet.
799 if (highest_ready_state_ > WebMediaPlayer::kReadyStateHaveMetadata)
800 paused_time_ = pipeline_controller_->GetMediaTime();
[email protected]090f7312011-08-05 23:26:40801
xjz48a9cb72016-12-20 04:02:49802 if (observer_)
803 observer_->OnPaused();
804
dalecurtis04bdb582016-08-17 22:15:23805 DCHECK(watch_time_reporter_);
806 watch_time_reporter_->OnPaused();
Chris Cunninghamd9df58e2017-08-29 00:04:23807
808 if (video_decode_stats_reporter_)
809 video_decode_stats_reporter_->OnPaused();
810
acolwell9e0840d2014-09-06 19:01:32811 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PAUSE));
avayvod2135a642017-01-13 00:17:14812
sandersd50a635e2016-04-04 22:50:09813 UpdatePlayState();
[email protected]ec9212f2008-12-18 21:40:36814}
815
Blink Reformat1c4d759e2017-04-09 16:34:54816void WebMediaPlayerImpl::Seek(double seconds) {
pkastingf5279482016-07-27 02:18:20817 DVLOG(1) << __func__ << "(" << seconds << "s)";
acolwellb4034942014-08-28 15:42:43818 DCHECK(main_task_runner_->BelongsToCurrentThread());
Mounir Lamourid864f752019-02-08 22:22:41819 media_log_->AddEvent(
820 media_log_->CreateTimeEvent(MediaLogEvent::SEEK, "seek_target", seconds));
sandersd1c0bba02016-03-04 23:14:08821 DoSeek(base::TimeDelta::FromSecondsD(seconds), true);
822}
823
824void WebMediaPlayerImpl::DoSeek(base::TimeDelta time, bool time_updated) {
825 DCHECK(main_task_runner_->BelongsToCurrentThread());
John Chen5b164a02017-11-01 00:36:09826 TRACE_EVENT2("media", "WebMediaPlayerImpl::DoSeek", "target",
827 time.InSecondsF(), "id", media_log_->id());
[email protected]d43ed912009-02-03 04:52:53828
srirama.mccf671812015-01-08 11:59:13829 ReadyState old_state = ready_state_;
Blink Reformat1c4d759e2017-04-09 16:34:54830 if (ready_state_ > WebMediaPlayer::kReadyStateHaveMetadata)
831 SetReadyState(WebMediaPlayer::kReadyStateHaveMetadata);
[email protected]1bb666802013-11-28 06:12:08832
Dale Curtis051fdf62017-08-05 00:21:13833 // When paused or ended, we know exactly what the current time is and can
834 // elide seeks to it. However, there are two cases that are not elided:
sandersd1c0bba02016-03-04 23:14:08835 // 1) When the pipeline state is not stable.
836 // In this case we just let |pipeline_controller_| decide what to do, as
837 // it has complete information.
838 // 2) For MSE.
839 // Because the buffers may have changed between seeks, MSE seeks are
840 // never elided.
Antonio Gomes81b56552019-05-15 22:15:28841 if (paused_ && pipeline_controller_->IsStable() &&
Dale Curtis051fdf62017-08-05 00:21:13842 (paused_time_ == time ||
843 (ended_ && time == base::TimeDelta::FromSecondsD(Duration()))) &&
sandersd1c0bba02016-03-04 23:14:08844 !chunk_demuxer_) {
845 // If the ready state was high enough before, we can indicate that the seek
846 // completed just by restoring it. Otherwise we will just wait for the real
847 // ready state change to eventually happen.
Blink Reformat1c4d759e2017-04-09 16:34:54848 if (old_state == kReadyStateHaveEnoughData) {
srirama.m8f4a37562014-12-13 08:16:18849 main_task_runner_->PostTask(
Dale Curtisee9be30012018-09-21 22:21:51850 FROM_HERE, base::BindOnce(&WebMediaPlayerImpl::OnBufferingStateChange,
Chris Cunninghamfc0d67e2019-07-22 20:29:16851 weak_this_, BUFFERING_HAVE_ENOUGH,
852 BUFFERING_CHANGE_REASON_UNKNOWN));
srirama.m36ab2682014-12-11 04:20:01853 }
sandersd1c0bba02016-03-04 23:14:08854 return;
srirama.m36ab2682014-12-11 04:20:01855 }
[email protected]44ff37c02009-10-24 01:03:03856
dalecurtis04bdb582016-08-17 22:15:23857 // Call this before setting |seeking_| so that the current media time can be
858 // recorded by the reporter.
859 if (watch_time_reporter_)
860 watch_time_reporter_->OnSeeking();
861
sandersd35d2c3f2017-01-14 02:04:42862 // TODO(sandersd): Move |seeking_| to PipelineController.
863 // TODO(sandersd): Do we want to reset the idle timer here?
tguilbert1bb1c782017-01-23 21:15:11864 delegate_->SetIdle(delegate_id_, false);
sandersd50a635e2016-04-04 22:50:09865 ended_ = false;
[email protected]b3766a22010-12-22 17:34:13866 seeking_ = true;
sandersd1c0bba02016-03-04 23:14:08867 seek_time_ = time;
868 if (paused_)
869 paused_time_ = time;
Antonio Gomes81b56552019-05-15 22:15:28870 pipeline_controller_->Seek(time, time_updated);
[email protected]b3766a22010-12-22 17:34:13871
sandersd50a635e2016-04-04 22:50:09872 // This needs to be called after Seek() so that if a resume is triggered, it
873 // is to the correct time.
874 UpdatePlayState();
[email protected]ec9212f2008-12-18 21:40:36875}
876
Blink Reformat1c4d759e2017-04-09 16:34:54877void WebMediaPlayerImpl::SetRate(double rate) {
pkastingf5279482016-07-27 02:18:20878 DVLOG(1) << __func__ << "(" << rate << ")";
acolwellb4034942014-08-28 15:42:43879 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53880
Matt Wolenetz6010f6c2017-10-18 00:44:36881 if (rate != playback_rate_) {
882 LIMITED_MEDIA_LOG(INFO, media_log_.get(), num_playback_rate_logs_,
883 kMaxNumPlaybackRateLogs)
884 << "Effective playback rate changed from " << playback_rate_ << " to "
885 << rate;
886 }
887
[email protected]49480902009-07-14 20:23:43888 playback_rate_ = rate;
Dale Curtis18ad391b2019-05-30 23:25:09889 if (!paused_)
Antonio Gomes81b56552019-05-15 22:15:28890 pipeline_controller_->SetPlaybackRate(rate);
Dale Curtis18ad391b2019-05-30 23:25:09891
892 MaybeUpdateBufferSizesForPlayback();
[email protected]ec9212f2008-12-18 21:40:36893}
894
Blink Reformat1c4d759e2017-04-09 16:34:54895void WebMediaPlayerImpl::SetVolume(double volume) {
pkastingf5279482016-07-27 02:18:20896 DVLOG(1) << __func__ << "(" << volume << ")";
acolwellb4034942014-08-28 15:42:43897 DCHECK(main_task_runner_->BelongsToCurrentThread());
dalecurtisbb3eaac2016-01-27 21:10:25898 volume_ = volume;
Antonio Gomes81b56552019-05-15 22:15:28899 pipeline_controller_->SetVolume(volume_ * volume_multiplier_);
dalecurtis04bdb582016-08-17 22:15:23900 if (watch_time_reporter_)
901 watch_time_reporter_->OnVolumeChange(volume);
Becca Hughes9f6fd4b82017-06-15 10:01:40902 delegate_->DidPlayerMutedStatusChange(delegate_id_, volume == 0.0);
mlamouri910111362016-11-04 11:28:24903
904 // The play state is updated because the player might have left the autoplay
905 // muted state.
906 UpdatePlayState();
[email protected]ec9212f2008-12-18 21:40:36907}
[email protected]f0a51fb52009-03-05 12:46:38908
Mounir Lamouri967f8fb72019-02-13 02:34:22909void WebMediaPlayerImpl::OnRequestPictureInPicture() {
[email protected]69db58f2018-09-26 20:27:56910 if (!surface_layer_for_video_enabled_)
911 ActivateSurfaceLayerForVideo();
912
Mounir Lamourib642a3c2018-07-09 15:45:31913 DCHECK(bridge_);
Mounir Lamouri99ba5a62019-02-12 01:27:47914 DCHECK(bridge_->GetSurfaceId().is_valid());
Jennifer Apacible3f0489102018-01-19 20:10:31915}
916
Daniel Chengc1710b52018-10-24 03:12:28917void WebMediaPlayerImpl::SetSinkId(
918 const blink::WebString& sink_id,
Antonio Gomese7813f32019-04-02 06:11:03919 blink::WebSetSinkIdCompleteCallback completion_callback) {
guidou69223ce2015-06-16 10:36:19920 DCHECK(main_task_runner_->BelongsToCurrentThread());
pkastingf5279482016-07-27 02:18:20921 DVLOG(1) << __func__;
guidouc7babef2015-10-22 00:42:35922
Dale Curtisca1b78f2019-01-15 03:11:26923 OutputDeviceStatusCB callback =
Antonio Gomese7813f32019-04-02 06:11:03924 ConvertToOutputDeviceStatusCB(std::move(completion_callback));
guidouc7babef2015-10-22 00:42:35925 media_task_runner_->PostTask(
Dale Curtisee9be30012018-09-21 22:21:51926 FROM_HERE, base::BindOnce(&SetSinkIdOnMediaThread, audio_source_provider_,
Daniel Chengc1710b52018-10-24 03:12:28927 sink_id.Utf8(), std::move(callback)));
guidou69223ce2015-06-16 10:36:19928}
929
Blink Reformat1c4d759e2017-04-09 16:34:54930STATIC_ASSERT_ENUM(WebMediaPlayer::kPreloadNone, MultibufferDataSource::NONE);
931STATIC_ASSERT_ENUM(WebMediaPlayer::kPreloadMetaData,
dalecurtisb6e052f52016-08-25 00:35:55932 MultibufferDataSource::METADATA);
Blink Reformat1c4d759e2017-04-09 16:34:54933STATIC_ASSERT_ENUM(WebMediaPlayer::kPreloadAuto, MultibufferDataSource::AUTO);
[email protected]23a8b1d82011-04-05 16:28:20934
Blink Reformat1c4d759e2017-04-09 16:34:54935void WebMediaPlayerImpl::SetPreload(WebMediaPlayer::Preload preload) {
pkastingf5279482016-07-27 02:18:20936 DVLOG(1) << __func__ << "(" << preload << ")";
acolwellb4034942014-08-28 15:42:43937 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]4e6be3f2009-05-07 02:24:44938
dalecurtisb6e052f52016-08-25 00:35:55939 preload_ = static_cast<MultibufferDataSource::Preload>(preload);
Dale Curtis4841c712018-12-13 18:14:05940 if (mb_data_source_)
941 mb_data_source_->SetPreload(preload_);
[email protected]4e6be3f2009-05-07 02:24:44942}
943
Blink Reformat1c4d759e2017-04-09 16:34:54944bool WebMediaPlayerImpl::HasVideo() const {
acolwellb4034942014-08-28 15:42:43945 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53946
[email protected]b8877772014-03-26 20:17:15947 return pipeline_metadata_.has_video;
[email protected]d43ed912009-02-03 04:52:53948}
949
Blink Reformat1c4d759e2017-04-09 16:34:54950bool WebMediaPlayerImpl::HasAudio() const {
acolwellb4034942014-08-28 15:42:43951 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]fc367af2009-08-14 23:06:35952
[email protected]b8877772014-03-26 20:17:15953 return pipeline_metadata_.has_audio;
[email protected]fc367af2009-08-14 23:06:35954}
955
Blink Reformat1c4d759e2017-04-09 16:34:54956void WebMediaPlayerImpl::EnabledAudioTracksChanged(
servolkf25ceed2016-07-01 03:44:38957 const blink::WebVector<blink::WebMediaPlayer::TrackId>& enabledTrackIds) {
958 DCHECK(main_task_runner_->BelongsToCurrentThread());
959
960 std::ostringstream logstr;
961 std::vector<MediaTrack::Id> enabledMediaTrackIds;
962 for (const auto& blinkTrackId : enabledTrackIds) {
Maciej Pawlowskif2556d122019-06-03 08:14:18963 const auto track_id = MediaTrack::Id(blinkTrackId.Utf8().data());
servolkf25ceed2016-07-01 03:44:38964 logstr << track_id << " ";
965 enabledMediaTrackIds.push_back(track_id);
966 }
dalecurtis9cddc0b2017-04-19 21:23:38967 MEDIA_LOG(INFO, media_log_.get())
968 << "Enabled audio tracks: [" << logstr.str() << "]";
Antonio Gomes81b56552019-05-15 22:15:28969 pipeline_controller_->OnEnabledAudioTracksChanged(enabledMediaTrackIds);
servolkf25ceed2016-07-01 03:44:38970}
971
Blink Reformat1c4d759e2017-04-09 16:34:54972void WebMediaPlayerImpl::SelectedVideoTrackChanged(
servolkf25ceed2016-07-01 03:44:38973 blink::WebMediaPlayer::TrackId* selectedTrackId) {
974 DCHECK(main_task_runner_->BelongsToCurrentThread());
975
servolk9bed6602017-02-24 01:20:11976 base::Optional<MediaTrack::Id> selected_video_track_id;
977 if (selectedTrackId && !video_track_disabled_)
Blink Reformat1c4d759e2017-04-09 16:34:54978 selected_video_track_id = MediaTrack::Id(selectedTrackId->Utf8().data());
dalecurtis9cddc0b2017-04-19 21:23:38979 MEDIA_LOG(INFO, media_log_.get())
Maciej Pawlowskif2556d122019-06-03 08:14:18980 << "Selected video track: ["
981 << selected_video_track_id.value_or(MediaTrack::Id()) << "]";
Antonio Gomes81b56552019-05-15 22:15:28982 pipeline_controller_->OnSelectedVideoTrackChanged(selected_video_track_id);
servolkf25ceed2016-07-01 03:44:38983}
984
Blink Reformat1c4d759e2017-04-09 16:34:54985blink::WebSize WebMediaPlayerImpl::NaturalSize() const {
acolwellb4034942014-08-28 15:42:43986 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53987
[email protected]b8877772014-03-26 20:17:15988 return blink::WebSize(pipeline_metadata_.natural_size);
[email protected]d43ed912009-02-03 04:52:53989}
990
Jiajia Qin82acdc02017-07-31 09:55:14991blink::WebSize WebMediaPlayerImpl::VisibleRect() const {
992 DCHECK(main_task_runner_->BelongsToCurrentThread());
993 scoped_refptr<VideoFrame> video_frame = GetCurrentFrameFromCompositor();
994 if (!video_frame)
995 return blink::WebSize();
996
997 const gfx::Rect& visible_rect = video_frame->visible_rect();
998 return blink::WebSize(visible_rect.width(), visible_rect.height());
999}
1000
Blink Reformat1c4d759e2017-04-09 16:34:541001bool WebMediaPlayerImpl::Paused() const {
acolwellb4034942014-08-28 15:42:431002 DCHECK(main_task_runner_->BelongsToCurrentThread());
Antonio Gomes81b56552019-05-15 22:15:281003 return pipeline_controller_->GetPlaybackRate() == 0.0f;
[email protected]d43ed912009-02-03 04:52:531004}
1005
François Beaufort184f6042019-01-25 05:50:051006bool WebMediaPlayerImpl::PausedWhenHidden() const {
1007 return paused_when_hidden_;
1008}
1009
Blink Reformat1c4d759e2017-04-09 16:34:541010bool WebMediaPlayerImpl::Seeking() const {
acolwellb4034942014-08-28 15:42:431011 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:531012
Blink Reformat1c4d759e2017-04-09 16:34:541013 if (ready_state_ == WebMediaPlayer::kReadyStateHaveNothing)
[email protected]0acebfa2009-08-21 22:45:401014 return false;
[email protected]67cd5052009-09-10 21:53:221015
[email protected]b3766a22010-12-22 17:34:131016 return seeking_;
[email protected]ec9212f2008-12-18 21:40:361017}
1018
Blink Reformat1c4d759e2017-04-09 16:34:541019double WebMediaPlayerImpl::Duration() const {
acolwellb4034942014-08-28 15:42:431020 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]39bdde32013-04-17 17:44:201021
Blink Reformat1c4d759e2017-04-09 16:34:541022 if (ready_state_ == WebMediaPlayer::kReadyStateHaveNothing)
[email protected]39bdde32013-04-17 17:44:201023 return std::numeric_limits<double>::quiet_NaN();
1024
chcunninghamb92d5062017-01-10 21:50:221025 // Use duration from ChunkDemuxer when present. MSE allows users to specify
1026 // duration as a double. This propagates to the rest of the pipeline as a
1027 // TimeDelta with potentially reduced precision (limited to Microseconds).
1028 // ChunkDemuxer returns the full-precision user-specified double. This ensures
1029 // users can "get" the exact duration they "set".
1030 if (chunk_demuxer_)
1031 return chunk_demuxer_->GetDuration();
1032
avayvodcc273dd2017-01-19 19:35:121033 base::TimeDelta pipeline_duration = GetPipelineMediaDuration();
chcunninghamb92d5062017-01-10 21:50:221034 return pipeline_duration == kInfiniteDuration
1035 ? std::numeric_limits<double>::infinity()
1036 : pipeline_duration.InSecondsF();
[email protected]d43ed912009-02-03 04:52:531037}
1038
[email protected]db66d0092014-04-16 07:15:121039double WebMediaPlayerImpl::timelineOffset() const {
acolwellb4034942014-08-28 15:42:431040 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]db66d0092014-04-16 07:15:121041
1042 if (pipeline_metadata_.timeline_offset.is_null())
1043 return std::numeric_limits<double>::quiet_NaN();
1044
1045 return pipeline_metadata_.timeline_offset.ToJsTime();
1046}
1047
Dale Curtis051fdf62017-08-05 00:21:131048base::TimeDelta WebMediaPlayerImpl::GetCurrentTimeInternal() const {
1049 DCHECK(main_task_runner_->BelongsToCurrentThread());
Dale Curtis051fdf62017-08-05 00:21:131050
1051 base::TimeDelta current_time;
1052 if (Seeking())
1053 current_time = seek_time_;
Dale Curtis051fdf62017-08-05 00:21:131054 else if (paused_)
1055 current_time = paused_time_;
1056 else
Antonio Gomes81b56552019-05-15 22:15:281057 current_time = pipeline_controller_->GetMediaTime();
Dale Curtis051fdf62017-08-05 00:21:131058
Dale Curtis77d6057b2019-05-03 01:31:561059 // It's possible for |current_time| to be kInfiniteDuration here if the page
1060 // seeks to kInfiniteDuration (2**64 - 1) when Duration() is infinite.
Dale Curtis051fdf62017-08-05 00:21:131061 DCHECK_GE(current_time, base::TimeDelta());
1062 return current_time;
1063}
1064
Blink Reformat1c4d759e2017-04-09 16:34:541065double WebMediaPlayerImpl::CurrentTime() const {
acolwellb4034942014-08-28 15:42:431066 DCHECK(main_task_runner_->BelongsToCurrentThread());
Blink Reformat1c4d759e2017-04-09 16:34:541067 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
scherkusd2c745b2014-09-04 05:03:401068
1069 // TODO(scherkus): Replace with an explicit ended signal to HTMLMediaElement,
1070 // see http://crbug.com/409280
Dale Curtis051fdf62017-08-05 00:21:131071 // Note: Duration() may be infinity.
josephlolak918863bc2017-11-15 08:54:331072 return (ended_ && !std::isinf(Duration()))
1073 ? Duration()
1074 : GetCurrentTimeInternal().InSecondsF();
[email protected]d43ed912009-02-03 04:52:531075}
1076
Blink Reformat1c4d759e2017-04-09 16:34:541077WebMediaPlayer::NetworkState WebMediaPlayerImpl::GetNetworkState() const {
acolwellb4034942014-08-28 15:42:431078 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]ddb1e5a2010-12-13 20:10:451079 return network_state_;
1080}
1081
Blink Reformat1c4d759e2017-04-09 16:34:541082WebMediaPlayer::ReadyState WebMediaPlayerImpl::GetReadyState() const {
acolwellb4034942014-08-28 15:42:431083 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]ddb1e5a2010-12-13 20:10:451084 return ready_state_;
1085}
1086
CJ DiMeglio89240472018-10-18 18:21:101087blink::WebMediaPlayer::SurfaceLayerMode
1088WebMediaPlayerImpl::GetVideoSurfaceLayerMode() const {
1089 return surface_layer_mode_;
1090}
1091
wolenetzed8e7092017-04-21 16:28:591092blink::WebString WebMediaPlayerImpl::GetErrorMessage() const {
wolenetz4d39cc02016-04-05 19:54:411093 DCHECK(main_task_runner_->BelongsToCurrentThread());
wolenetzed8e7092017-04-21 16:28:591094 return blink::WebString::FromUTF8(media_log_->GetErrorMessage());
wolenetz4d39cc02016-04-05 19:54:411095}
1096
Blink Reformat1c4d759e2017-04-09 16:34:541097blink::WebTimeRanges WebMediaPlayerImpl::Buffered() const {
acolwellb4034942014-08-28 15:42:431098 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]779a8322014-08-22 21:28:371099
acolwell9e0840d2014-09-06 19:01:321100 Ranges<base::TimeDelta> buffered_time_ranges =
Antonio Gomes81b56552019-05-15 22:15:281101 pipeline_controller_->GetBufferedTimeRanges();
[email protected]779a8322014-08-22 21:28:371102
avayvodcc273dd2017-01-19 19:35:121103 const base::TimeDelta duration = GetPipelineMediaDuration();
dalecurtis39a7f932016-07-19 18:34:591104 if (duration != kInfiniteDuration) {
Antonio Gomes81b56552019-05-15 22:15:281105 buffered_data_source_host_->AddBufferedTimeRanges(&buffered_time_ranges,
1106 duration);
[email protected]779a8322014-08-22 21:28:371107 }
Antonio Gomesf01cfbd2019-07-12 08:53:111108 return blink::ConvertToWebTimeRanges(buffered_time_ranges);
[email protected]02022fc2014-05-16 00:05:311109}
1110
Blink Reformat1c4d759e2017-04-09 16:34:541111blink::WebTimeRanges WebMediaPlayerImpl::Seekable() const {
acolwellb4034942014-08-28 15:42:431112 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]39bdde32013-04-17 17:44:201113
Blink Reformat1c4d759e2017-04-09 16:34:541114 if (ready_state_ < WebMediaPlayer::kReadyStateHaveMetadata)
philipjb0e6f3f2014-09-30 09:51:531115 return blink::WebTimeRanges();
1116
Blink Reformat1c4d759e2017-04-09 16:34:541117 const double seekable_end = Duration();
dalecurtis56359cb2014-10-28 00:06:291118
1119 // Allow a special exception for seeks to zero for streaming sources with a
1120 // finite duration; this allows looping to work.
Dale Curtis4841c712018-12-13 18:14:051121 const bool is_finite_stream = mb_data_source_ &&
1122 mb_data_source_->IsStreaming() &&
tguilbertade2bcb2017-01-07 02:57:451123 std::isfinite(seekable_end);
1124
tguilbert75e2bf62017-04-26 20:13:121125 // Do not change the seekable range when using the MediaPlayerRenderer. It
1126 // will take care of dropping invalid seeks.
1127 const bool force_seeks_to_zero =
1128 !using_media_player_renderer_ && is_finite_stream;
dalecurtis56359cb2014-10-28 00:06:291129
1130 // TODO(dalecurtis): Technically this allows seeking on media which return an
tguilbertade2bcb2017-01-07 02:57:451131 // infinite duration so long as DataSource::IsStreaming() is false. While not
dalecurtis56359cb2014-10-28 00:06:291132 // expected, disabling this breaks semi-live players, http://crbug.com/427412.
1133 const blink::WebTimeRange seekable_range(
tguilbertade2bcb2017-01-07 02:57:451134 0.0, force_seeks_to_zero ? 0.0 : seekable_end);
philipjb0e6f3f2014-09-30 09:51:531135 return blink::WebTimeRanges(&seekable_range, 1);
[email protected]ec9212f2008-12-18 21:40:361136}
1137
sandersd35d2c3f2017-01-14 02:04:421138bool WebMediaPlayerImpl::IsPrerollAttemptNeeded() {
1139 // TODO(sandersd): Replace with |highest_ready_state_since_seek_| if we need
1140 // to ensure that preroll always gets a chance to complete.
1141 // See http://crbug.com/671525.
Dale Curtis69e8f302019-05-22 07:36:581142 //
1143 // Note: Even though we get play/pause signals at kReadyStateHaveMetadata, we
1144 // must attempt to preroll until kReadyStateHaveFutureData so that the
1145 // canplaythrough event will be fired to the page (which may be waiting).
1146 //
1147 // TODO(dalecurtis): We should try signaling kReadyStateHaveFutureData upon
1148 // automatic-suspend of a non-playing element to avoid wasting resources.
1149 if (highest_ready_state_ >= ReadyState::kReadyStateHaveFutureData)
sandersd35d2c3f2017-01-14 02:04:421150 return false;
1151
Fredrik Hubinette4cfb4412017-08-23 00:03:071152 // To suspend before we reach kReadyStateHaveCurrentData is only ok
1153 // if we know we're going to get woken up when we get more data, which
1154 // will only happen if the network is in the "Loading" state.
1155 // This happens when the network is fast, but multiple videos are loading
1156 // and multiplexing gets held up waiting for available threads.
1157 if (highest_ready_state_ <= ReadyState::kReadyStateHaveMetadata &&
1158 network_state_ != WebMediaPlayer::kNetworkStateLoading) {
1159 return true;
1160 }
1161
sandersd35d2c3f2017-01-14 02:04:421162 if (preroll_attempt_pending_)
1163 return true;
1164
1165 // Freshly initialized; there has never been any loading progress. (Otherwise
1166 // |preroll_attempt_pending_| would be true when the start time is null.)
1167 if (preroll_attempt_start_time_.is_null())
1168 return false;
1169
1170 base::TimeDelta preroll_attempt_duration =
1171 tick_clock_->NowTicks() - preroll_attempt_start_time_;
1172 return preroll_attempt_duration < kPrerollAttemptTimeout;
1173}
1174
Blink Reformat1c4d759e2017-04-09 16:34:541175bool WebMediaPlayerImpl::DidLoadingProgress() {
acolwellb4034942014-08-28 15:42:431176 DCHECK(main_task_runner_->BelongsToCurrentThread());
dalecurtise7120dc2016-09-03 02:54:351177
1178 // Note: Separate variables used to ensure both methods are called every time.
Antonio Gomes81b56552019-05-15 22:15:281179 const bool pipeline_progress = pipeline_controller_->DidLoadingProgress();
1180 const bool data_progress = buffered_data_source_host_->DidLoadingProgress();
hubbeb2d3efd2017-05-05 23:26:381181 return pipeline_progress || data_progress;
[email protected]d43ed912009-02-03 04:52:531182}
1183
danakjff6a0262018-06-26 19:50:311184void WebMediaPlayerImpl::Paint(cc::PaintCanvas* canvas,
[email protected]dd5c7972014-08-21 15:00:371185 const blink::WebRect& rect,
Kai Ninomiya9e8ae29b2017-09-06 23:45:161186 cc::PaintFlags& flags,
1187 int already_uploaded_id,
1188 VideoFrameUploadMetadata* out_metadata) {
acolwellb4034942014-08-28 15:42:431189 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]dd061e12014-05-06 19:21:221190 TRACE_EVENT0("media", "WebMediaPlayerImpl:paint");
[email protected]4e6be3f2009-05-07 02:24:441191
watkd16bb3e2017-04-25 01:18:311192 // We can't copy from protected frames.
Xiaohan Wang24cfe2c2018-01-22 23:16:001193 if (cdm_context_ref_)
xhwang80739452016-01-13 00:48:001194 return;
1195
mcasasf1236fc22015-05-29 22:38:561196 scoped_refptr<VideoFrame> video_frame = GetCurrentFrameFromCompositor();
[email protected]0fe5d43b2014-01-24 23:32:451197
[email protected]b49beeb2013-03-01 20:04:001198 gfx::Rect gfx_rect(rect);
mcasas265bdbf82015-06-12 18:44:071199 if (video_frame.get() && video_frame->HasTextures()) {
Antoine Labourfee4ae52019-04-24 23:53:571200 if (!context_provider_)
danakj53f7ec902016-05-21 01:30:101201 return; // Unable to get/create a shared main thread context.
Antoine Labourfee4ae52019-04-24 23:53:571202 if (!context_provider_->GrContext())
danakj53f7ec902016-05-21 01:30:101203 return; // The context has been lost since and can't setup a GrContext.
dongseong.hwang0c4e9d82015-01-08 20:11:131204 }
Kai Ninomiyaef8c9e02017-09-27 04:07:401205 if (out_metadata && video_frame) {
Kai Ninomiya9e8ae29b2017-09-06 23:45:161206 // WebGL last-uploaded-frame-metadata API enabled. https://crbug.com/639174
1207 ComputeFrameUploadMetadata(video_frame.get(), already_uploaded_id,
1208 out_metadata);
1209 if (out_metadata->skipped) {
1210 // Skip uploading this frame.
1211 return;
1212 }
1213 }
zhuoyu.qian4689dde22017-10-16 04:11:481214 video_renderer_.Paint(
Julien Isorce6c83d8de2017-10-12 13:11:291215 video_frame, canvas, gfx::RectF(gfx_rect), flags,
Ted Meyer4a427632019-05-01 19:05:271216 pipeline_metadata_.video_decoder_config.video_transformation(),
Antoine Labourfee4ae52019-04-24 23:53:571217 context_provider_.get());
[email protected]ec9212f2008-12-18 21:40:361218}
[email protected]5df51652009-01-17 00:03:001219
Yutaka Hirano657a0552018-11-09 00:52:551220bool WebMediaPlayerImpl::WouldTaintOrigin() const {
Thomas Guilbert153f84572018-07-19 05:03:581221 if (demuxer_found_hls_) {
1222 // HLS manifests might pull segments from a different origin. We can't know
1223 // for sure, so we conservatively say no here.
Yutaka Hiranoa9cbaa72018-10-10 08:35:221224 return true;
1225 }
1226
Dale Curtis4841c712018-12-13 18:14:051227 if (!mb_data_source_)
Yutaka Hirano657a0552018-11-09 00:52:551228 return false;
1229
1230 // When the resource is redirected to another origin we think it as
1231 // tainted. This is actually not specified, and is under discussion.
1232 // See https://github.com/whatwg/fetch/issues/737.
Dale Curtis4841c712018-12-13 18:14:051233 if (!mb_data_source_->HasSingleOrigin() &&
1234 mb_data_source_->cors_mode() == UrlData::CORS_UNSPECIFIED) {
Yutaka Hirano657a0552018-11-09 00:52:551235 return true;
1236 }
1237
Dale Curtis4841c712018-12-13 18:14:051238 return mb_data_source_->IsCorsCrossOrigin();
[email protected]3fe27112012-06-07 04:00:011239}
1240
Blink Reformat1c4d759e2017-04-09 16:34:541241double WebMediaPlayerImpl::MediaTimeForTimeValue(double timeValue) const {
qinminb4c39782015-08-10 18:43:241242 return base::TimeDelta::FromSecondsD(timeValue).InSecondsF();
[email protected]e06e16d82011-05-26 22:13:331243}
1244
Blink Reformat1c4d759e2017-04-09 16:34:541245unsigned WebMediaPlayerImpl::DecodedFrameCount() const {
acolwellb4034942014-08-28 15:42:431246 DCHECK(main_task_runner_->BelongsToCurrentThread());
Dale Curtisc7d2a7d22018-01-11 20:01:051247 return GetPipelineStatistics().video_frames_decoded;
[email protected]4c51bc662011-02-16 02:03:161248}
1249
Blink Reformat1c4d759e2017-04-09 16:34:541250unsigned WebMediaPlayerImpl::DroppedFrameCount() const {
acolwellb4034942014-08-28 15:42:431251 DCHECK(main_task_runner_->BelongsToCurrentThread());
Dale Curtisc7d2a7d22018-01-11 20:01:051252 return GetPipelineStatistics().video_frames_dropped;
[email protected]4c51bc662011-02-16 02:03:161253}
1254
Dave Tapuska6c7154912018-07-30 20:39:001255uint64_t WebMediaPlayerImpl::AudioDecodedByteCount() const {
acolwellb4034942014-08-28 15:42:431256 DCHECK(main_task_runner_->BelongsToCurrentThread());
Dale Curtisc7d2a7d22018-01-11 20:01:051257 return GetPipelineStatistics().audio_bytes_decoded;
[email protected]4c51bc662011-02-16 02:03:161258}
1259
Dave Tapuska6c7154912018-07-30 20:39:001260uint64_t WebMediaPlayerImpl::VideoDecodedByteCount() const {
acolwellb4034942014-08-28 15:42:431261 DCHECK(main_task_runner_->BelongsToCurrentThread());
Dale Curtisc7d2a7d22018-01-11 20:01:051262 return GetPipelineStatistics().video_bytes_decoded;
[email protected]4c51bc662011-02-16 02:03:161263}
1264
Dale Curtiscdfc6f22019-06-26 22:05:231265bool WebMediaPlayerImpl::HasAvailableVideoFrame() const {
1266 return has_first_frame_;
1267}
1268
Blink Reformat1c4d759e2017-04-09 16:34:541269bool WebMediaPlayerImpl::CopyVideoTextureToPlatformTexture(
danakj46070b02016-03-28 21:54:111270 gpu::gles2::GLES2Interface* gl,
jiajia.qinc2943162017-05-12 01:34:391271 unsigned int target,
zmo57d577a2015-10-30 18:28:591272 unsigned int texture,
kbr0986e622017-04-13 02:34:581273 unsigned internal_format,
1274 unsigned format,
1275 unsigned type,
jiajia.qinc2943162017-05-12 01:34:391276 int level,
zmo57d577a2015-10-30 18:28:591277 bool premultiply_alpha,
Kai Ninomiya9e8ae29b2017-09-06 23:45:161278 bool flip_y,
1279 int already_uploaded_id,
1280 VideoFrameUploadMetadata* out_metadata) {
xhwang213e50c2016-10-10 23:56:311281 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]bfc05f22013-10-19 17:55:161282 TRACE_EVENT0("media", "WebMediaPlayerImpl:copyVideoTextureToPlatformTexture");
1283
watkd16bb3e2017-04-25 01:18:311284 // We can't copy from protected frames.
Xiaohan Wang24cfe2c2018-01-22 23:16:001285 if (cdm_context_ref_)
xhwang213e50c2016-10-10 23:56:311286 return false;
[email protected]dd061e12014-05-06 19:21:221287
xhwang213e50c2016-10-10 23:56:311288 scoped_refptr<VideoFrame> video_frame = GetCurrentFrameFromCompositor();
jbauman581d041c2016-07-21 01:01:031289 if (!video_frame.get() || !video_frame->HasTextures()) {
[email protected]e56f88c72013-06-25 22:31:291290 return false;
dongseong.hwang0c4e9d82015-01-08 20:11:131291 }
Kai Ninomiya9e8ae29b2017-09-06 23:45:161292 if (out_metadata) {
1293 // WebGL last-uploaded-frame-metadata API is enabled.
1294 // https://crbug.com/639174
1295 ComputeFrameUploadMetadata(video_frame.get(), already_uploaded_id,
1296 out_metadata);
1297 if (out_metadata->skipped) {
1298 // Skip uploading this frame.
1299 return true;
1300 }
1301 }
[email protected]df41e252014-02-03 23:39:501302
zhuoyu.qian4689dde22017-10-16 04:11:481303 return video_renderer_.CopyVideoFrameTexturesToGLTexture(
Antoine Labourfee4ae52019-04-24 23:53:571304 context_provider_.get(), gl, video_frame.get(), target, texture,
Dan Sanders930cc1d2018-10-03 00:45:081305 internal_format, format, type, level, premultiply_alpha, flip_y);
[email protected]6523b242013-03-13 11:10:071306}
1307
Yan, Shaobo44b79ba2019-04-02 06:09:271308bool WebMediaPlayerImpl::PrepareVideoFrameForWebGL(
1309 gpu::gles2::GLES2Interface* gl,
1310 unsigned target,
1311 unsigned texture,
1312 int already_uploaded_id,
1313 WebMediaPlayer::VideoFrameUploadMetadata* out_metadata) {
1314 DCHECK(main_task_runner_->BelongsToCurrentThread());
1315 TRACE_EVENT0("media", "WebMediaPlayerImpl::PrepareVideoFrameForWebGL");
1316
1317 // TODO(crbug.com/776222): How to deal with protected frames.
1318 scoped_refptr<VideoFrame> video_frame = GetCurrentFrameFromCompositor();
1319 if (!video_frame.get() || !video_frame->HasTextures()) {
1320 return false;
1321 }
1322 if (out_metadata) {
1323 // WebGL last-uploaded-frame-metadata API is enabled.
1324 ComputeFrameUploadMetadata(video_frame.get(), already_uploaded_id,
1325 out_metadata);
1326 if (out_metadata->skipped) {
1327 // Skip uploading this frame.
1328 return true;
1329 }
1330 }
1331
Yan, Shaobo44b79ba2019-04-02 06:09:271332 return video_renderer_.PrepareVideoFrameForWebGL(
Antoine Labourfee4ae52019-04-24 23:53:571333 context_provider_.get(), gl, video_frame.get(), target, texture);
Yan, Shaobo44b79ba2019-04-02 06:09:271334}
1335
Matt Wolenetz95af6362018-01-04 20:23:421336// static
Kai Ninomiya9e8ae29b2017-09-06 23:45:161337void WebMediaPlayerImpl::ComputeFrameUploadMetadata(
1338 VideoFrame* frame,
1339 int already_uploaded_id,
1340 VideoFrameUploadMetadata* out_metadata) {
1341 DCHECK(out_metadata);
Kai Ninomiyaef8c9e02017-09-27 04:07:401342 DCHECK(frame);
Kai Ninomiya9e8ae29b2017-09-06 23:45:161343 out_metadata->frame_id = frame->unique_id();
1344 out_metadata->visible_rect = frame->visible_rect();
1345 out_metadata->timestamp = frame->timestamp();
1346 bool skip_possible = already_uploaded_id != -1;
1347 bool same_frame_id = frame->unique_id() == already_uploaded_id;
1348 out_metadata->skipped = skip_possible && same_frame_id;
1349}
1350
Blink Reformat1c4d759e2017-04-09 16:34:541351void WebMediaPlayerImpl::SetContentDecryptionModule(
[email protected]9ebc3b03f2014-08-13 04:01:231352 blink::WebContentDecryptionModule* cdm,
1353 blink::WebContentDecryptionModuleResult result) {
xhwang51139732017-02-24 19:36:081354 DVLOG(1) << __func__ << ": cdm = " << cdm;
acolwellb4034942014-08-28 15:42:431355 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]9ebc3b03f2014-08-13 04:01:231356
jrummell06f27072015-06-08 18:12:381357 // Once the CDM is set it can't be cleared as there may be frames being
1358 // decrypted on other threads. So fail this request.
1359 // http://crbug.com/462365#c7.
xhwang97de4202014-11-25 08:44:011360 if (!cdm) {
Blink Reformat1c4d759e2017-04-09 16:34:541361 result.CompleteWithError(
1362 blink::kWebContentDecryptionModuleExceptionInvalidStateError, 0,
xhwang79b193042016-12-13 18:52:431363 "The existing ContentDecryptionModule object cannot be removed at this "
1364 "time.");
xhwang97de4202014-11-25 08:44:011365 return;
1366 }
1367
jrummell89e61d82015-07-23 20:03:341368 // Create a local copy of |result| to avoid problems with the callback
1369 // getting passed to the media thread and causing |result| to be destructed
jrummell4acbec912016-02-27 02:45:031370 // on the wrong thread in some failure conditions. Blink should prevent
1371 // multiple simultaneous calls.
1372 DCHECK(!set_cdm_result_);
jrummell89e61d82015-07-23 20:03:341373 set_cdm_result_.reset(new blink::WebContentDecryptionModuleResult(result));
1374
Chris Cunninghamd4a00192019-03-21 20:02:491375 SetCdmInternal(cdm);
xhwang97de4202014-11-25 08:44:011376}
1377
xhwange8c4181a2014-12-06 08:10:011378void WebMediaPlayerImpl::OnEncryptedMediaInitData(
jrummellcf78967c2015-04-03 05:03:581379 EmeInitDataType init_data_type,
Avi Drissman97785ea2015-12-19 01:11:311380 const std::vector<uint8_t>& init_data) {
jrummellcf78967c2015-04-03 05:03:581381 DCHECK(init_data_type != EmeInitDataType::UNKNOWN);
xhwangbab66f52014-12-02 23:49:501382
Xiaohan Wangf63505d2017-10-21 08:00:531383 RecordEncryptedEvent(true);
xhwangbab66f52014-12-02 23:49:501384
dalecurtis04bdb582016-08-17 22:15:231385 // Recreate the watch time reporter if necessary.
1386 const bool was_encrypted = is_encrypted_;
1387 is_encrypted_ = true;
Dale Curtis3899090ea2018-01-12 00:10:351388 if (!was_encrypted) {
1389 media_metrics_provider_->SetIsEME();
1390 if (watch_time_reporter_)
1391 CreateWatchTimeReporter();
dalecurtis04bdb582016-08-17 22:15:231392
Chris Cunningham6c0ec292019-04-04 18:31:111393 // |was_encrypted| = false means we didn't have a CDM prior to observing
1394 // encrypted media init data. Reset the reporter until the CDM arrives. See
1395 // SetCdmInternal().
1396 DCHECK(!cdm_config_);
1397 video_decode_stats_reporter_.reset();
1398 }
Chris Cunninghamd9df58e2017-08-29 00:04:231399
Blink Reformat1c4d759e2017-04-09 16:34:541400 encrypted_client_->Encrypted(
Antonio Gomes89b70572019-07-13 00:44:211401 init_data_type, init_data.data(),
srirama.m26f864d02015-07-14 05:21:461402 base::saturated_cast<unsigned int>(init_data.size()));
xhwangbab66f52014-12-02 23:49:501403}
1404
servolk81e01e02016-03-05 03:29:151405void WebMediaPlayerImpl::OnFFmpegMediaTracksUpdated(
dcheng3076abbf2016-04-22 20:42:391406 std::unique_ptr<MediaTracks> tracks) {
servolk81e01e02016-03-05 03:29:151407 // For MSE/chunk_demuxer case the media track updates are handled by
1408 // WebSourceBufferImpl.
1409 DCHECK(demuxer_.get());
1410 DCHECK(!chunk_demuxer_);
servolkef1e5ef2016-03-25 04:55:261411
servolk16e8bdf82017-04-11 17:00:391412 // Report the media track information to blink. Only the first audio track and
1413 // the first video track are enabled by default to match blink logic.
1414 bool is_first_audio_track = true;
1415 bool is_first_video_track = true;
servolkef1e5ef2016-03-25 04:55:261416 for (const auto& track : tracks->tracks()) {
1417 if (track->type() == MediaTrack::Audio) {
Maciej Pawlowskif2556d122019-06-03 08:14:181418 client_->AddAudioTrack(
1419 blink::WebString::FromUTF8(track->id().value()),
1420 blink::WebMediaPlayerClient::kAudioTrackKindMain,
1421 blink::WebString::FromUTF8(track->label().value()),
1422 blink::WebString::FromUTF8(track->language().value()),
1423 is_first_audio_track);
servolk16e8bdf82017-04-11 17:00:391424 is_first_audio_track = false;
servolkef1e5ef2016-03-25 04:55:261425 } else if (track->type() == MediaTrack::Video) {
Maciej Pawlowskif2556d122019-06-03 08:14:181426 client_->AddVideoTrack(
1427 blink::WebString::FromUTF8(track->id().value()),
1428 blink::WebMediaPlayerClient::kVideoTrackKindMain,
1429 blink::WebString::FromUTF8(track->label().value()),
1430 blink::WebString::FromUTF8(track->language().value()),
1431 is_first_video_track);
servolk16e8bdf82017-04-11 17:00:391432 is_first_video_track = false;
servolkef1e5ef2016-03-25 04:55:261433 } else {
1434 // Text tracks are not supported through this code path yet.
1435 NOTREACHED();
1436 }
1437 }
servolk81e01e02016-03-05 03:29:151438}
1439
Chris Cunninghamd4a00192019-03-21 20:02:491440void WebMediaPlayerImpl::SetCdmInternal(
1441 blink::WebContentDecryptionModule* cdm) {
jrummelle616ee92016-10-08 02:15:441442 DCHECK(main_task_runner_->BelongsToCurrentThread());
1443 DCHECK(cdm);
Xiaohan Wang24cfe2c2018-01-22 23:16:001444
Chris Cunninghamd4a00192019-03-21 20:02:491445 const bool was_encrypted = is_encrypted_;
1446 is_encrypted_ = true;
1447
1448 // Recreate the watch time reporter if necessary.
1449 if (!was_encrypted) {
1450 media_metrics_provider_->SetIsEME();
1451 if (watch_time_reporter_)
1452 CreateWatchTimeReporter();
1453 }
1454
Chris Cunningham6c0ec292019-04-04 18:31:111455 WebContentDecryptionModuleImpl* web_cdm =
1456 ToWebContentDecryptionModuleImpl(cdm);
1457 auto cdm_context_ref = web_cdm->GetCdmContextRef();
Xiaohan Wang24cfe2c2018-01-22 23:16:001458 if (!cdm_context_ref) {
jrummelle616ee92016-10-08 02:15:441459 NOTREACHED();
1460 OnCdmAttached(false);
xhwang80739452016-01-13 00:48:001461 return;
1462 }
1463
Chris Cunningham6c0ec292019-04-04 18:31:111464 // Arrival of |cdm_config_| and |key_system_| unblocks recording of encrypted
1465 // stats. Attempt to create the stats reporter. Note, we do NOT guard this
1466 // within !was_encypted above because often the CDM arrives after the call to
1467 // OnEncryptedMediaInitData().
1468 cdm_config_ = web_cdm->GetCdmConfig();
1469 key_system_ = web_cdm->GetKeySystem();
1470 DCHECK(!key_system_.empty());
1471 CreateVideoDecodeStatsReporter();
1472
Xiaohan Wang24cfe2c2018-01-22 23:16:001473 CdmContext* cdm_context = cdm_context_ref->GetCdmContext();
1474 DCHECK(cdm_context);
jrummelle616ee92016-10-08 02:15:441475
1476 // Keep the reference to the CDM, as it shouldn't be destroyed until
1477 // after the pipeline is done with the |cdm_context|.
Xiaohan Wang24cfe2c2018-01-22 23:16:001478 pending_cdm_context_ref_ = std::move(cdm_context_ref);
Antonio Gomes81b56552019-05-15 22:15:281479 pipeline_controller_->SetCdm(
Antonio Gomes142f32a2019-05-15 23:32:561480 cdm_context, base::Bind(&WebMediaPlayerImpl::OnCdmAttached, weak_this_));
xhwang97de4202014-11-25 08:44:011481}
1482
jrummell89e61d82015-07-23 20:03:341483void WebMediaPlayerImpl::OnCdmAttached(bool success) {
xhwang51139732017-02-24 19:36:081484 DVLOG(1) << __func__ << ": success = " << success;
jrummelle616ee92016-10-08 02:15:441485 DCHECK(main_task_runner_->BelongsToCurrentThread());
Xiaohan Wang24cfe2c2018-01-22 23:16:001486 DCHECK(pending_cdm_context_ref_);
jrummelle616ee92016-10-08 02:15:441487
1488 // If the CDM is set from the constructor there is no promise
1489 // (|set_cdm_result_|) to fulfill.
xhwang97de4202014-11-25 08:44:011490 if (success) {
xhwang29c5ad202017-04-14 07:02:191491 media_log_->SetBooleanProperty("has_cdm", true);
1492
jrummelle616ee92016-10-08 02:15:441493 // This will release the previously attached CDM (if any).
Xiaohan Wang24cfe2c2018-01-22 23:16:001494 cdm_context_ref_ = std::move(pending_cdm_context_ref_);
jrummelle616ee92016-10-08 02:15:441495 if (set_cdm_result_) {
Blink Reformat1c4d759e2017-04-09 16:34:541496 set_cdm_result_->Complete();
jrummelle616ee92016-10-08 02:15:441497 set_cdm_result_.reset();
1498 }
1499
xhwang97de4202014-11-25 08:44:011500 return;
1501 }
1502
Xiaohan Wang24cfe2c2018-01-22 23:16:001503 pending_cdm_context_ref_.reset();
jrummelle616ee92016-10-08 02:15:441504 if (set_cdm_result_) {
Blink Reformat1c4d759e2017-04-09 16:34:541505 set_cdm_result_->CompleteWithError(
1506 blink::kWebContentDecryptionModuleExceptionNotSupportedError, 0,
xhwang79b193042016-12-13 18:52:431507 "Unable to set ContentDecryptionModule object");
jrummelle616ee92016-10-08 02:15:441508 set_cdm_result_.reset();
1509 }
[email protected]9ebc3b03f2014-08-13 04:01:231510}
1511
sandersd1c0bba02016-03-04 23:14:081512void WebMediaPlayerImpl::OnPipelineSeeked(bool time_updated) {
John Chen5b164a02017-11-01 00:36:091513 TRACE_EVENT2("media", "WebMediaPlayerImpl::OnPipelineSeeked", "target",
1514 seek_time_.InSecondsF(), "id", media_log_->id());
[email protected]5d11eff2011-09-15 00:06:061515 seeking_ = false;
wolenetz1b2ae7d2015-06-10 00:44:211516 seek_time_ = base::TimeDelta();
avayvod2135a642017-01-13 00:17:141517
hubbe5a2dec022016-03-17 01:14:231518 if (paused_) {
Antonio Gomes81b56552019-05-15 22:15:281519 paused_time_ = pipeline_controller_->GetMediaTime();
dalecurtis04bdb582016-08-17 22:15:231520 } else {
1521 DCHECK(watch_time_reporter_);
1522 watch_time_reporter_->OnPlaying();
hubbe5a2dec022016-03-17 01:14:231523 }
sandersd1c0bba02016-03-04 23:14:081524 if (time_updated)
1525 should_notify_time_changed_ = true;
dalecurtisaf34d8712016-09-20 04:32:261526
dalecurtis4f6d14d2017-02-22 17:42:221527 // Reset underflow duration upon seek; this prevents looping videos and user
1528 // actions from artificially inflating the duration.
1529 underflow_timer_.reset();
avayvod56e1f3942017-01-21 02:06:311530
1531 // Background video optimizations are delayed when shown/hidden if pipeline
1532 // is seeking.
1533 UpdateBackgroundVideoOptimizationState();
Dale Curtis2dc6089a2018-03-26 16:47:581534
Dale Curtisd71061f02019-05-21 21:33:541535 // If we successfully completed a suspended startup, we need to make a call to
1536 // UpdatePlayState() in case any events which should trigger a resume have
1537 // occurred during startup.
Dale Curtis2dc6089a2018-03-26 16:47:581538 if (attempting_suspended_start_ &&
Antonio Gomes81b56552019-05-15 22:15:281539 pipeline_controller_->IsPipelineSuspended()) {
Dale Curtisff576552018-03-30 02:32:441540 skip_metrics_due_to_startup_suspend_ = true;
Dale Curtisd71061f02019-05-21 21:33:541541
1542 // If we successfully completed a suspended startup, signal that we have
1543 // reached BUFFERING_HAVE_ENOUGH so that canplay and canplaythrough fire
1544 // correctly. We must unfortunately always do this because it's valid for
1545 // elements to play while not visible nor even in the DOM.
1546 //
1547 // Note: This call is dual purpose, it is also responsible for triggering an
1548 // UpdatePlayState() call which may need to resume the pipeline once Blink
1549 // has been told about the ReadyState change.
Chris Cunninghamfc0d67e2019-07-22 20:29:161550 OnBufferingStateChangeInternal(BUFFERING_HAVE_ENOUGH,
1551 BUFFERING_CHANGE_REASON_UNKNOWN, true);
Dale Curtisff576552018-03-30 02:32:441552
1553 // If |skip_metrics_due_to_startup_suspend_| is unset by a resume started by
1554 // the OnBufferingStateChangeInternal() call, record a histogram of it here.
1555 //
1556 // If the value is unset, that means we should not have suspended and we've
1557 // likely incurred some cost to TimeToFirstFrame and TimeToPlayReady which
1558 // will be reflected in those statistics.
1559 base::UmaHistogramBoolean(
1560 std::string("Media.PreloadMetadataSuspendWasIdeal.") +
1561 ((HasVideo() && HasAudio()) ? "AudioVideo"
1562 : (HasVideo() ? "Video" : "Audio")),
1563 skip_metrics_due_to_startup_suspend_);
Dale Curtis2dc6089a2018-03-26 16:47:581564 }
1565
1566 attempting_suspended_start_ = false;
[email protected]8931c41a2009-07-07 17:31:491567}
1568
sandersd1c0bba02016-03-04 23:14:081569void WebMediaPlayerImpl::OnPipelineSuspended() {
Dale Curtis83321152018-12-01 01:22:061570 // Add a log event so the player shows up as "SUSPENDED" in media-internals.
1571 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::SUSPENDED));
1572
Dale Curtis04769ca2019-05-25 00:38:101573 if (attempting_suspended_start_) {
1574 DCHECK(pipeline_controller_->IsSuspended());
1575 did_lazy_load_ = !has_poster_ && HasVideo();
1576 }
1577
sandersd2f5bb6152017-03-29 22:57:531578 // Tell the data source we have enough data so that it may release the
Dale Curtis04769ca2019-05-25 00:38:101579 // connection (unless blink is waiting on us to signal play()).
1580 if (mb_data_source_ && !client_->CouldPlayIfEnoughData()) {
1581 // |attempting_suspended_start_| will be cleared by OnPipelineSeeked() which
1582 // will occur after this method during a suspended startup.
1583 if (attempting_suspended_start_ && did_lazy_load_) {
1584 DCHECK(!has_first_frame_);
1585 DCHECK(have_enough_after_lazy_load_cb_.IsCancelled());
1586
1587 // For lazy load, we won't know if the element is non-visible until a
1588 // layout completes, so to avoid unnecessarily tearing down the network
1589 // connection, briefly (250ms chosen arbitrarily) delay signaling "have
1590 // enough" to the MultiBufferDataSource.
1591 //
1592 // base::Unretained() is safe here since the base::CancelableOnceClosure
1593 // will cancel upon destruction of this class and |mb_data_source_| is
1594 // gauranteeed to outlive us.
1595 have_enough_after_lazy_load_cb_.Reset(
1596 base::BindOnce(&MultibufferDataSource::OnBufferingHaveEnough,
1597 base::Unretained(mb_data_source_), true));
1598 main_task_runner_->PostDelayedTask(
1599 FROM_HERE, have_enough_after_lazy_load_cb_.callback(),
1600 base::TimeDelta::FromMilliseconds(250));
1601 } else {
1602 have_enough_after_lazy_load_cb_.Cancel();
1603 mb_data_source_->OnBufferingHaveEnough(true);
1604 }
1605 }
dalecurtis37fe5862016-03-15 19:29:091606
sandersd50a635e2016-04-04 22:50:091607 ReportMemoryUsage();
1608
sandersd1c0bba02016-03-04 23:14:081609 if (pending_suspend_resume_cycle_) {
watkdee516f2016-02-18 02:22:191610 pending_suspend_resume_cycle_ = false;
sandersd50a635e2016-04-04 22:50:091611 UpdatePlayState();
dalecurtis0431cbf2016-03-12 01:19:431612 }
sandersd1c0bba02016-03-04 23:14:081613}
1614
avayvod2135a642017-01-13 00:17:141615void WebMediaPlayerImpl::OnBeforePipelineResume() {
Dale Curtis04769ca2019-05-25 00:38:101616 // Since we're resuming, cancel closing of the network connection.
1617 have_enough_after_lazy_load_cb_.Cancel();
1618
Dale Curtisff576552018-03-30 02:32:441619 // We went through suspended startup, so the player is only just now spooling
1620 // up for playback. As such adjust |load_start_time_| so it reports the same
1621 // metric as what would be reported if we had not suspended at startup.
1622 if (skip_metrics_due_to_startup_suspend_) {
1623 // In the event that the call to SetReadyState() initiated after pipeline
1624 // startup immediately tries to start playback, we should not update
1625 // |load_start_time_| to avoid losing visibility into the impact of a
1626 // suspended startup on the time until first frame / play ready for cases
1627 // where suspended startup was applied incorrectly.
1628 if (!attempting_suspended_start_)
1629 load_start_time_ = base::TimeTicks::Now() - time_to_metadata_;
1630 skip_metrics_due_to_startup_suspend_ = false;
1631 }
1632
avayvod2135a642017-01-13 00:17:141633 // Enable video track if we disabled it in the background - this way the new
1634 // renderer will attach its callbacks to the video stream properly.
1635 // TODO(avayvod): Remove this when disabling and enabling video tracks in
1636 // non-playing state works correctly. See https://crbug.com/678374.
1637 EnableVideoTrackIfNeeded();
1638 is_pipeline_resuming_ = true;
1639}
1640
1641void WebMediaPlayerImpl::OnPipelineResumed() {
1642 is_pipeline_resuming_ = false;
1643
avayvod56e1f3942017-01-21 02:06:311644 UpdateBackgroundVideoOptimizationState();
avayvod2135a642017-01-13 00:17:141645}
1646
alokp967c902452016-05-06 05:21:371647void WebMediaPlayerImpl::OnDemuxerOpened() {
1648 DCHECK(main_task_runner_->BelongsToCurrentThread());
dalecurtis9cddc0b2017-04-19 21:23:381649 client_->MediaSourceOpened(new WebMediaSourceImpl(chunk_demuxer_));
alokp967c902452016-05-06 05:21:371650}
1651
servolkf94b4602017-01-31 16:44:271652void WebMediaPlayerImpl::OnMemoryPressure(
1653 base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
1654 DVLOG(2) << __func__ << " memory_pressure_level=" << memory_pressure_level;
1655 DCHECK(main_task_runner_->BelongsToCurrentThread());
1656 DCHECK(base::FeatureList::IsEnabled(kMemoryPressureBasedSourceBufferGC));
1657 DCHECK(chunk_demuxer_);
1658
1659 // The new value of |memory_pressure_level| will take effect on the next
1660 // garbage collection. Typically this means the next SourceBuffer append()
1661 // operation, since per MSE spec, the garbage collection must only occur
1662 // during SourceBuffer append(). But if memory pressure is critical it might
1663 // be better to perform GC immediately rather than wait for the next append
1664 // and potentially get killed due to out-of-memory.
1665 // So if this experiment is enabled and pressure level is critical, we'll pass
1666 // down force_instant_gc==true, which will force immediate GC on
1667 // SourceBufferStreams.
1668 bool force_instant_gc =
1669 (enable_instant_source_buffer_gc_ &&
1670 memory_pressure_level ==
1671 base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
1672
Matt Wolenetz95af6362018-01-04 20:23:421673 // base::Unretained is safe, since |chunk_demuxer_| is actually owned by
1674 // |this| via this->demuxer_. Note the destruction of |chunk_demuxer_| is done
1675 // from ~WMPI by first hopping to |media_task_runner_| to prevent race with
1676 // this task.
servolkf94b4602017-01-31 16:44:271677 media_task_runner_->PostTask(
Dale Curtisee9be30012018-09-21 22:21:511678 FROM_HERE, base::BindOnce(&ChunkDemuxer::OnMemoryPressure,
1679 base::Unretained(chunk_demuxer_),
1680 base::TimeDelta::FromSecondsD(CurrentTime()),
1681 memory_pressure_level, force_instant_gc));
servolkf94b4602017-01-31 16:44:271682}
1683
alokp967c902452016-05-06 05:21:371684void WebMediaPlayerImpl::OnError(PipelineStatus status) {
pkastingf5279482016-07-27 02:18:201685 DVLOG(1) << __func__;
alokp967c902452016-05-06 05:21:371686 DCHECK(main_task_runner_->BelongsToCurrentThread());
1687 DCHECK_NE(status, PIPELINE_OK);
1688
1689 if (suppress_destruction_errors_)
1690 return;
1691
Thomas Guilbert6b6be3d2017-08-18 03:17:271692#if defined(OS_ANDROID)
Dale Curtisf273f8f2018-12-13 23:40:331693 // |mb_data_source_| may be nullptr if someone passes in a m3u8 as a data://
1694 // URL, since MediaPlayer doesn't support data:// URLs, fail playback now.
Dan Sanders675250992019-05-11 00:07:491695 const bool found_hls = base::FeatureList::IsEnabled(kHlsPlayer) &&
1696 status == PipelineStatus::DEMUXER_ERROR_DETECTED_HLS;
Dale Curtisf273f8f2018-12-13 23:40:331697 if (found_hls && mb_data_source_) {
Dan Sandersae245e42019-03-07 23:25:291698 demuxer_found_hls_ = true;
1699
Dan Sandersd80b1842019-02-05 00:36:161700 UMA_HISTOGRAM_BOOLEAN("Media.WebMediaPlayerImpl.HLS.IsCorsCrossOrigin",
1701 mb_data_source_->IsCorsCrossOrigin());
Dan Sandersae245e42019-03-07 23:25:291702 if (mb_data_source_->IsCorsCrossOrigin()) {
1703 UMA_HISTOGRAM_BOOLEAN("Media.WebMediaPlayerImpl.HLS.HasAccessControl",
1704 mb_data_source_->HasAccessControl());
1705 }
1706
1707 // Note: Does not consider the full redirect chain, which could contain
1708 // undetected mixed content.
Dan Sandersd80b1842019-02-05 00:36:161709 bool frame_url_is_cryptographic = url::Origin(frame_->GetSecurityOrigin())
1710 .GetURL()
1711 .SchemeIsCryptographic();
1712 bool manifest_url_is_cryptographic =
1713 loaded_url_.SchemeIsCryptographic() &&
1714 mb_data_source_->GetUrlAfterRedirects().SchemeIsCryptographic();
1715 UMA_HISTOGRAM_BOOLEAN(
1716 "Media.WebMediaPlayerImpl.HLS.IsMixedContent",
1717 frame_url_is_cryptographic && !manifest_url_is_cryptographic);
Thomas Guilbert153f84572018-07-19 05:03:581718
Thomas Guilbert6b6be3d2017-08-18 03:17:271719 renderer_factory_selector_->SetUseMediaPlayer(true);
1720
Dale Curtisf273f8f2018-12-13 23:40:331721 loaded_url_ = mb_data_source_->GetUrlAfterRedirects();
1722 DCHECK(data_source_);
1723 data_source_->Stop();
1724 mb_data_source_ = nullptr;
1725
Antonio Gomes81b56552019-05-15 22:15:281726 pipeline_controller_->Stop();
Dale Curtis8a6281322017-08-31 00:35:531727 SetMemoryReportingState(false);
Thomas Guilbert6b6be3d2017-08-18 03:17:271728
Dale Curtisf273f8f2018-12-13 23:40:331729 // Trampoline through the media task runner to destruct the demuxer and
1730 // data source now that we're switching to HLS playback.
1731 media_task_runner_->PostTask(
Dale Curtisee9be30012018-09-21 22:21:511732 FROM_HERE,
Dale Curtisf273f8f2018-12-13 23:40:331733 BindToCurrentLoop(base::BindOnce(
1734 [](std::unique_ptr<Demuxer> demuxer,
1735 std::unique_ptr<DataSource> data_source,
1736 base::OnceClosure start_pipeline_cb) {
1737 // Release resources before starting HLS.
1738 demuxer.reset();
1739 data_source.reset();
1740
1741 std::move(start_pipeline_cb).Run();
1742 },
1743 std::move(demuxer_), std::move(data_source_),
Antonio Gomes142f32a2019-05-15 23:32:561744 base::BindOnce(&WebMediaPlayerImpl::StartPipeline, weak_this_))));
Dale Curtisf273f8f2018-12-13 23:40:331745
Thomas Guilbert6b6be3d2017-08-18 03:17:271746 return;
1747 }
Dale Curtisf273f8f2018-12-13 23:40:331748
1749 // We found hls in a data:// URL, fail immediately.
1750 if (found_hls)
1751 status = PIPELINE_ERROR_EXTERNAL_RENDERER_FAILED;
Thomas Guilbert6b6be3d2017-08-18 03:17:271752#endif
1753
Dale Curtis5bba03232018-08-30 17:57:381754 MaybeSetContainerName();
dalecurtis9cddc0b2017-04-19 21:23:381755 ReportPipelineError(load_type_, status, media_log_.get());
alokp967c902452016-05-06 05:21:371756 media_log_->AddEvent(media_log_->CreatePipelineErrorEvent(status));
Dale Curtis74612b72017-12-14 20:56:191757 media_metrics_provider_->OnError(status);
Dale Curtisccfd0cca2017-08-31 01:27:561758 if (watch_time_reporter_)
1759 watch_time_reporter_->OnError(status);
alokp967c902452016-05-06 05:21:371760
Blink Reformat1c4d759e2017-04-09 16:34:541761 if (ready_state_ == WebMediaPlayer::kReadyStateHaveNothing) {
alokp967c902452016-05-06 05:21:371762 // Any error that occurs before reaching ReadyStateHaveMetadata should
1763 // be considered a format error.
Blink Reformat1c4d759e2017-04-09 16:34:541764 SetNetworkState(WebMediaPlayer::kNetworkStateFormatError);
alokp967c902452016-05-06 05:21:371765 } else {
Antonio Gomesf01cfbd2019-07-12 08:53:111766 SetNetworkState(blink::PipelineErrorToNetworkState(status));
alokp967c902452016-05-06 05:21:371767 }
1768
Thomas Guilbert2e591392017-08-12 00:56:381769 // PipelineController::Stop() is idempotent.
Antonio Gomes81b56552019-05-15 22:15:281770 pipeline_controller_->Stop();
Thomas Guilbert2e591392017-08-12 00:56:381771
alokp967c902452016-05-06 05:21:371772 UpdatePlayState();
1773}
1774
1775void WebMediaPlayerImpl::OnEnded() {
John Chen5b164a02017-11-01 00:36:091776 TRACE_EVENT2("media", "WebMediaPlayerImpl::OnEnded", "duration", Duration(),
1777 "id", media_log_->id());
pkastingf5279482016-07-27 02:18:201778 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:431779 DCHECK(main_task_runner_->BelongsToCurrentThread());
scherkusd2c745b2014-09-04 05:03:401780
sandersd1c0bba02016-03-04 23:14:081781 // Ignore state changes until we've completed all outstanding operations.
Antonio Gomes81b56552019-05-15 22:15:281782 if (!pipeline_controller_->IsStable())
scherkusd2c745b2014-09-04 05:03:401783 return;
1784
1785 ended_ = true;
Blink Reformat1c4d759e2017-04-09 16:34:541786 client_->TimeChanged();
sandersd50a635e2016-04-04 22:50:091787
1788 // We don't actually want this to run until |client_| calls seek() or pause(),
1789 // but that should have already happened in timeChanged() and so this is
1790 // expected to be a no-op.
1791 UpdatePlayState();
[email protected]576537842009-08-12 23:52:051792}
1793
Chisoon Jeong0a8e4bc2019-05-11 00:06:141794void WebMediaPlayerImpl::OnMetadata(const PipelineMetadata& metadata) {
pkastingf5279482016-07-27 02:18:201795 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:431796 DCHECK(main_task_runner_->BelongsToCurrentThread());
Dale Curtisff576552018-03-30 02:32:441797
1798 // Cache the |time_to_metadata_| to use for adjusting the TimeToFirstFrame and
1799 // TimeToPlayReady metrics later if we end up doing a suspended startup.
1800 time_to_metadata_ = base::TimeTicks::Now() - load_start_time_;
1801 media_metrics_provider_->SetTimeToMetadata(time_to_metadata_);
1802 RecordTimingUMA("Media.TimeToMetadata", time_to_metadata_);
[email protected]a8e2cb82012-08-17 00:02:391803
Dale Curtis5bba03232018-08-30 17:57:381804 MaybeSetContainerName();
1805
[email protected]b8877772014-03-26 20:17:151806 pipeline_metadata_ = metadata;
[email protected]739847c02014-01-16 00:12:251807
Ted Meyer4a427632019-05-01 19:05:271808 UMA_HISTOGRAM_ENUMERATION(
1809 "Media.VideoRotation",
1810 metadata.video_decoder_config.video_transformation().rotation,
1811 VIDEO_ROTATION_MAX + 1);
[email protected]21c3f7502013-03-23 03:29:511812
John Rummelldb5a7ef2018-05-16 00:28:011813 if (HasAudio()) {
Ted Meyerd5885f82019-07-16 19:19:171814 media_metrics_provider_->SetHasAudio(metadata.audio_decoder_config.codec());
John Rummelldb5a7ef2018-05-16 00:28:011815 RecordEncryptionScheme("Audio",
1816 metadata.audio_decoder_config.encryption_scheme());
1817 }
1818
Blink Reformat1c4d759e2017-04-09 16:34:541819 if (HasVideo()) {
Ted Meyerd5885f82019-07-16 19:19:171820 media_metrics_provider_->SetHasVideo(metadata.video_decoder_config.codec());
John Rummelldb5a7ef2018-05-16 00:28:011821 RecordEncryptionScheme("Video",
1822 metadata.video_decoder_config.encryption_scheme());
1823
liberato2fd111be2017-01-04 00:25:061824 if (overlay_enabled_) {
1825 // SurfaceView doesn't support rotated video, so transition back if
[email protected]c8d574722017-08-30 20:53:431826 // the video is now rotated. If |always_enable_overlays_|, we keep the
liberato2fd111be2017-01-04 00:25:061827 // overlay anyway so that the state machine keeps working.
[email protected]c8d574722017-08-30 20:53:431828 // TODO(liberato): verify if compositor feedback catches this. If so,
1829 // then we don't need this check.
1830 if (!always_enable_overlays_ && !DoesOverlaySupportMetadata())
liberato2fd111be2017-01-04 00:25:061831 DisableOverlay();
liberato2fd111be2017-01-04 00:25:061832 }
watkf835a792016-06-24 23:24:401833
[email protected]702d721d2018-10-25 21:55:271834 if (surface_layer_mode_ ==
1835 blink::WebMediaPlayer::SurfaceLayerMode::kAlways ||
1836 (surface_layer_mode_ ==
1837 blink::WebMediaPlayer::SurfaceLayerMode::kOnDemand &&
1838 client_->DisplayType() ==
1839 WebMediaPlayer::DisplayType::kPictureInPicture)) {
1840 ActivateSurfaceLayerForVideo();
1841 } else {
danakj6e669e782018-05-16 16:57:171842 DCHECK(!video_layer_);
Ted Meyer4a427632019-05-01 19:05:271843 // TODO(tmathmeyer) does this need support for reflections as well?
danakj25f030112018-05-11 18:26:541844 video_layer_ = cc::VideoLayer::Create(
Julien Isorce6c83d8de2017-10-12 13:11:291845 compositor_.get(),
Ted Meyer4a427632019-05-01 19:05:271846 pipeline_metadata_.video_decoder_config.video_transformation()
1847 .rotation);
danakj8bc61c72018-05-16 13:55:061848 video_layer_->SetContentsOpaque(opaque_);
danakj8d204a42018-05-18 18:05:351849 client_->SetCcLayer(video_layer_.get());
lethalantidote7f6009d2017-07-07 21:47:391850 }
[email protected]a8e2cb82012-08-17 00:02:391851 }
dalecurtis8e4dc682016-03-15 02:30:301852
xjzd3fe45a2016-10-12 18:26:371853 if (observer_)
xjz15b483f2017-01-12 00:21:361854 observer_->OnMetadataChanged(pipeline_metadata_);
xjzd3fe45a2016-10-12 18:26:371855
Dale Curtisc7d2a7d22018-01-11 20:01:051856 // TODO(dalecurtis): Don't create these until kReadyStateHaveFutureData; when
1857 // we create them early we just increase the chances of needing to throw them
1858 // away unnecessarily.
dalecurtis04bdb582016-08-17 22:15:231859 CreateWatchTimeReporter();
Chris Cunninghamd9df58e2017-08-29 00:04:231860 CreateVideoDecodeStatsReporter();
Dale Curtisc7d2a7d22018-01-11 20:01:051861
Dale Curtis1e7a02b42019-05-28 20:12:241862 // SetReadyState() may trigger all sorts of calls into this class (e.g.,
1863 // Play(), Pause(), etc) so do it last to avoid unexpected states during the
1864 // calls. An exception to this is UpdatePlayState(), which is safe to call and
1865 // needs to use the new ReadyState in its calculations.
Dale Curtis2fc01cc2019-05-20 22:53:521866 SetReadyState(WebMediaPlayer::kReadyStateHaveMetadata);
Dale Curtis1e7a02b42019-05-28 20:12:241867 UpdatePlayState();
[email protected]a8e2cb82012-08-17 00:02:391868}
1869
[email protected]69db58f2018-09-26 20:27:561870void WebMediaPlayerImpl::ActivateSurfaceLayerForVideo() {
1871 // Note that we might or might not already be in VideoLayer mode.
1872 DCHECK(!bridge_);
1873
1874 surface_layer_for_video_enabled_ = true;
1875
1876 // If we're in VideoLayer mode, then get rid of the layer.
1877 if (video_layer_) {
1878 client_->SetCcLayer(nullptr);
1879 video_layer_ = nullptr;
1880 }
1881
1882 bridge_ = std::move(create_bridge_callback_)
1883 .Run(this, compositor_->GetUpdateSubmissionStateCallback());
1884 bridge_->CreateSurfaceLayer();
1885
Ted Meyer4a427632019-05-01 19:05:271886 // TODO(tmathmeyer) does this need support for the reflection transformation
1887 // as well?
[email protected]69db58f2018-09-26 20:27:561888 vfc_task_runner_->PostTask(
1889 FROM_HERE,
Ted Meyer4a427632019-05-01 19:05:271890 base::BindOnce(
1891 &VideoFrameCompositor::EnableSubmission,
1892 base::Unretained(compositor_.get()), bridge_->GetSurfaceId(),
1893 bridge_->GetLocalSurfaceIdAllocationTime(),
1894 pipeline_metadata_.video_decoder_config.video_transformation()
1895 .rotation,
1896 IsInPictureInPicture()));
[email protected]69db58f2018-09-26 20:27:561897 bridge_->SetContentsOpaque(opaque_);
1898
1899 // If the element is already in Picture-in-Picture mode, it means that it
1900 // was set in this mode prior to this load, with a different
1901 // WebMediaPlayerImpl. The new player needs to send its id, size and
1902 // surface id to the browser process to make sure the states are properly
1903 // updated.
1904 // TODO(872056): the surface should be activated but for some reasons, it
1905 // does not. It is possible that this will no longer be needed after 872056
1906 // is fixed.
Dale Curtisca1b78f2019-01-15 03:11:261907 if (IsInPictureInPicture())
[email protected]69db58f2018-09-26 20:27:561908 OnSurfaceIdUpdated(bridge_->GetSurfaceId());
[email protected]69db58f2018-09-26 20:27:561909}
1910
Chris Cunninghamfc0d67e2019-07-22 20:29:161911void WebMediaPlayerImpl::OnBufferingStateChange(
1912 BufferingState state,
1913 BufferingStateChangeReason reason) {
1914 OnBufferingStateChangeInternal(state, reason, false);
Dale Curtis2dc6089a2018-03-26 16:47:581915}
1916
Chris Cunninghamd9df58e2017-08-29 00:04:231917void WebMediaPlayerImpl::CreateVideoDecodeStatsReporter() {
1918 // TODO(chcunningham): destroy reporter if we initially have video but the
1919 // track gets disabled. Currently not possible in default desktop Chrome.
1920 if (!HasVideo())
1921 return;
1922
Chris Cunningham89b4b762019-03-27 17:13:331923 // Only record stats from the local pipeline.
1924 if (is_flinging_ || is_remote_rendering_ || using_media_player_renderer_)
1925 return;
1926
Chris Cunninghamd9df58e2017-08-29 00:04:231927 // Stats reporter requires a valid config. We may not have one for HLS cases
1928 // where URL demuxer doesn't know details of the stream.
1929 if (!pipeline_metadata_.video_decoder_config.IsValidConfig())
1930 return;
1931
Chris Cunningham6c0ec292019-04-04 18:31:111932 // Profile must be known for use as index to save the reported stats.
Chris Cunningham5b1b67eb2019-03-23 03:24:411933 if (pipeline_metadata_.video_decoder_config.profile() ==
1934 VIDEO_CODEC_PROFILE_UNKNOWN) {
1935 return;
1936 }
1937
Chris Cunningham6c0ec292019-04-04 18:31:111938 // CdmConfig must be provided for use as index to save encrypted stats.
1939 if (is_encrypted_ && !cdm_config_) {
Chris Cunninghamd9df58e2017-08-29 00:04:231940 return;
Chris Cunningham6c0ec292019-04-04 18:31:111941 } else if (cdm_config_) {
1942 DCHECK(!key_system_.empty());
1943 }
Chris Cunninghamd9df58e2017-08-29 00:04:231944
Dale Curtis7e8a510d2017-12-14 19:19:481945 mojom::VideoDecodeStatsRecorderPtr recorder;
1946 media_metrics_provider_->AcquireVideoDecodeStatsRecorder(
Dale Curtis7e8a510d2017-12-14 19:19:481947 mojo::MakeRequest(&recorder));
Chris Cunninghamc7c6a6d2017-11-23 14:06:451948
Chris Cunninghamd9df58e2017-08-29 00:04:231949 // Create capabilities reporter and synchronize its initial state.
1950 video_decode_stats_reporter_.reset(new VideoDecodeStatsReporter(
Chris Cunninghamc7c6a6d2017-11-23 14:06:451951 std::move(recorder),
Chris Cunninghamd9df58e2017-08-29 00:04:231952 base::Bind(&WebMediaPlayerImpl::GetPipelineStatistics,
1953 base::Unretained(this)),
Chris Cunningham5b1b67eb2019-03-23 03:24:411954 pipeline_metadata_.video_decoder_config.profile(),
Chris Cunningham6c0ec292019-04-04 18:31:111955 pipeline_metadata_.natural_size, key_system_, cdm_config_,
Hajime Hoshib5a26ee2018-05-14 12:47:511956 frame_->GetTaskRunner(blink::TaskType::kInternalMedia)));
Chris Cunninghamd9df58e2017-08-29 00:04:231957
1958 if (delegate_->IsFrameHidden())
1959 video_decode_stats_reporter_->OnHidden();
1960 else
1961 video_decode_stats_reporter_->OnShown();
1962
1963 if (paused_)
1964 video_decode_stats_reporter_->OnPaused();
1965 else
1966 video_decode_stats_reporter_->OnPlaying();
1967}
1968
hubbeb2d3efd2017-05-05 23:26:381969void WebMediaPlayerImpl::OnProgress() {
Chris Watkins1ffabc5f2017-05-10 20:52:091970 DVLOG(4) << __func__;
Dale Curtisd71061f02019-05-21 21:33:541971 if (highest_ready_state_ < ReadyState::kReadyStateHaveMetadata) {
hubbeb2d3efd2017-05-05 23:26:381972 // Reset the preroll attempt clock.
1973 preroll_attempt_pending_ = true;
1974 preroll_attempt_start_time_ = base::TimeTicks();
1975
1976 // Clear any 'stale' flag and give the pipeline a chance to resume. If we
1977 // are already resumed, this will cause |preroll_attempt_start_time_| to
1978 // be set.
1979 delegate_->ClearStaleFlag(delegate_id_);
1980 UpdatePlayState();
1981 } else if (ready_state_ == ReadyState::kReadyStateHaveFutureData &&
1982 CanPlayThrough()) {
1983 SetReadyState(WebMediaPlayer::kReadyStateHaveEnoughData);
1984 }
1985}
1986
1987bool WebMediaPlayerImpl::CanPlayThrough() {
1988 if (!base::FeatureList::IsEnabled(kSpecCompliantCanPlayThrough))
1989 return true;
1990 if (chunk_demuxer_)
1991 return true;
Dale Curtis4841c712018-12-13 18:14:051992 if (data_source_ && data_source_->AssumeFullyBuffered())
hubbeb2d3efd2017-05-05 23:26:381993 return true;
1994 // If we're not currently downloading, we have as much buffer as
1995 // we're ever going to get, which means we say we can play through.
1996 if (network_state_ == WebMediaPlayer::kNetworkStateIdle)
1997 return true;
Antonio Gomes81b56552019-05-15 22:15:281998 return buffered_data_source_host_->CanPlayThrough(
hubbeb2d3efd2017-05-05 23:26:381999 base::TimeDelta::FromSecondsD(CurrentTime()),
2000 base::TimeDelta::FromSecondsD(Duration()),
2001 playback_rate_ == 0.0 ? 1.0 : playback_rate_);
2002}
2003
Dale Curtisff576552018-03-30 02:32:442004void WebMediaPlayerImpl::OnBufferingStateChangeInternal(
2005 BufferingState state,
Chris Cunninghamfc0d67e2019-07-22 20:29:162006 BufferingStateChangeReason reason,
Dale Curtisff576552018-03-30 02:32:442007 bool for_suspended_start) {
Chris Cunninghamfc0d67e2019-07-22 20:29:162008 DVLOG(1) << __func__ << "(" << state << ", " << reason << ")";
alokp967c902452016-05-06 05:21:372009 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]b8877772014-03-26 20:17:152010
Ted Meyer742212b82018-08-22 17:21:422011 // Ignore buffering state changes caused by back-to-back seeking, so as not
2012 // to assume the second seek has finished when it was only the first seek.
Antonio Gomes81b56552019-05-15 22:15:282013 if (pipeline_controller_->IsPendingSeek())
[email protected]ba7d5f92014-06-24 05:37:402014 return;
[email protected]b8877772014-03-26 20:17:152015
Dale Curtisff576552018-03-30 02:32:442016 auto log_event = media_log_->CreateBufferingStateChangedEvent(
Chris Cunninghamfc0d67e2019-07-22 20:29:162017 "pipeline_buffering_state", state, reason);
Dale Curtisff576552018-03-30 02:32:442018 log_event->params.SetBoolean("for_suspended_start", for_suspended_start);
2019 media_log_->AddEvent(std::move(log_event));
dalecurtis869bf2f2017-01-10 18:01:102020
Ted Meyerd5885f82019-07-16 19:19:172021 if (state == BUFFERING_HAVE_ENOUGH && !for_suspended_start)
2022 media_metrics_provider_->SetHaveEnough();
2023
chcunninghameb270c92016-07-15 01:00:452024 if (state == BUFFERING_HAVE_ENOUGH) {
John Chen5b164a02017-11-01 00:36:092025 TRACE_EVENT1("media", "WebMediaPlayerImpl::BufferingHaveEnough", "id",
2026 media_log_->id());
Dale Curtisff576552018-03-30 02:32:442027 // The SetReadyState() call below may clear
2028 // |skip_metrics_due_to_startup_suspend_| so report this first.
2029 if (!have_reported_time_to_play_ready_ &&
2030 !skip_metrics_due_to_startup_suspend_) {
2031 DCHECK(!for_suspended_start);
Dale Curtis3899090ea2018-01-12 00:10:352032 have_reported_time_to_play_ready_ = true;
2033 const base::TimeDelta elapsed = base::TimeTicks::Now() - load_start_time_;
2034 media_metrics_provider_->SetTimeToPlayReady(elapsed);
2035 RecordTimingUMA("Media.TimeToPlayReady", elapsed);
2036 }
[email protected]ba7d5f92014-06-24 05:37:402037
Dale Curtisff576552018-03-30 02:32:442038 // Warning: This call may be re-entrant.
2039 SetReadyState(CanPlayThrough() ? WebMediaPlayer::kReadyStateHaveEnoughData
2040 : WebMediaPlayer::kReadyStateHaveFutureData);
2041
Dale Curtis18ad391b2019-05-30 23:25:092042 // Let the DataSource know we have enough data -- this is the only function
2043 // during which we advance to (or past) the kReadyStateHaveEnoughData state.
2044 // It may use this information to update buffer sizes or release unused
2045 // network connections.
2046 MaybeUpdateBufferSizesForPlayback();
Dale Curtis04769ca2019-05-25 00:38:102047 if (mb_data_source_ && !client_->CouldPlayIfEnoughData()) {
2048 // For LazyLoad this will be handled during OnPipelineSuspended().
2049 if (for_suspended_start && did_lazy_load_)
2050 DCHECK(!have_enough_after_lazy_load_cb_.IsCancelled());
2051 else
2052 mb_data_source_->OnBufferingHaveEnough(false);
2053 }
dalecurtis849cf4b22015-03-27 18:35:452054
chcunninghameb270c92016-07-15 01:00:452055 // Blink expects a timeChanged() in response to a seek().
sandersd35d2c3f2017-01-14 02:04:422056 if (should_notify_time_changed_) {
2057 should_notify_time_changed_ = false;
Blink Reformat1c4d759e2017-04-09 16:34:542058 client_->TimeChanged();
sandersd35d2c3f2017-01-14 02:04:422059 }
dalecurtis0f0097a2015-12-01 17:40:472060
chcunninghameb270c92016-07-15 01:00:452061 // Once we have enough, start reporting the total memory usage. We'll also
2062 // report once playback starts.
2063 ReportMemoryUsage();
dalecurtis9d638a12016-08-30 06:20:552064
dalecurtis4f6d14d2017-02-22 17:42:222065 // Report the amount of time it took to leave the underflow state.
2066 if (underflow_timer_) {
2067 RecordUnderflowDuration(underflow_timer_->Elapsed());
dalecurtis9d638a12016-08-30 06:20:552068 underflow_timer_.reset();
2069 }
chcunninghameb270c92016-07-15 01:00:452070 } else {
2071 // Buffering has underflowed.
2072 DCHECK_EQ(state, BUFFERING_HAVE_NOTHING);
dalecurtisacd77d62016-09-09 23:23:142073
dalecurtisd06eabc2017-02-24 23:43:292074 // Report the number of times we've entered the underflow state. Ensure we
2075 // only report the value when transitioning from HAVE_ENOUGH to
2076 // HAVE_NOTHING.
Dale Curtis6995b862017-05-31 22:20:082077 if (ready_state_ == WebMediaPlayer::kReadyStateHaveEnoughData &&
2078 !seeking_) {
dalecurtisacd77d62016-09-09 23:23:142079 underflow_timer_.reset(new base::ElapsedTimer());
Dale Curtis6995b862017-05-31 22:20:082080 watch_time_reporter_->OnUnderflow();
2081 }
dalecurtisacd77d62016-09-09 23:23:142082
chcunninghameb270c92016-07-15 01:00:452083 // It shouldn't be possible to underflow if we've not advanced past
2084 // HAVE_CURRENT_DATA.
Blink Reformat1c4d759e2017-04-09 16:34:542085 DCHECK_GT(highest_ready_state_, WebMediaPlayer::kReadyStateHaveCurrentData);
2086 SetReadyState(WebMediaPlayer::kReadyStateHaveCurrentData);
chcunninghameb270c92016-07-15 01:00:452087 }
sandersd50a635e2016-04-04 22:50:092088
2089 UpdatePlayState();
[email protected]b8877772014-03-26 20:17:152090}
2091
alokp967c902452016-05-06 05:21:372092void WebMediaPlayerImpl::OnDurationChange() {
acolwellb4034942014-08-28 15:42:432093 DCHECK(main_task_runner_->BelongsToCurrentThread());
alokp967c902452016-05-06 05:21:372094
John Delaney2371b452018-12-13 04:30:332095 if (frame_->IsAdSubframe()) {
2096 UMA_HISTOGRAM_CUSTOM_TIMES("Ads.Media.Duration", GetPipelineMediaDuration(),
2097 base::TimeDelta::FromMilliseconds(1),
2098 base::TimeDelta::FromDays(1),
2099 50 /* bucket_count */);
2100 }
2101
alokp967c902452016-05-06 05:21:372102 // TODO(sandersd): We should call delegate_->DidPlay() with the new duration,
2103 // especially if it changed from <5s to >5s.
Blink Reformat1c4d759e2017-04-09 16:34:542104 if (ready_state_ == WebMediaPlayer::kReadyStateHaveNothing)
alokp967c902452016-05-06 05:21:372105 return;
2106
Blink Reformat1c4d759e2017-04-09 16:34:542107 client_->DurationChanged();
Dale Curtisaebaeea2018-07-19 23:42:112108 if (watch_time_reporter_)
2109 watch_time_reporter_->OnDurationChanged(GetPipelineMediaDuration());
[email protected]81bb3322011-07-21 15:55:502110}
2111
alokp967c902452016-05-06 05:21:372112void WebMediaPlayerImpl::OnAddTextTrack(const TextTrackConfig& config,
2113 const AddTextTrackDoneCB& done_cb) {
acolwellb4034942014-08-28 15:42:432114 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]71537722013-05-23 06:47:532115
[email protected]8a561062013-11-22 01:19:312116 const WebInbandTextTrackImpl::Kind web_kind =
2117 static_cast<WebInbandTextTrackImpl::Kind>(config.kind());
Blink Reformat1c4d759e2017-04-09 16:34:542118 const blink::WebString web_label = blink::WebString::FromUTF8(config.label());
[email protected]8a561062013-11-22 01:19:312119 const blink::WebString web_language =
Blink Reformat1c4d759e2017-04-09 16:34:542120 blink::WebString::FromUTF8(config.language());
2121 const blink::WebString web_id = blink::WebString::FromUTF8(config.id());
[email protected]71537722013-05-23 06:47:532122
dcheng3076abbf2016-04-22 20:42:392123 std::unique_ptr<WebInbandTextTrackImpl> web_inband_text_track(
henriks9cce5fa2014-12-12 09:35:302124 new WebInbandTextTrackImpl(web_kind, web_label, web_language, web_id));
[email protected]8a561062013-11-22 01:19:312125
Dale Curtisca1b78f2019-01-15 03:11:262126 std::unique_ptr<TextTrack> text_track(new TextTrackImpl(
dcheng652f5ff2015-12-27 08:54:002127 main_task_runner_, client_, std::move(web_inband_text_track)));
[email protected]8a561062013-11-22 01:19:312128
dcheng652f5ff2015-12-27 08:54:002129 done_cb.Run(std::move(text_track));
[email protected]71537722013-05-23 06:47:532130}
2131
Xiaohan Wang640b41d2018-12-18 19:00:462132void WebMediaPlayerImpl::OnWaiting(WaitingReason reason) {
alokp967c902452016-05-06 05:21:372133 DCHECK(main_task_runner_->BelongsToCurrentThread());
2134
Xiaohan Wang640b41d2018-12-18 19:00:462135 switch (reason) {
2136 case WaitingReason::kNoDecryptionKey:
2137 encrypted_client_->DidBlockPlaybackWaitingForKey();
2138 // TODO(jrummell): didResumePlaybackBlockedForKey() should only be called
2139 // when a key has been successfully added (e.g. OnSessionKeysChange() with
2140 // |has_additional_usable_key| = true). http://crbug.com/461903
2141 encrypted_client_->DidResumePlaybackBlockedForKey();
2142 return;
Xiaohan Wang640b41d2018-12-18 19:00:462143
Xiaohan Wanga7224d62019-01-04 22:22:302144 // Ideally this should be handled by PipelineController directly without
2145 // being proxied here. But currently Pipeline::Client (|this|) is passed to
2146 // PipelineImpl directly without going through |pipeline_controller_|,
2147 // making it difficult to do.
2148 // TODO(xhwang): Handle this in PipelineController when we have a clearer
2149 // picture on how to refactor WebMediaPlayerImpl, PipelineController and
2150 // PipelineImpl.
2151 case WaitingReason::kDecoderStateLost:
Antonio Gomes81b56552019-05-15 22:15:282152 pipeline_controller_->OnDecoderStateLost();
Xiaohan Wanga7224d62019-01-04 22:22:302153 return;
2154 }
alokp967c902452016-05-06 05:21:372155}
2156
alokp5d86e9b2016-05-17 20:20:412157void WebMediaPlayerImpl::OnVideoNaturalSizeChange(const gfx::Size& size) {
2158 DCHECK(main_task_runner_->BelongsToCurrentThread());
Blink Reformat1c4d759e2017-04-09 16:34:542159 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
alokp5d86e9b2016-05-17 20:20:412160
Chris Cunningham038548b2017-07-10 22:36:302161 TRACE_EVENT0("media", "WebMediaPlayerImpl::OnVideoNaturalSizeChange");
xhwang60802652017-04-19 07:29:582162
xjz15b483f2017-01-12 00:21:362163 // The input |size| is from the decoded video frame, which is the original
2164 // natural size and need to be rotated accordingly.
Julien Isorce6c83d8de2017-10-12 13:11:292165 gfx::Size rotated_size = GetRotatedVideoSize(
Ted Meyer4a427632019-05-01 19:05:272166 pipeline_metadata_.video_decoder_config.video_transformation().rotation,
2167 size);
sandersd2c478422016-08-02 01:19:252168
xhwang60802652017-04-19 07:29:582169 RecordVideoNaturalSize(rotated_size);
2170
2171 gfx::Size old_size = pipeline_metadata_.natural_size;
2172 if (rotated_size == old_size)
alokp5d86e9b2016-05-17 20:20:412173 return;
2174
xjz516ef6d2017-01-07 00:23:062175 pipeline_metadata_.natural_size = rotated_size;
Dan Sanders7ef5d0f2019-05-03 18:30:112176
2177 if (using_media_player_renderer_ && old_size.IsEmpty()) {
2178 // If we are using MediaPlayerRenderer and this is the first size change, we
2179 // now know that there is a video track. This condition is paired with code
2180 // in CreateWatchTimeReporter() that guesses the existence of a video track.
2181 CreateWatchTimeReporter();
2182 } else {
Dan Sanders7ef5d0f2019-05-03 18:30:112183 UpdateSecondaryProperties();
2184 }
dalecurtis25405562017-04-14 23:35:112185
Chris Cunningham5b1b67eb2019-03-23 03:24:412186 if (video_decode_stats_reporter_ &&
2187 !video_decode_stats_reporter_->MatchesBucketedNaturalSize(
2188 pipeline_metadata_.natural_size)) {
2189 CreateVideoDecodeStatsReporter();
2190 }
Chris Cunninghamd9df58e2017-08-29 00:04:232191
Blink Reformat1c4d759e2017-04-09 16:34:542192 client_->SizeChanged();
xjz516ef6d2017-01-07 00:23:062193
xjz15b483f2017-01-12 00:21:362194 if (observer_)
2195 observer_->OnMetadataChanged(pipeline_metadata_);
peconn257951522017-06-09 18:24:592196
2197 delegate_->DidPlayerSizeChange(delegate_id_, NaturalSize());
alokp5d86e9b2016-05-17 20:20:412198}
2199
2200void WebMediaPlayerImpl::OnVideoOpacityChange(bool opaque) {
2201 DCHECK(main_task_runner_->BelongsToCurrentThread());
Blink Reformat1c4d759e2017-04-09 16:34:542202 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
alokp5d86e9b2016-05-17 20:20:412203
2204 opaque_ = opaque;
Dale Curtis357630f22019-01-18 01:10:172205 if (!surface_layer_for_video_enabled_ && video_layer_)
2206 video_layer_->SetContentsOpaque(opaque_);
2207 else if (bridge_->GetCcLayer())
CJ DiMeglioa2b13fbc2018-06-27 00:50:592208 bridge_->SetContentsOpaque(opaque_);
alokp5d86e9b2016-05-17 20:20:412209}
2210
Chris Cunningham038548b2017-07-10 22:36:302211void WebMediaPlayerImpl::OnAudioConfigChange(const AudioDecoderConfig& config) {
2212 DCHECK(main_task_runner_->BelongsToCurrentThread());
2213 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
2214
Dale Curtisccfd0cca2017-08-31 01:27:562215 const bool codec_change =
2216 pipeline_metadata_.audio_decoder_config.codec() != config.codec();
Chris Cunningham038548b2017-07-10 22:36:302217 pipeline_metadata_.audio_decoder_config = config;
2218
2219 if (observer_)
2220 observer_->OnMetadataChanged(pipeline_metadata_);
Dale Curtisccfd0cca2017-08-31 01:27:562221
2222 if (codec_change)
Dale Curtis96d6e9382018-07-18 18:01:072223 UpdateSecondaryProperties();
Chris Cunningham038548b2017-07-10 22:36:302224}
2225
2226void WebMediaPlayerImpl::OnVideoConfigChange(const VideoDecoderConfig& config) {
2227 DCHECK(main_task_runner_->BelongsToCurrentThread());
2228 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
2229
Dale Curtisccfd0cca2017-08-31 01:27:562230 const bool codec_change =
2231 pipeline_metadata_.video_decoder_config.codec() != config.codec();
Chris Cunningham5b1b67eb2019-03-23 03:24:412232 const bool codec_profile_change =
2233 pipeline_metadata_.video_decoder_config.profile() != config.profile();
Dale Curtisccfd0cca2017-08-31 01:27:562234
Chris Cunningham038548b2017-07-10 22:36:302235 pipeline_metadata_.video_decoder_config = config;
2236
2237 if (observer_)
2238 observer_->OnMetadataChanged(pipeline_metadata_);
Chris Cunninghamd9df58e2017-08-29 00:04:232239
Dale Curtisccfd0cca2017-08-31 01:27:562240 if (codec_change)
Dale Curtis96d6e9382018-07-18 18:01:072241 UpdateSecondaryProperties();
Chris Cunningham5b1b67eb2019-03-23 03:24:412242
2243 if (video_decode_stats_reporter_ && codec_profile_change)
2244 CreateVideoDecodeStatsReporter();
Chris Cunningham038548b2017-07-10 22:36:302245}
2246
avayvodeecec52c2017-02-14 01:25:092247void WebMediaPlayerImpl::OnVideoAverageKeyframeDistanceUpdate() {
2248 UpdateBackgroundVideoOptimizationState();
2249}
2250
Ted Meyerd5885f82019-07-16 19:19:172251void WebMediaPlayerImpl::OnAudioDecoderChange(const PipelineDecoderInfo& info) {
2252 media_metrics_provider_->SetAudioPipelineInfo(info);
2253 if (info.decoder_name == audio_decoder_name_)
Dale Curtisc7d2a7d22018-01-11 20:01:052254 return;
2255
Ted Meyerd5885f82019-07-16 19:19:172256 audio_decoder_name_ = info.decoder_name;
Dale Curtisc7d2a7d22018-01-11 20:01:052257
2258 // If there's no current reporter, there's nothing to be done.
2259 if (!watch_time_reporter_)
2260 return;
2261
Dale Curtis96d6e9382018-07-18 18:01:072262 UpdateSecondaryProperties();
Dale Curtisc7d2a7d22018-01-11 20:01:052263}
2264
Ted Meyerd5885f82019-07-16 19:19:172265void WebMediaPlayerImpl::OnVideoDecoderChange(const PipelineDecoderInfo& info) {
2266 media_metrics_provider_->SetVideoPipelineInfo(info);
2267 if (info.decoder_name == video_decoder_name_)
Dale Curtisc7d2a7d22018-01-11 20:01:052268 return;
2269
Ted Meyerd5885f82019-07-16 19:19:172270 video_decoder_name_ = info.decoder_name;
Dale Curtisc7d2a7d22018-01-11 20:01:052271
2272 // If there's no current reporter, there's nothing to be done.
2273 if (!watch_time_reporter_)
2274 return;
2275
Dale Curtis96d6e9382018-07-18 18:01:072276 UpdateSecondaryProperties();
Dale Curtisc7d2a7d22018-01-11 20:01:052277}
2278
sandersd35d2c3f2017-01-14 02:04:422279void WebMediaPlayerImpl::OnFrameHidden() {
sandersd1e49fb62015-12-12 01:18:062280 DCHECK(main_task_runner_->BelongsToCurrentThread());
avayvod39c102402016-11-23 21:43:132281
avayvod65fad272017-02-24 01:00:482282 // Backgrounding a video requires a user gesture to resume playback.
2283 if (IsHidden())
2284 video_locked_when_paused_when_hidden_ = true;
2285
dalecurtis04bdb582016-08-17 22:15:232286 if (watch_time_reporter_)
2287 watch_time_reporter_->OnHidden();
avayvod48a8be52016-08-04 19:52:502288
Chris Cunninghamd9df58e2017-08-29 00:04:232289 if (video_decode_stats_reporter_)
2290 video_decode_stats_reporter_->OnHidden();
2291
avayvod65fad272017-02-24 01:00:482292 UpdateBackgroundVideoOptimizationState();
sandersd50a635e2016-04-04 22:50:092293 UpdatePlayState();
dalecurtis8b8505e72016-06-10 21:59:172294
2295 // Schedule suspended playing media to be paused if the user doesn't come back
2296 // to it within some timeout period to avoid any autoplay surprises.
2297 ScheduleIdlePauseTimer();
Dale Curtisca1b78f2019-01-15 03:11:262298
2299 // Notify the compositor of our page visibility status.
2300 vfc_task_runner_->PostTask(
2301 FROM_HERE,
2302 base::BindOnce(&VideoFrameCompositor::SetIsPageVisible,
2303 base::Unretained(compositor_.get()), !IsHidden()));
sandersd1e49fb62015-12-12 01:18:062304}
2305
sandersd35d2c3f2017-01-14 02:04:422306void WebMediaPlayerImpl::OnFrameClosed() {
sandersd1e49fb62015-12-12 01:18:062307 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]28347e72017-06-27 17:30:112308
sandersd35d2c3f2017-01-14 02:04:422309 UpdatePlayState();
2310}
2311
2312void WebMediaPlayerImpl::OnFrameShown() {
2313 DCHECK(main_task_runner_->BelongsToCurrentThread());
2314 background_pause_timer_.Stop();
2315
avayvod65fad272017-02-24 01:00:482316 // Foreground videos don't require user gesture to continue playback.
2317 video_locked_when_paused_when_hidden_ = false;
2318
dalecurtis04bdb582016-08-17 22:15:232319 if (watch_time_reporter_)
2320 watch_time_reporter_->OnShown();
2321
Chris Cunninghamd9df58e2017-08-29 00:04:232322 if (video_decode_stats_reporter_)
2323 video_decode_stats_reporter_->OnShown();
2324
Dale Curtisca1b78f2019-01-15 03:11:262325 // Notify the compositor of our page visibility status.
2326 vfc_task_runner_->PostTask(
2327 FROM_HERE,
2328 base::BindOnce(&VideoFrameCompositor::SetIsPageVisible,
2329 base::Unretained(compositor_.get()), !IsHidden()));
2330
Dale Curtisdcbb81a2017-08-18 01:06:122331 UpdateBackgroundVideoOptimizationState();
avayvod65fad272017-02-24 01:00:482332
avayvod2135a642017-01-13 00:17:142333 if (paused_when_hidden_) {
2334 paused_when_hidden_ = false;
2335 OnPlay(); // Calls UpdatePlayState() so return afterwards.
2336 return;
2337 }
2338
sandersd50a635e2016-04-04 22:50:092339 UpdatePlayState();
sandersd1e49fb62015-12-12 01:18:062340}
2341
sandersd35d2c3f2017-01-14 02:04:422342void WebMediaPlayerImpl::OnIdleTimeout() {
dalecurtis0431cbf2016-03-12 01:19:432343 DCHECK(main_task_runner_->BelongsToCurrentThread());
2344
Dale Curtis99a9b482018-02-01 02:23:282345 // This should never be called when stale state testing overrides are used.
2346 DCHECK(!stale_state_override_for_testing_.has_value());
2347
sandersd35d2c3f2017-01-14 02:04:422348 // If we are attempting preroll, clear the stale flag.
2349 if (IsPrerollAttemptNeeded()) {
tguilbert1bb1c782017-01-23 21:15:112350 delegate_->ClearStaleFlag(delegate_id_);
sandersd35d2c3f2017-01-14 02:04:422351 return;
watkd026f792016-11-05 00:28:512352 }
sandersd50a635e2016-04-04 22:50:092353
sandersd35d2c3f2017-01-14 02:04:422354 UpdatePlayState();
dalecurtis0431cbf2016-03-12 01:19:432355}
2356
dalecurtisbb3eaac2016-01-27 21:10:252357void WebMediaPlayerImpl::OnPlay() {
Mounir Lamouri703106e2018-05-30 14:31:092358 client_->RequestPlay();
dalecurtisbb3eaac2016-01-27 21:10:252359}
2360
2361void WebMediaPlayerImpl::OnPause() {
Mounir Lamouri703106e2018-05-30 14:31:092362 client_->RequestPause();
dalecurtisbb3eaac2016-01-27 21:10:252363}
2364
François Beaufortb4fe7c62019-02-27 08:19:442365void WebMediaPlayerImpl::OnMuted(bool muted) {
2366 client_->RequestMuted(muted);
2367}
2368
Alec Douglas316cce42017-10-31 13:28:082369void WebMediaPlayerImpl::OnSeekForward(double seconds) {
2370 DCHECK_GE(seconds, 0) << "Attempted to seek by a negative number of seconds";
2371 client_->RequestSeek(CurrentTime() + seconds);
2372}
2373
2374void WebMediaPlayerImpl::OnSeekBackward(double seconds) {
2375 DCHECK_GE(seconds, 0) << "Attempted to seek by a negative number of seconds";
2376 client_->RequestSeek(CurrentTime() - seconds);
2377}
2378
dalecurtisbb3eaac2016-01-27 21:10:252379void WebMediaPlayerImpl::OnVolumeMultiplierUpdate(double multiplier) {
2380 volume_multiplier_ = multiplier;
Blink Reformat1c4d759e2017-04-09 16:34:542381 SetVolume(volume_);
dalecurtisbb3eaac2016-01-27 21:10:252382}
2383
zqzhang8ac49002017-03-16 21:51:352384void WebMediaPlayerImpl::OnBecamePersistentVideo(bool value) {
Blink Reformat1c4d759e2017-04-09 16:34:542385 client_->OnBecamePersistentVideo(value);
[email protected]6490e2d12019-01-14 19:18:372386 overlay_info_.is_persistent_video = value;
2387 MaybeSendOverlayInfoToDecoder();
zqzhang8ac49002017-03-16 21:51:352388}
2389
John Delaneyc9abf4a2018-10-31 00:39:162390void WebMediaPlayerImpl::SendBytesReceivedUpdate() {
2391 media_metrics_provider_->AddBytesReceived(bytes_received_since_last_update_);
2392 bytes_received_since_last_update_ = 0;
2393}
2394
John Delaneyb933391602018-10-17 21:50:472395void WebMediaPlayerImpl::OnBytesReceived(uint64_t data_length) {
John Delaneyc9abf4a2018-10-31 00:39:162396 bytes_received_since_last_update_ += data_length;
2397 constexpr base::TimeDelta kBytesReceivedUpdateInterval =
2398 base::TimeDelta::FromMilliseconds(500);
2399 auto current_time = base::TimeTicks::Now();
2400 if (earliest_time_next_bytes_received_update_.is_null() ||
2401 earliest_time_next_bytes_received_update_ <= current_time) {
2402 report_bytes_received_timer_.Stop();
2403 SendBytesReceivedUpdate();
2404 earliest_time_next_bytes_received_update_ =
2405 current_time + kBytesReceivedUpdateInterval;
2406 } else {
2407 report_bytes_received_timer_.Start(
2408 FROM_HERE, kBytesReceivedUpdateInterval, this,
2409 &WebMediaPlayerImpl::SendBytesReceivedUpdate);
2410 }
John Delaneyb933391602018-10-17 21:50:472411}
2412
watkdee516f2016-02-18 02:22:192413void WebMediaPlayerImpl::ScheduleRestart() {
sandersd50a635e2016-04-04 22:50:092414 // TODO(watk): All restart logic should be moved into PipelineController.
Antonio Gomes81b56552019-05-15 22:15:282415 if (pipeline_controller_->IsPipelineRunning() &&
2416 !pipeline_controller_->IsPipelineSuspended()) {
watkdee516f2016-02-18 02:22:192417 pending_suspend_resume_cycle_ = true;
sandersd50a635e2016-04-04 22:50:092418 UpdatePlayState();
watkdee516f2016-02-18 02:22:192419 }
2420}
2421
Blink Reformat1c4d759e2017-04-09 16:34:542422void WebMediaPlayerImpl::RequestRemotePlaybackDisabled(bool disabled) {
miu77f914c2016-11-19 23:56:182423 if (observer_)
2424 observer_->OnRemotePlaybackDisabled(disabled);
2425}
2426
Thomas Guilbert7350fdad2019-01-29 23:09:242427#if defined(OS_ANDROID)
Thomas Guilbertb341bae02018-05-09 00:02:132428void WebMediaPlayerImpl::FlingingStarted() {
2429 DCHECK(main_task_runner_->BelongsToCurrentThread());
2430 DCHECK(!disable_pipeline_auto_suspend_);
2431 disable_pipeline_auto_suspend_ = true;
2432
Thomas Guilbert29ae1a902018-10-20 01:53:382433 is_flinging_ = true;
2434
Thomas Guilbertb341bae02018-05-09 00:02:132435 // Capabilities reporting should only be performed for local playbacks.
2436 video_decode_stats_reporter_.reset();
2437
2438 // Requests to restart media pipeline. A flinging renderer will be created via
2439 // the |renderer_factory_selector_|.
2440 ScheduleRestart();
2441}
2442
2443void WebMediaPlayerImpl::FlingingStopped() {
2444 DCHECK(main_task_runner_->BelongsToCurrentThread());
2445 DCHECK(disable_pipeline_auto_suspend_);
2446 disable_pipeline_auto_suspend_ = false;
2447
Thomas Guilbert29ae1a902018-10-20 01:53:382448 is_flinging_ = false;
2449
Thomas Guilbertb341bae02018-05-09 00:02:132450 CreateVideoDecodeStatsReporter();
2451
2452 ScheduleRestart();
2453}
Thomas Guilbert901808982019-07-03 20:38:182454
2455void WebMediaPlayerImpl::OnRemotePlayStateChange(MediaStatus::State state) {
2456 DCHECK(is_flinging_);
2457
2458 if (state == MediaStatus::State::PLAYING && Paused()) {
2459 DVLOG(1) << __func__ << " requesting PLAY.";
2460 client_->RequestPlay();
2461 } else if (state == MediaStatus::State::PAUSED && !Paused()) {
2462 DVLOG(1) << __func__ << " requesting PAUSE.";
2463 client_->RequestPause();
2464 }
2465}
Thomas Guilbert7350fdad2019-01-29 23:09:242466#endif // defined(OS_ANDROID)
hubbee4027f92016-05-19 05:18:132467
Blink Reformat1c4d759e2017-04-09 16:34:542468void WebMediaPlayerImpl::SetPoster(const blink::WebURL& poster) {
Dan Sanderscd8981c2017-08-31 22:37:022469 has_poster_ = !poster.IsEmpty();
Dan Sanderscd8981c2017-08-31 22:37:022470}
xjzc102fd82017-01-04 20:13:532471
[email protected]fee8a902014-06-03 13:43:362472void WebMediaPlayerImpl::DataSourceInitialized(bool success) {
pkastingf5279482016-07-27 02:18:202473 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:432474 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]a9415292012-01-19 19:55:202475
Thomas Guilberta8a6e922019-02-01 00:02:472476 if (observer_ && mb_data_source_)
Dale Curtis4841c712018-12-13 18:14:052477 observer_->OnDataSourceInitialized(mb_data_source_->GetUrlAfterRedirects());
Anton Vayvod09fa66e2017-07-20 23:02:122478
[email protected]d250190da3b2012-07-23 22:57:302479 if (!success) {
Blink Reformat1c4d759e2017-04-09 16:34:542480 SetNetworkState(WebMediaPlayer::kNetworkStateFormatError);
Dale Curtis74612b72017-12-14 20:56:192481 media_metrics_provider_->OnError(PIPELINE_ERROR_NETWORK);
sandersd50a635e2016-04-04 22:50:092482
2483 // Not really necessary, since the pipeline was never started, but it at
2484 // least this makes sure that the error handling code is in sync.
2485 UpdatePlayState();
2486
[email protected]a9415292012-01-19 19:55:202487 return;
2488 }
2489
hubbee2cc88c092017-07-14 23:10:412490 // No point in preloading data as we'll probably just throw it away anyways.
Dale Curtis4841c712018-12-13 18:14:052491 if (IsStreaming() && preload_ > MultibufferDataSource::METADATA &&
2492 mb_data_source_) {
2493 mb_data_source_->SetPreload(MultibufferDataSource::METADATA);
hubbee2cc88c092017-07-14 23:10:412494 }
2495
[email protected]ef8394c2013-08-21 20:26:302496 StartPipeline();
[email protected]a9415292012-01-19 19:55:202497}
2498
[email protected]122f40252012-06-12 05:01:562499void WebMediaPlayerImpl::NotifyDownloading(bool is_downloading) {
hubbeb2d3efd2017-05-05 23:26:382500 DVLOG(1) << __func__ << "(" << is_downloading << ")";
Blink Reformat1c4d759e2017-04-09 16:34:542501 if (!is_downloading && network_state_ == WebMediaPlayer::kNetworkStateLoading)
2502 SetNetworkState(WebMediaPlayer::kNetworkStateIdle);
2503 else if (is_downloading &&
2504 network_state_ == WebMediaPlayer::kNetworkStateIdle)
2505 SetNetworkState(WebMediaPlayer::kNetworkStateLoading);
hubbeb2d3efd2017-05-05 23:26:382506 if (ready_state_ == ReadyState::kReadyStateHaveFutureData && !is_downloading)
2507 SetReadyState(WebMediaPlayer::kReadyStateHaveEnoughData);
[email protected]122f40252012-06-12 05:01:562508}
2509
liberato2ff93ad2017-05-17 07:28:242510void WebMediaPlayerImpl::OnOverlayRoutingToken(
2511 const base::UnguessableToken& token) {
2512 DCHECK(overlay_mode_ == OverlayMode::kUseAndroidOverlay);
liberatofe8f9692017-06-08 19:17:362513 // TODO(liberato): |token| should already be a RoutingToken.
2514 overlay_routing_token_is_pending_ = false;
2515 overlay_routing_token_ = OverlayInfo::RoutingToken(token);
liberato2ff93ad2017-05-17 07:28:242516 MaybeSendOverlayInfoToDecoder();
2517}
2518
2519void WebMediaPlayerImpl::OnOverlayInfoRequested(
dalecurtis4b632fce22016-11-10 00:52:172520 bool decoder_requires_restart_for_overlay,
liberato2ff93ad2017-05-17 07:28:242521 const ProvideOverlayInfoCB& provide_overlay_info_cb) {
watkdee516f2016-02-18 02:22:192522 DCHECK(main_task_runner_->BelongsToCurrentThread());
watkdee516f2016-02-18 02:22:192523
Chris Watkins557f84d2017-09-16 02:31:462524 // If we get a non-null cb, a decoder is initializing and requires overlay
2525 // info. If we get a null cb, a previously initialized decoder is
2526 // unregistering for overlay info updates.
Dale Curtise25163812018-09-21 22:13:392527 if (!provide_overlay_info_cb) {
tsunghungee562e92016-07-20 18:03:312528 decoder_requires_restart_for_overlay_ = false;
liberato2ff93ad2017-05-17 07:28:242529 provide_overlay_info_cb_.Reset();
watkdee516f2016-02-18 02:22:192530 return;
2531 }
2532
dalecurtis4b632fce22016-11-10 00:52:172533 // If |decoder_requires_restart_for_overlay| is true, we must restart the
2534 // pipeline for fullscreen transitions. The decoder is unable to switch
2535 // surfaces otherwise. If false, we simply need to tell the decoder about the
2536 // new surface and it will handle things seamlessly.
Chris Watkins557f84d2017-09-16 02:31:462537 // For encrypted video we pretend that the decoder doesn't require a restart
2538 // because it needs an overlay all the time anyway. We'll switch into
2539 // |always_enable_overlays_| mode below.
2540 decoder_requires_restart_for_overlay_ =
2541 (overlay_mode_ == OverlayMode::kUseAndroidOverlay && is_encrypted_)
2542 ? false
2543 : decoder_requires_restart_for_overlay;
liberato2ff93ad2017-05-17 07:28:242544 provide_overlay_info_cb_ = provide_overlay_info_cb;
dalecurtis4b632fce22016-11-10 00:52:172545
Chris Watkins557f84d2017-09-16 02:31:462546 // If the decoder doesn't require restarts for surface transitions, and we're
2547 // using AndroidOverlay mode, we can always enable the overlay and the decoder
2548 // can choose whether or not to use it. Otherwise, we'll restart the decoder
2549 // and enable the overlay on fullscreen transitions.
[email protected]77568482017-06-21 21:16:522550 if (overlay_mode_ == OverlayMode::kUseAndroidOverlay &&
Chris Watkins557f84d2017-09-16 02:31:462551 !decoder_requires_restart_for_overlay_) {
[email protected]c8d574722017-08-30 20:53:432552 always_enable_overlays_ = true;
[email protected]77568482017-06-21 21:16:522553 if (!overlay_enabled_)
2554 EnableOverlay();
2555 }
2556
Chris Watkins557f84d2017-09-16 02:31:462557 // Send the overlay info if we already have it. If not, it will be sent later.
liberato2ff93ad2017-05-17 07:28:242558 MaybeSendOverlayInfoToDecoder();
2559}
2560
2561void WebMediaPlayerImpl::MaybeSendOverlayInfoToDecoder() {
2562 // If the decoder didn't request overlay info, then don't send it.
2563 if (!provide_overlay_info_cb_)
dalecurtis4b632fce22016-11-10 00:52:172564 return;
2565
liberato2ff93ad2017-05-17 07:28:242566 // We should send the overlay info as long as we know it. This includes the
2567 // case where |!overlay_enabled_|, since we want to tell the decoder to avoid
2568 // using overlays. Assuming that the decoder has requested info, the only
2569 // case in which we don't want to send something is if we've requested the
2570 // info but not received it yet. Then, we should wait until we do.
liberatofe8f9692017-06-08 19:17:362571 //
2572 // Initialization requires this; AVDA should start with enough info to make an
2573 // overlay, so that (pre-M) the initial codec is created with the right output
2574 // surface; it can't switch later.
[email protected]f7df5b342018-07-13 20:22:132575 if (overlay_mode_ == OverlayMode::kUseAndroidOverlay) {
liberatofe8f9692017-06-08 19:17:362576 if (overlay_routing_token_is_pending_)
liberato2ff93ad2017-05-17 07:28:242577 return;
liberatofe8f9692017-06-08 19:17:362578
2579 overlay_info_.routing_token = overlay_routing_token_;
liberato2ff93ad2017-05-17 07:28:242580 }
2581
liberato2ff93ad2017-05-17 07:28:242582 // If restart is required, the callback is one-shot only.
2583 if (decoder_requires_restart_for_overlay_) {
Dale Curtise25163812018-09-21 22:13:392584 std::move(provide_overlay_info_cb_).Run(overlay_info_);
liberato2ff93ad2017-05-17 07:28:242585 } else {
liberatofe8f9692017-06-08 19:17:362586 provide_overlay_info_cb_.Run(overlay_info_);
liberato2ff93ad2017-05-17 07:28:242587 }
watkdee516f2016-02-18 02:22:192588}
2589
dcheng3076abbf2016-04-22 20:42:392590std::unique_ptr<Renderer> WebMediaPlayerImpl::CreateRenderer() {
dcheng37b415b92017-01-27 20:17:432591 DCHECK(main_task_runner_->BelongsToCurrentThread());
2592
[email protected]c8d574722017-08-30 20:53:432593 // Make sure that overlays are enabled if they're always allowed.
2594 if (always_enable_overlays_)
tsunghungee562e92016-07-20 18:03:312595 EnableOverlay();
2596
liberato2ff93ad2017-05-17 07:28:242597 RequestOverlayInfoCB request_overlay_info_cb;
watkdee516f2016-02-18 02:22:192598#if defined(OS_ANDROID)
liberato2ff93ad2017-05-17 07:28:242599 request_overlay_info_cb = BindToCurrentLoop(
Antonio Gomes142f32a2019-05-15 23:32:562600 base::Bind(&WebMediaPlayerImpl::OnOverlayInfoRequested, weak_this_));
watkdee516f2016-02-18 02:22:192601#endif
tguilbert70d2a00a2017-04-25 00:30:442602 return renderer_factory_selector_->GetCurrentFactory()->CreateRenderer(
sandersd1e49fb62015-12-12 01:18:062603 media_task_runner_, worker_task_runner_, audio_source_provider_.get(),
CJ DiMeglio2302d202017-08-31 08:38:042604 compositor_.get(), request_overlay_info_cb, client_->TargetColorSpace());
sandersd1e49fb62015-12-12 01:18:062605}
2606
[email protected]ef8394c2013-08-21 20:26:302607void WebMediaPlayerImpl::StartPipeline() {
acolwellb4034942014-08-28 15:42:432608 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]ddbc6ff2013-04-19 15:28:332609
xhwange8c4181a2014-12-06 08:10:012610 Demuxer::EncryptedMediaInitDataCB encrypted_media_init_data_cb =
dcheng37b415b92017-01-27 20:17:432611 BindToCurrentLoop(base::Bind(
Antonio Gomes142f32a2019-05-15 23:32:562612 &WebMediaPlayerImpl::OnEncryptedMediaInitData, weak_this_));
[email protected]2b57e2e2014-05-09 11:07:252613
Dale Curtis3899090ea2018-01-12 00:10:352614 vfc_task_runner_->PostTask(
2615 FROM_HERE,
2616 base::BindOnce(&VideoFrameCompositor::SetOnNewProcessedFrameCallback,
2617 base::Unretained(compositor_.get()),
2618 BindToCurrentLoop(base::BindOnce(
Antonio Gomes142f32a2019-05-15 23:32:562619 &WebMediaPlayerImpl::OnFirstFrame, weak_this_))));
Dale Curtis3899090ea2018-01-12 00:10:352620
Thomas Guilbert55b48d92019-03-25 23:16:542621#if defined(OS_ANDROID)
Dale Curtis65c151a2019-02-26 02:09:322622 if (demuxer_found_hls_ ||
2623 renderer_factory_selector_->GetCurrentFactory()
2624 ->GetRequiredMediaResourceType() == MediaResource::Type::URL) {
Thomas Guilbert8a42fcf2019-03-01 20:21:452625 // MediaPlayerRendererClientFactory is the only factory that a uses
2626 // MediaResource::Type::URL for the moment.
tguilbert75e2bf62017-04-26 20:13:122627 using_media_player_renderer_ = true;
2628
Chris Cunninghamd9df58e2017-08-29 00:04:232629 // MediaPlayerRenderer does not provide pipeline stats, so nuke capabilities
2630 // reporter.
2631 video_decode_stats_reporter_.reset();
2632
Thomas Guilbert55b48d92019-03-25 23:16:542633 demuxer_.reset(new MediaUrlDemuxer(
2634 media_task_runner_, loaded_url_, frame_->GetDocument().SiteForCookies(),
Dan Sanders3ff9ffe2019-07-19 22:24:122635 allow_media_player_renderer_credentials_, demuxer_found_hls_));
Antonio Gomes81b56552019-05-15 22:15:282636 pipeline_controller_->Start(Pipeline::StartType::kNormal, demuxer_.get(),
2637 this, false, false);
tguilbert25a4d112016-10-13 21:56:512638 return;
2639 }
Thomas Guilbert55b48d92019-03-25 23:16:542640#endif // defined(OS_ANDROID)
tguilbert25a4d112016-10-13 21:56:512641
[email protected]ddbc6ff2013-04-19 15:28:332642 // Figure out which demuxer to use.
Blink Reformat1c4d759e2017-04-09 16:34:542643 if (load_type_ != kLoadTypeMediaSource) {
[email protected]ddbc6ff2013-04-19 15:28:332644 DCHECK(!chunk_demuxer_);
[email protected]f5443ef72013-04-22 04:03:382645 DCHECK(data_source_);
2646
Dale Curtisbcf523b2018-01-17 02:59:012647#if BUILDFLAG(ENABLE_FFMPEG)
servolk81e01e02016-03-05 03:29:152648 Demuxer::MediaTracksUpdatedCB media_tracks_updated_cb =
dcheng37b415b92017-01-27 20:17:432649 BindToCurrentLoop(base::Bind(
Antonio Gomes142f32a2019-05-15 23:32:562650 &WebMediaPlayerImpl::OnFFmpegMediaTracksUpdated, weak_this_));
servolk81e01e02016-03-05 03:29:152651
dalecurtis9cddc0b2017-04-19 21:23:382652 demuxer_.reset(new FFmpegDemuxer(
2653 media_task_runner_, data_source_.get(), encrypted_media_init_data_cb,
Dale Curtisb8139f72018-08-27 23:28:482654 media_tracks_updated_cb, media_log_.get(), IsLocalFile(loaded_url_)));
j.isorcef6778e652015-11-16 17:14:252655#else
alokp967c902452016-05-06 05:21:372656 OnError(PipelineStatus::DEMUXER_ERROR_COULD_NOT_OPEN);
j.isorcef6778e652015-11-16 17:14:252657 return;
2658#endif
[email protected]ddbc6ff2013-04-19 15:28:332659 } else {
[email protected]f5443ef72013-04-22 04:03:382660 DCHECK(!chunk_demuxer_);
2661 DCHECK(!data_source_);
2662
Antonio Gomes142f32a2019-05-15 23:32:562663 chunk_demuxer_ =
2664 new ChunkDemuxer(BindToCurrentLoop(base::Bind(
2665 &WebMediaPlayerImpl::OnDemuxerOpened, weak_this_)),
2666 BindToCurrentLoop(base::Bind(
2667 &WebMediaPlayerImpl::OnProgress, weak_this_)),
2668 encrypted_media_init_data_cb, media_log_.get());
John Delaneyb933391602018-10-17 21:50:472669 // Notify |this| of bytes that are received via MSE.
Antonio Gomes142f32a2019-05-15 23:32:562670 chunk_demuxer_->AddBytesReceivedCallback(BindToCurrentLoop(
2671 base::BindRepeating(&WebMediaPlayerImpl::OnBytesReceived, weak_this_)));
[email protected]f5443ef72013-04-22 04:03:382672 demuxer_.reset(chunk_demuxer_);
servolkf94b4602017-01-31 16:44:272673
2674 if (base::FeatureList::IsEnabled(kMemoryPressureBasedSourceBufferGC)) {
2675 // base::Unretained is safe because |this| owns memory_pressure_listener_.
2676 memory_pressure_listener_ =
Gyuyoung Kim62a5de42018-01-10 09:48:422677 std::make_unique<base::MemoryPressureListener>(base::Bind(
servolkf94b4602017-01-31 16:44:272678 &WebMediaPlayerImpl::OnMemoryPressure, base::Unretained(this)));
2679 }
[email protected]ddbc6ff2013-04-19 15:28:332680 }
2681
sandersdb5e21462016-03-09 01:49:072682 // TODO(sandersd): FileSystem objects may also be non-static, but due to our
2683 // caching layer such situations are broken already. http://crbug.com/593159
2684 bool is_static = !chunk_demuxer_;
avayvod102cdb62017-01-07 03:11:092685 bool is_streaming = IsStreaming();
sandersdb8eb5f1d2016-11-19 04:04:022686 UMA_HISTOGRAM_BOOLEAN("Media.IsStreaming", is_streaming);
sandersdb5e21462016-03-09 01:49:072687
Dale Curtis2dc6089a2018-03-26 16:47:582688 // If possible attempt to avoid decoder spool up until playback starts.
2689 Pipeline::StartType start_type = Pipeline::StartType::kNormal;
Dale Curtis7c63f2e22018-09-19 21:06:272690 if (!chunk_demuxer_ && preload_ == MultibufferDataSource::METADATA &&
Dale Curtisd6ccd1992019-04-29 19:03:462691 !client_->CouldPlayIfEnoughData() && !IsStreaming()) {
Dale Curtis7c63f2e22018-09-19 21:06:272692 start_type =
2693 (has_poster_ || base::FeatureList::IsEnabled(kPreloadMetadataLazyLoad))
2694 ? Pipeline::StartType::kSuspendAfterMetadata
2695 : Pipeline::StartType::kSuspendAfterMetadataForAudioOnly;
Dale Curtis2dc6089a2018-03-26 16:47:582696 attempting_suspended_start_ = true;
2697 }
2698
[email protected]f5443ef72013-04-22 04:03:382699 // ... and we're ready to go!
sandersd1e49fb62015-12-12 01:18:062700 // TODO(sandersd): On Android, defer Start() if the tab is not visible.
sandersdb8eb5f1d2016-11-19 04:04:022701 seeking_ = true;
Antonio Gomes81b56552019-05-15 22:15:282702 pipeline_controller_->Start(start_type, demuxer_.get(), this, is_streaming,
2703 is_static);
[email protected]f5443ef72013-04-22 04:03:382704}
2705
2706void WebMediaPlayerImpl::SetNetworkState(WebMediaPlayer::NetworkState state) {
pkastingf5279482016-07-27 02:18:202707 DVLOG(1) << __func__ << "(" << state << ")";
acolwellb4034942014-08-28 15:42:432708 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]f5443ef72013-04-22 04:03:382709 network_state_ = state;
2710 // Always notify to ensure client has the latest value.
Blink Reformat1c4d759e2017-04-09 16:34:542711 client_->NetworkStateChanged();
[email protected]f5443ef72013-04-22 04:03:382712}
2713
2714void WebMediaPlayerImpl::SetReadyState(WebMediaPlayer::ReadyState state) {
pkastingf5279482016-07-27 02:18:202715 DVLOG(1) << __func__ << "(" << state << ")";
acolwellb4034942014-08-28 15:42:432716 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]f5443ef72013-04-22 04:03:382717
Blink Reformat1c4d759e2017-04-09 16:34:542718 if (state == WebMediaPlayer::kReadyStateHaveEnoughData && data_source_ &&
Dale Curtis4841c712018-12-13 18:14:052719 data_source_->AssumeFullyBuffered() &&
2720 network_state_ == WebMediaPlayer::kNetworkStateLoading) {
Blink Reformat1c4d759e2017-04-09 16:34:542721 SetNetworkState(WebMediaPlayer::kNetworkStateLoaded);
Dale Curtis4841c712018-12-13 18:14:052722 }
[email protected]f5443ef72013-04-22 04:03:382723
2724 ready_state_ = state;
sandersd50a635e2016-04-04 22:50:092725 highest_ready_state_ = std::max(highest_ready_state_, ready_state_);
2726
[email protected]f5443ef72013-04-22 04:03:382727 // Always notify to ensure client has the latest value.
Blink Reformat1c4d759e2017-04-09 16:34:542728 client_->ReadyStateChanged();
[email protected]f5443ef72013-04-22 04:03:382729}
2730
Antonio Gomesa38bb7cb2019-05-31 03:02:522731scoped_refptr<blink::WebAudioSourceProviderImpl>
2732WebMediaPlayerImpl::GetAudioSourceProvider() {
2733 return audio_source_provider_;
[email protected]f5443ef72013-04-22 04:03:382734}
2735
Jiajia Qin82acdc02017-07-31 09:55:142736scoped_refptr<VideoFrame> WebMediaPlayerImpl::GetCurrentFrameFromCompositor()
2737 const {
xhwang213e50c2016-10-10 23:56:312738 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]dd061e12014-05-06 19:21:222739 TRACE_EVENT0("media", "WebMediaPlayerImpl::GetCurrentFrameFromCompositor");
xhwang213e50c2016-10-10 23:56:312740
Thomas Guilbertd85407412017-11-08 05:03:462741 // Can be null.
2742 scoped_refptr<VideoFrame> video_frame =
2743 compositor_->GetCurrentFrameOnAnyThread();
[email protected]dd061e12014-05-06 19:21:222744
Thomas Guilbertd85407412017-11-08 05:03:462745 // base::Unretained is safe here because |compositor_| is destroyed on
2746 // |vfc_task_runner_|. The destruction is queued from |this|' destructor,
2747 // which also runs on |main_task_runner_|, which makes it impossible for
2748 // UpdateCurrentFrameIfStale() to be queued after |compositor_|'s dtor.
CJ DiMeglio2302d202017-08-31 08:38:042749 vfc_task_runner_->PostTask(
Dale Curtisee9be30012018-09-21 22:21:512750 FROM_HERE,
2751 base::BindOnce(&VideoFrameCompositor::UpdateCurrentFrameIfStale,
2752 base::Unretained(compositor_.get())));
kainino36eeff82017-03-30 00:55:302753
[email protected]dd061e12014-05-06 19:21:222754 return video_frame;
2755}
2756
sandersd50a635e2016-04-04 22:50:092757void WebMediaPlayerImpl::UpdatePlayState() {
xhwang213e50c2016-10-10 23:56:312758 DCHECK(main_task_runner_->BelongsToCurrentThread());
hubbee2cc88c092017-07-14 23:10:412759 bool can_auto_suspend = !disable_pipeline_auto_suspend_;
2760 // For streaming videos, we only allow suspending at the very beginning of the
2761 // video, and only if we know the length of the video. (If we don't know
2762 // the length, it might be a dynamically generated video, and suspending
2763 // will not work at all.)
2764 if (IsStreaming()) {
2765 bool at_beginning =
2766 ready_state_ == WebMediaPlayer::kReadyStateHaveNothing ||
2767 CurrentTime() == 0.0;
2768 if (!at_beginning || GetPipelineMediaDuration() == kInfiniteDuration)
2769 can_auto_suspend = false;
2770 }
xhwang213e50c2016-10-10 23:56:312771
Antonio Gomes81b56552019-05-15 22:15:282772 bool is_suspended = pipeline_controller_->IsSuspended();
Sergey Volk8b09c2c52018-12-12 23:20:402773 bool is_backgrounded = IsBackgroundSuspendEnabled(this) && IsHidden();
sandersdaaff1a652016-11-17 01:47:252774 PlayState state = UpdatePlayState_ComputePlayState(
Thomas Guilbert7350fdad2019-01-29 23:09:242775 is_flinging_, can_auto_suspend, is_suspended, is_backgrounded);
sandersd35d2c3f2017-01-14 02:04:422776 SetDelegateState(state.delegate_state, state.is_idle);
sandersd50a635e2016-04-04 22:50:092777 SetMemoryReportingState(state.is_memory_reporting_enabled);
2778 SetSuspendState(state.is_suspended || pending_suspend_resume_cycle_);
2779}
dalecurtis5bbc487e2016-02-27 04:15:052780
sandersd35d2c3f2017-01-14 02:04:422781void WebMediaPlayerImpl::SetDelegateState(DelegateState new_state,
2782 bool is_idle) {
tguilbert1bb1c782017-01-23 21:15:112783 DCHECK(delegate_);
Dale Curtis779ed842018-03-10 06:20:132784 DVLOG(2) << __func__ << "(" << static_cast<int>(new_state) << ", " << is_idle
2785 << ")";
dalecurtis5bbc487e2016-02-27 04:15:052786
sandersd35d2c3f2017-01-14 02:04:422787 // Prevent duplicate delegate calls.
2788 // TODO(sandersd): Move this deduplication into the delegate itself.
2789 // TODO(sandersd): WebContentsObserverSanityChecker does not allow sending the
2790 // 'playing' IPC more than once in a row, even if the metadata has changed.
2791 // Figure out whether it should.
Mounir Lamouri366dd8472018-06-19 17:20:042792 // Pretend that the media has no audio if it never played unmuted. This is to
2793 // avoid any action related to audible media such as taking audio focus or
2794 // showing a media notification. To preserve a consistent experience, it does
2795 // not apply if a media was audible so the system states do not flicker
2796 // depending on whether the user muted the player.
2797 bool has_audio = HasAudio() && !client_->WasAlwaysMuted();
sandersd35d2c3f2017-01-14 02:04:422798 if (delegate_state_ == new_state &&
2799 (delegate_state_ != DelegateState::PLAYING ||
2800 delegate_has_audio_ == has_audio)) {
2801 return;
mlamouri910111362016-11-04 11:28:242802 }
sandersd50a635e2016-04-04 22:50:092803 delegate_state_ = new_state;
sandersd35d2c3f2017-01-14 02:04:422804 delegate_has_audio_ = has_audio;
sandersd50a635e2016-04-04 22:50:092805
sandersd35d2c3f2017-01-14 02:04:422806 switch (new_state) {
sandersd50a635e2016-04-04 22:50:092807 case DelegateState::GONE:
2808 delegate_->PlayerGone(delegate_id_);
2809 break;
mlamouri910111362016-11-04 11:28:242810 case DelegateState::PLAYING: {
peconn257951522017-06-09 18:24:592811 if (HasVideo())
2812 delegate_->DidPlayerSizeChange(delegate_id_, NaturalSize());
zqzhang5d8eab72016-08-26 20:34:302813 delegate_->DidPlay(
Blink Reformat1c4d759e2017-04-09 16:34:542814 delegate_id_, HasVideo(), has_audio,
Dale Curtisca1b78f2019-01-15 03:11:262815 DurationToMediaContentType(GetPipelineMediaDuration()));
sandersd50a635e2016-04-04 22:50:092816 break;
mlamouri910111362016-11-04 11:28:242817 }
sandersd50a635e2016-04-04 22:50:092818 case DelegateState::PAUSED:
sandersd35d2c3f2017-01-14 02:04:422819 delegate_->DidPause(delegate_id_);
sandersd50a635e2016-04-04 22:50:092820 break;
dalecurtis0f0097a2015-12-01 17:40:472821 }
sandersd35d2c3f2017-01-14 02:04:422822
2823 delegate_->SetIdle(delegate_id_, is_idle);
dalecurtis0f0097a2015-12-01 17:40:472824}
2825
sandersd50a635e2016-04-04 22:50:092826void WebMediaPlayerImpl::SetMemoryReportingState(
2827 bool is_memory_reporting_enabled) {
2828 if (memory_usage_reporting_timer_.IsRunning() ==
2829 is_memory_reporting_enabled) {
hubbed5f36882016-01-15 22:40:372830 return;
sandersd50a635e2016-04-04 22:50:092831 }
sandersd1c0bba02016-03-04 23:14:082832
sandersd50a635e2016-04-04 22:50:092833 if (is_memory_reporting_enabled) {
2834 memory_usage_reporting_timer_.Start(FROM_HERE,
2835 base::TimeDelta::FromSeconds(2), this,
2836 &WebMediaPlayerImpl::ReportMemoryUsage);
2837 } else {
2838 memory_usage_reporting_timer_.Stop();
2839 ReportMemoryUsage();
2840 }
2841}
2842
2843void WebMediaPlayerImpl::SetSuspendState(bool is_suspended) {
xhwang213e50c2016-10-10 23:56:312844 DCHECK(main_task_runner_->BelongsToCurrentThread());
Dale Curtis779ed842018-03-10 06:20:132845 DVLOG(2) << __func__ << "(" << is_suspended << ")";
xhwang213e50c2016-10-10 23:56:312846
sandersd50a635e2016-04-04 22:50:092847 // Do not change the state after an error has occurred.
2848 // TODO(sandersd): Update PipelineController to remove the need for this.
2849 if (IsNetworkStateError(network_state_))
sandersd1c0bba02016-03-04 23:14:082850 return;
2851
jameswest451a5bb2017-01-27 03:59:392852 if (is_suspended) {
sandersd35d2c3f2017-01-14 02:04:422853 // If we were not resumed for long enough to satisfy the preroll attempt,
2854 // reset the clock.
2855 if (!preroll_attempt_pending_ && IsPrerollAttemptNeeded()) {
2856 preroll_attempt_pending_ = true;
2857 preroll_attempt_start_time_ = base::TimeTicks();
2858 }
Antonio Gomes81b56552019-05-15 22:15:282859 pipeline_controller_->Suspend();
sandersd50a635e2016-04-04 22:50:092860 } else {
sandersd35d2c3f2017-01-14 02:04:422861 // When resuming, start the preroll attempt clock.
2862 if (preroll_attempt_pending_) {
2863 preroll_attempt_pending_ = false;
2864 preroll_attempt_start_time_ = tick_clock_->NowTicks();
2865 }
Antonio Gomes81b56552019-05-15 22:15:282866 pipeline_controller_->Resume();
sandersd50a635e2016-04-04 22:50:092867 }
2868}
2869
2870WebMediaPlayerImpl::PlayState
Thomas Guilbert7350fdad2019-01-29 23:09:242871WebMediaPlayerImpl::UpdatePlayState_ComputePlayState(bool is_flinging,
xjz4e5d4bf32017-02-15 21:26:352872 bool can_auto_suspend,
dalecurtis8b8505e72016-06-10 21:59:172873 bool is_suspended,
sandersd50a635e2016-04-04 22:50:092874 bool is_backgrounded) {
2875 PlayState result;
2876
tguilbert1bb1c782017-01-23 21:15:112877 bool must_suspend = delegate_->IsFrameClosed();
Dale Curtis6438cf12018-03-29 02:34:012878 bool is_stale = delegate_->IsStale(delegate_id_);
2879
2880 if (stale_state_override_for_testing_.has_value() &&
2881 ready_state_ >= stale_state_override_for_testing_.value()) {
2882 is_stale = true;
2883 }
sandersd35d2c3f2017-01-14 02:04:422884
sandersd50a635e2016-04-04 22:50:092885 // This includes both data source (before pipeline startup) and pipeline
2886 // errors.
2887 bool has_error = IsNetworkStateError(network_state_);
2888
Dale Curtisd71061f02019-05-21 21:33:542889 // After kReadyStateHaveMetadata, Blink will call play() if the state is not
2890 // paused; prior to this point |paused_| is not accurate.
2891 bool have_metadata =
2892 highest_ready_state_ >= WebMediaPlayer::kReadyStateHaveMetadata;
sandersd50a635e2016-04-04 22:50:092893
avayvod65fad272017-02-24 01:00:482894 // Background suspend is only enabled for paused players.
2895 // In the case of players with audio the session should be kept.
2896 bool background_suspended =
Dale Curtisd71061f02019-05-21 21:33:542897 can_auto_suspend && is_backgrounded && paused_ && have_metadata;
sandersd50a635e2016-04-04 22:50:092898
Dale Curtisd71061f02019-05-21 21:33:542899 // Idle suspension is allowed prior to kReadyStateHaveMetadata since there
2900 // exist mechanisms to exit the idle state when the player is capable of
2901 // reaching the kReadyStateHaveMetadata state; see didLoadingProgress().
dalecurtiscc8baf72016-10-27 01:49:442902 //
sandersd50a635e2016-04-04 22:50:092903 // TODO(sandersd): Make the delegate suspend idle players immediately when
2904 // hidden.
Dale Curtis7c63f2e22018-09-19 21:06:272905 bool idle_suspended = can_auto_suspend && is_stale && paused_ && !seeking_ &&
2906 !overlay_enabled_ && !needs_first_frame_;
dalecurtise7120dc2016-09-03 02:54:352907
2908 // If we're already suspended, see if we can wait for user interaction. Prior
Dale Curtisd71061f02019-05-21 21:33:542909 // to kReadyStateHaveMetadata, we require |is_stale| to remain suspended.
2910 // |is_stale| will be cleared when we receive data which may take us to
2911 // kReadyStateHaveMetadata.
2912 bool can_stay_suspended = (is_stale || have_metadata) && is_suspended &&
Dale Curtis7c63f2e22018-09-19 21:06:272913 paused_ && !seeking_ && !needs_first_frame_;
sandersd50a635e2016-04-04 22:50:092914
2915 // Combined suspend state.
Thomas Guilbert7350fdad2019-01-29 23:09:242916 result.is_suspended = must_suspend || idle_suspended ||
avayvod65fad272017-02-24 01:00:482917 background_suspended || can_stay_suspended;
sandersd50a635e2016-04-04 22:50:092918
Thomas Guilbert7350fdad2019-01-29 23:09:242919 DVLOG(3) << __func__ << ": must_suspend=" << must_suspend
Dale Curtis779ed842018-03-10 06:20:132920 << ", idle_suspended=" << idle_suspended
2921 << ", background_suspended=" << background_suspended
2922 << ", can_stay_suspended=" << can_stay_suspended
Dale Curtisd71061f02019-05-21 21:33:542923 << ", is_stale=" << is_stale << ", have_metadata=" << have_metadata
Dale Curtis779ed842018-03-10 06:20:132924 << ", paused_=" << paused_ << ", seeking_=" << seeking_;
2925
sandersd50a635e2016-04-04 22:50:092926 // We do not treat |playback_rate_| == 0 as paused. For the media session,
2927 // being paused implies displaying a play button, which is incorrect in this
2928 // case. For memory usage reporting, we just use the same definition (but we
2929 // don't have to).
2930 //
2931 // Similarly, we don't consider |ended_| to be paused. Blink will immediately
2932 // call pause() or seek(), so |ended_| should not affect the computation.
2933 // Despite that, |ended_| does result in a separate paused state, to simplfy
2934 // the contract for SetDelegateState().
2935 //
avayvod65fad272017-02-24 01:00:482936 // |has_remote_controls| indicates if the player can be controlled outside the
2937 // page (e.g. via the notification controls or by audio focus events). Idle
sandersd50a635e2016-04-04 22:50:092938 // suspension does not destroy the media session, because we expect that the
avayvod5f34b642017-03-23 03:14:042939 // notification controls (and audio focus) remain. With some exceptions for
2940 // background videos, the player only needs to have audio to have controls
Dale Curtisd71061f02019-05-21 21:33:542941 // (requires |have_current_data|).
avayvod5f34b642017-03-23 03:14:042942 //
2943 // |alive| indicates if the player should be present (not |GONE|) to the
2944 // delegate, either paused or playing. The following must be true for the
2945 // player:
Dale Curtisd71061f02019-05-21 21:33:542946 // - |have_current_data|, since playback can't begin before that point, we
2947 // need to know whether we are paused to correctly configure the session,
2948 // and also because the tracks and duration are passed to DidPlay(),
Thomas Guilbert7350fdad2019-01-29 23:09:242949 // - |is_flinging| is false (RemotePlayback is not handled by the delegate)
avayvod5f34b642017-03-23 03:14:042950 // - |has_error| is false as player should have no errors,
2951 // - |background_suspended| is false, otherwise |has_remote_controls| must
2952 // be true.
sandersd50a635e2016-04-04 22:50:092953 //
avayvod65fad272017-02-24 01:00:482954 // TODO(sandersd): If Blink told us the paused state sooner, we could detect
2955 // if the remote controls are available sooner.
2956
2957 // Background videos with audio don't have remote controls if background
2958 // suspend is enabled and resuming background videos is not (original Android
2959 // behavior).
2960 bool backgrounded_video_has_no_remote_controls =
Sergey Volk8b09c2c52018-12-12 23:20:402961 IsBackgroundSuspendEnabled(this) && !IsResumeBackgroundVideosEnabled() &&
2962 is_backgrounded && HasVideo();
Dale Curtisd71061f02019-05-21 21:33:542963 bool have_current_data = highest_ready_state_ >= kReadyStateHaveCurrentData;
2964 bool can_play = !has_error && have_current_data;
avayvod5f34b642017-03-23 03:14:042965 bool has_remote_controls =
Blink Reformat1c4d759e2017-04-09 16:34:542966 HasAudio() && !backgrounded_video_has_no_remote_controls;
Thomas Guilbert7350fdad2019-01-29 23:09:242967 bool alive = can_play && !is_flinging && !must_suspend &&
avayvod5f34b642017-03-23 03:14:042968 (!background_suspended || has_remote_controls);
2969 if (!alive) {
Thomas Guilbert4c6feff2018-11-09 19:53:322970 // Do not mark players as idle when flinging.
sandersd50a635e2016-04-04 22:50:092971 result.delegate_state = DelegateState::GONE;
Thomas Guilbert4c6feff2018-11-09 19:53:322972 result.is_idle = delegate_->IsIdle(delegate_id_) && !is_flinging;
avayvod65fad272017-02-24 01:00:482973 } else if (paused_) {
sandersd35d2c3f2017-01-14 02:04:422974 // TODO(sandersd): Is it possible to have a suspended session, be ended,
2975 // and not be paused? If so we should be in a PLAYING state.
dalecurtise7120dc2016-09-03 02:54:352976 result.delegate_state =
sandersd35d2c3f2017-01-14 02:04:422977 ended_ ? DelegateState::GONE : DelegateState::PAUSED;
2978 result.is_idle = !seeking_;
sandersd50a635e2016-04-04 22:50:092979 } else {
2980 result.delegate_state = DelegateState::PLAYING;
sandersd35d2c3f2017-01-14 02:04:422981 result.is_idle = false;
sandersd50a635e2016-04-04 22:50:092982 }
2983
dalecurtis8b8505e72016-06-10 21:59:172984 // It's not critical if some cases where memory usage can change are missed,
sandersd50a635e2016-04-04 22:50:092985 // since media memory changes are usually gradual.
Thomas Guilbert7350fdad2019-01-29 23:09:242986 result.is_memory_reporting_enabled = !has_error && can_play && !is_flinging &&
2987 !result.is_suspended &&
2988 (!paused_ || seeking_);
sandersd50a635e2016-04-04 22:50:092989
2990 return result;
dalecurtis0f0097a2015-12-01 17:40:472991}
2992
dalecurtis83266c72015-10-29 18:43:202993void WebMediaPlayerImpl::ReportMemoryUsage() {
2994 DCHECK(main_task_runner_->BelongsToCurrentThread());
2995
wdzierzanowskifd4cd91c52015-12-02 23:50:202996 // About base::Unretained() usage below: We destroy |demuxer_| on the main
2997 // thread. Before that, however, ~WebMediaPlayerImpl() posts a task to the
2998 // media thread and waits for it to finish. Hence, the GetMemoryUsage() task
2999 // posted here must finish earlier.
Dale Curtis8a6281322017-08-31 00:35:533000 //
3001 // The exception to the above is when OnError() has been called. If we're in
3002 // the error state we've already shut down the pipeline and can't rely on it
3003 // to cycle the media thread before we destroy |demuxer_|. In this case skip
3004 // collection of the demuxer memory stats.
3005 if (demuxer_ && !IsNetworkStateError(network_state_)) {
wdzierzanowskifd4cd91c52015-12-02 23:50:203006 base::PostTaskAndReplyWithResult(
3007 media_task_runner_.get(), FROM_HERE,
3008 base::Bind(&Demuxer::GetMemoryUsage, base::Unretained(demuxer_.get())),
Antonio Gomes142f32a2019-05-15 23:32:563009 base::Bind(&WebMediaPlayerImpl::FinishMemoryUsageReport, weak_this_));
wdzierzanowskifd4cd91c52015-12-02 23:50:203010 } else {
3011 FinishMemoryUsageReport(0);
3012 }
3013}
3014
3015void WebMediaPlayerImpl::FinishMemoryUsageReport(int64_t demuxer_memory_usage) {
3016 DCHECK(main_task_runner_->BelongsToCurrentThread());
3017
avayvodc4bfb0e62017-01-13 01:07:013018 const PipelineStatistics stats = GetPipelineStatistics();
servolk639473e492016-12-15 04:14:203019 const int64_t data_source_memory_usage =
3020 data_source_ ? data_source_->GetMemoryUsage() : 0;
dalecurtisecc76612017-04-19 00:31:203021
Dale Curtisc2c5dcb12018-04-16 23:21:293022 // If we have video and no video memory usage and we've rendered the first
3023 // frame, assume the VideoFrameCompositor is holding onto the last frame after
3024 // we've suspended the pipeline; which thus reports zero memory usage from the
3025 // video renderer.
dalecurtisecc76612017-04-19 00:31:203026 //
3027 // Technically this should use the coded size, but that requires us to hop to
3028 // the compositor to get and byte-perfect accuracy isn't important here.
3029 const int64_t video_memory_usage =
3030 stats.video_memory_usage +
Dale Curtisc2c5dcb12018-04-16 23:21:293031 ((pipeline_metadata_.has_video && !stats.video_memory_usage &&
3032 has_first_frame_)
Miguel Casas9e7766022018-01-08 16:13:133033 ? VideoFrame::AllocationSize(PIXEL_FORMAT_I420,
dalecurtisecc76612017-04-19 00:31:203034 pipeline_metadata_.natural_size)
3035 : 0);
3036
dalecurtis83266c72015-10-29 18:43:203037 const int64_t current_memory_usage =
dalecurtisecc76612017-04-19 00:31:203038 stats.audio_memory_usage + video_memory_usage + data_source_memory_usage +
3039 demuxer_memory_usage;
dalecurtis83266c72015-10-29 18:43:203040
dalecurtisecc76612017-04-19 00:31:203041 DVLOG(2) << "Memory Usage -- Total: " << current_memory_usage
3042 << " Audio: " << stats.audio_memory_usage
3043 << ", Video: " << video_memory_usage
servolk639473e492016-12-15 04:14:203044 << ", DataSource: " << data_source_memory_usage
wdzierzanowskifd4cd91c52015-12-02 23:50:203045 << ", Demuxer: " << demuxer_memory_usage;
dalecurtis83266c72015-10-29 18:43:203046
3047 const int64_t delta = current_memory_usage - last_reported_memory_usage_;
3048 last_reported_memory_usage_ = current_memory_usage;
3049 adjust_allocated_memory_cb_.Run(delta);
servolk639473e492016-12-15 04:14:203050
Blink Reformat1c4d759e2017-04-09 16:34:543051 if (HasAudio()) {
servolk639473e492016-12-15 04:14:203052 UMA_HISTOGRAM_MEMORY_KB("Media.WebMediaPlayerImpl.Memory.Audio",
3053 stats.audio_memory_usage / 1024);
3054 }
Blink Reformat1c4d759e2017-04-09 16:34:543055 if (HasVideo()) {
servolk639473e492016-12-15 04:14:203056 UMA_HISTOGRAM_MEMORY_KB("Media.WebMediaPlayerImpl.Memory.Video",
dalecurtisecc76612017-04-19 00:31:203057 video_memory_usage / 1024);
servolk639473e492016-12-15 04:14:203058 }
3059 if (data_source_) {
3060 UMA_HISTOGRAM_MEMORY_KB("Media.WebMediaPlayerImpl.Memory.DataSource",
3061 data_source_memory_usage / 1024);
3062 }
3063 if (demuxer_) {
3064 UMA_HISTOGRAM_MEMORY_KB("Media.WebMediaPlayerImpl.Memory.Demuxer",
3065 demuxer_memory_usage / 1024);
3066 }
dalecurtis83266c72015-10-29 18:43:203067}
3068
dalecurtis8b8505e72016-06-10 21:59:173069void WebMediaPlayerImpl::ScheduleIdlePauseTimer() {
avayvod65fad272017-02-24 01:00:483070 // Only schedule the pause timer if we're not paused or paused but going to
avayvod52efd282017-03-07 21:13:043071 // resume when foregrounded, and are suspended and have audio.
3072 if ((paused_ && !paused_when_hidden_) ||
Antonio Gomes81b56552019-05-15 22:15:283073 !pipeline_controller_->IsSuspended() || !HasAudio()) {
dalecurtis8b8505e72016-06-10 21:59:173074 return;
avayvod52efd282017-03-07 21:13:043075 }
dalecurtis8b8505e72016-06-10 21:59:173076
3077#if defined(OS_ANDROID)
Thomas Guilbert7350fdad2019-01-29 23:09:243078 // Don't pause videos casted as part of RemotePlayback.
3079 if (is_flinging_)
dalecurtis8b8505e72016-06-10 21:59:173080 return;
3081#endif
3082
3083 // Idle timeout chosen arbitrarily.
3084 background_pause_timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(5),
3085 this, &WebMediaPlayerImpl::OnPause);
3086}
3087
dalecurtis04bdb582016-08-17 22:15:233088void WebMediaPlayerImpl::CreateWatchTimeReporter() {
wdzierzanowskia78fa9b2017-06-13 18:12:103089 if (!HasVideo() && !HasAudio())
3090 return;
3091
Dan Sanders7ef5d0f2019-05-03 18:30:113092 // MediaPlayerRenderer does not know about tracks until playback starts.
3093 // Assume audio-only unless the natural size has been detected.
3094 bool has_video = pipeline_metadata_.has_video;
3095 if (using_media_player_renderer_) {
3096 has_video = !pipeline_metadata_.natural_size.IsEmpty();
3097 }
3098
dalecurtis04bdb582016-08-17 22:15:233099 // Create the watch time reporter and synchronize its initial state.
Dale Curtis1adbe6a2017-08-02 02:09:133100 watch_time_reporter_.reset(new WatchTimeReporter(
Dan Sanders7ef5d0f2019-05-03 18:30:113101 mojom::PlaybackProperties::New(
3102 pipeline_metadata_.has_audio, has_video, false, false,
3103 !!chunk_demuxer_, is_encrypted_, embedded_media_experience_enabled_),
Dale Curtis96d6e9382018-07-18 18:01:073104 pipeline_metadata_.natural_size,
Dale Curtis051fdf62017-08-05 00:21:133105 base::BindRepeating(&WebMediaPlayerImpl::GetCurrentTimeInternal,
3106 base::Unretained(this)),
Hajime Hoshi8bb37dc2017-12-19 09:35:103107 media_metrics_provider_.get(),
Hajime Hoshib5a26ee2018-05-14 12:47:513108 frame_->GetTaskRunner(blink::TaskType::kInternalMedia)));
dalecurtis04bdb582016-08-17 22:15:233109 watch_time_reporter_->OnVolumeChange(volume_);
Dale Curtisaebaeea2018-07-19 23:42:113110 watch_time_reporter_->OnDurationChanged(GetPipelineMediaDuration());
Mounir Lamourif9af74e72017-06-19 19:31:453111
tguilbert1bb1c782017-01-23 21:15:113112 if (delegate_->IsFrameHidden())
dalecurtis04bdb582016-08-17 22:15:233113 watch_time_reporter_->OnHidden();
3114 else
3115 watch_time_reporter_->OnShown();
Mounir Lamourif9af74e72017-06-19 19:31:453116
Mounir Lamouri41a79c62017-06-06 12:53:163117 if (client_->HasNativeControls())
3118 watch_time_reporter_->OnNativeControlsEnabled();
3119 else
3120 watch_time_reporter_->OnNativeControlsDisabled();
Mounir Lamourif9af74e72017-06-19 19:31:453121
3122 switch (client_->DisplayType()) {
3123 case WebMediaPlayer::DisplayType::kInline:
3124 watch_time_reporter_->OnDisplayTypeInline();
3125 break;
3126 case WebMediaPlayer::DisplayType::kFullscreen:
3127 watch_time_reporter_->OnDisplayTypeFullscreen();
3128 break;
3129 case WebMediaPlayer::DisplayType::kPictureInPicture:
3130 watch_time_reporter_->OnDisplayTypePictureInPicture();
3131 break;
3132 }
Dale Curtis96d6e9382018-07-18 18:01:073133
3134 UpdateSecondaryProperties();
Dale Curtis7fd27c4b2018-07-30 22:14:213135
3136 // If the WatchTimeReporter was recreated in the middle of playback, we want
3137 // to resume playback here too since we won't get another play() call. When
3138 // seeking, the seek completion will restart it if necessary.
3139 if (!paused_ && !seeking_)
3140 watch_time_reporter_->OnPlaying();
Dale Curtis96d6e9382018-07-18 18:01:073141}
3142
3143void WebMediaPlayerImpl::UpdateSecondaryProperties() {
3144 watch_time_reporter_->UpdateSecondaryProperties(
3145 mojom::SecondaryPlaybackProperties::New(
3146 pipeline_metadata_.audio_decoder_config.codec(),
3147 pipeline_metadata_.video_decoder_config.codec(), audio_decoder_name_,
John Rummelld30555352018-09-21 20:47:253148 video_decoder_name_,
3149 DetermineEncryptionMode(
3150 pipeline_metadata_.audio_decoder_config.encryption_scheme()),
3151 DetermineEncryptionMode(
3152 pipeline_metadata_.video_decoder_config.encryption_scheme()),
3153 pipeline_metadata_.natural_size));
dalecurtis04bdb582016-08-17 22:15:233154}
3155
avayvod39c102402016-11-23 21:43:133156bool WebMediaPlayerImpl::IsHidden() const {
3157 DCHECK(main_task_runner_->BelongsToCurrentThread());
3158
tguilbert1bb1c782017-01-23 21:15:113159 return delegate_->IsFrameHidden() && !delegate_->IsFrameClosed();
avayvod39c102402016-11-23 21:43:133160}
3161
avayvod102cdb62017-01-07 03:11:093162bool WebMediaPlayerImpl::IsStreaming() const {
3163 return data_source_ && data_source_->IsStreaming();
3164}
3165
liberato2fd111be2017-01-04 00:25:063166bool WebMediaPlayerImpl::DoesOverlaySupportMetadata() const {
Ted Meyer4a427632019-05-01 19:05:273167 return pipeline_metadata_.video_decoder_config.video_transformation() ==
3168 kNoTransformation;
liberato2fd111be2017-01-04 00:25:063169}
3170
xjzaf29d4182016-12-16 01:52:323171void WebMediaPlayerImpl::ActivateViewportIntersectionMonitoring(bool activate) {
3172 DCHECK(main_task_runner_->BelongsToCurrentThread());
3173
Blink Reformat1c4d759e2017-04-09 16:34:543174 client_->ActivateViewportIntersectionMonitoring(activate);
xjzaf29d4182016-12-16 01:52:323175}
3176
Anton Vayvod09fa66e2017-07-20 23:02:123177void WebMediaPlayerImpl::UpdateRemotePlaybackCompatibility(bool is_compatible) {
3178 DCHECK(main_task_runner_->BelongsToCurrentThread());
3179
3180 client_->RemotePlaybackCompatibilityChanged(loaded_url_, is_compatible);
3181}
3182
Dale Curtis6438cf12018-03-29 02:34:013183void WebMediaPlayerImpl::ForceStaleStateForTesting(ReadyState target_state) {
3184 stale_state_override_for_testing_.emplace(target_state);
Dale Curtis99a9b482018-02-01 02:23:283185 UpdatePlayState();
3186}
3187
3188bool WebMediaPlayerImpl::IsSuspendedForTesting() {
3189 // This intentionally uses IsPipelineSuspended since we need to know when the
3190 // pipeline has reached the suspended state, not when it's in suspending.
Antonio Gomes81b56552019-05-15 22:15:283191 return pipeline_controller_->IsPipelineSuspended();
Dale Curtis99a9b482018-02-01 02:23:283192}
3193
Dale Curtis7c63f2e22018-09-19 21:06:273194bool WebMediaPlayerImpl::DidLazyLoad() const {
3195 return did_lazy_load_;
3196}
3197
3198void WebMediaPlayerImpl::OnBecameVisible() {
Dale Curtis04769ca2019-05-25 00:38:103199 have_enough_after_lazy_load_cb_.Cancel();
Dale Curtis7c63f2e22018-09-19 21:06:273200 needs_first_frame_ = !has_first_frame_;
3201 UpdatePlayState();
3202}
3203
Miguel Casasfb63a5792018-12-04 23:50:413204bool WebMediaPlayerImpl::IsOpaque() const {
3205 return opaque_;
3206}
3207
Mounir Lamouri99ba5a62019-02-12 01:27:473208int WebMediaPlayerImpl::GetDelegateId() {
3209 return delegate_id_;
3210}
3211
3212base::Optional<viz::SurfaceId> WebMediaPlayerImpl::GetSurfaceId() {
3213 if (!surface_layer_for_video_enabled_)
3214 return base::nullopt;
3215 return bridge_->GetSurfaceId();
3216}
3217
Antonio Gomes142f32a2019-05-15 23:32:563218base::WeakPtr<blink::WebMediaPlayer> WebMediaPlayerImpl::AsWeakPtr() {
3219 return weak_this_;
3220}
3221
Yuchen Liue7813972019-04-12 22:34:243222bool WebMediaPlayerImpl::ShouldPausePlaybackWhenHidden() const {
3223 // Audio only stream is allowed to play when in background.
3224 // TODO: We should check IsBackgroundOptimizationCandidate here. But we need
3225 // to move the logic of checking video frames out of that function.
3226 if (!HasVideo())
3227 return false;
3228
Junbo Kefba620b2019-01-16 02:54:363229 if (!is_background_video_playback_enabled_)
3230 return true;
3231
avayvod65fad272017-02-24 01:00:483232 // If suspending background video, pause any video that's not remoted or
3233 // not unlocked to play in the background.
Sergey Volk8b09c2c52018-12-12 23:20:403234 if (IsBackgroundSuspendEnabled(this)) {
avayvod65fad272017-02-24 01:00:483235#if defined(OS_ANDROID)
Thomas Guilbert7350fdad2019-01-29 23:09:243236 if (is_flinging_)
avayvod65fad272017-02-24 01:00:483237 return false;
avayvodcc273dd2017-01-19 19:35:123238#endif
avayvodeb9098d2017-01-07 00:33:033239
Blink Reformat1c4d759e2017-04-09 16:34:543240 return !HasAudio() || (IsResumeBackgroundVideosEnabled() &&
3241 video_locked_when_paused_when_hidden_);
avayvod65fad272017-02-24 01:00:483242 }
3243
3244 // Otherwise only pause if the optimization is on and it's a video-only
3245 // optimization candidate.
avayvod01201332017-04-14 00:27:153246 return IsBackgroundVideoPauseOptimizationEnabled() && !HasAudio() &&
Thomas Guilbert29ae1a902018-10-20 01:53:383247 IsBackgroundOptimizationCandidate() && !is_flinging_;
avayvodeb9098d2017-01-07 00:33:033248}
3249
avayvod2135a642017-01-13 00:17:143250bool WebMediaPlayerImpl::ShouldDisableVideoWhenHidden() const {
Ted Meyera918e592018-09-08 00:16:203251 // This optimization is behind the flag on all platforms, only for non-mse
3252 // video. MSE video track switching on hide has gone through a field test.
3253 // TODO(tmathmeyer): Passing load_type_ won't be needed after src= field
3254 // testing is finished. see: http://crbug.com/709302
Ted Meyer0e105992019-05-04 01:47:213255 if (!is_background_video_track_optimization_supported_)
avayvodc4bfb0e62017-01-13 01:07:013256 return false;
avayvodc4bfb0e62017-01-13 01:07:013257
avayvodcc273dd2017-01-19 19:35:123258 // Disable video track only for players with audio that match the criteria for
3259 // being optimized.
Blink Reformat1c4d759e2017-04-09 16:34:543260 return HasAudio() && IsBackgroundOptimizationCandidate();
avayvodcc273dd2017-01-19 19:35:123261}
3262
3263bool WebMediaPlayerImpl::IsBackgroundOptimizationCandidate() const {
3264 DCHECK(main_task_runner_->BelongsToCurrentThread());
3265
François Beaufort664c3ca72018-04-13 07:24:513266 // Don't optimize Picture-in-Picture players.
Mounir Lamouri0484f40a2018-07-25 03:03:263267 if (IsInPictureInPicture())
François Beaufort664c3ca72018-04-13 07:24:513268 return false;
3269
Thomas Guilbert7350fdad2019-01-29 23:09:243270#if defined(OS_ANDROID)
3271 // Don't optimize videos casted as part of RemotePlayback.
3272 if (is_flinging_)
avayvodcc273dd2017-01-19 19:35:123273 return false;
Thomas Guilbert7350fdad2019-01-29 23:09:243274#endif
avayvodcc273dd2017-01-19 19:35:123275
3276 // Don't optimize audio-only or streaming players.
Blink Reformat1c4d759e2017-04-09 16:34:543277 if (!HasVideo() || IsStreaming())
avayvodcc273dd2017-01-19 19:35:123278 return false;
3279
Dale Curtis3f4935b2017-09-09 00:11:593280 // Video-only players are always optimized (paused).
3281 // Don't check the keyframe distance and duration.
3282 if (!HasAudio() && HasVideo())
3283 return true;
3284
avayvodcc273dd2017-01-19 19:35:123285 // Videos shorter than the maximum allowed keyframe distance can be optimized.
3286 base::TimeDelta duration = GetPipelineMediaDuration();
Ted Meyera918e592018-09-08 00:16:203287
Dale Curtis456808a2018-10-23 17:50:213288 constexpr base::TimeDelta kMaxKeyframeDistanceToDisableBackgroundVideo =
3289 base::TimeDelta::FromMilliseconds(
3290 kMaxKeyframeDistanceToDisableBackgroundVideoMs);
3291 if (duration < kMaxKeyframeDistanceToDisableBackgroundVideo)
avayvodcc273dd2017-01-19 19:35:123292 return true;
3293
3294 // Otherwise, only optimize videos with shorter average keyframe distance.
avayvodc4bfb0e62017-01-13 01:07:013295 PipelineStatistics stats = GetPipelineStatistics();
Dale Curtis456808a2018-10-23 17:50:213296 return stats.video_keyframe_distance_average <
3297 kMaxKeyframeDistanceToDisableBackgroundVideo;
avayvod2135a642017-01-13 00:17:143298}
3299
avayvod56e1f3942017-01-21 02:06:313300void WebMediaPlayerImpl::UpdateBackgroundVideoOptimizationState() {
3301 if (IsHidden()) {
Yuchen Liue7813972019-04-12 22:34:243302 if (ShouldPausePlaybackWhenHidden()) {
avayvod56e1f3942017-01-21 02:06:313303 PauseVideoIfNeeded();
Dale Curtisa75a7892017-08-09 20:21:513304 } else if (update_background_status_cb_.IsCancelled()) {
3305 // Only trigger updates when we don't have one already scheduled.
3306 update_background_status_cb_.Reset(
3307 base::Bind(&WebMediaPlayerImpl::DisableVideoTrackIfNeeded,
3308 base::Unretained(this)));
3309
3310 // Defer disable track until we're sure the clip will be backgrounded for
3311 // some time. Resuming may take half a second, so frequent tab switches
3312 // will yield a poor user experience otherwise. http://crbug.com/709302
3313 // may also cause AV sync issues if disable/enable happens too fast.
3314 main_task_runner_->PostDelayedTask(
3315 FROM_HERE, update_background_status_cb_.callback(),
3316 base::TimeDelta::FromSeconds(10));
3317 }
avayvod56e1f3942017-01-21 02:06:313318 } else {
Dale Curtisa75a7892017-08-09 20:21:513319 update_background_status_cb_.Cancel();
avayvod56e1f3942017-01-21 02:06:313320 EnableVideoTrackIfNeeded();
3321 }
3322}
3323
3324void WebMediaPlayerImpl::PauseVideoIfNeeded() {
3325 DCHECK(IsHidden());
3326
3327 // Don't pause video while the pipeline is stopped, resuming or seeking.
3328 // Also if the video is paused already.
Antonio Gomes81b56552019-05-15 22:15:283329 if (!pipeline_controller_->IsPipelineRunning() || is_pipeline_resuming_ ||
tguilbert350936ff2017-02-24 05:39:273330 seeking_ || paused_)
avayvod56e1f3942017-01-21 02:06:313331 return;
3332
3333 // OnPause() will set |paused_when_hidden_| to false and call
3334 // UpdatePlayState(), so set the flag to true after and then return.
3335 OnPause();
3336 paused_when_hidden_ = true;
3337}
3338
avayvod2135a642017-01-13 00:17:143339void WebMediaPlayerImpl::EnableVideoTrackIfNeeded() {
avayvod56e1f3942017-01-21 02:06:313340 // Don't change video track while the pipeline is stopped, resuming or
3341 // seeking.
Antonio Gomes81b56552019-05-15 22:15:283342 if (!pipeline_controller_->IsPipelineRunning() || is_pipeline_resuming_ ||
tguilbert350936ff2017-02-24 05:39:273343 seeking_)
avayvod2135a642017-01-13 00:17:143344 return;
3345
3346 if (video_track_disabled_) {
3347 video_track_disabled_ = false;
Blink Reformat1c4d759e2017-04-09 16:34:543348 if (client_->HasSelectedVideoTrack()) {
3349 WebMediaPlayer::TrackId trackId = client_->GetSelectedVideoTrackId();
3350 SelectedVideoTrackChanged(&trackId);
avayvod2135a642017-01-13 00:17:143351 }
3352 }
3353}
3354
3355void WebMediaPlayerImpl::DisableVideoTrackIfNeeded() {
3356 DCHECK(IsHidden());
3357
3358 // Don't change video track while the pipeline is resuming or seeking.
3359 if (is_pipeline_resuming_ || seeking_)
3360 return;
3361
3362 if (!video_track_disabled_ && ShouldDisableVideoWhenHidden()) {
3363 video_track_disabled_ = true;
Blink Reformat1c4d759e2017-04-09 16:34:543364 SelectedVideoTrackChanged(nullptr);
avayvod2135a642017-01-13 00:17:143365 }
3366}
3367
avayvodc4bfb0e62017-01-13 01:07:013368void WebMediaPlayerImpl::SetPipelineStatisticsForTest(
3369 const PipelineStatistics& stats) {
3370 pipeline_statistics_for_test_ = base::make_optional(stats);
3371}
3372
3373PipelineStatistics WebMediaPlayerImpl::GetPipelineStatistics() const {
3374 DCHECK(main_task_runner_->BelongsToCurrentThread());
3375
tguilbert350936ff2017-02-24 05:39:273376 return pipeline_statistics_for_test_.value_or(
Antonio Gomes81b56552019-05-15 22:15:283377 pipeline_controller_->GetStatistics());
avayvodc4bfb0e62017-01-13 01:07:013378}
3379
avayvodcc273dd2017-01-19 19:35:123380void WebMediaPlayerImpl::SetPipelineMediaDurationForTest(
3381 base::TimeDelta duration) {
3382 pipeline_media_duration_for_test_ = base::make_optional(duration);
3383}
3384
3385base::TimeDelta WebMediaPlayerImpl::GetPipelineMediaDuration() const {
3386 DCHECK(main_task_runner_->BelongsToCurrentThread());
3387
3388 return pipeline_media_duration_for_test_.value_or(
Antonio Gomes81b56552019-05-15 22:15:283389 pipeline_controller_->GetMediaDuration());
avayvodcc273dd2017-01-19 19:35:123390}
3391
Xiangjun Zhangba8724f482017-08-03 06:43:253392void WebMediaPlayerImpl::SwitchToRemoteRenderer(
3393 const std::string& remote_device_friendly_name) {
xjz4e5d4bf32017-02-15 21:26:353394 DCHECK(main_task_runner_->BelongsToCurrentThread());
Chris Cunningham89b4b762019-03-27 17:13:333395
3396 DCHECK(!is_remote_rendering_);
3397 is_remote_rendering_ = true;
3398
Thomas Guilbertb341bae02018-05-09 00:02:133399 DCHECK(!disable_pipeline_auto_suspend_);
Xiangjun Zhangba8724f482017-08-03 06:43:253400 disable_pipeline_auto_suspend_ = true;
Chris Cunninghamd9df58e2017-08-29 00:04:233401
3402 // Capabilities reporting should only be performed for local playbacks.
3403 video_decode_stats_reporter_.reset();
3404
Xiangjun Zhangba8724f482017-08-03 06:43:253405 // Requests to restart media pipeline. A remote renderer will be created via
3406 // the |renderer_factory_selector_|.
xjz4e5d4bf32017-02-15 21:26:353407 ScheduleRestart();
xjzdf9b67e2017-04-13 23:28:253408 if (client_) {
Xiangjun Zhangba8724f482017-08-03 06:43:253409 client_->MediaRemotingStarted(
3410 WebString::FromUTF8(remote_device_friendly_name));
xjzdf9b67e2017-04-13 23:28:253411 }
xjz4e5d4bf32017-02-15 21:26:353412}
3413
Xiangjun Zhang5e20cba42018-01-10 19:54:563414void WebMediaPlayerImpl::SwitchToLocalRenderer(
3415 MediaObserverClient::ReasonToSwitchToLocal reason) {
Xiangjun Zhangba8724f482017-08-03 06:43:253416 DCHECK(main_task_runner_->BelongsToCurrentThread());
Chris Cunningham89b4b762019-03-27 17:13:333417 if (!is_remote_rendering_)
Xiangjun Zhang12f55272018-07-30 23:19:373418 return; // Is currently with local renderer.
Chris Cunningham89b4b762019-03-27 17:13:333419 is_remote_rendering_ = false;
3420
3421 DCHECK(disable_pipeline_auto_suspend_);
Xiangjun Zhangba8724f482017-08-03 06:43:253422 disable_pipeline_auto_suspend_ = false;
Chris Cunninghamd9df58e2017-08-29 00:04:233423
3424 // Capabilities reporting may resume now that playback is local.
3425 CreateVideoDecodeStatsReporter();
3426
Xiangjun Zhangba8724f482017-08-03 06:43:253427 // Requests to restart media pipeline. A local renderer will be created via
3428 // the |renderer_factory_selector_|.
3429 ScheduleRestart();
3430 if (client_)
Xiangjun Zhang5e20cba42018-01-10 19:54:563431 client_->MediaRemotingStopped(GetSwitchToLocalMessage(reason));
Xiangjun Zhangba8724f482017-08-03 06:43:253432}
3433
dalecurtis4f6d14d2017-02-22 17:42:223434void WebMediaPlayerImpl::RecordUnderflowDuration(base::TimeDelta duration) {
3435 DCHECK(data_source_ || chunk_demuxer_);
xhwang68b3fab82017-05-17 21:31:463436
dalecurtis4f6d14d2017-02-22 17:42:223437 if (data_source_)
Jennifer Apacible82e25c92017-08-07 18:15:273438 UMA_HISTOGRAM_TIMES("Media.UnderflowDuration2.SRC", duration);
dalecurtis4f6d14d2017-02-22 17:42:223439 else
Jennifer Apacible82e25c92017-08-07 18:15:273440 UMA_HISTOGRAM_TIMES("Media.UnderflowDuration2.MSE", duration);
xhwang68b3fab82017-05-17 21:31:463441
3442 if (is_encrypted_)
Jennifer Apacible82e25c92017-08-07 18:15:273443 UMA_HISTOGRAM_TIMES("Media.UnderflowDuration2.EME", duration);
dalecurtis4f6d14d2017-02-22 17:42:223444}
3445
xhwang60802652017-04-19 07:29:583446#define UMA_HISTOGRAM_VIDEO_HEIGHT(name, sample) \
3447 UMA_HISTOGRAM_CUSTOM_COUNTS(name, sample, 100, 10000, 50)
3448
3449void WebMediaPlayerImpl::RecordVideoNaturalSize(const gfx::Size& natural_size) {
3450 // Always report video natural size to MediaLog.
3451 media_log_->AddEvent(media_log_->CreateVideoSizeSetEvent(
3452 natural_size.width(), natural_size.height()));
3453
3454 if (initial_video_height_recorded_)
3455 return;
3456
3457 initial_video_height_recorded_ = true;
3458
3459 int height = natural_size.height();
3460
3461 if (load_type_ == kLoadTypeURL)
3462 UMA_HISTOGRAM_VIDEO_HEIGHT("Media.VideoHeight.Initial.SRC", height);
3463 else if (load_type_ == kLoadTypeMediaSource)
3464 UMA_HISTOGRAM_VIDEO_HEIGHT("Media.VideoHeight.Initial.MSE", height);
3465
3466 if (is_encrypted_)
3467 UMA_HISTOGRAM_VIDEO_HEIGHT("Media.VideoHeight.Initial.EME", height);
3468
3469 UMA_HISTOGRAM_VIDEO_HEIGHT("Media.VideoHeight.Initial.All", height);
3470}
3471
3472#undef UMA_HISTOGRAM_VIDEO_HEIGHT
3473
Greg Thompsonaa48ce8d2018-04-03 06:11:433474void WebMediaPlayerImpl::SetTickClockForTest(
3475 const base::TickClock* tick_clock) {
tzik2c963b872017-12-07 06:57:243476 tick_clock_ = tick_clock;
Antonio Gomes81b56552019-05-15 22:15:283477 buffered_data_source_host_->SetTickClockForTest(tick_clock);
hubbeb2d3efd2017-05-05 23:26:383478}
3479
Dale Curtis3899090ea2018-01-12 00:10:353480void WebMediaPlayerImpl::OnFirstFrame(base::TimeTicks frame_time) {
3481 DCHECK(!load_start_time_.is_null());
Dale Curtisff576552018-03-30 02:32:443482 DCHECK(!skip_metrics_due_to_startup_suspend_);
Dale Curtisc2c5dcb12018-04-16 23:21:293483 has_first_frame_ = true;
Dale Curtis7c63f2e22018-09-19 21:06:273484 needs_first_frame_ = false;
Dale Curtis3899090ea2018-01-12 00:10:353485 const base::TimeDelta elapsed = frame_time - load_start_time_;
3486 media_metrics_provider_->SetTimeToFirstFrame(elapsed);
3487 RecordTimingUMA("Media.TimeToFirstFrame", elapsed);
Dale Curtiscdfc6f22019-06-26 22:05:233488
3489 // Needed to signal HTMLVideoElement that it should remove the poster image.
Dale Curtis66790f32019-07-11 00:14:243490 if (client_ && has_poster_)
Dale Curtiscdfc6f22019-06-26 22:05:233491 client_->Repaint();
Dale Curtis3899090ea2018-01-12 00:10:353492}
3493
3494void WebMediaPlayerImpl::RecordTimingUMA(const std::string& key,
3495 base::TimeDelta elapsed) {
3496 if (chunk_demuxer_)
3497 base::UmaHistogramMediumTimes(key + ".MSE", elapsed);
3498 else
3499 base::UmaHistogramMediumTimes(key + ".SRC", elapsed);
3500 if (is_encrypted_)
3501 base::UmaHistogramMediumTimes(key + ".EME", elapsed);
3502}
3503
John Rummelldb5a7ef2018-05-16 00:28:013504void WebMediaPlayerImpl::RecordEncryptionScheme(
3505 const std::string& stream_name,
3506 const EncryptionScheme& encryption_scheme) {
3507 DCHECK(stream_name == "Audio" || stream_name == "Video");
3508
3509 // If the stream is not encrypted, don't record it.
3510 if (encryption_scheme.mode() == EncryptionScheme::CIPHER_MODE_UNENCRYPTED)
3511 return;
3512
3513 base::UmaHistogramEnumeration(
3514 "Media.EME.EncryptionScheme.Initial." + stream_name,
3515 DetermineEncryptionSchemeUMAValue(encryption_scheme),
3516 EncryptionSchemeUMA::kCount);
3517}
3518
Mounir Lamouri0484f40a2018-07-25 03:03:263519bool WebMediaPlayerImpl::IsInPictureInPicture() const {
3520 DCHECK(client_);
3521 return client_->DisplayType() ==
3522 WebMediaPlayer::DisplayType::kPictureInPicture;
3523}
3524
Dale Curtis5bba03232018-08-30 17:57:383525void WebMediaPlayerImpl::MaybeSetContainerName() {
Dale Curtisf01c8262018-09-04 23:50:433526 // MSE nor MediaPlayerRenderer provide container information.
3527 if (chunk_demuxer_ || using_media_player_renderer_)
Dale Curtis5bba03232018-08-30 17:57:383528 return;
3529
3530 // Pipeline startup failed before even getting a demuxer setup.
3531 if (!demuxer_)
3532 return;
3533
3534 // Container has already been set.
3535 if (highest_ready_state_ >= WebMediaPlayer::kReadyStateHaveMetadata)
3536 return;
3537
3538// If ffmpeg isn't enabled, we can't get the container name.
3539#if BUILDFLAG(ENABLE_FFMPEG)
3540 media_metrics_provider_->SetContainerName(
3541 static_cast<FFmpegDemuxer*>(demuxer_.get())->container());
3542#endif
3543}
3544
Dale Curtis18ad391b2019-05-30 23:25:093545void WebMediaPlayerImpl::MaybeUpdateBufferSizesForPlayback() {
3546 // Don't increase the MultiBufferDataSource buffer size until we've reached
3547 // kReadyStateHaveEnoughData. Otherwise we will unnecessarily slow down
3548 // playback startup -- it can instead be done for free after playback starts.
3549 if (!mb_data_source_ || highest_ready_state_ < kReadyStateHaveEnoughData)
3550 return;
3551
3552 mb_data_source_->MediaPlaybackRateChanged(playback_rate_);
3553 if (!paused_)
3554 mb_data_source_->MediaIsPlaying();
3555}
3556
acolwell9e0840d2014-09-06 19:01:323557} // namespace media