blob: 254902da241f14435c2e84dcc127c162be04f953 [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"
Gabriel Charetted5c656c2020-02-26 16:35:2227#include "base/task/thread_pool.h"
wdzierzanowskifd4cd91c52015-12-02 23:50:2028#include "base/task_runner_util.h"
gabba14a442016-05-11 20:10:2029#include "base/threading/thread_task_runner_handle.h"
Eugene Zemtsov77d56262020-03-06 05:52:0330#include "base/trace_event/memory_dump_manager.h"
ssid9525f4672015-01-28 12:13:1531#include "base/trace_event/trace_event.h"
sandersd1e49fb62015-12-12 01:18:0632#include "build/build_config.h"
[email protected]21c3f7502013-03-23 03:29:5133#include "cc/layers/video_layer.h"
[email protected]e4fc09e2012-04-06 03:17:4434#include "media/audio/null_audio_sink.h"
[email protected]2eccbed2014-01-10 05:15:5335#include "media/base/bind_to_current_loop.h"
xhwang0ad11e512014-11-25 23:43:0936#include "media/base/cdm_context.h"
John Rummelldb5a7ef2018-05-16 00:28:0137#include "media/base/encryption_scheme.h"
[email protected]32da1002010-03-03 21:57:3538#include "media/base/limits.h"
zqzhang5d8eab72016-08-26 20:34:3039#include "media/base/media_content_type.h"
[email protected]090f7312011-08-05 23:26:4040#include "media/base/media_log.h"
sandersd1e49fb62015-12-12 01:18:0641#include "media/base/media_switches.h"
tguilbert25a4d112016-10-13 21:56:5142#include "media/base/media_url_demuxer.h"
Eugene Zemtsov77d56262020-03-06 05:52:0343#include "media/base/memory_dump_provider_proxy.h"
[email protected]8a561062013-11-22 01:19:3144#include "media/base/text_renderer.h"
watk9f9dfdc92015-09-04 21:33:2945#include "media/base/timestamp_constants.h"
[email protected]e81283bb2010-08-31 18:01:2146#include "media/base/video_frame.h"
acolwell9e0840d2014-09-06 19:01:3247#include "media/blink/texttrack_impl.h"
John Delaneyb933391602018-10-17 21:50:4748#include "media/blink/url_index.h"
Chris Cunninghamd9df58e2017-08-29 00:04:2349#include "media/blink/video_decode_stats_reporter.h"
dalecurtis04bdb582016-08-17 22:15:2350#include "media/blink/watch_time_reporter.h"
xhwang97de4202014-11-25 08:44:0151#include "media/blink/webcontentdecryptionmodule_impl.h"
acolwell9e0840d2014-09-06 19:01:3252#include "media/blink/webinbandtexttrack_impl.h"
acolwell9e0840d2014-09-06 19:01:3253#include "media/blink/webmediasource_impl.h"
[email protected]efe7cd22012-09-12 23:55:0154#include "media/filters/chunk_demuxer.h"
[email protected]ddbc6ff2013-04-19 15:28:3355#include "media/filters/ffmpeg_demuxer.h"
Dale Curtis4841c712018-12-13 18:14:0556#include "media/filters/memory_data_source.h"
[email protected]96665a82020-01-23 00:35:3757#include "media/learning/mojo/public/cpp/mojo_learning_task_controller.h"
Scott Violeta35f9a42018-03-22 22:00:4458#include "media/media_buildflags.h"
Gyuyoung Kima040bc52019-10-30 01:14:3559#include "mojo/public/cpp/bindings/pending_remote.h"
Dale Curtis4841c712018-12-13 18:14:0560#include "net/base/data_url.h"
Blink Reformata30d4232018-04-07 15:31:0661#include "third_party/blink/public/platform/web_encrypted_media_types.h"
[email protected]0526d5692020-02-28 00:24:3162#include "third_party/blink/public/platform/web_fullscreen_video_status.h"
Blink Reformata30d4232018-04-07 15:31:0663#include "third_party/blink/public/platform/web_media_player_client.h"
64#include "third_party/blink/public/platform/web_media_player_encrypted_media_client.h"
65#include "third_party/blink/public/platform/web_media_player_source.h"
66#include "third_party/blink/public/platform/web_media_source.h"
67#include "third_party/blink/public/platform/web_rect.h"
68#include "third_party/blink/public/platform/web_runtime_features.h"
69#include "third_party/blink/public/platform/web_security_origin.h"
70#include "third_party/blink/public/platform/web_size.h"
71#include "third_party/blink/public/platform/web_string.h"
72#include "third_party/blink/public/platform/web_surface_layer_bridge.h"
73#include "third_party/blink/public/platform/web_url.h"
Antonio Gomes3a858b52019-05-31 02:47:5274#include "third_party/blink/public/platform/webaudiosourceprovider_impl.h"
Gyuyoung Kimf99f5f32019-09-26 03:45:1575#include "third_party/blink/public/strings/grit/blink_strings.h"
Antonio Gomesf01cfbd2019-07-12 08:53:1176#include "third_party/blink/public/web/modules/media/webmediaplayer_util.h"
Blink Reformata30d4232018-04-07 15:31:0677#include "third_party/blink/public/web/web_document.h"
78#include "third_party/blink/public/web/web_frame.h"
79#include "third_party/blink/public/web/web_local_frame.h"
Blink Reformata30d4232018-04-07 15:31:0680#include "third_party/blink/public/web/web_view.h"
[email protected]b3f2b912009-04-09 16:18:5281
dalecurtisea27a3ed2016-06-24 01:41:3082#if defined(OS_ANDROID)
83#include "media/base/android/media_codec_util.h"
84#endif
85
[email protected]180ef242013-11-07 06:50:4686using blink::WebMediaPlayer;
87using blink::WebRect;
[email protected]180ef242013-11-07 06:50:4688using blink::WebString;
hubbed5f36882016-01-15 22:40:3789using gpu::gles2::GLES2Interface;
90
danakj365175c2016-02-06 00:37:3791#define STATIC_ASSERT_ENUM(a, b) \
92 static_assert(static_cast<int>(a) == static_cast<int>(b), \
93 "mismatching enums: " #a)
94
hubbed5f36882016-01-15 22:40:3795namespace media {
[email protected]ec9212f2008-12-18 21:40:3696
[email protected]8931c41a2009-07-07 17:31:4997namespace {
98
Dan Sanders6edfd782019-08-13 00:13:1899const char kWatchTimeHistogram[] = "Media.WebMediaPlayerImpl.WatchTime";
100
Xiaohan Wang48aaa192019-12-05 01:29:00101void RecordSimpleWatchTimeUMA(RendererFactoryType type) {
102 UMA_HISTOGRAM_ENUMERATION(kWatchTimeHistogram, type);
Dan Sanders6edfd782019-08-13 00:13:18103}
104
Antonio Gomes3a858b52019-05-31 02:47:52105void SetSinkIdOnMediaThread(
106 scoped_refptr<blink::WebAudioSourceProviderImpl> sink,
107 const std::string& device_id,
108 OutputDeviceStatusCB callback) {
Daniel Chengc1710b52018-10-24 03:12:28109 sink->SwitchOutputDevice(device_id, std::move(callback));
guidouc7babef2015-10-22 00:42:35110}
111
Sergey Volk8b09c2c52018-12-12 23:20:40112bool IsBackgroundSuspendEnabled(const WebMediaPlayerImpl* wmpi) {
Luke Halliwell7a8a8982018-07-25 01:07:05113 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
Dan Sanders5aeeb212020-04-10 19:37:41114 switches::kDisableBackgroundMediaSuspend)) {
Luke Halliwell7a8a8982018-07-25 01:07:05115 return false;
Dan Sanders5aeeb212020-04-10 19:37:41116 }
Sergey Volk8b09c2c52018-12-12 23:20:40117 return wmpi->IsBackgroundMediaSuspendEnabled();
dalecurtis0431cbf2016-03-12 01:19:43118}
119
avayvod48a8be52016-08-04 19:52:50120bool IsResumeBackgroundVideosEnabled() {
121 return base::FeatureList::IsEnabled(kResumeBackgroundVideo);
122}
123
avayvod01201332017-04-14 00:27:15124bool IsBackgroundVideoPauseOptimizationEnabled() {
125 return base::FeatureList::IsEnabled(kBackgroundVideoPauseOptimization);
126}
127
sandersd50a635e2016-04-04 22:50:09128bool IsNetworkStateError(blink::WebMediaPlayer::NetworkState state) {
Blink Reformat1c4d759e2017-04-09 16:34:54129 bool result = state == blink::WebMediaPlayer::kNetworkStateFormatError ||
130 state == blink::WebMediaPlayer::kNetworkStateNetworkError ||
131 state == blink::WebMediaPlayer::kNetworkStateDecodeError;
132 DCHECK_EQ(state > blink::WebMediaPlayer::kNetworkStateLoaded, result);
sandersd50a635e2016-04-04 22:50:09133 return result;
134}
135
sandersd2c478422016-08-02 01:19:25136gfx::Size GetRotatedVideoSize(VideoRotation rotation, gfx::Size natural_size) {
137 if (rotation == VIDEO_ROTATION_90 || rotation == VIDEO_ROTATION_270)
138 return gfx::Size(natural_size.height(), natural_size.width());
139 return natural_size;
140}
141
Xiaohan Wangf63505d2017-10-21 08:00:53142void RecordEncryptedEvent(bool encrypted_event_fired) {
143 UMA_HISTOGRAM_BOOLEAN("Media.EME.EncryptedEvent", encrypted_event_fired);
144}
145
sandersd35d2c3f2017-01-14 02:04:42146// How much time must have elapsed since loading last progressed before we
147// assume that the decoder will have had time to complete preroll.
148constexpr base::TimeDelta kPrerollAttemptTimeout =
watkd026f792016-11-05 00:28:51149 base::TimeDelta::FromSeconds(3);
150
Matt Wolenetz6010f6c2017-10-18 00:44:36151// Maximum number, per-WMPI, of media logs of playback rate changes.
152constexpr int kMaxNumPlaybackRateLogs = 10;
153
Gyuyoung Kimf99f5f32019-09-26 03:45:15154int GetSwitchToLocalMessage(MediaObserverClient::ReasonToSwitchToLocal reason) {
Xiangjun Zhang5e20cba42018-01-10 19:54:56155 switch (reason) {
156 case MediaObserverClient::ReasonToSwitchToLocal::NORMAL:
Gyuyoung Kimf99f5f32019-09-26 03:45:15157 return IDS_MEDIA_REMOTING_STOP_TEXT;
Xiangjun Zhang5e20cba42018-01-10 19:54:56158 case MediaObserverClient::ReasonToSwitchToLocal::POOR_PLAYBACK_QUALITY:
Gyuyoung Kimf99f5f32019-09-26 03:45:15159 return IDS_MEDIA_REMOTING_STOP_BY_PLAYBACK_QUALITY_TEXT;
Xiangjun Zhang5e20cba42018-01-10 19:54:56160 case MediaObserverClient::ReasonToSwitchToLocal::PIPELINE_ERROR:
Gyuyoung Kimf99f5f32019-09-26 03:45:15161 return IDS_MEDIA_REMOTING_STOP_BY_ERROR_TEXT;
Xiangjun Zhang5e20cba42018-01-10 19:54:56162 case MediaObserverClient::ReasonToSwitchToLocal::ROUTE_TERMINATED:
Gyuyoung Kimf99f5f32019-09-26 03:45:15163 return blink::WebMediaPlayerClient::kMediaRemotingStopNoText;
Xiangjun Zhang5e20cba42018-01-10 19:54:56164 }
165 NOTREACHED();
166 // To suppress compiler warning on Windows.
Gyuyoung Kimf99f5f32019-09-26 03:45:15167 return blink::WebMediaPlayerClient::kMediaRemotingStopNoText;
Xiangjun Zhang5e20cba42018-01-10 19:54:56168}
169
John Rummelldb5a7ef2018-05-16 00:28:01170// These values are persisted to UMA. Entries should not be renumbered and
171// numeric values should never be reused.
Yuchen Liub33bfc12019-11-08 20:16:12172// TODO(crbug.com/825041): This should use EncryptionScheme when kUnencrypted
John Rummelldb5a7ef2018-05-16 00:28:01173// removed.
174enum class EncryptionSchemeUMA { kCenc = 0, kCbcs = 1, kCount };
175
176EncryptionSchemeUMA DetermineEncryptionSchemeUMAValue(
Yuchen Liub33bfc12019-11-08 20:16:12177 EncryptionScheme encryption_scheme) {
178 if (encryption_scheme == EncryptionScheme::kCbcs)
John Rummelldb5a7ef2018-05-16 00:28:01179 return EncryptionSchemeUMA::kCbcs;
180
Yuchen Liub33bfc12019-11-08 20:16:12181 DCHECK_EQ(encryption_scheme, EncryptionScheme::kCenc);
John Rummelldb5a7ef2018-05-16 00:28:01182 return EncryptionSchemeUMA::kCenc;
183}
184
Pavel Feldman023c3e62018-08-28 17:59:47185#if BUILDFLAG(ENABLE_FFMPEG)
Dale Curtisb8139f72018-08-27 23:28:48186// Returns true if |url| represents (or is likely to) a local file.
187bool IsLocalFile(const GURL& url) {
188 return url.SchemeIsFile() || url.SchemeIsFileSystem() ||
189 url.SchemeIs(url::kContentScheme) ||
190 url.SchemeIs(url::kContentIDScheme) ||
191 url.SchemeIs("chrome-extension");
192}
Pavel Feldman023c3e62018-08-28 17:59:47193#endif
Dale Curtisb8139f72018-08-27 23:28:48194
Dale Curtisf273f8f2018-12-13 23:40:33195// Handles destruction of media::Renderer dependent components after the
196// renderer has been destructed on the media thread.
197void DestructionHelper(
198 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
199 scoped_refptr<base::SingleThreadTaskRunner> vfc_task_runner,
200 std::unique_ptr<Demuxer> demuxer,
201 std::unique_ptr<DataSource> data_source,
202 std::unique_ptr<VideoFrameCompositor> compositor,
203 std::unique_ptr<CdmContextRef> cdm_context_1,
204 std::unique_ptr<CdmContextRef> cdm_context_2,
205 std::unique_ptr<MediaLog> media_log,
206 std::unique_ptr<RendererFactorySelector> renderer_factory_selector,
207 std::unique_ptr<blink::WebSurfaceLayerBridge> bridge,
208 bool is_chunk_demuxer) {
209 // We release |bridge| after pipeline stop to ensure layout tests receive
210 // painted video frames before test harness exit.
211 main_task_runner->DeleteSoon(FROM_HERE, std::move(bridge));
212
213 // Since the media::Renderer is gone we can now destroy the compositor and
214 // renderer factory selector.
215 vfc_task_runner->DeleteSoon(FROM_HERE, std::move(compositor));
216 main_task_runner->DeleteSoon(FROM_HERE, std::move(renderer_factory_selector));
217
218 // ChunkDemuxer can be deleted on any thread, but other demuxers are bound to
219 // the main thread and must be deleted there now that the renderer is gone.
220 if (!is_chunk_demuxer) {
221 main_task_runner->DeleteSoon(FROM_HERE, std::move(demuxer));
222 main_task_runner->DeleteSoon(FROM_HERE, std::move(data_source));
223 main_task_runner->DeleteSoon(FROM_HERE, std::move(cdm_context_1));
224 main_task_runner->DeleteSoon(FROM_HERE, std::move(cdm_context_2));
225 main_task_runner->DeleteSoon(FROM_HERE, std::move(media_log));
226 return;
227 }
228
229 // ChunkDemuxer's streams may contain much buffered, compressed media that
230 // may need to be paged back in during destruction. Paging delay may exceed
231 // the renderer hang monitor's threshold on at least Windows while also
232 // blocking other work on the renderer main thread, so we do the actual
233 // destruction in the background without blocking WMPI destruction or
234 // |task_runner|. On advice of task_scheduler OWNERS, MayBlock() is not
235 // used because virtual memory overhead is not considered blocking I/O; and
236 // CONTINUE_ON_SHUTDOWN is used to allow process termination to not block on
237 // completing the task.
Gabriel Charetted5c656c2020-02-26 16:35:22238 base::ThreadPool::PostTask(
Dale Curtisf273f8f2018-12-13 23:40:33239 FROM_HERE,
Gabriel Charetted5c656c2020-02-26 16:35:22240 {base::TaskPriority::BEST_EFFORT,
Dale Curtisf273f8f2018-12-13 23:40:33241 base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
242 base::BindOnce(
243 [](scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
244 std::unique_ptr<Demuxer> demuxer_to_destroy,
245 std::unique_ptr<CdmContextRef> cdm_context_1,
246 std::unique_ptr<CdmContextRef> cdm_context_2,
247 std::unique_ptr<MediaLog> media_log) {
248 SCOPED_UMA_HISTOGRAM_TIMER("Media.MSE.DemuxerDestructionTime");
249 demuxer_to_destroy.reset();
250 main_task_runner->DeleteSoon(FROM_HERE, std::move(cdm_context_1));
251 main_task_runner->DeleteSoon(FROM_HERE, std::move(cdm_context_2));
252 main_task_runner->DeleteSoon(FROM_HERE, std::move(media_log));
253 },
254 std::move(main_task_runner), std::move(demuxer),
255 std::move(cdm_context_1), std::move(cdm_context_2),
256 std::move(media_log)));
257}
258
Ted Meyer7f5b4e22019-11-21 03:21:19259std::string SanitizeUserStringProperty(blink::WebString value) {
Ted Meyera698afe2019-11-06 20:58:03260 std::string converted = value.Utf8();
Ted Meyer7f5b4e22019-11-21 03:21:19261 return base::IsStringUTF8(converted) ? converted : "[invalid property]";
Ted Meyera698afe2019-11-06 20:58:03262}
263
Eugene Zemtsov77d56262020-03-06 05:52:03264void CreateAllocation(base::trace_event::ProcessMemoryDump* pmd,
265 int32_t id,
266 const char* name,
267 int64_t bytes) {
268 if (bytes <= 0)
269 return;
270 auto full_name =
Eugene Zemtsovc4c6db262020-03-20 22:19:41271 base::StringPrintf("media/webmediaplayer/%s/player_0x%x", name, id);
Eugene Zemtsov77d56262020-03-06 05:52:03272 auto* dump = pmd->CreateAllocatorDump(full_name);
273
274 dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
275 base::trace_event::MemoryAllocatorDump::kUnitsBytes, bytes);
276
277 auto* std_allocator = base::trace_event::MemoryDumpManager::GetInstance()
278 ->system_allocator_pool_name();
Eugene Zemtsovbe7150372020-04-21 18:35:14279 if (std_allocator)
280 pmd->AddSuballocation(dump->guid(), std_allocator);
Eugene Zemtsov77d56262020-03-06 05:52:03281}
282
[email protected]8931c41a2009-07-07 17:31:49283} // namespace
284
[email protected]6683e1b2014-04-10 01:45:38285class BufferedDataSourceHostImpl;
286
Takashi Toyoshima2e01e692018-11-16 03:23:27287STATIC_ASSERT_ENUM(WebMediaPlayer::kCorsModeUnspecified,
danakj365175c2016-02-06 00:37:37288 UrlData::CORS_UNSPECIFIED);
Takashi Toyoshima2e01e692018-11-16 03:23:27289STATIC_ASSERT_ENUM(WebMediaPlayer::kCorsModeAnonymous, UrlData::CORS_ANONYMOUS);
290STATIC_ASSERT_ENUM(WebMediaPlayer::kCorsModeUseCredentials,
danakj365175c2016-02-06 00:37:37291 UrlData::CORS_USE_CREDENTIALS);
[email protected]a5a01102012-06-06 17:01:24292
[email protected]5b5bb9d2010-10-22 19:57:36293WebMediaPlayerImpl::WebMediaPlayerImpl(
[email protected]35b2a972014-04-04 15:50:22294 blink::WebLocalFrame* frame,
[email protected]180ef242013-11-07 06:50:46295 blink::WebMediaPlayerClient* client,
srirama.m26f864d02015-07-14 05:21:46296 blink::WebMediaPlayerEncryptedMediaClient* encrypted_client,
Antonio Gomes423df612019-07-11 12:40:07297 blink::WebMediaPlayerDelegate* delegate,
tguilbert70d2a00a2017-04-25 00:30:44298 std::unique_ptr<RendererFactorySelector> renderer_factory_selector,
Alok Priyadarshi7166d4d2017-07-29 04:04:25299 UrlIndex* url_index,
CJ DiMegliod7ac6772017-11-10 00:19:06300 std::unique_ptr<VideoFrameCompositor> compositor,
dalecurtis9cddc0b2017-04-19 21:23:38301 std::unique_ptr<WebMediaPlayerParams> params)
[email protected]f6af7592014-02-28 10:09:11302 : frame_(frame),
Alexander Timin310368112017-09-13 10:01:44303 main_task_runner_(
304 frame->GetTaskRunner(blink::TaskType::kMediaElementEvent)),
dalecurtis9cddc0b2017-04-19 21:23:38305 media_task_runner_(params->media_task_runner()),
306 worker_task_runner_(params->worker_task_runner()),
307 media_log_(params->take_media_log()),
[email protected]5badb082010-06-11 17:40:15308 client_(client),
srirama.m26f864d02015-07-14 05:21:46309 encrypted_client_(encrypted_client),
[email protected]baff4512011-10-19 18:21:07310 delegate_(delegate),
dalecurtis9cddc0b2017-04-19 21:23:38311 defer_load_cb_(params->defer_load_cb()),
dalecurtis9cddc0b2017-04-19 21:23:38312 adjust_allocated_memory_cb_(params->adjust_allocated_memory_cb()),
tzik2c963b872017-12-07 06:57:24313 tick_clock_(base::DefaultTickClock::GetInstance()),
hubbe5f0ad43b2015-12-14 20:57:26314 url_index_(url_index),
Nathan Zabriskie04cec1c2020-03-12 00:55:26315 raster_context_provider_(params->raster_context_provider()),
CJ DiMegliod7ac6772017-11-10 00:19:06316 vfc_task_runner_(params->video_frame_compositor_task_runner()),
317 compositor_(std::move(compositor)),
tguilbert70d2a00a2017-04-25 00:30:44318 renderer_factory_selector_(std::move(renderer_factory_selector)),
dalecurtis9cddc0b2017-04-19 21:23:38319 observer_(params->media_observer()),
servolkf94b4602017-01-31 16:44:27320 enable_instant_source_buffer_gc_(
dalecurtis9cddc0b2017-04-19 21:23:38321 params->enable_instant_source_buffer_gc()),
shaktisahu24189c12017-03-11 17:42:55322 embedded_media_experience_enabled_(
liberato2ff93ad2017-05-17 07:28:24323 params->embedded_media_experience_enabled()),
[email protected]69db58f2018-09-26 20:27:56324 surface_layer_mode_(params->use_surface_layer_for_video()),
CJ DiMeglio96c18b692018-07-04 03:39:06325 create_bridge_callback_(params->create_bridge_callback()),
liberato2ff93ad2017-05-17 07:28:24326 request_routing_token_cb_(params->request_routing_token_cb()),
Dale Curtis1adbe6a2017-08-02 02:09:13327 overlay_routing_token_(OverlayInfo::RoutingToken()),
Sergey Volk8b09c2c52018-12-12 23:20:40328 media_metrics_provider_(params->take_metrics_provider()),
329 is_background_suspend_enabled_(params->IsBackgroundSuspendEnabled()),
Junbo Kefba620b2019-01-16 02:54:36330 is_background_video_playback_enabled_(
331 params->IsBackgroundVideoPlaybackEnabled()),
Sergey Volk8b09c2c52018-12-12 23:20:40332 is_background_video_track_optimization_supported_(
Dan Sanders6edfd782019-08-13 00:13:18333 params->IsBackgroundVideoTrackOptimizationSupported()),
Chih-Hsuan Kuo7b4fb102020-03-04 08:21:49334 is_remoting_renderer_enabled_(params->IsRemotingRendererEnabled()),
Dan Sanders6edfd782019-08-13 00:13:18335 simple_watch_timer_(
336 base::BindRepeating(&WebMediaPlayerImpl::OnSimpleWatchTimerTick,
337 base::Unretained(this)),
338 base::BindRepeating(&WebMediaPlayerImpl::GetCurrentTimeInternal,
[email protected]91fd3162019-09-05 23:51:32339 base::Unretained(this))),
[email protected]dc996312019-12-19 19:26:38340 will_play_helper_(nullptr),
David Dorwin30993312020-05-07 22:39:09341 demuxer_override_(params->TakeDemuxerOverride()),
[email protected]dc996312019-12-19 19:26:38342 power_status_helper_(params->TakePowerStatusHelper()) {
xhwang51139732017-02-24 19:36:08343 DVLOG(1) << __func__;
Dale Curtise25163812018-09-21 22:13:39344 DCHECK(adjust_allocated_memory_cb_);
tguilbert70d2a00a2017-04-25 00:30:44345 DCHECK(renderer_factory_selector_);
servolkef1e5ef2016-03-25 04:55:26346 DCHECK(client_);
tguilbert1bb1c782017-01-23 21:15:11347 DCHECK(delegate_);
dalecurtis83266c72015-10-29 18:43:20348
Antonio Gomes142f32a2019-05-15 23:32:56349 weak_this_ = weak_factory_.GetWeakPtr();
350
Xiaohan Wang2480de72019-11-15 01:44:47351 // Using base::Unretained(this) is safe because the |pipeline| is owned by
352 // |this| and the callback will always be made on the main task runner.
353 // Not using BindToCurrentLoop() because CreateRenderer() is a sync call.
354 auto pipeline = std::make_unique<PipelineImpl>(
355 media_task_runner_, main_task_runner_,
356 base::BindRepeating(&WebMediaPlayerImpl::CreateRenderer,
357 base::Unretained(this)),
358 media_log_.get());
359
Antonio Gomes81b56552019-05-15 22:15:28360 pipeline_controller_ = std::make_unique<PipelineController>(
Xiaohan Wang2480de72019-11-15 01:44:47361 std::move(pipeline),
Antonio Gomes142f32a2019-05-15 23:32:56362 base::BindRepeating(&WebMediaPlayerImpl::OnPipelineSeeked, weak_this_),
363 base::BindRepeating(&WebMediaPlayerImpl::OnPipelineSuspended, weak_this_),
Antonio Gomes81b56552019-05-15 22:15:28364 base::BindRepeating(&WebMediaPlayerImpl::OnBeforePipelineResume,
Antonio Gomes142f32a2019-05-15 23:32:56365 weak_this_),
366 base::BindRepeating(&WebMediaPlayerImpl::OnPipelineResumed, weak_this_),
367 base::BindRepeating(&WebMediaPlayerImpl::OnError, weak_this_));
Antonio Gomes81b56552019-05-15 22:15:28368
369 buffered_data_source_host_ = std::make_unique<BufferedDataSourceHostImpl>(
Antonio Gomes142f32a2019-05-15 23:32:56370 base::BindRepeating(&WebMediaPlayerImpl::OnProgress, weak_this_),
Antonio Gomes81b56552019-05-15 22:15:28371 tick_clock_);
372
[email protected]c8d574722017-08-30 20:53:43373 // If we're supposed to force video overlays, then make sure that they're
374 // enabled all the time.
375 always_enable_overlays_ = base::CommandLine::ForCurrentProcess()->HasSwitch(
tsunghungee562e92016-07-20 18:03:31376 switches::kForceVideoOverlays);
377
Jinsong Fan982342112019-11-07 23:45:45378 if (base::FeatureList::IsEnabled(kOverlayFullscreenVideo))
379 overlay_mode_ = OverlayMode::kUseAndroidOverlay;
380 else
liberato2ff93ad2017-05-17 07:28:24381 overlay_mode_ = OverlayMode::kNoOverlays;
ampea73f792017-01-19 04:05:39382
tguilbert1bb1c782017-01-23 21:15:11383 delegate_id_ = delegate_->AddObserver(this);
384 delegate_->SetIdle(delegate_id_, true);
sandersd1e49fb62015-12-12 01:18:06385
Ted Meyer0134aed2020-01-23 23:56:40386 media_log_->AddEvent<MediaLogEvent::kWebMediaPlayerCreated>(
387 url::Origin(frame_->GetSecurityOrigin()).GetURL().spec());
Ted Meyera698afe2019-11-06 20:58:03388
Ted Meyer7f5b4e22019-11-21 03:21:19389 media_log_->SetProperty<MediaLogProperty::kFrameUrl>(
390 SanitizeUserStringProperty(frame_->GetDocument().Url().GetString()));
391 media_log_->SetProperty<MediaLogProperty::kFrameTitle>(
392 SanitizeUserStringProperty(frame_->GetDocument().Title()));
[email protected]52b0b212018-10-10 05:25:28393
dalecurtis9cddc0b2017-04-19 21:23:38394 if (params->initial_cdm())
Chris Cunninghamd4a00192019-03-21 20:02:49395 SetCdmInternal(params->initial_cdm());
xhwang0ad11e512014-11-25 23:43:09396
Xiaohan Wangf63505d2017-10-21 08:00:53397 // Report a false "EncrytpedEvent" here as a baseline.
398 RecordEncryptedEvent(false);
399
xhwangf94a634d2014-10-22 22:07:27400 // TODO(xhwang): When we use an external Renderer, many methods won't work,
xhwang6fa356202014-12-11 00:44:12401 // e.g. GetCurrentFrameFromCompositor(). See http://crbug.com/434861
Antonio Gomes3a858b52019-05-31 02:47:52402 audio_source_provider_ = new blink::WebAudioSourceProviderImpl(
dalecurtis9cddc0b2017-04-19 21:23:38403 params->audio_renderer_sink(), media_log_.get());
xjz4e5d4bf32017-02-15 21:26:35404
405 if (observer_)
406 observer_->SetClient(this);
Hajime Hoshi8bb37dc2017-12-19 09:35:10407
408 memory_usage_reporting_timer_.SetTaskRunner(
Hajime Hoshib5a26ee2018-05-14 12:47:51409 frame_->GetTaskRunner(blink::TaskType::kInternalMedia));
John Delaney6c8ecc1b2018-10-21 19:07:29410
Eugene Zemtsov77d56262020-03-06 05:52:03411 main_thread_mem_dumper_ = std::make_unique<MemoryDumpProviderProxy>(
412 "WebMediaPlayer_MainThread", main_task_runner_,
413 base::BindRepeating(&WebMediaPlayerImpl::OnMainThreadMemoryDump,
414 weak_this_, media_log_->id()));
415
Sergey Ulanovb8656772020-04-21 22:56:14416 media_metrics_provider_->AcquirePlaybackEventsRecorder(
417 playback_events_recorder_.BindNewPipeAndPassReceiver());
418
Sergey Ulanovb55701812020-04-29 01:39:37419 // MediaMetricsProvider may drop the request for PlaybackEventsRecorder if
420 // it's not interested in recording these events.
421 playback_events_recorder_.reset_on_disconnect();
422
Thomas Guilbert901808982019-07-03 20:38:18423#if defined(OS_ANDROID)
Thomas Guilbertf6d0702e2019-09-12 23:40:14424 renderer_factory_selector_->SetRemotePlayStateChangeCB(
425 BindToCurrentLoop(base::BindRepeating(
426 &WebMediaPlayerImpl::OnRemotePlayStateChange, weak_this_)));
Thomas Guilbert901808982019-07-03 20:38:18427#endif // defined (OS_ANDROID)
[email protected]ec9212f2008-12-18 21:40:36428}
429
[email protected]4e6be3f2009-05-07 02:24:44430WebMediaPlayerImpl::~WebMediaPlayerImpl() {
xhwang51139732017-02-24 19:36:08431 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:43432 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53433
xhwang51139732017-02-24 19:36:08434 if (set_cdm_result_) {
Chris Cunninghamd4a00192019-03-21 20:02:49435 DVLOG(2)
436 << "Resolve pending SetCdmInternal() when media player is destroyed.";
Blink Reformat1c4d759e2017-04-09 16:34:54437 set_cdm_result_->Complete();
xhwang51139732017-02-24 19:36:08438 set_cdm_result_.reset();
439 }
440
alokp1116967f2016-06-11 17:30:56441 suppress_destruction_errors_ = true;
tguilbert1bb1c782017-01-23 21:15:11442
443 delegate_->PlayerGone(delegate_id_);
444 delegate_->RemoveObserver(delegate_id_);
[email protected]baff4512011-10-19 18:21:07445
dalecurtis04bdb582016-08-17 22:15:23446 // Finalize any watch time metrics before destroying the pipeline.
447 watch_time_reporter_.reset();
448
Eugene Zemtsov77d56262020-03-06 05:52:03449 // Unregister dump providers on their corresponding threads.
450 media_task_runner_->DeleteSoon(FROM_HERE,
451 std::move(media_thread_mem_dumper_));
452 main_thread_mem_dumper_.reset();
453
tguilbert350936ff2017-02-24 05:39:27454 // The underlying Pipeline must be stopped before it is destroyed.
Dale Curtisf273f8f2018-12-13 23:40:33455 //
456 // Note: This destruction happens synchronously on the media thread and
457 // |demuxer_|, |data_source_|, |compositor_|, and |media_log_| must outlive
458 // this process. They will be destructed by the DestructionHelper below
459 // after trampolining through the media thread.
Antonio Gomes81b56552019-05-15 22:15:28460 pipeline_controller_->Stop();
[email protected]f6af7592014-02-28 10:09:11461
dalecurtis83266c72015-10-29 18:43:20462 if (last_reported_memory_usage_)
463 adjust_allocated_memory_cb_.Run(-last_reported_memory_usage_);
464
dalecurtise1edb312016-06-22 02:33:21465 // Destruct compositor resources in the proper order.
danakj8d204a42018-05-18 18:05:35466 client_->SetCcLayer(nullptr);
CJ DiMeglio2302d202017-08-31 08:38:04467
Xiangjun Zhang5e20cba42018-01-10 19:54:56468 client_->MediaRemotingStopped(
Gyuyoung Kimf99f5f32019-09-26 03:45:15469 blink::WebMediaPlayerClient::kMediaRemotingStopNoText);
Xiangjun Zhang87299142017-09-13 20:35:03470
Dale Curtisf273f8f2018-12-13 23:40:33471 if (!surface_layer_for_video_enabled_ && video_layer_)
danakj25f030112018-05-11 18:26:54472 video_layer_->StopUsingProvider();
Matt Wolenetz95af6362018-01-04 20:23:42473
Dan Sanders6edfd782019-08-13 00:13:18474 simple_watch_timer_.Stop();
Ted Meyer257b682a2019-11-01 20:50:51475 media_log_->OnWebMediaPlayerDestroyed();
[email protected]ec9212f2008-12-18 21:40:36476
Dale Curtisf273f8f2018-12-13 23:40:33477 if (data_source_)
478 data_source_->Stop();
479
480 // Disconnect from the surface layer. We still preserve the |bridge_| until
481 // after pipeline shutdown to ensure any pending frames are painted for tests.
482 if (bridge_)
483 bridge_->ClearObserver();
484
Dale Curtisc96a3542018-12-17 22:15:23485 // Disconnect from the MediaObserver implementation since it's lifetime is
486 // tied to the RendererFactorySelector which can't be destroyed until after
487 // the Pipeline stops.
488 //
489 // Note: We can't use a WeakPtr with the RendererFactory because its methods
490 // are called on the media thread and this destruction takes place on the
491 // renderer thread.
492 if (observer_)
493 observer_->SetClient(nullptr);
494
[email protected]91fd3162019-09-05 23:51:32495 // If we're in the middle of an observation, then finish it.
496 will_play_helper_.CompleteObservationIfNeeded(learning::TargetValue(false));
497
Dale Curtisf273f8f2018-12-13 23:40:33498 // Handle destruction of things that need to be destructed after the pipeline
499 // completes stopping on the media thread.
500 media_task_runner_->PostTask(
Matt Wolenetz95af6362018-01-04 20:23:42501 FROM_HERE,
Dale Curtisf273f8f2018-12-13 23:40:33502 base::BindOnce(&DestructionHelper, std::move(main_task_runner_),
503 std::move(vfc_task_runner_), std::move(demuxer_),
504 std::move(data_source_), std::move(compositor_),
505 std::move(cdm_context_ref_),
506 std::move(pending_cdm_context_ref_), std::move(media_log_),
507 std::move(renderer_factory_selector_), std::move(bridge_),
508 !!chunk_demuxer_));
Matt Wolenetz95af6362018-01-04 20:23:42509}
510
chcunningham707b821e2018-05-29 08:42:19511WebMediaPlayer::LoadTiming WebMediaPlayerImpl::Load(
512 LoadType load_type,
513 const blink::WebMediaPlayerSource& source,
Takashi Toyoshima2e01e692018-11-16 03:23:27514 CorsMode cors_mode) {
guidou9bfe4e2f2016-04-09 08:31:19515 // Only URL or MSE blob URL is supported.
Blink Reformat1c4d759e2017-04-09 16:34:54516 DCHECK(source.IsURL());
517 blink::WebURL url = source.GetAsURL();
Xiaohan Wang81fd0022017-07-11 17:45:24518 DVLOG(1) << __func__ << "(" << load_type << ", " << GURL(url) << ", "
519 << cors_mode << ")";
chcunningham707b821e2018-05-29 08:42:19520
521 bool is_deferred = false;
522
Dale Curtise25163812018-09-21 22:13:39523 if (defer_load_cb_) {
chcunningham707b821e2018-05-29 08:42:19524 is_deferred = defer_load_cb_.Run(base::BindOnce(
Antonio Gomes142f32a2019-05-15 23:32:56525 &WebMediaPlayerImpl::DoLoad, weak_this_, load_type, url, cors_mode));
chcunningham707b821e2018-05-29 08:42:19526 } else {
527 DoLoad(load_type, url, cors_mode);
[email protected]d726eddc2013-07-02 22:25:55528 }
chcunningham707b821e2018-05-29 08:42:19529
530 return is_deferred ? LoadTiming::kDeferred : LoadTiming::kImmediate;
[email protected]62e5e682013-03-07 23:53:24531}
532
CJ DiMeglio013d4c472017-11-21 03:27:30533void WebMediaPlayerImpl::OnWebLayerUpdated() {}
534
danakj6a062b112018-05-17 16:25:45535void WebMediaPlayerImpl::RegisterContentsLayer(cc::Layer* layer) {
CJ DiMeglio2302d202017-08-31 08:38:04536 DCHECK(bridge_);
CJ DiMeglioa2b13fbc2018-06-27 00:50:59537 bridge_->SetContentsOpaque(opaque_);
danakj8d204a42018-05-18 18:05:35538 client_->SetCcLayer(layer);
CJ DiMeglio013d4c472017-11-21 03:27:30539}
540
danakj6a062b112018-05-17 16:25:45541void WebMediaPlayerImpl::UnregisterContentsLayer(cc::Layer* layer) {
542 // |client_| will unregister its cc::Layer if given a nullptr.
danakj8d204a42018-05-18 18:05:35543 client_->SetCcLayer(nullptr);
CJ DiMeglio2302d202017-08-31 08:38:04544}
545
Jennifer Apaciblec45fd052018-02-25 12:04:55546void WebMediaPlayerImpl::OnSurfaceIdUpdated(viz::SurfaceId surface_id) {
Jennifer Apaciblec45fd052018-02-25 12:04:55547 // TODO(726619): Handle the behavior when Picture-in-Picture mode is
548 // disabled.
Jennifer Apacible2b1dc5eb2018-04-27 16:23:28549 // The viz::SurfaceId may be updated when the video begins playback or when
550 // the size of the video changes.
Mounir Lamouri99ba5a62019-02-12 01:27:47551 if (client_)
552 client_->OnPictureInPictureStateChange();
Jennifer Apaciblec45fd052018-02-25 12:04:55553}
554
tsunghungee562e92016-07-20 18:03:31555void WebMediaPlayerImpl::EnableOverlay() {
556 overlay_enabled_ = true;
[email protected]f7df5b342018-07-13 20:22:13557 if (request_routing_token_cb_ &&
558 overlay_mode_ == OverlayMode::kUseAndroidOverlay) {
liberatofe8f9692017-06-08 19:17:36559 overlay_routing_token_is_pending_ = true;
liberato2ff93ad2017-05-17 07:28:24560 token_available_cb_.Reset(
Antonio Gomes142f32a2019-05-15 23:32:56561 base::Bind(&WebMediaPlayerImpl::OnOverlayRoutingToken, weak_this_));
liberato2ff93ad2017-05-17 07:28:24562 request_routing_token_cb_.Run(token_available_cb_.callback());
watkf835a792016-06-24 23:24:40563 }
tsunghungee562e92016-07-20 18:03:31564
liberato2ff93ad2017-05-17 07:28:24565 // We have requested (and maybe already have) overlay information. If the
566 // restarted decoder requests overlay information, then we'll defer providing
567 // it if it hasn't arrived yet. Otherwise, this would be a race, since we
568 // don't know if the request for overlay info or restart will complete first.
tsunghungee562e92016-07-20 18:03:31569 if (decoder_requires_restart_for_overlay_)
watkdee516f2016-02-18 02:22:19570 ScheduleRestart();
571}
572
tsunghungee562e92016-07-20 18:03:31573void WebMediaPlayerImpl::DisableOverlay() {
574 overlay_enabled_ = false;
Jinsong Fan982342112019-11-07 23:45:45575 if (overlay_mode_ == OverlayMode::kUseAndroidOverlay) {
liberato2ff93ad2017-05-17 07:28:24576 token_available_cb_.Cancel();
liberatofe8f9692017-06-08 19:17:36577 overlay_routing_token_is_pending_ = false;
578 overlay_routing_token_ = OverlayInfo::RoutingToken();
liberato2ff93ad2017-05-17 07:28:24579 }
tsunghungee562e92016-07-20 18:03:31580
581 if (decoder_requires_restart_for_overlay_)
watkdee516f2016-02-18 02:22:19582 ScheduleRestart();
liberato2ff93ad2017-05-17 07:28:24583 else
584 MaybeSendOverlayInfoToDecoder();
watkdee516f2016-02-18 02:22:19585}
586
Blink Reformat1c4d759e2017-04-09 16:34:54587void WebMediaPlayerImpl::EnteredFullscreen() {
liberatofe8f9692017-06-08 19:17:36588 overlay_info_.is_fullscreen = true;
589
[email protected]c8d574722017-08-30 20:53:43590 // |always_enable_overlays_| implies that we're already in overlay mode, so
591 // take no action here. Otherwise, switch to an overlay if it's allowed and
592 // if it will display properly.
593 if (!always_enable_overlays_ && overlay_mode_ != OverlayMode::kNoOverlays &&
liberato2fd111be2017-01-04 00:25:06594 DoesOverlaySupportMetadata()) {
tsunghungee562e92016-07-20 18:03:31595 EnableOverlay();
liberato2fd111be2017-01-04 00:25:06596 }
liberato2ff93ad2017-05-17 07:28:24597
liberatofe8f9692017-06-08 19:17:36598 // We send this only if we can send multiple calls. Otherwise, either (a)
599 // we already sent it and we don't have a callback anyway (we reset it when
600 // it's called in restart mode), or (b) we'll send this later when the surface
601 // actually arrives. GVD assumes that the first overlay info will have the
602 // routing information. Note that we set |is_fullscreen_| earlier, so that
603 // if EnableOverlay() can include fullscreen info in case it sends the overlay
604 // info before returning.
605 if (!decoder_requires_restart_for_overlay_)
606 MaybeSendOverlayInfoToDecoder();
tsunghungee562e92016-07-20 18:03:31607}
608
Blink Reformat1c4d759e2017-04-09 16:34:54609void WebMediaPlayerImpl::ExitedFullscreen() {
liberatofe8f9692017-06-08 19:17:36610 overlay_info_.is_fullscreen = false;
611
[email protected]c8d574722017-08-30 20:53:43612 // If we're in overlay mode, then exit it unless we're supposed to allow
613 // overlays all the time.
614 if (!always_enable_overlays_ && overlay_enabled_)
tsunghungee562e92016-07-20 18:03:31615 DisableOverlay();
liberato2ff93ad2017-05-17 07:28:24616
liberatofe8f9692017-06-08 19:17:36617 // See EnteredFullscreen for why we do this.
618 if (!decoder_requires_restart_for_overlay_)
619 MaybeSendOverlayInfoToDecoder();
tsunghungee562e92016-07-20 18:03:31620}
621
Chisoon Jeong81080c922019-09-03 23:40:18622void WebMediaPlayerImpl::BecameDominantVisibleContent(bool is_dominant) {
xjzcdbbe732016-12-03 20:47:42623 if (observer_)
Chisoon Jeong81080c922019-09-03 23:40:18624 observer_->OnBecameDominantVisibleContent(is_dominant);
xjzcdbbe732016-12-03 20:47:42625}
626
Blink Reformat1c4d759e2017-04-09 16:34:54627void WebMediaPlayerImpl::SetIsEffectivelyFullscreen(
François Beaufortad6c5232018-02-26 11:00:44628 blink::WebFullscreenVideoStatus fullscreen_video_status) {
629 delegate_->SetIsEffectivelyFullscreen(delegate_id_, fullscreen_video_status);
[email protected]0526d5692020-02-28 00:24:31630
631 if (power_status_helper_) {
632 // We don't care about pip, so anything that's "not fullscreen" is good
633 // enough for us.
634 power_status_helper_->SetIsFullscreen(
635 fullscreen_video_status !=
636 blink::WebFullscreenVideoStatus::kNotEffectivelyFullscreen);
637 }
zqzhangabc08242017-03-02 16:07:14638}
639
Mounir Lamouri41a79c62017-06-06 12:53:16640void WebMediaPlayerImpl::OnHasNativeControlsChanged(bool has_native_controls) {
641 if (!watch_time_reporter_)
642 return;
643
644 if (has_native_controls)
645 watch_time_reporter_->OnNativeControlsEnabled();
646 else
647 watch_time_reporter_->OnNativeControlsDisabled();
648}
649
Mounir Lamourif9af74e72017-06-19 19:31:45650void WebMediaPlayerImpl::OnDisplayTypeChanged(
651 WebMediaPlayer::DisplayType display_type) {
Mounir Lamouri0484f40a2018-07-25 03:03:26652 if (surface_layer_for_video_enabled_) {
653 vfc_task_runner_->PostTask(
654 FROM_HERE,
655 base::BindOnce(
656 &VideoFrameCompositor::SetForceSubmit,
657 base::Unretained(compositor_.get()),
658 display_type == WebMediaPlayer::DisplayType::kPictureInPicture));
659 }
660
Mounir Lamourif9af74e72017-06-19 19:31:45661 if (!watch_time_reporter_)
662 return;
663
664 switch (display_type) {
665 case WebMediaPlayer::DisplayType::kInline:
666 watch_time_reporter_->OnDisplayTypeInline();
667 break;
668 case WebMediaPlayer::DisplayType::kFullscreen:
669 watch_time_reporter_->OnDisplayTypeFullscreen();
670 break;
671 case WebMediaPlayer::DisplayType::kPictureInPicture:
672 watch_time_reporter_->OnDisplayTypePictureInPicture();
François Beaufort3f62f382019-01-18 15:05:17673
674 // Resumes playback if it was paused when hidden.
675 if (paused_when_hidden_) {
676 paused_when_hidden_ = false;
677 OnPlay();
678 }
Mounir Lamourif9af74e72017-06-19 19:31:45679 break;
680 }
681}
682
[email protected]ef8394c2013-08-21 20:26:30683void WebMediaPlayerImpl::DoLoad(LoadType load_type,
[email protected]180ef242013-11-07 06:50:46684 const blink::WebURL& url,
Takashi Toyoshima2e01e692018-11-16 03:23:27685 CorsMode cors_mode) {
John Chen5b164a02017-11-01 00:36:09686 TRACE_EVENT1("media", "WebMediaPlayerImpl::DoLoad", "id", media_log_->id());
pkastingf5279482016-07-27 02:18:20687 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:43688 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d726eddc2013-07-02 22:25:55689
[email protected]91fd3162019-09-05 23:51:32690 // Start a new observation. If there was one before, then we didn't play it.
691 will_play_helper_.CompleteObservationIfNeeded(learning::TargetValue(false));
692 // For now, send in an empty set of features. We should fill some in here,
693 // and / or ask blink (via |client_|) for features from the DOM.
694 learning::FeatureDictionary dict;
695 will_play_helper_.BeginObservation(dict);
696
Thomas Guilbert55b48d92019-03-25 23:16:54697#if defined(OS_ANDROID)
698 // Only allow credentials if the crossorigin attribute is unspecified
699 // (kCorsModeUnspecified) or "use-credentials" (kCorsModeUseCredentials).
700 // This value is only used by the MediaPlayerRenderer.
701 // See https://crbug.com/936566.
702 //
703 // The credentials mode also has repercussions in WouldTaintOrigin(), but we
704 // access what we need from |mb_data_source_|->cors_mode() directly, instead
705 // of storing it here.
706 allow_media_player_renderer_credentials_ = cors_mode != kCorsModeAnonymous;
707#endif // defined(OS_ANDROID)
708
Dale Curtis4841c712018-12-13 18:14:05709 // Note: |url| may be very large, take care when making copies.
710 loaded_url_ = GURL(url);
711 load_type_ = load_type;
712
713 ReportMetrics(load_type, loaded_url_, *frame_, media_log_.get());
[email protected]62e5e682013-03-07 23:53:24714
Dale Curtis4841c712018-12-13 18:14:05715 // Set subresource URL for crash reporting; will be truncated to 256 bytes.
Robert Sesekc5e91df2017-12-12 21:11:03716 static base::debug::CrashKeyString* subresource_url =
717 base::debug::AllocateCrashKeyString("subresource_url",
718 base::debug::CrashKeySize::Size256);
Dale Curtis4841c712018-12-13 18:14:05719 base::debug::SetCrashKeyString(subresource_url, loaded_url_.spec());
[email protected]ef8394c2013-08-21 20:26:30720
Blink Reformat1c4d759e2017-04-09 16:34:54721 SetNetworkState(WebMediaPlayer::kNetworkStateLoading);
722 SetReadyState(WebMediaPlayer::kReadyStateHaveNothing);
Ted Meyer0134aed2020-01-23 23:56:40723 media_log_->AddEvent<MediaLogEvent::kLoad>(url.GetString().Utf8());
Dale Curtis3899090ea2018-01-12 00:10:35724 load_start_time_ = base::TimeTicks::Now();
[email protected]d726eddc2013-07-02 22:25:55725
[email protected]91379332020-01-26 03:58:20726 // If we're adapting, then restart the smoothness experiment.
727 if (smoothness_helper_)
728 smoothness_helper_.reset();
729
Antonio Gomesf01cfbd2019-07-12 08:53:11730 media_metrics_provider_->Initialize(
731 load_type == kLoadTypeMediaSource,
732 load_type == kLoadTypeURL ? blink::GetMediaURLScheme(loaded_url_)
733 : mojom::MediaURLScheme::kUnknown);
Dale Curtis74612b72017-12-14 20:56:19734
David Dorwin30993312020-05-07 22:39:09735 if (demuxer_override_ || load_type == kLoadTypeMediaSource) {
736 // If a demuxer override was specified or a Media Source pipeline will be
737 // used, the pipeline can start immediately.
[email protected]ef8394c2013-08-21 20:26:30738 StartPipeline();
hubbe5f0ad43b2015-12-14 20:57:26739 } else {
Dale Curtis4841c712018-12-13 18:14:05740 // Short circuit the more complex loading path for data:// URLs. Sending
741 // them through the network based loading path just wastes memory and causes
742 // worse performance since reads become asynchronous.
743 if (loaded_url_.SchemeIs(url::kDataScheme)) {
744 std::string mime_type, charset, data;
Dale Curtis44eacb72019-06-10 20:41:28745 if (!net::DataURL::Parse(loaded_url_, &mime_type, &charset, &data) ||
746 data.empty()) {
Dale Curtis4841c712018-12-13 18:14:05747 DataSourceInitialized(false);
748 return;
749 }
750
751 // Replace |loaded_url_| with an empty data:// URL since it may be large.
752 loaded_url_ = GURL("data:,");
753
754 // Mark all the data as buffered.
Antonio Gomes81b56552019-05-15 22:15:28755 buffered_data_source_host_->SetTotalBytes(data.size());
756 buffered_data_source_host_->AddBufferedByteRange(0, data.size());
Dale Curtis4841c712018-12-13 18:14:05757
758 DCHECK(!mb_data_source_);
Jose Lopes9023b6d2020-02-19 20:42:37759 data_source_ = std::make_unique<MemoryDataSource>(std::move(data));
Dale Curtis4841c712018-12-13 18:14:05760 DataSourceInitialized(true);
761 return;
762 }
763
John Delaneyb933391602018-10-17 21:50:47764 auto url_data =
Takashi Toyoshima2e01e692018-11-16 03:23:27765 url_index_->GetByUrl(url, static_cast<UrlData::CorsMode>(cors_mode));
Dale Curtis4841c712018-12-13 18:14:05766 mb_data_source_ = new MultibufferDataSource(
John Delaneyb933391602018-10-17 21:50:47767 main_task_runner_, std::move(url_data), media_log_.get(),
Antonio Gomes81b56552019-05-15 22:15:28768 buffered_data_source_host_.get(),
Dale Curtis4841c712018-12-13 18:14:05769 base::BindRepeating(&WebMediaPlayerImpl::NotifyDownloading,
Antonio Gomes142f32a2019-05-15 23:32:56770 weak_this_));
Dale Curtis4841c712018-12-13 18:14:05771 data_source_.reset(mb_data_source_);
772 mb_data_source_->SetPreload(preload_);
773 mb_data_source_->SetIsClientAudioElement(client_->IsAudioElement());
774 mb_data_source_->Initialize(
Jose Lopes6c523d42020-02-13 19:52:21775 base::BindOnce(&WebMediaPlayerImpl::DataSourceInitialized, weak_this_));
hubbe5f0ad43b2015-12-14 20:57:26776 }
[email protected]62e5e682013-03-07 23:53:24777}
778
Blink Reformat1c4d759e2017-04-09 16:34:54779void WebMediaPlayerImpl::Play() {
pkastingf5279482016-07-27 02:18:20780 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:43781 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53782
avayvod65fad272017-02-24 01:00:48783 // User initiated play unlocks background video playback.
Mustaq Ahmed4baa9a6e82019-12-20 23:43:46784 if (frame_->HasTransientUserActivation())
avayvod65fad272017-02-24 01:00:48785 video_locked_when_paused_when_hidden_ = false;
786
sandersd35d2c3f2017-01-14 02:04:42787 // TODO(sandersd): Do we want to reset the idle timer here?
tguilbert1bb1c782017-01-23 21:15:11788 delegate_->SetIdle(delegate_id_, false);
[email protected]49480902009-07-14 20:23:43789 paused_ = false;
Antonio Gomes81b56552019-05-15 22:15:28790 pipeline_controller_->SetPlaybackRate(playback_rate_);
dalecurtis4619cd02016-09-22 21:39:10791 background_pause_timer_.Stop();
sandersd1c0bba02016-03-04 23:14:08792
xjz48a9cb72016-12-20 04:02:49793 if (observer_)
794 observer_->OnPlaying();
795
[email protected]96665a82020-01-23 00:35:37796 // Try to create the smoothness helper, in case we were paused before.
797 UpdateSmoothnessHelper();
798
Sergey Ulanovb8656772020-04-21 22:56:14799 if (playback_events_recorder_)
800 playback_events_recorder_->OnPlaying();
801
Mounir Lamouri89c0a1b2018-03-01 15:00:44802 watch_time_reporter_->SetAutoplayInitiated(client_->WasAutoplayInitiated());
803
Dale Curtis051fdf62017-08-05 00:21:13804 // If we're seeking we'll trigger the watch time reporter upon seek completed;
805 // we don't want to start it here since the seek time is unstable. E.g., when
806 // playing content with a positive start time we would have a zero seek time.
807 if (!Seeking()) {
808 DCHECK(watch_time_reporter_);
809 watch_time_reporter_->OnPlaying();
810 }
811
Chris Cunninghamd9df58e2017-08-29 00:04:23812 if (video_decode_stats_reporter_)
813 video_decode_stats_reporter_->OnPlaying();
814
Dan Sanders6edfd782019-08-13 00:13:18815 simple_watch_timer_.Start();
Ted Meyerd5885f82019-07-16 19:19:17816 media_metrics_provider_->SetHasPlayed();
Ted Meyer0134aed2020-01-23 23:56:40817 media_log_->AddEvent<MediaLogEvent::kPlay>();
Dale Curtis18ad391b2019-05-30 23:25:09818
819 MaybeUpdateBufferSizesForPlayback();
sandersd50a635e2016-04-04 22:50:09820 UpdatePlayState();
[email protected]91fd3162019-09-05 23:51:32821
Wojciech Dzierżanowski68f4a522020-04-27 09:48:12822 // Paused changed so we should update media position state.
823 UpdateMediaPositionState();
824
[email protected]91fd3162019-09-05 23:51:32825 // Notify the learning task, if needed.
826 will_play_helper_.CompleteObservationIfNeeded(learning::TargetValue(true));
[email protected]ec9212f2008-12-18 21:40:36827}
828
Blink Reformat1c4d759e2017-04-09 16:34:54829void WebMediaPlayerImpl::Pause() {
pkastingf5279482016-07-27 02:18:20830 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:43831 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53832
sandersd50a635e2016-04-04 22:50:09833 // We update the paused state even when casting, since we expect pause() to be
834 // called when casting begins, and when we exit casting we should end up in a
835 // paused state.
[email protected]49480902009-07-14 20:23:43836 paused_ = true;
hubbed5f36882016-01-15 22:40:37837
avayvodeb9098d2017-01-07 00:33:03838 // No longer paused because it was hidden.
839 paused_when_hidden_ = false;
840
[email protected]96665a82020-01-23 00:35:37841 UpdateSmoothnessHelper();
842
avayvod65fad272017-02-24 01:00:48843 // User initiated pause locks background videos.
Mustaq Ahmed4baa9a6e82019-12-20 23:43:46844 if (frame_->HasTransientUserActivation())
avayvod65fad272017-02-24 01:00:48845 video_locked_when_paused_when_hidden_ = true;
846
Antonio Gomes81b56552019-05-15 22:15:28847 pipeline_controller_->SetPlaybackRate(0.0);
Dale Curtis2fc01cc2019-05-20 22:53:52848
849 // For states <= kReadyStateHaveMetadata, we may not have a renderer yet.
850 if (highest_ready_state_ > WebMediaPlayer::kReadyStateHaveMetadata)
851 paused_time_ = pipeline_controller_->GetMediaTime();
[email protected]090f7312011-08-05 23:26:40852
xjz48a9cb72016-12-20 04:02:49853 if (observer_)
854 observer_->OnPaused();
855
Sergey Ulanovb8656772020-04-21 22:56:14856 if (playback_events_recorder_)
857 playback_events_recorder_->OnPaused();
858
dalecurtis04bdb582016-08-17 22:15:23859 DCHECK(watch_time_reporter_);
860 watch_time_reporter_->OnPaused();
Chris Cunninghamd9df58e2017-08-29 00:04:23861
862 if (video_decode_stats_reporter_)
863 video_decode_stats_reporter_->OnPaused();
864
Dan Sanders6edfd782019-08-13 00:13:18865 simple_watch_timer_.Stop();
Ted Meyer0134aed2020-01-23 23:56:40866 media_log_->AddEvent<MediaLogEvent::kPause>();
avayvod2135a642017-01-13 00:17:14867
Becca Hughes7a85bf22019-07-24 16:16:58868 // Paused changed so we should update media position state.
869 UpdateMediaPositionState();
870
sandersd50a635e2016-04-04 22:50:09871 UpdatePlayState();
[email protected]ec9212f2008-12-18 21:40:36872}
873
Blink Reformat1c4d759e2017-04-09 16:34:54874void WebMediaPlayerImpl::Seek(double seconds) {
pkastingf5279482016-07-27 02:18:20875 DVLOG(1) << __func__ << "(" << seconds << "s)";
acolwellb4034942014-08-28 15:42:43876 DCHECK(main_task_runner_->BelongsToCurrentThread());
Ted Meyer0134aed2020-01-23 23:56:40877 media_log_->AddEvent<MediaLogEvent::kSeek>(seconds);
sandersd1c0bba02016-03-04 23:14:08878 DoSeek(base::TimeDelta::FromSecondsD(seconds), true);
879}
880
881void WebMediaPlayerImpl::DoSeek(base::TimeDelta time, bool time_updated) {
882 DCHECK(main_task_runner_->BelongsToCurrentThread());
John Chen5b164a02017-11-01 00:36:09883 TRACE_EVENT2("media", "WebMediaPlayerImpl::DoSeek", "target",
884 time.InSecondsF(), "id", media_log_->id());
[email protected]d43ed912009-02-03 04:52:53885
srirama.mccf671812015-01-08 11:59:13886 ReadyState old_state = ready_state_;
Blink Reformat1c4d759e2017-04-09 16:34:54887 if (ready_state_ > WebMediaPlayer::kReadyStateHaveMetadata)
888 SetReadyState(WebMediaPlayer::kReadyStateHaveMetadata);
[email protected]1bb666802013-11-28 06:12:08889
Dale Curtis051fdf62017-08-05 00:21:13890 // When paused or ended, we know exactly what the current time is and can
891 // elide seeks to it. However, there are two cases that are not elided:
sandersd1c0bba02016-03-04 23:14:08892 // 1) When the pipeline state is not stable.
893 // In this case we just let |pipeline_controller_| decide what to do, as
894 // it has complete information.
895 // 2) For MSE.
896 // Because the buffers may have changed between seeks, MSE seeks are
897 // never elided.
Antonio Gomes81b56552019-05-15 22:15:28898 if (paused_ && pipeline_controller_->IsStable() &&
Dale Curtis051fdf62017-08-05 00:21:13899 (paused_time_ == time ||
900 (ended_ && time == base::TimeDelta::FromSecondsD(Duration()))) &&
sandersd1c0bba02016-03-04 23:14:08901 !chunk_demuxer_) {
902 // If the ready state was high enough before, we can indicate that the seek
903 // completed just by restoring it. Otherwise we will just wait for the real
904 // ready state change to eventually happen.
Blink Reformat1c4d759e2017-04-09 16:34:54905 if (old_state == kReadyStateHaveEnoughData) {
srirama.m8f4a37562014-12-13 08:16:18906 main_task_runner_->PostTask(
Dale Curtisee9be30012018-09-21 22:21:51907 FROM_HERE, base::BindOnce(&WebMediaPlayerImpl::OnBufferingStateChange,
Chris Cunninghamfc0d67e2019-07-22 20:29:16908 weak_this_, BUFFERING_HAVE_ENOUGH,
909 BUFFERING_CHANGE_REASON_UNKNOWN));
srirama.m36ab2682014-12-11 04:20:01910 }
sandersd1c0bba02016-03-04 23:14:08911 return;
srirama.m36ab2682014-12-11 04:20:01912 }
[email protected]44ff37c02009-10-24 01:03:03913
Sergey Ulanovb8656772020-04-21 22:56:14914 if (playback_events_recorder_)
915 playback_events_recorder_->OnSeeking();
916
dalecurtis04bdb582016-08-17 22:15:23917 // Call this before setting |seeking_| so that the current media time can be
918 // recorded by the reporter.
919 if (watch_time_reporter_)
920 watch_time_reporter_->OnSeeking();
921
sandersd35d2c3f2017-01-14 02:04:42922 // TODO(sandersd): Move |seeking_| to PipelineController.
923 // TODO(sandersd): Do we want to reset the idle timer here?
tguilbert1bb1c782017-01-23 21:15:11924 delegate_->SetIdle(delegate_id_, false);
sandersd50a635e2016-04-04 22:50:09925 ended_ = false;
[email protected]b3766a22010-12-22 17:34:13926 seeking_ = true;
sandersd1c0bba02016-03-04 23:14:08927 seek_time_ = time;
928 if (paused_)
929 paused_time_ = time;
Antonio Gomes81b56552019-05-15 22:15:28930 pipeline_controller_->Seek(time, time_updated);
[email protected]b3766a22010-12-22 17:34:13931
sandersd50a635e2016-04-04 22:50:09932 // This needs to be called after Seek() so that if a resume is triggered, it
933 // is to the correct time.
934 UpdatePlayState();
Becca Hughes7a85bf22019-07-24 16:16:58935
936 // The seek time has changed so we should update the media position state.
937 UpdateMediaPositionState();
[email protected]ec9212f2008-12-18 21:40:36938}
939
Blink Reformat1c4d759e2017-04-09 16:34:54940void WebMediaPlayerImpl::SetRate(double rate) {
pkastingf5279482016-07-27 02:18:20941 DVLOG(1) << __func__ << "(" << rate << ")";
acolwellb4034942014-08-28 15:42:43942 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53943
Matt Wolenetz6010f6c2017-10-18 00:44:36944 if (rate != playback_rate_) {
945 LIMITED_MEDIA_LOG(INFO, media_log_.get(), num_playback_rate_logs_,
946 kMaxNumPlaybackRateLogs)
947 << "Effective playback rate changed from " << playback_rate_ << " to "
948 << rate;
949 }
950
[email protected]49480902009-07-14 20:23:43951 playback_rate_ = rate;
Dale Curtis18ad391b2019-05-30 23:25:09952 if (!paused_)
Antonio Gomes81b56552019-05-15 22:15:28953 pipeline_controller_->SetPlaybackRate(rate);
Dale Curtis18ad391b2019-05-30 23:25:09954
955 MaybeUpdateBufferSizesForPlayback();
Wojciech Dzierżanowski68f4a522020-04-27 09:48:12956
957 // The playback rate has changed so we should rebuild the media position
958 // state.
959 UpdateMediaPositionState();
[email protected]ec9212f2008-12-18 21:40:36960}
961
Blink Reformat1c4d759e2017-04-09 16:34:54962void WebMediaPlayerImpl::SetVolume(double volume) {
pkastingf5279482016-07-27 02:18:20963 DVLOG(1) << __func__ << "(" << volume << ")";
acolwellb4034942014-08-28 15:42:43964 DCHECK(main_task_runner_->BelongsToCurrentThread());
dalecurtisbb3eaac2016-01-27 21:10:25965 volume_ = volume;
Antonio Gomes81b56552019-05-15 22:15:28966 pipeline_controller_->SetVolume(volume_ * volume_multiplier_);
dalecurtis04bdb582016-08-17 22:15:23967 if (watch_time_reporter_)
968 watch_time_reporter_->OnVolumeChange(volume);
Becca Hughes9f6fd4b82017-06-15 10:01:40969 delegate_->DidPlayerMutedStatusChange(delegate_id_, volume == 0.0);
mlamouri910111362016-11-04 11:28:24970
971 // The play state is updated because the player might have left the autoplay
972 // muted state.
973 UpdatePlayState();
[email protected]ec9212f2008-12-18 21:40:36974}
[email protected]f0a51fb52009-03-05 12:46:38975
Chris Cunningham8c2ef912019-11-15 23:10:41976void WebMediaPlayerImpl::SetLatencyHint(double seconds) {
977 DVLOG(1) << __func__ << "(" << seconds << ")";
Chris Cunninghame8c626332019-11-20 23:34:27978 DCHECK(main_task_runner_->BelongsToCurrentThread());
979 base::Optional<base::TimeDelta> latency_hint;
980 if (std::isfinite(seconds)) {
981 DCHECK_GE(seconds, 0);
982 latency_hint = base::TimeDelta::FromSecondsD(seconds);
983 }
984 pipeline_controller_->SetLatencyHint(latency_hint);
Chris Cunningham8c2ef912019-11-15 23:10:41985}
986
Mounir Lamouri967f8fb72019-02-13 02:34:22987void WebMediaPlayerImpl::OnRequestPictureInPicture() {
[email protected]69db58f2018-09-26 20:27:56988 if (!surface_layer_for_video_enabled_)
989 ActivateSurfaceLayerForVideo();
990
Mounir Lamourib642a3c2018-07-09 15:45:31991 DCHECK(bridge_);
Mounir Lamouri99ba5a62019-02-12 01:27:47992 DCHECK(bridge_->GetSurfaceId().is_valid());
Jennifer Apacible3f0489102018-01-19 20:10:31993}
994
Daniel Chengc1710b52018-10-24 03:12:28995void WebMediaPlayerImpl::SetSinkId(
996 const blink::WebString& sink_id,
Antonio Gomese7813f32019-04-02 06:11:03997 blink::WebSetSinkIdCompleteCallback completion_callback) {
guidou69223ce2015-06-16 10:36:19998 DCHECK(main_task_runner_->BelongsToCurrentThread());
pkastingf5279482016-07-27 02:18:20999 DVLOG(1) << __func__;
guidouc7babef2015-10-22 00:42:351000
Dale Curtisca1b78f2019-01-15 03:11:261001 OutputDeviceStatusCB callback =
Antonio Gomese7813f32019-04-02 06:11:031002 ConvertToOutputDeviceStatusCB(std::move(completion_callback));
guidouc7babef2015-10-22 00:42:351003 media_task_runner_->PostTask(
Dale Curtisee9be30012018-09-21 22:21:511004 FROM_HERE, base::BindOnce(&SetSinkIdOnMediaThread, audio_source_provider_,
Daniel Chengc1710b52018-10-24 03:12:281005 sink_id.Utf8(), std::move(callback)));
guidou69223ce2015-06-16 10:36:191006}
1007
Blink Reformat1c4d759e2017-04-09 16:34:541008STATIC_ASSERT_ENUM(WebMediaPlayer::kPreloadNone, MultibufferDataSource::NONE);
1009STATIC_ASSERT_ENUM(WebMediaPlayer::kPreloadMetaData,
dalecurtisb6e052f52016-08-25 00:35:551010 MultibufferDataSource::METADATA);
Blink Reformat1c4d759e2017-04-09 16:34:541011STATIC_ASSERT_ENUM(WebMediaPlayer::kPreloadAuto, MultibufferDataSource::AUTO);
[email protected]23a8b1d82011-04-05 16:28:201012
Blink Reformat1c4d759e2017-04-09 16:34:541013void WebMediaPlayerImpl::SetPreload(WebMediaPlayer::Preload preload) {
pkastingf5279482016-07-27 02:18:201014 DVLOG(1) << __func__ << "(" << preload << ")";
acolwellb4034942014-08-28 15:42:431015 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]4e6be3f2009-05-07 02:24:441016
dalecurtisb6e052f52016-08-25 00:35:551017 preload_ = static_cast<MultibufferDataSource::Preload>(preload);
Dale Curtis4841c712018-12-13 18:14:051018 if (mb_data_source_)
1019 mb_data_source_->SetPreload(preload_);
[email protected]4e6be3f2009-05-07 02:24:441020}
1021
Blink Reformat1c4d759e2017-04-09 16:34:541022bool WebMediaPlayerImpl::HasVideo() const {
acolwellb4034942014-08-28 15:42:431023 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:531024
[email protected]b8877772014-03-26 20:17:151025 return pipeline_metadata_.has_video;
[email protected]d43ed912009-02-03 04:52:531026}
1027
Blink Reformat1c4d759e2017-04-09 16:34:541028bool WebMediaPlayerImpl::HasAudio() const {
acolwellb4034942014-08-28 15:42:431029 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]fc367af2009-08-14 23:06:351030
[email protected]b8877772014-03-26 20:17:151031 return pipeline_metadata_.has_audio;
[email protected]fc367af2009-08-14 23:06:351032}
1033
Blink Reformat1c4d759e2017-04-09 16:34:541034void WebMediaPlayerImpl::EnabledAudioTracksChanged(
servolkf25ceed2016-07-01 03:44:381035 const blink::WebVector<blink::WebMediaPlayer::TrackId>& enabledTrackIds) {
1036 DCHECK(main_task_runner_->BelongsToCurrentThread());
1037
1038 std::ostringstream logstr;
1039 std::vector<MediaTrack::Id> enabledMediaTrackIds;
1040 for (const auto& blinkTrackId : enabledTrackIds) {
Maciej Pawlowskif2556d122019-06-03 08:14:181041 const auto track_id = MediaTrack::Id(blinkTrackId.Utf8().data());
servolkf25ceed2016-07-01 03:44:381042 logstr << track_id << " ";
1043 enabledMediaTrackIds.push_back(track_id);
1044 }
dalecurtis9cddc0b2017-04-19 21:23:381045 MEDIA_LOG(INFO, media_log_.get())
1046 << "Enabled audio tracks: [" << logstr.str() << "]";
Antonio Gomes81b56552019-05-15 22:15:281047 pipeline_controller_->OnEnabledAudioTracksChanged(enabledMediaTrackIds);
servolkf25ceed2016-07-01 03:44:381048}
1049
Blink Reformat1c4d759e2017-04-09 16:34:541050void WebMediaPlayerImpl::SelectedVideoTrackChanged(
servolkf25ceed2016-07-01 03:44:381051 blink::WebMediaPlayer::TrackId* selectedTrackId) {
1052 DCHECK(main_task_runner_->BelongsToCurrentThread());
1053
servolk9bed6602017-02-24 01:20:111054 base::Optional<MediaTrack::Id> selected_video_track_id;
1055 if (selectedTrackId && !video_track_disabled_)
Blink Reformat1c4d759e2017-04-09 16:34:541056 selected_video_track_id = MediaTrack::Id(selectedTrackId->Utf8().data());
dalecurtis9cddc0b2017-04-19 21:23:381057 MEDIA_LOG(INFO, media_log_.get())
Maciej Pawlowskif2556d122019-06-03 08:14:181058 << "Selected video track: ["
1059 << selected_video_track_id.value_or(MediaTrack::Id()) << "]";
Antonio Gomes81b56552019-05-15 22:15:281060 pipeline_controller_->OnSelectedVideoTrackChanged(selected_video_track_id);
servolkf25ceed2016-07-01 03:44:381061}
1062
Dave Tapuskaec1a6d42020-02-12 20:57:481063gfx::Size WebMediaPlayerImpl::NaturalSize() const {
acolwellb4034942014-08-28 15:42:431064 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:531065
Dave Tapuskaec1a6d42020-02-12 20:57:481066 return pipeline_metadata_.natural_size;
[email protected]d43ed912009-02-03 04:52:531067}
1068
Dave Tapuskaec1a6d42020-02-12 20:57:481069gfx::Size WebMediaPlayerImpl::VisibleSize() const {
Jiajia Qin82acdc02017-07-31 09:55:141070 DCHECK(main_task_runner_->BelongsToCurrentThread());
1071 scoped_refptr<VideoFrame> video_frame = GetCurrentFrameFromCompositor();
1072 if (!video_frame)
Dave Tapuskaec1a6d42020-02-12 20:57:481073 return gfx::Size();
Jiajia Qin82acdc02017-07-31 09:55:141074
Dave Tapuskaec1a6d42020-02-12 20:57:481075 return video_frame->visible_rect().size();
Jiajia Qin82acdc02017-07-31 09:55:141076}
1077
Blink Reformat1c4d759e2017-04-09 16:34:541078bool WebMediaPlayerImpl::Paused() const {
acolwellb4034942014-08-28 15:42:431079 DCHECK(main_task_runner_->BelongsToCurrentThread());
Antonio Gomes81b56552019-05-15 22:15:281080 return pipeline_controller_->GetPlaybackRate() == 0.0f;
[email protected]d43ed912009-02-03 04:52:531081}
1082
François Beaufort184f6042019-01-25 05:50:051083bool WebMediaPlayerImpl::PausedWhenHidden() const {
1084 return paused_when_hidden_;
1085}
1086
Blink Reformat1c4d759e2017-04-09 16:34:541087bool WebMediaPlayerImpl::Seeking() const {
acolwellb4034942014-08-28 15:42:431088 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:531089
Blink Reformat1c4d759e2017-04-09 16:34:541090 if (ready_state_ == WebMediaPlayer::kReadyStateHaveNothing)
[email protected]0acebfa2009-08-21 22:45:401091 return false;
[email protected]67cd5052009-09-10 21:53:221092
[email protected]b3766a22010-12-22 17:34:131093 return seeking_;
[email protected]ec9212f2008-12-18 21:40:361094}
1095
Blink Reformat1c4d759e2017-04-09 16:34:541096double WebMediaPlayerImpl::Duration() const {
acolwellb4034942014-08-28 15:42:431097 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]39bdde32013-04-17 17:44:201098
Blink Reformat1c4d759e2017-04-09 16:34:541099 if (ready_state_ == WebMediaPlayer::kReadyStateHaveNothing)
[email protected]39bdde32013-04-17 17:44:201100 return std::numeric_limits<double>::quiet_NaN();
1101
chcunninghamb92d5062017-01-10 21:50:221102 // Use duration from ChunkDemuxer when present. MSE allows users to specify
1103 // duration as a double. This propagates to the rest of the pipeline as a
1104 // TimeDelta with potentially reduced precision (limited to Microseconds).
1105 // ChunkDemuxer returns the full-precision user-specified double. This ensures
1106 // users can "get" the exact duration they "set".
1107 if (chunk_demuxer_)
1108 return chunk_demuxer_->GetDuration();
1109
avayvodcc273dd2017-01-19 19:35:121110 base::TimeDelta pipeline_duration = GetPipelineMediaDuration();
chcunninghamb92d5062017-01-10 21:50:221111 return pipeline_duration == kInfiniteDuration
1112 ? std::numeric_limits<double>::infinity()
1113 : pipeline_duration.InSecondsF();
[email protected]d43ed912009-02-03 04:52:531114}
1115
[email protected]db66d0092014-04-16 07:15:121116double WebMediaPlayerImpl::timelineOffset() const {
acolwellb4034942014-08-28 15:42:431117 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]db66d0092014-04-16 07:15:121118
1119 if (pipeline_metadata_.timeline_offset.is_null())
1120 return std::numeric_limits<double>::quiet_NaN();
1121
1122 return pipeline_metadata_.timeline_offset.ToJsTime();
1123}
1124
Dale Curtis051fdf62017-08-05 00:21:131125base::TimeDelta WebMediaPlayerImpl::GetCurrentTimeInternal() const {
1126 DCHECK(main_task_runner_->BelongsToCurrentThread());
Dale Curtis051fdf62017-08-05 00:21:131127
1128 base::TimeDelta current_time;
1129 if (Seeking())
1130 current_time = seek_time_;
Dale Curtis051fdf62017-08-05 00:21:131131 else if (paused_)
1132 current_time = paused_time_;
1133 else
Antonio Gomes81b56552019-05-15 22:15:281134 current_time = pipeline_controller_->GetMediaTime();
Dale Curtis051fdf62017-08-05 00:21:131135
Dale Curtis77d6057b2019-05-03 01:31:561136 // It's possible for |current_time| to be kInfiniteDuration here if the page
1137 // seeks to kInfiniteDuration (2**64 - 1) when Duration() is infinite.
Dale Curtis051fdf62017-08-05 00:21:131138 DCHECK_GE(current_time, base::TimeDelta());
1139 return current_time;
1140}
1141
Blink Reformat1c4d759e2017-04-09 16:34:541142double WebMediaPlayerImpl::CurrentTime() const {
acolwellb4034942014-08-28 15:42:431143 DCHECK(main_task_runner_->BelongsToCurrentThread());
Blink Reformat1c4d759e2017-04-09 16:34:541144 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
scherkusd2c745b2014-09-04 05:03:401145
Dale Curtis0da6f162020-02-01 01:02:591146 // Even though we have an explicit ended signal, a lot of content doesn't have
1147 // an accurate duration -- with some formats (e.g., VBR MP3, OGG) it can't be
1148 // known without a complete play-through from beginning to end.
1149 //
1150 // The HTML5 spec says that upon ended, current time must equal duration. Due
1151 // to the aforementioned issue, if we rely exclusively on current time, we can
1152 // be a few milliseconds off of the duration.
1153 const auto duration = Duration();
1154 return (ended_ && !std::isinf(duration))
1155 ? duration
Xida Chenccd11472020-01-31 20:02:021156 : GetCurrentTimeInternal().InSecondsF();
[email protected]d43ed912009-02-03 04:52:531157}
1158
Dale Curtis0da6f162020-02-01 01:02:591159bool WebMediaPlayerImpl::IsEnded() const {
1160 DCHECK(main_task_runner_->BelongsToCurrentThread());
1161 return ended_;
1162}
1163
Blink Reformat1c4d759e2017-04-09 16:34:541164WebMediaPlayer::NetworkState WebMediaPlayerImpl::GetNetworkState() const {
acolwellb4034942014-08-28 15:42:431165 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]ddb1e5a2010-12-13 20:10:451166 return network_state_;
1167}
1168
Blink Reformat1c4d759e2017-04-09 16:34:541169WebMediaPlayer::ReadyState WebMediaPlayerImpl::GetReadyState() const {
acolwellb4034942014-08-28 15:42:431170 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]ddb1e5a2010-12-13 20:10:451171 return ready_state_;
1172}
1173
CJ DiMeglio89240472018-10-18 18:21:101174blink::WebMediaPlayer::SurfaceLayerMode
1175WebMediaPlayerImpl::GetVideoSurfaceLayerMode() const {
1176 return surface_layer_mode_;
1177}
1178
wolenetzed8e7092017-04-21 16:28:591179blink::WebString WebMediaPlayerImpl::GetErrorMessage() const {
wolenetz4d39cc02016-04-05 19:54:411180 DCHECK(main_task_runner_->BelongsToCurrentThread());
wolenetzed8e7092017-04-21 16:28:591181 return blink::WebString::FromUTF8(media_log_->GetErrorMessage());
wolenetz4d39cc02016-04-05 19:54:411182}
1183
Blink Reformat1c4d759e2017-04-09 16:34:541184blink::WebTimeRanges WebMediaPlayerImpl::Buffered() const {
acolwellb4034942014-08-28 15:42:431185 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]779a8322014-08-22 21:28:371186
acolwell9e0840d2014-09-06 19:01:321187 Ranges<base::TimeDelta> buffered_time_ranges =
Antonio Gomes81b56552019-05-15 22:15:281188 pipeline_controller_->GetBufferedTimeRanges();
[email protected]779a8322014-08-22 21:28:371189
avayvodcc273dd2017-01-19 19:35:121190 const base::TimeDelta duration = GetPipelineMediaDuration();
dalecurtis39a7f932016-07-19 18:34:591191 if (duration != kInfiniteDuration) {
Antonio Gomes81b56552019-05-15 22:15:281192 buffered_data_source_host_->AddBufferedTimeRanges(&buffered_time_ranges,
1193 duration);
[email protected]779a8322014-08-22 21:28:371194 }
Antonio Gomesf01cfbd2019-07-12 08:53:111195 return blink::ConvertToWebTimeRanges(buffered_time_ranges);
[email protected]02022fc2014-05-16 00:05:311196}
1197
Blink Reformat1c4d759e2017-04-09 16:34:541198blink::WebTimeRanges WebMediaPlayerImpl::Seekable() const {
acolwellb4034942014-08-28 15:42:431199 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]39bdde32013-04-17 17:44:201200
Blink Reformat1c4d759e2017-04-09 16:34:541201 if (ready_state_ < WebMediaPlayer::kReadyStateHaveMetadata)
philipjb0e6f3f2014-09-30 09:51:531202 return blink::WebTimeRanges();
1203
Blink Reformat1c4d759e2017-04-09 16:34:541204 const double seekable_end = Duration();
dalecurtis56359cb2014-10-28 00:06:291205
1206 // Allow a special exception for seeks to zero for streaming sources with a
1207 // finite duration; this allows looping to work.
Dale Curtis4841c712018-12-13 18:14:051208 const bool is_finite_stream = mb_data_source_ &&
1209 mb_data_source_->IsStreaming() &&
tguilbertade2bcb2017-01-07 02:57:451210 std::isfinite(seekable_end);
1211
tguilbert75e2bf62017-04-26 20:13:121212 // Do not change the seekable range when using the MediaPlayerRenderer. It
1213 // will take care of dropping invalid seeks.
1214 const bool force_seeks_to_zero =
1215 !using_media_player_renderer_ && is_finite_stream;
dalecurtis56359cb2014-10-28 00:06:291216
1217 // TODO(dalecurtis): Technically this allows seeking on media which return an
tguilbertade2bcb2017-01-07 02:57:451218 // infinite duration so long as DataSource::IsStreaming() is false. While not
dalecurtis56359cb2014-10-28 00:06:291219 // expected, disabling this breaks semi-live players, http://crbug.com/427412.
1220 const blink::WebTimeRange seekable_range(
tguilbertade2bcb2017-01-07 02:57:451221 0.0, force_seeks_to_zero ? 0.0 : seekable_end);
philipjb0e6f3f2014-09-30 09:51:531222 return blink::WebTimeRanges(&seekable_range, 1);
[email protected]ec9212f2008-12-18 21:40:361223}
1224
sandersd35d2c3f2017-01-14 02:04:421225bool WebMediaPlayerImpl::IsPrerollAttemptNeeded() {
1226 // TODO(sandersd): Replace with |highest_ready_state_since_seek_| if we need
1227 // to ensure that preroll always gets a chance to complete.
1228 // See http://crbug.com/671525.
Dale Curtis69e8f302019-05-22 07:36:581229 //
1230 // Note: Even though we get play/pause signals at kReadyStateHaveMetadata, we
1231 // must attempt to preroll until kReadyStateHaveFutureData so that the
1232 // canplaythrough event will be fired to the page (which may be waiting).
1233 //
1234 // TODO(dalecurtis): We should try signaling kReadyStateHaveFutureData upon
1235 // automatic-suspend of a non-playing element to avoid wasting resources.
1236 if (highest_ready_state_ >= ReadyState::kReadyStateHaveFutureData)
sandersd35d2c3f2017-01-14 02:04:421237 return false;
1238
Fredrik Hubinette4cfb4412017-08-23 00:03:071239 // To suspend before we reach kReadyStateHaveCurrentData is only ok
1240 // if we know we're going to get woken up when we get more data, which
1241 // will only happen if the network is in the "Loading" state.
1242 // This happens when the network is fast, but multiple videos are loading
1243 // and multiplexing gets held up waiting for available threads.
1244 if (highest_ready_state_ <= ReadyState::kReadyStateHaveMetadata &&
1245 network_state_ != WebMediaPlayer::kNetworkStateLoading) {
1246 return true;
1247 }
1248
sandersd35d2c3f2017-01-14 02:04:421249 if (preroll_attempt_pending_)
1250 return true;
1251
1252 // Freshly initialized; there has never been any loading progress. (Otherwise
1253 // |preroll_attempt_pending_| would be true when the start time is null.)
1254 if (preroll_attempt_start_time_.is_null())
1255 return false;
1256
1257 base::TimeDelta preroll_attempt_duration =
1258 tick_clock_->NowTicks() - preroll_attempt_start_time_;
1259 return preroll_attempt_duration < kPrerollAttemptTimeout;
1260}
1261
Blink Reformat1c4d759e2017-04-09 16:34:541262bool WebMediaPlayerImpl::DidLoadingProgress() {
acolwellb4034942014-08-28 15:42:431263 DCHECK(main_task_runner_->BelongsToCurrentThread());
dalecurtise7120dc2016-09-03 02:54:351264
1265 // Note: Separate variables used to ensure both methods are called every time.
Antonio Gomes81b56552019-05-15 22:15:281266 const bool pipeline_progress = pipeline_controller_->DidLoadingProgress();
1267 const bool data_progress = buffered_data_source_host_->DidLoadingProgress();
hubbeb2d3efd2017-05-05 23:26:381268 return pipeline_progress || data_progress;
[email protected]d43ed912009-02-03 04:52:531269}
1270
danakjff6a0262018-06-26 19:50:311271void WebMediaPlayerImpl::Paint(cc::PaintCanvas* canvas,
[email protected]dd5c7972014-08-21 15:00:371272 const blink::WebRect& rect,
Kai Ninomiya9e8ae29b2017-09-06 23:45:161273 cc::PaintFlags& flags,
1274 int already_uploaded_id,
1275 VideoFrameUploadMetadata* out_metadata) {
acolwellb4034942014-08-28 15:42:431276 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]dd061e12014-05-06 19:21:221277 TRACE_EVENT0("media", "WebMediaPlayerImpl:paint");
[email protected]4e6be3f2009-05-07 02:24:441278
watkd16bb3e2017-04-25 01:18:311279 // We can't copy from protected frames.
Xiaohan Wang24cfe2c2018-01-22 23:16:001280 if (cdm_context_ref_)
xhwang80739452016-01-13 00:48:001281 return;
1282
mcasasf1236fc22015-05-29 22:38:561283 scoped_refptr<VideoFrame> video_frame = GetCurrentFrameFromCompositor();
[email protected]0fe5d43b2014-01-24 23:32:451284
[email protected]b49beeb2013-03-01 20:04:001285 gfx::Rect gfx_rect(rect);
mcasas265bdbf82015-06-12 18:44:071286 if (video_frame.get() && video_frame->HasTextures()) {
Nathan Zabriskie04cec1c2020-03-12 00:55:261287 if (!raster_context_provider_)
danakj53f7ec902016-05-21 01:30:101288 return; // Unable to get/create a shared main thread context.
Nathan Zabriskie04cec1c2020-03-12 00:55:261289 if (!raster_context_provider_->GrContext())
danakj53f7ec902016-05-21 01:30:101290 return; // The context has been lost since and can't setup a GrContext.
dongseong.hwang0c4e9d82015-01-08 20:11:131291 }
Kai Ninomiyaef8c9e02017-09-27 04:07:401292 if (out_metadata && video_frame) {
Kai Ninomiya9e8ae29b2017-09-06 23:45:161293 // WebGL last-uploaded-frame-metadata API enabled. https://crbug.com/639174
1294 ComputeFrameUploadMetadata(video_frame.get(), already_uploaded_id,
1295 out_metadata);
1296 if (out_metadata->skipped) {
1297 // Skip uploading this frame.
1298 return;
1299 }
1300 }
zhuoyu.qian4689dde22017-10-16 04:11:481301 video_renderer_.Paint(
Julien Isorce6c83d8de2017-10-12 13:11:291302 video_frame, canvas, gfx::RectF(gfx_rect), flags,
Ted Meyer4a427632019-05-01 19:05:271303 pipeline_metadata_.video_decoder_config.video_transformation(),
Nathan Zabriskie04cec1c2020-03-12 00:55:261304 raster_context_provider_.get());
[email protected]ec9212f2008-12-18 21:40:361305}
[email protected]5df51652009-01-17 00:03:001306
Yutaka Hirano657a0552018-11-09 00:52:551307bool WebMediaPlayerImpl::WouldTaintOrigin() const {
Thomas Guilbert153f84572018-07-19 05:03:581308 if (demuxer_found_hls_) {
1309 // HLS manifests might pull segments from a different origin. We can't know
1310 // for sure, so we conservatively say no here.
Yutaka Hiranoa9cbaa72018-10-10 08:35:221311 return true;
1312 }
1313
Dale Curtis4841c712018-12-13 18:14:051314 if (!mb_data_source_)
Yutaka Hirano657a0552018-11-09 00:52:551315 return false;
1316
1317 // When the resource is redirected to another origin we think it as
1318 // tainted. This is actually not specified, and is under discussion.
1319 // See https://github.com/whatwg/fetch/issues/737.
Dale Curtis4841c712018-12-13 18:14:051320 if (!mb_data_source_->HasSingleOrigin() &&
1321 mb_data_source_->cors_mode() == UrlData::CORS_UNSPECIFIED) {
Yutaka Hirano657a0552018-11-09 00:52:551322 return true;
1323 }
1324
Dale Curtis4841c712018-12-13 18:14:051325 return mb_data_source_->IsCorsCrossOrigin();
[email protected]3fe27112012-06-07 04:00:011326}
1327
Blink Reformat1c4d759e2017-04-09 16:34:541328double WebMediaPlayerImpl::MediaTimeForTimeValue(double timeValue) const {
qinminb4c39782015-08-10 18:43:241329 return base::TimeDelta::FromSecondsD(timeValue).InSecondsF();
[email protected]e06e16d82011-05-26 22:13:331330}
1331
Blink Reformat1c4d759e2017-04-09 16:34:541332unsigned WebMediaPlayerImpl::DecodedFrameCount() const {
acolwellb4034942014-08-28 15:42:431333 DCHECK(main_task_runner_->BelongsToCurrentThread());
Dale Curtisc7d2a7d22018-01-11 20:01:051334 return GetPipelineStatistics().video_frames_decoded;
[email protected]4c51bc662011-02-16 02:03:161335}
1336
Blink Reformat1c4d759e2017-04-09 16:34:541337unsigned WebMediaPlayerImpl::DroppedFrameCount() const {
acolwellb4034942014-08-28 15:42:431338 DCHECK(main_task_runner_->BelongsToCurrentThread());
Dale Curtisc7d2a7d22018-01-11 20:01:051339 return GetPipelineStatistics().video_frames_dropped;
[email protected]4c51bc662011-02-16 02:03:161340}
1341
Dave Tapuska6c7154912018-07-30 20:39:001342uint64_t WebMediaPlayerImpl::AudioDecodedByteCount() const {
acolwellb4034942014-08-28 15:42:431343 DCHECK(main_task_runner_->BelongsToCurrentThread());
Dale Curtisc7d2a7d22018-01-11 20:01:051344 return GetPipelineStatistics().audio_bytes_decoded;
[email protected]4c51bc662011-02-16 02:03:161345}
1346
Dave Tapuska6c7154912018-07-30 20:39:001347uint64_t WebMediaPlayerImpl::VideoDecodedByteCount() const {
acolwellb4034942014-08-28 15:42:431348 DCHECK(main_task_runner_->BelongsToCurrentThread());
Dale Curtisc7d2a7d22018-01-11 20:01:051349 return GetPipelineStatistics().video_bytes_decoded;
[email protected]4c51bc662011-02-16 02:03:161350}
1351
Dale Curtiscdfc6f22019-06-26 22:05:231352bool WebMediaPlayerImpl::HasAvailableVideoFrame() const {
1353 return has_first_frame_;
1354}
1355
Blink Reformat1c4d759e2017-04-09 16:34:541356bool WebMediaPlayerImpl::CopyVideoTextureToPlatformTexture(
danakj46070b02016-03-28 21:54:111357 gpu::gles2::GLES2Interface* gl,
jiajia.qinc2943162017-05-12 01:34:391358 unsigned int target,
zmo57d577a2015-10-30 18:28:591359 unsigned int texture,
kbr0986e622017-04-13 02:34:581360 unsigned internal_format,
1361 unsigned format,
1362 unsigned type,
jiajia.qinc2943162017-05-12 01:34:391363 int level,
zmo57d577a2015-10-30 18:28:591364 bool premultiply_alpha,
Kai Ninomiya9e8ae29b2017-09-06 23:45:161365 bool flip_y,
1366 int already_uploaded_id,
1367 VideoFrameUploadMetadata* out_metadata) {
xhwang213e50c2016-10-10 23:56:311368 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]bfc05f22013-10-19 17:55:161369 TRACE_EVENT0("media", "WebMediaPlayerImpl:copyVideoTextureToPlatformTexture");
1370
watkd16bb3e2017-04-25 01:18:311371 // We can't copy from protected frames.
Xiaohan Wang24cfe2c2018-01-22 23:16:001372 if (cdm_context_ref_)
xhwang213e50c2016-10-10 23:56:311373 return false;
[email protected]dd061e12014-05-06 19:21:221374
xhwang213e50c2016-10-10 23:56:311375 scoped_refptr<VideoFrame> video_frame = GetCurrentFrameFromCompositor();
jbauman581d041c2016-07-21 01:01:031376 if (!video_frame.get() || !video_frame->HasTextures()) {
[email protected]e56f88c72013-06-25 22:31:291377 return false;
dongseong.hwang0c4e9d82015-01-08 20:11:131378 }
Kai Ninomiya9e8ae29b2017-09-06 23:45:161379 if (out_metadata) {
1380 // WebGL last-uploaded-frame-metadata API is enabled.
1381 // https://crbug.com/639174
1382 ComputeFrameUploadMetadata(video_frame.get(), already_uploaded_id,
1383 out_metadata);
1384 if (out_metadata->skipped) {
1385 // Skip uploading this frame.
1386 return true;
1387 }
1388 }
[email protected]df41e252014-02-03 23:39:501389
zhuoyu.qian4689dde22017-10-16 04:11:481390 return video_renderer_.CopyVideoFrameTexturesToGLTexture(
Nathan Zabriskie04cec1c2020-03-12 00:55:261391 raster_context_provider_.get(), gl, video_frame.get(), target, texture,
Dan Sanders930cc1d2018-10-03 00:45:081392 internal_format, format, type, level, premultiply_alpha, flip_y);
[email protected]6523b242013-03-13 11:10:071393}
1394
Yan, Shaobo44b79ba2019-04-02 06:09:271395bool WebMediaPlayerImpl::PrepareVideoFrameForWebGL(
1396 gpu::gles2::GLES2Interface* gl,
1397 unsigned target,
1398 unsigned texture,
1399 int already_uploaded_id,
1400 WebMediaPlayer::VideoFrameUploadMetadata* out_metadata) {
1401 DCHECK(main_task_runner_->BelongsToCurrentThread());
1402 TRACE_EVENT0("media", "WebMediaPlayerImpl::PrepareVideoFrameForWebGL");
1403
1404 // TODO(crbug.com/776222): How to deal with protected frames.
1405 scoped_refptr<VideoFrame> video_frame = GetCurrentFrameFromCompositor();
1406 if (!video_frame.get() || !video_frame->HasTextures()) {
1407 return false;
1408 }
1409 if (out_metadata) {
1410 // WebGL last-uploaded-frame-metadata API is enabled.
1411 ComputeFrameUploadMetadata(video_frame.get(), already_uploaded_id,
1412 out_metadata);
1413 if (out_metadata->skipped) {
1414 // Skip uploading this frame.
1415 return true;
1416 }
1417 }
1418
Yan, Shaobo44b79ba2019-04-02 06:09:271419 return video_renderer_.PrepareVideoFrameForWebGL(
Nathan Zabriskie04cec1c2020-03-12 00:55:261420 raster_context_provider_.get(), gl, video_frame.get(), target, texture);
Yan, Shaobo44b79ba2019-04-02 06:09:271421}
1422
Matt Wolenetz95af6362018-01-04 20:23:421423// static
Kai Ninomiya9e8ae29b2017-09-06 23:45:161424void WebMediaPlayerImpl::ComputeFrameUploadMetadata(
1425 VideoFrame* frame,
1426 int already_uploaded_id,
1427 VideoFrameUploadMetadata* out_metadata) {
1428 DCHECK(out_metadata);
Kai Ninomiyaef8c9e02017-09-27 04:07:401429 DCHECK(frame);
Kai Ninomiya9e8ae29b2017-09-06 23:45:161430 out_metadata->frame_id = frame->unique_id();
1431 out_metadata->visible_rect = frame->visible_rect();
1432 out_metadata->timestamp = frame->timestamp();
Li, Hao0fab96a2019-10-31 02:46:471433 base::TimeDelta frame_duration;
1434 if (frame->metadata()->GetTimeDelta(media::VideoFrameMetadata::FRAME_DURATION,
1435 &frame_duration)) {
1436 out_metadata->expected_timestamp = frame->timestamp() + frame_duration;
1437 };
Kai Ninomiya9e8ae29b2017-09-06 23:45:161438 bool skip_possible = already_uploaded_id != -1;
1439 bool same_frame_id = frame->unique_id() == already_uploaded_id;
1440 out_metadata->skipped = skip_possible && same_frame_id;
1441}
1442
Blink Reformat1c4d759e2017-04-09 16:34:541443void WebMediaPlayerImpl::SetContentDecryptionModule(
[email protected]9ebc3b03f2014-08-13 04:01:231444 blink::WebContentDecryptionModule* cdm,
1445 blink::WebContentDecryptionModuleResult result) {
xhwang51139732017-02-24 19:36:081446 DVLOG(1) << __func__ << ": cdm = " << cdm;
acolwellb4034942014-08-28 15:42:431447 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]9ebc3b03f2014-08-13 04:01:231448
jrummell06f27072015-06-08 18:12:381449 // Once the CDM is set it can't be cleared as there may be frames being
1450 // decrypted on other threads. So fail this request.
1451 // http://crbug.com/462365#c7.
xhwang97de4202014-11-25 08:44:011452 if (!cdm) {
Blink Reformat1c4d759e2017-04-09 16:34:541453 result.CompleteWithError(
1454 blink::kWebContentDecryptionModuleExceptionInvalidStateError, 0,
xhwang79b193042016-12-13 18:52:431455 "The existing ContentDecryptionModule object cannot be removed at this "
1456 "time.");
xhwang97de4202014-11-25 08:44:011457 return;
1458 }
1459
jrummell89e61d82015-07-23 20:03:341460 // Create a local copy of |result| to avoid problems with the callback
1461 // getting passed to the media thread and causing |result| to be destructed
jrummell4acbec912016-02-27 02:45:031462 // on the wrong thread in some failure conditions. Blink should prevent
1463 // multiple simultaneous calls.
1464 DCHECK(!set_cdm_result_);
Jose Lopes9023b6d2020-02-19 20:42:371465 set_cdm_result_ =
1466 std::make_unique<blink::WebContentDecryptionModuleResult>(result);
jrummell89e61d82015-07-23 20:03:341467
Chris Cunninghamd4a00192019-03-21 20:02:491468 SetCdmInternal(cdm);
xhwang97de4202014-11-25 08:44:011469}
1470
xhwange8c4181a2014-12-06 08:10:011471void WebMediaPlayerImpl::OnEncryptedMediaInitData(
jrummellcf78967c2015-04-03 05:03:581472 EmeInitDataType init_data_type,
Avi Drissman97785ea2015-12-19 01:11:311473 const std::vector<uint8_t>& init_data) {
jrummellcf78967c2015-04-03 05:03:581474 DCHECK(init_data_type != EmeInitDataType::UNKNOWN);
xhwangbab66f52014-12-02 23:49:501475
Xiaohan Wangf63505d2017-10-21 08:00:531476 RecordEncryptedEvent(true);
xhwangbab66f52014-12-02 23:49:501477
dalecurtis04bdb582016-08-17 22:15:231478 // Recreate the watch time reporter if necessary.
1479 const bool was_encrypted = is_encrypted_;
1480 is_encrypted_ = true;
Dale Curtis3899090ea2018-01-12 00:10:351481 if (!was_encrypted) {
1482 media_metrics_provider_->SetIsEME();
1483 if (watch_time_reporter_)
1484 CreateWatchTimeReporter();
dalecurtis04bdb582016-08-17 22:15:231485
Chris Cunningham6c0ec292019-04-04 18:31:111486 // |was_encrypted| = false means we didn't have a CDM prior to observing
1487 // encrypted media init data. Reset the reporter until the CDM arrives. See
1488 // SetCdmInternal().
1489 DCHECK(!cdm_config_);
1490 video_decode_stats_reporter_.reset();
1491 }
Chris Cunninghamd9df58e2017-08-29 00:04:231492
Blink Reformat1c4d759e2017-04-09 16:34:541493 encrypted_client_->Encrypted(
Antonio Gomes89b70572019-07-13 00:44:211494 init_data_type, init_data.data(),
srirama.m26f864d02015-07-14 05:21:461495 base::saturated_cast<unsigned int>(init_data.size()));
xhwangbab66f52014-12-02 23:49:501496}
1497
servolk81e01e02016-03-05 03:29:151498void WebMediaPlayerImpl::OnFFmpegMediaTracksUpdated(
dcheng3076abbf2016-04-22 20:42:391499 std::unique_ptr<MediaTracks> tracks) {
servolk81e01e02016-03-05 03:29:151500 // For MSE/chunk_demuxer case the media track updates are handled by
1501 // WebSourceBufferImpl.
1502 DCHECK(demuxer_.get());
1503 DCHECK(!chunk_demuxer_);
servolkef1e5ef2016-03-25 04:55:261504
servolk16e8bdf82017-04-11 17:00:391505 // Report the media track information to blink. Only the first audio track and
1506 // the first video track are enabled by default to match blink logic.
1507 bool is_first_audio_track = true;
1508 bool is_first_video_track = true;
servolkef1e5ef2016-03-25 04:55:261509 for (const auto& track : tracks->tracks()) {
1510 if (track->type() == MediaTrack::Audio) {
Maciej Pawlowskif2556d122019-06-03 08:14:181511 client_->AddAudioTrack(
1512 blink::WebString::FromUTF8(track->id().value()),
1513 blink::WebMediaPlayerClient::kAudioTrackKindMain,
1514 blink::WebString::FromUTF8(track->label().value()),
1515 blink::WebString::FromUTF8(track->language().value()),
1516 is_first_audio_track);
servolk16e8bdf82017-04-11 17:00:391517 is_first_audio_track = false;
servolkef1e5ef2016-03-25 04:55:261518 } else if (track->type() == MediaTrack::Video) {
Maciej Pawlowskif2556d122019-06-03 08:14:181519 client_->AddVideoTrack(
1520 blink::WebString::FromUTF8(track->id().value()),
1521 blink::WebMediaPlayerClient::kVideoTrackKindMain,
1522 blink::WebString::FromUTF8(track->label().value()),
1523 blink::WebString::FromUTF8(track->language().value()),
1524 is_first_video_track);
servolk16e8bdf82017-04-11 17:00:391525 is_first_video_track = false;
servolkef1e5ef2016-03-25 04:55:261526 } else {
1527 // Text tracks are not supported through this code path yet.
1528 NOTREACHED();
1529 }
1530 }
servolk81e01e02016-03-05 03:29:151531}
1532
Chris Cunninghamd4a00192019-03-21 20:02:491533void WebMediaPlayerImpl::SetCdmInternal(
1534 blink::WebContentDecryptionModule* cdm) {
jrummelle616ee92016-10-08 02:15:441535 DCHECK(main_task_runner_->BelongsToCurrentThread());
1536 DCHECK(cdm);
Xiaohan Wang24cfe2c2018-01-22 23:16:001537
Chris Cunninghamd4a00192019-03-21 20:02:491538 const bool was_encrypted = is_encrypted_;
1539 is_encrypted_ = true;
1540
1541 // Recreate the watch time reporter if necessary.
1542 if (!was_encrypted) {
1543 media_metrics_provider_->SetIsEME();
1544 if (watch_time_reporter_)
1545 CreateWatchTimeReporter();
1546 }
1547
Chris Cunningham6c0ec292019-04-04 18:31:111548 WebContentDecryptionModuleImpl* web_cdm =
1549 ToWebContentDecryptionModuleImpl(cdm);
1550 auto cdm_context_ref = web_cdm->GetCdmContextRef();
Xiaohan Wang24cfe2c2018-01-22 23:16:001551 if (!cdm_context_ref) {
jrummelle616ee92016-10-08 02:15:441552 NOTREACHED();
1553 OnCdmAttached(false);
xhwang80739452016-01-13 00:48:001554 return;
1555 }
1556
Chris Cunningham6c0ec292019-04-04 18:31:111557 // Arrival of |cdm_config_| and |key_system_| unblocks recording of encrypted
1558 // stats. Attempt to create the stats reporter. Note, we do NOT guard this
1559 // within !was_encypted above because often the CDM arrives after the call to
1560 // OnEncryptedMediaInitData().
1561 cdm_config_ = web_cdm->GetCdmConfig();
1562 key_system_ = web_cdm->GetKeySystem();
1563 DCHECK(!key_system_.empty());
1564 CreateVideoDecodeStatsReporter();
1565
Xiaohan Wang24cfe2c2018-01-22 23:16:001566 CdmContext* cdm_context = cdm_context_ref->GetCdmContext();
1567 DCHECK(cdm_context);
jrummelle616ee92016-10-08 02:15:441568
1569 // Keep the reference to the CDM, as it shouldn't be destroyed until
1570 // after the pipeline is done with the |cdm_context|.
Xiaohan Wang24cfe2c2018-01-22 23:16:001571 pending_cdm_context_ref_ = std::move(cdm_context_ref);
Antonio Gomes81b56552019-05-15 22:15:281572 pipeline_controller_->SetCdm(
Jose Lopes25ba7b32020-03-12 16:01:271573 cdm_context,
1574 base::BindOnce(&WebMediaPlayerImpl::OnCdmAttached, weak_this_));
xhwang97de4202014-11-25 08:44:011575}
1576
jrummell89e61d82015-07-23 20:03:341577void WebMediaPlayerImpl::OnCdmAttached(bool success) {
xhwang51139732017-02-24 19:36:081578 DVLOG(1) << __func__ << ": success = " << success;
jrummelle616ee92016-10-08 02:15:441579 DCHECK(main_task_runner_->BelongsToCurrentThread());
Xiaohan Wang24cfe2c2018-01-22 23:16:001580 DCHECK(pending_cdm_context_ref_);
jrummelle616ee92016-10-08 02:15:441581
1582 // If the CDM is set from the constructor there is no promise
1583 // (|set_cdm_result_|) to fulfill.
xhwang97de4202014-11-25 08:44:011584 if (success) {
Ted Meyer7f5b4e22019-11-21 03:21:191585 media_log_->SetProperty<MediaLogProperty::kIsVideoEncrypted>(true);
xhwang29c5ad202017-04-14 07:02:191586
jrummelle616ee92016-10-08 02:15:441587 // This will release the previously attached CDM (if any).
Xiaohan Wang24cfe2c2018-01-22 23:16:001588 cdm_context_ref_ = std::move(pending_cdm_context_ref_);
jrummelle616ee92016-10-08 02:15:441589 if (set_cdm_result_) {
Blink Reformat1c4d759e2017-04-09 16:34:541590 set_cdm_result_->Complete();
jrummelle616ee92016-10-08 02:15:441591 set_cdm_result_.reset();
1592 }
1593
xhwang97de4202014-11-25 08:44:011594 return;
1595 }
1596
Xiaohan Wang24cfe2c2018-01-22 23:16:001597 pending_cdm_context_ref_.reset();
jrummelle616ee92016-10-08 02:15:441598 if (set_cdm_result_) {
Blink Reformat1c4d759e2017-04-09 16:34:541599 set_cdm_result_->CompleteWithError(
1600 blink::kWebContentDecryptionModuleExceptionNotSupportedError, 0,
xhwang79b193042016-12-13 18:52:431601 "Unable to set ContentDecryptionModule object");
jrummelle616ee92016-10-08 02:15:441602 set_cdm_result_.reset();
1603 }
[email protected]9ebc3b03f2014-08-13 04:01:231604}
1605
sandersd1c0bba02016-03-04 23:14:081606void WebMediaPlayerImpl::OnPipelineSeeked(bool time_updated) {
John Chen5b164a02017-11-01 00:36:091607 TRACE_EVENT2("media", "WebMediaPlayerImpl::OnPipelineSeeked", "target",
1608 seek_time_.InSecondsF(), "id", media_log_->id());
[email protected]5d11eff2011-09-15 00:06:061609 seeking_ = false;
wolenetz1b2ae7d2015-06-10 00:44:211610 seek_time_ = base::TimeDelta();
avayvod2135a642017-01-13 00:17:141611
hubbe5a2dec022016-03-17 01:14:231612 if (paused_) {
Antonio Gomes81b56552019-05-15 22:15:281613 paused_time_ = pipeline_controller_->GetMediaTime();
dalecurtis04bdb582016-08-17 22:15:231614 } else {
1615 DCHECK(watch_time_reporter_);
1616 watch_time_reporter_->OnPlaying();
Sergey Ulanovb8656772020-04-21 22:56:141617 if (playback_events_recorder_)
1618 playback_events_recorder_->OnPlaying();
hubbe5a2dec022016-03-17 01:14:231619 }
sandersd1c0bba02016-03-04 23:14:081620 if (time_updated)
1621 should_notify_time_changed_ = true;
dalecurtisaf34d8712016-09-20 04:32:261622
dalecurtis4f6d14d2017-02-22 17:42:221623 // Reset underflow duration upon seek; this prevents looping videos and user
1624 // actions from artificially inflating the duration.
1625 underflow_timer_.reset();
avayvod56e1f3942017-01-21 02:06:311626
1627 // Background video optimizations are delayed when shown/hidden if pipeline
1628 // is seeking.
1629 UpdateBackgroundVideoOptimizationState();
Dale Curtis2dc6089a2018-03-26 16:47:581630
Dale Curtisd71061f02019-05-21 21:33:541631 // If we successfully completed a suspended startup, we need to make a call to
1632 // UpdatePlayState() in case any events which should trigger a resume have
1633 // occurred during startup.
Dale Curtis2dc6089a2018-03-26 16:47:581634 if (attempting_suspended_start_ &&
Antonio Gomes81b56552019-05-15 22:15:281635 pipeline_controller_->IsPipelineSuspended()) {
Dale Curtisff576552018-03-30 02:32:441636 skip_metrics_due_to_startup_suspend_ = true;
Dale Curtisd71061f02019-05-21 21:33:541637
1638 // If we successfully completed a suspended startup, signal that we have
1639 // reached BUFFERING_HAVE_ENOUGH so that canplay and canplaythrough fire
1640 // correctly. We must unfortunately always do this because it's valid for
1641 // elements to play while not visible nor even in the DOM.
1642 //
1643 // Note: This call is dual purpose, it is also responsible for triggering an
1644 // UpdatePlayState() call which may need to resume the pipeline once Blink
1645 // has been told about the ReadyState change.
Chris Cunninghamfc0d67e2019-07-22 20:29:161646 OnBufferingStateChangeInternal(BUFFERING_HAVE_ENOUGH,
1647 BUFFERING_CHANGE_REASON_UNKNOWN, true);
Dale Curtis2dc6089a2018-03-26 16:47:581648 }
1649
1650 attempting_suspended_start_ = false;
Becca Hughes7a85bf22019-07-24 16:16:581651
1652 // The current time has changed so we should update the media position state.
1653 UpdateMediaPositionState();
[email protected]8931c41a2009-07-07 17:31:491654}
1655
sandersd1c0bba02016-03-04 23:14:081656void WebMediaPlayerImpl::OnPipelineSuspended() {
Dale Curtis83321152018-12-01 01:22:061657 // Add a log event so the player shows up as "SUSPENDED" in media-internals.
Ted Meyer0134aed2020-01-23 23:56:401658 media_log_->AddEvent<MediaLogEvent::kSuspended>();
Dale Curtis83321152018-12-01 01:22:061659
Dale Curtis04769ca2019-05-25 00:38:101660 if (attempting_suspended_start_) {
1661 DCHECK(pipeline_controller_->IsSuspended());
1662 did_lazy_load_ = !has_poster_ && HasVideo();
1663 }
1664
sandersd2f5bb6152017-03-29 22:57:531665 // Tell the data source we have enough data so that it may release the
Dale Curtis04769ca2019-05-25 00:38:101666 // connection (unless blink is waiting on us to signal play()).
1667 if (mb_data_source_ && !client_->CouldPlayIfEnoughData()) {
1668 // |attempting_suspended_start_| will be cleared by OnPipelineSeeked() which
1669 // will occur after this method during a suspended startup.
1670 if (attempting_suspended_start_ && did_lazy_load_) {
1671 DCHECK(!has_first_frame_);
1672 DCHECK(have_enough_after_lazy_load_cb_.IsCancelled());
1673
1674 // For lazy load, we won't know if the element is non-visible until a
1675 // layout completes, so to avoid unnecessarily tearing down the network
1676 // connection, briefly (250ms chosen arbitrarily) delay signaling "have
1677 // enough" to the MultiBufferDataSource.
1678 //
1679 // base::Unretained() is safe here since the base::CancelableOnceClosure
1680 // will cancel upon destruction of this class and |mb_data_source_| is
1681 // gauranteeed to outlive us.
1682 have_enough_after_lazy_load_cb_.Reset(
1683 base::BindOnce(&MultibufferDataSource::OnBufferingHaveEnough,
1684 base::Unretained(mb_data_source_), true));
1685 main_task_runner_->PostDelayedTask(
1686 FROM_HERE, have_enough_after_lazy_load_cb_.callback(),
1687 base::TimeDelta::FromMilliseconds(250));
1688 } else {
1689 have_enough_after_lazy_load_cb_.Cancel();
1690 mb_data_source_->OnBufferingHaveEnough(true);
1691 }
1692 }
dalecurtis37fe5862016-03-15 19:29:091693
sandersd50a635e2016-04-04 22:50:091694 ReportMemoryUsage();
1695
sandersd1c0bba02016-03-04 23:14:081696 if (pending_suspend_resume_cycle_) {
watkdee516f2016-02-18 02:22:191697 pending_suspend_resume_cycle_ = false;
sandersd50a635e2016-04-04 22:50:091698 UpdatePlayState();
dalecurtis0431cbf2016-03-12 01:19:431699 }
sandersd1c0bba02016-03-04 23:14:081700}
1701
avayvod2135a642017-01-13 00:17:141702void WebMediaPlayerImpl::OnBeforePipelineResume() {
Dale Curtis04769ca2019-05-25 00:38:101703 // Since we're resuming, cancel closing of the network connection.
1704 have_enough_after_lazy_load_cb_.Cancel();
1705
Dale Curtisff576552018-03-30 02:32:441706 // We went through suspended startup, so the player is only just now spooling
1707 // up for playback. As such adjust |load_start_time_| so it reports the same
1708 // metric as what would be reported if we had not suspended at startup.
1709 if (skip_metrics_due_to_startup_suspend_) {
1710 // In the event that the call to SetReadyState() initiated after pipeline
1711 // startup immediately tries to start playback, we should not update
1712 // |load_start_time_| to avoid losing visibility into the impact of a
1713 // suspended startup on the time until first frame / play ready for cases
1714 // where suspended startup was applied incorrectly.
1715 if (!attempting_suspended_start_)
1716 load_start_time_ = base::TimeTicks::Now() - time_to_metadata_;
1717 skip_metrics_due_to_startup_suspend_ = false;
1718 }
1719
avayvod2135a642017-01-13 00:17:141720 // Enable video track if we disabled it in the background - this way the new
1721 // renderer will attach its callbacks to the video stream properly.
1722 // TODO(avayvod): Remove this when disabling and enabling video tracks in
1723 // non-playing state works correctly. See https://crbug.com/678374.
1724 EnableVideoTrackIfNeeded();
1725 is_pipeline_resuming_ = true;
1726}
1727
1728void WebMediaPlayerImpl::OnPipelineResumed() {
1729 is_pipeline_resuming_ = false;
1730
avayvod56e1f3942017-01-21 02:06:311731 UpdateBackgroundVideoOptimizationState();
avayvod2135a642017-01-13 00:17:141732}
1733
alokp967c902452016-05-06 05:21:371734void WebMediaPlayerImpl::OnDemuxerOpened() {
1735 DCHECK(main_task_runner_->BelongsToCurrentThread());
dalecurtis9cddc0b2017-04-19 21:23:381736 client_->MediaSourceOpened(new WebMediaSourceImpl(chunk_demuxer_));
alokp967c902452016-05-06 05:21:371737}
1738
servolkf94b4602017-01-31 16:44:271739void WebMediaPlayerImpl::OnMemoryPressure(
1740 base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
1741 DVLOG(2) << __func__ << " memory_pressure_level=" << memory_pressure_level;
1742 DCHECK(main_task_runner_->BelongsToCurrentThread());
1743 DCHECK(base::FeatureList::IsEnabled(kMemoryPressureBasedSourceBufferGC));
1744 DCHECK(chunk_demuxer_);
1745
Sebastien Marchand6f03d35f2020-01-28 15:12:451746 if (memory_pressure_level ==
1747 base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE) {
1748 return;
1749 }
1750
servolkf94b4602017-01-31 16:44:271751 // The new value of |memory_pressure_level| will take effect on the next
1752 // garbage collection. Typically this means the next SourceBuffer append()
1753 // operation, since per MSE spec, the garbage collection must only occur
1754 // during SourceBuffer append(). But if memory pressure is critical it might
1755 // be better to perform GC immediately rather than wait for the next append
1756 // and potentially get killed due to out-of-memory.
1757 // So if this experiment is enabled and pressure level is critical, we'll pass
1758 // down force_instant_gc==true, which will force immediate GC on
1759 // SourceBufferStreams.
1760 bool force_instant_gc =
1761 (enable_instant_source_buffer_gc_ &&
1762 memory_pressure_level ==
1763 base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
1764
Matt Wolenetz95af6362018-01-04 20:23:421765 // base::Unretained is safe, since |chunk_demuxer_| is actually owned by
1766 // |this| via this->demuxer_. Note the destruction of |chunk_demuxer_| is done
1767 // from ~WMPI by first hopping to |media_task_runner_| to prevent race with
1768 // this task.
servolkf94b4602017-01-31 16:44:271769 media_task_runner_->PostTask(
Dale Curtisee9be30012018-09-21 22:21:511770 FROM_HERE, base::BindOnce(&ChunkDemuxer::OnMemoryPressure,
1771 base::Unretained(chunk_demuxer_),
1772 base::TimeDelta::FromSecondsD(CurrentTime()),
1773 memory_pressure_level, force_instant_gc));
servolkf94b4602017-01-31 16:44:271774}
1775
alokp967c902452016-05-06 05:21:371776void WebMediaPlayerImpl::OnError(PipelineStatus status) {
Xiaohan Wang73b433f2019-11-05 20:13:011777 DVLOG(1) << __func__ << ": status=" << status;
alokp967c902452016-05-06 05:21:371778 DCHECK(main_task_runner_->BelongsToCurrentThread());
1779 DCHECK_NE(status, PIPELINE_OK);
1780
1781 if (suppress_destruction_errors_)
1782 return;
1783
Thomas Guilbert6b6be3d2017-08-18 03:17:271784#if defined(OS_ANDROID)
Dale Curtisf273f8f2018-12-13 23:40:331785 // |mb_data_source_| may be nullptr if someone passes in a m3u8 as a data://
1786 // URL, since MediaPlayer doesn't support data:// URLs, fail playback now.
Dan Sanders675250992019-05-11 00:07:491787 const bool found_hls = base::FeatureList::IsEnabled(kHlsPlayer) &&
1788 status == PipelineStatus::DEMUXER_ERROR_DETECTED_HLS;
Dale Curtisf273f8f2018-12-13 23:40:331789 if (found_hls && mb_data_source_) {
Dan Sandersae245e42019-03-07 23:25:291790 demuxer_found_hls_ = true;
1791
Thomas Guilbert8cb48612020-04-29 19:28:451792 if (observer_)
1793 observer_->OnHlsManifestDetected();
1794
Dan Sandersd80b1842019-02-05 00:36:161795 UMA_HISTOGRAM_BOOLEAN("Media.WebMediaPlayerImpl.HLS.IsCorsCrossOrigin",
1796 mb_data_source_->IsCorsCrossOrigin());
Dan Sandersae245e42019-03-07 23:25:291797 if (mb_data_source_->IsCorsCrossOrigin()) {
1798 UMA_HISTOGRAM_BOOLEAN("Media.WebMediaPlayerImpl.HLS.HasAccessControl",
1799 mb_data_source_->HasAccessControl());
1800 }
1801
1802 // Note: Does not consider the full redirect chain, which could contain
1803 // undetected mixed content.
Dan Sandersd80b1842019-02-05 00:36:161804 bool frame_url_is_cryptographic = url::Origin(frame_->GetSecurityOrigin())
1805 .GetURL()
1806 .SchemeIsCryptographic();
1807 bool manifest_url_is_cryptographic =
1808 loaded_url_.SchemeIsCryptographic() &&
1809 mb_data_source_->GetUrlAfterRedirects().SchemeIsCryptographic();
1810 UMA_HISTOGRAM_BOOLEAN(
1811 "Media.WebMediaPlayerImpl.HLS.IsMixedContent",
1812 frame_url_is_cryptographic && !manifest_url_is_cryptographic);
Thomas Guilbert153f84572018-07-19 05:03:581813
Xiaohan Wang3684e0c2019-10-30 01:04:301814 renderer_factory_selector_->SetBaseFactoryType(
Xiaohan Wang48aaa192019-12-05 01:29:001815 RendererFactoryType::kMediaPlayer);
Thomas Guilbert6b6be3d2017-08-18 03:17:271816
Dale Curtisf273f8f2018-12-13 23:40:331817 loaded_url_ = mb_data_source_->GetUrlAfterRedirects();
1818 DCHECK(data_source_);
1819 data_source_->Stop();
1820 mb_data_source_ = nullptr;
1821
Antonio Gomes81b56552019-05-15 22:15:281822 pipeline_controller_->Stop();
Dale Curtis8a6281322017-08-31 00:35:531823 SetMemoryReportingState(false);
Eugene Zemtsov77d56262020-03-06 05:52:031824 media_task_runner_->DeleteSoon(FROM_HERE,
1825 std::move(media_thread_mem_dumper_));
Thomas Guilbert6b6be3d2017-08-18 03:17:271826
Dale Curtisf273f8f2018-12-13 23:40:331827 // Trampoline through the media task runner to destruct the demuxer and
1828 // data source now that we're switching to HLS playback.
1829 media_task_runner_->PostTask(
Dale Curtisee9be30012018-09-21 22:21:511830 FROM_HERE,
Dale Curtisf273f8f2018-12-13 23:40:331831 BindToCurrentLoop(base::BindOnce(
1832 [](std::unique_ptr<Demuxer> demuxer,
1833 std::unique_ptr<DataSource> data_source,
1834 base::OnceClosure start_pipeline_cb) {
1835 // Release resources before starting HLS.
1836 demuxer.reset();
1837 data_source.reset();
1838
1839 std::move(start_pipeline_cb).Run();
1840 },
1841 std::move(demuxer_), std::move(data_source_),
Antonio Gomes142f32a2019-05-15 23:32:561842 base::BindOnce(&WebMediaPlayerImpl::StartPipeline, weak_this_))));
Dale Curtisf273f8f2018-12-13 23:40:331843
Thomas Guilbert6b6be3d2017-08-18 03:17:271844 return;
1845 }
Dale Curtisf273f8f2018-12-13 23:40:331846
1847 // We found hls in a data:// URL, fail immediately.
1848 if (found_hls)
1849 status = PIPELINE_ERROR_EXTERNAL_RENDERER_FAILED;
Thomas Guilbert6b6be3d2017-08-18 03:17:271850#endif
1851
David Dorwin89fe8d02020-05-01 05:42:421852 MaybeSetContainerNameForMetrics();
Dan Sanders6edfd782019-08-13 00:13:181853 simple_watch_timer_.Stop();
Ted Meyer0134aed2020-01-23 23:56:401854 media_log_->NotifyError(status);
Dale Curtis74612b72017-12-14 20:56:191855 media_metrics_provider_->OnError(status);
Sergey Ulanovb8656772020-04-21 22:56:141856 if (playback_events_recorder_)
1857 playback_events_recorder_->OnError(status);
Dale Curtisccfd0cca2017-08-31 01:27:561858 if (watch_time_reporter_)
1859 watch_time_reporter_->OnError(status);
alokp967c902452016-05-06 05:21:371860
Blink Reformat1c4d759e2017-04-09 16:34:541861 if (ready_state_ == WebMediaPlayer::kReadyStateHaveNothing) {
alokp967c902452016-05-06 05:21:371862 // Any error that occurs before reaching ReadyStateHaveMetadata should
1863 // be considered a format error.
Blink Reformat1c4d759e2017-04-09 16:34:541864 SetNetworkState(WebMediaPlayer::kNetworkStateFormatError);
alokp967c902452016-05-06 05:21:371865 } else {
Antonio Gomesf01cfbd2019-07-12 08:53:111866 SetNetworkState(blink::PipelineErrorToNetworkState(status));
alokp967c902452016-05-06 05:21:371867 }
1868
Thomas Guilbert2e591392017-08-12 00:56:381869 // PipelineController::Stop() is idempotent.
Antonio Gomes81b56552019-05-15 22:15:281870 pipeline_controller_->Stop();
Thomas Guilbert2e591392017-08-12 00:56:381871
alokp967c902452016-05-06 05:21:371872 UpdatePlayState();
1873}
1874
1875void WebMediaPlayerImpl::OnEnded() {
John Chen5b164a02017-11-01 00:36:091876 TRACE_EVENT2("media", "WebMediaPlayerImpl::OnEnded", "duration", Duration(),
1877 "id", media_log_->id());
pkastingf5279482016-07-27 02:18:201878 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:431879 DCHECK(main_task_runner_->BelongsToCurrentThread());
scherkusd2c745b2014-09-04 05:03:401880
sandersd1c0bba02016-03-04 23:14:081881 // Ignore state changes until we've completed all outstanding operations.
Antonio Gomes81b56552019-05-15 22:15:281882 if (!pipeline_controller_->IsStable())
scherkusd2c745b2014-09-04 05:03:401883 return;
1884
1885 ended_ = true;
Blink Reformat1c4d759e2017-04-09 16:34:541886 client_->TimeChanged();
sandersd50a635e2016-04-04 22:50:091887
Sergey Ulanovb8656772020-04-21 22:56:141888 if (playback_events_recorder_)
1889 playback_events_recorder_->OnEnded();
1890
sandersd50a635e2016-04-04 22:50:091891 // We don't actually want this to run until |client_| calls seek() or pause(),
1892 // but that should have already happened in timeChanged() and so this is
1893 // expected to be a no-op.
1894 UpdatePlayState();
[email protected]576537842009-08-12 23:52:051895}
1896
Chisoon Jeong0a8e4bc2019-05-11 00:06:141897void WebMediaPlayerImpl::OnMetadata(const PipelineMetadata& metadata) {
pkastingf5279482016-07-27 02:18:201898 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:431899 DCHECK(main_task_runner_->BelongsToCurrentThread());
Dale Curtisff576552018-03-30 02:32:441900
1901 // Cache the |time_to_metadata_| to use for adjusting the TimeToFirstFrame and
1902 // TimeToPlayReady metrics later if we end up doing a suspended startup.
1903 time_to_metadata_ = base::TimeTicks::Now() - load_start_time_;
1904 media_metrics_provider_->SetTimeToMetadata(time_to_metadata_);
1905 RecordTimingUMA("Media.TimeToMetadata", time_to_metadata_);
[email protected]a8e2cb82012-08-17 00:02:391906
David Dorwin89fe8d02020-05-01 05:42:421907 MaybeSetContainerNameForMetrics();
Dale Curtis5bba03232018-08-30 17:57:381908
[email protected]b8877772014-03-26 20:17:151909 pipeline_metadata_ = metadata;
[email protected]c7a918e2020-01-17 00:18:271910 if (power_status_helper_)
[email protected]dc996312019-12-19 19:26:381911 power_status_helper_->SetMetadata(metadata);
[email protected]739847c02014-01-16 00:12:251912
Ted Meyer4a427632019-05-01 19:05:271913 UMA_HISTOGRAM_ENUMERATION(
1914 "Media.VideoRotation",
1915 metadata.video_decoder_config.video_transformation().rotation,
1916 VIDEO_ROTATION_MAX + 1);
[email protected]21c3f7502013-03-23 03:29:511917
John Rummelldb5a7ef2018-05-16 00:28:011918 if (HasAudio()) {
Ted Meyerd5885f82019-07-16 19:19:171919 media_metrics_provider_->SetHasAudio(metadata.audio_decoder_config.codec());
John Rummelldb5a7ef2018-05-16 00:28:011920 RecordEncryptionScheme("Audio",
1921 metadata.audio_decoder_config.encryption_scheme());
1922 }
1923
Blink Reformat1c4d759e2017-04-09 16:34:541924 if (HasVideo()) {
Ted Meyerd5885f82019-07-16 19:19:171925 media_metrics_provider_->SetHasVideo(metadata.video_decoder_config.codec());
John Rummelldb5a7ef2018-05-16 00:28:011926 RecordEncryptionScheme("Video",
1927 metadata.video_decoder_config.encryption_scheme());
1928
liberato2fd111be2017-01-04 00:25:061929 if (overlay_enabled_) {
1930 // SurfaceView doesn't support rotated video, so transition back if
[email protected]c8d574722017-08-30 20:53:431931 // the video is now rotated. If |always_enable_overlays_|, we keep the
liberato2fd111be2017-01-04 00:25:061932 // overlay anyway so that the state machine keeps working.
[email protected]c8d574722017-08-30 20:53:431933 // TODO(liberato): verify if compositor feedback catches this. If so,
1934 // then we don't need this check.
1935 if (!always_enable_overlays_ && !DoesOverlaySupportMetadata())
liberato2fd111be2017-01-04 00:25:061936 DisableOverlay();
liberato2fd111be2017-01-04 00:25:061937 }
watkf835a792016-06-24 23:24:401938
[email protected]702d721d2018-10-25 21:55:271939 if (surface_layer_mode_ ==
Mounir Lamouri28d648102019-11-27 16:49:031940 blink::WebMediaPlayer::SurfaceLayerMode::kAlways) {
[email protected]702d721d2018-10-25 21:55:271941 ActivateSurfaceLayerForVideo();
1942 } else {
danakj6e669e782018-05-16 16:57:171943 DCHECK(!video_layer_);
Ted Meyer4a427632019-05-01 19:05:271944 // TODO(tmathmeyer) does this need support for reflections as well?
danakj25f030112018-05-11 18:26:541945 video_layer_ = cc::VideoLayer::Create(
Julien Isorce6c83d8de2017-10-12 13:11:291946 compositor_.get(),
Ted Meyer4a427632019-05-01 19:05:271947 pipeline_metadata_.video_decoder_config.video_transformation()
1948 .rotation);
danakj8bc61c72018-05-16 13:55:061949 video_layer_->SetContentsOpaque(opaque_);
danakj8d204a42018-05-18 18:05:351950 client_->SetCcLayer(video_layer_.get());
lethalantidote7f6009d2017-07-07 21:47:391951 }
[email protected]a8e2cb82012-08-17 00:02:391952 }
dalecurtis8e4dc682016-03-15 02:30:301953
xjzd3fe45a2016-10-12 18:26:371954 if (observer_)
xjz15b483f2017-01-12 00:21:361955 observer_->OnMetadataChanged(pipeline_metadata_);
xjzd3fe45a2016-10-12 18:26:371956
Dale Curtisc7d2a7d22018-01-11 20:01:051957 // TODO(dalecurtis): Don't create these until kReadyStateHaveFutureData; when
1958 // we create them early we just increase the chances of needing to throw them
1959 // away unnecessarily.
dalecurtis04bdb582016-08-17 22:15:231960 CreateWatchTimeReporter();
Chris Cunninghamd9df58e2017-08-29 00:04:231961 CreateVideoDecodeStatsReporter();
Dale Curtisc7d2a7d22018-01-11 20:01:051962
Dale Curtis1e7a02b42019-05-28 20:12:241963 // SetReadyState() may trigger all sorts of calls into this class (e.g.,
1964 // Play(), Pause(), etc) so do it last to avoid unexpected states during the
1965 // calls. An exception to this is UpdatePlayState(), which is safe to call and
1966 // needs to use the new ReadyState in its calculations.
Dale Curtis2fc01cc2019-05-20 22:53:521967 SetReadyState(WebMediaPlayer::kReadyStateHaveMetadata);
Dale Curtis1e7a02b42019-05-28 20:12:241968 UpdatePlayState();
[email protected]a8e2cb82012-08-17 00:02:391969}
1970
[email protected]69db58f2018-09-26 20:27:561971void WebMediaPlayerImpl::ActivateSurfaceLayerForVideo() {
1972 // Note that we might or might not already be in VideoLayer mode.
1973 DCHECK(!bridge_);
1974
1975 surface_layer_for_video_enabled_ = true;
1976
1977 // If we're in VideoLayer mode, then get rid of the layer.
1978 if (video_layer_) {
1979 client_->SetCcLayer(nullptr);
1980 video_layer_ = nullptr;
1981 }
1982
1983 bridge_ = std::move(create_bridge_callback_)
1984 .Run(this, compositor_->GetUpdateSubmissionStateCallback());
1985 bridge_->CreateSurfaceLayer();
1986
Ted Meyer4a427632019-05-01 19:05:271987 // TODO(tmathmeyer) does this need support for the reflection transformation
1988 // as well?
[email protected]69db58f2018-09-26 20:27:561989 vfc_task_runner_->PostTask(
1990 FROM_HERE,
Ted Meyer4a427632019-05-01 19:05:271991 base::BindOnce(
1992 &VideoFrameCompositor::EnableSubmission,
1993 base::Unretained(compositor_.get()), bridge_->GetSurfaceId(),
1994 bridge_->GetLocalSurfaceIdAllocationTime(),
1995 pipeline_metadata_.video_decoder_config.video_transformation()
1996 .rotation,
1997 IsInPictureInPicture()));
[email protected]69db58f2018-09-26 20:27:561998 bridge_->SetContentsOpaque(opaque_);
1999
2000 // If the element is already in Picture-in-Picture mode, it means that it
2001 // was set in this mode prior to this load, with a different
2002 // WebMediaPlayerImpl. The new player needs to send its id, size and
2003 // surface id to the browser process to make sure the states are properly
2004 // updated.
2005 // TODO(872056): the surface should be activated but for some reasons, it
2006 // does not. It is possible that this will no longer be needed after 872056
2007 // is fixed.
Dale Curtisca1b78f2019-01-15 03:11:262008 if (IsInPictureInPicture())
[email protected]69db58f2018-09-26 20:27:562009 OnSurfaceIdUpdated(bridge_->GetSurfaceId());
[email protected]69db58f2018-09-26 20:27:562010}
2011
Chris Cunninghamfc0d67e2019-07-22 20:29:162012void WebMediaPlayerImpl::OnBufferingStateChange(
2013 BufferingState state,
2014 BufferingStateChangeReason reason) {
2015 OnBufferingStateChangeInternal(state, reason, false);
Dale Curtis2dc6089a2018-03-26 16:47:582016}
2017
Chris Cunninghamd9df58e2017-08-29 00:04:232018void WebMediaPlayerImpl::CreateVideoDecodeStatsReporter() {
2019 // TODO(chcunningham): destroy reporter if we initially have video but the
2020 // track gets disabled. Currently not possible in default desktop Chrome.
2021 if (!HasVideo())
2022 return;
2023
Chris Cunningham89b4b762019-03-27 17:13:332024 // Only record stats from the local pipeline.
2025 if (is_flinging_ || is_remote_rendering_ || using_media_player_renderer_)
2026 return;
2027
Chris Cunninghamd9df58e2017-08-29 00:04:232028 // Stats reporter requires a valid config. We may not have one for HLS cases
2029 // where URL demuxer doesn't know details of the stream.
2030 if (!pipeline_metadata_.video_decoder_config.IsValidConfig())
2031 return;
2032
Chris Cunningham6c0ec292019-04-04 18:31:112033 // Profile must be known for use as index to save the reported stats.
Chris Cunningham5b1b67eb2019-03-23 03:24:412034 if (pipeline_metadata_.video_decoder_config.profile() ==
2035 VIDEO_CODEC_PROFILE_UNKNOWN) {
2036 return;
2037 }
2038
Chris Cunningham6c0ec292019-04-04 18:31:112039 // CdmConfig must be provided for use as index to save encrypted stats.
2040 if (is_encrypted_ && !cdm_config_) {
Chris Cunninghamd9df58e2017-08-29 00:04:232041 return;
Chris Cunningham6c0ec292019-04-04 18:31:112042 } else if (cdm_config_) {
2043 DCHECK(!key_system_.empty());
2044 }
Chris Cunninghamd9df58e2017-08-29 00:04:232045
Gyuyoung Kima040bc52019-10-30 01:14:352046 mojo::PendingRemote<mojom::VideoDecodeStatsRecorder> recorder;
Dale Curtis7e8a510d2017-12-14 19:19:482047 media_metrics_provider_->AcquireVideoDecodeStatsRecorder(
Gyuyoung Kima040bc52019-10-30 01:14:352048 recorder.InitWithNewPipeAndPassReceiver());
Chris Cunninghamc7c6a6d2017-11-23 14:06:452049
Chris Cunninghamd9df58e2017-08-29 00:04:232050 // Create capabilities reporter and synchronize its initial state.
Jose Lopes9023b6d2020-02-19 20:42:372051 video_decode_stats_reporter_ = std::make_unique<VideoDecodeStatsReporter>(
Chris Cunninghamc7c6a6d2017-11-23 14:06:452052 std::move(recorder),
Jose Lopesdda34ca2020-02-19 11:56:172053 base::BindRepeating(&WebMediaPlayerImpl::GetPipelineStatistics,
2054 base::Unretained(this)),
Chris Cunningham5b1b67eb2019-03-23 03:24:412055 pipeline_metadata_.video_decoder_config.profile(),
Chris Cunningham6c0ec292019-04-04 18:31:112056 pipeline_metadata_.natural_size, key_system_, cdm_config_,
Jose Lopes9023b6d2020-02-19 20:42:372057 frame_->GetTaskRunner(blink::TaskType::kInternalMedia));
Chris Cunninghamd9df58e2017-08-29 00:04:232058
2059 if (delegate_->IsFrameHidden())
2060 video_decode_stats_reporter_->OnHidden();
2061 else
2062 video_decode_stats_reporter_->OnShown();
2063
2064 if (paused_)
2065 video_decode_stats_reporter_->OnPaused();
2066 else
2067 video_decode_stats_reporter_->OnPlaying();
2068}
2069
hubbeb2d3efd2017-05-05 23:26:382070void WebMediaPlayerImpl::OnProgress() {
Chris Watkins1ffabc5f2017-05-10 20:52:092071 DVLOG(4) << __func__;
Dale Curtisad645f72019-09-06 23:28:162072
2073 // See IsPrerollAttemptNeeded() for more details. We can't use that method
2074 // here since it considers |preroll_attempt_start_time_| and for OnProgress()
2075 // events we must make the attempt -- since there may not be another event.
2076 if (highest_ready_state_ < ReadyState::kReadyStateHaveFutureData) {
hubbeb2d3efd2017-05-05 23:26:382077 // Reset the preroll attempt clock.
2078 preroll_attempt_pending_ = true;
2079 preroll_attempt_start_time_ = base::TimeTicks();
2080
2081 // Clear any 'stale' flag and give the pipeline a chance to resume. If we
2082 // are already resumed, this will cause |preroll_attempt_start_time_| to
2083 // be set.
2084 delegate_->ClearStaleFlag(delegate_id_);
2085 UpdatePlayState();
2086 } else if (ready_state_ == ReadyState::kReadyStateHaveFutureData &&
2087 CanPlayThrough()) {
2088 SetReadyState(WebMediaPlayer::kReadyStateHaveEnoughData);
2089 }
2090}
2091
2092bool WebMediaPlayerImpl::CanPlayThrough() {
2093 if (!base::FeatureList::IsEnabled(kSpecCompliantCanPlayThrough))
2094 return true;
2095 if (chunk_demuxer_)
2096 return true;
Dale Curtis4841c712018-12-13 18:14:052097 if (data_source_ && data_source_->AssumeFullyBuffered())
hubbeb2d3efd2017-05-05 23:26:382098 return true;
2099 // If we're not currently downloading, we have as much buffer as
2100 // we're ever going to get, which means we say we can play through.
2101 if (network_state_ == WebMediaPlayer::kNetworkStateIdle)
2102 return true;
Antonio Gomes81b56552019-05-15 22:15:282103 return buffered_data_source_host_->CanPlayThrough(
hubbeb2d3efd2017-05-05 23:26:382104 base::TimeDelta::FromSecondsD(CurrentTime()),
2105 base::TimeDelta::FromSecondsD(Duration()),
2106 playback_rate_ == 0.0 ? 1.0 : playback_rate_);
2107}
2108
Dale Curtisff576552018-03-30 02:32:442109void WebMediaPlayerImpl::OnBufferingStateChangeInternal(
2110 BufferingState state,
Chris Cunninghamfc0d67e2019-07-22 20:29:162111 BufferingStateChangeReason reason,
Dale Curtisff576552018-03-30 02:32:442112 bool for_suspended_start) {
Chris Cunninghamfc0d67e2019-07-22 20:29:162113 DVLOG(1) << __func__ << "(" << state << ", " << reason << ")";
alokp967c902452016-05-06 05:21:372114 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]b8877772014-03-26 20:17:152115
Ted Meyer742212b82018-08-22 17:21:422116 // Ignore buffering state changes caused by back-to-back seeking, so as not
2117 // to assume the second seek has finished when it was only the first seek.
Antonio Gomes81b56552019-05-15 22:15:282118 if (pipeline_controller_->IsPendingSeek())
[email protected]ba7d5f92014-06-24 05:37:402119 return;
[email protected]b8877772014-03-26 20:17:152120
Ted Meyer0134aed2020-01-23 23:56:402121 media_log_->AddEvent<MediaLogEvent::kBufferingStateChanged>(
2122 SerializableBufferingState<SerializableBufferingStateType::kPipeline>{
2123 state, reason, for_suspended_start});
dalecurtis869bf2f2017-01-10 18:01:102124
Ted Meyerd5885f82019-07-16 19:19:172125 if (state == BUFFERING_HAVE_ENOUGH && !for_suspended_start)
2126 media_metrics_provider_->SetHaveEnough();
2127
chcunninghameb270c92016-07-15 01:00:452128 if (state == BUFFERING_HAVE_ENOUGH) {
John Chen5b164a02017-11-01 00:36:092129 TRACE_EVENT1("media", "WebMediaPlayerImpl::BufferingHaveEnough", "id",
2130 media_log_->id());
Dale Curtisff576552018-03-30 02:32:442131 // The SetReadyState() call below may clear
2132 // |skip_metrics_due_to_startup_suspend_| so report this first.
2133 if (!have_reported_time_to_play_ready_ &&
2134 !skip_metrics_due_to_startup_suspend_) {
2135 DCHECK(!for_suspended_start);
Dale Curtis3899090ea2018-01-12 00:10:352136 have_reported_time_to_play_ready_ = true;
2137 const base::TimeDelta elapsed = base::TimeTicks::Now() - load_start_time_;
2138 media_metrics_provider_->SetTimeToPlayReady(elapsed);
2139 RecordTimingUMA("Media.TimeToPlayReady", elapsed);
2140 }
[email protected]ba7d5f92014-06-24 05:37:402141
Dale Curtisff576552018-03-30 02:32:442142 // Warning: This call may be re-entrant.
2143 SetReadyState(CanPlayThrough() ? WebMediaPlayer::kReadyStateHaveEnoughData
2144 : WebMediaPlayer::kReadyStateHaveFutureData);
2145
Dale Curtis18ad391b2019-05-30 23:25:092146 // Let the DataSource know we have enough data -- this is the only function
2147 // during which we advance to (or past) the kReadyStateHaveEnoughData state.
2148 // It may use this information to update buffer sizes or release unused
2149 // network connections.
2150 MaybeUpdateBufferSizesForPlayback();
Dale Curtis04769ca2019-05-25 00:38:102151 if (mb_data_source_ && !client_->CouldPlayIfEnoughData()) {
2152 // For LazyLoad this will be handled during OnPipelineSuspended().
2153 if (for_suspended_start && did_lazy_load_)
2154 DCHECK(!have_enough_after_lazy_load_cb_.IsCancelled());
2155 else
2156 mb_data_source_->OnBufferingHaveEnough(false);
2157 }
dalecurtis849cf4b22015-03-27 18:35:452158
chcunninghameb270c92016-07-15 01:00:452159 // Blink expects a timeChanged() in response to a seek().
sandersd35d2c3f2017-01-14 02:04:422160 if (should_notify_time_changed_) {
2161 should_notify_time_changed_ = false;
Blink Reformat1c4d759e2017-04-09 16:34:542162 client_->TimeChanged();
sandersd35d2c3f2017-01-14 02:04:422163 }
dalecurtis0f0097a2015-12-01 17:40:472164
chcunninghameb270c92016-07-15 01:00:452165 // Once we have enough, start reporting the total memory usage. We'll also
2166 // report once playback starts.
2167 ReportMemoryUsage();
dalecurtis9d638a12016-08-30 06:20:552168
dalecurtis4f6d14d2017-02-22 17:42:222169 // Report the amount of time it took to leave the underflow state.
2170 if (underflow_timer_) {
Dale Curtisc9069622019-10-24 20:20:502171 auto elapsed = underflow_timer_->Elapsed();
2172 RecordUnderflowDuration(elapsed);
2173 watch_time_reporter_->OnUnderflowComplete(elapsed);
dalecurtis9d638a12016-08-30 06:20:552174 underflow_timer_.reset();
2175 }
Sergey Ulanovb8656772020-04-21 22:56:142176
2177 if (playback_events_recorder_)
2178 playback_events_recorder_->OnBufferingComplete();
chcunninghameb270c92016-07-15 01:00:452179 } else {
2180 // Buffering has underflowed.
2181 DCHECK_EQ(state, BUFFERING_HAVE_NOTHING);
dalecurtisacd77d62016-09-09 23:23:142182
dalecurtisd06eabc2017-02-24 23:43:292183 // Report the number of times we've entered the underflow state. Ensure we
2184 // only report the value when transitioning from HAVE_ENOUGH to
2185 // HAVE_NOTHING.
Dale Curtis6995b862017-05-31 22:20:082186 if (ready_state_ == WebMediaPlayer::kReadyStateHaveEnoughData &&
2187 !seeking_) {
Jose Lopes9023b6d2020-02-19 20:42:372188 underflow_timer_ = std::make_unique<base::ElapsedTimer>();
Dale Curtis6995b862017-05-31 22:20:082189 watch_time_reporter_->OnUnderflow();
Sergey Ulanovb8656772020-04-21 22:56:142190
2191 if (playback_events_recorder_)
2192 playback_events_recorder_->OnBuffering();
Dale Curtis6995b862017-05-31 22:20:082193 }
dalecurtisacd77d62016-09-09 23:23:142194
chcunninghameb270c92016-07-15 01:00:452195 // It shouldn't be possible to underflow if we've not advanced past
2196 // HAVE_CURRENT_DATA.
Blink Reformat1c4d759e2017-04-09 16:34:542197 DCHECK_GT(highest_ready_state_, WebMediaPlayer::kReadyStateHaveCurrentData);
2198 SetReadyState(WebMediaPlayer::kReadyStateHaveCurrentData);
chcunninghameb270c92016-07-15 01:00:452199 }
sandersd50a635e2016-04-04 22:50:092200
[email protected]91379332020-01-26 03:58:202201 // If this is an NNR, then notify the smoothness helper about it. Note that
2202 // it's unclear what we should do if there is no smoothness helper yet. As it
2203 // is, we just discard the NNR.
2204 if (state == BUFFERING_HAVE_NOTHING && reason == DECODER_UNDERFLOW &&
2205 smoothness_helper_) {
2206 smoothness_helper_->NotifyNNR();
2207 }
2208
sandersd50a635e2016-04-04 22:50:092209 UpdatePlayState();
[email protected]b8877772014-03-26 20:17:152210}
2211
alokp967c902452016-05-06 05:21:372212void WebMediaPlayerImpl::OnDurationChange() {
acolwellb4034942014-08-28 15:42:432213 DCHECK(main_task_runner_->BelongsToCurrentThread());
alokp967c902452016-05-06 05:21:372214
John Delaney2371b452018-12-13 04:30:332215 if (frame_->IsAdSubframe()) {
2216 UMA_HISTOGRAM_CUSTOM_TIMES("Ads.Media.Duration", GetPipelineMediaDuration(),
2217 base::TimeDelta::FromMilliseconds(1),
2218 base::TimeDelta::FromDays(1),
2219 50 /* bucket_count */);
2220 }
2221
alokp967c902452016-05-06 05:21:372222 // TODO(sandersd): We should call delegate_->DidPlay() with the new duration,
2223 // especially if it changed from <5s to >5s.
Blink Reformat1c4d759e2017-04-09 16:34:542224 if (ready_state_ == WebMediaPlayer::kReadyStateHaveNothing)
alokp967c902452016-05-06 05:21:372225 return;
2226
Blink Reformat1c4d759e2017-04-09 16:34:542227 client_->DurationChanged();
Dale Curtisaebaeea2018-07-19 23:42:112228 if (watch_time_reporter_)
2229 watch_time_reporter_->OnDurationChanged(GetPipelineMediaDuration());
Becca Hughes7a85bf22019-07-24 16:16:582230
2231 // The duration has changed so we should update the media position state.
2232 UpdateMediaPositionState();
[email protected]81bb3322011-07-21 15:55:502233}
2234
alokp967c902452016-05-06 05:21:372235void WebMediaPlayerImpl::OnAddTextTrack(const TextTrackConfig& config,
Raymond Toy85ad6802019-12-17 23:55:192236 AddTextTrackDoneCB done_cb) {
acolwellb4034942014-08-28 15:42:432237 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]71537722013-05-23 06:47:532238
[email protected]8a561062013-11-22 01:19:312239 const WebInbandTextTrackImpl::Kind web_kind =
2240 static_cast<WebInbandTextTrackImpl::Kind>(config.kind());
Blink Reformat1c4d759e2017-04-09 16:34:542241 const blink::WebString web_label = blink::WebString::FromUTF8(config.label());
[email protected]8a561062013-11-22 01:19:312242 const blink::WebString web_language =
Blink Reformat1c4d759e2017-04-09 16:34:542243 blink::WebString::FromUTF8(config.language());
2244 const blink::WebString web_id = blink::WebString::FromUTF8(config.id());
[email protected]71537722013-05-23 06:47:532245
dcheng3076abbf2016-04-22 20:42:392246 std::unique_ptr<WebInbandTextTrackImpl> web_inband_text_track(
henriks9cce5fa2014-12-12 09:35:302247 new WebInbandTextTrackImpl(web_kind, web_label, web_language, web_id));
[email protected]8a561062013-11-22 01:19:312248
Dale Curtisca1b78f2019-01-15 03:11:262249 std::unique_ptr<TextTrack> text_track(new TextTrackImpl(
dcheng652f5ff2015-12-27 08:54:002250 main_task_runner_, client_, std::move(web_inband_text_track)));
[email protected]8a561062013-11-22 01:19:312251
Raymond Toy85ad6802019-12-17 23:55:192252 std::move(done_cb).Run(std::move(text_track));
[email protected]71537722013-05-23 06:47:532253}
2254
Xiaohan Wang640b41d2018-12-18 19:00:462255void WebMediaPlayerImpl::OnWaiting(WaitingReason reason) {
alokp967c902452016-05-06 05:21:372256 DCHECK(main_task_runner_->BelongsToCurrentThread());
2257
Xiaohan Wang640b41d2018-12-18 19:00:462258 switch (reason) {
Xiaohan Wangb54a75282019-10-04 21:34:432259 case WaitingReason::kNoCdm:
Xiaohan Wang640b41d2018-12-18 19:00:462260 case WaitingReason::kNoDecryptionKey:
2261 encrypted_client_->DidBlockPlaybackWaitingForKey();
2262 // TODO(jrummell): didResumePlaybackBlockedForKey() should only be called
2263 // when a key has been successfully added (e.g. OnSessionKeysChange() with
2264 // |has_additional_usable_key| = true). http://crbug.com/461903
2265 encrypted_client_->DidResumePlaybackBlockedForKey();
2266 return;
Xiaohan Wang640b41d2018-12-18 19:00:462267
Xiaohan Wanga7224d62019-01-04 22:22:302268 // Ideally this should be handled by PipelineController directly without
2269 // being proxied here. But currently Pipeline::Client (|this|) is passed to
2270 // PipelineImpl directly without going through |pipeline_controller_|,
2271 // making it difficult to do.
2272 // TODO(xhwang): Handle this in PipelineController when we have a clearer
2273 // picture on how to refactor WebMediaPlayerImpl, PipelineController and
2274 // PipelineImpl.
2275 case WaitingReason::kDecoderStateLost:
Antonio Gomes81b56552019-05-15 22:15:282276 pipeline_controller_->OnDecoderStateLost();
Xiaohan Wanga7224d62019-01-04 22:22:302277 return;
2278 }
alokp967c902452016-05-06 05:21:372279}
2280
alokp5d86e9b2016-05-17 20:20:412281void WebMediaPlayerImpl::OnVideoNaturalSizeChange(const gfx::Size& size) {
2282 DCHECK(main_task_runner_->BelongsToCurrentThread());
Blink Reformat1c4d759e2017-04-09 16:34:542283 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
alokp5d86e9b2016-05-17 20:20:412284
Chris Cunningham038548b2017-07-10 22:36:302285 TRACE_EVENT0("media", "WebMediaPlayerImpl::OnVideoNaturalSizeChange");
xhwang60802652017-04-19 07:29:582286
xjz15b483f2017-01-12 00:21:362287 // The input |size| is from the decoded video frame, which is the original
2288 // natural size and need to be rotated accordingly.
Julien Isorce6c83d8de2017-10-12 13:11:292289 gfx::Size rotated_size = GetRotatedVideoSize(
Ted Meyer4a427632019-05-01 19:05:272290 pipeline_metadata_.video_decoder_config.video_transformation().rotation,
2291 size);
sandersd2c478422016-08-02 01:19:252292
xhwang60802652017-04-19 07:29:582293 RecordVideoNaturalSize(rotated_size);
2294
2295 gfx::Size old_size = pipeline_metadata_.natural_size;
2296 if (rotated_size == old_size)
alokp5d86e9b2016-05-17 20:20:412297 return;
2298
xjz516ef6d2017-01-07 00:23:062299 pipeline_metadata_.natural_size = rotated_size;
Dan Sanders7ef5d0f2019-05-03 18:30:112300
2301 if (using_media_player_renderer_ && old_size.IsEmpty()) {
2302 // If we are using MediaPlayerRenderer and this is the first size change, we
2303 // now know that there is a video track. This condition is paired with code
2304 // in CreateWatchTimeReporter() that guesses the existence of a video track.
2305 CreateWatchTimeReporter();
2306 } else {
Dan Sanders7ef5d0f2019-05-03 18:30:112307 UpdateSecondaryProperties();
2308 }
dalecurtis25405562017-04-14 23:35:112309
Chris Cunningham5b1b67eb2019-03-23 03:24:412310 if (video_decode_stats_reporter_ &&
2311 !video_decode_stats_reporter_->MatchesBucketedNaturalSize(
2312 pipeline_metadata_.natural_size)) {
2313 CreateVideoDecodeStatsReporter();
2314 }
Chris Cunninghamd9df58e2017-08-29 00:04:232315
[email protected]96665a82020-01-23 00:35:372316 // Create or replace the smoothness helper now that we have a size.
2317 UpdateSmoothnessHelper();
2318
Blink Reformat1c4d759e2017-04-09 16:34:542319 client_->SizeChanged();
xjz516ef6d2017-01-07 00:23:062320
xjz15b483f2017-01-12 00:21:362321 if (observer_)
2322 observer_->OnMetadataChanged(pipeline_metadata_);
peconn257951522017-06-09 18:24:592323
2324 delegate_->DidPlayerSizeChange(delegate_id_, NaturalSize());
alokp5d86e9b2016-05-17 20:20:412325}
2326
2327void WebMediaPlayerImpl::OnVideoOpacityChange(bool opaque) {
2328 DCHECK(main_task_runner_->BelongsToCurrentThread());
Blink Reformat1c4d759e2017-04-09 16:34:542329 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
alokp5d86e9b2016-05-17 20:20:412330
2331 opaque_ = opaque;
Dale Curtis357630f22019-01-18 01:10:172332 if (!surface_layer_for_video_enabled_ && video_layer_)
2333 video_layer_->SetContentsOpaque(opaque_);
2334 else if (bridge_->GetCcLayer())
CJ DiMeglioa2b13fbc2018-06-27 00:50:592335 bridge_->SetContentsOpaque(opaque_);
alokp5d86e9b2016-05-17 20:20:412336}
2337
[email protected]218ac8de2020-01-03 23:41:432338void WebMediaPlayerImpl::OnVideoFrameRateChange(base::Optional<int> fps) {
2339 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]c7a918e2020-01-17 00:18:272340 if (power_status_helper_)
2341 power_status_helper_->SetAverageFrameRate(fps);
[email protected]96665a82020-01-23 00:35:372342
2343 last_reported_fps_ = fps;
2344 UpdateSmoothnessHelper();
[email protected]218ac8de2020-01-03 23:41:432345}
2346
Chris Cunningham038548b2017-07-10 22:36:302347void WebMediaPlayerImpl::OnAudioConfigChange(const AudioDecoderConfig& config) {
2348 DCHECK(main_task_runner_->BelongsToCurrentThread());
2349 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
2350
Dale Curtisccfd0cca2017-08-31 01:27:562351 const bool codec_change =
2352 pipeline_metadata_.audio_decoder_config.codec() != config.codec();
Dale Curtisf8afcef32020-01-18 06:23:262353 const bool codec_profile_change =
2354 pipeline_metadata_.audio_decoder_config.profile() != config.profile();
2355
Chris Cunningham038548b2017-07-10 22:36:302356 pipeline_metadata_.audio_decoder_config = config;
2357
2358 if (observer_)
2359 observer_->OnMetadataChanged(pipeline_metadata_);
Dale Curtisccfd0cca2017-08-31 01:27:562360
Dale Curtisf8afcef32020-01-18 06:23:262361 if (codec_change || codec_profile_change)
Dale Curtis96d6e9382018-07-18 18:01:072362 UpdateSecondaryProperties();
Chris Cunningham038548b2017-07-10 22:36:302363}
2364
2365void WebMediaPlayerImpl::OnVideoConfigChange(const VideoDecoderConfig& config) {
2366 DCHECK(main_task_runner_->BelongsToCurrentThread());
2367 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
2368
Dale Curtisccfd0cca2017-08-31 01:27:562369 const bool codec_change =
2370 pipeline_metadata_.video_decoder_config.codec() != config.codec();
Chris Cunningham5b1b67eb2019-03-23 03:24:412371 const bool codec_profile_change =
2372 pipeline_metadata_.video_decoder_config.profile() != config.profile();
Dale Curtisccfd0cca2017-08-31 01:27:562373
Chris Cunningham038548b2017-07-10 22:36:302374 pipeline_metadata_.video_decoder_config = config;
2375
2376 if (observer_)
2377 observer_->OnMetadataChanged(pipeline_metadata_);
Chris Cunninghamd9df58e2017-08-29 00:04:232378
Dale Curtisf8afcef32020-01-18 06:23:262379 if (codec_change || codec_profile_change)
Dale Curtis96d6e9382018-07-18 18:01:072380 UpdateSecondaryProperties();
Chris Cunningham5b1b67eb2019-03-23 03:24:412381
2382 if (video_decode_stats_reporter_ && codec_profile_change)
2383 CreateVideoDecodeStatsReporter();
Chris Cunningham038548b2017-07-10 22:36:302384}
2385
avayvodeecec52c2017-02-14 01:25:092386void WebMediaPlayerImpl::OnVideoAverageKeyframeDistanceUpdate() {
2387 UpdateBackgroundVideoOptimizationState();
2388}
2389
Ted Meyerd5885f82019-07-16 19:19:172390void WebMediaPlayerImpl::OnAudioDecoderChange(const PipelineDecoderInfo& info) {
2391 media_metrics_provider_->SetAudioPipelineInfo(info);
2392 if (info.decoder_name == audio_decoder_name_)
Dale Curtisc7d2a7d22018-01-11 20:01:052393 return;
2394
Ted Meyerd5885f82019-07-16 19:19:172395 audio_decoder_name_ = info.decoder_name;
Dale Curtisc7d2a7d22018-01-11 20:01:052396
2397 // If there's no current reporter, there's nothing to be done.
2398 if (!watch_time_reporter_)
2399 return;
2400
Dale Curtis96d6e9382018-07-18 18:01:072401 UpdateSecondaryProperties();
Dale Curtisc7d2a7d22018-01-11 20:01:052402}
2403
Ted Meyerd5885f82019-07-16 19:19:172404void WebMediaPlayerImpl::OnVideoDecoderChange(const PipelineDecoderInfo& info) {
2405 media_metrics_provider_->SetVideoPipelineInfo(info);
2406 if (info.decoder_name == video_decoder_name_)
Dale Curtisc7d2a7d22018-01-11 20:01:052407 return;
2408
Ted Meyerd5885f82019-07-16 19:19:172409 video_decoder_name_ = info.decoder_name;
Dale Curtisc7d2a7d22018-01-11 20:01:052410
2411 // If there's no current reporter, there's nothing to be done.
2412 if (!watch_time_reporter_)
2413 return;
2414
Dale Curtis96d6e9382018-07-18 18:01:072415 UpdateSecondaryProperties();
Dale Curtisc7d2a7d22018-01-11 20:01:052416}
2417
sandersd35d2c3f2017-01-14 02:04:422418void WebMediaPlayerImpl::OnFrameHidden() {
sandersd1e49fb62015-12-12 01:18:062419 DCHECK(main_task_runner_->BelongsToCurrentThread());
avayvod39c102402016-11-23 21:43:132420
avayvod65fad272017-02-24 01:00:482421 // Backgrounding a video requires a user gesture to resume playback.
2422 if (IsHidden())
2423 video_locked_when_paused_when_hidden_ = true;
2424
dalecurtis04bdb582016-08-17 22:15:232425 if (watch_time_reporter_)
2426 watch_time_reporter_->OnHidden();
avayvod48a8be52016-08-04 19:52:502427
Chris Cunninghamd9df58e2017-08-29 00:04:232428 if (video_decode_stats_reporter_)
2429 video_decode_stats_reporter_->OnHidden();
2430
avayvod65fad272017-02-24 01:00:482431 UpdateBackgroundVideoOptimizationState();
sandersd50a635e2016-04-04 22:50:092432 UpdatePlayState();
dalecurtis8b8505e72016-06-10 21:59:172433
2434 // Schedule suspended playing media to be paused if the user doesn't come back
2435 // to it within some timeout period to avoid any autoplay surprises.
2436 ScheduleIdlePauseTimer();
Dale Curtisca1b78f2019-01-15 03:11:262437
2438 // Notify the compositor of our page visibility status.
2439 vfc_task_runner_->PostTask(
2440 FROM_HERE,
2441 base::BindOnce(&VideoFrameCompositor::SetIsPageVisible,
2442 base::Unretained(compositor_.get()), !IsHidden()));
sandersd1e49fb62015-12-12 01:18:062443}
2444
sandersd35d2c3f2017-01-14 02:04:422445void WebMediaPlayerImpl::OnFrameClosed() {
sandersd1e49fb62015-12-12 01:18:062446 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]28347e72017-06-27 17:30:112447
sandersd35d2c3f2017-01-14 02:04:422448 UpdatePlayState();
2449}
2450
2451void WebMediaPlayerImpl::OnFrameShown() {
2452 DCHECK(main_task_runner_->BelongsToCurrentThread());
2453 background_pause_timer_.Stop();
2454
avayvod65fad272017-02-24 01:00:482455 // Foreground videos don't require user gesture to continue playback.
2456 video_locked_when_paused_when_hidden_ = false;
2457
dalecurtis04bdb582016-08-17 22:15:232458 if (watch_time_reporter_)
2459 watch_time_reporter_->OnShown();
2460
Chris Cunninghamd9df58e2017-08-29 00:04:232461 if (video_decode_stats_reporter_)
2462 video_decode_stats_reporter_->OnShown();
2463
Dale Curtisca1b78f2019-01-15 03:11:262464 // Notify the compositor of our page visibility status.
2465 vfc_task_runner_->PostTask(
2466 FROM_HERE,
2467 base::BindOnce(&VideoFrameCompositor::SetIsPageVisible,
2468 base::Unretained(compositor_.get()), !IsHidden()));
2469
Dale Curtisdcbb81a2017-08-18 01:06:122470 UpdateBackgroundVideoOptimizationState();
avayvod65fad272017-02-24 01:00:482471
avayvod2135a642017-01-13 00:17:142472 if (paused_when_hidden_) {
2473 paused_when_hidden_ = false;
2474 OnPlay(); // Calls UpdatePlayState() so return afterwards.
2475 return;
2476 }
2477
sandersd50a635e2016-04-04 22:50:092478 UpdatePlayState();
sandersd1e49fb62015-12-12 01:18:062479}
2480
sandersd35d2c3f2017-01-14 02:04:422481void WebMediaPlayerImpl::OnIdleTimeout() {
dalecurtis0431cbf2016-03-12 01:19:432482 DCHECK(main_task_runner_->BelongsToCurrentThread());
2483
Dale Curtis99a9b482018-02-01 02:23:282484 // This should never be called when stale state testing overrides are used.
2485 DCHECK(!stale_state_override_for_testing_.has_value());
2486
sandersd35d2c3f2017-01-14 02:04:422487 // If we are attempting preroll, clear the stale flag.
2488 if (IsPrerollAttemptNeeded()) {
tguilbert1bb1c782017-01-23 21:15:112489 delegate_->ClearStaleFlag(delegate_id_);
sandersd35d2c3f2017-01-14 02:04:422490 return;
watkd026f792016-11-05 00:28:512491 }
sandersd50a635e2016-04-04 22:50:092492
sandersd35d2c3f2017-01-14 02:04:422493 UpdatePlayState();
dalecurtis0431cbf2016-03-12 01:19:432494}
2495
dalecurtisbb3eaac2016-01-27 21:10:252496void WebMediaPlayerImpl::OnPlay() {
Mounir Lamouri703106e2018-05-30 14:31:092497 client_->RequestPlay();
dalecurtisbb3eaac2016-01-27 21:10:252498}
2499
2500void WebMediaPlayerImpl::OnPause() {
Mounir Lamouri703106e2018-05-30 14:31:092501 client_->RequestPause();
dalecurtisbb3eaac2016-01-27 21:10:252502}
2503
François Beaufortb4fe7c62019-02-27 08:19:442504void WebMediaPlayerImpl::OnMuted(bool muted) {
2505 client_->RequestMuted(muted);
2506}
2507
Alec Douglas316cce42017-10-31 13:28:082508void WebMediaPlayerImpl::OnSeekForward(double seconds) {
2509 DCHECK_GE(seconds, 0) << "Attempted to seek by a negative number of seconds";
2510 client_->RequestSeek(CurrentTime() + seconds);
2511}
2512
2513void WebMediaPlayerImpl::OnSeekBackward(double seconds) {
2514 DCHECK_GE(seconds, 0) << "Attempted to seek by a negative number of seconds";
2515 client_->RequestSeek(CurrentTime() - seconds);
2516}
2517
Jazz Xuf8564dc2020-01-24 14:26:022518void WebMediaPlayerImpl::OnEnterPictureInPicture() {
2519 client_->RequestEnterPictureInPicture();
2520}
2521
2522void WebMediaPlayerImpl::OnExitPictureInPicture() {
2523 client_->RequestExitPictureInPicture();
2524}
2525
dalecurtisbb3eaac2016-01-27 21:10:252526void WebMediaPlayerImpl::OnVolumeMultiplierUpdate(double multiplier) {
2527 volume_multiplier_ = multiplier;
Blink Reformat1c4d759e2017-04-09 16:34:542528 SetVolume(volume_);
dalecurtisbb3eaac2016-01-27 21:10:252529}
2530
zqzhang8ac49002017-03-16 21:51:352531void WebMediaPlayerImpl::OnBecamePersistentVideo(bool value) {
Blink Reformat1c4d759e2017-04-09 16:34:542532 client_->OnBecamePersistentVideo(value);
[email protected]6490e2d12019-01-14 19:18:372533 overlay_info_.is_persistent_video = value;
2534 MaybeSendOverlayInfoToDecoder();
zqzhang8ac49002017-03-16 21:51:352535}
2536
[email protected]201ce4ba2020-01-09 22:19:092537void WebMediaPlayerImpl::OnPowerExperimentState(bool state) {
2538 if (power_status_helper_)
2539 power_status_helper_->UpdatePowerExperimentState(state);
2540}
2541
watkdee516f2016-02-18 02:22:192542void WebMediaPlayerImpl::ScheduleRestart() {
sandersd50a635e2016-04-04 22:50:092543 // TODO(watk): All restart logic should be moved into PipelineController.
Antonio Gomes81b56552019-05-15 22:15:282544 if (pipeline_controller_->IsPipelineRunning() &&
2545 !pipeline_controller_->IsPipelineSuspended()) {
watkdee516f2016-02-18 02:22:192546 pending_suspend_resume_cycle_ = true;
sandersd50a635e2016-04-04 22:50:092547 UpdatePlayState();
watkdee516f2016-02-18 02:22:192548 }
2549}
2550
Blink Reformat1c4d759e2017-04-09 16:34:542551void WebMediaPlayerImpl::RequestRemotePlaybackDisabled(bool disabled) {
miu77f914c2016-11-19 23:56:182552 if (observer_)
2553 observer_->OnRemotePlaybackDisabled(disabled);
2554}
2555
Thomas Guilbert7350fdad2019-01-29 23:09:242556#if defined(OS_ANDROID)
Thomas Guilbertb341bae02018-05-09 00:02:132557void WebMediaPlayerImpl::FlingingStarted() {
2558 DCHECK(main_task_runner_->BelongsToCurrentThread());
2559 DCHECK(!disable_pipeline_auto_suspend_);
2560 disable_pipeline_auto_suspend_ = true;
2561
Thomas Guilbert29ae1a902018-10-20 01:53:382562 is_flinging_ = true;
2563
Thomas Guilbertb341bae02018-05-09 00:02:132564 // Capabilities reporting should only be performed for local playbacks.
2565 video_decode_stats_reporter_.reset();
2566
2567 // Requests to restart media pipeline. A flinging renderer will be created via
2568 // the |renderer_factory_selector_|.
2569 ScheduleRestart();
2570}
2571
2572void WebMediaPlayerImpl::FlingingStopped() {
2573 DCHECK(main_task_runner_->BelongsToCurrentThread());
2574 DCHECK(disable_pipeline_auto_suspend_);
2575 disable_pipeline_auto_suspend_ = false;
2576
Thomas Guilbert29ae1a902018-10-20 01:53:382577 is_flinging_ = false;
2578
Thomas Guilbertb341bae02018-05-09 00:02:132579 CreateVideoDecodeStatsReporter();
2580
2581 ScheduleRestart();
2582}
Thomas Guilbert901808982019-07-03 20:38:182583
2584void WebMediaPlayerImpl::OnRemotePlayStateChange(MediaStatus::State state) {
2585 DCHECK(is_flinging_);
Thomas Guilbertf6d0702e2019-09-12 23:40:142586 DCHECK(main_task_runner_->BelongsToCurrentThread());
Thomas Guilbert901808982019-07-03 20:38:182587
2588 if (state == MediaStatus::State::PLAYING && Paused()) {
2589 DVLOG(1) << __func__ << " requesting PLAY.";
2590 client_->RequestPlay();
2591 } else if (state == MediaStatus::State::PAUSED && !Paused()) {
2592 DVLOG(1) << __func__ << " requesting PAUSE.";
2593 client_->RequestPause();
2594 }
2595}
Thomas Guilbert7350fdad2019-01-29 23:09:242596#endif // defined(OS_ANDROID)
hubbee4027f92016-05-19 05:18:132597
Blink Reformat1c4d759e2017-04-09 16:34:542598void WebMediaPlayerImpl::SetPoster(const blink::WebURL& poster) {
Dan Sanderscd8981c2017-08-31 22:37:022599 has_poster_ = !poster.IsEmpty();
Dan Sanderscd8981c2017-08-31 22:37:022600}
xjzc102fd82017-01-04 20:13:532601
[email protected]fee8a902014-06-03 13:43:362602void WebMediaPlayerImpl::DataSourceInitialized(bool success) {
pkastingf5279482016-07-27 02:18:202603 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:432604 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]a9415292012-01-19 19:55:202605
Thomas Guilberta8a6e922019-02-01 00:02:472606 if (observer_ && mb_data_source_)
Dale Curtis4841c712018-12-13 18:14:052607 observer_->OnDataSourceInitialized(mb_data_source_->GetUrlAfterRedirects());
Anton Vayvod09fa66e2017-07-20 23:02:122608
[email protected]d250190da3b2012-07-23 22:57:302609 if (!success) {
Blink Reformat1c4d759e2017-04-09 16:34:542610 SetNetworkState(WebMediaPlayer::kNetworkStateFormatError);
Dale Curtis74612b72017-12-14 20:56:192611 media_metrics_provider_->OnError(PIPELINE_ERROR_NETWORK);
sandersd50a635e2016-04-04 22:50:092612
2613 // Not really necessary, since the pipeline was never started, but it at
2614 // least this makes sure that the error handling code is in sync.
2615 UpdatePlayState();
2616
[email protected]a9415292012-01-19 19:55:202617 return;
2618 }
2619
hubbee2cc88c092017-07-14 23:10:412620 // No point in preloading data as we'll probably just throw it away anyways.
Dale Curtis4841c712018-12-13 18:14:052621 if (IsStreaming() && preload_ > MultibufferDataSource::METADATA &&
2622 mb_data_source_) {
2623 mb_data_source_->SetPreload(MultibufferDataSource::METADATA);
hubbee2cc88c092017-07-14 23:10:412624 }
2625
[email protected]ef8394c2013-08-21 20:26:302626 StartPipeline();
[email protected]a9415292012-01-19 19:55:202627}
2628
[email protected]122f40252012-06-12 05:01:562629void WebMediaPlayerImpl::NotifyDownloading(bool is_downloading) {
hubbeb2d3efd2017-05-05 23:26:382630 DVLOG(1) << __func__ << "(" << is_downloading << ")";
Blink Reformat1c4d759e2017-04-09 16:34:542631 if (!is_downloading && network_state_ == WebMediaPlayer::kNetworkStateLoading)
2632 SetNetworkState(WebMediaPlayer::kNetworkStateIdle);
2633 else if (is_downloading &&
2634 network_state_ == WebMediaPlayer::kNetworkStateIdle)
2635 SetNetworkState(WebMediaPlayer::kNetworkStateLoading);
hubbeb2d3efd2017-05-05 23:26:382636 if (ready_state_ == ReadyState::kReadyStateHaveFutureData && !is_downloading)
2637 SetReadyState(WebMediaPlayer::kReadyStateHaveEnoughData);
[email protected]122f40252012-06-12 05:01:562638}
2639
liberato2ff93ad2017-05-17 07:28:242640void WebMediaPlayerImpl::OnOverlayRoutingToken(
2641 const base::UnguessableToken& token) {
2642 DCHECK(overlay_mode_ == OverlayMode::kUseAndroidOverlay);
liberatofe8f9692017-06-08 19:17:362643 // TODO(liberato): |token| should already be a RoutingToken.
2644 overlay_routing_token_is_pending_ = false;
2645 overlay_routing_token_ = OverlayInfo::RoutingToken(token);
liberato2ff93ad2017-05-17 07:28:242646 MaybeSendOverlayInfoToDecoder();
2647}
2648
2649void WebMediaPlayerImpl::OnOverlayInfoRequested(
dalecurtis4b632fce22016-11-10 00:52:172650 bool decoder_requires_restart_for_overlay,
Jose Lopes689012d2020-02-27 09:04:492651 ProvideOverlayInfoCB provide_overlay_info_cb) {
watkdee516f2016-02-18 02:22:192652 DCHECK(main_task_runner_->BelongsToCurrentThread());
watkdee516f2016-02-18 02:22:192653
Chris Watkins557f84d2017-09-16 02:31:462654 // If we get a non-null cb, a decoder is initializing and requires overlay
2655 // info. If we get a null cb, a previously initialized decoder is
2656 // unregistering for overlay info updates.
Dale Curtise25163812018-09-21 22:13:392657 if (!provide_overlay_info_cb) {
tsunghungee562e92016-07-20 18:03:312658 decoder_requires_restart_for_overlay_ = false;
liberato2ff93ad2017-05-17 07:28:242659 provide_overlay_info_cb_.Reset();
watkdee516f2016-02-18 02:22:192660 return;
2661 }
2662
dalecurtis4b632fce22016-11-10 00:52:172663 // If |decoder_requires_restart_for_overlay| is true, we must restart the
2664 // pipeline for fullscreen transitions. The decoder is unable to switch
2665 // surfaces otherwise. If false, we simply need to tell the decoder about the
2666 // new surface and it will handle things seamlessly.
Chris Watkins557f84d2017-09-16 02:31:462667 // For encrypted video we pretend that the decoder doesn't require a restart
2668 // because it needs an overlay all the time anyway. We'll switch into
2669 // |always_enable_overlays_| mode below.
2670 decoder_requires_restart_for_overlay_ =
2671 (overlay_mode_ == OverlayMode::kUseAndroidOverlay && is_encrypted_)
2672 ? false
2673 : decoder_requires_restart_for_overlay;
Jose Lopes689012d2020-02-27 09:04:492674 provide_overlay_info_cb_ = std::move(provide_overlay_info_cb);
dalecurtis4b632fce22016-11-10 00:52:172675
Chris Watkins557f84d2017-09-16 02:31:462676 // If the decoder doesn't require restarts for surface transitions, and we're
2677 // using AndroidOverlay mode, we can always enable the overlay and the decoder
2678 // can choose whether or not to use it. Otherwise, we'll restart the decoder
2679 // and enable the overlay on fullscreen transitions.
[email protected]77568482017-06-21 21:16:522680 if (overlay_mode_ == OverlayMode::kUseAndroidOverlay &&
Chris Watkins557f84d2017-09-16 02:31:462681 !decoder_requires_restart_for_overlay_) {
[email protected]c8d574722017-08-30 20:53:432682 always_enable_overlays_ = true;
[email protected]77568482017-06-21 21:16:522683 if (!overlay_enabled_)
2684 EnableOverlay();
2685 }
2686
Chris Watkins557f84d2017-09-16 02:31:462687 // Send the overlay info if we already have it. If not, it will be sent later.
liberato2ff93ad2017-05-17 07:28:242688 MaybeSendOverlayInfoToDecoder();
2689}
2690
2691void WebMediaPlayerImpl::MaybeSendOverlayInfoToDecoder() {
2692 // If the decoder didn't request overlay info, then don't send it.
2693 if (!provide_overlay_info_cb_)
dalecurtis4b632fce22016-11-10 00:52:172694 return;
2695
liberato2ff93ad2017-05-17 07:28:242696 // We should send the overlay info as long as we know it. This includes the
2697 // case where |!overlay_enabled_|, since we want to tell the decoder to avoid
2698 // using overlays. Assuming that the decoder has requested info, the only
2699 // case in which we don't want to send something is if we've requested the
2700 // info but not received it yet. Then, we should wait until we do.
liberatofe8f9692017-06-08 19:17:362701 //
2702 // Initialization requires this; AVDA should start with enough info to make an
2703 // overlay, so that (pre-M) the initial codec is created with the right output
2704 // surface; it can't switch later.
[email protected]f7df5b342018-07-13 20:22:132705 if (overlay_mode_ == OverlayMode::kUseAndroidOverlay) {
liberatofe8f9692017-06-08 19:17:362706 if (overlay_routing_token_is_pending_)
liberato2ff93ad2017-05-17 07:28:242707 return;
liberatofe8f9692017-06-08 19:17:362708
2709 overlay_info_.routing_token = overlay_routing_token_;
liberato2ff93ad2017-05-17 07:28:242710 }
2711
liberato2ff93ad2017-05-17 07:28:242712 // If restart is required, the callback is one-shot only.
2713 if (decoder_requires_restart_for_overlay_) {
Dale Curtise25163812018-09-21 22:13:392714 std::move(provide_overlay_info_cb_).Run(overlay_info_);
liberato2ff93ad2017-05-17 07:28:242715 } else {
liberatofe8f9692017-06-08 19:17:362716 provide_overlay_info_cb_.Run(overlay_info_);
liberato2ff93ad2017-05-17 07:28:242717 }
watkdee516f2016-02-18 02:22:192718}
2719
Xiaohan Wangcd4df0a2019-12-04 20:59:242720std::unique_ptr<Renderer> WebMediaPlayerImpl::CreateRenderer(
Xiaohan Wang48aaa192019-12-05 01:29:002721 base::Optional<RendererFactoryType> factory_type) {
dcheng37b415b92017-01-27 20:17:432722 DCHECK(main_task_runner_->BelongsToCurrentThread());
2723
[email protected]c8d574722017-08-30 20:53:432724 // Make sure that overlays are enabled if they're always allowed.
2725 if (always_enable_overlays_)
tsunghungee562e92016-07-20 18:03:312726 EnableOverlay();
2727
liberato2ff93ad2017-05-17 07:28:242728 RequestOverlayInfoCB request_overlay_info_cb;
watkdee516f2016-02-18 02:22:192729#if defined(OS_ANDROID)
Jose Lopes689012d2020-02-27 09:04:492730 request_overlay_info_cb = BindToCurrentLoop(base::BindRepeating(
2731 &WebMediaPlayerImpl::OnOverlayInfoRequested, weak_this_));
watkdee516f2016-02-18 02:22:192732#endif
Xiaohan Wangcd4df0a2019-12-04 20:59:242733
2734 if (factory_type) {
Xiaohan Wang48aaa192019-12-05 01:29:002735 DVLOG(1) << __func__
2736 << ": factory_type=" << static_cast<int>(factory_type.value());
Xiaohan Wangcd4df0a2019-12-04 20:59:242737 renderer_factory_selector_->SetBaseFactoryType(factory_type.value());
2738 }
2739
Dan Sanders6edfd782019-08-13 00:13:182740 reported_renderer_type_ = renderer_factory_selector_->GetCurrentFactoryType();
Xiaohan Wang73b433f2019-11-05 20:13:012741
Xiaohan Wang2480de72019-11-15 01:44:472742 return renderer_factory_selector_->GetCurrentFactory()->CreateRenderer(
2743 media_task_runner_, worker_task_runner_, audio_source_provider_.get(),
Jose Lopes689012d2020-02-27 09:04:492744 compositor_.get(), std::move(request_overlay_info_cb),
2745 client_->TargetColorSpace());
sandersd1e49fb62015-12-12 01:18:062746}
2747
[email protected]ef8394c2013-08-21 20:26:302748void WebMediaPlayerImpl::StartPipeline() {
acolwellb4034942014-08-28 15:42:432749 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]ddbc6ff2013-04-19 15:28:332750
xhwange8c4181a2014-12-06 08:10:012751 Demuxer::EncryptedMediaInitDataCB encrypted_media_init_data_cb =
Jose Lopes066452e2020-02-19 20:45:342752 BindToCurrentLoop(base::BindRepeating(
Antonio Gomes142f32a2019-05-15 23:32:562753 &WebMediaPlayerImpl::OnEncryptedMediaInitData, weak_this_));
[email protected]2b57e2e2014-05-09 11:07:252754
Dale Curtis3899090ea2018-01-12 00:10:352755 vfc_task_runner_->PostTask(
2756 FROM_HERE,
2757 base::BindOnce(&VideoFrameCompositor::SetOnNewProcessedFrameCallback,
2758 base::Unretained(compositor_.get()),
2759 BindToCurrentLoop(base::BindOnce(
Antonio Gomes142f32a2019-05-15 23:32:562760 &WebMediaPlayerImpl::OnFirstFrame, weak_this_))));
Dale Curtis3899090ea2018-01-12 00:10:352761
Thomas Guilbert55b48d92019-03-25 23:16:542762#if defined(OS_ANDROID)
Dale Curtis65c151a2019-02-26 02:09:322763 if (demuxer_found_hls_ ||
2764 renderer_factory_selector_->GetCurrentFactory()
2765 ->GetRequiredMediaResourceType() == MediaResource::Type::URL) {
Thomas Guilbert8a42fcf2019-03-01 20:21:452766 // MediaPlayerRendererClientFactory is the only factory that a uses
2767 // MediaResource::Type::URL for the moment.
tguilbert75e2bf62017-04-26 20:13:122768 using_media_player_renderer_ = true;
2769
Chris Cunninghamd9df58e2017-08-29 00:04:232770 // MediaPlayerRenderer does not provide pipeline stats, so nuke capabilities
2771 // reporter.
2772 video_decode_stats_reporter_.reset();
2773
Eugene Zemtsov77d56262020-03-06 05:52:032774 SetDemuxer(std::make_unique<MediaUrlDemuxer>(
Maks Orlovichab27e242020-01-07 18:10:392775 media_task_runner_, loaded_url_,
2776 frame_->GetDocument().SiteForCookies().RepresentativeUrl(),
Christian Dullweberacff9bd32019-08-20 09:44:372777 frame_->GetDocument().TopFrameOrigin(),
Eugene Zemtsov77d56262020-03-06 05:52:032778 allow_media_player_renderer_credentials_, demuxer_found_hls_));
Antonio Gomes81b56552019-05-15 22:15:282779 pipeline_controller_->Start(Pipeline::StartType::kNormal, demuxer_.get(),
2780 this, false, false);
tguilbert25a4d112016-10-13 21:56:512781 return;
2782 }
Thomas Guilbert55b48d92019-03-25 23:16:542783#endif // defined(OS_ANDROID)
tguilbert25a4d112016-10-13 21:56:512784
[email protected]ddbc6ff2013-04-19 15:28:332785 // Figure out which demuxer to use.
David Dorwin30993312020-05-07 22:39:092786 if (demuxer_override_) {
2787 DCHECK(!chunk_demuxer_);
2788
2789 SetDemuxer(std::move(demuxer_override_));
2790 // TODO(https://crbug.com/1076267): Should everything else after this block
2791 // run in the demuxer override case?
2792 } else if (load_type_ != kLoadTypeMediaSource) {
[email protected]ddbc6ff2013-04-19 15:28:332793 DCHECK(!chunk_demuxer_);
[email protected]f5443ef72013-04-22 04:03:382794 DCHECK(data_source_);
2795
Dale Curtisbcf523b2018-01-17 02:59:012796#if BUILDFLAG(ENABLE_FFMPEG)
servolk81e01e02016-03-05 03:29:152797 Demuxer::MediaTracksUpdatedCB media_tracks_updated_cb =
Jose Lopes239a0912020-02-20 10:59:332798 BindToCurrentLoop(base::BindRepeating(
Antonio Gomes142f32a2019-05-15 23:32:562799 &WebMediaPlayerImpl::OnFFmpegMediaTracksUpdated, weak_this_));
servolk81e01e02016-03-05 03:29:152800
Eugene Zemtsov77d56262020-03-06 05:52:032801 SetDemuxer(std::make_unique<FFmpegDemuxer>(
dalecurtis9cddc0b2017-04-19 21:23:382802 media_task_runner_, data_source_.get(), encrypted_media_init_data_cb,
Eugene Zemtsov77d56262020-03-06 05:52:032803 media_tracks_updated_cb, media_log_.get(), IsLocalFile(loaded_url_)));
j.isorcef6778e652015-11-16 17:14:252804#else
alokp967c902452016-05-06 05:21:372805 OnError(PipelineStatus::DEMUXER_ERROR_COULD_NOT_OPEN);
j.isorcef6778e652015-11-16 17:14:252806 return;
2807#endif
[email protected]ddbc6ff2013-04-19 15:28:332808 } else {
[email protected]f5443ef72013-04-22 04:03:382809 DCHECK(!chunk_demuxer_);
2810 DCHECK(!data_source_);
2811
Antonio Gomes142f32a2019-05-15 23:32:562812 chunk_demuxer_ =
2813 new ChunkDemuxer(BindToCurrentLoop(base::Bind(
2814 &WebMediaPlayerImpl::OnDemuxerOpened, weak_this_)),
2815 BindToCurrentLoop(base::Bind(
2816 &WebMediaPlayerImpl::OnProgress, weak_this_)),
2817 encrypted_media_init_data_cb, media_log_.get());
Eugene Zemtsov77d56262020-03-06 05:52:032818 SetDemuxer(std::unique_ptr<Demuxer>(chunk_demuxer_));
servolkf94b4602017-01-31 16:44:272819
2820 if (base::FeatureList::IsEnabled(kMemoryPressureBasedSourceBufferGC)) {
2821 // base::Unretained is safe because |this| owns memory_pressure_listener_.
2822 memory_pressure_listener_ =
Gyuyoung Kim62a5de42018-01-10 09:48:422823 std::make_unique<base::MemoryPressureListener>(base::Bind(
servolkf94b4602017-01-31 16:44:272824 &WebMediaPlayerImpl::OnMemoryPressure, base::Unretained(this)));
2825 }
[email protected]ddbc6ff2013-04-19 15:28:332826 }
2827
Dale Curtis2dc6089a2018-03-26 16:47:582828 // If possible attempt to avoid decoder spool up until playback starts.
2829 Pipeline::StartType start_type = Pipeline::StartType::kNormal;
Dale Curtis7c63f2e22018-09-19 21:06:272830 if (!chunk_demuxer_ && preload_ == MultibufferDataSource::METADATA &&
Dale Curtisd6ccd1992019-04-29 19:03:462831 !client_->CouldPlayIfEnoughData() && !IsStreaming()) {
Dale Curtis7c63f2e22018-09-19 21:06:272832 start_type =
2833 (has_poster_ || base::FeatureList::IsEnabled(kPreloadMetadataLazyLoad))
2834 ? Pipeline::StartType::kSuspendAfterMetadata
2835 : Pipeline::StartType::kSuspendAfterMetadataForAudioOnly;
Dale Curtis2dc6089a2018-03-26 16:47:582836 attempting_suspended_start_ = true;
2837 }
2838
Dale Curtis6e2151a2020-05-11 19:45:062839 // TODO(sandersd): FileSystem objects may also be non-static, but due to our
2840 // caching layer such situations are broken already. http://crbug.com/593159
2841 const bool is_static = !chunk_demuxer_;
2842
[email protected]f5443ef72013-04-22 04:03:382843 // ... and we're ready to go!
sandersd1e49fb62015-12-12 01:18:062844 // TODO(sandersd): On Android, defer Start() if the tab is not visible.
sandersdb8eb5f1d2016-11-19 04:04:022845 seeking_ = true;
Dale Curtis6e2151a2020-05-11 19:45:062846 pipeline_controller_->Start(start_type, demuxer_.get(), this, IsStreaming(),
Antonio Gomes81b56552019-05-15 22:15:282847 is_static);
[email protected]f5443ef72013-04-22 04:03:382848}
2849
2850void WebMediaPlayerImpl::SetNetworkState(WebMediaPlayer::NetworkState state) {
pkastingf5279482016-07-27 02:18:202851 DVLOG(1) << __func__ << "(" << state << ")";
acolwellb4034942014-08-28 15:42:432852 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]f5443ef72013-04-22 04:03:382853 network_state_ = state;
2854 // Always notify to ensure client has the latest value.
Blink Reformat1c4d759e2017-04-09 16:34:542855 client_->NetworkStateChanged();
[email protected]f5443ef72013-04-22 04:03:382856}
2857
2858void WebMediaPlayerImpl::SetReadyState(WebMediaPlayer::ReadyState state) {
pkastingf5279482016-07-27 02:18:202859 DVLOG(1) << __func__ << "(" << state << ")";
acolwellb4034942014-08-28 15:42:432860 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]f5443ef72013-04-22 04:03:382861
Blink Reformat1c4d759e2017-04-09 16:34:542862 if (state == WebMediaPlayer::kReadyStateHaveEnoughData && data_source_ &&
Dale Curtis4841c712018-12-13 18:14:052863 data_source_->AssumeFullyBuffered() &&
2864 network_state_ == WebMediaPlayer::kNetworkStateLoading) {
Blink Reformat1c4d759e2017-04-09 16:34:542865 SetNetworkState(WebMediaPlayer::kNetworkStateLoaded);
Dale Curtis4841c712018-12-13 18:14:052866 }
[email protected]f5443ef72013-04-22 04:03:382867
2868 ready_state_ = state;
sandersd50a635e2016-04-04 22:50:092869 highest_ready_state_ = std::max(highest_ready_state_, ready_state_);
2870
[email protected]f5443ef72013-04-22 04:03:382871 // Always notify to ensure client has the latest value.
Blink Reformat1c4d759e2017-04-09 16:34:542872 client_->ReadyStateChanged();
Wojciech Dzierżanowski68f4a522020-04-27 09:48:122873
2874 // The ready state affects the effective playback rate so we should update
2875 // the media position state.
2876 UpdateMediaPositionState();
[email protected]f5443ef72013-04-22 04:03:382877}
2878
Antonio Gomesa38bb7cb2019-05-31 03:02:522879scoped_refptr<blink::WebAudioSourceProviderImpl>
2880WebMediaPlayerImpl::GetAudioSourceProvider() {
2881 return audio_source_provider_;
[email protected]f5443ef72013-04-22 04:03:382882}
2883
Jiajia Qin82acdc02017-07-31 09:55:142884scoped_refptr<VideoFrame> WebMediaPlayerImpl::GetCurrentFrameFromCompositor()
2885 const {
xhwang213e50c2016-10-10 23:56:312886 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]dd061e12014-05-06 19:21:222887 TRACE_EVENT0("media", "WebMediaPlayerImpl::GetCurrentFrameFromCompositor");
xhwang213e50c2016-10-10 23:56:312888
Thomas Guilbertd85407412017-11-08 05:03:462889 // Can be null.
2890 scoped_refptr<VideoFrame> video_frame =
2891 compositor_->GetCurrentFrameOnAnyThread();
[email protected]dd061e12014-05-06 19:21:222892
Thomas Guilbertd85407412017-11-08 05:03:462893 // base::Unretained is safe here because |compositor_| is destroyed on
2894 // |vfc_task_runner_|. The destruction is queued from |this|' destructor,
2895 // which also runs on |main_task_runner_|, which makes it impossible for
2896 // UpdateCurrentFrameIfStale() to be queued after |compositor_|'s dtor.
CJ DiMeglio2302d202017-08-31 08:38:042897 vfc_task_runner_->PostTask(
Dale Curtisee9be30012018-09-21 22:21:512898 FROM_HERE,
2899 base::BindOnce(&VideoFrameCompositor::UpdateCurrentFrameIfStale,
2900 base::Unretained(compositor_.get())));
kainino36eeff82017-03-30 00:55:302901
[email protected]dd061e12014-05-06 19:21:222902 return video_frame;
2903}
2904
sandersd50a635e2016-04-04 22:50:092905void WebMediaPlayerImpl::UpdatePlayState() {
xhwang213e50c2016-10-10 23:56:312906 DCHECK(main_task_runner_->BelongsToCurrentThread());
hubbee2cc88c092017-07-14 23:10:412907 bool can_auto_suspend = !disable_pipeline_auto_suspend_;
2908 // For streaming videos, we only allow suspending at the very beginning of the
2909 // video, and only if we know the length of the video. (If we don't know
2910 // the length, it might be a dynamically generated video, and suspending
2911 // will not work at all.)
2912 if (IsStreaming()) {
2913 bool at_beginning =
2914 ready_state_ == WebMediaPlayer::kReadyStateHaveNothing ||
2915 CurrentTime() == 0.0;
2916 if (!at_beginning || GetPipelineMediaDuration() == kInfiniteDuration)
2917 can_auto_suspend = false;
2918 }
xhwang213e50c2016-10-10 23:56:312919
Antonio Gomes81b56552019-05-15 22:15:282920 bool is_suspended = pipeline_controller_->IsSuspended();
Sergey Volk8b09c2c52018-12-12 23:20:402921 bool is_backgrounded = IsBackgroundSuspendEnabled(this) && IsHidden();
sandersdaaff1a652016-11-17 01:47:252922 PlayState state = UpdatePlayState_ComputePlayState(
Thomas Guilbert7350fdad2019-01-29 23:09:242923 is_flinging_, can_auto_suspend, is_suspended, is_backgrounded);
sandersd35d2c3f2017-01-14 02:04:422924 SetDelegateState(state.delegate_state, state.is_idle);
sandersd50a635e2016-04-04 22:50:092925 SetMemoryReportingState(state.is_memory_reporting_enabled);
2926 SetSuspendState(state.is_suspended || pending_suspend_resume_cycle_);
[email protected]dc996312019-12-19 19:26:382927 if (power_status_helper_) {
2928 // Make sure that we're in something like steady-state before recording.
2929 power_status_helper_->SetIsPlaying(
2930 !paused_ && !seeking_ && !IsHidden() && !state.is_suspended &&
2931 ready_state_ == kReadyStateHaveEnoughData);
2932 }
[email protected]91379332020-01-26 03:58:202933 UpdateSmoothnessHelper();
sandersd50a635e2016-04-04 22:50:092934}
dalecurtis5bbc487e2016-02-27 04:15:052935
Becca Hughes7a85bf22019-07-24 16:16:582936void WebMediaPlayerImpl::UpdateMediaPositionState() {
2937 DCHECK(delegate_);
2938
2939 // When seeking the current time can go beyond the duration so we should
2940 // cap the current time at the duration.
2941 base::TimeDelta duration = GetPipelineMediaDuration();
2942 base::TimeDelta current_time = GetCurrentTimeInternal();
2943 if (current_time > duration)
2944 current_time = duration;
2945
Wojciech Dzierżanowski68f4a522020-04-27 09:48:122946 const double effective_playback_rate =
2947 paused_ || ready_state_ < kReadyStateHaveFutureData ? 0.0
2948 : playback_rate_;
2949
2950 media_session::MediaPosition new_position(effective_playback_rate, duration,
2951 current_time);
Becca Hughes7a85bf22019-07-24 16:16:582952
2953 if (media_position_state_ == new_position)
2954 return;
2955
2956 DVLOG(2) << __func__ << "(" << new_position.ToString() << ")";
2957 media_position_state_ = new_position;
2958 delegate_->DidPlayerMediaPositionStateChange(delegate_id_,
2959 media_position_state_);
2960}
2961
sandersd35d2c3f2017-01-14 02:04:422962void WebMediaPlayerImpl::SetDelegateState(DelegateState new_state,
2963 bool is_idle) {
tguilbert1bb1c782017-01-23 21:15:112964 DCHECK(delegate_);
Dale Curtis779ed842018-03-10 06:20:132965 DVLOG(2) << __func__ << "(" << static_cast<int>(new_state) << ", " << is_idle
2966 << ")";
dalecurtis5bbc487e2016-02-27 04:15:052967
sandersd35d2c3f2017-01-14 02:04:422968 // Prevent duplicate delegate calls.
2969 // TODO(sandersd): Move this deduplication into the delegate itself.
2970 // TODO(sandersd): WebContentsObserverSanityChecker does not allow sending the
2971 // 'playing' IPC more than once in a row, even if the metadata has changed.
2972 // Figure out whether it should.
Mounir Lamouri366dd8472018-06-19 17:20:042973 // Pretend that the media has no audio if it never played unmuted. This is to
2974 // avoid any action related to audible media such as taking audio focus or
2975 // showing a media notification. To preserve a consistent experience, it does
2976 // not apply if a media was audible so the system states do not flicker
2977 // depending on whether the user muted the player.
2978 bool has_audio = HasAudio() && !client_->WasAlwaysMuted();
sandersd35d2c3f2017-01-14 02:04:422979 if (delegate_state_ == new_state &&
2980 (delegate_state_ != DelegateState::PLAYING ||
2981 delegate_has_audio_ == has_audio)) {
2982 return;
mlamouri910111362016-11-04 11:28:242983 }
sandersd50a635e2016-04-04 22:50:092984 delegate_state_ = new_state;
sandersd35d2c3f2017-01-14 02:04:422985 delegate_has_audio_ = has_audio;
sandersd50a635e2016-04-04 22:50:092986
sandersd35d2c3f2017-01-14 02:04:422987 switch (new_state) {
sandersd50a635e2016-04-04 22:50:092988 case DelegateState::GONE:
2989 delegate_->PlayerGone(delegate_id_);
2990 break;
mlamouri910111362016-11-04 11:28:242991 case DelegateState::PLAYING: {
peconn257951522017-06-09 18:24:592992 if (HasVideo())
2993 delegate_->DidPlayerSizeChange(delegate_id_, NaturalSize());
zqzhang5d8eab72016-08-26 20:34:302994 delegate_->DidPlay(
Blink Reformat1c4d759e2017-04-09 16:34:542995 delegate_id_, HasVideo(), has_audio,
Dale Curtisca1b78f2019-01-15 03:11:262996 DurationToMediaContentType(GetPipelineMediaDuration()));
sandersd50a635e2016-04-04 22:50:092997 break;
mlamouri910111362016-11-04 11:28:242998 }
sandersd50a635e2016-04-04 22:50:092999 case DelegateState::PAUSED:
sandersd35d2c3f2017-01-14 02:04:423000 delegate_->DidPause(delegate_id_);
sandersd50a635e2016-04-04 22:50:093001 break;
dalecurtis0f0097a2015-12-01 17:40:473002 }
sandersd35d2c3f2017-01-14 02:04:423003
3004 delegate_->SetIdle(delegate_id_, is_idle);
dalecurtis0f0097a2015-12-01 17:40:473005}
3006
sandersd50a635e2016-04-04 22:50:093007void WebMediaPlayerImpl::SetMemoryReportingState(
3008 bool is_memory_reporting_enabled) {
3009 if (memory_usage_reporting_timer_.IsRunning() ==
3010 is_memory_reporting_enabled) {
hubbed5f36882016-01-15 22:40:373011 return;
sandersd50a635e2016-04-04 22:50:093012 }
sandersd1c0bba02016-03-04 23:14:083013
sandersd50a635e2016-04-04 22:50:093014 if (is_memory_reporting_enabled) {
3015 memory_usage_reporting_timer_.Start(FROM_HERE,
3016 base::TimeDelta::FromSeconds(2), this,
3017 &WebMediaPlayerImpl::ReportMemoryUsage);
3018 } else {
3019 memory_usage_reporting_timer_.Stop();
3020 ReportMemoryUsage();
3021 }
3022}
3023
3024void WebMediaPlayerImpl::SetSuspendState(bool is_suspended) {
xhwang213e50c2016-10-10 23:56:313025 DCHECK(main_task_runner_->BelongsToCurrentThread());
Dale Curtis779ed842018-03-10 06:20:133026 DVLOG(2) << __func__ << "(" << is_suspended << ")";
xhwang213e50c2016-10-10 23:56:313027
sandersd50a635e2016-04-04 22:50:093028 // Do not change the state after an error has occurred.
3029 // TODO(sandersd): Update PipelineController to remove the need for this.
3030 if (IsNetworkStateError(network_state_))
sandersd1c0bba02016-03-04 23:14:083031 return;
3032
jameswest451a5bb2017-01-27 03:59:393033 if (is_suspended) {
sandersd35d2c3f2017-01-14 02:04:423034 // If we were not resumed for long enough to satisfy the preroll attempt,
3035 // reset the clock.
3036 if (!preroll_attempt_pending_ && IsPrerollAttemptNeeded()) {
3037 preroll_attempt_pending_ = true;
3038 preroll_attempt_start_time_ = base::TimeTicks();
3039 }
Antonio Gomes81b56552019-05-15 22:15:283040 pipeline_controller_->Suspend();
sandersd50a635e2016-04-04 22:50:093041 } else {
sandersd35d2c3f2017-01-14 02:04:423042 // When resuming, start the preroll attempt clock.
3043 if (preroll_attempt_pending_) {
3044 preroll_attempt_pending_ = false;
3045 preroll_attempt_start_time_ = tick_clock_->NowTicks();
3046 }
Antonio Gomes81b56552019-05-15 22:15:283047 pipeline_controller_->Resume();
sandersd50a635e2016-04-04 22:50:093048 }
3049}
3050
3051WebMediaPlayerImpl::PlayState
Thomas Guilbert7350fdad2019-01-29 23:09:243052WebMediaPlayerImpl::UpdatePlayState_ComputePlayState(bool is_flinging,
xjz4e5d4bf32017-02-15 21:26:353053 bool can_auto_suspend,
dalecurtis8b8505e72016-06-10 21:59:173054 bool is_suspended,
sandersd50a635e2016-04-04 22:50:093055 bool is_backgrounded) {
3056 PlayState result;
3057
tguilbert1bb1c782017-01-23 21:15:113058 bool must_suspend = delegate_->IsFrameClosed();
Dale Curtis6438cf12018-03-29 02:34:013059 bool is_stale = delegate_->IsStale(delegate_id_);
3060
3061 if (stale_state_override_for_testing_.has_value() &&
3062 ready_state_ >= stale_state_override_for_testing_.value()) {
3063 is_stale = true;
3064 }
sandersd35d2c3f2017-01-14 02:04:423065
sandersd50a635e2016-04-04 22:50:093066 // This includes both data source (before pipeline startup) and pipeline
3067 // errors.
3068 bool has_error = IsNetworkStateError(network_state_);
3069
Dale Curtisc56158c2019-09-09 23:00:323070 // Note: Even though we get play/pause signals at kReadyStateHaveMetadata, we
3071 // must attempt to preroll until kReadyStateHaveFutureData so that the
3072 // canplaythrough event will be fired to the page (which may be waiting).
3073 bool have_future_data =
3074 highest_ready_state_ >= WebMediaPlayer::kReadyStateHaveFutureData;
sandersd50a635e2016-04-04 22:50:093075
avayvod65fad272017-02-24 01:00:483076 // Background suspend is only enabled for paused players.
3077 // In the case of players with audio the session should be kept.
3078 bool background_suspended =
Dale Curtisc56158c2019-09-09 23:00:323079 can_auto_suspend && is_backgrounded && paused_ && have_future_data;
sandersd50a635e2016-04-04 22:50:093080
Dale Curtisd71061f02019-05-21 21:33:543081 // Idle suspension is allowed prior to kReadyStateHaveMetadata since there
3082 // exist mechanisms to exit the idle state when the player is capable of
3083 // reaching the kReadyStateHaveMetadata state; see didLoadingProgress().
dalecurtiscc8baf72016-10-27 01:49:443084 //
sandersd50a635e2016-04-04 22:50:093085 // TODO(sandersd): Make the delegate suspend idle players immediately when
3086 // hidden.
Dale Curtis7c63f2e22018-09-19 21:06:273087 bool idle_suspended = can_auto_suspend && is_stale && paused_ && !seeking_ &&
3088 !overlay_enabled_ && !needs_first_frame_;
dalecurtise7120dc2016-09-03 02:54:353089
3090 // If we're already suspended, see if we can wait for user interaction. Prior
Dale Curtisd71061f02019-05-21 21:33:543091 // to kReadyStateHaveMetadata, we require |is_stale| to remain suspended.
3092 // |is_stale| will be cleared when we receive data which may take us to
3093 // kReadyStateHaveMetadata.
Dale Curtisc56158c2019-09-09 23:00:323094 bool can_stay_suspended = (is_stale || have_future_data) && is_suspended &&
Dale Curtis7c63f2e22018-09-19 21:06:273095 paused_ && !seeking_ && !needs_first_frame_;
sandersd50a635e2016-04-04 22:50:093096
3097 // Combined suspend state.
Thomas Guilbert7350fdad2019-01-29 23:09:243098 result.is_suspended = must_suspend || idle_suspended ||
avayvod65fad272017-02-24 01:00:483099 background_suspended || can_stay_suspended;
sandersd50a635e2016-04-04 22:50:093100
Thomas Guilbert7350fdad2019-01-29 23:09:243101 DVLOG(3) << __func__ << ": must_suspend=" << must_suspend
Dale Curtis779ed842018-03-10 06:20:133102 << ", idle_suspended=" << idle_suspended
3103 << ", background_suspended=" << background_suspended
3104 << ", can_stay_suspended=" << can_stay_suspended
Dale Curtisc56158c2019-09-09 23:00:323105 << ", is_stale=" << is_stale
3106 << ", have_future_data=" << have_future_data
Dale Curtis779ed842018-03-10 06:20:133107 << ", paused_=" << paused_ << ", seeking_=" << seeking_;
3108
sandersd50a635e2016-04-04 22:50:093109 // We do not treat |playback_rate_| == 0 as paused. For the media session,
3110 // being paused implies displaying a play button, which is incorrect in this
3111 // case. For memory usage reporting, we just use the same definition (but we
3112 // don't have to).
3113 //
3114 // Similarly, we don't consider |ended_| to be paused. Blink will immediately
3115 // call pause() or seek(), so |ended_| should not affect the computation.
3116 // Despite that, |ended_| does result in a separate paused state, to simplfy
3117 // the contract for SetDelegateState().
3118 //
avayvod65fad272017-02-24 01:00:483119 // |has_remote_controls| indicates if the player can be controlled outside the
3120 // page (e.g. via the notification controls or by audio focus events). Idle
sandersd50a635e2016-04-04 22:50:093121 // suspension does not destroy the media session, because we expect that the
avayvod5f34b642017-03-23 03:14:043122 // notification controls (and audio focus) remain. With some exceptions for
3123 // background videos, the player only needs to have audio to have controls
Dale Curtisd71061f02019-05-21 21:33:543124 // (requires |have_current_data|).
avayvod5f34b642017-03-23 03:14:043125 //
3126 // |alive| indicates if the player should be present (not |GONE|) to the
3127 // delegate, either paused or playing. The following must be true for the
3128 // player:
Dale Curtisd71061f02019-05-21 21:33:543129 // - |have_current_data|, since playback can't begin before that point, we
3130 // need to know whether we are paused to correctly configure the session,
3131 // and also because the tracks and duration are passed to DidPlay(),
Thomas Guilbert7350fdad2019-01-29 23:09:243132 // - |is_flinging| is false (RemotePlayback is not handled by the delegate)
avayvod5f34b642017-03-23 03:14:043133 // - |has_error| is false as player should have no errors,
3134 // - |background_suspended| is false, otherwise |has_remote_controls| must
3135 // be true.
sandersd50a635e2016-04-04 22:50:093136 //
avayvod65fad272017-02-24 01:00:483137 // TODO(sandersd): If Blink told us the paused state sooner, we could detect
3138 // if the remote controls are available sooner.
3139
3140 // Background videos with audio don't have remote controls if background
3141 // suspend is enabled and resuming background videos is not (original Android
3142 // behavior).
3143 bool backgrounded_video_has_no_remote_controls =
Sergey Volk8b09c2c52018-12-12 23:20:403144 IsBackgroundSuspendEnabled(this) && !IsResumeBackgroundVideosEnabled() &&
3145 is_backgrounded && HasVideo();
Dale Curtisd71061f02019-05-21 21:33:543146 bool have_current_data = highest_ready_state_ >= kReadyStateHaveCurrentData;
3147 bool can_play = !has_error && have_current_data;
avayvod5f34b642017-03-23 03:14:043148 bool has_remote_controls =
Blink Reformat1c4d759e2017-04-09 16:34:543149 HasAudio() && !backgrounded_video_has_no_remote_controls;
Thomas Guilbert7350fdad2019-01-29 23:09:243150 bool alive = can_play && !is_flinging && !must_suspend &&
avayvod5f34b642017-03-23 03:14:043151 (!background_suspended || has_remote_controls);
3152 if (!alive) {
Thomas Guilbert4c6feff2018-11-09 19:53:323153 // Do not mark players as idle when flinging.
sandersd50a635e2016-04-04 22:50:093154 result.delegate_state = DelegateState::GONE;
Thomas Guilbert4c6feff2018-11-09 19:53:323155 result.is_idle = delegate_->IsIdle(delegate_id_) && !is_flinging;
avayvod65fad272017-02-24 01:00:483156 } else if (paused_) {
sandersd35d2c3f2017-01-14 02:04:423157 // TODO(sandersd): Is it possible to have a suspended session, be ended,
3158 // and not be paused? If so we should be in a PLAYING state.
dalecurtise7120dc2016-09-03 02:54:353159 result.delegate_state =
sandersd35d2c3f2017-01-14 02:04:423160 ended_ ? DelegateState::GONE : DelegateState::PAUSED;
3161 result.is_idle = !seeking_;
sandersd50a635e2016-04-04 22:50:093162 } else {
3163 result.delegate_state = DelegateState::PLAYING;
sandersd35d2c3f2017-01-14 02:04:423164 result.is_idle = false;
sandersd50a635e2016-04-04 22:50:093165 }
3166
dalecurtis8b8505e72016-06-10 21:59:173167 // It's not critical if some cases where memory usage can change are missed,
sandersd50a635e2016-04-04 22:50:093168 // since media memory changes are usually gradual.
Thomas Guilbert7350fdad2019-01-29 23:09:243169 result.is_memory_reporting_enabled = !has_error && can_play && !is_flinging &&
3170 !result.is_suspended &&
3171 (!paused_ || seeking_);
sandersd50a635e2016-04-04 22:50:093172
3173 return result;
dalecurtis0f0097a2015-12-01 17:40:473174}
3175
Eugene Zemtsov77d56262020-03-06 05:52:033176void WebMediaPlayerImpl::SetDemuxer(std::unique_ptr<Demuxer> demuxer) {
3177 DCHECK(main_task_runner_->BelongsToCurrentThread());
3178 DCHECK(!demuxer_);
3179 DCHECK(!media_thread_mem_dumper_);
3180 DCHECK(demuxer);
3181
3182 demuxer_ = std::move(demuxer);
3183
3184 // base::Unretained() is safe here. |demuxer_| is destroyed on the main
3185 // thread, but before doing it ~WebMediaPlayerImpl() posts a media thread task
3186 // that deletes media_thread_mem_dumper_ and waits for it to finish.
3187 media_thread_mem_dumper_ = std::make_unique<MemoryDumpProviderProxy>(
3188 "WebMediaPlayer_MediaThread", media_task_runner_,
3189 base::BindRepeating(&WebMediaPlayerImpl::OnMediaThreadMemoryDump,
3190 media_log_->id(), base::Unretained(demuxer_.get())));
3191}
3192
dalecurtis83266c72015-10-29 18:43:203193void WebMediaPlayerImpl::ReportMemoryUsage() {
3194 DCHECK(main_task_runner_->BelongsToCurrentThread());
3195
wdzierzanowskifd4cd91c52015-12-02 23:50:203196 // About base::Unretained() usage below: We destroy |demuxer_| on the main
3197 // thread. Before that, however, ~WebMediaPlayerImpl() posts a task to the
3198 // media thread and waits for it to finish. Hence, the GetMemoryUsage() task
3199 // posted here must finish earlier.
Dale Curtis8a6281322017-08-31 00:35:533200 //
3201 // The exception to the above is when OnError() has been called. If we're in
3202 // the error state we've already shut down the pipeline and can't rely on it
3203 // to cycle the media thread before we destroy |demuxer_|. In this case skip
3204 // collection of the demuxer memory stats.
3205 if (demuxer_ && !IsNetworkStateError(network_state_)) {
wdzierzanowskifd4cd91c52015-12-02 23:50:203206 base::PostTaskAndReplyWithResult(
3207 media_task_runner_.get(), FROM_HERE,
Jan Wilken Dörrie2e1d2d9a2020-01-24 17:14:183208 base::BindOnce(&Demuxer::GetMemoryUsage,
3209 base::Unretained(demuxer_.get())),
3210 base::BindOnce(&WebMediaPlayerImpl::FinishMemoryUsageReport,
3211 weak_this_));
wdzierzanowskifd4cd91c52015-12-02 23:50:203212 } else {
3213 FinishMemoryUsageReport(0);
3214 }
3215}
3216
3217void WebMediaPlayerImpl::FinishMemoryUsageReport(int64_t demuxer_memory_usage) {
3218 DCHECK(main_task_runner_->BelongsToCurrentThread());
3219
avayvodc4bfb0e62017-01-13 01:07:013220 const PipelineStatistics stats = GetPipelineStatistics();
servolk639473e492016-12-15 04:14:203221 const int64_t data_source_memory_usage =
3222 data_source_ ? data_source_->GetMemoryUsage() : 0;
dalecurtisecc76612017-04-19 00:31:203223
Dale Curtisc2c5dcb12018-04-16 23:21:293224 // If we have video and no video memory usage and we've rendered the first
3225 // frame, assume the VideoFrameCompositor is holding onto the last frame after
3226 // we've suspended the pipeline; which thus reports zero memory usage from the
3227 // video renderer.
dalecurtisecc76612017-04-19 00:31:203228 //
3229 // Technically this should use the coded size, but that requires us to hop to
3230 // the compositor to get and byte-perfect accuracy isn't important here.
3231 const int64_t video_memory_usage =
3232 stats.video_memory_usage +
Dale Curtisc2c5dcb12018-04-16 23:21:293233 ((pipeline_metadata_.has_video && !stats.video_memory_usage &&
3234 has_first_frame_)
Miguel Casas9e7766022018-01-08 16:13:133235 ? VideoFrame::AllocationSize(PIXEL_FORMAT_I420,
dalecurtisecc76612017-04-19 00:31:203236 pipeline_metadata_.natural_size)
3237 : 0);
3238
dalecurtis83266c72015-10-29 18:43:203239 const int64_t current_memory_usage =
dalecurtisecc76612017-04-19 00:31:203240 stats.audio_memory_usage + video_memory_usage + data_source_memory_usage +
3241 demuxer_memory_usage;
dalecurtis83266c72015-10-29 18:43:203242
Xiaohan Wang8859b07e2020-04-29 17:59:053243 DVLOG(3) << "Memory Usage -- Total: " << current_memory_usage
dalecurtisecc76612017-04-19 00:31:203244 << " Audio: " << stats.audio_memory_usage
3245 << ", Video: " << video_memory_usage
servolk639473e492016-12-15 04:14:203246 << ", DataSource: " << data_source_memory_usage
wdzierzanowskifd4cd91c52015-12-02 23:50:203247 << ", Demuxer: " << demuxer_memory_usage;
dalecurtis83266c72015-10-29 18:43:203248
3249 const int64_t delta = current_memory_usage - last_reported_memory_usage_;
3250 last_reported_memory_usage_ = current_memory_usage;
3251 adjust_allocated_memory_cb_.Run(delta);
dalecurtis83266c72015-10-29 18:43:203252}
3253
Eugene Zemtsov77d56262020-03-06 05:52:033254void WebMediaPlayerImpl::OnMainThreadMemoryDump(
3255 int32_t id,
Eugene Zemtsovc4c6db262020-03-20 22:19:413256 const base::trace_event::MemoryDumpArgs& args,
Eugene Zemtsov77d56262020-03-06 05:52:033257 base::trace_event::ProcessMemoryDump* pmd) {
3258 const PipelineStatistics stats = GetPipelineStatistics();
Eugene Zemtsovfc2b67a2020-04-01 02:58:173259 auto player_node_name =
3260 base::StringPrintf("media/webmediaplayer/player_0x%x", id);
3261 auto* player_node = pmd->CreateAllocatorDump(player_node_name);
3262 player_node->AddScalar(
3263 base::trace_event::MemoryAllocatorDump::kNameObjectCount,
3264 base::trace_event::MemoryAllocatorDump::kUnitsObjects, 1);
Eugene Zemtsov77d56262020-03-06 05:52:033265
Eugene Zemtsovc4c6db262020-03-20 22:19:413266 if (args.level_of_detail !=
3267 base::trace_event::MemoryDumpLevelOfDetail::BACKGROUND) {
3268 bool suspended = pipeline_controller_->IsPipelineSuspended();
Eugene Zemtsovc4c6db262020-03-20 22:19:413269 auto player_state =
3270 base::StringPrintf("Paused: %d Ended: %d ReadyState: %d Suspended: %d",
3271 paused_, ended_, GetReadyState(), suspended);
Eugene Zemtsovfc2b67a2020-04-01 02:58:173272 player_node->AddString("player_state", "", player_state);
Eugene Zemtsovc4c6db262020-03-20 22:19:413273 }
Eugene Zemtsov77d56262020-03-06 05:52:033274
3275 CreateAllocation(pmd, id, "audio", stats.audio_memory_usage);
3276 CreateAllocation(pmd, id, "video", stats.video_memory_usage);
3277
3278 if (data_source_)
3279 CreateAllocation(pmd, id, "data_source", data_source_->GetMemoryUsage());
3280}
3281
3282// static
3283void WebMediaPlayerImpl::OnMediaThreadMemoryDump(
3284 int32_t id,
3285 Demuxer* demuxer,
Eugene Zemtsovc4c6db262020-03-20 22:19:413286 const base::trace_event::MemoryDumpArgs& args,
Eugene Zemtsov77d56262020-03-06 05:52:033287 base::trace_event::ProcessMemoryDump* pmd) {
3288 if (!demuxer)
3289 return;
3290
3291 CreateAllocation(pmd, id, "demuxer", demuxer->GetMemoryUsage());
3292}
3293
dalecurtis8b8505e72016-06-10 21:59:173294void WebMediaPlayerImpl::ScheduleIdlePauseTimer() {
avayvod65fad272017-02-24 01:00:483295 // Only schedule the pause timer if we're not paused or paused but going to
avayvod52efd282017-03-07 21:13:043296 // resume when foregrounded, and are suspended and have audio.
3297 if ((paused_ && !paused_when_hidden_) ||
Antonio Gomes81b56552019-05-15 22:15:283298 !pipeline_controller_->IsSuspended() || !HasAudio()) {
dalecurtis8b8505e72016-06-10 21:59:173299 return;
avayvod52efd282017-03-07 21:13:043300 }
dalecurtis8b8505e72016-06-10 21:59:173301
3302#if defined(OS_ANDROID)
Thomas Guilbert7350fdad2019-01-29 23:09:243303 // Don't pause videos casted as part of RemotePlayback.
3304 if (is_flinging_)
dalecurtis8b8505e72016-06-10 21:59:173305 return;
3306#endif
3307
3308 // Idle timeout chosen arbitrarily.
3309 background_pause_timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(5),
3310 this, &WebMediaPlayerImpl::OnPause);
3311}
3312
dalecurtis04bdb582016-08-17 22:15:233313void WebMediaPlayerImpl::CreateWatchTimeReporter() {
wdzierzanowskia78fa9b2017-06-13 18:12:103314 if (!HasVideo() && !HasAudio())
3315 return;
3316
Dan Sanders7ef5d0f2019-05-03 18:30:113317 // MediaPlayerRenderer does not know about tracks until playback starts.
3318 // Assume audio-only unless the natural size has been detected.
3319 bool has_video = pipeline_metadata_.has_video;
3320 if (using_media_player_renderer_) {
3321 has_video = !pipeline_metadata_.natural_size.IsEmpty();
3322 }
3323
dalecurtis04bdb582016-08-17 22:15:233324 // Create the watch time reporter and synchronize its initial state.
Jose Lopes9023b6d2020-02-19 20:42:373325 watch_time_reporter_ = std::make_unique<WatchTimeReporter>(
Dan Sanders7ef5d0f2019-05-03 18:30:113326 mojom::PlaybackProperties::New(
3327 pipeline_metadata_.has_audio, has_video, false, false,
3328 !!chunk_demuxer_, is_encrypted_, embedded_media_experience_enabled_),
Dale Curtis96d6e9382018-07-18 18:01:073329 pipeline_metadata_.natural_size,
Dale Curtis051fdf62017-08-05 00:21:133330 base::BindRepeating(&WebMediaPlayerImpl::GetCurrentTimeInternal,
3331 base::Unretained(this)),
Dale Curtis0f8d7b32019-10-24 22:10:283332 base::BindRepeating(&WebMediaPlayerImpl::GetPipelineStatistics,
3333 base::Unretained(this)),
Hajime Hoshi8bb37dc2017-12-19 09:35:103334 media_metrics_provider_.get(),
Jose Lopes9023b6d2020-02-19 20:42:373335 frame_->GetTaskRunner(blink::TaskType::kInternalMedia));
dalecurtis04bdb582016-08-17 22:15:233336 watch_time_reporter_->OnVolumeChange(volume_);
Dale Curtisaebaeea2018-07-19 23:42:113337 watch_time_reporter_->OnDurationChanged(GetPipelineMediaDuration());
Mounir Lamourif9af74e72017-06-19 19:31:453338
tguilbert1bb1c782017-01-23 21:15:113339 if (delegate_->IsFrameHidden())
dalecurtis04bdb582016-08-17 22:15:233340 watch_time_reporter_->OnHidden();
3341 else
3342 watch_time_reporter_->OnShown();
Mounir Lamourif9af74e72017-06-19 19:31:453343
Mounir Lamouri41a79c62017-06-06 12:53:163344 if (client_->HasNativeControls())
3345 watch_time_reporter_->OnNativeControlsEnabled();
3346 else
3347 watch_time_reporter_->OnNativeControlsDisabled();
Mounir Lamourif9af74e72017-06-19 19:31:453348
3349 switch (client_->DisplayType()) {
3350 case WebMediaPlayer::DisplayType::kInline:
3351 watch_time_reporter_->OnDisplayTypeInline();
3352 break;
3353 case WebMediaPlayer::DisplayType::kFullscreen:
3354 watch_time_reporter_->OnDisplayTypeFullscreen();
3355 break;
3356 case WebMediaPlayer::DisplayType::kPictureInPicture:
3357 watch_time_reporter_->OnDisplayTypePictureInPicture();
3358 break;
3359 }
Dale Curtis96d6e9382018-07-18 18:01:073360
3361 UpdateSecondaryProperties();
Dale Curtis7fd27c4b2018-07-30 22:14:213362
3363 // If the WatchTimeReporter was recreated in the middle of playback, we want
3364 // to resume playback here too since we won't get another play() call. When
3365 // seeking, the seek completion will restart it if necessary.
3366 if (!paused_ && !seeking_)
3367 watch_time_reporter_->OnPlaying();
Dale Curtis96d6e9382018-07-18 18:01:073368}
3369
3370void WebMediaPlayerImpl::UpdateSecondaryProperties() {
3371 watch_time_reporter_->UpdateSecondaryProperties(
3372 mojom::SecondaryPlaybackProperties::New(
3373 pipeline_metadata_.audio_decoder_config.codec(),
Dale Curtis7140b502019-10-23 20:34:423374 pipeline_metadata_.video_decoder_config.codec(),
Dale Curtisf8afcef32020-01-18 06:23:263375 pipeline_metadata_.audio_decoder_config.profile(),
Dale Curtis7140b502019-10-23 20:34:423376 pipeline_metadata_.video_decoder_config.profile(),
3377 audio_decoder_name_, video_decoder_name_,
Yuchen Liub33bfc12019-11-08 20:16:123378 pipeline_metadata_.audio_decoder_config.encryption_scheme(),
3379 pipeline_metadata_.video_decoder_config.encryption_scheme(),
John Rummelld30555352018-09-21 20:47:253380 pipeline_metadata_.natural_size));
dalecurtis04bdb582016-08-17 22:15:233381}
3382
avayvod39c102402016-11-23 21:43:133383bool WebMediaPlayerImpl::IsHidden() const {
3384 DCHECK(main_task_runner_->BelongsToCurrentThread());
3385
tguilbert1bb1c782017-01-23 21:15:113386 return delegate_->IsFrameHidden() && !delegate_->IsFrameClosed();
avayvod39c102402016-11-23 21:43:133387}
3388
avayvod102cdb62017-01-07 03:11:093389bool WebMediaPlayerImpl::IsStreaming() const {
3390 return data_source_ && data_source_->IsStreaming();
3391}
3392
liberato2fd111be2017-01-04 00:25:063393bool WebMediaPlayerImpl::DoesOverlaySupportMetadata() const {
Ted Meyer4a427632019-05-01 19:05:273394 return pipeline_metadata_.video_decoder_config.video_transformation() ==
3395 kNoTransformation;
liberato2fd111be2017-01-04 00:25:063396}
3397
Anton Vayvod09fa66e2017-07-20 23:02:123398void WebMediaPlayerImpl::UpdateRemotePlaybackCompatibility(bool is_compatible) {
3399 DCHECK(main_task_runner_->BelongsToCurrentThread());
3400
3401 client_->RemotePlaybackCompatibilityChanged(loaded_url_, is_compatible);
3402}
3403
Dale Curtis6438cf12018-03-29 02:34:013404void WebMediaPlayerImpl::ForceStaleStateForTesting(ReadyState target_state) {
3405 stale_state_override_for_testing_.emplace(target_state);
Dale Curtis99a9b482018-02-01 02:23:283406 UpdatePlayState();
3407}
3408
3409bool WebMediaPlayerImpl::IsSuspendedForTesting() {
3410 // This intentionally uses IsPipelineSuspended since we need to know when the
3411 // pipeline has reached the suspended state, not when it's in suspending.
Antonio Gomes81b56552019-05-15 22:15:283412 return pipeline_controller_->IsPipelineSuspended();
Dale Curtis99a9b482018-02-01 02:23:283413}
3414
Dale Curtis7c63f2e22018-09-19 21:06:273415bool WebMediaPlayerImpl::DidLazyLoad() const {
3416 return did_lazy_load_;
3417}
3418
3419void WebMediaPlayerImpl::OnBecameVisible() {
Dale Curtis04769ca2019-05-25 00:38:103420 have_enough_after_lazy_load_cb_.Cancel();
Dale Curtis7c63f2e22018-09-19 21:06:273421 needs_first_frame_ = !has_first_frame_;
3422 UpdatePlayState();
3423}
3424
Miguel Casasfb63a5792018-12-04 23:50:413425bool WebMediaPlayerImpl::IsOpaque() const {
3426 return opaque_;
3427}
3428
Mounir Lamouri99ba5a62019-02-12 01:27:473429int WebMediaPlayerImpl::GetDelegateId() {
3430 return delegate_id_;
3431}
3432
3433base::Optional<viz::SurfaceId> WebMediaPlayerImpl::GetSurfaceId() {
3434 if (!surface_layer_for_video_enabled_)
3435 return base::nullopt;
3436 return bridge_->GetSurfaceId();
3437}
3438
Thomas Guilbert83fdc9b82020-04-11 01:21:543439void WebMediaPlayerImpl::RequestVideoFrameCallback() {
Thomas Guilberte95597002020-02-06 01:08:153440 compositor_->SetOnFramePresentedCallback(BindToCurrentLoop(base::BindOnce(
3441 &WebMediaPlayerImpl::OnNewFramePresentedCallback, weak_this_)));
Thomas Guilberte90fe312019-11-07 22:27:563442}
3443
Thomas Guilberte4669d42020-02-21 02:40:203444void WebMediaPlayerImpl::OnNewFramePresentedCallback() {
Thomas Guilbert83fdc9b82020-04-11 01:21:543445 client_->OnRequestVideoFrameCallback();
Thomas Guilberte4669d42020-02-21 02:40:203446}
3447
3448std::unique_ptr<blink::WebMediaPlayer::VideoFramePresentationMetadata>
3449WebMediaPlayerImpl::GetVideoFramePresentationMetadata() {
3450 return compositor_->GetLastPresentedFrameMetadata();
Thomas Guilberte90fe312019-11-07 22:27:563451}
3452
Antonio Gomes142f32a2019-05-15 23:32:563453base::WeakPtr<blink::WebMediaPlayer> WebMediaPlayerImpl::AsWeakPtr() {
3454 return weak_this_;
3455}
3456
Yuchen Liue7813972019-04-12 22:34:243457bool WebMediaPlayerImpl::ShouldPausePlaybackWhenHidden() const {
3458 // Audio only stream is allowed to play when in background.
3459 // TODO: We should check IsBackgroundOptimizationCandidate here. But we need
3460 // to move the logic of checking video frames out of that function.
3461 if (!HasVideo())
3462 return false;
3463
Junbo Kefba620b2019-01-16 02:54:363464 if (!is_background_video_playback_enabled_)
3465 return true;
3466
avayvod65fad272017-02-24 01:00:483467 // If suspending background video, pause any video that's not remoted or
3468 // not unlocked to play in the background.
Sergey Volk8b09c2c52018-12-12 23:20:403469 if (IsBackgroundSuspendEnabled(this)) {
avayvod65fad272017-02-24 01:00:483470#if defined(OS_ANDROID)
Thomas Guilbert7350fdad2019-01-29 23:09:243471 if (is_flinging_)
avayvod65fad272017-02-24 01:00:483472 return false;
avayvodcc273dd2017-01-19 19:35:123473#endif
avayvodeb9098d2017-01-07 00:33:033474
Blink Reformat1c4d759e2017-04-09 16:34:543475 return !HasAudio() || (IsResumeBackgroundVideosEnabled() &&
3476 video_locked_when_paused_when_hidden_);
avayvod65fad272017-02-24 01:00:483477 }
3478
3479 // Otherwise only pause if the optimization is on and it's a video-only
3480 // optimization candidate.
avayvod01201332017-04-14 00:27:153481 return IsBackgroundVideoPauseOptimizationEnabled() && !HasAudio() &&
Thomas Guilbert29ae1a902018-10-20 01:53:383482 IsBackgroundOptimizationCandidate() && !is_flinging_;
avayvodeb9098d2017-01-07 00:33:033483}
3484
avayvod2135a642017-01-13 00:17:143485bool WebMediaPlayerImpl::ShouldDisableVideoWhenHidden() const {
Ted Meyera918e592018-09-08 00:16:203486 // This optimization is behind the flag on all platforms, only for non-mse
3487 // video. MSE video track switching on hide has gone through a field test.
3488 // TODO(tmathmeyer): Passing load_type_ won't be needed after src= field
3489 // testing is finished. see: http://crbug.com/709302
Ted Meyer0e105992019-05-04 01:47:213490 if (!is_background_video_track_optimization_supported_)
avayvodc4bfb0e62017-01-13 01:07:013491 return false;
avayvodc4bfb0e62017-01-13 01:07:013492
avayvodcc273dd2017-01-19 19:35:123493 // Disable video track only for players with audio that match the criteria for
3494 // being optimized.
Blink Reformat1c4d759e2017-04-09 16:34:543495 return HasAudio() && IsBackgroundOptimizationCandidate();
avayvodcc273dd2017-01-19 19:35:123496}
3497
3498bool WebMediaPlayerImpl::IsBackgroundOptimizationCandidate() const {
3499 DCHECK(main_task_runner_->BelongsToCurrentThread());
3500
François Beaufort664c3ca72018-04-13 07:24:513501 // Don't optimize Picture-in-Picture players.
Mounir Lamouri0484f40a2018-07-25 03:03:263502 if (IsInPictureInPicture())
François Beaufort664c3ca72018-04-13 07:24:513503 return false;
3504
Thomas Guilbert7350fdad2019-01-29 23:09:243505#if defined(OS_ANDROID)
3506 // Don't optimize videos casted as part of RemotePlayback.
3507 if (is_flinging_)
avayvodcc273dd2017-01-19 19:35:123508 return false;
Thomas Guilbert7350fdad2019-01-29 23:09:243509#endif
avayvodcc273dd2017-01-19 19:35:123510
3511 // Don't optimize audio-only or streaming players.
Blink Reformat1c4d759e2017-04-09 16:34:543512 if (!HasVideo() || IsStreaming())
avayvodcc273dd2017-01-19 19:35:123513 return false;
3514
Dale Curtis3f4935b2017-09-09 00:11:593515 // Video-only players are always optimized (paused).
3516 // Don't check the keyframe distance and duration.
3517 if (!HasAudio() && HasVideo())
3518 return true;
3519
avayvodcc273dd2017-01-19 19:35:123520 // Videos shorter than the maximum allowed keyframe distance can be optimized.
3521 base::TimeDelta duration = GetPipelineMediaDuration();
Ted Meyera918e592018-09-08 00:16:203522
Dale Curtis456808a2018-10-23 17:50:213523 constexpr base::TimeDelta kMaxKeyframeDistanceToDisableBackgroundVideo =
3524 base::TimeDelta::FromMilliseconds(
3525 kMaxKeyframeDistanceToDisableBackgroundVideoMs);
3526 if (duration < kMaxKeyframeDistanceToDisableBackgroundVideo)
avayvodcc273dd2017-01-19 19:35:123527 return true;
3528
3529 // Otherwise, only optimize videos with shorter average keyframe distance.
avayvodc4bfb0e62017-01-13 01:07:013530 PipelineStatistics stats = GetPipelineStatistics();
Dale Curtis456808a2018-10-23 17:50:213531 return stats.video_keyframe_distance_average <
3532 kMaxKeyframeDistanceToDisableBackgroundVideo;
avayvod2135a642017-01-13 00:17:143533}
3534
avayvod56e1f3942017-01-21 02:06:313535void WebMediaPlayerImpl::UpdateBackgroundVideoOptimizationState() {
Takumi Fujimotof2319684e2019-12-03 18:51:513536 if (IsHidden()) {
Yuchen Liue7813972019-04-12 22:34:243537 if (ShouldPausePlaybackWhenHidden()) {
avayvod56e1f3942017-01-21 02:06:313538 PauseVideoIfNeeded();
Dale Curtisa75a7892017-08-09 20:21:513539 } else if (update_background_status_cb_.IsCancelled()) {
3540 // Only trigger updates when we don't have one already scheduled.
3541 update_background_status_cb_.Reset(
3542 base::Bind(&WebMediaPlayerImpl::DisableVideoTrackIfNeeded,
3543 base::Unretained(this)));
3544
3545 // Defer disable track until we're sure the clip will be backgrounded for
3546 // some time. Resuming may take half a second, so frequent tab switches
3547 // will yield a poor user experience otherwise. http://crbug.com/709302
3548 // may also cause AV sync issues if disable/enable happens too fast.
3549 main_task_runner_->PostDelayedTask(
3550 FROM_HERE, update_background_status_cb_.callback(),
3551 base::TimeDelta::FromSeconds(10));
3552 }
avayvod56e1f3942017-01-21 02:06:313553 } else {
Dale Curtisa75a7892017-08-09 20:21:513554 update_background_status_cb_.Cancel();
avayvod56e1f3942017-01-21 02:06:313555 EnableVideoTrackIfNeeded();
3556 }
3557}
3558
3559void WebMediaPlayerImpl::PauseVideoIfNeeded() {
3560 DCHECK(IsHidden());
3561
3562 // Don't pause video while the pipeline is stopped, resuming or seeking.
3563 // Also if the video is paused already.
Antonio Gomes81b56552019-05-15 22:15:283564 if (!pipeline_controller_->IsPipelineRunning() || is_pipeline_resuming_ ||
tguilbert350936ff2017-02-24 05:39:273565 seeking_ || paused_)
avayvod56e1f3942017-01-21 02:06:313566 return;
3567
3568 // OnPause() will set |paused_when_hidden_| to false and call
3569 // UpdatePlayState(), so set the flag to true after and then return.
3570 OnPause();
3571 paused_when_hidden_ = true;
3572}
3573
avayvod2135a642017-01-13 00:17:143574void WebMediaPlayerImpl::EnableVideoTrackIfNeeded() {
avayvod56e1f3942017-01-21 02:06:313575 // Don't change video track while the pipeline is stopped, resuming or
3576 // seeking.
Antonio Gomes81b56552019-05-15 22:15:283577 if (!pipeline_controller_->IsPipelineRunning() || is_pipeline_resuming_ ||
tguilbert350936ff2017-02-24 05:39:273578 seeking_)
avayvod2135a642017-01-13 00:17:143579 return;
3580
3581 if (video_track_disabled_) {
3582 video_track_disabled_ = false;
Blink Reformat1c4d759e2017-04-09 16:34:543583 if (client_->HasSelectedVideoTrack()) {
3584 WebMediaPlayer::TrackId trackId = client_->GetSelectedVideoTrackId();
3585 SelectedVideoTrackChanged(&trackId);
avayvod2135a642017-01-13 00:17:143586 }
3587 }
3588}
3589
3590void WebMediaPlayerImpl::DisableVideoTrackIfNeeded() {
3591 DCHECK(IsHidden());
3592
3593 // Don't change video track while the pipeline is resuming or seeking.
3594 if (is_pipeline_resuming_ || seeking_)
3595 return;
3596
3597 if (!video_track_disabled_ && ShouldDisableVideoWhenHidden()) {
3598 video_track_disabled_ = true;
Blink Reformat1c4d759e2017-04-09 16:34:543599 SelectedVideoTrackChanged(nullptr);
avayvod2135a642017-01-13 00:17:143600 }
3601}
3602
avayvodc4bfb0e62017-01-13 01:07:013603void WebMediaPlayerImpl::SetPipelineStatisticsForTest(
3604 const PipelineStatistics& stats) {
3605 pipeline_statistics_for_test_ = base::make_optional(stats);
3606}
3607
3608PipelineStatistics WebMediaPlayerImpl::GetPipelineStatistics() const {
3609 DCHECK(main_task_runner_->BelongsToCurrentThread());
3610
tguilbert350936ff2017-02-24 05:39:273611 return pipeline_statistics_for_test_.value_or(
Antonio Gomes81b56552019-05-15 22:15:283612 pipeline_controller_->GetStatistics());
avayvodc4bfb0e62017-01-13 01:07:013613}
3614
avayvodcc273dd2017-01-19 19:35:123615void WebMediaPlayerImpl::SetPipelineMediaDurationForTest(
3616 base::TimeDelta duration) {
3617 pipeline_media_duration_for_test_ = base::make_optional(duration);
3618}
3619
3620base::TimeDelta WebMediaPlayerImpl::GetPipelineMediaDuration() const {
3621 DCHECK(main_task_runner_->BelongsToCurrentThread());
3622
3623 return pipeline_media_duration_for_test_.value_or(
Antonio Gomes81b56552019-05-15 22:15:283624 pipeline_controller_->GetMediaDuration());
avayvodcc273dd2017-01-19 19:35:123625}
3626
Xiangjun Zhangba8724f482017-08-03 06:43:253627void WebMediaPlayerImpl::SwitchToRemoteRenderer(
3628 const std::string& remote_device_friendly_name) {
xjz4e5d4bf32017-02-15 21:26:353629 DCHECK(main_task_runner_->BelongsToCurrentThread());
Chris Cunningham89b4b762019-03-27 17:13:333630
3631 DCHECK(!is_remote_rendering_);
3632 is_remote_rendering_ = true;
3633
Thomas Guilbertb341bae02018-05-09 00:02:133634 DCHECK(!disable_pipeline_auto_suspend_);
Xiangjun Zhangba8724f482017-08-03 06:43:253635 disable_pipeline_auto_suspend_ = true;
Chris Cunninghamd9df58e2017-08-29 00:04:233636
3637 // Capabilities reporting should only be performed for local playbacks.
3638 video_decode_stats_reporter_.reset();
3639
Xiangjun Zhangba8724f482017-08-03 06:43:253640 // Requests to restart media pipeline. A remote renderer will be created via
3641 // the |renderer_factory_selector_|.
xjz4e5d4bf32017-02-15 21:26:353642 ScheduleRestart();
xjzdf9b67e2017-04-13 23:28:253643 if (client_) {
Xiangjun Zhangba8724f482017-08-03 06:43:253644 client_->MediaRemotingStarted(
3645 WebString::FromUTF8(remote_device_friendly_name));
xjzdf9b67e2017-04-13 23:28:253646 }
xjz4e5d4bf32017-02-15 21:26:353647}
3648
Xiangjun Zhang5e20cba42018-01-10 19:54:563649void WebMediaPlayerImpl::SwitchToLocalRenderer(
3650 MediaObserverClient::ReasonToSwitchToLocal reason) {
Xiangjun Zhangba8724f482017-08-03 06:43:253651 DCHECK(main_task_runner_->BelongsToCurrentThread());
Chris Cunningham89b4b762019-03-27 17:13:333652 if (!is_remote_rendering_)
Xiangjun Zhang12f55272018-07-30 23:19:373653 return; // Is currently with local renderer.
Chris Cunningham89b4b762019-03-27 17:13:333654 is_remote_rendering_ = false;
3655
3656 DCHECK(disable_pipeline_auto_suspend_);
Xiangjun Zhangba8724f482017-08-03 06:43:253657 disable_pipeline_auto_suspend_ = false;
Chris Cunninghamd9df58e2017-08-29 00:04:233658
3659 // Capabilities reporting may resume now that playback is local.
3660 CreateVideoDecodeStatsReporter();
3661
Xiangjun Zhangba8724f482017-08-03 06:43:253662 // Requests to restart media pipeline. A local renderer will be created via
3663 // the |renderer_factory_selector_|.
3664 ScheduleRestart();
3665 if (client_)
Xiangjun Zhang5e20cba42018-01-10 19:54:563666 client_->MediaRemotingStopped(GetSwitchToLocalMessage(reason));
Xiangjun Zhangba8724f482017-08-03 06:43:253667}
3668
dalecurtis4f6d14d2017-02-22 17:42:223669void WebMediaPlayerImpl::RecordUnderflowDuration(base::TimeDelta duration) {
3670 DCHECK(data_source_ || chunk_demuxer_);
xhwang68b3fab82017-05-17 21:31:463671
dalecurtis4f6d14d2017-02-22 17:42:223672 if (data_source_)
Jennifer Apacible82e25c92017-08-07 18:15:273673 UMA_HISTOGRAM_TIMES("Media.UnderflowDuration2.SRC", duration);
dalecurtis4f6d14d2017-02-22 17:42:223674 else
Jennifer Apacible82e25c92017-08-07 18:15:273675 UMA_HISTOGRAM_TIMES("Media.UnderflowDuration2.MSE", duration);
xhwang68b3fab82017-05-17 21:31:463676
3677 if (is_encrypted_)
Jennifer Apacible82e25c92017-08-07 18:15:273678 UMA_HISTOGRAM_TIMES("Media.UnderflowDuration2.EME", duration);
dalecurtis4f6d14d2017-02-22 17:42:223679}
3680
xhwang60802652017-04-19 07:29:583681#define UMA_HISTOGRAM_VIDEO_HEIGHT(name, sample) \
3682 UMA_HISTOGRAM_CUSTOM_COUNTS(name, sample, 100, 10000, 50)
3683
3684void WebMediaPlayerImpl::RecordVideoNaturalSize(const gfx::Size& natural_size) {
3685 // Always report video natural size to MediaLog.
Ted Meyer0134aed2020-01-23 23:56:403686 media_log_->AddEvent<MediaLogEvent::kVideoSizeChanged>(natural_size);
Ted Meyer7f5b4e22019-11-21 03:21:193687 media_log_->SetProperty<MediaLogProperty::kResolution>(natural_size);
xhwang60802652017-04-19 07:29:583688
3689 if (initial_video_height_recorded_)
3690 return;
3691
3692 initial_video_height_recorded_ = true;
3693
3694 int height = natural_size.height();
3695
3696 if (load_type_ == kLoadTypeURL)
3697 UMA_HISTOGRAM_VIDEO_HEIGHT("Media.VideoHeight.Initial.SRC", height);
3698 else if (load_type_ == kLoadTypeMediaSource)
3699 UMA_HISTOGRAM_VIDEO_HEIGHT("Media.VideoHeight.Initial.MSE", height);
3700
3701 if (is_encrypted_)
3702 UMA_HISTOGRAM_VIDEO_HEIGHT("Media.VideoHeight.Initial.EME", height);
3703
3704 UMA_HISTOGRAM_VIDEO_HEIGHT("Media.VideoHeight.Initial.All", height);
Sergey Ulanovb8656772020-04-21 22:56:143705
3706 if (playback_events_recorder_)
3707 playback_events_recorder_->OnNaturalSizeChanged(natural_size);
xhwang60802652017-04-19 07:29:583708}
3709
3710#undef UMA_HISTOGRAM_VIDEO_HEIGHT
3711
Greg Thompsonaa48ce8d2018-04-03 06:11:433712void WebMediaPlayerImpl::SetTickClockForTest(
3713 const base::TickClock* tick_clock) {
tzik2c963b872017-12-07 06:57:243714 tick_clock_ = tick_clock;
Antonio Gomes81b56552019-05-15 22:15:283715 buffered_data_source_host_->SetTickClockForTest(tick_clock);
hubbeb2d3efd2017-05-05 23:26:383716}
3717
Dale Curtis3899090ea2018-01-12 00:10:353718void WebMediaPlayerImpl::OnFirstFrame(base::TimeTicks frame_time) {
3719 DCHECK(!load_start_time_.is_null());
Dale Curtisff576552018-03-30 02:32:443720 DCHECK(!skip_metrics_due_to_startup_suspend_);
Dale Curtisc2c5dcb12018-04-16 23:21:293721 has_first_frame_ = true;
Dale Curtis7c63f2e22018-09-19 21:06:273722 needs_first_frame_ = false;
Dale Curtis3899090ea2018-01-12 00:10:353723 const base::TimeDelta elapsed = frame_time - load_start_time_;
3724 media_metrics_provider_->SetTimeToFirstFrame(elapsed);
3725 RecordTimingUMA("Media.TimeToFirstFrame", elapsed);
Dale Curtiscdfc6f22019-06-26 22:05:233726
3727 // Needed to signal HTMLVideoElement that it should remove the poster image.
Dale Curtis66790f32019-07-11 00:14:243728 if (client_ && has_poster_)
Dale Curtiscdfc6f22019-06-26 22:05:233729 client_->Repaint();
Dale Curtis3899090ea2018-01-12 00:10:353730}
3731
3732void WebMediaPlayerImpl::RecordTimingUMA(const std::string& key,
3733 base::TimeDelta elapsed) {
3734 if (chunk_demuxer_)
3735 base::UmaHistogramMediumTimes(key + ".MSE", elapsed);
3736 else
3737 base::UmaHistogramMediumTimes(key + ".SRC", elapsed);
3738 if (is_encrypted_)
3739 base::UmaHistogramMediumTimes(key + ".EME", elapsed);
3740}
3741
John Rummelldb5a7ef2018-05-16 00:28:013742void WebMediaPlayerImpl::RecordEncryptionScheme(
3743 const std::string& stream_name,
Yuchen Liub33bfc12019-11-08 20:16:123744 EncryptionScheme encryption_scheme) {
John Rummelldb5a7ef2018-05-16 00:28:013745 DCHECK(stream_name == "Audio" || stream_name == "Video");
3746
3747 // If the stream is not encrypted, don't record it.
Yuchen Liub33bfc12019-11-08 20:16:123748 if (encryption_scheme == EncryptionScheme::kUnencrypted)
John Rummelldb5a7ef2018-05-16 00:28:013749 return;
3750
3751 base::UmaHistogramEnumeration(
3752 "Media.EME.EncryptionScheme.Initial." + stream_name,
3753 DetermineEncryptionSchemeUMAValue(encryption_scheme),
3754 EncryptionSchemeUMA::kCount);
3755}
3756
Mounir Lamouri0484f40a2018-07-25 03:03:263757bool WebMediaPlayerImpl::IsInPictureInPicture() const {
3758 DCHECK(client_);
3759 return client_->DisplayType() ==
3760 WebMediaPlayer::DisplayType::kPictureInPicture;
3761}
3762
Jazz Xu74690262020-01-30 14:02:273763void WebMediaPlayerImpl::OnPictureInPictureAvailabilityChanged(bool available) {
3764 delegate_->DidPictureInPictureAvailabilityChange(delegate_id_, available);
3765}
3766
David Dorwin89fe8d02020-05-01 05:42:423767void WebMediaPlayerImpl::MaybeSetContainerNameForMetrics() {
Dale Curtis5bba03232018-08-30 17:57:383768 // Pipeline startup failed before even getting a demuxer setup.
3769 if (!demuxer_)
3770 return;
3771
3772 // Container has already been set.
3773 if (highest_ready_state_ >= WebMediaPlayer::kReadyStateHaveMetadata)
3774 return;
3775
David Dorwin89fe8d02020-05-01 05:42:423776 // Only report metrics for demuxers that provide container information.
3777 auto container = demuxer_->GetContainerForMetrics();
3778 if (container.has_value())
3779 media_metrics_provider_->SetContainerName(container.value());
Dale Curtis5bba03232018-08-30 17:57:383780}
3781
Dale Curtis18ad391b2019-05-30 23:25:093782void WebMediaPlayerImpl::MaybeUpdateBufferSizesForPlayback() {
3783 // Don't increase the MultiBufferDataSource buffer size until we've reached
3784 // kReadyStateHaveEnoughData. Otherwise we will unnecessarily slow down
3785 // playback startup -- it can instead be done for free after playback starts.
3786 if (!mb_data_source_ || highest_ready_state_ < kReadyStateHaveEnoughData)
3787 return;
3788
3789 mb_data_source_->MediaPlaybackRateChanged(playback_rate_);
3790 if (!paused_)
3791 mb_data_source_->MediaIsPlaying();
Dale Curtis18ad391b2019-05-30 23:25:093792}
3793
Dan Sanders6edfd782019-08-13 00:13:183794void WebMediaPlayerImpl::OnSimpleWatchTimerTick() {
3795 RecordSimpleWatchTimeUMA(reported_renderer_type_);
Sergey Ulanovb8656772020-04-21 22:56:143796
3797 if (playback_events_recorder_)
3798 playback_events_recorder_->OnPipelineStatistics(GetPipelineStatistics());
Dan Sanders6edfd782019-08-13 00:13:183799}
3800
[email protected]dbb3ff372019-10-15 19:09:423801GURL WebMediaPlayerImpl::GetSrcAfterRedirects() {
3802 return mb_data_source_ ? mb_data_source_->GetUrlAfterRedirects() : GURL();
3803}
3804
[email protected]96665a82020-01-23 00:35:373805void WebMediaPlayerImpl::UpdateSmoothnessHelper() {
3806 // If the experiment flag is off, then do nothing.
3807 if (!base::FeatureList::IsEnabled(kMediaLearningSmoothnessExperiment))
3808 return;
3809
3810 // If we're paused, or if we can't get all the features, then clear any
3811 // smoothness helper and stop. We'll try to create it later when we're
3812 // playing and have all the features.
3813 if (paused_ || !HasVideo() || pipeline_metadata_.natural_size.IsEmpty() ||
3814 !last_reported_fps_) {
3815 smoothness_helper_.reset();
3816 return;
3817 }
3818
3819 // Fill in features.
3820 // NOTE: this is a very bad way to do this, since it memorizes the order of
3821 // features in the task. However, it'll do for now.
3822 learning::FeatureVector features;
3823 features.push_back(
3824 learning::FeatureValue(pipeline_metadata_.video_decoder_config.codec()));
3825 features.push_back(learning::FeatureValue(
3826 pipeline_metadata_.video_decoder_config.profile()));
3827 features.push_back(
3828 learning::FeatureValue(pipeline_metadata_.natural_size.width()));
3829 features.push_back(learning::FeatureValue(*last_reported_fps_));
3830
3831 // If we have a smoothness helper, and we're not changing the features, then
3832 // do nothing. This prevents restarting the helper for no reason.
3833 if (smoothness_helper_ && features == smoothness_helper_->features())
3834 return;
3835
3836 // Create or restart the smoothness helper with |features|.
[email protected]91379332020-01-26 03:58:203837 smoothness_helper_ = SmoothnessHelper::Create(
Chris Cunningham64546ed2020-02-13 17:28:493838 GetLearningTaskController(learning::tasknames::kConsecutiveBadWindows),
3839 GetLearningTaskController(learning::tasknames::kConsecutiveNNRs),
[email protected]91379332020-01-26 03:58:203840 features, this);
3841}
3842
3843std::unique_ptr<learning::LearningTaskController>
Chris Cunningham64546ed2020-02-13 17:28:493844WebMediaPlayerImpl::GetLearningTaskController(const char* task_name) {
[email protected]91379332020-01-26 03:58:203845 // Get the LearningTaskController for |task_id|.
Chris Cunningham64546ed2020-02-13 17:28:493846 learning::LearningTask task = learning::MediaLearningTasks::Get(task_name);
3847 DCHECK_EQ(task.name, task_name);
[email protected]96665a82020-01-23 00:35:373848
3849 mojo::Remote<media::learning::mojom::LearningTaskController> remote_ltc;
3850 media_metrics_provider_->AcquireLearningTaskController(
3851 task.name, remote_ltc.BindNewPipeAndPassReceiver());
[email protected]91379332020-01-26 03:58:203852 return std::make_unique<learning::MojoLearningTaskController>(
[email protected]96665a82020-01-23 00:35:373853 task, std::move(remote_ltc));
[email protected]96665a82020-01-23 00:35:373854}
3855
acolwell9e0840d2014-09-06 19:01:323856} // namespace media