blob: 6fae8f9f49fad256e0f825794f240780d209cd26 [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"
[email protected]b0b258f2011-11-08 00:34:2321#include "base/metrics/histogram.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"
[email protected]32da1002010-03-03 21:57:3533#include "media/base/limits.h"
[email protected]090f7312011-08-05 23:26:4034#include "media/base/media_log.h"
sandersd1e49fb62015-12-12 01:18:0635#include "media/base/media_switches.h"
[email protected]8a561062013-11-22 01:19:3136#include "media/base/text_renderer.h"
watk9f9dfdc92015-09-04 21:33:2937#include "media/base/timestamp_constants.h"
[email protected]e81283bb2010-08-31 18:01:2138#include "media/base/video_frame.h"
acolwell9e0840d2014-09-06 19:01:3239#include "media/blink/texttrack_impl.h"
40#include "media/blink/webaudiosourceprovider_impl.h"
xhwang97de4202014-11-25 08:44:0141#include "media/blink/webcontentdecryptionmodule_impl.h"
acolwell9e0840d2014-09-06 19:01:3242#include "media/blink/webinbandtexttrack_impl.h"
43#include "media/blink/webmediaplayer_delegate.h"
acolwell9e0840d2014-09-06 19:01:3244#include "media/blink/webmediaplayer_util.h"
45#include "media/blink/webmediasource_impl.h"
[email protected]efe7cd22012-09-12 23:55:0146#include "media/filters/chunk_demuxer.h"
[email protected]ddbc6ff2013-04-19 15:28:3347#include "media/filters/ffmpeg_demuxer.h"
jrummellc9d8e532015-02-26 18:38:1948#include "third_party/WebKit/public/platform/WebEncryptedMediaTypes.h"
srirama.m26f864d02015-07-14 05:21:4649#include "third_party/WebKit/public/platform/WebMediaPlayerClient.h"
50#include "third_party/WebKit/public/platform/WebMediaPlayerEncryptedMediaClient.h"
guidou9bfe4e2f2016-04-09 08:31:1951#include "third_party/WebKit/public/platform/WebMediaPlayerSource.h"
[email protected]745746d2013-08-23 02:09:1652#include "third_party/WebKit/public/platform/WebMediaSource.h"
[email protected]c10884462013-05-30 00:22:0953#include "third_party/WebKit/public/platform/WebRect.h"
mek966863c2016-02-04 23:39:0554#include "third_party/WebKit/public/platform/WebSecurityOrigin.h"
[email protected]c10884462013-05-30 00:22:0955#include "third_party/WebKit/public/platform/WebSize.h"
56#include "third_party/WebKit/public/platform/WebString.h"
57#include "third_party/WebKit/public/platform/WebURL.h"
xhwang0acca44b2015-06-18 00:43:3158#include "third_party/WebKit/public/web/WebFrame.h"
[email protected]80504652014-04-18 04:41:5059#include "third_party/WebKit/public/web/WebLocalFrame.h"
[email protected]2255a9332013-06-17 05:12:3160#include "third_party/WebKit/public/web/WebView.h"
[email protected]b3f2b912009-04-09 16:18:5261
dalecurtisea27a3ed2016-06-24 01:41:3062#if defined(OS_ANDROID)
63#include "media/base/android/media_codec_util.h"
64#endif
65
[email protected]180ef242013-11-07 06:50:4666using blink::WebCanvas;
67using blink::WebMediaPlayer;
68using blink::WebRect;
69using blink::WebSize;
70using blink::WebString;
hubbed5f36882016-01-15 22:40:3771using gpu::gles2::GLES2Interface;
72
danakj365175c2016-02-06 00:37:3773#define STATIC_ASSERT_ENUM(a, b) \
74 static_assert(static_cast<int>(a) == static_cast<int>(b), \
75 "mismatching enums: " #a)
76
hubbed5f36882016-01-15 22:40:3777namespace media {
[email protected]ec9212f2008-12-18 21:40:3678
[email protected]8931c41a2009-07-07 17:31:4979namespace {
80
[email protected]378f0b72009-08-11 17:11:4281// Limits the range of playback rate.
82//
83// TODO(kylep): Revisit these.
84//
85// Vista has substantially lower performance than XP or Windows7. If you speed
86// up a video too much, it can't keep up, and rendering stops updating except on
87// the time bar. For really high speeds, audio becomes a bottleneck and we just
88// use up the data we have, which may not achieve the speed requested, but will
89// not crash the tab.
90//
91// A very slow speed, ie 0.00000001x, causes the machine to lock up. (It seems
92// like a busy loop). It gets unresponsive, although its not completely dead.
93//
94// Also our timers are not very accurate (especially for ogg), which becomes
95// evident at low speeds and on Vista. Since other speeds are risky and outside
96// the norms, we think 1/16x to 16x is a safe and useful range for now.
[email protected]39bdde32013-04-17 17:44:2097const double kMinRate = 0.0625;
98const double kMaxRate = 16.0;
[email protected]378f0b72009-08-11 17:11:4299
hubbed5f36882016-01-15 22:40:37100void SetSinkIdOnMediaThread(scoped_refptr<WebAudioSourceProviderImpl> sink,
101 const std::string& device_id,
102 const url::Origin& security_origin,
olka68b69392016-04-01 11:42:12103 const OutputDeviceStatusCB& callback) {
104 sink->SwitchOutputDevice(device_id, security_origin, callback);
guidouc7babef2015-10-22 00:42:35105}
106
sandersd50a635e2016-04-04 22:50:09107bool IsBackgroundedSuspendEnabled() {
dalecurtis0431cbf2016-03-12 01:19:43108#if !defined(OS_ANDROID)
109 // Suspend/Resume is only enabled by default on Android.
110 return base::CommandLine::ForCurrentProcess()->HasSwitch(
111 switches::kEnableMediaSuspend);
112#else
113 return !base::CommandLine::ForCurrentProcess()->HasSwitch(
114 switches::kDisableMediaSuspend);
115#endif
116}
117
sandersd50a635e2016-04-04 22:50:09118bool IsNetworkStateError(blink::WebMediaPlayer::NetworkState state) {
119 bool result = state == blink::WebMediaPlayer::NetworkStateFormatError ||
120 state == blink::WebMediaPlayer::NetworkStateNetworkError ||
121 state == blink::WebMediaPlayer::NetworkStateDecodeError;
122 DCHECK_EQ(state > blink::WebMediaPlayer::NetworkStateLoaded, result);
123 return result;
124}
125
[email protected]8931c41a2009-07-07 17:31:49126} // namespace
127
[email protected]6683e1b2014-04-10 01:45:38128class BufferedDataSourceHostImpl;
129
danakj365175c2016-02-06 00:37:37130STATIC_ASSERT_ENUM(WebMediaPlayer::CORSModeUnspecified,
131 UrlData::CORS_UNSPECIFIED);
132STATIC_ASSERT_ENUM(WebMediaPlayer::CORSModeAnonymous, UrlData::CORS_ANONYMOUS);
133STATIC_ASSERT_ENUM(WebMediaPlayer::CORSModeUseCredentials,
134 UrlData::CORS_USE_CREDENTIALS);
[email protected]a5a01102012-06-06 17:01:24135
[email protected]2c539b82012-08-18 04:10:19136#define BIND_TO_RENDER_LOOP(function) \
acolwellb4034942014-08-28 15:42:43137 (DCHECK(main_task_runner_->BelongsToCurrentThread()), \
acolwell9e0840d2014-09-06 19:01:32138 BindToCurrentLoop(base::Bind(function, AsWeakPtr())))
[email protected]5983adb2012-10-24 00:12:00139
[email protected]4e982192014-06-21 13:35:45140#define BIND_TO_RENDER_LOOP1(function, arg1) \
acolwellb4034942014-08-28 15:42:43141 (DCHECK(main_task_runner_->BelongsToCurrentThread()), \
acolwell9e0840d2014-09-06 19:01:32142 BindToCurrentLoop(base::Bind(function, AsWeakPtr(), arg1)))
[email protected]4e982192014-06-21 13:35:45143
[email protected]5b5bb9d2010-10-22 19:57:36144WebMediaPlayerImpl::WebMediaPlayerImpl(
[email protected]35b2a972014-04-04 15:50:22145 blink::WebLocalFrame* frame,
[email protected]180ef242013-11-07 06:50:46146 blink::WebMediaPlayerClient* client,
srirama.m26f864d02015-07-14 05:21:46147 blink::WebMediaPlayerEncryptedMediaClient* encrypted_client,
[email protected]b8976652011-10-26 23:46:55148 base::WeakPtr<WebMediaPlayerDelegate> delegate,
dcheng3076abbf2016-04-22 20:42:39149 std::unique_ptr<RendererFactory> renderer_factory,
hubbe5f0ad43b2015-12-14 20:57:26150 linked_ptr<UrlIndex> url_index,
[email protected]e82b2bd2013-01-02 17:47:57151 const WebMediaPlayerParams& params)
[email protected]f6af7592014-02-28 10:09:11152 : frame_(frame),
sandersd50a635e2016-04-04 22:50:09153 delegate_state_(DelegateState::GONE),
154 is_idle_(false),
155 must_suspend_(false),
[email protected]ef405f66b2012-04-18 02:39:55156 network_state_(WebMediaPlayer::NetworkStateEmpty),
157 ready_state_(WebMediaPlayer::ReadyStateHaveNothing),
sandersd50a635e2016-04-04 22:50:09158 highest_ready_state_(WebMediaPlayer::ReadyStateHaveNothing),
acolwella5081a42014-08-28 23:42:52159 preload_(BufferedDataSource::AUTO),
sandersdc6ab163a2015-12-12 03:56:13160 buffering_strategy_(
161 BufferedDataSourceInterface::BUFFERING_STRATEGY_NORMAL),
anujk.sharma2fa37a02015-04-30 05:51:32162 main_task_runner_(base::ThreadTaskRunnerHandle::Get()),
acolwell755d12d2014-08-30 01:09:19163 media_task_runner_(params.media_task_runner()),
dcastagna617d086b2015-08-20 01:39:30164 worker_task_runner_(params.worker_task_runner()),
acolwell755d12d2014-08-30 01:09:19165 media_log_(params.media_log()),
acolwellb4034942014-08-28 15:42:43166 pipeline_(media_task_runner_, media_log_.get()),
sandersd1c0bba02016-03-04 23:14:08167 pipeline_controller_(
168 &pipeline_,
169 base::Bind(&WebMediaPlayerImpl::CreateRenderer,
170 base::Unretained(this)),
171 base::Bind(&WebMediaPlayerImpl::OnPipelineSeeked, AsWeakPtr()),
172 base::Bind(&WebMediaPlayerImpl::OnPipelineSuspended, AsWeakPtr()),
alokp967c902452016-05-06 05:21:37173 base::Bind(&WebMediaPlayerImpl::OnError, AsWeakPtr())),
[email protected]f988d9b2014-07-25 00:35:43174 load_type_(LoadTypeURL),
[email protected]75e145a2014-04-15 17:44:32175 opaque_(false),
wolenetz1b2ae7d2015-06-10 00:44:21176 playback_rate_(0.0),
[email protected]49480902009-07-14 20:23:43177 paused_(true),
[email protected]b3766a22010-12-22 17:34:13178 seeking_(false),
watkdee516f2016-02-18 02:22:19179 pending_suspend_resume_cycle_(false),
scherkusd2c745b2014-09-04 05:03:40180 ended_(false),
yoichio863bebf2016-03-04 07:56:58181 should_notify_time_changed_(false),
tsunghungee562e92016-07-20 18:03:31182 overlay_enabled_(false),
183 decoder_requires_restart_for_overlay_(false),
[email protected]5badb082010-06-11 17:40:15184 client_(client),
srirama.m26f864d02015-07-14 05:21:46185 encrypted_client_(encrypted_client),
[email protected]baff4512011-10-19 18:21:07186 delegate_(delegate),
dalecurtisbb3eaac2016-01-27 21:10:25187 delegate_id_(0),
[email protected]d726eddc2013-07-02 22:25:55188 defer_load_cb_(params.defer_load_cb()),
dongseong.hwang0c4e9d82015-01-08 20:11:13189 context_3d_cb_(params.context_3d_cb()),
dalecurtis83266c72015-10-29 18:43:20190 adjust_allocated_memory_cb_(params.adjust_allocated_memory_cb()),
191 last_reported_memory_usage_(0),
[email protected]132dd57c2012-08-10 23:24:34192 supports_save_(true),
[email protected]f5443ef72013-04-22 04:03:38193 chunk_demuxer_(NULL),
hubbe5f0ad43b2015-12-14 20:57:26194 url_index_(url_index),
Bartosz Fabianowski85a823812015-04-16 10:27:51195 // Threaded compositing isn't enabled universally yet.
fdoraydb3ef7d2016-06-09 15:42:38196 compositor_task_runner_(params.compositor_task_runner()
197 ? params.compositor_task_runner()
198 : base::ThreadTaskRunnerHandle::Get()),
alokp5d86e9b2016-05-17 20:20:41199 compositor_(new VideoFrameCompositor(compositor_task_runner_)),
xhwang80739452016-01-13 00:48:00200 is_cdm_attached_(false),
hubbed5f36882016-01-15 22:40:37201#if defined(OS_ANDROID) // WMPI_CAST
dalecurtisbb3eaac2016-01-27 21:10:25202 cast_impl_(this, client_, params.context_3d_cb()),
hubbed5f36882016-01-15 22:40:37203#endif
dalecurtisbb3eaac2016-01-27 21:10:25204 volume_(1.0),
205 volume_multiplier_(1.0),
watkdee516f2016-02-18 02:22:19206 renderer_factory_(std::move(renderer_factory)),
dalecurtis2ff781da2016-03-03 01:52:13207 surface_manager_(params.surface_manager()),
tsunghungee562e92016-07-20 18:03:31208 overlay_surface_id_(SurfaceManager::kNoSurfaceID),
dalecurtis7f366b2242016-04-13 01:16:17209 suppress_destruction_errors_(false),
210 can_suspend_state_(CanSuspendState::UNKNOWN) {
dalecurtis83266c72015-10-29 18:43:20211 DCHECK(!adjust_allocated_memory_cb_.is_null());
xhwang59d4175a2016-01-14 03:19:30212 DCHECK(renderer_factory_);
servolkef1e5ef2016-03-25 04:55:26213 DCHECK(client_);
dalecurtis83266c72015-10-29 18:43:20214
tsunghungee562e92016-07-20 18:03:31215 force_video_overlays_ = base::CommandLine::ForCurrentProcess()->HasSwitch(
216 switches::kForceVideoOverlays);
217
dalecurtisbb3eaac2016-01-27 21:10:25218 if (delegate_)
219 delegate_id_ = delegate_->AddObserver(this);
sandersd1e49fb62015-12-12 01:18:06220
[email protected]c93eb0a62011-08-09 22:47:24221 media_log_->AddEvent(
acolwell9e0840d2014-09-06 19:01:32222 media_log_->CreateEvent(MediaLogEvent::WEBMEDIAPLAYER_CREATED));
[email protected]4e6be3f2009-05-07 02:24:44223
xhwang0ad11e512014-11-25 23:43:09224 if (params.initial_cdm()) {
xhwang9bd8c732015-04-13 23:27:53225 SetCdm(base::Bind(&IgnoreCdmAttached),
226 ToWebContentDecryptionModuleImpl(params.initial_cdm())
227 ->GetCdmContext());
xhwang0ad11e512014-11-25 23:43:09228 }
229
xhwangf94a634d2014-10-22 22:07:27230 // TODO(xhwang): When we use an external Renderer, many methods won't work,
xhwang6fa356202014-12-11 00:44:12231 // e.g. GetCurrentFrameFromCompositor(). See http://crbug.com/434861
[email protected]c50edb962013-10-19 18:05:07232
[email protected]ddbc6ff2013-04-19 15:28:33233 // Use the null sink if no sink was provided.
[email protected]4a914882013-01-10 00:43:48234 audio_source_provider_ = new WebAudioSourceProviderImpl(
[email protected]ff875be52013-06-02 23:47:38235 params.audio_renderer_sink().get()
236 ? params.audio_renderer_sink()
acolwell9e0840d2014-09-06 19:01:32237 : new NullAudioSink(media_task_runner_));
[email protected]ec9212f2008-12-18 21:40:36238}
239
[email protected]4e6be3f2009-05-07 02:24:44240WebMediaPlayerImpl::~WebMediaPlayerImpl() {
acolwellb4034942014-08-28 15:42:43241 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53242
alokp1116967f2016-06-11 17:30:56243 suppress_destruction_errors_ = true;
sandersd1e49fb62015-12-12 01:18:06244 if (delegate_) {
dalecurtisbb3eaac2016-01-27 21:10:25245 delegate_->PlayerGone(delegate_id_);
246 delegate_->RemoveObserver(delegate_id_);
sandersd1e49fb62015-12-12 01:18:06247 }
[email protected]baff4512011-10-19 18:21:07248
alokp967c902452016-05-06 05:21:37249 // Pipeline must be stopped before it is destroyed.
250 pipeline_.Stop();
[email protected]f6af7592014-02-28 10:09:11251
dalecurtis83266c72015-10-29 18:43:20252 if (last_reported_memory_usage_)
253 adjust_allocated_memory_cb_.Run(-last_reported_memory_usage_);
254
dalecurtise1edb312016-06-22 02:33:21255 // Destruct compositor resources in the proper order.
256 client_->setWebLayer(nullptr);
257 if (video_weblayer_)
258 static_cast<cc::VideoLayer*>(video_weblayer_->layer())->StopUsingProvider();
[email protected]dd061e12014-05-06 19:21:22259 compositor_task_runner_->DeleteSoon(FROM_HERE, compositor_);
xhwangea8bb3562015-06-08 21:18:37260
261 media_log_->AddEvent(
262 media_log_->CreateEvent(MediaLogEvent::WEBMEDIAPLAYER_DESTROYED));
[email protected]ec9212f2008-12-18 21:40:36263}
264
guidou9bfe4e2f2016-04-09 08:31:19265void WebMediaPlayerImpl::load(LoadType load_type,
266 const blink::WebMediaPlayerSource& source,
[email protected]62e5e682013-03-07 23:53:24267 CORSMode cors_mode) {
guidou9bfe4e2f2016-04-09 08:31:19268 // Only URL or MSE blob URL is supported.
269 DCHECK(source.isURL());
270 blink::WebURL url = source.getAsURL();
[email protected]2a06ca62014-06-04 13:59:52271 DVLOG(1) << __FUNCTION__ << "(" << load_type << ", " << url << ", "
272 << cors_mode << ")";
[email protected]d726eddc2013-07-02 22:25:55273 if (!defer_load_cb_.is_null()) {
274 defer_load_cb_.Run(base::Bind(
[email protected]ef8394c2013-08-21 20:26:30275 &WebMediaPlayerImpl::DoLoad, AsWeakPtr(), load_type, url, cors_mode));
[email protected]d726eddc2013-07-02 22:25:55276 return;
277 }
[email protected]ef8394c2013-08-21 20:26:30278 DoLoad(load_type, url, cors_mode);
[email protected]62e5e682013-03-07 23:53:24279}
280
watk9c87c6fa2016-05-06 20:36:51281bool WebMediaPlayerImpl::supportsOverlayFullscreenVideo() {
282#if defined(OS_ANDROID)
watkf835a792016-06-24 23:24:40283 return true;
watk9c87c6fa2016-05-06 20:36:51284#else
285 return false;
286#endif
287}
288
tsunghungee562e92016-07-20 18:03:31289void WebMediaPlayerImpl::EnableOverlay() {
290 overlay_enabled_ = true;
watkf835a792016-06-24 23:24:40291 if (surface_manager_) {
292 surface_created_cb_.Reset(
293 base::Bind(&WebMediaPlayerImpl::OnSurfaceCreated, AsWeakPtr()));
294 surface_manager_->CreateFullscreenSurface(pipeline_metadata_.natural_size,
295 surface_created_cb_.callback());
296 }
tsunghungee562e92016-07-20 18:03:31297
298 if (decoder_requires_restart_for_overlay_)
watkdee516f2016-02-18 02:22:19299 ScheduleRestart();
300}
301
tsunghungee562e92016-07-20 18:03:31302void WebMediaPlayerImpl::DisableOverlay() {
303 overlay_enabled_ = false;
watkf835a792016-06-24 23:24:40304 surface_created_cb_.Cancel();
tsunghungee562e92016-07-20 18:03:31305 overlay_surface_id_ = SurfaceManager::kNoSurfaceID;
306
307 if (decoder_requires_restart_for_overlay_)
watkdee516f2016-02-18 02:22:19308 ScheduleRestart();
309}
310
tsunghungee562e92016-07-20 18:03:31311void WebMediaPlayerImpl::enteredFullscreen() {
312 if (!force_video_overlays_)
313 EnableOverlay();
314}
315
316void WebMediaPlayerImpl::exitedFullscreen() {
317 if (!force_video_overlays_)
318 DisableOverlay();
319}
320
[email protected]ef8394c2013-08-21 20:26:30321void WebMediaPlayerImpl::DoLoad(LoadType load_type,
[email protected]180ef242013-11-07 06:50:46322 const blink::WebURL& url,
[email protected]d726eddc2013-07-02 22:25:55323 CORSMode cors_mode) {
hubbed82bed52015-12-15 23:07:16324 DVLOG(1) << __FUNCTION__;
acolwellb4034942014-08-28 15:42:43325 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d726eddc2013-07-02 22:25:55326
[email protected]62e5e682013-03-07 23:53:24327 GURL gurl(url);
xhwangbffbf452016-04-01 05:26:45328 ReportMetrics(load_type, gurl, frame_->getSecurityOrigin());
[email protected]62e5e682013-03-07 23:53:24329
[email protected]926f8fd2013-04-12 20:27:53330 // Set subresource URL for crash reporting.
331 base::debug::SetCrashKeyValue("subresource_url", gurl.spec());
332
[email protected]ef8394c2013-08-21 20:26:30333 load_type_ = load_type;
334
[email protected]62e5e682013-03-07 23:53:24335 SetNetworkState(WebMediaPlayer::NetworkStateLoading);
336 SetReadyState(WebMediaPlayer::ReadyStateHaveNothing);
kinukof19cde72015-12-18 23:15:25337 media_log_->AddEvent(media_log_->CreateLoadEvent(url.string().utf8()));
[email protected]d726eddc2013-07-02 22:25:55338
339 // Media source pipelines can start immediately.
[email protected]ef8394c2013-08-21 20:26:30340 if (load_type == LoadTypeMediaSource) {
[email protected]d726eddc2013-07-02 22:25:55341 supports_save_ = false;
[email protected]ef8394c2013-08-21 20:26:30342 StartPipeline();
hubbe5f0ad43b2015-12-14 20:57:26343 } else {
avayvode46d7bef2016-03-30 23:18:26344 // TODO(hubbe): This experiment is temporary and should be removed once
345 // we have enough data to support the primacy of the new media cache.
346 // See http://crbug.com/514719 for details.
347 // Otherwise it's a regular request which requires resolving the URL first.
348 if (base::FeatureList::IsEnabled(kUseNewMediaCache)) {
349 // Remove this when MultiBufferDataSource becomes default.
350 LOG(WARNING) << "Using MultibufferDataSource";
351 data_source_.reset(new MultibufferDataSource(
352 url, static_cast<UrlData::CORSMode>(cors_mode), main_task_runner_,
353 url_index_, frame_, media_log_.get(), &buffered_data_source_host_,
354 base::Bind(&WebMediaPlayerImpl::NotifyDownloading, AsWeakPtr())));
355 } else {
356 data_source_.reset(new BufferedDataSource(
357 url, static_cast<BufferedResourceLoader::CORSMode>(cors_mode),
358 main_task_runner_, frame_, media_log_.get(),
359 &buffered_data_source_host_,
360 base::Bind(&WebMediaPlayerImpl::NotifyDownloading, AsWeakPtr())));
361 }
362 data_source_->SetPreload(preload_);
363 data_source_->SetBufferingStrategy(buffering_strategy_);
364 data_source_->Initialize(
365 base::Bind(&WebMediaPlayerImpl::DataSourceInitialized, AsWeakPtr()));
hubbe5f0ad43b2015-12-14 20:57:26366 }
hubbed5f36882016-01-15 22:40:37367
368#if defined(OS_ANDROID) // WMPI_CAST
dalecurtisbb3eaac2016-01-27 21:10:25369 cast_impl_.Initialize(url, frame_, delegate_id_);
hubbed5f36882016-01-15 22:40:37370#endif
[email protected]62e5e682013-03-07 23:53:24371}
372
[email protected]4e6be3f2009-05-07 02:24:44373void WebMediaPlayerImpl::play() {
[email protected]2a06ca62014-06-04 13:59:52374 DVLOG(1) << __FUNCTION__;
acolwellb4034942014-08-28 15:42:43375 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53376
hubbed5f36882016-01-15 22:40:37377#if defined(OS_ANDROID) // WMPI_CAST
378 if (isRemote()) {
dalecurtis6e2716d2016-01-21 04:49:15379 cast_impl_.play();
hubbed5f36882016-01-15 22:40:37380 return;
381 }
382#endif
383
[email protected]49480902009-07-14 20:23:43384 paused_ = false;
sandersd50a635e2016-04-04 22:50:09385 is_idle_ = false;
yoichio863bebf2016-03-04 07:56:58386 pipeline_.SetPlaybackRate(playback_rate_);
sandersd1c0bba02016-03-04 23:14:08387
[email protected]039b7542013-10-17 22:06:25388 if (data_source_)
389 data_source_->MediaIsPlaying();
[email protected]090f7312011-08-05 23:26:40390
acolwell9e0840d2014-09-06 19:01:32391 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PLAY));
sandersd50a635e2016-04-04 22:50:09392 UpdatePlayState();
[email protected]ec9212f2008-12-18 21:40:36393}
394
[email protected]4e6be3f2009-05-07 02:24:44395void WebMediaPlayerImpl::pause() {
[email protected]2a06ca62014-06-04 13:59:52396 DVLOG(1) << __FUNCTION__;
acolwellb4034942014-08-28 15:42:43397 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53398
sandersd50a635e2016-04-04 22:50:09399 // We update the paused state even when casting, since we expect pause() to be
400 // called when casting begins, and when we exit casting we should end up in a
401 // paused state.
[email protected]49480902009-07-14 20:23:43402 paused_ = true;
hubbed5f36882016-01-15 22:40:37403
404#if defined(OS_ANDROID) // WMPI_CAST
405 if (isRemote()) {
dalecurtis6e2716d2016-01-21 04:49:15406 cast_impl_.pause();
hubbed5f36882016-01-15 22:40:37407 return;
408 }
409#endif
410
a.berwal338bf002015-04-22 11:14:50411 pipeline_.SetPlaybackRate(0.0);
sandersd1c0bba02016-03-04 23:14:08412
413 // pause() may be called after playback has ended and the HTMLMediaElement
414 // requires that currentTime() == duration() after ending. We want to ensure
415 // |paused_time_| matches currentTime() in this case or a future seek() may
416 // incorrectly discard what it thinks is a seek to the existing time.
417 paused_time_ =
418 ended_ ? pipeline_.GetMediaDuration() : pipeline_.GetMediaTime();
[email protected]090f7312011-08-05 23:26:40419
acolwell9e0840d2014-09-06 19:01:32420 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PAUSE));
sandersd50a635e2016-04-04 22:50:09421 UpdatePlayState();
[email protected]ec9212f2008-12-18 21:40:36422}
423
[email protected]574a1d62009-07-17 03:23:46424bool WebMediaPlayerImpl::supportsSave() const {
acolwellb4034942014-08-28 15:42:43425 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]132dd57c2012-08-10 23:24:34426 return supports_save_;
[email protected]574a1d62009-07-17 03:23:46427}
428
[email protected]39bdde32013-04-17 17:44:20429void WebMediaPlayerImpl::seek(double seconds) {
xhwang12d8d042014-12-01 21:48:57430 DVLOG(1) << __FUNCTION__ << "(" << seconds << "s)";
acolwellb4034942014-08-28 15:42:43431 DCHECK(main_task_runner_->BelongsToCurrentThread());
sandersd1c0bba02016-03-04 23:14:08432 DoSeek(base::TimeDelta::FromSecondsD(seconds), true);
433}
434
435void WebMediaPlayerImpl::DoSeek(base::TimeDelta time, bool time_updated) {
436 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53437
hubbed5f36882016-01-15 22:40:37438#if defined(OS_ANDROID) // WMPI_CAST
439 if (isRemote()) {
sandersd1c0bba02016-03-04 23:14:08440 cast_impl_.seek(time);
hubbed5f36882016-01-15 22:40:37441 return;
442 }
443#endif
444
srirama.mccf671812015-01-08 11:59:13445 ReadyState old_state = ready_state_;
[email protected]1bb666802013-11-28 06:12:08446 if (ready_state_ > WebMediaPlayer::ReadyStateHaveMetadata)
447 SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata);
448
sandersd1c0bba02016-03-04 23:14:08449 // When paused, we know exactly what the current time is and can elide seeks
450 // to it. However, there are two cases that are not elided:
451 // 1) When the pipeline state is not stable.
452 // In this case we just let |pipeline_controller_| decide what to do, as
453 // it has complete information.
454 // 2) For MSE.
455 // Because the buffers may have changed between seeks, MSE seeks are
456 // never elided.
457 if (paused_ && pipeline_controller_.IsStable() && paused_time_ == time &&
458 !chunk_demuxer_) {
459 // If the ready state was high enough before, we can indicate that the seek
460 // completed just by restoring it. Otherwise we will just wait for the real
461 // ready state change to eventually happen.
462 if (old_state == ReadyStateHaveEnoughData) {
srirama.m8f4a37562014-12-13 08:16:18463 main_task_runner_->PostTask(
alokp967c902452016-05-06 05:21:37464 FROM_HERE, base::Bind(&WebMediaPlayerImpl::OnBufferingStateChange,
465 AsWeakPtr(), BUFFERING_HAVE_ENOUGH));
srirama.m36ab2682014-12-11 04:20:01466 }
sandersd1c0bba02016-03-04 23:14:08467 return;
srirama.m36ab2682014-12-11 04:20:01468 }
[email protected]44ff37c02009-10-24 01:03:03469
sandersd50a635e2016-04-04 22:50:09470 // TODO(sandersd): Ideally we would not clear the idle state if
471 // |pipeline_controller_| can elide the seek.
472 is_idle_ = false;
473 ended_ = false;
474
[email protected]b3766a22010-12-22 17:34:13475 seeking_ = true;
sandersd1c0bba02016-03-04 23:14:08476 seek_time_ = time;
477 if (paused_)
478 paused_time_ = time;
479 pipeline_controller_.Seek(time, time_updated);
[email protected]b3766a22010-12-22 17:34:13480
sandersd50a635e2016-04-04 22:50:09481 // This needs to be called after Seek() so that if a resume is triggered, it
482 // is to the correct time.
483 UpdatePlayState();
[email protected]ec9212f2008-12-18 21:40:36484}
485
[email protected]39bdde32013-04-17 17:44:20486void WebMediaPlayerImpl::setRate(double rate) {
[email protected]2a06ca62014-06-04 13:59:52487 DVLOG(1) << __FUNCTION__ << "(" << rate << ")";
acolwellb4034942014-08-28 15:42:43488 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53489
[email protected]378f0b72009-08-11 17:11:42490 // TODO(kylep): Remove when support for negatives is added. Also, modify the
491 // following checks so rewind uses reasonable values also.
[email protected]39bdde32013-04-17 17:44:20492 if (rate < 0.0)
[email protected]378f0b72009-08-11 17:11:42493 return;
494
495 // Limit rates to reasonable values by clamping.
[email protected]39bdde32013-04-17 17:44:20496 if (rate != 0.0) {
[email protected]378f0b72009-08-11 17:11:42497 if (rate < kMinRate)
498 rate = kMinRate;
499 else if (rate > kMaxRate)
500 rate = kMaxRate;
501 }
502
[email protected]49480902009-07-14 20:23:43503 playback_rate_ = rate;
504 if (!paused_) {
[email protected]f6af7592014-02-28 10:09:11505 pipeline_.SetPlaybackRate(rate);
[email protected]039b7542013-10-17 22:06:25506 if (data_source_)
507 data_source_->MediaPlaybackRateChanged(rate);
[email protected]49480902009-07-14 20:23:43508 }
[email protected]ec9212f2008-12-18 21:40:36509}
510
[email protected]39bdde32013-04-17 17:44:20511void WebMediaPlayerImpl::setVolume(double volume) {
[email protected]2a06ca62014-06-04 13:59:52512 DVLOG(1) << __FUNCTION__ << "(" << volume << ")";
acolwellb4034942014-08-28 15:42:43513 DCHECK(main_task_runner_->BelongsToCurrentThread());
dalecurtisbb3eaac2016-01-27 21:10:25514 volume_ = volume;
515 pipeline_.SetVolume(volume_ * volume_multiplier_);
[email protected]ec9212f2008-12-18 21:40:36516}
[email protected]f0a51fb52009-03-05 12:46:38517
guidouc7babef2015-10-22 00:42:35518void WebMediaPlayerImpl::setSinkId(
519 const blink::WebString& sink_id,
520 const blink::WebSecurityOrigin& security_origin,
521 blink::WebSetSinkIdCallbacks* web_callback) {
guidou69223ce2015-06-16 10:36:19522 DCHECK(main_task_runner_->BelongsToCurrentThread());
guidou5754e612015-07-31 08:09:41523 DVLOG(1) << __FUNCTION__;
guidouc7babef2015-10-22 00:42:35524
olka68b69392016-04-01 11:42:12525 media::OutputDeviceStatusCB callback =
526 media::ConvertToOutputDeviceStatusCB(web_callback);
guidouc7babef2015-10-22 00:42:35527 media_task_runner_->PostTask(
528 FROM_HERE,
529 base::Bind(&SetSinkIdOnMediaThread, audio_source_provider_,
530 sink_id.utf8(), static_cast<url::Origin>(security_origin),
531 callback));
guidou69223ce2015-06-16 10:36:19532}
533
danakj365175c2016-02-06 00:37:37534STATIC_ASSERT_ENUM(WebMediaPlayer::PreloadNone, BufferedDataSource::NONE);
535STATIC_ASSERT_ENUM(WebMediaPlayer::PreloadMetaData,
536 BufferedDataSource::METADATA);
537STATIC_ASSERT_ENUM(WebMediaPlayer::PreloadAuto, BufferedDataSource::AUTO);
[email protected]23a8b1d82011-04-05 16:28:20538
[email protected]ef405f66b2012-04-18 02:39:55539void WebMediaPlayerImpl::setPreload(WebMediaPlayer::Preload preload) {
[email protected]2a06ca62014-06-04 13:59:52540 DVLOG(1) << __FUNCTION__ << "(" << preload << ")";
acolwellb4034942014-08-28 15:42:43541 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]4e6be3f2009-05-07 02:24:44542
acolwella5081a42014-08-28 23:42:52543 preload_ = static_cast<BufferedDataSource::Preload>(preload);
[email protected]b49beeb2013-03-01 20:04:00544 if (data_source_)
[email protected]09c60222014-08-07 16:42:31545 data_source_->SetPreload(preload_);
[email protected]4e6be3f2009-05-07 02:24:44546}
547
danakj365175c2016-02-06 00:37:37548STATIC_ASSERT_ENUM(WebMediaPlayer::BufferingStrategy::Normal,
549 BufferedDataSource::BUFFERING_STRATEGY_NORMAL);
550STATIC_ASSERT_ENUM(WebMediaPlayer::BufferingStrategy::Aggressive,
551 BufferedDataSource::BUFFERING_STRATEGY_AGGRESSIVE);
sandersdc6ab163a2015-12-12 03:56:13552
553void WebMediaPlayerImpl::setBufferingStrategy(
554 WebMediaPlayer::BufferingStrategy buffering_strategy) {
555 DVLOG(1) << __FUNCTION__;
556 DCHECK(main_task_runner_->BelongsToCurrentThread());
557
dalecurtis37fe5862016-03-15 19:29:09558#if defined(OS_ANDROID)
559 // We disallow aggressive buffering on Android since it matches the behavior
560 // of the platform media player and may have data usage penalties.
561 // TODO(dalecurtis, hubbe): We should probably stop using "pause-and-buffer"
562 // everywhere. See http://crbug.com/594669 for more details.
563 buffering_strategy_ = BufferedDataSource::BUFFERING_STRATEGY_NORMAL;
564#else
sandersdc6ab163a2015-12-12 03:56:13565 buffering_strategy_ =
566 static_cast<BufferedDataSource::BufferingStrategy>(buffering_strategy);
dalecurtis37fe5862016-03-15 19:29:09567#endif
568
sandersdc6ab163a2015-12-12 03:56:13569 if (data_source_)
570 data_source_->SetBufferingStrategy(buffering_strategy_);
571}
572
[email protected]4e6be3f2009-05-07 02:24:44573bool WebMediaPlayerImpl::hasVideo() const {
acolwellb4034942014-08-28 15:42:43574 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53575
[email protected]b8877772014-03-26 20:17:15576 return pipeline_metadata_.has_video;
[email protected]d43ed912009-02-03 04:52:53577}
578
[email protected]fc367af2009-08-14 23:06:35579bool WebMediaPlayerImpl::hasAudio() const {
acolwellb4034942014-08-28 15:42:43580 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]fc367af2009-08-14 23:06:35581
[email protected]b8877772014-03-26 20:17:15582 return pipeline_metadata_.has_audio;
[email protected]fc367af2009-08-14 23:06:35583}
584
servolkf25ceed2016-07-01 03:44:38585void WebMediaPlayerImpl::enabledAudioTracksChanged(
586 const blink::WebVector<blink::WebMediaPlayer::TrackId>& enabledTrackIds) {
587 DCHECK(main_task_runner_->BelongsToCurrentThread());
588
589 std::ostringstream logstr;
590 std::vector<MediaTrack::Id> enabledMediaTrackIds;
591 for (const auto& blinkTrackId : enabledTrackIds) {
592 MediaTrack::Id track_id = blinkTrackId.utf8().data();
593 logstr << track_id << " ";
594 enabledMediaTrackIds.push_back(track_id);
595 }
596 MEDIA_LOG(INFO, media_log_) << "Enabled audio tracks: [" << logstr.str()
597 << "]";
598 pipeline_.OnEnabledAudioTracksChanged(enabledMediaTrackIds);
599}
600
601void WebMediaPlayerImpl::selectedVideoTrackChanged(
602 blink::WebMediaPlayer::TrackId* selectedTrackId) {
603 DCHECK(main_task_runner_->BelongsToCurrentThread());
604
605 std::ostringstream logstr;
606 std::vector<MediaTrack::Id> selectedVideoMediaTrackId;
607 if (selectedTrackId) {
608 selectedVideoMediaTrackId.push_back(selectedTrackId->utf8().data());
609 logstr << selectedVideoMediaTrackId[0];
610 }
611 MEDIA_LOG(INFO, media_log_) << "Selected video track: [" << logstr.str()
612 << "]";
613 pipeline_.OnSelectedVideoTrackChanged(selectedVideoMediaTrackId);
614}
615
[email protected]180ef242013-11-07 06:50:46616blink::WebSize WebMediaPlayerImpl::naturalSize() const {
acolwellb4034942014-08-28 15:42:43617 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53618
[email protected]b8877772014-03-26 20:17:15619 return blink::WebSize(pipeline_metadata_.natural_size);
[email protected]d43ed912009-02-03 04:52:53620}
621
[email protected]4e6be3f2009-05-07 02:24:44622bool WebMediaPlayerImpl::paused() const {
acolwellb4034942014-08-28 15:42:43623 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53624
hubbed5f36882016-01-15 22:40:37625#if defined(OS_ANDROID) // WMPI_CAST
626 if (isRemote())
627 return cast_impl_.paused();
628#endif
sandersd50a635e2016-04-04 22:50:09629
[email protected]f6af7592014-02-28 10:09:11630 return pipeline_.GetPlaybackRate() == 0.0f;
[email protected]d43ed912009-02-03 04:52:53631}
632
[email protected]4e6be3f2009-05-07 02:24:44633bool WebMediaPlayerImpl::seeking() const {
acolwellb4034942014-08-28 15:42:43634 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53635
[email protected]ef405f66b2012-04-18 02:39:55636 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing)
[email protected]0acebfa2009-08-21 22:45:40637 return false;
[email protected]67cd5052009-09-10 21:53:22638
[email protected]b3766a22010-12-22 17:34:13639 return seeking_;
[email protected]ec9212f2008-12-18 21:40:36640}
641
[email protected]39bdde32013-04-17 17:44:20642double WebMediaPlayerImpl::duration() const {
acolwellb4034942014-08-28 15:42:43643 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]39bdde32013-04-17 17:44:20644
645 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing)
646 return std::numeric_limits<double>::quiet_NaN();
647
[email protected]39bdde32013-04-17 17:44:20648 return GetPipelineDuration();
[email protected]d43ed912009-02-03 04:52:53649}
650
[email protected]db66d0092014-04-16 07:15:12651double WebMediaPlayerImpl::timelineOffset() const {
acolwellb4034942014-08-28 15:42:43652 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]db66d0092014-04-16 07:15:12653
654 if (pipeline_metadata_.timeline_offset.is_null())
655 return std::numeric_limits<double>::quiet_NaN();
656
657 return pipeline_metadata_.timeline_offset.ToJsTime();
658}
659
[email protected]39bdde32013-04-17 17:44:20660double WebMediaPlayerImpl::currentTime() const {
acolwellb4034942014-08-28 15:42:43661 DCHECK(main_task_runner_->BelongsToCurrentThread());
scherkusd2c745b2014-09-04 05:03:40662 DCHECK_NE(ready_state_, WebMediaPlayer::ReadyStateHaveNothing);
663
664 // TODO(scherkus): Replace with an explicit ended signal to HTMLMediaElement,
665 // see http://crbug.com/409280
666 if (ended_)
667 return duration();
668
sandersd1c0bba02016-03-04 23:14:08669 if (seeking())
670 return seek_time_.InSecondsF();
wolenetz1b2ae7d2015-06-10 00:44:21671
hubbed5f36882016-01-15 22:40:37672#if defined(OS_ANDROID) // WMPI_CAST
sandersd1c0bba02016-03-04 23:14:08673 if (isRemote())
hubbed5f36882016-01-15 22:40:37674 return cast_impl_.currentTime();
hubbed5f36882016-01-15 22:40:37675#endif
676
sandersd1c0bba02016-03-04 23:14:08677 if (paused_)
hubbed5f36882016-01-15 22:40:37678 return paused_time_.InSecondsF();
hubbed5f36882016-01-15 22:40:37679
680 return pipeline_.GetMediaTime().InSecondsF();
[email protected]d43ed912009-02-03 04:52:53681}
682
danakj13afe0362016-02-27 01:22:50683WebMediaPlayer::NetworkState WebMediaPlayerImpl::getNetworkState() const {
acolwellb4034942014-08-28 15:42:43684 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]ddb1e5a2010-12-13 20:10:45685 return network_state_;
686}
687
danakj13afe0362016-02-27 01:22:50688WebMediaPlayer::ReadyState WebMediaPlayerImpl::getReadyState() const {
acolwellb4034942014-08-28 15:42:43689 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]ddb1e5a2010-12-13 20:10:45690 return ready_state_;
691}
692
wolenetz4d39cc02016-04-05 19:54:41693blink::WebString WebMediaPlayerImpl::getErrorMessage() {
694 DCHECK(main_task_runner_->BelongsToCurrentThread());
695 return blink::WebString::fromUTF8(media_log_->GetLastErrorMessage());
696}
697
[email protected]02022fc2014-05-16 00:05:31698blink::WebTimeRanges WebMediaPlayerImpl::buffered() const {
acolwellb4034942014-08-28 15:42:43699 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]779a8322014-08-22 21:28:37700
acolwell9e0840d2014-09-06 19:01:32701 Ranges<base::TimeDelta> buffered_time_ranges =
[email protected]02022fc2014-05-16 00:05:31702 pipeline_.GetBufferedTimeRanges();
[email protected]779a8322014-08-22 21:28:37703
704 const base::TimeDelta duration = pipeline_.GetMediaDuration();
dalecurtis39a7f932016-07-19 18:34:59705 if (duration != kInfiniteDuration) {
[email protected]779a8322014-08-22 21:28:37706 buffered_data_source_host_.AddBufferedTimeRanges(
707 &buffered_time_ranges, duration);
708 }
[email protected]02022fc2014-05-16 00:05:31709 return ConvertToWebTimeRanges(buffered_time_ranges);
710}
711
philipjb0e6f3f2014-09-30 09:51:53712blink::WebTimeRanges WebMediaPlayerImpl::seekable() const {
acolwellb4034942014-08-28 15:42:43713 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]39bdde32013-04-17 17:44:20714
dalecurtis56359cb2014-10-28 00:06:29715 if (ready_state_ < WebMediaPlayer::ReadyStateHaveMetadata)
philipjb0e6f3f2014-09-30 09:51:53716 return blink::WebTimeRanges();
717
dalecurtis56359cb2014-10-28 00:06:29718 const double seekable_end = duration();
719
720 // Allow a special exception for seeks to zero for streaming sources with a
721 // finite duration; this allows looping to work.
722 const bool allow_seek_to_zero = data_source_ && data_source_->IsStreaming() &&
mateuszs3371ab02015-04-24 13:20:23723 std::isfinite(seekable_end);
dalecurtis56359cb2014-10-28 00:06:29724
725 // TODO(dalecurtis): Technically this allows seeking on media which return an
726 // infinite duration so long as DataSource::IsStreaming() is false. While not
727 // expected, disabling this breaks semi-live players, http://crbug.com/427412.
728 const blink::WebTimeRange seekable_range(
729 0.0, allow_seek_to_zero ? 0.0 : seekable_end);
philipjb0e6f3f2014-09-30 09:51:53730 return blink::WebTimeRanges(&seekable_range, 1);
[email protected]ec9212f2008-12-18 21:40:36731}
732
[email protected]5d2b3e4c2014-05-12 23:27:30733bool WebMediaPlayerImpl::didLoadingProgress() {
acolwellb4034942014-08-28 15:42:43734 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]6683e1b2014-04-10 01:45:38735 bool pipeline_progress = pipeline_.DidLoadingProgress();
736 bool data_progress = buffered_data_source_host_.DidLoadingProgress();
737 return pipeline_progress || data_progress;
[email protected]d43ed912009-02-03 04:52:53738}
739
[email protected]dd5c7972014-08-21 15:00:37740void WebMediaPlayerImpl::paint(blink::WebCanvas* canvas,
741 const blink::WebRect& rect,
[email protected]dd5c7972014-08-21 15:00:37742 unsigned char alpha,
743 SkXfermode::Mode mode) {
acolwellb4034942014-08-28 15:42:43744 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]dd061e12014-05-06 19:21:22745 TRACE_EVENT0("media", "WebMediaPlayerImpl:paint");
[email protected]4e6be3f2009-05-07 02:24:44746
xhwang80739452016-01-13 00:48:00747 if (is_cdm_attached_)
748 return;
749
mcasasf1236fc22015-05-29 22:38:56750 scoped_refptr<VideoFrame> video_frame = GetCurrentFrameFromCompositor();
[email protected]0fe5d43b2014-01-24 23:32:45751
[email protected]b49beeb2013-03-01 20:04:00752 gfx::Rect gfx_rect(rect);
dongseong.hwang0c4e9d82015-01-08 20:11:13753 Context3D context_3d;
mcasas265bdbf82015-06-12 18:44:07754 if (video_frame.get() && video_frame->HasTextures()) {
mcasasf1236fc22015-05-29 22:38:56755 if (!context_3d_cb_.is_null())
dongseong.hwang0c4e9d82015-01-08 20:11:13756 context_3d = context_3d_cb_.Run();
dongseong.hwang0c4e9d82015-01-08 20:11:13757 if (!context_3d.gl)
danakj53f7ec902016-05-21 01:30:10758 return; // Unable to get/create a shared main thread context.
759 if (!context_3d.gr_context)
760 return; // The context has been lost since and can't setup a GrContext.
dongseong.hwang0c4e9d82015-01-08 20:11:13761 }
danakj795f1732015-08-31 23:40:22762 skcanvas_video_renderer_.Paint(video_frame, canvas, gfx::RectF(gfx_rect),
763 alpha, mode, pipeline_metadata_.video_rotation,
764 context_3d);
[email protected]ec9212f2008-12-18 21:40:36765}
[email protected]5df51652009-01-17 00:03:00766
[email protected]38259a7a82009-07-29 21:49:49767bool WebMediaPlayerImpl::hasSingleSecurityOrigin() const {
[email protected]b49beeb2013-03-01 20:04:00768 if (data_source_)
769 return data_source_->HasSingleOrigin();
[email protected]fcdb7462009-10-21 21:05:11770 return true;
[email protected]38259a7a82009-07-29 21:49:49771}
772
[email protected]3fe27112012-06-07 04:00:01773bool WebMediaPlayerImpl::didPassCORSAccessCheck() const {
[email protected]b49beeb2013-03-01 20:04:00774 if (data_source_)
775 return data_source_->DidPassCORSAccessCheck();
776 return false;
[email protected]3fe27112012-06-07 04:00:01777}
778
[email protected]39bdde32013-04-17 17:44:20779double WebMediaPlayerImpl::mediaTimeForTimeValue(double timeValue) const {
qinminb4c39782015-08-10 18:43:24780 return base::TimeDelta::FromSecondsD(timeValue).InSecondsF();
[email protected]e06e16d82011-05-26 22:13:33781}
782
[email protected]d82b18ae2011-03-23 21:28:59783unsigned WebMediaPlayerImpl::decodedFrameCount() const {
acolwellb4034942014-08-28 15:42:43784 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]4c51bc662011-02-16 02:03:16785
acolwell9e0840d2014-09-06 19:01:32786 PipelineStatistics stats = pipeline_.GetStatistics();
[email protected]4c51bc662011-02-16 02:03:16787 return stats.video_frames_decoded;
788}
789
[email protected]d82b18ae2011-03-23 21:28:59790unsigned WebMediaPlayerImpl::droppedFrameCount() const {
acolwellb4034942014-08-28 15:42:43791 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]4c51bc662011-02-16 02:03:16792
acolwell9e0840d2014-09-06 19:01:32793 PipelineStatistics stats = pipeline_.GetStatistics();
[email protected]dd061e12014-05-06 19:21:22794 return stats.video_frames_dropped;
[email protected]4c51bc662011-02-16 02:03:16795}
796
chakshu.a94326b72016-03-08 05:11:44797size_t WebMediaPlayerImpl::audioDecodedByteCount() const {
acolwellb4034942014-08-28 15:42:43798 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]4c51bc662011-02-16 02:03:16799
acolwell9e0840d2014-09-06 19:01:32800 PipelineStatistics stats = pipeline_.GetStatistics();
[email protected]4c51bc662011-02-16 02:03:16801 return stats.audio_bytes_decoded;
802}
803
chakshu.a94326b72016-03-08 05:11:44804size_t WebMediaPlayerImpl::videoDecodedByteCount() const {
acolwellb4034942014-08-28 15:42:43805 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]4c51bc662011-02-16 02:03:16806
acolwell9e0840d2014-09-06 19:01:32807 PipelineStatistics stats = pipeline_.GetStatistics();
[email protected]4c51bc662011-02-16 02:03:16808 return stats.video_bytes_decoded;
809}
810
[email protected]6523b242013-03-13 11:10:07811bool WebMediaPlayerImpl::copyVideoTextureToPlatformTexture(
danakj46070b02016-03-28 21:54:11812 gpu::gles2::GLES2Interface* gl,
zmo57d577a2015-10-30 18:28:59813 unsigned int texture,
814 unsigned int internal_format,
815 unsigned int type,
816 bool premultiply_alpha,
817 bool flip_y) {
[email protected]bfc05f22013-10-19 17:55:16818 TRACE_EVENT0("media", "WebMediaPlayerImpl:copyVideoTextureToPlatformTexture");
819
mcasasf1236fc22015-05-29 22:38:56820 scoped_refptr<VideoFrame> video_frame = GetCurrentFrameFromCompositor();
[email protected]dd061e12014-05-06 19:21:22821
jbauman581d041c2016-07-21 01:01:03822 if (!video_frame.get() || !video_frame->HasTextures()) {
[email protected]e56f88c72013-06-25 22:31:29823 return false;
dongseong.hwang0c4e9d82015-01-08 20:11:13824 }
[email protected]df41e252014-02-03 23:39:50825
jbauman581d041c2016-07-21 01:01:03826 Context3D context_3d;
827 if (!context_3d_cb_.is_null())
828 context_3d = context_3d_cb_.Run();
829 return skcanvas_video_renderer_.CopyVideoFrameTexturesToGLTexture(
830 context_3d, gl, video_frame.get(), texture, internal_format, type,
831 premultiply_alpha, flip_y);
[email protected]6523b242013-03-13 11:10:07832}
833
[email protected]7bce1832014-01-09 00:01:22834void WebMediaPlayerImpl::setContentDecryptionModule(
[email protected]9ebc3b03f2014-08-13 04:01:23835 blink::WebContentDecryptionModule* cdm,
836 blink::WebContentDecryptionModuleResult result) {
acolwellb4034942014-08-28 15:42:43837 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]9ebc3b03f2014-08-13 04:01:23838
jrummell06f27072015-06-08 18:12:38839 // Once the CDM is set it can't be cleared as there may be frames being
840 // decrypted on other threads. So fail this request.
841 // http://crbug.com/462365#c7.
xhwang97de4202014-11-25 08:44:01842 if (!cdm) {
843 result.completeWithError(
jrummell06f27072015-06-08 18:12:38844 blink::WebContentDecryptionModuleExceptionInvalidStateError, 0,
845 "The existing MediaKeys object cannot be removed at this time.");
xhwang97de4202014-11-25 08:44:01846 return;
847 }
848
jrummell89e61d82015-07-23 20:03:34849 // Create a local copy of |result| to avoid problems with the callback
850 // getting passed to the media thread and causing |result| to be destructed
jrummell4acbec912016-02-27 02:45:03851 // on the wrong thread in some failure conditions. Blink should prevent
852 // multiple simultaneous calls.
853 DCHECK(!set_cdm_result_);
jrummell89e61d82015-07-23 20:03:34854 set_cdm_result_.reset(new blink::WebContentDecryptionModuleResult(result));
855
856 SetCdm(BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnCdmAttached),
xhwang9bd8c732015-04-13 23:27:53857 ToWebContentDecryptionModuleImpl(cdm)->GetCdmContext());
xhwang97de4202014-11-25 08:44:01858}
859
xhwange8c4181a2014-12-06 08:10:01860void WebMediaPlayerImpl::OnEncryptedMediaInitData(
jrummellcf78967c2015-04-03 05:03:58861 EmeInitDataType init_data_type,
Avi Drissman97785ea2015-12-19 01:11:31862 const std::vector<uint8_t>& init_data) {
jrummellcf78967c2015-04-03 05:03:58863 DCHECK(init_data_type != EmeInitDataType::UNKNOWN);
xhwangbab66f52014-12-02 23:49:50864
ddorwin301ccdb2016-02-25 02:39:17865 // TODO(xhwang): Update this UMA name. https://crbug.com/589251
xhwangbab66f52014-12-02 23:49:50866 UMA_HISTOGRAM_COUNTS("Media.EME.NeedKey", 1);
867
srirama.m26f864d02015-07-14 05:21:46868 encrypted_client_->encrypted(
davidbenb50f00c2015-12-01 00:01:50869 ConvertToWebInitDataType(init_data_type), init_data.data(),
srirama.m26f864d02015-07-14 05:21:46870 base::saturated_cast<unsigned int>(init_data.size()));
xhwangbab66f52014-12-02 23:49:50871}
872
servolk81e01e02016-03-05 03:29:15873void WebMediaPlayerImpl::OnFFmpegMediaTracksUpdated(
dcheng3076abbf2016-04-22 20:42:39874 std::unique_ptr<MediaTracks> tracks) {
servolk81e01e02016-03-05 03:29:15875 // For MSE/chunk_demuxer case the media track updates are handled by
876 // WebSourceBufferImpl.
877 DCHECK(demuxer_.get());
878 DCHECK(!chunk_demuxer_);
servolkef1e5ef2016-03-25 04:55:26879
880 // Report the media track information to blink.
881 for (const auto& track : tracks->tracks()) {
882 if (track->type() == MediaTrack::Audio) {
servolkfa5c37c2016-06-16 17:56:47883 client_->addAudioTrack(blink::WebString::fromUTF8(track->id()),
884 blink::WebMediaPlayerClient::AudioTrackKindMain,
885 blink::WebString::fromUTF8(track->label()),
886 blink::WebString::fromUTF8(track->language()),
887 /*enabled*/ true);
servolkef1e5ef2016-03-25 04:55:26888 } else if (track->type() == MediaTrack::Video) {
servolkfa5c37c2016-06-16 17:56:47889 client_->addVideoTrack(blink::WebString::fromUTF8(track->id()),
890 blink::WebMediaPlayerClient::VideoTrackKindMain,
891 blink::WebString::fromUTF8(track->label()),
892 blink::WebString::fromUTF8(track->language()),
893 /*selected*/ true);
servolkef1e5ef2016-03-25 04:55:26894 } else {
895 // Text tracks are not supported through this code path yet.
896 NOTREACHED();
897 }
898 }
servolk81e01e02016-03-05 03:29:15899}
900
xhwang9bd8c732015-04-13 23:27:53901void WebMediaPlayerImpl::SetCdm(const CdmAttachedCB& cdm_attached_cb,
902 CdmContext* cdm_context) {
xhwang80739452016-01-13 00:48:00903 if (!cdm_context) {
904 cdm_attached_cb.Run(false);
905 return;
906 }
907
jrummell87a2db52015-05-05 22:27:18908 // If CDM initialization succeeded, tell the pipeline about it.
xhwang80739452016-01-13 00:48:00909 pipeline_.SetCdm(cdm_context, cdm_attached_cb);
xhwang97de4202014-11-25 08:44:01910}
911
jrummell89e61d82015-07-23 20:03:34912void WebMediaPlayerImpl::OnCdmAttached(bool success) {
xhwang97de4202014-11-25 08:44:01913 if (success) {
jrummell89e61d82015-07-23 20:03:34914 set_cdm_result_->complete();
915 set_cdm_result_.reset();
xhwang80739452016-01-13 00:48:00916 is_cdm_attached_ = true;
xhwang97de4202014-11-25 08:44:01917 return;
918 }
919
jrummell89e61d82015-07-23 20:03:34920 set_cdm_result_->completeWithError(
xhwang97de4202014-11-25 08:44:01921 blink::WebContentDecryptionModuleExceptionNotSupportedError, 0,
922 "Unable to set MediaKeys object");
jrummell89e61d82015-07-23 20:03:34923 set_cdm_result_.reset();
[email protected]9ebc3b03f2014-08-13 04:01:23924}
925
sandersd1c0bba02016-03-04 23:14:08926void WebMediaPlayerImpl::OnPipelineSeeked(bool time_updated) {
[email protected]5d11eff2011-09-15 00:06:06927 seeking_ = false;
wolenetz1b2ae7d2015-06-10 00:44:21928 seek_time_ = base::TimeDelta();
hubbe5a2dec022016-03-17 01:14:23929 if (paused_) {
930#if defined(OS_ANDROID) // WMPI_CAST
931 if (isRemote()) {
932 paused_time_ = base::TimeDelta::FromSecondsD(cast_impl_.currentTime());
933 } else {
934 paused_time_ = pipeline_.GetMediaTime();
935 }
936#else
sandersd1c0bba02016-03-04 23:14:08937 paused_time_ = pipeline_.GetMediaTime();
hubbe5a2dec022016-03-17 01:14:23938#endif
939 }
sandersd1c0bba02016-03-04 23:14:08940 if (time_updated)
941 should_notify_time_changed_ = true;
[email protected]8931c41a2009-07-07 17:31:49942}
943
sandersd1c0bba02016-03-04 23:14:08944void WebMediaPlayerImpl::OnPipelineSuspended() {
hubbed5f36882016-01-15 22:40:37945#if defined(OS_ANDROID)
946 if (isRemote()) {
947 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner();
sandersd50a635e2016-04-04 22:50:09948 if (frame)
dalecurtise9c89e92016-05-20 19:38:00949 compositor_->PaintSingleFrame(frame);
hubbed5f36882016-01-15 22:40:37950 }
951#endif
952
dalecurtis37fe5862016-03-15 19:29:09953 // If we're not in an aggressive buffering state, tell the data source we have
954 // enough data so that it may release the connection.
955 if (buffering_strategy_ !=
956 BufferedDataSource::BUFFERING_STRATEGY_AGGRESSIVE) {
liberato3f9f32b2016-03-16 16:54:51957 if (data_source_)
958 data_source_->OnBufferingHaveEnough(true);
dalecurtis37fe5862016-03-15 19:29:09959 }
960
sandersd50a635e2016-04-04 22:50:09961 ReportMemoryUsage();
962
sandersd1c0bba02016-03-04 23:14:08963 if (pending_suspend_resume_cycle_) {
watkdee516f2016-02-18 02:22:19964 pending_suspend_resume_cycle_ = false;
sandersd50a635e2016-04-04 22:50:09965 UpdatePlayState();
dalecurtis0431cbf2016-03-12 01:19:43966 }
sandersd1c0bba02016-03-04 23:14:08967}
968
alokp967c902452016-05-06 05:21:37969void WebMediaPlayerImpl::OnDemuxerOpened() {
970 DCHECK(main_task_runner_->BelongsToCurrentThread());
971 client_->mediaSourceOpened(
972 new WebMediaSourceImpl(chunk_demuxer_, media_log_));
973}
974
975void WebMediaPlayerImpl::OnError(PipelineStatus status) {
976 DVLOG(1) << __FUNCTION__;
977 DCHECK(main_task_runner_->BelongsToCurrentThread());
978 DCHECK_NE(status, PIPELINE_OK);
979
980 if (suppress_destruction_errors_)
981 return;
982
983 ReportPipelineError(load_type_, frame_->getSecurityOrigin(), status);
984 media_log_->AddEvent(media_log_->CreatePipelineErrorEvent(status));
985
986 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing) {
987 // Any error that occurs before reaching ReadyStateHaveMetadata should
988 // be considered a format error.
989 SetNetworkState(WebMediaPlayer::NetworkStateFormatError);
990 } else {
991 SetNetworkState(PipelineErrorToNetworkState(status));
992 }
993
994 UpdatePlayState();
995}
996
997void WebMediaPlayerImpl::OnEnded() {
[email protected]2a06ca62014-06-04 13:59:52998 DVLOG(1) << __FUNCTION__;
acolwellb4034942014-08-28 15:42:43999 DCHECK(main_task_runner_->BelongsToCurrentThread());
scherkusd2c745b2014-09-04 05:03:401000
sandersd1c0bba02016-03-04 23:14:081001 // Ignore state changes until we've completed all outstanding operations.
1002 if (!pipeline_controller_.IsStable())
scherkusd2c745b2014-09-04 05:03:401003 return;
1004
1005 ended_ = true;
[email protected]ce70c982013-12-20 17:04:321006 client_->timeChanged();
sandersd50a635e2016-04-04 22:50:091007
1008 // We don't actually want this to run until |client_| calls seek() or pause(),
1009 // but that should have already happened in timeChanged() and so this is
1010 // expected to be a no-op.
1011 UpdatePlayState();
[email protected]576537842009-08-12 23:52:051012}
1013
alokp967c902452016-05-06 05:21:371014void WebMediaPlayerImpl::OnMetadata(PipelineMetadata metadata) {
hubbed82bed52015-12-15 23:07:161015 DVLOG(1) << __FUNCTION__;
acolwellb4034942014-08-28 15:42:431016 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]a8e2cb82012-08-17 00:02:391017
[email protected]b8877772014-03-26 20:17:151018 pipeline_metadata_ = metadata;
[email protected]739847c02014-01-16 00:12:251019
dalecurtis849cf4b22015-03-27 18:35:451020 UMA_HISTOGRAM_ENUMERATION("Media.VideoRotation", metadata.video_rotation,
acolwell9e0840d2014-09-06 19:01:321021 VIDEO_ROTATION_MAX + 1);
[email protected]b8877772014-03-26 20:17:151022 SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata);
[email protected]21c3f7502013-03-23 03:29:511023
[email protected]b8877772014-03-26 20:17:151024 if (hasVideo()) {
acolwell9e0840d2014-09-06 19:01:321025 if (pipeline_metadata_.video_rotation == VIDEO_ROTATION_90 ||
1026 pipeline_metadata_.video_rotation == VIDEO_ROTATION_270) {
[email protected]f78c3e82014-08-08 01:24:471027 gfx::Size size = pipeline_metadata_.natural_size;
1028 pipeline_metadata_.natural_size = gfx::Size(size.height(), size.width());
1029 }
1030
tsunghungee562e92016-07-20 18:03:311031 if (overlay_enabled_ && surface_manager_)
watkf835a792016-06-24 23:24:401032 surface_manager_->NaturalSizeChanged(pipeline_metadata_.natural_size);
1033
1034 DCHECK(!video_weblayer_);
dalecurtise1edb312016-06-22 02:33:211035 video_weblayer_.reset(new cc_blink::WebLayerImpl(cc::VideoLayer::Create(
1036 compositor_, pipeline_metadata_.video_rotation)));
jbauman952274d2015-09-10 23:23:361037 video_weblayer_->layer()->SetContentsOpaque(opaque_);
1038 video_weblayer_->SetContentsOpaqueIsFixed(true);
[email protected]a7c4f582014-04-16 18:44:491039 client_->setWebLayer(video_weblayer_.get());
[email protected]a8e2cb82012-08-17 00:02:391040 }
dalecurtis8e4dc682016-03-15 02:30:301041
sandersd50a635e2016-04-04 22:50:091042 UpdatePlayState();
[email protected]a8e2cb82012-08-17 00:02:391043}
1044
alokp967c902452016-05-06 05:21:371045void WebMediaPlayerImpl::OnBufferingStateChange(BufferingState state) {
1046 DVLOG(1) << __FUNCTION__ << "(" << state << ")";
1047 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]b8877772014-03-26 20:17:151048
sandersd1c0bba02016-03-04 23:14:081049 // Ignore buffering state changes until we've completed all outstanding
1050 // operations.
1051 if (!pipeline_controller_.IsStable())
[email protected]ba7d5f92014-06-24 05:37:401052 return;
[email protected]b8877772014-03-26 20:17:151053
chcunninghameb270c92016-07-15 01:00:451054 if (state == BUFFERING_HAVE_ENOUGH) {
1055 // TODO(chcunningham): Monitor playback position vs buffered. Potentially
1056 // transition to HAVE_FUTURE_DATA here if not enough is buffered.
1057 SetReadyState(WebMediaPlayer::ReadyStateHaveEnoughData);
[email protected]ba7d5f92014-06-24 05:37:401058
chcunninghameb270c92016-07-15 01:00:451059 // Let the DataSource know we have enough data. It may use this information
1060 // to release unused network connections.
1061 if (data_source_)
1062 data_source_->OnBufferingHaveEnough(false);
dalecurtis849cf4b22015-03-27 18:35:451063
chcunninghameb270c92016-07-15 01:00:451064 // Blink expects a timeChanged() in response to a seek().
1065 if (should_notify_time_changed_)
1066 client_->timeChanged();
dalecurtis0f0097a2015-12-01 17:40:471067
chcunninghameb270c92016-07-15 01:00:451068 // Once we have enough, start reporting the total memory usage. We'll also
1069 // report once playback starts.
1070 ReportMemoryUsage();
1071 } else {
1072 // Buffering has underflowed.
1073 DCHECK_EQ(state, BUFFERING_HAVE_NOTHING);
1074 // It shouldn't be possible to underflow if we've not advanced past
1075 // HAVE_CURRENT_DATA.
1076 DCHECK_GT(highest_ready_state_, WebMediaPlayer::ReadyStateHaveCurrentData);
1077 SetReadyState(WebMediaPlayer::ReadyStateHaveCurrentData);
1078 }
sandersd50a635e2016-04-04 22:50:091079
1080 UpdatePlayState();
[email protected]b8877772014-03-26 20:17:151081}
1082
alokp967c902452016-05-06 05:21:371083void WebMediaPlayerImpl::OnDurationChange() {
acolwellb4034942014-08-28 15:42:431084 DCHECK(main_task_runner_->BelongsToCurrentThread());
alokp967c902452016-05-06 05:21:371085
1086 // TODO(sandersd): We should call delegate_->DidPlay() with the new duration,
1087 // especially if it changed from <5s to >5s.
1088 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing)
1089 return;
1090
1091 client_->durationChanged();
[email protected]81bb3322011-07-21 15:55:501092}
1093
alokp967c902452016-05-06 05:21:371094void WebMediaPlayerImpl::OnAddTextTrack(const TextTrackConfig& config,
1095 const AddTextTrackDoneCB& done_cb) {
acolwellb4034942014-08-28 15:42:431096 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]71537722013-05-23 06:47:531097
[email protected]8a561062013-11-22 01:19:311098 const WebInbandTextTrackImpl::Kind web_kind =
1099 static_cast<WebInbandTextTrackImpl::Kind>(config.kind());
1100 const blink::WebString web_label =
1101 blink::WebString::fromUTF8(config.label());
1102 const blink::WebString web_language =
1103 blink::WebString::fromUTF8(config.language());
[email protected]427ff102013-11-26 23:45:401104 const blink::WebString web_id =
1105 blink::WebString::fromUTF8(config.id());
[email protected]71537722013-05-23 06:47:531106
dcheng3076abbf2016-04-22 20:42:391107 std::unique_ptr<WebInbandTextTrackImpl> web_inband_text_track(
henriks9cce5fa2014-12-12 09:35:301108 new WebInbandTextTrackImpl(web_kind, web_label, web_language, web_id));
[email protected]8a561062013-11-22 01:19:311109
dcheng3076abbf2016-04-22 20:42:391110 std::unique_ptr<media::TextTrack> text_track(new TextTrackImpl(
dcheng652f5ff2015-12-27 08:54:001111 main_task_runner_, client_, std::move(web_inband_text_track)));
[email protected]8a561062013-11-22 01:19:311112
dcheng652f5ff2015-12-27 08:54:001113 done_cb.Run(std::move(text_track));
[email protected]71537722013-05-23 06:47:531114}
1115
alokp967c902452016-05-06 05:21:371116void WebMediaPlayerImpl::OnWaitingForDecryptionKey() {
1117 DCHECK(main_task_runner_->BelongsToCurrentThread());
1118
1119 encrypted_client_->didBlockPlaybackWaitingForKey();
1120 // TODO(jrummell): didResumePlaybackBlockedForKey() should only be called
1121 // when a key has been successfully added (e.g. OnSessionKeysChange() with
1122 // |has_additional_usable_key| = true). http://crbug.com/461903
1123 encrypted_client_->didResumePlaybackBlockedForKey();
1124}
1125
alokp5d86e9b2016-05-17 20:20:411126void WebMediaPlayerImpl::OnVideoNaturalSizeChange(const gfx::Size& size) {
1127 DCHECK(main_task_runner_->BelongsToCurrentThread());
1128 DCHECK_NE(ready_state_, WebMediaPlayer::ReadyStateHaveNothing);
1129
1130 if (size == pipeline_metadata_.natural_size)
1131 return;
1132
1133 TRACE_EVENT0("media", "WebMediaPlayerImpl::OnNaturalSizeChanged");
1134 media_log_->AddEvent(
1135 media_log_->CreateVideoSizeSetEvent(size.width(), size.height()));
1136
tsunghungee562e92016-07-20 18:03:311137 if (overlay_enabled_ && surface_manager_)
alokp5d86e9b2016-05-17 20:20:411138 surface_manager_->NaturalSizeChanged(size);
1139
1140 pipeline_metadata_.natural_size = size;
1141 client_->sizeChanged();
1142}
1143
1144void WebMediaPlayerImpl::OnVideoOpacityChange(bool opaque) {
1145 DCHECK(main_task_runner_->BelongsToCurrentThread());
1146 DCHECK_NE(ready_state_, WebMediaPlayer::ReadyStateHaveNothing);
1147
1148 opaque_ = opaque;
1149 // Modify content opaqueness of cc::Layer directly so that
1150 // SetContentsOpaqueIsFixed is ignored.
1151 if (video_weblayer_)
1152 video_weblayer_->layer()->SetContentsOpaque(opaque_);
1153}
1154
dalecurtis0431cbf2016-03-12 01:19:431155void WebMediaPlayerImpl::OnHidden() {
sandersd1e49fb62015-12-12 01:18:061156 DCHECK(main_task_runner_->BelongsToCurrentThread());
sandersd50a635e2016-04-04 22:50:091157 UpdatePlayState();
dalecurtis8b8505e72016-06-10 21:59:171158
1159 // Schedule suspended playing media to be paused if the user doesn't come back
1160 // to it within some timeout period to avoid any autoplay surprises.
1161 ScheduleIdlePauseTimer();
sandersd1e49fb62015-12-12 01:18:061162}
1163
1164void WebMediaPlayerImpl::OnShown() {
1165 DCHECK(main_task_runner_->BelongsToCurrentThread());
sandersd50a635e2016-04-04 22:50:091166 must_suspend_ = false;
dalecurtis8b8505e72016-06-10 21:59:171167 background_pause_timer_.Stop();
sandersd50a635e2016-04-04 22:50:091168 UpdatePlayState();
sandersd1e49fb62015-12-12 01:18:061169}
1170
dalecurtis0431cbf2016-03-12 01:19:431171void WebMediaPlayerImpl::OnSuspendRequested(bool must_suspend) {
1172 DCHECK(main_task_runner_->BelongsToCurrentThread());
1173
sandersd50a635e2016-04-04 22:50:091174 if (must_suspend) {
1175 must_suspend_ = true;
1176 } else {
watk81727bf2016-04-12 00:25:131177 // TODO(sandersd): Remove this when idleness is separate from play state.
1178 if (delegate_state_ == DelegateState::PAUSED_BUT_NOT_IDLE)
sandersd5ea2ba4c2016-04-05 22:40:561179 return;
sandersd50a635e2016-04-04 22:50:091180 is_idle_ = true;
1181 }
1182
1183 UpdatePlayState();
dalecurtis0431cbf2016-03-12 01:19:431184}
1185
dalecurtisbb3eaac2016-01-27 21:10:251186void WebMediaPlayerImpl::OnPlay() {
1187 play();
1188 client_->playbackStateChanged();
1189}
1190
1191void WebMediaPlayerImpl::OnPause() {
1192 pause();
1193 client_->playbackStateChanged();
1194}
1195
1196void WebMediaPlayerImpl::OnVolumeMultiplierUpdate(double multiplier) {
1197 volume_multiplier_ = multiplier;
1198 setVolume(volume_);
1199}
1200
watkdee516f2016-02-18 02:22:191201void WebMediaPlayerImpl::ScheduleRestart() {
sandersd50a635e2016-04-04 22:50:091202 // TODO(watk): All restart logic should be moved into PipelineController.
1203 if (pipeline_.IsRunning() && !pipeline_controller_.IsPipelineSuspended()) {
watkdee516f2016-02-18 02:22:191204 pending_suspend_resume_cycle_ = true;
sandersd50a635e2016-04-04 22:50:091205 UpdatePlayState();
watkdee516f2016-02-18 02:22:191206 }
1207}
1208
hubbed5f36882016-01-15 22:40:371209#if defined(OS_ANDROID) // WMPI_CAST
hubbed5f36882016-01-15 22:40:371210bool WebMediaPlayerImpl::isRemote() const {
1211 return cast_impl_.isRemote();
1212}
1213
1214void WebMediaPlayerImpl::SetMediaPlayerManager(
1215 RendererMediaPlayerManagerInterface* media_player_manager) {
1216 cast_impl_.SetMediaPlayerManager(media_player_manager);
1217}
1218
1219void WebMediaPlayerImpl::requestRemotePlayback() {
1220 cast_impl_.requestRemotePlayback();
1221}
1222
1223void WebMediaPlayerImpl::requestRemotePlaybackControl() {
1224 cast_impl_.requestRemotePlaybackControl();
1225}
1226
1227void WebMediaPlayerImpl::OnRemotePlaybackEnded() {
1228 DVLOG(1) << __FUNCTION__;
1229 DCHECK(main_task_runner_->BelongsToCurrentThread());
1230
1231 ended_ = true;
1232 client_->timeChanged();
1233}
1234
1235void WebMediaPlayerImpl::OnDisconnectedFromRemoteDevice(double t) {
sandersd1c0bba02016-03-04 23:14:081236 DoSeek(base::TimeDelta::FromSecondsD(t), false);
hubbed5f36882016-01-15 22:40:371237
hubbed5f36882016-01-15 22:40:371238 // We already told the delegate we're paused when remoting started.
1239 client_->playbackStateChanged();
1240 client_->disconnectedFromRemoteDevice();
sandersd50a635e2016-04-04 22:50:091241
1242 UpdatePlayState();
hubbed5f36882016-01-15 22:40:371243}
1244
1245void WebMediaPlayerImpl::SuspendForRemote() {
sandersd50a635e2016-04-04 22:50:091246 if (pipeline_controller_.IsPipelineSuspended()) {
hubbed5f36882016-01-15 22:40:371247 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner();
sandersd50a635e2016-04-04 22:50:091248 if (frame)
dalecurtise9c89e92016-05-20 19:38:001249 compositor_->PaintSingleFrame(frame);
hubbed5f36882016-01-15 22:40:371250 }
sandersd50a635e2016-04-04 22:50:091251
1252 UpdatePlayState();
hubbed5f36882016-01-15 22:40:371253}
1254
1255gfx::Size WebMediaPlayerImpl::GetCanvasSize() const {
1256 if (!video_weblayer_)
1257 return pipeline_metadata_.natural_size;
1258
1259 return video_weblayer_->bounds();
1260}
1261
1262void WebMediaPlayerImpl::SetDeviceScaleFactor(float scale_factor) {
1263 cast_impl_.SetDeviceScaleFactor(scale_factor);
1264}
hubbee4027f92016-05-19 05:18:131265
1266void WebMediaPlayerImpl::setPoster(const blink::WebURL& poster) {
1267 cast_impl_.setPoster(poster);
1268}
hubbed5f36882016-01-15 22:40:371269#endif // defined(OS_ANDROID) // WMPI_CAST
1270
[email protected]fee8a902014-06-03 13:43:361271void WebMediaPlayerImpl::DataSourceInitialized(bool success) {
hubbed82bed52015-12-15 23:07:161272 DVLOG(1) << __FUNCTION__;
acolwellb4034942014-08-28 15:42:431273 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]a9415292012-01-19 19:55:201274
dalecurtisea27a3ed2016-06-24 01:41:301275#if defined(OS_ANDROID)
1276 // We can't play HLS URLs with WebMediaPlayerImpl, so in cases where they are
1277 // encountered, instruct the HTML media element to create a new WebMediaPlayer
1278 // instance with the correct URL to trigger WebMediaPlayerAndroid creation.
1279 //
1280 // TODO(tguilbert): Remove this code path once we have the ability to host a
1281 // MediaPlayer within a Mojo media renderer. http://crbug.com/580626
1282 if (data_source_) {
1283 const GURL url_after_redirects = data_source_->GetUrlAfterRedirects();
1284 if (MediaCodecUtil::IsHLSPath(url_after_redirects)) {
1285 client_->requestReload(url_after_redirects);
1286 // |this| may be destructed, do nothing after this.
1287 return;
1288 }
1289 }
1290#endif
1291
[email protected]d250190da3b2012-07-23 22:57:301292 if (!success) {
[email protected]ef405f66b2012-04-18 02:39:551293 SetNetworkState(WebMediaPlayer::NetworkStateFormatError);
sandersd50a635e2016-04-04 22:50:091294
1295 // Not really necessary, since the pipeline was never started, but it at
1296 // least this makes sure that the error handling code is in sync.
1297 UpdatePlayState();
1298
[email protected]a9415292012-01-19 19:55:201299 return;
1300 }
1301
[email protected]ef8394c2013-08-21 20:26:301302 StartPipeline();
[email protected]a9415292012-01-19 19:55:201303}
1304
[email protected]122f40252012-06-12 05:01:561305void WebMediaPlayerImpl::NotifyDownloading(bool is_downloading) {
hubbed82bed52015-12-15 23:07:161306 DVLOG(1) << __FUNCTION__;
[email protected]122f40252012-06-12 05:01:561307 if (!is_downloading && network_state_ == WebMediaPlayer::NetworkStateLoading)
1308 SetNetworkState(WebMediaPlayer::NetworkStateIdle);
1309 else if (is_downloading && network_state_ == WebMediaPlayer::NetworkStateIdle)
1310 SetNetworkState(WebMediaPlayer::NetworkStateLoading);
1311 media_log_->AddEvent(
1312 media_log_->CreateBooleanEvent(
acolwell9e0840d2014-09-06 19:01:321313 MediaLogEvent::NETWORK_ACTIVITY_SET,
[email protected]122f40252012-06-12 05:01:561314 "is_downloading_data", is_downloading));
1315}
1316
watkf835a792016-06-24 23:24:401317void WebMediaPlayerImpl::OnSurfaceCreated(int surface_id) {
tsunghungee562e92016-07-20 18:03:311318 if (force_video_overlays_ && surface_id == SurfaceManager::kNoSurfaceID)
1319 LOG(ERROR) << "Create surface failed.";
1320
1321 overlay_surface_id_ = surface_id;
watkf835a792016-06-24 23:24:401322 if (!pending_surface_request_cb_.is_null())
1323 base::ResetAndReturn(&pending_surface_request_cb_).Run(surface_id);
1324}
1325
watkdee516f2016-02-18 02:22:191326// TODO(watk): Move this state management out of WMPI.
1327void WebMediaPlayerImpl::OnSurfaceRequested(
1328 const SurfaceCreatedCB& surface_created_cb) {
1329 DCHECK(main_task_runner_->BelongsToCurrentThread());
1330 DCHECK(surface_manager_);
1331
1332 // A null callback indicates that the decoder is going away.
1333 if (surface_created_cb.is_null()) {
tsunghungee562e92016-07-20 18:03:311334 decoder_requires_restart_for_overlay_ = false;
watkf835a792016-06-24 23:24:401335 pending_surface_request_cb_.Reset();
watkdee516f2016-02-18 02:22:191336 return;
1337 }
1338
1339 // If we're getting a surface request it means GVD is initializing, so until
1340 // we get a null surface request, GVD is the active decoder. While that's the
1341 // case we should restart the pipeline on fullscreen transitions so that when
1342 // we create a new GVD it will request a surface again and get the right kind
1343 // of surface for the fullscreen state.
1344 // TODO(watk): Don't require a pipeline restart to switch surfaces for
1345 // cases where it isn't necessary.
tsunghungee562e92016-07-20 18:03:311346 decoder_requires_restart_for_overlay_ = true;
1347 if (overlay_enabled_) {
1348 if (overlay_surface_id_ != SurfaceManager::kNoSurfaceID)
1349 surface_created_cb.Run(overlay_surface_id_);
watkf835a792016-06-24 23:24:401350 else
1351 pending_surface_request_cb_ = surface_created_cb;
watkdee516f2016-02-18 02:22:191352 } else {
1353 // Tell the decoder to create its own surface.
1354 surface_created_cb.Run(SurfaceManager::kNoSurfaceID);
1355 }
1356}
1357
dcheng3076abbf2016-04-22 20:42:391358std::unique_ptr<Renderer> WebMediaPlayerImpl::CreateRenderer() {
tsunghungee562e92016-07-20 18:03:311359 if (force_video_overlays_)
1360 EnableOverlay();
1361
watkdee516f2016-02-18 02:22:191362 RequestSurfaceCB request_surface_cb;
1363#if defined(OS_ANDROID)
1364 request_surface_cb =
1365 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnSurfaceRequested);
1366#endif
sandersd1e49fb62015-12-12 01:18:061367 return renderer_factory_->CreateRenderer(
1368 media_task_runner_, worker_task_runner_, audio_source_provider_.get(),
watkdee516f2016-02-18 02:22:191369 compositor_, request_surface_cb);
sandersd1e49fb62015-12-12 01:18:061370}
1371
[email protected]ef8394c2013-08-21 20:26:301372void WebMediaPlayerImpl::StartPipeline() {
acolwellb4034942014-08-28 15:42:431373 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]ddbc6ff2013-04-19 15:28:331374
xhwange8c4181a2014-12-06 08:10:011375 Demuxer::EncryptedMediaInitDataCB encrypted_media_init_data_cb =
1376 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnEncryptedMediaInitData);
[email protected]2b57e2e2014-05-09 11:07:251377
[email protected]ddbc6ff2013-04-19 15:28:331378 // Figure out which demuxer to use.
[email protected]ef8394c2013-08-21 20:26:301379 if (load_type_ != LoadTypeMediaSource) {
[email protected]ddbc6ff2013-04-19 15:28:331380 DCHECK(!chunk_demuxer_);
[email protected]f5443ef72013-04-22 04:03:381381 DCHECK(data_source_);
1382
j.isorcef6778e652015-11-16 17:14:251383#if !defined(MEDIA_DISABLE_FFMPEG)
servolk81e01e02016-03-05 03:29:151384 Demuxer::MediaTracksUpdatedCB media_tracks_updated_cb =
servolkef1e5ef2016-03-25 04:55:261385 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnFFmpegMediaTracksUpdated);
servolk81e01e02016-03-05 03:29:151386
xhwange8c4181a2014-12-06 08:10:011387 demuxer_.reset(new FFmpegDemuxer(media_task_runner_, data_source_.get(),
servolk81e01e02016-03-05 03:29:151388 encrypted_media_init_data_cb,
1389 media_tracks_updated_cb, media_log_));
j.isorcef6778e652015-11-16 17:14:251390#else
alokp967c902452016-05-06 05:21:371391 OnError(PipelineStatus::DEMUXER_ERROR_COULD_NOT_OPEN);
j.isorcef6778e652015-11-16 17:14:251392 return;
1393#endif
[email protected]ddbc6ff2013-04-19 15:28:331394 } else {
[email protected]f5443ef72013-04-22 04:03:381395 DCHECK(!chunk_demuxer_);
1396 DCHECK(!data_source_);
1397
acolwell9e0840d2014-09-06 19:01:321398 chunk_demuxer_ = new ChunkDemuxer(
[email protected]ef8394c2013-08-21 20:26:301399 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnDemuxerOpened),
wolenetz1fb319d2015-07-14 17:49:041400 encrypted_media_init_data_cb, media_log_, true);
[email protected]f5443ef72013-04-22 04:03:381401 demuxer_.reset(chunk_demuxer_);
[email protected]ddbc6ff2013-04-19 15:28:331402 }
1403
sandersdb5e21462016-03-09 01:49:071404 // TODO(sandersd): FileSystem objects may also be non-static, but due to our
1405 // caching layer such situations are broken already. http://crbug.com/593159
1406 bool is_static = !chunk_demuxer_;
1407
[email protected]f5443ef72013-04-22 04:03:381408 // ... and we're ready to go!
[email protected]d228aeec2014-06-20 19:16:491409 seeking_ = true;
xhwangf94a634d2014-10-22 22:07:271410
sandersd1e49fb62015-12-12 01:18:061411 // TODO(sandersd): On Android, defer Start() if the tab is not visible.
sandersd1c0bba02016-03-04 23:14:081412 bool is_streaming = (data_source_ && data_source_->IsStreaming());
alokp967c902452016-05-06 05:21:371413 pipeline_controller_.Start(demuxer_.get(), this, is_streaming, is_static);
[email protected]f5443ef72013-04-22 04:03:381414}
1415
1416void WebMediaPlayerImpl::SetNetworkState(WebMediaPlayer::NetworkState state) {
[email protected]2a06ca62014-06-04 13:59:521417 DVLOG(1) << __FUNCTION__ << "(" << state << ")";
acolwellb4034942014-08-28 15:42:431418 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]f5443ef72013-04-22 04:03:381419 network_state_ = state;
1420 // Always notify to ensure client has the latest value.
[email protected]ce70c982013-12-20 17:04:321421 client_->networkStateChanged();
[email protected]f5443ef72013-04-22 04:03:381422}
1423
1424void WebMediaPlayerImpl::SetReadyState(WebMediaPlayer::ReadyState state) {
[email protected]2a06ca62014-06-04 13:59:521425 DVLOG(1) << __FUNCTION__ << "(" << state << ")";
acolwellb4034942014-08-28 15:42:431426 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]f5443ef72013-04-22 04:03:381427
[email protected]fee8a902014-06-03 13:43:361428 if (state == WebMediaPlayer::ReadyStateHaveEnoughData && data_source_ &&
1429 data_source_->assume_fully_buffered() &&
[email protected]f5443ef72013-04-22 04:03:381430 network_state_ == WebMediaPlayer::NetworkStateLoading)
1431 SetNetworkState(WebMediaPlayer::NetworkStateLoaded);
1432
1433 ready_state_ = state;
sandersd50a635e2016-04-04 22:50:091434 highest_ready_state_ = std::max(highest_ready_state_, ready_state_);
1435
[email protected]f5443ef72013-04-22 04:03:381436 // Always notify to ensure client has the latest value.
[email protected]ce70c982013-12-20 17:04:321437 client_->readyStateChanged();
[email protected]f5443ef72013-04-22 04:03:381438}
1439
Dana Jansens71331252016-03-09 20:57:221440blink::WebAudioSourceProvider* WebMediaPlayerImpl::getAudioSourceProvider() {
[email protected]ff875be52013-06-02 23:47:381441 return audio_source_provider_.get();
[email protected]f5443ef72013-04-22 04:03:381442}
1443
[email protected]f5443ef72013-04-22 04:03:381444double WebMediaPlayerImpl::GetPipelineDuration() const {
[email protected]f6af7592014-02-28 10:09:111445 base::TimeDelta duration = pipeline_.GetMediaDuration();
[email protected]f5443ef72013-04-22 04:03:381446
1447 // Return positive infinity if the resource is unbounded.
1448 // http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html#dom-media-duration
dalecurtis39a7f932016-07-19 18:34:591449 if (duration == kInfiniteDuration)
[email protected]f5443ef72013-04-22 04:03:381450 return std::numeric_limits<double>::infinity();
1451
1452 return duration.InSecondsF();
1453}
1454
[email protected]dd061e12014-05-06 19:21:221455static void GetCurrentFrameAndSignal(
1456 VideoFrameCompositor* compositor,
acolwell9e0840d2014-09-06 19:01:321457 scoped_refptr<VideoFrame>* video_frame_out,
[email protected]dd061e12014-05-06 19:21:221458 base::WaitableEvent* event) {
1459 TRACE_EVENT0("media", "GetCurrentFrameAndSignal");
dalecurtis44ce4de2015-05-11 18:42:071460 *video_frame_out = compositor->GetCurrentFrameAndUpdateIfStale();
[email protected]dd061e12014-05-06 19:21:221461 event->Signal();
1462}
1463
acolwell9e0840d2014-09-06 19:01:321464scoped_refptr<VideoFrame>
[email protected]dd061e12014-05-06 19:21:221465WebMediaPlayerImpl::GetCurrentFrameFromCompositor() {
1466 TRACE_EVENT0("media", "WebMediaPlayerImpl::GetCurrentFrameFromCompositor");
1467 if (compositor_task_runner_->BelongsToCurrentThread())
dalecurtis44ce4de2015-05-11 18:42:071468 return compositor_->GetCurrentFrameAndUpdateIfStale();
[email protected]dd061e12014-05-06 19:21:221469
1470 // Use a posted task and waitable event instead of a lock otherwise
1471 // WebGL/Canvas can see different content than what the compositor is seeing.
acolwell9e0840d2014-09-06 19:01:321472 scoped_refptr<VideoFrame> video_frame;
gab0d77c7cb2016-06-02 00:00:231473 base::WaitableEvent event(base::WaitableEvent::ResetPolicy::AUTOMATIC,
1474 base::WaitableEvent::InitialState::NOT_SIGNALED);
[email protected]dd061e12014-05-06 19:21:221475 compositor_task_runner_->PostTask(FROM_HERE,
1476 base::Bind(&GetCurrentFrameAndSignal,
1477 base::Unretained(compositor_),
1478 &video_frame,
1479 &event));
1480 event.Wait();
1481 return video_frame;
1482}
1483
sandersd50a635e2016-04-04 22:50:091484void WebMediaPlayerImpl::UpdatePlayState() {
hubbed5f36882016-01-15 22:40:371485#if defined(OS_ANDROID) // WMPI_CAST
sandersd50a635e2016-04-04 22:50:091486 bool is_remote = isRemote();
1487#else
1488 bool is_remote = false;
hubbed5f36882016-01-15 22:40:371489#endif
dalecurtis8b8505e72016-06-10 21:59:171490 bool is_suspended = pipeline_controller_.IsSuspended();
sandersd50a635e2016-04-04 22:50:091491 bool is_backgrounded =
1492 IsBackgroundedSuspendEnabled() && delegate_ && delegate_->IsHidden();
dalecurtis8b8505e72016-06-10 21:59:171493 PlayState state = UpdatePlayState_ComputePlayState(is_remote, is_suspended,
1494 is_backgrounded);
sandersd50a635e2016-04-04 22:50:091495 SetDelegateState(state.delegate_state);
1496 SetMemoryReportingState(state.is_memory_reporting_enabled);
1497 SetSuspendState(state.is_suspended || pending_suspend_resume_cycle_);
1498}
dalecurtis5bbc487e2016-02-27 04:15:051499
sandersd50a635e2016-04-04 22:50:091500void WebMediaPlayerImpl::SetDelegateState(DelegateState new_state) {
1501 if (!delegate_ || delegate_state_ == new_state)
dalecurtis5bbc487e2016-02-27 04:15:051502 return;
1503
sandersd50a635e2016-04-04 22:50:091504 delegate_state_ = new_state;
1505
1506 switch (delegate_state_) {
1507 case DelegateState::GONE:
1508 delegate_->PlayerGone(delegate_id_);
1509 break;
1510 case DelegateState::PLAYING:
1511 delegate_->DidPlay(delegate_id_, hasVideo(), hasAudio(), false,
1512 pipeline_.GetMediaDuration());
1513 break;
1514 case DelegateState::PAUSED:
1515 delegate_->DidPause(delegate_id_, false);
1516 break;
watk81727bf2016-04-12 00:25:131517 case DelegateState::PAUSED_BUT_NOT_IDLE:
sandersd5ea2ba4c2016-04-05 22:40:561518 // It doesn't really matter what happens when we enter this state, only
1519 // that we reset the idle timer when leaving it.
1520 //
watk81727bf2016-04-12 00:25:131521 // TODO(sandersd): Ideally the delegate would consider idleness and play
1522 // state as orthogonal properties so that we could avoid this.
sandersd5ea2ba4c2016-04-05 22:40:561523 delegate_->DidPause(delegate_id_, false);
1524 break;
sandersd50a635e2016-04-04 22:50:091525 case DelegateState::ENDED:
1526 delegate_->DidPause(delegate_id_, true);
1527 break;
dalecurtis0f0097a2015-12-01 17:40:471528 }
1529}
1530
sandersd50a635e2016-04-04 22:50:091531void WebMediaPlayerImpl::SetMemoryReportingState(
1532 bool is_memory_reporting_enabled) {
1533 if (memory_usage_reporting_timer_.IsRunning() ==
1534 is_memory_reporting_enabled) {
hubbed5f36882016-01-15 22:40:371535 return;
sandersd50a635e2016-04-04 22:50:091536 }
sandersd1c0bba02016-03-04 23:14:081537
sandersd50a635e2016-04-04 22:50:091538 if (is_memory_reporting_enabled) {
1539 memory_usage_reporting_timer_.Start(FROM_HERE,
1540 base::TimeDelta::FromSeconds(2), this,
1541 &WebMediaPlayerImpl::ReportMemoryUsage);
1542 } else {
1543 memory_usage_reporting_timer_.Stop();
1544 ReportMemoryUsage();
1545 }
1546}
1547
1548void WebMediaPlayerImpl::SetSuspendState(bool is_suspended) {
1549 // Do not change the state after an error has occurred.
1550 // TODO(sandersd): Update PipelineController to remove the need for this.
1551 if (IsNetworkStateError(network_state_))
sandersd1c0bba02016-03-04 23:14:081552 return;
1553
halliwell6451e242016-06-01 15:00:241554#if !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
1555 // TODO(sandersd): idle suspend is disabled if decoder owns video frame.
1556 // Used on OSX,Windows+Chromecast. Since GetCurrentFrameFromCompositor is
1557 // a synchronous cross-thread post, avoid the cost on platforms that
1558 // always allow suspend. Need to find a better mechanism for this. See
1559 // http://crbug.com/595716 and http://crbug.com/602708
dalecurtis7f366b2242016-04-13 01:16:171560 if (can_suspend_state_ == CanSuspendState::UNKNOWN) {
1561 scoped_refptr<VideoFrame> frame = GetCurrentFrameFromCompositor();
1562 if (frame) {
1563 can_suspend_state_ =
1564 frame->metadata()->IsTrue(VideoFrameMetadata::DECODER_OWNS_FRAME)
1565 ? CanSuspendState::NO
1566 : CanSuspendState::YES;
1567 }
1568 }
1569#else
1570 can_suspend_state_ = CanSuspendState::YES;
1571#endif
1572
1573 if (can_suspend_state_ == CanSuspendState::NO)
1574 return;
1575
sandersd50a635e2016-04-04 22:50:091576 if (is_suspended) {
1577 pipeline_controller_.Suspend();
1578 } else {
1579 pipeline_controller_.Resume();
1580 }
1581}
1582
1583WebMediaPlayerImpl::PlayState
1584WebMediaPlayerImpl::UpdatePlayState_ComputePlayState(bool is_remote,
dalecurtis8b8505e72016-06-10 21:59:171585 bool is_suspended,
sandersd50a635e2016-04-04 22:50:091586 bool is_backgrounded) {
1587 PlayState result;
1588
1589 // This includes both data source (before pipeline startup) and pipeline
1590 // errors.
1591 bool has_error = IsNetworkStateError(network_state_);
1592
1593 // After HaveMetadata, we know which tracks are present and the duration.
1594 bool have_metadata = ready_state_ >= WebMediaPlayer::ReadyStateHaveMetadata;
1595
1596 // After HaveFutureData, Blink will call play() if the state is not paused.
1597 bool have_future_data =
1598 highest_ready_state_ >= WebMediaPlayer::ReadyStateHaveFutureData;
1599
dalecurtis8b8505e72016-06-10 21:59:171600 // Background suspend is not enabled for audio-only players unless paused,
1601 // though in the case of audio-only the session should be kept.
sandersd50a635e2016-04-04 22:50:091602 bool background_suspended = is_backgrounded && have_metadata && hasVideo();
1603
dalecurtis8b8505e72016-06-10 21:59:171604 // The |paused_| state is not reliable until we |have_future_data|.
1605 bool background_pause_suspended =
1606 is_backgrounded && have_future_data && paused_;
1607
sandersd50a635e2016-04-04 22:50:091608 // Idle suspend is enabled once there is future data. We don't want to idle
1609 // suspend before that because play() may never be triggered to leave the idle
1610 // state. There could be other theoretical problems if the page is waiting for
1611 // other events before actually calling play(), but at least we don't break
1612 // Blink.
1613 //
1614 // TODO(sandersd): Make the delegate suspend idle players immediately when
1615 // hidden.
1616 // TODO(sandersd): If Blink told us the paused state sooner, we could
1617 // idle suspend sooner.
1618 bool idle_suspended = is_idle_ && have_future_data;
1619
1620 // Combined suspend state.
1621 result.is_suspended =
dalecurtis8b8505e72016-06-10 21:59:171622 is_remote || must_suspend_ || idle_suspended || background_suspended ||
1623 background_pause_suspended ||
1624 // If we're already suspended, see if we can wait for user interaction.
1625 (is_suspended && have_future_data && paused_ && !seeking_);
sandersd50a635e2016-04-04 22:50:091626
1627 // We do not treat |playback_rate_| == 0 as paused. For the media session,
1628 // being paused implies displaying a play button, which is incorrect in this
1629 // case. For memory usage reporting, we just use the same definition (but we
1630 // don't have to).
1631 //
1632 // Similarly, we don't consider |ended_| to be paused. Blink will immediately
1633 // call pause() or seek(), so |ended_| should not affect the computation.
1634 // Despite that, |ended_| does result in a separate paused state, to simplfy
1635 // the contract for SetDelegateState().
1636 //
1637 // |has_session| is used to decide when to create a media session. Idle
1638 // suspension does not destroy the media session, because we expect that the
1639 // notification controls (and audio focus) remain. We also require:
1640 // - |have_metadata|, since the tracks and duration are passed to DidPlay().
1641 // - |have_future_data|, since we need to know whether we are paused to
1642 // correctly configure the session.
1643 //
1644 // TODO(sandersd): If Blink told us the paused state sooner, we could create
1645 // the media session sooner.
1646 bool can_play = !has_error && !is_remote && have_future_data;
1647 bool has_session = can_play && !must_suspend_ && !background_suspended;
1648
1649 if (!has_session) {
1650 result.delegate_state = DelegateState::GONE;
1651 } else if (paused_) {
tsunghungee562e92016-07-20 18:03:311652 if (seeking() || overlay_enabled_) {
watk81727bf2016-04-12 00:25:131653 result.delegate_state = DelegateState::PAUSED_BUT_NOT_IDLE;
sandersd5ea2ba4c2016-04-05 22:40:561654 } else if (ended_) {
1655 result.delegate_state = DelegateState::ENDED;
1656 } else {
1657 result.delegate_state = DelegateState::PAUSED;
1658 }
sandersd50a635e2016-04-04 22:50:091659 } else {
1660 result.delegate_state = DelegateState::PLAYING;
1661 }
1662
dalecurtis8b8505e72016-06-10 21:59:171663 // It's not critical if some cases where memory usage can change are missed,
sandersd50a635e2016-04-04 22:50:091664 // since media memory changes are usually gradual.
1665 result.is_memory_reporting_enabled =
1666 can_play && !result.is_suspended && !paused_;
1667
1668 return result;
dalecurtis0f0097a2015-12-01 17:40:471669}
1670
dalecurtis83266c72015-10-29 18:43:201671void WebMediaPlayerImpl::ReportMemoryUsage() {
1672 DCHECK(main_task_runner_->BelongsToCurrentThread());
1673
wdzierzanowskifd4cd91c52015-12-02 23:50:201674 // About base::Unretained() usage below: We destroy |demuxer_| on the main
1675 // thread. Before that, however, ~WebMediaPlayerImpl() posts a task to the
1676 // media thread and waits for it to finish. Hence, the GetMemoryUsage() task
1677 // posted here must finish earlier.
1678
1679 if (demuxer_) {
1680 base::PostTaskAndReplyWithResult(
1681 media_task_runner_.get(), FROM_HERE,
1682 base::Bind(&Demuxer::GetMemoryUsage, base::Unretained(demuxer_.get())),
1683 base::Bind(&WebMediaPlayerImpl::FinishMemoryUsageReport, AsWeakPtr()));
1684 } else {
1685 FinishMemoryUsageReport(0);
1686 }
1687}
1688
1689void WebMediaPlayerImpl::FinishMemoryUsageReport(int64_t demuxer_memory_usage) {
1690 DCHECK(main_task_runner_->BelongsToCurrentThread());
1691
dalecurtis83266c72015-10-29 18:43:201692 const PipelineStatistics stats = pipeline_.GetStatistics();
1693 const int64_t current_memory_usage =
1694 stats.audio_memory_usage + stats.video_memory_usage +
1695 (data_source_ ? data_source_->GetMemoryUsage() : 0) +
wdzierzanowskifd4cd91c52015-12-02 23:50:201696 demuxer_memory_usage;
dalecurtis83266c72015-10-29 18:43:201697
dalecurtis3a7d38f42016-03-07 21:17:131698 // Note, this isn't entirely accurate, there may be VideoFrames held by the
1699 // compositor or other resources that we're unaware of.
1700
dalecurtis83266c72015-10-29 18:43:201701 DVLOG(2) << "Memory Usage -- Audio: " << stats.audio_memory_usage
1702 << ", Video: " << stats.video_memory_usage << ", DataSource: "
1703 << (data_source_ ? data_source_->GetMemoryUsage() : 0)
wdzierzanowskifd4cd91c52015-12-02 23:50:201704 << ", Demuxer: " << demuxer_memory_usage;
dalecurtis83266c72015-10-29 18:43:201705
1706 const int64_t delta = current_memory_usage - last_reported_memory_usage_;
1707 last_reported_memory_usage_ = current_memory_usage;
1708 adjust_allocated_memory_cb_.Run(delta);
1709}
1710
dalecurtis8b8505e72016-06-10 21:59:171711void WebMediaPlayerImpl::ScheduleIdlePauseTimer() {
1712 // Only schedule the pause timer if we're playing and are suspended. We use
1713 // delegate state as a proxy for suspended here since the suspension may be in
1714 // flight at the time of this call.
1715 if (paused_ || delegate_state_ != DelegateState::GONE)
1716 return;
1717
1718#if defined(OS_ANDROID)
1719 // Remote players will be suspended and locally paused.
1720 if (isRemote())
1721 return;
1722#endif
1723
1724 // Idle timeout chosen arbitrarily.
1725 background_pause_timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(5),
1726 this, &WebMediaPlayerImpl::OnPause);
1727}
1728
acolwell9e0840d2014-09-06 19:01:321729} // namespace media