blob: b4330c5a797a7c73281fdcd6c31a7e44fe8a7f63 [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),
watkdee516f2016-02-18 02:22:19182 fullscreen_(false),
183 decoder_requires_restart_for_fullscreen_(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()),
watkf835a792016-06-24 23:24:40208 fullscreen_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
dalecurtisbb3eaac2016-01-27 21:10:25215 if (delegate_)
216 delegate_id_ = delegate_->AddObserver(this);
sandersd1e49fb62015-12-12 01:18:06217
[email protected]c93eb0a62011-08-09 22:47:24218 media_log_->AddEvent(
acolwell9e0840d2014-09-06 19:01:32219 media_log_->CreateEvent(MediaLogEvent::WEBMEDIAPLAYER_CREATED));
[email protected]4e6be3f2009-05-07 02:24:44220
xhwang0ad11e512014-11-25 23:43:09221 if (params.initial_cdm()) {
xhwang9bd8c732015-04-13 23:27:53222 SetCdm(base::Bind(&IgnoreCdmAttached),
223 ToWebContentDecryptionModuleImpl(params.initial_cdm())
224 ->GetCdmContext());
xhwang0ad11e512014-11-25 23:43:09225 }
226
xhwangf94a634d2014-10-22 22:07:27227 // TODO(xhwang): When we use an external Renderer, many methods won't work,
xhwang6fa356202014-12-11 00:44:12228 // e.g. GetCurrentFrameFromCompositor(). See http://crbug.com/434861
[email protected]c50edb962013-10-19 18:05:07229
[email protected]ddbc6ff2013-04-19 15:28:33230 // Use the null sink if no sink was provided.
[email protected]4a914882013-01-10 00:43:48231 audio_source_provider_ = new WebAudioSourceProviderImpl(
[email protected]ff875be52013-06-02 23:47:38232 params.audio_renderer_sink().get()
233 ? params.audio_renderer_sink()
acolwell9e0840d2014-09-06 19:01:32234 : new NullAudioSink(media_task_runner_));
[email protected]ec9212f2008-12-18 21:40:36235}
236
[email protected]4e6be3f2009-05-07 02:24:44237WebMediaPlayerImpl::~WebMediaPlayerImpl() {
acolwellb4034942014-08-28 15:42:43238 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53239
alokp1116967f2016-06-11 17:30:56240 suppress_destruction_errors_ = true;
sandersd1e49fb62015-12-12 01:18:06241 if (delegate_) {
dalecurtisbb3eaac2016-01-27 21:10:25242 delegate_->PlayerGone(delegate_id_);
243 delegate_->RemoveObserver(delegate_id_);
sandersd1e49fb62015-12-12 01:18:06244 }
[email protected]baff4512011-10-19 18:21:07245
alokp967c902452016-05-06 05:21:37246 // Pipeline must be stopped before it is destroyed.
247 pipeline_.Stop();
[email protected]f6af7592014-02-28 10:09:11248
dalecurtis83266c72015-10-29 18:43:20249 if (last_reported_memory_usage_)
250 adjust_allocated_memory_cb_.Run(-last_reported_memory_usage_);
251
dalecurtise1edb312016-06-22 02:33:21252 // Destruct compositor resources in the proper order.
253 client_->setWebLayer(nullptr);
254 if (video_weblayer_)
255 static_cast<cc::VideoLayer*>(video_weblayer_->layer())->StopUsingProvider();
[email protected]dd061e12014-05-06 19:21:22256 compositor_task_runner_->DeleteSoon(FROM_HERE, compositor_);
xhwangea8bb3562015-06-08 21:18:37257
258 media_log_->AddEvent(
259 media_log_->CreateEvent(MediaLogEvent::WEBMEDIAPLAYER_DESTROYED));
[email protected]ec9212f2008-12-18 21:40:36260}
261
guidou9bfe4e2f2016-04-09 08:31:19262void WebMediaPlayerImpl::load(LoadType load_type,
263 const blink::WebMediaPlayerSource& source,
[email protected]62e5e682013-03-07 23:53:24264 CORSMode cors_mode) {
guidou9bfe4e2f2016-04-09 08:31:19265 // Only URL or MSE blob URL is supported.
266 DCHECK(source.isURL());
267 blink::WebURL url = source.getAsURL();
[email protected]2a06ca62014-06-04 13:59:52268 DVLOG(1) << __FUNCTION__ << "(" << load_type << ", " << url << ", "
269 << cors_mode << ")";
[email protected]d726eddc2013-07-02 22:25:55270 if (!defer_load_cb_.is_null()) {
271 defer_load_cb_.Run(base::Bind(
[email protected]ef8394c2013-08-21 20:26:30272 &WebMediaPlayerImpl::DoLoad, AsWeakPtr(), load_type, url, cors_mode));
[email protected]d726eddc2013-07-02 22:25:55273 return;
274 }
[email protected]ef8394c2013-08-21 20:26:30275 DoLoad(load_type, url, cors_mode);
[email protected]62e5e682013-03-07 23:53:24276}
277
watk9c87c6fa2016-05-06 20:36:51278bool WebMediaPlayerImpl::supportsOverlayFullscreenVideo() {
279#if defined(OS_ANDROID)
watkf835a792016-06-24 23:24:40280 return true;
watk9c87c6fa2016-05-06 20:36:51281#else
282 return false;
283#endif
284}
285
watkdee516f2016-02-18 02:22:19286void WebMediaPlayerImpl::enteredFullscreen() {
287 fullscreen_ = true;
watkf835a792016-06-24 23:24:40288 if (surface_manager_) {
289 surface_created_cb_.Reset(
290 base::Bind(&WebMediaPlayerImpl::OnSurfaceCreated, AsWeakPtr()));
291 surface_manager_->CreateFullscreenSurface(pipeline_metadata_.natural_size,
292 surface_created_cb_.callback());
293 }
watkdee516f2016-02-18 02:22:19294 if (decoder_requires_restart_for_fullscreen_)
295 ScheduleRestart();
296}
297
298void WebMediaPlayerImpl::exitedFullscreen() {
299 fullscreen_ = false;
watkf835a792016-06-24 23:24:40300 surface_created_cb_.Cancel();
301 fullscreen_surface_id_ = SurfaceManager::kNoSurfaceID;
watkdee516f2016-02-18 02:22:19302 if (decoder_requires_restart_for_fullscreen_)
303 ScheduleRestart();
304}
305
[email protected]ef8394c2013-08-21 20:26:30306void WebMediaPlayerImpl::DoLoad(LoadType load_type,
[email protected]180ef242013-11-07 06:50:46307 const blink::WebURL& url,
[email protected]d726eddc2013-07-02 22:25:55308 CORSMode cors_mode) {
hubbed82bed52015-12-15 23:07:16309 DVLOG(1) << __FUNCTION__;
acolwellb4034942014-08-28 15:42:43310 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d726eddc2013-07-02 22:25:55311
[email protected]62e5e682013-03-07 23:53:24312 GURL gurl(url);
xhwangbffbf452016-04-01 05:26:45313 ReportMetrics(load_type, gurl, frame_->getSecurityOrigin());
[email protected]62e5e682013-03-07 23:53:24314
[email protected]926f8fd2013-04-12 20:27:53315 // Set subresource URL for crash reporting.
316 base::debug::SetCrashKeyValue("subresource_url", gurl.spec());
317
[email protected]ef8394c2013-08-21 20:26:30318 load_type_ = load_type;
319
[email protected]62e5e682013-03-07 23:53:24320 SetNetworkState(WebMediaPlayer::NetworkStateLoading);
321 SetReadyState(WebMediaPlayer::ReadyStateHaveNothing);
kinukof19cde72015-12-18 23:15:25322 media_log_->AddEvent(media_log_->CreateLoadEvent(url.string().utf8()));
[email protected]d726eddc2013-07-02 22:25:55323
324 // Media source pipelines can start immediately.
[email protected]ef8394c2013-08-21 20:26:30325 if (load_type == LoadTypeMediaSource) {
[email protected]d726eddc2013-07-02 22:25:55326 supports_save_ = false;
[email protected]ef8394c2013-08-21 20:26:30327 StartPipeline();
hubbe5f0ad43b2015-12-14 20:57:26328 } else {
avayvode46d7bef2016-03-30 23:18:26329 // TODO(hubbe): This experiment is temporary and should be removed once
330 // we have enough data to support the primacy of the new media cache.
331 // See http://crbug.com/514719 for details.
332 // Otherwise it's a regular request which requires resolving the URL first.
333 if (base::FeatureList::IsEnabled(kUseNewMediaCache)) {
334 // Remove this when MultiBufferDataSource becomes default.
335 LOG(WARNING) << "Using MultibufferDataSource";
336 data_source_.reset(new MultibufferDataSource(
337 url, static_cast<UrlData::CORSMode>(cors_mode), main_task_runner_,
338 url_index_, frame_, media_log_.get(), &buffered_data_source_host_,
339 base::Bind(&WebMediaPlayerImpl::NotifyDownloading, AsWeakPtr())));
340 } else {
341 data_source_.reset(new BufferedDataSource(
342 url, static_cast<BufferedResourceLoader::CORSMode>(cors_mode),
343 main_task_runner_, frame_, media_log_.get(),
344 &buffered_data_source_host_,
345 base::Bind(&WebMediaPlayerImpl::NotifyDownloading, AsWeakPtr())));
346 }
347 data_source_->SetPreload(preload_);
348 data_source_->SetBufferingStrategy(buffering_strategy_);
349 data_source_->Initialize(
350 base::Bind(&WebMediaPlayerImpl::DataSourceInitialized, AsWeakPtr()));
hubbe5f0ad43b2015-12-14 20:57:26351 }
hubbed5f36882016-01-15 22:40:37352
353#if defined(OS_ANDROID) // WMPI_CAST
dalecurtisbb3eaac2016-01-27 21:10:25354 cast_impl_.Initialize(url, frame_, delegate_id_);
hubbed5f36882016-01-15 22:40:37355#endif
[email protected]62e5e682013-03-07 23:53:24356}
357
[email protected]4e6be3f2009-05-07 02:24:44358void WebMediaPlayerImpl::play() {
[email protected]2a06ca62014-06-04 13:59:52359 DVLOG(1) << __FUNCTION__;
acolwellb4034942014-08-28 15:42:43360 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53361
hubbed5f36882016-01-15 22:40:37362#if defined(OS_ANDROID) // WMPI_CAST
363 if (isRemote()) {
dalecurtis6e2716d2016-01-21 04:49:15364 cast_impl_.play();
hubbed5f36882016-01-15 22:40:37365 return;
366 }
367#endif
368
[email protected]49480902009-07-14 20:23:43369 paused_ = false;
sandersd50a635e2016-04-04 22:50:09370 is_idle_ = false;
yoichio863bebf2016-03-04 07:56:58371 pipeline_.SetPlaybackRate(playback_rate_);
sandersd1c0bba02016-03-04 23:14:08372
[email protected]039b7542013-10-17 22:06:25373 if (data_source_)
374 data_source_->MediaIsPlaying();
[email protected]090f7312011-08-05 23:26:40375
acolwell9e0840d2014-09-06 19:01:32376 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PLAY));
sandersd50a635e2016-04-04 22:50:09377 UpdatePlayState();
[email protected]ec9212f2008-12-18 21:40:36378}
379
[email protected]4e6be3f2009-05-07 02:24:44380void WebMediaPlayerImpl::pause() {
[email protected]2a06ca62014-06-04 13:59:52381 DVLOG(1) << __FUNCTION__;
acolwellb4034942014-08-28 15:42:43382 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53383
sandersd50a635e2016-04-04 22:50:09384 // We update the paused state even when casting, since we expect pause() to be
385 // called when casting begins, and when we exit casting we should end up in a
386 // paused state.
[email protected]49480902009-07-14 20:23:43387 paused_ = true;
hubbed5f36882016-01-15 22:40:37388
389#if defined(OS_ANDROID) // WMPI_CAST
390 if (isRemote()) {
dalecurtis6e2716d2016-01-21 04:49:15391 cast_impl_.pause();
hubbed5f36882016-01-15 22:40:37392 return;
393 }
394#endif
395
a.berwal338bf002015-04-22 11:14:50396 pipeline_.SetPlaybackRate(0.0);
sandersd1c0bba02016-03-04 23:14:08397
398 // pause() may be called after playback has ended and the HTMLMediaElement
399 // requires that currentTime() == duration() after ending. We want to ensure
400 // |paused_time_| matches currentTime() in this case or a future seek() may
401 // incorrectly discard what it thinks is a seek to the existing time.
402 paused_time_ =
403 ended_ ? pipeline_.GetMediaDuration() : pipeline_.GetMediaTime();
[email protected]090f7312011-08-05 23:26:40404
acolwell9e0840d2014-09-06 19:01:32405 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PAUSE));
sandersd50a635e2016-04-04 22:50:09406 UpdatePlayState();
[email protected]ec9212f2008-12-18 21:40:36407}
408
[email protected]574a1d62009-07-17 03:23:46409bool WebMediaPlayerImpl::supportsSave() const {
acolwellb4034942014-08-28 15:42:43410 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]132dd57c2012-08-10 23:24:34411 return supports_save_;
[email protected]574a1d62009-07-17 03:23:46412}
413
[email protected]39bdde32013-04-17 17:44:20414void WebMediaPlayerImpl::seek(double seconds) {
xhwang12d8d042014-12-01 21:48:57415 DVLOG(1) << __FUNCTION__ << "(" << seconds << "s)";
acolwellb4034942014-08-28 15:42:43416 DCHECK(main_task_runner_->BelongsToCurrentThread());
sandersd1c0bba02016-03-04 23:14:08417 DoSeek(base::TimeDelta::FromSecondsD(seconds), true);
418}
419
420void WebMediaPlayerImpl::DoSeek(base::TimeDelta time, bool time_updated) {
421 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53422
hubbed5f36882016-01-15 22:40:37423#if defined(OS_ANDROID) // WMPI_CAST
424 if (isRemote()) {
sandersd1c0bba02016-03-04 23:14:08425 cast_impl_.seek(time);
hubbed5f36882016-01-15 22:40:37426 return;
427 }
428#endif
429
srirama.mccf671812015-01-08 11:59:13430 ReadyState old_state = ready_state_;
[email protected]1bb666802013-11-28 06:12:08431 if (ready_state_ > WebMediaPlayer::ReadyStateHaveMetadata)
432 SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata);
433
sandersd1c0bba02016-03-04 23:14:08434 // When paused, we know exactly what the current time is and can elide seeks
435 // to it. However, there are two cases that are not elided:
436 // 1) When the pipeline state is not stable.
437 // In this case we just let |pipeline_controller_| decide what to do, as
438 // it has complete information.
439 // 2) For MSE.
440 // Because the buffers may have changed between seeks, MSE seeks are
441 // never elided.
442 if (paused_ && pipeline_controller_.IsStable() && paused_time_ == time &&
443 !chunk_demuxer_) {
444 // If the ready state was high enough before, we can indicate that the seek
445 // completed just by restoring it. Otherwise we will just wait for the real
446 // ready state change to eventually happen.
447 if (old_state == ReadyStateHaveEnoughData) {
srirama.m8f4a37562014-12-13 08:16:18448 main_task_runner_->PostTask(
alokp967c902452016-05-06 05:21:37449 FROM_HERE, base::Bind(&WebMediaPlayerImpl::OnBufferingStateChange,
450 AsWeakPtr(), BUFFERING_HAVE_ENOUGH));
srirama.m36ab2682014-12-11 04:20:01451 }
sandersd1c0bba02016-03-04 23:14:08452 return;
srirama.m36ab2682014-12-11 04:20:01453 }
[email protected]44ff37c02009-10-24 01:03:03454
sandersd50a635e2016-04-04 22:50:09455 // TODO(sandersd): Ideally we would not clear the idle state if
456 // |pipeline_controller_| can elide the seek.
457 is_idle_ = false;
458 ended_ = false;
459
[email protected]b3766a22010-12-22 17:34:13460 seeking_ = true;
sandersd1c0bba02016-03-04 23:14:08461 seek_time_ = time;
462 if (paused_)
463 paused_time_ = time;
464 pipeline_controller_.Seek(time, time_updated);
[email protected]b3766a22010-12-22 17:34:13465
sandersd50a635e2016-04-04 22:50:09466 // This needs to be called after Seek() so that if a resume is triggered, it
467 // is to the correct time.
468 UpdatePlayState();
[email protected]ec9212f2008-12-18 21:40:36469}
470
[email protected]39bdde32013-04-17 17:44:20471void WebMediaPlayerImpl::setRate(double rate) {
[email protected]2a06ca62014-06-04 13:59:52472 DVLOG(1) << __FUNCTION__ << "(" << rate << ")";
acolwellb4034942014-08-28 15:42:43473 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53474
[email protected]378f0b72009-08-11 17:11:42475 // TODO(kylep): Remove when support for negatives is added. Also, modify the
476 // following checks so rewind uses reasonable values also.
[email protected]39bdde32013-04-17 17:44:20477 if (rate < 0.0)
[email protected]378f0b72009-08-11 17:11:42478 return;
479
480 // Limit rates to reasonable values by clamping.
[email protected]39bdde32013-04-17 17:44:20481 if (rate != 0.0) {
[email protected]378f0b72009-08-11 17:11:42482 if (rate < kMinRate)
483 rate = kMinRate;
484 else if (rate > kMaxRate)
485 rate = kMaxRate;
486 }
487
[email protected]49480902009-07-14 20:23:43488 playback_rate_ = rate;
489 if (!paused_) {
[email protected]f6af7592014-02-28 10:09:11490 pipeline_.SetPlaybackRate(rate);
[email protected]039b7542013-10-17 22:06:25491 if (data_source_)
492 data_source_->MediaPlaybackRateChanged(rate);
[email protected]49480902009-07-14 20:23:43493 }
[email protected]ec9212f2008-12-18 21:40:36494}
495
[email protected]39bdde32013-04-17 17:44:20496void WebMediaPlayerImpl::setVolume(double volume) {
[email protected]2a06ca62014-06-04 13:59:52497 DVLOG(1) << __FUNCTION__ << "(" << volume << ")";
acolwellb4034942014-08-28 15:42:43498 DCHECK(main_task_runner_->BelongsToCurrentThread());
dalecurtisbb3eaac2016-01-27 21:10:25499 volume_ = volume;
500 pipeline_.SetVolume(volume_ * volume_multiplier_);
[email protected]ec9212f2008-12-18 21:40:36501}
[email protected]f0a51fb52009-03-05 12:46:38502
guidouc7babef2015-10-22 00:42:35503void WebMediaPlayerImpl::setSinkId(
504 const blink::WebString& sink_id,
505 const blink::WebSecurityOrigin& security_origin,
506 blink::WebSetSinkIdCallbacks* web_callback) {
guidou69223ce2015-06-16 10:36:19507 DCHECK(main_task_runner_->BelongsToCurrentThread());
guidou5754e612015-07-31 08:09:41508 DVLOG(1) << __FUNCTION__;
guidouc7babef2015-10-22 00:42:35509
olka68b69392016-04-01 11:42:12510 media::OutputDeviceStatusCB callback =
511 media::ConvertToOutputDeviceStatusCB(web_callback);
guidouc7babef2015-10-22 00:42:35512 media_task_runner_->PostTask(
513 FROM_HERE,
514 base::Bind(&SetSinkIdOnMediaThread, audio_source_provider_,
515 sink_id.utf8(), static_cast<url::Origin>(security_origin),
516 callback));
guidou69223ce2015-06-16 10:36:19517}
518
danakj365175c2016-02-06 00:37:37519STATIC_ASSERT_ENUM(WebMediaPlayer::PreloadNone, BufferedDataSource::NONE);
520STATIC_ASSERT_ENUM(WebMediaPlayer::PreloadMetaData,
521 BufferedDataSource::METADATA);
522STATIC_ASSERT_ENUM(WebMediaPlayer::PreloadAuto, BufferedDataSource::AUTO);
[email protected]23a8b1d82011-04-05 16:28:20523
[email protected]ef405f66b2012-04-18 02:39:55524void WebMediaPlayerImpl::setPreload(WebMediaPlayer::Preload preload) {
[email protected]2a06ca62014-06-04 13:59:52525 DVLOG(1) << __FUNCTION__ << "(" << preload << ")";
acolwellb4034942014-08-28 15:42:43526 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]4e6be3f2009-05-07 02:24:44527
acolwella5081a42014-08-28 23:42:52528 preload_ = static_cast<BufferedDataSource::Preload>(preload);
[email protected]b49beeb2013-03-01 20:04:00529 if (data_source_)
[email protected]09c60222014-08-07 16:42:31530 data_source_->SetPreload(preload_);
[email protected]4e6be3f2009-05-07 02:24:44531}
532
danakj365175c2016-02-06 00:37:37533STATIC_ASSERT_ENUM(WebMediaPlayer::BufferingStrategy::Normal,
534 BufferedDataSource::BUFFERING_STRATEGY_NORMAL);
535STATIC_ASSERT_ENUM(WebMediaPlayer::BufferingStrategy::Aggressive,
536 BufferedDataSource::BUFFERING_STRATEGY_AGGRESSIVE);
sandersdc6ab163a2015-12-12 03:56:13537
538void WebMediaPlayerImpl::setBufferingStrategy(
539 WebMediaPlayer::BufferingStrategy buffering_strategy) {
540 DVLOG(1) << __FUNCTION__;
541 DCHECK(main_task_runner_->BelongsToCurrentThread());
542
dalecurtis37fe5862016-03-15 19:29:09543#if defined(OS_ANDROID)
544 // We disallow aggressive buffering on Android since it matches the behavior
545 // of the platform media player and may have data usage penalties.
546 // TODO(dalecurtis, hubbe): We should probably stop using "pause-and-buffer"
547 // everywhere. See http://crbug.com/594669 for more details.
548 buffering_strategy_ = BufferedDataSource::BUFFERING_STRATEGY_NORMAL;
549#else
sandersdc6ab163a2015-12-12 03:56:13550 buffering_strategy_ =
551 static_cast<BufferedDataSource::BufferingStrategy>(buffering_strategy);
dalecurtis37fe5862016-03-15 19:29:09552#endif
553
sandersdc6ab163a2015-12-12 03:56:13554 if (data_source_)
555 data_source_->SetBufferingStrategy(buffering_strategy_);
556}
557
[email protected]4e6be3f2009-05-07 02:24:44558bool WebMediaPlayerImpl::hasVideo() const {
acolwellb4034942014-08-28 15:42:43559 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53560
[email protected]b8877772014-03-26 20:17:15561 return pipeline_metadata_.has_video;
[email protected]d43ed912009-02-03 04:52:53562}
563
[email protected]fc367af2009-08-14 23:06:35564bool WebMediaPlayerImpl::hasAudio() const {
acolwellb4034942014-08-28 15:42:43565 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]fc367af2009-08-14 23:06:35566
[email protected]b8877772014-03-26 20:17:15567 return pipeline_metadata_.has_audio;
[email protected]fc367af2009-08-14 23:06:35568}
569
servolkf25ceed2016-07-01 03:44:38570void WebMediaPlayerImpl::enabledAudioTracksChanged(
571 const blink::WebVector<blink::WebMediaPlayer::TrackId>& enabledTrackIds) {
572 DCHECK(main_task_runner_->BelongsToCurrentThread());
573
574 std::ostringstream logstr;
575 std::vector<MediaTrack::Id> enabledMediaTrackIds;
576 for (const auto& blinkTrackId : enabledTrackIds) {
577 MediaTrack::Id track_id = blinkTrackId.utf8().data();
578 logstr << track_id << " ";
579 enabledMediaTrackIds.push_back(track_id);
580 }
581 MEDIA_LOG(INFO, media_log_) << "Enabled audio tracks: [" << logstr.str()
582 << "]";
583 pipeline_.OnEnabledAudioTracksChanged(enabledMediaTrackIds);
584}
585
586void WebMediaPlayerImpl::selectedVideoTrackChanged(
587 blink::WebMediaPlayer::TrackId* selectedTrackId) {
588 DCHECK(main_task_runner_->BelongsToCurrentThread());
589
590 std::ostringstream logstr;
591 std::vector<MediaTrack::Id> selectedVideoMediaTrackId;
592 if (selectedTrackId) {
593 selectedVideoMediaTrackId.push_back(selectedTrackId->utf8().data());
594 logstr << selectedVideoMediaTrackId[0];
595 }
596 MEDIA_LOG(INFO, media_log_) << "Selected video track: [" << logstr.str()
597 << "]";
598 pipeline_.OnSelectedVideoTrackChanged(selectedVideoMediaTrackId);
599}
600
[email protected]180ef242013-11-07 06:50:46601blink::WebSize WebMediaPlayerImpl::naturalSize() const {
acolwellb4034942014-08-28 15:42:43602 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53603
[email protected]b8877772014-03-26 20:17:15604 return blink::WebSize(pipeline_metadata_.natural_size);
[email protected]d43ed912009-02-03 04:52:53605}
606
[email protected]4e6be3f2009-05-07 02:24:44607bool WebMediaPlayerImpl::paused() const {
acolwellb4034942014-08-28 15:42:43608 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53609
hubbed5f36882016-01-15 22:40:37610#if defined(OS_ANDROID) // WMPI_CAST
611 if (isRemote())
612 return cast_impl_.paused();
613#endif
sandersd50a635e2016-04-04 22:50:09614
[email protected]f6af7592014-02-28 10:09:11615 return pipeline_.GetPlaybackRate() == 0.0f;
[email protected]d43ed912009-02-03 04:52:53616}
617
[email protected]4e6be3f2009-05-07 02:24:44618bool WebMediaPlayerImpl::seeking() const {
acolwellb4034942014-08-28 15:42:43619 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53620
[email protected]ef405f66b2012-04-18 02:39:55621 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing)
[email protected]0acebfa2009-08-21 22:45:40622 return false;
[email protected]67cd5052009-09-10 21:53:22623
[email protected]b3766a22010-12-22 17:34:13624 return seeking_;
[email protected]ec9212f2008-12-18 21:40:36625}
626
[email protected]39bdde32013-04-17 17:44:20627double WebMediaPlayerImpl::duration() const {
acolwellb4034942014-08-28 15:42:43628 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]39bdde32013-04-17 17:44:20629
630 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing)
631 return std::numeric_limits<double>::quiet_NaN();
632
[email protected]39bdde32013-04-17 17:44:20633 return GetPipelineDuration();
[email protected]d43ed912009-02-03 04:52:53634}
635
[email protected]db66d0092014-04-16 07:15:12636double WebMediaPlayerImpl::timelineOffset() const {
acolwellb4034942014-08-28 15:42:43637 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]db66d0092014-04-16 07:15:12638
639 if (pipeline_metadata_.timeline_offset.is_null())
640 return std::numeric_limits<double>::quiet_NaN();
641
642 return pipeline_metadata_.timeline_offset.ToJsTime();
643}
644
[email protected]39bdde32013-04-17 17:44:20645double WebMediaPlayerImpl::currentTime() const {
acolwellb4034942014-08-28 15:42:43646 DCHECK(main_task_runner_->BelongsToCurrentThread());
scherkusd2c745b2014-09-04 05:03:40647 DCHECK_NE(ready_state_, WebMediaPlayer::ReadyStateHaveNothing);
648
649 // TODO(scherkus): Replace with an explicit ended signal to HTMLMediaElement,
650 // see http://crbug.com/409280
651 if (ended_)
652 return duration();
653
sandersd1c0bba02016-03-04 23:14:08654 if (seeking())
655 return seek_time_.InSecondsF();
wolenetz1b2ae7d2015-06-10 00:44:21656
hubbed5f36882016-01-15 22:40:37657#if defined(OS_ANDROID) // WMPI_CAST
sandersd1c0bba02016-03-04 23:14:08658 if (isRemote())
hubbed5f36882016-01-15 22:40:37659 return cast_impl_.currentTime();
hubbed5f36882016-01-15 22:40:37660#endif
661
sandersd1c0bba02016-03-04 23:14:08662 if (paused_)
hubbed5f36882016-01-15 22:40:37663 return paused_time_.InSecondsF();
hubbed5f36882016-01-15 22:40:37664
665 return pipeline_.GetMediaTime().InSecondsF();
[email protected]d43ed912009-02-03 04:52:53666}
667
danakj13afe0362016-02-27 01:22:50668WebMediaPlayer::NetworkState WebMediaPlayerImpl::getNetworkState() const {
acolwellb4034942014-08-28 15:42:43669 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]ddb1e5a2010-12-13 20:10:45670 return network_state_;
671}
672
danakj13afe0362016-02-27 01:22:50673WebMediaPlayer::ReadyState WebMediaPlayerImpl::getReadyState() const {
acolwellb4034942014-08-28 15:42:43674 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]ddb1e5a2010-12-13 20:10:45675 return ready_state_;
676}
677
wolenetz4d39cc02016-04-05 19:54:41678blink::WebString WebMediaPlayerImpl::getErrorMessage() {
679 DCHECK(main_task_runner_->BelongsToCurrentThread());
680 return blink::WebString::fromUTF8(media_log_->GetLastErrorMessage());
681}
682
[email protected]02022fc2014-05-16 00:05:31683blink::WebTimeRanges WebMediaPlayerImpl::buffered() const {
acolwellb4034942014-08-28 15:42:43684 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]779a8322014-08-22 21:28:37685
acolwell9e0840d2014-09-06 19:01:32686 Ranges<base::TimeDelta> buffered_time_ranges =
[email protected]02022fc2014-05-16 00:05:31687 pipeline_.GetBufferedTimeRanges();
[email protected]779a8322014-08-22 21:28:37688
689 const base::TimeDelta duration = pipeline_.GetMediaDuration();
dalecurtis39a7f932016-07-19 18:34:59690 if (duration != kInfiniteDuration) {
[email protected]779a8322014-08-22 21:28:37691 buffered_data_source_host_.AddBufferedTimeRanges(
692 &buffered_time_ranges, duration);
693 }
[email protected]02022fc2014-05-16 00:05:31694 return ConvertToWebTimeRanges(buffered_time_ranges);
695}
696
philipjb0e6f3f2014-09-30 09:51:53697blink::WebTimeRanges WebMediaPlayerImpl::seekable() const {
acolwellb4034942014-08-28 15:42:43698 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]39bdde32013-04-17 17:44:20699
dalecurtis56359cb2014-10-28 00:06:29700 if (ready_state_ < WebMediaPlayer::ReadyStateHaveMetadata)
philipjb0e6f3f2014-09-30 09:51:53701 return blink::WebTimeRanges();
702
dalecurtis56359cb2014-10-28 00:06:29703 const double seekable_end = duration();
704
705 // Allow a special exception for seeks to zero for streaming sources with a
706 // finite duration; this allows looping to work.
707 const bool allow_seek_to_zero = data_source_ && data_source_->IsStreaming() &&
mateuszs3371ab02015-04-24 13:20:23708 std::isfinite(seekable_end);
dalecurtis56359cb2014-10-28 00:06:29709
710 // TODO(dalecurtis): Technically this allows seeking on media which return an
711 // infinite duration so long as DataSource::IsStreaming() is false. While not
712 // expected, disabling this breaks semi-live players, http://crbug.com/427412.
713 const blink::WebTimeRange seekable_range(
714 0.0, allow_seek_to_zero ? 0.0 : seekable_end);
philipjb0e6f3f2014-09-30 09:51:53715 return blink::WebTimeRanges(&seekable_range, 1);
[email protected]ec9212f2008-12-18 21:40:36716}
717
[email protected]5d2b3e4c2014-05-12 23:27:30718bool WebMediaPlayerImpl::didLoadingProgress() {
acolwellb4034942014-08-28 15:42:43719 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]6683e1b2014-04-10 01:45:38720 bool pipeline_progress = pipeline_.DidLoadingProgress();
721 bool data_progress = buffered_data_source_host_.DidLoadingProgress();
722 return pipeline_progress || data_progress;
[email protected]d43ed912009-02-03 04:52:53723}
724
[email protected]dd5c7972014-08-21 15:00:37725void WebMediaPlayerImpl::paint(blink::WebCanvas* canvas,
726 const blink::WebRect& rect,
[email protected]dd5c7972014-08-21 15:00:37727 unsigned char alpha,
728 SkXfermode::Mode mode) {
acolwellb4034942014-08-28 15:42:43729 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]dd061e12014-05-06 19:21:22730 TRACE_EVENT0("media", "WebMediaPlayerImpl:paint");
[email protected]4e6be3f2009-05-07 02:24:44731
xhwang80739452016-01-13 00:48:00732 if (is_cdm_attached_)
733 return;
734
mcasasf1236fc22015-05-29 22:38:56735 scoped_refptr<VideoFrame> video_frame = GetCurrentFrameFromCompositor();
[email protected]0fe5d43b2014-01-24 23:32:45736
[email protected]b49beeb2013-03-01 20:04:00737 gfx::Rect gfx_rect(rect);
dongseong.hwang0c4e9d82015-01-08 20:11:13738 Context3D context_3d;
mcasas265bdbf82015-06-12 18:44:07739 if (video_frame.get() && video_frame->HasTextures()) {
mcasasf1236fc22015-05-29 22:38:56740 if (!context_3d_cb_.is_null())
dongseong.hwang0c4e9d82015-01-08 20:11:13741 context_3d = context_3d_cb_.Run();
dongseong.hwang0c4e9d82015-01-08 20:11:13742 if (!context_3d.gl)
danakj53f7ec902016-05-21 01:30:10743 return; // Unable to get/create a shared main thread context.
744 if (!context_3d.gr_context)
745 return; // The context has been lost since and can't setup a GrContext.
dongseong.hwang0c4e9d82015-01-08 20:11:13746 }
danakj795f1732015-08-31 23:40:22747 skcanvas_video_renderer_.Paint(video_frame, canvas, gfx::RectF(gfx_rect),
748 alpha, mode, pipeline_metadata_.video_rotation,
749 context_3d);
[email protected]ec9212f2008-12-18 21:40:36750}
[email protected]5df51652009-01-17 00:03:00751
[email protected]38259a7a82009-07-29 21:49:49752bool WebMediaPlayerImpl::hasSingleSecurityOrigin() const {
[email protected]b49beeb2013-03-01 20:04:00753 if (data_source_)
754 return data_source_->HasSingleOrigin();
[email protected]fcdb7462009-10-21 21:05:11755 return true;
[email protected]38259a7a82009-07-29 21:49:49756}
757
[email protected]3fe27112012-06-07 04:00:01758bool WebMediaPlayerImpl::didPassCORSAccessCheck() const {
[email protected]b49beeb2013-03-01 20:04:00759 if (data_source_)
760 return data_source_->DidPassCORSAccessCheck();
761 return false;
[email protected]3fe27112012-06-07 04:00:01762}
763
[email protected]39bdde32013-04-17 17:44:20764double WebMediaPlayerImpl::mediaTimeForTimeValue(double timeValue) const {
qinminb4c39782015-08-10 18:43:24765 return base::TimeDelta::FromSecondsD(timeValue).InSecondsF();
[email protected]e06e16d82011-05-26 22:13:33766}
767
[email protected]d82b18ae2011-03-23 21:28:59768unsigned WebMediaPlayerImpl::decodedFrameCount() const {
acolwellb4034942014-08-28 15:42:43769 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]4c51bc662011-02-16 02:03:16770
acolwell9e0840d2014-09-06 19:01:32771 PipelineStatistics stats = pipeline_.GetStatistics();
[email protected]4c51bc662011-02-16 02:03:16772 return stats.video_frames_decoded;
773}
774
[email protected]d82b18ae2011-03-23 21:28:59775unsigned WebMediaPlayerImpl::droppedFrameCount() const {
acolwellb4034942014-08-28 15:42:43776 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]4c51bc662011-02-16 02:03:16777
acolwell9e0840d2014-09-06 19:01:32778 PipelineStatistics stats = pipeline_.GetStatistics();
[email protected]dd061e12014-05-06 19:21:22779 return stats.video_frames_dropped;
[email protected]4c51bc662011-02-16 02:03:16780}
781
chakshu.a94326b72016-03-08 05:11:44782size_t WebMediaPlayerImpl::audioDecodedByteCount() const {
acolwellb4034942014-08-28 15:42:43783 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]4c51bc662011-02-16 02:03:16784
acolwell9e0840d2014-09-06 19:01:32785 PipelineStatistics stats = pipeline_.GetStatistics();
[email protected]4c51bc662011-02-16 02:03:16786 return stats.audio_bytes_decoded;
787}
788
chakshu.a94326b72016-03-08 05:11:44789size_t WebMediaPlayerImpl::videoDecodedByteCount() const {
acolwellb4034942014-08-28 15:42:43790 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]4c51bc662011-02-16 02:03:16791
acolwell9e0840d2014-09-06 19:01:32792 PipelineStatistics stats = pipeline_.GetStatistics();
[email protected]4c51bc662011-02-16 02:03:16793 return stats.video_bytes_decoded;
794}
795
[email protected]6523b242013-03-13 11:10:07796bool WebMediaPlayerImpl::copyVideoTextureToPlatformTexture(
danakj46070b02016-03-28 21:54:11797 gpu::gles2::GLES2Interface* gl,
zmo57d577a2015-10-30 18:28:59798 unsigned int texture,
799 unsigned int internal_format,
800 unsigned int type,
801 bool premultiply_alpha,
802 bool flip_y) {
[email protected]bfc05f22013-10-19 17:55:16803 TRACE_EVENT0("media", "WebMediaPlayerImpl:copyVideoTextureToPlatformTexture");
804
mcasasf1236fc22015-05-29 22:38:56805 scoped_refptr<VideoFrame> video_frame = GetCurrentFrameFromCompositor();
[email protected]dd061e12014-05-06 19:21:22806
mcasas265bdbf82015-06-12 18:44:07807 if (!video_frame.get() || !video_frame->HasTextures() ||
dcastagna31a65d432015-06-11 19:01:00808 media::VideoFrame::NumPlanes(video_frame->format()) != 1) {
[email protected]e56f88c72013-06-25 22:31:29809 return false;
dongseong.hwang0c4e9d82015-01-08 20:11:13810 }
[email protected]df41e252014-02-03 23:39:50811
dcastagna31a65d432015-06-11 19:01:00812 SkCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture(
zmo57d577a2015-10-30 18:28:59813 gl, video_frame.get(), texture, internal_format, type, premultiply_alpha,
814 flip_y);
[email protected]e56f88c72013-06-25 22:31:29815 return true;
[email protected]6523b242013-03-13 11:10:07816}
817
[email protected]7bce1832014-01-09 00:01:22818void WebMediaPlayerImpl::setContentDecryptionModule(
[email protected]9ebc3b03f2014-08-13 04:01:23819 blink::WebContentDecryptionModule* cdm,
820 blink::WebContentDecryptionModuleResult result) {
acolwellb4034942014-08-28 15:42:43821 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]9ebc3b03f2014-08-13 04:01:23822
jrummell06f27072015-06-08 18:12:38823 // Once the CDM is set it can't be cleared as there may be frames being
824 // decrypted on other threads. So fail this request.
825 // http://crbug.com/462365#c7.
xhwang97de4202014-11-25 08:44:01826 if (!cdm) {
827 result.completeWithError(
jrummell06f27072015-06-08 18:12:38828 blink::WebContentDecryptionModuleExceptionInvalidStateError, 0,
829 "The existing MediaKeys object cannot be removed at this time.");
xhwang97de4202014-11-25 08:44:01830 return;
831 }
832
jrummell89e61d82015-07-23 20:03:34833 // Create a local copy of |result| to avoid problems with the callback
834 // getting passed to the media thread and causing |result| to be destructed
jrummell4acbec912016-02-27 02:45:03835 // on the wrong thread in some failure conditions. Blink should prevent
836 // multiple simultaneous calls.
837 DCHECK(!set_cdm_result_);
jrummell89e61d82015-07-23 20:03:34838 set_cdm_result_.reset(new blink::WebContentDecryptionModuleResult(result));
839
840 SetCdm(BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnCdmAttached),
xhwang9bd8c732015-04-13 23:27:53841 ToWebContentDecryptionModuleImpl(cdm)->GetCdmContext());
xhwang97de4202014-11-25 08:44:01842}
843
xhwange8c4181a2014-12-06 08:10:01844void WebMediaPlayerImpl::OnEncryptedMediaInitData(
jrummellcf78967c2015-04-03 05:03:58845 EmeInitDataType init_data_type,
Avi Drissman97785ea2015-12-19 01:11:31846 const std::vector<uint8_t>& init_data) {
jrummellcf78967c2015-04-03 05:03:58847 DCHECK(init_data_type != EmeInitDataType::UNKNOWN);
xhwangbab66f52014-12-02 23:49:50848
ddorwin301ccdb2016-02-25 02:39:17849 // TODO(xhwang): Update this UMA name. https://crbug.com/589251
xhwangbab66f52014-12-02 23:49:50850 UMA_HISTOGRAM_COUNTS("Media.EME.NeedKey", 1);
851
srirama.m26f864d02015-07-14 05:21:46852 encrypted_client_->encrypted(
davidbenb50f00c2015-12-01 00:01:50853 ConvertToWebInitDataType(init_data_type), init_data.data(),
srirama.m26f864d02015-07-14 05:21:46854 base::saturated_cast<unsigned int>(init_data.size()));
xhwangbab66f52014-12-02 23:49:50855}
856
servolk81e01e02016-03-05 03:29:15857void WebMediaPlayerImpl::OnFFmpegMediaTracksUpdated(
dcheng3076abbf2016-04-22 20:42:39858 std::unique_ptr<MediaTracks> tracks) {
servolk81e01e02016-03-05 03:29:15859 // For MSE/chunk_demuxer case the media track updates are handled by
860 // WebSourceBufferImpl.
861 DCHECK(demuxer_.get());
862 DCHECK(!chunk_demuxer_);
servolkef1e5ef2016-03-25 04:55:26863
864 // Report the media track information to blink.
865 for (const auto& track : tracks->tracks()) {
866 if (track->type() == MediaTrack::Audio) {
servolkfa5c37c2016-06-16 17:56:47867 client_->addAudioTrack(blink::WebString::fromUTF8(track->id()),
868 blink::WebMediaPlayerClient::AudioTrackKindMain,
869 blink::WebString::fromUTF8(track->label()),
870 blink::WebString::fromUTF8(track->language()),
871 /*enabled*/ true);
servolkef1e5ef2016-03-25 04:55:26872 } else if (track->type() == MediaTrack::Video) {
servolkfa5c37c2016-06-16 17:56:47873 client_->addVideoTrack(blink::WebString::fromUTF8(track->id()),
874 blink::WebMediaPlayerClient::VideoTrackKindMain,
875 blink::WebString::fromUTF8(track->label()),
876 blink::WebString::fromUTF8(track->language()),
877 /*selected*/ true);
servolkef1e5ef2016-03-25 04:55:26878 } else {
879 // Text tracks are not supported through this code path yet.
880 NOTREACHED();
881 }
882 }
servolk81e01e02016-03-05 03:29:15883}
884
xhwang9bd8c732015-04-13 23:27:53885void WebMediaPlayerImpl::SetCdm(const CdmAttachedCB& cdm_attached_cb,
886 CdmContext* cdm_context) {
xhwang80739452016-01-13 00:48:00887 if (!cdm_context) {
888 cdm_attached_cb.Run(false);
889 return;
890 }
891
jrummell87a2db52015-05-05 22:27:18892 // If CDM initialization succeeded, tell the pipeline about it.
xhwang80739452016-01-13 00:48:00893 pipeline_.SetCdm(cdm_context, cdm_attached_cb);
xhwang97de4202014-11-25 08:44:01894}
895
jrummell89e61d82015-07-23 20:03:34896void WebMediaPlayerImpl::OnCdmAttached(bool success) {
xhwang97de4202014-11-25 08:44:01897 if (success) {
jrummell89e61d82015-07-23 20:03:34898 set_cdm_result_->complete();
899 set_cdm_result_.reset();
xhwang80739452016-01-13 00:48:00900 is_cdm_attached_ = true;
xhwang97de4202014-11-25 08:44:01901 return;
902 }
903
jrummell89e61d82015-07-23 20:03:34904 set_cdm_result_->completeWithError(
xhwang97de4202014-11-25 08:44:01905 blink::WebContentDecryptionModuleExceptionNotSupportedError, 0,
906 "Unable to set MediaKeys object");
jrummell89e61d82015-07-23 20:03:34907 set_cdm_result_.reset();
[email protected]9ebc3b03f2014-08-13 04:01:23908}
909
sandersd1c0bba02016-03-04 23:14:08910void WebMediaPlayerImpl::OnPipelineSeeked(bool time_updated) {
[email protected]5d11eff2011-09-15 00:06:06911 seeking_ = false;
wolenetz1b2ae7d2015-06-10 00:44:21912 seek_time_ = base::TimeDelta();
hubbe5a2dec022016-03-17 01:14:23913 if (paused_) {
914#if defined(OS_ANDROID) // WMPI_CAST
915 if (isRemote()) {
916 paused_time_ = base::TimeDelta::FromSecondsD(cast_impl_.currentTime());
917 } else {
918 paused_time_ = pipeline_.GetMediaTime();
919 }
920#else
sandersd1c0bba02016-03-04 23:14:08921 paused_time_ = pipeline_.GetMediaTime();
hubbe5a2dec022016-03-17 01:14:23922#endif
923 }
sandersd1c0bba02016-03-04 23:14:08924 if (time_updated)
925 should_notify_time_changed_ = true;
[email protected]8931c41a2009-07-07 17:31:49926}
927
sandersd1c0bba02016-03-04 23:14:08928void WebMediaPlayerImpl::OnPipelineSuspended() {
hubbed5f36882016-01-15 22:40:37929#if defined(OS_ANDROID)
930 if (isRemote()) {
931 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner();
sandersd50a635e2016-04-04 22:50:09932 if (frame)
dalecurtise9c89e92016-05-20 19:38:00933 compositor_->PaintSingleFrame(frame);
hubbed5f36882016-01-15 22:40:37934 }
935#endif
936
dalecurtis37fe5862016-03-15 19:29:09937 // If we're not in an aggressive buffering state, tell the data source we have
938 // enough data so that it may release the connection.
939 if (buffering_strategy_ !=
940 BufferedDataSource::BUFFERING_STRATEGY_AGGRESSIVE) {
liberato3f9f32b2016-03-16 16:54:51941 if (data_source_)
942 data_source_->OnBufferingHaveEnough(true);
dalecurtis37fe5862016-03-15 19:29:09943 }
944
sandersd50a635e2016-04-04 22:50:09945 ReportMemoryUsage();
946
sandersd1c0bba02016-03-04 23:14:08947 if (pending_suspend_resume_cycle_) {
watkdee516f2016-02-18 02:22:19948 pending_suspend_resume_cycle_ = false;
sandersd50a635e2016-04-04 22:50:09949 UpdatePlayState();
dalecurtis0431cbf2016-03-12 01:19:43950 }
sandersd1c0bba02016-03-04 23:14:08951}
952
alokp967c902452016-05-06 05:21:37953void WebMediaPlayerImpl::OnDemuxerOpened() {
954 DCHECK(main_task_runner_->BelongsToCurrentThread());
955 client_->mediaSourceOpened(
956 new WebMediaSourceImpl(chunk_demuxer_, media_log_));
957}
958
959void WebMediaPlayerImpl::OnError(PipelineStatus status) {
960 DVLOG(1) << __FUNCTION__;
961 DCHECK(main_task_runner_->BelongsToCurrentThread());
962 DCHECK_NE(status, PIPELINE_OK);
963
964 if (suppress_destruction_errors_)
965 return;
966
967 ReportPipelineError(load_type_, frame_->getSecurityOrigin(), status);
968 media_log_->AddEvent(media_log_->CreatePipelineErrorEvent(status));
969
970 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing) {
971 // Any error that occurs before reaching ReadyStateHaveMetadata should
972 // be considered a format error.
973 SetNetworkState(WebMediaPlayer::NetworkStateFormatError);
974 } else {
975 SetNetworkState(PipelineErrorToNetworkState(status));
976 }
977
978 UpdatePlayState();
979}
980
981void WebMediaPlayerImpl::OnEnded() {
[email protected]2a06ca62014-06-04 13:59:52982 DVLOG(1) << __FUNCTION__;
acolwellb4034942014-08-28 15:42:43983 DCHECK(main_task_runner_->BelongsToCurrentThread());
scherkusd2c745b2014-09-04 05:03:40984
sandersd1c0bba02016-03-04 23:14:08985 // Ignore state changes until we've completed all outstanding operations.
986 if (!pipeline_controller_.IsStable())
scherkusd2c745b2014-09-04 05:03:40987 return;
988
989 ended_ = true;
[email protected]ce70c982013-12-20 17:04:32990 client_->timeChanged();
sandersd50a635e2016-04-04 22:50:09991
992 // We don't actually want this to run until |client_| calls seek() or pause(),
993 // but that should have already happened in timeChanged() and so this is
994 // expected to be a no-op.
995 UpdatePlayState();
[email protected]576537842009-08-12 23:52:05996}
997
alokp967c902452016-05-06 05:21:37998void WebMediaPlayerImpl::OnMetadata(PipelineMetadata metadata) {
hubbed82bed52015-12-15 23:07:16999 DVLOG(1) << __FUNCTION__;
acolwellb4034942014-08-28 15:42:431000 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]a8e2cb82012-08-17 00:02:391001
[email protected]b8877772014-03-26 20:17:151002 pipeline_metadata_ = metadata;
[email protected]739847c02014-01-16 00:12:251003
dalecurtis849cf4b22015-03-27 18:35:451004 UMA_HISTOGRAM_ENUMERATION("Media.VideoRotation", metadata.video_rotation,
acolwell9e0840d2014-09-06 19:01:321005 VIDEO_ROTATION_MAX + 1);
[email protected]b8877772014-03-26 20:17:151006 SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata);
[email protected]21c3f7502013-03-23 03:29:511007
[email protected]b8877772014-03-26 20:17:151008 if (hasVideo()) {
acolwell9e0840d2014-09-06 19:01:321009 if (pipeline_metadata_.video_rotation == VIDEO_ROTATION_90 ||
1010 pipeline_metadata_.video_rotation == VIDEO_ROTATION_270) {
[email protected]f78c3e82014-08-08 01:24:471011 gfx::Size size = pipeline_metadata_.natural_size;
1012 pipeline_metadata_.natural_size = gfx::Size(size.height(), size.width());
1013 }
1014
watkf835a792016-06-24 23:24:401015 if (fullscreen_ && surface_manager_)
1016 surface_manager_->NaturalSizeChanged(pipeline_metadata_.natural_size);
1017
1018 DCHECK(!video_weblayer_);
dalecurtise1edb312016-06-22 02:33:211019 video_weblayer_.reset(new cc_blink::WebLayerImpl(cc::VideoLayer::Create(
1020 compositor_, pipeline_metadata_.video_rotation)));
jbauman952274d2015-09-10 23:23:361021 video_weblayer_->layer()->SetContentsOpaque(opaque_);
1022 video_weblayer_->SetContentsOpaqueIsFixed(true);
[email protected]a7c4f582014-04-16 18:44:491023 client_->setWebLayer(video_weblayer_.get());
[email protected]a8e2cb82012-08-17 00:02:391024 }
dalecurtis8e4dc682016-03-15 02:30:301025
sandersd50a635e2016-04-04 22:50:091026 UpdatePlayState();
[email protected]a8e2cb82012-08-17 00:02:391027}
1028
alokp967c902452016-05-06 05:21:371029void WebMediaPlayerImpl::OnBufferingStateChange(BufferingState state) {
1030 DVLOG(1) << __FUNCTION__ << "(" << state << ")";
1031 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]b8877772014-03-26 20:17:151032
sandersd1c0bba02016-03-04 23:14:081033 // Ignore buffering state changes until we've completed all outstanding
1034 // operations.
1035 if (!pipeline_controller_.IsStable())
[email protected]ba7d5f92014-06-24 05:37:401036 return;
[email protected]b8877772014-03-26 20:17:151037
chcunninghameb270c92016-07-15 01:00:451038 if (state == BUFFERING_HAVE_ENOUGH) {
1039 // TODO(chcunningham): Monitor playback position vs buffered. Potentially
1040 // transition to HAVE_FUTURE_DATA here if not enough is buffered.
1041 SetReadyState(WebMediaPlayer::ReadyStateHaveEnoughData);
[email protected]ba7d5f92014-06-24 05:37:401042
chcunninghameb270c92016-07-15 01:00:451043 // Let the DataSource know we have enough data. It may use this information
1044 // to release unused network connections.
1045 if (data_source_)
1046 data_source_->OnBufferingHaveEnough(false);
dalecurtis849cf4b22015-03-27 18:35:451047
chcunninghameb270c92016-07-15 01:00:451048 // Blink expects a timeChanged() in response to a seek().
1049 if (should_notify_time_changed_)
1050 client_->timeChanged();
dalecurtis0f0097a2015-12-01 17:40:471051
chcunninghameb270c92016-07-15 01:00:451052 // Once we have enough, start reporting the total memory usage. We'll also
1053 // report once playback starts.
1054 ReportMemoryUsage();
1055 } else {
1056 // Buffering has underflowed.
1057 DCHECK_EQ(state, BUFFERING_HAVE_NOTHING);
1058 // It shouldn't be possible to underflow if we've not advanced past
1059 // HAVE_CURRENT_DATA.
1060 DCHECK_GT(highest_ready_state_, WebMediaPlayer::ReadyStateHaveCurrentData);
1061 SetReadyState(WebMediaPlayer::ReadyStateHaveCurrentData);
1062 }
sandersd50a635e2016-04-04 22:50:091063
1064 UpdatePlayState();
[email protected]b8877772014-03-26 20:17:151065}
1066
alokp967c902452016-05-06 05:21:371067void WebMediaPlayerImpl::OnDurationChange() {
acolwellb4034942014-08-28 15:42:431068 DCHECK(main_task_runner_->BelongsToCurrentThread());
alokp967c902452016-05-06 05:21:371069
1070 // TODO(sandersd): We should call delegate_->DidPlay() with the new duration,
1071 // especially if it changed from <5s to >5s.
1072 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing)
1073 return;
1074
1075 client_->durationChanged();
[email protected]81bb3322011-07-21 15:55:501076}
1077
alokp967c902452016-05-06 05:21:371078void WebMediaPlayerImpl::OnAddTextTrack(const TextTrackConfig& config,
1079 const AddTextTrackDoneCB& done_cb) {
acolwellb4034942014-08-28 15:42:431080 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]71537722013-05-23 06:47:531081
[email protected]8a561062013-11-22 01:19:311082 const WebInbandTextTrackImpl::Kind web_kind =
1083 static_cast<WebInbandTextTrackImpl::Kind>(config.kind());
1084 const blink::WebString web_label =
1085 blink::WebString::fromUTF8(config.label());
1086 const blink::WebString web_language =
1087 blink::WebString::fromUTF8(config.language());
[email protected]427ff102013-11-26 23:45:401088 const blink::WebString web_id =
1089 blink::WebString::fromUTF8(config.id());
[email protected]71537722013-05-23 06:47:531090
dcheng3076abbf2016-04-22 20:42:391091 std::unique_ptr<WebInbandTextTrackImpl> web_inband_text_track(
henriks9cce5fa2014-12-12 09:35:301092 new WebInbandTextTrackImpl(web_kind, web_label, web_language, web_id));
[email protected]8a561062013-11-22 01:19:311093
dcheng3076abbf2016-04-22 20:42:391094 std::unique_ptr<media::TextTrack> text_track(new TextTrackImpl(
dcheng652f5ff2015-12-27 08:54:001095 main_task_runner_, client_, std::move(web_inband_text_track)));
[email protected]8a561062013-11-22 01:19:311096
dcheng652f5ff2015-12-27 08:54:001097 done_cb.Run(std::move(text_track));
[email protected]71537722013-05-23 06:47:531098}
1099
alokp967c902452016-05-06 05:21:371100void WebMediaPlayerImpl::OnWaitingForDecryptionKey() {
1101 DCHECK(main_task_runner_->BelongsToCurrentThread());
1102
1103 encrypted_client_->didBlockPlaybackWaitingForKey();
1104 // TODO(jrummell): didResumePlaybackBlockedForKey() should only be called
1105 // when a key has been successfully added (e.g. OnSessionKeysChange() with
1106 // |has_additional_usable_key| = true). http://crbug.com/461903
1107 encrypted_client_->didResumePlaybackBlockedForKey();
1108}
1109
alokp5d86e9b2016-05-17 20:20:411110void WebMediaPlayerImpl::OnVideoNaturalSizeChange(const gfx::Size& size) {
1111 DCHECK(main_task_runner_->BelongsToCurrentThread());
1112 DCHECK_NE(ready_state_, WebMediaPlayer::ReadyStateHaveNothing);
1113
1114 if (size == pipeline_metadata_.natural_size)
1115 return;
1116
1117 TRACE_EVENT0("media", "WebMediaPlayerImpl::OnNaturalSizeChanged");
1118 media_log_->AddEvent(
1119 media_log_->CreateVideoSizeSetEvent(size.width(), size.height()));
1120
1121 if (fullscreen_ && surface_manager_)
1122 surface_manager_->NaturalSizeChanged(size);
1123
1124 pipeline_metadata_.natural_size = size;
1125 client_->sizeChanged();
1126}
1127
1128void WebMediaPlayerImpl::OnVideoOpacityChange(bool opaque) {
1129 DCHECK(main_task_runner_->BelongsToCurrentThread());
1130 DCHECK_NE(ready_state_, WebMediaPlayer::ReadyStateHaveNothing);
1131
1132 opaque_ = opaque;
1133 // Modify content opaqueness of cc::Layer directly so that
1134 // SetContentsOpaqueIsFixed is ignored.
1135 if (video_weblayer_)
1136 video_weblayer_->layer()->SetContentsOpaque(opaque_);
1137}
1138
dalecurtis0431cbf2016-03-12 01:19:431139void WebMediaPlayerImpl::OnHidden() {
sandersd1e49fb62015-12-12 01:18:061140 DCHECK(main_task_runner_->BelongsToCurrentThread());
sandersd50a635e2016-04-04 22:50:091141 UpdatePlayState();
dalecurtis8b8505e72016-06-10 21:59:171142
1143 // Schedule suspended playing media to be paused if the user doesn't come back
1144 // to it within some timeout period to avoid any autoplay surprises.
1145 ScheduleIdlePauseTimer();
sandersd1e49fb62015-12-12 01:18:061146}
1147
1148void WebMediaPlayerImpl::OnShown() {
1149 DCHECK(main_task_runner_->BelongsToCurrentThread());
sandersd50a635e2016-04-04 22:50:091150 must_suspend_ = false;
dalecurtis8b8505e72016-06-10 21:59:171151 background_pause_timer_.Stop();
sandersd50a635e2016-04-04 22:50:091152 UpdatePlayState();
sandersd1e49fb62015-12-12 01:18:061153}
1154
dalecurtis0431cbf2016-03-12 01:19:431155void WebMediaPlayerImpl::OnSuspendRequested(bool must_suspend) {
1156 DCHECK(main_task_runner_->BelongsToCurrentThread());
1157
sandersd50a635e2016-04-04 22:50:091158 if (must_suspend) {
1159 must_suspend_ = true;
1160 } else {
watk81727bf2016-04-12 00:25:131161 // TODO(sandersd): Remove this when idleness is separate from play state.
1162 if (delegate_state_ == DelegateState::PAUSED_BUT_NOT_IDLE)
sandersd5ea2ba4c2016-04-05 22:40:561163 return;
sandersd50a635e2016-04-04 22:50:091164 is_idle_ = true;
1165 }
1166
1167 UpdatePlayState();
dalecurtis0431cbf2016-03-12 01:19:431168}
1169
dalecurtisbb3eaac2016-01-27 21:10:251170void WebMediaPlayerImpl::OnPlay() {
1171 play();
1172 client_->playbackStateChanged();
1173}
1174
1175void WebMediaPlayerImpl::OnPause() {
1176 pause();
1177 client_->playbackStateChanged();
1178}
1179
1180void WebMediaPlayerImpl::OnVolumeMultiplierUpdate(double multiplier) {
1181 volume_multiplier_ = multiplier;
1182 setVolume(volume_);
1183}
1184
watkdee516f2016-02-18 02:22:191185void WebMediaPlayerImpl::ScheduleRestart() {
sandersd50a635e2016-04-04 22:50:091186 // TODO(watk): All restart logic should be moved into PipelineController.
1187 if (pipeline_.IsRunning() && !pipeline_controller_.IsPipelineSuspended()) {
watkdee516f2016-02-18 02:22:191188 pending_suspend_resume_cycle_ = true;
sandersd50a635e2016-04-04 22:50:091189 UpdatePlayState();
watkdee516f2016-02-18 02:22:191190 }
1191}
1192
hubbed5f36882016-01-15 22:40:371193#if defined(OS_ANDROID) // WMPI_CAST
hubbed5f36882016-01-15 22:40:371194bool WebMediaPlayerImpl::isRemote() const {
1195 return cast_impl_.isRemote();
1196}
1197
1198void WebMediaPlayerImpl::SetMediaPlayerManager(
1199 RendererMediaPlayerManagerInterface* media_player_manager) {
1200 cast_impl_.SetMediaPlayerManager(media_player_manager);
1201}
1202
1203void WebMediaPlayerImpl::requestRemotePlayback() {
1204 cast_impl_.requestRemotePlayback();
1205}
1206
1207void WebMediaPlayerImpl::requestRemotePlaybackControl() {
1208 cast_impl_.requestRemotePlaybackControl();
1209}
1210
1211void WebMediaPlayerImpl::OnRemotePlaybackEnded() {
1212 DVLOG(1) << __FUNCTION__;
1213 DCHECK(main_task_runner_->BelongsToCurrentThread());
1214
1215 ended_ = true;
1216 client_->timeChanged();
1217}
1218
1219void WebMediaPlayerImpl::OnDisconnectedFromRemoteDevice(double t) {
sandersd1c0bba02016-03-04 23:14:081220 DoSeek(base::TimeDelta::FromSecondsD(t), false);
hubbed5f36882016-01-15 22:40:371221
hubbed5f36882016-01-15 22:40:371222 // We already told the delegate we're paused when remoting started.
1223 client_->playbackStateChanged();
1224 client_->disconnectedFromRemoteDevice();
sandersd50a635e2016-04-04 22:50:091225
1226 UpdatePlayState();
hubbed5f36882016-01-15 22:40:371227}
1228
1229void WebMediaPlayerImpl::SuspendForRemote() {
sandersd50a635e2016-04-04 22:50:091230 if (pipeline_controller_.IsPipelineSuspended()) {
hubbed5f36882016-01-15 22:40:371231 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner();
sandersd50a635e2016-04-04 22:50:091232 if (frame)
dalecurtise9c89e92016-05-20 19:38:001233 compositor_->PaintSingleFrame(frame);
hubbed5f36882016-01-15 22:40:371234 }
sandersd50a635e2016-04-04 22:50:091235
1236 UpdatePlayState();
hubbed5f36882016-01-15 22:40:371237}
1238
1239gfx::Size WebMediaPlayerImpl::GetCanvasSize() const {
1240 if (!video_weblayer_)
1241 return pipeline_metadata_.natural_size;
1242
1243 return video_weblayer_->bounds();
1244}
1245
1246void WebMediaPlayerImpl::SetDeviceScaleFactor(float scale_factor) {
1247 cast_impl_.SetDeviceScaleFactor(scale_factor);
1248}
hubbee4027f92016-05-19 05:18:131249
1250void WebMediaPlayerImpl::setPoster(const blink::WebURL& poster) {
1251 cast_impl_.setPoster(poster);
1252}
hubbed5f36882016-01-15 22:40:371253#endif // defined(OS_ANDROID) // WMPI_CAST
1254
[email protected]fee8a902014-06-03 13:43:361255void WebMediaPlayerImpl::DataSourceInitialized(bool success) {
hubbed82bed52015-12-15 23:07:161256 DVLOG(1) << __FUNCTION__;
acolwellb4034942014-08-28 15:42:431257 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]a9415292012-01-19 19:55:201258
dalecurtisea27a3ed2016-06-24 01:41:301259#if defined(OS_ANDROID)
1260 // We can't play HLS URLs with WebMediaPlayerImpl, so in cases where they are
1261 // encountered, instruct the HTML media element to create a new WebMediaPlayer
1262 // instance with the correct URL to trigger WebMediaPlayerAndroid creation.
1263 //
1264 // TODO(tguilbert): Remove this code path once we have the ability to host a
1265 // MediaPlayer within a Mojo media renderer. http://crbug.com/580626
1266 if (data_source_) {
1267 const GURL url_after_redirects = data_source_->GetUrlAfterRedirects();
1268 if (MediaCodecUtil::IsHLSPath(url_after_redirects)) {
1269 client_->requestReload(url_after_redirects);
1270 // |this| may be destructed, do nothing after this.
1271 return;
1272 }
1273 }
1274#endif
1275
[email protected]d250190da3b2012-07-23 22:57:301276 if (!success) {
[email protected]ef405f66b2012-04-18 02:39:551277 SetNetworkState(WebMediaPlayer::NetworkStateFormatError);
sandersd50a635e2016-04-04 22:50:091278
1279 // Not really necessary, since the pipeline was never started, but it at
1280 // least this makes sure that the error handling code is in sync.
1281 UpdatePlayState();
1282
[email protected]a9415292012-01-19 19:55:201283 return;
1284 }
1285
[email protected]ef8394c2013-08-21 20:26:301286 StartPipeline();
[email protected]a9415292012-01-19 19:55:201287}
1288
[email protected]122f40252012-06-12 05:01:561289void WebMediaPlayerImpl::NotifyDownloading(bool is_downloading) {
hubbed82bed52015-12-15 23:07:161290 DVLOG(1) << __FUNCTION__;
[email protected]122f40252012-06-12 05:01:561291 if (!is_downloading && network_state_ == WebMediaPlayer::NetworkStateLoading)
1292 SetNetworkState(WebMediaPlayer::NetworkStateIdle);
1293 else if (is_downloading && network_state_ == WebMediaPlayer::NetworkStateIdle)
1294 SetNetworkState(WebMediaPlayer::NetworkStateLoading);
1295 media_log_->AddEvent(
1296 media_log_->CreateBooleanEvent(
acolwell9e0840d2014-09-06 19:01:321297 MediaLogEvent::NETWORK_ACTIVITY_SET,
[email protected]122f40252012-06-12 05:01:561298 "is_downloading_data", is_downloading));
1299}
1300
watkf835a792016-06-24 23:24:401301void WebMediaPlayerImpl::OnSurfaceCreated(int surface_id) {
1302 fullscreen_surface_id_ = surface_id;
1303 if (!pending_surface_request_cb_.is_null())
1304 base::ResetAndReturn(&pending_surface_request_cb_).Run(surface_id);
1305}
1306
watkdee516f2016-02-18 02:22:191307// TODO(watk): Move this state management out of WMPI.
1308void WebMediaPlayerImpl::OnSurfaceRequested(
1309 const SurfaceCreatedCB& surface_created_cb) {
1310 DCHECK(main_task_runner_->BelongsToCurrentThread());
1311 DCHECK(surface_manager_);
1312
1313 // A null callback indicates that the decoder is going away.
1314 if (surface_created_cb.is_null()) {
1315 decoder_requires_restart_for_fullscreen_ = false;
watkf835a792016-06-24 23:24:401316 pending_surface_request_cb_.Reset();
watkdee516f2016-02-18 02:22:191317 return;
1318 }
1319
1320 // If we're getting a surface request it means GVD is initializing, so until
1321 // we get a null surface request, GVD is the active decoder. While that's the
1322 // case we should restart the pipeline on fullscreen transitions so that when
1323 // we create a new GVD it will request a surface again and get the right kind
1324 // of surface for the fullscreen state.
1325 // TODO(watk): Don't require a pipeline restart to switch surfaces for
1326 // cases where it isn't necessary.
1327 decoder_requires_restart_for_fullscreen_ = true;
1328 if (fullscreen_) {
watkf835a792016-06-24 23:24:401329 if (fullscreen_surface_id_ != SurfaceManager::kNoSurfaceID)
1330 surface_created_cb.Run(fullscreen_surface_id_);
1331 else
1332 pending_surface_request_cb_ = surface_created_cb;
watkdee516f2016-02-18 02:22:191333 } else {
1334 // Tell the decoder to create its own surface.
1335 surface_created_cb.Run(SurfaceManager::kNoSurfaceID);
1336 }
1337}
1338
dcheng3076abbf2016-04-22 20:42:391339std::unique_ptr<Renderer> WebMediaPlayerImpl::CreateRenderer() {
watkdee516f2016-02-18 02:22:191340 RequestSurfaceCB request_surface_cb;
1341#if defined(OS_ANDROID)
1342 request_surface_cb =
1343 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnSurfaceRequested);
1344#endif
sandersd1e49fb62015-12-12 01:18:061345 return renderer_factory_->CreateRenderer(
1346 media_task_runner_, worker_task_runner_, audio_source_provider_.get(),
watkdee516f2016-02-18 02:22:191347 compositor_, request_surface_cb);
sandersd1e49fb62015-12-12 01:18:061348}
1349
[email protected]ef8394c2013-08-21 20:26:301350void WebMediaPlayerImpl::StartPipeline() {
acolwellb4034942014-08-28 15:42:431351 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]ddbc6ff2013-04-19 15:28:331352
xhwange8c4181a2014-12-06 08:10:011353 Demuxer::EncryptedMediaInitDataCB encrypted_media_init_data_cb =
1354 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnEncryptedMediaInitData);
[email protected]2b57e2e2014-05-09 11:07:251355
[email protected]ddbc6ff2013-04-19 15:28:331356 // Figure out which demuxer to use.
[email protected]ef8394c2013-08-21 20:26:301357 if (load_type_ != LoadTypeMediaSource) {
[email protected]ddbc6ff2013-04-19 15:28:331358 DCHECK(!chunk_demuxer_);
[email protected]f5443ef72013-04-22 04:03:381359 DCHECK(data_source_);
1360
j.isorcef6778e652015-11-16 17:14:251361#if !defined(MEDIA_DISABLE_FFMPEG)
servolk81e01e02016-03-05 03:29:151362 Demuxer::MediaTracksUpdatedCB media_tracks_updated_cb =
servolkef1e5ef2016-03-25 04:55:261363 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnFFmpegMediaTracksUpdated);
servolk81e01e02016-03-05 03:29:151364
xhwange8c4181a2014-12-06 08:10:011365 demuxer_.reset(new FFmpegDemuxer(media_task_runner_, data_source_.get(),
servolk81e01e02016-03-05 03:29:151366 encrypted_media_init_data_cb,
1367 media_tracks_updated_cb, media_log_));
j.isorcef6778e652015-11-16 17:14:251368#else
alokp967c902452016-05-06 05:21:371369 OnError(PipelineStatus::DEMUXER_ERROR_COULD_NOT_OPEN);
j.isorcef6778e652015-11-16 17:14:251370 return;
1371#endif
[email protected]ddbc6ff2013-04-19 15:28:331372 } else {
[email protected]f5443ef72013-04-22 04:03:381373 DCHECK(!chunk_demuxer_);
1374 DCHECK(!data_source_);
1375
acolwell9e0840d2014-09-06 19:01:321376 chunk_demuxer_ = new ChunkDemuxer(
[email protected]ef8394c2013-08-21 20:26:301377 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnDemuxerOpened),
wolenetz1fb319d2015-07-14 17:49:041378 encrypted_media_init_data_cb, media_log_, true);
[email protected]f5443ef72013-04-22 04:03:381379 demuxer_.reset(chunk_demuxer_);
[email protected]ddbc6ff2013-04-19 15:28:331380 }
1381
sandersdb5e21462016-03-09 01:49:071382 // TODO(sandersd): FileSystem objects may also be non-static, but due to our
1383 // caching layer such situations are broken already. http://crbug.com/593159
1384 bool is_static = !chunk_demuxer_;
1385
[email protected]f5443ef72013-04-22 04:03:381386 // ... and we're ready to go!
[email protected]d228aeec2014-06-20 19:16:491387 seeking_ = true;
xhwangf94a634d2014-10-22 22:07:271388
sandersd1e49fb62015-12-12 01:18:061389 // TODO(sandersd): On Android, defer Start() if the tab is not visible.
sandersd1c0bba02016-03-04 23:14:081390 bool is_streaming = (data_source_ && data_source_->IsStreaming());
alokp967c902452016-05-06 05:21:371391 pipeline_controller_.Start(demuxer_.get(), this, is_streaming, is_static);
[email protected]f5443ef72013-04-22 04:03:381392}
1393
1394void WebMediaPlayerImpl::SetNetworkState(WebMediaPlayer::NetworkState state) {
[email protected]2a06ca62014-06-04 13:59:521395 DVLOG(1) << __FUNCTION__ << "(" << state << ")";
acolwellb4034942014-08-28 15:42:431396 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]f5443ef72013-04-22 04:03:381397 network_state_ = state;
1398 // Always notify to ensure client has the latest value.
[email protected]ce70c982013-12-20 17:04:321399 client_->networkStateChanged();
[email protected]f5443ef72013-04-22 04:03:381400}
1401
1402void WebMediaPlayerImpl::SetReadyState(WebMediaPlayer::ReadyState state) {
[email protected]2a06ca62014-06-04 13:59:521403 DVLOG(1) << __FUNCTION__ << "(" << state << ")";
acolwellb4034942014-08-28 15:42:431404 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]f5443ef72013-04-22 04:03:381405
[email protected]fee8a902014-06-03 13:43:361406 if (state == WebMediaPlayer::ReadyStateHaveEnoughData && data_source_ &&
1407 data_source_->assume_fully_buffered() &&
[email protected]f5443ef72013-04-22 04:03:381408 network_state_ == WebMediaPlayer::NetworkStateLoading)
1409 SetNetworkState(WebMediaPlayer::NetworkStateLoaded);
1410
1411 ready_state_ = state;
sandersd50a635e2016-04-04 22:50:091412 highest_ready_state_ = std::max(highest_ready_state_, ready_state_);
1413
[email protected]f5443ef72013-04-22 04:03:381414 // Always notify to ensure client has the latest value.
[email protected]ce70c982013-12-20 17:04:321415 client_->readyStateChanged();
[email protected]f5443ef72013-04-22 04:03:381416}
1417
Dana Jansens71331252016-03-09 20:57:221418blink::WebAudioSourceProvider* WebMediaPlayerImpl::getAudioSourceProvider() {
[email protected]ff875be52013-06-02 23:47:381419 return audio_source_provider_.get();
[email protected]f5443ef72013-04-22 04:03:381420}
1421
[email protected]f5443ef72013-04-22 04:03:381422double WebMediaPlayerImpl::GetPipelineDuration() const {
[email protected]f6af7592014-02-28 10:09:111423 base::TimeDelta duration = pipeline_.GetMediaDuration();
[email protected]f5443ef72013-04-22 04:03:381424
1425 // Return positive infinity if the resource is unbounded.
1426 // http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html#dom-media-duration
dalecurtis39a7f932016-07-19 18:34:591427 if (duration == kInfiniteDuration)
[email protected]f5443ef72013-04-22 04:03:381428 return std::numeric_limits<double>::infinity();
1429
1430 return duration.InSecondsF();
1431}
1432
[email protected]dd061e12014-05-06 19:21:221433static void GetCurrentFrameAndSignal(
1434 VideoFrameCompositor* compositor,
acolwell9e0840d2014-09-06 19:01:321435 scoped_refptr<VideoFrame>* video_frame_out,
[email protected]dd061e12014-05-06 19:21:221436 base::WaitableEvent* event) {
1437 TRACE_EVENT0("media", "GetCurrentFrameAndSignal");
dalecurtis44ce4de2015-05-11 18:42:071438 *video_frame_out = compositor->GetCurrentFrameAndUpdateIfStale();
[email protected]dd061e12014-05-06 19:21:221439 event->Signal();
1440}
1441
acolwell9e0840d2014-09-06 19:01:321442scoped_refptr<VideoFrame>
[email protected]dd061e12014-05-06 19:21:221443WebMediaPlayerImpl::GetCurrentFrameFromCompositor() {
1444 TRACE_EVENT0("media", "WebMediaPlayerImpl::GetCurrentFrameFromCompositor");
1445 if (compositor_task_runner_->BelongsToCurrentThread())
dalecurtis44ce4de2015-05-11 18:42:071446 return compositor_->GetCurrentFrameAndUpdateIfStale();
[email protected]dd061e12014-05-06 19:21:221447
1448 // Use a posted task and waitable event instead of a lock otherwise
1449 // WebGL/Canvas can see different content than what the compositor is seeing.
acolwell9e0840d2014-09-06 19:01:321450 scoped_refptr<VideoFrame> video_frame;
gab0d77c7cb2016-06-02 00:00:231451 base::WaitableEvent event(base::WaitableEvent::ResetPolicy::AUTOMATIC,
1452 base::WaitableEvent::InitialState::NOT_SIGNALED);
[email protected]dd061e12014-05-06 19:21:221453 compositor_task_runner_->PostTask(FROM_HERE,
1454 base::Bind(&GetCurrentFrameAndSignal,
1455 base::Unretained(compositor_),
1456 &video_frame,
1457 &event));
1458 event.Wait();
1459 return video_frame;
1460}
1461
sandersd50a635e2016-04-04 22:50:091462void WebMediaPlayerImpl::UpdatePlayState() {
hubbed5f36882016-01-15 22:40:371463#if defined(OS_ANDROID) // WMPI_CAST
sandersd50a635e2016-04-04 22:50:091464 bool is_remote = isRemote();
1465#else
1466 bool is_remote = false;
hubbed5f36882016-01-15 22:40:371467#endif
dalecurtis8b8505e72016-06-10 21:59:171468 bool is_suspended = pipeline_controller_.IsSuspended();
sandersd50a635e2016-04-04 22:50:091469 bool is_backgrounded =
1470 IsBackgroundedSuspendEnabled() && delegate_ && delegate_->IsHidden();
dalecurtis8b8505e72016-06-10 21:59:171471 PlayState state = UpdatePlayState_ComputePlayState(is_remote, is_suspended,
1472 is_backgrounded);
sandersd50a635e2016-04-04 22:50:091473 SetDelegateState(state.delegate_state);
1474 SetMemoryReportingState(state.is_memory_reporting_enabled);
1475 SetSuspendState(state.is_suspended || pending_suspend_resume_cycle_);
1476}
dalecurtis5bbc487e2016-02-27 04:15:051477
sandersd50a635e2016-04-04 22:50:091478void WebMediaPlayerImpl::SetDelegateState(DelegateState new_state) {
1479 if (!delegate_ || delegate_state_ == new_state)
dalecurtis5bbc487e2016-02-27 04:15:051480 return;
1481
sandersd50a635e2016-04-04 22:50:091482 delegate_state_ = new_state;
1483
1484 switch (delegate_state_) {
1485 case DelegateState::GONE:
1486 delegate_->PlayerGone(delegate_id_);
1487 break;
1488 case DelegateState::PLAYING:
1489 delegate_->DidPlay(delegate_id_, hasVideo(), hasAudio(), false,
1490 pipeline_.GetMediaDuration());
1491 break;
1492 case DelegateState::PAUSED:
1493 delegate_->DidPause(delegate_id_, false);
1494 break;
watk81727bf2016-04-12 00:25:131495 case DelegateState::PAUSED_BUT_NOT_IDLE:
sandersd5ea2ba4c2016-04-05 22:40:561496 // It doesn't really matter what happens when we enter this state, only
1497 // that we reset the idle timer when leaving it.
1498 //
watk81727bf2016-04-12 00:25:131499 // TODO(sandersd): Ideally the delegate would consider idleness and play
1500 // state as orthogonal properties so that we could avoid this.
sandersd5ea2ba4c2016-04-05 22:40:561501 delegate_->DidPause(delegate_id_, false);
1502 break;
sandersd50a635e2016-04-04 22:50:091503 case DelegateState::ENDED:
1504 delegate_->DidPause(delegate_id_, true);
1505 break;
dalecurtis0f0097a2015-12-01 17:40:471506 }
1507}
1508
sandersd50a635e2016-04-04 22:50:091509void WebMediaPlayerImpl::SetMemoryReportingState(
1510 bool is_memory_reporting_enabled) {
1511 if (memory_usage_reporting_timer_.IsRunning() ==
1512 is_memory_reporting_enabled) {
hubbed5f36882016-01-15 22:40:371513 return;
sandersd50a635e2016-04-04 22:50:091514 }
sandersd1c0bba02016-03-04 23:14:081515
sandersd50a635e2016-04-04 22:50:091516 if (is_memory_reporting_enabled) {
1517 memory_usage_reporting_timer_.Start(FROM_HERE,
1518 base::TimeDelta::FromSeconds(2), this,
1519 &WebMediaPlayerImpl::ReportMemoryUsage);
1520 } else {
1521 memory_usage_reporting_timer_.Stop();
1522 ReportMemoryUsage();
1523 }
1524}
1525
1526void WebMediaPlayerImpl::SetSuspendState(bool is_suspended) {
1527 // Do not change the state after an error has occurred.
1528 // TODO(sandersd): Update PipelineController to remove the need for this.
1529 if (IsNetworkStateError(network_state_))
sandersd1c0bba02016-03-04 23:14:081530 return;
1531
halliwell6451e242016-06-01 15:00:241532#if !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
1533 // TODO(sandersd): idle suspend is disabled if decoder owns video frame.
1534 // Used on OSX,Windows+Chromecast. Since GetCurrentFrameFromCompositor is
1535 // a synchronous cross-thread post, avoid the cost on platforms that
1536 // always allow suspend. Need to find a better mechanism for this. See
1537 // http://crbug.com/595716 and http://crbug.com/602708
dalecurtis7f366b2242016-04-13 01:16:171538 if (can_suspend_state_ == CanSuspendState::UNKNOWN) {
1539 scoped_refptr<VideoFrame> frame = GetCurrentFrameFromCompositor();
1540 if (frame) {
1541 can_suspend_state_ =
1542 frame->metadata()->IsTrue(VideoFrameMetadata::DECODER_OWNS_FRAME)
1543 ? CanSuspendState::NO
1544 : CanSuspendState::YES;
1545 }
1546 }
1547#else
1548 can_suspend_state_ = CanSuspendState::YES;
1549#endif
1550
1551 if (can_suspend_state_ == CanSuspendState::NO)
1552 return;
1553
sandersd50a635e2016-04-04 22:50:091554 if (is_suspended) {
1555 pipeline_controller_.Suspend();
1556 } else {
1557 pipeline_controller_.Resume();
1558 }
1559}
1560
1561WebMediaPlayerImpl::PlayState
1562WebMediaPlayerImpl::UpdatePlayState_ComputePlayState(bool is_remote,
dalecurtis8b8505e72016-06-10 21:59:171563 bool is_suspended,
sandersd50a635e2016-04-04 22:50:091564 bool is_backgrounded) {
1565 PlayState result;
1566
1567 // This includes both data source (before pipeline startup) and pipeline
1568 // errors.
1569 bool has_error = IsNetworkStateError(network_state_);
1570
1571 // After HaveMetadata, we know which tracks are present and the duration.
1572 bool have_metadata = ready_state_ >= WebMediaPlayer::ReadyStateHaveMetadata;
1573
1574 // After HaveFutureData, Blink will call play() if the state is not paused.
1575 bool have_future_data =
1576 highest_ready_state_ >= WebMediaPlayer::ReadyStateHaveFutureData;
1577
dalecurtis8b8505e72016-06-10 21:59:171578 // Background suspend is not enabled for audio-only players unless paused,
1579 // though in the case of audio-only the session should be kept.
sandersd50a635e2016-04-04 22:50:091580 bool background_suspended = is_backgrounded && have_metadata && hasVideo();
1581
dalecurtis8b8505e72016-06-10 21:59:171582 // The |paused_| state is not reliable until we |have_future_data|.
1583 bool background_pause_suspended =
1584 is_backgrounded && have_future_data && paused_;
1585
sandersd50a635e2016-04-04 22:50:091586 // Idle suspend is enabled once there is future data. We don't want to idle
1587 // suspend before that because play() may never be triggered to leave the idle
1588 // state. There could be other theoretical problems if the page is waiting for
1589 // other events before actually calling play(), but at least we don't break
1590 // Blink.
1591 //
1592 // TODO(sandersd): Make the delegate suspend idle players immediately when
1593 // hidden.
1594 // TODO(sandersd): If Blink told us the paused state sooner, we could
1595 // idle suspend sooner.
1596 bool idle_suspended = is_idle_ && have_future_data;
1597
1598 // Combined suspend state.
1599 result.is_suspended =
dalecurtis8b8505e72016-06-10 21:59:171600 is_remote || must_suspend_ || idle_suspended || background_suspended ||
1601 background_pause_suspended ||
1602 // If we're already suspended, see if we can wait for user interaction.
1603 (is_suspended && have_future_data && paused_ && !seeking_);
sandersd50a635e2016-04-04 22:50:091604
1605 // We do not treat |playback_rate_| == 0 as paused. For the media session,
1606 // being paused implies displaying a play button, which is incorrect in this
1607 // case. For memory usage reporting, we just use the same definition (but we
1608 // don't have to).
1609 //
1610 // Similarly, we don't consider |ended_| to be paused. Blink will immediately
1611 // call pause() or seek(), so |ended_| should not affect the computation.
1612 // Despite that, |ended_| does result in a separate paused state, to simplfy
1613 // the contract for SetDelegateState().
1614 //
1615 // |has_session| is used to decide when to create a media session. Idle
1616 // suspension does not destroy the media session, because we expect that the
1617 // notification controls (and audio focus) remain. We also require:
1618 // - |have_metadata|, since the tracks and duration are passed to DidPlay().
1619 // - |have_future_data|, since we need to know whether we are paused to
1620 // correctly configure the session.
1621 //
1622 // TODO(sandersd): If Blink told us the paused state sooner, we could create
1623 // the media session sooner.
1624 bool can_play = !has_error && !is_remote && have_future_data;
1625 bool has_session = can_play && !must_suspend_ && !background_suspended;
1626
1627 if (!has_session) {
1628 result.delegate_state = DelegateState::GONE;
1629 } else if (paused_) {
watk81727bf2016-04-12 00:25:131630 if (seeking() || fullscreen_) {
1631 result.delegate_state = DelegateState::PAUSED_BUT_NOT_IDLE;
sandersd5ea2ba4c2016-04-05 22:40:561632 } else if (ended_) {
1633 result.delegate_state = DelegateState::ENDED;
1634 } else {
1635 result.delegate_state = DelegateState::PAUSED;
1636 }
sandersd50a635e2016-04-04 22:50:091637 } else {
1638 result.delegate_state = DelegateState::PLAYING;
1639 }
1640
dalecurtis8b8505e72016-06-10 21:59:171641 // It's not critical if some cases where memory usage can change are missed,
sandersd50a635e2016-04-04 22:50:091642 // since media memory changes are usually gradual.
1643 result.is_memory_reporting_enabled =
1644 can_play && !result.is_suspended && !paused_;
1645
1646 return result;
dalecurtis0f0097a2015-12-01 17:40:471647}
1648
dalecurtis83266c72015-10-29 18:43:201649void WebMediaPlayerImpl::ReportMemoryUsage() {
1650 DCHECK(main_task_runner_->BelongsToCurrentThread());
1651
wdzierzanowskifd4cd91c52015-12-02 23:50:201652 // About base::Unretained() usage below: We destroy |demuxer_| on the main
1653 // thread. Before that, however, ~WebMediaPlayerImpl() posts a task to the
1654 // media thread and waits for it to finish. Hence, the GetMemoryUsage() task
1655 // posted here must finish earlier.
1656
1657 if (demuxer_) {
1658 base::PostTaskAndReplyWithResult(
1659 media_task_runner_.get(), FROM_HERE,
1660 base::Bind(&Demuxer::GetMemoryUsage, base::Unretained(demuxer_.get())),
1661 base::Bind(&WebMediaPlayerImpl::FinishMemoryUsageReport, AsWeakPtr()));
1662 } else {
1663 FinishMemoryUsageReport(0);
1664 }
1665}
1666
1667void WebMediaPlayerImpl::FinishMemoryUsageReport(int64_t demuxer_memory_usage) {
1668 DCHECK(main_task_runner_->BelongsToCurrentThread());
1669
dalecurtis83266c72015-10-29 18:43:201670 const PipelineStatistics stats = pipeline_.GetStatistics();
1671 const int64_t current_memory_usage =
1672 stats.audio_memory_usage + stats.video_memory_usage +
1673 (data_source_ ? data_source_->GetMemoryUsage() : 0) +
wdzierzanowskifd4cd91c52015-12-02 23:50:201674 demuxer_memory_usage;
dalecurtis83266c72015-10-29 18:43:201675
dalecurtis3a7d38f42016-03-07 21:17:131676 // Note, this isn't entirely accurate, there may be VideoFrames held by the
1677 // compositor or other resources that we're unaware of.
1678
dalecurtis83266c72015-10-29 18:43:201679 DVLOG(2) << "Memory Usage -- Audio: " << stats.audio_memory_usage
1680 << ", Video: " << stats.video_memory_usage << ", DataSource: "
1681 << (data_source_ ? data_source_->GetMemoryUsage() : 0)
wdzierzanowskifd4cd91c52015-12-02 23:50:201682 << ", Demuxer: " << demuxer_memory_usage;
dalecurtis83266c72015-10-29 18:43:201683
1684 const int64_t delta = current_memory_usage - last_reported_memory_usage_;
1685 last_reported_memory_usage_ = current_memory_usage;
1686 adjust_allocated_memory_cb_.Run(delta);
1687}
1688
dalecurtis8b8505e72016-06-10 21:59:171689void WebMediaPlayerImpl::ScheduleIdlePauseTimer() {
1690 // Only schedule the pause timer if we're playing and are suspended. We use
1691 // delegate state as a proxy for suspended here since the suspension may be in
1692 // flight at the time of this call.
1693 if (paused_ || delegate_state_ != DelegateState::GONE)
1694 return;
1695
1696#if defined(OS_ANDROID)
1697 // Remote players will be suspended and locally paused.
1698 if (isRemote())
1699 return;
1700#endif
1701
1702 // Idle timeout chosen arbitrarily.
1703 background_pause_timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(5),
1704 this, &WebMediaPlayerImpl::OnPause);
1705}
1706
acolwell9e0840d2014-09-06 19:01:321707} // namespace media