blob: 0b1aa3941182c5d4ef871c1d733ce17de6fe9feb [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"
[email protected]96665a82020-01-23 00:35:3755#include "media/learning/mojo/public/cpp/mojo_learning_task_controller.h"
Scott Violeta35f9a42018-03-22 22:00:4456#include "media/media_buildflags.h"
Gyuyoung Kima040bc52019-10-30 01:14:3557#include "mojo/public/cpp/bindings/pending_remote.h"
Dale Curtis4841c712018-12-13 18:14:0558#include "net/base/data_url.h"
Blink Reformata30d4232018-04-07 15:31:0659#include "third_party/blink/public/platform/web_encrypted_media_types.h"
Blink Reformata30d4232018-04-07 15:31:0660#include "third_party/blink/public/platform/web_media_player_client.h"
61#include "third_party/blink/public/platform/web_media_player_encrypted_media_client.h"
62#include "third_party/blink/public/platform/web_media_player_source.h"
63#include "third_party/blink/public/platform/web_media_source.h"
64#include "third_party/blink/public/platform/web_rect.h"
65#include "third_party/blink/public/platform/web_runtime_features.h"
66#include "third_party/blink/public/platform/web_security_origin.h"
67#include "third_party/blink/public/platform/web_size.h"
68#include "third_party/blink/public/platform/web_string.h"
69#include "third_party/blink/public/platform/web_surface_layer_bridge.h"
70#include "third_party/blink/public/platform/web_url.h"
Antonio Gomes3a858b52019-05-31 02:47:5271#include "third_party/blink/public/platform/webaudiosourceprovider_impl.h"
Gyuyoung Kimf99f5f32019-09-26 03:45:1572#include "third_party/blink/public/strings/grit/blink_strings.h"
Antonio Gomesf01cfbd2019-07-12 08:53:1173#include "third_party/blink/public/web/modules/media/webmediaplayer_util.h"
Blink Reformata30d4232018-04-07 15:31:0674#include "third_party/blink/public/web/web_document.h"
75#include "third_party/blink/public/web/web_frame.h"
76#include "third_party/blink/public/web/web_local_frame.h"
Blink Reformata30d4232018-04-07 15:31:0677#include "third_party/blink/public/web/web_view.h"
[email protected]b3f2b912009-04-09 16:18:5278
dalecurtisea27a3ed2016-06-24 01:41:3079#if defined(OS_ANDROID)
80#include "media/base/android/media_codec_util.h"
81#endif
82
[email protected]180ef242013-11-07 06:50:4683using blink::WebMediaPlayer;
84using blink::WebRect;
85using blink::WebSize;
86using blink::WebString;
hubbed5f36882016-01-15 22:40:3787using gpu::gles2::GLES2Interface;
88
danakj365175c2016-02-06 00:37:3789#define STATIC_ASSERT_ENUM(a, b) \
90 static_assert(static_cast<int>(a) == static_cast<int>(b), \
91 "mismatching enums: " #a)
92
hubbed5f36882016-01-15 22:40:3793namespace media {
[email protected]ec9212f2008-12-18 21:40:3694
[email protected]8931c41a2009-07-07 17:31:4995namespace {
96
Dan Sanders6edfd782019-08-13 00:13:1897const char kWatchTimeHistogram[] = "Media.WebMediaPlayerImpl.WatchTime";
98
Xiaohan Wang48aaa192019-12-05 01:29:0099void RecordSimpleWatchTimeUMA(RendererFactoryType type) {
100 UMA_HISTOGRAM_ENUMERATION(kWatchTimeHistogram, type);
Dan Sanders6edfd782019-08-13 00:13:18101}
102
Antonio Gomes3a858b52019-05-31 02:47:52103void SetSinkIdOnMediaThread(
104 scoped_refptr<blink::WebAudioSourceProviderImpl> sink,
105 const std::string& device_id,
106 OutputDeviceStatusCB callback) {
Daniel Chengc1710b52018-10-24 03:12:28107 sink->SwitchOutputDevice(device_id, std::move(callback));
guidouc7babef2015-10-22 00:42:35108}
109
Sergey Volk8b09c2c52018-12-12 23:20:40110bool IsBackgroundSuspendEnabled(const WebMediaPlayerImpl* wmpi) {
Luke Halliwell7a8a8982018-07-25 01:07:05111 // TODO(crbug.com/867146): remove these switches.
112 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
113 switches::kDisableMediaSuspend))
114 return false;
115 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
116 switches::kEnableMediaSuspend))
117 return true;
118
Sergey Volk8b09c2c52018-12-12 23:20:40119 return wmpi->IsBackgroundMediaSuspendEnabled();
dalecurtis0431cbf2016-03-12 01:19:43120}
121
avayvod48a8be52016-08-04 19:52:50122bool IsResumeBackgroundVideosEnabled() {
123 return base::FeatureList::IsEnabled(kResumeBackgroundVideo);
124}
125
avayvod01201332017-04-14 00:27:15126bool IsBackgroundVideoPauseOptimizationEnabled() {
127 return base::FeatureList::IsEnabled(kBackgroundVideoPauseOptimization);
128}
129
sandersd50a635e2016-04-04 22:50:09130bool IsNetworkStateError(blink::WebMediaPlayer::NetworkState state) {
Blink Reformat1c4d759e2017-04-09 16:34:54131 bool result = state == blink::WebMediaPlayer::kNetworkStateFormatError ||
132 state == blink::WebMediaPlayer::kNetworkStateNetworkError ||
133 state == blink::WebMediaPlayer::kNetworkStateDecodeError;
134 DCHECK_EQ(state > blink::WebMediaPlayer::kNetworkStateLoaded, result);
sandersd50a635e2016-04-04 22:50:09135 return result;
136}
137
sandersd2c478422016-08-02 01:19:25138gfx::Size GetRotatedVideoSize(VideoRotation rotation, gfx::Size natural_size) {
139 if (rotation == VIDEO_ROTATION_90 || rotation == VIDEO_ROTATION_270)
140 return gfx::Size(natural_size.height(), natural_size.width());
141 return natural_size;
142}
143
Xiaohan Wangf63505d2017-10-21 08:00:53144void RecordEncryptedEvent(bool encrypted_event_fired) {
145 UMA_HISTOGRAM_BOOLEAN("Media.EME.EncryptedEvent", encrypted_event_fired);
146}
147
sandersd35d2c3f2017-01-14 02:04:42148// How much time must have elapsed since loading last progressed before we
149// assume that the decoder will have had time to complete preroll.
150constexpr base::TimeDelta kPrerollAttemptTimeout =
watkd026f792016-11-05 00:28:51151 base::TimeDelta::FromSeconds(3);
152
Matt Wolenetz6010f6c2017-10-18 00:44:36153// Maximum number, per-WMPI, of media logs of playback rate changes.
154constexpr int kMaxNumPlaybackRateLogs = 10;
155
Gyuyoung Kimf99f5f32019-09-26 03:45:15156int GetSwitchToLocalMessage(MediaObserverClient::ReasonToSwitchToLocal reason) {
Xiangjun Zhang5e20cba42018-01-10 19:54:56157 switch (reason) {
158 case MediaObserverClient::ReasonToSwitchToLocal::NORMAL:
Gyuyoung Kimf99f5f32019-09-26 03:45:15159 return IDS_MEDIA_REMOTING_STOP_TEXT;
Xiangjun Zhang5e20cba42018-01-10 19:54:56160 case MediaObserverClient::ReasonToSwitchToLocal::POOR_PLAYBACK_QUALITY:
Gyuyoung Kimf99f5f32019-09-26 03:45:15161 return IDS_MEDIA_REMOTING_STOP_BY_PLAYBACK_QUALITY_TEXT;
Xiangjun Zhang5e20cba42018-01-10 19:54:56162 case MediaObserverClient::ReasonToSwitchToLocal::PIPELINE_ERROR:
Gyuyoung Kimf99f5f32019-09-26 03:45:15163 return IDS_MEDIA_REMOTING_STOP_BY_ERROR_TEXT;
Xiangjun Zhang5e20cba42018-01-10 19:54:56164 case MediaObserverClient::ReasonToSwitchToLocal::ROUTE_TERMINATED:
Gyuyoung Kimf99f5f32019-09-26 03:45:15165 return blink::WebMediaPlayerClient::kMediaRemotingStopNoText;
Xiangjun Zhang5e20cba42018-01-10 19:54:56166 }
167 NOTREACHED();
168 // To suppress compiler warning on Windows.
Gyuyoung Kimf99f5f32019-09-26 03:45:15169 return blink::WebMediaPlayerClient::kMediaRemotingStopNoText;
Xiangjun Zhang5e20cba42018-01-10 19:54:56170}
171
John Rummelldb5a7ef2018-05-16 00:28:01172// These values are persisted to UMA. Entries should not be renumbered and
173// numeric values should never be reused.
Yuchen Liub33bfc12019-11-08 20:16:12174// TODO(crbug.com/825041): This should use EncryptionScheme when kUnencrypted
John Rummelldb5a7ef2018-05-16 00:28:01175// removed.
176enum class EncryptionSchemeUMA { kCenc = 0, kCbcs = 1, kCount };
177
178EncryptionSchemeUMA DetermineEncryptionSchemeUMAValue(
Yuchen Liub33bfc12019-11-08 20:16:12179 EncryptionScheme encryption_scheme) {
180 if (encryption_scheme == EncryptionScheme::kCbcs)
John Rummelldb5a7ef2018-05-16 00:28:01181 return EncryptionSchemeUMA::kCbcs;
182
Yuchen Liub33bfc12019-11-08 20:16:12183 DCHECK_EQ(encryption_scheme, EncryptionScheme::kCenc);
John Rummelldb5a7ef2018-05-16 00:28:01184 return EncryptionSchemeUMA::kCenc;
185}
186
Pavel Feldman023c3e62018-08-28 17:59:47187#if BUILDFLAG(ENABLE_FFMPEG)
Dale Curtisb8139f72018-08-27 23:28:48188// Returns true if |url| represents (or is likely to) a local file.
189bool IsLocalFile(const GURL& url) {
190 return url.SchemeIsFile() || url.SchemeIsFileSystem() ||
191 url.SchemeIs(url::kContentScheme) ||
192 url.SchemeIs(url::kContentIDScheme) ||
193 url.SchemeIs("chrome-extension");
194}
Pavel Feldman023c3e62018-08-28 17:59:47195#endif
Dale Curtisb8139f72018-08-27 23:28:48196
Dale Curtisf273f8f2018-12-13 23:40:33197// Handles destruction of media::Renderer dependent components after the
198// renderer has been destructed on the media thread.
199void DestructionHelper(
200 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
201 scoped_refptr<base::SingleThreadTaskRunner> vfc_task_runner,
202 std::unique_ptr<Demuxer> demuxer,
203 std::unique_ptr<DataSource> data_source,
204 std::unique_ptr<VideoFrameCompositor> compositor,
205 std::unique_ptr<CdmContextRef> cdm_context_1,
206 std::unique_ptr<CdmContextRef> cdm_context_2,
207 std::unique_ptr<MediaLog> media_log,
208 std::unique_ptr<RendererFactorySelector> renderer_factory_selector,
209 std::unique_ptr<blink::WebSurfaceLayerBridge> bridge,
210 bool is_chunk_demuxer) {
211 // We release |bridge| after pipeline stop to ensure layout tests receive
212 // painted video frames before test harness exit.
213 main_task_runner->DeleteSoon(FROM_HERE, std::move(bridge));
214
215 // Since the media::Renderer is gone we can now destroy the compositor and
216 // renderer factory selector.
217 vfc_task_runner->DeleteSoon(FROM_HERE, std::move(compositor));
218 main_task_runner->DeleteSoon(FROM_HERE, std::move(renderer_factory_selector));
219
220 // ChunkDemuxer can be deleted on any thread, but other demuxers are bound to
221 // the main thread and must be deleted there now that the renderer is gone.
222 if (!is_chunk_demuxer) {
223 main_task_runner->DeleteSoon(FROM_HERE, std::move(demuxer));
224 main_task_runner->DeleteSoon(FROM_HERE, std::move(data_source));
225 main_task_runner->DeleteSoon(FROM_HERE, std::move(cdm_context_1));
226 main_task_runner->DeleteSoon(FROM_HERE, std::move(cdm_context_2));
227 main_task_runner->DeleteSoon(FROM_HERE, std::move(media_log));
228 return;
229 }
230
231 // ChunkDemuxer's streams may contain much buffered, compressed media that
232 // may need to be paged back in during destruction. Paging delay may exceed
233 // the renderer hang monitor's threshold on at least Windows while also
234 // blocking other work on the renderer main thread, so we do the actual
235 // destruction in the background without blocking WMPI destruction or
236 // |task_runner|. On advice of task_scheduler OWNERS, MayBlock() is not
237 // used because virtual memory overhead is not considered blocking I/O; and
238 // CONTINUE_ON_SHUTDOWN is used to allow process termination to not block on
239 // completing the task.
Sami Kyostila127d6632019-08-06 21:32:25240 base::PostTask(
Dale Curtisf273f8f2018-12-13 23:40:33241 FROM_HERE,
Sami Kyostila127d6632019-08-06 21:32:25242 {base::ThreadPool(), base::TaskPriority::BEST_EFFORT,
Dale Curtisf273f8f2018-12-13 23:40:33243 base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
244 base::BindOnce(
245 [](scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
246 std::unique_ptr<Demuxer> demuxer_to_destroy,
247 std::unique_ptr<CdmContextRef> cdm_context_1,
248 std::unique_ptr<CdmContextRef> cdm_context_2,
249 std::unique_ptr<MediaLog> media_log) {
250 SCOPED_UMA_HISTOGRAM_TIMER("Media.MSE.DemuxerDestructionTime");
251 demuxer_to_destroy.reset();
252 main_task_runner->DeleteSoon(FROM_HERE, std::move(cdm_context_1));
253 main_task_runner->DeleteSoon(FROM_HERE, std::move(cdm_context_2));
254 main_task_runner->DeleteSoon(FROM_HERE, std::move(media_log));
255 },
256 std::move(main_task_runner), std::move(demuxer),
257 std::move(cdm_context_1), std::move(cdm_context_2),
258 std::move(media_log)));
259}
260
Ted Meyer7f5b4e22019-11-21 03:21:19261std::string SanitizeUserStringProperty(blink::WebString value) {
Ted Meyera698afe2019-11-06 20:58:03262 std::string converted = value.Utf8();
Ted Meyer7f5b4e22019-11-21 03:21:19263 return base::IsStringUTF8(converted) ? converted : "[invalid property]";
Ted Meyera698afe2019-11-06 20:58:03264}
265
[email protected]8931c41a2009-07-07 17:31:49266} // namespace
267
[email protected]6683e1b2014-04-10 01:45:38268class BufferedDataSourceHostImpl;
269
Takashi Toyoshima2e01e692018-11-16 03:23:27270STATIC_ASSERT_ENUM(WebMediaPlayer::kCorsModeUnspecified,
danakj365175c2016-02-06 00:37:37271 UrlData::CORS_UNSPECIFIED);
Takashi Toyoshima2e01e692018-11-16 03:23:27272STATIC_ASSERT_ENUM(WebMediaPlayer::kCorsModeAnonymous, UrlData::CORS_ANONYMOUS);
273STATIC_ASSERT_ENUM(WebMediaPlayer::kCorsModeUseCredentials,
danakj365175c2016-02-06 00:37:37274 UrlData::CORS_USE_CREDENTIALS);
[email protected]a5a01102012-06-06 17:01:24275
[email protected]5b5bb9d2010-10-22 19:57:36276WebMediaPlayerImpl::WebMediaPlayerImpl(
[email protected]35b2a972014-04-04 15:50:22277 blink::WebLocalFrame* frame,
[email protected]180ef242013-11-07 06:50:46278 blink::WebMediaPlayerClient* client,
srirama.m26f864d02015-07-14 05:21:46279 blink::WebMediaPlayerEncryptedMediaClient* encrypted_client,
Antonio Gomes423df612019-07-11 12:40:07280 blink::WebMediaPlayerDelegate* delegate,
tguilbert70d2a00a2017-04-25 00:30:44281 std::unique_ptr<RendererFactorySelector> renderer_factory_selector,
Alok Priyadarshi7166d4d2017-07-29 04:04:25282 UrlIndex* url_index,
CJ DiMegliod7ac6772017-11-10 00:19:06283 std::unique_ptr<VideoFrameCompositor> compositor,
dalecurtis9cddc0b2017-04-19 21:23:38284 std::unique_ptr<WebMediaPlayerParams> params)
[email protected]f6af7592014-02-28 10:09:11285 : frame_(frame),
Alexander Timin310368112017-09-13 10:01:44286 main_task_runner_(
287 frame->GetTaskRunner(blink::TaskType::kMediaElementEvent)),
dalecurtis9cddc0b2017-04-19 21:23:38288 media_task_runner_(params->media_task_runner()),
289 worker_task_runner_(params->worker_task_runner()),
290 media_log_(params->take_media_log()),
[email protected]5badb082010-06-11 17:40:15291 client_(client),
srirama.m26f864d02015-07-14 05:21:46292 encrypted_client_(encrypted_client),
[email protected]baff4512011-10-19 18:21:07293 delegate_(delegate),
dalecurtis9cddc0b2017-04-19 21:23:38294 defer_load_cb_(params->defer_load_cb()),
dalecurtis9cddc0b2017-04-19 21:23:38295 adjust_allocated_memory_cb_(params->adjust_allocated_memory_cb()),
tzik2c963b872017-12-07 06:57:24296 tick_clock_(base::DefaultTickClock::GetInstance()),
hubbe5f0ad43b2015-12-14 20:57:26297 url_index_(url_index),
CJ DiMeglioc60a5cf2017-09-27 20:08:41298 context_provider_(params->context_provider()),
CJ DiMegliod7ac6772017-11-10 00:19:06299 vfc_task_runner_(params->video_frame_compositor_task_runner()),
300 compositor_(std::move(compositor)),
tguilbert70d2a00a2017-04-25 00:30:44301 renderer_factory_selector_(std::move(renderer_factory_selector)),
dalecurtis9cddc0b2017-04-19 21:23:38302 observer_(params->media_observer()),
servolkf94b4602017-01-31 16:44:27303 enable_instant_source_buffer_gc_(
dalecurtis9cddc0b2017-04-19 21:23:38304 params->enable_instant_source_buffer_gc()),
shaktisahu24189c12017-03-11 17:42:55305 embedded_media_experience_enabled_(
liberato2ff93ad2017-05-17 07:28:24306 params->embedded_media_experience_enabled()),
[email protected]69db58f2018-09-26 20:27:56307 surface_layer_mode_(params->use_surface_layer_for_video()),
CJ DiMeglio96c18b692018-07-04 03:39:06308 create_bridge_callback_(params->create_bridge_callback()),
liberato2ff93ad2017-05-17 07:28:24309 request_routing_token_cb_(params->request_routing_token_cb()),
Dale Curtis1adbe6a2017-08-02 02:09:13310 overlay_routing_token_(OverlayInfo::RoutingToken()),
Sergey Volk8b09c2c52018-12-12 23:20:40311 media_metrics_provider_(params->take_metrics_provider()),
312 is_background_suspend_enabled_(params->IsBackgroundSuspendEnabled()),
Junbo Kefba620b2019-01-16 02:54:36313 is_background_video_playback_enabled_(
314 params->IsBackgroundVideoPlaybackEnabled()),
Sergey Volk8b09c2c52018-12-12 23:20:40315 is_background_video_track_optimization_supported_(
Dan Sanders6edfd782019-08-13 00:13:18316 params->IsBackgroundVideoTrackOptimizationSupported()),
Xiaohan Wang48aaa192019-12-05 01:29:00317 reported_renderer_type_(RendererFactoryType::kDefault),
Dan Sanders6edfd782019-08-13 00:13:18318 simple_watch_timer_(
319 base::BindRepeating(&WebMediaPlayerImpl::OnSimpleWatchTimerTick,
320 base::Unretained(this)),
321 base::BindRepeating(&WebMediaPlayerImpl::GetCurrentTimeInternal,
[email protected]91fd3162019-09-05 23:51:32322 base::Unretained(this))),
[email protected]dc996312019-12-19 19:26:38323 will_play_helper_(nullptr),
324 power_status_helper_(params->TakePowerStatusHelper()) {
xhwang51139732017-02-24 19:36:08325 DVLOG(1) << __func__;
Dale Curtise25163812018-09-21 22:13:39326 DCHECK(adjust_allocated_memory_cb_);
tguilbert70d2a00a2017-04-25 00:30:44327 DCHECK(renderer_factory_selector_);
servolkef1e5ef2016-03-25 04:55:26328 DCHECK(client_);
tguilbert1bb1c782017-01-23 21:15:11329 DCHECK(delegate_);
dalecurtis83266c72015-10-29 18:43:20330
Antonio Gomes142f32a2019-05-15 23:32:56331 weak_this_ = weak_factory_.GetWeakPtr();
332
Xiaohan Wang2480de72019-11-15 01:44:47333 // Using base::Unretained(this) is safe because the |pipeline| is owned by
334 // |this| and the callback will always be made on the main task runner.
335 // Not using BindToCurrentLoop() because CreateRenderer() is a sync call.
336 auto pipeline = std::make_unique<PipelineImpl>(
337 media_task_runner_, main_task_runner_,
338 base::BindRepeating(&WebMediaPlayerImpl::CreateRenderer,
339 base::Unretained(this)),
340 media_log_.get());
341
Antonio Gomes81b56552019-05-15 22:15:28342 pipeline_controller_ = std::make_unique<PipelineController>(
Xiaohan Wang2480de72019-11-15 01:44:47343 std::move(pipeline),
Antonio Gomes142f32a2019-05-15 23:32:56344 base::BindRepeating(&WebMediaPlayerImpl::OnPipelineSeeked, weak_this_),
345 base::BindRepeating(&WebMediaPlayerImpl::OnPipelineSuspended, weak_this_),
Antonio Gomes81b56552019-05-15 22:15:28346 base::BindRepeating(&WebMediaPlayerImpl::OnBeforePipelineResume,
Antonio Gomes142f32a2019-05-15 23:32:56347 weak_this_),
348 base::BindRepeating(&WebMediaPlayerImpl::OnPipelineResumed, weak_this_),
349 base::BindRepeating(&WebMediaPlayerImpl::OnError, weak_this_));
Antonio Gomes81b56552019-05-15 22:15:28350
351 buffered_data_source_host_ = std::make_unique<BufferedDataSourceHostImpl>(
Antonio Gomes142f32a2019-05-15 23:32:56352 base::BindRepeating(&WebMediaPlayerImpl::OnProgress, weak_this_),
Antonio Gomes81b56552019-05-15 22:15:28353 tick_clock_);
354
[email protected]c8d574722017-08-30 20:53:43355 // If we're supposed to force video overlays, then make sure that they're
356 // enabled all the time.
357 always_enable_overlays_ = base::CommandLine::ForCurrentProcess()->HasSwitch(
tsunghungee562e92016-07-20 18:03:31358 switches::kForceVideoOverlays);
359
Jinsong Fan982342112019-11-07 23:45:45360 if (base::FeatureList::IsEnabled(kOverlayFullscreenVideo))
361 overlay_mode_ = OverlayMode::kUseAndroidOverlay;
362 else
liberato2ff93ad2017-05-17 07:28:24363 overlay_mode_ = OverlayMode::kNoOverlays;
ampea73f792017-01-19 04:05:39364
tguilbert1bb1c782017-01-23 21:15:11365 delegate_id_ = delegate_->AddObserver(this);
366 delegate_->SetIdle(delegate_id_, true);
sandersd1e49fb62015-12-12 01:18:06367
Ted Meyer0134aed2020-01-23 23:56:40368 media_log_->AddEvent<MediaLogEvent::kWebMediaPlayerCreated>(
369 url::Origin(frame_->GetSecurityOrigin()).GetURL().spec());
Ted Meyera698afe2019-11-06 20:58:03370
Ted Meyer7f5b4e22019-11-21 03:21:19371 media_log_->SetProperty<MediaLogProperty::kFrameUrl>(
372 SanitizeUserStringProperty(frame_->GetDocument().Url().GetString()));
373 media_log_->SetProperty<MediaLogProperty::kFrameTitle>(
374 SanitizeUserStringProperty(frame_->GetDocument().Title()));
[email protected]52b0b212018-10-10 05:25:28375
dalecurtis9cddc0b2017-04-19 21:23:38376 if (params->initial_cdm())
Chris Cunninghamd4a00192019-03-21 20:02:49377 SetCdmInternal(params->initial_cdm());
xhwang0ad11e512014-11-25 23:43:09378
Xiaohan Wangf63505d2017-10-21 08:00:53379 // Report a false "EncrytpedEvent" here as a baseline.
380 RecordEncryptedEvent(false);
381
xhwangf94a634d2014-10-22 22:07:27382 // TODO(xhwang): When we use an external Renderer, many methods won't work,
xhwang6fa356202014-12-11 00:44:12383 // e.g. GetCurrentFrameFromCompositor(). See http://crbug.com/434861
Antonio Gomes3a858b52019-05-31 02:47:52384 audio_source_provider_ = new blink::WebAudioSourceProviderImpl(
dalecurtis9cddc0b2017-04-19 21:23:38385 params->audio_renderer_sink(), media_log_.get());
xjz4e5d4bf32017-02-15 21:26:35386
387 if (observer_)
388 observer_->SetClient(this);
Hajime Hoshi8bb37dc2017-12-19 09:35:10389
390 memory_usage_reporting_timer_.SetTaskRunner(
Hajime Hoshib5a26ee2018-05-14 12:47:51391 frame_->GetTaskRunner(blink::TaskType::kInternalMedia));
John Delaney6c8ecc1b2018-10-21 19:07:29392
Thomas Guilbert901808982019-07-03 20:38:18393#if defined(OS_ANDROID)
Thomas Guilbertf6d0702e2019-09-12 23:40:14394 renderer_factory_selector_->SetRemotePlayStateChangeCB(
395 BindToCurrentLoop(base::BindRepeating(
396 &WebMediaPlayerImpl::OnRemotePlayStateChange, weak_this_)));
Thomas Guilbert901808982019-07-03 20:38:18397#endif // defined (OS_ANDROID)
[email protected]ec9212f2008-12-18 21:40:36398}
399
[email protected]4e6be3f2009-05-07 02:24:44400WebMediaPlayerImpl::~WebMediaPlayerImpl() {
xhwang51139732017-02-24 19:36:08401 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:43402 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53403
xhwang51139732017-02-24 19:36:08404 if (set_cdm_result_) {
Chris Cunninghamd4a00192019-03-21 20:02:49405 DVLOG(2)
406 << "Resolve pending SetCdmInternal() when media player is destroyed.";
Blink Reformat1c4d759e2017-04-09 16:34:54407 set_cdm_result_->Complete();
xhwang51139732017-02-24 19:36:08408 set_cdm_result_.reset();
409 }
410
alokp1116967f2016-06-11 17:30:56411 suppress_destruction_errors_ = true;
tguilbert1bb1c782017-01-23 21:15:11412
413 delegate_->PlayerGone(delegate_id_);
414 delegate_->RemoveObserver(delegate_id_);
[email protected]baff4512011-10-19 18:21:07415
dalecurtis04bdb582016-08-17 22:15:23416 // Finalize any watch time metrics before destroying the pipeline.
417 watch_time_reporter_.reset();
418
tguilbert350936ff2017-02-24 05:39:27419 // The underlying Pipeline must be stopped before it is destroyed.
Dale Curtisf273f8f2018-12-13 23:40:33420 //
421 // Note: This destruction happens synchronously on the media thread and
422 // |demuxer_|, |data_source_|, |compositor_|, and |media_log_| must outlive
423 // this process. They will be destructed by the DestructionHelper below
424 // after trampolining through the media thread.
Antonio Gomes81b56552019-05-15 22:15:28425 pipeline_controller_->Stop();
[email protected]f6af7592014-02-28 10:09:11426
dalecurtis83266c72015-10-29 18:43:20427 if (last_reported_memory_usage_)
428 adjust_allocated_memory_cb_.Run(-last_reported_memory_usage_);
429
dalecurtise1edb312016-06-22 02:33:21430 // Destruct compositor resources in the proper order.
danakj8d204a42018-05-18 18:05:35431 client_->SetCcLayer(nullptr);
CJ DiMeglio2302d202017-08-31 08:38:04432
Xiangjun Zhang5e20cba42018-01-10 19:54:56433 client_->MediaRemotingStopped(
Gyuyoung Kimf99f5f32019-09-26 03:45:15434 blink::WebMediaPlayerClient::kMediaRemotingStopNoText);
Xiangjun Zhang87299142017-09-13 20:35:03435
Dale Curtisf273f8f2018-12-13 23:40:33436 if (!surface_layer_for_video_enabled_ && video_layer_)
danakj25f030112018-05-11 18:26:54437 video_layer_->StopUsingProvider();
Matt Wolenetz95af6362018-01-04 20:23:42438
Dan Sanders6edfd782019-08-13 00:13:18439 simple_watch_timer_.Stop();
Ted Meyer257b682a2019-11-01 20:50:51440 media_log_->OnWebMediaPlayerDestroyed();
[email protected]ec9212f2008-12-18 21:40:36441
Dale Curtisf273f8f2018-12-13 23:40:33442 if (data_source_)
443 data_source_->Stop();
444
445 // Disconnect from the surface layer. We still preserve the |bridge_| until
446 // after pipeline shutdown to ensure any pending frames are painted for tests.
447 if (bridge_)
448 bridge_->ClearObserver();
449
Dale Curtisc96a3542018-12-17 22:15:23450 // Disconnect from the MediaObserver implementation since it's lifetime is
451 // tied to the RendererFactorySelector which can't be destroyed until after
452 // the Pipeline stops.
453 //
454 // Note: We can't use a WeakPtr with the RendererFactory because its methods
455 // are called on the media thread and this destruction takes place on the
456 // renderer thread.
457 if (observer_)
458 observer_->SetClient(nullptr);
459
[email protected]91fd3162019-09-05 23:51:32460 // If we're in the middle of an observation, then finish it.
461 will_play_helper_.CompleteObservationIfNeeded(learning::TargetValue(false));
462
Dale Curtisf273f8f2018-12-13 23:40:33463 // Handle destruction of things that need to be destructed after the pipeline
464 // completes stopping on the media thread.
465 media_task_runner_->PostTask(
Matt Wolenetz95af6362018-01-04 20:23:42466 FROM_HERE,
Dale Curtisf273f8f2018-12-13 23:40:33467 base::BindOnce(&DestructionHelper, std::move(main_task_runner_),
468 std::move(vfc_task_runner_), std::move(demuxer_),
469 std::move(data_source_), std::move(compositor_),
470 std::move(cdm_context_ref_),
471 std::move(pending_cdm_context_ref_), std::move(media_log_),
472 std::move(renderer_factory_selector_), std::move(bridge_),
473 !!chunk_demuxer_));
Matt Wolenetz95af6362018-01-04 20:23:42474}
475
chcunningham707b821e2018-05-29 08:42:19476WebMediaPlayer::LoadTiming WebMediaPlayerImpl::Load(
477 LoadType load_type,
478 const blink::WebMediaPlayerSource& source,
Takashi Toyoshima2e01e692018-11-16 03:23:27479 CorsMode cors_mode) {
guidou9bfe4e2f2016-04-09 08:31:19480 // Only URL or MSE blob URL is supported.
Blink Reformat1c4d759e2017-04-09 16:34:54481 DCHECK(source.IsURL());
482 blink::WebURL url = source.GetAsURL();
Xiaohan Wang81fd0022017-07-11 17:45:24483 DVLOG(1) << __func__ << "(" << load_type << ", " << GURL(url) << ", "
484 << cors_mode << ")";
chcunningham707b821e2018-05-29 08:42:19485
486 bool is_deferred = false;
487
Dale Curtise25163812018-09-21 22:13:39488 if (defer_load_cb_) {
chcunningham707b821e2018-05-29 08:42:19489 is_deferred = defer_load_cb_.Run(base::BindOnce(
Antonio Gomes142f32a2019-05-15 23:32:56490 &WebMediaPlayerImpl::DoLoad, weak_this_, load_type, url, cors_mode));
chcunningham707b821e2018-05-29 08:42:19491 } else {
492 DoLoad(load_type, url, cors_mode);
[email protected]d726eddc2013-07-02 22:25:55493 }
chcunningham707b821e2018-05-29 08:42:19494
495 return is_deferred ? LoadTiming::kDeferred : LoadTiming::kImmediate;
[email protected]62e5e682013-03-07 23:53:24496}
497
CJ DiMeglio013d4c472017-11-21 03:27:30498void WebMediaPlayerImpl::OnWebLayerUpdated() {}
499
danakj6a062b112018-05-17 16:25:45500void WebMediaPlayerImpl::RegisterContentsLayer(cc::Layer* layer) {
CJ DiMeglio2302d202017-08-31 08:38:04501 DCHECK(bridge_);
CJ DiMeglioa2b13fbc2018-06-27 00:50:59502 bridge_->SetContentsOpaque(opaque_);
danakj8d204a42018-05-18 18:05:35503 client_->SetCcLayer(layer);
CJ DiMeglio013d4c472017-11-21 03:27:30504}
505
danakj6a062b112018-05-17 16:25:45506void WebMediaPlayerImpl::UnregisterContentsLayer(cc::Layer* layer) {
507 // |client_| will unregister its cc::Layer if given a nullptr.
danakj8d204a42018-05-18 18:05:35508 client_->SetCcLayer(nullptr);
CJ DiMeglio2302d202017-08-31 08:38:04509}
510
Jennifer Apaciblec45fd052018-02-25 12:04:55511void WebMediaPlayerImpl::OnSurfaceIdUpdated(viz::SurfaceId surface_id) {
Jennifer Apaciblec45fd052018-02-25 12:04:55512 // TODO(726619): Handle the behavior when Picture-in-Picture mode is
513 // disabled.
Jennifer Apacible2b1dc5eb2018-04-27 16:23:28514 // The viz::SurfaceId may be updated when the video begins playback or when
515 // the size of the video changes.
Mounir Lamouri99ba5a62019-02-12 01:27:47516 if (client_)
517 client_->OnPictureInPictureStateChange();
Jennifer Apaciblec45fd052018-02-25 12:04:55518}
519
tsunghungee562e92016-07-20 18:03:31520void WebMediaPlayerImpl::EnableOverlay() {
521 overlay_enabled_ = true;
[email protected]f7df5b342018-07-13 20:22:13522 if (request_routing_token_cb_ &&
523 overlay_mode_ == OverlayMode::kUseAndroidOverlay) {
liberatofe8f9692017-06-08 19:17:36524 overlay_routing_token_is_pending_ = true;
liberato2ff93ad2017-05-17 07:28:24525 token_available_cb_.Reset(
Antonio Gomes142f32a2019-05-15 23:32:56526 base::Bind(&WebMediaPlayerImpl::OnOverlayRoutingToken, weak_this_));
liberato2ff93ad2017-05-17 07:28:24527 request_routing_token_cb_.Run(token_available_cb_.callback());
watkf835a792016-06-24 23:24:40528 }
tsunghungee562e92016-07-20 18:03:31529
liberato2ff93ad2017-05-17 07:28:24530 // We have requested (and maybe already have) overlay information. If the
531 // restarted decoder requests overlay information, then we'll defer providing
532 // it if it hasn't arrived yet. Otherwise, this would be a race, since we
533 // don't know if the request for overlay info or restart will complete first.
tsunghungee562e92016-07-20 18:03:31534 if (decoder_requires_restart_for_overlay_)
watkdee516f2016-02-18 02:22:19535 ScheduleRestart();
536}
537
tsunghungee562e92016-07-20 18:03:31538void WebMediaPlayerImpl::DisableOverlay() {
539 overlay_enabled_ = false;
Jinsong Fan982342112019-11-07 23:45:45540 if (overlay_mode_ == OverlayMode::kUseAndroidOverlay) {
liberato2ff93ad2017-05-17 07:28:24541 token_available_cb_.Cancel();
liberatofe8f9692017-06-08 19:17:36542 overlay_routing_token_is_pending_ = false;
543 overlay_routing_token_ = OverlayInfo::RoutingToken();
liberato2ff93ad2017-05-17 07:28:24544 }
tsunghungee562e92016-07-20 18:03:31545
546 if (decoder_requires_restart_for_overlay_)
watkdee516f2016-02-18 02:22:19547 ScheduleRestart();
liberato2ff93ad2017-05-17 07:28:24548 else
549 MaybeSendOverlayInfoToDecoder();
watkdee516f2016-02-18 02:22:19550}
551
Blink Reformat1c4d759e2017-04-09 16:34:54552void WebMediaPlayerImpl::EnteredFullscreen() {
liberatofe8f9692017-06-08 19:17:36553 overlay_info_.is_fullscreen = true;
554
[email protected]c8d574722017-08-30 20:53:43555 // |always_enable_overlays_| implies that we're already in overlay mode, so
556 // take no action here. Otherwise, switch to an overlay if it's allowed and
557 // if it will display properly.
558 if (!always_enable_overlays_ && overlay_mode_ != OverlayMode::kNoOverlays &&
liberato2fd111be2017-01-04 00:25:06559 DoesOverlaySupportMetadata()) {
tsunghungee562e92016-07-20 18:03:31560 EnableOverlay();
liberato2fd111be2017-01-04 00:25:06561 }
liberato2ff93ad2017-05-17 07:28:24562
liberatofe8f9692017-06-08 19:17:36563 // We send this only if we can send multiple calls. Otherwise, either (a)
564 // we already sent it and we don't have a callback anyway (we reset it when
565 // it's called in restart mode), or (b) we'll send this later when the surface
566 // actually arrives. GVD assumes that the first overlay info will have the
567 // routing information. Note that we set |is_fullscreen_| earlier, so that
568 // if EnableOverlay() can include fullscreen info in case it sends the overlay
569 // info before returning.
570 if (!decoder_requires_restart_for_overlay_)
571 MaybeSendOverlayInfoToDecoder();
[email protected]dc996312019-12-19 19:26:38572
573 if (power_status_helper_)
574 power_status_helper_->SetIsFullscreen(true);
tsunghungee562e92016-07-20 18:03:31575}
576
Blink Reformat1c4d759e2017-04-09 16:34:54577void WebMediaPlayerImpl::ExitedFullscreen() {
[email protected]dc996312019-12-19 19:26:38578 if (power_status_helper_)
579 power_status_helper_->SetIsFullscreen(false);
580
liberatofe8f9692017-06-08 19:17:36581 overlay_info_.is_fullscreen = false;
582
[email protected]c8d574722017-08-30 20:53:43583 // If we're in overlay mode, then exit it unless we're supposed to allow
584 // overlays all the time.
585 if (!always_enable_overlays_ && overlay_enabled_)
tsunghungee562e92016-07-20 18:03:31586 DisableOverlay();
liberato2ff93ad2017-05-17 07:28:24587
liberatofe8f9692017-06-08 19:17:36588 // See EnteredFullscreen for why we do this.
589 if (!decoder_requires_restart_for_overlay_)
590 MaybeSendOverlayInfoToDecoder();
tsunghungee562e92016-07-20 18:03:31591}
592
Chisoon Jeong81080c922019-09-03 23:40:18593void WebMediaPlayerImpl::BecameDominantVisibleContent(bool is_dominant) {
xjzcdbbe732016-12-03 20:47:42594 if (observer_)
Chisoon Jeong81080c922019-09-03 23:40:18595 observer_->OnBecameDominantVisibleContent(is_dominant);
xjzcdbbe732016-12-03 20:47:42596}
597
Blink Reformat1c4d759e2017-04-09 16:34:54598void WebMediaPlayerImpl::SetIsEffectivelyFullscreen(
François Beaufortad6c5232018-02-26 11:00:44599 blink::WebFullscreenVideoStatus fullscreen_video_status) {
600 delegate_->SetIsEffectivelyFullscreen(delegate_id_, fullscreen_video_status);
zqzhangabc08242017-03-02 16:07:14601}
602
Mounir Lamouri41a79c62017-06-06 12:53:16603void WebMediaPlayerImpl::OnHasNativeControlsChanged(bool has_native_controls) {
604 if (!watch_time_reporter_)
605 return;
606
607 if (has_native_controls)
608 watch_time_reporter_->OnNativeControlsEnabled();
609 else
610 watch_time_reporter_->OnNativeControlsDisabled();
611}
612
Mounir Lamourif9af74e72017-06-19 19:31:45613void WebMediaPlayerImpl::OnDisplayTypeChanged(
614 WebMediaPlayer::DisplayType display_type) {
Mounir Lamouri0484f40a2018-07-25 03:03:26615 if (surface_layer_for_video_enabled_) {
616 vfc_task_runner_->PostTask(
617 FROM_HERE,
618 base::BindOnce(
619 &VideoFrameCompositor::SetForceSubmit,
620 base::Unretained(compositor_.get()),
621 display_type == WebMediaPlayer::DisplayType::kPictureInPicture));
622 }
623
Mounir Lamourif9af74e72017-06-19 19:31:45624 if (!watch_time_reporter_)
625 return;
626
627 switch (display_type) {
628 case WebMediaPlayer::DisplayType::kInline:
629 watch_time_reporter_->OnDisplayTypeInline();
630 break;
631 case WebMediaPlayer::DisplayType::kFullscreen:
632 watch_time_reporter_->OnDisplayTypeFullscreen();
633 break;
634 case WebMediaPlayer::DisplayType::kPictureInPicture:
635 watch_time_reporter_->OnDisplayTypePictureInPicture();
François Beaufort3f62f382019-01-18 15:05:17636
637 // Resumes playback if it was paused when hidden.
638 if (paused_when_hidden_) {
639 paused_when_hidden_ = false;
640 OnPlay();
641 }
Mounir Lamourif9af74e72017-06-19 19:31:45642 break;
643 }
644}
645
[email protected]ef8394c2013-08-21 20:26:30646void WebMediaPlayerImpl::DoLoad(LoadType load_type,
[email protected]180ef242013-11-07 06:50:46647 const blink::WebURL& url,
Takashi Toyoshima2e01e692018-11-16 03:23:27648 CorsMode cors_mode) {
John Chen5b164a02017-11-01 00:36:09649 TRACE_EVENT1("media", "WebMediaPlayerImpl::DoLoad", "id", media_log_->id());
pkastingf5279482016-07-27 02:18:20650 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:43651 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d726eddc2013-07-02 22:25:55652
[email protected]91fd3162019-09-05 23:51:32653 // Start a new observation. If there was one before, then we didn't play it.
654 will_play_helper_.CompleteObservationIfNeeded(learning::TargetValue(false));
655 // For now, send in an empty set of features. We should fill some in here,
656 // and / or ask blink (via |client_|) for features from the DOM.
657 learning::FeatureDictionary dict;
658 will_play_helper_.BeginObservation(dict);
659
Thomas Guilbert55b48d92019-03-25 23:16:54660#if defined(OS_ANDROID)
661 // Only allow credentials if the crossorigin attribute is unspecified
662 // (kCorsModeUnspecified) or "use-credentials" (kCorsModeUseCredentials).
663 // This value is only used by the MediaPlayerRenderer.
664 // See https://crbug.com/936566.
665 //
666 // The credentials mode also has repercussions in WouldTaintOrigin(), but we
667 // access what we need from |mb_data_source_|->cors_mode() directly, instead
668 // of storing it here.
669 allow_media_player_renderer_credentials_ = cors_mode != kCorsModeAnonymous;
670#endif // defined(OS_ANDROID)
671
Dale Curtis4841c712018-12-13 18:14:05672 // Note: |url| may be very large, take care when making copies.
673 loaded_url_ = GURL(url);
674 load_type_ = load_type;
675
676 ReportMetrics(load_type, loaded_url_, *frame_, media_log_.get());
[email protected]62e5e682013-03-07 23:53:24677
Dale Curtis4841c712018-12-13 18:14:05678 // Set subresource URL for crash reporting; will be truncated to 256 bytes.
Robert Sesekc5e91df2017-12-12 21:11:03679 static base::debug::CrashKeyString* subresource_url =
680 base::debug::AllocateCrashKeyString("subresource_url",
681 base::debug::CrashKeySize::Size256);
Dale Curtis4841c712018-12-13 18:14:05682 base::debug::SetCrashKeyString(subresource_url, loaded_url_.spec());
[email protected]ef8394c2013-08-21 20:26:30683
Blink Reformat1c4d759e2017-04-09 16:34:54684 SetNetworkState(WebMediaPlayer::kNetworkStateLoading);
685 SetReadyState(WebMediaPlayer::kReadyStateHaveNothing);
Ted Meyer0134aed2020-01-23 23:56:40686 media_log_->AddEvent<MediaLogEvent::kLoad>(url.GetString().Utf8());
Dale Curtis3899090ea2018-01-12 00:10:35687 load_start_time_ = base::TimeTicks::Now();
[email protected]d726eddc2013-07-02 22:25:55688
[email protected]91379332020-01-26 03:58:20689 // If we're adapting, then restart the smoothness experiment.
690 if (smoothness_helper_)
691 smoothness_helper_.reset();
692
Antonio Gomesf01cfbd2019-07-12 08:53:11693 media_metrics_provider_->Initialize(
694 load_type == kLoadTypeMediaSource,
695 load_type == kLoadTypeURL ? blink::GetMediaURLScheme(loaded_url_)
696 : mojom::MediaURLScheme::kUnknown);
Dale Curtis74612b72017-12-14 20:56:19697
[email protected]d726eddc2013-07-02 22:25:55698 // Media source pipelines can start immediately.
Blink Reformat1c4d759e2017-04-09 16:34:54699 if (load_type == kLoadTypeMediaSource) {
[email protected]ef8394c2013-08-21 20:26:30700 StartPipeline();
hubbe5f0ad43b2015-12-14 20:57:26701 } else {
Dale Curtis4841c712018-12-13 18:14:05702 // Short circuit the more complex loading path for data:// URLs. Sending
703 // them through the network based loading path just wastes memory and causes
704 // worse performance since reads become asynchronous.
705 if (loaded_url_.SchemeIs(url::kDataScheme)) {
706 std::string mime_type, charset, data;
Dale Curtis44eacb72019-06-10 20:41:28707 if (!net::DataURL::Parse(loaded_url_, &mime_type, &charset, &data) ||
708 data.empty()) {
Dale Curtis4841c712018-12-13 18:14:05709 DataSourceInitialized(false);
710 return;
711 }
712
713 // Replace |loaded_url_| with an empty data:// URL since it may be large.
714 loaded_url_ = GURL("data:,");
715
716 // Mark all the data as buffered.
Antonio Gomes81b56552019-05-15 22:15:28717 buffered_data_source_host_->SetTotalBytes(data.size());
718 buffered_data_source_host_->AddBufferedByteRange(0, data.size());
Dale Curtis4841c712018-12-13 18:14:05719
720 DCHECK(!mb_data_source_);
721 data_source_.reset(new MemoryDataSource(std::move(data)));
722 DataSourceInitialized(true);
723 return;
724 }
725
John Delaneyb933391602018-10-17 21:50:47726 auto url_data =
Takashi Toyoshima2e01e692018-11-16 03:23:27727 url_index_->GetByUrl(url, static_cast<UrlData::CorsMode>(cors_mode));
Dale Curtis4841c712018-12-13 18:14:05728 mb_data_source_ = new MultibufferDataSource(
John Delaneyb933391602018-10-17 21:50:47729 main_task_runner_, std::move(url_data), media_log_.get(),
Antonio Gomes81b56552019-05-15 22:15:28730 buffered_data_source_host_.get(),
Dale Curtis4841c712018-12-13 18:14:05731 base::BindRepeating(&WebMediaPlayerImpl::NotifyDownloading,
Antonio Gomes142f32a2019-05-15 23:32:56732 weak_this_));
Dale Curtis4841c712018-12-13 18:14:05733 data_source_.reset(mb_data_source_);
734 mb_data_source_->SetPreload(preload_);
735 mb_data_source_->SetIsClientAudioElement(client_->IsAudioElement());
736 mb_data_source_->Initialize(
Antonio Gomes142f32a2019-05-15 23:32:56737 base::Bind(&WebMediaPlayerImpl::DataSourceInitialized, weak_this_));
hubbe5f0ad43b2015-12-14 20:57:26738 }
[email protected]62e5e682013-03-07 23:53:24739}
740
Blink Reformat1c4d759e2017-04-09 16:34:54741void WebMediaPlayerImpl::Play() {
pkastingf5279482016-07-27 02:18:20742 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:43743 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53744
avayvod65fad272017-02-24 01:00:48745 // User initiated play unlocks background video playback.
Mustaq Ahmed4baa9a6e82019-12-20 23:43:46746 if (frame_->HasTransientUserActivation())
avayvod65fad272017-02-24 01:00:48747 video_locked_when_paused_when_hidden_ = false;
748
sandersd35d2c3f2017-01-14 02:04:42749 // TODO(sandersd): Do we want to reset the idle timer here?
tguilbert1bb1c782017-01-23 21:15:11750 delegate_->SetIdle(delegate_id_, false);
[email protected]49480902009-07-14 20:23:43751 paused_ = false;
Antonio Gomes81b56552019-05-15 22:15:28752 pipeline_controller_->SetPlaybackRate(playback_rate_);
dalecurtis4619cd02016-09-22 21:39:10753 background_pause_timer_.Stop();
sandersd1c0bba02016-03-04 23:14:08754
xjz48a9cb72016-12-20 04:02:49755 if (observer_)
756 observer_->OnPlaying();
757
[email protected]96665a82020-01-23 00:35:37758 // Try to create the smoothness helper, in case we were paused before.
759 UpdateSmoothnessHelper();
760
Mounir Lamouri89c0a1b2018-03-01 15:00:44761 watch_time_reporter_->SetAutoplayInitiated(client_->WasAutoplayInitiated());
762
Dale Curtis051fdf62017-08-05 00:21:13763 // If we're seeking we'll trigger the watch time reporter upon seek completed;
764 // we don't want to start it here since the seek time is unstable. E.g., when
765 // playing content with a positive start time we would have a zero seek time.
766 if (!Seeking()) {
767 DCHECK(watch_time_reporter_);
768 watch_time_reporter_->OnPlaying();
769 }
770
Chris Cunninghamd9df58e2017-08-29 00:04:23771 if (video_decode_stats_reporter_)
772 video_decode_stats_reporter_->OnPlaying();
773
Dan Sanders6edfd782019-08-13 00:13:18774 simple_watch_timer_.Start();
Ted Meyerd5885f82019-07-16 19:19:17775 media_metrics_provider_->SetHasPlayed();
Ted Meyer0134aed2020-01-23 23:56:40776 media_log_->AddEvent<MediaLogEvent::kPlay>();
Dale Curtis18ad391b2019-05-30 23:25:09777
778 MaybeUpdateBufferSizesForPlayback();
sandersd50a635e2016-04-04 22:50:09779 UpdatePlayState();
[email protected]91fd3162019-09-05 23:51:32780
781 // Notify the learning task, if needed.
782 will_play_helper_.CompleteObservationIfNeeded(learning::TargetValue(true));
[email protected]ec9212f2008-12-18 21:40:36783}
784
Blink Reformat1c4d759e2017-04-09 16:34:54785void WebMediaPlayerImpl::Pause() {
pkastingf5279482016-07-27 02:18:20786 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:43787 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53788
sandersd50a635e2016-04-04 22:50:09789 // We update the paused state even when casting, since we expect pause() to be
790 // called when casting begins, and when we exit casting we should end up in a
791 // paused state.
[email protected]49480902009-07-14 20:23:43792 paused_ = true;
hubbed5f36882016-01-15 22:40:37793
avayvodeb9098d2017-01-07 00:33:03794 // No longer paused because it was hidden.
795 paused_when_hidden_ = false;
796
[email protected]96665a82020-01-23 00:35:37797 UpdateSmoothnessHelper();
798
avayvod65fad272017-02-24 01:00:48799 // User initiated pause locks background videos.
Mustaq Ahmed4baa9a6e82019-12-20 23:43:46800 if (frame_->HasTransientUserActivation())
avayvod65fad272017-02-24 01:00:48801 video_locked_when_paused_when_hidden_ = true;
802
Antonio Gomes81b56552019-05-15 22:15:28803 pipeline_controller_->SetPlaybackRate(0.0);
Dale Curtis2fc01cc2019-05-20 22:53:52804
805 // For states <= kReadyStateHaveMetadata, we may not have a renderer yet.
806 if (highest_ready_state_ > WebMediaPlayer::kReadyStateHaveMetadata)
807 paused_time_ = pipeline_controller_->GetMediaTime();
[email protected]090f7312011-08-05 23:26:40808
xjz48a9cb72016-12-20 04:02:49809 if (observer_)
810 observer_->OnPaused();
811
dalecurtis04bdb582016-08-17 22:15:23812 DCHECK(watch_time_reporter_);
813 watch_time_reporter_->OnPaused();
Chris Cunninghamd9df58e2017-08-29 00:04:23814
815 if (video_decode_stats_reporter_)
816 video_decode_stats_reporter_->OnPaused();
817
Dan Sanders6edfd782019-08-13 00:13:18818 simple_watch_timer_.Stop();
Ted Meyer0134aed2020-01-23 23:56:40819 media_log_->AddEvent<MediaLogEvent::kPause>();
avayvod2135a642017-01-13 00:17:14820
Becca Hughes7a85bf22019-07-24 16:16:58821 // Paused changed so we should update media position state.
822 UpdateMediaPositionState();
823
sandersd50a635e2016-04-04 22:50:09824 UpdatePlayState();
[email protected]ec9212f2008-12-18 21:40:36825}
826
Blink Reformat1c4d759e2017-04-09 16:34:54827void WebMediaPlayerImpl::Seek(double seconds) {
pkastingf5279482016-07-27 02:18:20828 DVLOG(1) << __func__ << "(" << seconds << "s)";
acolwellb4034942014-08-28 15:42:43829 DCHECK(main_task_runner_->BelongsToCurrentThread());
Ted Meyer0134aed2020-01-23 23:56:40830 media_log_->AddEvent<MediaLogEvent::kSeek>(seconds);
sandersd1c0bba02016-03-04 23:14:08831 DoSeek(base::TimeDelta::FromSecondsD(seconds), true);
832}
833
834void WebMediaPlayerImpl::DoSeek(base::TimeDelta time, bool time_updated) {
835 DCHECK(main_task_runner_->BelongsToCurrentThread());
John Chen5b164a02017-11-01 00:36:09836 TRACE_EVENT2("media", "WebMediaPlayerImpl::DoSeek", "target",
837 time.InSecondsF(), "id", media_log_->id());
[email protected]d43ed912009-02-03 04:52:53838
srirama.mccf671812015-01-08 11:59:13839 ReadyState old_state = ready_state_;
Blink Reformat1c4d759e2017-04-09 16:34:54840 if (ready_state_ > WebMediaPlayer::kReadyStateHaveMetadata)
841 SetReadyState(WebMediaPlayer::kReadyStateHaveMetadata);
[email protected]1bb666802013-11-28 06:12:08842
Dale Curtis051fdf62017-08-05 00:21:13843 // When paused or ended, we know exactly what the current time is and can
844 // elide seeks to it. However, there are two cases that are not elided:
sandersd1c0bba02016-03-04 23:14:08845 // 1) When the pipeline state is not stable.
846 // In this case we just let |pipeline_controller_| decide what to do, as
847 // it has complete information.
848 // 2) For MSE.
849 // Because the buffers may have changed between seeks, MSE seeks are
850 // never elided.
Antonio Gomes81b56552019-05-15 22:15:28851 if (paused_ && pipeline_controller_->IsStable() &&
Dale Curtis051fdf62017-08-05 00:21:13852 (paused_time_ == time ||
853 (ended_ && time == base::TimeDelta::FromSecondsD(Duration()))) &&
sandersd1c0bba02016-03-04 23:14:08854 !chunk_demuxer_) {
855 // If the ready state was high enough before, we can indicate that the seek
856 // completed just by restoring it. Otherwise we will just wait for the real
857 // ready state change to eventually happen.
Blink Reformat1c4d759e2017-04-09 16:34:54858 if (old_state == kReadyStateHaveEnoughData) {
srirama.m8f4a37562014-12-13 08:16:18859 main_task_runner_->PostTask(
Dale Curtisee9be30012018-09-21 22:21:51860 FROM_HERE, base::BindOnce(&WebMediaPlayerImpl::OnBufferingStateChange,
Chris Cunninghamfc0d67e2019-07-22 20:29:16861 weak_this_, BUFFERING_HAVE_ENOUGH,
862 BUFFERING_CHANGE_REASON_UNKNOWN));
srirama.m36ab2682014-12-11 04:20:01863 }
sandersd1c0bba02016-03-04 23:14:08864 return;
srirama.m36ab2682014-12-11 04:20:01865 }
[email protected]44ff37c02009-10-24 01:03:03866
dalecurtis04bdb582016-08-17 22:15:23867 // Call this before setting |seeking_| so that the current media time can be
868 // recorded by the reporter.
869 if (watch_time_reporter_)
870 watch_time_reporter_->OnSeeking();
871
sandersd35d2c3f2017-01-14 02:04:42872 // TODO(sandersd): Move |seeking_| to PipelineController.
873 // TODO(sandersd): Do we want to reset the idle timer here?
tguilbert1bb1c782017-01-23 21:15:11874 delegate_->SetIdle(delegate_id_, false);
sandersd50a635e2016-04-04 22:50:09875 ended_ = false;
[email protected]b3766a22010-12-22 17:34:13876 seeking_ = true;
sandersd1c0bba02016-03-04 23:14:08877 seek_time_ = time;
878 if (paused_)
879 paused_time_ = time;
Antonio Gomes81b56552019-05-15 22:15:28880 pipeline_controller_->Seek(time, time_updated);
[email protected]b3766a22010-12-22 17:34:13881
sandersd50a635e2016-04-04 22:50:09882 // This needs to be called after Seek() so that if a resume is triggered, it
883 // is to the correct time.
884 UpdatePlayState();
Becca Hughes7a85bf22019-07-24 16:16:58885
886 // The seek time has changed so we should update the media position state.
887 UpdateMediaPositionState();
[email protected]ec9212f2008-12-18 21:40:36888}
889
Blink Reformat1c4d759e2017-04-09 16:34:54890void WebMediaPlayerImpl::SetRate(double rate) {
pkastingf5279482016-07-27 02:18:20891 DVLOG(1) << __func__ << "(" << rate << ")";
acolwellb4034942014-08-28 15:42:43892 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53893
Matt Wolenetz6010f6c2017-10-18 00:44:36894 if (rate != playback_rate_) {
895 LIMITED_MEDIA_LOG(INFO, media_log_.get(), num_playback_rate_logs_,
896 kMaxNumPlaybackRateLogs)
897 << "Effective playback rate changed from " << playback_rate_ << " to "
898 << rate;
899 }
900
[email protected]49480902009-07-14 20:23:43901 playback_rate_ = rate;
Dale Curtis18ad391b2019-05-30 23:25:09902 if (!paused_)
Antonio Gomes81b56552019-05-15 22:15:28903 pipeline_controller_->SetPlaybackRate(rate);
Dale Curtis18ad391b2019-05-30 23:25:09904
905 MaybeUpdateBufferSizesForPlayback();
[email protected]ec9212f2008-12-18 21:40:36906}
907
Blink Reformat1c4d759e2017-04-09 16:34:54908void WebMediaPlayerImpl::SetVolume(double volume) {
pkastingf5279482016-07-27 02:18:20909 DVLOG(1) << __func__ << "(" << volume << ")";
acolwellb4034942014-08-28 15:42:43910 DCHECK(main_task_runner_->BelongsToCurrentThread());
dalecurtisbb3eaac2016-01-27 21:10:25911 volume_ = volume;
Antonio Gomes81b56552019-05-15 22:15:28912 pipeline_controller_->SetVolume(volume_ * volume_multiplier_);
dalecurtis04bdb582016-08-17 22:15:23913 if (watch_time_reporter_)
914 watch_time_reporter_->OnVolumeChange(volume);
Becca Hughes9f6fd4b82017-06-15 10:01:40915 delegate_->DidPlayerMutedStatusChange(delegate_id_, volume == 0.0);
mlamouri910111362016-11-04 11:28:24916
917 // The play state is updated because the player might have left the autoplay
918 // muted state.
919 UpdatePlayState();
[email protected]ec9212f2008-12-18 21:40:36920}
[email protected]f0a51fb52009-03-05 12:46:38921
Chris Cunningham8c2ef912019-11-15 23:10:41922void WebMediaPlayerImpl::SetLatencyHint(double seconds) {
923 DVLOG(1) << __func__ << "(" << seconds << ")";
Chris Cunninghame8c626332019-11-20 23:34:27924 DCHECK(main_task_runner_->BelongsToCurrentThread());
925 base::Optional<base::TimeDelta> latency_hint;
926 if (std::isfinite(seconds)) {
927 DCHECK_GE(seconds, 0);
928 latency_hint = base::TimeDelta::FromSecondsD(seconds);
929 }
930 pipeline_controller_->SetLatencyHint(latency_hint);
Chris Cunningham8c2ef912019-11-15 23:10:41931}
932
Mounir Lamouri967f8fb72019-02-13 02:34:22933void WebMediaPlayerImpl::OnRequestPictureInPicture() {
[email protected]69db58f2018-09-26 20:27:56934 if (!surface_layer_for_video_enabled_)
935 ActivateSurfaceLayerForVideo();
936
Mounir Lamourib642a3c2018-07-09 15:45:31937 DCHECK(bridge_);
Mounir Lamouri99ba5a62019-02-12 01:27:47938 DCHECK(bridge_->GetSurfaceId().is_valid());
Jennifer Apacible3f0489102018-01-19 20:10:31939}
940
Daniel Chengc1710b52018-10-24 03:12:28941void WebMediaPlayerImpl::SetSinkId(
942 const blink::WebString& sink_id,
Antonio Gomese7813f32019-04-02 06:11:03943 blink::WebSetSinkIdCompleteCallback completion_callback) {
guidou69223ce2015-06-16 10:36:19944 DCHECK(main_task_runner_->BelongsToCurrentThread());
pkastingf5279482016-07-27 02:18:20945 DVLOG(1) << __func__;
guidouc7babef2015-10-22 00:42:35946
Dale Curtisca1b78f2019-01-15 03:11:26947 OutputDeviceStatusCB callback =
Antonio Gomese7813f32019-04-02 06:11:03948 ConvertToOutputDeviceStatusCB(std::move(completion_callback));
guidouc7babef2015-10-22 00:42:35949 media_task_runner_->PostTask(
Dale Curtisee9be30012018-09-21 22:21:51950 FROM_HERE, base::BindOnce(&SetSinkIdOnMediaThread, audio_source_provider_,
Daniel Chengc1710b52018-10-24 03:12:28951 sink_id.Utf8(), std::move(callback)));
guidou69223ce2015-06-16 10:36:19952}
953
Blink Reformat1c4d759e2017-04-09 16:34:54954STATIC_ASSERT_ENUM(WebMediaPlayer::kPreloadNone, MultibufferDataSource::NONE);
955STATIC_ASSERT_ENUM(WebMediaPlayer::kPreloadMetaData,
dalecurtisb6e052f52016-08-25 00:35:55956 MultibufferDataSource::METADATA);
Blink Reformat1c4d759e2017-04-09 16:34:54957STATIC_ASSERT_ENUM(WebMediaPlayer::kPreloadAuto, MultibufferDataSource::AUTO);
[email protected]23a8b1d82011-04-05 16:28:20958
Blink Reformat1c4d759e2017-04-09 16:34:54959void WebMediaPlayerImpl::SetPreload(WebMediaPlayer::Preload preload) {
pkastingf5279482016-07-27 02:18:20960 DVLOG(1) << __func__ << "(" << preload << ")";
acolwellb4034942014-08-28 15:42:43961 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]4e6be3f2009-05-07 02:24:44962
dalecurtisb6e052f52016-08-25 00:35:55963 preload_ = static_cast<MultibufferDataSource::Preload>(preload);
Dale Curtis4841c712018-12-13 18:14:05964 if (mb_data_source_)
965 mb_data_source_->SetPreload(preload_);
[email protected]4e6be3f2009-05-07 02:24:44966}
967
Blink Reformat1c4d759e2017-04-09 16:34:54968bool WebMediaPlayerImpl::HasVideo() const {
acolwellb4034942014-08-28 15:42:43969 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53970
[email protected]b8877772014-03-26 20:17:15971 return pipeline_metadata_.has_video;
[email protected]d43ed912009-02-03 04:52:53972}
973
Blink Reformat1c4d759e2017-04-09 16:34:54974bool WebMediaPlayerImpl::HasAudio() const {
acolwellb4034942014-08-28 15:42:43975 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]fc367af2009-08-14 23:06:35976
[email protected]b8877772014-03-26 20:17:15977 return pipeline_metadata_.has_audio;
[email protected]fc367af2009-08-14 23:06:35978}
979
Blink Reformat1c4d759e2017-04-09 16:34:54980void WebMediaPlayerImpl::EnabledAudioTracksChanged(
servolkf25ceed2016-07-01 03:44:38981 const blink::WebVector<blink::WebMediaPlayer::TrackId>& enabledTrackIds) {
982 DCHECK(main_task_runner_->BelongsToCurrentThread());
983
984 std::ostringstream logstr;
985 std::vector<MediaTrack::Id> enabledMediaTrackIds;
986 for (const auto& blinkTrackId : enabledTrackIds) {
Maciej Pawlowskif2556d122019-06-03 08:14:18987 const auto track_id = MediaTrack::Id(blinkTrackId.Utf8().data());
servolkf25ceed2016-07-01 03:44:38988 logstr << track_id << " ";
989 enabledMediaTrackIds.push_back(track_id);
990 }
dalecurtis9cddc0b2017-04-19 21:23:38991 MEDIA_LOG(INFO, media_log_.get())
992 << "Enabled audio tracks: [" << logstr.str() << "]";
Antonio Gomes81b56552019-05-15 22:15:28993 pipeline_controller_->OnEnabledAudioTracksChanged(enabledMediaTrackIds);
servolkf25ceed2016-07-01 03:44:38994}
995
Blink Reformat1c4d759e2017-04-09 16:34:54996void WebMediaPlayerImpl::SelectedVideoTrackChanged(
servolkf25ceed2016-07-01 03:44:38997 blink::WebMediaPlayer::TrackId* selectedTrackId) {
998 DCHECK(main_task_runner_->BelongsToCurrentThread());
999
servolk9bed6602017-02-24 01:20:111000 base::Optional<MediaTrack::Id> selected_video_track_id;
1001 if (selectedTrackId && !video_track_disabled_)
Blink Reformat1c4d759e2017-04-09 16:34:541002 selected_video_track_id = MediaTrack::Id(selectedTrackId->Utf8().data());
dalecurtis9cddc0b2017-04-19 21:23:381003 MEDIA_LOG(INFO, media_log_.get())
Maciej Pawlowskif2556d122019-06-03 08:14:181004 << "Selected video track: ["
1005 << selected_video_track_id.value_or(MediaTrack::Id()) << "]";
Antonio Gomes81b56552019-05-15 22:15:281006 pipeline_controller_->OnSelectedVideoTrackChanged(selected_video_track_id);
servolkf25ceed2016-07-01 03:44:381007}
1008
Blink Reformat1c4d759e2017-04-09 16:34:541009blink::WebSize WebMediaPlayerImpl::NaturalSize() const {
acolwellb4034942014-08-28 15:42:431010 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:531011
[email protected]b8877772014-03-26 20:17:151012 return blink::WebSize(pipeline_metadata_.natural_size);
[email protected]d43ed912009-02-03 04:52:531013}
1014
Jiajia Qin82acdc02017-07-31 09:55:141015blink::WebSize WebMediaPlayerImpl::VisibleRect() const {
1016 DCHECK(main_task_runner_->BelongsToCurrentThread());
1017 scoped_refptr<VideoFrame> video_frame = GetCurrentFrameFromCompositor();
1018 if (!video_frame)
1019 return blink::WebSize();
1020
1021 const gfx::Rect& visible_rect = video_frame->visible_rect();
1022 return blink::WebSize(visible_rect.width(), visible_rect.height());
1023}
1024
Blink Reformat1c4d759e2017-04-09 16:34:541025bool WebMediaPlayerImpl::Paused() const {
acolwellb4034942014-08-28 15:42:431026 DCHECK(main_task_runner_->BelongsToCurrentThread());
Antonio Gomes81b56552019-05-15 22:15:281027 return pipeline_controller_->GetPlaybackRate() == 0.0f;
[email protected]d43ed912009-02-03 04:52:531028}
1029
François Beaufort184f6042019-01-25 05:50:051030bool WebMediaPlayerImpl::PausedWhenHidden() const {
1031 return paused_when_hidden_;
1032}
1033
Blink Reformat1c4d759e2017-04-09 16:34:541034bool WebMediaPlayerImpl::Seeking() const {
acolwellb4034942014-08-28 15:42:431035 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:531036
Blink Reformat1c4d759e2017-04-09 16:34:541037 if (ready_state_ == WebMediaPlayer::kReadyStateHaveNothing)
[email protected]0acebfa2009-08-21 22:45:401038 return false;
[email protected]67cd5052009-09-10 21:53:221039
[email protected]b3766a22010-12-22 17:34:131040 return seeking_;
[email protected]ec9212f2008-12-18 21:40:361041}
1042
Blink Reformat1c4d759e2017-04-09 16:34:541043double WebMediaPlayerImpl::Duration() const {
acolwellb4034942014-08-28 15:42:431044 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]39bdde32013-04-17 17:44:201045
Blink Reformat1c4d759e2017-04-09 16:34:541046 if (ready_state_ == WebMediaPlayer::kReadyStateHaveNothing)
[email protected]39bdde32013-04-17 17:44:201047 return std::numeric_limits<double>::quiet_NaN();
1048
chcunninghamb92d5062017-01-10 21:50:221049 // Use duration from ChunkDemuxer when present. MSE allows users to specify
1050 // duration as a double. This propagates to the rest of the pipeline as a
1051 // TimeDelta with potentially reduced precision (limited to Microseconds).
1052 // ChunkDemuxer returns the full-precision user-specified double. This ensures
1053 // users can "get" the exact duration they "set".
1054 if (chunk_demuxer_)
1055 return chunk_demuxer_->GetDuration();
1056
avayvodcc273dd2017-01-19 19:35:121057 base::TimeDelta pipeline_duration = GetPipelineMediaDuration();
chcunninghamb92d5062017-01-10 21:50:221058 return pipeline_duration == kInfiniteDuration
1059 ? std::numeric_limits<double>::infinity()
1060 : pipeline_duration.InSecondsF();
[email protected]d43ed912009-02-03 04:52:531061}
1062
[email protected]db66d0092014-04-16 07:15:121063double WebMediaPlayerImpl::timelineOffset() const {
acolwellb4034942014-08-28 15:42:431064 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]db66d0092014-04-16 07:15:121065
1066 if (pipeline_metadata_.timeline_offset.is_null())
1067 return std::numeric_limits<double>::quiet_NaN();
1068
1069 return pipeline_metadata_.timeline_offset.ToJsTime();
1070}
1071
Dale Curtis051fdf62017-08-05 00:21:131072base::TimeDelta WebMediaPlayerImpl::GetCurrentTimeInternal() const {
1073 DCHECK(main_task_runner_->BelongsToCurrentThread());
Dale Curtis051fdf62017-08-05 00:21:131074
1075 base::TimeDelta current_time;
1076 if (Seeking())
1077 current_time = seek_time_;
Dale Curtis051fdf62017-08-05 00:21:131078 else if (paused_)
1079 current_time = paused_time_;
1080 else
Antonio Gomes81b56552019-05-15 22:15:281081 current_time = pipeline_controller_->GetMediaTime();
Dale Curtis051fdf62017-08-05 00:21:131082
Dale Curtis77d6057b2019-05-03 01:31:561083 // It's possible for |current_time| to be kInfiniteDuration here if the page
1084 // seeks to kInfiniteDuration (2**64 - 1) when Duration() is infinite.
Dale Curtis051fdf62017-08-05 00:21:131085 DCHECK_GE(current_time, base::TimeDelta());
1086 return current_time;
1087}
1088
Blink Reformat1c4d759e2017-04-09 16:34:541089double WebMediaPlayerImpl::CurrentTime() const {
acolwellb4034942014-08-28 15:42:431090 DCHECK(main_task_runner_->BelongsToCurrentThread());
Blink Reformat1c4d759e2017-04-09 16:34:541091 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
scherkusd2c745b2014-09-04 05:03:401092
Dale Curtis0da6f162020-02-01 01:02:591093 // Even though we have an explicit ended signal, a lot of content doesn't have
1094 // an accurate duration -- with some formats (e.g., VBR MP3, OGG) it can't be
1095 // known without a complete play-through from beginning to end.
1096 //
1097 // The HTML5 spec says that upon ended, current time must equal duration. Due
1098 // to the aforementioned issue, if we rely exclusively on current time, we can
1099 // be a few milliseconds off of the duration.
1100 const auto duration = Duration();
1101 return (ended_ && !std::isinf(duration))
1102 ? duration
Xida Chenccd11472020-01-31 20:02:021103 : GetCurrentTimeInternal().InSecondsF();
[email protected]d43ed912009-02-03 04:52:531104}
1105
Dale Curtis0da6f162020-02-01 01:02:591106bool WebMediaPlayerImpl::IsEnded() const {
1107 DCHECK(main_task_runner_->BelongsToCurrentThread());
1108 return ended_;
1109}
1110
Blink Reformat1c4d759e2017-04-09 16:34:541111WebMediaPlayer::NetworkState WebMediaPlayerImpl::GetNetworkState() const {
acolwellb4034942014-08-28 15:42:431112 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]ddb1e5a2010-12-13 20:10:451113 return network_state_;
1114}
1115
Blink Reformat1c4d759e2017-04-09 16:34:541116WebMediaPlayer::ReadyState WebMediaPlayerImpl::GetReadyState() const {
acolwellb4034942014-08-28 15:42:431117 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]ddb1e5a2010-12-13 20:10:451118 return ready_state_;
1119}
1120
CJ DiMeglio89240472018-10-18 18:21:101121blink::WebMediaPlayer::SurfaceLayerMode
1122WebMediaPlayerImpl::GetVideoSurfaceLayerMode() const {
1123 return surface_layer_mode_;
1124}
1125
wolenetzed8e7092017-04-21 16:28:591126blink::WebString WebMediaPlayerImpl::GetErrorMessage() const {
wolenetz4d39cc02016-04-05 19:54:411127 DCHECK(main_task_runner_->BelongsToCurrentThread());
wolenetzed8e7092017-04-21 16:28:591128 return blink::WebString::FromUTF8(media_log_->GetErrorMessage());
wolenetz4d39cc02016-04-05 19:54:411129}
1130
Blink Reformat1c4d759e2017-04-09 16:34:541131blink::WebTimeRanges WebMediaPlayerImpl::Buffered() const {
acolwellb4034942014-08-28 15:42:431132 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]779a8322014-08-22 21:28:371133
acolwell9e0840d2014-09-06 19:01:321134 Ranges<base::TimeDelta> buffered_time_ranges =
Antonio Gomes81b56552019-05-15 22:15:281135 pipeline_controller_->GetBufferedTimeRanges();
[email protected]779a8322014-08-22 21:28:371136
avayvodcc273dd2017-01-19 19:35:121137 const base::TimeDelta duration = GetPipelineMediaDuration();
dalecurtis39a7f932016-07-19 18:34:591138 if (duration != kInfiniteDuration) {
Antonio Gomes81b56552019-05-15 22:15:281139 buffered_data_source_host_->AddBufferedTimeRanges(&buffered_time_ranges,
1140 duration);
[email protected]779a8322014-08-22 21:28:371141 }
Antonio Gomesf01cfbd2019-07-12 08:53:111142 return blink::ConvertToWebTimeRanges(buffered_time_ranges);
[email protected]02022fc2014-05-16 00:05:311143}
1144
Blink Reformat1c4d759e2017-04-09 16:34:541145blink::WebTimeRanges WebMediaPlayerImpl::Seekable() const {
acolwellb4034942014-08-28 15:42:431146 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]39bdde32013-04-17 17:44:201147
Blink Reformat1c4d759e2017-04-09 16:34:541148 if (ready_state_ < WebMediaPlayer::kReadyStateHaveMetadata)
philipjb0e6f3f2014-09-30 09:51:531149 return blink::WebTimeRanges();
1150
Blink Reformat1c4d759e2017-04-09 16:34:541151 const double seekable_end = Duration();
dalecurtis56359cb2014-10-28 00:06:291152
1153 // Allow a special exception for seeks to zero for streaming sources with a
1154 // finite duration; this allows looping to work.
Dale Curtis4841c712018-12-13 18:14:051155 const bool is_finite_stream = mb_data_source_ &&
1156 mb_data_source_->IsStreaming() &&
tguilbertade2bcb2017-01-07 02:57:451157 std::isfinite(seekable_end);
1158
tguilbert75e2bf62017-04-26 20:13:121159 // Do not change the seekable range when using the MediaPlayerRenderer. It
1160 // will take care of dropping invalid seeks.
1161 const bool force_seeks_to_zero =
1162 !using_media_player_renderer_ && is_finite_stream;
dalecurtis56359cb2014-10-28 00:06:291163
1164 // TODO(dalecurtis): Technically this allows seeking on media which return an
tguilbertade2bcb2017-01-07 02:57:451165 // infinite duration so long as DataSource::IsStreaming() is false. While not
dalecurtis56359cb2014-10-28 00:06:291166 // expected, disabling this breaks semi-live players, http://crbug.com/427412.
1167 const blink::WebTimeRange seekable_range(
tguilbertade2bcb2017-01-07 02:57:451168 0.0, force_seeks_to_zero ? 0.0 : seekable_end);
philipjb0e6f3f2014-09-30 09:51:531169 return blink::WebTimeRanges(&seekable_range, 1);
[email protected]ec9212f2008-12-18 21:40:361170}
1171
sandersd35d2c3f2017-01-14 02:04:421172bool WebMediaPlayerImpl::IsPrerollAttemptNeeded() {
1173 // TODO(sandersd): Replace with |highest_ready_state_since_seek_| if we need
1174 // to ensure that preroll always gets a chance to complete.
1175 // See http://crbug.com/671525.
Dale Curtis69e8f302019-05-22 07:36:581176 //
1177 // Note: Even though we get play/pause signals at kReadyStateHaveMetadata, we
1178 // must attempt to preroll until kReadyStateHaveFutureData so that the
1179 // canplaythrough event will be fired to the page (which may be waiting).
1180 //
1181 // TODO(dalecurtis): We should try signaling kReadyStateHaveFutureData upon
1182 // automatic-suspend of a non-playing element to avoid wasting resources.
1183 if (highest_ready_state_ >= ReadyState::kReadyStateHaveFutureData)
sandersd35d2c3f2017-01-14 02:04:421184 return false;
1185
Fredrik Hubinette4cfb4412017-08-23 00:03:071186 // To suspend before we reach kReadyStateHaveCurrentData is only ok
1187 // if we know we're going to get woken up when we get more data, which
1188 // will only happen if the network is in the "Loading" state.
1189 // This happens when the network is fast, but multiple videos are loading
1190 // and multiplexing gets held up waiting for available threads.
1191 if (highest_ready_state_ <= ReadyState::kReadyStateHaveMetadata &&
1192 network_state_ != WebMediaPlayer::kNetworkStateLoading) {
1193 return true;
1194 }
1195
sandersd35d2c3f2017-01-14 02:04:421196 if (preroll_attempt_pending_)
1197 return true;
1198
1199 // Freshly initialized; there has never been any loading progress. (Otherwise
1200 // |preroll_attempt_pending_| would be true when the start time is null.)
1201 if (preroll_attempt_start_time_.is_null())
1202 return false;
1203
1204 base::TimeDelta preroll_attempt_duration =
1205 tick_clock_->NowTicks() - preroll_attempt_start_time_;
1206 return preroll_attempt_duration < kPrerollAttemptTimeout;
1207}
1208
Blink Reformat1c4d759e2017-04-09 16:34:541209bool WebMediaPlayerImpl::DidLoadingProgress() {
acolwellb4034942014-08-28 15:42:431210 DCHECK(main_task_runner_->BelongsToCurrentThread());
dalecurtise7120dc2016-09-03 02:54:351211
1212 // Note: Separate variables used to ensure both methods are called every time.
Antonio Gomes81b56552019-05-15 22:15:281213 const bool pipeline_progress = pipeline_controller_->DidLoadingProgress();
1214 const bool data_progress = buffered_data_source_host_->DidLoadingProgress();
hubbeb2d3efd2017-05-05 23:26:381215 return pipeline_progress || data_progress;
[email protected]d43ed912009-02-03 04:52:531216}
1217
danakjff6a0262018-06-26 19:50:311218void WebMediaPlayerImpl::Paint(cc::PaintCanvas* canvas,
[email protected]dd5c7972014-08-21 15:00:371219 const blink::WebRect& rect,
Kai Ninomiya9e8ae29b2017-09-06 23:45:161220 cc::PaintFlags& flags,
1221 int already_uploaded_id,
1222 VideoFrameUploadMetadata* out_metadata) {
acolwellb4034942014-08-28 15:42:431223 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]dd061e12014-05-06 19:21:221224 TRACE_EVENT0("media", "WebMediaPlayerImpl:paint");
[email protected]4e6be3f2009-05-07 02:24:441225
watkd16bb3e2017-04-25 01:18:311226 // We can't copy from protected frames.
Xiaohan Wang24cfe2c2018-01-22 23:16:001227 if (cdm_context_ref_)
xhwang80739452016-01-13 00:48:001228 return;
1229
mcasasf1236fc22015-05-29 22:38:561230 scoped_refptr<VideoFrame> video_frame = GetCurrentFrameFromCompositor();
[email protected]0fe5d43b2014-01-24 23:32:451231
[email protected]b49beeb2013-03-01 20:04:001232 gfx::Rect gfx_rect(rect);
mcasas265bdbf82015-06-12 18:44:071233 if (video_frame.get() && video_frame->HasTextures()) {
Antoine Labourfee4ae52019-04-24 23:53:571234 if (!context_provider_)
danakj53f7ec902016-05-21 01:30:101235 return; // Unable to get/create a shared main thread context.
Antoine Labourfee4ae52019-04-24 23:53:571236 if (!context_provider_->GrContext())
danakj53f7ec902016-05-21 01:30:101237 return; // The context has been lost since and can't setup a GrContext.
dongseong.hwang0c4e9d82015-01-08 20:11:131238 }
Kai Ninomiyaef8c9e02017-09-27 04:07:401239 if (out_metadata && video_frame) {
Kai Ninomiya9e8ae29b2017-09-06 23:45:161240 // WebGL last-uploaded-frame-metadata API enabled. https://crbug.com/639174
1241 ComputeFrameUploadMetadata(video_frame.get(), already_uploaded_id,
1242 out_metadata);
1243 if (out_metadata->skipped) {
1244 // Skip uploading this frame.
1245 return;
1246 }
1247 }
zhuoyu.qian4689dde22017-10-16 04:11:481248 video_renderer_.Paint(
Julien Isorce6c83d8de2017-10-12 13:11:291249 video_frame, canvas, gfx::RectF(gfx_rect), flags,
Ted Meyer4a427632019-05-01 19:05:271250 pipeline_metadata_.video_decoder_config.video_transformation(),
Antoine Labourfee4ae52019-04-24 23:53:571251 context_provider_.get());
[email protected]ec9212f2008-12-18 21:40:361252}
[email protected]5df51652009-01-17 00:03:001253
Yutaka Hirano657a0552018-11-09 00:52:551254bool WebMediaPlayerImpl::WouldTaintOrigin() const {
Thomas Guilbert153f84572018-07-19 05:03:581255 if (demuxer_found_hls_) {
1256 // HLS manifests might pull segments from a different origin. We can't know
1257 // for sure, so we conservatively say no here.
Yutaka Hiranoa9cbaa72018-10-10 08:35:221258 return true;
1259 }
1260
Dale Curtis4841c712018-12-13 18:14:051261 if (!mb_data_source_)
Yutaka Hirano657a0552018-11-09 00:52:551262 return false;
1263
1264 // When the resource is redirected to another origin we think it as
1265 // tainted. This is actually not specified, and is under discussion.
1266 // See https://github.com/whatwg/fetch/issues/737.
Dale Curtis4841c712018-12-13 18:14:051267 if (!mb_data_source_->HasSingleOrigin() &&
1268 mb_data_source_->cors_mode() == UrlData::CORS_UNSPECIFIED) {
Yutaka Hirano657a0552018-11-09 00:52:551269 return true;
1270 }
1271
Dale Curtis4841c712018-12-13 18:14:051272 return mb_data_source_->IsCorsCrossOrigin();
[email protected]3fe27112012-06-07 04:00:011273}
1274
Blink Reformat1c4d759e2017-04-09 16:34:541275double WebMediaPlayerImpl::MediaTimeForTimeValue(double timeValue) const {
qinminb4c39782015-08-10 18:43:241276 return base::TimeDelta::FromSecondsD(timeValue).InSecondsF();
[email protected]e06e16d82011-05-26 22:13:331277}
1278
Blink Reformat1c4d759e2017-04-09 16:34:541279unsigned WebMediaPlayerImpl::DecodedFrameCount() const {
acolwellb4034942014-08-28 15:42:431280 DCHECK(main_task_runner_->BelongsToCurrentThread());
Dale Curtisc7d2a7d22018-01-11 20:01:051281 return GetPipelineStatistics().video_frames_decoded;
[email protected]4c51bc662011-02-16 02:03:161282}
1283
Blink Reformat1c4d759e2017-04-09 16:34:541284unsigned WebMediaPlayerImpl::DroppedFrameCount() const {
acolwellb4034942014-08-28 15:42:431285 DCHECK(main_task_runner_->BelongsToCurrentThread());
Dale Curtisc7d2a7d22018-01-11 20:01:051286 return GetPipelineStatistics().video_frames_dropped;
[email protected]4c51bc662011-02-16 02:03:161287}
1288
Dave Tapuska6c7154912018-07-30 20:39:001289uint64_t WebMediaPlayerImpl::AudioDecodedByteCount() const {
acolwellb4034942014-08-28 15:42:431290 DCHECK(main_task_runner_->BelongsToCurrentThread());
Dale Curtisc7d2a7d22018-01-11 20:01:051291 return GetPipelineStatistics().audio_bytes_decoded;
[email protected]4c51bc662011-02-16 02:03:161292}
1293
Dave Tapuska6c7154912018-07-30 20:39:001294uint64_t WebMediaPlayerImpl::VideoDecodedByteCount() const {
acolwellb4034942014-08-28 15:42:431295 DCHECK(main_task_runner_->BelongsToCurrentThread());
Dale Curtisc7d2a7d22018-01-11 20:01:051296 return GetPipelineStatistics().video_bytes_decoded;
[email protected]4c51bc662011-02-16 02:03:161297}
1298
Dale Curtiscdfc6f22019-06-26 22:05:231299bool WebMediaPlayerImpl::HasAvailableVideoFrame() const {
1300 return has_first_frame_;
1301}
1302
Blink Reformat1c4d759e2017-04-09 16:34:541303bool WebMediaPlayerImpl::CopyVideoTextureToPlatformTexture(
danakj46070b02016-03-28 21:54:111304 gpu::gles2::GLES2Interface* gl,
jiajia.qinc2943162017-05-12 01:34:391305 unsigned int target,
zmo57d577a2015-10-30 18:28:591306 unsigned int texture,
kbr0986e622017-04-13 02:34:581307 unsigned internal_format,
1308 unsigned format,
1309 unsigned type,
jiajia.qinc2943162017-05-12 01:34:391310 int level,
zmo57d577a2015-10-30 18:28:591311 bool premultiply_alpha,
Kai Ninomiya9e8ae29b2017-09-06 23:45:161312 bool flip_y,
1313 int already_uploaded_id,
1314 VideoFrameUploadMetadata* out_metadata) {
xhwang213e50c2016-10-10 23:56:311315 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]bfc05f22013-10-19 17:55:161316 TRACE_EVENT0("media", "WebMediaPlayerImpl:copyVideoTextureToPlatformTexture");
1317
watkd16bb3e2017-04-25 01:18:311318 // We can't copy from protected frames.
Xiaohan Wang24cfe2c2018-01-22 23:16:001319 if (cdm_context_ref_)
xhwang213e50c2016-10-10 23:56:311320 return false;
[email protected]dd061e12014-05-06 19:21:221321
xhwang213e50c2016-10-10 23:56:311322 scoped_refptr<VideoFrame> video_frame = GetCurrentFrameFromCompositor();
jbauman581d041c2016-07-21 01:01:031323 if (!video_frame.get() || !video_frame->HasTextures()) {
[email protected]e56f88c72013-06-25 22:31:291324 return false;
dongseong.hwang0c4e9d82015-01-08 20:11:131325 }
Kai Ninomiya9e8ae29b2017-09-06 23:45:161326 if (out_metadata) {
1327 // WebGL last-uploaded-frame-metadata API is enabled.
1328 // https://crbug.com/639174
1329 ComputeFrameUploadMetadata(video_frame.get(), already_uploaded_id,
1330 out_metadata);
1331 if (out_metadata->skipped) {
1332 // Skip uploading this frame.
1333 return true;
1334 }
1335 }
[email protected]df41e252014-02-03 23:39:501336
zhuoyu.qian4689dde22017-10-16 04:11:481337 return video_renderer_.CopyVideoFrameTexturesToGLTexture(
Antoine Labourfee4ae52019-04-24 23:53:571338 context_provider_.get(), gl, video_frame.get(), target, texture,
Dan Sanders930cc1d2018-10-03 00:45:081339 internal_format, format, type, level, premultiply_alpha, flip_y);
[email protected]6523b242013-03-13 11:10:071340}
1341
Yan, Shaobo44b79ba2019-04-02 06:09:271342bool WebMediaPlayerImpl::PrepareVideoFrameForWebGL(
1343 gpu::gles2::GLES2Interface* gl,
1344 unsigned target,
1345 unsigned texture,
1346 int already_uploaded_id,
1347 WebMediaPlayer::VideoFrameUploadMetadata* out_metadata) {
1348 DCHECK(main_task_runner_->BelongsToCurrentThread());
1349 TRACE_EVENT0("media", "WebMediaPlayerImpl::PrepareVideoFrameForWebGL");
1350
1351 // TODO(crbug.com/776222): How to deal with protected frames.
1352 scoped_refptr<VideoFrame> video_frame = GetCurrentFrameFromCompositor();
1353 if (!video_frame.get() || !video_frame->HasTextures()) {
1354 return false;
1355 }
1356 if (out_metadata) {
1357 // WebGL last-uploaded-frame-metadata API is enabled.
1358 ComputeFrameUploadMetadata(video_frame.get(), already_uploaded_id,
1359 out_metadata);
1360 if (out_metadata->skipped) {
1361 // Skip uploading this frame.
1362 return true;
1363 }
1364 }
1365
Yan, Shaobo44b79ba2019-04-02 06:09:271366 return video_renderer_.PrepareVideoFrameForWebGL(
Antoine Labourfee4ae52019-04-24 23:53:571367 context_provider_.get(), gl, video_frame.get(), target, texture);
Yan, Shaobo44b79ba2019-04-02 06:09:271368}
1369
Matt Wolenetz95af6362018-01-04 20:23:421370// static
Kai Ninomiya9e8ae29b2017-09-06 23:45:161371void WebMediaPlayerImpl::ComputeFrameUploadMetadata(
1372 VideoFrame* frame,
1373 int already_uploaded_id,
1374 VideoFrameUploadMetadata* out_metadata) {
1375 DCHECK(out_metadata);
Kai Ninomiyaef8c9e02017-09-27 04:07:401376 DCHECK(frame);
Kai Ninomiya9e8ae29b2017-09-06 23:45:161377 out_metadata->frame_id = frame->unique_id();
1378 out_metadata->visible_rect = frame->visible_rect();
1379 out_metadata->timestamp = frame->timestamp();
Li, Hao0fab96a2019-10-31 02:46:471380 base::TimeDelta frame_duration;
1381 if (frame->metadata()->GetTimeDelta(media::VideoFrameMetadata::FRAME_DURATION,
1382 &frame_duration)) {
1383 out_metadata->expected_timestamp = frame->timestamp() + frame_duration;
1384 };
Kai Ninomiya9e8ae29b2017-09-06 23:45:161385 bool skip_possible = already_uploaded_id != -1;
1386 bool same_frame_id = frame->unique_id() == already_uploaded_id;
1387 out_metadata->skipped = skip_possible && same_frame_id;
1388}
1389
Blink Reformat1c4d759e2017-04-09 16:34:541390void WebMediaPlayerImpl::SetContentDecryptionModule(
[email protected]9ebc3b03f2014-08-13 04:01:231391 blink::WebContentDecryptionModule* cdm,
1392 blink::WebContentDecryptionModuleResult result) {
xhwang51139732017-02-24 19:36:081393 DVLOG(1) << __func__ << ": cdm = " << cdm;
acolwellb4034942014-08-28 15:42:431394 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]9ebc3b03f2014-08-13 04:01:231395
jrummell06f27072015-06-08 18:12:381396 // Once the CDM is set it can't be cleared as there may be frames being
1397 // decrypted on other threads. So fail this request.
1398 // http://crbug.com/462365#c7.
xhwang97de4202014-11-25 08:44:011399 if (!cdm) {
Blink Reformat1c4d759e2017-04-09 16:34:541400 result.CompleteWithError(
1401 blink::kWebContentDecryptionModuleExceptionInvalidStateError, 0,
xhwang79b193042016-12-13 18:52:431402 "The existing ContentDecryptionModule object cannot be removed at this "
1403 "time.");
xhwang97de4202014-11-25 08:44:011404 return;
1405 }
1406
jrummell89e61d82015-07-23 20:03:341407 // Create a local copy of |result| to avoid problems with the callback
1408 // getting passed to the media thread and causing |result| to be destructed
jrummell4acbec912016-02-27 02:45:031409 // on the wrong thread in some failure conditions. Blink should prevent
1410 // multiple simultaneous calls.
1411 DCHECK(!set_cdm_result_);
jrummell89e61d82015-07-23 20:03:341412 set_cdm_result_.reset(new blink::WebContentDecryptionModuleResult(result));
1413
Chris Cunninghamd4a00192019-03-21 20:02:491414 SetCdmInternal(cdm);
xhwang97de4202014-11-25 08:44:011415}
1416
xhwange8c4181a2014-12-06 08:10:011417void WebMediaPlayerImpl::OnEncryptedMediaInitData(
jrummellcf78967c2015-04-03 05:03:581418 EmeInitDataType init_data_type,
Avi Drissman97785ea2015-12-19 01:11:311419 const std::vector<uint8_t>& init_data) {
jrummellcf78967c2015-04-03 05:03:581420 DCHECK(init_data_type != EmeInitDataType::UNKNOWN);
xhwangbab66f52014-12-02 23:49:501421
Xiaohan Wangf63505d2017-10-21 08:00:531422 RecordEncryptedEvent(true);
xhwangbab66f52014-12-02 23:49:501423
dalecurtis04bdb582016-08-17 22:15:231424 // Recreate the watch time reporter if necessary.
1425 const bool was_encrypted = is_encrypted_;
1426 is_encrypted_ = true;
Dale Curtis3899090ea2018-01-12 00:10:351427 if (!was_encrypted) {
1428 media_metrics_provider_->SetIsEME();
1429 if (watch_time_reporter_)
1430 CreateWatchTimeReporter();
dalecurtis04bdb582016-08-17 22:15:231431
Chris Cunningham6c0ec292019-04-04 18:31:111432 // |was_encrypted| = false means we didn't have a CDM prior to observing
1433 // encrypted media init data. Reset the reporter until the CDM arrives. See
1434 // SetCdmInternal().
1435 DCHECK(!cdm_config_);
1436 video_decode_stats_reporter_.reset();
1437 }
Chris Cunninghamd9df58e2017-08-29 00:04:231438
Blink Reformat1c4d759e2017-04-09 16:34:541439 encrypted_client_->Encrypted(
Antonio Gomes89b70572019-07-13 00:44:211440 init_data_type, init_data.data(),
srirama.m26f864d02015-07-14 05:21:461441 base::saturated_cast<unsigned int>(init_data.size()));
xhwangbab66f52014-12-02 23:49:501442}
1443
servolk81e01e02016-03-05 03:29:151444void WebMediaPlayerImpl::OnFFmpegMediaTracksUpdated(
dcheng3076abbf2016-04-22 20:42:391445 std::unique_ptr<MediaTracks> tracks) {
servolk81e01e02016-03-05 03:29:151446 // For MSE/chunk_demuxer case the media track updates are handled by
1447 // WebSourceBufferImpl.
1448 DCHECK(demuxer_.get());
1449 DCHECK(!chunk_demuxer_);
servolkef1e5ef2016-03-25 04:55:261450
servolk16e8bdf82017-04-11 17:00:391451 // Report the media track information to blink. Only the first audio track and
1452 // the first video track are enabled by default to match blink logic.
1453 bool is_first_audio_track = true;
1454 bool is_first_video_track = true;
servolkef1e5ef2016-03-25 04:55:261455 for (const auto& track : tracks->tracks()) {
1456 if (track->type() == MediaTrack::Audio) {
Maciej Pawlowskif2556d122019-06-03 08:14:181457 client_->AddAudioTrack(
1458 blink::WebString::FromUTF8(track->id().value()),
1459 blink::WebMediaPlayerClient::kAudioTrackKindMain,
1460 blink::WebString::FromUTF8(track->label().value()),
1461 blink::WebString::FromUTF8(track->language().value()),
1462 is_first_audio_track);
servolk16e8bdf82017-04-11 17:00:391463 is_first_audio_track = false;
servolkef1e5ef2016-03-25 04:55:261464 } else if (track->type() == MediaTrack::Video) {
Maciej Pawlowskif2556d122019-06-03 08:14:181465 client_->AddVideoTrack(
1466 blink::WebString::FromUTF8(track->id().value()),
1467 blink::WebMediaPlayerClient::kVideoTrackKindMain,
1468 blink::WebString::FromUTF8(track->label().value()),
1469 blink::WebString::FromUTF8(track->language().value()),
1470 is_first_video_track);
servolk16e8bdf82017-04-11 17:00:391471 is_first_video_track = false;
servolkef1e5ef2016-03-25 04:55:261472 } else {
1473 // Text tracks are not supported through this code path yet.
1474 NOTREACHED();
1475 }
1476 }
servolk81e01e02016-03-05 03:29:151477}
1478
Chris Cunninghamd4a00192019-03-21 20:02:491479void WebMediaPlayerImpl::SetCdmInternal(
1480 blink::WebContentDecryptionModule* cdm) {
jrummelle616ee92016-10-08 02:15:441481 DCHECK(main_task_runner_->BelongsToCurrentThread());
1482 DCHECK(cdm);
Xiaohan Wang24cfe2c2018-01-22 23:16:001483
Chris Cunninghamd4a00192019-03-21 20:02:491484 const bool was_encrypted = is_encrypted_;
1485 is_encrypted_ = true;
1486
1487 // Recreate the watch time reporter if necessary.
1488 if (!was_encrypted) {
1489 media_metrics_provider_->SetIsEME();
1490 if (watch_time_reporter_)
1491 CreateWatchTimeReporter();
1492 }
1493
Chris Cunningham6c0ec292019-04-04 18:31:111494 WebContentDecryptionModuleImpl* web_cdm =
1495 ToWebContentDecryptionModuleImpl(cdm);
1496 auto cdm_context_ref = web_cdm->GetCdmContextRef();
Xiaohan Wang24cfe2c2018-01-22 23:16:001497 if (!cdm_context_ref) {
jrummelle616ee92016-10-08 02:15:441498 NOTREACHED();
1499 OnCdmAttached(false);
xhwang80739452016-01-13 00:48:001500 return;
1501 }
1502
Chris Cunningham6c0ec292019-04-04 18:31:111503 // Arrival of |cdm_config_| and |key_system_| unblocks recording of encrypted
1504 // stats. Attempt to create the stats reporter. Note, we do NOT guard this
1505 // within !was_encypted above because often the CDM arrives after the call to
1506 // OnEncryptedMediaInitData().
1507 cdm_config_ = web_cdm->GetCdmConfig();
1508 key_system_ = web_cdm->GetKeySystem();
1509 DCHECK(!key_system_.empty());
1510 CreateVideoDecodeStatsReporter();
1511
Xiaohan Wang24cfe2c2018-01-22 23:16:001512 CdmContext* cdm_context = cdm_context_ref->GetCdmContext();
1513 DCHECK(cdm_context);
jrummelle616ee92016-10-08 02:15:441514
1515 // Keep the reference to the CDM, as it shouldn't be destroyed until
1516 // after the pipeline is done with the |cdm_context|.
Xiaohan Wang24cfe2c2018-01-22 23:16:001517 pending_cdm_context_ref_ = std::move(cdm_context_ref);
Antonio Gomes81b56552019-05-15 22:15:281518 pipeline_controller_->SetCdm(
Antonio Gomes142f32a2019-05-15 23:32:561519 cdm_context, base::Bind(&WebMediaPlayerImpl::OnCdmAttached, weak_this_));
xhwang97de4202014-11-25 08:44:011520}
1521
jrummell89e61d82015-07-23 20:03:341522void WebMediaPlayerImpl::OnCdmAttached(bool success) {
xhwang51139732017-02-24 19:36:081523 DVLOG(1) << __func__ << ": success = " << success;
jrummelle616ee92016-10-08 02:15:441524 DCHECK(main_task_runner_->BelongsToCurrentThread());
Xiaohan Wang24cfe2c2018-01-22 23:16:001525 DCHECK(pending_cdm_context_ref_);
jrummelle616ee92016-10-08 02:15:441526
1527 // If the CDM is set from the constructor there is no promise
1528 // (|set_cdm_result_|) to fulfill.
xhwang97de4202014-11-25 08:44:011529 if (success) {
Ted Meyer7f5b4e22019-11-21 03:21:191530 media_log_->SetProperty<MediaLogProperty::kIsVideoEncrypted>(true);
xhwang29c5ad202017-04-14 07:02:191531
jrummelle616ee92016-10-08 02:15:441532 // This will release the previously attached CDM (if any).
Xiaohan Wang24cfe2c2018-01-22 23:16:001533 cdm_context_ref_ = std::move(pending_cdm_context_ref_);
jrummelle616ee92016-10-08 02:15:441534 if (set_cdm_result_) {
Blink Reformat1c4d759e2017-04-09 16:34:541535 set_cdm_result_->Complete();
jrummelle616ee92016-10-08 02:15:441536 set_cdm_result_.reset();
1537 }
1538
xhwang97de4202014-11-25 08:44:011539 return;
1540 }
1541
Xiaohan Wang24cfe2c2018-01-22 23:16:001542 pending_cdm_context_ref_.reset();
jrummelle616ee92016-10-08 02:15:441543 if (set_cdm_result_) {
Blink Reformat1c4d759e2017-04-09 16:34:541544 set_cdm_result_->CompleteWithError(
1545 blink::kWebContentDecryptionModuleExceptionNotSupportedError, 0,
xhwang79b193042016-12-13 18:52:431546 "Unable to set ContentDecryptionModule object");
jrummelle616ee92016-10-08 02:15:441547 set_cdm_result_.reset();
1548 }
[email protected]9ebc3b03f2014-08-13 04:01:231549}
1550
sandersd1c0bba02016-03-04 23:14:081551void WebMediaPlayerImpl::OnPipelineSeeked(bool time_updated) {
John Chen5b164a02017-11-01 00:36:091552 TRACE_EVENT2("media", "WebMediaPlayerImpl::OnPipelineSeeked", "target",
1553 seek_time_.InSecondsF(), "id", media_log_->id());
[email protected]5d11eff2011-09-15 00:06:061554 seeking_ = false;
wolenetz1b2ae7d2015-06-10 00:44:211555 seek_time_ = base::TimeDelta();
avayvod2135a642017-01-13 00:17:141556
hubbe5a2dec022016-03-17 01:14:231557 if (paused_) {
Antonio Gomes81b56552019-05-15 22:15:281558 paused_time_ = pipeline_controller_->GetMediaTime();
dalecurtis04bdb582016-08-17 22:15:231559 } else {
1560 DCHECK(watch_time_reporter_);
1561 watch_time_reporter_->OnPlaying();
hubbe5a2dec022016-03-17 01:14:231562 }
sandersd1c0bba02016-03-04 23:14:081563 if (time_updated)
1564 should_notify_time_changed_ = true;
dalecurtisaf34d8712016-09-20 04:32:261565
dalecurtis4f6d14d2017-02-22 17:42:221566 // Reset underflow duration upon seek; this prevents looping videos and user
1567 // actions from artificially inflating the duration.
1568 underflow_timer_.reset();
avayvod56e1f3942017-01-21 02:06:311569
1570 // Background video optimizations are delayed when shown/hidden if pipeline
1571 // is seeking.
1572 UpdateBackgroundVideoOptimizationState();
Dale Curtis2dc6089a2018-03-26 16:47:581573
Dale Curtisd71061f02019-05-21 21:33:541574 // If we successfully completed a suspended startup, we need to make a call to
1575 // UpdatePlayState() in case any events which should trigger a resume have
1576 // occurred during startup.
Dale Curtis2dc6089a2018-03-26 16:47:581577 if (attempting_suspended_start_ &&
Antonio Gomes81b56552019-05-15 22:15:281578 pipeline_controller_->IsPipelineSuspended()) {
Dale Curtisff576552018-03-30 02:32:441579 skip_metrics_due_to_startup_suspend_ = true;
Dale Curtisd71061f02019-05-21 21:33:541580
1581 // If we successfully completed a suspended startup, signal that we have
1582 // reached BUFFERING_HAVE_ENOUGH so that canplay and canplaythrough fire
1583 // correctly. We must unfortunately always do this because it's valid for
1584 // elements to play while not visible nor even in the DOM.
1585 //
1586 // Note: This call is dual purpose, it is also responsible for triggering an
1587 // UpdatePlayState() call which may need to resume the pipeline once Blink
1588 // has been told about the ReadyState change.
Chris Cunninghamfc0d67e2019-07-22 20:29:161589 OnBufferingStateChangeInternal(BUFFERING_HAVE_ENOUGH,
1590 BUFFERING_CHANGE_REASON_UNKNOWN, true);
Dale Curtisff576552018-03-30 02:32:441591
1592 // If |skip_metrics_due_to_startup_suspend_| is unset by a resume started by
1593 // the OnBufferingStateChangeInternal() call, record a histogram of it here.
1594 //
1595 // If the value is unset, that means we should not have suspended and we've
1596 // likely incurred some cost to TimeToFirstFrame and TimeToPlayReady which
1597 // will be reflected in those statistics.
1598 base::UmaHistogramBoolean(
1599 std::string("Media.PreloadMetadataSuspendWasIdeal.") +
1600 ((HasVideo() && HasAudio()) ? "AudioVideo"
1601 : (HasVideo() ? "Video" : "Audio")),
1602 skip_metrics_due_to_startup_suspend_);
Dale Curtis2dc6089a2018-03-26 16:47:581603 }
1604
1605 attempting_suspended_start_ = false;
Becca Hughes7a85bf22019-07-24 16:16:581606
1607 // The current time has changed so we should update the media position state.
1608 UpdateMediaPositionState();
[email protected]8931c41a2009-07-07 17:31:491609}
1610
sandersd1c0bba02016-03-04 23:14:081611void WebMediaPlayerImpl::OnPipelineSuspended() {
Dale Curtis83321152018-12-01 01:22:061612 // Add a log event so the player shows up as "SUSPENDED" in media-internals.
Ted Meyer0134aed2020-01-23 23:56:401613 media_log_->AddEvent<MediaLogEvent::kSuspended>();
Dale Curtis83321152018-12-01 01:22:061614
Dale Curtis04769ca2019-05-25 00:38:101615 if (attempting_suspended_start_) {
1616 DCHECK(pipeline_controller_->IsSuspended());
1617 did_lazy_load_ = !has_poster_ && HasVideo();
1618 }
1619
sandersd2f5bb6152017-03-29 22:57:531620 // Tell the data source we have enough data so that it may release the
Dale Curtis04769ca2019-05-25 00:38:101621 // connection (unless blink is waiting on us to signal play()).
1622 if (mb_data_source_ && !client_->CouldPlayIfEnoughData()) {
1623 // |attempting_suspended_start_| will be cleared by OnPipelineSeeked() which
1624 // will occur after this method during a suspended startup.
1625 if (attempting_suspended_start_ && did_lazy_load_) {
1626 DCHECK(!has_first_frame_);
1627 DCHECK(have_enough_after_lazy_load_cb_.IsCancelled());
1628
1629 // For lazy load, we won't know if the element is non-visible until a
1630 // layout completes, so to avoid unnecessarily tearing down the network
1631 // connection, briefly (250ms chosen arbitrarily) delay signaling "have
1632 // enough" to the MultiBufferDataSource.
1633 //
1634 // base::Unretained() is safe here since the base::CancelableOnceClosure
1635 // will cancel upon destruction of this class and |mb_data_source_| is
1636 // gauranteeed to outlive us.
1637 have_enough_after_lazy_load_cb_.Reset(
1638 base::BindOnce(&MultibufferDataSource::OnBufferingHaveEnough,
1639 base::Unretained(mb_data_source_), true));
1640 main_task_runner_->PostDelayedTask(
1641 FROM_HERE, have_enough_after_lazy_load_cb_.callback(),
1642 base::TimeDelta::FromMilliseconds(250));
1643 } else {
1644 have_enough_after_lazy_load_cb_.Cancel();
1645 mb_data_source_->OnBufferingHaveEnough(true);
1646 }
1647 }
dalecurtis37fe5862016-03-15 19:29:091648
sandersd50a635e2016-04-04 22:50:091649 ReportMemoryUsage();
1650
sandersd1c0bba02016-03-04 23:14:081651 if (pending_suspend_resume_cycle_) {
watkdee516f2016-02-18 02:22:191652 pending_suspend_resume_cycle_ = false;
sandersd50a635e2016-04-04 22:50:091653 UpdatePlayState();
dalecurtis0431cbf2016-03-12 01:19:431654 }
sandersd1c0bba02016-03-04 23:14:081655}
1656
avayvod2135a642017-01-13 00:17:141657void WebMediaPlayerImpl::OnBeforePipelineResume() {
Dale Curtis04769ca2019-05-25 00:38:101658 // Since we're resuming, cancel closing of the network connection.
1659 have_enough_after_lazy_load_cb_.Cancel();
1660
Dale Curtisff576552018-03-30 02:32:441661 // We went through suspended startup, so the player is only just now spooling
1662 // up for playback. As such adjust |load_start_time_| so it reports the same
1663 // metric as what would be reported if we had not suspended at startup.
1664 if (skip_metrics_due_to_startup_suspend_) {
1665 // In the event that the call to SetReadyState() initiated after pipeline
1666 // startup immediately tries to start playback, we should not update
1667 // |load_start_time_| to avoid losing visibility into the impact of a
1668 // suspended startup on the time until first frame / play ready for cases
1669 // where suspended startup was applied incorrectly.
1670 if (!attempting_suspended_start_)
1671 load_start_time_ = base::TimeTicks::Now() - time_to_metadata_;
1672 skip_metrics_due_to_startup_suspend_ = false;
1673 }
1674
avayvod2135a642017-01-13 00:17:141675 // Enable video track if we disabled it in the background - this way the new
1676 // renderer will attach its callbacks to the video stream properly.
1677 // TODO(avayvod): Remove this when disabling and enabling video tracks in
1678 // non-playing state works correctly. See https://crbug.com/678374.
1679 EnableVideoTrackIfNeeded();
1680 is_pipeline_resuming_ = true;
1681}
1682
1683void WebMediaPlayerImpl::OnPipelineResumed() {
1684 is_pipeline_resuming_ = false;
1685
avayvod56e1f3942017-01-21 02:06:311686 UpdateBackgroundVideoOptimizationState();
avayvod2135a642017-01-13 00:17:141687}
1688
alokp967c902452016-05-06 05:21:371689void WebMediaPlayerImpl::OnDemuxerOpened() {
1690 DCHECK(main_task_runner_->BelongsToCurrentThread());
dalecurtis9cddc0b2017-04-19 21:23:381691 client_->MediaSourceOpened(new WebMediaSourceImpl(chunk_demuxer_));
alokp967c902452016-05-06 05:21:371692}
1693
servolkf94b4602017-01-31 16:44:271694void WebMediaPlayerImpl::OnMemoryPressure(
1695 base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
1696 DVLOG(2) << __func__ << " memory_pressure_level=" << memory_pressure_level;
1697 DCHECK(main_task_runner_->BelongsToCurrentThread());
1698 DCHECK(base::FeatureList::IsEnabled(kMemoryPressureBasedSourceBufferGC));
1699 DCHECK(chunk_demuxer_);
1700
Sebastien Marchand6f03d35f2020-01-28 15:12:451701 if (memory_pressure_level ==
1702 base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE) {
1703 return;
1704 }
1705
servolkf94b4602017-01-31 16:44:271706 // The new value of |memory_pressure_level| will take effect on the next
1707 // garbage collection. Typically this means the next SourceBuffer append()
1708 // operation, since per MSE spec, the garbage collection must only occur
1709 // during SourceBuffer append(). But if memory pressure is critical it might
1710 // be better to perform GC immediately rather than wait for the next append
1711 // and potentially get killed due to out-of-memory.
1712 // So if this experiment is enabled and pressure level is critical, we'll pass
1713 // down force_instant_gc==true, which will force immediate GC on
1714 // SourceBufferStreams.
1715 bool force_instant_gc =
1716 (enable_instant_source_buffer_gc_ &&
1717 memory_pressure_level ==
1718 base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
1719
Matt Wolenetz95af6362018-01-04 20:23:421720 // base::Unretained is safe, since |chunk_demuxer_| is actually owned by
1721 // |this| via this->demuxer_. Note the destruction of |chunk_demuxer_| is done
1722 // from ~WMPI by first hopping to |media_task_runner_| to prevent race with
1723 // this task.
servolkf94b4602017-01-31 16:44:271724 media_task_runner_->PostTask(
Dale Curtisee9be30012018-09-21 22:21:511725 FROM_HERE, base::BindOnce(&ChunkDemuxer::OnMemoryPressure,
1726 base::Unretained(chunk_demuxer_),
1727 base::TimeDelta::FromSecondsD(CurrentTime()),
1728 memory_pressure_level, force_instant_gc));
servolkf94b4602017-01-31 16:44:271729}
1730
alokp967c902452016-05-06 05:21:371731void WebMediaPlayerImpl::OnError(PipelineStatus status) {
Xiaohan Wang73b433f2019-11-05 20:13:011732 DVLOG(1) << __func__ << ": status=" << status;
alokp967c902452016-05-06 05:21:371733 DCHECK(main_task_runner_->BelongsToCurrentThread());
1734 DCHECK_NE(status, PIPELINE_OK);
1735
1736 if (suppress_destruction_errors_)
1737 return;
1738
Thomas Guilbert6b6be3d2017-08-18 03:17:271739#if defined(OS_ANDROID)
Dale Curtisf273f8f2018-12-13 23:40:331740 // |mb_data_source_| may be nullptr if someone passes in a m3u8 as a data://
1741 // URL, since MediaPlayer doesn't support data:// URLs, fail playback now.
Dan Sanders675250992019-05-11 00:07:491742 const bool found_hls = base::FeatureList::IsEnabled(kHlsPlayer) &&
1743 status == PipelineStatus::DEMUXER_ERROR_DETECTED_HLS;
Dale Curtisf273f8f2018-12-13 23:40:331744 if (found_hls && mb_data_source_) {
Dan Sandersae245e42019-03-07 23:25:291745 demuxer_found_hls_ = true;
1746
Dan Sandersd80b1842019-02-05 00:36:161747 UMA_HISTOGRAM_BOOLEAN("Media.WebMediaPlayerImpl.HLS.IsCorsCrossOrigin",
1748 mb_data_source_->IsCorsCrossOrigin());
Dan Sandersae245e42019-03-07 23:25:291749 if (mb_data_source_->IsCorsCrossOrigin()) {
1750 UMA_HISTOGRAM_BOOLEAN("Media.WebMediaPlayerImpl.HLS.HasAccessControl",
1751 mb_data_source_->HasAccessControl());
1752 }
1753
1754 // Note: Does not consider the full redirect chain, which could contain
1755 // undetected mixed content.
Dan Sandersd80b1842019-02-05 00:36:161756 bool frame_url_is_cryptographic = url::Origin(frame_->GetSecurityOrigin())
1757 .GetURL()
1758 .SchemeIsCryptographic();
1759 bool manifest_url_is_cryptographic =
1760 loaded_url_.SchemeIsCryptographic() &&
1761 mb_data_source_->GetUrlAfterRedirects().SchemeIsCryptographic();
1762 UMA_HISTOGRAM_BOOLEAN(
1763 "Media.WebMediaPlayerImpl.HLS.IsMixedContent",
1764 frame_url_is_cryptographic && !manifest_url_is_cryptographic);
Thomas Guilbert153f84572018-07-19 05:03:581765
Xiaohan Wang3684e0c2019-10-30 01:04:301766 renderer_factory_selector_->SetBaseFactoryType(
Xiaohan Wang48aaa192019-12-05 01:29:001767 RendererFactoryType::kMediaPlayer);
Thomas Guilbert6b6be3d2017-08-18 03:17:271768
Dale Curtisf273f8f2018-12-13 23:40:331769 loaded_url_ = mb_data_source_->GetUrlAfterRedirects();
1770 DCHECK(data_source_);
1771 data_source_->Stop();
1772 mb_data_source_ = nullptr;
1773
Antonio Gomes81b56552019-05-15 22:15:281774 pipeline_controller_->Stop();
Dale Curtis8a6281322017-08-31 00:35:531775 SetMemoryReportingState(false);
Thomas Guilbert6b6be3d2017-08-18 03:17:271776
Dale Curtisf273f8f2018-12-13 23:40:331777 // Trampoline through the media task runner to destruct the demuxer and
1778 // data source now that we're switching to HLS playback.
1779 media_task_runner_->PostTask(
Dale Curtisee9be30012018-09-21 22:21:511780 FROM_HERE,
Dale Curtisf273f8f2018-12-13 23:40:331781 BindToCurrentLoop(base::BindOnce(
1782 [](std::unique_ptr<Demuxer> demuxer,
1783 std::unique_ptr<DataSource> data_source,
1784 base::OnceClosure start_pipeline_cb) {
1785 // Release resources before starting HLS.
1786 demuxer.reset();
1787 data_source.reset();
1788
1789 std::move(start_pipeline_cb).Run();
1790 },
1791 std::move(demuxer_), std::move(data_source_),
Antonio Gomes142f32a2019-05-15 23:32:561792 base::BindOnce(&WebMediaPlayerImpl::StartPipeline, weak_this_))));
Dale Curtisf273f8f2018-12-13 23:40:331793
Thomas Guilbert6b6be3d2017-08-18 03:17:271794 return;
1795 }
Dale Curtisf273f8f2018-12-13 23:40:331796
1797 // We found hls in a data:// URL, fail immediately.
1798 if (found_hls)
1799 status = PIPELINE_ERROR_EXTERNAL_RENDERER_FAILED;
Thomas Guilbert6b6be3d2017-08-18 03:17:271800#endif
1801
Dale Curtis5bba03232018-08-30 17:57:381802 MaybeSetContainerName();
Dan Sanders6edfd782019-08-13 00:13:181803 simple_watch_timer_.Stop();
Ted Meyer0134aed2020-01-23 23:56:401804 media_log_->NotifyError(status);
Dale Curtis74612b72017-12-14 20:56:191805 media_metrics_provider_->OnError(status);
Dale Curtisccfd0cca2017-08-31 01:27:561806 if (watch_time_reporter_)
1807 watch_time_reporter_->OnError(status);
alokp967c902452016-05-06 05:21:371808
Blink Reformat1c4d759e2017-04-09 16:34:541809 if (ready_state_ == WebMediaPlayer::kReadyStateHaveNothing) {
alokp967c902452016-05-06 05:21:371810 // Any error that occurs before reaching ReadyStateHaveMetadata should
1811 // be considered a format error.
Blink Reformat1c4d759e2017-04-09 16:34:541812 SetNetworkState(WebMediaPlayer::kNetworkStateFormatError);
alokp967c902452016-05-06 05:21:371813 } else {
Antonio Gomesf01cfbd2019-07-12 08:53:111814 SetNetworkState(blink::PipelineErrorToNetworkState(status));
alokp967c902452016-05-06 05:21:371815 }
1816
Thomas Guilbert2e591392017-08-12 00:56:381817 // PipelineController::Stop() is idempotent.
Antonio Gomes81b56552019-05-15 22:15:281818 pipeline_controller_->Stop();
Thomas Guilbert2e591392017-08-12 00:56:381819
alokp967c902452016-05-06 05:21:371820 UpdatePlayState();
1821}
1822
1823void WebMediaPlayerImpl::OnEnded() {
John Chen5b164a02017-11-01 00:36:091824 TRACE_EVENT2("media", "WebMediaPlayerImpl::OnEnded", "duration", Duration(),
1825 "id", media_log_->id());
pkastingf5279482016-07-27 02:18:201826 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:431827 DCHECK(main_task_runner_->BelongsToCurrentThread());
scherkusd2c745b2014-09-04 05:03:401828
sandersd1c0bba02016-03-04 23:14:081829 // Ignore state changes until we've completed all outstanding operations.
Antonio Gomes81b56552019-05-15 22:15:281830 if (!pipeline_controller_->IsStable())
scherkusd2c745b2014-09-04 05:03:401831 return;
1832
1833 ended_ = true;
Blink Reformat1c4d759e2017-04-09 16:34:541834 client_->TimeChanged();
sandersd50a635e2016-04-04 22:50:091835
1836 // We don't actually want this to run until |client_| calls seek() or pause(),
1837 // but that should have already happened in timeChanged() and so this is
1838 // expected to be a no-op.
1839 UpdatePlayState();
[email protected]576537842009-08-12 23:52:051840}
1841
Chisoon Jeong0a8e4bc2019-05-11 00:06:141842void WebMediaPlayerImpl::OnMetadata(const PipelineMetadata& metadata) {
pkastingf5279482016-07-27 02:18:201843 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:431844 DCHECK(main_task_runner_->BelongsToCurrentThread());
Dale Curtisff576552018-03-30 02:32:441845
1846 // Cache the |time_to_metadata_| to use for adjusting the TimeToFirstFrame and
1847 // TimeToPlayReady metrics later if we end up doing a suspended startup.
1848 time_to_metadata_ = base::TimeTicks::Now() - load_start_time_;
1849 media_metrics_provider_->SetTimeToMetadata(time_to_metadata_);
1850 RecordTimingUMA("Media.TimeToMetadata", time_to_metadata_);
[email protected]a8e2cb82012-08-17 00:02:391851
Dale Curtis5bba03232018-08-30 17:57:381852 MaybeSetContainerName();
1853
[email protected]b8877772014-03-26 20:17:151854 pipeline_metadata_ = metadata;
[email protected]c7a918e2020-01-17 00:18:271855 if (power_status_helper_)
[email protected]dc996312019-12-19 19:26:381856 power_status_helper_->SetMetadata(metadata);
[email protected]739847c02014-01-16 00:12:251857
Ted Meyer4a427632019-05-01 19:05:271858 UMA_HISTOGRAM_ENUMERATION(
1859 "Media.VideoRotation",
1860 metadata.video_decoder_config.video_transformation().rotation,
1861 VIDEO_ROTATION_MAX + 1);
[email protected]21c3f7502013-03-23 03:29:511862
John Rummelldb5a7ef2018-05-16 00:28:011863 if (HasAudio()) {
Ted Meyerd5885f82019-07-16 19:19:171864 media_metrics_provider_->SetHasAudio(metadata.audio_decoder_config.codec());
John Rummelldb5a7ef2018-05-16 00:28:011865 RecordEncryptionScheme("Audio",
1866 metadata.audio_decoder_config.encryption_scheme());
1867 }
1868
Blink Reformat1c4d759e2017-04-09 16:34:541869 if (HasVideo()) {
Ted Meyerd5885f82019-07-16 19:19:171870 media_metrics_provider_->SetHasVideo(metadata.video_decoder_config.codec());
John Rummelldb5a7ef2018-05-16 00:28:011871 RecordEncryptionScheme("Video",
1872 metadata.video_decoder_config.encryption_scheme());
1873
liberato2fd111be2017-01-04 00:25:061874 if (overlay_enabled_) {
1875 // SurfaceView doesn't support rotated video, so transition back if
[email protected]c8d574722017-08-30 20:53:431876 // the video is now rotated. If |always_enable_overlays_|, we keep the
liberato2fd111be2017-01-04 00:25:061877 // overlay anyway so that the state machine keeps working.
[email protected]c8d574722017-08-30 20:53:431878 // TODO(liberato): verify if compositor feedback catches this. If so,
1879 // then we don't need this check.
1880 if (!always_enable_overlays_ && !DoesOverlaySupportMetadata())
liberato2fd111be2017-01-04 00:25:061881 DisableOverlay();
liberato2fd111be2017-01-04 00:25:061882 }
watkf835a792016-06-24 23:24:401883
[email protected]702d721d2018-10-25 21:55:271884 if (surface_layer_mode_ ==
Mounir Lamouri28d648102019-11-27 16:49:031885 blink::WebMediaPlayer::SurfaceLayerMode::kAlways) {
[email protected]702d721d2018-10-25 21:55:271886 ActivateSurfaceLayerForVideo();
1887 } else {
danakj6e669e782018-05-16 16:57:171888 DCHECK(!video_layer_);
Ted Meyer4a427632019-05-01 19:05:271889 // TODO(tmathmeyer) does this need support for reflections as well?
danakj25f030112018-05-11 18:26:541890 video_layer_ = cc::VideoLayer::Create(
Julien Isorce6c83d8de2017-10-12 13:11:291891 compositor_.get(),
Ted Meyer4a427632019-05-01 19:05:271892 pipeline_metadata_.video_decoder_config.video_transformation()
1893 .rotation);
danakj8bc61c72018-05-16 13:55:061894 video_layer_->SetContentsOpaque(opaque_);
danakj8d204a42018-05-18 18:05:351895 client_->SetCcLayer(video_layer_.get());
lethalantidote7f6009d2017-07-07 21:47:391896 }
[email protected]a8e2cb82012-08-17 00:02:391897 }
dalecurtis8e4dc682016-03-15 02:30:301898
xjzd3fe45a2016-10-12 18:26:371899 if (observer_)
xjz15b483f2017-01-12 00:21:361900 observer_->OnMetadataChanged(pipeline_metadata_);
xjzd3fe45a2016-10-12 18:26:371901
Dale Curtisc7d2a7d22018-01-11 20:01:051902 // TODO(dalecurtis): Don't create these until kReadyStateHaveFutureData; when
1903 // we create them early we just increase the chances of needing to throw them
1904 // away unnecessarily.
dalecurtis04bdb582016-08-17 22:15:231905 CreateWatchTimeReporter();
Chris Cunninghamd9df58e2017-08-29 00:04:231906 CreateVideoDecodeStatsReporter();
Dale Curtisc7d2a7d22018-01-11 20:01:051907
Dale Curtis1e7a02b42019-05-28 20:12:241908 // SetReadyState() may trigger all sorts of calls into this class (e.g.,
1909 // Play(), Pause(), etc) so do it last to avoid unexpected states during the
1910 // calls. An exception to this is UpdatePlayState(), which is safe to call and
1911 // needs to use the new ReadyState in its calculations.
Dale Curtis2fc01cc2019-05-20 22:53:521912 SetReadyState(WebMediaPlayer::kReadyStateHaveMetadata);
Dale Curtis1e7a02b42019-05-28 20:12:241913 UpdatePlayState();
[email protected]a8e2cb82012-08-17 00:02:391914}
1915
[email protected]69db58f2018-09-26 20:27:561916void WebMediaPlayerImpl::ActivateSurfaceLayerForVideo() {
1917 // Note that we might or might not already be in VideoLayer mode.
1918 DCHECK(!bridge_);
1919
1920 surface_layer_for_video_enabled_ = true;
1921
1922 // If we're in VideoLayer mode, then get rid of the layer.
1923 if (video_layer_) {
1924 client_->SetCcLayer(nullptr);
1925 video_layer_ = nullptr;
1926 }
1927
1928 bridge_ = std::move(create_bridge_callback_)
1929 .Run(this, compositor_->GetUpdateSubmissionStateCallback());
1930 bridge_->CreateSurfaceLayer();
1931
Ted Meyer4a427632019-05-01 19:05:271932 // TODO(tmathmeyer) does this need support for the reflection transformation
1933 // as well?
[email protected]69db58f2018-09-26 20:27:561934 vfc_task_runner_->PostTask(
1935 FROM_HERE,
Ted Meyer4a427632019-05-01 19:05:271936 base::BindOnce(
1937 &VideoFrameCompositor::EnableSubmission,
1938 base::Unretained(compositor_.get()), bridge_->GetSurfaceId(),
1939 bridge_->GetLocalSurfaceIdAllocationTime(),
1940 pipeline_metadata_.video_decoder_config.video_transformation()
1941 .rotation,
1942 IsInPictureInPicture()));
[email protected]69db58f2018-09-26 20:27:561943 bridge_->SetContentsOpaque(opaque_);
1944
1945 // If the element is already in Picture-in-Picture mode, it means that it
1946 // was set in this mode prior to this load, with a different
1947 // WebMediaPlayerImpl. The new player needs to send its id, size and
1948 // surface id to the browser process to make sure the states are properly
1949 // updated.
1950 // TODO(872056): the surface should be activated but for some reasons, it
1951 // does not. It is possible that this will no longer be needed after 872056
1952 // is fixed.
Dale Curtisca1b78f2019-01-15 03:11:261953 if (IsInPictureInPicture())
[email protected]69db58f2018-09-26 20:27:561954 OnSurfaceIdUpdated(bridge_->GetSurfaceId());
[email protected]69db58f2018-09-26 20:27:561955}
1956
Chris Cunninghamfc0d67e2019-07-22 20:29:161957void WebMediaPlayerImpl::OnBufferingStateChange(
1958 BufferingState state,
1959 BufferingStateChangeReason reason) {
1960 OnBufferingStateChangeInternal(state, reason, false);
Dale Curtis2dc6089a2018-03-26 16:47:581961}
1962
Chris Cunninghamd9df58e2017-08-29 00:04:231963void WebMediaPlayerImpl::CreateVideoDecodeStatsReporter() {
1964 // TODO(chcunningham): destroy reporter if we initially have video but the
1965 // track gets disabled. Currently not possible in default desktop Chrome.
1966 if (!HasVideo())
1967 return;
1968
Chris Cunningham89b4b762019-03-27 17:13:331969 // Only record stats from the local pipeline.
1970 if (is_flinging_ || is_remote_rendering_ || using_media_player_renderer_)
1971 return;
1972
Chris Cunninghamd9df58e2017-08-29 00:04:231973 // Stats reporter requires a valid config. We may not have one for HLS cases
1974 // where URL demuxer doesn't know details of the stream.
1975 if (!pipeline_metadata_.video_decoder_config.IsValidConfig())
1976 return;
1977
Chris Cunningham6c0ec292019-04-04 18:31:111978 // Profile must be known for use as index to save the reported stats.
Chris Cunningham5b1b67eb2019-03-23 03:24:411979 if (pipeline_metadata_.video_decoder_config.profile() ==
1980 VIDEO_CODEC_PROFILE_UNKNOWN) {
1981 return;
1982 }
1983
Chris Cunningham6c0ec292019-04-04 18:31:111984 // CdmConfig must be provided for use as index to save encrypted stats.
1985 if (is_encrypted_ && !cdm_config_) {
Chris Cunninghamd9df58e2017-08-29 00:04:231986 return;
Chris Cunningham6c0ec292019-04-04 18:31:111987 } else if (cdm_config_) {
1988 DCHECK(!key_system_.empty());
1989 }
Chris Cunninghamd9df58e2017-08-29 00:04:231990
Gyuyoung Kima040bc52019-10-30 01:14:351991 mojo::PendingRemote<mojom::VideoDecodeStatsRecorder> recorder;
Dale Curtis7e8a510d2017-12-14 19:19:481992 media_metrics_provider_->AcquireVideoDecodeStatsRecorder(
Gyuyoung Kima040bc52019-10-30 01:14:351993 recorder.InitWithNewPipeAndPassReceiver());
Chris Cunninghamc7c6a6d2017-11-23 14:06:451994
Chris Cunninghamd9df58e2017-08-29 00:04:231995 // Create capabilities reporter and synchronize its initial state.
1996 video_decode_stats_reporter_.reset(new VideoDecodeStatsReporter(
Chris Cunninghamc7c6a6d2017-11-23 14:06:451997 std::move(recorder),
Chris Cunninghamd9df58e2017-08-29 00:04:231998 base::Bind(&WebMediaPlayerImpl::GetPipelineStatistics,
1999 base::Unretained(this)),
Chris Cunningham5b1b67eb2019-03-23 03:24:412000 pipeline_metadata_.video_decoder_config.profile(),
Chris Cunningham6c0ec292019-04-04 18:31:112001 pipeline_metadata_.natural_size, key_system_, cdm_config_,
Hajime Hoshib5a26ee2018-05-14 12:47:512002 frame_->GetTaskRunner(blink::TaskType::kInternalMedia)));
Chris Cunninghamd9df58e2017-08-29 00:04:232003
2004 if (delegate_->IsFrameHidden())
2005 video_decode_stats_reporter_->OnHidden();
2006 else
2007 video_decode_stats_reporter_->OnShown();
2008
2009 if (paused_)
2010 video_decode_stats_reporter_->OnPaused();
2011 else
2012 video_decode_stats_reporter_->OnPlaying();
2013}
2014
hubbeb2d3efd2017-05-05 23:26:382015void WebMediaPlayerImpl::OnProgress() {
Chris Watkins1ffabc5f2017-05-10 20:52:092016 DVLOG(4) << __func__;
Dale Curtisad645f72019-09-06 23:28:162017
2018 // See IsPrerollAttemptNeeded() for more details. We can't use that method
2019 // here since it considers |preroll_attempt_start_time_| and for OnProgress()
2020 // events we must make the attempt -- since there may not be another event.
2021 if (highest_ready_state_ < ReadyState::kReadyStateHaveFutureData) {
hubbeb2d3efd2017-05-05 23:26:382022 // Reset the preroll attempt clock.
2023 preroll_attempt_pending_ = true;
2024 preroll_attempt_start_time_ = base::TimeTicks();
2025
2026 // Clear any 'stale' flag and give the pipeline a chance to resume. If we
2027 // are already resumed, this will cause |preroll_attempt_start_time_| to
2028 // be set.
2029 delegate_->ClearStaleFlag(delegate_id_);
2030 UpdatePlayState();
2031 } else if (ready_state_ == ReadyState::kReadyStateHaveFutureData &&
2032 CanPlayThrough()) {
2033 SetReadyState(WebMediaPlayer::kReadyStateHaveEnoughData);
2034 }
2035}
2036
2037bool WebMediaPlayerImpl::CanPlayThrough() {
2038 if (!base::FeatureList::IsEnabled(kSpecCompliantCanPlayThrough))
2039 return true;
2040 if (chunk_demuxer_)
2041 return true;
Dale Curtis4841c712018-12-13 18:14:052042 if (data_source_ && data_source_->AssumeFullyBuffered())
hubbeb2d3efd2017-05-05 23:26:382043 return true;
2044 // If we're not currently downloading, we have as much buffer as
2045 // we're ever going to get, which means we say we can play through.
2046 if (network_state_ == WebMediaPlayer::kNetworkStateIdle)
2047 return true;
Antonio Gomes81b56552019-05-15 22:15:282048 return buffered_data_source_host_->CanPlayThrough(
hubbeb2d3efd2017-05-05 23:26:382049 base::TimeDelta::FromSecondsD(CurrentTime()),
2050 base::TimeDelta::FromSecondsD(Duration()),
2051 playback_rate_ == 0.0 ? 1.0 : playback_rate_);
2052}
2053
Dale Curtisff576552018-03-30 02:32:442054void WebMediaPlayerImpl::OnBufferingStateChangeInternal(
2055 BufferingState state,
Chris Cunninghamfc0d67e2019-07-22 20:29:162056 BufferingStateChangeReason reason,
Dale Curtisff576552018-03-30 02:32:442057 bool for_suspended_start) {
Chris Cunninghamfc0d67e2019-07-22 20:29:162058 DVLOG(1) << __func__ << "(" << state << ", " << reason << ")";
alokp967c902452016-05-06 05:21:372059 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]b8877772014-03-26 20:17:152060
Ted Meyer742212b82018-08-22 17:21:422061 // Ignore buffering state changes caused by back-to-back seeking, so as not
2062 // to assume the second seek has finished when it was only the first seek.
Antonio Gomes81b56552019-05-15 22:15:282063 if (pipeline_controller_->IsPendingSeek())
[email protected]ba7d5f92014-06-24 05:37:402064 return;
[email protected]b8877772014-03-26 20:17:152065
Ted Meyer0134aed2020-01-23 23:56:402066 media_log_->AddEvent<MediaLogEvent::kBufferingStateChanged>(
2067 SerializableBufferingState<SerializableBufferingStateType::kPipeline>{
2068 state, reason, for_suspended_start});
dalecurtis869bf2f2017-01-10 18:01:102069
Ted Meyerd5885f82019-07-16 19:19:172070 if (state == BUFFERING_HAVE_ENOUGH && !for_suspended_start)
2071 media_metrics_provider_->SetHaveEnough();
2072
chcunninghameb270c92016-07-15 01:00:452073 if (state == BUFFERING_HAVE_ENOUGH) {
John Chen5b164a02017-11-01 00:36:092074 TRACE_EVENT1("media", "WebMediaPlayerImpl::BufferingHaveEnough", "id",
2075 media_log_->id());
Dale Curtisff576552018-03-30 02:32:442076 // The SetReadyState() call below may clear
2077 // |skip_metrics_due_to_startup_suspend_| so report this first.
2078 if (!have_reported_time_to_play_ready_ &&
2079 !skip_metrics_due_to_startup_suspend_) {
2080 DCHECK(!for_suspended_start);
Dale Curtis3899090ea2018-01-12 00:10:352081 have_reported_time_to_play_ready_ = true;
2082 const base::TimeDelta elapsed = base::TimeTicks::Now() - load_start_time_;
2083 media_metrics_provider_->SetTimeToPlayReady(elapsed);
2084 RecordTimingUMA("Media.TimeToPlayReady", elapsed);
2085 }
[email protected]ba7d5f92014-06-24 05:37:402086
Dale Curtisff576552018-03-30 02:32:442087 // Warning: This call may be re-entrant.
2088 SetReadyState(CanPlayThrough() ? WebMediaPlayer::kReadyStateHaveEnoughData
2089 : WebMediaPlayer::kReadyStateHaveFutureData);
2090
Dale Curtis18ad391b2019-05-30 23:25:092091 // Let the DataSource know we have enough data -- this is the only function
2092 // during which we advance to (or past) the kReadyStateHaveEnoughData state.
2093 // It may use this information to update buffer sizes or release unused
2094 // network connections.
2095 MaybeUpdateBufferSizesForPlayback();
Dale Curtis04769ca2019-05-25 00:38:102096 if (mb_data_source_ && !client_->CouldPlayIfEnoughData()) {
2097 // For LazyLoad this will be handled during OnPipelineSuspended().
2098 if (for_suspended_start && did_lazy_load_)
2099 DCHECK(!have_enough_after_lazy_load_cb_.IsCancelled());
2100 else
2101 mb_data_source_->OnBufferingHaveEnough(false);
2102 }
dalecurtis849cf4b22015-03-27 18:35:452103
chcunninghameb270c92016-07-15 01:00:452104 // Blink expects a timeChanged() in response to a seek().
sandersd35d2c3f2017-01-14 02:04:422105 if (should_notify_time_changed_) {
2106 should_notify_time_changed_ = false;
Blink Reformat1c4d759e2017-04-09 16:34:542107 client_->TimeChanged();
sandersd35d2c3f2017-01-14 02:04:422108 }
dalecurtis0f0097a2015-12-01 17:40:472109
chcunninghameb270c92016-07-15 01:00:452110 // Once we have enough, start reporting the total memory usage. We'll also
2111 // report once playback starts.
2112 ReportMemoryUsage();
dalecurtis9d638a12016-08-30 06:20:552113
dalecurtis4f6d14d2017-02-22 17:42:222114 // Report the amount of time it took to leave the underflow state.
2115 if (underflow_timer_) {
Dale Curtisc9069622019-10-24 20:20:502116 auto elapsed = underflow_timer_->Elapsed();
2117 RecordUnderflowDuration(elapsed);
2118 watch_time_reporter_->OnUnderflowComplete(elapsed);
dalecurtis9d638a12016-08-30 06:20:552119 underflow_timer_.reset();
2120 }
chcunninghameb270c92016-07-15 01:00:452121 } else {
2122 // Buffering has underflowed.
2123 DCHECK_EQ(state, BUFFERING_HAVE_NOTHING);
dalecurtisacd77d62016-09-09 23:23:142124
dalecurtisd06eabc2017-02-24 23:43:292125 // Report the number of times we've entered the underflow state. Ensure we
2126 // only report the value when transitioning from HAVE_ENOUGH to
2127 // HAVE_NOTHING.
Dale Curtis6995b862017-05-31 22:20:082128 if (ready_state_ == WebMediaPlayer::kReadyStateHaveEnoughData &&
2129 !seeking_) {
dalecurtisacd77d62016-09-09 23:23:142130 underflow_timer_.reset(new base::ElapsedTimer());
Dale Curtis6995b862017-05-31 22:20:082131 watch_time_reporter_->OnUnderflow();
2132 }
dalecurtisacd77d62016-09-09 23:23:142133
chcunninghameb270c92016-07-15 01:00:452134 // It shouldn't be possible to underflow if we've not advanced past
2135 // HAVE_CURRENT_DATA.
Blink Reformat1c4d759e2017-04-09 16:34:542136 DCHECK_GT(highest_ready_state_, WebMediaPlayer::kReadyStateHaveCurrentData);
2137 SetReadyState(WebMediaPlayer::kReadyStateHaveCurrentData);
chcunninghameb270c92016-07-15 01:00:452138 }
sandersd50a635e2016-04-04 22:50:092139
[email protected]91379332020-01-26 03:58:202140 // If this is an NNR, then notify the smoothness helper about it. Note that
2141 // it's unclear what we should do if there is no smoothness helper yet. As it
2142 // is, we just discard the NNR.
2143 if (state == BUFFERING_HAVE_NOTHING && reason == DECODER_UNDERFLOW &&
2144 smoothness_helper_) {
2145 smoothness_helper_->NotifyNNR();
2146 }
2147
sandersd50a635e2016-04-04 22:50:092148 UpdatePlayState();
[email protected]b8877772014-03-26 20:17:152149}
2150
alokp967c902452016-05-06 05:21:372151void WebMediaPlayerImpl::OnDurationChange() {
acolwellb4034942014-08-28 15:42:432152 DCHECK(main_task_runner_->BelongsToCurrentThread());
alokp967c902452016-05-06 05:21:372153
John Delaney2371b452018-12-13 04:30:332154 if (frame_->IsAdSubframe()) {
2155 UMA_HISTOGRAM_CUSTOM_TIMES("Ads.Media.Duration", GetPipelineMediaDuration(),
2156 base::TimeDelta::FromMilliseconds(1),
2157 base::TimeDelta::FromDays(1),
2158 50 /* bucket_count */);
2159 }
2160
alokp967c902452016-05-06 05:21:372161 // TODO(sandersd): We should call delegate_->DidPlay() with the new duration,
2162 // especially if it changed from <5s to >5s.
Blink Reformat1c4d759e2017-04-09 16:34:542163 if (ready_state_ == WebMediaPlayer::kReadyStateHaveNothing)
alokp967c902452016-05-06 05:21:372164 return;
2165
Blink Reformat1c4d759e2017-04-09 16:34:542166 client_->DurationChanged();
Dale Curtisaebaeea2018-07-19 23:42:112167 if (watch_time_reporter_)
2168 watch_time_reporter_->OnDurationChanged(GetPipelineMediaDuration());
Becca Hughes7a85bf22019-07-24 16:16:582169
2170 // The duration has changed so we should update the media position state.
2171 UpdateMediaPositionState();
[email protected]81bb3322011-07-21 15:55:502172}
2173
alokp967c902452016-05-06 05:21:372174void WebMediaPlayerImpl::OnAddTextTrack(const TextTrackConfig& config,
Raymond Toy85ad6802019-12-17 23:55:192175 AddTextTrackDoneCB done_cb) {
acolwellb4034942014-08-28 15:42:432176 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]71537722013-05-23 06:47:532177
[email protected]8a561062013-11-22 01:19:312178 const WebInbandTextTrackImpl::Kind web_kind =
2179 static_cast<WebInbandTextTrackImpl::Kind>(config.kind());
Blink Reformat1c4d759e2017-04-09 16:34:542180 const blink::WebString web_label = blink::WebString::FromUTF8(config.label());
[email protected]8a561062013-11-22 01:19:312181 const blink::WebString web_language =
Blink Reformat1c4d759e2017-04-09 16:34:542182 blink::WebString::FromUTF8(config.language());
2183 const blink::WebString web_id = blink::WebString::FromUTF8(config.id());
[email protected]71537722013-05-23 06:47:532184
dcheng3076abbf2016-04-22 20:42:392185 std::unique_ptr<WebInbandTextTrackImpl> web_inband_text_track(
henriks9cce5fa2014-12-12 09:35:302186 new WebInbandTextTrackImpl(web_kind, web_label, web_language, web_id));
[email protected]8a561062013-11-22 01:19:312187
Dale Curtisca1b78f2019-01-15 03:11:262188 std::unique_ptr<TextTrack> text_track(new TextTrackImpl(
dcheng652f5ff2015-12-27 08:54:002189 main_task_runner_, client_, std::move(web_inband_text_track)));
[email protected]8a561062013-11-22 01:19:312190
Raymond Toy85ad6802019-12-17 23:55:192191 std::move(done_cb).Run(std::move(text_track));
[email protected]71537722013-05-23 06:47:532192}
2193
Xiaohan Wang640b41d2018-12-18 19:00:462194void WebMediaPlayerImpl::OnWaiting(WaitingReason reason) {
alokp967c902452016-05-06 05:21:372195 DCHECK(main_task_runner_->BelongsToCurrentThread());
2196
Xiaohan Wang640b41d2018-12-18 19:00:462197 switch (reason) {
Xiaohan Wangb54a75282019-10-04 21:34:432198 case WaitingReason::kNoCdm:
Xiaohan Wang640b41d2018-12-18 19:00:462199 case WaitingReason::kNoDecryptionKey:
2200 encrypted_client_->DidBlockPlaybackWaitingForKey();
2201 // TODO(jrummell): didResumePlaybackBlockedForKey() should only be called
2202 // when a key has been successfully added (e.g. OnSessionKeysChange() with
2203 // |has_additional_usable_key| = true). http://crbug.com/461903
2204 encrypted_client_->DidResumePlaybackBlockedForKey();
2205 return;
Xiaohan Wang640b41d2018-12-18 19:00:462206
Xiaohan Wanga7224d62019-01-04 22:22:302207 // Ideally this should be handled by PipelineController directly without
2208 // being proxied here. But currently Pipeline::Client (|this|) is passed to
2209 // PipelineImpl directly without going through |pipeline_controller_|,
2210 // making it difficult to do.
2211 // TODO(xhwang): Handle this in PipelineController when we have a clearer
2212 // picture on how to refactor WebMediaPlayerImpl, PipelineController and
2213 // PipelineImpl.
2214 case WaitingReason::kDecoderStateLost:
Antonio Gomes81b56552019-05-15 22:15:282215 pipeline_controller_->OnDecoderStateLost();
Xiaohan Wanga7224d62019-01-04 22:22:302216 return;
2217 }
alokp967c902452016-05-06 05:21:372218}
2219
alokp5d86e9b2016-05-17 20:20:412220void WebMediaPlayerImpl::OnVideoNaturalSizeChange(const gfx::Size& size) {
2221 DCHECK(main_task_runner_->BelongsToCurrentThread());
Blink Reformat1c4d759e2017-04-09 16:34:542222 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
alokp5d86e9b2016-05-17 20:20:412223
Chris Cunningham038548b2017-07-10 22:36:302224 TRACE_EVENT0("media", "WebMediaPlayerImpl::OnVideoNaturalSizeChange");
xhwang60802652017-04-19 07:29:582225
xjz15b483f2017-01-12 00:21:362226 // The input |size| is from the decoded video frame, which is the original
2227 // natural size and need to be rotated accordingly.
Julien Isorce6c83d8de2017-10-12 13:11:292228 gfx::Size rotated_size = GetRotatedVideoSize(
Ted Meyer4a427632019-05-01 19:05:272229 pipeline_metadata_.video_decoder_config.video_transformation().rotation,
2230 size);
sandersd2c478422016-08-02 01:19:252231
xhwang60802652017-04-19 07:29:582232 RecordVideoNaturalSize(rotated_size);
2233
2234 gfx::Size old_size = pipeline_metadata_.natural_size;
2235 if (rotated_size == old_size)
alokp5d86e9b2016-05-17 20:20:412236 return;
2237
xjz516ef6d2017-01-07 00:23:062238 pipeline_metadata_.natural_size = rotated_size;
Dan Sanders7ef5d0f2019-05-03 18:30:112239
2240 if (using_media_player_renderer_ && old_size.IsEmpty()) {
2241 // If we are using MediaPlayerRenderer and this is the first size change, we
2242 // now know that there is a video track. This condition is paired with code
2243 // in CreateWatchTimeReporter() that guesses the existence of a video track.
2244 CreateWatchTimeReporter();
2245 } else {
Dan Sanders7ef5d0f2019-05-03 18:30:112246 UpdateSecondaryProperties();
2247 }
dalecurtis25405562017-04-14 23:35:112248
Chris Cunningham5b1b67eb2019-03-23 03:24:412249 if (video_decode_stats_reporter_ &&
2250 !video_decode_stats_reporter_->MatchesBucketedNaturalSize(
2251 pipeline_metadata_.natural_size)) {
2252 CreateVideoDecodeStatsReporter();
2253 }
Chris Cunninghamd9df58e2017-08-29 00:04:232254
[email protected]96665a82020-01-23 00:35:372255 // Create or replace the smoothness helper now that we have a size.
2256 UpdateSmoothnessHelper();
2257
Blink Reformat1c4d759e2017-04-09 16:34:542258 client_->SizeChanged();
xjz516ef6d2017-01-07 00:23:062259
xjz15b483f2017-01-12 00:21:362260 if (observer_)
2261 observer_->OnMetadataChanged(pipeline_metadata_);
peconn257951522017-06-09 18:24:592262
2263 delegate_->DidPlayerSizeChange(delegate_id_, NaturalSize());
alokp5d86e9b2016-05-17 20:20:412264}
2265
2266void WebMediaPlayerImpl::OnVideoOpacityChange(bool opaque) {
2267 DCHECK(main_task_runner_->BelongsToCurrentThread());
Blink Reformat1c4d759e2017-04-09 16:34:542268 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
alokp5d86e9b2016-05-17 20:20:412269
2270 opaque_ = opaque;
Dale Curtis357630f22019-01-18 01:10:172271 if (!surface_layer_for_video_enabled_ && video_layer_)
2272 video_layer_->SetContentsOpaque(opaque_);
2273 else if (bridge_->GetCcLayer())
CJ DiMeglioa2b13fbc2018-06-27 00:50:592274 bridge_->SetContentsOpaque(opaque_);
alokp5d86e9b2016-05-17 20:20:412275}
2276
[email protected]218ac8de2020-01-03 23:41:432277void WebMediaPlayerImpl::OnVideoFrameRateChange(base::Optional<int> fps) {
2278 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]c7a918e2020-01-17 00:18:272279 if (power_status_helper_)
2280 power_status_helper_->SetAverageFrameRate(fps);
[email protected]96665a82020-01-23 00:35:372281
2282 last_reported_fps_ = fps;
2283 UpdateSmoothnessHelper();
[email protected]218ac8de2020-01-03 23:41:432284}
2285
Chris Cunningham038548b2017-07-10 22:36:302286void WebMediaPlayerImpl::OnAudioConfigChange(const AudioDecoderConfig& config) {
2287 DCHECK(main_task_runner_->BelongsToCurrentThread());
2288 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
2289
Dale Curtisccfd0cca2017-08-31 01:27:562290 const bool codec_change =
2291 pipeline_metadata_.audio_decoder_config.codec() != config.codec();
Dale Curtisf8afcef32020-01-18 06:23:262292 const bool codec_profile_change =
2293 pipeline_metadata_.audio_decoder_config.profile() != config.profile();
2294
Chris Cunningham038548b2017-07-10 22:36:302295 pipeline_metadata_.audio_decoder_config = config;
2296
2297 if (observer_)
2298 observer_->OnMetadataChanged(pipeline_metadata_);
Dale Curtisccfd0cca2017-08-31 01:27:562299
Dale Curtisf8afcef32020-01-18 06:23:262300 if (codec_change || codec_profile_change)
Dale Curtis96d6e9382018-07-18 18:01:072301 UpdateSecondaryProperties();
Chris Cunningham038548b2017-07-10 22:36:302302}
2303
2304void WebMediaPlayerImpl::OnVideoConfigChange(const VideoDecoderConfig& config) {
2305 DCHECK(main_task_runner_->BelongsToCurrentThread());
2306 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
2307
Dale Curtisccfd0cca2017-08-31 01:27:562308 const bool codec_change =
2309 pipeline_metadata_.video_decoder_config.codec() != config.codec();
Chris Cunningham5b1b67eb2019-03-23 03:24:412310 const bool codec_profile_change =
2311 pipeline_metadata_.video_decoder_config.profile() != config.profile();
Dale Curtisccfd0cca2017-08-31 01:27:562312
Chris Cunningham038548b2017-07-10 22:36:302313 pipeline_metadata_.video_decoder_config = config;
2314
2315 if (observer_)
2316 observer_->OnMetadataChanged(pipeline_metadata_);
Chris Cunninghamd9df58e2017-08-29 00:04:232317
Dale Curtisf8afcef32020-01-18 06:23:262318 if (codec_change || codec_profile_change)
Dale Curtis96d6e9382018-07-18 18:01:072319 UpdateSecondaryProperties();
Chris Cunningham5b1b67eb2019-03-23 03:24:412320
2321 if (video_decode_stats_reporter_ && codec_profile_change)
2322 CreateVideoDecodeStatsReporter();
Chris Cunningham038548b2017-07-10 22:36:302323}
2324
avayvodeecec52c2017-02-14 01:25:092325void WebMediaPlayerImpl::OnVideoAverageKeyframeDistanceUpdate() {
2326 UpdateBackgroundVideoOptimizationState();
2327}
2328
Ted Meyerd5885f82019-07-16 19:19:172329void WebMediaPlayerImpl::OnAudioDecoderChange(const PipelineDecoderInfo& info) {
2330 media_metrics_provider_->SetAudioPipelineInfo(info);
2331 if (info.decoder_name == audio_decoder_name_)
Dale Curtisc7d2a7d22018-01-11 20:01:052332 return;
2333
Ted Meyerd5885f82019-07-16 19:19:172334 audio_decoder_name_ = info.decoder_name;
Dale Curtisc7d2a7d22018-01-11 20:01:052335
2336 // If there's no current reporter, there's nothing to be done.
2337 if (!watch_time_reporter_)
2338 return;
2339
Dale Curtis96d6e9382018-07-18 18:01:072340 UpdateSecondaryProperties();
Dale Curtisc7d2a7d22018-01-11 20:01:052341}
2342
Ted Meyerd5885f82019-07-16 19:19:172343void WebMediaPlayerImpl::OnVideoDecoderChange(const PipelineDecoderInfo& info) {
2344 media_metrics_provider_->SetVideoPipelineInfo(info);
2345 if (info.decoder_name == video_decoder_name_)
Dale Curtisc7d2a7d22018-01-11 20:01:052346 return;
2347
Ted Meyerd5885f82019-07-16 19:19:172348 video_decoder_name_ = info.decoder_name;
Dale Curtisc7d2a7d22018-01-11 20:01:052349
2350 // If there's no current reporter, there's nothing to be done.
2351 if (!watch_time_reporter_)
2352 return;
2353
Dale Curtis96d6e9382018-07-18 18:01:072354 UpdateSecondaryProperties();
Dale Curtisc7d2a7d22018-01-11 20:01:052355}
2356
sandersd35d2c3f2017-01-14 02:04:422357void WebMediaPlayerImpl::OnFrameHidden() {
sandersd1e49fb62015-12-12 01:18:062358 DCHECK(main_task_runner_->BelongsToCurrentThread());
avayvod39c102402016-11-23 21:43:132359
avayvod65fad272017-02-24 01:00:482360 // Backgrounding a video requires a user gesture to resume playback.
2361 if (IsHidden())
2362 video_locked_when_paused_when_hidden_ = true;
2363
dalecurtis04bdb582016-08-17 22:15:232364 if (watch_time_reporter_)
2365 watch_time_reporter_->OnHidden();
avayvod48a8be52016-08-04 19:52:502366
Chris Cunninghamd9df58e2017-08-29 00:04:232367 if (video_decode_stats_reporter_)
2368 video_decode_stats_reporter_->OnHidden();
2369
avayvod65fad272017-02-24 01:00:482370 UpdateBackgroundVideoOptimizationState();
sandersd50a635e2016-04-04 22:50:092371 UpdatePlayState();
dalecurtis8b8505e72016-06-10 21:59:172372
2373 // Schedule suspended playing media to be paused if the user doesn't come back
2374 // to it within some timeout period to avoid any autoplay surprises.
2375 ScheduleIdlePauseTimer();
Dale Curtisca1b78f2019-01-15 03:11:262376
2377 // Notify the compositor of our page visibility status.
2378 vfc_task_runner_->PostTask(
2379 FROM_HERE,
2380 base::BindOnce(&VideoFrameCompositor::SetIsPageVisible,
2381 base::Unretained(compositor_.get()), !IsHidden()));
sandersd1e49fb62015-12-12 01:18:062382}
2383
sandersd35d2c3f2017-01-14 02:04:422384void WebMediaPlayerImpl::OnFrameClosed() {
sandersd1e49fb62015-12-12 01:18:062385 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]28347e72017-06-27 17:30:112386
sandersd35d2c3f2017-01-14 02:04:422387 UpdatePlayState();
2388}
2389
2390void WebMediaPlayerImpl::OnFrameShown() {
2391 DCHECK(main_task_runner_->BelongsToCurrentThread());
2392 background_pause_timer_.Stop();
2393
avayvod65fad272017-02-24 01:00:482394 // Foreground videos don't require user gesture to continue playback.
2395 video_locked_when_paused_when_hidden_ = false;
2396
dalecurtis04bdb582016-08-17 22:15:232397 if (watch_time_reporter_)
2398 watch_time_reporter_->OnShown();
2399
Chris Cunninghamd9df58e2017-08-29 00:04:232400 if (video_decode_stats_reporter_)
2401 video_decode_stats_reporter_->OnShown();
2402
Dale Curtisca1b78f2019-01-15 03:11:262403 // Notify the compositor of our page visibility status.
2404 vfc_task_runner_->PostTask(
2405 FROM_HERE,
2406 base::BindOnce(&VideoFrameCompositor::SetIsPageVisible,
2407 base::Unretained(compositor_.get()), !IsHidden()));
2408
Dale Curtisdcbb81a2017-08-18 01:06:122409 UpdateBackgroundVideoOptimizationState();
avayvod65fad272017-02-24 01:00:482410
avayvod2135a642017-01-13 00:17:142411 if (paused_when_hidden_) {
2412 paused_when_hidden_ = false;
2413 OnPlay(); // Calls UpdatePlayState() so return afterwards.
2414 return;
2415 }
2416
sandersd50a635e2016-04-04 22:50:092417 UpdatePlayState();
sandersd1e49fb62015-12-12 01:18:062418}
2419
sandersd35d2c3f2017-01-14 02:04:422420void WebMediaPlayerImpl::OnIdleTimeout() {
dalecurtis0431cbf2016-03-12 01:19:432421 DCHECK(main_task_runner_->BelongsToCurrentThread());
2422
Dale Curtis99a9b482018-02-01 02:23:282423 // This should never be called when stale state testing overrides are used.
2424 DCHECK(!stale_state_override_for_testing_.has_value());
2425
sandersd35d2c3f2017-01-14 02:04:422426 // If we are attempting preroll, clear the stale flag.
2427 if (IsPrerollAttemptNeeded()) {
tguilbert1bb1c782017-01-23 21:15:112428 delegate_->ClearStaleFlag(delegate_id_);
sandersd35d2c3f2017-01-14 02:04:422429 return;
watkd026f792016-11-05 00:28:512430 }
sandersd50a635e2016-04-04 22:50:092431
sandersd35d2c3f2017-01-14 02:04:422432 UpdatePlayState();
dalecurtis0431cbf2016-03-12 01:19:432433}
2434
dalecurtisbb3eaac2016-01-27 21:10:252435void WebMediaPlayerImpl::OnPlay() {
Mounir Lamouri703106e2018-05-30 14:31:092436 client_->RequestPlay();
dalecurtisbb3eaac2016-01-27 21:10:252437}
2438
2439void WebMediaPlayerImpl::OnPause() {
Mounir Lamouri703106e2018-05-30 14:31:092440 client_->RequestPause();
dalecurtisbb3eaac2016-01-27 21:10:252441}
2442
François Beaufortb4fe7c62019-02-27 08:19:442443void WebMediaPlayerImpl::OnMuted(bool muted) {
2444 client_->RequestMuted(muted);
2445}
2446
Alec Douglas316cce42017-10-31 13:28:082447void WebMediaPlayerImpl::OnSeekForward(double seconds) {
2448 DCHECK_GE(seconds, 0) << "Attempted to seek by a negative number of seconds";
2449 client_->RequestSeek(CurrentTime() + seconds);
2450}
2451
2452void WebMediaPlayerImpl::OnSeekBackward(double seconds) {
2453 DCHECK_GE(seconds, 0) << "Attempted to seek by a negative number of seconds";
2454 client_->RequestSeek(CurrentTime() - seconds);
2455}
2456
Jazz Xuf8564dc2020-01-24 14:26:022457void WebMediaPlayerImpl::OnEnterPictureInPicture() {
2458 client_->RequestEnterPictureInPicture();
2459}
2460
2461void WebMediaPlayerImpl::OnExitPictureInPicture() {
2462 client_->RequestExitPictureInPicture();
2463}
2464
dalecurtisbb3eaac2016-01-27 21:10:252465void WebMediaPlayerImpl::OnVolumeMultiplierUpdate(double multiplier) {
2466 volume_multiplier_ = multiplier;
Blink Reformat1c4d759e2017-04-09 16:34:542467 SetVolume(volume_);
dalecurtisbb3eaac2016-01-27 21:10:252468}
2469
zqzhang8ac49002017-03-16 21:51:352470void WebMediaPlayerImpl::OnBecamePersistentVideo(bool value) {
Blink Reformat1c4d759e2017-04-09 16:34:542471 client_->OnBecamePersistentVideo(value);
[email protected]6490e2d12019-01-14 19:18:372472 overlay_info_.is_persistent_video = value;
2473 MaybeSendOverlayInfoToDecoder();
zqzhang8ac49002017-03-16 21:51:352474}
2475
[email protected]201ce4ba2020-01-09 22:19:092476void WebMediaPlayerImpl::OnPowerExperimentState(bool state) {
2477 if (power_status_helper_)
2478 power_status_helper_->UpdatePowerExperimentState(state);
2479}
2480
watkdee516f2016-02-18 02:22:192481void WebMediaPlayerImpl::ScheduleRestart() {
sandersd50a635e2016-04-04 22:50:092482 // TODO(watk): All restart logic should be moved into PipelineController.
Antonio Gomes81b56552019-05-15 22:15:282483 if (pipeline_controller_->IsPipelineRunning() &&
2484 !pipeline_controller_->IsPipelineSuspended()) {
watkdee516f2016-02-18 02:22:192485 pending_suspend_resume_cycle_ = true;
sandersd50a635e2016-04-04 22:50:092486 UpdatePlayState();
watkdee516f2016-02-18 02:22:192487 }
2488}
2489
Blink Reformat1c4d759e2017-04-09 16:34:542490void WebMediaPlayerImpl::RequestRemotePlaybackDisabled(bool disabled) {
miu77f914c2016-11-19 23:56:182491 if (observer_)
2492 observer_->OnRemotePlaybackDisabled(disabled);
2493}
2494
Thomas Guilbert7350fdad2019-01-29 23:09:242495#if defined(OS_ANDROID)
Thomas Guilbertb341bae02018-05-09 00:02:132496void WebMediaPlayerImpl::FlingingStarted() {
2497 DCHECK(main_task_runner_->BelongsToCurrentThread());
2498 DCHECK(!disable_pipeline_auto_suspend_);
2499 disable_pipeline_auto_suspend_ = true;
2500
Thomas Guilbert29ae1a902018-10-20 01:53:382501 is_flinging_ = true;
2502
Thomas Guilbertb341bae02018-05-09 00:02:132503 // Capabilities reporting should only be performed for local playbacks.
2504 video_decode_stats_reporter_.reset();
2505
2506 // Requests to restart media pipeline. A flinging renderer will be created via
2507 // the |renderer_factory_selector_|.
2508 ScheduleRestart();
2509}
2510
2511void WebMediaPlayerImpl::FlingingStopped() {
2512 DCHECK(main_task_runner_->BelongsToCurrentThread());
2513 DCHECK(disable_pipeline_auto_suspend_);
2514 disable_pipeline_auto_suspend_ = false;
2515
Thomas Guilbert29ae1a902018-10-20 01:53:382516 is_flinging_ = false;
2517
Thomas Guilbertb341bae02018-05-09 00:02:132518 CreateVideoDecodeStatsReporter();
2519
2520 ScheduleRestart();
2521}
Thomas Guilbert901808982019-07-03 20:38:182522
2523void WebMediaPlayerImpl::OnRemotePlayStateChange(MediaStatus::State state) {
2524 DCHECK(is_flinging_);
Thomas Guilbertf6d0702e2019-09-12 23:40:142525 DCHECK(main_task_runner_->BelongsToCurrentThread());
Thomas Guilbert901808982019-07-03 20:38:182526
2527 if (state == MediaStatus::State::PLAYING && Paused()) {
2528 DVLOG(1) << __func__ << " requesting PLAY.";
2529 client_->RequestPlay();
2530 } else if (state == MediaStatus::State::PAUSED && !Paused()) {
2531 DVLOG(1) << __func__ << " requesting PAUSE.";
2532 client_->RequestPause();
2533 }
2534}
Thomas Guilbert7350fdad2019-01-29 23:09:242535#endif // defined(OS_ANDROID)
hubbee4027f92016-05-19 05:18:132536
Blink Reformat1c4d759e2017-04-09 16:34:542537void WebMediaPlayerImpl::SetPoster(const blink::WebURL& poster) {
Dan Sanderscd8981c2017-08-31 22:37:022538 has_poster_ = !poster.IsEmpty();
Dan Sanderscd8981c2017-08-31 22:37:022539}
xjzc102fd82017-01-04 20:13:532540
[email protected]fee8a902014-06-03 13:43:362541void WebMediaPlayerImpl::DataSourceInitialized(bool success) {
pkastingf5279482016-07-27 02:18:202542 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:432543 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]a9415292012-01-19 19:55:202544
Thomas Guilberta8a6e922019-02-01 00:02:472545 if (observer_ && mb_data_source_)
Dale Curtis4841c712018-12-13 18:14:052546 observer_->OnDataSourceInitialized(mb_data_source_->GetUrlAfterRedirects());
Anton Vayvod09fa66e2017-07-20 23:02:122547
[email protected]d250190da3b2012-07-23 22:57:302548 if (!success) {
Blink Reformat1c4d759e2017-04-09 16:34:542549 SetNetworkState(WebMediaPlayer::kNetworkStateFormatError);
Dale Curtis74612b72017-12-14 20:56:192550 media_metrics_provider_->OnError(PIPELINE_ERROR_NETWORK);
sandersd50a635e2016-04-04 22:50:092551
2552 // Not really necessary, since the pipeline was never started, but it at
2553 // least this makes sure that the error handling code is in sync.
2554 UpdatePlayState();
2555
[email protected]a9415292012-01-19 19:55:202556 return;
2557 }
2558
hubbee2cc88c092017-07-14 23:10:412559 // No point in preloading data as we'll probably just throw it away anyways.
Dale Curtis4841c712018-12-13 18:14:052560 if (IsStreaming() && preload_ > MultibufferDataSource::METADATA &&
2561 mb_data_source_) {
2562 mb_data_source_->SetPreload(MultibufferDataSource::METADATA);
hubbee2cc88c092017-07-14 23:10:412563 }
2564
[email protected]ef8394c2013-08-21 20:26:302565 StartPipeline();
[email protected]a9415292012-01-19 19:55:202566}
2567
[email protected]122f40252012-06-12 05:01:562568void WebMediaPlayerImpl::NotifyDownloading(bool is_downloading) {
hubbeb2d3efd2017-05-05 23:26:382569 DVLOG(1) << __func__ << "(" << is_downloading << ")";
Blink Reformat1c4d759e2017-04-09 16:34:542570 if (!is_downloading && network_state_ == WebMediaPlayer::kNetworkStateLoading)
2571 SetNetworkState(WebMediaPlayer::kNetworkStateIdle);
2572 else if (is_downloading &&
2573 network_state_ == WebMediaPlayer::kNetworkStateIdle)
2574 SetNetworkState(WebMediaPlayer::kNetworkStateLoading);
hubbeb2d3efd2017-05-05 23:26:382575 if (ready_state_ == ReadyState::kReadyStateHaveFutureData && !is_downloading)
2576 SetReadyState(WebMediaPlayer::kReadyStateHaveEnoughData);
[email protected]122f40252012-06-12 05:01:562577}
2578
liberato2ff93ad2017-05-17 07:28:242579void WebMediaPlayerImpl::OnOverlayRoutingToken(
2580 const base::UnguessableToken& token) {
2581 DCHECK(overlay_mode_ == OverlayMode::kUseAndroidOverlay);
liberatofe8f9692017-06-08 19:17:362582 // TODO(liberato): |token| should already be a RoutingToken.
2583 overlay_routing_token_is_pending_ = false;
2584 overlay_routing_token_ = OverlayInfo::RoutingToken(token);
liberato2ff93ad2017-05-17 07:28:242585 MaybeSendOverlayInfoToDecoder();
2586}
2587
2588void WebMediaPlayerImpl::OnOverlayInfoRequested(
dalecurtis4b632fce22016-11-10 00:52:172589 bool decoder_requires_restart_for_overlay,
liberato2ff93ad2017-05-17 07:28:242590 const ProvideOverlayInfoCB& provide_overlay_info_cb) {
watkdee516f2016-02-18 02:22:192591 DCHECK(main_task_runner_->BelongsToCurrentThread());
watkdee516f2016-02-18 02:22:192592
Chris Watkins557f84d2017-09-16 02:31:462593 // If we get a non-null cb, a decoder is initializing and requires overlay
2594 // info. If we get a null cb, a previously initialized decoder is
2595 // unregistering for overlay info updates.
Dale Curtise25163812018-09-21 22:13:392596 if (!provide_overlay_info_cb) {
tsunghungee562e92016-07-20 18:03:312597 decoder_requires_restart_for_overlay_ = false;
liberato2ff93ad2017-05-17 07:28:242598 provide_overlay_info_cb_.Reset();
watkdee516f2016-02-18 02:22:192599 return;
2600 }
2601
dalecurtis4b632fce22016-11-10 00:52:172602 // If |decoder_requires_restart_for_overlay| is true, we must restart the
2603 // pipeline for fullscreen transitions. The decoder is unable to switch
2604 // surfaces otherwise. If false, we simply need to tell the decoder about the
2605 // new surface and it will handle things seamlessly.
Chris Watkins557f84d2017-09-16 02:31:462606 // For encrypted video we pretend that the decoder doesn't require a restart
2607 // because it needs an overlay all the time anyway. We'll switch into
2608 // |always_enable_overlays_| mode below.
2609 decoder_requires_restart_for_overlay_ =
2610 (overlay_mode_ == OverlayMode::kUseAndroidOverlay && is_encrypted_)
2611 ? false
2612 : decoder_requires_restart_for_overlay;
liberato2ff93ad2017-05-17 07:28:242613 provide_overlay_info_cb_ = provide_overlay_info_cb;
dalecurtis4b632fce22016-11-10 00:52:172614
Chris Watkins557f84d2017-09-16 02:31:462615 // If the decoder doesn't require restarts for surface transitions, and we're
2616 // using AndroidOverlay mode, we can always enable the overlay and the decoder
2617 // can choose whether or not to use it. Otherwise, we'll restart the decoder
2618 // and enable the overlay on fullscreen transitions.
[email protected]77568482017-06-21 21:16:522619 if (overlay_mode_ == OverlayMode::kUseAndroidOverlay &&
Chris Watkins557f84d2017-09-16 02:31:462620 !decoder_requires_restart_for_overlay_) {
[email protected]c8d574722017-08-30 20:53:432621 always_enable_overlays_ = true;
[email protected]77568482017-06-21 21:16:522622 if (!overlay_enabled_)
2623 EnableOverlay();
2624 }
2625
Chris Watkins557f84d2017-09-16 02:31:462626 // Send the overlay info if we already have it. If not, it will be sent later.
liberato2ff93ad2017-05-17 07:28:242627 MaybeSendOverlayInfoToDecoder();
2628}
2629
2630void WebMediaPlayerImpl::MaybeSendOverlayInfoToDecoder() {
2631 // If the decoder didn't request overlay info, then don't send it.
2632 if (!provide_overlay_info_cb_)
dalecurtis4b632fce22016-11-10 00:52:172633 return;
2634
liberato2ff93ad2017-05-17 07:28:242635 // We should send the overlay info as long as we know it. This includes the
2636 // case where |!overlay_enabled_|, since we want to tell the decoder to avoid
2637 // using overlays. Assuming that the decoder has requested info, the only
2638 // case in which we don't want to send something is if we've requested the
2639 // info but not received it yet. Then, we should wait until we do.
liberatofe8f9692017-06-08 19:17:362640 //
2641 // Initialization requires this; AVDA should start with enough info to make an
2642 // overlay, so that (pre-M) the initial codec is created with the right output
2643 // surface; it can't switch later.
[email protected]f7df5b342018-07-13 20:22:132644 if (overlay_mode_ == OverlayMode::kUseAndroidOverlay) {
liberatofe8f9692017-06-08 19:17:362645 if (overlay_routing_token_is_pending_)
liberato2ff93ad2017-05-17 07:28:242646 return;
liberatofe8f9692017-06-08 19:17:362647
2648 overlay_info_.routing_token = overlay_routing_token_;
liberato2ff93ad2017-05-17 07:28:242649 }
2650
liberato2ff93ad2017-05-17 07:28:242651 // If restart is required, the callback is one-shot only.
2652 if (decoder_requires_restart_for_overlay_) {
Dale Curtise25163812018-09-21 22:13:392653 std::move(provide_overlay_info_cb_).Run(overlay_info_);
liberato2ff93ad2017-05-17 07:28:242654 } else {
liberatofe8f9692017-06-08 19:17:362655 provide_overlay_info_cb_.Run(overlay_info_);
liberato2ff93ad2017-05-17 07:28:242656 }
watkdee516f2016-02-18 02:22:192657}
2658
Xiaohan Wangcd4df0a2019-12-04 20:59:242659std::unique_ptr<Renderer> WebMediaPlayerImpl::CreateRenderer(
Xiaohan Wang48aaa192019-12-05 01:29:002660 base::Optional<RendererFactoryType> factory_type) {
dcheng37b415b92017-01-27 20:17:432661 DCHECK(main_task_runner_->BelongsToCurrentThread());
2662
[email protected]c8d574722017-08-30 20:53:432663 // Make sure that overlays are enabled if they're always allowed.
2664 if (always_enable_overlays_)
tsunghungee562e92016-07-20 18:03:312665 EnableOverlay();
2666
liberato2ff93ad2017-05-17 07:28:242667 RequestOverlayInfoCB request_overlay_info_cb;
watkdee516f2016-02-18 02:22:192668#if defined(OS_ANDROID)
liberato2ff93ad2017-05-17 07:28:242669 request_overlay_info_cb = BindToCurrentLoop(
Antonio Gomes142f32a2019-05-15 23:32:562670 base::Bind(&WebMediaPlayerImpl::OnOverlayInfoRequested, weak_this_));
watkdee516f2016-02-18 02:22:192671#endif
Xiaohan Wangcd4df0a2019-12-04 20:59:242672
2673 if (factory_type) {
Xiaohan Wang48aaa192019-12-05 01:29:002674 DVLOG(1) << __func__
2675 << ": factory_type=" << static_cast<int>(factory_type.value());
Xiaohan Wangcd4df0a2019-12-04 20:59:242676 renderer_factory_selector_->SetBaseFactoryType(factory_type.value());
2677 }
2678
Dan Sanders6edfd782019-08-13 00:13:182679 reported_renderer_type_ = renderer_factory_selector_->GetCurrentFactoryType();
Xiaohan Wang73b433f2019-11-05 20:13:012680
Xiaohan Wang2480de72019-11-15 01:44:472681 return renderer_factory_selector_->GetCurrentFactory()->CreateRenderer(
2682 media_task_runner_, worker_task_runner_, audio_source_provider_.get(),
2683 compositor_.get(), request_overlay_info_cb, client_->TargetColorSpace());
sandersd1e49fb62015-12-12 01:18:062684}
2685
[email protected]ef8394c2013-08-21 20:26:302686void WebMediaPlayerImpl::StartPipeline() {
acolwellb4034942014-08-28 15:42:432687 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]ddbc6ff2013-04-19 15:28:332688
xhwange8c4181a2014-12-06 08:10:012689 Demuxer::EncryptedMediaInitDataCB encrypted_media_init_data_cb =
dcheng37b415b92017-01-27 20:17:432690 BindToCurrentLoop(base::Bind(
Antonio Gomes142f32a2019-05-15 23:32:562691 &WebMediaPlayerImpl::OnEncryptedMediaInitData, weak_this_));
[email protected]2b57e2e2014-05-09 11:07:252692
Dale Curtis3899090ea2018-01-12 00:10:352693 vfc_task_runner_->PostTask(
2694 FROM_HERE,
2695 base::BindOnce(&VideoFrameCompositor::SetOnNewProcessedFrameCallback,
2696 base::Unretained(compositor_.get()),
2697 BindToCurrentLoop(base::BindOnce(
Antonio Gomes142f32a2019-05-15 23:32:562698 &WebMediaPlayerImpl::OnFirstFrame, weak_this_))));
Dale Curtis3899090ea2018-01-12 00:10:352699
Thomas Guilbert55b48d92019-03-25 23:16:542700#if defined(OS_ANDROID)
Dale Curtis65c151a2019-02-26 02:09:322701 if (demuxer_found_hls_ ||
2702 renderer_factory_selector_->GetCurrentFactory()
2703 ->GetRequiredMediaResourceType() == MediaResource::Type::URL) {
Thomas Guilbert8a42fcf2019-03-01 20:21:452704 // MediaPlayerRendererClientFactory is the only factory that a uses
2705 // MediaResource::Type::URL for the moment.
tguilbert75e2bf62017-04-26 20:13:122706 using_media_player_renderer_ = true;
2707
Chris Cunninghamd9df58e2017-08-29 00:04:232708 // MediaPlayerRenderer does not provide pipeline stats, so nuke capabilities
2709 // reporter.
2710 video_decode_stats_reporter_.reset();
2711
Thomas Guilbert55b48d92019-03-25 23:16:542712 demuxer_.reset(new MediaUrlDemuxer(
Maks Orlovichab27e242020-01-07 18:10:392713 media_task_runner_, loaded_url_,
2714 frame_->GetDocument().SiteForCookies().RepresentativeUrl(),
Christian Dullweberacff9bd32019-08-20 09:44:372715 frame_->GetDocument().TopFrameOrigin(),
Dan Sanders3ff9ffe2019-07-19 22:24:122716 allow_media_player_renderer_credentials_, demuxer_found_hls_));
Antonio Gomes81b56552019-05-15 22:15:282717 pipeline_controller_->Start(Pipeline::StartType::kNormal, demuxer_.get(),
2718 this, false, false);
tguilbert25a4d112016-10-13 21:56:512719 return;
2720 }
Thomas Guilbert55b48d92019-03-25 23:16:542721#endif // defined(OS_ANDROID)
tguilbert25a4d112016-10-13 21:56:512722
[email protected]ddbc6ff2013-04-19 15:28:332723 // Figure out which demuxer to use.
Blink Reformat1c4d759e2017-04-09 16:34:542724 if (load_type_ != kLoadTypeMediaSource) {
[email protected]ddbc6ff2013-04-19 15:28:332725 DCHECK(!chunk_demuxer_);
[email protected]f5443ef72013-04-22 04:03:382726 DCHECK(data_source_);
2727
Dale Curtisbcf523b2018-01-17 02:59:012728#if BUILDFLAG(ENABLE_FFMPEG)
servolk81e01e02016-03-05 03:29:152729 Demuxer::MediaTracksUpdatedCB media_tracks_updated_cb =
dcheng37b415b92017-01-27 20:17:432730 BindToCurrentLoop(base::Bind(
Antonio Gomes142f32a2019-05-15 23:32:562731 &WebMediaPlayerImpl::OnFFmpegMediaTracksUpdated, weak_this_));
servolk81e01e02016-03-05 03:29:152732
dalecurtis9cddc0b2017-04-19 21:23:382733 demuxer_.reset(new FFmpegDemuxer(
2734 media_task_runner_, data_source_.get(), encrypted_media_init_data_cb,
Dale Curtisb8139f72018-08-27 23:28:482735 media_tracks_updated_cb, media_log_.get(), IsLocalFile(loaded_url_)));
j.isorcef6778e652015-11-16 17:14:252736#else
alokp967c902452016-05-06 05:21:372737 OnError(PipelineStatus::DEMUXER_ERROR_COULD_NOT_OPEN);
j.isorcef6778e652015-11-16 17:14:252738 return;
2739#endif
[email protected]ddbc6ff2013-04-19 15:28:332740 } else {
[email protected]f5443ef72013-04-22 04:03:382741 DCHECK(!chunk_demuxer_);
2742 DCHECK(!data_source_);
2743
Antonio Gomes142f32a2019-05-15 23:32:562744 chunk_demuxer_ =
2745 new ChunkDemuxer(BindToCurrentLoop(base::Bind(
2746 &WebMediaPlayerImpl::OnDemuxerOpened, weak_this_)),
2747 BindToCurrentLoop(base::Bind(
2748 &WebMediaPlayerImpl::OnProgress, weak_this_)),
2749 encrypted_media_init_data_cb, media_log_.get());
[email protected]f5443ef72013-04-22 04:03:382750 demuxer_.reset(chunk_demuxer_);
servolkf94b4602017-01-31 16:44:272751
2752 if (base::FeatureList::IsEnabled(kMemoryPressureBasedSourceBufferGC)) {
2753 // base::Unretained is safe because |this| owns memory_pressure_listener_.
2754 memory_pressure_listener_ =
Gyuyoung Kim62a5de42018-01-10 09:48:422755 std::make_unique<base::MemoryPressureListener>(base::Bind(
servolkf94b4602017-01-31 16:44:272756 &WebMediaPlayerImpl::OnMemoryPressure, base::Unretained(this)));
2757 }
[email protected]ddbc6ff2013-04-19 15:28:332758 }
2759
sandersdb5e21462016-03-09 01:49:072760 // TODO(sandersd): FileSystem objects may also be non-static, but due to our
2761 // caching layer such situations are broken already. http://crbug.com/593159
2762 bool is_static = !chunk_demuxer_;
avayvod102cdb62017-01-07 03:11:092763 bool is_streaming = IsStreaming();
sandersdb8eb5f1d2016-11-19 04:04:022764 UMA_HISTOGRAM_BOOLEAN("Media.IsStreaming", is_streaming);
sandersdb5e21462016-03-09 01:49:072765
Dale Curtis2dc6089a2018-03-26 16:47:582766 // If possible attempt to avoid decoder spool up until playback starts.
2767 Pipeline::StartType start_type = Pipeline::StartType::kNormal;
Dale Curtis7c63f2e22018-09-19 21:06:272768 if (!chunk_demuxer_ && preload_ == MultibufferDataSource::METADATA &&
Dale Curtisd6ccd1992019-04-29 19:03:462769 !client_->CouldPlayIfEnoughData() && !IsStreaming()) {
Dale Curtis7c63f2e22018-09-19 21:06:272770 start_type =
2771 (has_poster_ || base::FeatureList::IsEnabled(kPreloadMetadataLazyLoad))
2772 ? Pipeline::StartType::kSuspendAfterMetadata
2773 : Pipeline::StartType::kSuspendAfterMetadataForAudioOnly;
Dale Curtis2dc6089a2018-03-26 16:47:582774 attempting_suspended_start_ = true;
2775 }
2776
[email protected]f5443ef72013-04-22 04:03:382777 // ... and we're ready to go!
sandersd1e49fb62015-12-12 01:18:062778 // TODO(sandersd): On Android, defer Start() if the tab is not visible.
sandersdb8eb5f1d2016-11-19 04:04:022779 seeking_ = true;
Antonio Gomes81b56552019-05-15 22:15:282780 pipeline_controller_->Start(start_type, demuxer_.get(), this, is_streaming,
2781 is_static);
[email protected]f5443ef72013-04-22 04:03:382782}
2783
2784void WebMediaPlayerImpl::SetNetworkState(WebMediaPlayer::NetworkState state) {
pkastingf5279482016-07-27 02:18:202785 DVLOG(1) << __func__ << "(" << state << ")";
acolwellb4034942014-08-28 15:42:432786 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]f5443ef72013-04-22 04:03:382787 network_state_ = state;
2788 // Always notify to ensure client has the latest value.
Blink Reformat1c4d759e2017-04-09 16:34:542789 client_->NetworkStateChanged();
[email protected]f5443ef72013-04-22 04:03:382790}
2791
2792void WebMediaPlayerImpl::SetReadyState(WebMediaPlayer::ReadyState state) {
pkastingf5279482016-07-27 02:18:202793 DVLOG(1) << __func__ << "(" << state << ")";
acolwellb4034942014-08-28 15:42:432794 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]f5443ef72013-04-22 04:03:382795
Blink Reformat1c4d759e2017-04-09 16:34:542796 if (state == WebMediaPlayer::kReadyStateHaveEnoughData && data_source_ &&
Dale Curtis4841c712018-12-13 18:14:052797 data_source_->AssumeFullyBuffered() &&
2798 network_state_ == WebMediaPlayer::kNetworkStateLoading) {
Blink Reformat1c4d759e2017-04-09 16:34:542799 SetNetworkState(WebMediaPlayer::kNetworkStateLoaded);
Dale Curtis4841c712018-12-13 18:14:052800 }
[email protected]f5443ef72013-04-22 04:03:382801
2802 ready_state_ = state;
sandersd50a635e2016-04-04 22:50:092803 highest_ready_state_ = std::max(highest_ready_state_, ready_state_);
2804
[email protected]f5443ef72013-04-22 04:03:382805 // Always notify to ensure client has the latest value.
Blink Reformat1c4d759e2017-04-09 16:34:542806 client_->ReadyStateChanged();
[email protected]f5443ef72013-04-22 04:03:382807}
2808
Antonio Gomesa38bb7cb2019-05-31 03:02:522809scoped_refptr<blink::WebAudioSourceProviderImpl>
2810WebMediaPlayerImpl::GetAudioSourceProvider() {
2811 return audio_source_provider_;
[email protected]f5443ef72013-04-22 04:03:382812}
2813
Jiajia Qin82acdc02017-07-31 09:55:142814scoped_refptr<VideoFrame> WebMediaPlayerImpl::GetCurrentFrameFromCompositor()
2815 const {
xhwang213e50c2016-10-10 23:56:312816 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]dd061e12014-05-06 19:21:222817 TRACE_EVENT0("media", "WebMediaPlayerImpl::GetCurrentFrameFromCompositor");
xhwang213e50c2016-10-10 23:56:312818
Thomas Guilberte90fe312019-11-07 22:27:562819 if (current_frame_override_)
2820 return current_frame_override_;
2821
Thomas Guilbertd85407412017-11-08 05:03:462822 // Can be null.
2823 scoped_refptr<VideoFrame> video_frame =
2824 compositor_->GetCurrentFrameOnAnyThread();
[email protected]dd061e12014-05-06 19:21:222825
Thomas Guilbertd85407412017-11-08 05:03:462826 // base::Unretained is safe here because |compositor_| is destroyed on
2827 // |vfc_task_runner_|. The destruction is queued from |this|' destructor,
2828 // which also runs on |main_task_runner_|, which makes it impossible for
2829 // UpdateCurrentFrameIfStale() to be queued after |compositor_|'s dtor.
CJ DiMeglio2302d202017-08-31 08:38:042830 vfc_task_runner_->PostTask(
Dale Curtisee9be30012018-09-21 22:21:512831 FROM_HERE,
2832 base::BindOnce(&VideoFrameCompositor::UpdateCurrentFrameIfStale,
2833 base::Unretained(compositor_.get())));
kainino36eeff82017-03-30 00:55:302834
[email protected]dd061e12014-05-06 19:21:222835 return video_frame;
2836}
2837
sandersd50a635e2016-04-04 22:50:092838void WebMediaPlayerImpl::UpdatePlayState() {
xhwang213e50c2016-10-10 23:56:312839 DCHECK(main_task_runner_->BelongsToCurrentThread());
hubbee2cc88c092017-07-14 23:10:412840 bool can_auto_suspend = !disable_pipeline_auto_suspend_;
2841 // For streaming videos, we only allow suspending at the very beginning of the
2842 // video, and only if we know the length of the video. (If we don't know
2843 // the length, it might be a dynamically generated video, and suspending
2844 // will not work at all.)
2845 if (IsStreaming()) {
2846 bool at_beginning =
2847 ready_state_ == WebMediaPlayer::kReadyStateHaveNothing ||
2848 CurrentTime() == 0.0;
2849 if (!at_beginning || GetPipelineMediaDuration() == kInfiniteDuration)
2850 can_auto_suspend = false;
2851 }
xhwang213e50c2016-10-10 23:56:312852
Antonio Gomes81b56552019-05-15 22:15:282853 bool is_suspended = pipeline_controller_->IsSuspended();
Sergey Volk8b09c2c52018-12-12 23:20:402854 bool is_backgrounded = IsBackgroundSuspendEnabled(this) && IsHidden();
sandersdaaff1a652016-11-17 01:47:252855 PlayState state = UpdatePlayState_ComputePlayState(
Thomas Guilbert7350fdad2019-01-29 23:09:242856 is_flinging_, can_auto_suspend, is_suspended, is_backgrounded);
sandersd35d2c3f2017-01-14 02:04:422857 SetDelegateState(state.delegate_state, state.is_idle);
sandersd50a635e2016-04-04 22:50:092858 SetMemoryReportingState(state.is_memory_reporting_enabled);
2859 SetSuspendState(state.is_suspended || pending_suspend_resume_cycle_);
[email protected]dc996312019-12-19 19:26:382860 if (power_status_helper_) {
2861 // Make sure that we're in something like steady-state before recording.
2862 power_status_helper_->SetIsPlaying(
2863 !paused_ && !seeking_ && !IsHidden() && !state.is_suspended &&
2864 ready_state_ == kReadyStateHaveEnoughData);
2865 }
[email protected]91379332020-01-26 03:58:202866 UpdateSmoothnessHelper();
sandersd50a635e2016-04-04 22:50:092867}
dalecurtis5bbc487e2016-02-27 04:15:052868
Becca Hughes7a85bf22019-07-24 16:16:582869void WebMediaPlayerImpl::UpdateMediaPositionState() {
2870 DCHECK(delegate_);
2871
2872 // When seeking the current time can go beyond the duration so we should
2873 // cap the current time at the duration.
2874 base::TimeDelta duration = GetPipelineMediaDuration();
2875 base::TimeDelta current_time = GetCurrentTimeInternal();
2876 if (current_time > duration)
2877 current_time = duration;
2878
2879 media_session::MediaPosition new_position(paused_ ? 0.0 : playback_rate_,
2880 duration, current_time);
2881
2882 if (media_position_state_ == new_position)
2883 return;
2884
2885 DVLOG(2) << __func__ << "(" << new_position.ToString() << ")";
2886 media_position_state_ = new_position;
2887 delegate_->DidPlayerMediaPositionStateChange(delegate_id_,
2888 media_position_state_);
2889}
2890
sandersd35d2c3f2017-01-14 02:04:422891void WebMediaPlayerImpl::SetDelegateState(DelegateState new_state,
2892 bool is_idle) {
tguilbert1bb1c782017-01-23 21:15:112893 DCHECK(delegate_);
Dale Curtis779ed842018-03-10 06:20:132894 DVLOG(2) << __func__ << "(" << static_cast<int>(new_state) << ", " << is_idle
2895 << ")";
dalecurtis5bbc487e2016-02-27 04:15:052896
sandersd35d2c3f2017-01-14 02:04:422897 // Prevent duplicate delegate calls.
2898 // TODO(sandersd): Move this deduplication into the delegate itself.
2899 // TODO(sandersd): WebContentsObserverSanityChecker does not allow sending the
2900 // 'playing' IPC more than once in a row, even if the metadata has changed.
2901 // Figure out whether it should.
Mounir Lamouri366dd8472018-06-19 17:20:042902 // Pretend that the media has no audio if it never played unmuted. This is to
2903 // avoid any action related to audible media such as taking audio focus or
2904 // showing a media notification. To preserve a consistent experience, it does
2905 // not apply if a media was audible so the system states do not flicker
2906 // depending on whether the user muted the player.
2907 bool has_audio = HasAudio() && !client_->WasAlwaysMuted();
sandersd35d2c3f2017-01-14 02:04:422908 if (delegate_state_ == new_state &&
2909 (delegate_state_ != DelegateState::PLAYING ||
2910 delegate_has_audio_ == has_audio)) {
2911 return;
mlamouri910111362016-11-04 11:28:242912 }
sandersd50a635e2016-04-04 22:50:092913 delegate_state_ = new_state;
sandersd35d2c3f2017-01-14 02:04:422914 delegate_has_audio_ = has_audio;
sandersd50a635e2016-04-04 22:50:092915
sandersd35d2c3f2017-01-14 02:04:422916 switch (new_state) {
sandersd50a635e2016-04-04 22:50:092917 case DelegateState::GONE:
2918 delegate_->PlayerGone(delegate_id_);
2919 break;
mlamouri910111362016-11-04 11:28:242920 case DelegateState::PLAYING: {
peconn257951522017-06-09 18:24:592921 if (HasVideo())
2922 delegate_->DidPlayerSizeChange(delegate_id_, NaturalSize());
zqzhang5d8eab72016-08-26 20:34:302923 delegate_->DidPlay(
Blink Reformat1c4d759e2017-04-09 16:34:542924 delegate_id_, HasVideo(), has_audio,
Dale Curtisca1b78f2019-01-15 03:11:262925 DurationToMediaContentType(GetPipelineMediaDuration()));
sandersd50a635e2016-04-04 22:50:092926 break;
mlamouri910111362016-11-04 11:28:242927 }
sandersd50a635e2016-04-04 22:50:092928 case DelegateState::PAUSED:
sandersd35d2c3f2017-01-14 02:04:422929 delegate_->DidPause(delegate_id_);
sandersd50a635e2016-04-04 22:50:092930 break;
dalecurtis0f0097a2015-12-01 17:40:472931 }
sandersd35d2c3f2017-01-14 02:04:422932
2933 delegate_->SetIdle(delegate_id_, is_idle);
dalecurtis0f0097a2015-12-01 17:40:472934}
2935
sandersd50a635e2016-04-04 22:50:092936void WebMediaPlayerImpl::SetMemoryReportingState(
2937 bool is_memory_reporting_enabled) {
2938 if (memory_usage_reporting_timer_.IsRunning() ==
2939 is_memory_reporting_enabled) {
hubbed5f36882016-01-15 22:40:372940 return;
sandersd50a635e2016-04-04 22:50:092941 }
sandersd1c0bba02016-03-04 23:14:082942
sandersd50a635e2016-04-04 22:50:092943 if (is_memory_reporting_enabled) {
2944 memory_usage_reporting_timer_.Start(FROM_HERE,
2945 base::TimeDelta::FromSeconds(2), this,
2946 &WebMediaPlayerImpl::ReportMemoryUsage);
2947 } else {
2948 memory_usage_reporting_timer_.Stop();
2949 ReportMemoryUsage();
2950 }
2951}
2952
2953void WebMediaPlayerImpl::SetSuspendState(bool is_suspended) {
xhwang213e50c2016-10-10 23:56:312954 DCHECK(main_task_runner_->BelongsToCurrentThread());
Dale Curtis779ed842018-03-10 06:20:132955 DVLOG(2) << __func__ << "(" << is_suspended << ")";
xhwang213e50c2016-10-10 23:56:312956
sandersd50a635e2016-04-04 22:50:092957 // Do not change the state after an error has occurred.
2958 // TODO(sandersd): Update PipelineController to remove the need for this.
2959 if (IsNetworkStateError(network_state_))
sandersd1c0bba02016-03-04 23:14:082960 return;
2961
jameswest451a5bb2017-01-27 03:59:392962 if (is_suspended) {
sandersd35d2c3f2017-01-14 02:04:422963 // If we were not resumed for long enough to satisfy the preroll attempt,
2964 // reset the clock.
2965 if (!preroll_attempt_pending_ && IsPrerollAttemptNeeded()) {
2966 preroll_attempt_pending_ = true;
2967 preroll_attempt_start_time_ = base::TimeTicks();
2968 }
Antonio Gomes81b56552019-05-15 22:15:282969 pipeline_controller_->Suspend();
sandersd50a635e2016-04-04 22:50:092970 } else {
sandersd35d2c3f2017-01-14 02:04:422971 // When resuming, start the preroll attempt clock.
2972 if (preroll_attempt_pending_) {
2973 preroll_attempt_pending_ = false;
2974 preroll_attempt_start_time_ = tick_clock_->NowTicks();
2975 }
Antonio Gomes81b56552019-05-15 22:15:282976 pipeline_controller_->Resume();
sandersd50a635e2016-04-04 22:50:092977 }
2978}
2979
2980WebMediaPlayerImpl::PlayState
Thomas Guilbert7350fdad2019-01-29 23:09:242981WebMediaPlayerImpl::UpdatePlayState_ComputePlayState(bool is_flinging,
xjz4e5d4bf32017-02-15 21:26:352982 bool can_auto_suspend,
dalecurtis8b8505e72016-06-10 21:59:172983 bool is_suspended,
sandersd50a635e2016-04-04 22:50:092984 bool is_backgrounded) {
2985 PlayState result;
2986
tguilbert1bb1c782017-01-23 21:15:112987 bool must_suspend = delegate_->IsFrameClosed();
Dale Curtis6438cf12018-03-29 02:34:012988 bool is_stale = delegate_->IsStale(delegate_id_);
2989
2990 if (stale_state_override_for_testing_.has_value() &&
2991 ready_state_ >= stale_state_override_for_testing_.value()) {
2992 is_stale = true;
2993 }
sandersd35d2c3f2017-01-14 02:04:422994
sandersd50a635e2016-04-04 22:50:092995 // This includes both data source (before pipeline startup) and pipeline
2996 // errors.
2997 bool has_error = IsNetworkStateError(network_state_);
2998
Dale Curtisc56158c2019-09-09 23:00:322999 // Note: Even though we get play/pause signals at kReadyStateHaveMetadata, we
3000 // must attempt to preroll until kReadyStateHaveFutureData so that the
3001 // canplaythrough event will be fired to the page (which may be waiting).
3002 bool have_future_data =
3003 highest_ready_state_ >= WebMediaPlayer::kReadyStateHaveFutureData;
sandersd50a635e2016-04-04 22:50:093004
avayvod65fad272017-02-24 01:00:483005 // Background suspend is only enabled for paused players.
3006 // In the case of players with audio the session should be kept.
3007 bool background_suspended =
Dale Curtisc56158c2019-09-09 23:00:323008 can_auto_suspend && is_backgrounded && paused_ && have_future_data;
sandersd50a635e2016-04-04 22:50:093009
Dale Curtisd71061f02019-05-21 21:33:543010 // Idle suspension is allowed prior to kReadyStateHaveMetadata since there
3011 // exist mechanisms to exit the idle state when the player is capable of
3012 // reaching the kReadyStateHaveMetadata state; see didLoadingProgress().
dalecurtiscc8baf72016-10-27 01:49:443013 //
sandersd50a635e2016-04-04 22:50:093014 // TODO(sandersd): Make the delegate suspend idle players immediately when
3015 // hidden.
Dale Curtis7c63f2e22018-09-19 21:06:273016 bool idle_suspended = can_auto_suspend && is_stale && paused_ && !seeking_ &&
3017 !overlay_enabled_ && !needs_first_frame_;
dalecurtise7120dc2016-09-03 02:54:353018
3019 // If we're already suspended, see if we can wait for user interaction. Prior
Dale Curtisd71061f02019-05-21 21:33:543020 // to kReadyStateHaveMetadata, we require |is_stale| to remain suspended.
3021 // |is_stale| will be cleared when we receive data which may take us to
3022 // kReadyStateHaveMetadata.
Dale Curtisc56158c2019-09-09 23:00:323023 bool can_stay_suspended = (is_stale || have_future_data) && is_suspended &&
Dale Curtis7c63f2e22018-09-19 21:06:273024 paused_ && !seeking_ && !needs_first_frame_;
sandersd50a635e2016-04-04 22:50:093025
3026 // Combined suspend state.
Thomas Guilbert7350fdad2019-01-29 23:09:243027 result.is_suspended = must_suspend || idle_suspended ||
avayvod65fad272017-02-24 01:00:483028 background_suspended || can_stay_suspended;
sandersd50a635e2016-04-04 22:50:093029
Thomas Guilbert7350fdad2019-01-29 23:09:243030 DVLOG(3) << __func__ << ": must_suspend=" << must_suspend
Dale Curtis779ed842018-03-10 06:20:133031 << ", idle_suspended=" << idle_suspended
3032 << ", background_suspended=" << background_suspended
3033 << ", can_stay_suspended=" << can_stay_suspended
Dale Curtisc56158c2019-09-09 23:00:323034 << ", is_stale=" << is_stale
3035 << ", have_future_data=" << have_future_data
Dale Curtis779ed842018-03-10 06:20:133036 << ", paused_=" << paused_ << ", seeking_=" << seeking_;
3037
sandersd50a635e2016-04-04 22:50:093038 // We do not treat |playback_rate_| == 0 as paused. For the media session,
3039 // being paused implies displaying a play button, which is incorrect in this
3040 // case. For memory usage reporting, we just use the same definition (but we
3041 // don't have to).
3042 //
3043 // Similarly, we don't consider |ended_| to be paused. Blink will immediately
3044 // call pause() or seek(), so |ended_| should not affect the computation.
3045 // Despite that, |ended_| does result in a separate paused state, to simplfy
3046 // the contract for SetDelegateState().
3047 //
avayvod65fad272017-02-24 01:00:483048 // |has_remote_controls| indicates if the player can be controlled outside the
3049 // page (e.g. via the notification controls or by audio focus events). Idle
sandersd50a635e2016-04-04 22:50:093050 // suspension does not destroy the media session, because we expect that the
avayvod5f34b642017-03-23 03:14:043051 // notification controls (and audio focus) remain. With some exceptions for
3052 // background videos, the player only needs to have audio to have controls
Dale Curtisd71061f02019-05-21 21:33:543053 // (requires |have_current_data|).
avayvod5f34b642017-03-23 03:14:043054 //
3055 // |alive| indicates if the player should be present (not |GONE|) to the
3056 // delegate, either paused or playing. The following must be true for the
3057 // player:
Dale Curtisd71061f02019-05-21 21:33:543058 // - |have_current_data|, since playback can't begin before that point, we
3059 // need to know whether we are paused to correctly configure the session,
3060 // and also because the tracks and duration are passed to DidPlay(),
Thomas Guilbert7350fdad2019-01-29 23:09:243061 // - |is_flinging| is false (RemotePlayback is not handled by the delegate)
avayvod5f34b642017-03-23 03:14:043062 // - |has_error| is false as player should have no errors,
3063 // - |background_suspended| is false, otherwise |has_remote_controls| must
3064 // be true.
sandersd50a635e2016-04-04 22:50:093065 //
avayvod65fad272017-02-24 01:00:483066 // TODO(sandersd): If Blink told us the paused state sooner, we could detect
3067 // if the remote controls are available sooner.
3068
3069 // Background videos with audio don't have remote controls if background
3070 // suspend is enabled and resuming background videos is not (original Android
3071 // behavior).
3072 bool backgrounded_video_has_no_remote_controls =
Sergey Volk8b09c2c52018-12-12 23:20:403073 IsBackgroundSuspendEnabled(this) && !IsResumeBackgroundVideosEnabled() &&
3074 is_backgrounded && HasVideo();
Dale Curtisd71061f02019-05-21 21:33:543075 bool have_current_data = highest_ready_state_ >= kReadyStateHaveCurrentData;
3076 bool can_play = !has_error && have_current_data;
avayvod5f34b642017-03-23 03:14:043077 bool has_remote_controls =
Blink Reformat1c4d759e2017-04-09 16:34:543078 HasAudio() && !backgrounded_video_has_no_remote_controls;
Thomas Guilbert7350fdad2019-01-29 23:09:243079 bool alive = can_play && !is_flinging && !must_suspend &&
avayvod5f34b642017-03-23 03:14:043080 (!background_suspended || has_remote_controls);
3081 if (!alive) {
Thomas Guilbert4c6feff2018-11-09 19:53:323082 // Do not mark players as idle when flinging.
sandersd50a635e2016-04-04 22:50:093083 result.delegate_state = DelegateState::GONE;
Thomas Guilbert4c6feff2018-11-09 19:53:323084 result.is_idle = delegate_->IsIdle(delegate_id_) && !is_flinging;
avayvod65fad272017-02-24 01:00:483085 } else if (paused_) {
sandersd35d2c3f2017-01-14 02:04:423086 // TODO(sandersd): Is it possible to have a suspended session, be ended,
3087 // and not be paused? If so we should be in a PLAYING state.
dalecurtise7120dc2016-09-03 02:54:353088 result.delegate_state =
sandersd35d2c3f2017-01-14 02:04:423089 ended_ ? DelegateState::GONE : DelegateState::PAUSED;
3090 result.is_idle = !seeking_;
sandersd50a635e2016-04-04 22:50:093091 } else {
3092 result.delegate_state = DelegateState::PLAYING;
sandersd35d2c3f2017-01-14 02:04:423093 result.is_idle = false;
sandersd50a635e2016-04-04 22:50:093094 }
3095
dalecurtis8b8505e72016-06-10 21:59:173096 // It's not critical if some cases where memory usage can change are missed,
sandersd50a635e2016-04-04 22:50:093097 // since media memory changes are usually gradual.
Thomas Guilbert7350fdad2019-01-29 23:09:243098 result.is_memory_reporting_enabled = !has_error && can_play && !is_flinging &&
3099 !result.is_suspended &&
3100 (!paused_ || seeking_);
sandersd50a635e2016-04-04 22:50:093101
3102 return result;
dalecurtis0f0097a2015-12-01 17:40:473103}
3104
dalecurtis83266c72015-10-29 18:43:203105void WebMediaPlayerImpl::ReportMemoryUsage() {
3106 DCHECK(main_task_runner_->BelongsToCurrentThread());
3107
wdzierzanowskifd4cd91c52015-12-02 23:50:203108 // About base::Unretained() usage below: We destroy |demuxer_| on the main
3109 // thread. Before that, however, ~WebMediaPlayerImpl() posts a task to the
3110 // media thread and waits for it to finish. Hence, the GetMemoryUsage() task
3111 // posted here must finish earlier.
Dale Curtis8a6281322017-08-31 00:35:533112 //
3113 // The exception to the above is when OnError() has been called. If we're in
3114 // the error state we've already shut down the pipeline and can't rely on it
3115 // to cycle the media thread before we destroy |demuxer_|. In this case skip
3116 // collection of the demuxer memory stats.
3117 if (demuxer_ && !IsNetworkStateError(network_state_)) {
wdzierzanowskifd4cd91c52015-12-02 23:50:203118 base::PostTaskAndReplyWithResult(
3119 media_task_runner_.get(), FROM_HERE,
Jan Wilken Dörrie2e1d2d9a2020-01-24 17:14:183120 base::BindOnce(&Demuxer::GetMemoryUsage,
3121 base::Unretained(demuxer_.get())),
3122 base::BindOnce(&WebMediaPlayerImpl::FinishMemoryUsageReport,
3123 weak_this_));
wdzierzanowskifd4cd91c52015-12-02 23:50:203124 } else {
3125 FinishMemoryUsageReport(0);
3126 }
3127}
3128
3129void WebMediaPlayerImpl::FinishMemoryUsageReport(int64_t demuxer_memory_usage) {
3130 DCHECK(main_task_runner_->BelongsToCurrentThread());
3131
avayvodc4bfb0e62017-01-13 01:07:013132 const PipelineStatistics stats = GetPipelineStatistics();
servolk639473e492016-12-15 04:14:203133 const int64_t data_source_memory_usage =
3134 data_source_ ? data_source_->GetMemoryUsage() : 0;
dalecurtisecc76612017-04-19 00:31:203135
Dale Curtisc2c5dcb12018-04-16 23:21:293136 // If we have video and no video memory usage and we've rendered the first
3137 // frame, assume the VideoFrameCompositor is holding onto the last frame after
3138 // we've suspended the pipeline; which thus reports zero memory usage from the
3139 // video renderer.
dalecurtisecc76612017-04-19 00:31:203140 //
3141 // Technically this should use the coded size, but that requires us to hop to
3142 // the compositor to get and byte-perfect accuracy isn't important here.
3143 const int64_t video_memory_usage =
3144 stats.video_memory_usage +
Dale Curtisc2c5dcb12018-04-16 23:21:293145 ((pipeline_metadata_.has_video && !stats.video_memory_usage &&
3146 has_first_frame_)
Miguel Casas9e7766022018-01-08 16:13:133147 ? VideoFrame::AllocationSize(PIXEL_FORMAT_I420,
dalecurtisecc76612017-04-19 00:31:203148 pipeline_metadata_.natural_size)
3149 : 0);
3150
dalecurtis83266c72015-10-29 18:43:203151 const int64_t current_memory_usage =
dalecurtisecc76612017-04-19 00:31:203152 stats.audio_memory_usage + video_memory_usage + data_source_memory_usage +
3153 demuxer_memory_usage;
dalecurtis83266c72015-10-29 18:43:203154
dalecurtisecc76612017-04-19 00:31:203155 DVLOG(2) << "Memory Usage -- Total: " << current_memory_usage
3156 << " Audio: " << stats.audio_memory_usage
3157 << ", Video: " << video_memory_usage
servolk639473e492016-12-15 04:14:203158 << ", DataSource: " << data_source_memory_usage
wdzierzanowskifd4cd91c52015-12-02 23:50:203159 << ", Demuxer: " << demuxer_memory_usage;
dalecurtis83266c72015-10-29 18:43:203160
3161 const int64_t delta = current_memory_usage - last_reported_memory_usage_;
3162 last_reported_memory_usage_ = current_memory_usage;
3163 adjust_allocated_memory_cb_.Run(delta);
servolk639473e492016-12-15 04:14:203164
Blink Reformat1c4d759e2017-04-09 16:34:543165 if (HasAudio()) {
servolk639473e492016-12-15 04:14:203166 UMA_HISTOGRAM_MEMORY_KB("Media.WebMediaPlayerImpl.Memory.Audio",
3167 stats.audio_memory_usage / 1024);
3168 }
Blink Reformat1c4d759e2017-04-09 16:34:543169 if (HasVideo()) {
servolk639473e492016-12-15 04:14:203170 UMA_HISTOGRAM_MEMORY_KB("Media.WebMediaPlayerImpl.Memory.Video",
dalecurtisecc76612017-04-19 00:31:203171 video_memory_usage / 1024);
servolk639473e492016-12-15 04:14:203172 }
3173 if (data_source_) {
3174 UMA_HISTOGRAM_MEMORY_KB("Media.WebMediaPlayerImpl.Memory.DataSource",
3175 data_source_memory_usage / 1024);
3176 }
3177 if (demuxer_) {
3178 UMA_HISTOGRAM_MEMORY_KB("Media.WebMediaPlayerImpl.Memory.Demuxer",
3179 demuxer_memory_usage / 1024);
3180 }
dalecurtis83266c72015-10-29 18:43:203181}
3182
dalecurtis8b8505e72016-06-10 21:59:173183void WebMediaPlayerImpl::ScheduleIdlePauseTimer() {
avayvod65fad272017-02-24 01:00:483184 // Only schedule the pause timer if we're not paused or paused but going to
avayvod52efd282017-03-07 21:13:043185 // resume when foregrounded, and are suspended and have audio.
3186 if ((paused_ && !paused_when_hidden_) ||
Antonio Gomes81b56552019-05-15 22:15:283187 !pipeline_controller_->IsSuspended() || !HasAudio()) {
dalecurtis8b8505e72016-06-10 21:59:173188 return;
avayvod52efd282017-03-07 21:13:043189 }
dalecurtis8b8505e72016-06-10 21:59:173190
3191#if defined(OS_ANDROID)
Thomas Guilbert7350fdad2019-01-29 23:09:243192 // Don't pause videos casted as part of RemotePlayback.
3193 if (is_flinging_)
dalecurtis8b8505e72016-06-10 21:59:173194 return;
3195#endif
3196
3197 // Idle timeout chosen arbitrarily.
3198 background_pause_timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(5),
3199 this, &WebMediaPlayerImpl::OnPause);
3200}
3201
dalecurtis04bdb582016-08-17 22:15:233202void WebMediaPlayerImpl::CreateWatchTimeReporter() {
wdzierzanowskia78fa9b2017-06-13 18:12:103203 if (!HasVideo() && !HasAudio())
3204 return;
3205
Dan Sanders7ef5d0f2019-05-03 18:30:113206 // MediaPlayerRenderer does not know about tracks until playback starts.
3207 // Assume audio-only unless the natural size has been detected.
3208 bool has_video = pipeline_metadata_.has_video;
3209 if (using_media_player_renderer_) {
3210 has_video = !pipeline_metadata_.natural_size.IsEmpty();
3211 }
3212
dalecurtis04bdb582016-08-17 22:15:233213 // Create the watch time reporter and synchronize its initial state.
Dale Curtis1adbe6a2017-08-02 02:09:133214 watch_time_reporter_.reset(new WatchTimeReporter(
Dan Sanders7ef5d0f2019-05-03 18:30:113215 mojom::PlaybackProperties::New(
3216 pipeline_metadata_.has_audio, has_video, false, false,
3217 !!chunk_demuxer_, is_encrypted_, embedded_media_experience_enabled_),
Dale Curtis96d6e9382018-07-18 18:01:073218 pipeline_metadata_.natural_size,
Dale Curtis051fdf62017-08-05 00:21:133219 base::BindRepeating(&WebMediaPlayerImpl::GetCurrentTimeInternal,
3220 base::Unretained(this)),
Dale Curtis0f8d7b32019-10-24 22:10:283221 base::BindRepeating(&WebMediaPlayerImpl::GetPipelineStatistics,
3222 base::Unretained(this)),
Hajime Hoshi8bb37dc2017-12-19 09:35:103223 media_metrics_provider_.get(),
Hajime Hoshib5a26ee2018-05-14 12:47:513224 frame_->GetTaskRunner(blink::TaskType::kInternalMedia)));
dalecurtis04bdb582016-08-17 22:15:233225 watch_time_reporter_->OnVolumeChange(volume_);
Dale Curtisaebaeea2018-07-19 23:42:113226 watch_time_reporter_->OnDurationChanged(GetPipelineMediaDuration());
Mounir Lamourif9af74e72017-06-19 19:31:453227
tguilbert1bb1c782017-01-23 21:15:113228 if (delegate_->IsFrameHidden())
dalecurtis04bdb582016-08-17 22:15:233229 watch_time_reporter_->OnHidden();
3230 else
3231 watch_time_reporter_->OnShown();
Mounir Lamourif9af74e72017-06-19 19:31:453232
Mounir Lamouri41a79c62017-06-06 12:53:163233 if (client_->HasNativeControls())
3234 watch_time_reporter_->OnNativeControlsEnabled();
3235 else
3236 watch_time_reporter_->OnNativeControlsDisabled();
Mounir Lamourif9af74e72017-06-19 19:31:453237
3238 switch (client_->DisplayType()) {
3239 case WebMediaPlayer::DisplayType::kInline:
3240 watch_time_reporter_->OnDisplayTypeInline();
3241 break;
3242 case WebMediaPlayer::DisplayType::kFullscreen:
3243 watch_time_reporter_->OnDisplayTypeFullscreen();
3244 break;
3245 case WebMediaPlayer::DisplayType::kPictureInPicture:
3246 watch_time_reporter_->OnDisplayTypePictureInPicture();
3247 break;
3248 }
Dale Curtis96d6e9382018-07-18 18:01:073249
3250 UpdateSecondaryProperties();
Dale Curtis7fd27c4b2018-07-30 22:14:213251
3252 // If the WatchTimeReporter was recreated in the middle of playback, we want
3253 // to resume playback here too since we won't get another play() call. When
3254 // seeking, the seek completion will restart it if necessary.
3255 if (!paused_ && !seeking_)
3256 watch_time_reporter_->OnPlaying();
Dale Curtis96d6e9382018-07-18 18:01:073257}
3258
3259void WebMediaPlayerImpl::UpdateSecondaryProperties() {
3260 watch_time_reporter_->UpdateSecondaryProperties(
3261 mojom::SecondaryPlaybackProperties::New(
3262 pipeline_metadata_.audio_decoder_config.codec(),
Dale Curtis7140b502019-10-23 20:34:423263 pipeline_metadata_.video_decoder_config.codec(),
Dale Curtisf8afcef32020-01-18 06:23:263264 pipeline_metadata_.audio_decoder_config.profile(),
Dale Curtis7140b502019-10-23 20:34:423265 pipeline_metadata_.video_decoder_config.profile(),
3266 audio_decoder_name_, video_decoder_name_,
Yuchen Liub33bfc12019-11-08 20:16:123267 pipeline_metadata_.audio_decoder_config.encryption_scheme(),
3268 pipeline_metadata_.video_decoder_config.encryption_scheme(),
John Rummelld30555352018-09-21 20:47:253269 pipeline_metadata_.natural_size));
dalecurtis04bdb582016-08-17 22:15:233270}
3271
avayvod39c102402016-11-23 21:43:133272bool WebMediaPlayerImpl::IsHidden() const {
3273 DCHECK(main_task_runner_->BelongsToCurrentThread());
3274
tguilbert1bb1c782017-01-23 21:15:113275 return delegate_->IsFrameHidden() && !delegate_->IsFrameClosed();
avayvod39c102402016-11-23 21:43:133276}
3277
avayvod102cdb62017-01-07 03:11:093278bool WebMediaPlayerImpl::IsStreaming() const {
3279 return data_source_ && data_source_->IsStreaming();
3280}
3281
liberato2fd111be2017-01-04 00:25:063282bool WebMediaPlayerImpl::DoesOverlaySupportMetadata() const {
Ted Meyer4a427632019-05-01 19:05:273283 return pipeline_metadata_.video_decoder_config.video_transformation() ==
3284 kNoTransformation;
liberato2fd111be2017-01-04 00:25:063285}
3286
xjzaf29d4182016-12-16 01:52:323287void WebMediaPlayerImpl::ActivateViewportIntersectionMonitoring(bool activate) {
3288 DCHECK(main_task_runner_->BelongsToCurrentThread());
3289
Blink Reformat1c4d759e2017-04-09 16:34:543290 client_->ActivateViewportIntersectionMonitoring(activate);
xjzaf29d4182016-12-16 01:52:323291}
3292
Anton Vayvod09fa66e2017-07-20 23:02:123293void WebMediaPlayerImpl::UpdateRemotePlaybackCompatibility(bool is_compatible) {
3294 DCHECK(main_task_runner_->BelongsToCurrentThread());
3295
3296 client_->RemotePlaybackCompatibilityChanged(loaded_url_, is_compatible);
3297}
3298
Dale Curtis6438cf12018-03-29 02:34:013299void WebMediaPlayerImpl::ForceStaleStateForTesting(ReadyState target_state) {
3300 stale_state_override_for_testing_.emplace(target_state);
Dale Curtis99a9b482018-02-01 02:23:283301 UpdatePlayState();
3302}
3303
3304bool WebMediaPlayerImpl::IsSuspendedForTesting() {
3305 // This intentionally uses IsPipelineSuspended since we need to know when the
3306 // pipeline has reached the suspended state, not when it's in suspending.
Antonio Gomes81b56552019-05-15 22:15:283307 return pipeline_controller_->IsPipelineSuspended();
Dale Curtis99a9b482018-02-01 02:23:283308}
3309
Dale Curtis7c63f2e22018-09-19 21:06:273310bool WebMediaPlayerImpl::DidLazyLoad() const {
3311 return did_lazy_load_;
3312}
3313
3314void WebMediaPlayerImpl::OnBecameVisible() {
Dale Curtis04769ca2019-05-25 00:38:103315 have_enough_after_lazy_load_cb_.Cancel();
Dale Curtis7c63f2e22018-09-19 21:06:273316 needs_first_frame_ = !has_first_frame_;
3317 UpdatePlayState();
3318}
3319
Miguel Casasfb63a5792018-12-04 23:50:413320bool WebMediaPlayerImpl::IsOpaque() const {
3321 return opaque_;
3322}
3323
Mounir Lamouri99ba5a62019-02-12 01:27:473324int WebMediaPlayerImpl::GetDelegateId() {
3325 return delegate_id_;
3326}
3327
3328base::Optional<viz::SurfaceId> WebMediaPlayerImpl::GetSurfaceId() {
3329 if (!surface_layer_for_video_enabled_)
3330 return base::nullopt;
3331 return bridge_->GetSurfaceId();
3332}
3333
Thomas Guilberte90fe312019-11-07 22:27:563334void WebMediaPlayerImpl::RequestAnimationFrame() {
Thomas Guilberte95597002020-02-06 01:08:153335 compositor_->SetOnFramePresentedCallback(BindToCurrentLoop(base::BindOnce(
3336 &WebMediaPlayerImpl::OnNewFramePresentedCallback, weak_this_)));
Thomas Guilberte90fe312019-11-07 22:27:563337}
3338
3339void WebMediaPlayerImpl::OnNewFramePresentedCallback(
3340 scoped_refptr<VideoFrame> presented_frame,
3341 base::TimeTicks presentation_time,
3342 base::TimeTicks expected_presentation_time,
3343 uint32_t presentation_counter) {
3344 current_frame_override_ = std::move(presented_frame);
3345 client_->OnRequestAnimationFrame(
3346 presentation_time, expected_presentation_time, presentation_counter,
3347 *current_frame_override_);
3348 current_frame_override_.reset();
3349}
3350
Antonio Gomes142f32a2019-05-15 23:32:563351base::WeakPtr<blink::WebMediaPlayer> WebMediaPlayerImpl::AsWeakPtr() {
3352 return weak_this_;
3353}
3354
Yuchen Liue7813972019-04-12 22:34:243355bool WebMediaPlayerImpl::ShouldPausePlaybackWhenHidden() const {
3356 // Audio only stream is allowed to play when in background.
3357 // TODO: We should check IsBackgroundOptimizationCandidate here. But we need
3358 // to move the logic of checking video frames out of that function.
3359 if (!HasVideo())
3360 return false;
3361
Junbo Kefba620b2019-01-16 02:54:363362 if (!is_background_video_playback_enabled_)
3363 return true;
3364
avayvod65fad272017-02-24 01:00:483365 // If suspending background video, pause any video that's not remoted or
3366 // not unlocked to play in the background.
Sergey Volk8b09c2c52018-12-12 23:20:403367 if (IsBackgroundSuspendEnabled(this)) {
avayvod65fad272017-02-24 01:00:483368#if defined(OS_ANDROID)
Thomas Guilbert7350fdad2019-01-29 23:09:243369 if (is_flinging_)
avayvod65fad272017-02-24 01:00:483370 return false;
avayvodcc273dd2017-01-19 19:35:123371#endif
avayvodeb9098d2017-01-07 00:33:033372
Blink Reformat1c4d759e2017-04-09 16:34:543373 return !HasAudio() || (IsResumeBackgroundVideosEnabled() &&
3374 video_locked_when_paused_when_hidden_);
avayvod65fad272017-02-24 01:00:483375 }
3376
3377 // Otherwise only pause if the optimization is on and it's a video-only
3378 // optimization candidate.
avayvod01201332017-04-14 00:27:153379 return IsBackgroundVideoPauseOptimizationEnabled() && !HasAudio() &&
Thomas Guilbert29ae1a902018-10-20 01:53:383380 IsBackgroundOptimizationCandidate() && !is_flinging_;
avayvodeb9098d2017-01-07 00:33:033381}
3382
avayvod2135a642017-01-13 00:17:143383bool WebMediaPlayerImpl::ShouldDisableVideoWhenHidden() const {
Ted Meyera918e592018-09-08 00:16:203384 // This optimization is behind the flag on all platforms, only for non-mse
3385 // video. MSE video track switching on hide has gone through a field test.
3386 // TODO(tmathmeyer): Passing load_type_ won't be needed after src= field
3387 // testing is finished. see: http://crbug.com/709302
Ted Meyer0e105992019-05-04 01:47:213388 if (!is_background_video_track_optimization_supported_)
avayvodc4bfb0e62017-01-13 01:07:013389 return false;
avayvodc4bfb0e62017-01-13 01:07:013390
avayvodcc273dd2017-01-19 19:35:123391 // Disable video track only for players with audio that match the criteria for
3392 // being optimized.
Blink Reformat1c4d759e2017-04-09 16:34:543393 return HasAudio() && IsBackgroundOptimizationCandidate();
avayvodcc273dd2017-01-19 19:35:123394}
3395
3396bool WebMediaPlayerImpl::IsBackgroundOptimizationCandidate() const {
3397 DCHECK(main_task_runner_->BelongsToCurrentThread());
3398
François Beaufort664c3ca72018-04-13 07:24:513399 // Don't optimize Picture-in-Picture players.
Mounir Lamouri0484f40a2018-07-25 03:03:263400 if (IsInPictureInPicture())
François Beaufort664c3ca72018-04-13 07:24:513401 return false;
3402
Thomas Guilbert7350fdad2019-01-29 23:09:243403#if defined(OS_ANDROID)
3404 // Don't optimize videos casted as part of RemotePlayback.
3405 if (is_flinging_)
avayvodcc273dd2017-01-19 19:35:123406 return false;
Thomas Guilbert7350fdad2019-01-29 23:09:243407#endif
avayvodcc273dd2017-01-19 19:35:123408
3409 // Don't optimize audio-only or streaming players.
Blink Reformat1c4d759e2017-04-09 16:34:543410 if (!HasVideo() || IsStreaming())
avayvodcc273dd2017-01-19 19:35:123411 return false;
3412
Dale Curtis3f4935b2017-09-09 00:11:593413 // Video-only players are always optimized (paused).
3414 // Don't check the keyframe distance and duration.
3415 if (!HasAudio() && HasVideo())
3416 return true;
3417
avayvodcc273dd2017-01-19 19:35:123418 // Videos shorter than the maximum allowed keyframe distance can be optimized.
3419 base::TimeDelta duration = GetPipelineMediaDuration();
Ted Meyera918e592018-09-08 00:16:203420
Dale Curtis456808a2018-10-23 17:50:213421 constexpr base::TimeDelta kMaxKeyframeDistanceToDisableBackgroundVideo =
3422 base::TimeDelta::FromMilliseconds(
3423 kMaxKeyframeDistanceToDisableBackgroundVideoMs);
3424 if (duration < kMaxKeyframeDistanceToDisableBackgroundVideo)
avayvodcc273dd2017-01-19 19:35:123425 return true;
3426
3427 // Otherwise, only optimize videos with shorter average keyframe distance.
avayvodc4bfb0e62017-01-13 01:07:013428 PipelineStatistics stats = GetPipelineStatistics();
Dale Curtis456808a2018-10-23 17:50:213429 return stats.video_keyframe_distance_average <
3430 kMaxKeyframeDistanceToDisableBackgroundVideo;
avayvod2135a642017-01-13 00:17:143431}
3432
avayvod56e1f3942017-01-21 02:06:313433void WebMediaPlayerImpl::UpdateBackgroundVideoOptimizationState() {
Takumi Fujimotof2319684e2019-12-03 18:51:513434 if (IsHidden()) {
Yuchen Liue7813972019-04-12 22:34:243435 if (ShouldPausePlaybackWhenHidden()) {
avayvod56e1f3942017-01-21 02:06:313436 PauseVideoIfNeeded();
Dale Curtisa75a7892017-08-09 20:21:513437 } else if (update_background_status_cb_.IsCancelled()) {
3438 // Only trigger updates when we don't have one already scheduled.
3439 update_background_status_cb_.Reset(
3440 base::Bind(&WebMediaPlayerImpl::DisableVideoTrackIfNeeded,
3441 base::Unretained(this)));
3442
3443 // Defer disable track until we're sure the clip will be backgrounded for
3444 // some time. Resuming may take half a second, so frequent tab switches
3445 // will yield a poor user experience otherwise. http://crbug.com/709302
3446 // may also cause AV sync issues if disable/enable happens too fast.
3447 main_task_runner_->PostDelayedTask(
3448 FROM_HERE, update_background_status_cb_.callback(),
3449 base::TimeDelta::FromSeconds(10));
3450 }
avayvod56e1f3942017-01-21 02:06:313451 } else {
Dale Curtisa75a7892017-08-09 20:21:513452 update_background_status_cb_.Cancel();
avayvod56e1f3942017-01-21 02:06:313453 EnableVideoTrackIfNeeded();
3454 }
3455}
3456
3457void WebMediaPlayerImpl::PauseVideoIfNeeded() {
3458 DCHECK(IsHidden());
3459
3460 // Don't pause video while the pipeline is stopped, resuming or seeking.
3461 // Also if the video is paused already.
Antonio Gomes81b56552019-05-15 22:15:283462 if (!pipeline_controller_->IsPipelineRunning() || is_pipeline_resuming_ ||
tguilbert350936ff2017-02-24 05:39:273463 seeking_ || paused_)
avayvod56e1f3942017-01-21 02:06:313464 return;
3465
3466 // OnPause() will set |paused_when_hidden_| to false and call
3467 // UpdatePlayState(), so set the flag to true after and then return.
3468 OnPause();
3469 paused_when_hidden_ = true;
3470}
3471
avayvod2135a642017-01-13 00:17:143472void WebMediaPlayerImpl::EnableVideoTrackIfNeeded() {
avayvod56e1f3942017-01-21 02:06:313473 // Don't change video track while the pipeline is stopped, resuming or
3474 // seeking.
Antonio Gomes81b56552019-05-15 22:15:283475 if (!pipeline_controller_->IsPipelineRunning() || is_pipeline_resuming_ ||
tguilbert350936ff2017-02-24 05:39:273476 seeking_)
avayvod2135a642017-01-13 00:17:143477 return;
3478
3479 if (video_track_disabled_) {
3480 video_track_disabled_ = false;
Blink Reformat1c4d759e2017-04-09 16:34:543481 if (client_->HasSelectedVideoTrack()) {
3482 WebMediaPlayer::TrackId trackId = client_->GetSelectedVideoTrackId();
3483 SelectedVideoTrackChanged(&trackId);
avayvod2135a642017-01-13 00:17:143484 }
3485 }
3486}
3487
3488void WebMediaPlayerImpl::DisableVideoTrackIfNeeded() {
3489 DCHECK(IsHidden());
3490
3491 // Don't change video track while the pipeline is resuming or seeking.
3492 if (is_pipeline_resuming_ || seeking_)
3493 return;
3494
3495 if (!video_track_disabled_ && ShouldDisableVideoWhenHidden()) {
3496 video_track_disabled_ = true;
Blink Reformat1c4d759e2017-04-09 16:34:543497 SelectedVideoTrackChanged(nullptr);
avayvod2135a642017-01-13 00:17:143498 }
3499}
3500
avayvodc4bfb0e62017-01-13 01:07:013501void WebMediaPlayerImpl::SetPipelineStatisticsForTest(
3502 const PipelineStatistics& stats) {
3503 pipeline_statistics_for_test_ = base::make_optional(stats);
3504}
3505
3506PipelineStatistics WebMediaPlayerImpl::GetPipelineStatistics() const {
3507 DCHECK(main_task_runner_->BelongsToCurrentThread());
3508
tguilbert350936ff2017-02-24 05:39:273509 return pipeline_statistics_for_test_.value_or(
Antonio Gomes81b56552019-05-15 22:15:283510 pipeline_controller_->GetStatistics());
avayvodc4bfb0e62017-01-13 01:07:013511}
3512
avayvodcc273dd2017-01-19 19:35:123513void WebMediaPlayerImpl::SetPipelineMediaDurationForTest(
3514 base::TimeDelta duration) {
3515 pipeline_media_duration_for_test_ = base::make_optional(duration);
3516}
3517
3518base::TimeDelta WebMediaPlayerImpl::GetPipelineMediaDuration() const {
3519 DCHECK(main_task_runner_->BelongsToCurrentThread());
3520
3521 return pipeline_media_duration_for_test_.value_or(
Antonio Gomes81b56552019-05-15 22:15:283522 pipeline_controller_->GetMediaDuration());
avayvodcc273dd2017-01-19 19:35:123523}
3524
Xiangjun Zhangba8724f482017-08-03 06:43:253525void WebMediaPlayerImpl::SwitchToRemoteRenderer(
3526 const std::string& remote_device_friendly_name) {
xjz4e5d4bf32017-02-15 21:26:353527 DCHECK(main_task_runner_->BelongsToCurrentThread());
Chris Cunningham89b4b762019-03-27 17:13:333528
3529 DCHECK(!is_remote_rendering_);
3530 is_remote_rendering_ = true;
3531
Thomas Guilbertb341bae02018-05-09 00:02:133532 DCHECK(!disable_pipeline_auto_suspend_);
Xiangjun Zhangba8724f482017-08-03 06:43:253533 disable_pipeline_auto_suspend_ = true;
Chris Cunninghamd9df58e2017-08-29 00:04:233534
3535 // Capabilities reporting should only be performed for local playbacks.
3536 video_decode_stats_reporter_.reset();
3537
Xiangjun Zhangba8724f482017-08-03 06:43:253538 // Requests to restart media pipeline. A remote renderer will be created via
3539 // the |renderer_factory_selector_|.
xjz4e5d4bf32017-02-15 21:26:353540 ScheduleRestart();
xjzdf9b67e2017-04-13 23:28:253541 if (client_) {
Xiangjun Zhangba8724f482017-08-03 06:43:253542 client_->MediaRemotingStarted(
3543 WebString::FromUTF8(remote_device_friendly_name));
xjzdf9b67e2017-04-13 23:28:253544 }
xjz4e5d4bf32017-02-15 21:26:353545}
3546
Xiangjun Zhang5e20cba42018-01-10 19:54:563547void WebMediaPlayerImpl::SwitchToLocalRenderer(
3548 MediaObserverClient::ReasonToSwitchToLocal reason) {
Xiangjun Zhangba8724f482017-08-03 06:43:253549 DCHECK(main_task_runner_->BelongsToCurrentThread());
Chris Cunningham89b4b762019-03-27 17:13:333550 if (!is_remote_rendering_)
Xiangjun Zhang12f55272018-07-30 23:19:373551 return; // Is currently with local renderer.
Chris Cunningham89b4b762019-03-27 17:13:333552 is_remote_rendering_ = false;
3553
3554 DCHECK(disable_pipeline_auto_suspend_);
Xiangjun Zhangba8724f482017-08-03 06:43:253555 disable_pipeline_auto_suspend_ = false;
Chris Cunninghamd9df58e2017-08-29 00:04:233556
3557 // Capabilities reporting may resume now that playback is local.
3558 CreateVideoDecodeStatsReporter();
3559
Xiangjun Zhangba8724f482017-08-03 06:43:253560 // Requests to restart media pipeline. A local renderer will be created via
3561 // the |renderer_factory_selector_|.
3562 ScheduleRestart();
3563 if (client_)
Xiangjun Zhang5e20cba42018-01-10 19:54:563564 client_->MediaRemotingStopped(GetSwitchToLocalMessage(reason));
Xiangjun Zhangba8724f482017-08-03 06:43:253565}
3566
dalecurtis4f6d14d2017-02-22 17:42:223567void WebMediaPlayerImpl::RecordUnderflowDuration(base::TimeDelta duration) {
3568 DCHECK(data_source_ || chunk_demuxer_);
xhwang68b3fab82017-05-17 21:31:463569
dalecurtis4f6d14d2017-02-22 17:42:223570 if (data_source_)
Jennifer Apacible82e25c92017-08-07 18:15:273571 UMA_HISTOGRAM_TIMES("Media.UnderflowDuration2.SRC", duration);
dalecurtis4f6d14d2017-02-22 17:42:223572 else
Jennifer Apacible82e25c92017-08-07 18:15:273573 UMA_HISTOGRAM_TIMES("Media.UnderflowDuration2.MSE", duration);
xhwang68b3fab82017-05-17 21:31:463574
3575 if (is_encrypted_)
Jennifer Apacible82e25c92017-08-07 18:15:273576 UMA_HISTOGRAM_TIMES("Media.UnderflowDuration2.EME", duration);
dalecurtis4f6d14d2017-02-22 17:42:223577}
3578
xhwang60802652017-04-19 07:29:583579#define UMA_HISTOGRAM_VIDEO_HEIGHT(name, sample) \
3580 UMA_HISTOGRAM_CUSTOM_COUNTS(name, sample, 100, 10000, 50)
3581
3582void WebMediaPlayerImpl::RecordVideoNaturalSize(const gfx::Size& natural_size) {
3583 // Always report video natural size to MediaLog.
Ted Meyer0134aed2020-01-23 23:56:403584 media_log_->AddEvent<MediaLogEvent::kVideoSizeChanged>(natural_size);
Ted Meyer7f5b4e22019-11-21 03:21:193585 media_log_->SetProperty<MediaLogProperty::kResolution>(natural_size);
xhwang60802652017-04-19 07:29:583586
3587 if (initial_video_height_recorded_)
3588 return;
3589
3590 initial_video_height_recorded_ = true;
3591
3592 int height = natural_size.height();
3593
3594 if (load_type_ == kLoadTypeURL)
3595 UMA_HISTOGRAM_VIDEO_HEIGHT("Media.VideoHeight.Initial.SRC", height);
3596 else if (load_type_ == kLoadTypeMediaSource)
3597 UMA_HISTOGRAM_VIDEO_HEIGHT("Media.VideoHeight.Initial.MSE", height);
3598
3599 if (is_encrypted_)
3600 UMA_HISTOGRAM_VIDEO_HEIGHT("Media.VideoHeight.Initial.EME", height);
3601
3602 UMA_HISTOGRAM_VIDEO_HEIGHT("Media.VideoHeight.Initial.All", height);
3603}
3604
3605#undef UMA_HISTOGRAM_VIDEO_HEIGHT
3606
Greg Thompsonaa48ce8d2018-04-03 06:11:433607void WebMediaPlayerImpl::SetTickClockForTest(
3608 const base::TickClock* tick_clock) {
tzik2c963b872017-12-07 06:57:243609 tick_clock_ = tick_clock;
Antonio Gomes81b56552019-05-15 22:15:283610 buffered_data_source_host_->SetTickClockForTest(tick_clock);
hubbeb2d3efd2017-05-05 23:26:383611}
3612
Dale Curtis3899090ea2018-01-12 00:10:353613void WebMediaPlayerImpl::OnFirstFrame(base::TimeTicks frame_time) {
3614 DCHECK(!load_start_time_.is_null());
Dale Curtisff576552018-03-30 02:32:443615 DCHECK(!skip_metrics_due_to_startup_suspend_);
Dale Curtisc2c5dcb12018-04-16 23:21:293616 has_first_frame_ = true;
Dale Curtis7c63f2e22018-09-19 21:06:273617 needs_first_frame_ = false;
Dale Curtis3899090ea2018-01-12 00:10:353618 const base::TimeDelta elapsed = frame_time - load_start_time_;
3619 media_metrics_provider_->SetTimeToFirstFrame(elapsed);
3620 RecordTimingUMA("Media.TimeToFirstFrame", elapsed);
Dale Curtiscdfc6f22019-06-26 22:05:233621
3622 // Needed to signal HTMLVideoElement that it should remove the poster image.
Dale Curtis66790f32019-07-11 00:14:243623 if (client_ && has_poster_)
Dale Curtiscdfc6f22019-06-26 22:05:233624 client_->Repaint();
Dale Curtis3899090ea2018-01-12 00:10:353625}
3626
3627void WebMediaPlayerImpl::RecordTimingUMA(const std::string& key,
3628 base::TimeDelta elapsed) {
3629 if (chunk_demuxer_)
3630 base::UmaHistogramMediumTimes(key + ".MSE", elapsed);
3631 else
3632 base::UmaHistogramMediumTimes(key + ".SRC", elapsed);
3633 if (is_encrypted_)
3634 base::UmaHistogramMediumTimes(key + ".EME", elapsed);
3635}
3636
John Rummelldb5a7ef2018-05-16 00:28:013637void WebMediaPlayerImpl::RecordEncryptionScheme(
3638 const std::string& stream_name,
Yuchen Liub33bfc12019-11-08 20:16:123639 EncryptionScheme encryption_scheme) {
John Rummelldb5a7ef2018-05-16 00:28:013640 DCHECK(stream_name == "Audio" || stream_name == "Video");
3641
3642 // If the stream is not encrypted, don't record it.
Yuchen Liub33bfc12019-11-08 20:16:123643 if (encryption_scheme == EncryptionScheme::kUnencrypted)
John Rummelldb5a7ef2018-05-16 00:28:013644 return;
3645
3646 base::UmaHistogramEnumeration(
3647 "Media.EME.EncryptionScheme.Initial." + stream_name,
3648 DetermineEncryptionSchemeUMAValue(encryption_scheme),
3649 EncryptionSchemeUMA::kCount);
3650}
3651
Mounir Lamouri0484f40a2018-07-25 03:03:263652bool WebMediaPlayerImpl::IsInPictureInPicture() const {
3653 DCHECK(client_);
3654 return client_->DisplayType() ==
3655 WebMediaPlayer::DisplayType::kPictureInPicture;
3656}
3657
Jazz Xu74690262020-01-30 14:02:273658void WebMediaPlayerImpl::OnPictureInPictureAvailabilityChanged(bool available) {
3659 delegate_->DidPictureInPictureAvailabilityChange(delegate_id_, available);
3660}
3661
Dale Curtis5bba03232018-08-30 17:57:383662void WebMediaPlayerImpl::MaybeSetContainerName() {
Dale Curtisf01c8262018-09-04 23:50:433663 // MSE nor MediaPlayerRenderer provide container information.
3664 if (chunk_demuxer_ || using_media_player_renderer_)
Dale Curtis5bba03232018-08-30 17:57:383665 return;
3666
3667 // Pipeline startup failed before even getting a demuxer setup.
3668 if (!demuxer_)
3669 return;
3670
3671 // Container has already been set.
3672 if (highest_ready_state_ >= WebMediaPlayer::kReadyStateHaveMetadata)
3673 return;
3674
3675// If ffmpeg isn't enabled, we can't get the container name.
3676#if BUILDFLAG(ENABLE_FFMPEG)
3677 media_metrics_provider_->SetContainerName(
3678 static_cast<FFmpegDemuxer*>(demuxer_.get())->container());
3679#endif
3680}
3681
Dale Curtis18ad391b2019-05-30 23:25:093682void WebMediaPlayerImpl::MaybeUpdateBufferSizesForPlayback() {
3683 // Don't increase the MultiBufferDataSource buffer size until we've reached
3684 // kReadyStateHaveEnoughData. Otherwise we will unnecessarily slow down
3685 // playback startup -- it can instead be done for free after playback starts.
3686 if (!mb_data_source_ || highest_ready_state_ < kReadyStateHaveEnoughData)
3687 return;
3688
3689 mb_data_source_->MediaPlaybackRateChanged(playback_rate_);
3690 if (!paused_)
3691 mb_data_source_->MediaIsPlaying();
Becca Hughes7a85bf22019-07-24 16:16:583692
3693 // The playback rate has changed so we should rebuild the media position
3694 // state.
3695 UpdateMediaPositionState();
Dale Curtis18ad391b2019-05-30 23:25:093696}
3697
Dan Sanders6edfd782019-08-13 00:13:183698void WebMediaPlayerImpl::OnSimpleWatchTimerTick() {
3699 RecordSimpleWatchTimeUMA(reported_renderer_type_);
3700}
3701
[email protected]dbb3ff372019-10-15 19:09:423702GURL WebMediaPlayerImpl::GetSrcAfterRedirects() {
3703 return mb_data_source_ ? mb_data_source_->GetUrlAfterRedirects() : GURL();
3704}
3705
Thomas Guilberte90fe312019-11-07 22:27:563706void WebMediaPlayerImpl::SetCurrentFrameOverrideForTesting(
3707 scoped_refptr<VideoFrame> current_frame_override) {
3708 current_frame_override_ = current_frame_override;
3709}
3710
[email protected]96665a82020-01-23 00:35:373711void WebMediaPlayerImpl::UpdateSmoothnessHelper() {
3712 // If the experiment flag is off, then do nothing.
3713 if (!base::FeatureList::IsEnabled(kMediaLearningSmoothnessExperiment))
3714 return;
3715
3716 // If we're paused, or if we can't get all the features, then clear any
3717 // smoothness helper and stop. We'll try to create it later when we're
3718 // playing and have all the features.
3719 if (paused_ || !HasVideo() || pipeline_metadata_.natural_size.IsEmpty() ||
3720 !last_reported_fps_) {
3721 smoothness_helper_.reset();
3722 return;
3723 }
3724
3725 // Fill in features.
3726 // NOTE: this is a very bad way to do this, since it memorizes the order of
3727 // features in the task. However, it'll do for now.
3728 learning::FeatureVector features;
3729 features.push_back(
3730 learning::FeatureValue(pipeline_metadata_.video_decoder_config.codec()));
3731 features.push_back(learning::FeatureValue(
3732 pipeline_metadata_.video_decoder_config.profile()));
3733 features.push_back(
3734 learning::FeatureValue(pipeline_metadata_.natural_size.width()));
3735 features.push_back(learning::FeatureValue(*last_reported_fps_));
3736
3737 // If we have a smoothness helper, and we're not changing the features, then
3738 // do nothing. This prevents restarting the helper for no reason.
3739 if (smoothness_helper_ && features == smoothness_helper_->features())
3740 return;
3741
3742 // Create or restart the smoothness helper with |features|.
[email protected]91379332020-01-26 03:58:203743 smoothness_helper_ = SmoothnessHelper::Create(
3744 GetLearningTaskController(
3745 learning::MediaLearningTasks::Id::kConsecutiveBadWindows),
3746 GetLearningTaskController(
3747 learning::MediaLearningTasks::Id::kConsecutiveNNRs),
3748 features, this);
3749}
3750
3751std::unique_ptr<learning::LearningTaskController>
3752WebMediaPlayerImpl::GetLearningTaskController(
3753 learning::MediaLearningTasks::Id task_id) {
3754 // Get the LearningTaskController for |task_id|.
3755 learning::LearningTask task = learning::MediaLearningTasks::Get(task_id);
[email protected]96665a82020-01-23 00:35:373756
3757 mojo::Remote<media::learning::mojom::LearningTaskController> remote_ltc;
3758 media_metrics_provider_->AcquireLearningTaskController(
3759 task.name, remote_ltc.BindNewPipeAndPassReceiver());
[email protected]91379332020-01-26 03:58:203760 return std::make_unique<learning::MojoLearningTaskController>(
[email protected]96665a82020-01-23 00:35:373761 task, std::move(remote_ltc));
[email protected]96665a82020-01-23 00:35:373762}
3763
acolwell9e0840d2014-09-06 19:01:323764} // namespace media