blob: ca5df6e2f9777eafe246f94b053932927efc440c [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"
CJ DiMeglioc60a5cf2017-09-27 20:08:4134#include "components/viz/common/gpu/context_provider.h"
[email protected]e4fc09e2012-04-06 03:17:4435#include "media/audio/null_audio_sink.h"
[email protected]2eccbed2014-01-10 05:15:5336#include "media/base/bind_to_current_loop.h"
xhwang0ad11e512014-11-25 23:43:0937#include "media/base/cdm_context.h"
John Rummelldb5a7ef2018-05-16 00:28:0138#include "media/base/encryption_scheme.h"
[email protected]32da1002010-03-03 21:57:3539#include "media/base/limits.h"
zqzhang5d8eab72016-08-26 20:34:3040#include "media/base/media_content_type.h"
[email protected]090f7312011-08-05 23:26:4041#include "media/base/media_log.h"
sandersd1e49fb62015-12-12 01:18:0642#include "media/base/media_switches.h"
tguilbert25a4d112016-10-13 21:56:5143#include "media/base/media_url_demuxer.h"
Eugene Zemtsov77d56262020-03-06 05:52:0344#include "media/base/memory_dump_provider_proxy.h"
[email protected]8a561062013-11-22 01:19:3145#include "media/base/text_renderer.h"
watk9f9dfdc92015-09-04 21:33:2946#include "media/base/timestamp_constants.h"
[email protected]e81283bb2010-08-31 18:01:2147#include "media/base/video_frame.h"
acolwell9e0840d2014-09-06 19:01:3248#include "media/blink/texttrack_impl.h"
John Delaneyb933391602018-10-17 21:50:4749#include "media/blink/url_index.h"
Chris Cunninghamd9df58e2017-08-29 00:04:2350#include "media/blink/video_decode_stats_reporter.h"
dalecurtis04bdb582016-08-17 22:15:2351#include "media/blink/watch_time_reporter.h"
xhwang97de4202014-11-25 08:44:0152#include "media/blink/webcontentdecryptionmodule_impl.h"
acolwell9e0840d2014-09-06 19:01:3253#include "media/blink/webinbandtexttrack_impl.h"
acolwell9e0840d2014-09-06 19:01:3254#include "media/blink/webmediasource_impl.h"
[email protected]efe7cd22012-09-12 23:55:0155#include "media/filters/chunk_demuxer.h"
[email protected]ddbc6ff2013-04-19 15:28:3356#include "media/filters/ffmpeg_demuxer.h"
Dale Curtis4841c712018-12-13 18:14:0557#include "media/filters/memory_data_source.h"
[email protected]96665a82020-01-23 00:35:3758#include "media/learning/mojo/public/cpp/mojo_learning_task_controller.h"
Scott Violeta35f9a42018-03-22 22:00:4459#include "media/media_buildflags.h"
Gyuyoung Kima040bc52019-10-30 01:14:3560#include "mojo/public/cpp/bindings/pending_remote.h"
Dale Curtis4841c712018-12-13 18:14:0561#include "net/base/data_url.h"
Blink Reformata30d4232018-04-07 15:31:0662#include "third_party/blink/public/platform/web_encrypted_media_types.h"
[email protected]0526d5692020-02-28 00:24:3163#include "third_party/blink/public/platform/web_fullscreen_video_status.h"
Blink Reformata30d4232018-04-07 15:31:0664#include "third_party/blink/public/platform/web_media_player_client.h"
65#include "third_party/blink/public/platform/web_media_player_encrypted_media_client.h"
66#include "third_party/blink/public/platform/web_media_player_source.h"
67#include "third_party/blink/public/platform/web_media_source.h"
68#include "third_party/blink/public/platform/web_rect.h"
69#include "third_party/blink/public/platform/web_runtime_features.h"
70#include "third_party/blink/public/platform/web_security_origin.h"
71#include "third_party/blink/public/platform/web_size.h"
72#include "third_party/blink/public/platform/web_string.h"
73#include "third_party/blink/public/platform/web_surface_layer_bridge.h"
74#include "third_party/blink/public/platform/web_url.h"
Antonio Gomes3a858b52019-05-31 02:47:5275#include "third_party/blink/public/platform/webaudiosourceprovider_impl.h"
Gyuyoung Kimf99f5f32019-09-26 03:45:1576#include "third_party/blink/public/strings/grit/blink_strings.h"
Antonio Gomesf01cfbd2019-07-12 08:53:1177#include "third_party/blink/public/web/modules/media/webmediaplayer_util.h"
Blink Reformata30d4232018-04-07 15:31:0678#include "third_party/blink/public/web/web_document.h"
79#include "third_party/blink/public/web/web_frame.h"
80#include "third_party/blink/public/web/web_local_frame.h"
Blink Reformata30d4232018-04-07 15:31:0681#include "third_party/blink/public/web/web_view.h"
[email protected]b3f2b912009-04-09 16:18:5282
dalecurtisea27a3ed2016-06-24 01:41:3083#if defined(OS_ANDROID)
84#include "media/base/android/media_codec_util.h"
85#endif
86
[email protected]180ef242013-11-07 06:50:4687using blink::WebMediaPlayer;
88using blink::WebRect;
[email protected]180ef242013-11-07 06:50:4689using blink::WebString;
hubbed5f36882016-01-15 22:40:3790using gpu::gles2::GLES2Interface;
91
danakj365175c2016-02-06 00:37:3792#define STATIC_ASSERT_ENUM(a, b) \
93 static_assert(static_cast<int>(a) == static_cast<int>(b), \
94 "mismatching enums: " #a)
95
hubbed5f36882016-01-15 22:40:3796namespace media {
[email protected]ec9212f2008-12-18 21:40:3697
[email protected]8931c41a2009-07-07 17:31:4998namespace {
99
Dan Sanders6edfd782019-08-13 00:13:18100const char kWatchTimeHistogram[] = "Media.WebMediaPlayerImpl.WatchTime";
101
Xiaohan Wang48aaa192019-12-05 01:29:00102void RecordSimpleWatchTimeUMA(RendererFactoryType type) {
103 UMA_HISTOGRAM_ENUMERATION(kWatchTimeHistogram, type);
Dan Sanders6edfd782019-08-13 00:13:18104}
105
Antonio Gomes3a858b52019-05-31 02:47:52106void SetSinkIdOnMediaThread(
107 scoped_refptr<blink::WebAudioSourceProviderImpl> sink,
108 const std::string& device_id,
109 OutputDeviceStatusCB callback) {
Daniel Chengc1710b52018-10-24 03:12:28110 sink->SwitchOutputDevice(device_id, std::move(callback));
guidouc7babef2015-10-22 00:42:35111}
112
Sergey Volk8b09c2c52018-12-12 23:20:40113bool IsBackgroundSuspendEnabled(const WebMediaPlayerImpl* wmpi) {
Luke Halliwell7a8a8982018-07-25 01:07:05114 // TODO(crbug.com/867146): remove these switches.
115 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
116 switches::kDisableMediaSuspend))
117 return false;
118 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
119 switches::kEnableMediaSuspend))
120 return true;
121
Sergey Volk8b09c2c52018-12-12 23:20:40122 return wmpi->IsBackgroundMediaSuspendEnabled();
dalecurtis0431cbf2016-03-12 01:19:43123}
124
avayvod48a8be52016-08-04 19:52:50125bool IsResumeBackgroundVideosEnabled() {
126 return base::FeatureList::IsEnabled(kResumeBackgroundVideo);
127}
128
avayvod01201332017-04-14 00:27:15129bool IsBackgroundVideoPauseOptimizationEnabled() {
130 return base::FeatureList::IsEnabled(kBackgroundVideoPauseOptimization);
131}
132
sandersd50a635e2016-04-04 22:50:09133bool IsNetworkStateError(blink::WebMediaPlayer::NetworkState state) {
Blink Reformat1c4d759e2017-04-09 16:34:54134 bool result = state == blink::WebMediaPlayer::kNetworkStateFormatError ||
135 state == blink::WebMediaPlayer::kNetworkStateNetworkError ||
136 state == blink::WebMediaPlayer::kNetworkStateDecodeError;
137 DCHECK_EQ(state > blink::WebMediaPlayer::kNetworkStateLoaded, result);
sandersd50a635e2016-04-04 22:50:09138 return result;
139}
140
sandersd2c478422016-08-02 01:19:25141gfx::Size GetRotatedVideoSize(VideoRotation rotation, gfx::Size natural_size) {
142 if (rotation == VIDEO_ROTATION_90 || rotation == VIDEO_ROTATION_270)
143 return gfx::Size(natural_size.height(), natural_size.width());
144 return natural_size;
145}
146
Xiaohan Wangf63505d2017-10-21 08:00:53147void RecordEncryptedEvent(bool encrypted_event_fired) {
148 UMA_HISTOGRAM_BOOLEAN("Media.EME.EncryptedEvent", encrypted_event_fired);
149}
150
sandersd35d2c3f2017-01-14 02:04:42151// How much time must have elapsed since loading last progressed before we
152// assume that the decoder will have had time to complete preroll.
153constexpr base::TimeDelta kPrerollAttemptTimeout =
watkd026f792016-11-05 00:28:51154 base::TimeDelta::FromSeconds(3);
155
Matt Wolenetz6010f6c2017-10-18 00:44:36156// Maximum number, per-WMPI, of media logs of playback rate changes.
157constexpr int kMaxNumPlaybackRateLogs = 10;
158
Gyuyoung Kimf99f5f32019-09-26 03:45:15159int GetSwitchToLocalMessage(MediaObserverClient::ReasonToSwitchToLocal reason) {
Xiangjun Zhang5e20cba42018-01-10 19:54:56160 switch (reason) {
161 case MediaObserverClient::ReasonToSwitchToLocal::NORMAL:
Gyuyoung Kimf99f5f32019-09-26 03:45:15162 return IDS_MEDIA_REMOTING_STOP_TEXT;
Xiangjun Zhang5e20cba42018-01-10 19:54:56163 case MediaObserverClient::ReasonToSwitchToLocal::POOR_PLAYBACK_QUALITY:
Gyuyoung Kimf99f5f32019-09-26 03:45:15164 return IDS_MEDIA_REMOTING_STOP_BY_PLAYBACK_QUALITY_TEXT;
Xiangjun Zhang5e20cba42018-01-10 19:54:56165 case MediaObserverClient::ReasonToSwitchToLocal::PIPELINE_ERROR:
Gyuyoung Kimf99f5f32019-09-26 03:45:15166 return IDS_MEDIA_REMOTING_STOP_BY_ERROR_TEXT;
Xiangjun Zhang5e20cba42018-01-10 19:54:56167 case MediaObserverClient::ReasonToSwitchToLocal::ROUTE_TERMINATED:
Gyuyoung Kimf99f5f32019-09-26 03:45:15168 return blink::WebMediaPlayerClient::kMediaRemotingStopNoText;
Xiangjun Zhang5e20cba42018-01-10 19:54:56169 }
170 NOTREACHED();
171 // To suppress compiler warning on Windows.
Gyuyoung Kimf99f5f32019-09-26 03:45:15172 return blink::WebMediaPlayerClient::kMediaRemotingStopNoText;
Xiangjun Zhang5e20cba42018-01-10 19:54:56173}
174
John Rummelldb5a7ef2018-05-16 00:28:01175// These values are persisted to UMA. Entries should not be renumbered and
176// numeric values should never be reused.
Yuchen Liub33bfc12019-11-08 20:16:12177// TODO(crbug.com/825041): This should use EncryptionScheme when kUnencrypted
John Rummelldb5a7ef2018-05-16 00:28:01178// removed.
179enum class EncryptionSchemeUMA { kCenc = 0, kCbcs = 1, kCount };
180
181EncryptionSchemeUMA DetermineEncryptionSchemeUMAValue(
Yuchen Liub33bfc12019-11-08 20:16:12182 EncryptionScheme encryption_scheme) {
183 if (encryption_scheme == EncryptionScheme::kCbcs)
John Rummelldb5a7ef2018-05-16 00:28:01184 return EncryptionSchemeUMA::kCbcs;
185
Yuchen Liub33bfc12019-11-08 20:16:12186 DCHECK_EQ(encryption_scheme, EncryptionScheme::kCenc);
John Rummelldb5a7ef2018-05-16 00:28:01187 return EncryptionSchemeUMA::kCenc;
188}
189
Pavel Feldman023c3e62018-08-28 17:59:47190#if BUILDFLAG(ENABLE_FFMPEG)
Dale Curtisb8139f72018-08-27 23:28:48191// Returns true if |url| represents (or is likely to) a local file.
192bool IsLocalFile(const GURL& url) {
193 return url.SchemeIsFile() || url.SchemeIsFileSystem() ||
194 url.SchemeIs(url::kContentScheme) ||
195 url.SchemeIs(url::kContentIDScheme) ||
196 url.SchemeIs("chrome-extension");
197}
Pavel Feldman023c3e62018-08-28 17:59:47198#endif
Dale Curtisb8139f72018-08-27 23:28:48199
Dale Curtisf273f8f2018-12-13 23:40:33200// Handles destruction of media::Renderer dependent components after the
201// renderer has been destructed on the media thread.
202void DestructionHelper(
203 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
204 scoped_refptr<base::SingleThreadTaskRunner> vfc_task_runner,
205 std::unique_ptr<Demuxer> demuxer,
206 std::unique_ptr<DataSource> data_source,
207 std::unique_ptr<VideoFrameCompositor> compositor,
208 std::unique_ptr<CdmContextRef> cdm_context_1,
209 std::unique_ptr<CdmContextRef> cdm_context_2,
210 std::unique_ptr<MediaLog> media_log,
211 std::unique_ptr<RendererFactorySelector> renderer_factory_selector,
212 std::unique_ptr<blink::WebSurfaceLayerBridge> bridge,
213 bool is_chunk_demuxer) {
214 // We release |bridge| after pipeline stop to ensure layout tests receive
215 // painted video frames before test harness exit.
216 main_task_runner->DeleteSoon(FROM_HERE, std::move(bridge));
217
218 // Since the media::Renderer is gone we can now destroy the compositor and
219 // renderer factory selector.
220 vfc_task_runner->DeleteSoon(FROM_HERE, std::move(compositor));
221 main_task_runner->DeleteSoon(FROM_HERE, std::move(renderer_factory_selector));
222
223 // ChunkDemuxer can be deleted on any thread, but other demuxers are bound to
224 // the main thread and must be deleted there now that the renderer is gone.
225 if (!is_chunk_demuxer) {
226 main_task_runner->DeleteSoon(FROM_HERE, std::move(demuxer));
227 main_task_runner->DeleteSoon(FROM_HERE, std::move(data_source));
228 main_task_runner->DeleteSoon(FROM_HERE, std::move(cdm_context_1));
229 main_task_runner->DeleteSoon(FROM_HERE, std::move(cdm_context_2));
230 main_task_runner->DeleteSoon(FROM_HERE, std::move(media_log));
231 return;
232 }
233
234 // ChunkDemuxer's streams may contain much buffered, compressed media that
235 // may need to be paged back in during destruction. Paging delay may exceed
236 // the renderer hang monitor's threshold on at least Windows while also
237 // blocking other work on the renderer main thread, so we do the actual
238 // destruction in the background without blocking WMPI destruction or
239 // |task_runner|. On advice of task_scheduler OWNERS, MayBlock() is not
240 // used because virtual memory overhead is not considered blocking I/O; and
241 // CONTINUE_ON_SHUTDOWN is used to allow process termination to not block on
242 // completing the task.
Gabriel Charetted5c656c2020-02-26 16:35:22243 base::ThreadPool::PostTask(
Dale Curtisf273f8f2018-12-13 23:40:33244 FROM_HERE,
Gabriel Charetted5c656c2020-02-26 16:35:22245 {base::TaskPriority::BEST_EFFORT,
Dale Curtisf273f8f2018-12-13 23:40:33246 base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
247 base::BindOnce(
248 [](scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
249 std::unique_ptr<Demuxer> demuxer_to_destroy,
250 std::unique_ptr<CdmContextRef> cdm_context_1,
251 std::unique_ptr<CdmContextRef> cdm_context_2,
252 std::unique_ptr<MediaLog> media_log) {
253 SCOPED_UMA_HISTOGRAM_TIMER("Media.MSE.DemuxerDestructionTime");
254 demuxer_to_destroy.reset();
255 main_task_runner->DeleteSoon(FROM_HERE, std::move(cdm_context_1));
256 main_task_runner->DeleteSoon(FROM_HERE, std::move(cdm_context_2));
257 main_task_runner->DeleteSoon(FROM_HERE, std::move(media_log));
258 },
259 std::move(main_task_runner), std::move(demuxer),
260 std::move(cdm_context_1), std::move(cdm_context_2),
261 std::move(media_log)));
262}
263
Ted Meyer7f5b4e22019-11-21 03:21:19264std::string SanitizeUserStringProperty(blink::WebString value) {
Ted Meyera698afe2019-11-06 20:58:03265 std::string converted = value.Utf8();
Ted Meyer7f5b4e22019-11-21 03:21:19266 return base::IsStringUTF8(converted) ? converted : "[invalid property]";
Ted Meyera698afe2019-11-06 20:58:03267}
268
Eugene Zemtsov77d56262020-03-06 05:52:03269void CreateAllocation(base::trace_event::ProcessMemoryDump* pmd,
270 int32_t id,
271 const char* name,
272 int64_t bytes) {
273 if (bytes <= 0)
274 return;
275 auto full_name =
276 base::StringPrintf("media/webmediaplayer/player_%d/%s", id, name);
277 auto* dump = pmd->CreateAllocatorDump(full_name);
278
279 dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
280 base::trace_event::MemoryAllocatorDump::kUnitsBytes, bytes);
281
282 auto* std_allocator = base::trace_event::MemoryDumpManager::GetInstance()
283 ->system_allocator_pool_name();
284 pmd->AddSuballocation(dump->guid(), std_allocator);
285}
286
[email protected]8931c41a2009-07-07 17:31:49287} // namespace
288
[email protected]6683e1b2014-04-10 01:45:38289class BufferedDataSourceHostImpl;
290
Takashi Toyoshima2e01e692018-11-16 03:23:27291STATIC_ASSERT_ENUM(WebMediaPlayer::kCorsModeUnspecified,
danakj365175c2016-02-06 00:37:37292 UrlData::CORS_UNSPECIFIED);
Takashi Toyoshima2e01e692018-11-16 03:23:27293STATIC_ASSERT_ENUM(WebMediaPlayer::kCorsModeAnonymous, UrlData::CORS_ANONYMOUS);
294STATIC_ASSERT_ENUM(WebMediaPlayer::kCorsModeUseCredentials,
danakj365175c2016-02-06 00:37:37295 UrlData::CORS_USE_CREDENTIALS);
[email protected]a5a01102012-06-06 17:01:24296
[email protected]5b5bb9d2010-10-22 19:57:36297WebMediaPlayerImpl::WebMediaPlayerImpl(
[email protected]35b2a972014-04-04 15:50:22298 blink::WebLocalFrame* frame,
[email protected]180ef242013-11-07 06:50:46299 blink::WebMediaPlayerClient* client,
srirama.m26f864d02015-07-14 05:21:46300 blink::WebMediaPlayerEncryptedMediaClient* encrypted_client,
Antonio Gomes423df612019-07-11 12:40:07301 blink::WebMediaPlayerDelegate* delegate,
tguilbert70d2a00a2017-04-25 00:30:44302 std::unique_ptr<RendererFactorySelector> renderer_factory_selector,
Alok Priyadarshi7166d4d2017-07-29 04:04:25303 UrlIndex* url_index,
CJ DiMegliod7ac6772017-11-10 00:19:06304 std::unique_ptr<VideoFrameCompositor> compositor,
dalecurtis9cddc0b2017-04-19 21:23:38305 std::unique_ptr<WebMediaPlayerParams> params)
[email protected]f6af7592014-02-28 10:09:11306 : frame_(frame),
Alexander Timin310368112017-09-13 10:01:44307 main_task_runner_(
308 frame->GetTaskRunner(blink::TaskType::kMediaElementEvent)),
dalecurtis9cddc0b2017-04-19 21:23:38309 media_task_runner_(params->media_task_runner()),
310 worker_task_runner_(params->worker_task_runner()),
311 media_log_(params->take_media_log()),
[email protected]5badb082010-06-11 17:40:15312 client_(client),
srirama.m26f864d02015-07-14 05:21:46313 encrypted_client_(encrypted_client),
[email protected]baff4512011-10-19 18:21:07314 delegate_(delegate),
dalecurtis9cddc0b2017-04-19 21:23:38315 defer_load_cb_(params->defer_load_cb()),
dalecurtis9cddc0b2017-04-19 21:23:38316 adjust_allocated_memory_cb_(params->adjust_allocated_memory_cb()),
tzik2c963b872017-12-07 06:57:24317 tick_clock_(base::DefaultTickClock::GetInstance()),
hubbe5f0ad43b2015-12-14 20:57:26318 url_index_(url_index),
CJ DiMeglioc60a5cf2017-09-27 20:08:41319 context_provider_(params->context_provider()),
CJ DiMegliod7ac6772017-11-10 00:19:06320 vfc_task_runner_(params->video_frame_compositor_task_runner()),
321 compositor_(std::move(compositor)),
tguilbert70d2a00a2017-04-25 00:30:44322 renderer_factory_selector_(std::move(renderer_factory_selector)),
dalecurtis9cddc0b2017-04-19 21:23:38323 observer_(params->media_observer()),
servolkf94b4602017-01-31 16:44:27324 enable_instant_source_buffer_gc_(
dalecurtis9cddc0b2017-04-19 21:23:38325 params->enable_instant_source_buffer_gc()),
shaktisahu24189c12017-03-11 17:42:55326 embedded_media_experience_enabled_(
liberato2ff93ad2017-05-17 07:28:24327 params->embedded_media_experience_enabled()),
[email protected]69db58f2018-09-26 20:27:56328 surface_layer_mode_(params->use_surface_layer_for_video()),
CJ DiMeglio96c18b692018-07-04 03:39:06329 create_bridge_callback_(params->create_bridge_callback()),
liberato2ff93ad2017-05-17 07:28:24330 request_routing_token_cb_(params->request_routing_token_cb()),
Dale Curtis1adbe6a2017-08-02 02:09:13331 overlay_routing_token_(OverlayInfo::RoutingToken()),
Sergey Volk8b09c2c52018-12-12 23:20:40332 media_metrics_provider_(params->take_metrics_provider()),
333 is_background_suspend_enabled_(params->IsBackgroundSuspendEnabled()),
Junbo Kefba620b2019-01-16 02:54:36334 is_background_video_playback_enabled_(
335 params->IsBackgroundVideoPlaybackEnabled()),
Sergey Volk8b09c2c52018-12-12 23:20:40336 is_background_video_track_optimization_supported_(
Dan Sanders6edfd782019-08-13 00:13:18337 params->IsBackgroundVideoTrackOptimizationSupported()),
Chih-Hsuan Kuo7b4fb102020-03-04 08:21:49338 is_remoting_renderer_enabled_(params->IsRemotingRendererEnabled()),
Xiaohan Wang48aaa192019-12-05 01:29:00339 reported_renderer_type_(RendererFactoryType::kDefault),
Dan Sanders6edfd782019-08-13 00:13:18340 simple_watch_timer_(
341 base::BindRepeating(&WebMediaPlayerImpl::OnSimpleWatchTimerTick,
342 base::Unretained(this)),
343 base::BindRepeating(&WebMediaPlayerImpl::GetCurrentTimeInternal,
[email protected]91fd3162019-09-05 23:51:32344 base::Unretained(this))),
[email protected]dc996312019-12-19 19:26:38345 will_play_helper_(nullptr),
346 power_status_helper_(params->TakePowerStatusHelper()) {
xhwang51139732017-02-24 19:36:08347 DVLOG(1) << __func__;
Dale Curtise25163812018-09-21 22:13:39348 DCHECK(adjust_allocated_memory_cb_);
tguilbert70d2a00a2017-04-25 00:30:44349 DCHECK(renderer_factory_selector_);
servolkef1e5ef2016-03-25 04:55:26350 DCHECK(client_);
tguilbert1bb1c782017-01-23 21:15:11351 DCHECK(delegate_);
dalecurtis83266c72015-10-29 18:43:20352
Antonio Gomes142f32a2019-05-15 23:32:56353 weak_this_ = weak_factory_.GetWeakPtr();
354
Xiaohan Wang2480de72019-11-15 01:44:47355 // Using base::Unretained(this) is safe because the |pipeline| is owned by
356 // |this| and the callback will always be made on the main task runner.
357 // Not using BindToCurrentLoop() because CreateRenderer() is a sync call.
358 auto pipeline = std::make_unique<PipelineImpl>(
359 media_task_runner_, main_task_runner_,
360 base::BindRepeating(&WebMediaPlayerImpl::CreateRenderer,
361 base::Unretained(this)),
362 media_log_.get());
363
Antonio Gomes81b56552019-05-15 22:15:28364 pipeline_controller_ = std::make_unique<PipelineController>(
Xiaohan Wang2480de72019-11-15 01:44:47365 std::move(pipeline),
Antonio Gomes142f32a2019-05-15 23:32:56366 base::BindRepeating(&WebMediaPlayerImpl::OnPipelineSeeked, weak_this_),
367 base::BindRepeating(&WebMediaPlayerImpl::OnPipelineSuspended, weak_this_),
Antonio Gomes81b56552019-05-15 22:15:28368 base::BindRepeating(&WebMediaPlayerImpl::OnBeforePipelineResume,
Antonio Gomes142f32a2019-05-15 23:32:56369 weak_this_),
370 base::BindRepeating(&WebMediaPlayerImpl::OnPipelineResumed, weak_this_),
371 base::BindRepeating(&WebMediaPlayerImpl::OnError, weak_this_));
Antonio Gomes81b56552019-05-15 22:15:28372
373 buffered_data_source_host_ = std::make_unique<BufferedDataSourceHostImpl>(
Antonio Gomes142f32a2019-05-15 23:32:56374 base::BindRepeating(&WebMediaPlayerImpl::OnProgress, weak_this_),
Antonio Gomes81b56552019-05-15 22:15:28375 tick_clock_);
376
[email protected]c8d574722017-08-30 20:53:43377 // If we're supposed to force video overlays, then make sure that they're
378 // enabled all the time.
379 always_enable_overlays_ = base::CommandLine::ForCurrentProcess()->HasSwitch(
tsunghungee562e92016-07-20 18:03:31380 switches::kForceVideoOverlays);
381
Jinsong Fan982342112019-11-07 23:45:45382 if (base::FeatureList::IsEnabled(kOverlayFullscreenVideo))
383 overlay_mode_ = OverlayMode::kUseAndroidOverlay;
384 else
liberato2ff93ad2017-05-17 07:28:24385 overlay_mode_ = OverlayMode::kNoOverlays;
ampea73f792017-01-19 04:05:39386
tguilbert1bb1c782017-01-23 21:15:11387 delegate_id_ = delegate_->AddObserver(this);
388 delegate_->SetIdle(delegate_id_, true);
sandersd1e49fb62015-12-12 01:18:06389
Ted Meyer0134aed2020-01-23 23:56:40390 media_log_->AddEvent<MediaLogEvent::kWebMediaPlayerCreated>(
391 url::Origin(frame_->GetSecurityOrigin()).GetURL().spec());
Ted Meyera698afe2019-11-06 20:58:03392
Ted Meyer7f5b4e22019-11-21 03:21:19393 media_log_->SetProperty<MediaLogProperty::kFrameUrl>(
394 SanitizeUserStringProperty(frame_->GetDocument().Url().GetString()));
395 media_log_->SetProperty<MediaLogProperty::kFrameTitle>(
396 SanitizeUserStringProperty(frame_->GetDocument().Title()));
[email protected]52b0b212018-10-10 05:25:28397
dalecurtis9cddc0b2017-04-19 21:23:38398 if (params->initial_cdm())
Chris Cunninghamd4a00192019-03-21 20:02:49399 SetCdmInternal(params->initial_cdm());
xhwang0ad11e512014-11-25 23:43:09400
Xiaohan Wangf63505d2017-10-21 08:00:53401 // Report a false "EncrytpedEvent" here as a baseline.
402 RecordEncryptedEvent(false);
403
xhwangf94a634d2014-10-22 22:07:27404 // TODO(xhwang): When we use an external Renderer, many methods won't work,
xhwang6fa356202014-12-11 00:44:12405 // e.g. GetCurrentFrameFromCompositor(). See http://crbug.com/434861
Antonio Gomes3a858b52019-05-31 02:47:52406 audio_source_provider_ = new blink::WebAudioSourceProviderImpl(
dalecurtis9cddc0b2017-04-19 21:23:38407 params->audio_renderer_sink(), media_log_.get());
xjz4e5d4bf32017-02-15 21:26:35408
409 if (observer_)
410 observer_->SetClient(this);
Hajime Hoshi8bb37dc2017-12-19 09:35:10411
412 memory_usage_reporting_timer_.SetTaskRunner(
Hajime Hoshib5a26ee2018-05-14 12:47:51413 frame_->GetTaskRunner(blink::TaskType::kInternalMedia));
John Delaney6c8ecc1b2018-10-21 19:07:29414
Eugene Zemtsov77d56262020-03-06 05:52:03415 main_thread_mem_dumper_ = std::make_unique<MemoryDumpProviderProxy>(
416 "WebMediaPlayer_MainThread", main_task_runner_,
417 base::BindRepeating(&WebMediaPlayerImpl::OnMainThreadMemoryDump,
418 weak_this_, media_log_->id()));
419
Thomas Guilbert901808982019-07-03 20:38:18420#if defined(OS_ANDROID)
Thomas Guilbertf6d0702e2019-09-12 23:40:14421 renderer_factory_selector_->SetRemotePlayStateChangeCB(
422 BindToCurrentLoop(base::BindRepeating(
423 &WebMediaPlayerImpl::OnRemotePlayStateChange, weak_this_)));
Thomas Guilbert901808982019-07-03 20:38:18424#endif // defined (OS_ANDROID)
[email protected]ec9212f2008-12-18 21:40:36425}
426
[email protected]4e6be3f2009-05-07 02:24:44427WebMediaPlayerImpl::~WebMediaPlayerImpl() {
xhwang51139732017-02-24 19:36:08428 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:43429 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53430
xhwang51139732017-02-24 19:36:08431 if (set_cdm_result_) {
Chris Cunninghamd4a00192019-03-21 20:02:49432 DVLOG(2)
433 << "Resolve pending SetCdmInternal() when media player is destroyed.";
Blink Reformat1c4d759e2017-04-09 16:34:54434 set_cdm_result_->Complete();
xhwang51139732017-02-24 19:36:08435 set_cdm_result_.reset();
436 }
437
alokp1116967f2016-06-11 17:30:56438 suppress_destruction_errors_ = true;
tguilbert1bb1c782017-01-23 21:15:11439
440 delegate_->PlayerGone(delegate_id_);
441 delegate_->RemoveObserver(delegate_id_);
[email protected]baff4512011-10-19 18:21:07442
dalecurtis04bdb582016-08-17 22:15:23443 // Finalize any watch time metrics before destroying the pipeline.
444 watch_time_reporter_.reset();
445
Eugene Zemtsov77d56262020-03-06 05:52:03446 // Unregister dump providers on their corresponding threads.
447 media_task_runner_->DeleteSoon(FROM_HERE,
448 std::move(media_thread_mem_dumper_));
449 main_thread_mem_dumper_.reset();
450
tguilbert350936ff2017-02-24 05:39:27451 // The underlying Pipeline must be stopped before it is destroyed.
Dale Curtisf273f8f2018-12-13 23:40:33452 //
453 // Note: This destruction happens synchronously on the media thread and
454 // |demuxer_|, |data_source_|, |compositor_|, and |media_log_| must outlive
455 // this process. They will be destructed by the DestructionHelper below
456 // after trampolining through the media thread.
Antonio Gomes81b56552019-05-15 22:15:28457 pipeline_controller_->Stop();
[email protected]f6af7592014-02-28 10:09:11458
dalecurtis83266c72015-10-29 18:43:20459 if (last_reported_memory_usage_)
460 adjust_allocated_memory_cb_.Run(-last_reported_memory_usage_);
461
dalecurtise1edb312016-06-22 02:33:21462 // Destruct compositor resources in the proper order.
danakj8d204a42018-05-18 18:05:35463 client_->SetCcLayer(nullptr);
CJ DiMeglio2302d202017-08-31 08:38:04464
Xiangjun Zhang5e20cba42018-01-10 19:54:56465 client_->MediaRemotingStopped(
Gyuyoung Kimf99f5f32019-09-26 03:45:15466 blink::WebMediaPlayerClient::kMediaRemotingStopNoText);
Xiangjun Zhang87299142017-09-13 20:35:03467
Dale Curtisf273f8f2018-12-13 23:40:33468 if (!surface_layer_for_video_enabled_ && video_layer_)
danakj25f030112018-05-11 18:26:54469 video_layer_->StopUsingProvider();
Matt Wolenetz95af6362018-01-04 20:23:42470
Dan Sanders6edfd782019-08-13 00:13:18471 simple_watch_timer_.Stop();
Ted Meyer257b682a2019-11-01 20:50:51472 media_log_->OnWebMediaPlayerDestroyed();
[email protected]ec9212f2008-12-18 21:40:36473
Dale Curtisf273f8f2018-12-13 23:40:33474 if (data_source_)
475 data_source_->Stop();
476
477 // Disconnect from the surface layer. We still preserve the |bridge_| until
478 // after pipeline shutdown to ensure any pending frames are painted for tests.
479 if (bridge_)
480 bridge_->ClearObserver();
481
Dale Curtisc96a3542018-12-17 22:15:23482 // Disconnect from the MediaObserver implementation since it's lifetime is
483 // tied to the RendererFactorySelector which can't be destroyed until after
484 // the Pipeline stops.
485 //
486 // Note: We can't use a WeakPtr with the RendererFactory because its methods
487 // are called on the media thread and this destruction takes place on the
488 // renderer thread.
489 if (observer_)
490 observer_->SetClient(nullptr);
491
[email protected]91fd3162019-09-05 23:51:32492 // If we're in the middle of an observation, then finish it.
493 will_play_helper_.CompleteObservationIfNeeded(learning::TargetValue(false));
494
Dale Curtisf273f8f2018-12-13 23:40:33495 // Handle destruction of things that need to be destructed after the pipeline
496 // completes stopping on the media thread.
497 media_task_runner_->PostTask(
Matt Wolenetz95af6362018-01-04 20:23:42498 FROM_HERE,
Dale Curtisf273f8f2018-12-13 23:40:33499 base::BindOnce(&DestructionHelper, std::move(main_task_runner_),
500 std::move(vfc_task_runner_), std::move(demuxer_),
501 std::move(data_source_), std::move(compositor_),
502 std::move(cdm_context_ref_),
503 std::move(pending_cdm_context_ref_), std::move(media_log_),
504 std::move(renderer_factory_selector_), std::move(bridge_),
505 !!chunk_demuxer_));
Matt Wolenetz95af6362018-01-04 20:23:42506}
507
chcunningham707b821e2018-05-29 08:42:19508WebMediaPlayer::LoadTiming WebMediaPlayerImpl::Load(
509 LoadType load_type,
510 const blink::WebMediaPlayerSource& source,
Takashi Toyoshima2e01e692018-11-16 03:23:27511 CorsMode cors_mode) {
guidou9bfe4e2f2016-04-09 08:31:19512 // Only URL or MSE blob URL is supported.
Blink Reformat1c4d759e2017-04-09 16:34:54513 DCHECK(source.IsURL());
514 blink::WebURL url = source.GetAsURL();
Xiaohan Wang81fd0022017-07-11 17:45:24515 DVLOG(1) << __func__ << "(" << load_type << ", " << GURL(url) << ", "
516 << cors_mode << ")";
chcunningham707b821e2018-05-29 08:42:19517
518 bool is_deferred = false;
519
Dale Curtise25163812018-09-21 22:13:39520 if (defer_load_cb_) {
chcunningham707b821e2018-05-29 08:42:19521 is_deferred = defer_load_cb_.Run(base::BindOnce(
Antonio Gomes142f32a2019-05-15 23:32:56522 &WebMediaPlayerImpl::DoLoad, weak_this_, load_type, url, cors_mode));
chcunningham707b821e2018-05-29 08:42:19523 } else {
524 DoLoad(load_type, url, cors_mode);
[email protected]d726eddc2013-07-02 22:25:55525 }
chcunningham707b821e2018-05-29 08:42:19526
527 return is_deferred ? LoadTiming::kDeferred : LoadTiming::kImmediate;
[email protected]62e5e682013-03-07 23:53:24528}
529
CJ DiMeglio013d4c472017-11-21 03:27:30530void WebMediaPlayerImpl::OnWebLayerUpdated() {}
531
danakj6a062b112018-05-17 16:25:45532void WebMediaPlayerImpl::RegisterContentsLayer(cc::Layer* layer) {
CJ DiMeglio2302d202017-08-31 08:38:04533 DCHECK(bridge_);
CJ DiMeglioa2b13fbc2018-06-27 00:50:59534 bridge_->SetContentsOpaque(opaque_);
danakj8d204a42018-05-18 18:05:35535 client_->SetCcLayer(layer);
CJ DiMeglio013d4c472017-11-21 03:27:30536}
537
danakj6a062b112018-05-17 16:25:45538void WebMediaPlayerImpl::UnregisterContentsLayer(cc::Layer* layer) {
539 // |client_| will unregister its cc::Layer if given a nullptr.
danakj8d204a42018-05-18 18:05:35540 client_->SetCcLayer(nullptr);
CJ DiMeglio2302d202017-08-31 08:38:04541}
542
Jennifer Apaciblec45fd052018-02-25 12:04:55543void WebMediaPlayerImpl::OnSurfaceIdUpdated(viz::SurfaceId surface_id) {
Jennifer Apaciblec45fd052018-02-25 12:04:55544 // TODO(726619): Handle the behavior when Picture-in-Picture mode is
545 // disabled.
Jennifer Apacible2b1dc5eb2018-04-27 16:23:28546 // The viz::SurfaceId may be updated when the video begins playback or when
547 // the size of the video changes.
Mounir Lamouri99ba5a62019-02-12 01:27:47548 if (client_)
549 client_->OnPictureInPictureStateChange();
Jennifer Apaciblec45fd052018-02-25 12:04:55550}
551
tsunghungee562e92016-07-20 18:03:31552void WebMediaPlayerImpl::EnableOverlay() {
553 overlay_enabled_ = true;
[email protected]f7df5b342018-07-13 20:22:13554 if (request_routing_token_cb_ &&
555 overlay_mode_ == OverlayMode::kUseAndroidOverlay) {
liberatofe8f9692017-06-08 19:17:36556 overlay_routing_token_is_pending_ = true;
liberato2ff93ad2017-05-17 07:28:24557 token_available_cb_.Reset(
Antonio Gomes142f32a2019-05-15 23:32:56558 base::Bind(&WebMediaPlayerImpl::OnOverlayRoutingToken, weak_this_));
liberato2ff93ad2017-05-17 07:28:24559 request_routing_token_cb_.Run(token_available_cb_.callback());
watkf835a792016-06-24 23:24:40560 }
tsunghungee562e92016-07-20 18:03:31561
liberato2ff93ad2017-05-17 07:28:24562 // We have requested (and maybe already have) overlay information. If the
563 // restarted decoder requests overlay information, then we'll defer providing
564 // it if it hasn't arrived yet. Otherwise, this would be a race, since we
565 // don't know if the request for overlay info or restart will complete first.
tsunghungee562e92016-07-20 18:03:31566 if (decoder_requires_restart_for_overlay_)
watkdee516f2016-02-18 02:22:19567 ScheduleRestart();
568}
569
tsunghungee562e92016-07-20 18:03:31570void WebMediaPlayerImpl::DisableOverlay() {
571 overlay_enabled_ = false;
Jinsong Fan982342112019-11-07 23:45:45572 if (overlay_mode_ == OverlayMode::kUseAndroidOverlay) {
liberato2ff93ad2017-05-17 07:28:24573 token_available_cb_.Cancel();
liberatofe8f9692017-06-08 19:17:36574 overlay_routing_token_is_pending_ = false;
575 overlay_routing_token_ = OverlayInfo::RoutingToken();
liberato2ff93ad2017-05-17 07:28:24576 }
tsunghungee562e92016-07-20 18:03:31577
578 if (decoder_requires_restart_for_overlay_)
watkdee516f2016-02-18 02:22:19579 ScheduleRestart();
liberato2ff93ad2017-05-17 07:28:24580 else
581 MaybeSendOverlayInfoToDecoder();
watkdee516f2016-02-18 02:22:19582}
583
Blink Reformat1c4d759e2017-04-09 16:34:54584void WebMediaPlayerImpl::EnteredFullscreen() {
liberatofe8f9692017-06-08 19:17:36585 overlay_info_.is_fullscreen = true;
586
[email protected]c8d574722017-08-30 20:53:43587 // |always_enable_overlays_| implies that we're already in overlay mode, so
588 // take no action here. Otherwise, switch to an overlay if it's allowed and
589 // if it will display properly.
590 if (!always_enable_overlays_ && overlay_mode_ != OverlayMode::kNoOverlays &&
liberato2fd111be2017-01-04 00:25:06591 DoesOverlaySupportMetadata()) {
tsunghungee562e92016-07-20 18:03:31592 EnableOverlay();
liberato2fd111be2017-01-04 00:25:06593 }
liberato2ff93ad2017-05-17 07:28:24594
liberatofe8f9692017-06-08 19:17:36595 // We send this only if we can send multiple calls. Otherwise, either (a)
596 // we already sent it and we don't have a callback anyway (we reset it when
597 // it's called in restart mode), or (b) we'll send this later when the surface
598 // actually arrives. GVD assumes that the first overlay info will have the
599 // routing information. Note that we set |is_fullscreen_| earlier, so that
600 // if EnableOverlay() can include fullscreen info in case it sends the overlay
601 // info before returning.
602 if (!decoder_requires_restart_for_overlay_)
603 MaybeSendOverlayInfoToDecoder();
tsunghungee562e92016-07-20 18:03:31604}
605
Blink Reformat1c4d759e2017-04-09 16:34:54606void WebMediaPlayerImpl::ExitedFullscreen() {
liberatofe8f9692017-06-08 19:17:36607 overlay_info_.is_fullscreen = false;
608
[email protected]c8d574722017-08-30 20:53:43609 // If we're in overlay mode, then exit it unless we're supposed to allow
610 // overlays all the time.
611 if (!always_enable_overlays_ && overlay_enabled_)
tsunghungee562e92016-07-20 18:03:31612 DisableOverlay();
liberato2ff93ad2017-05-17 07:28:24613
liberatofe8f9692017-06-08 19:17:36614 // See EnteredFullscreen for why we do this.
615 if (!decoder_requires_restart_for_overlay_)
616 MaybeSendOverlayInfoToDecoder();
tsunghungee562e92016-07-20 18:03:31617}
618
Chisoon Jeong81080c922019-09-03 23:40:18619void WebMediaPlayerImpl::BecameDominantVisibleContent(bool is_dominant) {
xjzcdbbe732016-12-03 20:47:42620 if (observer_)
Chisoon Jeong81080c922019-09-03 23:40:18621 observer_->OnBecameDominantVisibleContent(is_dominant);
xjzcdbbe732016-12-03 20:47:42622}
623
Blink Reformat1c4d759e2017-04-09 16:34:54624void WebMediaPlayerImpl::SetIsEffectivelyFullscreen(
François Beaufortad6c5232018-02-26 11:00:44625 blink::WebFullscreenVideoStatus fullscreen_video_status) {
626 delegate_->SetIsEffectivelyFullscreen(delegate_id_, fullscreen_video_status);
[email protected]0526d5692020-02-28 00:24:31627
628 if (power_status_helper_) {
629 // We don't care about pip, so anything that's "not fullscreen" is good
630 // enough for us.
631 power_status_helper_->SetIsFullscreen(
632 fullscreen_video_status !=
633 blink::WebFullscreenVideoStatus::kNotEffectivelyFullscreen);
634 }
zqzhangabc08242017-03-02 16:07:14635}
636
Mounir Lamouri41a79c62017-06-06 12:53:16637void WebMediaPlayerImpl::OnHasNativeControlsChanged(bool has_native_controls) {
638 if (!watch_time_reporter_)
639 return;
640
641 if (has_native_controls)
642 watch_time_reporter_->OnNativeControlsEnabled();
643 else
644 watch_time_reporter_->OnNativeControlsDisabled();
645}
646
Mounir Lamourif9af74e72017-06-19 19:31:45647void WebMediaPlayerImpl::OnDisplayTypeChanged(
648 WebMediaPlayer::DisplayType display_type) {
Mounir Lamouri0484f40a2018-07-25 03:03:26649 if (surface_layer_for_video_enabled_) {
650 vfc_task_runner_->PostTask(
651 FROM_HERE,
652 base::BindOnce(
653 &VideoFrameCompositor::SetForceSubmit,
654 base::Unretained(compositor_.get()),
655 display_type == WebMediaPlayer::DisplayType::kPictureInPicture));
656 }
657
Mounir Lamourif9af74e72017-06-19 19:31:45658 if (!watch_time_reporter_)
659 return;
660
661 switch (display_type) {
662 case WebMediaPlayer::DisplayType::kInline:
663 watch_time_reporter_->OnDisplayTypeInline();
664 break;
665 case WebMediaPlayer::DisplayType::kFullscreen:
666 watch_time_reporter_->OnDisplayTypeFullscreen();
667 break;
668 case WebMediaPlayer::DisplayType::kPictureInPicture:
669 watch_time_reporter_->OnDisplayTypePictureInPicture();
François Beaufort3f62f382019-01-18 15:05:17670
671 // Resumes playback if it was paused when hidden.
672 if (paused_when_hidden_) {
673 paused_when_hidden_ = false;
674 OnPlay();
675 }
Mounir Lamourif9af74e72017-06-19 19:31:45676 break;
677 }
678}
679
[email protected]ef8394c2013-08-21 20:26:30680void WebMediaPlayerImpl::DoLoad(LoadType load_type,
[email protected]180ef242013-11-07 06:50:46681 const blink::WebURL& url,
Takashi Toyoshima2e01e692018-11-16 03:23:27682 CorsMode cors_mode) {
John Chen5b164a02017-11-01 00:36:09683 TRACE_EVENT1("media", "WebMediaPlayerImpl::DoLoad", "id", media_log_->id());
pkastingf5279482016-07-27 02:18:20684 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:43685 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d726eddc2013-07-02 22:25:55686
[email protected]91fd3162019-09-05 23:51:32687 // Start a new observation. If there was one before, then we didn't play it.
688 will_play_helper_.CompleteObservationIfNeeded(learning::TargetValue(false));
689 // For now, send in an empty set of features. We should fill some in here,
690 // and / or ask blink (via |client_|) for features from the DOM.
691 learning::FeatureDictionary dict;
692 will_play_helper_.BeginObservation(dict);
693
Thomas Guilbert55b48d92019-03-25 23:16:54694#if defined(OS_ANDROID)
695 // Only allow credentials if the crossorigin attribute is unspecified
696 // (kCorsModeUnspecified) or "use-credentials" (kCorsModeUseCredentials).
697 // This value is only used by the MediaPlayerRenderer.
698 // See https://crbug.com/936566.
699 //
700 // The credentials mode also has repercussions in WouldTaintOrigin(), but we
701 // access what we need from |mb_data_source_|->cors_mode() directly, instead
702 // of storing it here.
703 allow_media_player_renderer_credentials_ = cors_mode != kCorsModeAnonymous;
704#endif // defined(OS_ANDROID)
705
Dale Curtis4841c712018-12-13 18:14:05706 // Note: |url| may be very large, take care when making copies.
707 loaded_url_ = GURL(url);
708 load_type_ = load_type;
709
710 ReportMetrics(load_type, loaded_url_, *frame_, media_log_.get());
[email protected]62e5e682013-03-07 23:53:24711
Dale Curtis4841c712018-12-13 18:14:05712 // Set subresource URL for crash reporting; will be truncated to 256 bytes.
Robert Sesekc5e91df2017-12-12 21:11:03713 static base::debug::CrashKeyString* subresource_url =
714 base::debug::AllocateCrashKeyString("subresource_url",
715 base::debug::CrashKeySize::Size256);
Dale Curtis4841c712018-12-13 18:14:05716 base::debug::SetCrashKeyString(subresource_url, loaded_url_.spec());
[email protected]ef8394c2013-08-21 20:26:30717
Blink Reformat1c4d759e2017-04-09 16:34:54718 SetNetworkState(WebMediaPlayer::kNetworkStateLoading);
719 SetReadyState(WebMediaPlayer::kReadyStateHaveNothing);
Ted Meyer0134aed2020-01-23 23:56:40720 media_log_->AddEvent<MediaLogEvent::kLoad>(url.GetString().Utf8());
Dale Curtis3899090ea2018-01-12 00:10:35721 load_start_time_ = base::TimeTicks::Now();
[email protected]d726eddc2013-07-02 22:25:55722
[email protected]91379332020-01-26 03:58:20723 // If we're adapting, then restart the smoothness experiment.
724 if (smoothness_helper_)
725 smoothness_helper_.reset();
726
Antonio Gomesf01cfbd2019-07-12 08:53:11727 media_metrics_provider_->Initialize(
728 load_type == kLoadTypeMediaSource,
729 load_type == kLoadTypeURL ? blink::GetMediaURLScheme(loaded_url_)
730 : mojom::MediaURLScheme::kUnknown);
Dale Curtis74612b72017-12-14 20:56:19731
[email protected]d726eddc2013-07-02 22:25:55732 // Media source pipelines can start immediately.
Blink Reformat1c4d759e2017-04-09 16:34:54733 if (load_type == kLoadTypeMediaSource) {
[email protected]ef8394c2013-08-21 20:26:30734 StartPipeline();
hubbe5f0ad43b2015-12-14 20:57:26735 } else {
Dale Curtis4841c712018-12-13 18:14:05736 // Short circuit the more complex loading path for data:// URLs. Sending
737 // them through the network based loading path just wastes memory and causes
738 // worse performance since reads become asynchronous.
739 if (loaded_url_.SchemeIs(url::kDataScheme)) {
740 std::string mime_type, charset, data;
Dale Curtis44eacb72019-06-10 20:41:28741 if (!net::DataURL::Parse(loaded_url_, &mime_type, &charset, &data) ||
742 data.empty()) {
Dale Curtis4841c712018-12-13 18:14:05743 DataSourceInitialized(false);
744 return;
745 }
746
747 // Replace |loaded_url_| with an empty data:// URL since it may be large.
748 loaded_url_ = GURL("data:,");
749
750 // Mark all the data as buffered.
Antonio Gomes81b56552019-05-15 22:15:28751 buffered_data_source_host_->SetTotalBytes(data.size());
752 buffered_data_source_host_->AddBufferedByteRange(0, data.size());
Dale Curtis4841c712018-12-13 18:14:05753
754 DCHECK(!mb_data_source_);
Jose Lopes9023b6d2020-02-19 20:42:37755 data_source_ = std::make_unique<MemoryDataSource>(std::move(data));
Dale Curtis4841c712018-12-13 18:14:05756 DataSourceInitialized(true);
757 return;
758 }
759
John Delaneyb933391602018-10-17 21:50:47760 auto url_data =
Takashi Toyoshima2e01e692018-11-16 03:23:27761 url_index_->GetByUrl(url, static_cast<UrlData::CorsMode>(cors_mode));
Dale Curtis4841c712018-12-13 18:14:05762 mb_data_source_ = new MultibufferDataSource(
John Delaneyb933391602018-10-17 21:50:47763 main_task_runner_, std::move(url_data), media_log_.get(),
Antonio Gomes81b56552019-05-15 22:15:28764 buffered_data_source_host_.get(),
Dale Curtis4841c712018-12-13 18:14:05765 base::BindRepeating(&WebMediaPlayerImpl::NotifyDownloading,
Antonio Gomes142f32a2019-05-15 23:32:56766 weak_this_));
Dale Curtis4841c712018-12-13 18:14:05767 data_source_.reset(mb_data_source_);
768 mb_data_source_->SetPreload(preload_);
769 mb_data_source_->SetIsClientAudioElement(client_->IsAudioElement());
770 mb_data_source_->Initialize(
Jose Lopes6c523d42020-02-13 19:52:21771 base::BindOnce(&WebMediaPlayerImpl::DataSourceInitialized, weak_this_));
hubbe5f0ad43b2015-12-14 20:57:26772 }
[email protected]62e5e682013-03-07 23:53:24773}
774
Blink Reformat1c4d759e2017-04-09 16:34:54775void WebMediaPlayerImpl::Play() {
pkastingf5279482016-07-27 02:18:20776 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:43777 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53778
avayvod65fad272017-02-24 01:00:48779 // User initiated play unlocks background video playback.
Mustaq Ahmed4baa9a6e82019-12-20 23:43:46780 if (frame_->HasTransientUserActivation())
avayvod65fad272017-02-24 01:00:48781 video_locked_when_paused_when_hidden_ = false;
782
sandersd35d2c3f2017-01-14 02:04:42783 // TODO(sandersd): Do we want to reset the idle timer here?
tguilbert1bb1c782017-01-23 21:15:11784 delegate_->SetIdle(delegate_id_, false);
[email protected]49480902009-07-14 20:23:43785 paused_ = false;
Antonio Gomes81b56552019-05-15 22:15:28786 pipeline_controller_->SetPlaybackRate(playback_rate_);
dalecurtis4619cd02016-09-22 21:39:10787 background_pause_timer_.Stop();
sandersd1c0bba02016-03-04 23:14:08788
xjz48a9cb72016-12-20 04:02:49789 if (observer_)
790 observer_->OnPlaying();
791
[email protected]96665a82020-01-23 00:35:37792 // Try to create the smoothness helper, in case we were paused before.
793 UpdateSmoothnessHelper();
794
Mounir Lamouri89c0a1b2018-03-01 15:00:44795 watch_time_reporter_->SetAutoplayInitiated(client_->WasAutoplayInitiated());
796
Dale Curtis051fdf62017-08-05 00:21:13797 // If we're seeking we'll trigger the watch time reporter upon seek completed;
798 // we don't want to start it here since the seek time is unstable. E.g., when
799 // playing content with a positive start time we would have a zero seek time.
800 if (!Seeking()) {
801 DCHECK(watch_time_reporter_);
802 watch_time_reporter_->OnPlaying();
803 }
804
Chris Cunninghamd9df58e2017-08-29 00:04:23805 if (video_decode_stats_reporter_)
806 video_decode_stats_reporter_->OnPlaying();
807
Dan Sanders6edfd782019-08-13 00:13:18808 simple_watch_timer_.Start();
Ted Meyerd5885f82019-07-16 19:19:17809 media_metrics_provider_->SetHasPlayed();
Ted Meyer0134aed2020-01-23 23:56:40810 media_log_->AddEvent<MediaLogEvent::kPlay>();
Dale Curtis18ad391b2019-05-30 23:25:09811
812 MaybeUpdateBufferSizesForPlayback();
sandersd50a635e2016-04-04 22:50:09813 UpdatePlayState();
[email protected]91fd3162019-09-05 23:51:32814
815 // Notify the learning task, if needed.
816 will_play_helper_.CompleteObservationIfNeeded(learning::TargetValue(true));
[email protected]ec9212f2008-12-18 21:40:36817}
818
Blink Reformat1c4d759e2017-04-09 16:34:54819void WebMediaPlayerImpl::Pause() {
pkastingf5279482016-07-27 02:18:20820 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:43821 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53822
sandersd50a635e2016-04-04 22:50:09823 // We update the paused state even when casting, since we expect pause() to be
824 // called when casting begins, and when we exit casting we should end up in a
825 // paused state.
[email protected]49480902009-07-14 20:23:43826 paused_ = true;
hubbed5f36882016-01-15 22:40:37827
avayvodeb9098d2017-01-07 00:33:03828 // No longer paused because it was hidden.
829 paused_when_hidden_ = false;
830
[email protected]96665a82020-01-23 00:35:37831 UpdateSmoothnessHelper();
832
avayvod65fad272017-02-24 01:00:48833 // User initiated pause locks background videos.
Mustaq Ahmed4baa9a6e82019-12-20 23:43:46834 if (frame_->HasTransientUserActivation())
avayvod65fad272017-02-24 01:00:48835 video_locked_when_paused_when_hidden_ = true;
836
Antonio Gomes81b56552019-05-15 22:15:28837 pipeline_controller_->SetPlaybackRate(0.0);
Dale Curtis2fc01cc2019-05-20 22:53:52838
839 // For states <= kReadyStateHaveMetadata, we may not have a renderer yet.
840 if (highest_ready_state_ > WebMediaPlayer::kReadyStateHaveMetadata)
841 paused_time_ = pipeline_controller_->GetMediaTime();
[email protected]090f7312011-08-05 23:26:40842
xjz48a9cb72016-12-20 04:02:49843 if (observer_)
844 observer_->OnPaused();
845
dalecurtis04bdb582016-08-17 22:15:23846 DCHECK(watch_time_reporter_);
847 watch_time_reporter_->OnPaused();
Chris Cunninghamd9df58e2017-08-29 00:04:23848
849 if (video_decode_stats_reporter_)
850 video_decode_stats_reporter_->OnPaused();
851
Dan Sanders6edfd782019-08-13 00:13:18852 simple_watch_timer_.Stop();
Ted Meyer0134aed2020-01-23 23:56:40853 media_log_->AddEvent<MediaLogEvent::kPause>();
avayvod2135a642017-01-13 00:17:14854
Becca Hughes7a85bf22019-07-24 16:16:58855 // Paused changed so we should update media position state.
856 UpdateMediaPositionState();
857
sandersd50a635e2016-04-04 22:50:09858 UpdatePlayState();
[email protected]ec9212f2008-12-18 21:40:36859}
860
Blink Reformat1c4d759e2017-04-09 16:34:54861void WebMediaPlayerImpl::Seek(double seconds) {
pkastingf5279482016-07-27 02:18:20862 DVLOG(1) << __func__ << "(" << seconds << "s)";
acolwellb4034942014-08-28 15:42:43863 DCHECK(main_task_runner_->BelongsToCurrentThread());
Ted Meyer0134aed2020-01-23 23:56:40864 media_log_->AddEvent<MediaLogEvent::kSeek>(seconds);
sandersd1c0bba02016-03-04 23:14:08865 DoSeek(base::TimeDelta::FromSecondsD(seconds), true);
866}
867
868void WebMediaPlayerImpl::DoSeek(base::TimeDelta time, bool time_updated) {
869 DCHECK(main_task_runner_->BelongsToCurrentThread());
John Chen5b164a02017-11-01 00:36:09870 TRACE_EVENT2("media", "WebMediaPlayerImpl::DoSeek", "target",
871 time.InSecondsF(), "id", media_log_->id());
[email protected]d43ed912009-02-03 04:52:53872
srirama.mccf671812015-01-08 11:59:13873 ReadyState old_state = ready_state_;
Blink Reformat1c4d759e2017-04-09 16:34:54874 if (ready_state_ > WebMediaPlayer::kReadyStateHaveMetadata)
875 SetReadyState(WebMediaPlayer::kReadyStateHaveMetadata);
[email protected]1bb666802013-11-28 06:12:08876
Dale Curtis051fdf62017-08-05 00:21:13877 // When paused or ended, we know exactly what the current time is and can
878 // elide seeks to it. However, there are two cases that are not elided:
sandersd1c0bba02016-03-04 23:14:08879 // 1) When the pipeline state is not stable.
880 // In this case we just let |pipeline_controller_| decide what to do, as
881 // it has complete information.
882 // 2) For MSE.
883 // Because the buffers may have changed between seeks, MSE seeks are
884 // never elided.
Antonio Gomes81b56552019-05-15 22:15:28885 if (paused_ && pipeline_controller_->IsStable() &&
Dale Curtis051fdf62017-08-05 00:21:13886 (paused_time_ == time ||
887 (ended_ && time == base::TimeDelta::FromSecondsD(Duration()))) &&
sandersd1c0bba02016-03-04 23:14:08888 !chunk_demuxer_) {
889 // If the ready state was high enough before, we can indicate that the seek
890 // completed just by restoring it. Otherwise we will just wait for the real
891 // ready state change to eventually happen.
Blink Reformat1c4d759e2017-04-09 16:34:54892 if (old_state == kReadyStateHaveEnoughData) {
srirama.m8f4a37562014-12-13 08:16:18893 main_task_runner_->PostTask(
Dale Curtisee9be30012018-09-21 22:21:51894 FROM_HERE, base::BindOnce(&WebMediaPlayerImpl::OnBufferingStateChange,
Chris Cunninghamfc0d67e2019-07-22 20:29:16895 weak_this_, BUFFERING_HAVE_ENOUGH,
896 BUFFERING_CHANGE_REASON_UNKNOWN));
srirama.m36ab2682014-12-11 04:20:01897 }
sandersd1c0bba02016-03-04 23:14:08898 return;
srirama.m36ab2682014-12-11 04:20:01899 }
[email protected]44ff37c02009-10-24 01:03:03900
dalecurtis04bdb582016-08-17 22:15:23901 // Call this before setting |seeking_| so that the current media time can be
902 // recorded by the reporter.
903 if (watch_time_reporter_)
904 watch_time_reporter_->OnSeeking();
905
sandersd35d2c3f2017-01-14 02:04:42906 // TODO(sandersd): Move |seeking_| to PipelineController.
907 // TODO(sandersd): Do we want to reset the idle timer here?
tguilbert1bb1c782017-01-23 21:15:11908 delegate_->SetIdle(delegate_id_, false);
sandersd50a635e2016-04-04 22:50:09909 ended_ = false;
[email protected]b3766a22010-12-22 17:34:13910 seeking_ = true;
sandersd1c0bba02016-03-04 23:14:08911 seek_time_ = time;
912 if (paused_)
913 paused_time_ = time;
Antonio Gomes81b56552019-05-15 22:15:28914 pipeline_controller_->Seek(time, time_updated);
[email protected]b3766a22010-12-22 17:34:13915
sandersd50a635e2016-04-04 22:50:09916 // This needs to be called after Seek() so that if a resume is triggered, it
917 // is to the correct time.
918 UpdatePlayState();
Becca Hughes7a85bf22019-07-24 16:16:58919
920 // The seek time has changed so we should update the media position state.
921 UpdateMediaPositionState();
[email protected]ec9212f2008-12-18 21:40:36922}
923
Blink Reformat1c4d759e2017-04-09 16:34:54924void WebMediaPlayerImpl::SetRate(double rate) {
pkastingf5279482016-07-27 02:18:20925 DVLOG(1) << __func__ << "(" << rate << ")";
acolwellb4034942014-08-28 15:42:43926 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53927
Matt Wolenetz6010f6c2017-10-18 00:44:36928 if (rate != playback_rate_) {
929 LIMITED_MEDIA_LOG(INFO, media_log_.get(), num_playback_rate_logs_,
930 kMaxNumPlaybackRateLogs)
931 << "Effective playback rate changed from " << playback_rate_ << " to "
932 << rate;
933 }
934
[email protected]49480902009-07-14 20:23:43935 playback_rate_ = rate;
Dale Curtis18ad391b2019-05-30 23:25:09936 if (!paused_)
Antonio Gomes81b56552019-05-15 22:15:28937 pipeline_controller_->SetPlaybackRate(rate);
Dale Curtis18ad391b2019-05-30 23:25:09938
939 MaybeUpdateBufferSizesForPlayback();
[email protected]ec9212f2008-12-18 21:40:36940}
941
Blink Reformat1c4d759e2017-04-09 16:34:54942void WebMediaPlayerImpl::SetVolume(double volume) {
pkastingf5279482016-07-27 02:18:20943 DVLOG(1) << __func__ << "(" << volume << ")";
acolwellb4034942014-08-28 15:42:43944 DCHECK(main_task_runner_->BelongsToCurrentThread());
dalecurtisbb3eaac2016-01-27 21:10:25945 volume_ = volume;
Antonio Gomes81b56552019-05-15 22:15:28946 pipeline_controller_->SetVolume(volume_ * volume_multiplier_);
dalecurtis04bdb582016-08-17 22:15:23947 if (watch_time_reporter_)
948 watch_time_reporter_->OnVolumeChange(volume);
Becca Hughes9f6fd4b82017-06-15 10:01:40949 delegate_->DidPlayerMutedStatusChange(delegate_id_, volume == 0.0);
mlamouri910111362016-11-04 11:28:24950
951 // The play state is updated because the player might have left the autoplay
952 // muted state.
953 UpdatePlayState();
[email protected]ec9212f2008-12-18 21:40:36954}
[email protected]f0a51fb52009-03-05 12:46:38955
Chris Cunningham8c2ef912019-11-15 23:10:41956void WebMediaPlayerImpl::SetLatencyHint(double seconds) {
957 DVLOG(1) << __func__ << "(" << seconds << ")";
Chris Cunninghame8c626332019-11-20 23:34:27958 DCHECK(main_task_runner_->BelongsToCurrentThread());
959 base::Optional<base::TimeDelta> latency_hint;
960 if (std::isfinite(seconds)) {
961 DCHECK_GE(seconds, 0);
962 latency_hint = base::TimeDelta::FromSecondsD(seconds);
963 }
964 pipeline_controller_->SetLatencyHint(latency_hint);
Chris Cunningham8c2ef912019-11-15 23:10:41965}
966
Mounir Lamouri967f8fb72019-02-13 02:34:22967void WebMediaPlayerImpl::OnRequestPictureInPicture() {
[email protected]69db58f2018-09-26 20:27:56968 if (!surface_layer_for_video_enabled_)
969 ActivateSurfaceLayerForVideo();
970
Mounir Lamourib642a3c2018-07-09 15:45:31971 DCHECK(bridge_);
Mounir Lamouri99ba5a62019-02-12 01:27:47972 DCHECK(bridge_->GetSurfaceId().is_valid());
Jennifer Apacible3f0489102018-01-19 20:10:31973}
974
Daniel Chengc1710b52018-10-24 03:12:28975void WebMediaPlayerImpl::SetSinkId(
976 const blink::WebString& sink_id,
Antonio Gomese7813f32019-04-02 06:11:03977 blink::WebSetSinkIdCompleteCallback completion_callback) {
guidou69223ce2015-06-16 10:36:19978 DCHECK(main_task_runner_->BelongsToCurrentThread());
pkastingf5279482016-07-27 02:18:20979 DVLOG(1) << __func__;
guidouc7babef2015-10-22 00:42:35980
Dale Curtisca1b78f2019-01-15 03:11:26981 OutputDeviceStatusCB callback =
Antonio Gomese7813f32019-04-02 06:11:03982 ConvertToOutputDeviceStatusCB(std::move(completion_callback));
guidouc7babef2015-10-22 00:42:35983 media_task_runner_->PostTask(
Dale Curtisee9be30012018-09-21 22:21:51984 FROM_HERE, base::BindOnce(&SetSinkIdOnMediaThread, audio_source_provider_,
Daniel Chengc1710b52018-10-24 03:12:28985 sink_id.Utf8(), std::move(callback)));
guidou69223ce2015-06-16 10:36:19986}
987
Blink Reformat1c4d759e2017-04-09 16:34:54988STATIC_ASSERT_ENUM(WebMediaPlayer::kPreloadNone, MultibufferDataSource::NONE);
989STATIC_ASSERT_ENUM(WebMediaPlayer::kPreloadMetaData,
dalecurtisb6e052f52016-08-25 00:35:55990 MultibufferDataSource::METADATA);
Blink Reformat1c4d759e2017-04-09 16:34:54991STATIC_ASSERT_ENUM(WebMediaPlayer::kPreloadAuto, MultibufferDataSource::AUTO);
[email protected]23a8b1d82011-04-05 16:28:20992
Blink Reformat1c4d759e2017-04-09 16:34:54993void WebMediaPlayerImpl::SetPreload(WebMediaPlayer::Preload preload) {
pkastingf5279482016-07-27 02:18:20994 DVLOG(1) << __func__ << "(" << preload << ")";
acolwellb4034942014-08-28 15:42:43995 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]4e6be3f2009-05-07 02:24:44996
dalecurtisb6e052f52016-08-25 00:35:55997 preload_ = static_cast<MultibufferDataSource::Preload>(preload);
Dale Curtis4841c712018-12-13 18:14:05998 if (mb_data_source_)
999 mb_data_source_->SetPreload(preload_);
[email protected]4e6be3f2009-05-07 02:24:441000}
1001
Blink Reformat1c4d759e2017-04-09 16:34:541002bool WebMediaPlayerImpl::HasVideo() const {
acolwellb4034942014-08-28 15:42:431003 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:531004
[email protected]b8877772014-03-26 20:17:151005 return pipeline_metadata_.has_video;
[email protected]d43ed912009-02-03 04:52:531006}
1007
Blink Reformat1c4d759e2017-04-09 16:34:541008bool WebMediaPlayerImpl::HasAudio() const {
acolwellb4034942014-08-28 15:42:431009 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]fc367af2009-08-14 23:06:351010
[email protected]b8877772014-03-26 20:17:151011 return pipeline_metadata_.has_audio;
[email protected]fc367af2009-08-14 23:06:351012}
1013
Blink Reformat1c4d759e2017-04-09 16:34:541014void WebMediaPlayerImpl::EnabledAudioTracksChanged(
servolkf25ceed2016-07-01 03:44:381015 const blink::WebVector<blink::WebMediaPlayer::TrackId>& enabledTrackIds) {
1016 DCHECK(main_task_runner_->BelongsToCurrentThread());
1017
1018 std::ostringstream logstr;
1019 std::vector<MediaTrack::Id> enabledMediaTrackIds;
1020 for (const auto& blinkTrackId : enabledTrackIds) {
Maciej Pawlowskif2556d122019-06-03 08:14:181021 const auto track_id = MediaTrack::Id(blinkTrackId.Utf8().data());
servolkf25ceed2016-07-01 03:44:381022 logstr << track_id << " ";
1023 enabledMediaTrackIds.push_back(track_id);
1024 }
dalecurtis9cddc0b2017-04-19 21:23:381025 MEDIA_LOG(INFO, media_log_.get())
1026 << "Enabled audio tracks: [" << logstr.str() << "]";
Antonio Gomes81b56552019-05-15 22:15:281027 pipeline_controller_->OnEnabledAudioTracksChanged(enabledMediaTrackIds);
servolkf25ceed2016-07-01 03:44:381028}
1029
Blink Reformat1c4d759e2017-04-09 16:34:541030void WebMediaPlayerImpl::SelectedVideoTrackChanged(
servolkf25ceed2016-07-01 03:44:381031 blink::WebMediaPlayer::TrackId* selectedTrackId) {
1032 DCHECK(main_task_runner_->BelongsToCurrentThread());
1033
servolk9bed6602017-02-24 01:20:111034 base::Optional<MediaTrack::Id> selected_video_track_id;
1035 if (selectedTrackId && !video_track_disabled_)
Blink Reformat1c4d759e2017-04-09 16:34:541036 selected_video_track_id = MediaTrack::Id(selectedTrackId->Utf8().data());
dalecurtis9cddc0b2017-04-19 21:23:381037 MEDIA_LOG(INFO, media_log_.get())
Maciej Pawlowskif2556d122019-06-03 08:14:181038 << "Selected video track: ["
1039 << selected_video_track_id.value_or(MediaTrack::Id()) << "]";
Antonio Gomes81b56552019-05-15 22:15:281040 pipeline_controller_->OnSelectedVideoTrackChanged(selected_video_track_id);
servolkf25ceed2016-07-01 03:44:381041}
1042
Dave Tapuskaec1a6d42020-02-12 20:57:481043gfx::Size WebMediaPlayerImpl::NaturalSize() const {
acolwellb4034942014-08-28 15:42:431044 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:531045
Dave Tapuskaec1a6d42020-02-12 20:57:481046 return pipeline_metadata_.natural_size;
[email protected]d43ed912009-02-03 04:52:531047}
1048
Dave Tapuskaec1a6d42020-02-12 20:57:481049gfx::Size WebMediaPlayerImpl::VisibleSize() const {
Jiajia Qin82acdc02017-07-31 09:55:141050 DCHECK(main_task_runner_->BelongsToCurrentThread());
1051 scoped_refptr<VideoFrame> video_frame = GetCurrentFrameFromCompositor();
1052 if (!video_frame)
Dave Tapuskaec1a6d42020-02-12 20:57:481053 return gfx::Size();
Jiajia Qin82acdc02017-07-31 09:55:141054
Dave Tapuskaec1a6d42020-02-12 20:57:481055 return video_frame->visible_rect().size();
Jiajia Qin82acdc02017-07-31 09:55:141056}
1057
Blink Reformat1c4d759e2017-04-09 16:34:541058bool WebMediaPlayerImpl::Paused() const {
acolwellb4034942014-08-28 15:42:431059 DCHECK(main_task_runner_->BelongsToCurrentThread());
Antonio Gomes81b56552019-05-15 22:15:281060 return pipeline_controller_->GetPlaybackRate() == 0.0f;
[email protected]d43ed912009-02-03 04:52:531061}
1062
François Beaufort184f6042019-01-25 05:50:051063bool WebMediaPlayerImpl::PausedWhenHidden() const {
1064 return paused_when_hidden_;
1065}
1066
Blink Reformat1c4d759e2017-04-09 16:34:541067bool WebMediaPlayerImpl::Seeking() const {
acolwellb4034942014-08-28 15:42:431068 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:531069
Blink Reformat1c4d759e2017-04-09 16:34:541070 if (ready_state_ == WebMediaPlayer::kReadyStateHaveNothing)
[email protected]0acebfa2009-08-21 22:45:401071 return false;
[email protected]67cd5052009-09-10 21:53:221072
[email protected]b3766a22010-12-22 17:34:131073 return seeking_;
[email protected]ec9212f2008-12-18 21:40:361074}
1075
Blink Reformat1c4d759e2017-04-09 16:34:541076double WebMediaPlayerImpl::Duration() const {
acolwellb4034942014-08-28 15:42:431077 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]39bdde32013-04-17 17:44:201078
Blink Reformat1c4d759e2017-04-09 16:34:541079 if (ready_state_ == WebMediaPlayer::kReadyStateHaveNothing)
[email protected]39bdde32013-04-17 17:44:201080 return std::numeric_limits<double>::quiet_NaN();
1081
chcunninghamb92d5062017-01-10 21:50:221082 // Use duration from ChunkDemuxer when present. MSE allows users to specify
1083 // duration as a double. This propagates to the rest of the pipeline as a
1084 // TimeDelta with potentially reduced precision (limited to Microseconds).
1085 // ChunkDemuxer returns the full-precision user-specified double. This ensures
1086 // users can "get" the exact duration they "set".
1087 if (chunk_demuxer_)
1088 return chunk_demuxer_->GetDuration();
1089
avayvodcc273dd2017-01-19 19:35:121090 base::TimeDelta pipeline_duration = GetPipelineMediaDuration();
chcunninghamb92d5062017-01-10 21:50:221091 return pipeline_duration == kInfiniteDuration
1092 ? std::numeric_limits<double>::infinity()
1093 : pipeline_duration.InSecondsF();
[email protected]d43ed912009-02-03 04:52:531094}
1095
[email protected]db66d0092014-04-16 07:15:121096double WebMediaPlayerImpl::timelineOffset() const {
acolwellb4034942014-08-28 15:42:431097 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]db66d0092014-04-16 07:15:121098
1099 if (pipeline_metadata_.timeline_offset.is_null())
1100 return std::numeric_limits<double>::quiet_NaN();
1101
1102 return pipeline_metadata_.timeline_offset.ToJsTime();
1103}
1104
Dale Curtis051fdf62017-08-05 00:21:131105base::TimeDelta WebMediaPlayerImpl::GetCurrentTimeInternal() const {
1106 DCHECK(main_task_runner_->BelongsToCurrentThread());
Dale Curtis051fdf62017-08-05 00:21:131107
1108 base::TimeDelta current_time;
1109 if (Seeking())
1110 current_time = seek_time_;
Dale Curtis051fdf62017-08-05 00:21:131111 else if (paused_)
1112 current_time = paused_time_;
1113 else
Antonio Gomes81b56552019-05-15 22:15:281114 current_time = pipeline_controller_->GetMediaTime();
Dale Curtis051fdf62017-08-05 00:21:131115
Dale Curtis77d6057b2019-05-03 01:31:561116 // It's possible for |current_time| to be kInfiniteDuration here if the page
1117 // seeks to kInfiniteDuration (2**64 - 1) when Duration() is infinite.
Dale Curtis051fdf62017-08-05 00:21:131118 DCHECK_GE(current_time, base::TimeDelta());
1119 return current_time;
1120}
1121
Blink Reformat1c4d759e2017-04-09 16:34:541122double WebMediaPlayerImpl::CurrentTime() const {
acolwellb4034942014-08-28 15:42:431123 DCHECK(main_task_runner_->BelongsToCurrentThread());
Blink Reformat1c4d759e2017-04-09 16:34:541124 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
scherkusd2c745b2014-09-04 05:03:401125
Dale Curtis0da6f162020-02-01 01:02:591126 // Even though we have an explicit ended signal, a lot of content doesn't have
1127 // an accurate duration -- with some formats (e.g., VBR MP3, OGG) it can't be
1128 // known without a complete play-through from beginning to end.
1129 //
1130 // The HTML5 spec says that upon ended, current time must equal duration. Due
1131 // to the aforementioned issue, if we rely exclusively on current time, we can
1132 // be a few milliseconds off of the duration.
1133 const auto duration = Duration();
1134 return (ended_ && !std::isinf(duration))
1135 ? duration
Xida Chenccd11472020-01-31 20:02:021136 : GetCurrentTimeInternal().InSecondsF();
[email protected]d43ed912009-02-03 04:52:531137}
1138
Dale Curtis0da6f162020-02-01 01:02:591139bool WebMediaPlayerImpl::IsEnded() const {
1140 DCHECK(main_task_runner_->BelongsToCurrentThread());
1141 return ended_;
1142}
1143
Blink Reformat1c4d759e2017-04-09 16:34:541144WebMediaPlayer::NetworkState WebMediaPlayerImpl::GetNetworkState() const {
acolwellb4034942014-08-28 15:42:431145 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]ddb1e5a2010-12-13 20:10:451146 return network_state_;
1147}
1148
Blink Reformat1c4d759e2017-04-09 16:34:541149WebMediaPlayer::ReadyState WebMediaPlayerImpl::GetReadyState() const {
acolwellb4034942014-08-28 15:42:431150 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]ddb1e5a2010-12-13 20:10:451151 return ready_state_;
1152}
1153
CJ DiMeglio89240472018-10-18 18:21:101154blink::WebMediaPlayer::SurfaceLayerMode
1155WebMediaPlayerImpl::GetVideoSurfaceLayerMode() const {
1156 return surface_layer_mode_;
1157}
1158
wolenetzed8e7092017-04-21 16:28:591159blink::WebString WebMediaPlayerImpl::GetErrorMessage() const {
wolenetz4d39cc02016-04-05 19:54:411160 DCHECK(main_task_runner_->BelongsToCurrentThread());
wolenetzed8e7092017-04-21 16:28:591161 return blink::WebString::FromUTF8(media_log_->GetErrorMessage());
wolenetz4d39cc02016-04-05 19:54:411162}
1163
Blink Reformat1c4d759e2017-04-09 16:34:541164blink::WebTimeRanges WebMediaPlayerImpl::Buffered() const {
acolwellb4034942014-08-28 15:42:431165 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]779a8322014-08-22 21:28:371166
acolwell9e0840d2014-09-06 19:01:321167 Ranges<base::TimeDelta> buffered_time_ranges =
Antonio Gomes81b56552019-05-15 22:15:281168 pipeline_controller_->GetBufferedTimeRanges();
[email protected]779a8322014-08-22 21:28:371169
avayvodcc273dd2017-01-19 19:35:121170 const base::TimeDelta duration = GetPipelineMediaDuration();
dalecurtis39a7f932016-07-19 18:34:591171 if (duration != kInfiniteDuration) {
Antonio Gomes81b56552019-05-15 22:15:281172 buffered_data_source_host_->AddBufferedTimeRanges(&buffered_time_ranges,
1173 duration);
[email protected]779a8322014-08-22 21:28:371174 }
Antonio Gomesf01cfbd2019-07-12 08:53:111175 return blink::ConvertToWebTimeRanges(buffered_time_ranges);
[email protected]02022fc2014-05-16 00:05:311176}
1177
Blink Reformat1c4d759e2017-04-09 16:34:541178blink::WebTimeRanges WebMediaPlayerImpl::Seekable() const {
acolwellb4034942014-08-28 15:42:431179 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]39bdde32013-04-17 17:44:201180
Blink Reformat1c4d759e2017-04-09 16:34:541181 if (ready_state_ < WebMediaPlayer::kReadyStateHaveMetadata)
philipjb0e6f3f2014-09-30 09:51:531182 return blink::WebTimeRanges();
1183
Blink Reformat1c4d759e2017-04-09 16:34:541184 const double seekable_end = Duration();
dalecurtis56359cb2014-10-28 00:06:291185
1186 // Allow a special exception for seeks to zero for streaming sources with a
1187 // finite duration; this allows looping to work.
Dale Curtis4841c712018-12-13 18:14:051188 const bool is_finite_stream = mb_data_source_ &&
1189 mb_data_source_->IsStreaming() &&
tguilbertade2bcb2017-01-07 02:57:451190 std::isfinite(seekable_end);
1191
tguilbert75e2bf62017-04-26 20:13:121192 // Do not change the seekable range when using the MediaPlayerRenderer. It
1193 // will take care of dropping invalid seeks.
1194 const bool force_seeks_to_zero =
1195 !using_media_player_renderer_ && is_finite_stream;
dalecurtis56359cb2014-10-28 00:06:291196
1197 // TODO(dalecurtis): Technically this allows seeking on media which return an
tguilbertade2bcb2017-01-07 02:57:451198 // infinite duration so long as DataSource::IsStreaming() is false. While not
dalecurtis56359cb2014-10-28 00:06:291199 // expected, disabling this breaks semi-live players, http://crbug.com/427412.
1200 const blink::WebTimeRange seekable_range(
tguilbertade2bcb2017-01-07 02:57:451201 0.0, force_seeks_to_zero ? 0.0 : seekable_end);
philipjb0e6f3f2014-09-30 09:51:531202 return blink::WebTimeRanges(&seekable_range, 1);
[email protected]ec9212f2008-12-18 21:40:361203}
1204
sandersd35d2c3f2017-01-14 02:04:421205bool WebMediaPlayerImpl::IsPrerollAttemptNeeded() {
1206 // TODO(sandersd): Replace with |highest_ready_state_since_seek_| if we need
1207 // to ensure that preroll always gets a chance to complete.
1208 // See http://crbug.com/671525.
Dale Curtis69e8f302019-05-22 07:36:581209 //
1210 // Note: Even though we get play/pause signals at kReadyStateHaveMetadata, we
1211 // must attempt to preroll until kReadyStateHaveFutureData so that the
1212 // canplaythrough event will be fired to the page (which may be waiting).
1213 //
1214 // TODO(dalecurtis): We should try signaling kReadyStateHaveFutureData upon
1215 // automatic-suspend of a non-playing element to avoid wasting resources.
1216 if (highest_ready_state_ >= ReadyState::kReadyStateHaveFutureData)
sandersd35d2c3f2017-01-14 02:04:421217 return false;
1218
Fredrik Hubinette4cfb4412017-08-23 00:03:071219 // To suspend before we reach kReadyStateHaveCurrentData is only ok
1220 // if we know we're going to get woken up when we get more data, which
1221 // will only happen if the network is in the "Loading" state.
1222 // This happens when the network is fast, but multiple videos are loading
1223 // and multiplexing gets held up waiting for available threads.
1224 if (highest_ready_state_ <= ReadyState::kReadyStateHaveMetadata &&
1225 network_state_ != WebMediaPlayer::kNetworkStateLoading) {
1226 return true;
1227 }
1228
sandersd35d2c3f2017-01-14 02:04:421229 if (preroll_attempt_pending_)
1230 return true;
1231
1232 // Freshly initialized; there has never been any loading progress. (Otherwise
1233 // |preroll_attempt_pending_| would be true when the start time is null.)
1234 if (preroll_attempt_start_time_.is_null())
1235 return false;
1236
1237 base::TimeDelta preroll_attempt_duration =
1238 tick_clock_->NowTicks() - preroll_attempt_start_time_;
1239 return preroll_attempt_duration < kPrerollAttemptTimeout;
1240}
1241
Blink Reformat1c4d759e2017-04-09 16:34:541242bool WebMediaPlayerImpl::DidLoadingProgress() {
acolwellb4034942014-08-28 15:42:431243 DCHECK(main_task_runner_->BelongsToCurrentThread());
dalecurtise7120dc2016-09-03 02:54:351244
1245 // Note: Separate variables used to ensure both methods are called every time.
Antonio Gomes81b56552019-05-15 22:15:281246 const bool pipeline_progress = pipeline_controller_->DidLoadingProgress();
1247 const bool data_progress = buffered_data_source_host_->DidLoadingProgress();
hubbeb2d3efd2017-05-05 23:26:381248 return pipeline_progress || data_progress;
[email protected]d43ed912009-02-03 04:52:531249}
1250
danakjff6a0262018-06-26 19:50:311251void WebMediaPlayerImpl::Paint(cc::PaintCanvas* canvas,
[email protected]dd5c7972014-08-21 15:00:371252 const blink::WebRect& rect,
Kai Ninomiya9e8ae29b2017-09-06 23:45:161253 cc::PaintFlags& flags,
1254 int already_uploaded_id,
1255 VideoFrameUploadMetadata* out_metadata) {
acolwellb4034942014-08-28 15:42:431256 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]dd061e12014-05-06 19:21:221257 TRACE_EVENT0("media", "WebMediaPlayerImpl:paint");
[email protected]4e6be3f2009-05-07 02:24:441258
watkd16bb3e2017-04-25 01:18:311259 // We can't copy from protected frames.
Xiaohan Wang24cfe2c2018-01-22 23:16:001260 if (cdm_context_ref_)
xhwang80739452016-01-13 00:48:001261 return;
1262
mcasasf1236fc22015-05-29 22:38:561263 scoped_refptr<VideoFrame> video_frame = GetCurrentFrameFromCompositor();
[email protected]0fe5d43b2014-01-24 23:32:451264
[email protected]b49beeb2013-03-01 20:04:001265 gfx::Rect gfx_rect(rect);
mcasas265bdbf82015-06-12 18:44:071266 if (video_frame.get() && video_frame->HasTextures()) {
Antoine Labourfee4ae52019-04-24 23:53:571267 if (!context_provider_)
danakj53f7ec902016-05-21 01:30:101268 return; // Unable to get/create a shared main thread context.
Antoine Labourfee4ae52019-04-24 23:53:571269 if (!context_provider_->GrContext())
danakj53f7ec902016-05-21 01:30:101270 return; // The context has been lost since and can't setup a GrContext.
dongseong.hwang0c4e9d82015-01-08 20:11:131271 }
Kai Ninomiyaef8c9e02017-09-27 04:07:401272 if (out_metadata && video_frame) {
Kai Ninomiya9e8ae29b2017-09-06 23:45:161273 // WebGL last-uploaded-frame-metadata API enabled. https://crbug.com/639174
1274 ComputeFrameUploadMetadata(video_frame.get(), already_uploaded_id,
1275 out_metadata);
1276 if (out_metadata->skipped) {
1277 // Skip uploading this frame.
1278 return;
1279 }
1280 }
zhuoyu.qian4689dde22017-10-16 04:11:481281 video_renderer_.Paint(
Julien Isorce6c83d8de2017-10-12 13:11:291282 video_frame, canvas, gfx::RectF(gfx_rect), flags,
Ted Meyer4a427632019-05-01 19:05:271283 pipeline_metadata_.video_decoder_config.video_transformation(),
Antoine Labourfee4ae52019-04-24 23:53:571284 context_provider_.get());
[email protected]ec9212f2008-12-18 21:40:361285}
[email protected]5df51652009-01-17 00:03:001286
Yutaka Hirano657a0552018-11-09 00:52:551287bool WebMediaPlayerImpl::WouldTaintOrigin() const {
Thomas Guilbert153f84572018-07-19 05:03:581288 if (demuxer_found_hls_) {
1289 // HLS manifests might pull segments from a different origin. We can't know
1290 // for sure, so we conservatively say no here.
Yutaka Hiranoa9cbaa72018-10-10 08:35:221291 return true;
1292 }
1293
Dale Curtis4841c712018-12-13 18:14:051294 if (!mb_data_source_)
Yutaka Hirano657a0552018-11-09 00:52:551295 return false;
1296
1297 // When the resource is redirected to another origin we think it as
1298 // tainted. This is actually not specified, and is under discussion.
1299 // See https://github.com/whatwg/fetch/issues/737.
Dale Curtis4841c712018-12-13 18:14:051300 if (!mb_data_source_->HasSingleOrigin() &&
1301 mb_data_source_->cors_mode() == UrlData::CORS_UNSPECIFIED) {
Yutaka Hirano657a0552018-11-09 00:52:551302 return true;
1303 }
1304
Dale Curtis4841c712018-12-13 18:14:051305 return mb_data_source_->IsCorsCrossOrigin();
[email protected]3fe27112012-06-07 04:00:011306}
1307
Blink Reformat1c4d759e2017-04-09 16:34:541308double WebMediaPlayerImpl::MediaTimeForTimeValue(double timeValue) const {
qinminb4c39782015-08-10 18:43:241309 return base::TimeDelta::FromSecondsD(timeValue).InSecondsF();
[email protected]e06e16d82011-05-26 22:13:331310}
1311
Blink Reformat1c4d759e2017-04-09 16:34:541312unsigned WebMediaPlayerImpl::DecodedFrameCount() const {
acolwellb4034942014-08-28 15:42:431313 DCHECK(main_task_runner_->BelongsToCurrentThread());
Dale Curtisc7d2a7d22018-01-11 20:01:051314 return GetPipelineStatistics().video_frames_decoded;
[email protected]4c51bc662011-02-16 02:03:161315}
1316
Blink Reformat1c4d759e2017-04-09 16:34:541317unsigned WebMediaPlayerImpl::DroppedFrameCount() const {
acolwellb4034942014-08-28 15:42:431318 DCHECK(main_task_runner_->BelongsToCurrentThread());
Dale Curtisc7d2a7d22018-01-11 20:01:051319 return GetPipelineStatistics().video_frames_dropped;
[email protected]4c51bc662011-02-16 02:03:161320}
1321
Dave Tapuska6c7154912018-07-30 20:39:001322uint64_t WebMediaPlayerImpl::AudioDecodedByteCount() const {
acolwellb4034942014-08-28 15:42:431323 DCHECK(main_task_runner_->BelongsToCurrentThread());
Dale Curtisc7d2a7d22018-01-11 20:01:051324 return GetPipelineStatistics().audio_bytes_decoded;
[email protected]4c51bc662011-02-16 02:03:161325}
1326
Dave Tapuska6c7154912018-07-30 20:39:001327uint64_t WebMediaPlayerImpl::VideoDecodedByteCount() const {
acolwellb4034942014-08-28 15:42:431328 DCHECK(main_task_runner_->BelongsToCurrentThread());
Dale Curtisc7d2a7d22018-01-11 20:01:051329 return GetPipelineStatistics().video_bytes_decoded;
[email protected]4c51bc662011-02-16 02:03:161330}
1331
Dale Curtiscdfc6f22019-06-26 22:05:231332bool WebMediaPlayerImpl::HasAvailableVideoFrame() const {
1333 return has_first_frame_;
1334}
1335
Blink Reformat1c4d759e2017-04-09 16:34:541336bool WebMediaPlayerImpl::CopyVideoTextureToPlatformTexture(
danakj46070b02016-03-28 21:54:111337 gpu::gles2::GLES2Interface* gl,
jiajia.qinc2943162017-05-12 01:34:391338 unsigned int target,
zmo57d577a2015-10-30 18:28:591339 unsigned int texture,
kbr0986e622017-04-13 02:34:581340 unsigned internal_format,
1341 unsigned format,
1342 unsigned type,
jiajia.qinc2943162017-05-12 01:34:391343 int level,
zmo57d577a2015-10-30 18:28:591344 bool premultiply_alpha,
Kai Ninomiya9e8ae29b2017-09-06 23:45:161345 bool flip_y,
1346 int already_uploaded_id,
1347 VideoFrameUploadMetadata* out_metadata) {
xhwang213e50c2016-10-10 23:56:311348 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]bfc05f22013-10-19 17:55:161349 TRACE_EVENT0("media", "WebMediaPlayerImpl:copyVideoTextureToPlatformTexture");
1350
watkd16bb3e2017-04-25 01:18:311351 // We can't copy from protected frames.
Xiaohan Wang24cfe2c2018-01-22 23:16:001352 if (cdm_context_ref_)
xhwang213e50c2016-10-10 23:56:311353 return false;
[email protected]dd061e12014-05-06 19:21:221354
xhwang213e50c2016-10-10 23:56:311355 scoped_refptr<VideoFrame> video_frame = GetCurrentFrameFromCompositor();
jbauman581d041c2016-07-21 01:01:031356 if (!video_frame.get() || !video_frame->HasTextures()) {
[email protected]e56f88c72013-06-25 22:31:291357 return false;
dongseong.hwang0c4e9d82015-01-08 20:11:131358 }
Kai Ninomiya9e8ae29b2017-09-06 23:45:161359 if (out_metadata) {
1360 // WebGL last-uploaded-frame-metadata API is enabled.
1361 // https://crbug.com/639174
1362 ComputeFrameUploadMetadata(video_frame.get(), already_uploaded_id,
1363 out_metadata);
1364 if (out_metadata->skipped) {
1365 // Skip uploading this frame.
1366 return true;
1367 }
1368 }
[email protected]df41e252014-02-03 23:39:501369
zhuoyu.qian4689dde22017-10-16 04:11:481370 return video_renderer_.CopyVideoFrameTexturesToGLTexture(
Antoine Labourfee4ae52019-04-24 23:53:571371 context_provider_.get(), gl, video_frame.get(), target, texture,
Dan Sanders930cc1d2018-10-03 00:45:081372 internal_format, format, type, level, premultiply_alpha, flip_y);
[email protected]6523b242013-03-13 11:10:071373}
1374
Yan, Shaobo44b79ba2019-04-02 06:09:271375bool WebMediaPlayerImpl::PrepareVideoFrameForWebGL(
1376 gpu::gles2::GLES2Interface* gl,
1377 unsigned target,
1378 unsigned texture,
1379 int already_uploaded_id,
1380 WebMediaPlayer::VideoFrameUploadMetadata* out_metadata) {
1381 DCHECK(main_task_runner_->BelongsToCurrentThread());
1382 TRACE_EVENT0("media", "WebMediaPlayerImpl::PrepareVideoFrameForWebGL");
1383
1384 // TODO(crbug.com/776222): How to deal with protected frames.
1385 scoped_refptr<VideoFrame> video_frame = GetCurrentFrameFromCompositor();
1386 if (!video_frame.get() || !video_frame->HasTextures()) {
1387 return false;
1388 }
1389 if (out_metadata) {
1390 // WebGL last-uploaded-frame-metadata API is enabled.
1391 ComputeFrameUploadMetadata(video_frame.get(), already_uploaded_id,
1392 out_metadata);
1393 if (out_metadata->skipped) {
1394 // Skip uploading this frame.
1395 return true;
1396 }
1397 }
1398
Yan, Shaobo44b79ba2019-04-02 06:09:271399 return video_renderer_.PrepareVideoFrameForWebGL(
Antoine Labourfee4ae52019-04-24 23:53:571400 context_provider_.get(), gl, video_frame.get(), target, texture);
Yan, Shaobo44b79ba2019-04-02 06:09:271401}
1402
Matt Wolenetz95af6362018-01-04 20:23:421403// static
Kai Ninomiya9e8ae29b2017-09-06 23:45:161404void WebMediaPlayerImpl::ComputeFrameUploadMetadata(
1405 VideoFrame* frame,
1406 int already_uploaded_id,
1407 VideoFrameUploadMetadata* out_metadata) {
1408 DCHECK(out_metadata);
Kai Ninomiyaef8c9e02017-09-27 04:07:401409 DCHECK(frame);
Kai Ninomiya9e8ae29b2017-09-06 23:45:161410 out_metadata->frame_id = frame->unique_id();
1411 out_metadata->visible_rect = frame->visible_rect();
1412 out_metadata->timestamp = frame->timestamp();
Li, Hao0fab96a2019-10-31 02:46:471413 base::TimeDelta frame_duration;
1414 if (frame->metadata()->GetTimeDelta(media::VideoFrameMetadata::FRAME_DURATION,
1415 &frame_duration)) {
1416 out_metadata->expected_timestamp = frame->timestamp() + frame_duration;
1417 };
Kai Ninomiya9e8ae29b2017-09-06 23:45:161418 bool skip_possible = already_uploaded_id != -1;
1419 bool same_frame_id = frame->unique_id() == already_uploaded_id;
1420 out_metadata->skipped = skip_possible && same_frame_id;
1421}
1422
Blink Reformat1c4d759e2017-04-09 16:34:541423void WebMediaPlayerImpl::SetContentDecryptionModule(
[email protected]9ebc3b03f2014-08-13 04:01:231424 blink::WebContentDecryptionModule* cdm,
1425 blink::WebContentDecryptionModuleResult result) {
xhwang51139732017-02-24 19:36:081426 DVLOG(1) << __func__ << ": cdm = " << cdm;
acolwellb4034942014-08-28 15:42:431427 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]9ebc3b03f2014-08-13 04:01:231428
jrummell06f27072015-06-08 18:12:381429 // Once the CDM is set it can't be cleared as there may be frames being
1430 // decrypted on other threads. So fail this request.
1431 // http://crbug.com/462365#c7.
xhwang97de4202014-11-25 08:44:011432 if (!cdm) {
Blink Reformat1c4d759e2017-04-09 16:34:541433 result.CompleteWithError(
1434 blink::kWebContentDecryptionModuleExceptionInvalidStateError, 0,
xhwang79b193042016-12-13 18:52:431435 "The existing ContentDecryptionModule object cannot be removed at this "
1436 "time.");
xhwang97de4202014-11-25 08:44:011437 return;
1438 }
1439
jrummell89e61d82015-07-23 20:03:341440 // Create a local copy of |result| to avoid problems with the callback
1441 // getting passed to the media thread and causing |result| to be destructed
jrummell4acbec912016-02-27 02:45:031442 // on the wrong thread in some failure conditions. Blink should prevent
1443 // multiple simultaneous calls.
1444 DCHECK(!set_cdm_result_);
Jose Lopes9023b6d2020-02-19 20:42:371445 set_cdm_result_ =
1446 std::make_unique<blink::WebContentDecryptionModuleResult>(result);
jrummell89e61d82015-07-23 20:03:341447
Chris Cunninghamd4a00192019-03-21 20:02:491448 SetCdmInternal(cdm);
xhwang97de4202014-11-25 08:44:011449}
1450
xhwange8c4181a2014-12-06 08:10:011451void WebMediaPlayerImpl::OnEncryptedMediaInitData(
jrummellcf78967c2015-04-03 05:03:581452 EmeInitDataType init_data_type,
Avi Drissman97785ea2015-12-19 01:11:311453 const std::vector<uint8_t>& init_data) {
jrummellcf78967c2015-04-03 05:03:581454 DCHECK(init_data_type != EmeInitDataType::UNKNOWN);
xhwangbab66f52014-12-02 23:49:501455
Xiaohan Wangf63505d2017-10-21 08:00:531456 RecordEncryptedEvent(true);
xhwangbab66f52014-12-02 23:49:501457
dalecurtis04bdb582016-08-17 22:15:231458 // Recreate the watch time reporter if necessary.
1459 const bool was_encrypted = is_encrypted_;
1460 is_encrypted_ = true;
Dale Curtis3899090ea2018-01-12 00:10:351461 if (!was_encrypted) {
1462 media_metrics_provider_->SetIsEME();
1463 if (watch_time_reporter_)
1464 CreateWatchTimeReporter();
dalecurtis04bdb582016-08-17 22:15:231465
Chris Cunningham6c0ec292019-04-04 18:31:111466 // |was_encrypted| = false means we didn't have a CDM prior to observing
1467 // encrypted media init data. Reset the reporter until the CDM arrives. See
1468 // SetCdmInternal().
1469 DCHECK(!cdm_config_);
1470 video_decode_stats_reporter_.reset();
1471 }
Chris Cunninghamd9df58e2017-08-29 00:04:231472
Blink Reformat1c4d759e2017-04-09 16:34:541473 encrypted_client_->Encrypted(
Antonio Gomes89b70572019-07-13 00:44:211474 init_data_type, init_data.data(),
srirama.m26f864d02015-07-14 05:21:461475 base::saturated_cast<unsigned int>(init_data.size()));
xhwangbab66f52014-12-02 23:49:501476}
1477
servolk81e01e02016-03-05 03:29:151478void WebMediaPlayerImpl::OnFFmpegMediaTracksUpdated(
dcheng3076abbf2016-04-22 20:42:391479 std::unique_ptr<MediaTracks> tracks) {
servolk81e01e02016-03-05 03:29:151480 // For MSE/chunk_demuxer case the media track updates are handled by
1481 // WebSourceBufferImpl.
1482 DCHECK(demuxer_.get());
1483 DCHECK(!chunk_demuxer_);
servolkef1e5ef2016-03-25 04:55:261484
servolk16e8bdf82017-04-11 17:00:391485 // Report the media track information to blink. Only the first audio track and
1486 // the first video track are enabled by default to match blink logic.
1487 bool is_first_audio_track = true;
1488 bool is_first_video_track = true;
servolkef1e5ef2016-03-25 04:55:261489 for (const auto& track : tracks->tracks()) {
1490 if (track->type() == MediaTrack::Audio) {
Maciej Pawlowskif2556d122019-06-03 08:14:181491 client_->AddAudioTrack(
1492 blink::WebString::FromUTF8(track->id().value()),
1493 blink::WebMediaPlayerClient::kAudioTrackKindMain,
1494 blink::WebString::FromUTF8(track->label().value()),
1495 blink::WebString::FromUTF8(track->language().value()),
1496 is_first_audio_track);
servolk16e8bdf82017-04-11 17:00:391497 is_first_audio_track = false;
servolkef1e5ef2016-03-25 04:55:261498 } else if (track->type() == MediaTrack::Video) {
Maciej Pawlowskif2556d122019-06-03 08:14:181499 client_->AddVideoTrack(
1500 blink::WebString::FromUTF8(track->id().value()),
1501 blink::WebMediaPlayerClient::kVideoTrackKindMain,
1502 blink::WebString::FromUTF8(track->label().value()),
1503 blink::WebString::FromUTF8(track->language().value()),
1504 is_first_video_track);
servolk16e8bdf82017-04-11 17:00:391505 is_first_video_track = false;
servolkef1e5ef2016-03-25 04:55:261506 } else {
1507 // Text tracks are not supported through this code path yet.
1508 NOTREACHED();
1509 }
1510 }
servolk81e01e02016-03-05 03:29:151511}
1512
Chris Cunninghamd4a00192019-03-21 20:02:491513void WebMediaPlayerImpl::SetCdmInternal(
1514 blink::WebContentDecryptionModule* cdm) {
jrummelle616ee92016-10-08 02:15:441515 DCHECK(main_task_runner_->BelongsToCurrentThread());
1516 DCHECK(cdm);
Xiaohan Wang24cfe2c2018-01-22 23:16:001517
Chris Cunninghamd4a00192019-03-21 20:02:491518 const bool was_encrypted = is_encrypted_;
1519 is_encrypted_ = true;
1520
1521 // Recreate the watch time reporter if necessary.
1522 if (!was_encrypted) {
1523 media_metrics_provider_->SetIsEME();
1524 if (watch_time_reporter_)
1525 CreateWatchTimeReporter();
1526 }
1527
Chris Cunningham6c0ec292019-04-04 18:31:111528 WebContentDecryptionModuleImpl* web_cdm =
1529 ToWebContentDecryptionModuleImpl(cdm);
1530 auto cdm_context_ref = web_cdm->GetCdmContextRef();
Xiaohan Wang24cfe2c2018-01-22 23:16:001531 if (!cdm_context_ref) {
jrummelle616ee92016-10-08 02:15:441532 NOTREACHED();
1533 OnCdmAttached(false);
xhwang80739452016-01-13 00:48:001534 return;
1535 }
1536
Chris Cunningham6c0ec292019-04-04 18:31:111537 // Arrival of |cdm_config_| and |key_system_| unblocks recording of encrypted
1538 // stats. Attempt to create the stats reporter. Note, we do NOT guard this
1539 // within !was_encypted above because often the CDM arrives after the call to
1540 // OnEncryptedMediaInitData().
1541 cdm_config_ = web_cdm->GetCdmConfig();
1542 key_system_ = web_cdm->GetKeySystem();
1543 DCHECK(!key_system_.empty());
1544 CreateVideoDecodeStatsReporter();
1545
Xiaohan Wang24cfe2c2018-01-22 23:16:001546 CdmContext* cdm_context = cdm_context_ref->GetCdmContext();
1547 DCHECK(cdm_context);
jrummelle616ee92016-10-08 02:15:441548
1549 // Keep the reference to the CDM, as it shouldn't be destroyed until
1550 // after the pipeline is done with the |cdm_context|.
Xiaohan Wang24cfe2c2018-01-22 23:16:001551 pending_cdm_context_ref_ = std::move(cdm_context_ref);
Antonio Gomes81b56552019-05-15 22:15:281552 pipeline_controller_->SetCdm(
Antonio Gomes142f32a2019-05-15 23:32:561553 cdm_context, base::Bind(&WebMediaPlayerImpl::OnCdmAttached, weak_this_));
xhwang97de4202014-11-25 08:44:011554}
1555
jrummell89e61d82015-07-23 20:03:341556void WebMediaPlayerImpl::OnCdmAttached(bool success) {
xhwang51139732017-02-24 19:36:081557 DVLOG(1) << __func__ << ": success = " << success;
jrummelle616ee92016-10-08 02:15:441558 DCHECK(main_task_runner_->BelongsToCurrentThread());
Xiaohan Wang24cfe2c2018-01-22 23:16:001559 DCHECK(pending_cdm_context_ref_);
jrummelle616ee92016-10-08 02:15:441560
1561 // If the CDM is set from the constructor there is no promise
1562 // (|set_cdm_result_|) to fulfill.
xhwang97de4202014-11-25 08:44:011563 if (success) {
Ted Meyer7f5b4e22019-11-21 03:21:191564 media_log_->SetProperty<MediaLogProperty::kIsVideoEncrypted>(true);
xhwang29c5ad202017-04-14 07:02:191565
jrummelle616ee92016-10-08 02:15:441566 // This will release the previously attached CDM (if any).
Xiaohan Wang24cfe2c2018-01-22 23:16:001567 cdm_context_ref_ = std::move(pending_cdm_context_ref_);
jrummelle616ee92016-10-08 02:15:441568 if (set_cdm_result_) {
Blink Reformat1c4d759e2017-04-09 16:34:541569 set_cdm_result_->Complete();
jrummelle616ee92016-10-08 02:15:441570 set_cdm_result_.reset();
1571 }
1572
xhwang97de4202014-11-25 08:44:011573 return;
1574 }
1575
Xiaohan Wang24cfe2c2018-01-22 23:16:001576 pending_cdm_context_ref_.reset();
jrummelle616ee92016-10-08 02:15:441577 if (set_cdm_result_) {
Blink Reformat1c4d759e2017-04-09 16:34:541578 set_cdm_result_->CompleteWithError(
1579 blink::kWebContentDecryptionModuleExceptionNotSupportedError, 0,
xhwang79b193042016-12-13 18:52:431580 "Unable to set ContentDecryptionModule object");
jrummelle616ee92016-10-08 02:15:441581 set_cdm_result_.reset();
1582 }
[email protected]9ebc3b03f2014-08-13 04:01:231583}
1584
sandersd1c0bba02016-03-04 23:14:081585void WebMediaPlayerImpl::OnPipelineSeeked(bool time_updated) {
John Chen5b164a02017-11-01 00:36:091586 TRACE_EVENT2("media", "WebMediaPlayerImpl::OnPipelineSeeked", "target",
1587 seek_time_.InSecondsF(), "id", media_log_->id());
[email protected]5d11eff2011-09-15 00:06:061588 seeking_ = false;
wolenetz1b2ae7d2015-06-10 00:44:211589 seek_time_ = base::TimeDelta();
avayvod2135a642017-01-13 00:17:141590
hubbe5a2dec022016-03-17 01:14:231591 if (paused_) {
Antonio Gomes81b56552019-05-15 22:15:281592 paused_time_ = pipeline_controller_->GetMediaTime();
dalecurtis04bdb582016-08-17 22:15:231593 } else {
1594 DCHECK(watch_time_reporter_);
1595 watch_time_reporter_->OnPlaying();
hubbe5a2dec022016-03-17 01:14:231596 }
sandersd1c0bba02016-03-04 23:14:081597 if (time_updated)
1598 should_notify_time_changed_ = true;
dalecurtisaf34d8712016-09-20 04:32:261599
dalecurtis4f6d14d2017-02-22 17:42:221600 // Reset underflow duration upon seek; this prevents looping videos and user
1601 // actions from artificially inflating the duration.
1602 underflow_timer_.reset();
avayvod56e1f3942017-01-21 02:06:311603
1604 // Background video optimizations are delayed when shown/hidden if pipeline
1605 // is seeking.
1606 UpdateBackgroundVideoOptimizationState();
Dale Curtis2dc6089a2018-03-26 16:47:581607
Dale Curtisd71061f02019-05-21 21:33:541608 // If we successfully completed a suspended startup, we need to make a call to
1609 // UpdatePlayState() in case any events which should trigger a resume have
1610 // occurred during startup.
Dale Curtis2dc6089a2018-03-26 16:47:581611 if (attempting_suspended_start_ &&
Antonio Gomes81b56552019-05-15 22:15:281612 pipeline_controller_->IsPipelineSuspended()) {
Dale Curtisff576552018-03-30 02:32:441613 skip_metrics_due_to_startup_suspend_ = true;
Dale Curtisd71061f02019-05-21 21:33:541614
1615 // If we successfully completed a suspended startup, signal that we have
1616 // reached BUFFERING_HAVE_ENOUGH so that canplay and canplaythrough fire
1617 // correctly. We must unfortunately always do this because it's valid for
1618 // elements to play while not visible nor even in the DOM.
1619 //
1620 // Note: This call is dual purpose, it is also responsible for triggering an
1621 // UpdatePlayState() call which may need to resume the pipeline once Blink
1622 // has been told about the ReadyState change.
Chris Cunninghamfc0d67e2019-07-22 20:29:161623 OnBufferingStateChangeInternal(BUFFERING_HAVE_ENOUGH,
1624 BUFFERING_CHANGE_REASON_UNKNOWN, true);
Dale Curtisff576552018-03-30 02:32:441625
1626 // If |skip_metrics_due_to_startup_suspend_| is unset by a resume started by
1627 // the OnBufferingStateChangeInternal() call, record a histogram of it here.
1628 //
1629 // If the value is unset, that means we should not have suspended and we've
1630 // likely incurred some cost to TimeToFirstFrame and TimeToPlayReady which
1631 // will be reflected in those statistics.
1632 base::UmaHistogramBoolean(
1633 std::string("Media.PreloadMetadataSuspendWasIdeal.") +
1634 ((HasVideo() && HasAudio()) ? "AudioVideo"
1635 : (HasVideo() ? "Video" : "Audio")),
1636 skip_metrics_due_to_startup_suspend_);
Dale Curtis2dc6089a2018-03-26 16:47:581637 }
1638
1639 attempting_suspended_start_ = false;
Becca Hughes7a85bf22019-07-24 16:16:581640
1641 // The current time has changed so we should update the media position state.
1642 UpdateMediaPositionState();
[email protected]8931c41a2009-07-07 17:31:491643}
1644
sandersd1c0bba02016-03-04 23:14:081645void WebMediaPlayerImpl::OnPipelineSuspended() {
Dale Curtis83321152018-12-01 01:22:061646 // Add a log event so the player shows up as "SUSPENDED" in media-internals.
Ted Meyer0134aed2020-01-23 23:56:401647 media_log_->AddEvent<MediaLogEvent::kSuspended>();
Dale Curtis83321152018-12-01 01:22:061648
Dale Curtis04769ca2019-05-25 00:38:101649 if (attempting_suspended_start_) {
1650 DCHECK(pipeline_controller_->IsSuspended());
1651 did_lazy_load_ = !has_poster_ && HasVideo();
1652 }
1653
sandersd2f5bb6152017-03-29 22:57:531654 // Tell the data source we have enough data so that it may release the
Dale Curtis04769ca2019-05-25 00:38:101655 // connection (unless blink is waiting on us to signal play()).
1656 if (mb_data_source_ && !client_->CouldPlayIfEnoughData()) {
1657 // |attempting_suspended_start_| will be cleared by OnPipelineSeeked() which
1658 // will occur after this method during a suspended startup.
1659 if (attempting_suspended_start_ && did_lazy_load_) {
1660 DCHECK(!has_first_frame_);
1661 DCHECK(have_enough_after_lazy_load_cb_.IsCancelled());
1662
1663 // For lazy load, we won't know if the element is non-visible until a
1664 // layout completes, so to avoid unnecessarily tearing down the network
1665 // connection, briefly (250ms chosen arbitrarily) delay signaling "have
1666 // enough" to the MultiBufferDataSource.
1667 //
1668 // base::Unretained() is safe here since the base::CancelableOnceClosure
1669 // will cancel upon destruction of this class and |mb_data_source_| is
1670 // gauranteeed to outlive us.
1671 have_enough_after_lazy_load_cb_.Reset(
1672 base::BindOnce(&MultibufferDataSource::OnBufferingHaveEnough,
1673 base::Unretained(mb_data_source_), true));
1674 main_task_runner_->PostDelayedTask(
1675 FROM_HERE, have_enough_after_lazy_load_cb_.callback(),
1676 base::TimeDelta::FromMilliseconds(250));
1677 } else {
1678 have_enough_after_lazy_load_cb_.Cancel();
1679 mb_data_source_->OnBufferingHaveEnough(true);
1680 }
1681 }
dalecurtis37fe5862016-03-15 19:29:091682
sandersd50a635e2016-04-04 22:50:091683 ReportMemoryUsage();
1684
sandersd1c0bba02016-03-04 23:14:081685 if (pending_suspend_resume_cycle_) {
watkdee516f2016-02-18 02:22:191686 pending_suspend_resume_cycle_ = false;
sandersd50a635e2016-04-04 22:50:091687 UpdatePlayState();
dalecurtis0431cbf2016-03-12 01:19:431688 }
sandersd1c0bba02016-03-04 23:14:081689}
1690
avayvod2135a642017-01-13 00:17:141691void WebMediaPlayerImpl::OnBeforePipelineResume() {
Dale Curtis04769ca2019-05-25 00:38:101692 // Since we're resuming, cancel closing of the network connection.
1693 have_enough_after_lazy_load_cb_.Cancel();
1694
Dale Curtisff576552018-03-30 02:32:441695 // We went through suspended startup, so the player is only just now spooling
1696 // up for playback. As such adjust |load_start_time_| so it reports the same
1697 // metric as what would be reported if we had not suspended at startup.
1698 if (skip_metrics_due_to_startup_suspend_) {
1699 // In the event that the call to SetReadyState() initiated after pipeline
1700 // startup immediately tries to start playback, we should not update
1701 // |load_start_time_| to avoid losing visibility into the impact of a
1702 // suspended startup on the time until first frame / play ready for cases
1703 // where suspended startup was applied incorrectly.
1704 if (!attempting_suspended_start_)
1705 load_start_time_ = base::TimeTicks::Now() - time_to_metadata_;
1706 skip_metrics_due_to_startup_suspend_ = false;
1707 }
1708
avayvod2135a642017-01-13 00:17:141709 // Enable video track if we disabled it in the background - this way the new
1710 // renderer will attach its callbacks to the video stream properly.
1711 // TODO(avayvod): Remove this when disabling and enabling video tracks in
1712 // non-playing state works correctly. See https://crbug.com/678374.
1713 EnableVideoTrackIfNeeded();
1714 is_pipeline_resuming_ = true;
1715}
1716
1717void WebMediaPlayerImpl::OnPipelineResumed() {
1718 is_pipeline_resuming_ = false;
1719
avayvod56e1f3942017-01-21 02:06:311720 UpdateBackgroundVideoOptimizationState();
avayvod2135a642017-01-13 00:17:141721}
1722
alokp967c902452016-05-06 05:21:371723void WebMediaPlayerImpl::OnDemuxerOpened() {
1724 DCHECK(main_task_runner_->BelongsToCurrentThread());
dalecurtis9cddc0b2017-04-19 21:23:381725 client_->MediaSourceOpened(new WebMediaSourceImpl(chunk_demuxer_));
alokp967c902452016-05-06 05:21:371726}
1727
servolkf94b4602017-01-31 16:44:271728void WebMediaPlayerImpl::OnMemoryPressure(
1729 base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
1730 DVLOG(2) << __func__ << " memory_pressure_level=" << memory_pressure_level;
1731 DCHECK(main_task_runner_->BelongsToCurrentThread());
1732 DCHECK(base::FeatureList::IsEnabled(kMemoryPressureBasedSourceBufferGC));
1733 DCHECK(chunk_demuxer_);
1734
Sebastien Marchand6f03d35f2020-01-28 15:12:451735 if (memory_pressure_level ==
1736 base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE) {
1737 return;
1738 }
1739
servolkf94b4602017-01-31 16:44:271740 // The new value of |memory_pressure_level| will take effect on the next
1741 // garbage collection. Typically this means the next SourceBuffer append()
1742 // operation, since per MSE spec, the garbage collection must only occur
1743 // during SourceBuffer append(). But if memory pressure is critical it might
1744 // be better to perform GC immediately rather than wait for the next append
1745 // and potentially get killed due to out-of-memory.
1746 // So if this experiment is enabled and pressure level is critical, we'll pass
1747 // down force_instant_gc==true, which will force immediate GC on
1748 // SourceBufferStreams.
1749 bool force_instant_gc =
1750 (enable_instant_source_buffer_gc_ &&
1751 memory_pressure_level ==
1752 base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
1753
Matt Wolenetz95af6362018-01-04 20:23:421754 // base::Unretained is safe, since |chunk_demuxer_| is actually owned by
1755 // |this| via this->demuxer_. Note the destruction of |chunk_demuxer_| is done
1756 // from ~WMPI by first hopping to |media_task_runner_| to prevent race with
1757 // this task.
servolkf94b4602017-01-31 16:44:271758 media_task_runner_->PostTask(
Dale Curtisee9be30012018-09-21 22:21:511759 FROM_HERE, base::BindOnce(&ChunkDemuxer::OnMemoryPressure,
1760 base::Unretained(chunk_demuxer_),
1761 base::TimeDelta::FromSecondsD(CurrentTime()),
1762 memory_pressure_level, force_instant_gc));
servolkf94b4602017-01-31 16:44:271763}
1764
alokp967c902452016-05-06 05:21:371765void WebMediaPlayerImpl::OnError(PipelineStatus status) {
Xiaohan Wang73b433f2019-11-05 20:13:011766 DVLOG(1) << __func__ << ": status=" << status;
alokp967c902452016-05-06 05:21:371767 DCHECK(main_task_runner_->BelongsToCurrentThread());
1768 DCHECK_NE(status, PIPELINE_OK);
1769
1770 if (suppress_destruction_errors_)
1771 return;
1772
Thomas Guilbert6b6be3d2017-08-18 03:17:271773#if defined(OS_ANDROID)
Dale Curtisf273f8f2018-12-13 23:40:331774 // |mb_data_source_| may be nullptr if someone passes in a m3u8 as a data://
1775 // URL, since MediaPlayer doesn't support data:// URLs, fail playback now.
Dan Sanders675250992019-05-11 00:07:491776 const bool found_hls = base::FeatureList::IsEnabled(kHlsPlayer) &&
1777 status == PipelineStatus::DEMUXER_ERROR_DETECTED_HLS;
Dale Curtisf273f8f2018-12-13 23:40:331778 if (found_hls && mb_data_source_) {
Dan Sandersae245e42019-03-07 23:25:291779 demuxer_found_hls_ = true;
1780
Dan Sandersd80b1842019-02-05 00:36:161781 UMA_HISTOGRAM_BOOLEAN("Media.WebMediaPlayerImpl.HLS.IsCorsCrossOrigin",
1782 mb_data_source_->IsCorsCrossOrigin());
Dan Sandersae245e42019-03-07 23:25:291783 if (mb_data_source_->IsCorsCrossOrigin()) {
1784 UMA_HISTOGRAM_BOOLEAN("Media.WebMediaPlayerImpl.HLS.HasAccessControl",
1785 mb_data_source_->HasAccessControl());
1786 }
1787
1788 // Note: Does not consider the full redirect chain, which could contain
1789 // undetected mixed content.
Dan Sandersd80b1842019-02-05 00:36:161790 bool frame_url_is_cryptographic = url::Origin(frame_->GetSecurityOrigin())
1791 .GetURL()
1792 .SchemeIsCryptographic();
1793 bool manifest_url_is_cryptographic =
1794 loaded_url_.SchemeIsCryptographic() &&
1795 mb_data_source_->GetUrlAfterRedirects().SchemeIsCryptographic();
1796 UMA_HISTOGRAM_BOOLEAN(
1797 "Media.WebMediaPlayerImpl.HLS.IsMixedContent",
1798 frame_url_is_cryptographic && !manifest_url_is_cryptographic);
Thomas Guilbert153f84572018-07-19 05:03:581799
Xiaohan Wang3684e0c2019-10-30 01:04:301800 renderer_factory_selector_->SetBaseFactoryType(
Xiaohan Wang48aaa192019-12-05 01:29:001801 RendererFactoryType::kMediaPlayer);
Thomas Guilbert6b6be3d2017-08-18 03:17:271802
Dale Curtisf273f8f2018-12-13 23:40:331803 loaded_url_ = mb_data_source_->GetUrlAfterRedirects();
1804 DCHECK(data_source_);
1805 data_source_->Stop();
1806 mb_data_source_ = nullptr;
1807
Antonio Gomes81b56552019-05-15 22:15:281808 pipeline_controller_->Stop();
Dale Curtis8a6281322017-08-31 00:35:531809 SetMemoryReportingState(false);
Eugene Zemtsov77d56262020-03-06 05:52:031810 media_task_runner_->DeleteSoon(FROM_HERE,
1811 std::move(media_thread_mem_dumper_));
Thomas Guilbert6b6be3d2017-08-18 03:17:271812
Dale Curtisf273f8f2018-12-13 23:40:331813 // Trampoline through the media task runner to destruct the demuxer and
1814 // data source now that we're switching to HLS playback.
1815 media_task_runner_->PostTask(
Dale Curtisee9be30012018-09-21 22:21:511816 FROM_HERE,
Dale Curtisf273f8f2018-12-13 23:40:331817 BindToCurrentLoop(base::BindOnce(
1818 [](std::unique_ptr<Demuxer> demuxer,
1819 std::unique_ptr<DataSource> data_source,
1820 base::OnceClosure start_pipeline_cb) {
1821 // Release resources before starting HLS.
1822 demuxer.reset();
1823 data_source.reset();
1824
1825 std::move(start_pipeline_cb).Run();
1826 },
1827 std::move(demuxer_), std::move(data_source_),
Antonio Gomes142f32a2019-05-15 23:32:561828 base::BindOnce(&WebMediaPlayerImpl::StartPipeline, weak_this_))));
Dale Curtisf273f8f2018-12-13 23:40:331829
Thomas Guilbert6b6be3d2017-08-18 03:17:271830 return;
1831 }
Dale Curtisf273f8f2018-12-13 23:40:331832
1833 // We found hls in a data:// URL, fail immediately.
1834 if (found_hls)
1835 status = PIPELINE_ERROR_EXTERNAL_RENDERER_FAILED;
Thomas Guilbert6b6be3d2017-08-18 03:17:271836#endif
1837
Dale Curtis5bba03232018-08-30 17:57:381838 MaybeSetContainerName();
Dan Sanders6edfd782019-08-13 00:13:181839 simple_watch_timer_.Stop();
Ted Meyer0134aed2020-01-23 23:56:401840 media_log_->NotifyError(status);
Dale Curtis74612b72017-12-14 20:56:191841 media_metrics_provider_->OnError(status);
Dale Curtisccfd0cca2017-08-31 01:27:561842 if (watch_time_reporter_)
1843 watch_time_reporter_->OnError(status);
alokp967c902452016-05-06 05:21:371844
Blink Reformat1c4d759e2017-04-09 16:34:541845 if (ready_state_ == WebMediaPlayer::kReadyStateHaveNothing) {
alokp967c902452016-05-06 05:21:371846 // Any error that occurs before reaching ReadyStateHaveMetadata should
1847 // be considered a format error.
Blink Reformat1c4d759e2017-04-09 16:34:541848 SetNetworkState(WebMediaPlayer::kNetworkStateFormatError);
alokp967c902452016-05-06 05:21:371849 } else {
Antonio Gomesf01cfbd2019-07-12 08:53:111850 SetNetworkState(blink::PipelineErrorToNetworkState(status));
alokp967c902452016-05-06 05:21:371851 }
1852
Thomas Guilbert2e591392017-08-12 00:56:381853 // PipelineController::Stop() is idempotent.
Antonio Gomes81b56552019-05-15 22:15:281854 pipeline_controller_->Stop();
Thomas Guilbert2e591392017-08-12 00:56:381855
alokp967c902452016-05-06 05:21:371856 UpdatePlayState();
1857}
1858
1859void WebMediaPlayerImpl::OnEnded() {
John Chen5b164a02017-11-01 00:36:091860 TRACE_EVENT2("media", "WebMediaPlayerImpl::OnEnded", "duration", Duration(),
1861 "id", media_log_->id());
pkastingf5279482016-07-27 02:18:201862 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:431863 DCHECK(main_task_runner_->BelongsToCurrentThread());
scherkusd2c745b2014-09-04 05:03:401864
sandersd1c0bba02016-03-04 23:14:081865 // Ignore state changes until we've completed all outstanding operations.
Antonio Gomes81b56552019-05-15 22:15:281866 if (!pipeline_controller_->IsStable())
scherkusd2c745b2014-09-04 05:03:401867 return;
1868
1869 ended_ = true;
Blink Reformat1c4d759e2017-04-09 16:34:541870 client_->TimeChanged();
sandersd50a635e2016-04-04 22:50:091871
1872 // We don't actually want this to run until |client_| calls seek() or pause(),
1873 // but that should have already happened in timeChanged() and so this is
1874 // expected to be a no-op.
1875 UpdatePlayState();
[email protected]576537842009-08-12 23:52:051876}
1877
Chisoon Jeong0a8e4bc2019-05-11 00:06:141878void WebMediaPlayerImpl::OnMetadata(const PipelineMetadata& metadata) {
pkastingf5279482016-07-27 02:18:201879 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:431880 DCHECK(main_task_runner_->BelongsToCurrentThread());
Dale Curtisff576552018-03-30 02:32:441881
1882 // Cache the |time_to_metadata_| to use for adjusting the TimeToFirstFrame and
1883 // TimeToPlayReady metrics later if we end up doing a suspended startup.
1884 time_to_metadata_ = base::TimeTicks::Now() - load_start_time_;
1885 media_metrics_provider_->SetTimeToMetadata(time_to_metadata_);
1886 RecordTimingUMA("Media.TimeToMetadata", time_to_metadata_);
[email protected]a8e2cb82012-08-17 00:02:391887
Dale Curtis5bba03232018-08-30 17:57:381888 MaybeSetContainerName();
1889
[email protected]b8877772014-03-26 20:17:151890 pipeline_metadata_ = metadata;
[email protected]c7a918e2020-01-17 00:18:271891 if (power_status_helper_)
[email protected]dc996312019-12-19 19:26:381892 power_status_helper_->SetMetadata(metadata);
[email protected]739847c02014-01-16 00:12:251893
Ted Meyer4a427632019-05-01 19:05:271894 UMA_HISTOGRAM_ENUMERATION(
1895 "Media.VideoRotation",
1896 metadata.video_decoder_config.video_transformation().rotation,
1897 VIDEO_ROTATION_MAX + 1);
[email protected]21c3f7502013-03-23 03:29:511898
John Rummelldb5a7ef2018-05-16 00:28:011899 if (HasAudio()) {
Ted Meyerd5885f82019-07-16 19:19:171900 media_metrics_provider_->SetHasAudio(metadata.audio_decoder_config.codec());
John Rummelldb5a7ef2018-05-16 00:28:011901 RecordEncryptionScheme("Audio",
1902 metadata.audio_decoder_config.encryption_scheme());
1903 }
1904
Blink Reformat1c4d759e2017-04-09 16:34:541905 if (HasVideo()) {
Ted Meyerd5885f82019-07-16 19:19:171906 media_metrics_provider_->SetHasVideo(metadata.video_decoder_config.codec());
John Rummelldb5a7ef2018-05-16 00:28:011907 RecordEncryptionScheme("Video",
1908 metadata.video_decoder_config.encryption_scheme());
1909
liberato2fd111be2017-01-04 00:25:061910 if (overlay_enabled_) {
1911 // SurfaceView doesn't support rotated video, so transition back if
[email protected]c8d574722017-08-30 20:53:431912 // the video is now rotated. If |always_enable_overlays_|, we keep the
liberato2fd111be2017-01-04 00:25:061913 // overlay anyway so that the state machine keeps working.
[email protected]c8d574722017-08-30 20:53:431914 // TODO(liberato): verify if compositor feedback catches this. If so,
1915 // then we don't need this check.
1916 if (!always_enable_overlays_ && !DoesOverlaySupportMetadata())
liberato2fd111be2017-01-04 00:25:061917 DisableOverlay();
liberato2fd111be2017-01-04 00:25:061918 }
watkf835a792016-06-24 23:24:401919
[email protected]702d721d2018-10-25 21:55:271920 if (surface_layer_mode_ ==
Mounir Lamouri28d648102019-11-27 16:49:031921 blink::WebMediaPlayer::SurfaceLayerMode::kAlways) {
[email protected]702d721d2018-10-25 21:55:271922 ActivateSurfaceLayerForVideo();
1923 } else {
danakj6e669e782018-05-16 16:57:171924 DCHECK(!video_layer_);
Ted Meyer4a427632019-05-01 19:05:271925 // TODO(tmathmeyer) does this need support for reflections as well?
danakj25f030112018-05-11 18:26:541926 video_layer_ = cc::VideoLayer::Create(
Julien Isorce6c83d8de2017-10-12 13:11:291927 compositor_.get(),
Ted Meyer4a427632019-05-01 19:05:271928 pipeline_metadata_.video_decoder_config.video_transformation()
1929 .rotation);
danakj8bc61c72018-05-16 13:55:061930 video_layer_->SetContentsOpaque(opaque_);
danakj8d204a42018-05-18 18:05:351931 client_->SetCcLayer(video_layer_.get());
lethalantidote7f6009d2017-07-07 21:47:391932 }
[email protected]a8e2cb82012-08-17 00:02:391933 }
dalecurtis8e4dc682016-03-15 02:30:301934
xjzd3fe45a2016-10-12 18:26:371935 if (observer_)
xjz15b483f2017-01-12 00:21:361936 observer_->OnMetadataChanged(pipeline_metadata_);
xjzd3fe45a2016-10-12 18:26:371937
Dale Curtisc7d2a7d22018-01-11 20:01:051938 // TODO(dalecurtis): Don't create these until kReadyStateHaveFutureData; when
1939 // we create them early we just increase the chances of needing to throw them
1940 // away unnecessarily.
dalecurtis04bdb582016-08-17 22:15:231941 CreateWatchTimeReporter();
Chris Cunninghamd9df58e2017-08-29 00:04:231942 CreateVideoDecodeStatsReporter();
Dale Curtisc7d2a7d22018-01-11 20:01:051943
Dale Curtis1e7a02b42019-05-28 20:12:241944 // SetReadyState() may trigger all sorts of calls into this class (e.g.,
1945 // Play(), Pause(), etc) so do it last to avoid unexpected states during the
1946 // calls. An exception to this is UpdatePlayState(), which is safe to call and
1947 // needs to use the new ReadyState in its calculations.
Dale Curtis2fc01cc2019-05-20 22:53:521948 SetReadyState(WebMediaPlayer::kReadyStateHaveMetadata);
Dale Curtis1e7a02b42019-05-28 20:12:241949 UpdatePlayState();
[email protected]a8e2cb82012-08-17 00:02:391950}
1951
[email protected]69db58f2018-09-26 20:27:561952void WebMediaPlayerImpl::ActivateSurfaceLayerForVideo() {
1953 // Note that we might or might not already be in VideoLayer mode.
1954 DCHECK(!bridge_);
1955
1956 surface_layer_for_video_enabled_ = true;
1957
1958 // If we're in VideoLayer mode, then get rid of the layer.
1959 if (video_layer_) {
1960 client_->SetCcLayer(nullptr);
1961 video_layer_ = nullptr;
1962 }
1963
1964 bridge_ = std::move(create_bridge_callback_)
1965 .Run(this, compositor_->GetUpdateSubmissionStateCallback());
1966 bridge_->CreateSurfaceLayer();
1967
Ted Meyer4a427632019-05-01 19:05:271968 // TODO(tmathmeyer) does this need support for the reflection transformation
1969 // as well?
[email protected]69db58f2018-09-26 20:27:561970 vfc_task_runner_->PostTask(
1971 FROM_HERE,
Ted Meyer4a427632019-05-01 19:05:271972 base::BindOnce(
1973 &VideoFrameCompositor::EnableSubmission,
1974 base::Unretained(compositor_.get()), bridge_->GetSurfaceId(),
1975 bridge_->GetLocalSurfaceIdAllocationTime(),
1976 pipeline_metadata_.video_decoder_config.video_transformation()
1977 .rotation,
1978 IsInPictureInPicture()));
[email protected]69db58f2018-09-26 20:27:561979 bridge_->SetContentsOpaque(opaque_);
1980
1981 // If the element is already in Picture-in-Picture mode, it means that it
1982 // was set in this mode prior to this load, with a different
1983 // WebMediaPlayerImpl. The new player needs to send its id, size and
1984 // surface id to the browser process to make sure the states are properly
1985 // updated.
1986 // TODO(872056): the surface should be activated but for some reasons, it
1987 // does not. It is possible that this will no longer be needed after 872056
1988 // is fixed.
Dale Curtisca1b78f2019-01-15 03:11:261989 if (IsInPictureInPicture())
[email protected]69db58f2018-09-26 20:27:561990 OnSurfaceIdUpdated(bridge_->GetSurfaceId());
[email protected]69db58f2018-09-26 20:27:561991}
1992
Chris Cunninghamfc0d67e2019-07-22 20:29:161993void WebMediaPlayerImpl::OnBufferingStateChange(
1994 BufferingState state,
1995 BufferingStateChangeReason reason) {
1996 OnBufferingStateChangeInternal(state, reason, false);
Dale Curtis2dc6089a2018-03-26 16:47:581997}
1998
Chris Cunninghamd9df58e2017-08-29 00:04:231999void WebMediaPlayerImpl::CreateVideoDecodeStatsReporter() {
2000 // TODO(chcunningham): destroy reporter if we initially have video but the
2001 // track gets disabled. Currently not possible in default desktop Chrome.
2002 if (!HasVideo())
2003 return;
2004
Chris Cunningham89b4b762019-03-27 17:13:332005 // Only record stats from the local pipeline.
2006 if (is_flinging_ || is_remote_rendering_ || using_media_player_renderer_)
2007 return;
2008
Chris Cunninghamd9df58e2017-08-29 00:04:232009 // Stats reporter requires a valid config. We may not have one for HLS cases
2010 // where URL demuxer doesn't know details of the stream.
2011 if (!pipeline_metadata_.video_decoder_config.IsValidConfig())
2012 return;
2013
Chris Cunningham6c0ec292019-04-04 18:31:112014 // Profile must be known for use as index to save the reported stats.
Chris Cunningham5b1b67eb2019-03-23 03:24:412015 if (pipeline_metadata_.video_decoder_config.profile() ==
2016 VIDEO_CODEC_PROFILE_UNKNOWN) {
2017 return;
2018 }
2019
Chris Cunningham6c0ec292019-04-04 18:31:112020 // CdmConfig must be provided for use as index to save encrypted stats.
2021 if (is_encrypted_ && !cdm_config_) {
Chris Cunninghamd9df58e2017-08-29 00:04:232022 return;
Chris Cunningham6c0ec292019-04-04 18:31:112023 } else if (cdm_config_) {
2024 DCHECK(!key_system_.empty());
2025 }
Chris Cunninghamd9df58e2017-08-29 00:04:232026
Gyuyoung Kima040bc52019-10-30 01:14:352027 mojo::PendingRemote<mojom::VideoDecodeStatsRecorder> recorder;
Dale Curtis7e8a510d2017-12-14 19:19:482028 media_metrics_provider_->AcquireVideoDecodeStatsRecorder(
Gyuyoung Kima040bc52019-10-30 01:14:352029 recorder.InitWithNewPipeAndPassReceiver());
Chris Cunninghamc7c6a6d2017-11-23 14:06:452030
Chris Cunninghamd9df58e2017-08-29 00:04:232031 // Create capabilities reporter and synchronize its initial state.
Jose Lopes9023b6d2020-02-19 20:42:372032 video_decode_stats_reporter_ = std::make_unique<VideoDecodeStatsReporter>(
Chris Cunninghamc7c6a6d2017-11-23 14:06:452033 std::move(recorder),
Jose Lopesdda34ca2020-02-19 11:56:172034 base::BindRepeating(&WebMediaPlayerImpl::GetPipelineStatistics,
2035 base::Unretained(this)),
Chris Cunningham5b1b67eb2019-03-23 03:24:412036 pipeline_metadata_.video_decoder_config.profile(),
Chris Cunningham6c0ec292019-04-04 18:31:112037 pipeline_metadata_.natural_size, key_system_, cdm_config_,
Jose Lopes9023b6d2020-02-19 20:42:372038 frame_->GetTaskRunner(blink::TaskType::kInternalMedia));
Chris Cunninghamd9df58e2017-08-29 00:04:232039
2040 if (delegate_->IsFrameHidden())
2041 video_decode_stats_reporter_->OnHidden();
2042 else
2043 video_decode_stats_reporter_->OnShown();
2044
2045 if (paused_)
2046 video_decode_stats_reporter_->OnPaused();
2047 else
2048 video_decode_stats_reporter_->OnPlaying();
2049}
2050
hubbeb2d3efd2017-05-05 23:26:382051void WebMediaPlayerImpl::OnProgress() {
Chris Watkins1ffabc5f2017-05-10 20:52:092052 DVLOG(4) << __func__;
Dale Curtisad645f72019-09-06 23:28:162053
2054 // See IsPrerollAttemptNeeded() for more details. We can't use that method
2055 // here since it considers |preroll_attempt_start_time_| and for OnProgress()
2056 // events we must make the attempt -- since there may not be another event.
2057 if (highest_ready_state_ < ReadyState::kReadyStateHaveFutureData) {
hubbeb2d3efd2017-05-05 23:26:382058 // Reset the preroll attempt clock.
2059 preroll_attempt_pending_ = true;
2060 preroll_attempt_start_time_ = base::TimeTicks();
2061
2062 // Clear any 'stale' flag and give the pipeline a chance to resume. If we
2063 // are already resumed, this will cause |preroll_attempt_start_time_| to
2064 // be set.
2065 delegate_->ClearStaleFlag(delegate_id_);
2066 UpdatePlayState();
2067 } else if (ready_state_ == ReadyState::kReadyStateHaveFutureData &&
2068 CanPlayThrough()) {
2069 SetReadyState(WebMediaPlayer::kReadyStateHaveEnoughData);
2070 }
2071}
2072
2073bool WebMediaPlayerImpl::CanPlayThrough() {
2074 if (!base::FeatureList::IsEnabled(kSpecCompliantCanPlayThrough))
2075 return true;
2076 if (chunk_demuxer_)
2077 return true;
Dale Curtis4841c712018-12-13 18:14:052078 if (data_source_ && data_source_->AssumeFullyBuffered())
hubbeb2d3efd2017-05-05 23:26:382079 return true;
2080 // If we're not currently downloading, we have as much buffer as
2081 // we're ever going to get, which means we say we can play through.
2082 if (network_state_ == WebMediaPlayer::kNetworkStateIdle)
2083 return true;
Antonio Gomes81b56552019-05-15 22:15:282084 return buffered_data_source_host_->CanPlayThrough(
hubbeb2d3efd2017-05-05 23:26:382085 base::TimeDelta::FromSecondsD(CurrentTime()),
2086 base::TimeDelta::FromSecondsD(Duration()),
2087 playback_rate_ == 0.0 ? 1.0 : playback_rate_);
2088}
2089
Dale Curtisff576552018-03-30 02:32:442090void WebMediaPlayerImpl::OnBufferingStateChangeInternal(
2091 BufferingState state,
Chris Cunninghamfc0d67e2019-07-22 20:29:162092 BufferingStateChangeReason reason,
Dale Curtisff576552018-03-30 02:32:442093 bool for_suspended_start) {
Chris Cunninghamfc0d67e2019-07-22 20:29:162094 DVLOG(1) << __func__ << "(" << state << ", " << reason << ")";
alokp967c902452016-05-06 05:21:372095 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]b8877772014-03-26 20:17:152096
Ted Meyer742212b82018-08-22 17:21:422097 // Ignore buffering state changes caused by back-to-back seeking, so as not
2098 // to assume the second seek has finished when it was only the first seek.
Antonio Gomes81b56552019-05-15 22:15:282099 if (pipeline_controller_->IsPendingSeek())
[email protected]ba7d5f92014-06-24 05:37:402100 return;
[email protected]b8877772014-03-26 20:17:152101
Ted Meyer0134aed2020-01-23 23:56:402102 media_log_->AddEvent<MediaLogEvent::kBufferingStateChanged>(
2103 SerializableBufferingState<SerializableBufferingStateType::kPipeline>{
2104 state, reason, for_suspended_start});
dalecurtis869bf2f2017-01-10 18:01:102105
Ted Meyerd5885f82019-07-16 19:19:172106 if (state == BUFFERING_HAVE_ENOUGH && !for_suspended_start)
2107 media_metrics_provider_->SetHaveEnough();
2108
chcunninghameb270c92016-07-15 01:00:452109 if (state == BUFFERING_HAVE_ENOUGH) {
John Chen5b164a02017-11-01 00:36:092110 TRACE_EVENT1("media", "WebMediaPlayerImpl::BufferingHaveEnough", "id",
2111 media_log_->id());
Dale Curtisff576552018-03-30 02:32:442112 // The SetReadyState() call below may clear
2113 // |skip_metrics_due_to_startup_suspend_| so report this first.
2114 if (!have_reported_time_to_play_ready_ &&
2115 !skip_metrics_due_to_startup_suspend_) {
2116 DCHECK(!for_suspended_start);
Dale Curtis3899090ea2018-01-12 00:10:352117 have_reported_time_to_play_ready_ = true;
2118 const base::TimeDelta elapsed = base::TimeTicks::Now() - load_start_time_;
2119 media_metrics_provider_->SetTimeToPlayReady(elapsed);
2120 RecordTimingUMA("Media.TimeToPlayReady", elapsed);
2121 }
[email protected]ba7d5f92014-06-24 05:37:402122
Dale Curtisff576552018-03-30 02:32:442123 // Warning: This call may be re-entrant.
2124 SetReadyState(CanPlayThrough() ? WebMediaPlayer::kReadyStateHaveEnoughData
2125 : WebMediaPlayer::kReadyStateHaveFutureData);
2126
Dale Curtis18ad391b2019-05-30 23:25:092127 // Let the DataSource know we have enough data -- this is the only function
2128 // during which we advance to (or past) the kReadyStateHaveEnoughData state.
2129 // It may use this information to update buffer sizes or release unused
2130 // network connections.
2131 MaybeUpdateBufferSizesForPlayback();
Dale Curtis04769ca2019-05-25 00:38:102132 if (mb_data_source_ && !client_->CouldPlayIfEnoughData()) {
2133 // For LazyLoad this will be handled during OnPipelineSuspended().
2134 if (for_suspended_start && did_lazy_load_)
2135 DCHECK(!have_enough_after_lazy_load_cb_.IsCancelled());
2136 else
2137 mb_data_source_->OnBufferingHaveEnough(false);
2138 }
dalecurtis849cf4b22015-03-27 18:35:452139
chcunninghameb270c92016-07-15 01:00:452140 // Blink expects a timeChanged() in response to a seek().
sandersd35d2c3f2017-01-14 02:04:422141 if (should_notify_time_changed_) {
2142 should_notify_time_changed_ = false;
Blink Reformat1c4d759e2017-04-09 16:34:542143 client_->TimeChanged();
sandersd35d2c3f2017-01-14 02:04:422144 }
dalecurtis0f0097a2015-12-01 17:40:472145
chcunninghameb270c92016-07-15 01:00:452146 // Once we have enough, start reporting the total memory usage. We'll also
2147 // report once playback starts.
2148 ReportMemoryUsage();
dalecurtis9d638a12016-08-30 06:20:552149
dalecurtis4f6d14d2017-02-22 17:42:222150 // Report the amount of time it took to leave the underflow state.
2151 if (underflow_timer_) {
Dale Curtisc9069622019-10-24 20:20:502152 auto elapsed = underflow_timer_->Elapsed();
2153 RecordUnderflowDuration(elapsed);
2154 watch_time_reporter_->OnUnderflowComplete(elapsed);
dalecurtis9d638a12016-08-30 06:20:552155 underflow_timer_.reset();
2156 }
chcunninghameb270c92016-07-15 01:00:452157 } else {
2158 // Buffering has underflowed.
2159 DCHECK_EQ(state, BUFFERING_HAVE_NOTHING);
dalecurtisacd77d62016-09-09 23:23:142160
dalecurtisd06eabc2017-02-24 23:43:292161 // Report the number of times we've entered the underflow state. Ensure we
2162 // only report the value when transitioning from HAVE_ENOUGH to
2163 // HAVE_NOTHING.
Dale Curtis6995b862017-05-31 22:20:082164 if (ready_state_ == WebMediaPlayer::kReadyStateHaveEnoughData &&
2165 !seeking_) {
Jose Lopes9023b6d2020-02-19 20:42:372166 underflow_timer_ = std::make_unique<base::ElapsedTimer>();
Dale Curtis6995b862017-05-31 22:20:082167 watch_time_reporter_->OnUnderflow();
2168 }
dalecurtisacd77d62016-09-09 23:23:142169
chcunninghameb270c92016-07-15 01:00:452170 // It shouldn't be possible to underflow if we've not advanced past
2171 // HAVE_CURRENT_DATA.
Blink Reformat1c4d759e2017-04-09 16:34:542172 DCHECK_GT(highest_ready_state_, WebMediaPlayer::kReadyStateHaveCurrentData);
2173 SetReadyState(WebMediaPlayer::kReadyStateHaveCurrentData);
chcunninghameb270c92016-07-15 01:00:452174 }
sandersd50a635e2016-04-04 22:50:092175
[email protected]91379332020-01-26 03:58:202176 // If this is an NNR, then notify the smoothness helper about it. Note that
2177 // it's unclear what we should do if there is no smoothness helper yet. As it
2178 // is, we just discard the NNR.
2179 if (state == BUFFERING_HAVE_NOTHING && reason == DECODER_UNDERFLOW &&
2180 smoothness_helper_) {
2181 smoothness_helper_->NotifyNNR();
2182 }
2183
sandersd50a635e2016-04-04 22:50:092184 UpdatePlayState();
[email protected]b8877772014-03-26 20:17:152185}
2186
alokp967c902452016-05-06 05:21:372187void WebMediaPlayerImpl::OnDurationChange() {
acolwellb4034942014-08-28 15:42:432188 DCHECK(main_task_runner_->BelongsToCurrentThread());
alokp967c902452016-05-06 05:21:372189
John Delaney2371b452018-12-13 04:30:332190 if (frame_->IsAdSubframe()) {
2191 UMA_HISTOGRAM_CUSTOM_TIMES("Ads.Media.Duration", GetPipelineMediaDuration(),
2192 base::TimeDelta::FromMilliseconds(1),
2193 base::TimeDelta::FromDays(1),
2194 50 /* bucket_count */);
2195 }
2196
alokp967c902452016-05-06 05:21:372197 // TODO(sandersd): We should call delegate_->DidPlay() with the new duration,
2198 // especially if it changed from <5s to >5s.
Blink Reformat1c4d759e2017-04-09 16:34:542199 if (ready_state_ == WebMediaPlayer::kReadyStateHaveNothing)
alokp967c902452016-05-06 05:21:372200 return;
2201
Blink Reformat1c4d759e2017-04-09 16:34:542202 client_->DurationChanged();
Dale Curtisaebaeea2018-07-19 23:42:112203 if (watch_time_reporter_)
2204 watch_time_reporter_->OnDurationChanged(GetPipelineMediaDuration());
Becca Hughes7a85bf22019-07-24 16:16:582205
2206 // The duration has changed so we should update the media position state.
2207 UpdateMediaPositionState();
[email protected]81bb3322011-07-21 15:55:502208}
2209
alokp967c902452016-05-06 05:21:372210void WebMediaPlayerImpl::OnAddTextTrack(const TextTrackConfig& config,
Raymond Toy85ad6802019-12-17 23:55:192211 AddTextTrackDoneCB done_cb) {
acolwellb4034942014-08-28 15:42:432212 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]71537722013-05-23 06:47:532213
[email protected]8a561062013-11-22 01:19:312214 const WebInbandTextTrackImpl::Kind web_kind =
2215 static_cast<WebInbandTextTrackImpl::Kind>(config.kind());
Blink Reformat1c4d759e2017-04-09 16:34:542216 const blink::WebString web_label = blink::WebString::FromUTF8(config.label());
[email protected]8a561062013-11-22 01:19:312217 const blink::WebString web_language =
Blink Reformat1c4d759e2017-04-09 16:34:542218 blink::WebString::FromUTF8(config.language());
2219 const blink::WebString web_id = blink::WebString::FromUTF8(config.id());
[email protected]71537722013-05-23 06:47:532220
dcheng3076abbf2016-04-22 20:42:392221 std::unique_ptr<WebInbandTextTrackImpl> web_inband_text_track(
henriks9cce5fa2014-12-12 09:35:302222 new WebInbandTextTrackImpl(web_kind, web_label, web_language, web_id));
[email protected]8a561062013-11-22 01:19:312223
Dale Curtisca1b78f2019-01-15 03:11:262224 std::unique_ptr<TextTrack> text_track(new TextTrackImpl(
dcheng652f5ff2015-12-27 08:54:002225 main_task_runner_, client_, std::move(web_inband_text_track)));
[email protected]8a561062013-11-22 01:19:312226
Raymond Toy85ad6802019-12-17 23:55:192227 std::move(done_cb).Run(std::move(text_track));
[email protected]71537722013-05-23 06:47:532228}
2229
Xiaohan Wang640b41d2018-12-18 19:00:462230void WebMediaPlayerImpl::OnWaiting(WaitingReason reason) {
alokp967c902452016-05-06 05:21:372231 DCHECK(main_task_runner_->BelongsToCurrentThread());
2232
Xiaohan Wang640b41d2018-12-18 19:00:462233 switch (reason) {
Xiaohan Wangb54a75282019-10-04 21:34:432234 case WaitingReason::kNoCdm:
Xiaohan Wang640b41d2018-12-18 19:00:462235 case WaitingReason::kNoDecryptionKey:
2236 encrypted_client_->DidBlockPlaybackWaitingForKey();
2237 // TODO(jrummell): didResumePlaybackBlockedForKey() should only be called
2238 // when a key has been successfully added (e.g. OnSessionKeysChange() with
2239 // |has_additional_usable_key| = true). http://crbug.com/461903
2240 encrypted_client_->DidResumePlaybackBlockedForKey();
2241 return;
Xiaohan Wang640b41d2018-12-18 19:00:462242
Xiaohan Wanga7224d62019-01-04 22:22:302243 // Ideally this should be handled by PipelineController directly without
2244 // being proxied here. But currently Pipeline::Client (|this|) is passed to
2245 // PipelineImpl directly without going through |pipeline_controller_|,
2246 // making it difficult to do.
2247 // TODO(xhwang): Handle this in PipelineController when we have a clearer
2248 // picture on how to refactor WebMediaPlayerImpl, PipelineController and
2249 // PipelineImpl.
2250 case WaitingReason::kDecoderStateLost:
Antonio Gomes81b56552019-05-15 22:15:282251 pipeline_controller_->OnDecoderStateLost();
Xiaohan Wanga7224d62019-01-04 22:22:302252 return;
2253 }
alokp967c902452016-05-06 05:21:372254}
2255
alokp5d86e9b2016-05-17 20:20:412256void WebMediaPlayerImpl::OnVideoNaturalSizeChange(const gfx::Size& size) {
2257 DCHECK(main_task_runner_->BelongsToCurrentThread());
Blink Reformat1c4d759e2017-04-09 16:34:542258 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
alokp5d86e9b2016-05-17 20:20:412259
Chris Cunningham038548b2017-07-10 22:36:302260 TRACE_EVENT0("media", "WebMediaPlayerImpl::OnVideoNaturalSizeChange");
xhwang60802652017-04-19 07:29:582261
xjz15b483f2017-01-12 00:21:362262 // The input |size| is from the decoded video frame, which is the original
2263 // natural size and need to be rotated accordingly.
Julien Isorce6c83d8de2017-10-12 13:11:292264 gfx::Size rotated_size = GetRotatedVideoSize(
Ted Meyer4a427632019-05-01 19:05:272265 pipeline_metadata_.video_decoder_config.video_transformation().rotation,
2266 size);
sandersd2c478422016-08-02 01:19:252267
xhwang60802652017-04-19 07:29:582268 RecordVideoNaturalSize(rotated_size);
2269
2270 gfx::Size old_size = pipeline_metadata_.natural_size;
2271 if (rotated_size == old_size)
alokp5d86e9b2016-05-17 20:20:412272 return;
2273
xjz516ef6d2017-01-07 00:23:062274 pipeline_metadata_.natural_size = rotated_size;
Dan Sanders7ef5d0f2019-05-03 18:30:112275
2276 if (using_media_player_renderer_ && old_size.IsEmpty()) {
2277 // If we are using MediaPlayerRenderer and this is the first size change, we
2278 // now know that there is a video track. This condition is paired with code
2279 // in CreateWatchTimeReporter() that guesses the existence of a video track.
2280 CreateWatchTimeReporter();
2281 } else {
Dan Sanders7ef5d0f2019-05-03 18:30:112282 UpdateSecondaryProperties();
2283 }
dalecurtis25405562017-04-14 23:35:112284
Chris Cunningham5b1b67eb2019-03-23 03:24:412285 if (video_decode_stats_reporter_ &&
2286 !video_decode_stats_reporter_->MatchesBucketedNaturalSize(
2287 pipeline_metadata_.natural_size)) {
2288 CreateVideoDecodeStatsReporter();
2289 }
Chris Cunninghamd9df58e2017-08-29 00:04:232290
[email protected]96665a82020-01-23 00:35:372291 // Create or replace the smoothness helper now that we have a size.
2292 UpdateSmoothnessHelper();
2293
Blink Reformat1c4d759e2017-04-09 16:34:542294 client_->SizeChanged();
xjz516ef6d2017-01-07 00:23:062295
xjz15b483f2017-01-12 00:21:362296 if (observer_)
2297 observer_->OnMetadataChanged(pipeline_metadata_);
peconn257951522017-06-09 18:24:592298
2299 delegate_->DidPlayerSizeChange(delegate_id_, NaturalSize());
alokp5d86e9b2016-05-17 20:20:412300}
2301
2302void WebMediaPlayerImpl::OnVideoOpacityChange(bool opaque) {
2303 DCHECK(main_task_runner_->BelongsToCurrentThread());
Blink Reformat1c4d759e2017-04-09 16:34:542304 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
alokp5d86e9b2016-05-17 20:20:412305
2306 opaque_ = opaque;
Dale Curtis357630f22019-01-18 01:10:172307 if (!surface_layer_for_video_enabled_ && video_layer_)
2308 video_layer_->SetContentsOpaque(opaque_);
2309 else if (bridge_->GetCcLayer())
CJ DiMeglioa2b13fbc2018-06-27 00:50:592310 bridge_->SetContentsOpaque(opaque_);
alokp5d86e9b2016-05-17 20:20:412311}
2312
[email protected]218ac8de2020-01-03 23:41:432313void WebMediaPlayerImpl::OnVideoFrameRateChange(base::Optional<int> fps) {
2314 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]c7a918e2020-01-17 00:18:272315 if (power_status_helper_)
2316 power_status_helper_->SetAverageFrameRate(fps);
[email protected]96665a82020-01-23 00:35:372317
2318 last_reported_fps_ = fps;
2319 UpdateSmoothnessHelper();
[email protected]218ac8de2020-01-03 23:41:432320}
2321
Chris Cunningham038548b2017-07-10 22:36:302322void WebMediaPlayerImpl::OnAudioConfigChange(const AudioDecoderConfig& config) {
2323 DCHECK(main_task_runner_->BelongsToCurrentThread());
2324 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
2325
Dale Curtisccfd0cca2017-08-31 01:27:562326 const bool codec_change =
2327 pipeline_metadata_.audio_decoder_config.codec() != config.codec();
Dale Curtisf8afcef32020-01-18 06:23:262328 const bool codec_profile_change =
2329 pipeline_metadata_.audio_decoder_config.profile() != config.profile();
2330
Chris Cunningham038548b2017-07-10 22:36:302331 pipeline_metadata_.audio_decoder_config = config;
2332
2333 if (observer_)
2334 observer_->OnMetadataChanged(pipeline_metadata_);
Dale Curtisccfd0cca2017-08-31 01:27:562335
Dale Curtisf8afcef32020-01-18 06:23:262336 if (codec_change || codec_profile_change)
Dale Curtis96d6e9382018-07-18 18:01:072337 UpdateSecondaryProperties();
Chris Cunningham038548b2017-07-10 22:36:302338}
2339
2340void WebMediaPlayerImpl::OnVideoConfigChange(const VideoDecoderConfig& config) {
2341 DCHECK(main_task_runner_->BelongsToCurrentThread());
2342 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
2343
Dale Curtisccfd0cca2017-08-31 01:27:562344 const bool codec_change =
2345 pipeline_metadata_.video_decoder_config.codec() != config.codec();
Chris Cunningham5b1b67eb2019-03-23 03:24:412346 const bool codec_profile_change =
2347 pipeline_metadata_.video_decoder_config.profile() != config.profile();
Dale Curtisccfd0cca2017-08-31 01:27:562348
Chris Cunningham038548b2017-07-10 22:36:302349 pipeline_metadata_.video_decoder_config = config;
2350
2351 if (observer_)
2352 observer_->OnMetadataChanged(pipeline_metadata_);
Chris Cunninghamd9df58e2017-08-29 00:04:232353
Dale Curtisf8afcef32020-01-18 06:23:262354 if (codec_change || codec_profile_change)
Dale Curtis96d6e9382018-07-18 18:01:072355 UpdateSecondaryProperties();
Chris Cunningham5b1b67eb2019-03-23 03:24:412356
2357 if (video_decode_stats_reporter_ && codec_profile_change)
2358 CreateVideoDecodeStatsReporter();
Chris Cunningham038548b2017-07-10 22:36:302359}
2360
avayvodeecec52c2017-02-14 01:25:092361void WebMediaPlayerImpl::OnVideoAverageKeyframeDistanceUpdate() {
2362 UpdateBackgroundVideoOptimizationState();
2363}
2364
Ted Meyerd5885f82019-07-16 19:19:172365void WebMediaPlayerImpl::OnAudioDecoderChange(const PipelineDecoderInfo& info) {
2366 media_metrics_provider_->SetAudioPipelineInfo(info);
2367 if (info.decoder_name == audio_decoder_name_)
Dale Curtisc7d2a7d22018-01-11 20:01:052368 return;
2369
Ted Meyerd5885f82019-07-16 19:19:172370 audio_decoder_name_ = info.decoder_name;
Dale Curtisc7d2a7d22018-01-11 20:01:052371
2372 // If there's no current reporter, there's nothing to be done.
2373 if (!watch_time_reporter_)
2374 return;
2375
Dale Curtis96d6e9382018-07-18 18:01:072376 UpdateSecondaryProperties();
Dale Curtisc7d2a7d22018-01-11 20:01:052377}
2378
Ted Meyerd5885f82019-07-16 19:19:172379void WebMediaPlayerImpl::OnVideoDecoderChange(const PipelineDecoderInfo& info) {
2380 media_metrics_provider_->SetVideoPipelineInfo(info);
2381 if (info.decoder_name == video_decoder_name_)
Dale Curtisc7d2a7d22018-01-11 20:01:052382 return;
2383
Ted Meyerd5885f82019-07-16 19:19:172384 video_decoder_name_ = info.decoder_name;
Dale Curtisc7d2a7d22018-01-11 20:01:052385
2386 // If there's no current reporter, there's nothing to be done.
2387 if (!watch_time_reporter_)
2388 return;
2389
Dale Curtis96d6e9382018-07-18 18:01:072390 UpdateSecondaryProperties();
Dale Curtisc7d2a7d22018-01-11 20:01:052391}
2392
sandersd35d2c3f2017-01-14 02:04:422393void WebMediaPlayerImpl::OnFrameHidden() {
sandersd1e49fb62015-12-12 01:18:062394 DCHECK(main_task_runner_->BelongsToCurrentThread());
avayvod39c102402016-11-23 21:43:132395
avayvod65fad272017-02-24 01:00:482396 // Backgrounding a video requires a user gesture to resume playback.
2397 if (IsHidden())
2398 video_locked_when_paused_when_hidden_ = true;
2399
dalecurtis04bdb582016-08-17 22:15:232400 if (watch_time_reporter_)
2401 watch_time_reporter_->OnHidden();
avayvod48a8be52016-08-04 19:52:502402
Chris Cunninghamd9df58e2017-08-29 00:04:232403 if (video_decode_stats_reporter_)
2404 video_decode_stats_reporter_->OnHidden();
2405
avayvod65fad272017-02-24 01:00:482406 UpdateBackgroundVideoOptimizationState();
sandersd50a635e2016-04-04 22:50:092407 UpdatePlayState();
dalecurtis8b8505e72016-06-10 21:59:172408
2409 // Schedule suspended playing media to be paused if the user doesn't come back
2410 // to it within some timeout period to avoid any autoplay surprises.
2411 ScheduleIdlePauseTimer();
Dale Curtisca1b78f2019-01-15 03:11:262412
2413 // Notify the compositor of our page visibility status.
2414 vfc_task_runner_->PostTask(
2415 FROM_HERE,
2416 base::BindOnce(&VideoFrameCompositor::SetIsPageVisible,
2417 base::Unretained(compositor_.get()), !IsHidden()));
sandersd1e49fb62015-12-12 01:18:062418}
2419
sandersd35d2c3f2017-01-14 02:04:422420void WebMediaPlayerImpl::OnFrameClosed() {
sandersd1e49fb62015-12-12 01:18:062421 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]28347e72017-06-27 17:30:112422
sandersd35d2c3f2017-01-14 02:04:422423 UpdatePlayState();
2424}
2425
2426void WebMediaPlayerImpl::OnFrameShown() {
2427 DCHECK(main_task_runner_->BelongsToCurrentThread());
2428 background_pause_timer_.Stop();
2429
avayvod65fad272017-02-24 01:00:482430 // Foreground videos don't require user gesture to continue playback.
2431 video_locked_when_paused_when_hidden_ = false;
2432
dalecurtis04bdb582016-08-17 22:15:232433 if (watch_time_reporter_)
2434 watch_time_reporter_->OnShown();
2435
Chris Cunninghamd9df58e2017-08-29 00:04:232436 if (video_decode_stats_reporter_)
2437 video_decode_stats_reporter_->OnShown();
2438
Dale Curtisca1b78f2019-01-15 03:11:262439 // Notify the compositor of our page visibility status.
2440 vfc_task_runner_->PostTask(
2441 FROM_HERE,
2442 base::BindOnce(&VideoFrameCompositor::SetIsPageVisible,
2443 base::Unretained(compositor_.get()), !IsHidden()));
2444
Dale Curtisdcbb81a2017-08-18 01:06:122445 UpdateBackgroundVideoOptimizationState();
avayvod65fad272017-02-24 01:00:482446
avayvod2135a642017-01-13 00:17:142447 if (paused_when_hidden_) {
2448 paused_when_hidden_ = false;
2449 OnPlay(); // Calls UpdatePlayState() so return afterwards.
2450 return;
2451 }
2452
sandersd50a635e2016-04-04 22:50:092453 UpdatePlayState();
sandersd1e49fb62015-12-12 01:18:062454}
2455
sandersd35d2c3f2017-01-14 02:04:422456void WebMediaPlayerImpl::OnIdleTimeout() {
dalecurtis0431cbf2016-03-12 01:19:432457 DCHECK(main_task_runner_->BelongsToCurrentThread());
2458
Dale Curtis99a9b482018-02-01 02:23:282459 // This should never be called when stale state testing overrides are used.
2460 DCHECK(!stale_state_override_for_testing_.has_value());
2461
sandersd35d2c3f2017-01-14 02:04:422462 // If we are attempting preroll, clear the stale flag.
2463 if (IsPrerollAttemptNeeded()) {
tguilbert1bb1c782017-01-23 21:15:112464 delegate_->ClearStaleFlag(delegate_id_);
sandersd35d2c3f2017-01-14 02:04:422465 return;
watkd026f792016-11-05 00:28:512466 }
sandersd50a635e2016-04-04 22:50:092467
sandersd35d2c3f2017-01-14 02:04:422468 UpdatePlayState();
dalecurtis0431cbf2016-03-12 01:19:432469}
2470
dalecurtisbb3eaac2016-01-27 21:10:252471void WebMediaPlayerImpl::OnPlay() {
Mounir Lamouri703106e2018-05-30 14:31:092472 client_->RequestPlay();
dalecurtisbb3eaac2016-01-27 21:10:252473}
2474
2475void WebMediaPlayerImpl::OnPause() {
Mounir Lamouri703106e2018-05-30 14:31:092476 client_->RequestPause();
dalecurtisbb3eaac2016-01-27 21:10:252477}
2478
François Beaufortb4fe7c62019-02-27 08:19:442479void WebMediaPlayerImpl::OnMuted(bool muted) {
2480 client_->RequestMuted(muted);
2481}
2482
Alec Douglas316cce42017-10-31 13:28:082483void WebMediaPlayerImpl::OnSeekForward(double seconds) {
2484 DCHECK_GE(seconds, 0) << "Attempted to seek by a negative number of seconds";
2485 client_->RequestSeek(CurrentTime() + seconds);
2486}
2487
2488void WebMediaPlayerImpl::OnSeekBackward(double seconds) {
2489 DCHECK_GE(seconds, 0) << "Attempted to seek by a negative number of seconds";
2490 client_->RequestSeek(CurrentTime() - seconds);
2491}
2492
Jazz Xuf8564dc2020-01-24 14:26:022493void WebMediaPlayerImpl::OnEnterPictureInPicture() {
2494 client_->RequestEnterPictureInPicture();
2495}
2496
2497void WebMediaPlayerImpl::OnExitPictureInPicture() {
2498 client_->RequestExitPictureInPicture();
2499}
2500
dalecurtisbb3eaac2016-01-27 21:10:252501void WebMediaPlayerImpl::OnVolumeMultiplierUpdate(double multiplier) {
2502 volume_multiplier_ = multiplier;
Blink Reformat1c4d759e2017-04-09 16:34:542503 SetVolume(volume_);
dalecurtisbb3eaac2016-01-27 21:10:252504}
2505
zqzhang8ac49002017-03-16 21:51:352506void WebMediaPlayerImpl::OnBecamePersistentVideo(bool value) {
Blink Reformat1c4d759e2017-04-09 16:34:542507 client_->OnBecamePersistentVideo(value);
[email protected]6490e2d12019-01-14 19:18:372508 overlay_info_.is_persistent_video = value;
2509 MaybeSendOverlayInfoToDecoder();
zqzhang8ac49002017-03-16 21:51:352510}
2511
[email protected]201ce4ba2020-01-09 22:19:092512void WebMediaPlayerImpl::OnPowerExperimentState(bool state) {
2513 if (power_status_helper_)
2514 power_status_helper_->UpdatePowerExperimentState(state);
2515}
2516
watkdee516f2016-02-18 02:22:192517void WebMediaPlayerImpl::ScheduleRestart() {
sandersd50a635e2016-04-04 22:50:092518 // TODO(watk): All restart logic should be moved into PipelineController.
Antonio Gomes81b56552019-05-15 22:15:282519 if (pipeline_controller_->IsPipelineRunning() &&
2520 !pipeline_controller_->IsPipelineSuspended()) {
watkdee516f2016-02-18 02:22:192521 pending_suspend_resume_cycle_ = true;
sandersd50a635e2016-04-04 22:50:092522 UpdatePlayState();
watkdee516f2016-02-18 02:22:192523 }
2524}
2525
Blink Reformat1c4d759e2017-04-09 16:34:542526void WebMediaPlayerImpl::RequestRemotePlaybackDisabled(bool disabled) {
miu77f914c2016-11-19 23:56:182527 if (observer_)
2528 observer_->OnRemotePlaybackDisabled(disabled);
2529}
2530
Thomas Guilbert7350fdad2019-01-29 23:09:242531#if defined(OS_ANDROID)
Thomas Guilbertb341bae02018-05-09 00:02:132532void WebMediaPlayerImpl::FlingingStarted() {
2533 DCHECK(main_task_runner_->BelongsToCurrentThread());
2534 DCHECK(!disable_pipeline_auto_suspend_);
2535 disable_pipeline_auto_suspend_ = true;
2536
Thomas Guilbert29ae1a902018-10-20 01:53:382537 is_flinging_ = true;
2538
Thomas Guilbertb341bae02018-05-09 00:02:132539 // Capabilities reporting should only be performed for local playbacks.
2540 video_decode_stats_reporter_.reset();
2541
2542 // Requests to restart media pipeline. A flinging renderer will be created via
2543 // the |renderer_factory_selector_|.
2544 ScheduleRestart();
2545}
2546
2547void WebMediaPlayerImpl::FlingingStopped() {
2548 DCHECK(main_task_runner_->BelongsToCurrentThread());
2549 DCHECK(disable_pipeline_auto_suspend_);
2550 disable_pipeline_auto_suspend_ = false;
2551
Thomas Guilbert29ae1a902018-10-20 01:53:382552 is_flinging_ = false;
2553
Thomas Guilbertb341bae02018-05-09 00:02:132554 CreateVideoDecodeStatsReporter();
2555
2556 ScheduleRestart();
2557}
Thomas Guilbert901808982019-07-03 20:38:182558
2559void WebMediaPlayerImpl::OnRemotePlayStateChange(MediaStatus::State state) {
2560 DCHECK(is_flinging_);
Thomas Guilbertf6d0702e2019-09-12 23:40:142561 DCHECK(main_task_runner_->BelongsToCurrentThread());
Thomas Guilbert901808982019-07-03 20:38:182562
2563 if (state == MediaStatus::State::PLAYING && Paused()) {
2564 DVLOG(1) << __func__ << " requesting PLAY.";
2565 client_->RequestPlay();
2566 } else if (state == MediaStatus::State::PAUSED && !Paused()) {
2567 DVLOG(1) << __func__ << " requesting PAUSE.";
2568 client_->RequestPause();
2569 }
2570}
Thomas Guilbert7350fdad2019-01-29 23:09:242571#endif // defined(OS_ANDROID)
hubbee4027f92016-05-19 05:18:132572
Blink Reformat1c4d759e2017-04-09 16:34:542573void WebMediaPlayerImpl::SetPoster(const blink::WebURL& poster) {
Dan Sanderscd8981c2017-08-31 22:37:022574 has_poster_ = !poster.IsEmpty();
Dan Sanderscd8981c2017-08-31 22:37:022575}
xjzc102fd82017-01-04 20:13:532576
[email protected]fee8a902014-06-03 13:43:362577void WebMediaPlayerImpl::DataSourceInitialized(bool success) {
pkastingf5279482016-07-27 02:18:202578 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:432579 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]a9415292012-01-19 19:55:202580
Thomas Guilberta8a6e922019-02-01 00:02:472581 if (observer_ && mb_data_source_)
Dale Curtis4841c712018-12-13 18:14:052582 observer_->OnDataSourceInitialized(mb_data_source_->GetUrlAfterRedirects());
Anton Vayvod09fa66e2017-07-20 23:02:122583
[email protected]d250190da3b2012-07-23 22:57:302584 if (!success) {
Blink Reformat1c4d759e2017-04-09 16:34:542585 SetNetworkState(WebMediaPlayer::kNetworkStateFormatError);
Dale Curtis74612b72017-12-14 20:56:192586 media_metrics_provider_->OnError(PIPELINE_ERROR_NETWORK);
sandersd50a635e2016-04-04 22:50:092587
2588 // Not really necessary, since the pipeline was never started, but it at
2589 // least this makes sure that the error handling code is in sync.
2590 UpdatePlayState();
2591
[email protected]a9415292012-01-19 19:55:202592 return;
2593 }
2594
hubbee2cc88c092017-07-14 23:10:412595 // No point in preloading data as we'll probably just throw it away anyways.
Dale Curtis4841c712018-12-13 18:14:052596 if (IsStreaming() && preload_ > MultibufferDataSource::METADATA &&
2597 mb_data_source_) {
2598 mb_data_source_->SetPreload(MultibufferDataSource::METADATA);
hubbee2cc88c092017-07-14 23:10:412599 }
2600
[email protected]ef8394c2013-08-21 20:26:302601 StartPipeline();
[email protected]a9415292012-01-19 19:55:202602}
2603
[email protected]122f40252012-06-12 05:01:562604void WebMediaPlayerImpl::NotifyDownloading(bool is_downloading) {
hubbeb2d3efd2017-05-05 23:26:382605 DVLOG(1) << __func__ << "(" << is_downloading << ")";
Blink Reformat1c4d759e2017-04-09 16:34:542606 if (!is_downloading && network_state_ == WebMediaPlayer::kNetworkStateLoading)
2607 SetNetworkState(WebMediaPlayer::kNetworkStateIdle);
2608 else if (is_downloading &&
2609 network_state_ == WebMediaPlayer::kNetworkStateIdle)
2610 SetNetworkState(WebMediaPlayer::kNetworkStateLoading);
hubbeb2d3efd2017-05-05 23:26:382611 if (ready_state_ == ReadyState::kReadyStateHaveFutureData && !is_downloading)
2612 SetReadyState(WebMediaPlayer::kReadyStateHaveEnoughData);
[email protected]122f40252012-06-12 05:01:562613}
2614
liberato2ff93ad2017-05-17 07:28:242615void WebMediaPlayerImpl::OnOverlayRoutingToken(
2616 const base::UnguessableToken& token) {
2617 DCHECK(overlay_mode_ == OverlayMode::kUseAndroidOverlay);
liberatofe8f9692017-06-08 19:17:362618 // TODO(liberato): |token| should already be a RoutingToken.
2619 overlay_routing_token_is_pending_ = false;
2620 overlay_routing_token_ = OverlayInfo::RoutingToken(token);
liberato2ff93ad2017-05-17 07:28:242621 MaybeSendOverlayInfoToDecoder();
2622}
2623
2624void WebMediaPlayerImpl::OnOverlayInfoRequested(
dalecurtis4b632fce22016-11-10 00:52:172625 bool decoder_requires_restart_for_overlay,
Jose Lopes689012d2020-02-27 09:04:492626 ProvideOverlayInfoCB provide_overlay_info_cb) {
watkdee516f2016-02-18 02:22:192627 DCHECK(main_task_runner_->BelongsToCurrentThread());
watkdee516f2016-02-18 02:22:192628
Chris Watkins557f84d2017-09-16 02:31:462629 // If we get a non-null cb, a decoder is initializing and requires overlay
2630 // info. If we get a null cb, a previously initialized decoder is
2631 // unregistering for overlay info updates.
Dale Curtise25163812018-09-21 22:13:392632 if (!provide_overlay_info_cb) {
tsunghungee562e92016-07-20 18:03:312633 decoder_requires_restart_for_overlay_ = false;
liberato2ff93ad2017-05-17 07:28:242634 provide_overlay_info_cb_.Reset();
watkdee516f2016-02-18 02:22:192635 return;
2636 }
2637
dalecurtis4b632fce22016-11-10 00:52:172638 // If |decoder_requires_restart_for_overlay| is true, we must restart the
2639 // pipeline for fullscreen transitions. The decoder is unable to switch
2640 // surfaces otherwise. If false, we simply need to tell the decoder about the
2641 // new surface and it will handle things seamlessly.
Chris Watkins557f84d2017-09-16 02:31:462642 // For encrypted video we pretend that the decoder doesn't require a restart
2643 // because it needs an overlay all the time anyway. We'll switch into
2644 // |always_enable_overlays_| mode below.
2645 decoder_requires_restart_for_overlay_ =
2646 (overlay_mode_ == OverlayMode::kUseAndroidOverlay && is_encrypted_)
2647 ? false
2648 : decoder_requires_restart_for_overlay;
Jose Lopes689012d2020-02-27 09:04:492649 provide_overlay_info_cb_ = std::move(provide_overlay_info_cb);
dalecurtis4b632fce22016-11-10 00:52:172650
Chris Watkins557f84d2017-09-16 02:31:462651 // If the decoder doesn't require restarts for surface transitions, and we're
2652 // using AndroidOverlay mode, we can always enable the overlay and the decoder
2653 // can choose whether or not to use it. Otherwise, we'll restart the decoder
2654 // and enable the overlay on fullscreen transitions.
[email protected]77568482017-06-21 21:16:522655 if (overlay_mode_ == OverlayMode::kUseAndroidOverlay &&
Chris Watkins557f84d2017-09-16 02:31:462656 !decoder_requires_restart_for_overlay_) {
[email protected]c8d574722017-08-30 20:53:432657 always_enable_overlays_ = true;
[email protected]77568482017-06-21 21:16:522658 if (!overlay_enabled_)
2659 EnableOverlay();
2660 }
2661
Chris Watkins557f84d2017-09-16 02:31:462662 // Send the overlay info if we already have it. If not, it will be sent later.
liberato2ff93ad2017-05-17 07:28:242663 MaybeSendOverlayInfoToDecoder();
2664}
2665
2666void WebMediaPlayerImpl::MaybeSendOverlayInfoToDecoder() {
2667 // If the decoder didn't request overlay info, then don't send it.
2668 if (!provide_overlay_info_cb_)
dalecurtis4b632fce22016-11-10 00:52:172669 return;
2670
liberato2ff93ad2017-05-17 07:28:242671 // We should send the overlay info as long as we know it. This includes the
2672 // case where |!overlay_enabled_|, since we want to tell the decoder to avoid
2673 // using overlays. Assuming that the decoder has requested info, the only
2674 // case in which we don't want to send something is if we've requested the
2675 // info but not received it yet. Then, we should wait until we do.
liberatofe8f9692017-06-08 19:17:362676 //
2677 // Initialization requires this; AVDA should start with enough info to make an
2678 // overlay, so that (pre-M) the initial codec is created with the right output
2679 // surface; it can't switch later.
[email protected]f7df5b342018-07-13 20:22:132680 if (overlay_mode_ == OverlayMode::kUseAndroidOverlay) {
liberatofe8f9692017-06-08 19:17:362681 if (overlay_routing_token_is_pending_)
liberato2ff93ad2017-05-17 07:28:242682 return;
liberatofe8f9692017-06-08 19:17:362683
2684 overlay_info_.routing_token = overlay_routing_token_;
liberato2ff93ad2017-05-17 07:28:242685 }
2686
liberato2ff93ad2017-05-17 07:28:242687 // If restart is required, the callback is one-shot only.
2688 if (decoder_requires_restart_for_overlay_) {
Dale Curtise25163812018-09-21 22:13:392689 std::move(provide_overlay_info_cb_).Run(overlay_info_);
liberato2ff93ad2017-05-17 07:28:242690 } else {
liberatofe8f9692017-06-08 19:17:362691 provide_overlay_info_cb_.Run(overlay_info_);
liberato2ff93ad2017-05-17 07:28:242692 }
watkdee516f2016-02-18 02:22:192693}
2694
Xiaohan Wangcd4df0a2019-12-04 20:59:242695std::unique_ptr<Renderer> WebMediaPlayerImpl::CreateRenderer(
Xiaohan Wang48aaa192019-12-05 01:29:002696 base::Optional<RendererFactoryType> factory_type) {
dcheng37b415b92017-01-27 20:17:432697 DCHECK(main_task_runner_->BelongsToCurrentThread());
2698
[email protected]c8d574722017-08-30 20:53:432699 // Make sure that overlays are enabled if they're always allowed.
2700 if (always_enable_overlays_)
tsunghungee562e92016-07-20 18:03:312701 EnableOverlay();
2702
liberato2ff93ad2017-05-17 07:28:242703 RequestOverlayInfoCB request_overlay_info_cb;
watkdee516f2016-02-18 02:22:192704#if defined(OS_ANDROID)
Jose Lopes689012d2020-02-27 09:04:492705 request_overlay_info_cb = BindToCurrentLoop(base::BindRepeating(
2706 &WebMediaPlayerImpl::OnOverlayInfoRequested, weak_this_));
watkdee516f2016-02-18 02:22:192707#endif
Xiaohan Wangcd4df0a2019-12-04 20:59:242708
2709 if (factory_type) {
Xiaohan Wang48aaa192019-12-05 01:29:002710 DVLOG(1) << __func__
2711 << ": factory_type=" << static_cast<int>(factory_type.value());
Xiaohan Wangcd4df0a2019-12-04 20:59:242712 renderer_factory_selector_->SetBaseFactoryType(factory_type.value());
2713 }
2714
Dan Sanders6edfd782019-08-13 00:13:182715 reported_renderer_type_ = renderer_factory_selector_->GetCurrentFactoryType();
Xiaohan Wang73b433f2019-11-05 20:13:012716
Xiaohan Wang2480de72019-11-15 01:44:472717 return renderer_factory_selector_->GetCurrentFactory()->CreateRenderer(
2718 media_task_runner_, worker_task_runner_, audio_source_provider_.get(),
Jose Lopes689012d2020-02-27 09:04:492719 compositor_.get(), std::move(request_overlay_info_cb),
2720 client_->TargetColorSpace());
sandersd1e49fb62015-12-12 01:18:062721}
2722
[email protected]ef8394c2013-08-21 20:26:302723void WebMediaPlayerImpl::StartPipeline() {
acolwellb4034942014-08-28 15:42:432724 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]ddbc6ff2013-04-19 15:28:332725
xhwange8c4181a2014-12-06 08:10:012726 Demuxer::EncryptedMediaInitDataCB encrypted_media_init_data_cb =
Jose Lopes066452e2020-02-19 20:45:342727 BindToCurrentLoop(base::BindRepeating(
Antonio Gomes142f32a2019-05-15 23:32:562728 &WebMediaPlayerImpl::OnEncryptedMediaInitData, weak_this_));
[email protected]2b57e2e2014-05-09 11:07:252729
Dale Curtis3899090ea2018-01-12 00:10:352730 vfc_task_runner_->PostTask(
2731 FROM_HERE,
2732 base::BindOnce(&VideoFrameCompositor::SetOnNewProcessedFrameCallback,
2733 base::Unretained(compositor_.get()),
2734 BindToCurrentLoop(base::BindOnce(
Antonio Gomes142f32a2019-05-15 23:32:562735 &WebMediaPlayerImpl::OnFirstFrame, weak_this_))));
Dale Curtis3899090ea2018-01-12 00:10:352736
Thomas Guilbert55b48d92019-03-25 23:16:542737#if defined(OS_ANDROID)
Dale Curtis65c151a2019-02-26 02:09:322738 if (demuxer_found_hls_ ||
2739 renderer_factory_selector_->GetCurrentFactory()
2740 ->GetRequiredMediaResourceType() == MediaResource::Type::URL) {
Thomas Guilbert8a42fcf2019-03-01 20:21:452741 // MediaPlayerRendererClientFactory is the only factory that a uses
2742 // MediaResource::Type::URL for the moment.
tguilbert75e2bf62017-04-26 20:13:122743 using_media_player_renderer_ = true;
2744
Chris Cunninghamd9df58e2017-08-29 00:04:232745 // MediaPlayerRenderer does not provide pipeline stats, so nuke capabilities
2746 // reporter.
2747 video_decode_stats_reporter_.reset();
2748
Eugene Zemtsov77d56262020-03-06 05:52:032749 SetDemuxer(std::make_unique<MediaUrlDemuxer>(
Maks Orlovichab27e242020-01-07 18:10:392750 media_task_runner_, loaded_url_,
2751 frame_->GetDocument().SiteForCookies().RepresentativeUrl(),
Christian Dullweberacff9bd32019-08-20 09:44:372752 frame_->GetDocument().TopFrameOrigin(),
Eugene Zemtsov77d56262020-03-06 05:52:032753 allow_media_player_renderer_credentials_, demuxer_found_hls_));
Antonio Gomes81b56552019-05-15 22:15:282754 pipeline_controller_->Start(Pipeline::StartType::kNormal, demuxer_.get(),
2755 this, false, false);
tguilbert25a4d112016-10-13 21:56:512756 return;
2757 }
Thomas Guilbert55b48d92019-03-25 23:16:542758#endif // defined(OS_ANDROID)
tguilbert25a4d112016-10-13 21:56:512759
[email protected]ddbc6ff2013-04-19 15:28:332760 // Figure out which demuxer to use.
Blink Reformat1c4d759e2017-04-09 16:34:542761 if (load_type_ != kLoadTypeMediaSource) {
[email protected]ddbc6ff2013-04-19 15:28:332762 DCHECK(!chunk_demuxer_);
[email protected]f5443ef72013-04-22 04:03:382763 DCHECK(data_source_);
2764
Dale Curtisbcf523b2018-01-17 02:59:012765#if BUILDFLAG(ENABLE_FFMPEG)
servolk81e01e02016-03-05 03:29:152766 Demuxer::MediaTracksUpdatedCB media_tracks_updated_cb =
Jose Lopes239a0912020-02-20 10:59:332767 BindToCurrentLoop(base::BindRepeating(
Antonio Gomes142f32a2019-05-15 23:32:562768 &WebMediaPlayerImpl::OnFFmpegMediaTracksUpdated, weak_this_));
servolk81e01e02016-03-05 03:29:152769
Eugene Zemtsov77d56262020-03-06 05:52:032770 SetDemuxer(std::make_unique<FFmpegDemuxer>(
dalecurtis9cddc0b2017-04-19 21:23:382771 media_task_runner_, data_source_.get(), encrypted_media_init_data_cb,
Eugene Zemtsov77d56262020-03-06 05:52:032772 media_tracks_updated_cb, media_log_.get(), IsLocalFile(loaded_url_)));
j.isorcef6778e652015-11-16 17:14:252773#else
alokp967c902452016-05-06 05:21:372774 OnError(PipelineStatus::DEMUXER_ERROR_COULD_NOT_OPEN);
j.isorcef6778e652015-11-16 17:14:252775 return;
2776#endif
[email protected]ddbc6ff2013-04-19 15:28:332777 } else {
[email protected]f5443ef72013-04-22 04:03:382778 DCHECK(!chunk_demuxer_);
2779 DCHECK(!data_source_);
2780
Antonio Gomes142f32a2019-05-15 23:32:562781 chunk_demuxer_ =
2782 new ChunkDemuxer(BindToCurrentLoop(base::Bind(
2783 &WebMediaPlayerImpl::OnDemuxerOpened, weak_this_)),
2784 BindToCurrentLoop(base::Bind(
2785 &WebMediaPlayerImpl::OnProgress, weak_this_)),
2786 encrypted_media_init_data_cb, media_log_.get());
Eugene Zemtsov77d56262020-03-06 05:52:032787 SetDemuxer(std::unique_ptr<Demuxer>(chunk_demuxer_));
servolkf94b4602017-01-31 16:44:272788
2789 if (base::FeatureList::IsEnabled(kMemoryPressureBasedSourceBufferGC)) {
2790 // base::Unretained is safe because |this| owns memory_pressure_listener_.
2791 memory_pressure_listener_ =
Gyuyoung Kim62a5de42018-01-10 09:48:422792 std::make_unique<base::MemoryPressureListener>(base::Bind(
servolkf94b4602017-01-31 16:44:272793 &WebMediaPlayerImpl::OnMemoryPressure, base::Unretained(this)));
2794 }
[email protected]ddbc6ff2013-04-19 15:28:332795 }
2796
sandersdb5e21462016-03-09 01:49:072797 // TODO(sandersd): FileSystem objects may also be non-static, but due to our
2798 // caching layer such situations are broken already. http://crbug.com/593159
2799 bool is_static = !chunk_demuxer_;
avayvod102cdb62017-01-07 03:11:092800 bool is_streaming = IsStreaming();
sandersdb8eb5f1d2016-11-19 04:04:022801 UMA_HISTOGRAM_BOOLEAN("Media.IsStreaming", is_streaming);
sandersdb5e21462016-03-09 01:49:072802
Dale Curtis2dc6089a2018-03-26 16:47:582803 // If possible attempt to avoid decoder spool up until playback starts.
2804 Pipeline::StartType start_type = Pipeline::StartType::kNormal;
Dale Curtis7c63f2e22018-09-19 21:06:272805 if (!chunk_demuxer_ && preload_ == MultibufferDataSource::METADATA &&
Dale Curtisd6ccd1992019-04-29 19:03:462806 !client_->CouldPlayIfEnoughData() && !IsStreaming()) {
Dale Curtis7c63f2e22018-09-19 21:06:272807 start_type =
2808 (has_poster_ || base::FeatureList::IsEnabled(kPreloadMetadataLazyLoad))
2809 ? Pipeline::StartType::kSuspendAfterMetadata
2810 : Pipeline::StartType::kSuspendAfterMetadataForAudioOnly;
Dale Curtis2dc6089a2018-03-26 16:47:582811 attempting_suspended_start_ = true;
2812 }
2813
[email protected]f5443ef72013-04-22 04:03:382814 // ... and we're ready to go!
sandersd1e49fb62015-12-12 01:18:062815 // TODO(sandersd): On Android, defer Start() if the tab is not visible.
sandersdb8eb5f1d2016-11-19 04:04:022816 seeking_ = true;
Antonio Gomes81b56552019-05-15 22:15:282817 pipeline_controller_->Start(start_type, demuxer_.get(), this, is_streaming,
2818 is_static);
[email protected]f5443ef72013-04-22 04:03:382819}
2820
2821void WebMediaPlayerImpl::SetNetworkState(WebMediaPlayer::NetworkState state) {
pkastingf5279482016-07-27 02:18:202822 DVLOG(1) << __func__ << "(" << state << ")";
acolwellb4034942014-08-28 15:42:432823 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]f5443ef72013-04-22 04:03:382824 network_state_ = state;
2825 // Always notify to ensure client has the latest value.
Blink Reformat1c4d759e2017-04-09 16:34:542826 client_->NetworkStateChanged();
[email protected]f5443ef72013-04-22 04:03:382827}
2828
2829void WebMediaPlayerImpl::SetReadyState(WebMediaPlayer::ReadyState state) {
pkastingf5279482016-07-27 02:18:202830 DVLOG(1) << __func__ << "(" << state << ")";
acolwellb4034942014-08-28 15:42:432831 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]f5443ef72013-04-22 04:03:382832
Blink Reformat1c4d759e2017-04-09 16:34:542833 if (state == WebMediaPlayer::kReadyStateHaveEnoughData && data_source_ &&
Dale Curtis4841c712018-12-13 18:14:052834 data_source_->AssumeFullyBuffered() &&
2835 network_state_ == WebMediaPlayer::kNetworkStateLoading) {
Blink Reformat1c4d759e2017-04-09 16:34:542836 SetNetworkState(WebMediaPlayer::kNetworkStateLoaded);
Dale Curtis4841c712018-12-13 18:14:052837 }
[email protected]f5443ef72013-04-22 04:03:382838
2839 ready_state_ = state;
sandersd50a635e2016-04-04 22:50:092840 highest_ready_state_ = std::max(highest_ready_state_, ready_state_);
2841
[email protected]f5443ef72013-04-22 04:03:382842 // Always notify to ensure client has the latest value.
Blink Reformat1c4d759e2017-04-09 16:34:542843 client_->ReadyStateChanged();
[email protected]f5443ef72013-04-22 04:03:382844}
2845
Antonio Gomesa38bb7cb2019-05-31 03:02:522846scoped_refptr<blink::WebAudioSourceProviderImpl>
2847WebMediaPlayerImpl::GetAudioSourceProvider() {
2848 return audio_source_provider_;
[email protected]f5443ef72013-04-22 04:03:382849}
2850
Jiajia Qin82acdc02017-07-31 09:55:142851scoped_refptr<VideoFrame> WebMediaPlayerImpl::GetCurrentFrameFromCompositor()
2852 const {
xhwang213e50c2016-10-10 23:56:312853 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]dd061e12014-05-06 19:21:222854 TRACE_EVENT0("media", "WebMediaPlayerImpl::GetCurrentFrameFromCompositor");
xhwang213e50c2016-10-10 23:56:312855
Thomas Guilbertd85407412017-11-08 05:03:462856 // Can be null.
2857 scoped_refptr<VideoFrame> video_frame =
2858 compositor_->GetCurrentFrameOnAnyThread();
[email protected]dd061e12014-05-06 19:21:222859
Thomas Guilbertd85407412017-11-08 05:03:462860 // base::Unretained is safe here because |compositor_| is destroyed on
2861 // |vfc_task_runner_|. The destruction is queued from |this|' destructor,
2862 // which also runs on |main_task_runner_|, which makes it impossible for
2863 // UpdateCurrentFrameIfStale() to be queued after |compositor_|'s dtor.
CJ DiMeglio2302d202017-08-31 08:38:042864 vfc_task_runner_->PostTask(
Dale Curtisee9be30012018-09-21 22:21:512865 FROM_HERE,
2866 base::BindOnce(&VideoFrameCompositor::UpdateCurrentFrameIfStale,
2867 base::Unretained(compositor_.get())));
kainino36eeff82017-03-30 00:55:302868
[email protected]dd061e12014-05-06 19:21:222869 return video_frame;
2870}
2871
sandersd50a635e2016-04-04 22:50:092872void WebMediaPlayerImpl::UpdatePlayState() {
xhwang213e50c2016-10-10 23:56:312873 DCHECK(main_task_runner_->BelongsToCurrentThread());
hubbee2cc88c092017-07-14 23:10:412874 bool can_auto_suspend = !disable_pipeline_auto_suspend_;
2875 // For streaming videos, we only allow suspending at the very beginning of the
2876 // video, and only if we know the length of the video. (If we don't know
2877 // the length, it might be a dynamically generated video, and suspending
2878 // will not work at all.)
2879 if (IsStreaming()) {
2880 bool at_beginning =
2881 ready_state_ == WebMediaPlayer::kReadyStateHaveNothing ||
2882 CurrentTime() == 0.0;
2883 if (!at_beginning || GetPipelineMediaDuration() == kInfiniteDuration)
2884 can_auto_suspend = false;
2885 }
xhwang213e50c2016-10-10 23:56:312886
Antonio Gomes81b56552019-05-15 22:15:282887 bool is_suspended = pipeline_controller_->IsSuspended();
Sergey Volk8b09c2c52018-12-12 23:20:402888 bool is_backgrounded = IsBackgroundSuspendEnabled(this) && IsHidden();
sandersdaaff1a652016-11-17 01:47:252889 PlayState state = UpdatePlayState_ComputePlayState(
Thomas Guilbert7350fdad2019-01-29 23:09:242890 is_flinging_, can_auto_suspend, is_suspended, is_backgrounded);
sandersd35d2c3f2017-01-14 02:04:422891 SetDelegateState(state.delegate_state, state.is_idle);
sandersd50a635e2016-04-04 22:50:092892 SetMemoryReportingState(state.is_memory_reporting_enabled);
2893 SetSuspendState(state.is_suspended || pending_suspend_resume_cycle_);
[email protected]dc996312019-12-19 19:26:382894 if (power_status_helper_) {
2895 // Make sure that we're in something like steady-state before recording.
2896 power_status_helper_->SetIsPlaying(
2897 !paused_ && !seeking_ && !IsHidden() && !state.is_suspended &&
2898 ready_state_ == kReadyStateHaveEnoughData);
2899 }
[email protected]91379332020-01-26 03:58:202900 UpdateSmoothnessHelper();
sandersd50a635e2016-04-04 22:50:092901}
dalecurtis5bbc487e2016-02-27 04:15:052902
Becca Hughes7a85bf22019-07-24 16:16:582903void WebMediaPlayerImpl::UpdateMediaPositionState() {
2904 DCHECK(delegate_);
2905
2906 // When seeking the current time can go beyond the duration so we should
2907 // cap the current time at the duration.
2908 base::TimeDelta duration = GetPipelineMediaDuration();
2909 base::TimeDelta current_time = GetCurrentTimeInternal();
2910 if (current_time > duration)
2911 current_time = duration;
2912
2913 media_session::MediaPosition new_position(paused_ ? 0.0 : playback_rate_,
2914 duration, current_time);
2915
2916 if (media_position_state_ == new_position)
2917 return;
2918
2919 DVLOG(2) << __func__ << "(" << new_position.ToString() << ")";
2920 media_position_state_ = new_position;
2921 delegate_->DidPlayerMediaPositionStateChange(delegate_id_,
2922 media_position_state_);
2923}
2924
sandersd35d2c3f2017-01-14 02:04:422925void WebMediaPlayerImpl::SetDelegateState(DelegateState new_state,
2926 bool is_idle) {
tguilbert1bb1c782017-01-23 21:15:112927 DCHECK(delegate_);
Dale Curtis779ed842018-03-10 06:20:132928 DVLOG(2) << __func__ << "(" << static_cast<int>(new_state) << ", " << is_idle
2929 << ")";
dalecurtis5bbc487e2016-02-27 04:15:052930
sandersd35d2c3f2017-01-14 02:04:422931 // Prevent duplicate delegate calls.
2932 // TODO(sandersd): Move this deduplication into the delegate itself.
2933 // TODO(sandersd): WebContentsObserverSanityChecker does not allow sending the
2934 // 'playing' IPC more than once in a row, even if the metadata has changed.
2935 // Figure out whether it should.
Mounir Lamouri366dd8472018-06-19 17:20:042936 // Pretend that the media has no audio if it never played unmuted. This is to
2937 // avoid any action related to audible media such as taking audio focus or
2938 // showing a media notification. To preserve a consistent experience, it does
2939 // not apply if a media was audible so the system states do not flicker
2940 // depending on whether the user muted the player.
2941 bool has_audio = HasAudio() && !client_->WasAlwaysMuted();
sandersd35d2c3f2017-01-14 02:04:422942 if (delegate_state_ == new_state &&
2943 (delegate_state_ != DelegateState::PLAYING ||
2944 delegate_has_audio_ == has_audio)) {
2945 return;
mlamouri910111362016-11-04 11:28:242946 }
sandersd50a635e2016-04-04 22:50:092947 delegate_state_ = new_state;
sandersd35d2c3f2017-01-14 02:04:422948 delegate_has_audio_ = has_audio;
sandersd50a635e2016-04-04 22:50:092949
sandersd35d2c3f2017-01-14 02:04:422950 switch (new_state) {
sandersd50a635e2016-04-04 22:50:092951 case DelegateState::GONE:
2952 delegate_->PlayerGone(delegate_id_);
2953 break;
mlamouri910111362016-11-04 11:28:242954 case DelegateState::PLAYING: {
peconn257951522017-06-09 18:24:592955 if (HasVideo())
2956 delegate_->DidPlayerSizeChange(delegate_id_, NaturalSize());
zqzhang5d8eab72016-08-26 20:34:302957 delegate_->DidPlay(
Blink Reformat1c4d759e2017-04-09 16:34:542958 delegate_id_, HasVideo(), has_audio,
Dale Curtisca1b78f2019-01-15 03:11:262959 DurationToMediaContentType(GetPipelineMediaDuration()));
sandersd50a635e2016-04-04 22:50:092960 break;
mlamouri910111362016-11-04 11:28:242961 }
sandersd50a635e2016-04-04 22:50:092962 case DelegateState::PAUSED:
sandersd35d2c3f2017-01-14 02:04:422963 delegate_->DidPause(delegate_id_);
sandersd50a635e2016-04-04 22:50:092964 break;
dalecurtis0f0097a2015-12-01 17:40:472965 }
sandersd35d2c3f2017-01-14 02:04:422966
2967 delegate_->SetIdle(delegate_id_, is_idle);
dalecurtis0f0097a2015-12-01 17:40:472968}
2969
sandersd50a635e2016-04-04 22:50:092970void WebMediaPlayerImpl::SetMemoryReportingState(
2971 bool is_memory_reporting_enabled) {
2972 if (memory_usage_reporting_timer_.IsRunning() ==
2973 is_memory_reporting_enabled) {
hubbed5f36882016-01-15 22:40:372974 return;
sandersd50a635e2016-04-04 22:50:092975 }
sandersd1c0bba02016-03-04 23:14:082976
sandersd50a635e2016-04-04 22:50:092977 if (is_memory_reporting_enabled) {
2978 memory_usage_reporting_timer_.Start(FROM_HERE,
2979 base::TimeDelta::FromSeconds(2), this,
2980 &WebMediaPlayerImpl::ReportMemoryUsage);
2981 } else {
2982 memory_usage_reporting_timer_.Stop();
2983 ReportMemoryUsage();
2984 }
2985}
2986
2987void WebMediaPlayerImpl::SetSuspendState(bool is_suspended) {
xhwang213e50c2016-10-10 23:56:312988 DCHECK(main_task_runner_->BelongsToCurrentThread());
Dale Curtis779ed842018-03-10 06:20:132989 DVLOG(2) << __func__ << "(" << is_suspended << ")";
xhwang213e50c2016-10-10 23:56:312990
sandersd50a635e2016-04-04 22:50:092991 // Do not change the state after an error has occurred.
2992 // TODO(sandersd): Update PipelineController to remove the need for this.
2993 if (IsNetworkStateError(network_state_))
sandersd1c0bba02016-03-04 23:14:082994 return;
2995
jameswest451a5bb2017-01-27 03:59:392996 if (is_suspended) {
sandersd35d2c3f2017-01-14 02:04:422997 // If we were not resumed for long enough to satisfy the preroll attempt,
2998 // reset the clock.
2999 if (!preroll_attempt_pending_ && IsPrerollAttemptNeeded()) {
3000 preroll_attempt_pending_ = true;
3001 preroll_attempt_start_time_ = base::TimeTicks();
3002 }
Antonio Gomes81b56552019-05-15 22:15:283003 pipeline_controller_->Suspend();
sandersd50a635e2016-04-04 22:50:093004 } else {
sandersd35d2c3f2017-01-14 02:04:423005 // When resuming, start the preroll attempt clock.
3006 if (preroll_attempt_pending_) {
3007 preroll_attempt_pending_ = false;
3008 preroll_attempt_start_time_ = tick_clock_->NowTicks();
3009 }
Antonio Gomes81b56552019-05-15 22:15:283010 pipeline_controller_->Resume();
sandersd50a635e2016-04-04 22:50:093011 }
3012}
3013
3014WebMediaPlayerImpl::PlayState
Thomas Guilbert7350fdad2019-01-29 23:09:243015WebMediaPlayerImpl::UpdatePlayState_ComputePlayState(bool is_flinging,
xjz4e5d4bf32017-02-15 21:26:353016 bool can_auto_suspend,
dalecurtis8b8505e72016-06-10 21:59:173017 bool is_suspended,
sandersd50a635e2016-04-04 22:50:093018 bool is_backgrounded) {
3019 PlayState result;
3020
tguilbert1bb1c782017-01-23 21:15:113021 bool must_suspend = delegate_->IsFrameClosed();
Dale Curtis6438cf12018-03-29 02:34:013022 bool is_stale = delegate_->IsStale(delegate_id_);
3023
3024 if (stale_state_override_for_testing_.has_value() &&
3025 ready_state_ >= stale_state_override_for_testing_.value()) {
3026 is_stale = true;
3027 }
sandersd35d2c3f2017-01-14 02:04:423028
sandersd50a635e2016-04-04 22:50:093029 // This includes both data source (before pipeline startup) and pipeline
3030 // errors.
3031 bool has_error = IsNetworkStateError(network_state_);
3032
Dale Curtisc56158c2019-09-09 23:00:323033 // Note: Even though we get play/pause signals at kReadyStateHaveMetadata, we
3034 // must attempt to preroll until kReadyStateHaveFutureData so that the
3035 // canplaythrough event will be fired to the page (which may be waiting).
3036 bool have_future_data =
3037 highest_ready_state_ >= WebMediaPlayer::kReadyStateHaveFutureData;
sandersd50a635e2016-04-04 22:50:093038
avayvod65fad272017-02-24 01:00:483039 // Background suspend is only enabled for paused players.
3040 // In the case of players with audio the session should be kept.
3041 bool background_suspended =
Dale Curtisc56158c2019-09-09 23:00:323042 can_auto_suspend && is_backgrounded && paused_ && have_future_data;
sandersd50a635e2016-04-04 22:50:093043
Dale Curtisd71061f02019-05-21 21:33:543044 // Idle suspension is allowed prior to kReadyStateHaveMetadata since there
3045 // exist mechanisms to exit the idle state when the player is capable of
3046 // reaching the kReadyStateHaveMetadata state; see didLoadingProgress().
dalecurtiscc8baf72016-10-27 01:49:443047 //
sandersd50a635e2016-04-04 22:50:093048 // TODO(sandersd): Make the delegate suspend idle players immediately when
3049 // hidden.
Dale Curtis7c63f2e22018-09-19 21:06:273050 bool idle_suspended = can_auto_suspend && is_stale && paused_ && !seeking_ &&
3051 !overlay_enabled_ && !needs_first_frame_;
dalecurtise7120dc2016-09-03 02:54:353052
3053 // If we're already suspended, see if we can wait for user interaction. Prior
Dale Curtisd71061f02019-05-21 21:33:543054 // to kReadyStateHaveMetadata, we require |is_stale| to remain suspended.
3055 // |is_stale| will be cleared when we receive data which may take us to
3056 // kReadyStateHaveMetadata.
Dale Curtisc56158c2019-09-09 23:00:323057 bool can_stay_suspended = (is_stale || have_future_data) && is_suspended &&
Dale Curtis7c63f2e22018-09-19 21:06:273058 paused_ && !seeking_ && !needs_first_frame_;
sandersd50a635e2016-04-04 22:50:093059
3060 // Combined suspend state.
Thomas Guilbert7350fdad2019-01-29 23:09:243061 result.is_suspended = must_suspend || idle_suspended ||
avayvod65fad272017-02-24 01:00:483062 background_suspended || can_stay_suspended;
sandersd50a635e2016-04-04 22:50:093063
Thomas Guilbert7350fdad2019-01-29 23:09:243064 DVLOG(3) << __func__ << ": must_suspend=" << must_suspend
Dale Curtis779ed842018-03-10 06:20:133065 << ", idle_suspended=" << idle_suspended
3066 << ", background_suspended=" << background_suspended
3067 << ", can_stay_suspended=" << can_stay_suspended
Dale Curtisc56158c2019-09-09 23:00:323068 << ", is_stale=" << is_stale
3069 << ", have_future_data=" << have_future_data
Dale Curtis779ed842018-03-10 06:20:133070 << ", paused_=" << paused_ << ", seeking_=" << seeking_;
3071
sandersd50a635e2016-04-04 22:50:093072 // We do not treat |playback_rate_| == 0 as paused. For the media session,
3073 // being paused implies displaying a play button, which is incorrect in this
3074 // case. For memory usage reporting, we just use the same definition (but we
3075 // don't have to).
3076 //
3077 // Similarly, we don't consider |ended_| to be paused. Blink will immediately
3078 // call pause() or seek(), so |ended_| should not affect the computation.
3079 // Despite that, |ended_| does result in a separate paused state, to simplfy
3080 // the contract for SetDelegateState().
3081 //
avayvod65fad272017-02-24 01:00:483082 // |has_remote_controls| indicates if the player can be controlled outside the
3083 // page (e.g. via the notification controls or by audio focus events). Idle
sandersd50a635e2016-04-04 22:50:093084 // suspension does not destroy the media session, because we expect that the
avayvod5f34b642017-03-23 03:14:043085 // notification controls (and audio focus) remain. With some exceptions for
3086 // background videos, the player only needs to have audio to have controls
Dale Curtisd71061f02019-05-21 21:33:543087 // (requires |have_current_data|).
avayvod5f34b642017-03-23 03:14:043088 //
3089 // |alive| indicates if the player should be present (not |GONE|) to the
3090 // delegate, either paused or playing. The following must be true for the
3091 // player:
Dale Curtisd71061f02019-05-21 21:33:543092 // - |have_current_data|, since playback can't begin before that point, we
3093 // need to know whether we are paused to correctly configure the session,
3094 // and also because the tracks and duration are passed to DidPlay(),
Thomas Guilbert7350fdad2019-01-29 23:09:243095 // - |is_flinging| is false (RemotePlayback is not handled by the delegate)
avayvod5f34b642017-03-23 03:14:043096 // - |has_error| is false as player should have no errors,
3097 // - |background_suspended| is false, otherwise |has_remote_controls| must
3098 // be true.
sandersd50a635e2016-04-04 22:50:093099 //
avayvod65fad272017-02-24 01:00:483100 // TODO(sandersd): If Blink told us the paused state sooner, we could detect
3101 // if the remote controls are available sooner.
3102
3103 // Background videos with audio don't have remote controls if background
3104 // suspend is enabled and resuming background videos is not (original Android
3105 // behavior).
3106 bool backgrounded_video_has_no_remote_controls =
Sergey Volk8b09c2c52018-12-12 23:20:403107 IsBackgroundSuspendEnabled(this) && !IsResumeBackgroundVideosEnabled() &&
3108 is_backgrounded && HasVideo();
Dale Curtisd71061f02019-05-21 21:33:543109 bool have_current_data = highest_ready_state_ >= kReadyStateHaveCurrentData;
3110 bool can_play = !has_error && have_current_data;
avayvod5f34b642017-03-23 03:14:043111 bool has_remote_controls =
Blink Reformat1c4d759e2017-04-09 16:34:543112 HasAudio() && !backgrounded_video_has_no_remote_controls;
Thomas Guilbert7350fdad2019-01-29 23:09:243113 bool alive = can_play && !is_flinging && !must_suspend &&
avayvod5f34b642017-03-23 03:14:043114 (!background_suspended || has_remote_controls);
3115 if (!alive) {
Thomas Guilbert4c6feff2018-11-09 19:53:323116 // Do not mark players as idle when flinging.
sandersd50a635e2016-04-04 22:50:093117 result.delegate_state = DelegateState::GONE;
Thomas Guilbert4c6feff2018-11-09 19:53:323118 result.is_idle = delegate_->IsIdle(delegate_id_) && !is_flinging;
avayvod65fad272017-02-24 01:00:483119 } else if (paused_) {
sandersd35d2c3f2017-01-14 02:04:423120 // TODO(sandersd): Is it possible to have a suspended session, be ended,
3121 // and not be paused? If so we should be in a PLAYING state.
dalecurtise7120dc2016-09-03 02:54:353122 result.delegate_state =
sandersd35d2c3f2017-01-14 02:04:423123 ended_ ? DelegateState::GONE : DelegateState::PAUSED;
3124 result.is_idle = !seeking_;
sandersd50a635e2016-04-04 22:50:093125 } else {
3126 result.delegate_state = DelegateState::PLAYING;
sandersd35d2c3f2017-01-14 02:04:423127 result.is_idle = false;
sandersd50a635e2016-04-04 22:50:093128 }
3129
dalecurtis8b8505e72016-06-10 21:59:173130 // It's not critical if some cases where memory usage can change are missed,
sandersd50a635e2016-04-04 22:50:093131 // since media memory changes are usually gradual.
Thomas Guilbert7350fdad2019-01-29 23:09:243132 result.is_memory_reporting_enabled = !has_error && can_play && !is_flinging &&
3133 !result.is_suspended &&
3134 (!paused_ || seeking_);
sandersd50a635e2016-04-04 22:50:093135
3136 return result;
dalecurtis0f0097a2015-12-01 17:40:473137}
3138
Eugene Zemtsov77d56262020-03-06 05:52:033139void WebMediaPlayerImpl::SetDemuxer(std::unique_ptr<Demuxer> demuxer) {
3140 DCHECK(main_task_runner_->BelongsToCurrentThread());
3141 DCHECK(!demuxer_);
3142 DCHECK(!media_thread_mem_dumper_);
3143 DCHECK(demuxer);
3144
3145 demuxer_ = std::move(demuxer);
3146
3147 // base::Unretained() is safe here. |demuxer_| is destroyed on the main
3148 // thread, but before doing it ~WebMediaPlayerImpl() posts a media thread task
3149 // that deletes media_thread_mem_dumper_ and waits for it to finish.
3150 media_thread_mem_dumper_ = std::make_unique<MemoryDumpProviderProxy>(
3151 "WebMediaPlayer_MediaThread", media_task_runner_,
3152 base::BindRepeating(&WebMediaPlayerImpl::OnMediaThreadMemoryDump,
3153 media_log_->id(), base::Unretained(demuxer_.get())));
3154}
3155
dalecurtis83266c72015-10-29 18:43:203156void WebMediaPlayerImpl::ReportMemoryUsage() {
3157 DCHECK(main_task_runner_->BelongsToCurrentThread());
3158
wdzierzanowskifd4cd91c52015-12-02 23:50:203159 // About base::Unretained() usage below: We destroy |demuxer_| on the main
3160 // thread. Before that, however, ~WebMediaPlayerImpl() posts a task to the
3161 // media thread and waits for it to finish. Hence, the GetMemoryUsage() task
3162 // posted here must finish earlier.
Dale Curtis8a6281322017-08-31 00:35:533163 //
3164 // The exception to the above is when OnError() has been called. If we're in
3165 // the error state we've already shut down the pipeline and can't rely on it
3166 // to cycle the media thread before we destroy |demuxer_|. In this case skip
3167 // collection of the demuxer memory stats.
3168 if (demuxer_ && !IsNetworkStateError(network_state_)) {
wdzierzanowskifd4cd91c52015-12-02 23:50:203169 base::PostTaskAndReplyWithResult(
3170 media_task_runner_.get(), FROM_HERE,
Jan Wilken Dörrie2e1d2d9a2020-01-24 17:14:183171 base::BindOnce(&Demuxer::GetMemoryUsage,
3172 base::Unretained(demuxer_.get())),
3173 base::BindOnce(&WebMediaPlayerImpl::FinishMemoryUsageReport,
3174 weak_this_));
wdzierzanowskifd4cd91c52015-12-02 23:50:203175 } else {
3176 FinishMemoryUsageReport(0);
3177 }
3178}
3179
3180void WebMediaPlayerImpl::FinishMemoryUsageReport(int64_t demuxer_memory_usage) {
3181 DCHECK(main_task_runner_->BelongsToCurrentThread());
3182
avayvodc4bfb0e62017-01-13 01:07:013183 const PipelineStatistics stats = GetPipelineStatistics();
servolk639473e492016-12-15 04:14:203184 const int64_t data_source_memory_usage =
3185 data_source_ ? data_source_->GetMemoryUsage() : 0;
dalecurtisecc76612017-04-19 00:31:203186
Dale Curtisc2c5dcb12018-04-16 23:21:293187 // If we have video and no video memory usage and we've rendered the first
3188 // frame, assume the VideoFrameCompositor is holding onto the last frame after
3189 // we've suspended the pipeline; which thus reports zero memory usage from the
3190 // video renderer.
dalecurtisecc76612017-04-19 00:31:203191 //
3192 // Technically this should use the coded size, but that requires us to hop to
3193 // the compositor to get and byte-perfect accuracy isn't important here.
3194 const int64_t video_memory_usage =
3195 stats.video_memory_usage +
Dale Curtisc2c5dcb12018-04-16 23:21:293196 ((pipeline_metadata_.has_video && !stats.video_memory_usage &&
3197 has_first_frame_)
Miguel Casas9e7766022018-01-08 16:13:133198 ? VideoFrame::AllocationSize(PIXEL_FORMAT_I420,
dalecurtisecc76612017-04-19 00:31:203199 pipeline_metadata_.natural_size)
3200 : 0);
3201
dalecurtis83266c72015-10-29 18:43:203202 const int64_t current_memory_usage =
dalecurtisecc76612017-04-19 00:31:203203 stats.audio_memory_usage + video_memory_usage + data_source_memory_usage +
3204 demuxer_memory_usage;
dalecurtis83266c72015-10-29 18:43:203205
dalecurtisecc76612017-04-19 00:31:203206 DVLOG(2) << "Memory Usage -- Total: " << current_memory_usage
3207 << " Audio: " << stats.audio_memory_usage
3208 << ", Video: " << video_memory_usage
servolk639473e492016-12-15 04:14:203209 << ", DataSource: " << data_source_memory_usage
wdzierzanowskifd4cd91c52015-12-02 23:50:203210 << ", Demuxer: " << demuxer_memory_usage;
dalecurtis83266c72015-10-29 18:43:203211
3212 const int64_t delta = current_memory_usage - last_reported_memory_usage_;
3213 last_reported_memory_usage_ = current_memory_usage;
3214 adjust_allocated_memory_cb_.Run(delta);
servolk639473e492016-12-15 04:14:203215
Blink Reformat1c4d759e2017-04-09 16:34:543216 if (HasAudio()) {
servolk639473e492016-12-15 04:14:203217 UMA_HISTOGRAM_MEMORY_KB("Media.WebMediaPlayerImpl.Memory.Audio",
3218 stats.audio_memory_usage / 1024);
3219 }
Blink Reformat1c4d759e2017-04-09 16:34:543220 if (HasVideo()) {
servolk639473e492016-12-15 04:14:203221 UMA_HISTOGRAM_MEMORY_KB("Media.WebMediaPlayerImpl.Memory.Video",
dalecurtisecc76612017-04-19 00:31:203222 video_memory_usage / 1024);
servolk639473e492016-12-15 04:14:203223 }
3224 if (data_source_) {
3225 UMA_HISTOGRAM_MEMORY_KB("Media.WebMediaPlayerImpl.Memory.DataSource",
3226 data_source_memory_usage / 1024);
3227 }
3228 if (demuxer_) {
3229 UMA_HISTOGRAM_MEMORY_KB("Media.WebMediaPlayerImpl.Memory.Demuxer",
3230 demuxer_memory_usage / 1024);
3231 }
dalecurtis83266c72015-10-29 18:43:203232}
3233
Eugene Zemtsov77d56262020-03-06 05:52:033234void WebMediaPlayerImpl::OnMainThreadMemoryDump(
3235 int32_t id,
3236 base::trace_event::ProcessMemoryDump* pmd) {
3237 const PipelineStatistics stats = GetPipelineStatistics();
3238
3239 bool suspended = pipeline_controller_->IsPipelineSuspended();
3240 auto parent_dump_name =
3241 base::StringPrintf("media/webmediaplayer/player_%d", id);
3242 auto player_state =
3243 base::StringPrintf("Paused: %d Ended: %d ReadyState: %d Suspended: %d",
3244 paused_, ended_, GetReadyState(), suspended);
3245 auto* parent_dump = pmd->CreateAllocatorDump(parent_dump_name);
3246 parent_dump->AddString("player_state", "", player_state);
3247
3248 CreateAllocation(pmd, id, "audio", stats.audio_memory_usage);
3249 CreateAllocation(pmd, id, "video", stats.video_memory_usage);
3250
3251 if (data_source_)
3252 CreateAllocation(pmd, id, "data_source", data_source_->GetMemoryUsage());
3253}
3254
3255// static
3256void WebMediaPlayerImpl::OnMediaThreadMemoryDump(
3257 int32_t id,
3258 Demuxer* demuxer,
3259 base::trace_event::ProcessMemoryDump* pmd) {
3260 if (!demuxer)
3261 return;
3262
3263 CreateAllocation(pmd, id, "demuxer", demuxer->GetMemoryUsage());
3264}
3265
dalecurtis8b8505e72016-06-10 21:59:173266void WebMediaPlayerImpl::ScheduleIdlePauseTimer() {
avayvod65fad272017-02-24 01:00:483267 // Only schedule the pause timer if we're not paused or paused but going to
avayvod52efd282017-03-07 21:13:043268 // resume when foregrounded, and are suspended and have audio.
3269 if ((paused_ && !paused_when_hidden_) ||
Antonio Gomes81b56552019-05-15 22:15:283270 !pipeline_controller_->IsSuspended() || !HasAudio()) {
dalecurtis8b8505e72016-06-10 21:59:173271 return;
avayvod52efd282017-03-07 21:13:043272 }
dalecurtis8b8505e72016-06-10 21:59:173273
3274#if defined(OS_ANDROID)
Thomas Guilbert7350fdad2019-01-29 23:09:243275 // Don't pause videos casted as part of RemotePlayback.
3276 if (is_flinging_)
dalecurtis8b8505e72016-06-10 21:59:173277 return;
3278#endif
3279
3280 // Idle timeout chosen arbitrarily.
3281 background_pause_timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(5),
3282 this, &WebMediaPlayerImpl::OnPause);
3283}
3284
dalecurtis04bdb582016-08-17 22:15:233285void WebMediaPlayerImpl::CreateWatchTimeReporter() {
wdzierzanowskia78fa9b2017-06-13 18:12:103286 if (!HasVideo() && !HasAudio())
3287 return;
3288
Dan Sanders7ef5d0f2019-05-03 18:30:113289 // MediaPlayerRenderer does not know about tracks until playback starts.
3290 // Assume audio-only unless the natural size has been detected.
3291 bool has_video = pipeline_metadata_.has_video;
3292 if (using_media_player_renderer_) {
3293 has_video = !pipeline_metadata_.natural_size.IsEmpty();
3294 }
3295
dalecurtis04bdb582016-08-17 22:15:233296 // Create the watch time reporter and synchronize its initial state.
Jose Lopes9023b6d2020-02-19 20:42:373297 watch_time_reporter_ = std::make_unique<WatchTimeReporter>(
Dan Sanders7ef5d0f2019-05-03 18:30:113298 mojom::PlaybackProperties::New(
3299 pipeline_metadata_.has_audio, has_video, false, false,
3300 !!chunk_demuxer_, is_encrypted_, embedded_media_experience_enabled_),
Dale Curtis96d6e9382018-07-18 18:01:073301 pipeline_metadata_.natural_size,
Dale Curtis051fdf62017-08-05 00:21:133302 base::BindRepeating(&WebMediaPlayerImpl::GetCurrentTimeInternal,
3303 base::Unretained(this)),
Dale Curtis0f8d7b32019-10-24 22:10:283304 base::BindRepeating(&WebMediaPlayerImpl::GetPipelineStatistics,
3305 base::Unretained(this)),
Hajime Hoshi8bb37dc2017-12-19 09:35:103306 media_metrics_provider_.get(),
Jose Lopes9023b6d2020-02-19 20:42:373307 frame_->GetTaskRunner(blink::TaskType::kInternalMedia));
dalecurtis04bdb582016-08-17 22:15:233308 watch_time_reporter_->OnVolumeChange(volume_);
Dale Curtisaebaeea2018-07-19 23:42:113309 watch_time_reporter_->OnDurationChanged(GetPipelineMediaDuration());
Mounir Lamourif9af74e72017-06-19 19:31:453310
tguilbert1bb1c782017-01-23 21:15:113311 if (delegate_->IsFrameHidden())
dalecurtis04bdb582016-08-17 22:15:233312 watch_time_reporter_->OnHidden();
3313 else
3314 watch_time_reporter_->OnShown();
Mounir Lamourif9af74e72017-06-19 19:31:453315
Mounir Lamouri41a79c62017-06-06 12:53:163316 if (client_->HasNativeControls())
3317 watch_time_reporter_->OnNativeControlsEnabled();
3318 else
3319 watch_time_reporter_->OnNativeControlsDisabled();
Mounir Lamourif9af74e72017-06-19 19:31:453320
3321 switch (client_->DisplayType()) {
3322 case WebMediaPlayer::DisplayType::kInline:
3323 watch_time_reporter_->OnDisplayTypeInline();
3324 break;
3325 case WebMediaPlayer::DisplayType::kFullscreen:
3326 watch_time_reporter_->OnDisplayTypeFullscreen();
3327 break;
3328 case WebMediaPlayer::DisplayType::kPictureInPicture:
3329 watch_time_reporter_->OnDisplayTypePictureInPicture();
3330 break;
3331 }
Dale Curtis96d6e9382018-07-18 18:01:073332
3333 UpdateSecondaryProperties();
Dale Curtis7fd27c4b2018-07-30 22:14:213334
3335 // If the WatchTimeReporter was recreated in the middle of playback, we want
3336 // to resume playback here too since we won't get another play() call. When
3337 // seeking, the seek completion will restart it if necessary.
3338 if (!paused_ && !seeking_)
3339 watch_time_reporter_->OnPlaying();
Dale Curtis96d6e9382018-07-18 18:01:073340}
3341
3342void WebMediaPlayerImpl::UpdateSecondaryProperties() {
3343 watch_time_reporter_->UpdateSecondaryProperties(
3344 mojom::SecondaryPlaybackProperties::New(
3345 pipeline_metadata_.audio_decoder_config.codec(),
Dale Curtis7140b502019-10-23 20:34:423346 pipeline_metadata_.video_decoder_config.codec(),
Dale Curtisf8afcef32020-01-18 06:23:263347 pipeline_metadata_.audio_decoder_config.profile(),
Dale Curtis7140b502019-10-23 20:34:423348 pipeline_metadata_.video_decoder_config.profile(),
3349 audio_decoder_name_, video_decoder_name_,
Yuchen Liub33bfc12019-11-08 20:16:123350 pipeline_metadata_.audio_decoder_config.encryption_scheme(),
3351 pipeline_metadata_.video_decoder_config.encryption_scheme(),
John Rummelld30555352018-09-21 20:47:253352 pipeline_metadata_.natural_size));
dalecurtis04bdb582016-08-17 22:15:233353}
3354
avayvod39c102402016-11-23 21:43:133355bool WebMediaPlayerImpl::IsHidden() const {
3356 DCHECK(main_task_runner_->BelongsToCurrentThread());
3357
tguilbert1bb1c782017-01-23 21:15:113358 return delegate_->IsFrameHidden() && !delegate_->IsFrameClosed();
avayvod39c102402016-11-23 21:43:133359}
3360
avayvod102cdb62017-01-07 03:11:093361bool WebMediaPlayerImpl::IsStreaming() const {
3362 return data_source_ && data_source_->IsStreaming();
3363}
3364
liberato2fd111be2017-01-04 00:25:063365bool WebMediaPlayerImpl::DoesOverlaySupportMetadata() const {
Ted Meyer4a427632019-05-01 19:05:273366 return pipeline_metadata_.video_decoder_config.video_transformation() ==
3367 kNoTransformation;
liberato2fd111be2017-01-04 00:25:063368}
3369
Anton Vayvod09fa66e2017-07-20 23:02:123370void WebMediaPlayerImpl::UpdateRemotePlaybackCompatibility(bool is_compatible) {
3371 DCHECK(main_task_runner_->BelongsToCurrentThread());
3372
3373 client_->RemotePlaybackCompatibilityChanged(loaded_url_, is_compatible);
3374}
3375
Dale Curtis6438cf12018-03-29 02:34:013376void WebMediaPlayerImpl::ForceStaleStateForTesting(ReadyState target_state) {
3377 stale_state_override_for_testing_.emplace(target_state);
Dale Curtis99a9b482018-02-01 02:23:283378 UpdatePlayState();
3379}
3380
3381bool WebMediaPlayerImpl::IsSuspendedForTesting() {
3382 // This intentionally uses IsPipelineSuspended since we need to know when the
3383 // pipeline has reached the suspended state, not when it's in suspending.
Antonio Gomes81b56552019-05-15 22:15:283384 return pipeline_controller_->IsPipelineSuspended();
Dale Curtis99a9b482018-02-01 02:23:283385}
3386
Dale Curtis7c63f2e22018-09-19 21:06:273387bool WebMediaPlayerImpl::DidLazyLoad() const {
3388 return did_lazy_load_;
3389}
3390
3391void WebMediaPlayerImpl::OnBecameVisible() {
Dale Curtis04769ca2019-05-25 00:38:103392 have_enough_after_lazy_load_cb_.Cancel();
Dale Curtis7c63f2e22018-09-19 21:06:273393 needs_first_frame_ = !has_first_frame_;
3394 UpdatePlayState();
3395}
3396
Miguel Casasfb63a5792018-12-04 23:50:413397bool WebMediaPlayerImpl::IsOpaque() const {
3398 return opaque_;
3399}
3400
Mounir Lamouri99ba5a62019-02-12 01:27:473401int WebMediaPlayerImpl::GetDelegateId() {
3402 return delegate_id_;
3403}
3404
3405base::Optional<viz::SurfaceId> WebMediaPlayerImpl::GetSurfaceId() {
3406 if (!surface_layer_for_video_enabled_)
3407 return base::nullopt;
3408 return bridge_->GetSurfaceId();
3409}
3410
Thomas Guilberte90fe312019-11-07 22:27:563411void WebMediaPlayerImpl::RequestAnimationFrame() {
Thomas Guilberte95597002020-02-06 01:08:153412 compositor_->SetOnFramePresentedCallback(BindToCurrentLoop(base::BindOnce(
3413 &WebMediaPlayerImpl::OnNewFramePresentedCallback, weak_this_)));
Thomas Guilberte90fe312019-11-07 22:27:563414}
3415
Thomas Guilberte4669d42020-02-21 02:40:203416void WebMediaPlayerImpl::OnNewFramePresentedCallback() {
3417 client_->OnRequestAnimationFrame();
3418}
3419
3420std::unique_ptr<blink::WebMediaPlayer::VideoFramePresentationMetadata>
3421WebMediaPlayerImpl::GetVideoFramePresentationMetadata() {
3422 return compositor_->GetLastPresentedFrameMetadata();
Thomas Guilberte90fe312019-11-07 22:27:563423}
3424
Antonio Gomes142f32a2019-05-15 23:32:563425base::WeakPtr<blink::WebMediaPlayer> WebMediaPlayerImpl::AsWeakPtr() {
3426 return weak_this_;
3427}
3428
Yuchen Liue7813972019-04-12 22:34:243429bool WebMediaPlayerImpl::ShouldPausePlaybackWhenHidden() const {
3430 // Audio only stream is allowed to play when in background.
3431 // TODO: We should check IsBackgroundOptimizationCandidate here. But we need
3432 // to move the logic of checking video frames out of that function.
3433 if (!HasVideo())
3434 return false;
3435
Junbo Kefba620b2019-01-16 02:54:363436 if (!is_background_video_playback_enabled_)
3437 return true;
3438
avayvod65fad272017-02-24 01:00:483439 // If suspending background video, pause any video that's not remoted or
3440 // not unlocked to play in the background.
Sergey Volk8b09c2c52018-12-12 23:20:403441 if (IsBackgroundSuspendEnabled(this)) {
avayvod65fad272017-02-24 01:00:483442#if defined(OS_ANDROID)
Thomas Guilbert7350fdad2019-01-29 23:09:243443 if (is_flinging_)
avayvod65fad272017-02-24 01:00:483444 return false;
avayvodcc273dd2017-01-19 19:35:123445#endif
avayvodeb9098d2017-01-07 00:33:033446
Blink Reformat1c4d759e2017-04-09 16:34:543447 return !HasAudio() || (IsResumeBackgroundVideosEnabled() &&
3448 video_locked_when_paused_when_hidden_);
avayvod65fad272017-02-24 01:00:483449 }
3450
3451 // Otherwise only pause if the optimization is on and it's a video-only
3452 // optimization candidate.
avayvod01201332017-04-14 00:27:153453 return IsBackgroundVideoPauseOptimizationEnabled() && !HasAudio() &&
Thomas Guilbert29ae1a902018-10-20 01:53:383454 IsBackgroundOptimizationCandidate() && !is_flinging_;
avayvodeb9098d2017-01-07 00:33:033455}
3456
avayvod2135a642017-01-13 00:17:143457bool WebMediaPlayerImpl::ShouldDisableVideoWhenHidden() const {
Ted Meyera918e592018-09-08 00:16:203458 // This optimization is behind the flag on all platforms, only for non-mse
3459 // video. MSE video track switching on hide has gone through a field test.
3460 // TODO(tmathmeyer): Passing load_type_ won't be needed after src= field
3461 // testing is finished. see: http://crbug.com/709302
Ted Meyer0e105992019-05-04 01:47:213462 if (!is_background_video_track_optimization_supported_)
avayvodc4bfb0e62017-01-13 01:07:013463 return false;
avayvodc4bfb0e62017-01-13 01:07:013464
avayvodcc273dd2017-01-19 19:35:123465 // Disable video track only for players with audio that match the criteria for
3466 // being optimized.
Blink Reformat1c4d759e2017-04-09 16:34:543467 return HasAudio() && IsBackgroundOptimizationCandidate();
avayvodcc273dd2017-01-19 19:35:123468}
3469
3470bool WebMediaPlayerImpl::IsBackgroundOptimizationCandidate() const {
3471 DCHECK(main_task_runner_->BelongsToCurrentThread());
3472
François Beaufort664c3ca72018-04-13 07:24:513473 // Don't optimize Picture-in-Picture players.
Mounir Lamouri0484f40a2018-07-25 03:03:263474 if (IsInPictureInPicture())
François Beaufort664c3ca72018-04-13 07:24:513475 return false;
3476
Thomas Guilbert7350fdad2019-01-29 23:09:243477#if defined(OS_ANDROID)
3478 // Don't optimize videos casted as part of RemotePlayback.
3479 if (is_flinging_)
avayvodcc273dd2017-01-19 19:35:123480 return false;
Thomas Guilbert7350fdad2019-01-29 23:09:243481#endif
avayvodcc273dd2017-01-19 19:35:123482
3483 // Don't optimize audio-only or streaming players.
Blink Reformat1c4d759e2017-04-09 16:34:543484 if (!HasVideo() || IsStreaming())
avayvodcc273dd2017-01-19 19:35:123485 return false;
3486
Dale Curtis3f4935b2017-09-09 00:11:593487 // Video-only players are always optimized (paused).
3488 // Don't check the keyframe distance and duration.
3489 if (!HasAudio() && HasVideo())
3490 return true;
3491
avayvodcc273dd2017-01-19 19:35:123492 // Videos shorter than the maximum allowed keyframe distance can be optimized.
3493 base::TimeDelta duration = GetPipelineMediaDuration();
Ted Meyera918e592018-09-08 00:16:203494
Dale Curtis456808a2018-10-23 17:50:213495 constexpr base::TimeDelta kMaxKeyframeDistanceToDisableBackgroundVideo =
3496 base::TimeDelta::FromMilliseconds(
3497 kMaxKeyframeDistanceToDisableBackgroundVideoMs);
3498 if (duration < kMaxKeyframeDistanceToDisableBackgroundVideo)
avayvodcc273dd2017-01-19 19:35:123499 return true;
3500
3501 // Otherwise, only optimize videos with shorter average keyframe distance.
avayvodc4bfb0e62017-01-13 01:07:013502 PipelineStatistics stats = GetPipelineStatistics();
Dale Curtis456808a2018-10-23 17:50:213503 return stats.video_keyframe_distance_average <
3504 kMaxKeyframeDistanceToDisableBackgroundVideo;
avayvod2135a642017-01-13 00:17:143505}
3506
avayvod56e1f3942017-01-21 02:06:313507void WebMediaPlayerImpl::UpdateBackgroundVideoOptimizationState() {
Takumi Fujimotof2319684e2019-12-03 18:51:513508 if (IsHidden()) {
Yuchen Liue7813972019-04-12 22:34:243509 if (ShouldPausePlaybackWhenHidden()) {
avayvod56e1f3942017-01-21 02:06:313510 PauseVideoIfNeeded();
Dale Curtisa75a7892017-08-09 20:21:513511 } else if (update_background_status_cb_.IsCancelled()) {
3512 // Only trigger updates when we don't have one already scheduled.
3513 update_background_status_cb_.Reset(
3514 base::Bind(&WebMediaPlayerImpl::DisableVideoTrackIfNeeded,
3515 base::Unretained(this)));
3516
3517 // Defer disable track until we're sure the clip will be backgrounded for
3518 // some time. Resuming may take half a second, so frequent tab switches
3519 // will yield a poor user experience otherwise. http://crbug.com/709302
3520 // may also cause AV sync issues if disable/enable happens too fast.
3521 main_task_runner_->PostDelayedTask(
3522 FROM_HERE, update_background_status_cb_.callback(),
3523 base::TimeDelta::FromSeconds(10));
3524 }
avayvod56e1f3942017-01-21 02:06:313525 } else {
Dale Curtisa75a7892017-08-09 20:21:513526 update_background_status_cb_.Cancel();
avayvod56e1f3942017-01-21 02:06:313527 EnableVideoTrackIfNeeded();
3528 }
3529}
3530
3531void WebMediaPlayerImpl::PauseVideoIfNeeded() {
3532 DCHECK(IsHidden());
3533
3534 // Don't pause video while the pipeline is stopped, resuming or seeking.
3535 // Also if the video is paused already.
Antonio Gomes81b56552019-05-15 22:15:283536 if (!pipeline_controller_->IsPipelineRunning() || is_pipeline_resuming_ ||
tguilbert350936ff2017-02-24 05:39:273537 seeking_ || paused_)
avayvod56e1f3942017-01-21 02:06:313538 return;
3539
3540 // OnPause() will set |paused_when_hidden_| to false and call
3541 // UpdatePlayState(), so set the flag to true after and then return.
3542 OnPause();
3543 paused_when_hidden_ = true;
3544}
3545
avayvod2135a642017-01-13 00:17:143546void WebMediaPlayerImpl::EnableVideoTrackIfNeeded() {
avayvod56e1f3942017-01-21 02:06:313547 // Don't change video track while the pipeline is stopped, resuming or
3548 // seeking.
Antonio Gomes81b56552019-05-15 22:15:283549 if (!pipeline_controller_->IsPipelineRunning() || is_pipeline_resuming_ ||
tguilbert350936ff2017-02-24 05:39:273550 seeking_)
avayvod2135a642017-01-13 00:17:143551 return;
3552
3553 if (video_track_disabled_) {
3554 video_track_disabled_ = false;
Blink Reformat1c4d759e2017-04-09 16:34:543555 if (client_->HasSelectedVideoTrack()) {
3556 WebMediaPlayer::TrackId trackId = client_->GetSelectedVideoTrackId();
3557 SelectedVideoTrackChanged(&trackId);
avayvod2135a642017-01-13 00:17:143558 }
3559 }
3560}
3561
3562void WebMediaPlayerImpl::DisableVideoTrackIfNeeded() {
3563 DCHECK(IsHidden());
3564
3565 // Don't change video track while the pipeline is resuming or seeking.
3566 if (is_pipeline_resuming_ || seeking_)
3567 return;
3568
3569 if (!video_track_disabled_ && ShouldDisableVideoWhenHidden()) {
3570 video_track_disabled_ = true;
Blink Reformat1c4d759e2017-04-09 16:34:543571 SelectedVideoTrackChanged(nullptr);
avayvod2135a642017-01-13 00:17:143572 }
3573}
3574
avayvodc4bfb0e62017-01-13 01:07:013575void WebMediaPlayerImpl::SetPipelineStatisticsForTest(
3576 const PipelineStatistics& stats) {
3577 pipeline_statistics_for_test_ = base::make_optional(stats);
3578}
3579
3580PipelineStatistics WebMediaPlayerImpl::GetPipelineStatistics() const {
3581 DCHECK(main_task_runner_->BelongsToCurrentThread());
3582
tguilbert350936ff2017-02-24 05:39:273583 return pipeline_statistics_for_test_.value_or(
Antonio Gomes81b56552019-05-15 22:15:283584 pipeline_controller_->GetStatistics());
avayvodc4bfb0e62017-01-13 01:07:013585}
3586
avayvodcc273dd2017-01-19 19:35:123587void WebMediaPlayerImpl::SetPipelineMediaDurationForTest(
3588 base::TimeDelta duration) {
3589 pipeline_media_duration_for_test_ = base::make_optional(duration);
3590}
3591
3592base::TimeDelta WebMediaPlayerImpl::GetPipelineMediaDuration() const {
3593 DCHECK(main_task_runner_->BelongsToCurrentThread());
3594
3595 return pipeline_media_duration_for_test_.value_or(
Antonio Gomes81b56552019-05-15 22:15:283596 pipeline_controller_->GetMediaDuration());
avayvodcc273dd2017-01-19 19:35:123597}
3598
Xiangjun Zhangba8724f482017-08-03 06:43:253599void WebMediaPlayerImpl::SwitchToRemoteRenderer(
3600 const std::string& remote_device_friendly_name) {
xjz4e5d4bf32017-02-15 21:26:353601 DCHECK(main_task_runner_->BelongsToCurrentThread());
Chris Cunningham89b4b762019-03-27 17:13:333602
3603 DCHECK(!is_remote_rendering_);
3604 is_remote_rendering_ = true;
3605
Thomas Guilbertb341bae02018-05-09 00:02:133606 DCHECK(!disable_pipeline_auto_suspend_);
Xiangjun Zhangba8724f482017-08-03 06:43:253607 disable_pipeline_auto_suspend_ = true;
Chris Cunninghamd9df58e2017-08-29 00:04:233608
3609 // Capabilities reporting should only be performed for local playbacks.
3610 video_decode_stats_reporter_.reset();
3611
Xiangjun Zhangba8724f482017-08-03 06:43:253612 // Requests to restart media pipeline. A remote renderer will be created via
3613 // the |renderer_factory_selector_|.
xjz4e5d4bf32017-02-15 21:26:353614 ScheduleRestart();
xjzdf9b67e2017-04-13 23:28:253615 if (client_) {
Xiangjun Zhangba8724f482017-08-03 06:43:253616 client_->MediaRemotingStarted(
3617 WebString::FromUTF8(remote_device_friendly_name));
xjzdf9b67e2017-04-13 23:28:253618 }
xjz4e5d4bf32017-02-15 21:26:353619}
3620
Xiangjun Zhang5e20cba42018-01-10 19:54:563621void WebMediaPlayerImpl::SwitchToLocalRenderer(
3622 MediaObserverClient::ReasonToSwitchToLocal reason) {
Xiangjun Zhangba8724f482017-08-03 06:43:253623 DCHECK(main_task_runner_->BelongsToCurrentThread());
Chris Cunningham89b4b762019-03-27 17:13:333624 if (!is_remote_rendering_)
Xiangjun Zhang12f55272018-07-30 23:19:373625 return; // Is currently with local renderer.
Chris Cunningham89b4b762019-03-27 17:13:333626 is_remote_rendering_ = false;
3627
3628 DCHECK(disable_pipeline_auto_suspend_);
Xiangjun Zhangba8724f482017-08-03 06:43:253629 disable_pipeline_auto_suspend_ = false;
Chris Cunninghamd9df58e2017-08-29 00:04:233630
3631 // Capabilities reporting may resume now that playback is local.
3632 CreateVideoDecodeStatsReporter();
3633
Xiangjun Zhangba8724f482017-08-03 06:43:253634 // Requests to restart media pipeline. A local renderer will be created via
3635 // the |renderer_factory_selector_|.
3636 ScheduleRestart();
3637 if (client_)
Xiangjun Zhang5e20cba42018-01-10 19:54:563638 client_->MediaRemotingStopped(GetSwitchToLocalMessage(reason));
Xiangjun Zhangba8724f482017-08-03 06:43:253639}
3640
dalecurtis4f6d14d2017-02-22 17:42:223641void WebMediaPlayerImpl::RecordUnderflowDuration(base::TimeDelta duration) {
3642 DCHECK(data_source_ || chunk_demuxer_);
xhwang68b3fab82017-05-17 21:31:463643
dalecurtis4f6d14d2017-02-22 17:42:223644 if (data_source_)
Jennifer Apacible82e25c92017-08-07 18:15:273645 UMA_HISTOGRAM_TIMES("Media.UnderflowDuration2.SRC", duration);
dalecurtis4f6d14d2017-02-22 17:42:223646 else
Jennifer Apacible82e25c92017-08-07 18:15:273647 UMA_HISTOGRAM_TIMES("Media.UnderflowDuration2.MSE", duration);
xhwang68b3fab82017-05-17 21:31:463648
3649 if (is_encrypted_)
Jennifer Apacible82e25c92017-08-07 18:15:273650 UMA_HISTOGRAM_TIMES("Media.UnderflowDuration2.EME", duration);
dalecurtis4f6d14d2017-02-22 17:42:223651}
3652
xhwang60802652017-04-19 07:29:583653#define UMA_HISTOGRAM_VIDEO_HEIGHT(name, sample) \
3654 UMA_HISTOGRAM_CUSTOM_COUNTS(name, sample, 100, 10000, 50)
3655
3656void WebMediaPlayerImpl::RecordVideoNaturalSize(const gfx::Size& natural_size) {
3657 // Always report video natural size to MediaLog.
Ted Meyer0134aed2020-01-23 23:56:403658 media_log_->AddEvent<MediaLogEvent::kVideoSizeChanged>(natural_size);
Ted Meyer7f5b4e22019-11-21 03:21:193659 media_log_->SetProperty<MediaLogProperty::kResolution>(natural_size);
xhwang60802652017-04-19 07:29:583660
3661 if (initial_video_height_recorded_)
3662 return;
3663
3664 initial_video_height_recorded_ = true;
3665
3666 int height = natural_size.height();
3667
3668 if (load_type_ == kLoadTypeURL)
3669 UMA_HISTOGRAM_VIDEO_HEIGHT("Media.VideoHeight.Initial.SRC", height);
3670 else if (load_type_ == kLoadTypeMediaSource)
3671 UMA_HISTOGRAM_VIDEO_HEIGHT("Media.VideoHeight.Initial.MSE", height);
3672
3673 if (is_encrypted_)
3674 UMA_HISTOGRAM_VIDEO_HEIGHT("Media.VideoHeight.Initial.EME", height);
3675
3676 UMA_HISTOGRAM_VIDEO_HEIGHT("Media.VideoHeight.Initial.All", height);
3677}
3678
3679#undef UMA_HISTOGRAM_VIDEO_HEIGHT
3680
Greg Thompsonaa48ce8d2018-04-03 06:11:433681void WebMediaPlayerImpl::SetTickClockForTest(
3682 const base::TickClock* tick_clock) {
tzik2c963b872017-12-07 06:57:243683 tick_clock_ = tick_clock;
Antonio Gomes81b56552019-05-15 22:15:283684 buffered_data_source_host_->SetTickClockForTest(tick_clock);
hubbeb2d3efd2017-05-05 23:26:383685}
3686
Dale Curtis3899090ea2018-01-12 00:10:353687void WebMediaPlayerImpl::OnFirstFrame(base::TimeTicks frame_time) {
3688 DCHECK(!load_start_time_.is_null());
Dale Curtisff576552018-03-30 02:32:443689 DCHECK(!skip_metrics_due_to_startup_suspend_);
Dale Curtisc2c5dcb12018-04-16 23:21:293690 has_first_frame_ = true;
Dale Curtis7c63f2e22018-09-19 21:06:273691 needs_first_frame_ = false;
Dale Curtis3899090ea2018-01-12 00:10:353692 const base::TimeDelta elapsed = frame_time - load_start_time_;
3693 media_metrics_provider_->SetTimeToFirstFrame(elapsed);
3694 RecordTimingUMA("Media.TimeToFirstFrame", elapsed);
Dale Curtiscdfc6f22019-06-26 22:05:233695
3696 // Needed to signal HTMLVideoElement that it should remove the poster image.
Dale Curtis66790f32019-07-11 00:14:243697 if (client_ && has_poster_)
Dale Curtiscdfc6f22019-06-26 22:05:233698 client_->Repaint();
Dale Curtis3899090ea2018-01-12 00:10:353699}
3700
3701void WebMediaPlayerImpl::RecordTimingUMA(const std::string& key,
3702 base::TimeDelta elapsed) {
3703 if (chunk_demuxer_)
3704 base::UmaHistogramMediumTimes(key + ".MSE", elapsed);
3705 else
3706 base::UmaHistogramMediumTimes(key + ".SRC", elapsed);
3707 if (is_encrypted_)
3708 base::UmaHistogramMediumTimes(key + ".EME", elapsed);
3709}
3710
John Rummelldb5a7ef2018-05-16 00:28:013711void WebMediaPlayerImpl::RecordEncryptionScheme(
3712 const std::string& stream_name,
Yuchen Liub33bfc12019-11-08 20:16:123713 EncryptionScheme encryption_scheme) {
John Rummelldb5a7ef2018-05-16 00:28:013714 DCHECK(stream_name == "Audio" || stream_name == "Video");
3715
3716 // If the stream is not encrypted, don't record it.
Yuchen Liub33bfc12019-11-08 20:16:123717 if (encryption_scheme == EncryptionScheme::kUnencrypted)
John Rummelldb5a7ef2018-05-16 00:28:013718 return;
3719
3720 base::UmaHistogramEnumeration(
3721 "Media.EME.EncryptionScheme.Initial." + stream_name,
3722 DetermineEncryptionSchemeUMAValue(encryption_scheme),
3723 EncryptionSchemeUMA::kCount);
3724}
3725
Mounir Lamouri0484f40a2018-07-25 03:03:263726bool WebMediaPlayerImpl::IsInPictureInPicture() const {
3727 DCHECK(client_);
3728 return client_->DisplayType() ==
3729 WebMediaPlayer::DisplayType::kPictureInPicture;
3730}
3731
Jazz Xu74690262020-01-30 14:02:273732void WebMediaPlayerImpl::OnPictureInPictureAvailabilityChanged(bool available) {
3733 delegate_->DidPictureInPictureAvailabilityChange(delegate_id_, available);
3734}
3735
Dale Curtis5bba03232018-08-30 17:57:383736void WebMediaPlayerImpl::MaybeSetContainerName() {
Dale Curtisf01c8262018-09-04 23:50:433737 // MSE nor MediaPlayerRenderer provide container information.
3738 if (chunk_demuxer_ || using_media_player_renderer_)
Dale Curtis5bba03232018-08-30 17:57:383739 return;
3740
3741 // Pipeline startup failed before even getting a demuxer setup.
3742 if (!demuxer_)
3743 return;
3744
3745 // Container has already been set.
3746 if (highest_ready_state_ >= WebMediaPlayer::kReadyStateHaveMetadata)
3747 return;
3748
3749// If ffmpeg isn't enabled, we can't get the container name.
3750#if BUILDFLAG(ENABLE_FFMPEG)
3751 media_metrics_provider_->SetContainerName(
3752 static_cast<FFmpegDemuxer*>(demuxer_.get())->container());
3753#endif
3754}
3755
Dale Curtis18ad391b2019-05-30 23:25:093756void WebMediaPlayerImpl::MaybeUpdateBufferSizesForPlayback() {
3757 // Don't increase the MultiBufferDataSource buffer size until we've reached
3758 // kReadyStateHaveEnoughData. Otherwise we will unnecessarily slow down
3759 // playback startup -- it can instead be done for free after playback starts.
3760 if (!mb_data_source_ || highest_ready_state_ < kReadyStateHaveEnoughData)
3761 return;
3762
3763 mb_data_source_->MediaPlaybackRateChanged(playback_rate_);
3764 if (!paused_)
3765 mb_data_source_->MediaIsPlaying();
Becca Hughes7a85bf22019-07-24 16:16:583766
3767 // The playback rate has changed so we should rebuild the media position
3768 // state.
3769 UpdateMediaPositionState();
Dale Curtis18ad391b2019-05-30 23:25:093770}
3771
Dan Sanders6edfd782019-08-13 00:13:183772void WebMediaPlayerImpl::OnSimpleWatchTimerTick() {
3773 RecordSimpleWatchTimeUMA(reported_renderer_type_);
3774}
3775
[email protected]dbb3ff372019-10-15 19:09:423776GURL WebMediaPlayerImpl::GetSrcAfterRedirects() {
3777 return mb_data_source_ ? mb_data_source_->GetUrlAfterRedirects() : GURL();
3778}
3779
[email protected]96665a82020-01-23 00:35:373780void WebMediaPlayerImpl::UpdateSmoothnessHelper() {
3781 // If the experiment flag is off, then do nothing.
3782 if (!base::FeatureList::IsEnabled(kMediaLearningSmoothnessExperiment))
3783 return;
3784
3785 // If we're paused, or if we can't get all the features, then clear any
3786 // smoothness helper and stop. We'll try to create it later when we're
3787 // playing and have all the features.
3788 if (paused_ || !HasVideo() || pipeline_metadata_.natural_size.IsEmpty() ||
3789 !last_reported_fps_) {
3790 smoothness_helper_.reset();
3791 return;
3792 }
3793
3794 // Fill in features.
3795 // NOTE: this is a very bad way to do this, since it memorizes the order of
3796 // features in the task. However, it'll do for now.
3797 learning::FeatureVector features;
3798 features.push_back(
3799 learning::FeatureValue(pipeline_metadata_.video_decoder_config.codec()));
3800 features.push_back(learning::FeatureValue(
3801 pipeline_metadata_.video_decoder_config.profile()));
3802 features.push_back(
3803 learning::FeatureValue(pipeline_metadata_.natural_size.width()));
3804 features.push_back(learning::FeatureValue(*last_reported_fps_));
3805
3806 // If we have a smoothness helper, and we're not changing the features, then
3807 // do nothing. This prevents restarting the helper for no reason.
3808 if (smoothness_helper_ && features == smoothness_helper_->features())
3809 return;
3810
3811 // Create or restart the smoothness helper with |features|.
[email protected]91379332020-01-26 03:58:203812 smoothness_helper_ = SmoothnessHelper::Create(
Chris Cunningham64546ed2020-02-13 17:28:493813 GetLearningTaskController(learning::tasknames::kConsecutiveBadWindows),
3814 GetLearningTaskController(learning::tasknames::kConsecutiveNNRs),
[email protected]91379332020-01-26 03:58:203815 features, this);
3816}
3817
3818std::unique_ptr<learning::LearningTaskController>
Chris Cunningham64546ed2020-02-13 17:28:493819WebMediaPlayerImpl::GetLearningTaskController(const char* task_name) {
[email protected]91379332020-01-26 03:58:203820 // Get the LearningTaskController for |task_id|.
Chris Cunningham64546ed2020-02-13 17:28:493821 learning::LearningTask task = learning::MediaLearningTasks::Get(task_name);
3822 DCHECK_EQ(task.name, task_name);
[email protected]96665a82020-01-23 00:35:373823
3824 mojo::Remote<media::learning::mojom::LearningTaskController> remote_ltc;
3825 media_metrics_provider_->AcquireLearningTaskController(
3826 task.name, remote_ltc.BindNewPipeAndPassReceiver());
[email protected]91379332020-01-26 03:58:203827 return std::make_unique<learning::MojoLearningTaskController>(
[email protected]96665a82020-01-23 00:35:373828 task, std::move(remote_ltc));
[email protected]96665a82020-01-23 00:35:373829}
3830
acolwell9e0840d2014-09-06 19:01:323831} // namespace media