blob: fb081b50fae8f5ee7647a5be2c40ce74934f92d5 [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
sandersd35d2c3f2017-01-14 02:04:42152// How much time must have elapsed since loading last progressed before we
153// assume that the decoder will have had time to complete preroll.
154constexpr base::TimeDelta kPrerollAttemptTimeout =
watkd026f792016-11-05 00:28:51155 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),
sandersd35d2c3f2017-01-14 02:04:42185 delegate_has_audio_(false),
[email protected]ef405f66b2012-04-18 02:39:55186 network_state_(WebMediaPlayer::NetworkStateEmpty),
187 ready_state_(WebMediaPlayer::ReadyStateHaveNothing),
sandersd50a635e2016-04-04 22:50:09188 highest_ready_state_(WebMediaPlayer::ReadyStateHaveNothing),
dalecurtisb6e052f52016-08-25 00:35:55189 preload_(MultibufferDataSource::AUTO),
190 buffering_strategy_(MultibufferDataSource::BUFFERING_STRATEGY_NORMAL),
altiminbf328382016-12-07 14:28:31191 main_task_runner_(frame->loadingTaskRunner()),
acolwell755d12d2014-08-30 01:09:19192 media_task_runner_(params.media_task_runner()),
dcastagna617d086b2015-08-20 01:39:30193 worker_task_runner_(params.worker_task_runner()),
acolwell755d12d2014-08-30 01:09:19194 media_log_(params.media_log()),
acolwellb4034942014-08-28 15:42:43195 pipeline_(media_task_runner_, media_log_.get()),
sandersd1c0bba02016-03-04 23:14:08196 pipeline_controller_(
197 &pipeline_,
198 base::Bind(&WebMediaPlayerImpl::CreateRenderer,
199 base::Unretained(this)),
200 base::Bind(&WebMediaPlayerImpl::OnPipelineSeeked, AsWeakPtr()),
201 base::Bind(&WebMediaPlayerImpl::OnPipelineSuspended, AsWeakPtr()),
avayvod2135a642017-01-13 00:17:14202 base::Bind(&WebMediaPlayerImpl::OnBeforePipelineResume, AsWeakPtr()),
203 base::Bind(&WebMediaPlayerImpl::OnPipelineResumed, AsWeakPtr()),
alokp967c902452016-05-06 05:21:37204 base::Bind(&WebMediaPlayerImpl::OnError, AsWeakPtr())),
[email protected]f988d9b2014-07-25 00:35:43205 load_type_(LoadTypeURL),
[email protected]75e145a2014-04-15 17:44:32206 opaque_(false),
wolenetz1b2ae7d2015-06-10 00:44:21207 playback_rate_(0.0),
[email protected]49480902009-07-14 20:23:43208 paused_(true),
avayvodeb9098d2017-01-07 00:33:03209 paused_when_hidden_(false),
[email protected]b3766a22010-12-22 17:34:13210 seeking_(false),
watkdee516f2016-02-18 02:22:19211 pending_suspend_resume_cycle_(false),
scherkusd2c745b2014-09-04 05:03:40212 ended_(false),
yoichio863bebf2016-03-04 07:56:58213 should_notify_time_changed_(false),
tsunghungee562e92016-07-20 18:03:31214 overlay_enabled_(false),
215 decoder_requires_restart_for_overlay_(false),
[email protected]5badb082010-06-11 17:40:15216 client_(client),
srirama.m26f864d02015-07-14 05:21:46217 encrypted_client_(encrypted_client),
[email protected]baff4512011-10-19 18:21:07218 delegate_(delegate),
dalecurtisbb3eaac2016-01-27 21:10:25219 delegate_id_(0),
[email protected]d726eddc2013-07-02 22:25:55220 defer_load_cb_(params.defer_load_cb()),
dongseong.hwang0c4e9d82015-01-08 20:11:13221 context_3d_cb_(params.context_3d_cb()),
dalecurtis83266c72015-10-29 18:43:20222 adjust_allocated_memory_cb_(params.adjust_allocated_memory_cb()),
223 last_reported_memory_usage_(0),
[email protected]132dd57c2012-08-10 23:24:34224 supports_save_(true),
[email protected]f5443ef72013-04-22 04:03:38225 chunk_demuxer_(NULL),
hubbe5f0ad43b2015-12-14 20:57:26226 url_index_(url_index),
Bartosz Fabianowski85a823812015-04-16 10:27:51227 // Threaded compositing isn't enabled universally yet.
fdoraydb3ef7d2016-06-09 15:42:38228 compositor_task_runner_(params.compositor_task_runner()
229 ? params.compositor_task_runner()
230 : base::ThreadTaskRunnerHandle::Get()),
alokp5d86e9b2016-05-17 20:20:41231 compositor_(new VideoFrameCompositor(compositor_task_runner_)),
hubbed5f36882016-01-15 22:40:37232#if defined(OS_ANDROID) // WMPI_CAST
dalecurtisbb3eaac2016-01-27 21:10:25233 cast_impl_(this, client_, params.context_3d_cb()),
hubbed5f36882016-01-15 22:40:37234#endif
dalecurtisbb3eaac2016-01-27 21:10:25235 volume_(1.0),
236 volume_multiplier_(1.0),
watkdee516f2016-02-18 02:22:19237 renderer_factory_(std::move(renderer_factory)),
dalecurtis2ff781da2016-03-03 01:52:13238 surface_manager_(params.surface_manager()),
tsunghungee562e92016-07-20 18:03:31239 overlay_surface_id_(SurfaceManager::kNoSurfaceID),
dalecurtis7f366b2242016-04-13 01:16:17240 suppress_destruction_errors_(false),
dalecurtis04bdb582016-08-17 22:15:23241 can_suspend_state_(CanSuspendState::UNKNOWN),
tguilbert25a4d112016-10-13 21:56:51242 use_fallback_path_(false),
dalecurtis9d638a12016-08-30 06:20:55243 is_encrypted_(false),
xjzd3fe45a2016-10-12 18:26:37244 underflow_count_(0),
sandersd35d2c3f2017-01-14 02:04:42245 preroll_attempt_pending_(false),
avayvod590011e32017-01-20 02:01:00246 observer_(params.media_observer()),
247 max_keyframe_distance_to_disable_background_video_(
248 params.max_keyframe_distance_to_disable_background_video()) {
dalecurtis83266c72015-10-29 18:43:20249 DCHECK(!adjust_allocated_memory_cb_.is_null());
xhwang59d4175a2016-01-14 03:19:30250 DCHECK(renderer_factory_);
servolkef1e5ef2016-03-25 04:55:26251 DCHECK(client_);
dalecurtis83266c72015-10-29 18:43:20252
watkd026f792016-11-05 00:28:51253 tick_clock_.reset(new base::DefaultTickClock());
254
tsunghungee562e92016-07-20 18:03:31255 force_video_overlays_ = base::CommandLine::ForCurrentProcess()->HasSwitch(
256 switches::kForceVideoOverlays);
257
ampea73f792017-01-19 04:05:39258 enable_fullscreen_video_overlays_ =
259 base::FeatureList::IsEnabled(media::kOverlayFullscreenVideo);
260
sandersd35d2c3f2017-01-14 02:04:42261 if (delegate_) {
dalecurtisbb3eaac2016-01-27 21:10:25262 delegate_id_ = delegate_->AddObserver(this);
sandersd35d2c3f2017-01-14 02:04:42263 delegate_->SetIdle(delegate_id_, true);
264 }
sandersd1e49fb62015-12-12 01:18:06265
[email protected]c93eb0a62011-08-09 22:47:24266 media_log_->AddEvent(
acolwell9e0840d2014-09-06 19:01:32267 media_log_->CreateEvent(MediaLogEvent::WEBMEDIAPLAYER_CREATED));
[email protected]4e6be3f2009-05-07 02:24:44268
jrummelle616ee92016-10-08 02:15:44269 if (params.initial_cdm())
270 SetCdm(params.initial_cdm());
xhwang0ad11e512014-11-25 23:43:09271
xhwangf94a634d2014-10-22 22:07:27272 // TODO(xhwang): When we use an external Renderer, many methods won't work,
xhwang6fa356202014-12-11 00:44:12273 // e.g. GetCurrentFrameFromCompositor(). See http://crbug.com/434861
olkae4ba2ed82016-12-06 16:34:51274 audio_source_provider_ =
275 new WebAudioSourceProviderImpl(params.audio_renderer_sink(), media_log_);
[email protected]ec9212f2008-12-18 21:40:36276}
277
[email protected]4e6be3f2009-05-07 02:24:44278WebMediaPlayerImpl::~WebMediaPlayerImpl() {
acolwellb4034942014-08-28 15:42:43279 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53280
alokp1116967f2016-06-11 17:30:56281 suppress_destruction_errors_ = true;
sandersd1e49fb62015-12-12 01:18:06282 if (delegate_) {
dalecurtisbb3eaac2016-01-27 21:10:25283 delegate_->PlayerGone(delegate_id_);
284 delegate_->RemoveObserver(delegate_id_);
sandersd1e49fb62015-12-12 01:18:06285 }
[email protected]baff4512011-10-19 18:21:07286
dalecurtis04bdb582016-08-17 22:15:23287 // Finalize any watch time metrics before destroying the pipeline.
288 watch_time_reporter_.reset();
289
alokp967c902452016-05-06 05:21:37290 // Pipeline must be stopped before it is destroyed.
291 pipeline_.Stop();
[email protected]f6af7592014-02-28 10:09:11292
dalecurtis83266c72015-10-29 18:43:20293 if (last_reported_memory_usage_)
294 adjust_allocated_memory_cb_.Run(-last_reported_memory_usage_);
295
dalecurtise1edb312016-06-22 02:33:21296 // Destruct compositor resources in the proper order.
297 client_->setWebLayer(nullptr);
298 if (video_weblayer_)
299 static_cast<cc::VideoLayer*>(video_weblayer_->layer())->StopUsingProvider();
[email protected]dd061e12014-05-06 19:21:22300 compositor_task_runner_->DeleteSoon(FROM_HERE, compositor_);
xhwangea8bb3562015-06-08 21:18:37301
302 media_log_->AddEvent(
303 media_log_->CreateEvent(MediaLogEvent::WEBMEDIAPLAYER_DESTROYED));
[email protected]ec9212f2008-12-18 21:40:36304}
305
guidou9bfe4e2f2016-04-09 08:31:19306void WebMediaPlayerImpl::load(LoadType load_type,
307 const blink::WebMediaPlayerSource& source,
[email protected]62e5e682013-03-07 23:53:24308 CORSMode cors_mode) {
guidou9bfe4e2f2016-04-09 08:31:19309 // Only URL or MSE blob URL is supported.
310 DCHECK(source.isURL());
311 blink::WebURL url = source.getAsURL();
pkastingf5279482016-07-27 02:18:20312 DVLOG(1) << __func__ << "(" << load_type << ", " << url << ", " << cors_mode
313 << ")";
[email protected]d726eddc2013-07-02 22:25:55314 if (!defer_load_cb_.is_null()) {
315 defer_load_cb_.Run(base::Bind(
[email protected]ef8394c2013-08-21 20:26:30316 &WebMediaPlayerImpl::DoLoad, AsWeakPtr(), load_type, url, cors_mode));
[email protected]d726eddc2013-07-02 22:25:55317 return;
318 }
[email protected]ef8394c2013-08-21 20:26:30319 DoLoad(load_type, url, cors_mode);
[email protected]62e5e682013-03-07 23:53:24320}
321
watk9c87c6fa2016-05-06 20:36:51322bool WebMediaPlayerImpl::supportsOverlayFullscreenVideo() {
323#if defined(OS_ANDROID)
watkf835a792016-06-24 23:24:40324 return true;
watk9c87c6fa2016-05-06 20:36:51325#else
326 return false;
327#endif
328}
329
tsunghungee562e92016-07-20 18:03:31330void WebMediaPlayerImpl::EnableOverlay() {
331 overlay_enabled_ = true;
watkf835a792016-06-24 23:24:40332 if (surface_manager_) {
333 surface_created_cb_.Reset(
334 base::Bind(&WebMediaPlayerImpl::OnSurfaceCreated, AsWeakPtr()));
335 surface_manager_->CreateFullscreenSurface(pipeline_metadata_.natural_size,
336 surface_created_cb_.callback());
337 }
tsunghungee562e92016-07-20 18:03:31338
339 if (decoder_requires_restart_for_overlay_)
watkdee516f2016-02-18 02:22:19340 ScheduleRestart();
341}
342
tsunghungee562e92016-07-20 18:03:31343void WebMediaPlayerImpl::DisableOverlay() {
344 overlay_enabled_ = false;
watkf835a792016-06-24 23:24:40345 surface_created_cb_.Cancel();
tsunghungee562e92016-07-20 18:03:31346 overlay_surface_id_ = SurfaceManager::kNoSurfaceID;
347
348 if (decoder_requires_restart_for_overlay_)
watkdee516f2016-02-18 02:22:19349 ScheduleRestart();
dalecurtis4b632fce22016-11-10 00:52:17350 else if (!set_surface_cb_.is_null())
351 set_surface_cb_.Run(overlay_surface_id_);
watkdee516f2016-02-18 02:22:19352}
353
tsunghungee562e92016-07-20 18:03:31354void WebMediaPlayerImpl::enteredFullscreen() {
liberato2fd111be2017-01-04 00:25:06355 // |force_video_overlays_| implies that we're already in overlay mode, so take
356 // no action here. Otherwise, switch to an overlay if it's allowed and if
357 // it will display properly.
358 if (!force_video_overlays_ && enable_fullscreen_video_overlays_ &&
359 DoesOverlaySupportMetadata()) {
tsunghungee562e92016-07-20 18:03:31360 EnableOverlay();
liberato2fd111be2017-01-04 00:25:06361 }
xjzd3fe45a2016-10-12 18:26:37362 if (observer_)
363 observer_->OnEnteredFullscreen();
tsunghungee562e92016-07-20 18:03:31364}
365
366void WebMediaPlayerImpl::exitedFullscreen() {
liberato2fd111be2017-01-04 00:25:06367 // If we're in overlay mode, then exit it unless we're supposed to be in
368 // overlay mode all the time.
369 if (!force_video_overlays_ && overlay_enabled_)
tsunghungee562e92016-07-20 18:03:31370 DisableOverlay();
xjzd3fe45a2016-10-12 18:26:37371 if (observer_)
372 observer_->OnExitedFullscreen();
tsunghungee562e92016-07-20 18:03:31373}
374
xjzcdbbe732016-12-03 20:47:42375void WebMediaPlayerImpl::becameDominantVisibleContent(bool isDominant) {
376 if (observer_)
377 observer_->OnBecameDominantVisibleContent(isDominant);
378}
379
[email protected]ef8394c2013-08-21 20:26:30380void WebMediaPlayerImpl::DoLoad(LoadType load_type,
[email protected]180ef242013-11-07 06:50:46381 const blink::WebURL& url,
[email protected]d726eddc2013-07-02 22:25:55382 CORSMode cors_mode) {
pkastingf5279482016-07-27 02:18:20383 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:43384 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d726eddc2013-07-02 22:25:55385
[email protected]62e5e682013-03-07 23:53:24386 GURL gurl(url);
xhwangbffbf452016-04-01 05:26:45387 ReportMetrics(load_type, gurl, frame_->getSecurityOrigin());
[email protected]62e5e682013-03-07 23:53:24388
[email protected]926f8fd2013-04-12 20:27:53389 // Set subresource URL for crash reporting.
390 base::debug::SetCrashKeyValue("subresource_url", gurl.spec());
391
tguilbert25a4d112016-10-13 21:56:51392 if (use_fallback_path_)
393 fallback_url_ = gurl;
394
[email protected]ef8394c2013-08-21 20:26:30395 load_type_ = load_type;
396
[email protected]62e5e682013-03-07 23:53:24397 SetNetworkState(WebMediaPlayer::NetworkStateLoading);
398 SetReadyState(WebMediaPlayer::ReadyStateHaveNothing);
kinukof19cde72015-12-18 23:15:25399 media_log_->AddEvent(media_log_->CreateLoadEvent(url.string().utf8()));
[email protected]d726eddc2013-07-02 22:25:55400
401 // Media source pipelines can start immediately.
[email protected]ef8394c2013-08-21 20:26:30402 if (load_type == LoadTypeMediaSource) {
[email protected]d726eddc2013-07-02 22:25:55403 supports_save_ = false;
[email protected]ef8394c2013-08-21 20:26:30404 StartPipeline();
hubbe5f0ad43b2015-12-14 20:57:26405 } else {
dalecurtisb6e052f52016-08-25 00:35:55406 data_source_.reset(new MultibufferDataSource(
407 url, static_cast<UrlData::CORSMode>(cors_mode), main_task_runner_,
408 url_index_, frame_, media_log_.get(), &buffered_data_source_host_,
409 base::Bind(&WebMediaPlayerImpl::NotifyDownloading, AsWeakPtr())));
avayvode46d7bef2016-03-30 23:18:26410 data_source_->SetPreload(preload_);
411 data_source_->SetBufferingStrategy(buffering_strategy_);
412 data_source_->Initialize(
413 base::Bind(&WebMediaPlayerImpl::DataSourceInitialized, AsWeakPtr()));
hubbe5f0ad43b2015-12-14 20:57:26414 }
hubbed5f36882016-01-15 22:40:37415
416#if defined(OS_ANDROID) // WMPI_CAST
dalecurtisbb3eaac2016-01-27 21:10:25417 cast_impl_.Initialize(url, frame_, delegate_id_);
hubbed5f36882016-01-15 22:40:37418#endif
[email protected]62e5e682013-03-07 23:53:24419}
420
[email protected]4e6be3f2009-05-07 02:24:44421void WebMediaPlayerImpl::play() {
pkastingf5279482016-07-27 02:18:20422 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:43423 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53424
hubbed5f36882016-01-15 22:40:37425#if defined(OS_ANDROID) // WMPI_CAST
426 if (isRemote()) {
dalecurtis6e2716d2016-01-21 04:49:15427 cast_impl_.play();
hubbed5f36882016-01-15 22:40:37428 return;
429 }
430#endif
sandersd35d2c3f2017-01-14 02:04:42431 // TODO(sandersd): Do we want to reset the idle timer here?
432 if (delegate_)
433 delegate_->SetIdle(delegate_id_, false);
[email protected]49480902009-07-14 20:23:43434 paused_ = false;
yoichio863bebf2016-03-04 07:56:58435 pipeline_.SetPlaybackRate(playback_rate_);
dalecurtis4619cd02016-09-22 21:39:10436 background_pause_timer_.Stop();
sandersd1c0bba02016-03-04 23:14:08437
[email protected]039b7542013-10-17 22:06:25438 if (data_source_)
439 data_source_->MediaIsPlaying();
[email protected]090f7312011-08-05 23:26:40440
xjz48a9cb72016-12-20 04:02:49441 if (observer_)
442 observer_->OnPlaying();
443
dalecurtis04bdb582016-08-17 22:15:23444 DCHECK(watch_time_reporter_);
445 watch_time_reporter_->OnPlaying();
acolwell9e0840d2014-09-06 19:01:32446 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PLAY));
sandersd50a635e2016-04-04 22:50:09447 UpdatePlayState();
[email protected]ec9212f2008-12-18 21:40:36448}
449
[email protected]4e6be3f2009-05-07 02:24:44450void WebMediaPlayerImpl::pause() {
pkastingf5279482016-07-27 02:18:20451 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:43452 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53453
sandersd50a635e2016-04-04 22:50:09454 // We update the paused state even when casting, since we expect pause() to be
455 // called when casting begins, and when we exit casting we should end up in a
456 // paused state.
[email protected]49480902009-07-14 20:23:43457 paused_ = true;
hubbed5f36882016-01-15 22:40:37458
avayvodeb9098d2017-01-07 00:33:03459 // No longer paused because it was hidden.
460 paused_when_hidden_ = false;
461
hubbed5f36882016-01-15 22:40:37462#if defined(OS_ANDROID) // WMPI_CAST
463 if (isRemote()) {
dalecurtis6e2716d2016-01-21 04:49:15464 cast_impl_.pause();
hubbed5f36882016-01-15 22:40:37465 return;
466 }
467#endif
468
a.berwal338bf002015-04-22 11:14:50469 pipeline_.SetPlaybackRate(0.0);
sandersd1c0bba02016-03-04 23:14:08470
471 // pause() may be called after playback has ended and the HTMLMediaElement
472 // requires that currentTime() == duration() after ending. We want to ensure
473 // |paused_time_| matches currentTime() in this case or a future seek() may
474 // incorrectly discard what it thinks is a seek to the existing time.
avayvodcc273dd2017-01-19 19:35:12475 paused_time_ = ended_ ? GetPipelineMediaDuration() : pipeline_.GetMediaTime();
[email protected]090f7312011-08-05 23:26:40476
xjz48a9cb72016-12-20 04:02:49477 if (observer_)
478 observer_->OnPaused();
479
dalecurtis04bdb582016-08-17 22:15:23480 DCHECK(watch_time_reporter_);
481 watch_time_reporter_->OnPaused();
acolwell9e0840d2014-09-06 19:01:32482 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PAUSE));
avayvod2135a642017-01-13 00:17:14483
sandersd50a635e2016-04-04 22:50:09484 UpdatePlayState();
[email protected]ec9212f2008-12-18 21:40:36485}
486
[email protected]574a1d62009-07-17 03:23:46487bool WebMediaPlayerImpl::supportsSave() const {
acolwellb4034942014-08-28 15:42:43488 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]132dd57c2012-08-10 23:24:34489 return supports_save_;
[email protected]574a1d62009-07-17 03:23:46490}
491
[email protected]39bdde32013-04-17 17:44:20492void WebMediaPlayerImpl::seek(double seconds) {
pkastingf5279482016-07-27 02:18:20493 DVLOG(1) << __func__ << "(" << seconds << "s)";
acolwellb4034942014-08-28 15:42:43494 DCHECK(main_task_runner_->BelongsToCurrentThread());
sandersd1c0bba02016-03-04 23:14:08495 DoSeek(base::TimeDelta::FromSecondsD(seconds), true);
496}
497
498void WebMediaPlayerImpl::DoSeek(base::TimeDelta time, bool time_updated) {
499 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53500
hubbed5f36882016-01-15 22:40:37501#if defined(OS_ANDROID) // WMPI_CAST
502 if (isRemote()) {
sandersd1c0bba02016-03-04 23:14:08503 cast_impl_.seek(time);
hubbed5f36882016-01-15 22:40:37504 return;
505 }
506#endif
507
srirama.mccf671812015-01-08 11:59:13508 ReadyState old_state = ready_state_;
[email protected]1bb666802013-11-28 06:12:08509 if (ready_state_ > WebMediaPlayer::ReadyStateHaveMetadata)
510 SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata);
511
sandersd1c0bba02016-03-04 23:14:08512 // When paused, we know exactly what the current time is and can elide seeks
513 // to it. However, there are two cases that are not elided:
514 // 1) When the pipeline state is not stable.
515 // In this case we just let |pipeline_controller_| decide what to do, as
516 // it has complete information.
517 // 2) For MSE.
518 // Because the buffers may have changed between seeks, MSE seeks are
519 // never elided.
520 if (paused_ && pipeline_controller_.IsStable() && paused_time_ == time &&
521 !chunk_demuxer_) {
522 // If the ready state was high enough before, we can indicate that the seek
523 // completed just by restoring it. Otherwise we will just wait for the real
524 // ready state change to eventually happen.
525 if (old_state == ReadyStateHaveEnoughData) {
srirama.m8f4a37562014-12-13 08:16:18526 main_task_runner_->PostTask(
alokp967c902452016-05-06 05:21:37527 FROM_HERE, base::Bind(&WebMediaPlayerImpl::OnBufferingStateChange,
528 AsWeakPtr(), BUFFERING_HAVE_ENOUGH));
srirama.m36ab2682014-12-11 04:20:01529 }
sandersd1c0bba02016-03-04 23:14:08530 return;
srirama.m36ab2682014-12-11 04:20:01531 }
[email protected]44ff37c02009-10-24 01:03:03532
dalecurtis04bdb582016-08-17 22:15:23533 // Call this before setting |seeking_| so that the current media time can be
534 // recorded by the reporter.
535 if (watch_time_reporter_)
536 watch_time_reporter_->OnSeeking();
537
sandersd35d2c3f2017-01-14 02:04:42538 // TODO(sandersd): Move |seeking_| to PipelineController.
539 // TODO(sandersd): Do we want to reset the idle timer here?
540 if (delegate_)
541 delegate_->SetIdle(delegate_id_, false);
sandersd50a635e2016-04-04 22:50:09542 ended_ = false;
[email protected]b3766a22010-12-22 17:34:13543 seeking_ = true;
sandersd1c0bba02016-03-04 23:14:08544 seek_time_ = time;
545 if (paused_)
546 paused_time_ = time;
547 pipeline_controller_.Seek(time, time_updated);
[email protected]b3766a22010-12-22 17:34:13548
sandersd50a635e2016-04-04 22:50:09549 // This needs to be called after Seek() so that if a resume is triggered, it
550 // is to the correct time.
551 UpdatePlayState();
[email protected]ec9212f2008-12-18 21:40:36552}
553
[email protected]39bdde32013-04-17 17:44:20554void WebMediaPlayerImpl::setRate(double rate) {
pkastingf5279482016-07-27 02:18:20555 DVLOG(1) << __func__ << "(" << rate << ")";
acolwellb4034942014-08-28 15:42:43556 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53557
[email protected]378f0b72009-08-11 17:11:42558 // TODO(kylep): Remove when support for negatives is added. Also, modify the
559 // following checks so rewind uses reasonable values also.
[email protected]39bdde32013-04-17 17:44:20560 if (rate < 0.0)
[email protected]378f0b72009-08-11 17:11:42561 return;
562
563 // Limit rates to reasonable values by clamping.
[email protected]39bdde32013-04-17 17:44:20564 if (rate != 0.0) {
[email protected]378f0b72009-08-11 17:11:42565 if (rate < kMinRate)
566 rate = kMinRate;
567 else if (rate > kMaxRate)
568 rate = kMaxRate;
569 }
570
[email protected]49480902009-07-14 20:23:43571 playback_rate_ = rate;
572 if (!paused_) {
[email protected]f6af7592014-02-28 10:09:11573 pipeline_.SetPlaybackRate(rate);
[email protected]039b7542013-10-17 22:06:25574 if (data_source_)
575 data_source_->MediaPlaybackRateChanged(rate);
[email protected]49480902009-07-14 20:23:43576 }
[email protected]ec9212f2008-12-18 21:40:36577}
578
[email protected]39bdde32013-04-17 17:44:20579void WebMediaPlayerImpl::setVolume(double volume) {
pkastingf5279482016-07-27 02:18:20580 DVLOG(1) << __func__ << "(" << volume << ")";
acolwellb4034942014-08-28 15:42:43581 DCHECK(main_task_runner_->BelongsToCurrentThread());
dalecurtisbb3eaac2016-01-27 21:10:25582 volume_ = volume;
583 pipeline_.SetVolume(volume_ * volume_multiplier_);
dalecurtis04bdb582016-08-17 22:15:23584 if (watch_time_reporter_)
585 watch_time_reporter_->OnVolumeChange(volume);
mlamouri910111362016-11-04 11:28:24586
587 // The play state is updated because the player might have left the autoplay
588 // muted state.
589 UpdatePlayState();
[email protected]ec9212f2008-12-18 21:40:36590}
[email protected]f0a51fb52009-03-05 12:46:38591
guidouc7babef2015-10-22 00:42:35592void WebMediaPlayerImpl::setSinkId(
593 const blink::WebString& sink_id,
594 const blink::WebSecurityOrigin& security_origin,
595 blink::WebSetSinkIdCallbacks* web_callback) {
guidou69223ce2015-06-16 10:36:19596 DCHECK(main_task_runner_->BelongsToCurrentThread());
pkastingf5279482016-07-27 02:18:20597 DVLOG(1) << __func__;
guidouc7babef2015-10-22 00:42:35598
olka68b69392016-04-01 11:42:12599 media::OutputDeviceStatusCB callback =
600 media::ConvertToOutputDeviceStatusCB(web_callback);
guidouc7babef2015-10-22 00:42:35601 media_task_runner_->PostTask(
602 FROM_HERE,
603 base::Bind(&SetSinkIdOnMediaThread, audio_source_provider_,
604 sink_id.utf8(), static_cast<url::Origin>(security_origin),
605 callback));
guidou69223ce2015-06-16 10:36:19606}
607
dalecurtisb6e052f52016-08-25 00:35:55608STATIC_ASSERT_ENUM(WebMediaPlayer::PreloadNone, MultibufferDataSource::NONE);
danakj365175c2016-02-06 00:37:37609STATIC_ASSERT_ENUM(WebMediaPlayer::PreloadMetaData,
dalecurtisb6e052f52016-08-25 00:35:55610 MultibufferDataSource::METADATA);
611STATIC_ASSERT_ENUM(WebMediaPlayer::PreloadAuto, MultibufferDataSource::AUTO);
[email protected]23a8b1d82011-04-05 16:28:20612
[email protected]ef405f66b2012-04-18 02:39:55613void WebMediaPlayerImpl::setPreload(WebMediaPlayer::Preload preload) {
pkastingf5279482016-07-27 02:18:20614 DVLOG(1) << __func__ << "(" << preload << ")";
acolwellb4034942014-08-28 15:42:43615 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]4e6be3f2009-05-07 02:24:44616
dalecurtisb6e052f52016-08-25 00:35:55617 preload_ = static_cast<MultibufferDataSource::Preload>(preload);
[email protected]b49beeb2013-03-01 20:04:00618 if (data_source_)
[email protected]09c60222014-08-07 16:42:31619 data_source_->SetPreload(preload_);
[email protected]4e6be3f2009-05-07 02:24:44620}
621
danakj365175c2016-02-06 00:37:37622STATIC_ASSERT_ENUM(WebMediaPlayer::BufferingStrategy::Normal,
dalecurtisb6e052f52016-08-25 00:35:55623 MultibufferDataSource::BUFFERING_STRATEGY_NORMAL);
danakj365175c2016-02-06 00:37:37624STATIC_ASSERT_ENUM(WebMediaPlayer::BufferingStrategy::Aggressive,
dalecurtisb6e052f52016-08-25 00:35:55625 MultibufferDataSource::BUFFERING_STRATEGY_AGGRESSIVE);
sandersdc6ab163a2015-12-12 03:56:13626
627void WebMediaPlayerImpl::setBufferingStrategy(
628 WebMediaPlayer::BufferingStrategy buffering_strategy) {
pkastingf5279482016-07-27 02:18:20629 DVLOG(1) << __func__;
sandersdc6ab163a2015-12-12 03:56:13630 DCHECK(main_task_runner_->BelongsToCurrentThread());
631
dalecurtis37fe5862016-03-15 19:29:09632#if defined(OS_ANDROID)
633 // We disallow aggressive buffering on Android since it matches the behavior
634 // of the platform media player and may have data usage penalties.
635 // TODO(dalecurtis, hubbe): We should probably stop using "pause-and-buffer"
636 // everywhere. See http://crbug.com/594669 for more details.
dalecurtisb6e052f52016-08-25 00:35:55637 buffering_strategy_ = MultibufferDataSource::BUFFERING_STRATEGY_NORMAL;
dalecurtis37fe5862016-03-15 19:29:09638#else
sandersdc6ab163a2015-12-12 03:56:13639 buffering_strategy_ =
dalecurtisb6e052f52016-08-25 00:35:55640 static_cast<MultibufferDataSource::BufferingStrategy>(buffering_strategy);
dalecurtis37fe5862016-03-15 19:29:09641#endif
642
sandersdc6ab163a2015-12-12 03:56:13643 if (data_source_)
644 data_source_->SetBufferingStrategy(buffering_strategy_);
645}
646
[email protected]4e6be3f2009-05-07 02:24:44647bool WebMediaPlayerImpl::hasVideo() const {
acolwellb4034942014-08-28 15:42:43648 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53649
[email protected]b8877772014-03-26 20:17:15650 return pipeline_metadata_.has_video;
[email protected]d43ed912009-02-03 04:52:53651}
652
[email protected]fc367af2009-08-14 23:06:35653bool WebMediaPlayerImpl::hasAudio() const {
acolwellb4034942014-08-28 15:42:43654 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]fc367af2009-08-14 23:06:35655
[email protected]b8877772014-03-26 20:17:15656 return pipeline_metadata_.has_audio;
[email protected]fc367af2009-08-14 23:06:35657}
658
servolkf25ceed2016-07-01 03:44:38659void WebMediaPlayerImpl::enabledAudioTracksChanged(
660 const blink::WebVector<blink::WebMediaPlayer::TrackId>& enabledTrackIds) {
661 DCHECK(main_task_runner_->BelongsToCurrentThread());
662
663 std::ostringstream logstr;
664 std::vector<MediaTrack::Id> enabledMediaTrackIds;
665 for (const auto& blinkTrackId : enabledTrackIds) {
666 MediaTrack::Id track_id = blinkTrackId.utf8().data();
667 logstr << track_id << " ";
668 enabledMediaTrackIds.push_back(track_id);
669 }
670 MEDIA_LOG(INFO, media_log_) << "Enabled audio tracks: [" << logstr.str()
671 << "]";
672 pipeline_.OnEnabledAudioTracksChanged(enabledMediaTrackIds);
673}
674
675void WebMediaPlayerImpl::selectedVideoTrackChanged(
676 blink::WebMediaPlayer::TrackId* selectedTrackId) {
677 DCHECK(main_task_runner_->BelongsToCurrentThread());
678
679 std::ostringstream logstr;
680 std::vector<MediaTrack::Id> selectedVideoMediaTrackId;
avayvod2135a642017-01-13 00:17:14681 if (selectedTrackId && !video_track_disabled_) {
servolkf25ceed2016-07-01 03:44:38682 selectedVideoMediaTrackId.push_back(selectedTrackId->utf8().data());
683 logstr << selectedVideoMediaTrackId[0];
684 }
685 MEDIA_LOG(INFO, media_log_) << "Selected video track: [" << logstr.str()
686 << "]";
687 pipeline_.OnSelectedVideoTrackChanged(selectedVideoMediaTrackId);
688}
689
[email protected]180ef242013-11-07 06:50:46690blink::WebSize WebMediaPlayerImpl::naturalSize() const {
acolwellb4034942014-08-28 15:42:43691 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53692
[email protected]b8877772014-03-26 20:17:15693 return blink::WebSize(pipeline_metadata_.natural_size);
[email protected]d43ed912009-02-03 04:52:53694}
695
[email protected]4e6be3f2009-05-07 02:24:44696bool WebMediaPlayerImpl::paused() const {
acolwellb4034942014-08-28 15:42:43697 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53698
hubbed5f36882016-01-15 22:40:37699#if defined(OS_ANDROID) // WMPI_CAST
700 if (isRemote())
danakj4f1fd6a2017-01-06 21:15:17701 return cast_impl_.IsPaused();
hubbed5f36882016-01-15 22:40:37702#endif
sandersd50a635e2016-04-04 22:50:09703
[email protected]f6af7592014-02-28 10:09:11704 return pipeline_.GetPlaybackRate() == 0.0f;
[email protected]d43ed912009-02-03 04:52:53705}
706
[email protected]4e6be3f2009-05-07 02:24:44707bool WebMediaPlayerImpl::seeking() const {
acolwellb4034942014-08-28 15:42:43708 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53709
[email protected]ef405f66b2012-04-18 02:39:55710 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing)
[email protected]0acebfa2009-08-21 22:45:40711 return false;
[email protected]67cd5052009-09-10 21:53:22712
[email protected]b3766a22010-12-22 17:34:13713 return seeking_;
[email protected]ec9212f2008-12-18 21:40:36714}
715
[email protected]39bdde32013-04-17 17:44:20716double WebMediaPlayerImpl::duration() const {
acolwellb4034942014-08-28 15:42:43717 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]39bdde32013-04-17 17:44:20718
719 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing)
720 return std::numeric_limits<double>::quiet_NaN();
721
chcunninghamb92d5062017-01-10 21:50:22722 // Use duration from ChunkDemuxer when present. MSE allows users to specify
723 // duration as a double. This propagates to the rest of the pipeline as a
724 // TimeDelta with potentially reduced precision (limited to Microseconds).
725 // ChunkDemuxer returns the full-precision user-specified double. This ensures
726 // users can "get" the exact duration they "set".
727 if (chunk_demuxer_)
728 return chunk_demuxer_->GetDuration();
729
avayvodcc273dd2017-01-19 19:35:12730 base::TimeDelta pipeline_duration = GetPipelineMediaDuration();
chcunninghamb92d5062017-01-10 21:50:22731 return pipeline_duration == kInfiniteDuration
732 ? std::numeric_limits<double>::infinity()
733 : pipeline_duration.InSecondsF();
[email protected]d43ed912009-02-03 04:52:53734}
735
[email protected]db66d0092014-04-16 07:15:12736double WebMediaPlayerImpl::timelineOffset() const {
acolwellb4034942014-08-28 15:42:43737 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]db66d0092014-04-16 07:15:12738
739 if (pipeline_metadata_.timeline_offset.is_null())
740 return std::numeric_limits<double>::quiet_NaN();
741
742 return pipeline_metadata_.timeline_offset.ToJsTime();
743}
744
[email protected]39bdde32013-04-17 17:44:20745double WebMediaPlayerImpl::currentTime() const {
acolwellb4034942014-08-28 15:42:43746 DCHECK(main_task_runner_->BelongsToCurrentThread());
scherkusd2c745b2014-09-04 05:03:40747 DCHECK_NE(ready_state_, WebMediaPlayer::ReadyStateHaveNothing);
748
749 // TODO(scherkus): Replace with an explicit ended signal to HTMLMediaElement,
750 // see http://crbug.com/409280
751 if (ended_)
752 return duration();
753
sandersd1c0bba02016-03-04 23:14:08754 if (seeking())
755 return seek_time_.InSecondsF();
wolenetz1b2ae7d2015-06-10 00:44:21756
hubbed5f36882016-01-15 22:40:37757#if defined(OS_ANDROID) // WMPI_CAST
sandersd1c0bba02016-03-04 23:14:08758 if (isRemote())
hubbed5f36882016-01-15 22:40:37759 return cast_impl_.currentTime();
hubbed5f36882016-01-15 22:40:37760#endif
761
sandersd1c0bba02016-03-04 23:14:08762 if (paused_)
hubbed5f36882016-01-15 22:40:37763 return paused_time_.InSecondsF();
hubbed5f36882016-01-15 22:40:37764
765 return pipeline_.GetMediaTime().InSecondsF();
[email protected]d43ed912009-02-03 04:52:53766}
767
danakj13afe0362016-02-27 01:22:50768WebMediaPlayer::NetworkState WebMediaPlayerImpl::getNetworkState() const {
acolwellb4034942014-08-28 15:42:43769 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]ddb1e5a2010-12-13 20:10:45770 return network_state_;
771}
772
danakj13afe0362016-02-27 01:22:50773WebMediaPlayer::ReadyState WebMediaPlayerImpl::getReadyState() const {
acolwellb4034942014-08-28 15:42:43774 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]ddb1e5a2010-12-13 20:10:45775 return ready_state_;
776}
777
wolenetz4d39cc02016-04-05 19:54:41778blink::WebString WebMediaPlayerImpl::getErrorMessage() {
779 DCHECK(main_task_runner_->BelongsToCurrentThread());
780 return blink::WebString::fromUTF8(media_log_->GetLastErrorMessage());
781}
782
[email protected]02022fc2014-05-16 00:05:31783blink::WebTimeRanges WebMediaPlayerImpl::buffered() const {
acolwellb4034942014-08-28 15:42:43784 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]779a8322014-08-22 21:28:37785
acolwell9e0840d2014-09-06 19:01:32786 Ranges<base::TimeDelta> buffered_time_ranges =
[email protected]02022fc2014-05-16 00:05:31787 pipeline_.GetBufferedTimeRanges();
[email protected]779a8322014-08-22 21:28:37788
avayvodcc273dd2017-01-19 19:35:12789 const base::TimeDelta duration = GetPipelineMediaDuration();
dalecurtis39a7f932016-07-19 18:34:59790 if (duration != kInfiniteDuration) {
[email protected]779a8322014-08-22 21:28:37791 buffered_data_source_host_.AddBufferedTimeRanges(
792 &buffered_time_ranges, duration);
793 }
[email protected]02022fc2014-05-16 00:05:31794 return ConvertToWebTimeRanges(buffered_time_ranges);
795}
796
philipjb0e6f3f2014-09-30 09:51:53797blink::WebTimeRanges WebMediaPlayerImpl::seekable() const {
acolwellb4034942014-08-28 15:42:43798 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]39bdde32013-04-17 17:44:20799
dalecurtis56359cb2014-10-28 00:06:29800 if (ready_state_ < WebMediaPlayer::ReadyStateHaveMetadata)
philipjb0e6f3f2014-09-30 09:51:53801 return blink::WebTimeRanges();
802
dalecurtis56359cb2014-10-28 00:06:29803 const double seekable_end = duration();
804
805 // Allow a special exception for seeks to zero for streaming sources with a
806 // finite duration; this allows looping to work.
tguilbertade2bcb2017-01-07 02:57:45807 const bool is_finite_stream = data_source_ && data_source_->IsStreaming() &&
808 std::isfinite(seekable_end);
809
810 // Do not change the seekable range when using the fallback path.
811 // The MediaPlayerRenderer will take care of dropping invalid seeks.
812 const bool force_seeks_to_zero = !use_fallback_path_ && is_finite_stream;
dalecurtis56359cb2014-10-28 00:06:29813
814 // TODO(dalecurtis): Technically this allows seeking on media which return an
tguilbertade2bcb2017-01-07 02:57:45815 // infinite duration so long as DataSource::IsStreaming() is false. While not
dalecurtis56359cb2014-10-28 00:06:29816 // expected, disabling this breaks semi-live players, http://crbug.com/427412.
817 const blink::WebTimeRange seekable_range(
tguilbertade2bcb2017-01-07 02:57:45818 0.0, force_seeks_to_zero ? 0.0 : seekable_end);
philipjb0e6f3f2014-09-30 09:51:53819 return blink::WebTimeRanges(&seekable_range, 1);
[email protected]ec9212f2008-12-18 21:40:36820}
821
sandersd35d2c3f2017-01-14 02:04:42822bool WebMediaPlayerImpl::IsPrerollAttemptNeeded() {
823 // TODO(sandersd): Replace with |highest_ready_state_since_seek_| if we need
824 // to ensure that preroll always gets a chance to complete.
825 // See http://crbug.com/671525.
826 if (highest_ready_state_ >= ReadyState::ReadyStateHaveFutureData)
827 return false;
828
829 if (preroll_attempt_pending_)
830 return true;
831
832 // Freshly initialized; there has never been any loading progress. (Otherwise
833 // |preroll_attempt_pending_| would be true when the start time is null.)
834 if (preroll_attempt_start_time_.is_null())
835 return false;
836
837 base::TimeDelta preroll_attempt_duration =
838 tick_clock_->NowTicks() - preroll_attempt_start_time_;
839 return preroll_attempt_duration < kPrerollAttemptTimeout;
840}
841
[email protected]5d2b3e4c2014-05-12 23:27:30842bool WebMediaPlayerImpl::didLoadingProgress() {
acolwellb4034942014-08-28 15:42:43843 DCHECK(main_task_runner_->BelongsToCurrentThread());
dalecurtise7120dc2016-09-03 02:54:35844
845 // Note: Separate variables used to ensure both methods are called every time.
846 const bool pipeline_progress = pipeline_.DidLoadingProgress();
847 const bool data_progress = buffered_data_source_host_.DidLoadingProgress();
848 const bool did_loading_progress = pipeline_progress || data_progress;
849
sandersd35d2c3f2017-01-14 02:04:42850 if (did_loading_progress &&
851 highest_ready_state_ < ReadyState::ReadyStateHaveFutureData) {
852 // Reset the preroll attempt clock.
853 preroll_attempt_pending_ = true;
854 preroll_attempt_start_time_ = base::TimeTicks();
855
856 // Clear any 'stale' flag and give the pipeline a chance to resume. If we
857 // are already resumed, this will cause |preroll_attempt_start_time_| to be
858 // set.
859 // TODO(sandersd): Should this be on the same stack? It might be surprising
860 // that didLoadingProgress() can synchronously change state.
861 if (delegate_)
862 delegate_->ClearStaleFlag(delegate_id_);
dalecurtise7120dc2016-09-03 02:54:35863 UpdatePlayState();
864 }
865
866 return did_loading_progress;
[email protected]d43ed912009-02-03 04:52:53867}
868
[email protected]dd5c7972014-08-21 15:00:37869void WebMediaPlayerImpl::paint(blink::WebCanvas* canvas,
870 const blink::WebRect& rect,
xidachen0ebd94d2016-09-07 15:47:22871 SkPaint& paint) {
acolwellb4034942014-08-28 15:42:43872 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]dd061e12014-05-06 19:21:22873 TRACE_EVENT0("media", "WebMediaPlayerImpl:paint");
[email protected]4e6be3f2009-05-07 02:24:44874
xhwang213e50c2016-10-10 23:56:31875 // TODO(sandersd): Move this check into GetCurrentFrameFromCompositor() when
876 // we have other ways to check if decoder owns video frame.
877 // See http://crbug.com/595716 and http://crbug.com/602708
jrummelle616ee92016-10-08 02:15:44878 if (cdm_)
xhwang80739452016-01-13 00:48:00879 return;
880
mcasasf1236fc22015-05-29 22:38:56881 scoped_refptr<VideoFrame> video_frame = GetCurrentFrameFromCompositor();
[email protected]0fe5d43b2014-01-24 23:32:45882
[email protected]b49beeb2013-03-01 20:04:00883 gfx::Rect gfx_rect(rect);
dongseong.hwang0c4e9d82015-01-08 20:11:13884 Context3D context_3d;
mcasas265bdbf82015-06-12 18:44:07885 if (video_frame.get() && video_frame->HasTextures()) {
mcasasf1236fc22015-05-29 22:38:56886 if (!context_3d_cb_.is_null())
dongseong.hwang0c4e9d82015-01-08 20:11:13887 context_3d = context_3d_cb_.Run();
dongseong.hwang0c4e9d82015-01-08 20:11:13888 if (!context_3d.gl)
danakj53f7ec902016-05-21 01:30:10889 return; // Unable to get/create a shared main thread context.
890 if (!context_3d.gr_context)
891 return; // The context has been lost since and can't setup a GrContext.
dongseong.hwang0c4e9d82015-01-08 20:11:13892 }
danakj795f1732015-08-31 23:40:22893 skcanvas_video_renderer_.Paint(video_frame, canvas, gfx::RectF(gfx_rect),
xidachen0ebd94d2016-09-07 15:47:22894 paint, pipeline_metadata_.video_rotation,
danakj795f1732015-08-31 23:40:22895 context_3d);
[email protected]ec9212f2008-12-18 21:40:36896}
[email protected]5df51652009-01-17 00:03:00897
[email protected]38259a7a82009-07-29 21:49:49898bool WebMediaPlayerImpl::hasSingleSecurityOrigin() const {
[email protected]b49beeb2013-03-01 20:04:00899 if (data_source_)
900 return data_source_->HasSingleOrigin();
[email protected]fcdb7462009-10-21 21:05:11901 return true;
[email protected]38259a7a82009-07-29 21:49:49902}
903
[email protected]3fe27112012-06-07 04:00:01904bool WebMediaPlayerImpl::didPassCORSAccessCheck() const {
[email protected]b49beeb2013-03-01 20:04:00905 if (data_source_)
906 return data_source_->DidPassCORSAccessCheck();
907 return false;
[email protected]3fe27112012-06-07 04:00:01908}
909
[email protected]39bdde32013-04-17 17:44:20910double WebMediaPlayerImpl::mediaTimeForTimeValue(double timeValue) const {
qinminb4c39782015-08-10 18:43:24911 return base::TimeDelta::FromSecondsD(timeValue).InSecondsF();
[email protected]e06e16d82011-05-26 22:13:33912}
913
[email protected]d82b18ae2011-03-23 21:28:59914unsigned WebMediaPlayerImpl::decodedFrameCount() const {
acolwellb4034942014-08-28 15:42:43915 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]4c51bc662011-02-16 02:03:16916
avayvodc4bfb0e62017-01-13 01:07:01917 PipelineStatistics stats = GetPipelineStatistics();
[email protected]4c51bc662011-02-16 02:03:16918 return stats.video_frames_decoded;
919}
920
[email protected]d82b18ae2011-03-23 21:28:59921unsigned WebMediaPlayerImpl::droppedFrameCount() const {
acolwellb4034942014-08-28 15:42:43922 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]4c51bc662011-02-16 02:03:16923
avayvodc4bfb0e62017-01-13 01:07:01924 PipelineStatistics stats = GetPipelineStatistics();
[email protected]dd061e12014-05-06 19:21:22925 return stats.video_frames_dropped;
[email protected]4c51bc662011-02-16 02:03:16926}
927
chakshu.a94326b72016-03-08 05:11:44928size_t WebMediaPlayerImpl::audioDecodedByteCount() const {
acolwellb4034942014-08-28 15:42:43929 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]4c51bc662011-02-16 02:03:16930
avayvodc4bfb0e62017-01-13 01:07:01931 PipelineStatistics stats = GetPipelineStatistics();
[email protected]4c51bc662011-02-16 02:03:16932 return stats.audio_bytes_decoded;
933}
934
chakshu.a94326b72016-03-08 05:11:44935size_t WebMediaPlayerImpl::videoDecodedByteCount() const {
acolwellb4034942014-08-28 15:42:43936 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]4c51bc662011-02-16 02:03:16937
avayvodc4bfb0e62017-01-13 01:07:01938 PipelineStatistics stats = GetPipelineStatistics();
[email protected]4c51bc662011-02-16 02:03:16939 return stats.video_bytes_decoded;
940}
941
[email protected]6523b242013-03-13 11:10:07942bool WebMediaPlayerImpl::copyVideoTextureToPlatformTexture(
danakj46070b02016-03-28 21:54:11943 gpu::gles2::GLES2Interface* gl,
zmo57d577a2015-10-30 18:28:59944 unsigned int texture,
zmo57d577a2015-10-30 18:28:59945 bool premultiply_alpha,
946 bool flip_y) {
xhwang213e50c2016-10-10 23:56:31947 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]bfc05f22013-10-19 17:55:16948 TRACE_EVENT0("media", "WebMediaPlayerImpl:copyVideoTextureToPlatformTexture");
949
xhwang213e50c2016-10-10 23:56:31950 // TODO(sandersd): Move this check into GetCurrentFrameFromCompositor() when
951 // we have other ways to check if decoder owns video frame.
952 // See http://crbug.com/595716 and http://crbug.com/602708
953 if (cdm_)
954 return false;
[email protected]dd061e12014-05-06 19:21:22955
xhwang213e50c2016-10-10 23:56:31956 scoped_refptr<VideoFrame> video_frame = GetCurrentFrameFromCompositor();
jbauman581d041c2016-07-21 01:01:03957 if (!video_frame.get() || !video_frame->HasTextures()) {
[email protected]e56f88c72013-06-25 22:31:29958 return false;
dongseong.hwang0c4e9d82015-01-08 20:11:13959 }
[email protected]df41e252014-02-03 23:39:50960
jbauman581d041c2016-07-21 01:01:03961 Context3D context_3d;
962 if (!context_3d_cb_.is_null())
963 context_3d = context_3d_cb_.Run();
964 return skcanvas_video_renderer_.CopyVideoFrameTexturesToGLTexture(
kbr4910ae52017-01-11 00:52:28965 context_3d, gl, video_frame.get(), texture, premultiply_alpha, flip_y);
[email protected]6523b242013-03-13 11:10:07966}
967
[email protected]7bce1832014-01-09 00:01:22968void WebMediaPlayerImpl::setContentDecryptionModule(
[email protected]9ebc3b03f2014-08-13 04:01:23969 blink::WebContentDecryptionModule* cdm,
970 blink::WebContentDecryptionModuleResult result) {
acolwellb4034942014-08-28 15:42:43971 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]9ebc3b03f2014-08-13 04:01:23972
jrummell06f27072015-06-08 18:12:38973 // Once the CDM is set it can't be cleared as there may be frames being
974 // decrypted on other threads. So fail this request.
975 // http://crbug.com/462365#c7.
xhwang97de4202014-11-25 08:44:01976 if (!cdm) {
977 result.completeWithError(
jrummell06f27072015-06-08 18:12:38978 blink::WebContentDecryptionModuleExceptionInvalidStateError, 0,
xhwang79b193042016-12-13 18:52:43979 "The existing ContentDecryptionModule object cannot be removed at this "
980 "time.");
xhwang97de4202014-11-25 08:44:01981 return;
982 }
983
jrummell89e61d82015-07-23 20:03:34984 // Create a local copy of |result| to avoid problems with the callback
985 // getting passed to the media thread and causing |result| to be destructed
jrummell4acbec912016-02-27 02:45:03986 // on the wrong thread in some failure conditions. Blink should prevent
987 // multiple simultaneous calls.
988 DCHECK(!set_cdm_result_);
jrummell89e61d82015-07-23 20:03:34989 set_cdm_result_.reset(new blink::WebContentDecryptionModuleResult(result));
990
dalecurtis04bdb582016-08-17 22:15:23991 // Recreate the watch time reporter if necessary.
992 const bool was_encrypted = is_encrypted_;
993 is_encrypted_ = true;
994 if (!was_encrypted && watch_time_reporter_)
995 CreateWatchTimeReporter();
996
jrummelle616ee92016-10-08 02:15:44997 SetCdm(cdm);
xhwang97de4202014-11-25 08:44:01998}
999
xhwange8c4181a2014-12-06 08:10:011000void WebMediaPlayerImpl::OnEncryptedMediaInitData(
jrummellcf78967c2015-04-03 05:03:581001 EmeInitDataType init_data_type,
Avi Drissman97785ea2015-12-19 01:11:311002 const std::vector<uint8_t>& init_data) {
jrummellcf78967c2015-04-03 05:03:581003 DCHECK(init_data_type != EmeInitDataType::UNKNOWN);
xhwangbab66f52014-12-02 23:49:501004
ddorwin301ccdb2016-02-25 02:39:171005 // TODO(xhwang): Update this UMA name. https://crbug.com/589251
xhwangbab66f52014-12-02 23:49:501006 UMA_HISTOGRAM_COUNTS("Media.EME.NeedKey", 1);
1007
dalecurtis04bdb582016-08-17 22:15:231008 // Recreate the watch time reporter if necessary.
1009 const bool was_encrypted = is_encrypted_;
1010 is_encrypted_ = true;
1011 if (!was_encrypted && watch_time_reporter_)
1012 CreateWatchTimeReporter();
1013
srirama.m26f864d02015-07-14 05:21:461014 encrypted_client_->encrypted(
davidbenb50f00c2015-12-01 00:01:501015 ConvertToWebInitDataType(init_data_type), init_data.data(),
srirama.m26f864d02015-07-14 05:21:461016 base::saturated_cast<unsigned int>(init_data.size()));
xhwangbab66f52014-12-02 23:49:501017}
1018
servolk81e01e02016-03-05 03:29:151019void WebMediaPlayerImpl::OnFFmpegMediaTracksUpdated(
dcheng3076abbf2016-04-22 20:42:391020 std::unique_ptr<MediaTracks> tracks) {
servolk81e01e02016-03-05 03:29:151021 // For MSE/chunk_demuxer case the media track updates are handled by
1022 // WebSourceBufferImpl.
1023 DCHECK(demuxer_.get());
1024 DCHECK(!chunk_demuxer_);
servolkef1e5ef2016-03-25 04:55:261025
1026 // Report the media track information to blink.
1027 for (const auto& track : tracks->tracks()) {
1028 if (track->type() == MediaTrack::Audio) {
servolkfa5c37c2016-06-16 17:56:471029 client_->addAudioTrack(blink::WebString::fromUTF8(track->id()),
1030 blink::WebMediaPlayerClient::AudioTrackKindMain,
1031 blink::WebString::fromUTF8(track->label()),
1032 blink::WebString::fromUTF8(track->language()),
1033 /*enabled*/ true);
servolkef1e5ef2016-03-25 04:55:261034 } else if (track->type() == MediaTrack::Video) {
servolkfa5c37c2016-06-16 17:56:471035 client_->addVideoTrack(blink::WebString::fromUTF8(track->id()),
1036 blink::WebMediaPlayerClient::VideoTrackKindMain,
1037 blink::WebString::fromUTF8(track->label()),
1038 blink::WebString::fromUTF8(track->language()),
1039 /*selected*/ true);
servolkef1e5ef2016-03-25 04:55:261040 } else {
1041 // Text tracks are not supported through this code path yet.
1042 NOTREACHED();
1043 }
1044 }
servolk81e01e02016-03-05 03:29:151045}
1046
jrummelle616ee92016-10-08 02:15:441047void WebMediaPlayerImpl::SetCdm(blink::WebContentDecryptionModule* cdm) {
1048 DCHECK(main_task_runner_->BelongsToCurrentThread());
1049 DCHECK(cdm);
xhwang79b193042016-12-13 18:52:431050 scoped_refptr<ContentDecryptionModule> cdm_reference =
jrummelle616ee92016-10-08 02:15:441051 ToWebContentDecryptionModuleImpl(cdm)->GetCdm();
1052 if (!cdm_reference) {
1053 NOTREACHED();
1054 OnCdmAttached(false);
xhwang80739452016-01-13 00:48:001055 return;
1056 }
1057
jrummelle616ee92016-10-08 02:15:441058 CdmContext* cdm_context = cdm_reference->GetCdmContext();
1059 if (!cdm_context) {
1060 OnCdmAttached(false);
1061 return;
1062 }
1063
xjzd3fe45a2016-10-12 18:26:371064 if (observer_)
1065 observer_->OnSetCdm(cdm_context);
1066
jrummelle616ee92016-10-08 02:15:441067 // Keep the reference to the CDM, as it shouldn't be destroyed until
1068 // after the pipeline is done with the |cdm_context|.
1069 pending_cdm_ = std::move(cdm_reference);
1070 pipeline_.SetCdm(cdm_context,
1071 base::Bind(&WebMediaPlayerImpl::OnCdmAttached, AsWeakPtr()));
xhwang97de4202014-11-25 08:44:011072}
1073
jrummell89e61d82015-07-23 20:03:341074void WebMediaPlayerImpl::OnCdmAttached(bool success) {
jrummelle616ee92016-10-08 02:15:441075 DCHECK(main_task_runner_->BelongsToCurrentThread());
1076 DCHECK(pending_cdm_);
1077
1078 // If the CDM is set from the constructor there is no promise
1079 // (|set_cdm_result_|) to fulfill.
xhwang97de4202014-11-25 08:44:011080 if (success) {
jrummelle616ee92016-10-08 02:15:441081 // This will release the previously attached CDM (if any).
1082 cdm_ = std::move(pending_cdm_);
1083 if (set_cdm_result_) {
1084 set_cdm_result_->complete();
1085 set_cdm_result_.reset();
1086 }
1087
xhwang97de4202014-11-25 08:44:011088 return;
1089 }
1090
jrummelle616ee92016-10-08 02:15:441091 pending_cdm_ = nullptr;
1092 if (set_cdm_result_) {
1093 set_cdm_result_->completeWithError(
1094 blink::WebContentDecryptionModuleExceptionNotSupportedError, 0,
xhwang79b193042016-12-13 18:52:431095 "Unable to set ContentDecryptionModule object");
jrummelle616ee92016-10-08 02:15:441096 set_cdm_result_.reset();
1097 }
[email protected]9ebc3b03f2014-08-13 04:01:231098}
1099
sandersd1c0bba02016-03-04 23:14:081100void WebMediaPlayerImpl::OnPipelineSeeked(bool time_updated) {
[email protected]5d11eff2011-09-15 00:06:061101 seeking_ = false;
wolenetz1b2ae7d2015-06-10 00:44:211102 seek_time_ = base::TimeDelta();
avayvod2135a642017-01-13 00:17:141103
hubbe5a2dec022016-03-17 01:14:231104 if (paused_) {
1105#if defined(OS_ANDROID) // WMPI_CAST
1106 if (isRemote()) {
1107 paused_time_ = base::TimeDelta::FromSecondsD(cast_impl_.currentTime());
1108 } else {
1109 paused_time_ = pipeline_.GetMediaTime();
1110 }
1111#else
sandersd1c0bba02016-03-04 23:14:081112 paused_time_ = pipeline_.GetMediaTime();
hubbe5a2dec022016-03-17 01:14:231113#endif
dalecurtis04bdb582016-08-17 22:15:231114 } else {
1115 DCHECK(watch_time_reporter_);
1116 watch_time_reporter_->OnPlaying();
hubbe5a2dec022016-03-17 01:14:231117 }
sandersd1c0bba02016-03-04 23:14:081118 if (time_updated)
1119 should_notify_time_changed_ = true;
dalecurtisaf34d8712016-09-20 04:32:261120
1121 // Reset underflow count upon seek; this prevents looping videos and user
1122 // actions from artificially inflating the underflow count.
1123 underflow_count_ = 0;
avayvod56e1f3942017-01-21 02:06:311124
1125 // Background video optimizations are delayed when shown/hidden if pipeline
1126 // is seeking.
1127 UpdateBackgroundVideoOptimizationState();
[email protected]8931c41a2009-07-07 17:31:491128}
1129
sandersd1c0bba02016-03-04 23:14:081130void WebMediaPlayerImpl::OnPipelineSuspended() {
hubbed5f36882016-01-15 22:40:371131#if defined(OS_ANDROID)
1132 if (isRemote()) {
1133 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner();
sandersd50a635e2016-04-04 22:50:091134 if (frame)
dalecurtise9c89e92016-05-20 19:38:001135 compositor_->PaintSingleFrame(frame);
hubbed5f36882016-01-15 22:40:371136 }
1137#endif
1138
dalecurtis37fe5862016-03-15 19:29:091139 // If we're not in an aggressive buffering state, tell the data source we have
1140 // enough data so that it may release the connection.
1141 if (buffering_strategy_ !=
dalecurtisb6e052f52016-08-25 00:35:551142 MultibufferDataSource::BUFFERING_STRATEGY_AGGRESSIVE) {
liberato3f9f32b2016-03-16 16:54:511143 if (data_source_)
1144 data_source_->OnBufferingHaveEnough(true);
dalecurtis37fe5862016-03-15 19:29:091145 }
1146
sandersd50a635e2016-04-04 22:50:091147 ReportMemoryUsage();
1148
sandersd1c0bba02016-03-04 23:14:081149 if (pending_suspend_resume_cycle_) {
watkdee516f2016-02-18 02:22:191150 pending_suspend_resume_cycle_ = false;
sandersd50a635e2016-04-04 22:50:091151 UpdatePlayState();
dalecurtis0431cbf2016-03-12 01:19:431152 }
sandersd1c0bba02016-03-04 23:14:081153}
1154
avayvod2135a642017-01-13 00:17:141155void WebMediaPlayerImpl::OnBeforePipelineResume() {
1156 // Enable video track if we disabled it in the background - this way the new
1157 // renderer will attach its callbacks to the video stream properly.
1158 // TODO(avayvod): Remove this when disabling and enabling video tracks in
1159 // non-playing state works correctly. See https://crbug.com/678374.
1160 EnableVideoTrackIfNeeded();
1161 is_pipeline_resuming_ = true;
1162}
1163
1164void WebMediaPlayerImpl::OnPipelineResumed() {
1165 is_pipeline_resuming_ = false;
1166
avayvod56e1f3942017-01-21 02:06:311167 UpdateBackgroundVideoOptimizationState();
avayvod2135a642017-01-13 00:17:141168}
1169
alokp967c902452016-05-06 05:21:371170void WebMediaPlayerImpl::OnDemuxerOpened() {
1171 DCHECK(main_task_runner_->BelongsToCurrentThread());
1172 client_->mediaSourceOpened(
1173 new WebMediaSourceImpl(chunk_demuxer_, media_log_));
1174}
1175
1176void WebMediaPlayerImpl::OnError(PipelineStatus status) {
pkastingf5279482016-07-27 02:18:201177 DVLOG(1) << __func__;
alokp967c902452016-05-06 05:21:371178 DCHECK(main_task_runner_->BelongsToCurrentThread());
1179 DCHECK_NE(status, PIPELINE_OK);
1180
1181 if (suppress_destruction_errors_)
1182 return;
1183
1184 ReportPipelineError(load_type_, frame_->getSecurityOrigin(), status);
1185 media_log_->AddEvent(media_log_->CreatePipelineErrorEvent(status));
1186
1187 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing) {
1188 // Any error that occurs before reaching ReadyStateHaveMetadata should
1189 // be considered a format error.
1190 SetNetworkState(WebMediaPlayer::NetworkStateFormatError);
1191 } else {
1192 SetNetworkState(PipelineErrorToNetworkState(status));
1193 }
1194
1195 UpdatePlayState();
1196}
1197
1198void WebMediaPlayerImpl::OnEnded() {
pkastingf5279482016-07-27 02:18:201199 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:431200 DCHECK(main_task_runner_->BelongsToCurrentThread());
scherkusd2c745b2014-09-04 05:03:401201
sandersd1c0bba02016-03-04 23:14:081202 // Ignore state changes until we've completed all outstanding operations.
1203 if (!pipeline_controller_.IsStable())
scherkusd2c745b2014-09-04 05:03:401204 return;
1205
1206 ended_ = true;
[email protected]ce70c982013-12-20 17:04:321207 client_->timeChanged();
sandersd50a635e2016-04-04 22:50:091208
1209 // We don't actually want this to run until |client_| calls seek() or pause(),
1210 // but that should have already happened in timeChanged() and so this is
1211 // expected to be a no-op.
1212 UpdatePlayState();
[email protected]576537842009-08-12 23:52:051213}
1214
alokp967c902452016-05-06 05:21:371215void WebMediaPlayerImpl::OnMetadata(PipelineMetadata metadata) {
pkastingf5279482016-07-27 02:18:201216 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:431217 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]a8e2cb82012-08-17 00:02:391218
[email protected]b8877772014-03-26 20:17:151219 pipeline_metadata_ = metadata;
[email protected]739847c02014-01-16 00:12:251220
dalecurtis04bdb582016-08-17 22:15:231221 SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata);
dalecurtis849cf4b22015-03-27 18:35:451222 UMA_HISTOGRAM_ENUMERATION("Media.VideoRotation", metadata.video_rotation,
acolwell9e0840d2014-09-06 19:01:321223 VIDEO_ROTATION_MAX + 1);
[email protected]21c3f7502013-03-23 03:29:511224
[email protected]b8877772014-03-26 20:17:151225 if (hasVideo()) {
liberato2fd111be2017-01-04 00:25:061226 if (overlay_enabled_) {
1227 // SurfaceView doesn't support rotated video, so transition back if
1228 // the video is now rotated. If |force_video_overlays_|, we keep the
1229 // overlay anyway so that the state machine keeps working.
1230 if (!force_video_overlays_ && !DoesOverlaySupportMetadata())
1231 DisableOverlay();
1232 else if (surface_manager_)
1233 surface_manager_->NaturalSizeChanged(pipeline_metadata_.natural_size);
1234 }
watkf835a792016-06-24 23:24:401235
1236 DCHECK(!video_weblayer_);
dalecurtise1edb312016-06-22 02:33:211237 video_weblayer_.reset(new cc_blink::WebLayerImpl(cc::VideoLayer::Create(
1238 compositor_, pipeline_metadata_.video_rotation)));
jbauman952274d2015-09-10 23:23:361239 video_weblayer_->layer()->SetContentsOpaque(opaque_);
1240 video_weblayer_->SetContentsOpaqueIsFixed(true);
[email protected]a7c4f582014-04-16 18:44:491241 client_->setWebLayer(video_weblayer_.get());
[email protected]a8e2cb82012-08-17 00:02:391242 }
dalecurtis8e4dc682016-03-15 02:30:301243
xjzd3fe45a2016-10-12 18:26:371244 if (observer_)
xjz15b483f2017-01-12 00:21:361245 observer_->OnMetadataChanged(pipeline_metadata_);
xjzd3fe45a2016-10-12 18:26:371246
dalecurtis04bdb582016-08-17 22:15:231247 CreateWatchTimeReporter();
sandersd50a635e2016-04-04 22:50:091248 UpdatePlayState();
[email protected]a8e2cb82012-08-17 00:02:391249}
1250
alokp967c902452016-05-06 05:21:371251void WebMediaPlayerImpl::OnBufferingStateChange(BufferingState state) {
pkastingf5279482016-07-27 02:18:201252 DVLOG(1) << __func__ << "(" << state << ")";
alokp967c902452016-05-06 05:21:371253 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]b8877772014-03-26 20:17:151254
sandersd1c0bba02016-03-04 23:14:081255 // Ignore buffering state changes until we've completed all outstanding
1256 // operations.
1257 if (!pipeline_controller_.IsStable())
[email protected]ba7d5f92014-06-24 05:37:401258 return;
[email protected]b8877772014-03-26 20:17:151259
dalecurtis869bf2f2017-01-10 18:01:101260 media_log_->AddEvent(media_log_->CreateBufferingStateChangedEvent(
1261 "pipeline_buffering_state", state));
1262
chcunninghameb270c92016-07-15 01:00:451263 if (state == BUFFERING_HAVE_ENOUGH) {
dalecurtis821e803f2016-09-01 18:44:151264 if (data_source_ &&
1265 highest_ready_state_ < WebMediaPlayer::ReadyStateHaveEnoughData) {
1266 DCHECK_EQ(underflow_count_, 0);
1267 // Record a zero value for underflow histograms so that the histogram
1268 // includes playbacks which never encounter an underflow event.
1269 UMA_HISTOGRAM_COUNTS_100("Media.UnderflowCount", 0);
1270 UMA_HISTOGRAM_TIMES("Media.UnderflowDuration", base::TimeDelta());
1271 }
1272
chcunninghameb270c92016-07-15 01:00:451273 // TODO(chcunningham): Monitor playback position vs buffered. Potentially
1274 // transition to HAVE_FUTURE_DATA here if not enough is buffered.
1275 SetReadyState(WebMediaPlayer::ReadyStateHaveEnoughData);
[email protected]ba7d5f92014-06-24 05:37:401276
chcunninghameb270c92016-07-15 01:00:451277 // Let the DataSource know we have enough data. It may use this information
1278 // to release unused network connections.
1279 if (data_source_)
1280 data_source_->OnBufferingHaveEnough(false);
dalecurtis849cf4b22015-03-27 18:35:451281
chcunninghameb270c92016-07-15 01:00:451282 // Blink expects a timeChanged() in response to a seek().
sandersd35d2c3f2017-01-14 02:04:421283 if (should_notify_time_changed_) {
1284 should_notify_time_changed_ = false;
chcunninghameb270c92016-07-15 01:00:451285 client_->timeChanged();
sandersd35d2c3f2017-01-14 02:04:421286 }
dalecurtis0f0097a2015-12-01 17:40:471287
chcunninghameb270c92016-07-15 01:00:451288 // Once we have enough, start reporting the total memory usage. We'll also
1289 // report once playback starts.
1290 ReportMemoryUsage();
dalecurtis9d638a12016-08-30 06:20:551291
1292 // Report the amount of time it took to leave the underflow state. Don't
1293 // bother to report this for MSE playbacks since it's out of our control.
1294 if (underflow_timer_ && data_source_) {
1295 UMA_HISTOGRAM_TIMES("Media.UnderflowDuration",
1296 underflow_timer_->Elapsed());
1297 underflow_timer_.reset();
1298 }
chcunninghameb270c92016-07-15 01:00:451299 } else {
1300 // Buffering has underflowed.
1301 DCHECK_EQ(state, BUFFERING_HAVE_NOTHING);
dalecurtisacd77d62016-09-09 23:23:141302
1303 // Report the number of times we've entered the underflow state. Only report
1304 // for src= playback since for MSE it's out of our control. Ensure we only
1305 // report the value when transitioning from HAVE_ENOUGH to HAVE_NOTHING.
1306 if (data_source_ &&
1307 ready_state_ == WebMediaPlayer::ReadyStateHaveEnoughData) {
1308 UMA_HISTOGRAM_COUNTS_100("Media.UnderflowCount", ++underflow_count_);
1309 underflow_timer_.reset(new base::ElapsedTimer());
1310 }
1311
chcunninghameb270c92016-07-15 01:00:451312 // It shouldn't be possible to underflow if we've not advanced past
1313 // HAVE_CURRENT_DATA.
1314 DCHECK_GT(highest_ready_state_, WebMediaPlayer::ReadyStateHaveCurrentData);
1315 SetReadyState(WebMediaPlayer::ReadyStateHaveCurrentData);
1316 }
sandersd50a635e2016-04-04 22:50:091317
1318 UpdatePlayState();
[email protected]b8877772014-03-26 20:17:151319}
1320
alokp967c902452016-05-06 05:21:371321void WebMediaPlayerImpl::OnDurationChange() {
acolwellb4034942014-08-28 15:42:431322 DCHECK(main_task_runner_->BelongsToCurrentThread());
alokp967c902452016-05-06 05:21:371323
1324 // TODO(sandersd): We should call delegate_->DidPlay() with the new duration,
1325 // especially if it changed from <5s to >5s.
1326 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing)
1327 return;
1328
1329 client_->durationChanged();
[email protected]81bb3322011-07-21 15:55:501330}
1331
alokp967c902452016-05-06 05:21:371332void WebMediaPlayerImpl::OnAddTextTrack(const TextTrackConfig& config,
1333 const AddTextTrackDoneCB& done_cb) {
acolwellb4034942014-08-28 15:42:431334 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]71537722013-05-23 06:47:531335
[email protected]8a561062013-11-22 01:19:311336 const WebInbandTextTrackImpl::Kind web_kind =
1337 static_cast<WebInbandTextTrackImpl::Kind>(config.kind());
1338 const blink::WebString web_label =
1339 blink::WebString::fromUTF8(config.label());
1340 const blink::WebString web_language =
1341 blink::WebString::fromUTF8(config.language());
[email protected]427ff102013-11-26 23:45:401342 const blink::WebString web_id =
1343 blink::WebString::fromUTF8(config.id());
[email protected]71537722013-05-23 06:47:531344
dcheng3076abbf2016-04-22 20:42:391345 std::unique_ptr<WebInbandTextTrackImpl> web_inband_text_track(
henriks9cce5fa2014-12-12 09:35:301346 new WebInbandTextTrackImpl(web_kind, web_label, web_language, web_id));
[email protected]8a561062013-11-22 01:19:311347
dcheng3076abbf2016-04-22 20:42:391348 std::unique_ptr<media::TextTrack> text_track(new TextTrackImpl(
dcheng652f5ff2015-12-27 08:54:001349 main_task_runner_, client_, std::move(web_inband_text_track)));
[email protected]8a561062013-11-22 01:19:311350
dcheng652f5ff2015-12-27 08:54:001351 done_cb.Run(std::move(text_track));
[email protected]71537722013-05-23 06:47:531352}
1353
alokp967c902452016-05-06 05:21:371354void WebMediaPlayerImpl::OnWaitingForDecryptionKey() {
1355 DCHECK(main_task_runner_->BelongsToCurrentThread());
1356
1357 encrypted_client_->didBlockPlaybackWaitingForKey();
1358 // TODO(jrummell): didResumePlaybackBlockedForKey() should only be called
1359 // when a key has been successfully added (e.g. OnSessionKeysChange() with
1360 // |has_additional_usable_key| = true). http://crbug.com/461903
1361 encrypted_client_->didResumePlaybackBlockedForKey();
1362}
1363
alokp5d86e9b2016-05-17 20:20:411364void WebMediaPlayerImpl::OnVideoNaturalSizeChange(const gfx::Size& size) {
1365 DCHECK(main_task_runner_->BelongsToCurrentThread());
1366 DCHECK_NE(ready_state_, WebMediaPlayer::ReadyStateHaveNothing);
1367
xjz15b483f2017-01-12 00:21:361368 // The input |size| is from the decoded video frame, which is the original
1369 // natural size and need to be rotated accordingly.
sandersd2c478422016-08-02 01:19:251370 gfx::Size rotated_size =
1371 GetRotatedVideoSize(pipeline_metadata_.video_rotation, size);
1372
1373 if (rotated_size == pipeline_metadata_.natural_size)
alokp5d86e9b2016-05-17 20:20:411374 return;
1375
1376 TRACE_EVENT0("media", "WebMediaPlayerImpl::OnNaturalSizeChanged");
sandersd2c478422016-08-02 01:19:251377 media_log_->AddEvent(media_log_->CreateVideoSizeSetEvent(
1378 rotated_size.width(), rotated_size.height()));
alokp5d86e9b2016-05-17 20:20:411379
tsunghungee562e92016-07-20 18:03:311380 if (overlay_enabled_ && surface_manager_)
sandersd2c478422016-08-02 01:19:251381 surface_manager_->NaturalSizeChanged(rotated_size);
alokp5d86e9b2016-05-17 20:20:411382
xjz516ef6d2017-01-07 00:23:061383 gfx::Size old_size = pipeline_metadata_.natural_size;
1384 pipeline_metadata_.natural_size = rotated_size;
1385 if (old_size.IsEmpty()) {
tguilbert796a40e2016-11-09 01:11:421386 // WatchTimeReporter doesn't report metrics for empty videos. Re-create
1387 // |watch_time_reporter_| if we didn't originally know the video size.
1388 CreateWatchTimeReporter();
1389 }
alokp5d86e9b2016-05-17 20:20:411390 client_->sizeChanged();
xjz516ef6d2017-01-07 00:23:061391
xjz15b483f2017-01-12 00:21:361392 if (observer_)
1393 observer_->OnMetadataChanged(pipeline_metadata_);
alokp5d86e9b2016-05-17 20:20:411394}
1395
1396void WebMediaPlayerImpl::OnVideoOpacityChange(bool opaque) {
1397 DCHECK(main_task_runner_->BelongsToCurrentThread());
1398 DCHECK_NE(ready_state_, WebMediaPlayer::ReadyStateHaveNothing);
1399
1400 opaque_ = opaque;
1401 // Modify content opaqueness of cc::Layer directly so that
1402 // SetContentsOpaqueIsFixed is ignored.
1403 if (video_weblayer_)
1404 video_weblayer_->layer()->SetContentsOpaque(opaque_);
1405}
1406
sandersd35d2c3f2017-01-14 02:04:421407void WebMediaPlayerImpl::OnFrameHidden() {
sandersd1e49fb62015-12-12 01:18:061408 DCHECK(main_task_runner_->BelongsToCurrentThread());
avayvod39c102402016-11-23 21:43:131409
dalecurtis04bdb582016-08-17 22:15:231410 if (watch_time_reporter_)
1411 watch_time_reporter_->OnHidden();
avayvod48a8be52016-08-04 19:52:501412
avayvodcc273dd2017-01-19 19:35:121413 if (ShouldPauseVideoWhenHidden()) {
avayvod56e1f3942017-01-21 02:06:311414 PauseVideoIfNeeded();
1415 return;
avayvod2135a642017-01-13 00:17:141416 } else {
1417 DisableVideoTrackIfNeeded();
avayvodeb9098d2017-01-07 00:33:031418 }
1419
sandersd50a635e2016-04-04 22:50:091420 UpdatePlayState();
dalecurtis8b8505e72016-06-10 21:59:171421
1422 // Schedule suspended playing media to be paused if the user doesn't come back
1423 // to it within some timeout period to avoid any autoplay surprises.
1424 ScheduleIdlePauseTimer();
sandersd1e49fb62015-12-12 01:18:061425}
1426
sandersd35d2c3f2017-01-14 02:04:421427void WebMediaPlayerImpl::OnFrameClosed() {
sandersd1e49fb62015-12-12 01:18:061428 DCHECK(main_task_runner_->BelongsToCurrentThread());
sandersd35d2c3f2017-01-14 02:04:421429 UpdatePlayState();
1430}
1431
1432void WebMediaPlayerImpl::OnFrameShown() {
1433 DCHECK(main_task_runner_->BelongsToCurrentThread());
1434 background_pause_timer_.Stop();
1435
dalecurtis04bdb582016-08-17 22:15:231436 if (watch_time_reporter_)
1437 watch_time_reporter_->OnShown();
1438
avayvodcc273dd2017-01-19 19:35:121439 // Only track the time to the first frame if playing or about to play because
1440 // of being shown and only for videos we would optimize background playback
1441 // for.
1442 if ((!paused_ && IsBackgroundOptimizationCandidate()) ||
1443 paused_when_hidden_) {
1444 VideoFrameCompositor::OnNewProcessedFrameCB new_processed_frame_cb =
1445 BIND_TO_RENDER_LOOP1(
1446 &WebMediaPlayerImpl::ReportTimeFromForegroundToFirstFrame,
1447 base::TimeTicks::Now());
1448 compositor_task_runner_->PostTask(
1449 FROM_HERE,
1450 base::Bind(&VideoFrameCompositor::SetOnNewProcessedFrameCallback,
1451 base::Unretained(compositor_), new_processed_frame_cb));
1452 }
avayvodac607d652017-01-06 03:16:431453
avayvod2135a642017-01-13 00:17:141454 if (paused_when_hidden_) {
1455 paused_when_hidden_ = false;
1456 OnPlay(); // Calls UpdatePlayState() so return afterwards.
1457 return;
1458 }
1459
1460 EnableVideoTrackIfNeeded();
1461
sandersd50a635e2016-04-04 22:50:091462 UpdatePlayState();
sandersd1e49fb62015-12-12 01:18:061463}
1464
sandersd35d2c3f2017-01-14 02:04:421465void WebMediaPlayerImpl::OnIdleTimeout() {
dalecurtis0431cbf2016-03-12 01:19:431466 DCHECK(main_task_runner_->BelongsToCurrentThread());
1467
sandersd35d2c3f2017-01-14 02:04:421468 // If we are attempting preroll, clear the stale flag.
1469 if (IsPrerollAttemptNeeded()) {
1470 if (delegate_)
1471 delegate_->ClearStaleFlag(delegate_id_);
1472 return;
watkd026f792016-11-05 00:28:511473 }
sandersd50a635e2016-04-04 22:50:091474
sandersd35d2c3f2017-01-14 02:04:421475 UpdatePlayState();
dalecurtis0431cbf2016-03-12 01:19:431476}
1477
dalecurtisbb3eaac2016-01-27 21:10:251478void WebMediaPlayerImpl::OnPlay() {
1479 play();
1480 client_->playbackStateChanged();
1481}
1482
1483void WebMediaPlayerImpl::OnPause() {
1484 pause();
1485 client_->playbackStateChanged();
1486}
1487
1488void WebMediaPlayerImpl::OnVolumeMultiplierUpdate(double multiplier) {
1489 volume_multiplier_ = multiplier;
1490 setVolume(volume_);
1491}
1492
watkdee516f2016-02-18 02:22:191493void WebMediaPlayerImpl::ScheduleRestart() {
sandersd50a635e2016-04-04 22:50:091494 // TODO(watk): All restart logic should be moved into PipelineController.
1495 if (pipeline_.IsRunning() && !pipeline_controller_.IsPipelineSuspended()) {
watkdee516f2016-02-18 02:22:191496 pending_suspend_resume_cycle_ = true;
sandersd50a635e2016-04-04 22:50:091497 UpdatePlayState();
watkdee516f2016-02-18 02:22:191498 }
1499}
1500
miu77f914c2016-11-19 23:56:181501void WebMediaPlayerImpl::requestRemotePlaybackDisabled(bool disabled) {
1502 if (observer_)
1503 observer_->OnRemotePlaybackDisabled(disabled);
1504}
1505
hubbed5f36882016-01-15 22:40:371506#if defined(OS_ANDROID) // WMPI_CAST
hubbed5f36882016-01-15 22:40:371507bool WebMediaPlayerImpl::isRemote() const {
1508 return cast_impl_.isRemote();
1509}
1510
1511void WebMediaPlayerImpl::SetMediaPlayerManager(
1512 RendererMediaPlayerManagerInterface* media_player_manager) {
1513 cast_impl_.SetMediaPlayerManager(media_player_manager);
1514}
1515
1516void WebMediaPlayerImpl::requestRemotePlayback() {
1517 cast_impl_.requestRemotePlayback();
1518}
1519
1520void WebMediaPlayerImpl::requestRemotePlaybackControl() {
1521 cast_impl_.requestRemotePlaybackControl();
1522}
1523
avayvod8d8c53b2016-11-04 16:10:301524void WebMediaPlayerImpl::requestRemotePlaybackStop() {
1525 cast_impl_.requestRemotePlaybackStop();
1526}
1527
hubbed5f36882016-01-15 22:40:371528void WebMediaPlayerImpl::OnRemotePlaybackEnded() {
pkastingf5279482016-07-27 02:18:201529 DVLOG(1) << __func__;
hubbed5f36882016-01-15 22:40:371530 DCHECK(main_task_runner_->BelongsToCurrentThread());
1531
1532 ended_ = true;
1533 client_->timeChanged();
1534}
1535
1536void WebMediaPlayerImpl::OnDisconnectedFromRemoteDevice(double t) {
sandersd1c0bba02016-03-04 23:14:081537 DoSeek(base::TimeDelta::FromSecondsD(t), false);
hubbed5f36882016-01-15 22:40:371538
hubbed5f36882016-01-15 22:40:371539 // We already told the delegate we're paused when remoting started.
1540 client_->playbackStateChanged();
1541 client_->disconnectedFromRemoteDevice();
sandersd50a635e2016-04-04 22:50:091542
1543 UpdatePlayState();
hubbed5f36882016-01-15 22:40:371544}
1545
1546void WebMediaPlayerImpl::SuspendForRemote() {
sandersd50a635e2016-04-04 22:50:091547 if (pipeline_controller_.IsPipelineSuspended()) {
hubbed5f36882016-01-15 22:40:371548 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner();
sandersd50a635e2016-04-04 22:50:091549 if (frame)
dalecurtise9c89e92016-05-20 19:38:001550 compositor_->PaintSingleFrame(frame);
hubbed5f36882016-01-15 22:40:371551 }
sandersd50a635e2016-04-04 22:50:091552
1553 UpdatePlayState();
hubbed5f36882016-01-15 22:40:371554}
1555
1556gfx::Size WebMediaPlayerImpl::GetCanvasSize() const {
1557 if (!video_weblayer_)
1558 return pipeline_metadata_.natural_size;
1559
1560 return video_weblayer_->bounds();
1561}
1562
1563void WebMediaPlayerImpl::SetDeviceScaleFactor(float scale_factor) {
1564 cast_impl_.SetDeviceScaleFactor(scale_factor);
1565}
hubbee4027f92016-05-19 05:18:131566
tguilbert25a4d112016-10-13 21:56:511567void WebMediaPlayerImpl::SetUseFallbackPath(bool use_fallback_path) {
1568 use_fallback_path_ = use_fallback_path;
1569}
hubbed5f36882016-01-15 22:40:371570#endif // defined(OS_ANDROID) // WMPI_CAST
1571
xjzc102fd82017-01-04 20:13:531572void WebMediaPlayerImpl::setPoster(const blink::WebURL& poster) {
1573#if defined(OS_ANDROID)
1574 cast_impl_.setPoster(poster);
1575#endif
1576
1577 if (observer_)
1578 observer_->OnSetPoster(poster);
1579}
1580
[email protected]fee8a902014-06-03 13:43:361581void WebMediaPlayerImpl::DataSourceInitialized(bool success) {
pkastingf5279482016-07-27 02:18:201582 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:431583 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]a9415292012-01-19 19:55:201584
dalecurtisea27a3ed2016-06-24 01:41:301585#if defined(OS_ANDROID)
1586 // We can't play HLS URLs with WebMediaPlayerImpl, so in cases where they are
1587 // encountered, instruct the HTML media element to create a new WebMediaPlayer
1588 // instance with the correct URL to trigger WebMediaPlayerAndroid creation.
1589 //
1590 // TODO(tguilbert): Remove this code path once we have the ability to host a
1591 // MediaPlayer within a Mojo media renderer. http://crbug.com/580626
tguilbert25a4d112016-10-13 21:56:511592 if (data_source_ && !use_fallback_path_) {
dalecurtisea27a3ed2016-06-24 01:41:301593 const GURL url_after_redirects = data_source_->GetUrlAfterRedirects();
qinmin0d9521272016-10-10 20:43:191594 if (MediaCodecUtil::IsHLSURL(url_after_redirects)) {
dalecurtisea27a3ed2016-06-24 01:41:301595 client_->requestReload(url_after_redirects);
1596 // |this| may be destructed, do nothing after this.
1597 return;
1598 }
1599 }
1600#endif
1601
[email protected]d250190da3b2012-07-23 22:57:301602 if (!success) {
[email protected]ef405f66b2012-04-18 02:39:551603 SetNetworkState(WebMediaPlayer::NetworkStateFormatError);
sandersd50a635e2016-04-04 22:50:091604
1605 // Not really necessary, since the pipeline was never started, but it at
1606 // least this makes sure that the error handling code is in sync.
1607 UpdatePlayState();
1608
[email protected]a9415292012-01-19 19:55:201609 return;
1610 }
1611
[email protected]ef8394c2013-08-21 20:26:301612 StartPipeline();
[email protected]a9415292012-01-19 19:55:201613}
1614
[email protected]122f40252012-06-12 05:01:561615void WebMediaPlayerImpl::NotifyDownloading(bool is_downloading) {
pkastingf5279482016-07-27 02:18:201616 DVLOG(1) << __func__;
[email protected]122f40252012-06-12 05:01:561617 if (!is_downloading && network_state_ == WebMediaPlayer::NetworkStateLoading)
1618 SetNetworkState(WebMediaPlayer::NetworkStateIdle);
1619 else if (is_downloading && network_state_ == WebMediaPlayer::NetworkStateIdle)
1620 SetNetworkState(WebMediaPlayer::NetworkStateLoading);
1621 media_log_->AddEvent(
1622 media_log_->CreateBooleanEvent(
acolwell9e0840d2014-09-06 19:01:321623 MediaLogEvent::NETWORK_ACTIVITY_SET,
[email protected]122f40252012-06-12 05:01:561624 "is_downloading_data", is_downloading));
1625}
1626
watkf835a792016-06-24 23:24:401627void WebMediaPlayerImpl::OnSurfaceCreated(int surface_id) {
tsunghungee562e92016-07-20 18:03:311628 overlay_surface_id_ = surface_id;
dalecurtis4b632fce22016-11-10 00:52:171629 if (!set_surface_cb_.is_null()) {
1630 // If restart is required, the callback is one-shot only.
1631 if (decoder_requires_restart_for_overlay_)
1632 base::ResetAndReturn(&set_surface_cb_).Run(surface_id);
1633 else
1634 set_surface_cb_.Run(surface_id);
1635 }
watkf835a792016-06-24 23:24:401636}
1637
watkdee516f2016-02-18 02:22:191638void WebMediaPlayerImpl::OnSurfaceRequested(
dalecurtis4b632fce22016-11-10 00:52:171639 bool decoder_requires_restart_for_overlay,
1640 const SurfaceCreatedCB& set_surface_cb) {
watkdee516f2016-02-18 02:22:191641 DCHECK(main_task_runner_->BelongsToCurrentThread());
1642 DCHECK(surface_manager_);
tguilbert25a4d112016-10-13 21:56:511643 DCHECK(!use_fallback_path_);
watkdee516f2016-02-18 02:22:191644
1645 // A null callback indicates that the decoder is going away.
dalecurtis4b632fce22016-11-10 00:52:171646 if (set_surface_cb.is_null()) {
tsunghungee562e92016-07-20 18:03:311647 decoder_requires_restart_for_overlay_ = false;
dalecurtis4b632fce22016-11-10 00:52:171648 set_surface_cb_.Reset();
watkdee516f2016-02-18 02:22:191649 return;
1650 }
1651
dalecurtis4b632fce22016-11-10 00:52:171652 // If we get a surface request it means GpuVideoDecoder is initializing, so
1653 // until we get a null surface request, GVD is the active decoder.
1654 //
1655 // If |decoder_requires_restart_for_overlay| is true, we must restart the
1656 // pipeline for fullscreen transitions. The decoder is unable to switch
1657 // surfaces otherwise. If false, we simply need to tell the decoder about the
1658 // new surface and it will handle things seamlessly.
1659 decoder_requires_restart_for_overlay_ = decoder_requires_restart_for_overlay;
1660 set_surface_cb_ = set_surface_cb;
1661
1662 // If we're waiting for the surface to arrive, OnSurfaceCreated() will be
1663 // called later when it arrives; so do nothing for now.
1664 if (overlay_enabled_ && overlay_surface_id_ == SurfaceManager::kNoSurfaceID)
1665 return;
1666
1667 OnSurfaceCreated(overlay_surface_id_);
watkdee516f2016-02-18 02:22:191668}
1669
dcheng3076abbf2016-04-22 20:42:391670std::unique_ptr<Renderer> WebMediaPlayerImpl::CreateRenderer() {
tsunghungee562e92016-07-20 18:03:311671 if (force_video_overlays_)
1672 EnableOverlay();
1673
watkdee516f2016-02-18 02:22:191674 RequestSurfaceCB request_surface_cb;
1675#if defined(OS_ANDROID)
1676 request_surface_cb =
1677 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnSurfaceRequested);
1678#endif
sandersd1e49fb62015-12-12 01:18:061679 return renderer_factory_->CreateRenderer(
1680 media_task_runner_, worker_task_runner_, audio_source_provider_.get(),
watkdee516f2016-02-18 02:22:191681 compositor_, request_surface_cb);
sandersd1e49fb62015-12-12 01:18:061682}
1683
[email protected]ef8394c2013-08-21 20:26:301684void WebMediaPlayerImpl::StartPipeline() {
acolwellb4034942014-08-28 15:42:431685 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]ddbc6ff2013-04-19 15:28:331686
xhwange8c4181a2014-12-06 08:10:011687 Demuxer::EncryptedMediaInitDataCB encrypted_media_init_data_cb =
1688 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnEncryptedMediaInitData);
[email protected]2b57e2e2014-05-09 11:07:251689
tguilbert25a4d112016-10-13 21:56:511690 if (use_fallback_path_) {
tguilbert9881bc22016-10-27 03:13:411691 demuxer_.reset(
1692 new MediaUrlDemuxer(media_task_runner_, fallback_url_,
1693 frame_->document().firstPartyForCookies()));
tguilbert25a4d112016-10-13 21:56:511694 pipeline_controller_.Start(demuxer_.get(), this, false, false);
1695 return;
1696 }
1697
[email protected]ddbc6ff2013-04-19 15:28:331698 // Figure out which demuxer to use.
[email protected]ef8394c2013-08-21 20:26:301699 if (load_type_ != LoadTypeMediaSource) {
[email protected]ddbc6ff2013-04-19 15:28:331700 DCHECK(!chunk_demuxer_);
[email protected]f5443ef72013-04-22 04:03:381701 DCHECK(data_source_);
1702
j.isorcef6778e652015-11-16 17:14:251703#if !defined(MEDIA_DISABLE_FFMPEG)
servolk81e01e02016-03-05 03:29:151704 Demuxer::MediaTracksUpdatedCB media_tracks_updated_cb =
servolkef1e5ef2016-03-25 04:55:261705 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnFFmpegMediaTracksUpdated);
servolk81e01e02016-03-05 03:29:151706
xhwange8c4181a2014-12-06 08:10:011707 demuxer_.reset(new FFmpegDemuxer(media_task_runner_, data_source_.get(),
servolk81e01e02016-03-05 03:29:151708 encrypted_media_init_data_cb,
1709 media_tracks_updated_cb, media_log_));
j.isorcef6778e652015-11-16 17:14:251710#else
alokp967c902452016-05-06 05:21:371711 OnError(PipelineStatus::DEMUXER_ERROR_COULD_NOT_OPEN);
j.isorcef6778e652015-11-16 17:14:251712 return;
1713#endif
[email protected]ddbc6ff2013-04-19 15:28:331714 } else {
[email protected]f5443ef72013-04-22 04:03:381715 DCHECK(!chunk_demuxer_);
1716 DCHECK(!data_source_);
1717
acolwell9e0840d2014-09-06 19:01:321718 chunk_demuxer_ = new ChunkDemuxer(
[email protected]ef8394c2013-08-21 20:26:301719 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnDemuxerOpened),
chcunningham967db2f2016-11-02 20:47:171720 encrypted_media_init_data_cb, media_log_);
[email protected]f5443ef72013-04-22 04:03:381721 demuxer_.reset(chunk_demuxer_);
[email protected]ddbc6ff2013-04-19 15:28:331722 }
1723
sandersdb5e21462016-03-09 01:49:071724 // TODO(sandersd): FileSystem objects may also be non-static, but due to our
1725 // caching layer such situations are broken already. http://crbug.com/593159
1726 bool is_static = !chunk_demuxer_;
avayvod102cdb62017-01-07 03:11:091727 bool is_streaming = IsStreaming();
sandersdb8eb5f1d2016-11-19 04:04:021728 UMA_HISTOGRAM_BOOLEAN("Media.IsStreaming", is_streaming);
sandersdb5e21462016-03-09 01:49:071729
[email protected]f5443ef72013-04-22 04:03:381730 // ... and we're ready to go!
sandersd1e49fb62015-12-12 01:18:061731 // TODO(sandersd): On Android, defer Start() if the tab is not visible.
sandersdb8eb5f1d2016-11-19 04:04:021732 seeking_ = true;
alokp967c902452016-05-06 05:21:371733 pipeline_controller_.Start(demuxer_.get(), this, is_streaming, is_static);
[email protected]f5443ef72013-04-22 04:03:381734}
1735
1736void WebMediaPlayerImpl::SetNetworkState(WebMediaPlayer::NetworkState state) {
pkastingf5279482016-07-27 02:18:201737 DVLOG(1) << __func__ << "(" << state << ")";
acolwellb4034942014-08-28 15:42:431738 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]f5443ef72013-04-22 04:03:381739 network_state_ = state;
1740 // Always notify to ensure client has the latest value.
[email protected]ce70c982013-12-20 17:04:321741 client_->networkStateChanged();
[email protected]f5443ef72013-04-22 04:03:381742}
1743
1744void WebMediaPlayerImpl::SetReadyState(WebMediaPlayer::ReadyState state) {
pkastingf5279482016-07-27 02:18:201745 DVLOG(1) << __func__ << "(" << state << ")";
acolwellb4034942014-08-28 15:42:431746 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]f5443ef72013-04-22 04:03:381747
[email protected]fee8a902014-06-03 13:43:361748 if (state == WebMediaPlayer::ReadyStateHaveEnoughData && data_source_ &&
1749 data_source_->assume_fully_buffered() &&
[email protected]f5443ef72013-04-22 04:03:381750 network_state_ == WebMediaPlayer::NetworkStateLoading)
1751 SetNetworkState(WebMediaPlayer::NetworkStateLoaded);
1752
1753 ready_state_ = state;
sandersd50a635e2016-04-04 22:50:091754 highest_ready_state_ = std::max(highest_ready_state_, ready_state_);
1755
[email protected]f5443ef72013-04-22 04:03:381756 // Always notify to ensure client has the latest value.
[email protected]ce70c982013-12-20 17:04:321757 client_->readyStateChanged();
[email protected]f5443ef72013-04-22 04:03:381758}
1759
Dana Jansens71331252016-03-09 20:57:221760blink::WebAudioSourceProvider* WebMediaPlayerImpl::getAudioSourceProvider() {
[email protected]ff875be52013-06-02 23:47:381761 return audio_source_provider_.get();
[email protected]f5443ef72013-04-22 04:03:381762}
1763
[email protected]dd061e12014-05-06 19:21:221764static void GetCurrentFrameAndSignal(
1765 VideoFrameCompositor* compositor,
acolwell9e0840d2014-09-06 19:01:321766 scoped_refptr<VideoFrame>* video_frame_out,
[email protected]dd061e12014-05-06 19:21:221767 base::WaitableEvent* event) {
1768 TRACE_EVENT0("media", "GetCurrentFrameAndSignal");
dalecurtis44ce4de2015-05-11 18:42:071769 *video_frame_out = compositor->GetCurrentFrameAndUpdateIfStale();
[email protected]dd061e12014-05-06 19:21:221770 event->Signal();
1771}
1772
acolwell9e0840d2014-09-06 19:01:321773scoped_refptr<VideoFrame>
[email protected]dd061e12014-05-06 19:21:221774WebMediaPlayerImpl::GetCurrentFrameFromCompositor() {
xhwang213e50c2016-10-10 23:56:311775 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]dd061e12014-05-06 19:21:221776 TRACE_EVENT0("media", "WebMediaPlayerImpl::GetCurrentFrameFromCompositor");
xhwang213e50c2016-10-10 23:56:311777
1778 // Needed when the |main_task_runner_| and |compositor_task_runner_| are the
1779 // same to avoid deadlock in the Wait() below.
[email protected]dd061e12014-05-06 19:21:221780 if (compositor_task_runner_->BelongsToCurrentThread())
dalecurtis44ce4de2015-05-11 18:42:071781 return compositor_->GetCurrentFrameAndUpdateIfStale();
[email protected]dd061e12014-05-06 19:21:221782
1783 // Use a posted task and waitable event instead of a lock otherwise
1784 // WebGL/Canvas can see different content than what the compositor is seeing.
acolwell9e0840d2014-09-06 19:01:321785 scoped_refptr<VideoFrame> video_frame;
gab0d77c7cb2016-06-02 00:00:231786 base::WaitableEvent event(base::WaitableEvent::ResetPolicy::AUTOMATIC,
1787 base::WaitableEvent::InitialState::NOT_SIGNALED);
[email protected]dd061e12014-05-06 19:21:221788 compositor_task_runner_->PostTask(FROM_HERE,
1789 base::Bind(&GetCurrentFrameAndSignal,
1790 base::Unretained(compositor_),
1791 &video_frame,
1792 &event));
1793 event.Wait();
1794 return video_frame;
1795}
1796
sandersd50a635e2016-04-04 22:50:091797void WebMediaPlayerImpl::UpdatePlayState() {
xhwang213e50c2016-10-10 23:56:311798 DCHECK(main_task_runner_->BelongsToCurrentThread());
1799
hubbed5f36882016-01-15 22:40:371800#if defined(OS_ANDROID) // WMPI_CAST
sandersd50a635e2016-04-04 22:50:091801 bool is_remote = isRemote();
sandersdaaff1a652016-11-17 01:47:251802 bool is_streaming = false;
sandersd50a635e2016-04-04 22:50:091803#else
1804 bool is_remote = false;
avayvod102cdb62017-01-07 03:11:091805 bool is_streaming = IsStreaming();
hubbed5f36882016-01-15 22:40:371806#endif
xhwang213e50c2016-10-10 23:56:311807
dalecurtis8b8505e72016-06-10 21:59:171808 bool is_suspended = pipeline_controller_.IsSuspended();
avayvod39c102402016-11-23 21:43:131809 bool is_backgrounded = IsBackgroundedSuspendEnabled() && IsHidden();
sandersdaaff1a652016-11-17 01:47:251810 PlayState state = UpdatePlayState_ComputePlayState(
1811 is_remote, is_streaming, is_suspended, is_backgrounded);
sandersd35d2c3f2017-01-14 02:04:421812 SetDelegateState(state.delegate_state, state.is_idle);
sandersd50a635e2016-04-04 22:50:091813 SetMemoryReportingState(state.is_memory_reporting_enabled);
1814 SetSuspendState(state.is_suspended || pending_suspend_resume_cycle_);
1815}
dalecurtis5bbc487e2016-02-27 04:15:051816
sandersd35d2c3f2017-01-14 02:04:421817void WebMediaPlayerImpl::SetDelegateState(DelegateState new_state,
1818 bool is_idle) {
mlamouri910111362016-11-04 11:28:241819 if (!delegate_)
dalecurtis5bbc487e2016-02-27 04:15:051820 return;
1821
sandersd35d2c3f2017-01-14 02:04:421822 // Prevent duplicate delegate calls.
1823 // TODO(sandersd): Move this deduplication into the delegate itself.
1824 // TODO(sandersd): WebContentsObserverSanityChecker does not allow sending the
1825 // 'playing' IPC more than once in a row, even if the metadata has changed.
1826 // Figure out whether it should.
1827 bool has_audio = hasAudio() && !client_->isAutoplayingMuted();
1828 if (delegate_state_ == new_state &&
1829 (delegate_state_ != DelegateState::PLAYING ||
1830 delegate_has_audio_ == has_audio)) {
1831 return;
mlamouri910111362016-11-04 11:28:241832 }
sandersd50a635e2016-04-04 22:50:091833 delegate_state_ = new_state;
sandersd35d2c3f2017-01-14 02:04:421834 delegate_has_audio_ = has_audio;
sandersd50a635e2016-04-04 22:50:091835
sandersd35d2c3f2017-01-14 02:04:421836 switch (new_state) {
sandersd50a635e2016-04-04 22:50:091837 case DelegateState::GONE:
1838 delegate_->PlayerGone(delegate_id_);
1839 break;
mlamouri910111362016-11-04 11:28:241840 case DelegateState::PLAYING: {
zqzhang5d8eab72016-08-26 20:34:301841 delegate_->DidPlay(
sandersd35d2c3f2017-01-14 02:04:421842 delegate_id_, hasVideo(), has_audio,
avayvodcc273dd2017-01-19 19:35:121843 media::DurationToMediaContentType(GetPipelineMediaDuration()));
sandersd50a635e2016-04-04 22:50:091844 break;
mlamouri910111362016-11-04 11:28:241845 }
sandersd50a635e2016-04-04 22:50:091846 case DelegateState::PAUSED:
sandersd35d2c3f2017-01-14 02:04:421847 delegate_->DidPause(delegate_id_);
sandersd50a635e2016-04-04 22:50:091848 break;
dalecurtis0f0097a2015-12-01 17:40:471849 }
sandersd35d2c3f2017-01-14 02:04:421850
1851 delegate_->SetIdle(delegate_id_, is_idle);
dalecurtis0f0097a2015-12-01 17:40:471852}
1853
sandersd50a635e2016-04-04 22:50:091854void WebMediaPlayerImpl::SetMemoryReportingState(
1855 bool is_memory_reporting_enabled) {
1856 if (memory_usage_reporting_timer_.IsRunning() ==
1857 is_memory_reporting_enabled) {
hubbed5f36882016-01-15 22:40:371858 return;
sandersd50a635e2016-04-04 22:50:091859 }
sandersd1c0bba02016-03-04 23:14:081860
sandersd50a635e2016-04-04 22:50:091861 if (is_memory_reporting_enabled) {
1862 memory_usage_reporting_timer_.Start(FROM_HERE,
1863 base::TimeDelta::FromSeconds(2), this,
1864 &WebMediaPlayerImpl::ReportMemoryUsage);
1865 } else {
1866 memory_usage_reporting_timer_.Stop();
1867 ReportMemoryUsage();
1868 }
1869}
1870
1871void WebMediaPlayerImpl::SetSuspendState(bool is_suspended) {
xhwang213e50c2016-10-10 23:56:311872 DCHECK(main_task_runner_->BelongsToCurrentThread());
1873
sandersd50a635e2016-04-04 22:50:091874 // Do not change the state after an error has occurred.
1875 // TODO(sandersd): Update PipelineController to remove the need for this.
1876 if (IsNetworkStateError(network_state_))
sandersd1c0bba02016-03-04 23:14:081877 return;
1878
jbauman2438e872016-11-15 04:45:191879#if defined(OS_LINUX)
halliwell6451e242016-06-01 15:00:241880 // TODO(sandersd): idle suspend is disabled if decoder owns video frame.
jbauman2438e872016-11-15 04:45:191881 // Used on Chromecast. Since GetCurrentFrameFromCompositor is a synchronous
1882 // cross-thread post, avoid the cost on platforms that always allow suspend.
1883 // Need to find a better mechanism for this. See http://crbug.com/602708
dalecurtis7f366b2242016-04-13 01:16:171884 if (can_suspend_state_ == CanSuspendState::UNKNOWN) {
1885 scoped_refptr<VideoFrame> frame = GetCurrentFrameFromCompositor();
1886 if (frame) {
1887 can_suspend_state_ =
1888 frame->metadata()->IsTrue(VideoFrameMetadata::DECODER_OWNS_FRAME)
1889 ? CanSuspendState::NO
1890 : CanSuspendState::YES;
1891 }
1892 }
1893#else
1894 can_suspend_state_ = CanSuspendState::YES;
1895#endif
1896
sandersd35d2c3f2017-01-14 02:04:421897 if (is_suspended && can_suspend_state_ != CanSuspendState::NO) {
1898 // If we were not resumed for long enough to satisfy the preroll attempt,
1899 // reset the clock.
1900 if (!preroll_attempt_pending_ && IsPrerollAttemptNeeded()) {
1901 preroll_attempt_pending_ = true;
1902 preroll_attempt_start_time_ = base::TimeTicks();
1903 }
sandersd50a635e2016-04-04 22:50:091904 pipeline_controller_.Suspend();
1905 } else {
sandersd35d2c3f2017-01-14 02:04:421906 // When resuming, start the preroll attempt clock.
1907 if (preroll_attempt_pending_) {
1908 preroll_attempt_pending_ = false;
1909 preroll_attempt_start_time_ = tick_clock_->NowTicks();
1910 }
sandersd50a635e2016-04-04 22:50:091911 pipeline_controller_.Resume();
1912 }
1913}
1914
1915WebMediaPlayerImpl::PlayState
1916WebMediaPlayerImpl::UpdatePlayState_ComputePlayState(bool is_remote,
sandersdaaff1a652016-11-17 01:47:251917 bool is_streaming,
dalecurtis8b8505e72016-06-10 21:59:171918 bool is_suspended,
sandersd50a635e2016-04-04 22:50:091919 bool is_backgrounded) {
1920 PlayState result;
1921
sandersd35d2c3f2017-01-14 02:04:421922 bool must_suspend = delegate_ && delegate_->IsFrameClosed();
1923 bool is_stale = delegate_ && delegate_->IsStale(delegate_id_);
1924
sandersd50a635e2016-04-04 22:50:091925 // This includes both data source (before pipeline startup) and pipeline
1926 // errors.
1927 bool has_error = IsNetworkStateError(network_state_);
1928
1929 // After HaveMetadata, we know which tracks are present and the duration.
1930 bool have_metadata = ready_state_ >= WebMediaPlayer::ReadyStateHaveMetadata;
1931
dalecurtiscc8baf72016-10-27 01:49:441932 // After HaveFutureData, Blink will call play() if the state is not paused;
1933 // prior to this point |paused_| is not accurate.
sandersd50a635e2016-04-04 22:50:091934 bool have_future_data =
1935 highest_ready_state_ >= WebMediaPlayer::ReadyStateHaveFutureData;
1936
dalecurtis8b8505e72016-06-10 21:59:171937 // Background suspend is not enabled for audio-only players unless paused,
1938 // though in the case of audio-only the session should be kept.
avayvod48a8be52016-08-04 19:52:501939 // Videos are not suspended if the user resumed the playback via the remote
1940 // controls earlier and it's still playing.
1941 bool is_backgrounded_video = is_backgrounded && have_metadata && hasVideo();
1942 bool can_play_backgrounded = is_backgrounded_video && !is_remote &&
1943 hasAudio() && IsResumeBackgroundVideosEnabled();
1944 bool is_background_playing =
sandersd35d2c3f2017-01-14 02:04:421945 delegate_ && delegate_->IsBackgroundVideoPlaybackUnlocked();
sandersdaaff1a652016-11-17 01:47:251946 bool background_suspended = !is_streaming && is_backgrounded_video &&
avayvod48a8be52016-08-04 19:52:501947 !(can_play_backgrounded && is_background_playing);
dalecurtiscc8baf72016-10-27 01:49:441948 bool background_pause_suspended =
sandersdaaff1a652016-11-17 01:47:251949 !is_streaming && is_backgrounded && paused_ && have_future_data;
sandersd50a635e2016-04-04 22:50:091950
dalecurtiscc8baf72016-10-27 01:49:441951 // Idle suspension is allowed prior to have future data since there exist
1952 // mechanisms to exit the idle state when the player is capable of reaching
1953 // the have future data state; see didLoadingProgress().
1954 //
sandersd50a635e2016-04-04 22:50:091955 // TODO(sandersd): Make the delegate suspend idle players immediately when
1956 // hidden.
sandersdaaff1a652016-11-17 01:47:251957 bool idle_suspended =
sandersd35d2c3f2017-01-14 02:04:421958 !is_streaming && is_stale && paused_ && !seeking_ && !overlay_enabled_;
dalecurtise7120dc2016-09-03 02:54:351959
1960 // If we're already suspended, see if we can wait for user interaction. Prior
sandersd35d2c3f2017-01-14 02:04:421961 // to HaveFutureData, we require |is_stale| to remain suspended. |is_stale|
dalecurtise7120dc2016-09-03 02:54:351962 // will be cleared when we receive data which may take us to HaveFutureData.
1963 bool can_stay_suspended =
sandersd35d2c3f2017-01-14 02:04:421964 (is_stale || have_future_data) && is_suspended && paused_ && !seeking_;
sandersd50a635e2016-04-04 22:50:091965
1966 // Combined suspend state.
sandersd35d2c3f2017-01-14 02:04:421967 result.is_suspended = is_remote || must_suspend || idle_suspended ||
dalecurtise7120dc2016-09-03 02:54:351968 background_suspended || background_pause_suspended ||
1969 can_stay_suspended;
sandersd50a635e2016-04-04 22:50:091970
1971 // We do not treat |playback_rate_| == 0 as paused. For the media session,
1972 // being paused implies displaying a play button, which is incorrect in this
1973 // case. For memory usage reporting, we just use the same definition (but we
1974 // don't have to).
1975 //
1976 // Similarly, we don't consider |ended_| to be paused. Blink will immediately
1977 // call pause() or seek(), so |ended_| should not affect the computation.
1978 // Despite that, |ended_| does result in a separate paused state, to simplfy
1979 // the contract for SetDelegateState().
1980 //
1981 // |has_session| is used to decide when to create a media session. Idle
1982 // suspension does not destroy the media session, because we expect that the
1983 // notification controls (and audio focus) remain. We also require:
1984 // - |have_metadata|, since the tracks and duration are passed to DidPlay().
1985 // - |have_future_data|, since we need to know whether we are paused to
1986 // correctly configure the session.
1987 //
1988 // TODO(sandersd): If Blink told us the paused state sooner, we could create
1989 // the media session sooner.
1990 bool can_play = !has_error && !is_remote && have_future_data;
sandersd35d2c3f2017-01-14 02:04:421991 bool has_session_playing = can_play && !must_suspend && !background_suspended;
avayvod48a8be52016-08-04 19:52:501992
1993 // |has_session_suspended| means the player is suspended from the media
1994 // element point of view but paused and can be resumed from the delegate point
1995 // of view. Therefore it behaves like |paused_| for the delegate.
sandersd35d2c3f2017-01-14 02:04:421996 bool has_session_suspended = can_play && !must_suspend &&
avayvod48a8be52016-08-04 19:52:501997 background_suspended && can_play_backgrounded;
1998
1999 bool has_session = has_session_playing || has_session_suspended;
sandersd50a635e2016-04-04 22:50:092000
2001 if (!has_session) {
2002 result.delegate_state = DelegateState::GONE;
sandersd35d2c3f2017-01-14 02:04:422003 result.is_idle = delegate_ && delegate_->IsIdle(delegate_id_);
avayvod48a8be52016-08-04 19:52:502004 } else if (paused_ || has_session_suspended) {
sandersd35d2c3f2017-01-14 02:04:422005 // TODO(sandersd): Is it possible to have a suspended session, be ended,
2006 // and not be paused? If so we should be in a PLAYING state.
dalecurtise7120dc2016-09-03 02:54:352007 result.delegate_state =
sandersd35d2c3f2017-01-14 02:04:422008 ended_ ? DelegateState::GONE : DelegateState::PAUSED;
2009 result.is_idle = !seeking_;
sandersd50a635e2016-04-04 22:50:092010 } else {
2011 result.delegate_state = DelegateState::PLAYING;
sandersd35d2c3f2017-01-14 02:04:422012 result.is_idle = false;
sandersd50a635e2016-04-04 22:50:092013 }
2014
dalecurtis8b8505e72016-06-10 21:59:172015 // It's not critical if some cases where memory usage can change are missed,
sandersd50a635e2016-04-04 22:50:092016 // since media memory changes are usually gradual.
2017 result.is_memory_reporting_enabled =
sandersd35d2c3f2017-01-14 02:04:422018 can_play && !result.is_suspended && (!paused_ || seeking_);
sandersd50a635e2016-04-04 22:50:092019
2020 return result;
dalecurtis0f0097a2015-12-01 17:40:472021}
2022
dalecurtis83266c72015-10-29 18:43:202023void WebMediaPlayerImpl::ReportMemoryUsage() {
2024 DCHECK(main_task_runner_->BelongsToCurrentThread());
2025
wdzierzanowskifd4cd91c52015-12-02 23:50:202026 // About base::Unretained() usage below: We destroy |demuxer_| on the main
2027 // thread. Before that, however, ~WebMediaPlayerImpl() posts a task to the
2028 // media thread and waits for it to finish. Hence, the GetMemoryUsage() task
2029 // posted here must finish earlier.
2030
2031 if (demuxer_) {
2032 base::PostTaskAndReplyWithResult(
2033 media_task_runner_.get(), FROM_HERE,
2034 base::Bind(&Demuxer::GetMemoryUsage, base::Unretained(demuxer_.get())),
2035 base::Bind(&WebMediaPlayerImpl::FinishMemoryUsageReport, AsWeakPtr()));
2036 } else {
2037 FinishMemoryUsageReport(0);
2038 }
2039}
2040
2041void WebMediaPlayerImpl::FinishMemoryUsageReport(int64_t demuxer_memory_usage) {
2042 DCHECK(main_task_runner_->BelongsToCurrentThread());
2043
avayvodc4bfb0e62017-01-13 01:07:012044 const PipelineStatistics stats = GetPipelineStatistics();
servolk639473e492016-12-15 04:14:202045 const int64_t data_source_memory_usage =
2046 data_source_ ? data_source_->GetMemoryUsage() : 0;
dalecurtis83266c72015-10-29 18:43:202047 const int64_t current_memory_usage =
2048 stats.audio_memory_usage + stats.video_memory_usage +
servolk639473e492016-12-15 04:14:202049 data_source_memory_usage + demuxer_memory_usage;
dalecurtis83266c72015-10-29 18:43:202050
dalecurtis3a7d38f42016-03-07 21:17:132051 // Note, this isn't entirely accurate, there may be VideoFrames held by the
2052 // compositor or other resources that we're unaware of.
2053
dalecurtis83266c72015-10-29 18:43:202054 DVLOG(2) << "Memory Usage -- Audio: " << stats.audio_memory_usage
servolk639473e492016-12-15 04:14:202055 << ", Video: " << stats.video_memory_usage
2056 << ", DataSource: " << data_source_memory_usage
wdzierzanowskifd4cd91c52015-12-02 23:50:202057 << ", Demuxer: " << demuxer_memory_usage;
dalecurtis83266c72015-10-29 18:43:202058
2059 const int64_t delta = current_memory_usage - last_reported_memory_usage_;
2060 last_reported_memory_usage_ = current_memory_usage;
2061 adjust_allocated_memory_cb_.Run(delta);
servolk639473e492016-12-15 04:14:202062
2063 if (hasAudio()) {
2064 UMA_HISTOGRAM_MEMORY_KB("Media.WebMediaPlayerImpl.Memory.Audio",
2065 stats.audio_memory_usage / 1024);
2066 }
2067 if (hasVideo()) {
2068 UMA_HISTOGRAM_MEMORY_KB("Media.WebMediaPlayerImpl.Memory.Video",
2069 stats.video_memory_usage / 1024);
2070 }
2071 if (data_source_) {
2072 UMA_HISTOGRAM_MEMORY_KB("Media.WebMediaPlayerImpl.Memory.DataSource",
2073 data_source_memory_usage / 1024);
2074 }
2075 if (demuxer_) {
2076 UMA_HISTOGRAM_MEMORY_KB("Media.WebMediaPlayerImpl.Memory.Demuxer",
2077 demuxer_memory_usage / 1024);
2078 }
dalecurtis83266c72015-10-29 18:43:202079}
2080
dalecurtis8b8505e72016-06-10 21:59:172081void WebMediaPlayerImpl::ScheduleIdlePauseTimer() {
dalecurtise7120dc2016-09-03 02:54:352082 // Only schedule the pause timer if we're playing and are suspended.
2083 if (paused_ || !pipeline_controller_.IsSuspended())
dalecurtis8b8505e72016-06-10 21:59:172084 return;
2085
2086#if defined(OS_ANDROID)
2087 // Remote players will be suspended and locally paused.
2088 if (isRemote())
2089 return;
2090#endif
2091
2092 // Idle timeout chosen arbitrarily.
2093 background_pause_timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(5),
2094 this, &WebMediaPlayerImpl::OnPause);
2095}
2096
dalecurtis04bdb582016-08-17 22:15:232097void WebMediaPlayerImpl::CreateWatchTimeReporter() {
2098 // Create the watch time reporter and synchronize its initial state.
2099 watch_time_reporter_.reset(new WatchTimeReporter(
2100 hasAudio(), hasVideo(), !!chunk_demuxer_, is_encrypted_, media_log_,
2101 pipeline_metadata_.natural_size,
2102 base::Bind(&GetCurrentTimeInternal, this)));
2103 watch_time_reporter_->OnVolumeChange(volume_);
sandersd35d2c3f2017-01-14 02:04:422104 if (delegate_ && delegate_->IsFrameHidden())
dalecurtis04bdb582016-08-17 22:15:232105 watch_time_reporter_->OnHidden();
2106 else
2107 watch_time_reporter_->OnShown();
2108}
2109
avayvod39c102402016-11-23 21:43:132110bool WebMediaPlayerImpl::IsHidden() const {
2111 DCHECK(main_task_runner_->BelongsToCurrentThread());
2112
sandersd35d2c3f2017-01-14 02:04:422113 return delegate_ && delegate_->IsFrameHidden() && !delegate_->IsFrameClosed();
avayvod39c102402016-11-23 21:43:132114}
2115
avayvod102cdb62017-01-07 03:11:092116bool WebMediaPlayerImpl::IsStreaming() const {
2117 return data_source_ && data_source_->IsStreaming();
2118}
2119
liberato2fd111be2017-01-04 00:25:062120bool WebMediaPlayerImpl::DoesOverlaySupportMetadata() const {
2121 return pipeline_metadata_.video_rotation == VIDEO_ROTATION_0;
2122}
2123
xjzaf29d4182016-12-16 01:52:322124void WebMediaPlayerImpl::ActivateViewportIntersectionMonitoring(bool activate) {
2125 DCHECK(main_task_runner_->BelongsToCurrentThread());
2126
2127 client_->activateViewportIntersectionMonitoring(activate);
2128}
2129
avayvodcc273dd2017-01-19 19:35:122130bool WebMediaPlayerImpl::ShouldPauseVideoWhenHidden() const {
2131#if !defined(OS_ANDROID)
2132 // On desktop, this behavior is behind the feature flag.
avayvod2135a642017-01-13 00:17:142133 if (!IsBackgroundVideoTrackOptimizationEnabled())
2134 return false;
avayvodcc273dd2017-01-19 19:35:122135#endif
avayvodeb9098d2017-01-07 00:33:032136
avayvodcc273dd2017-01-19 19:35:122137 // Pause video-only players that match the criteria for being optimized.
2138 return !hasAudio() && IsBackgroundOptimizationCandidate();
avayvodeb9098d2017-01-07 00:33:032139}
2140
avayvod2135a642017-01-13 00:17:142141bool WebMediaPlayerImpl::ShouldDisableVideoWhenHidden() const {
avayvodcc273dd2017-01-19 19:35:122142 // This optimization is behind the flag on all platforms.
2143 if (!IsBackgroundVideoTrackOptimizationEnabled())
avayvodc4bfb0e62017-01-13 01:07:012144 return false;
avayvodc4bfb0e62017-01-13 01:07:012145
avayvodcc273dd2017-01-19 19:35:122146 // Disable video track only for players with audio that match the criteria for
2147 // being optimized.
2148 return hasAudio() && IsBackgroundOptimizationCandidate();
2149}
2150
2151bool WebMediaPlayerImpl::IsBackgroundOptimizationCandidate() const {
2152 DCHECK(main_task_runner_->BelongsToCurrentThread());
2153
avayvodcc273dd2017-01-19 19:35:122154#if defined(OS_ANDROID) // WMPI_CAST
avayvodac1a8522017-01-20 19:02:502155 // Don't optimize players being Cast.
avayvodcc273dd2017-01-19 19:35:122156 if (isRemote())
2157 return false;
avayvodac1a8522017-01-20 19:02:502158
2159 // Video-only players are always optimized (paused) on Android.
2160 // Don't check the keyframe distance and duration.
2161 if (!hasAudio() && hasVideo())
2162 return true;
avayvodcc273dd2017-01-19 19:35:122163#endif // defined(OS_ANDROID)
2164
2165 // Don't optimize audio-only or streaming players.
2166 if (!hasVideo() || IsStreaming())
2167 return false;
2168
2169 // Videos shorter than the maximum allowed keyframe distance can be optimized.
2170 base::TimeDelta duration = GetPipelineMediaDuration();
2171 if (duration < max_keyframe_distance_to_disable_background_video_)
2172 return true;
2173
2174 // Otherwise, only optimize videos with shorter average keyframe distance.
avayvodc4bfb0e62017-01-13 01:07:012175 PipelineStatistics stats = GetPipelineStatistics();
2176 return stats.video_keyframe_distance_average <
2177 max_keyframe_distance_to_disable_background_video_;
avayvod2135a642017-01-13 00:17:142178}
2179
avayvod56e1f3942017-01-21 02:06:312180void WebMediaPlayerImpl::UpdateBackgroundVideoOptimizationState() {
2181 if (IsHidden()) {
2182 if (ShouldPauseVideoWhenHidden())
2183 PauseVideoIfNeeded();
2184 else
2185 DisableVideoTrackIfNeeded();
2186 } else {
2187 EnableVideoTrackIfNeeded();
2188 }
2189}
2190
2191void WebMediaPlayerImpl::PauseVideoIfNeeded() {
2192 DCHECK(IsHidden());
2193
2194 // Don't pause video while the pipeline is stopped, resuming or seeking.
2195 // Also if the video is paused already.
2196 if (!pipeline_.IsRunning() || is_pipeline_resuming_ || seeking_ || paused_)
2197 return;
2198
2199 // OnPause() will set |paused_when_hidden_| to false and call
2200 // UpdatePlayState(), so set the flag to true after and then return.
2201 OnPause();
2202 paused_when_hidden_ = true;
2203}
2204
avayvod2135a642017-01-13 00:17:142205void WebMediaPlayerImpl::EnableVideoTrackIfNeeded() {
avayvod56e1f3942017-01-21 02:06:312206 // Don't change video track while the pipeline is stopped, resuming or
2207 // seeking.
2208 if (!pipeline_.IsRunning() || is_pipeline_resuming_ || seeking_)
avayvod2135a642017-01-13 00:17:142209 return;
2210
2211 if (video_track_disabled_) {
2212 video_track_disabled_ = false;
2213 if (client_->hasSelectedVideoTrack()) {
2214 WebMediaPlayer::TrackId trackId = client_->getSelectedVideoTrackId();
2215 selectedVideoTrackChanged(&trackId);
2216 }
2217 }
2218}
2219
2220void WebMediaPlayerImpl::DisableVideoTrackIfNeeded() {
2221 DCHECK(IsHidden());
2222
2223 // Don't change video track while the pipeline is resuming or seeking.
2224 if (is_pipeline_resuming_ || seeking_)
2225 return;
2226
2227 if (!video_track_disabled_ && ShouldDisableVideoWhenHidden()) {
2228 video_track_disabled_ = true;
2229 selectedVideoTrackChanged(nullptr);
2230 }
2231}
2232
avayvodc4bfb0e62017-01-13 01:07:012233void WebMediaPlayerImpl::SetPipelineStatisticsForTest(
2234 const PipelineStatistics& stats) {
2235 pipeline_statistics_for_test_ = base::make_optional(stats);
2236}
2237
2238PipelineStatistics WebMediaPlayerImpl::GetPipelineStatistics() const {
2239 DCHECK(main_task_runner_->BelongsToCurrentThread());
2240
2241 return pipeline_statistics_for_test_.value_or(pipeline_.GetStatistics());
2242}
2243
avayvodcc273dd2017-01-19 19:35:122244void WebMediaPlayerImpl::SetPipelineMediaDurationForTest(
2245 base::TimeDelta duration) {
2246 pipeline_media_duration_for_test_ = base::make_optional(duration);
2247}
2248
2249base::TimeDelta WebMediaPlayerImpl::GetPipelineMediaDuration() const {
2250 DCHECK(main_task_runner_->BelongsToCurrentThread());
2251
2252 return pipeline_media_duration_for_test_.value_or(
2253 pipeline_.GetMediaDuration());
2254}
2255
2256void WebMediaPlayerImpl::ReportTimeFromForegroundToFirstFrame(
2257 base::TimeTicks foreground_time,
2258 base::TimeTicks new_frame_time) {
2259 base::TimeDelta time_to_first_frame = new_frame_time - foreground_time;
2260 if (hasAudio()) {
2261 UMA_HISTOGRAM_TIMES(
2262 "Media.Video.TimeFromForegroundToFirstFrame.DisableTrack",
2263 time_to_first_frame);
2264 } else {
2265 UMA_HISTOGRAM_TIMES("Media.Video.TimeFromForegroundToFirstFrame.Paused",
2266 time_to_first_frame);
2267 }
2268}
2269
acolwell9e0840d2014-09-06 19:01:322270} // namespace media