blob: a73d688ffb666568451ea1889d549ee59786de9f [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>
guidouc7babef2015-10-22 00:42:3510#include <string>
dcheng652f5ff2015-12-27 08:54:0011#include <utility>
[email protected]47b06ceb2010-08-04 22:41:1112
[email protected]08273c7b2011-09-17 00:33:5113#include "base/bind.h"
sandersd1c0bba02016-03-04 23:14:0814#include "base/bind_helpers.h"
[email protected]2041cf342010-02-19 03:15:5915#include "base/callback.h"
[email protected]7502ef12014-01-25 01:19:2716#include "base/callback_helpers.h"
sandersd1e49fb62015-12-12 01:18:0617#include "base/command_line.h"
[email protected]ca04095f2014-02-07 10:23:5618#include "base/debug/alias.h"
[email protected]926f8fd2013-04-12 20:27:5319#include "base/debug/crash_logging.h"
fdoraydb3ef7d2016-06-09 15:42:3820#include "base/location.h"
asvitkine30330812016-08-30 04:01:0821#include "base/metrics/histogram_macros.h"
acolwellb4034942014-08-28 15:42:4322#include "base/single_thread_task_runner.h"
servolka233f832016-06-10 20:39:0423#include "base/strings/string_number_conversions.h"
wdzierzanowskifd4cd91c52015-12-02 23:50:2024#include "base/task_runner_util.h"
gabba14a442016-05-11 20:10:2025#include "base/threading/thread_task_runner_handle.h"
ssid9525f4672015-01-28 12:13:1526#include "base/trace_event/trace_event.h"
sandersd1e49fb62015-12-12 01:18:0627#include "build/build_config.h"
[email protected]38564622014-08-19 02:47:1828#include "cc/blink/web_layer_impl.h"
[email protected]21c3f7502013-03-23 03:29:5129#include "cc/layers/video_layer.h"
[email protected]e4fc09e2012-04-06 03:17:4430#include "media/audio/null_audio_sink.h"
[email protected]2eccbed2014-01-10 05:15:5331#include "media/base/bind_to_current_loop.h"
xhwang0ad11e512014-11-25 23:43:0932#include "media/base/cdm_context.h"
xhwang79b193042016-12-13 18:52:4333#include "media/base/content_decryption_module.h"
[email protected]32da1002010-03-03 21:57:3534#include "media/base/limits.h"
zqzhang5d8eab72016-08-26 20:34:3035#include "media/base/media_content_type.h"
[email protected]090f7312011-08-05 23:26:4036#include "media/base/media_log.h"
sandersd1e49fb62015-12-12 01:18:0637#include "media/base/media_switches.h"
tguilbert25a4d112016-10-13 21:56:5138#include "media/base/media_url_demuxer.h"
[email protected]8a561062013-11-22 01:19:3139#include "media/base/text_renderer.h"
watk9f9dfdc92015-09-04 21:33:2940#include "media/base/timestamp_constants.h"
[email protected]e81283bb2010-08-31 18:01:2141#include "media/base/video_frame.h"
acolwell9e0840d2014-09-06 19:01:3242#include "media/blink/texttrack_impl.h"
dalecurtis04bdb582016-08-17 22:15:2343#include "media/blink/watch_time_reporter.h"
acolwell9e0840d2014-09-06 19:01:3244#include "media/blink/webaudiosourceprovider_impl.h"
xhwang97de4202014-11-25 08:44:0145#include "media/blink/webcontentdecryptionmodule_impl.h"
acolwell9e0840d2014-09-06 19:01:3246#include "media/blink/webinbandtexttrack_impl.h"
47#include "media/blink/webmediaplayer_delegate.h"
acolwell9e0840d2014-09-06 19:01:3248#include "media/blink/webmediaplayer_util.h"
49#include "media/blink/webmediasource_impl.h"
[email protected]efe7cd22012-09-12 23:55:0150#include "media/filters/chunk_demuxer.h"
[email protected]ddbc6ff2013-04-19 15:28:3351#include "media/filters/ffmpeg_demuxer.h"
jrummellc9d8e532015-02-26 18:38:1952#include "third_party/WebKit/public/platform/WebEncryptedMediaTypes.h"
srirama.m26f864d02015-07-14 05:21:4653#include "third_party/WebKit/public/platform/WebMediaPlayerClient.h"
54#include "third_party/WebKit/public/platform/WebMediaPlayerEncryptedMediaClient.h"
guidou9bfe4e2f2016-04-09 08:31:1955#include "third_party/WebKit/public/platform/WebMediaPlayerSource.h"
[email protected]745746d2013-08-23 02:09:1656#include "third_party/WebKit/public/platform/WebMediaSource.h"
[email protected]c10884462013-05-30 00:22:0957#include "third_party/WebKit/public/platform/WebRect.h"
mek966863c2016-02-04 23:39:0558#include "third_party/WebKit/public/platform/WebSecurityOrigin.h"
[email protected]c10884462013-05-30 00:22:0959#include "third_party/WebKit/public/platform/WebSize.h"
60#include "third_party/WebKit/public/platform/WebString.h"
61#include "third_party/WebKit/public/platform/WebURL.h"
tguilbert9881bc22016-10-27 03:13:4162#include "third_party/WebKit/public/web/WebDocument.h"
xhwang0acca44b2015-06-18 00:43:3163#include "third_party/WebKit/public/web/WebFrame.h"
[email protected]80504652014-04-18 04:41:5064#include "third_party/WebKit/public/web/WebLocalFrame.h"
[email protected]2255a9332013-06-17 05:12:3165#include "third_party/WebKit/public/web/WebView.h"
[email protected]b3f2b912009-04-09 16:18:5266
dalecurtisea27a3ed2016-06-24 01:41:3067#if defined(OS_ANDROID)
68#include "media/base/android/media_codec_util.h"
69#endif
70
[email protected]180ef242013-11-07 06:50:4671using blink::WebCanvas;
72using blink::WebMediaPlayer;
73using blink::WebRect;
74using blink::WebSize;
75using blink::WebString;
hubbed5f36882016-01-15 22:40:3776using gpu::gles2::GLES2Interface;
77
danakj365175c2016-02-06 00:37:3778#define STATIC_ASSERT_ENUM(a, b) \
79 static_assert(static_cast<int>(a) == static_cast<int>(b), \
80 "mismatching enums: " #a)
81
hubbed5f36882016-01-15 22:40:3782namespace media {
[email protected]ec9212f2008-12-18 21:40:3683
[email protected]8931c41a2009-07-07 17:31:4984namespace {
85
[email protected]378f0b72009-08-11 17:11:4286// Limits the range of playback rate.
87//
88// TODO(kylep): Revisit these.
89//
90// Vista has substantially lower performance than XP or Windows7. If you speed
91// up a video too much, it can't keep up, and rendering stops updating except on
92// the time bar. For really high speeds, audio becomes a bottleneck and we just
93// use up the data we have, which may not achieve the speed requested, but will
94// not crash the tab.
95//
96// A very slow speed, ie 0.00000001x, causes the machine to lock up. (It seems
97// like a busy loop). It gets unresponsive, although its not completely dead.
98//
99// Also our timers are not very accurate (especially for ogg), which becomes
100// evident at low speeds and on Vista. Since other speeds are risky and outside
101// the norms, we think 1/16x to 16x is a safe and useful range for now.
[email protected]39bdde32013-04-17 17:44:20102const double kMinRate = 0.0625;
103const double kMaxRate = 16.0;
[email protected]378f0b72009-08-11 17:11:42104
hubbed5f36882016-01-15 22:40:37105void SetSinkIdOnMediaThread(scoped_refptr<WebAudioSourceProviderImpl> sink,
106 const std::string& device_id,
107 const url::Origin& security_origin,
olka68b69392016-04-01 11:42:12108 const OutputDeviceStatusCB& callback) {
109 sink->SwitchOutputDevice(device_id, security_origin, callback);
guidouc7babef2015-10-22 00:42:35110}
111
sandersd50a635e2016-04-04 22:50:09112bool IsBackgroundedSuspendEnabled() {
dalecurtis0431cbf2016-03-12 01:19:43113#if !defined(OS_ANDROID)
114 // Suspend/Resume is only enabled by default on Android.
115 return base::CommandLine::ForCurrentProcess()->HasSwitch(
116 switches::kEnableMediaSuspend);
117#else
118 return !base::CommandLine::ForCurrentProcess()->HasSwitch(
119 switches::kDisableMediaSuspend);
120#endif
121}
122
avayvod48a8be52016-08-04 19:52:50123bool IsResumeBackgroundVideosEnabled() {
124 return base::FeatureList::IsEnabled(kResumeBackgroundVideo);
125}
126
avayvod39c102402016-11-23 21:43:13127bool IsBackgroundVideoTrackOptimizationEnabled() {
128 return base::FeatureList::IsEnabled(kBackgroundVideoTrackOptimization);
129}
130
sandersd50a635e2016-04-04 22:50:09131bool IsNetworkStateError(blink::WebMediaPlayer::NetworkState state) {
132 bool result = state == blink::WebMediaPlayer::NetworkStateFormatError ||
133 state == blink::WebMediaPlayer::NetworkStateNetworkError ||
134 state == blink::WebMediaPlayer::NetworkStateDecodeError;
135 DCHECK_EQ(state > blink::WebMediaPlayer::NetworkStateLoaded, result);
136 return result;
137}
138
sandersd2c478422016-08-02 01:19:25139gfx::Size GetRotatedVideoSize(VideoRotation rotation, gfx::Size natural_size) {
140 if (rotation == VIDEO_ROTATION_90 || rotation == VIDEO_ROTATION_270)
141 return gfx::Size(natural_size.height(), natural_size.width());
142 return natural_size;
143}
144
dalecurtis04bdb582016-08-17 22:15:23145base::TimeDelta GetCurrentTimeInternal(WebMediaPlayerImpl* p_this) {
146 // We wrap currentTime() instead of using pipeline_.GetMediaTime() since there
147 // are a variety of cases in which that time is not accurate; e.g., while
148 // remoting and during a pause or seek.
149 return base::TimeDelta::FromSecondsD(p_this->currentTime());
150}
151
watkd026f792016-11-05 00:28:51152// How much time must have elapsed since loading last progressed before the
153// player is eligible for idle suspension.
154constexpr base::TimeDelta kLoadingToIdleTimeout =
155 base::TimeDelta::FromSeconds(3);
156
[email protected]8931c41a2009-07-07 17:31:49157} // namespace
158
[email protected]6683e1b2014-04-10 01:45:38159class BufferedDataSourceHostImpl;
160
danakj365175c2016-02-06 00:37:37161STATIC_ASSERT_ENUM(WebMediaPlayer::CORSModeUnspecified,
162 UrlData::CORS_UNSPECIFIED);
163STATIC_ASSERT_ENUM(WebMediaPlayer::CORSModeAnonymous, UrlData::CORS_ANONYMOUS);
164STATIC_ASSERT_ENUM(WebMediaPlayer::CORSModeUseCredentials,
165 UrlData::CORS_USE_CREDENTIALS);
[email protected]a5a01102012-06-06 17:01:24166
[email protected]2c539b82012-08-18 04:10:19167#define BIND_TO_RENDER_LOOP(function) \
acolwellb4034942014-08-28 15:42:43168 (DCHECK(main_task_runner_->BelongsToCurrentThread()), \
acolwell9e0840d2014-09-06 19:01:32169 BindToCurrentLoop(base::Bind(function, AsWeakPtr())))
[email protected]5983adb2012-10-24 00:12:00170
[email protected]4e982192014-06-21 13:35:45171#define BIND_TO_RENDER_LOOP1(function, arg1) \
acolwellb4034942014-08-28 15:42:43172 (DCHECK(main_task_runner_->BelongsToCurrentThread()), \
acolwell9e0840d2014-09-06 19:01:32173 BindToCurrentLoop(base::Bind(function, AsWeakPtr(), arg1)))
[email protected]4e982192014-06-21 13:35:45174
[email protected]5b5bb9d2010-10-22 19:57:36175WebMediaPlayerImpl::WebMediaPlayerImpl(
[email protected]35b2a972014-04-04 15:50:22176 blink::WebLocalFrame* frame,
[email protected]180ef242013-11-07 06:50:46177 blink::WebMediaPlayerClient* client,
srirama.m26f864d02015-07-14 05:21:46178 blink::WebMediaPlayerEncryptedMediaClient* encrypted_client,
[email protected]b8976652011-10-26 23:46:55179 base::WeakPtr<WebMediaPlayerDelegate> delegate,
dcheng3076abbf2016-04-22 20:42:39180 std::unique_ptr<RendererFactory> renderer_factory,
hubbe5f0ad43b2015-12-14 20:57:26181 linked_ptr<UrlIndex> url_index,
[email protected]e82b2bd2013-01-02 17:47:57182 const WebMediaPlayerParams& params)
[email protected]f6af7592014-02-28 10:09:11183 : frame_(frame),
sandersd50a635e2016-04-04 22:50:09184 delegate_state_(DelegateState::GONE),
185 is_idle_(false),
186 must_suspend_(false),
[email protected]ef405f66b2012-04-18 02:39:55187 network_state_(WebMediaPlayer::NetworkStateEmpty),
188 ready_state_(WebMediaPlayer::ReadyStateHaveNothing),
sandersd50a635e2016-04-04 22:50:09189 highest_ready_state_(WebMediaPlayer::ReadyStateHaveNothing),
dalecurtisb6e052f52016-08-25 00:35:55190 preload_(MultibufferDataSource::AUTO),
191 buffering_strategy_(MultibufferDataSource::BUFFERING_STRATEGY_NORMAL),
altiminbf328382016-12-07 14:28:31192 main_task_runner_(frame->loadingTaskRunner()),
acolwell755d12d2014-08-30 01:09:19193 media_task_runner_(params.media_task_runner()),
dcastagna617d086b2015-08-20 01:39:30194 worker_task_runner_(params.worker_task_runner()),
acolwell755d12d2014-08-30 01:09:19195 media_log_(params.media_log()),
acolwellb4034942014-08-28 15:42:43196 pipeline_(media_task_runner_, media_log_.get()),
sandersd1c0bba02016-03-04 23:14:08197 pipeline_controller_(
198 &pipeline_,
199 base::Bind(&WebMediaPlayerImpl::CreateRenderer,
200 base::Unretained(this)),
201 base::Bind(&WebMediaPlayerImpl::OnPipelineSeeked, AsWeakPtr()),
202 base::Bind(&WebMediaPlayerImpl::OnPipelineSuspended, AsWeakPtr()),
alokp967c902452016-05-06 05:21:37203 base::Bind(&WebMediaPlayerImpl::OnError, AsWeakPtr())),
[email protected]f988d9b2014-07-25 00:35:43204 load_type_(LoadTypeURL),
[email protected]75e145a2014-04-15 17:44:32205 opaque_(false),
wolenetz1b2ae7d2015-06-10 00:44:21206 playback_rate_(0.0),
[email protected]49480902009-07-14 20:23:43207 paused_(true),
avayvodeb9098d2017-01-07 00:33:03208 paused_when_hidden_(false),
[email protected]b3766a22010-12-22 17:34:13209 seeking_(false),
watkdee516f2016-02-18 02:22:19210 pending_suspend_resume_cycle_(false),
scherkusd2c745b2014-09-04 05:03:40211 ended_(false),
yoichio863bebf2016-03-04 07:56:58212 should_notify_time_changed_(false),
tsunghungee562e92016-07-20 18:03:31213 overlay_enabled_(false),
214 decoder_requires_restart_for_overlay_(false),
[email protected]5badb082010-06-11 17:40:15215 client_(client),
srirama.m26f864d02015-07-14 05:21:46216 encrypted_client_(encrypted_client),
[email protected]baff4512011-10-19 18:21:07217 delegate_(delegate),
dalecurtisbb3eaac2016-01-27 21:10:25218 delegate_id_(0),
[email protected]d726eddc2013-07-02 22:25:55219 defer_load_cb_(params.defer_load_cb()),
dongseong.hwang0c4e9d82015-01-08 20:11:13220 context_3d_cb_(params.context_3d_cb()),
dalecurtis83266c72015-10-29 18:43:20221 adjust_allocated_memory_cb_(params.adjust_allocated_memory_cb()),
222 last_reported_memory_usage_(0),
[email protected]132dd57c2012-08-10 23:24:34223 supports_save_(true),
[email protected]f5443ef72013-04-22 04:03:38224 chunk_demuxer_(NULL),
hubbe5f0ad43b2015-12-14 20:57:26225 url_index_(url_index),
Bartosz Fabianowski85a823812015-04-16 10:27:51226 // Threaded compositing isn't enabled universally yet.
fdoraydb3ef7d2016-06-09 15:42:38227 compositor_task_runner_(params.compositor_task_runner()
228 ? params.compositor_task_runner()
229 : base::ThreadTaskRunnerHandle::Get()),
alokp5d86e9b2016-05-17 20:20:41230 compositor_(new VideoFrameCompositor(compositor_task_runner_)),
hubbed5f36882016-01-15 22:40:37231#if defined(OS_ANDROID) // WMPI_CAST
dalecurtisbb3eaac2016-01-27 21:10:25232 cast_impl_(this, client_, params.context_3d_cb()),
hubbed5f36882016-01-15 22:40:37233#endif
dalecurtisbb3eaac2016-01-27 21:10:25234 volume_(1.0),
235 volume_multiplier_(1.0),
watkdee516f2016-02-18 02:22:19236 renderer_factory_(std::move(renderer_factory)),
dalecurtis2ff781da2016-03-03 01:52:13237 surface_manager_(params.surface_manager()),
tsunghungee562e92016-07-20 18:03:31238 overlay_surface_id_(SurfaceManager::kNoSurfaceID),
dalecurtis7f366b2242016-04-13 01:16:17239 suppress_destruction_errors_(false),
dalecurtis04bdb582016-08-17 22:15:23240 can_suspend_state_(CanSuspendState::UNKNOWN),
tguilbert25a4d112016-10-13 21:56:51241 use_fallback_path_(false),
dalecurtis9d638a12016-08-30 06:20:55242 is_encrypted_(false),
xjzd3fe45a2016-10-12 18:26:37243 underflow_count_(0),
244 observer_(params.media_observer()) {
dalecurtis83266c72015-10-29 18:43:20245 DCHECK(!adjust_allocated_memory_cb_.is_null());
xhwang59d4175a2016-01-14 03:19:30246 DCHECK(renderer_factory_);
servolkef1e5ef2016-03-25 04:55:26247 DCHECK(client_);
dalecurtis83266c72015-10-29 18:43:20248
watkd026f792016-11-05 00:28:51249 tick_clock_.reset(new base::DefaultTickClock());
250
tsunghungee562e92016-07-20 18:03:31251 force_video_overlays_ = base::CommandLine::ForCurrentProcess()->HasSwitch(
252 switches::kForceVideoOverlays);
253
dalecurtisbb3eaac2016-01-27 21:10:25254 if (delegate_)
255 delegate_id_ = delegate_->AddObserver(this);
sandersd1e49fb62015-12-12 01:18:06256
[email protected]c93eb0a62011-08-09 22:47:24257 media_log_->AddEvent(
acolwell9e0840d2014-09-06 19:01:32258 media_log_->CreateEvent(MediaLogEvent::WEBMEDIAPLAYER_CREATED));
[email protected]4e6be3f2009-05-07 02:24:44259
jrummelle616ee92016-10-08 02:15:44260 if (params.initial_cdm())
261 SetCdm(params.initial_cdm());
xhwang0ad11e512014-11-25 23:43:09262
xhwangf94a634d2014-10-22 22:07:27263 // TODO(xhwang): When we use an external Renderer, many methods won't work,
xhwang6fa356202014-12-11 00:44:12264 // e.g. GetCurrentFrameFromCompositor(). See http://crbug.com/434861
olkae4ba2ed82016-12-06 16:34:51265 audio_source_provider_ =
266 new WebAudioSourceProviderImpl(params.audio_renderer_sink(), media_log_);
[email protected]ec9212f2008-12-18 21:40:36267}
268
[email protected]4e6be3f2009-05-07 02:24:44269WebMediaPlayerImpl::~WebMediaPlayerImpl() {
acolwellb4034942014-08-28 15:42:43270 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53271
alokp1116967f2016-06-11 17:30:56272 suppress_destruction_errors_ = true;
sandersd1e49fb62015-12-12 01:18:06273 if (delegate_) {
dalecurtisbb3eaac2016-01-27 21:10:25274 delegate_->PlayerGone(delegate_id_);
275 delegate_->RemoveObserver(delegate_id_);
sandersd1e49fb62015-12-12 01:18:06276 }
[email protected]baff4512011-10-19 18:21:07277
dalecurtis04bdb582016-08-17 22:15:23278 // Finalize any watch time metrics before destroying the pipeline.
279 watch_time_reporter_.reset();
280
alokp967c902452016-05-06 05:21:37281 // Pipeline must be stopped before it is destroyed.
282 pipeline_.Stop();
[email protected]f6af7592014-02-28 10:09:11283
dalecurtis83266c72015-10-29 18:43:20284 if (last_reported_memory_usage_)
285 adjust_allocated_memory_cb_.Run(-last_reported_memory_usage_);
286
dalecurtise1edb312016-06-22 02:33:21287 // Destruct compositor resources in the proper order.
288 client_->setWebLayer(nullptr);
289 if (video_weblayer_)
290 static_cast<cc::VideoLayer*>(video_weblayer_->layer())->StopUsingProvider();
[email protected]dd061e12014-05-06 19:21:22291 compositor_task_runner_->DeleteSoon(FROM_HERE, compositor_);
xhwangea8bb3562015-06-08 21:18:37292
293 media_log_->AddEvent(
294 media_log_->CreateEvent(MediaLogEvent::WEBMEDIAPLAYER_DESTROYED));
[email protected]ec9212f2008-12-18 21:40:36295}
296
guidou9bfe4e2f2016-04-09 08:31:19297void WebMediaPlayerImpl::load(LoadType load_type,
298 const blink::WebMediaPlayerSource& source,
[email protected]62e5e682013-03-07 23:53:24299 CORSMode cors_mode) {
guidou9bfe4e2f2016-04-09 08:31:19300 // Only URL or MSE blob URL is supported.
301 DCHECK(source.isURL());
302 blink::WebURL url = source.getAsURL();
pkastingf5279482016-07-27 02:18:20303 DVLOG(1) << __func__ << "(" << load_type << ", " << url << ", " << cors_mode
304 << ")";
[email protected]d726eddc2013-07-02 22:25:55305 if (!defer_load_cb_.is_null()) {
306 defer_load_cb_.Run(base::Bind(
[email protected]ef8394c2013-08-21 20:26:30307 &WebMediaPlayerImpl::DoLoad, AsWeakPtr(), load_type, url, cors_mode));
[email protected]d726eddc2013-07-02 22:25:55308 return;
309 }
[email protected]ef8394c2013-08-21 20:26:30310 DoLoad(load_type, url, cors_mode);
[email protected]62e5e682013-03-07 23:53:24311}
312
amp2ff7bf42d2016-12-17 00:06:52313void WebMediaPlayerImpl::SetEnableFullscreenOverlays(bool enable_overlays) {
314 enable_fullscreen_video_overlays_ = enable_overlays;
315}
316
watk9c87c6fa2016-05-06 20:36:51317bool WebMediaPlayerImpl::supportsOverlayFullscreenVideo() {
318#if defined(OS_ANDROID)
watkf835a792016-06-24 23:24:40319 return true;
watk9c87c6fa2016-05-06 20:36:51320#else
321 return false;
322#endif
323}
324
tsunghungee562e92016-07-20 18:03:31325void WebMediaPlayerImpl::EnableOverlay() {
326 overlay_enabled_ = true;
watkf835a792016-06-24 23:24:40327 if (surface_manager_) {
328 surface_created_cb_.Reset(
329 base::Bind(&WebMediaPlayerImpl::OnSurfaceCreated, AsWeakPtr()));
330 surface_manager_->CreateFullscreenSurface(pipeline_metadata_.natural_size,
331 surface_created_cb_.callback());
332 }
tsunghungee562e92016-07-20 18:03:31333
334 if (decoder_requires_restart_for_overlay_)
watkdee516f2016-02-18 02:22:19335 ScheduleRestart();
336}
337
tsunghungee562e92016-07-20 18:03:31338void WebMediaPlayerImpl::DisableOverlay() {
339 overlay_enabled_ = false;
watkf835a792016-06-24 23:24:40340 surface_created_cb_.Cancel();
tsunghungee562e92016-07-20 18:03:31341 overlay_surface_id_ = SurfaceManager::kNoSurfaceID;
342
343 if (decoder_requires_restart_for_overlay_)
watkdee516f2016-02-18 02:22:19344 ScheduleRestart();
dalecurtis4b632fce22016-11-10 00:52:17345 else if (!set_surface_cb_.is_null())
346 set_surface_cb_.Run(overlay_surface_id_);
watkdee516f2016-02-18 02:22:19347}
348
tsunghungee562e92016-07-20 18:03:31349void WebMediaPlayerImpl::enteredFullscreen() {
liberato2fd111be2017-01-04 00:25:06350 // |force_video_overlays_| implies that we're already in overlay mode, so take
351 // no action here. Otherwise, switch to an overlay if it's allowed and if
352 // it will display properly.
353 if (!force_video_overlays_ && enable_fullscreen_video_overlays_ &&
354 DoesOverlaySupportMetadata()) {
tsunghungee562e92016-07-20 18:03:31355 EnableOverlay();
liberato2fd111be2017-01-04 00:25:06356 }
xjzd3fe45a2016-10-12 18:26:37357 if (observer_)
358 observer_->OnEnteredFullscreen();
tsunghungee562e92016-07-20 18:03:31359}
360
361void WebMediaPlayerImpl::exitedFullscreen() {
liberato2fd111be2017-01-04 00:25:06362 // If we're in overlay mode, then exit it unless we're supposed to be in
363 // overlay mode all the time.
364 if (!force_video_overlays_ && overlay_enabled_)
tsunghungee562e92016-07-20 18:03:31365 DisableOverlay();
xjzd3fe45a2016-10-12 18:26:37366 if (observer_)
367 observer_->OnExitedFullscreen();
tsunghungee562e92016-07-20 18:03:31368}
369
xjzcdbbe732016-12-03 20:47:42370void WebMediaPlayerImpl::becameDominantVisibleContent(bool isDominant) {
371 if (observer_)
372 observer_->OnBecameDominantVisibleContent(isDominant);
373}
374
[email protected]ef8394c2013-08-21 20:26:30375void WebMediaPlayerImpl::DoLoad(LoadType load_type,
[email protected]180ef242013-11-07 06:50:46376 const blink::WebURL& url,
[email protected]d726eddc2013-07-02 22:25:55377 CORSMode cors_mode) {
pkastingf5279482016-07-27 02:18:20378 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:43379 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d726eddc2013-07-02 22:25:55380
[email protected]62e5e682013-03-07 23:53:24381 GURL gurl(url);
xhwangbffbf452016-04-01 05:26:45382 ReportMetrics(load_type, gurl, frame_->getSecurityOrigin());
[email protected]62e5e682013-03-07 23:53:24383
[email protected]926f8fd2013-04-12 20:27:53384 // Set subresource URL for crash reporting.
385 base::debug::SetCrashKeyValue("subresource_url", gurl.spec());
386
tguilbert25a4d112016-10-13 21:56:51387 if (use_fallback_path_)
388 fallback_url_ = gurl;
389
[email protected]ef8394c2013-08-21 20:26:30390 load_type_ = load_type;
391
[email protected]62e5e682013-03-07 23:53:24392 SetNetworkState(WebMediaPlayer::NetworkStateLoading);
393 SetReadyState(WebMediaPlayer::ReadyStateHaveNothing);
kinukof19cde72015-12-18 23:15:25394 media_log_->AddEvent(media_log_->CreateLoadEvent(url.string().utf8()));
[email protected]d726eddc2013-07-02 22:25:55395
396 // Media source pipelines can start immediately.
[email protected]ef8394c2013-08-21 20:26:30397 if (load_type == LoadTypeMediaSource) {
[email protected]d726eddc2013-07-02 22:25:55398 supports_save_ = false;
[email protected]ef8394c2013-08-21 20:26:30399 StartPipeline();
hubbe5f0ad43b2015-12-14 20:57:26400 } else {
dalecurtisb6e052f52016-08-25 00:35:55401 data_source_.reset(new MultibufferDataSource(
402 url, static_cast<UrlData::CORSMode>(cors_mode), main_task_runner_,
403 url_index_, frame_, media_log_.get(), &buffered_data_source_host_,
404 base::Bind(&WebMediaPlayerImpl::NotifyDownloading, AsWeakPtr())));
avayvode46d7bef2016-03-30 23:18:26405 data_source_->SetPreload(preload_);
406 data_source_->SetBufferingStrategy(buffering_strategy_);
407 data_source_->Initialize(
408 base::Bind(&WebMediaPlayerImpl::DataSourceInitialized, AsWeakPtr()));
hubbe5f0ad43b2015-12-14 20:57:26409 }
hubbed5f36882016-01-15 22:40:37410
411#if defined(OS_ANDROID) // WMPI_CAST
dalecurtisbb3eaac2016-01-27 21:10:25412 cast_impl_.Initialize(url, frame_, delegate_id_);
hubbed5f36882016-01-15 22:40:37413#endif
[email protected]62e5e682013-03-07 23:53:24414}
415
[email protected]4e6be3f2009-05-07 02:24:44416void WebMediaPlayerImpl::play() {
pkastingf5279482016-07-27 02:18:20417 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:43418 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53419
hubbed5f36882016-01-15 22:40:37420#if defined(OS_ANDROID) // WMPI_CAST
421 if (isRemote()) {
dalecurtis6e2716d2016-01-21 04:49:15422 cast_impl_.play();
hubbed5f36882016-01-15 22:40:37423 return;
424 }
425#endif
[email protected]49480902009-07-14 20:23:43426 paused_ = false;
sandersd50a635e2016-04-04 22:50:09427 is_idle_ = false;
yoichio863bebf2016-03-04 07:56:58428 pipeline_.SetPlaybackRate(playback_rate_);
dalecurtis4619cd02016-09-22 21:39:10429 background_pause_timer_.Stop();
sandersd1c0bba02016-03-04 23:14:08430
[email protected]039b7542013-10-17 22:06:25431 if (data_source_)
432 data_source_->MediaIsPlaying();
[email protected]090f7312011-08-05 23:26:40433
xjz48a9cb72016-12-20 04:02:49434 if (observer_)
435 observer_->OnPlaying();
436
dalecurtis04bdb582016-08-17 22:15:23437 DCHECK(watch_time_reporter_);
438 watch_time_reporter_->OnPlaying();
acolwell9e0840d2014-09-06 19:01:32439 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PLAY));
sandersd50a635e2016-04-04 22:50:09440 UpdatePlayState();
[email protected]ec9212f2008-12-18 21:40:36441}
442
[email protected]4e6be3f2009-05-07 02:24:44443void WebMediaPlayerImpl::pause() {
pkastingf5279482016-07-27 02:18:20444 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:43445 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53446
sandersd50a635e2016-04-04 22:50:09447 // We update the paused state even when casting, since we expect pause() to be
448 // called when casting begins, and when we exit casting we should end up in a
449 // paused state.
[email protected]49480902009-07-14 20:23:43450 paused_ = true;
hubbed5f36882016-01-15 22:40:37451
avayvodeb9098d2017-01-07 00:33:03452 // No longer paused because it was hidden.
453 paused_when_hidden_ = false;
454
hubbed5f36882016-01-15 22:40:37455#if defined(OS_ANDROID) // WMPI_CAST
456 if (isRemote()) {
dalecurtis6e2716d2016-01-21 04:49:15457 cast_impl_.pause();
hubbed5f36882016-01-15 22:40:37458 return;
459 }
460#endif
461
a.berwal338bf002015-04-22 11:14:50462 pipeline_.SetPlaybackRate(0.0);
sandersd1c0bba02016-03-04 23:14:08463
464 // pause() may be called after playback has ended and the HTMLMediaElement
465 // requires that currentTime() == duration() after ending. We want to ensure
466 // |paused_time_| matches currentTime() in this case or a future seek() may
467 // incorrectly discard what it thinks is a seek to the existing time.
468 paused_time_ =
469 ended_ ? pipeline_.GetMediaDuration() : pipeline_.GetMediaTime();
[email protected]090f7312011-08-05 23:26:40470
xjz48a9cb72016-12-20 04:02:49471 if (observer_)
472 observer_->OnPaused();
473
dalecurtis04bdb582016-08-17 22:15:23474 DCHECK(watch_time_reporter_);
475 watch_time_reporter_->OnPaused();
acolwell9e0840d2014-09-06 19:01:32476 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PAUSE));
sandersd50a635e2016-04-04 22:50:09477 UpdatePlayState();
[email protected]ec9212f2008-12-18 21:40:36478}
479
[email protected]574a1d62009-07-17 03:23:46480bool WebMediaPlayerImpl::supportsSave() const {
acolwellb4034942014-08-28 15:42:43481 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]132dd57c2012-08-10 23:24:34482 return supports_save_;
[email protected]574a1d62009-07-17 03:23:46483}
484
[email protected]39bdde32013-04-17 17:44:20485void WebMediaPlayerImpl::seek(double seconds) {
pkastingf5279482016-07-27 02:18:20486 DVLOG(1) << __func__ << "(" << seconds << "s)";
acolwellb4034942014-08-28 15:42:43487 DCHECK(main_task_runner_->BelongsToCurrentThread());
sandersd1c0bba02016-03-04 23:14:08488 DoSeek(base::TimeDelta::FromSecondsD(seconds), true);
489}
490
491void WebMediaPlayerImpl::DoSeek(base::TimeDelta time, bool time_updated) {
492 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53493
hubbed5f36882016-01-15 22:40:37494#if defined(OS_ANDROID) // WMPI_CAST
495 if (isRemote()) {
sandersd1c0bba02016-03-04 23:14:08496 cast_impl_.seek(time);
hubbed5f36882016-01-15 22:40:37497 return;
498 }
499#endif
500
srirama.mccf671812015-01-08 11:59:13501 ReadyState old_state = ready_state_;
[email protected]1bb666802013-11-28 06:12:08502 if (ready_state_ > WebMediaPlayer::ReadyStateHaveMetadata)
503 SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata);
504
sandersd1c0bba02016-03-04 23:14:08505 // When paused, we know exactly what the current time is and can elide seeks
506 // to it. However, there are two cases that are not elided:
507 // 1) When the pipeline state is not stable.
508 // In this case we just let |pipeline_controller_| decide what to do, as
509 // it has complete information.
510 // 2) For MSE.
511 // Because the buffers may have changed between seeks, MSE seeks are
512 // never elided.
513 if (paused_ && pipeline_controller_.IsStable() && paused_time_ == time &&
514 !chunk_demuxer_) {
515 // If the ready state was high enough before, we can indicate that the seek
516 // completed just by restoring it. Otherwise we will just wait for the real
517 // ready state change to eventually happen.
518 if (old_state == ReadyStateHaveEnoughData) {
srirama.m8f4a37562014-12-13 08:16:18519 main_task_runner_->PostTask(
alokp967c902452016-05-06 05:21:37520 FROM_HERE, base::Bind(&WebMediaPlayerImpl::OnBufferingStateChange,
521 AsWeakPtr(), BUFFERING_HAVE_ENOUGH));
srirama.m36ab2682014-12-11 04:20:01522 }
sandersd1c0bba02016-03-04 23:14:08523 return;
srirama.m36ab2682014-12-11 04:20:01524 }
[email protected]44ff37c02009-10-24 01:03:03525
dalecurtis04bdb582016-08-17 22:15:23526 // Call this before setting |seeking_| so that the current media time can be
527 // recorded by the reporter.
528 if (watch_time_reporter_)
529 watch_time_reporter_->OnSeeking();
530
sandersd50a635e2016-04-04 22:50:09531 // TODO(sandersd): Ideally we would not clear the idle state if
532 // |pipeline_controller_| can elide the seek.
533 is_idle_ = false;
534 ended_ = false;
535
[email protected]b3766a22010-12-22 17:34:13536 seeking_ = true;
sandersd1c0bba02016-03-04 23:14:08537 seek_time_ = time;
538 if (paused_)
539 paused_time_ = time;
540 pipeline_controller_.Seek(time, time_updated);
[email protected]b3766a22010-12-22 17:34:13541
sandersd50a635e2016-04-04 22:50:09542 // This needs to be called after Seek() so that if a resume is triggered, it
543 // is to the correct time.
544 UpdatePlayState();
[email protected]ec9212f2008-12-18 21:40:36545}
546
[email protected]39bdde32013-04-17 17:44:20547void WebMediaPlayerImpl::setRate(double rate) {
pkastingf5279482016-07-27 02:18:20548 DVLOG(1) << __func__ << "(" << rate << ")";
acolwellb4034942014-08-28 15:42:43549 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53550
[email protected]378f0b72009-08-11 17:11:42551 // TODO(kylep): Remove when support for negatives is added. Also, modify the
552 // following checks so rewind uses reasonable values also.
[email protected]39bdde32013-04-17 17:44:20553 if (rate < 0.0)
[email protected]378f0b72009-08-11 17:11:42554 return;
555
556 // Limit rates to reasonable values by clamping.
[email protected]39bdde32013-04-17 17:44:20557 if (rate != 0.0) {
[email protected]378f0b72009-08-11 17:11:42558 if (rate < kMinRate)
559 rate = kMinRate;
560 else if (rate > kMaxRate)
561 rate = kMaxRate;
562 }
563
[email protected]49480902009-07-14 20:23:43564 playback_rate_ = rate;
565 if (!paused_) {
[email protected]f6af7592014-02-28 10:09:11566 pipeline_.SetPlaybackRate(rate);
[email protected]039b7542013-10-17 22:06:25567 if (data_source_)
568 data_source_->MediaPlaybackRateChanged(rate);
[email protected]49480902009-07-14 20:23:43569 }
[email protected]ec9212f2008-12-18 21:40:36570}
571
[email protected]39bdde32013-04-17 17:44:20572void WebMediaPlayerImpl::setVolume(double volume) {
pkastingf5279482016-07-27 02:18:20573 DVLOG(1) << __func__ << "(" << volume << ")";
acolwellb4034942014-08-28 15:42:43574 DCHECK(main_task_runner_->BelongsToCurrentThread());
dalecurtisbb3eaac2016-01-27 21:10:25575 volume_ = volume;
576 pipeline_.SetVolume(volume_ * volume_multiplier_);
dalecurtis04bdb582016-08-17 22:15:23577 if (watch_time_reporter_)
578 watch_time_reporter_->OnVolumeChange(volume);
mlamouri910111362016-11-04 11:28:24579
580 // The play state is updated because the player might have left the autoplay
581 // muted state.
582 UpdatePlayState();
[email protected]ec9212f2008-12-18 21:40:36583}
[email protected]f0a51fb52009-03-05 12:46:38584
guidouc7babef2015-10-22 00:42:35585void WebMediaPlayerImpl::setSinkId(
586 const blink::WebString& sink_id,
587 const blink::WebSecurityOrigin& security_origin,
588 blink::WebSetSinkIdCallbacks* web_callback) {
guidou69223ce2015-06-16 10:36:19589 DCHECK(main_task_runner_->BelongsToCurrentThread());
pkastingf5279482016-07-27 02:18:20590 DVLOG(1) << __func__;
guidouc7babef2015-10-22 00:42:35591
olka68b69392016-04-01 11:42:12592 media::OutputDeviceStatusCB callback =
593 media::ConvertToOutputDeviceStatusCB(web_callback);
guidouc7babef2015-10-22 00:42:35594 media_task_runner_->PostTask(
595 FROM_HERE,
596 base::Bind(&SetSinkIdOnMediaThread, audio_source_provider_,
597 sink_id.utf8(), static_cast<url::Origin>(security_origin),
598 callback));
guidou69223ce2015-06-16 10:36:19599}
600
dalecurtisb6e052f52016-08-25 00:35:55601STATIC_ASSERT_ENUM(WebMediaPlayer::PreloadNone, MultibufferDataSource::NONE);
danakj365175c2016-02-06 00:37:37602STATIC_ASSERT_ENUM(WebMediaPlayer::PreloadMetaData,
dalecurtisb6e052f52016-08-25 00:35:55603 MultibufferDataSource::METADATA);
604STATIC_ASSERT_ENUM(WebMediaPlayer::PreloadAuto, MultibufferDataSource::AUTO);
[email protected]23a8b1d82011-04-05 16:28:20605
[email protected]ef405f66b2012-04-18 02:39:55606void WebMediaPlayerImpl::setPreload(WebMediaPlayer::Preload preload) {
pkastingf5279482016-07-27 02:18:20607 DVLOG(1) << __func__ << "(" << preload << ")";
acolwellb4034942014-08-28 15:42:43608 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]4e6be3f2009-05-07 02:24:44609
dalecurtisb6e052f52016-08-25 00:35:55610 preload_ = static_cast<MultibufferDataSource::Preload>(preload);
[email protected]b49beeb2013-03-01 20:04:00611 if (data_source_)
[email protected]09c60222014-08-07 16:42:31612 data_source_->SetPreload(preload_);
[email protected]4e6be3f2009-05-07 02:24:44613}
614
danakj365175c2016-02-06 00:37:37615STATIC_ASSERT_ENUM(WebMediaPlayer::BufferingStrategy::Normal,
dalecurtisb6e052f52016-08-25 00:35:55616 MultibufferDataSource::BUFFERING_STRATEGY_NORMAL);
danakj365175c2016-02-06 00:37:37617STATIC_ASSERT_ENUM(WebMediaPlayer::BufferingStrategy::Aggressive,
dalecurtisb6e052f52016-08-25 00:35:55618 MultibufferDataSource::BUFFERING_STRATEGY_AGGRESSIVE);
sandersdc6ab163a2015-12-12 03:56:13619
620void WebMediaPlayerImpl::setBufferingStrategy(
621 WebMediaPlayer::BufferingStrategy buffering_strategy) {
pkastingf5279482016-07-27 02:18:20622 DVLOG(1) << __func__;
sandersdc6ab163a2015-12-12 03:56:13623 DCHECK(main_task_runner_->BelongsToCurrentThread());
624
dalecurtis37fe5862016-03-15 19:29:09625#if defined(OS_ANDROID)
626 // We disallow aggressive buffering on Android since it matches the behavior
627 // of the platform media player and may have data usage penalties.
628 // TODO(dalecurtis, hubbe): We should probably stop using "pause-and-buffer"
629 // everywhere. See http://crbug.com/594669 for more details.
dalecurtisb6e052f52016-08-25 00:35:55630 buffering_strategy_ = MultibufferDataSource::BUFFERING_STRATEGY_NORMAL;
dalecurtis37fe5862016-03-15 19:29:09631#else
sandersdc6ab163a2015-12-12 03:56:13632 buffering_strategy_ =
dalecurtisb6e052f52016-08-25 00:35:55633 static_cast<MultibufferDataSource::BufferingStrategy>(buffering_strategy);
dalecurtis37fe5862016-03-15 19:29:09634#endif
635
sandersdc6ab163a2015-12-12 03:56:13636 if (data_source_)
637 data_source_->SetBufferingStrategy(buffering_strategy_);
638}
639
[email protected]4e6be3f2009-05-07 02:24:44640bool WebMediaPlayerImpl::hasVideo() const {
acolwellb4034942014-08-28 15:42:43641 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53642
[email protected]b8877772014-03-26 20:17:15643 return pipeline_metadata_.has_video;
[email protected]d43ed912009-02-03 04:52:53644}
645
[email protected]fc367af2009-08-14 23:06:35646bool WebMediaPlayerImpl::hasAudio() const {
acolwellb4034942014-08-28 15:42:43647 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]fc367af2009-08-14 23:06:35648
[email protected]b8877772014-03-26 20:17:15649 return pipeline_metadata_.has_audio;
[email protected]fc367af2009-08-14 23:06:35650}
651
servolkf25ceed2016-07-01 03:44:38652void WebMediaPlayerImpl::enabledAudioTracksChanged(
653 const blink::WebVector<blink::WebMediaPlayer::TrackId>& enabledTrackIds) {
654 DCHECK(main_task_runner_->BelongsToCurrentThread());
655
656 std::ostringstream logstr;
657 std::vector<MediaTrack::Id> enabledMediaTrackIds;
658 for (const auto& blinkTrackId : enabledTrackIds) {
659 MediaTrack::Id track_id = blinkTrackId.utf8().data();
660 logstr << track_id << " ";
661 enabledMediaTrackIds.push_back(track_id);
662 }
663 MEDIA_LOG(INFO, media_log_) << "Enabled audio tracks: [" << logstr.str()
664 << "]";
665 pipeline_.OnEnabledAudioTracksChanged(enabledMediaTrackIds);
666}
667
668void WebMediaPlayerImpl::selectedVideoTrackChanged(
669 blink::WebMediaPlayer::TrackId* selectedTrackId) {
670 DCHECK(main_task_runner_->BelongsToCurrentThread());
671
672 std::ostringstream logstr;
673 std::vector<MediaTrack::Id> selectedVideoMediaTrackId;
avayvod39c102402016-11-23 21:43:13674 bool canAddVideoTrack =
675 !IsBackgroundVideoTrackOptimizationEnabled() || !IsHidden();
676 if (selectedTrackId && canAddVideoTrack) {
servolkf25ceed2016-07-01 03:44:38677 selectedVideoMediaTrackId.push_back(selectedTrackId->utf8().data());
678 logstr << selectedVideoMediaTrackId[0];
679 }
680 MEDIA_LOG(INFO, media_log_) << "Selected video track: [" << logstr.str()
681 << "]";
682 pipeline_.OnSelectedVideoTrackChanged(selectedVideoMediaTrackId);
683}
684
[email protected]180ef242013-11-07 06:50:46685blink::WebSize WebMediaPlayerImpl::naturalSize() const {
acolwellb4034942014-08-28 15:42:43686 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53687
[email protected]b8877772014-03-26 20:17:15688 return blink::WebSize(pipeline_metadata_.natural_size);
[email protected]d43ed912009-02-03 04:52:53689}
690
[email protected]4e6be3f2009-05-07 02:24:44691bool WebMediaPlayerImpl::paused() const {
acolwellb4034942014-08-28 15:42:43692 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53693
hubbed5f36882016-01-15 22:40:37694#if defined(OS_ANDROID) // WMPI_CAST
695 if (isRemote())
danakj4f1fd6a2017-01-06 21:15:17696 return cast_impl_.IsPaused();
hubbed5f36882016-01-15 22:40:37697#endif
sandersd50a635e2016-04-04 22:50:09698
[email protected]f6af7592014-02-28 10:09:11699 return pipeline_.GetPlaybackRate() == 0.0f;
[email protected]d43ed912009-02-03 04:52:53700}
701
[email protected]4e6be3f2009-05-07 02:24:44702bool WebMediaPlayerImpl::seeking() const {
acolwellb4034942014-08-28 15:42:43703 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53704
[email protected]ef405f66b2012-04-18 02:39:55705 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing)
[email protected]0acebfa2009-08-21 22:45:40706 return false;
[email protected]67cd5052009-09-10 21:53:22707
[email protected]b3766a22010-12-22 17:34:13708 return seeking_;
[email protected]ec9212f2008-12-18 21:40:36709}
710
[email protected]39bdde32013-04-17 17:44:20711double WebMediaPlayerImpl::duration() const {
acolwellb4034942014-08-28 15:42:43712 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]39bdde32013-04-17 17:44:20713
714 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing)
715 return std::numeric_limits<double>::quiet_NaN();
716
[email protected]39bdde32013-04-17 17:44:20717 return GetPipelineDuration();
[email protected]d43ed912009-02-03 04:52:53718}
719
[email protected]db66d0092014-04-16 07:15:12720double WebMediaPlayerImpl::timelineOffset() const {
acolwellb4034942014-08-28 15:42:43721 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]db66d0092014-04-16 07:15:12722
723 if (pipeline_metadata_.timeline_offset.is_null())
724 return std::numeric_limits<double>::quiet_NaN();
725
726 return pipeline_metadata_.timeline_offset.ToJsTime();
727}
728
[email protected]39bdde32013-04-17 17:44:20729double WebMediaPlayerImpl::currentTime() const {
acolwellb4034942014-08-28 15:42:43730 DCHECK(main_task_runner_->BelongsToCurrentThread());
scherkusd2c745b2014-09-04 05:03:40731 DCHECK_NE(ready_state_, WebMediaPlayer::ReadyStateHaveNothing);
732
733 // TODO(scherkus): Replace with an explicit ended signal to HTMLMediaElement,
734 // see http://crbug.com/409280
735 if (ended_)
736 return duration();
737
sandersd1c0bba02016-03-04 23:14:08738 if (seeking())
739 return seek_time_.InSecondsF();
wolenetz1b2ae7d2015-06-10 00:44:21740
hubbed5f36882016-01-15 22:40:37741#if defined(OS_ANDROID) // WMPI_CAST
sandersd1c0bba02016-03-04 23:14:08742 if (isRemote())
hubbed5f36882016-01-15 22:40:37743 return cast_impl_.currentTime();
hubbed5f36882016-01-15 22:40:37744#endif
745
sandersd1c0bba02016-03-04 23:14:08746 if (paused_)
hubbed5f36882016-01-15 22:40:37747 return paused_time_.InSecondsF();
hubbed5f36882016-01-15 22:40:37748
749 return pipeline_.GetMediaTime().InSecondsF();
[email protected]d43ed912009-02-03 04:52:53750}
751
danakj13afe0362016-02-27 01:22:50752WebMediaPlayer::NetworkState WebMediaPlayerImpl::getNetworkState() const {
acolwellb4034942014-08-28 15:42:43753 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]ddb1e5a2010-12-13 20:10:45754 return network_state_;
755}
756
danakj13afe0362016-02-27 01:22:50757WebMediaPlayer::ReadyState WebMediaPlayerImpl::getReadyState() const {
acolwellb4034942014-08-28 15:42:43758 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]ddb1e5a2010-12-13 20:10:45759 return ready_state_;
760}
761
wolenetz4d39cc02016-04-05 19:54:41762blink::WebString WebMediaPlayerImpl::getErrorMessage() {
763 DCHECK(main_task_runner_->BelongsToCurrentThread());
764 return blink::WebString::fromUTF8(media_log_->GetLastErrorMessage());
765}
766
[email protected]02022fc2014-05-16 00:05:31767blink::WebTimeRanges WebMediaPlayerImpl::buffered() const {
acolwellb4034942014-08-28 15:42:43768 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]779a8322014-08-22 21:28:37769
acolwell9e0840d2014-09-06 19:01:32770 Ranges<base::TimeDelta> buffered_time_ranges =
[email protected]02022fc2014-05-16 00:05:31771 pipeline_.GetBufferedTimeRanges();
[email protected]779a8322014-08-22 21:28:37772
773 const base::TimeDelta duration = pipeline_.GetMediaDuration();
dalecurtis39a7f932016-07-19 18:34:59774 if (duration != kInfiniteDuration) {
[email protected]779a8322014-08-22 21:28:37775 buffered_data_source_host_.AddBufferedTimeRanges(
776 &buffered_time_ranges, duration);
777 }
[email protected]02022fc2014-05-16 00:05:31778 return ConvertToWebTimeRanges(buffered_time_ranges);
779}
780
philipjb0e6f3f2014-09-30 09:51:53781blink::WebTimeRanges WebMediaPlayerImpl::seekable() const {
acolwellb4034942014-08-28 15:42:43782 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]39bdde32013-04-17 17:44:20783
dalecurtis56359cb2014-10-28 00:06:29784 if (ready_state_ < WebMediaPlayer::ReadyStateHaveMetadata)
philipjb0e6f3f2014-09-30 09:51:53785 return blink::WebTimeRanges();
786
dalecurtis56359cb2014-10-28 00:06:29787 const double seekable_end = duration();
788
789 // Allow a special exception for seeks to zero for streaming sources with a
790 // finite duration; this allows looping to work.
tguilbertade2bcb2017-01-07 02:57:45791 const bool is_finite_stream = data_source_ && data_source_->IsStreaming() &&
792 std::isfinite(seekable_end);
793
794 // Do not change the seekable range when using the fallback path.
795 // The MediaPlayerRenderer will take care of dropping invalid seeks.
796 const bool force_seeks_to_zero = !use_fallback_path_ && is_finite_stream;
dalecurtis56359cb2014-10-28 00:06:29797
798 // TODO(dalecurtis): Technically this allows seeking on media which return an
tguilbertade2bcb2017-01-07 02:57:45799 // infinite duration so long as DataSource::IsStreaming() is false. While not
dalecurtis56359cb2014-10-28 00:06:29800 // expected, disabling this breaks semi-live players, http://crbug.com/427412.
801 const blink::WebTimeRange seekable_range(
tguilbertade2bcb2017-01-07 02:57:45802 0.0, force_seeks_to_zero ? 0.0 : seekable_end);
philipjb0e6f3f2014-09-30 09:51:53803 return blink::WebTimeRanges(&seekable_range, 1);
[email protected]ec9212f2008-12-18 21:40:36804}
805
[email protected]5d2b3e4c2014-05-12 23:27:30806bool WebMediaPlayerImpl::didLoadingProgress() {
acolwellb4034942014-08-28 15:42:43807 DCHECK(main_task_runner_->BelongsToCurrentThread());
dalecurtise7120dc2016-09-03 02:54:35808
809 // Note: Separate variables used to ensure both methods are called every time.
810 const bool pipeline_progress = pipeline_.DidLoadingProgress();
811 const bool data_progress = buffered_data_source_host_.DidLoadingProgress();
812 const bool did_loading_progress = pipeline_progress || data_progress;
813
814 // If we've idle suspended before reaching kHaveFutureData and loading has
815 // progressed we need to spin up the renderer and figure out if we have enough
816 // data yet; |client_| may be waiting on this signal to trigger playback. The
817 // idle timeout is long enough that this is a low-cost operation.
818 if (highest_ready_state_ < ReadyState::ReadyStateHaveFutureData &&
819 pipeline_controller_.IsSuspended() && did_loading_progress && is_idle_) {
820 is_idle_ = false;
821 UpdatePlayState();
822 }
823
watkd026f792016-11-05 00:28:51824 if (did_loading_progress)
825 last_time_loading_progressed_ = tick_clock_->NowTicks();
826
dalecurtise7120dc2016-09-03 02:54:35827 return did_loading_progress;
[email protected]d43ed912009-02-03 04:52:53828}
829
[email protected]dd5c7972014-08-21 15:00:37830void WebMediaPlayerImpl::paint(blink::WebCanvas* canvas,
831 const blink::WebRect& rect,
xidachen0ebd94d2016-09-07 15:47:22832 SkPaint& paint) {
acolwellb4034942014-08-28 15:42:43833 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]dd061e12014-05-06 19:21:22834 TRACE_EVENT0("media", "WebMediaPlayerImpl:paint");
[email protected]4e6be3f2009-05-07 02:24:44835
xhwang213e50c2016-10-10 23:56:31836 // TODO(sandersd): Move this check into GetCurrentFrameFromCompositor() when
837 // we have other ways to check if decoder owns video frame.
838 // See http://crbug.com/595716 and http://crbug.com/602708
jrummelle616ee92016-10-08 02:15:44839 if (cdm_)
xhwang80739452016-01-13 00:48:00840 return;
841
mcasasf1236fc22015-05-29 22:38:56842 scoped_refptr<VideoFrame> video_frame = GetCurrentFrameFromCompositor();
[email protected]0fe5d43b2014-01-24 23:32:45843
[email protected]b49beeb2013-03-01 20:04:00844 gfx::Rect gfx_rect(rect);
dongseong.hwang0c4e9d82015-01-08 20:11:13845 Context3D context_3d;
mcasas265bdbf82015-06-12 18:44:07846 if (video_frame.get() && video_frame->HasTextures()) {
mcasasf1236fc22015-05-29 22:38:56847 if (!context_3d_cb_.is_null())
dongseong.hwang0c4e9d82015-01-08 20:11:13848 context_3d = context_3d_cb_.Run();
dongseong.hwang0c4e9d82015-01-08 20:11:13849 if (!context_3d.gl)
danakj53f7ec902016-05-21 01:30:10850 return; // Unable to get/create a shared main thread context.
851 if (!context_3d.gr_context)
852 return; // The context has been lost since and can't setup a GrContext.
dongseong.hwang0c4e9d82015-01-08 20:11:13853 }
danakj795f1732015-08-31 23:40:22854 skcanvas_video_renderer_.Paint(video_frame, canvas, gfx::RectF(gfx_rect),
xidachen0ebd94d2016-09-07 15:47:22855 paint, pipeline_metadata_.video_rotation,
danakj795f1732015-08-31 23:40:22856 context_3d);
[email protected]ec9212f2008-12-18 21:40:36857}
[email protected]5df51652009-01-17 00:03:00858
[email protected]38259a7a82009-07-29 21:49:49859bool WebMediaPlayerImpl::hasSingleSecurityOrigin() const {
[email protected]b49beeb2013-03-01 20:04:00860 if (data_source_)
861 return data_source_->HasSingleOrigin();
[email protected]fcdb7462009-10-21 21:05:11862 return true;
[email protected]38259a7a82009-07-29 21:49:49863}
864
[email protected]3fe27112012-06-07 04:00:01865bool WebMediaPlayerImpl::didPassCORSAccessCheck() const {
[email protected]b49beeb2013-03-01 20:04:00866 if (data_source_)
867 return data_source_->DidPassCORSAccessCheck();
868 return false;
[email protected]3fe27112012-06-07 04:00:01869}
870
[email protected]39bdde32013-04-17 17:44:20871double WebMediaPlayerImpl::mediaTimeForTimeValue(double timeValue) const {
qinminb4c39782015-08-10 18:43:24872 return base::TimeDelta::FromSecondsD(timeValue).InSecondsF();
[email protected]e06e16d82011-05-26 22:13:33873}
874
[email protected]d82b18ae2011-03-23 21:28:59875unsigned WebMediaPlayerImpl::decodedFrameCount() const {
acolwellb4034942014-08-28 15:42:43876 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]4c51bc662011-02-16 02:03:16877
acolwell9e0840d2014-09-06 19:01:32878 PipelineStatistics stats = pipeline_.GetStatistics();
[email protected]4c51bc662011-02-16 02:03:16879 return stats.video_frames_decoded;
880}
881
[email protected]d82b18ae2011-03-23 21:28:59882unsigned WebMediaPlayerImpl::droppedFrameCount() const {
acolwellb4034942014-08-28 15:42:43883 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]4c51bc662011-02-16 02:03:16884
acolwell9e0840d2014-09-06 19:01:32885 PipelineStatistics stats = pipeline_.GetStatistics();
[email protected]dd061e12014-05-06 19:21:22886 return stats.video_frames_dropped;
[email protected]4c51bc662011-02-16 02:03:16887}
888
chakshu.a94326b72016-03-08 05:11:44889size_t WebMediaPlayerImpl::audioDecodedByteCount() const {
acolwellb4034942014-08-28 15:42:43890 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]4c51bc662011-02-16 02:03:16891
acolwell9e0840d2014-09-06 19:01:32892 PipelineStatistics stats = pipeline_.GetStatistics();
[email protected]4c51bc662011-02-16 02:03:16893 return stats.audio_bytes_decoded;
894}
895
chakshu.a94326b72016-03-08 05:11:44896size_t WebMediaPlayerImpl::videoDecodedByteCount() const {
acolwellb4034942014-08-28 15:42:43897 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]4c51bc662011-02-16 02:03:16898
acolwell9e0840d2014-09-06 19:01:32899 PipelineStatistics stats = pipeline_.GetStatistics();
[email protected]4c51bc662011-02-16 02:03:16900 return stats.video_bytes_decoded;
901}
902
[email protected]6523b242013-03-13 11:10:07903bool WebMediaPlayerImpl::copyVideoTextureToPlatformTexture(
danakj46070b02016-03-28 21:54:11904 gpu::gles2::GLES2Interface* gl,
zmo57d577a2015-10-30 18:28:59905 unsigned int texture,
906 unsigned int internal_format,
907 unsigned int type,
908 bool premultiply_alpha,
909 bool flip_y) {
xhwang213e50c2016-10-10 23:56:31910 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]bfc05f22013-10-19 17:55:16911 TRACE_EVENT0("media", "WebMediaPlayerImpl:copyVideoTextureToPlatformTexture");
912
xhwang213e50c2016-10-10 23:56:31913 // TODO(sandersd): Move this check into GetCurrentFrameFromCompositor() when
914 // we have other ways to check if decoder owns video frame.
915 // See http://crbug.com/595716 and http://crbug.com/602708
916 if (cdm_)
917 return false;
[email protected]dd061e12014-05-06 19:21:22918
xhwang213e50c2016-10-10 23:56:31919 scoped_refptr<VideoFrame> video_frame = GetCurrentFrameFromCompositor();
jbauman581d041c2016-07-21 01:01:03920 if (!video_frame.get() || !video_frame->HasTextures()) {
[email protected]e56f88c72013-06-25 22:31:29921 return false;
dongseong.hwang0c4e9d82015-01-08 20:11:13922 }
[email protected]df41e252014-02-03 23:39:50923
jbauman581d041c2016-07-21 01:01:03924 Context3D context_3d;
925 if (!context_3d_cb_.is_null())
926 context_3d = context_3d_cb_.Run();
927 return skcanvas_video_renderer_.CopyVideoFrameTexturesToGLTexture(
928 context_3d, gl, video_frame.get(), texture, internal_format, type,
929 premultiply_alpha, flip_y);
[email protected]6523b242013-03-13 11:10:07930}
931
[email protected]7bce1832014-01-09 00:01:22932void WebMediaPlayerImpl::setContentDecryptionModule(
[email protected]9ebc3b03f2014-08-13 04:01:23933 blink::WebContentDecryptionModule* cdm,
934 blink::WebContentDecryptionModuleResult result) {
acolwellb4034942014-08-28 15:42:43935 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]9ebc3b03f2014-08-13 04:01:23936
jrummell06f27072015-06-08 18:12:38937 // Once the CDM is set it can't be cleared as there may be frames being
938 // decrypted on other threads. So fail this request.
939 // http://crbug.com/462365#c7.
xhwang97de4202014-11-25 08:44:01940 if (!cdm) {
941 result.completeWithError(
jrummell06f27072015-06-08 18:12:38942 blink::WebContentDecryptionModuleExceptionInvalidStateError, 0,
xhwang79b193042016-12-13 18:52:43943 "The existing ContentDecryptionModule object cannot be removed at this "
944 "time.");
xhwang97de4202014-11-25 08:44:01945 return;
946 }
947
jrummell89e61d82015-07-23 20:03:34948 // Create a local copy of |result| to avoid problems with the callback
949 // getting passed to the media thread and causing |result| to be destructed
jrummell4acbec912016-02-27 02:45:03950 // on the wrong thread in some failure conditions. Blink should prevent
951 // multiple simultaneous calls.
952 DCHECK(!set_cdm_result_);
jrummell89e61d82015-07-23 20:03:34953 set_cdm_result_.reset(new blink::WebContentDecryptionModuleResult(result));
954
dalecurtis04bdb582016-08-17 22:15:23955 // Recreate the watch time reporter if necessary.
956 const bool was_encrypted = is_encrypted_;
957 is_encrypted_ = true;
958 if (!was_encrypted && watch_time_reporter_)
959 CreateWatchTimeReporter();
960
jrummelle616ee92016-10-08 02:15:44961 SetCdm(cdm);
xhwang97de4202014-11-25 08:44:01962}
963
xhwange8c4181a2014-12-06 08:10:01964void WebMediaPlayerImpl::OnEncryptedMediaInitData(
jrummellcf78967c2015-04-03 05:03:58965 EmeInitDataType init_data_type,
Avi Drissman97785ea2015-12-19 01:11:31966 const std::vector<uint8_t>& init_data) {
jrummellcf78967c2015-04-03 05:03:58967 DCHECK(init_data_type != EmeInitDataType::UNKNOWN);
xhwangbab66f52014-12-02 23:49:50968
ddorwin301ccdb2016-02-25 02:39:17969 // TODO(xhwang): Update this UMA name. https://crbug.com/589251
xhwangbab66f52014-12-02 23:49:50970 UMA_HISTOGRAM_COUNTS("Media.EME.NeedKey", 1);
971
dalecurtis04bdb582016-08-17 22:15:23972 // Recreate the watch time reporter if necessary.
973 const bool was_encrypted = is_encrypted_;
974 is_encrypted_ = true;
975 if (!was_encrypted && watch_time_reporter_)
976 CreateWatchTimeReporter();
977
srirama.m26f864d02015-07-14 05:21:46978 encrypted_client_->encrypted(
davidbenb50f00c2015-12-01 00:01:50979 ConvertToWebInitDataType(init_data_type), init_data.data(),
srirama.m26f864d02015-07-14 05:21:46980 base::saturated_cast<unsigned int>(init_data.size()));
xhwangbab66f52014-12-02 23:49:50981}
982
servolk81e01e02016-03-05 03:29:15983void WebMediaPlayerImpl::OnFFmpegMediaTracksUpdated(
dcheng3076abbf2016-04-22 20:42:39984 std::unique_ptr<MediaTracks> tracks) {
servolk81e01e02016-03-05 03:29:15985 // For MSE/chunk_demuxer case the media track updates are handled by
986 // WebSourceBufferImpl.
987 DCHECK(demuxer_.get());
988 DCHECK(!chunk_demuxer_);
servolkef1e5ef2016-03-25 04:55:26989
990 // Report the media track information to blink.
991 for (const auto& track : tracks->tracks()) {
992 if (track->type() == MediaTrack::Audio) {
servolkfa5c37c2016-06-16 17:56:47993 client_->addAudioTrack(blink::WebString::fromUTF8(track->id()),
994 blink::WebMediaPlayerClient::AudioTrackKindMain,
995 blink::WebString::fromUTF8(track->label()),
996 blink::WebString::fromUTF8(track->language()),
997 /*enabled*/ true);
servolkef1e5ef2016-03-25 04:55:26998 } else if (track->type() == MediaTrack::Video) {
servolkfa5c37c2016-06-16 17:56:47999 client_->addVideoTrack(blink::WebString::fromUTF8(track->id()),
1000 blink::WebMediaPlayerClient::VideoTrackKindMain,
1001 blink::WebString::fromUTF8(track->label()),
1002 blink::WebString::fromUTF8(track->language()),
1003 /*selected*/ true);
servolkef1e5ef2016-03-25 04:55:261004 } else {
1005 // Text tracks are not supported through this code path yet.
1006 NOTREACHED();
1007 }
1008 }
servolk81e01e02016-03-05 03:29:151009}
1010
jrummelle616ee92016-10-08 02:15:441011void WebMediaPlayerImpl::SetCdm(blink::WebContentDecryptionModule* cdm) {
1012 DCHECK(main_task_runner_->BelongsToCurrentThread());
1013 DCHECK(cdm);
xhwang79b193042016-12-13 18:52:431014 scoped_refptr<ContentDecryptionModule> cdm_reference =
jrummelle616ee92016-10-08 02:15:441015 ToWebContentDecryptionModuleImpl(cdm)->GetCdm();
1016 if (!cdm_reference) {
1017 NOTREACHED();
1018 OnCdmAttached(false);
xhwang80739452016-01-13 00:48:001019 return;
1020 }
1021
jrummelle616ee92016-10-08 02:15:441022 CdmContext* cdm_context = cdm_reference->GetCdmContext();
1023 if (!cdm_context) {
1024 OnCdmAttached(false);
1025 return;
1026 }
1027
xjzd3fe45a2016-10-12 18:26:371028 if (observer_)
1029 observer_->OnSetCdm(cdm_context);
1030
jrummelle616ee92016-10-08 02:15:441031 // Keep the reference to the CDM, as it shouldn't be destroyed until
1032 // after the pipeline is done with the |cdm_context|.
1033 pending_cdm_ = std::move(cdm_reference);
1034 pipeline_.SetCdm(cdm_context,
1035 base::Bind(&WebMediaPlayerImpl::OnCdmAttached, AsWeakPtr()));
xhwang97de4202014-11-25 08:44:011036}
1037
jrummell89e61d82015-07-23 20:03:341038void WebMediaPlayerImpl::OnCdmAttached(bool success) {
jrummelle616ee92016-10-08 02:15:441039 DCHECK(main_task_runner_->BelongsToCurrentThread());
1040 DCHECK(pending_cdm_);
1041
1042 // If the CDM is set from the constructor there is no promise
1043 // (|set_cdm_result_|) to fulfill.
xhwang97de4202014-11-25 08:44:011044 if (success) {
jrummelle616ee92016-10-08 02:15:441045 // This will release the previously attached CDM (if any).
1046 cdm_ = std::move(pending_cdm_);
1047 if (set_cdm_result_) {
1048 set_cdm_result_->complete();
1049 set_cdm_result_.reset();
1050 }
1051
xhwang97de4202014-11-25 08:44:011052 return;
1053 }
1054
jrummelle616ee92016-10-08 02:15:441055 pending_cdm_ = nullptr;
1056 if (set_cdm_result_) {
1057 set_cdm_result_->completeWithError(
1058 blink::WebContentDecryptionModuleExceptionNotSupportedError, 0,
xhwang79b193042016-12-13 18:52:431059 "Unable to set ContentDecryptionModule object");
jrummelle616ee92016-10-08 02:15:441060 set_cdm_result_.reset();
1061 }
[email protected]9ebc3b03f2014-08-13 04:01:231062}
1063
sandersd1c0bba02016-03-04 23:14:081064void WebMediaPlayerImpl::OnPipelineSeeked(bool time_updated) {
[email protected]5d11eff2011-09-15 00:06:061065 seeking_ = false;
wolenetz1b2ae7d2015-06-10 00:44:211066 seek_time_ = base::TimeDelta();
hubbe5a2dec022016-03-17 01:14:231067 if (paused_) {
1068#if defined(OS_ANDROID) // WMPI_CAST
1069 if (isRemote()) {
1070 paused_time_ = base::TimeDelta::FromSecondsD(cast_impl_.currentTime());
1071 } else {
1072 paused_time_ = pipeline_.GetMediaTime();
1073 }
1074#else
sandersd1c0bba02016-03-04 23:14:081075 paused_time_ = pipeline_.GetMediaTime();
hubbe5a2dec022016-03-17 01:14:231076#endif
dalecurtis04bdb582016-08-17 22:15:231077 } else {
1078 DCHECK(watch_time_reporter_);
1079 watch_time_reporter_->OnPlaying();
hubbe5a2dec022016-03-17 01:14:231080 }
sandersd1c0bba02016-03-04 23:14:081081 if (time_updated)
1082 should_notify_time_changed_ = true;
dalecurtisaf34d8712016-09-20 04:32:261083
1084 // Reset underflow count upon seek; this prevents looping videos and user
1085 // actions from artificially inflating the underflow count.
1086 underflow_count_ = 0;
[email protected]8931c41a2009-07-07 17:31:491087}
1088
sandersd1c0bba02016-03-04 23:14:081089void WebMediaPlayerImpl::OnPipelineSuspended() {
hubbed5f36882016-01-15 22:40:371090#if defined(OS_ANDROID)
1091 if (isRemote()) {
1092 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner();
sandersd50a635e2016-04-04 22:50:091093 if (frame)
dalecurtise9c89e92016-05-20 19:38:001094 compositor_->PaintSingleFrame(frame);
hubbed5f36882016-01-15 22:40:371095 }
1096#endif
1097
dalecurtis37fe5862016-03-15 19:29:091098 // If we're not in an aggressive buffering state, tell the data source we have
1099 // enough data so that it may release the connection.
1100 if (buffering_strategy_ !=
dalecurtisb6e052f52016-08-25 00:35:551101 MultibufferDataSource::BUFFERING_STRATEGY_AGGRESSIVE) {
liberato3f9f32b2016-03-16 16:54:511102 if (data_source_)
1103 data_source_->OnBufferingHaveEnough(true);
dalecurtis37fe5862016-03-15 19:29:091104 }
1105
sandersd50a635e2016-04-04 22:50:091106 ReportMemoryUsage();
1107
sandersd1c0bba02016-03-04 23:14:081108 if (pending_suspend_resume_cycle_) {
watkdee516f2016-02-18 02:22:191109 pending_suspend_resume_cycle_ = false;
sandersd50a635e2016-04-04 22:50:091110 UpdatePlayState();
dalecurtis0431cbf2016-03-12 01:19:431111 }
sandersd1c0bba02016-03-04 23:14:081112}
1113
alokp967c902452016-05-06 05:21:371114void WebMediaPlayerImpl::OnDemuxerOpened() {
1115 DCHECK(main_task_runner_->BelongsToCurrentThread());
1116 client_->mediaSourceOpened(
1117 new WebMediaSourceImpl(chunk_demuxer_, media_log_));
1118}
1119
1120void WebMediaPlayerImpl::OnError(PipelineStatus status) {
pkastingf5279482016-07-27 02:18:201121 DVLOG(1) << __func__;
alokp967c902452016-05-06 05:21:371122 DCHECK(main_task_runner_->BelongsToCurrentThread());
1123 DCHECK_NE(status, PIPELINE_OK);
1124
1125 if (suppress_destruction_errors_)
1126 return;
1127
1128 ReportPipelineError(load_type_, frame_->getSecurityOrigin(), status);
1129 media_log_->AddEvent(media_log_->CreatePipelineErrorEvent(status));
1130
1131 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing) {
1132 // Any error that occurs before reaching ReadyStateHaveMetadata should
1133 // be considered a format error.
1134 SetNetworkState(WebMediaPlayer::NetworkStateFormatError);
1135 } else {
1136 SetNetworkState(PipelineErrorToNetworkState(status));
1137 }
1138
1139 UpdatePlayState();
1140}
1141
1142void WebMediaPlayerImpl::OnEnded() {
pkastingf5279482016-07-27 02:18:201143 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:431144 DCHECK(main_task_runner_->BelongsToCurrentThread());
scherkusd2c745b2014-09-04 05:03:401145
sandersd1c0bba02016-03-04 23:14:081146 // Ignore state changes until we've completed all outstanding operations.
1147 if (!pipeline_controller_.IsStable())
scherkusd2c745b2014-09-04 05:03:401148 return;
1149
1150 ended_ = true;
[email protected]ce70c982013-12-20 17:04:321151 client_->timeChanged();
sandersd50a635e2016-04-04 22:50:091152
1153 // We don't actually want this to run until |client_| calls seek() or pause(),
1154 // but that should have already happened in timeChanged() and so this is
1155 // expected to be a no-op.
1156 UpdatePlayState();
[email protected]576537842009-08-12 23:52:051157}
1158
alokp967c902452016-05-06 05:21:371159void WebMediaPlayerImpl::OnMetadata(PipelineMetadata metadata) {
pkastingf5279482016-07-27 02:18:201160 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:431161 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]a8e2cb82012-08-17 00:02:391162
[email protected]b8877772014-03-26 20:17:151163 pipeline_metadata_ = metadata;
[email protected]739847c02014-01-16 00:12:251164
dalecurtis04bdb582016-08-17 22:15:231165 SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata);
dalecurtis849cf4b22015-03-27 18:35:451166 UMA_HISTOGRAM_ENUMERATION("Media.VideoRotation", metadata.video_rotation,
acolwell9e0840d2014-09-06 19:01:321167 VIDEO_ROTATION_MAX + 1);
[email protected]21c3f7502013-03-23 03:29:511168
[email protected]b8877772014-03-26 20:17:151169 if (hasVideo()) {
sandersd2c478422016-08-02 01:19:251170 pipeline_metadata_.natural_size = GetRotatedVideoSize(
1171 pipeline_metadata_.video_rotation, pipeline_metadata_.natural_size);
[email protected]f78c3e82014-08-08 01:24:471172
liberato2fd111be2017-01-04 00:25:061173 if (overlay_enabled_) {
1174 // SurfaceView doesn't support rotated video, so transition back if
1175 // the video is now rotated. If |force_video_overlays_|, we keep the
1176 // overlay anyway so that the state machine keeps working.
1177 if (!force_video_overlays_ && !DoesOverlaySupportMetadata())
1178 DisableOverlay();
1179 else if (surface_manager_)
1180 surface_manager_->NaturalSizeChanged(pipeline_metadata_.natural_size);
1181 }
watkf835a792016-06-24 23:24:401182
1183 DCHECK(!video_weblayer_);
dalecurtise1edb312016-06-22 02:33:211184 video_weblayer_.reset(new cc_blink::WebLayerImpl(cc::VideoLayer::Create(
1185 compositor_, pipeline_metadata_.video_rotation)));
jbauman952274d2015-09-10 23:23:361186 video_weblayer_->layer()->SetContentsOpaque(opaque_);
1187 video_weblayer_->SetContentsOpaqueIsFixed(true);
[email protected]a7c4f582014-04-16 18:44:491188 client_->setWebLayer(video_weblayer_.get());
[email protected]a8e2cb82012-08-17 00:02:391189 }
dalecurtis8e4dc682016-03-15 02:30:301190
xjzd3fe45a2016-10-12 18:26:371191 if (observer_)
1192 observer_->OnMetadataChanged(metadata);
1193
dalecurtis04bdb582016-08-17 22:15:231194 CreateWatchTimeReporter();
sandersd50a635e2016-04-04 22:50:091195 UpdatePlayState();
[email protected]a8e2cb82012-08-17 00:02:391196}
1197
alokp967c902452016-05-06 05:21:371198void WebMediaPlayerImpl::OnBufferingStateChange(BufferingState state) {
pkastingf5279482016-07-27 02:18:201199 DVLOG(1) << __func__ << "(" << state << ")";
alokp967c902452016-05-06 05:21:371200 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]b8877772014-03-26 20:17:151201
sandersd1c0bba02016-03-04 23:14:081202 // Ignore buffering state changes until we've completed all outstanding
1203 // operations.
1204 if (!pipeline_controller_.IsStable())
[email protected]ba7d5f92014-06-24 05:37:401205 return;
[email protected]b8877772014-03-26 20:17:151206
chcunninghameb270c92016-07-15 01:00:451207 if (state == BUFFERING_HAVE_ENOUGH) {
dalecurtis821e803f2016-09-01 18:44:151208 if (data_source_ &&
1209 highest_ready_state_ < WebMediaPlayer::ReadyStateHaveEnoughData) {
1210 DCHECK_EQ(underflow_count_, 0);
1211 // Record a zero value for underflow histograms so that the histogram
1212 // includes playbacks which never encounter an underflow event.
1213 UMA_HISTOGRAM_COUNTS_100("Media.UnderflowCount", 0);
1214 UMA_HISTOGRAM_TIMES("Media.UnderflowDuration", base::TimeDelta());
1215 }
1216
chcunninghameb270c92016-07-15 01:00:451217 // TODO(chcunningham): Monitor playback position vs buffered. Potentially
1218 // transition to HAVE_FUTURE_DATA here if not enough is buffered.
1219 SetReadyState(WebMediaPlayer::ReadyStateHaveEnoughData);
[email protected]ba7d5f92014-06-24 05:37:401220
chcunninghameb270c92016-07-15 01:00:451221 // Let the DataSource know we have enough data. It may use this information
1222 // to release unused network connections.
1223 if (data_source_)
1224 data_source_->OnBufferingHaveEnough(false);
dalecurtis849cf4b22015-03-27 18:35:451225
chcunninghameb270c92016-07-15 01:00:451226 // Blink expects a timeChanged() in response to a seek().
1227 if (should_notify_time_changed_)
1228 client_->timeChanged();
dalecurtis0f0097a2015-12-01 17:40:471229
chcunninghameb270c92016-07-15 01:00:451230 // Once we have enough, start reporting the total memory usage. We'll also
1231 // report once playback starts.
1232 ReportMemoryUsage();
dalecurtis9d638a12016-08-30 06:20:551233
1234 // Report the amount of time it took to leave the underflow state. Don't
1235 // bother to report this for MSE playbacks since it's out of our control.
1236 if (underflow_timer_ && data_source_) {
1237 UMA_HISTOGRAM_TIMES("Media.UnderflowDuration",
1238 underflow_timer_->Elapsed());
1239 underflow_timer_.reset();
1240 }
chcunninghameb270c92016-07-15 01:00:451241 } else {
1242 // Buffering has underflowed.
1243 DCHECK_EQ(state, BUFFERING_HAVE_NOTHING);
dalecurtisacd77d62016-09-09 23:23:141244
1245 // Report the number of times we've entered the underflow state. Only report
1246 // for src= playback since for MSE it's out of our control. Ensure we only
1247 // report the value when transitioning from HAVE_ENOUGH to HAVE_NOTHING.
1248 if (data_source_ &&
1249 ready_state_ == WebMediaPlayer::ReadyStateHaveEnoughData) {
1250 UMA_HISTOGRAM_COUNTS_100("Media.UnderflowCount", ++underflow_count_);
1251 underflow_timer_.reset(new base::ElapsedTimer());
1252 }
1253
chcunninghameb270c92016-07-15 01:00:451254 // It shouldn't be possible to underflow if we've not advanced past
1255 // HAVE_CURRENT_DATA.
1256 DCHECK_GT(highest_ready_state_, WebMediaPlayer::ReadyStateHaveCurrentData);
1257 SetReadyState(WebMediaPlayer::ReadyStateHaveCurrentData);
1258 }
sandersd50a635e2016-04-04 22:50:091259
1260 UpdatePlayState();
[email protected]b8877772014-03-26 20:17:151261}
1262
alokp967c902452016-05-06 05:21:371263void WebMediaPlayerImpl::OnDurationChange() {
acolwellb4034942014-08-28 15:42:431264 DCHECK(main_task_runner_->BelongsToCurrentThread());
alokp967c902452016-05-06 05:21:371265
1266 // TODO(sandersd): We should call delegate_->DidPlay() with the new duration,
1267 // especially if it changed from <5s to >5s.
1268 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing)
1269 return;
1270
1271 client_->durationChanged();
[email protected]81bb3322011-07-21 15:55:501272}
1273
alokp967c902452016-05-06 05:21:371274void WebMediaPlayerImpl::OnAddTextTrack(const TextTrackConfig& config,
1275 const AddTextTrackDoneCB& done_cb) {
acolwellb4034942014-08-28 15:42:431276 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]71537722013-05-23 06:47:531277
[email protected]8a561062013-11-22 01:19:311278 const WebInbandTextTrackImpl::Kind web_kind =
1279 static_cast<WebInbandTextTrackImpl::Kind>(config.kind());
1280 const blink::WebString web_label =
1281 blink::WebString::fromUTF8(config.label());
1282 const blink::WebString web_language =
1283 blink::WebString::fromUTF8(config.language());
[email protected]427ff102013-11-26 23:45:401284 const blink::WebString web_id =
1285 blink::WebString::fromUTF8(config.id());
[email protected]71537722013-05-23 06:47:531286
dcheng3076abbf2016-04-22 20:42:391287 std::unique_ptr<WebInbandTextTrackImpl> web_inband_text_track(
henriks9cce5fa2014-12-12 09:35:301288 new WebInbandTextTrackImpl(web_kind, web_label, web_language, web_id));
[email protected]8a561062013-11-22 01:19:311289
dcheng3076abbf2016-04-22 20:42:391290 std::unique_ptr<media::TextTrack> text_track(new TextTrackImpl(
dcheng652f5ff2015-12-27 08:54:001291 main_task_runner_, client_, std::move(web_inband_text_track)));
[email protected]8a561062013-11-22 01:19:311292
dcheng652f5ff2015-12-27 08:54:001293 done_cb.Run(std::move(text_track));
[email protected]71537722013-05-23 06:47:531294}
1295
alokp967c902452016-05-06 05:21:371296void WebMediaPlayerImpl::OnWaitingForDecryptionKey() {
1297 DCHECK(main_task_runner_->BelongsToCurrentThread());
1298
1299 encrypted_client_->didBlockPlaybackWaitingForKey();
1300 // TODO(jrummell): didResumePlaybackBlockedForKey() should only be called
1301 // when a key has been successfully added (e.g. OnSessionKeysChange() with
1302 // |has_additional_usable_key| = true). http://crbug.com/461903
1303 encrypted_client_->didResumePlaybackBlockedForKey();
1304}
1305
alokp5d86e9b2016-05-17 20:20:411306void WebMediaPlayerImpl::OnVideoNaturalSizeChange(const gfx::Size& size) {
1307 DCHECK(main_task_runner_->BelongsToCurrentThread());
1308 DCHECK_NE(ready_state_, WebMediaPlayer::ReadyStateHaveNothing);
1309
sandersd2c478422016-08-02 01:19:251310 gfx::Size rotated_size =
1311 GetRotatedVideoSize(pipeline_metadata_.video_rotation, size);
1312
1313 if (rotated_size == pipeline_metadata_.natural_size)
alokp5d86e9b2016-05-17 20:20:411314 return;
1315
1316 TRACE_EVENT0("media", "WebMediaPlayerImpl::OnNaturalSizeChanged");
sandersd2c478422016-08-02 01:19:251317 media_log_->AddEvent(media_log_->CreateVideoSizeSetEvent(
1318 rotated_size.width(), rotated_size.height()));
alokp5d86e9b2016-05-17 20:20:411319
tsunghungee562e92016-07-20 18:03:311320 if (overlay_enabled_ && surface_manager_)
sandersd2c478422016-08-02 01:19:251321 surface_manager_->NaturalSizeChanged(rotated_size);
alokp5d86e9b2016-05-17 20:20:411322
xjz516ef6d2017-01-07 00:23:061323 gfx::Size old_size = pipeline_metadata_.natural_size;
1324 pipeline_metadata_.natural_size = rotated_size;
1325 if (old_size.IsEmpty()) {
tguilbert796a40e2016-11-09 01:11:421326 // WatchTimeReporter doesn't report metrics for empty videos. Re-create
1327 // |watch_time_reporter_| if we didn't originally know the video size.
1328 CreateWatchTimeReporter();
1329 }
alokp5d86e9b2016-05-17 20:20:411330 client_->sizeChanged();
xjz516ef6d2017-01-07 00:23:061331
1332 if (observer_) {
1333 PipelineMetadata metadata = pipeline_metadata_;
1334 metadata.natural_size = size;
1335 observer_->OnMetadataChanged(metadata);
1336 }
alokp5d86e9b2016-05-17 20:20:411337}
1338
1339void WebMediaPlayerImpl::OnVideoOpacityChange(bool opaque) {
1340 DCHECK(main_task_runner_->BelongsToCurrentThread());
1341 DCHECK_NE(ready_state_, WebMediaPlayer::ReadyStateHaveNothing);
1342
1343 opaque_ = opaque;
1344 // Modify content opaqueness of cc::Layer directly so that
1345 // SetContentsOpaqueIsFixed is ignored.
1346 if (video_weblayer_)
1347 video_weblayer_->layer()->SetContentsOpaque(opaque_);
1348}
1349
dalecurtis0431cbf2016-03-12 01:19:431350void WebMediaPlayerImpl::OnHidden() {
sandersd1e49fb62015-12-12 01:18:061351 DCHECK(main_task_runner_->BelongsToCurrentThread());
avayvod39c102402016-11-23 21:43:131352
dalecurtis04bdb582016-08-17 22:15:231353 if (watch_time_reporter_)
1354 watch_time_reporter_->OnHidden();
avayvod48a8be52016-08-04 19:52:501355
avayvod102cdb62017-01-07 03:11:091356 if (!IsStreaming() && IsBackgroundVideoTrackOptimizationEnabled()) {
avayvodeb9098d2017-01-07 00:33:031357 if (ShouldPauseWhenHidden()) {
1358 // OnPause() will set |paused_when_hidden_| to false and call
1359 // UpdatePlayState(), so set the flag to true after and then return.
1360 OnPause();
1361 paused_when_hidden_ = true;
1362 return;
1363 }
1364
1365 selectedVideoTrackChanged(nullptr);
1366 }
1367
sandersd50a635e2016-04-04 22:50:091368 UpdatePlayState();
dalecurtis8b8505e72016-06-10 21:59:171369
1370 // Schedule suspended playing media to be paused if the user doesn't come back
1371 // to it within some timeout period to avoid any autoplay surprises.
1372 ScheduleIdlePauseTimer();
sandersd1e49fb62015-12-12 01:18:061373}
1374
1375void WebMediaPlayerImpl::OnShown() {
1376 DCHECK(main_task_runner_->BelongsToCurrentThread());
dalecurtis04bdb582016-08-17 22:15:231377 if (watch_time_reporter_)
1378 watch_time_reporter_->OnShown();
1379
avayvodac607d652017-01-06 03:16:431380 compositor_task_runner_->PostTask(
1381 FROM_HERE,
1382 base::Bind(&VideoFrameCompositor::SetForegroundTime,
1383 base::Unretained(compositor_), base::TimeTicks::Now()));
1384
avayvod102cdb62017-01-07 03:11:091385 if (!IsStreaming() && IsBackgroundVideoTrackOptimizationEnabled()) {
avayvodeb9098d2017-01-07 00:33:031386 if (paused_when_hidden_) {
1387 paused_when_hidden_ = false;
1388 OnPlay(); // Calls UpdatePlayState() so return afterwards.
1389 return;
1390 }
1391
1392 if (client_->hasSelectedVideoTrack()) {
1393 WebMediaPlayer::TrackId trackId = client_->getSelectedVideoTrackId();
1394 selectedVideoTrackChanged(&trackId);
1395 }
avayvod39c102402016-11-23 21:43:131396 }
1397
sandersd50a635e2016-04-04 22:50:091398 must_suspend_ = false;
dalecurtis8b8505e72016-06-10 21:59:171399 background_pause_timer_.Stop();
avayvod48a8be52016-08-04 19:52:501400
sandersd50a635e2016-04-04 22:50:091401 UpdatePlayState();
sandersd1e49fb62015-12-12 01:18:061402}
1403
watkd026f792016-11-05 00:28:511404bool WebMediaPlayerImpl::OnSuspendRequested(bool must_suspend) {
dalecurtis0431cbf2016-03-12 01:19:431405 DCHECK(main_task_runner_->BelongsToCurrentThread());
1406
watkd026f792016-11-05 00:28:511407 if (must_suspend) {
sandersd50a635e2016-04-04 22:50:091408 must_suspend_ = true;
watkd026f792016-11-05 00:28:511409 UpdatePlayState();
1410 return true;
1411 }
sandersd50a635e2016-04-04 22:50:091412
watkd026f792016-11-05 00:28:511413 // If we're beyond HaveFutureData, we can safely suspend at any time.
1414 if (highest_ready_state_ >= WebMediaPlayer::ReadyStateHaveFutureData) {
1415 is_idle_ = true;
1416 UpdatePlayState();
1417 return true;
1418 }
1419
1420 // Before HaveFutureData blink will not call play(), so we must be careful to
1421 // only suspend if we'll eventually receive an event that will trigger a
1422 // resume. If the last time loading progressed was a while ago, and we still
1423 // haven't reached HaveFutureData, we assume that we're waiting on more data
1424 // to continue pre-rolling. When that data is loaded the pipeline will be
1425 // resumed by didLoadingProgress().
1426 if (last_time_loading_progressed_.is_null() ||
1427 (tick_clock_->NowTicks() - last_time_loading_progressed_) >
1428 kLoadingToIdleTimeout) {
1429 is_idle_ = true;
1430 UpdatePlayState();
1431 return true;
1432 }
1433
1434 return false;
dalecurtis0431cbf2016-03-12 01:19:431435}
1436
dalecurtisbb3eaac2016-01-27 21:10:251437void WebMediaPlayerImpl::OnPlay() {
1438 play();
1439 client_->playbackStateChanged();
1440}
1441
1442void WebMediaPlayerImpl::OnPause() {
1443 pause();
1444 client_->playbackStateChanged();
1445}
1446
1447void WebMediaPlayerImpl::OnVolumeMultiplierUpdate(double multiplier) {
1448 volume_multiplier_ = multiplier;
1449 setVolume(volume_);
1450}
1451
watkdee516f2016-02-18 02:22:191452void WebMediaPlayerImpl::ScheduleRestart() {
sandersd50a635e2016-04-04 22:50:091453 // TODO(watk): All restart logic should be moved into PipelineController.
1454 if (pipeline_.IsRunning() && !pipeline_controller_.IsPipelineSuspended()) {
watkdee516f2016-02-18 02:22:191455 pending_suspend_resume_cycle_ = true;
sandersd50a635e2016-04-04 22:50:091456 UpdatePlayState();
watkdee516f2016-02-18 02:22:191457 }
1458}
1459
miu77f914c2016-11-19 23:56:181460void WebMediaPlayerImpl::requestRemotePlaybackDisabled(bool disabled) {
1461 if (observer_)
1462 observer_->OnRemotePlaybackDisabled(disabled);
1463}
1464
hubbed5f36882016-01-15 22:40:371465#if defined(OS_ANDROID) // WMPI_CAST
hubbed5f36882016-01-15 22:40:371466bool WebMediaPlayerImpl::isRemote() const {
1467 return cast_impl_.isRemote();
1468}
1469
1470void WebMediaPlayerImpl::SetMediaPlayerManager(
1471 RendererMediaPlayerManagerInterface* media_player_manager) {
1472 cast_impl_.SetMediaPlayerManager(media_player_manager);
1473}
1474
1475void WebMediaPlayerImpl::requestRemotePlayback() {
1476 cast_impl_.requestRemotePlayback();
1477}
1478
1479void WebMediaPlayerImpl::requestRemotePlaybackControl() {
1480 cast_impl_.requestRemotePlaybackControl();
1481}
1482
avayvod8d8c53b2016-11-04 16:10:301483void WebMediaPlayerImpl::requestRemotePlaybackStop() {
1484 cast_impl_.requestRemotePlaybackStop();
1485}
1486
hubbed5f36882016-01-15 22:40:371487void WebMediaPlayerImpl::OnRemotePlaybackEnded() {
pkastingf5279482016-07-27 02:18:201488 DVLOG(1) << __func__;
hubbed5f36882016-01-15 22:40:371489 DCHECK(main_task_runner_->BelongsToCurrentThread());
1490
1491 ended_ = true;
1492 client_->timeChanged();
1493}
1494
1495void WebMediaPlayerImpl::OnDisconnectedFromRemoteDevice(double t) {
sandersd1c0bba02016-03-04 23:14:081496 DoSeek(base::TimeDelta::FromSecondsD(t), false);
hubbed5f36882016-01-15 22:40:371497
hubbed5f36882016-01-15 22:40:371498 // We already told the delegate we're paused when remoting started.
1499 client_->playbackStateChanged();
1500 client_->disconnectedFromRemoteDevice();
sandersd50a635e2016-04-04 22:50:091501
1502 UpdatePlayState();
hubbed5f36882016-01-15 22:40:371503}
1504
1505void WebMediaPlayerImpl::SuspendForRemote() {
sandersd50a635e2016-04-04 22:50:091506 if (pipeline_controller_.IsPipelineSuspended()) {
hubbed5f36882016-01-15 22:40:371507 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner();
sandersd50a635e2016-04-04 22:50:091508 if (frame)
dalecurtise9c89e92016-05-20 19:38:001509 compositor_->PaintSingleFrame(frame);
hubbed5f36882016-01-15 22:40:371510 }
sandersd50a635e2016-04-04 22:50:091511
1512 UpdatePlayState();
hubbed5f36882016-01-15 22:40:371513}
1514
1515gfx::Size WebMediaPlayerImpl::GetCanvasSize() const {
1516 if (!video_weblayer_)
1517 return pipeline_metadata_.natural_size;
1518
1519 return video_weblayer_->bounds();
1520}
1521
1522void WebMediaPlayerImpl::SetDeviceScaleFactor(float scale_factor) {
1523 cast_impl_.SetDeviceScaleFactor(scale_factor);
1524}
hubbee4027f92016-05-19 05:18:131525
tguilbert25a4d112016-10-13 21:56:511526void WebMediaPlayerImpl::SetUseFallbackPath(bool use_fallback_path) {
1527 use_fallback_path_ = use_fallback_path;
1528}
hubbed5f36882016-01-15 22:40:371529#endif // defined(OS_ANDROID) // WMPI_CAST
1530
xjzc102fd82017-01-04 20:13:531531void WebMediaPlayerImpl::setPoster(const blink::WebURL& poster) {
1532#if defined(OS_ANDROID)
1533 cast_impl_.setPoster(poster);
1534#endif
1535
1536 if (observer_)
1537 observer_->OnSetPoster(poster);
1538}
1539
[email protected]fee8a902014-06-03 13:43:361540void WebMediaPlayerImpl::DataSourceInitialized(bool success) {
pkastingf5279482016-07-27 02:18:201541 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:431542 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]a9415292012-01-19 19:55:201543
dalecurtisea27a3ed2016-06-24 01:41:301544#if defined(OS_ANDROID)
1545 // We can't play HLS URLs with WebMediaPlayerImpl, so in cases where they are
1546 // encountered, instruct the HTML media element to create a new WebMediaPlayer
1547 // instance with the correct URL to trigger WebMediaPlayerAndroid creation.
1548 //
1549 // TODO(tguilbert): Remove this code path once we have the ability to host a
1550 // MediaPlayer within a Mojo media renderer. http://crbug.com/580626
tguilbert25a4d112016-10-13 21:56:511551 if (data_source_ && !use_fallback_path_) {
dalecurtisea27a3ed2016-06-24 01:41:301552 const GURL url_after_redirects = data_source_->GetUrlAfterRedirects();
qinmin0d9521272016-10-10 20:43:191553 if (MediaCodecUtil::IsHLSURL(url_after_redirects)) {
dalecurtisea27a3ed2016-06-24 01:41:301554 client_->requestReload(url_after_redirects);
1555 // |this| may be destructed, do nothing after this.
1556 return;
1557 }
1558 }
1559#endif
1560
[email protected]d250190da3b2012-07-23 22:57:301561 if (!success) {
[email protected]ef405f66b2012-04-18 02:39:551562 SetNetworkState(WebMediaPlayer::NetworkStateFormatError);
sandersd50a635e2016-04-04 22:50:091563
1564 // Not really necessary, since the pipeline was never started, but it at
1565 // least this makes sure that the error handling code is in sync.
1566 UpdatePlayState();
1567
[email protected]a9415292012-01-19 19:55:201568 return;
1569 }
1570
[email protected]ef8394c2013-08-21 20:26:301571 StartPipeline();
[email protected]a9415292012-01-19 19:55:201572}
1573
[email protected]122f40252012-06-12 05:01:561574void WebMediaPlayerImpl::NotifyDownloading(bool is_downloading) {
pkastingf5279482016-07-27 02:18:201575 DVLOG(1) << __func__;
[email protected]122f40252012-06-12 05:01:561576 if (!is_downloading && network_state_ == WebMediaPlayer::NetworkStateLoading)
1577 SetNetworkState(WebMediaPlayer::NetworkStateIdle);
1578 else if (is_downloading && network_state_ == WebMediaPlayer::NetworkStateIdle)
1579 SetNetworkState(WebMediaPlayer::NetworkStateLoading);
1580 media_log_->AddEvent(
1581 media_log_->CreateBooleanEvent(
acolwell9e0840d2014-09-06 19:01:321582 MediaLogEvent::NETWORK_ACTIVITY_SET,
[email protected]122f40252012-06-12 05:01:561583 "is_downloading_data", is_downloading));
1584}
1585
watkf835a792016-06-24 23:24:401586void WebMediaPlayerImpl::OnSurfaceCreated(int surface_id) {
tsunghungee562e92016-07-20 18:03:311587 overlay_surface_id_ = surface_id;
dalecurtis4b632fce22016-11-10 00:52:171588 if (!set_surface_cb_.is_null()) {
1589 // If restart is required, the callback is one-shot only.
1590 if (decoder_requires_restart_for_overlay_)
1591 base::ResetAndReturn(&set_surface_cb_).Run(surface_id);
1592 else
1593 set_surface_cb_.Run(surface_id);
1594 }
watkf835a792016-06-24 23:24:401595}
1596
watkdee516f2016-02-18 02:22:191597void WebMediaPlayerImpl::OnSurfaceRequested(
dalecurtis4b632fce22016-11-10 00:52:171598 bool decoder_requires_restart_for_overlay,
1599 const SurfaceCreatedCB& set_surface_cb) {
watkdee516f2016-02-18 02:22:191600 DCHECK(main_task_runner_->BelongsToCurrentThread());
1601 DCHECK(surface_manager_);
tguilbert25a4d112016-10-13 21:56:511602 DCHECK(!use_fallback_path_);
watkdee516f2016-02-18 02:22:191603
1604 // A null callback indicates that the decoder is going away.
dalecurtis4b632fce22016-11-10 00:52:171605 if (set_surface_cb.is_null()) {
tsunghungee562e92016-07-20 18:03:311606 decoder_requires_restart_for_overlay_ = false;
dalecurtis4b632fce22016-11-10 00:52:171607 set_surface_cb_.Reset();
watkdee516f2016-02-18 02:22:191608 return;
1609 }
1610
dalecurtis4b632fce22016-11-10 00:52:171611 // If we get a surface request it means GpuVideoDecoder is initializing, so
1612 // until we get a null surface request, GVD is the active decoder.
1613 //
1614 // If |decoder_requires_restart_for_overlay| is true, we must restart the
1615 // pipeline for fullscreen transitions. The decoder is unable to switch
1616 // surfaces otherwise. If false, we simply need to tell the decoder about the
1617 // new surface and it will handle things seamlessly.
1618 decoder_requires_restart_for_overlay_ = decoder_requires_restart_for_overlay;
1619 set_surface_cb_ = set_surface_cb;
1620
1621 // If we're waiting for the surface to arrive, OnSurfaceCreated() will be
1622 // called later when it arrives; so do nothing for now.
1623 if (overlay_enabled_ && overlay_surface_id_ == SurfaceManager::kNoSurfaceID)
1624 return;
1625
1626 OnSurfaceCreated(overlay_surface_id_);
watkdee516f2016-02-18 02:22:191627}
1628
dcheng3076abbf2016-04-22 20:42:391629std::unique_ptr<Renderer> WebMediaPlayerImpl::CreateRenderer() {
tsunghungee562e92016-07-20 18:03:311630 if (force_video_overlays_)
1631 EnableOverlay();
1632
watkdee516f2016-02-18 02:22:191633 RequestSurfaceCB request_surface_cb;
1634#if defined(OS_ANDROID)
1635 request_surface_cb =
1636 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnSurfaceRequested);
1637#endif
sandersd1e49fb62015-12-12 01:18:061638 return renderer_factory_->CreateRenderer(
1639 media_task_runner_, worker_task_runner_, audio_source_provider_.get(),
watkdee516f2016-02-18 02:22:191640 compositor_, request_surface_cb);
sandersd1e49fb62015-12-12 01:18:061641}
1642
[email protected]ef8394c2013-08-21 20:26:301643void WebMediaPlayerImpl::StartPipeline() {
acolwellb4034942014-08-28 15:42:431644 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]ddbc6ff2013-04-19 15:28:331645
xhwange8c4181a2014-12-06 08:10:011646 Demuxer::EncryptedMediaInitDataCB encrypted_media_init_data_cb =
1647 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnEncryptedMediaInitData);
[email protected]2b57e2e2014-05-09 11:07:251648
tguilbert25a4d112016-10-13 21:56:511649 if (use_fallback_path_) {
tguilbert9881bc22016-10-27 03:13:411650 demuxer_.reset(
1651 new MediaUrlDemuxer(media_task_runner_, fallback_url_,
1652 frame_->document().firstPartyForCookies()));
tguilbert25a4d112016-10-13 21:56:511653 pipeline_controller_.Start(demuxer_.get(), this, false, false);
1654 return;
1655 }
1656
[email protected]ddbc6ff2013-04-19 15:28:331657 // Figure out which demuxer to use.
[email protected]ef8394c2013-08-21 20:26:301658 if (load_type_ != LoadTypeMediaSource) {
[email protected]ddbc6ff2013-04-19 15:28:331659 DCHECK(!chunk_demuxer_);
[email protected]f5443ef72013-04-22 04:03:381660 DCHECK(data_source_);
1661
j.isorcef6778e652015-11-16 17:14:251662#if !defined(MEDIA_DISABLE_FFMPEG)
servolk81e01e02016-03-05 03:29:151663 Demuxer::MediaTracksUpdatedCB media_tracks_updated_cb =
servolkef1e5ef2016-03-25 04:55:261664 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnFFmpegMediaTracksUpdated);
servolk81e01e02016-03-05 03:29:151665
xhwange8c4181a2014-12-06 08:10:011666 demuxer_.reset(new FFmpegDemuxer(media_task_runner_, data_source_.get(),
servolk81e01e02016-03-05 03:29:151667 encrypted_media_init_data_cb,
1668 media_tracks_updated_cb, media_log_));
j.isorcef6778e652015-11-16 17:14:251669#else
alokp967c902452016-05-06 05:21:371670 OnError(PipelineStatus::DEMUXER_ERROR_COULD_NOT_OPEN);
j.isorcef6778e652015-11-16 17:14:251671 return;
1672#endif
[email protected]ddbc6ff2013-04-19 15:28:331673 } else {
[email protected]f5443ef72013-04-22 04:03:381674 DCHECK(!chunk_demuxer_);
1675 DCHECK(!data_source_);
1676
acolwell9e0840d2014-09-06 19:01:321677 chunk_demuxer_ = new ChunkDemuxer(
[email protected]ef8394c2013-08-21 20:26:301678 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnDemuxerOpened),
chcunningham967db2f2016-11-02 20:47:171679 encrypted_media_init_data_cb, media_log_);
[email protected]f5443ef72013-04-22 04:03:381680 demuxer_.reset(chunk_demuxer_);
[email protected]ddbc6ff2013-04-19 15:28:331681 }
1682
sandersdb5e21462016-03-09 01:49:071683 // TODO(sandersd): FileSystem objects may also be non-static, but due to our
1684 // caching layer such situations are broken already. http://crbug.com/593159
1685 bool is_static = !chunk_demuxer_;
avayvod102cdb62017-01-07 03:11:091686 bool is_streaming = IsStreaming();
sandersdb8eb5f1d2016-11-19 04:04:021687 UMA_HISTOGRAM_BOOLEAN("Media.IsStreaming", is_streaming);
sandersdb5e21462016-03-09 01:49:071688
[email protected]f5443ef72013-04-22 04:03:381689 // ... and we're ready to go!
sandersd1e49fb62015-12-12 01:18:061690 // TODO(sandersd): On Android, defer Start() if the tab is not visible.
sandersdb8eb5f1d2016-11-19 04:04:021691 seeking_ = true;
alokp967c902452016-05-06 05:21:371692 pipeline_controller_.Start(demuxer_.get(), this, is_streaming, is_static);
[email protected]f5443ef72013-04-22 04:03:381693}
1694
1695void WebMediaPlayerImpl::SetNetworkState(WebMediaPlayer::NetworkState state) {
pkastingf5279482016-07-27 02:18:201696 DVLOG(1) << __func__ << "(" << state << ")";
acolwellb4034942014-08-28 15:42:431697 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]f5443ef72013-04-22 04:03:381698 network_state_ = state;
1699 // Always notify to ensure client has the latest value.
[email protected]ce70c982013-12-20 17:04:321700 client_->networkStateChanged();
[email protected]f5443ef72013-04-22 04:03:381701}
1702
1703void WebMediaPlayerImpl::SetReadyState(WebMediaPlayer::ReadyState state) {
pkastingf5279482016-07-27 02:18:201704 DVLOG(1) << __func__ << "(" << state << ")";
acolwellb4034942014-08-28 15:42:431705 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]f5443ef72013-04-22 04:03:381706
[email protected]fee8a902014-06-03 13:43:361707 if (state == WebMediaPlayer::ReadyStateHaveEnoughData && data_source_ &&
1708 data_source_->assume_fully_buffered() &&
[email protected]f5443ef72013-04-22 04:03:381709 network_state_ == WebMediaPlayer::NetworkStateLoading)
1710 SetNetworkState(WebMediaPlayer::NetworkStateLoaded);
1711
1712 ready_state_ = state;
sandersd50a635e2016-04-04 22:50:091713 highest_ready_state_ = std::max(highest_ready_state_, ready_state_);
1714
[email protected]f5443ef72013-04-22 04:03:381715 // Always notify to ensure client has the latest value.
[email protected]ce70c982013-12-20 17:04:321716 client_->readyStateChanged();
[email protected]f5443ef72013-04-22 04:03:381717}
1718
Dana Jansens71331252016-03-09 20:57:221719blink::WebAudioSourceProvider* WebMediaPlayerImpl::getAudioSourceProvider() {
[email protected]ff875be52013-06-02 23:47:381720 return audio_source_provider_.get();
[email protected]f5443ef72013-04-22 04:03:381721}
1722
[email protected]f5443ef72013-04-22 04:03:381723double WebMediaPlayerImpl::GetPipelineDuration() const {
[email protected]f6af7592014-02-28 10:09:111724 base::TimeDelta duration = pipeline_.GetMediaDuration();
[email protected]f5443ef72013-04-22 04:03:381725
1726 // Return positive infinity if the resource is unbounded.
1727 // http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html#dom-media-duration
dalecurtis39a7f932016-07-19 18:34:591728 if (duration == kInfiniteDuration)
[email protected]f5443ef72013-04-22 04:03:381729 return std::numeric_limits<double>::infinity();
1730
1731 return duration.InSecondsF();
1732}
1733
[email protected]dd061e12014-05-06 19:21:221734static void GetCurrentFrameAndSignal(
1735 VideoFrameCompositor* compositor,
acolwell9e0840d2014-09-06 19:01:321736 scoped_refptr<VideoFrame>* video_frame_out,
[email protected]dd061e12014-05-06 19:21:221737 base::WaitableEvent* event) {
1738 TRACE_EVENT0("media", "GetCurrentFrameAndSignal");
dalecurtis44ce4de2015-05-11 18:42:071739 *video_frame_out = compositor->GetCurrentFrameAndUpdateIfStale();
[email protected]dd061e12014-05-06 19:21:221740 event->Signal();
1741}
1742
acolwell9e0840d2014-09-06 19:01:321743scoped_refptr<VideoFrame>
[email protected]dd061e12014-05-06 19:21:221744WebMediaPlayerImpl::GetCurrentFrameFromCompositor() {
xhwang213e50c2016-10-10 23:56:311745 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]dd061e12014-05-06 19:21:221746 TRACE_EVENT0("media", "WebMediaPlayerImpl::GetCurrentFrameFromCompositor");
xhwang213e50c2016-10-10 23:56:311747
1748 // Needed when the |main_task_runner_| and |compositor_task_runner_| are the
1749 // same to avoid deadlock in the Wait() below.
[email protected]dd061e12014-05-06 19:21:221750 if (compositor_task_runner_->BelongsToCurrentThread())
dalecurtis44ce4de2015-05-11 18:42:071751 return compositor_->GetCurrentFrameAndUpdateIfStale();
[email protected]dd061e12014-05-06 19:21:221752
1753 // Use a posted task and waitable event instead of a lock otherwise
1754 // WebGL/Canvas can see different content than what the compositor is seeing.
acolwell9e0840d2014-09-06 19:01:321755 scoped_refptr<VideoFrame> video_frame;
gab0d77c7cb2016-06-02 00:00:231756 base::WaitableEvent event(base::WaitableEvent::ResetPolicy::AUTOMATIC,
1757 base::WaitableEvent::InitialState::NOT_SIGNALED);
[email protected]dd061e12014-05-06 19:21:221758 compositor_task_runner_->PostTask(FROM_HERE,
1759 base::Bind(&GetCurrentFrameAndSignal,
1760 base::Unretained(compositor_),
1761 &video_frame,
1762 &event));
1763 event.Wait();
1764 return video_frame;
1765}
1766
sandersd50a635e2016-04-04 22:50:091767void WebMediaPlayerImpl::UpdatePlayState() {
xhwang213e50c2016-10-10 23:56:311768 DCHECK(main_task_runner_->BelongsToCurrentThread());
1769
hubbed5f36882016-01-15 22:40:371770#if defined(OS_ANDROID) // WMPI_CAST
sandersd50a635e2016-04-04 22:50:091771 bool is_remote = isRemote();
sandersdaaff1a652016-11-17 01:47:251772 bool is_streaming = false;
sandersd50a635e2016-04-04 22:50:091773#else
1774 bool is_remote = false;
avayvod102cdb62017-01-07 03:11:091775 bool is_streaming = IsStreaming();
hubbed5f36882016-01-15 22:40:371776#endif
xhwang213e50c2016-10-10 23:56:311777
dalecurtis8b8505e72016-06-10 21:59:171778 bool is_suspended = pipeline_controller_.IsSuspended();
avayvod39c102402016-11-23 21:43:131779 bool is_backgrounded = IsBackgroundedSuspendEnabled() && IsHidden();
sandersdaaff1a652016-11-17 01:47:251780 PlayState state = UpdatePlayState_ComputePlayState(
1781 is_remote, is_streaming, is_suspended, is_backgrounded);
sandersd50a635e2016-04-04 22:50:091782 SetDelegateState(state.delegate_state);
1783 SetMemoryReportingState(state.is_memory_reporting_enabled);
1784 SetSuspendState(state.is_suspended || pending_suspend_resume_cycle_);
1785}
dalecurtis5bbc487e2016-02-27 04:15:051786
sandersd50a635e2016-04-04 22:50:091787void WebMediaPlayerImpl::SetDelegateState(DelegateState new_state) {
mlamouri910111362016-11-04 11:28:241788 if (!delegate_)
dalecurtis5bbc487e2016-02-27 04:15:051789 return;
1790
mlamouri910111362016-11-04 11:28:241791 if (delegate_state_ == new_state) {
1792 if (delegate_state_ != DelegateState::PLAYING ||
1793 autoplay_muted_ == client_->isAutoplayingMuted()) {
1794 return;
1795 }
1796 }
1797
sandersd50a635e2016-04-04 22:50:091798 delegate_state_ = new_state;
1799
1800 switch (delegate_state_) {
1801 case DelegateState::GONE:
1802 delegate_->PlayerGone(delegate_id_);
1803 break;
mlamouri910111362016-11-04 11:28:241804 case DelegateState::PLAYING: {
1805 autoplay_muted_ = client_->isAutoplayingMuted();
1806 bool has_audio = autoplay_muted_ ? false : hasAudio();
zqzhang5d8eab72016-08-26 20:34:301807 delegate_->DidPlay(
mlamouri910111362016-11-04 11:28:241808 delegate_id_, hasVideo(), has_audio, false,
zqzhang5d8eab72016-08-26 20:34:301809 media::DurationToMediaContentType(pipeline_.GetMediaDuration()));
sandersd50a635e2016-04-04 22:50:091810 break;
mlamouri910111362016-11-04 11:28:241811 }
sandersd50a635e2016-04-04 22:50:091812 case DelegateState::PAUSED:
1813 delegate_->DidPause(delegate_id_, false);
1814 break;
1815 case DelegateState::ENDED:
1816 delegate_->DidPause(delegate_id_, true);
1817 break;
dalecurtis0f0097a2015-12-01 17:40:471818 }
1819}
1820
sandersd50a635e2016-04-04 22:50:091821void WebMediaPlayerImpl::SetMemoryReportingState(
1822 bool is_memory_reporting_enabled) {
1823 if (memory_usage_reporting_timer_.IsRunning() ==
1824 is_memory_reporting_enabled) {
hubbed5f36882016-01-15 22:40:371825 return;
sandersd50a635e2016-04-04 22:50:091826 }
sandersd1c0bba02016-03-04 23:14:081827
sandersd50a635e2016-04-04 22:50:091828 if (is_memory_reporting_enabled) {
1829 memory_usage_reporting_timer_.Start(FROM_HERE,
1830 base::TimeDelta::FromSeconds(2), this,
1831 &WebMediaPlayerImpl::ReportMemoryUsage);
1832 } else {
1833 memory_usage_reporting_timer_.Stop();
1834 ReportMemoryUsage();
1835 }
1836}
1837
1838void WebMediaPlayerImpl::SetSuspendState(bool is_suspended) {
xhwang213e50c2016-10-10 23:56:311839 DCHECK(main_task_runner_->BelongsToCurrentThread());
1840
sandersd50a635e2016-04-04 22:50:091841 // Do not change the state after an error has occurred.
1842 // TODO(sandersd): Update PipelineController to remove the need for this.
1843 if (IsNetworkStateError(network_state_))
sandersd1c0bba02016-03-04 23:14:081844 return;
1845
jbauman2438e872016-11-15 04:45:191846#if defined(OS_LINUX)
halliwell6451e242016-06-01 15:00:241847 // TODO(sandersd): idle suspend is disabled if decoder owns video frame.
jbauman2438e872016-11-15 04:45:191848 // Used on Chromecast. Since GetCurrentFrameFromCompositor is a synchronous
1849 // cross-thread post, avoid the cost on platforms that always allow suspend.
1850 // Need to find a better mechanism for this. See http://crbug.com/602708
dalecurtis7f366b2242016-04-13 01:16:171851 if (can_suspend_state_ == CanSuspendState::UNKNOWN) {
1852 scoped_refptr<VideoFrame> frame = GetCurrentFrameFromCompositor();
1853 if (frame) {
1854 can_suspend_state_ =
1855 frame->metadata()->IsTrue(VideoFrameMetadata::DECODER_OWNS_FRAME)
1856 ? CanSuspendState::NO
1857 : CanSuspendState::YES;
1858 }
1859 }
1860#else
1861 can_suspend_state_ = CanSuspendState::YES;
1862#endif
1863
1864 if (can_suspend_state_ == CanSuspendState::NO)
1865 return;
1866
sandersd50a635e2016-04-04 22:50:091867 if (is_suspended) {
1868 pipeline_controller_.Suspend();
1869 } else {
1870 pipeline_controller_.Resume();
1871 }
1872}
1873
1874WebMediaPlayerImpl::PlayState
1875WebMediaPlayerImpl::UpdatePlayState_ComputePlayState(bool is_remote,
sandersdaaff1a652016-11-17 01:47:251876 bool is_streaming,
dalecurtis8b8505e72016-06-10 21:59:171877 bool is_suspended,
sandersd50a635e2016-04-04 22:50:091878 bool is_backgrounded) {
1879 PlayState result;
1880
1881 // This includes both data source (before pipeline startup) and pipeline
1882 // errors.
1883 bool has_error = IsNetworkStateError(network_state_);
1884
1885 // After HaveMetadata, we know which tracks are present and the duration.
1886 bool have_metadata = ready_state_ >= WebMediaPlayer::ReadyStateHaveMetadata;
1887
dalecurtiscc8baf72016-10-27 01:49:441888 // After HaveFutureData, Blink will call play() if the state is not paused;
1889 // prior to this point |paused_| is not accurate.
sandersd50a635e2016-04-04 22:50:091890 bool have_future_data =
1891 highest_ready_state_ >= WebMediaPlayer::ReadyStateHaveFutureData;
1892
dalecurtis8b8505e72016-06-10 21:59:171893 // Background suspend is not enabled for audio-only players unless paused,
1894 // though in the case of audio-only the session should be kept.
avayvod48a8be52016-08-04 19:52:501895 // Videos are not suspended if the user resumed the playback via the remote
1896 // controls earlier and it's still playing.
1897 bool is_backgrounded_video = is_backgrounded && have_metadata && hasVideo();
1898 bool can_play_backgrounded = is_backgrounded_video && !is_remote &&
1899 hasAudio() && IsResumeBackgroundVideosEnabled();
1900 bool is_background_playing =
1901 delegate_ && delegate_->IsPlayingBackgroundVideo();
sandersdaaff1a652016-11-17 01:47:251902 bool background_suspended = !is_streaming && is_backgrounded_video &&
avayvod48a8be52016-08-04 19:52:501903 !(can_play_backgrounded && is_background_playing);
dalecurtiscc8baf72016-10-27 01:49:441904 bool background_pause_suspended =
sandersdaaff1a652016-11-17 01:47:251905 !is_streaming && is_backgrounded && paused_ && have_future_data;
sandersd50a635e2016-04-04 22:50:091906
dalecurtiscc8baf72016-10-27 01:49:441907 // Idle suspension is allowed prior to have future data since there exist
1908 // mechanisms to exit the idle state when the player is capable of reaching
1909 // the have future data state; see didLoadingProgress().
1910 //
sandersd50a635e2016-04-04 22:50:091911 // TODO(sandersd): Make the delegate suspend idle players immediately when
1912 // hidden.
sandersdaaff1a652016-11-17 01:47:251913 bool idle_suspended =
1914 !is_streaming && is_idle_ && paused_ && !seeking_ && !overlay_enabled_;
dalecurtise7120dc2016-09-03 02:54:351915
1916 // If we're already suspended, see if we can wait for user interaction. Prior
1917 // to HaveFutureData, we require |is_idle_| to remain suspended. |is_idle_|
1918 // will be cleared when we receive data which may take us to HaveFutureData.
1919 bool can_stay_suspended =
1920 (is_idle_ || have_future_data) && is_suspended && paused_ && !seeking_;
sandersd50a635e2016-04-04 22:50:091921
1922 // Combined suspend state.
dalecurtise7120dc2016-09-03 02:54:351923 result.is_suspended = is_remote || must_suspend_ || idle_suspended ||
1924 background_suspended || background_pause_suspended ||
1925 can_stay_suspended;
sandersd50a635e2016-04-04 22:50:091926
1927 // We do not treat |playback_rate_| == 0 as paused. For the media session,
1928 // being paused implies displaying a play button, which is incorrect in this
1929 // case. For memory usage reporting, we just use the same definition (but we
1930 // don't have to).
1931 //
1932 // Similarly, we don't consider |ended_| to be paused. Blink will immediately
1933 // call pause() or seek(), so |ended_| should not affect the computation.
1934 // Despite that, |ended_| does result in a separate paused state, to simplfy
1935 // the contract for SetDelegateState().
1936 //
1937 // |has_session| is used to decide when to create a media session. Idle
1938 // suspension does not destroy the media session, because we expect that the
1939 // notification controls (and audio focus) remain. We also require:
1940 // - |have_metadata|, since the tracks and duration are passed to DidPlay().
1941 // - |have_future_data|, since we need to know whether we are paused to
1942 // correctly configure the session.
1943 //
1944 // TODO(sandersd): If Blink told us the paused state sooner, we could create
1945 // the media session sooner.
1946 bool can_play = !has_error && !is_remote && have_future_data;
avayvod48a8be52016-08-04 19:52:501947 bool has_session_playing =
1948 can_play && !must_suspend_ && !background_suspended;
1949
1950 // |has_session_suspended| means the player is suspended from the media
1951 // element point of view but paused and can be resumed from the delegate point
1952 // of view. Therefore it behaves like |paused_| for the delegate.
1953 bool has_session_suspended = can_play && !must_suspend_ &&
1954 background_suspended && can_play_backgrounded;
1955
1956 bool has_session = has_session_playing || has_session_suspended;
sandersd50a635e2016-04-04 22:50:091957
1958 if (!has_session) {
1959 result.delegate_state = DelegateState::GONE;
avayvod48a8be52016-08-04 19:52:501960 } else if (paused_ || has_session_suspended) {
dalecurtise7120dc2016-09-03 02:54:351961 result.delegate_state =
1962 ended_ ? DelegateState::ENDED : DelegateState::PAUSED;
sandersd50a635e2016-04-04 22:50:091963 } else {
1964 result.delegate_state = DelegateState::PLAYING;
1965 }
1966
dalecurtis8b8505e72016-06-10 21:59:171967 // It's not critical if some cases where memory usage can change are missed,
sandersd50a635e2016-04-04 22:50:091968 // since media memory changes are usually gradual.
1969 result.is_memory_reporting_enabled =
1970 can_play && !result.is_suspended && !paused_;
1971
1972 return result;
dalecurtis0f0097a2015-12-01 17:40:471973}
1974
dalecurtis83266c72015-10-29 18:43:201975void WebMediaPlayerImpl::ReportMemoryUsage() {
1976 DCHECK(main_task_runner_->BelongsToCurrentThread());
1977
wdzierzanowskifd4cd91c52015-12-02 23:50:201978 // About base::Unretained() usage below: We destroy |demuxer_| on the main
1979 // thread. Before that, however, ~WebMediaPlayerImpl() posts a task to the
1980 // media thread and waits for it to finish. Hence, the GetMemoryUsage() task
1981 // posted here must finish earlier.
1982
1983 if (demuxer_) {
1984 base::PostTaskAndReplyWithResult(
1985 media_task_runner_.get(), FROM_HERE,
1986 base::Bind(&Demuxer::GetMemoryUsage, base::Unretained(demuxer_.get())),
1987 base::Bind(&WebMediaPlayerImpl::FinishMemoryUsageReport, AsWeakPtr()));
1988 } else {
1989 FinishMemoryUsageReport(0);
1990 }
1991}
1992
1993void WebMediaPlayerImpl::FinishMemoryUsageReport(int64_t demuxer_memory_usage) {
1994 DCHECK(main_task_runner_->BelongsToCurrentThread());
1995
dalecurtis83266c72015-10-29 18:43:201996 const PipelineStatistics stats = pipeline_.GetStatistics();
servolk639473e492016-12-15 04:14:201997 const int64_t data_source_memory_usage =
1998 data_source_ ? data_source_->GetMemoryUsage() : 0;
dalecurtis83266c72015-10-29 18:43:201999 const int64_t current_memory_usage =
2000 stats.audio_memory_usage + stats.video_memory_usage +
servolk639473e492016-12-15 04:14:202001 data_source_memory_usage + demuxer_memory_usage;
dalecurtis83266c72015-10-29 18:43:202002
dalecurtis3a7d38f42016-03-07 21:17:132003 // Note, this isn't entirely accurate, there may be VideoFrames held by the
2004 // compositor or other resources that we're unaware of.
2005
dalecurtis83266c72015-10-29 18:43:202006 DVLOG(2) << "Memory Usage -- Audio: " << stats.audio_memory_usage
servolk639473e492016-12-15 04:14:202007 << ", Video: " << stats.video_memory_usage
2008 << ", DataSource: " << data_source_memory_usage
wdzierzanowskifd4cd91c52015-12-02 23:50:202009 << ", Demuxer: " << demuxer_memory_usage;
dalecurtis83266c72015-10-29 18:43:202010
2011 const int64_t delta = current_memory_usage - last_reported_memory_usage_;
2012 last_reported_memory_usage_ = current_memory_usage;
2013 adjust_allocated_memory_cb_.Run(delta);
servolk639473e492016-12-15 04:14:202014
2015 if (hasAudio()) {
2016 UMA_HISTOGRAM_MEMORY_KB("Media.WebMediaPlayerImpl.Memory.Audio",
2017 stats.audio_memory_usage / 1024);
2018 }
2019 if (hasVideo()) {
2020 UMA_HISTOGRAM_MEMORY_KB("Media.WebMediaPlayerImpl.Memory.Video",
2021 stats.video_memory_usage / 1024);
2022 }
2023 if (data_source_) {
2024 UMA_HISTOGRAM_MEMORY_KB("Media.WebMediaPlayerImpl.Memory.DataSource",
2025 data_source_memory_usage / 1024);
2026 }
2027 if (demuxer_) {
2028 UMA_HISTOGRAM_MEMORY_KB("Media.WebMediaPlayerImpl.Memory.Demuxer",
2029 demuxer_memory_usage / 1024);
2030 }
dalecurtis83266c72015-10-29 18:43:202031}
2032
dalecurtis8b8505e72016-06-10 21:59:172033void WebMediaPlayerImpl::ScheduleIdlePauseTimer() {
dalecurtise7120dc2016-09-03 02:54:352034 // Only schedule the pause timer if we're playing and are suspended.
2035 if (paused_ || !pipeline_controller_.IsSuspended())
dalecurtis8b8505e72016-06-10 21:59:172036 return;
2037
2038#if defined(OS_ANDROID)
2039 // Remote players will be suspended and locally paused.
2040 if (isRemote())
2041 return;
2042#endif
2043
2044 // Idle timeout chosen arbitrarily.
2045 background_pause_timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(5),
2046 this, &WebMediaPlayerImpl::OnPause);
2047}
2048
dalecurtis04bdb582016-08-17 22:15:232049void WebMediaPlayerImpl::CreateWatchTimeReporter() {
2050 // Create the watch time reporter and synchronize its initial state.
2051 watch_time_reporter_.reset(new WatchTimeReporter(
2052 hasAudio(), hasVideo(), !!chunk_demuxer_, is_encrypted_, media_log_,
2053 pipeline_metadata_.natural_size,
2054 base::Bind(&GetCurrentTimeInternal, this)));
2055 watch_time_reporter_->OnVolumeChange(volume_);
avayvod39c102402016-11-23 21:43:132056 if (IsHidden())
dalecurtis04bdb582016-08-17 22:15:232057 watch_time_reporter_->OnHidden();
2058 else
2059 watch_time_reporter_->OnShown();
2060}
2061
avayvod39c102402016-11-23 21:43:132062bool WebMediaPlayerImpl::IsHidden() const {
2063 DCHECK(main_task_runner_->BelongsToCurrentThread());
2064
2065 return delegate_ && delegate_->IsHidden();
2066}
2067
avayvod102cdb62017-01-07 03:11:092068bool WebMediaPlayerImpl::IsStreaming() const {
2069 return data_source_ && data_source_->IsStreaming();
2070}
2071
liberato2fd111be2017-01-04 00:25:062072bool WebMediaPlayerImpl::DoesOverlaySupportMetadata() const {
2073 return pipeline_metadata_.video_rotation == VIDEO_ROTATION_0;
2074}
2075
xjzaf29d4182016-12-16 01:52:322076void WebMediaPlayerImpl::ActivateViewportIntersectionMonitoring(bool activate) {
2077 DCHECK(main_task_runner_->BelongsToCurrentThread());
2078
2079 client_->activateViewportIntersectionMonitoring(activate);
2080}
2081
avayvodeb9098d2017-01-07 00:33:032082bool WebMediaPlayerImpl::ShouldPauseWhenHidden() const {
2083#if defined(OS_ANDROID) // WMPI_CAST
2084 if (isRemote())
2085 return false;
2086#endif // defined(OS_ANDROID) // WMPI_CAST
2087
2088 return hasVideo() && !hasAudio();
2089}
2090
acolwell9e0840d2014-09-06 19:01:322091} // namespace media