blob: 9ecacb5983e0177d6f4b5cada9846b2b966dec0d [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"
servolkf94b4602017-01-31 16:44:2721#include "base/memory/ptr_util.h"
asvitkine30330812016-08-30 04:01:0822#include "base/metrics/histogram_macros.h"
acolwellb4034942014-08-28 15:42:4323#include "base/single_thread_task_runner.h"
servolka233f832016-06-10 20:39:0424#include "base/strings/string_number_conversions.h"
wdzierzanowskifd4cd91c52015-12-02 23:50:2025#include "base/task_runner_util.h"
gabba14a442016-05-11 20:10:2026#include "base/threading/thread_task_runner_handle.h"
ssid9525f4672015-01-28 12:13:1527#include "base/trace_event/trace_event.h"
sandersd1e49fb62015-12-12 01:18:0628#include "build/build_config.h"
[email protected]38564622014-08-19 02:47:1829#include "cc/blink/web_layer_impl.h"
[email protected]21c3f7502013-03-23 03:29:5130#include "cc/layers/video_layer.h"
[email protected]e4fc09e2012-04-06 03:17:4431#include "media/audio/null_audio_sink.h"
[email protected]2eccbed2014-01-10 05:15:5332#include "media/base/bind_to_current_loop.h"
xhwang0ad11e512014-11-25 23:43:0933#include "media/base/cdm_context.h"
xhwang79b193042016-12-13 18:52:4334#include "media/base/content_decryption_module.h"
[email protected]32da1002010-03-03 21:57:3535#include "media/base/limits.h"
zqzhang5d8eab72016-08-26 20:34:3036#include "media/base/media_content_type.h"
[email protected]090f7312011-08-05 23:26:4037#include "media/base/media_log.h"
sandersd1e49fb62015-12-12 01:18:0638#include "media/base/media_switches.h"
tguilbert25a4d112016-10-13 21:56:5139#include "media/base/media_url_demuxer.h"
[email protected]8a561062013-11-22 01:19:3140#include "media/base/text_renderer.h"
watk9f9dfdc92015-09-04 21:33:2941#include "media/base/timestamp_constants.h"
[email protected]e81283bb2010-08-31 18:01:2142#include "media/base/video_frame.h"
acolwell9e0840d2014-09-06 19:01:3243#include "media/blink/texttrack_impl.h"
dalecurtis04bdb582016-08-17 22:15:2344#include "media/blink/watch_time_reporter.h"
acolwell9e0840d2014-09-06 19:01:3245#include "media/blink/webaudiosourceprovider_impl.h"
xhwang97de4202014-11-25 08:44:0146#include "media/blink/webcontentdecryptionmodule_impl.h"
acolwell9e0840d2014-09-06 19:01:3247#include "media/blink/webinbandtexttrack_impl.h"
48#include "media/blink/webmediaplayer_delegate.h"
acolwell9e0840d2014-09-06 19:01:3249#include "media/blink/webmediaplayer_util.h"
50#include "media/blink/webmediasource_impl.h"
[email protected]efe7cd22012-09-12 23:55:0151#include "media/filters/chunk_demuxer.h"
[email protected]ddbc6ff2013-04-19 15:28:3352#include "media/filters/ffmpeg_demuxer.h"
jrummellc9d8e532015-02-26 18:38:1953#include "third_party/WebKit/public/platform/WebEncryptedMediaTypes.h"
srirama.m26f864d02015-07-14 05:21:4654#include "third_party/WebKit/public/platform/WebMediaPlayerClient.h"
55#include "third_party/WebKit/public/platform/WebMediaPlayerEncryptedMediaClient.h"
guidou9bfe4e2f2016-04-09 08:31:1956#include "third_party/WebKit/public/platform/WebMediaPlayerSource.h"
[email protected]745746d2013-08-23 02:09:1657#include "third_party/WebKit/public/platform/WebMediaSource.h"
[email protected]c10884462013-05-30 00:22:0958#include "third_party/WebKit/public/platform/WebRect.h"
mek966863c2016-02-04 23:39:0559#include "third_party/WebKit/public/platform/WebSecurityOrigin.h"
[email protected]c10884462013-05-30 00:22:0960#include "third_party/WebKit/public/platform/WebSize.h"
61#include "third_party/WebKit/public/platform/WebString.h"
62#include "third_party/WebKit/public/platform/WebURL.h"
tguilbert9881bc22016-10-27 03:13:4163#include "third_party/WebKit/public/web/WebDocument.h"
xhwang0acca44b2015-06-18 00:43:3164#include "third_party/WebKit/public/web/WebFrame.h"
[email protected]80504652014-04-18 04:41:5065#include "third_party/WebKit/public/web/WebLocalFrame.h"
[email protected]2255a9332013-06-17 05:12:3166#include "third_party/WebKit/public/web/WebView.h"
[email protected]b3f2b912009-04-09 16:18:5267
dalecurtisea27a3ed2016-06-24 01:41:3068#if defined(OS_ANDROID)
69#include "media/base/android/media_codec_util.h"
70#endif
71
[email protected]180ef242013-11-07 06:50:4672using blink::WebCanvas;
73using blink::WebMediaPlayer;
74using blink::WebRect;
75using blink::WebSize;
76using blink::WebString;
hubbed5f36882016-01-15 22:40:3777using gpu::gles2::GLES2Interface;
78
danakj365175c2016-02-06 00:37:3779#define STATIC_ASSERT_ENUM(a, b) \
80 static_assert(static_cast<int>(a) == static_cast<int>(b), \
81 "mismatching enums: " #a)
82
hubbed5f36882016-01-15 22:40:3783namespace media {
[email protected]ec9212f2008-12-18 21:40:3684
[email protected]8931c41a2009-07-07 17:31:4985namespace {
86
[email protected]378f0b72009-08-11 17:11:4287// Limits the range of playback rate.
88//
89// TODO(kylep): Revisit these.
90//
91// Vista has substantially lower performance than XP or Windows7. If you speed
92// up a video too much, it can't keep up, and rendering stops updating except on
93// the time bar. For really high speeds, audio becomes a bottleneck and we just
94// use up the data we have, which may not achieve the speed requested, but will
95// not crash the tab.
96//
97// A very slow speed, ie 0.00000001x, causes the machine to lock up. (It seems
98// like a busy loop). It gets unresponsive, although its not completely dead.
99//
100// Also our timers are not very accurate (especially for ogg), which becomes
101// evident at low speeds and on Vista. Since other speeds are risky and outside
102// the norms, we think 1/16x to 16x is a safe and useful range for now.
[email protected]39bdde32013-04-17 17:44:20103const double kMinRate = 0.0625;
104const double kMaxRate = 16.0;
[email protected]378f0b72009-08-11 17:11:42105
hubbed5f36882016-01-15 22:40:37106void SetSinkIdOnMediaThread(scoped_refptr<WebAudioSourceProviderImpl> sink,
107 const std::string& device_id,
108 const url::Origin& security_origin,
olka68b69392016-04-01 11:42:12109 const OutputDeviceStatusCB& callback) {
110 sink->SwitchOutputDevice(device_id, security_origin, callback);
guidouc7babef2015-10-22 00:42:35111}
112
sandersd50a635e2016-04-04 22:50:09113bool IsBackgroundedSuspendEnabled() {
dalecurtis0431cbf2016-03-12 01:19:43114#if !defined(OS_ANDROID)
115 // Suspend/Resume is only enabled by default on Android.
116 return base::CommandLine::ForCurrentProcess()->HasSwitch(
117 switches::kEnableMediaSuspend);
118#else
119 return !base::CommandLine::ForCurrentProcess()->HasSwitch(
120 switches::kDisableMediaSuspend);
121#endif
122}
123
avayvod48a8be52016-08-04 19:52:50124bool IsResumeBackgroundVideosEnabled() {
125 return base::FeatureList::IsEnabled(kResumeBackgroundVideo);
126}
127
avayvod39c102402016-11-23 21:43:13128bool IsBackgroundVideoTrackOptimizationEnabled() {
129 return base::FeatureList::IsEnabled(kBackgroundVideoTrackOptimization);
130}
131
sandersd50a635e2016-04-04 22:50:09132bool IsNetworkStateError(blink::WebMediaPlayer::NetworkState state) {
133 bool result = state == blink::WebMediaPlayer::NetworkStateFormatError ||
134 state == blink::WebMediaPlayer::NetworkStateNetworkError ||
135 state == blink::WebMediaPlayer::NetworkStateDecodeError;
136 DCHECK_EQ(state > blink::WebMediaPlayer::NetworkStateLoaded, result);
137 return result;
138}
139
sandersd2c478422016-08-02 01:19:25140gfx::Size GetRotatedVideoSize(VideoRotation rotation, gfx::Size natural_size) {
141 if (rotation == VIDEO_ROTATION_90 || rotation == VIDEO_ROTATION_270)
142 return gfx::Size(natural_size.height(), natural_size.width());
143 return natural_size;
144}
145
dalecurtis04bdb582016-08-17 22:15:23146base::TimeDelta GetCurrentTimeInternal(WebMediaPlayerImpl* p_this) {
147 // We wrap currentTime() instead of using pipeline_.GetMediaTime() since there
148 // are a variety of cases in which that time is not accurate; e.g., while
149 // remoting and during a pause or seek.
150 return base::TimeDelta::FromSecondsD(p_this->currentTime());
151}
152
sandersd35d2c3f2017-01-14 02:04:42153// How much time must have elapsed since loading last progressed before we
154// assume that the decoder will have had time to complete preroll.
155constexpr base::TimeDelta kPrerollAttemptTimeout =
watkd026f792016-11-05 00:28:51156 base::TimeDelta::FromSeconds(3);
157
[email protected]8931c41a2009-07-07 17:31:49158} // namespace
159
[email protected]6683e1b2014-04-10 01:45:38160class BufferedDataSourceHostImpl;
161
danakj365175c2016-02-06 00:37:37162STATIC_ASSERT_ENUM(WebMediaPlayer::CORSModeUnspecified,
163 UrlData::CORS_UNSPECIFIED);
164STATIC_ASSERT_ENUM(WebMediaPlayer::CORSModeAnonymous, UrlData::CORS_ANONYMOUS);
165STATIC_ASSERT_ENUM(WebMediaPlayer::CORSModeUseCredentials,
166 UrlData::CORS_USE_CREDENTIALS);
[email protected]a5a01102012-06-06 17:01:24167
[email protected]5b5bb9d2010-10-22 19:57:36168WebMediaPlayerImpl::WebMediaPlayerImpl(
[email protected]35b2a972014-04-04 15:50:22169 blink::WebLocalFrame* frame,
[email protected]180ef242013-11-07 06:50:46170 blink::WebMediaPlayerClient* client,
srirama.m26f864d02015-07-14 05:21:46171 blink::WebMediaPlayerEncryptedMediaClient* encrypted_client,
tguilbert1bb1c782017-01-23 21:15:11172 WebMediaPlayerDelegate* delegate,
dcheng3076abbf2016-04-22 20:42:39173 std::unique_ptr<RendererFactory> renderer_factory,
hubbe5f0ad43b2015-12-14 20:57:26174 linked_ptr<UrlIndex> url_index,
[email protected]e82b2bd2013-01-02 17:47:57175 const WebMediaPlayerParams& params)
[email protected]f6af7592014-02-28 10:09:11176 : frame_(frame),
sandersd50a635e2016-04-04 22:50:09177 delegate_state_(DelegateState::GONE),
sandersd35d2c3f2017-01-14 02:04:42178 delegate_has_audio_(false),
[email protected]ef405f66b2012-04-18 02:39:55179 network_state_(WebMediaPlayer::NetworkStateEmpty),
180 ready_state_(WebMediaPlayer::ReadyStateHaveNothing),
sandersd50a635e2016-04-04 22:50:09181 highest_ready_state_(WebMediaPlayer::ReadyStateHaveNothing),
dalecurtisb6e052f52016-08-25 00:35:55182 preload_(MultibufferDataSource::AUTO),
183 buffering_strategy_(MultibufferDataSource::BUFFERING_STRATEGY_NORMAL),
altiminbf328382016-12-07 14:28:31184 main_task_runner_(frame->loadingTaskRunner()),
acolwell755d12d2014-08-30 01:09:19185 media_task_runner_(params.media_task_runner()),
dcastagna617d086b2015-08-20 01:39:30186 worker_task_runner_(params.worker_task_runner()),
acolwell755d12d2014-08-30 01:09:19187 media_log_(params.media_log()),
acolwellb4034942014-08-28 15:42:43188 pipeline_(media_task_runner_, media_log_.get()),
sandersd1c0bba02016-03-04 23:14:08189 pipeline_controller_(
190 &pipeline_,
191 base::Bind(&WebMediaPlayerImpl::CreateRenderer,
192 base::Unretained(this)),
193 base::Bind(&WebMediaPlayerImpl::OnPipelineSeeked, AsWeakPtr()),
194 base::Bind(&WebMediaPlayerImpl::OnPipelineSuspended, AsWeakPtr()),
avayvod2135a642017-01-13 00:17:14195 base::Bind(&WebMediaPlayerImpl::OnBeforePipelineResume, AsWeakPtr()),
196 base::Bind(&WebMediaPlayerImpl::OnPipelineResumed, AsWeakPtr()),
alokp967c902452016-05-06 05:21:37197 base::Bind(&WebMediaPlayerImpl::OnError, AsWeakPtr())),
[email protected]f988d9b2014-07-25 00:35:43198 load_type_(LoadTypeURL),
[email protected]75e145a2014-04-15 17:44:32199 opaque_(false),
wolenetz1b2ae7d2015-06-10 00:44:21200 playback_rate_(0.0),
[email protected]49480902009-07-14 20:23:43201 paused_(true),
avayvodeb9098d2017-01-07 00:33:03202 paused_when_hidden_(false),
[email protected]b3766a22010-12-22 17:34:13203 seeking_(false),
watkdee516f2016-02-18 02:22:19204 pending_suspend_resume_cycle_(false),
scherkusd2c745b2014-09-04 05:03:40205 ended_(false),
yoichio863bebf2016-03-04 07:56:58206 should_notify_time_changed_(false),
tsunghungee562e92016-07-20 18:03:31207 overlay_enabled_(false),
208 decoder_requires_restart_for_overlay_(false),
[email protected]5badb082010-06-11 17:40:15209 client_(client),
srirama.m26f864d02015-07-14 05:21:46210 encrypted_client_(encrypted_client),
[email protected]baff4512011-10-19 18:21:07211 delegate_(delegate),
dalecurtisbb3eaac2016-01-27 21:10:25212 delegate_id_(0),
[email protected]d726eddc2013-07-02 22:25:55213 defer_load_cb_(params.defer_load_cb()),
dongseong.hwang0c4e9d82015-01-08 20:11:13214 context_3d_cb_(params.context_3d_cb()),
dalecurtis83266c72015-10-29 18:43:20215 adjust_allocated_memory_cb_(params.adjust_allocated_memory_cb()),
216 last_reported_memory_usage_(0),
[email protected]132dd57c2012-08-10 23:24:34217 supports_save_(true),
[email protected]f5443ef72013-04-22 04:03:38218 chunk_demuxer_(NULL),
hubbe5f0ad43b2015-12-14 20:57:26219 url_index_(url_index),
Bartosz Fabianowski85a823812015-04-16 10:27:51220 // Threaded compositing isn't enabled universally yet.
fdoraydb3ef7d2016-06-09 15:42:38221 compositor_task_runner_(params.compositor_task_runner()
222 ? params.compositor_task_runner()
223 : base::ThreadTaskRunnerHandle::Get()),
alokp5d86e9b2016-05-17 20:20:41224 compositor_(new VideoFrameCompositor(compositor_task_runner_)),
hubbed5f36882016-01-15 22:40:37225#if defined(OS_ANDROID) // WMPI_CAST
dalecurtisbb3eaac2016-01-27 21:10:25226 cast_impl_(this, client_, params.context_3d_cb()),
hubbed5f36882016-01-15 22:40:37227#endif
dalecurtisbb3eaac2016-01-27 21:10:25228 volume_(1.0),
229 volume_multiplier_(1.0),
watkdee516f2016-02-18 02:22:19230 renderer_factory_(std::move(renderer_factory)),
dalecurtis2ff781da2016-03-03 01:52:13231 surface_manager_(params.surface_manager()),
tsunghungee562e92016-07-20 18:03:31232 overlay_surface_id_(SurfaceManager::kNoSurfaceID),
dalecurtis7f366b2242016-04-13 01:16:17233 suppress_destruction_errors_(false),
jameswest451a5bb2017-01-27 03:59:39234 suspend_enabled_(params.allow_suspend()),
tguilbert25a4d112016-10-13 21:56:51235 use_fallback_path_(false),
dalecurtis9d638a12016-08-30 06:20:55236 is_encrypted_(false),
xjzd3fe45a2016-10-12 18:26:37237 underflow_count_(0),
sandersd35d2c3f2017-01-14 02:04:42238 preroll_attempt_pending_(false),
avayvod590011e32017-01-20 02:01:00239 observer_(params.media_observer()),
240 max_keyframe_distance_to_disable_background_video_(
servolkf94b4602017-01-31 16:44:27241 params.max_keyframe_distance_to_disable_background_video()),
242 enable_instant_source_buffer_gc_(
243 params.enable_instant_source_buffer_gc()) {
dalecurtis83266c72015-10-29 18:43:20244 DCHECK(!adjust_allocated_memory_cb_.is_null());
xhwang59d4175a2016-01-14 03:19:30245 DCHECK(renderer_factory_);
servolkef1e5ef2016-03-25 04:55:26246 DCHECK(client_);
tguilbert1bb1c782017-01-23 21:15:11247 DCHECK(delegate_);
dalecurtis83266c72015-10-29 18:43:20248
watkd026f792016-11-05 00:28:51249 tick_clock_.reset(new base::DefaultTickClock());
250
tsunghungee562e92016-07-20 18:03:31251 force_video_overlays_ = base::CommandLine::ForCurrentProcess()->HasSwitch(
252 switches::kForceVideoOverlays);
253
ampea73f792017-01-19 04:05:39254 enable_fullscreen_video_overlays_ =
255 base::FeatureList::IsEnabled(media::kOverlayFullscreenVideo);
256
tguilbert1bb1c782017-01-23 21:15:11257 delegate_id_ = delegate_->AddObserver(this);
258 delegate_->SetIdle(delegate_id_, true);
sandersd1e49fb62015-12-12 01:18:06259
[email protected]c93eb0a62011-08-09 22:47:24260 media_log_->AddEvent(
acolwell9e0840d2014-09-06 19:01:32261 media_log_->CreateEvent(MediaLogEvent::WEBMEDIAPLAYER_CREATED));
[email protected]4e6be3f2009-05-07 02:24:44262
jrummelle616ee92016-10-08 02:15:44263 if (params.initial_cdm())
264 SetCdm(params.initial_cdm());
xhwang0ad11e512014-11-25 23:43:09265
xhwangf94a634d2014-10-22 22:07:27266 // TODO(xhwang): When we use an external Renderer, many methods won't work,
xhwang6fa356202014-12-11 00:44:12267 // e.g. GetCurrentFrameFromCompositor(). See http://crbug.com/434861
olkae4ba2ed82016-12-06 16:34:51268 audio_source_provider_ =
269 new WebAudioSourceProviderImpl(params.audio_renderer_sink(), media_log_);
[email protected]ec9212f2008-12-18 21:40:36270}
271
[email protected]4e6be3f2009-05-07 02:24:44272WebMediaPlayerImpl::~WebMediaPlayerImpl() {
acolwellb4034942014-08-28 15:42:43273 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53274
alokp1116967f2016-06-11 17:30:56275 suppress_destruction_errors_ = true;
tguilbert1bb1c782017-01-23 21:15:11276
277 delegate_->PlayerGone(delegate_id_);
278 delegate_->RemoveObserver(delegate_id_);
[email protected]baff4512011-10-19 18:21:07279
dalecurtis04bdb582016-08-17 22:15:23280 // Finalize any watch time metrics before destroying the pipeline.
281 watch_time_reporter_.reset();
282
alokp967c902452016-05-06 05:21:37283 // Pipeline must be stopped before it is destroyed.
284 pipeline_.Stop();
[email protected]f6af7592014-02-28 10:09:11285
dalecurtis83266c72015-10-29 18:43:20286 if (last_reported_memory_usage_)
287 adjust_allocated_memory_cb_.Run(-last_reported_memory_usage_);
288
dalecurtise1edb312016-06-22 02:33:21289 // Destruct compositor resources in the proper order.
290 client_->setWebLayer(nullptr);
291 if (video_weblayer_)
292 static_cast<cc::VideoLayer*>(video_weblayer_->layer())->StopUsingProvider();
[email protected]dd061e12014-05-06 19:21:22293 compositor_task_runner_->DeleteSoon(FROM_HERE, compositor_);
xhwangea8bb3562015-06-08 21:18:37294
295 media_log_->AddEvent(
296 media_log_->CreateEvent(MediaLogEvent::WEBMEDIAPLAYER_DESTROYED));
[email protected]ec9212f2008-12-18 21:40:36297}
298
guidou9bfe4e2f2016-04-09 08:31:19299void WebMediaPlayerImpl::load(LoadType load_type,
300 const blink::WebMediaPlayerSource& source,
[email protected]62e5e682013-03-07 23:53:24301 CORSMode cors_mode) {
guidou9bfe4e2f2016-04-09 08:31:19302 // Only URL or MSE blob URL is supported.
303 DCHECK(source.isURL());
304 blink::WebURL url = source.getAsURL();
pkastingf5279482016-07-27 02:18:20305 DVLOG(1) << __func__ << "(" << load_type << ", " << url << ", " << cors_mode
306 << ")";
[email protected]d726eddc2013-07-02 22:25:55307 if (!defer_load_cb_.is_null()) {
308 defer_load_cb_.Run(base::Bind(
[email protected]ef8394c2013-08-21 20:26:30309 &WebMediaPlayerImpl::DoLoad, AsWeakPtr(), load_type, url, cors_mode));
[email protected]d726eddc2013-07-02 22:25:55310 return;
311 }
[email protected]ef8394c2013-08-21 20:26:30312 DoLoad(load_type, url, cors_mode);
[email protected]62e5e682013-03-07 23:53:24313}
314
watk9c87c6fa2016-05-06 20:36:51315bool WebMediaPlayerImpl::supportsOverlayFullscreenVideo() {
316#if defined(OS_ANDROID)
watkf835a792016-06-24 23:24:40317 return true;
watk9c87c6fa2016-05-06 20:36:51318#else
319 return false;
320#endif
321}
322
tsunghungee562e92016-07-20 18:03:31323void WebMediaPlayerImpl::EnableOverlay() {
324 overlay_enabled_ = true;
watkf835a792016-06-24 23:24:40325 if (surface_manager_) {
326 surface_created_cb_.Reset(
327 base::Bind(&WebMediaPlayerImpl::OnSurfaceCreated, AsWeakPtr()));
328 surface_manager_->CreateFullscreenSurface(pipeline_metadata_.natural_size,
329 surface_created_cb_.callback());
330 }
tsunghungee562e92016-07-20 18:03:31331
332 if (decoder_requires_restart_for_overlay_)
watkdee516f2016-02-18 02:22:19333 ScheduleRestart();
334}
335
tsunghungee562e92016-07-20 18:03:31336void WebMediaPlayerImpl::DisableOverlay() {
337 overlay_enabled_ = false;
watkf835a792016-06-24 23:24:40338 surface_created_cb_.Cancel();
tsunghungee562e92016-07-20 18:03:31339 overlay_surface_id_ = SurfaceManager::kNoSurfaceID;
340
341 if (decoder_requires_restart_for_overlay_)
watkdee516f2016-02-18 02:22:19342 ScheduleRestart();
dalecurtis4b632fce22016-11-10 00:52:17343 else if (!set_surface_cb_.is_null())
344 set_surface_cb_.Run(overlay_surface_id_);
watkdee516f2016-02-18 02:22:19345}
346
tsunghungee562e92016-07-20 18:03:31347void WebMediaPlayerImpl::enteredFullscreen() {
liberato2fd111be2017-01-04 00:25:06348 // |force_video_overlays_| implies that we're already in overlay mode, so take
349 // no action here. Otherwise, switch to an overlay if it's allowed and if
350 // it will display properly.
351 if (!force_video_overlays_ && enable_fullscreen_video_overlays_ &&
352 DoesOverlaySupportMetadata()) {
tsunghungee562e92016-07-20 18:03:31353 EnableOverlay();
liberato2fd111be2017-01-04 00:25:06354 }
xjzd3fe45a2016-10-12 18:26:37355 if (observer_)
356 observer_->OnEnteredFullscreen();
tsunghungee562e92016-07-20 18:03:31357}
358
359void WebMediaPlayerImpl::exitedFullscreen() {
liberato2fd111be2017-01-04 00:25:06360 // If we're in overlay mode, then exit it unless we're supposed to be in
361 // overlay mode all the time.
362 if (!force_video_overlays_ && overlay_enabled_)
tsunghungee562e92016-07-20 18:03:31363 DisableOverlay();
xjzd3fe45a2016-10-12 18:26:37364 if (observer_)
365 observer_->OnExitedFullscreen();
tsunghungee562e92016-07-20 18:03:31366}
367
xjzcdbbe732016-12-03 20:47:42368void WebMediaPlayerImpl::becameDominantVisibleContent(bool isDominant) {
369 if (observer_)
370 observer_->OnBecameDominantVisibleContent(isDominant);
371}
372
[email protected]ef8394c2013-08-21 20:26:30373void WebMediaPlayerImpl::DoLoad(LoadType load_type,
[email protected]180ef242013-11-07 06:50:46374 const blink::WebURL& url,
[email protected]d726eddc2013-07-02 22:25:55375 CORSMode cors_mode) {
pkastingf5279482016-07-27 02:18:20376 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:43377 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d726eddc2013-07-02 22:25:55378
[email protected]62e5e682013-03-07 23:53:24379 GURL gurl(url);
xhwangbffbf452016-04-01 05:26:45380 ReportMetrics(load_type, gurl, frame_->getSecurityOrigin());
[email protected]62e5e682013-03-07 23:53:24381
[email protected]926f8fd2013-04-12 20:27:53382 // Set subresource URL for crash reporting.
383 base::debug::SetCrashKeyValue("subresource_url", gurl.spec());
384
tguilbert25a4d112016-10-13 21:56:51385 if (use_fallback_path_)
386 fallback_url_ = gurl;
387
[email protected]ef8394c2013-08-21 20:26:30388 load_type_ = load_type;
389
[email protected]62e5e682013-03-07 23:53:24390 SetNetworkState(WebMediaPlayer::NetworkStateLoading);
391 SetReadyState(WebMediaPlayer::ReadyStateHaveNothing);
kinukof19cde72015-12-18 23:15:25392 media_log_->AddEvent(media_log_->CreateLoadEvent(url.string().utf8()));
[email protected]d726eddc2013-07-02 22:25:55393
394 // Media source pipelines can start immediately.
[email protected]ef8394c2013-08-21 20:26:30395 if (load_type == LoadTypeMediaSource) {
[email protected]d726eddc2013-07-02 22:25:55396 supports_save_ = false;
[email protected]ef8394c2013-08-21 20:26:30397 StartPipeline();
hubbe5f0ad43b2015-12-14 20:57:26398 } else {
dalecurtisb6e052f52016-08-25 00:35:55399 data_source_.reset(new MultibufferDataSource(
400 url, static_cast<UrlData::CORSMode>(cors_mode), main_task_runner_,
401 url_index_, frame_, media_log_.get(), &buffered_data_source_host_,
402 base::Bind(&WebMediaPlayerImpl::NotifyDownloading, AsWeakPtr())));
avayvode46d7bef2016-03-30 23:18:26403 data_source_->SetPreload(preload_);
404 data_source_->SetBufferingStrategy(buffering_strategy_);
405 data_source_->Initialize(
406 base::Bind(&WebMediaPlayerImpl::DataSourceInitialized, AsWeakPtr()));
hubbe5f0ad43b2015-12-14 20:57:26407 }
hubbed5f36882016-01-15 22:40:37408
409#if defined(OS_ANDROID) // WMPI_CAST
dalecurtisbb3eaac2016-01-27 21:10:25410 cast_impl_.Initialize(url, frame_, delegate_id_);
hubbed5f36882016-01-15 22:40:37411#endif
[email protected]62e5e682013-03-07 23:53:24412}
413
[email protected]4e6be3f2009-05-07 02:24:44414void WebMediaPlayerImpl::play() {
pkastingf5279482016-07-27 02:18:20415 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:43416 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53417
hubbed5f36882016-01-15 22:40:37418#if defined(OS_ANDROID) // WMPI_CAST
419 if (isRemote()) {
dalecurtis6e2716d2016-01-21 04:49:15420 cast_impl_.play();
hubbed5f36882016-01-15 22:40:37421 return;
422 }
423#endif
sandersd35d2c3f2017-01-14 02:04:42424 // TODO(sandersd): Do we want to reset the idle timer here?
tguilbert1bb1c782017-01-23 21:15:11425 delegate_->SetIdle(delegate_id_, false);
[email protected]49480902009-07-14 20:23:43426 paused_ = false;
yoichio863bebf2016-03-04 07:56:58427 pipeline_.SetPlaybackRate(playback_rate_);
dalecurtis4619cd02016-09-22 21:39:10428 background_pause_timer_.Stop();
sandersd1c0bba02016-03-04 23:14:08429
[email protected]039b7542013-10-17 22:06:25430 if (data_source_)
431 data_source_->MediaIsPlaying();
[email protected]090f7312011-08-05 23:26:40432
xjz48a9cb72016-12-20 04:02:49433 if (observer_)
434 observer_->OnPlaying();
435
dalecurtis04bdb582016-08-17 22:15:23436 DCHECK(watch_time_reporter_);
437 watch_time_reporter_->OnPlaying();
acolwell9e0840d2014-09-06 19:01:32438 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PLAY));
sandersd50a635e2016-04-04 22:50:09439 UpdatePlayState();
[email protected]ec9212f2008-12-18 21:40:36440}
441
[email protected]4e6be3f2009-05-07 02:24:44442void WebMediaPlayerImpl::pause() {
pkastingf5279482016-07-27 02:18:20443 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:43444 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53445
sandersd50a635e2016-04-04 22:50:09446 // We update the paused state even when casting, since we expect pause() to be
447 // called when casting begins, and when we exit casting we should end up in a
448 // paused state.
[email protected]49480902009-07-14 20:23:43449 paused_ = true;
hubbed5f36882016-01-15 22:40:37450
avayvodeb9098d2017-01-07 00:33:03451 // No longer paused because it was hidden.
452 paused_when_hidden_ = false;
453
hubbed5f36882016-01-15 22:40:37454#if defined(OS_ANDROID) // WMPI_CAST
455 if (isRemote()) {
dalecurtis6e2716d2016-01-21 04:49:15456 cast_impl_.pause();
hubbed5f36882016-01-15 22:40:37457 return;
458 }
459#endif
460
a.berwal338bf002015-04-22 11:14:50461 pipeline_.SetPlaybackRate(0.0);
sandersd1c0bba02016-03-04 23:14:08462
463 // pause() may be called after playback has ended and the HTMLMediaElement
464 // requires that currentTime() == duration() after ending. We want to ensure
465 // |paused_time_| matches currentTime() in this case or a future seek() may
466 // incorrectly discard what it thinks is a seek to the existing time.
avayvodcc273dd2017-01-19 19:35:12467 paused_time_ = ended_ ? GetPipelineMediaDuration() : pipeline_.GetMediaTime();
[email protected]090f7312011-08-05 23:26:40468
xjz48a9cb72016-12-20 04:02:49469 if (observer_)
470 observer_->OnPaused();
471
dalecurtis04bdb582016-08-17 22:15:23472 DCHECK(watch_time_reporter_);
473 watch_time_reporter_->OnPaused();
acolwell9e0840d2014-09-06 19:01:32474 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PAUSE));
avayvod2135a642017-01-13 00:17:14475
sandersd50a635e2016-04-04 22:50:09476 UpdatePlayState();
[email protected]ec9212f2008-12-18 21:40:36477}
478
[email protected]574a1d62009-07-17 03:23:46479bool WebMediaPlayerImpl::supportsSave() const {
acolwellb4034942014-08-28 15:42:43480 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]132dd57c2012-08-10 23:24:34481 return supports_save_;
[email protected]574a1d62009-07-17 03:23:46482}
483
[email protected]39bdde32013-04-17 17:44:20484void WebMediaPlayerImpl::seek(double seconds) {
pkastingf5279482016-07-27 02:18:20485 DVLOG(1) << __func__ << "(" << seconds << "s)";
acolwellb4034942014-08-28 15:42:43486 DCHECK(main_task_runner_->BelongsToCurrentThread());
sandersd1c0bba02016-03-04 23:14:08487 DoSeek(base::TimeDelta::FromSecondsD(seconds), true);
488}
489
490void WebMediaPlayerImpl::DoSeek(base::TimeDelta time, bool time_updated) {
491 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53492
hubbed5f36882016-01-15 22:40:37493#if defined(OS_ANDROID) // WMPI_CAST
494 if (isRemote()) {
sandersd1c0bba02016-03-04 23:14:08495 cast_impl_.seek(time);
hubbed5f36882016-01-15 22:40:37496 return;
497 }
498#endif
499
srirama.mccf671812015-01-08 11:59:13500 ReadyState old_state = ready_state_;
[email protected]1bb666802013-11-28 06:12:08501 if (ready_state_ > WebMediaPlayer::ReadyStateHaveMetadata)
502 SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata);
503
sandersd1c0bba02016-03-04 23:14:08504 // When paused, we know exactly what the current time is and can elide seeks
505 // to it. However, there are two cases that are not elided:
506 // 1) When the pipeline state is not stable.
507 // In this case we just let |pipeline_controller_| decide what to do, as
508 // it has complete information.
509 // 2) For MSE.
510 // Because the buffers may have changed between seeks, MSE seeks are
511 // never elided.
512 if (paused_ && pipeline_controller_.IsStable() && paused_time_ == time &&
513 !chunk_demuxer_) {
514 // If the ready state was high enough before, we can indicate that the seek
515 // completed just by restoring it. Otherwise we will just wait for the real
516 // ready state change to eventually happen.
517 if (old_state == ReadyStateHaveEnoughData) {
srirama.m8f4a37562014-12-13 08:16:18518 main_task_runner_->PostTask(
alokp967c902452016-05-06 05:21:37519 FROM_HERE, base::Bind(&WebMediaPlayerImpl::OnBufferingStateChange,
520 AsWeakPtr(), BUFFERING_HAVE_ENOUGH));
srirama.m36ab2682014-12-11 04:20:01521 }
sandersd1c0bba02016-03-04 23:14:08522 return;
srirama.m36ab2682014-12-11 04:20:01523 }
[email protected]44ff37c02009-10-24 01:03:03524
dalecurtis04bdb582016-08-17 22:15:23525 // Call this before setting |seeking_| so that the current media time can be
526 // recorded by the reporter.
527 if (watch_time_reporter_)
528 watch_time_reporter_->OnSeeking();
529
sandersd35d2c3f2017-01-14 02:04:42530 // TODO(sandersd): Move |seeking_| to PipelineController.
531 // TODO(sandersd): Do we want to reset the idle timer here?
tguilbert1bb1c782017-01-23 21:15:11532 delegate_->SetIdle(delegate_id_, false);
sandersd50a635e2016-04-04 22:50:09533 ended_ = false;
[email protected]b3766a22010-12-22 17:34:13534 seeking_ = true;
sandersd1c0bba02016-03-04 23:14:08535 seek_time_ = time;
536 if (paused_)
537 paused_time_ = time;
538 pipeline_controller_.Seek(time, time_updated);
[email protected]b3766a22010-12-22 17:34:13539
sandersd50a635e2016-04-04 22:50:09540 // This needs to be called after Seek() so that if a resume is triggered, it
541 // is to the correct time.
542 UpdatePlayState();
[email protected]ec9212f2008-12-18 21:40:36543}
544
[email protected]39bdde32013-04-17 17:44:20545void WebMediaPlayerImpl::setRate(double rate) {
pkastingf5279482016-07-27 02:18:20546 DVLOG(1) << __func__ << "(" << rate << ")";
acolwellb4034942014-08-28 15:42:43547 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53548
[email protected]378f0b72009-08-11 17:11:42549 // TODO(kylep): Remove when support for negatives is added. Also, modify the
550 // following checks so rewind uses reasonable values also.
[email protected]39bdde32013-04-17 17:44:20551 if (rate < 0.0)
[email protected]378f0b72009-08-11 17:11:42552 return;
553
554 // Limit rates to reasonable values by clamping.
[email protected]39bdde32013-04-17 17:44:20555 if (rate != 0.0) {
[email protected]378f0b72009-08-11 17:11:42556 if (rate < kMinRate)
557 rate = kMinRate;
558 else if (rate > kMaxRate)
559 rate = kMaxRate;
560 }
561
[email protected]49480902009-07-14 20:23:43562 playback_rate_ = rate;
563 if (!paused_) {
[email protected]f6af7592014-02-28 10:09:11564 pipeline_.SetPlaybackRate(rate);
[email protected]039b7542013-10-17 22:06:25565 if (data_source_)
566 data_source_->MediaPlaybackRateChanged(rate);
[email protected]49480902009-07-14 20:23:43567 }
[email protected]ec9212f2008-12-18 21:40:36568}
569
[email protected]39bdde32013-04-17 17:44:20570void WebMediaPlayerImpl::setVolume(double volume) {
pkastingf5279482016-07-27 02:18:20571 DVLOG(1) << __func__ << "(" << volume << ")";
acolwellb4034942014-08-28 15:42:43572 DCHECK(main_task_runner_->BelongsToCurrentThread());
dalecurtisbb3eaac2016-01-27 21:10:25573 volume_ = volume;
574 pipeline_.SetVolume(volume_ * volume_multiplier_);
dalecurtis04bdb582016-08-17 22:15:23575 if (watch_time_reporter_)
576 watch_time_reporter_->OnVolumeChange(volume);
mlamouri910111362016-11-04 11:28:24577
578 // The play state is updated because the player might have left the autoplay
579 // muted state.
580 UpdatePlayState();
[email protected]ec9212f2008-12-18 21:40:36581}
[email protected]f0a51fb52009-03-05 12:46:38582
guidouc7babef2015-10-22 00:42:35583void WebMediaPlayerImpl::setSinkId(
584 const blink::WebString& sink_id,
585 const blink::WebSecurityOrigin& security_origin,
586 blink::WebSetSinkIdCallbacks* web_callback) {
guidou69223ce2015-06-16 10:36:19587 DCHECK(main_task_runner_->BelongsToCurrentThread());
pkastingf5279482016-07-27 02:18:20588 DVLOG(1) << __func__;
guidouc7babef2015-10-22 00:42:35589
olka68b69392016-04-01 11:42:12590 media::OutputDeviceStatusCB callback =
591 media::ConvertToOutputDeviceStatusCB(web_callback);
guidouc7babef2015-10-22 00:42:35592 media_task_runner_->PostTask(
593 FROM_HERE,
594 base::Bind(&SetSinkIdOnMediaThread, audio_source_provider_,
595 sink_id.utf8(), static_cast<url::Origin>(security_origin),
596 callback));
guidou69223ce2015-06-16 10:36:19597}
598
dalecurtisb6e052f52016-08-25 00:35:55599STATIC_ASSERT_ENUM(WebMediaPlayer::PreloadNone, MultibufferDataSource::NONE);
danakj365175c2016-02-06 00:37:37600STATIC_ASSERT_ENUM(WebMediaPlayer::PreloadMetaData,
dalecurtisb6e052f52016-08-25 00:35:55601 MultibufferDataSource::METADATA);
602STATIC_ASSERT_ENUM(WebMediaPlayer::PreloadAuto, MultibufferDataSource::AUTO);
[email protected]23a8b1d82011-04-05 16:28:20603
[email protected]ef405f66b2012-04-18 02:39:55604void WebMediaPlayerImpl::setPreload(WebMediaPlayer::Preload preload) {
pkastingf5279482016-07-27 02:18:20605 DVLOG(1) << __func__ << "(" << preload << ")";
acolwellb4034942014-08-28 15:42:43606 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]4e6be3f2009-05-07 02:24:44607
dalecurtisb6e052f52016-08-25 00:35:55608 preload_ = static_cast<MultibufferDataSource::Preload>(preload);
[email protected]b49beeb2013-03-01 20:04:00609 if (data_source_)
[email protected]09c60222014-08-07 16:42:31610 data_source_->SetPreload(preload_);
[email protected]4e6be3f2009-05-07 02:24:44611}
612
danakj365175c2016-02-06 00:37:37613STATIC_ASSERT_ENUM(WebMediaPlayer::BufferingStrategy::Normal,
dalecurtisb6e052f52016-08-25 00:35:55614 MultibufferDataSource::BUFFERING_STRATEGY_NORMAL);
danakj365175c2016-02-06 00:37:37615STATIC_ASSERT_ENUM(WebMediaPlayer::BufferingStrategy::Aggressive,
dalecurtisb6e052f52016-08-25 00:35:55616 MultibufferDataSource::BUFFERING_STRATEGY_AGGRESSIVE);
sandersdc6ab163a2015-12-12 03:56:13617
618void WebMediaPlayerImpl::setBufferingStrategy(
619 WebMediaPlayer::BufferingStrategy buffering_strategy) {
pkastingf5279482016-07-27 02:18:20620 DVLOG(1) << __func__;
sandersdc6ab163a2015-12-12 03:56:13621 DCHECK(main_task_runner_->BelongsToCurrentThread());
622
dalecurtis37fe5862016-03-15 19:29:09623#if defined(OS_ANDROID)
624 // We disallow aggressive buffering on Android since it matches the behavior
625 // of the platform media player and may have data usage penalties.
626 // TODO(dalecurtis, hubbe): We should probably stop using "pause-and-buffer"
627 // everywhere. See http://crbug.com/594669 for more details.
dalecurtisb6e052f52016-08-25 00:35:55628 buffering_strategy_ = MultibufferDataSource::BUFFERING_STRATEGY_NORMAL;
dalecurtis37fe5862016-03-15 19:29:09629#else
sandersdc6ab163a2015-12-12 03:56:13630 buffering_strategy_ =
dalecurtisb6e052f52016-08-25 00:35:55631 static_cast<MultibufferDataSource::BufferingStrategy>(buffering_strategy);
dalecurtis37fe5862016-03-15 19:29:09632#endif
633
sandersdc6ab163a2015-12-12 03:56:13634 if (data_source_)
635 data_source_->SetBufferingStrategy(buffering_strategy_);
636}
637
[email protected]4e6be3f2009-05-07 02:24:44638bool WebMediaPlayerImpl::hasVideo() const {
acolwellb4034942014-08-28 15:42:43639 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53640
[email protected]b8877772014-03-26 20:17:15641 return pipeline_metadata_.has_video;
[email protected]d43ed912009-02-03 04:52:53642}
643
[email protected]fc367af2009-08-14 23:06:35644bool WebMediaPlayerImpl::hasAudio() const {
acolwellb4034942014-08-28 15:42:43645 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]fc367af2009-08-14 23:06:35646
[email protected]b8877772014-03-26 20:17:15647 return pipeline_metadata_.has_audio;
[email protected]fc367af2009-08-14 23:06:35648}
649
servolkf25ceed2016-07-01 03:44:38650void WebMediaPlayerImpl::enabledAudioTracksChanged(
651 const blink::WebVector<blink::WebMediaPlayer::TrackId>& enabledTrackIds) {
652 DCHECK(main_task_runner_->BelongsToCurrentThread());
653
654 std::ostringstream logstr;
655 std::vector<MediaTrack::Id> enabledMediaTrackIds;
656 for (const auto& blinkTrackId : enabledTrackIds) {
657 MediaTrack::Id track_id = blinkTrackId.utf8().data();
658 logstr << track_id << " ";
659 enabledMediaTrackIds.push_back(track_id);
660 }
661 MEDIA_LOG(INFO, media_log_) << "Enabled audio tracks: [" << logstr.str()
662 << "]";
663 pipeline_.OnEnabledAudioTracksChanged(enabledMediaTrackIds);
664}
665
666void WebMediaPlayerImpl::selectedVideoTrackChanged(
667 blink::WebMediaPlayer::TrackId* selectedTrackId) {
668 DCHECK(main_task_runner_->BelongsToCurrentThread());
669
670 std::ostringstream logstr;
671 std::vector<MediaTrack::Id> selectedVideoMediaTrackId;
avayvod2135a642017-01-13 00:17:14672 if (selectedTrackId && !video_track_disabled_) {
servolkf25ceed2016-07-01 03:44:38673 selectedVideoMediaTrackId.push_back(selectedTrackId->utf8().data());
674 logstr << selectedVideoMediaTrackId[0];
675 }
676 MEDIA_LOG(INFO, media_log_) << "Selected video track: [" << logstr.str()
677 << "]";
678 pipeline_.OnSelectedVideoTrackChanged(selectedVideoMediaTrackId);
679}
680
[email protected]180ef242013-11-07 06:50:46681blink::WebSize WebMediaPlayerImpl::naturalSize() const {
acolwellb4034942014-08-28 15:42:43682 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53683
[email protected]b8877772014-03-26 20:17:15684 return blink::WebSize(pipeline_metadata_.natural_size);
[email protected]d43ed912009-02-03 04:52:53685}
686
[email protected]4e6be3f2009-05-07 02:24:44687bool WebMediaPlayerImpl::paused() const {
acolwellb4034942014-08-28 15:42:43688 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53689
hubbed5f36882016-01-15 22:40:37690#if defined(OS_ANDROID) // WMPI_CAST
691 if (isRemote())
danakj4f1fd6a2017-01-06 21:15:17692 return cast_impl_.IsPaused();
hubbed5f36882016-01-15 22:40:37693#endif
sandersd50a635e2016-04-04 22:50:09694
[email protected]f6af7592014-02-28 10:09:11695 return pipeline_.GetPlaybackRate() == 0.0f;
[email protected]d43ed912009-02-03 04:52:53696}
697
[email protected]4e6be3f2009-05-07 02:24:44698bool WebMediaPlayerImpl::seeking() const {
acolwellb4034942014-08-28 15:42:43699 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53700
[email protected]ef405f66b2012-04-18 02:39:55701 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing)
[email protected]0acebfa2009-08-21 22:45:40702 return false;
[email protected]67cd5052009-09-10 21:53:22703
[email protected]b3766a22010-12-22 17:34:13704 return seeking_;
[email protected]ec9212f2008-12-18 21:40:36705}
706
[email protected]39bdde32013-04-17 17:44:20707double WebMediaPlayerImpl::duration() const {
acolwellb4034942014-08-28 15:42:43708 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]39bdde32013-04-17 17:44:20709
710 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing)
711 return std::numeric_limits<double>::quiet_NaN();
712
chcunninghamb92d5062017-01-10 21:50:22713 // Use duration from ChunkDemuxer when present. MSE allows users to specify
714 // duration as a double. This propagates to the rest of the pipeline as a
715 // TimeDelta with potentially reduced precision (limited to Microseconds).
716 // ChunkDemuxer returns the full-precision user-specified double. This ensures
717 // users can "get" the exact duration they "set".
718 if (chunk_demuxer_)
719 return chunk_demuxer_->GetDuration();
720
avayvodcc273dd2017-01-19 19:35:12721 base::TimeDelta pipeline_duration = GetPipelineMediaDuration();
chcunninghamb92d5062017-01-10 21:50:22722 return pipeline_duration == kInfiniteDuration
723 ? std::numeric_limits<double>::infinity()
724 : pipeline_duration.InSecondsF();
[email protected]d43ed912009-02-03 04:52:53725}
726
[email protected]db66d0092014-04-16 07:15:12727double WebMediaPlayerImpl::timelineOffset() const {
acolwellb4034942014-08-28 15:42:43728 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]db66d0092014-04-16 07:15:12729
730 if (pipeline_metadata_.timeline_offset.is_null())
731 return std::numeric_limits<double>::quiet_NaN();
732
733 return pipeline_metadata_.timeline_offset.ToJsTime();
734}
735
[email protected]39bdde32013-04-17 17:44:20736double WebMediaPlayerImpl::currentTime() const {
acolwellb4034942014-08-28 15:42:43737 DCHECK(main_task_runner_->BelongsToCurrentThread());
scherkusd2c745b2014-09-04 05:03:40738 DCHECK_NE(ready_state_, WebMediaPlayer::ReadyStateHaveNothing);
739
740 // TODO(scherkus): Replace with an explicit ended signal to HTMLMediaElement,
741 // see http://crbug.com/409280
742 if (ended_)
743 return duration();
744
sandersd1c0bba02016-03-04 23:14:08745 if (seeking())
746 return seek_time_.InSecondsF();
wolenetz1b2ae7d2015-06-10 00:44:21747
hubbed5f36882016-01-15 22:40:37748#if defined(OS_ANDROID) // WMPI_CAST
sandersd1c0bba02016-03-04 23:14:08749 if (isRemote())
hubbed5f36882016-01-15 22:40:37750 return cast_impl_.currentTime();
hubbed5f36882016-01-15 22:40:37751#endif
752
sandersd1c0bba02016-03-04 23:14:08753 if (paused_)
hubbed5f36882016-01-15 22:40:37754 return paused_time_.InSecondsF();
hubbed5f36882016-01-15 22:40:37755
756 return pipeline_.GetMediaTime().InSecondsF();
[email protected]d43ed912009-02-03 04:52:53757}
758
danakj13afe0362016-02-27 01:22:50759WebMediaPlayer::NetworkState WebMediaPlayerImpl::getNetworkState() const {
acolwellb4034942014-08-28 15:42:43760 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]ddb1e5a2010-12-13 20:10:45761 return network_state_;
762}
763
danakj13afe0362016-02-27 01:22:50764WebMediaPlayer::ReadyState WebMediaPlayerImpl::getReadyState() const {
acolwellb4034942014-08-28 15:42:43765 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]ddb1e5a2010-12-13 20:10:45766 return ready_state_;
767}
768
wolenetz4d39cc02016-04-05 19:54:41769blink::WebString WebMediaPlayerImpl::getErrorMessage() {
770 DCHECK(main_task_runner_->BelongsToCurrentThread());
771 return blink::WebString::fromUTF8(media_log_->GetLastErrorMessage());
772}
773
[email protected]02022fc2014-05-16 00:05:31774blink::WebTimeRanges WebMediaPlayerImpl::buffered() const {
acolwellb4034942014-08-28 15:42:43775 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]779a8322014-08-22 21:28:37776
acolwell9e0840d2014-09-06 19:01:32777 Ranges<base::TimeDelta> buffered_time_ranges =
[email protected]02022fc2014-05-16 00:05:31778 pipeline_.GetBufferedTimeRanges();
[email protected]779a8322014-08-22 21:28:37779
avayvodcc273dd2017-01-19 19:35:12780 const base::TimeDelta duration = GetPipelineMediaDuration();
dalecurtis39a7f932016-07-19 18:34:59781 if (duration != kInfiniteDuration) {
[email protected]779a8322014-08-22 21:28:37782 buffered_data_source_host_.AddBufferedTimeRanges(
783 &buffered_time_ranges, duration);
784 }
[email protected]02022fc2014-05-16 00:05:31785 return ConvertToWebTimeRanges(buffered_time_ranges);
786}
787
philipjb0e6f3f2014-09-30 09:51:53788blink::WebTimeRanges WebMediaPlayerImpl::seekable() const {
acolwellb4034942014-08-28 15:42:43789 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]39bdde32013-04-17 17:44:20790
dalecurtis56359cb2014-10-28 00:06:29791 if (ready_state_ < WebMediaPlayer::ReadyStateHaveMetadata)
philipjb0e6f3f2014-09-30 09:51:53792 return blink::WebTimeRanges();
793
dalecurtis56359cb2014-10-28 00:06:29794 const double seekable_end = duration();
795
796 // Allow a special exception for seeks to zero for streaming sources with a
797 // finite duration; this allows looping to work.
tguilbertade2bcb2017-01-07 02:57:45798 const bool is_finite_stream = data_source_ && data_source_->IsStreaming() &&
799 std::isfinite(seekable_end);
800
801 // Do not change the seekable range when using the fallback path.
802 // The MediaPlayerRenderer will take care of dropping invalid seeks.
803 const bool force_seeks_to_zero = !use_fallback_path_ && is_finite_stream;
dalecurtis56359cb2014-10-28 00:06:29804
805 // TODO(dalecurtis): Technically this allows seeking on media which return an
tguilbertade2bcb2017-01-07 02:57:45806 // infinite duration so long as DataSource::IsStreaming() is false. While not
dalecurtis56359cb2014-10-28 00:06:29807 // expected, disabling this breaks semi-live players, http://crbug.com/427412.
808 const blink::WebTimeRange seekable_range(
tguilbertade2bcb2017-01-07 02:57:45809 0.0, force_seeks_to_zero ? 0.0 : seekable_end);
philipjb0e6f3f2014-09-30 09:51:53810 return blink::WebTimeRanges(&seekable_range, 1);
[email protected]ec9212f2008-12-18 21:40:36811}
812
sandersd35d2c3f2017-01-14 02:04:42813bool WebMediaPlayerImpl::IsPrerollAttemptNeeded() {
814 // TODO(sandersd): Replace with |highest_ready_state_since_seek_| if we need
815 // to ensure that preroll always gets a chance to complete.
816 // See http://crbug.com/671525.
817 if (highest_ready_state_ >= ReadyState::ReadyStateHaveFutureData)
818 return false;
819
820 if (preroll_attempt_pending_)
821 return true;
822
823 // Freshly initialized; there has never been any loading progress. (Otherwise
824 // |preroll_attempt_pending_| would be true when the start time is null.)
825 if (preroll_attempt_start_time_.is_null())
826 return false;
827
828 base::TimeDelta preroll_attempt_duration =
829 tick_clock_->NowTicks() - preroll_attempt_start_time_;
830 return preroll_attempt_duration < kPrerollAttemptTimeout;
831}
832
[email protected]5d2b3e4c2014-05-12 23:27:30833bool WebMediaPlayerImpl::didLoadingProgress() {
acolwellb4034942014-08-28 15:42:43834 DCHECK(main_task_runner_->BelongsToCurrentThread());
dalecurtise7120dc2016-09-03 02:54:35835
836 // Note: Separate variables used to ensure both methods are called every time.
837 const bool pipeline_progress = pipeline_.DidLoadingProgress();
838 const bool data_progress = buffered_data_source_host_.DidLoadingProgress();
839 const bool did_loading_progress = pipeline_progress || data_progress;
840
sandersd35d2c3f2017-01-14 02:04:42841 if (did_loading_progress &&
842 highest_ready_state_ < ReadyState::ReadyStateHaveFutureData) {
843 // Reset the preroll attempt clock.
844 preroll_attempt_pending_ = true;
845 preroll_attempt_start_time_ = base::TimeTicks();
846
847 // Clear any 'stale' flag and give the pipeline a chance to resume. If we
848 // are already resumed, this will cause |preroll_attempt_start_time_| to be
849 // set.
850 // TODO(sandersd): Should this be on the same stack? It might be surprising
851 // that didLoadingProgress() can synchronously change state.
tguilbert1bb1c782017-01-23 21:15:11852 delegate_->ClearStaleFlag(delegate_id_);
dalecurtise7120dc2016-09-03 02:54:35853 UpdatePlayState();
854 }
855
856 return did_loading_progress;
[email protected]d43ed912009-02-03 04:52:53857}
858
[email protected]dd5c7972014-08-21 15:00:37859void WebMediaPlayerImpl::paint(blink::WebCanvas* canvas,
860 const blink::WebRect& rect,
xidachen0ebd94d2016-09-07 15:47:22861 SkPaint& paint) {
acolwellb4034942014-08-28 15:42:43862 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]dd061e12014-05-06 19:21:22863 TRACE_EVENT0("media", "WebMediaPlayerImpl:paint");
[email protected]4e6be3f2009-05-07 02:24:44864
xhwang213e50c2016-10-10 23:56:31865 // TODO(sandersd): Move this check into GetCurrentFrameFromCompositor() when
866 // we have other ways to check if decoder owns video frame.
867 // See http://crbug.com/595716 and http://crbug.com/602708
jrummelle616ee92016-10-08 02:15:44868 if (cdm_)
xhwang80739452016-01-13 00:48:00869 return;
870
mcasasf1236fc22015-05-29 22:38:56871 scoped_refptr<VideoFrame> video_frame = GetCurrentFrameFromCompositor();
[email protected]0fe5d43b2014-01-24 23:32:45872
[email protected]b49beeb2013-03-01 20:04:00873 gfx::Rect gfx_rect(rect);
dongseong.hwang0c4e9d82015-01-08 20:11:13874 Context3D context_3d;
mcasas265bdbf82015-06-12 18:44:07875 if (video_frame.get() && video_frame->HasTextures()) {
mcasasf1236fc22015-05-29 22:38:56876 if (!context_3d_cb_.is_null())
dongseong.hwang0c4e9d82015-01-08 20:11:13877 context_3d = context_3d_cb_.Run();
dongseong.hwang0c4e9d82015-01-08 20:11:13878 if (!context_3d.gl)
danakj53f7ec902016-05-21 01:30:10879 return; // Unable to get/create a shared main thread context.
880 if (!context_3d.gr_context)
881 return; // The context has been lost since and can't setup a GrContext.
dongseong.hwang0c4e9d82015-01-08 20:11:13882 }
danakj795f1732015-08-31 23:40:22883 skcanvas_video_renderer_.Paint(video_frame, canvas, gfx::RectF(gfx_rect),
xidachen0ebd94d2016-09-07 15:47:22884 paint, pipeline_metadata_.video_rotation,
danakj795f1732015-08-31 23:40:22885 context_3d);
[email protected]ec9212f2008-12-18 21:40:36886}
[email protected]5df51652009-01-17 00:03:00887
[email protected]38259a7a82009-07-29 21:49:49888bool WebMediaPlayerImpl::hasSingleSecurityOrigin() const {
[email protected]b49beeb2013-03-01 20:04:00889 if (data_source_)
890 return data_source_->HasSingleOrigin();
[email protected]fcdb7462009-10-21 21:05:11891 return true;
[email protected]38259a7a82009-07-29 21:49:49892}
893
[email protected]3fe27112012-06-07 04:00:01894bool WebMediaPlayerImpl::didPassCORSAccessCheck() const {
[email protected]b49beeb2013-03-01 20:04:00895 if (data_source_)
896 return data_source_->DidPassCORSAccessCheck();
897 return false;
[email protected]3fe27112012-06-07 04:00:01898}
899
[email protected]39bdde32013-04-17 17:44:20900double WebMediaPlayerImpl::mediaTimeForTimeValue(double timeValue) const {
qinminb4c39782015-08-10 18:43:24901 return base::TimeDelta::FromSecondsD(timeValue).InSecondsF();
[email protected]e06e16d82011-05-26 22:13:33902}
903
[email protected]d82b18ae2011-03-23 21:28:59904unsigned WebMediaPlayerImpl::decodedFrameCount() const {
acolwellb4034942014-08-28 15:42:43905 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]4c51bc662011-02-16 02:03:16906
avayvodc4bfb0e62017-01-13 01:07:01907 PipelineStatistics stats = GetPipelineStatistics();
[email protected]4c51bc662011-02-16 02:03:16908 return stats.video_frames_decoded;
909}
910
[email protected]d82b18ae2011-03-23 21:28:59911unsigned WebMediaPlayerImpl::droppedFrameCount() const {
acolwellb4034942014-08-28 15:42:43912 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]4c51bc662011-02-16 02:03:16913
avayvodc4bfb0e62017-01-13 01:07:01914 PipelineStatistics stats = GetPipelineStatistics();
[email protected]dd061e12014-05-06 19:21:22915 return stats.video_frames_dropped;
[email protected]4c51bc662011-02-16 02:03:16916}
917
chakshu.a94326b72016-03-08 05:11:44918size_t WebMediaPlayerImpl::audioDecodedByteCount() const {
acolwellb4034942014-08-28 15:42:43919 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]4c51bc662011-02-16 02:03:16920
avayvodc4bfb0e62017-01-13 01:07:01921 PipelineStatistics stats = GetPipelineStatistics();
[email protected]4c51bc662011-02-16 02:03:16922 return stats.audio_bytes_decoded;
923}
924
chakshu.a94326b72016-03-08 05:11:44925size_t WebMediaPlayerImpl::videoDecodedByteCount() const {
acolwellb4034942014-08-28 15:42:43926 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]4c51bc662011-02-16 02:03:16927
avayvodc4bfb0e62017-01-13 01:07:01928 PipelineStatistics stats = GetPipelineStatistics();
[email protected]4c51bc662011-02-16 02:03:16929 return stats.video_bytes_decoded;
930}
931
[email protected]6523b242013-03-13 11:10:07932bool WebMediaPlayerImpl::copyVideoTextureToPlatformTexture(
danakj46070b02016-03-28 21:54:11933 gpu::gles2::GLES2Interface* gl,
zmo57d577a2015-10-30 18:28:59934 unsigned int texture,
zmo57d577a2015-10-30 18:28:59935 bool premultiply_alpha,
936 bool flip_y) {
xhwang213e50c2016-10-10 23:56:31937 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]bfc05f22013-10-19 17:55:16938 TRACE_EVENT0("media", "WebMediaPlayerImpl:copyVideoTextureToPlatformTexture");
939
xhwang213e50c2016-10-10 23:56:31940 // TODO(sandersd): Move this check into GetCurrentFrameFromCompositor() when
941 // we have other ways to check if decoder owns video frame.
942 // See http://crbug.com/595716 and http://crbug.com/602708
943 if (cdm_)
944 return false;
[email protected]dd061e12014-05-06 19:21:22945
xhwang213e50c2016-10-10 23:56:31946 scoped_refptr<VideoFrame> video_frame = GetCurrentFrameFromCompositor();
jbauman581d041c2016-07-21 01:01:03947 if (!video_frame.get() || !video_frame->HasTextures()) {
[email protected]e56f88c72013-06-25 22:31:29948 return false;
dongseong.hwang0c4e9d82015-01-08 20:11:13949 }
[email protected]df41e252014-02-03 23:39:50950
jbauman581d041c2016-07-21 01:01:03951 Context3D context_3d;
952 if (!context_3d_cb_.is_null())
953 context_3d = context_3d_cb_.Run();
954 return skcanvas_video_renderer_.CopyVideoFrameTexturesToGLTexture(
kbr4910ae52017-01-11 00:52:28955 context_3d, gl, video_frame.get(), texture, premultiply_alpha, flip_y);
[email protected]6523b242013-03-13 11:10:07956}
957
[email protected]7bce1832014-01-09 00:01:22958void WebMediaPlayerImpl::setContentDecryptionModule(
[email protected]9ebc3b03f2014-08-13 04:01:23959 blink::WebContentDecryptionModule* cdm,
960 blink::WebContentDecryptionModuleResult result) {
acolwellb4034942014-08-28 15:42:43961 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]9ebc3b03f2014-08-13 04:01:23962
jrummell06f27072015-06-08 18:12:38963 // Once the CDM is set it can't be cleared as there may be frames being
964 // decrypted on other threads. So fail this request.
965 // http://crbug.com/462365#c7.
xhwang97de4202014-11-25 08:44:01966 if (!cdm) {
967 result.completeWithError(
jrummell06f27072015-06-08 18:12:38968 blink::WebContentDecryptionModuleExceptionInvalidStateError, 0,
xhwang79b193042016-12-13 18:52:43969 "The existing ContentDecryptionModule object cannot be removed at this "
970 "time.");
xhwang97de4202014-11-25 08:44:01971 return;
972 }
973
jrummell89e61d82015-07-23 20:03:34974 // Create a local copy of |result| to avoid problems with the callback
975 // getting passed to the media thread and causing |result| to be destructed
jrummell4acbec912016-02-27 02:45:03976 // on the wrong thread in some failure conditions. Blink should prevent
977 // multiple simultaneous calls.
978 DCHECK(!set_cdm_result_);
jrummell89e61d82015-07-23 20:03:34979 set_cdm_result_.reset(new blink::WebContentDecryptionModuleResult(result));
980
dalecurtis04bdb582016-08-17 22:15:23981 // Recreate the watch time reporter if necessary.
982 const bool was_encrypted = is_encrypted_;
983 is_encrypted_ = true;
984 if (!was_encrypted && watch_time_reporter_)
985 CreateWatchTimeReporter();
986
jrummelle616ee92016-10-08 02:15:44987 SetCdm(cdm);
xhwang97de4202014-11-25 08:44:01988}
989
xhwange8c4181a2014-12-06 08:10:01990void WebMediaPlayerImpl::OnEncryptedMediaInitData(
jrummellcf78967c2015-04-03 05:03:58991 EmeInitDataType init_data_type,
Avi Drissman97785ea2015-12-19 01:11:31992 const std::vector<uint8_t>& init_data) {
jrummellcf78967c2015-04-03 05:03:58993 DCHECK(init_data_type != EmeInitDataType::UNKNOWN);
xhwangbab66f52014-12-02 23:49:50994
ddorwin301ccdb2016-02-25 02:39:17995 // TODO(xhwang): Update this UMA name. https://crbug.com/589251
xhwangbab66f52014-12-02 23:49:50996 UMA_HISTOGRAM_COUNTS("Media.EME.NeedKey", 1);
997
dalecurtis04bdb582016-08-17 22:15:23998 // Recreate the watch time reporter if necessary.
999 const bool was_encrypted = is_encrypted_;
1000 is_encrypted_ = true;
1001 if (!was_encrypted && watch_time_reporter_)
1002 CreateWatchTimeReporter();
1003
srirama.m26f864d02015-07-14 05:21:461004 encrypted_client_->encrypted(
davidbenb50f00c2015-12-01 00:01:501005 ConvertToWebInitDataType(init_data_type), init_data.data(),
srirama.m26f864d02015-07-14 05:21:461006 base::saturated_cast<unsigned int>(init_data.size()));
xhwangbab66f52014-12-02 23:49:501007}
1008
servolk81e01e02016-03-05 03:29:151009void WebMediaPlayerImpl::OnFFmpegMediaTracksUpdated(
dcheng3076abbf2016-04-22 20:42:391010 std::unique_ptr<MediaTracks> tracks) {
servolk81e01e02016-03-05 03:29:151011 // For MSE/chunk_demuxer case the media track updates are handled by
1012 // WebSourceBufferImpl.
1013 DCHECK(demuxer_.get());
1014 DCHECK(!chunk_demuxer_);
servolkef1e5ef2016-03-25 04:55:261015
1016 // Report the media track information to blink.
1017 for (const auto& track : tracks->tracks()) {
1018 if (track->type() == MediaTrack::Audio) {
servolkfa5c37c2016-06-16 17:56:471019 client_->addAudioTrack(blink::WebString::fromUTF8(track->id()),
1020 blink::WebMediaPlayerClient::AudioTrackKindMain,
1021 blink::WebString::fromUTF8(track->label()),
1022 blink::WebString::fromUTF8(track->language()),
1023 /*enabled*/ true);
servolkef1e5ef2016-03-25 04:55:261024 } else if (track->type() == MediaTrack::Video) {
servolkfa5c37c2016-06-16 17:56:471025 client_->addVideoTrack(blink::WebString::fromUTF8(track->id()),
1026 blink::WebMediaPlayerClient::VideoTrackKindMain,
1027 blink::WebString::fromUTF8(track->label()),
1028 blink::WebString::fromUTF8(track->language()),
1029 /*selected*/ true);
servolkef1e5ef2016-03-25 04:55:261030 } else {
1031 // Text tracks are not supported through this code path yet.
1032 NOTREACHED();
1033 }
1034 }
servolk81e01e02016-03-05 03:29:151035}
1036
jrummelle616ee92016-10-08 02:15:441037void WebMediaPlayerImpl::SetCdm(blink::WebContentDecryptionModule* cdm) {
1038 DCHECK(main_task_runner_->BelongsToCurrentThread());
1039 DCHECK(cdm);
xhwang79b193042016-12-13 18:52:431040 scoped_refptr<ContentDecryptionModule> cdm_reference =
jrummelle616ee92016-10-08 02:15:441041 ToWebContentDecryptionModuleImpl(cdm)->GetCdm();
1042 if (!cdm_reference) {
1043 NOTREACHED();
1044 OnCdmAttached(false);
xhwang80739452016-01-13 00:48:001045 return;
1046 }
1047
jrummelle616ee92016-10-08 02:15:441048 CdmContext* cdm_context = cdm_reference->GetCdmContext();
1049 if (!cdm_context) {
1050 OnCdmAttached(false);
1051 return;
1052 }
1053
xjzd3fe45a2016-10-12 18:26:371054 if (observer_)
1055 observer_->OnSetCdm(cdm_context);
1056
jrummelle616ee92016-10-08 02:15:441057 // Keep the reference to the CDM, as it shouldn't be destroyed until
1058 // after the pipeline is done with the |cdm_context|.
1059 pending_cdm_ = std::move(cdm_reference);
1060 pipeline_.SetCdm(cdm_context,
1061 base::Bind(&WebMediaPlayerImpl::OnCdmAttached, AsWeakPtr()));
xhwang97de4202014-11-25 08:44:011062}
1063
jrummell89e61d82015-07-23 20:03:341064void WebMediaPlayerImpl::OnCdmAttached(bool success) {
jrummelle616ee92016-10-08 02:15:441065 DCHECK(main_task_runner_->BelongsToCurrentThread());
1066 DCHECK(pending_cdm_);
1067
1068 // If the CDM is set from the constructor there is no promise
1069 // (|set_cdm_result_|) to fulfill.
xhwang97de4202014-11-25 08:44:011070 if (success) {
jrummelle616ee92016-10-08 02:15:441071 // This will release the previously attached CDM (if any).
1072 cdm_ = std::move(pending_cdm_);
1073 if (set_cdm_result_) {
1074 set_cdm_result_->complete();
1075 set_cdm_result_.reset();
1076 }
1077
xhwang97de4202014-11-25 08:44:011078 return;
1079 }
1080
jrummelle616ee92016-10-08 02:15:441081 pending_cdm_ = nullptr;
1082 if (set_cdm_result_) {
1083 set_cdm_result_->completeWithError(
1084 blink::WebContentDecryptionModuleExceptionNotSupportedError, 0,
xhwang79b193042016-12-13 18:52:431085 "Unable to set ContentDecryptionModule object");
jrummelle616ee92016-10-08 02:15:441086 set_cdm_result_.reset();
1087 }
[email protected]9ebc3b03f2014-08-13 04:01:231088}
1089
sandersd1c0bba02016-03-04 23:14:081090void WebMediaPlayerImpl::OnPipelineSeeked(bool time_updated) {
[email protected]5d11eff2011-09-15 00:06:061091 seeking_ = false;
wolenetz1b2ae7d2015-06-10 00:44:211092 seek_time_ = base::TimeDelta();
avayvod2135a642017-01-13 00:17:141093
hubbe5a2dec022016-03-17 01:14:231094 if (paused_) {
1095#if defined(OS_ANDROID) // WMPI_CAST
1096 if (isRemote()) {
1097 paused_time_ = base::TimeDelta::FromSecondsD(cast_impl_.currentTime());
1098 } else {
1099 paused_time_ = pipeline_.GetMediaTime();
1100 }
1101#else
sandersd1c0bba02016-03-04 23:14:081102 paused_time_ = pipeline_.GetMediaTime();
hubbe5a2dec022016-03-17 01:14:231103#endif
dalecurtis04bdb582016-08-17 22:15:231104 } else {
1105 DCHECK(watch_time_reporter_);
1106 watch_time_reporter_->OnPlaying();
hubbe5a2dec022016-03-17 01:14:231107 }
sandersd1c0bba02016-03-04 23:14:081108 if (time_updated)
1109 should_notify_time_changed_ = true;
dalecurtisaf34d8712016-09-20 04:32:261110
1111 // Reset underflow count upon seek; this prevents looping videos and user
1112 // actions from artificially inflating the underflow count.
1113 underflow_count_ = 0;
avayvod56e1f3942017-01-21 02:06:311114
1115 // Background video optimizations are delayed when shown/hidden if pipeline
1116 // is seeking.
1117 UpdateBackgroundVideoOptimizationState();
[email protected]8931c41a2009-07-07 17:31:491118}
1119
sandersd1c0bba02016-03-04 23:14:081120void WebMediaPlayerImpl::OnPipelineSuspended() {
hubbed5f36882016-01-15 22:40:371121#if defined(OS_ANDROID)
1122 if (isRemote()) {
1123 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner();
sandersd50a635e2016-04-04 22:50:091124 if (frame)
dalecurtise9c89e92016-05-20 19:38:001125 compositor_->PaintSingleFrame(frame);
hubbed5f36882016-01-15 22:40:371126 }
1127#endif
1128
dalecurtis37fe5862016-03-15 19:29:091129 // If we're not in an aggressive buffering state, tell the data source we have
1130 // enough data so that it may release the connection.
1131 if (buffering_strategy_ !=
dalecurtisb6e052f52016-08-25 00:35:551132 MultibufferDataSource::BUFFERING_STRATEGY_AGGRESSIVE) {
liberato3f9f32b2016-03-16 16:54:511133 if (data_source_)
1134 data_source_->OnBufferingHaveEnough(true);
dalecurtis37fe5862016-03-15 19:29:091135 }
1136
sandersd50a635e2016-04-04 22:50:091137 ReportMemoryUsage();
1138
sandersd1c0bba02016-03-04 23:14:081139 if (pending_suspend_resume_cycle_) {
watkdee516f2016-02-18 02:22:191140 pending_suspend_resume_cycle_ = false;
sandersd50a635e2016-04-04 22:50:091141 UpdatePlayState();
dalecurtis0431cbf2016-03-12 01:19:431142 }
sandersd1c0bba02016-03-04 23:14:081143}
1144
avayvod2135a642017-01-13 00:17:141145void WebMediaPlayerImpl::OnBeforePipelineResume() {
1146 // Enable video track if we disabled it in the background - this way the new
1147 // renderer will attach its callbacks to the video stream properly.
1148 // TODO(avayvod): Remove this when disabling and enabling video tracks in
1149 // non-playing state works correctly. See https://crbug.com/678374.
1150 EnableVideoTrackIfNeeded();
1151 is_pipeline_resuming_ = true;
1152}
1153
1154void WebMediaPlayerImpl::OnPipelineResumed() {
1155 is_pipeline_resuming_ = false;
1156
avayvod56e1f3942017-01-21 02:06:311157 UpdateBackgroundVideoOptimizationState();
avayvod2135a642017-01-13 00:17:141158}
1159
alokp967c902452016-05-06 05:21:371160void WebMediaPlayerImpl::OnDemuxerOpened() {
1161 DCHECK(main_task_runner_->BelongsToCurrentThread());
1162 client_->mediaSourceOpened(
1163 new WebMediaSourceImpl(chunk_demuxer_, media_log_));
1164}
1165
servolkf94b4602017-01-31 16:44:271166void WebMediaPlayerImpl::OnMemoryPressure(
1167 base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
1168 DVLOG(2) << __func__ << " memory_pressure_level=" << memory_pressure_level;
1169 DCHECK(main_task_runner_->BelongsToCurrentThread());
1170 DCHECK(base::FeatureList::IsEnabled(kMemoryPressureBasedSourceBufferGC));
1171 DCHECK(chunk_demuxer_);
1172
1173 // The new value of |memory_pressure_level| will take effect on the next
1174 // garbage collection. Typically this means the next SourceBuffer append()
1175 // operation, since per MSE spec, the garbage collection must only occur
1176 // during SourceBuffer append(). But if memory pressure is critical it might
1177 // be better to perform GC immediately rather than wait for the next append
1178 // and potentially get killed due to out-of-memory.
1179 // So if this experiment is enabled and pressure level is critical, we'll pass
1180 // down force_instant_gc==true, which will force immediate GC on
1181 // SourceBufferStreams.
1182 bool force_instant_gc =
1183 (enable_instant_source_buffer_gc_ &&
1184 memory_pressure_level ==
1185 base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
1186
1187 // base::Unretained is safe, since chunk_demuxer_ is actually owned by
1188 // |this| via this->demuxer_.
1189 media_task_runner_->PostTask(
1190 FROM_HERE, base::Bind(&ChunkDemuxer::OnMemoryPressure,
1191 base::Unretained(chunk_demuxer_),
1192 base::TimeDelta::FromSecondsD(currentTime()),
1193 memory_pressure_level, force_instant_gc));
1194}
1195
alokp967c902452016-05-06 05:21:371196void WebMediaPlayerImpl::OnError(PipelineStatus status) {
pkastingf5279482016-07-27 02:18:201197 DVLOG(1) << __func__;
alokp967c902452016-05-06 05:21:371198 DCHECK(main_task_runner_->BelongsToCurrentThread());
1199 DCHECK_NE(status, PIPELINE_OK);
1200
1201 if (suppress_destruction_errors_)
1202 return;
1203
1204 ReportPipelineError(load_type_, frame_->getSecurityOrigin(), status);
1205 media_log_->AddEvent(media_log_->CreatePipelineErrorEvent(status));
1206
1207 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing) {
1208 // Any error that occurs before reaching ReadyStateHaveMetadata should
1209 // be considered a format error.
1210 SetNetworkState(WebMediaPlayer::NetworkStateFormatError);
1211 } else {
1212 SetNetworkState(PipelineErrorToNetworkState(status));
1213 }
1214
1215 UpdatePlayState();
1216}
1217
1218void WebMediaPlayerImpl::OnEnded() {
pkastingf5279482016-07-27 02:18:201219 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:431220 DCHECK(main_task_runner_->BelongsToCurrentThread());
scherkusd2c745b2014-09-04 05:03:401221
sandersd1c0bba02016-03-04 23:14:081222 // Ignore state changes until we've completed all outstanding operations.
1223 if (!pipeline_controller_.IsStable())
scherkusd2c745b2014-09-04 05:03:401224 return;
1225
1226 ended_ = true;
[email protected]ce70c982013-12-20 17:04:321227 client_->timeChanged();
sandersd50a635e2016-04-04 22:50:091228
1229 // We don't actually want this to run until |client_| calls seek() or pause(),
1230 // but that should have already happened in timeChanged() and so this is
1231 // expected to be a no-op.
1232 UpdatePlayState();
[email protected]576537842009-08-12 23:52:051233}
1234
alokp967c902452016-05-06 05:21:371235void WebMediaPlayerImpl::OnMetadata(PipelineMetadata metadata) {
pkastingf5279482016-07-27 02:18:201236 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:431237 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]a8e2cb82012-08-17 00:02:391238
[email protected]b8877772014-03-26 20:17:151239 pipeline_metadata_ = metadata;
[email protected]739847c02014-01-16 00:12:251240
dalecurtis04bdb582016-08-17 22:15:231241 SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata);
dalecurtis849cf4b22015-03-27 18:35:451242 UMA_HISTOGRAM_ENUMERATION("Media.VideoRotation", metadata.video_rotation,
acolwell9e0840d2014-09-06 19:01:321243 VIDEO_ROTATION_MAX + 1);
[email protected]21c3f7502013-03-23 03:29:511244
[email protected]b8877772014-03-26 20:17:151245 if (hasVideo()) {
liberato2fd111be2017-01-04 00:25:061246 if (overlay_enabled_) {
1247 // SurfaceView doesn't support rotated video, so transition back if
1248 // the video is now rotated. If |force_video_overlays_|, we keep the
1249 // overlay anyway so that the state machine keeps working.
1250 if (!force_video_overlays_ && !DoesOverlaySupportMetadata())
1251 DisableOverlay();
1252 else if (surface_manager_)
1253 surface_manager_->NaturalSizeChanged(pipeline_metadata_.natural_size);
1254 }
watkf835a792016-06-24 23:24:401255
1256 DCHECK(!video_weblayer_);
dalecurtise1edb312016-06-22 02:33:211257 video_weblayer_.reset(new cc_blink::WebLayerImpl(cc::VideoLayer::Create(
1258 compositor_, pipeline_metadata_.video_rotation)));
jbauman952274d2015-09-10 23:23:361259 video_weblayer_->layer()->SetContentsOpaque(opaque_);
1260 video_weblayer_->SetContentsOpaqueIsFixed(true);
[email protected]a7c4f582014-04-16 18:44:491261 client_->setWebLayer(video_weblayer_.get());
[email protected]a8e2cb82012-08-17 00:02:391262 }
dalecurtis8e4dc682016-03-15 02:30:301263
xjzd3fe45a2016-10-12 18:26:371264 if (observer_)
xjz15b483f2017-01-12 00:21:361265 observer_->OnMetadataChanged(pipeline_metadata_);
xjzd3fe45a2016-10-12 18:26:371266
dalecurtis04bdb582016-08-17 22:15:231267 CreateWatchTimeReporter();
sandersd50a635e2016-04-04 22:50:091268 UpdatePlayState();
[email protected]a8e2cb82012-08-17 00:02:391269}
1270
alokp967c902452016-05-06 05:21:371271void WebMediaPlayerImpl::OnBufferingStateChange(BufferingState state) {
pkastingf5279482016-07-27 02:18:201272 DVLOG(1) << __func__ << "(" << state << ")";
alokp967c902452016-05-06 05:21:371273 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]b8877772014-03-26 20:17:151274
sandersd1c0bba02016-03-04 23:14:081275 // Ignore buffering state changes until we've completed all outstanding
1276 // operations.
1277 if (!pipeline_controller_.IsStable())
[email protected]ba7d5f92014-06-24 05:37:401278 return;
[email protected]b8877772014-03-26 20:17:151279
dalecurtis869bf2f2017-01-10 18:01:101280 media_log_->AddEvent(media_log_->CreateBufferingStateChangedEvent(
1281 "pipeline_buffering_state", state));
1282
chcunninghameb270c92016-07-15 01:00:451283 if (state == BUFFERING_HAVE_ENOUGH) {
dalecurtis821e803f2016-09-01 18:44:151284 if (data_source_ &&
1285 highest_ready_state_ < WebMediaPlayer::ReadyStateHaveEnoughData) {
1286 DCHECK_EQ(underflow_count_, 0);
1287 // Record a zero value for underflow histograms so that the histogram
1288 // includes playbacks which never encounter an underflow event.
1289 UMA_HISTOGRAM_COUNTS_100("Media.UnderflowCount", 0);
1290 UMA_HISTOGRAM_TIMES("Media.UnderflowDuration", base::TimeDelta());
1291 }
1292
chcunninghameb270c92016-07-15 01:00:451293 // TODO(chcunningham): Monitor playback position vs buffered. Potentially
1294 // transition to HAVE_FUTURE_DATA here if not enough is buffered.
1295 SetReadyState(WebMediaPlayer::ReadyStateHaveEnoughData);
[email protected]ba7d5f92014-06-24 05:37:401296
chcunninghameb270c92016-07-15 01:00:451297 // Let the DataSource know we have enough data. It may use this information
1298 // to release unused network connections.
1299 if (data_source_)
1300 data_source_->OnBufferingHaveEnough(false);
dalecurtis849cf4b22015-03-27 18:35:451301
chcunninghameb270c92016-07-15 01:00:451302 // Blink expects a timeChanged() in response to a seek().
sandersd35d2c3f2017-01-14 02:04:421303 if (should_notify_time_changed_) {
1304 should_notify_time_changed_ = false;
chcunninghameb270c92016-07-15 01:00:451305 client_->timeChanged();
sandersd35d2c3f2017-01-14 02:04:421306 }
dalecurtis0f0097a2015-12-01 17:40:471307
chcunninghameb270c92016-07-15 01:00:451308 // Once we have enough, start reporting the total memory usage. We'll also
1309 // report once playback starts.
1310 ReportMemoryUsage();
dalecurtis9d638a12016-08-30 06:20:551311
1312 // Report the amount of time it took to leave the underflow state. Don't
1313 // bother to report this for MSE playbacks since it's out of our control.
1314 if (underflow_timer_ && data_source_) {
1315 UMA_HISTOGRAM_TIMES("Media.UnderflowDuration",
1316 underflow_timer_->Elapsed());
1317 underflow_timer_.reset();
1318 }
chcunninghameb270c92016-07-15 01:00:451319 } else {
1320 // Buffering has underflowed.
1321 DCHECK_EQ(state, BUFFERING_HAVE_NOTHING);
dalecurtisacd77d62016-09-09 23:23:141322
1323 // Report the number of times we've entered the underflow state. Only report
1324 // for src= playback since for MSE it's out of our control. Ensure we only
1325 // report the value when transitioning from HAVE_ENOUGH to HAVE_NOTHING.
1326 if (data_source_ &&
1327 ready_state_ == WebMediaPlayer::ReadyStateHaveEnoughData) {
1328 UMA_HISTOGRAM_COUNTS_100("Media.UnderflowCount", ++underflow_count_);
1329 underflow_timer_.reset(new base::ElapsedTimer());
1330 }
1331
chcunninghameb270c92016-07-15 01:00:451332 // It shouldn't be possible to underflow if we've not advanced past
1333 // HAVE_CURRENT_DATA.
1334 DCHECK_GT(highest_ready_state_, WebMediaPlayer::ReadyStateHaveCurrentData);
1335 SetReadyState(WebMediaPlayer::ReadyStateHaveCurrentData);
1336 }
sandersd50a635e2016-04-04 22:50:091337
1338 UpdatePlayState();
[email protected]b8877772014-03-26 20:17:151339}
1340
alokp967c902452016-05-06 05:21:371341void WebMediaPlayerImpl::OnDurationChange() {
acolwellb4034942014-08-28 15:42:431342 DCHECK(main_task_runner_->BelongsToCurrentThread());
alokp967c902452016-05-06 05:21:371343
1344 // TODO(sandersd): We should call delegate_->DidPlay() with the new duration,
1345 // especially if it changed from <5s to >5s.
1346 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing)
1347 return;
1348
1349 client_->durationChanged();
[email protected]81bb3322011-07-21 15:55:501350}
1351
alokp967c902452016-05-06 05:21:371352void WebMediaPlayerImpl::OnAddTextTrack(const TextTrackConfig& config,
1353 const AddTextTrackDoneCB& done_cb) {
acolwellb4034942014-08-28 15:42:431354 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]71537722013-05-23 06:47:531355
[email protected]8a561062013-11-22 01:19:311356 const WebInbandTextTrackImpl::Kind web_kind =
1357 static_cast<WebInbandTextTrackImpl::Kind>(config.kind());
1358 const blink::WebString web_label =
1359 blink::WebString::fromUTF8(config.label());
1360 const blink::WebString web_language =
1361 blink::WebString::fromUTF8(config.language());
[email protected]427ff102013-11-26 23:45:401362 const blink::WebString web_id =
1363 blink::WebString::fromUTF8(config.id());
[email protected]71537722013-05-23 06:47:531364
dcheng3076abbf2016-04-22 20:42:391365 std::unique_ptr<WebInbandTextTrackImpl> web_inband_text_track(
henriks9cce5fa2014-12-12 09:35:301366 new WebInbandTextTrackImpl(web_kind, web_label, web_language, web_id));
[email protected]8a561062013-11-22 01:19:311367
dcheng3076abbf2016-04-22 20:42:391368 std::unique_ptr<media::TextTrack> text_track(new TextTrackImpl(
dcheng652f5ff2015-12-27 08:54:001369 main_task_runner_, client_, std::move(web_inband_text_track)));
[email protected]8a561062013-11-22 01:19:311370
dcheng652f5ff2015-12-27 08:54:001371 done_cb.Run(std::move(text_track));
[email protected]71537722013-05-23 06:47:531372}
1373
alokp967c902452016-05-06 05:21:371374void WebMediaPlayerImpl::OnWaitingForDecryptionKey() {
1375 DCHECK(main_task_runner_->BelongsToCurrentThread());
1376
1377 encrypted_client_->didBlockPlaybackWaitingForKey();
1378 // TODO(jrummell): didResumePlaybackBlockedForKey() should only be called
1379 // when a key has been successfully added (e.g. OnSessionKeysChange() with
1380 // |has_additional_usable_key| = true). http://crbug.com/461903
1381 encrypted_client_->didResumePlaybackBlockedForKey();
1382}
1383
alokp5d86e9b2016-05-17 20:20:411384void WebMediaPlayerImpl::OnVideoNaturalSizeChange(const gfx::Size& size) {
1385 DCHECK(main_task_runner_->BelongsToCurrentThread());
1386 DCHECK_NE(ready_state_, WebMediaPlayer::ReadyStateHaveNothing);
1387
xjz15b483f2017-01-12 00:21:361388 // The input |size| is from the decoded video frame, which is the original
1389 // natural size and need to be rotated accordingly.
sandersd2c478422016-08-02 01:19:251390 gfx::Size rotated_size =
1391 GetRotatedVideoSize(pipeline_metadata_.video_rotation, size);
1392
1393 if (rotated_size == pipeline_metadata_.natural_size)
alokp5d86e9b2016-05-17 20:20:411394 return;
1395
1396 TRACE_EVENT0("media", "WebMediaPlayerImpl::OnNaturalSizeChanged");
sandersd2c478422016-08-02 01:19:251397 media_log_->AddEvent(media_log_->CreateVideoSizeSetEvent(
1398 rotated_size.width(), rotated_size.height()));
alokp5d86e9b2016-05-17 20:20:411399
tsunghungee562e92016-07-20 18:03:311400 if (overlay_enabled_ && surface_manager_)
sandersd2c478422016-08-02 01:19:251401 surface_manager_->NaturalSizeChanged(rotated_size);
alokp5d86e9b2016-05-17 20:20:411402
xjz516ef6d2017-01-07 00:23:061403 gfx::Size old_size = pipeline_metadata_.natural_size;
1404 pipeline_metadata_.natural_size = rotated_size;
1405 if (old_size.IsEmpty()) {
tguilbert796a40e2016-11-09 01:11:421406 // WatchTimeReporter doesn't report metrics for empty videos. Re-create
1407 // |watch_time_reporter_| if we didn't originally know the video size.
1408 CreateWatchTimeReporter();
1409 }
alokp5d86e9b2016-05-17 20:20:411410 client_->sizeChanged();
xjz516ef6d2017-01-07 00:23:061411
xjz15b483f2017-01-12 00:21:361412 if (observer_)
1413 observer_->OnMetadataChanged(pipeline_metadata_);
alokp5d86e9b2016-05-17 20:20:411414}
1415
1416void WebMediaPlayerImpl::OnVideoOpacityChange(bool opaque) {
1417 DCHECK(main_task_runner_->BelongsToCurrentThread());
1418 DCHECK_NE(ready_state_, WebMediaPlayer::ReadyStateHaveNothing);
1419
1420 opaque_ = opaque;
1421 // Modify content opaqueness of cc::Layer directly so that
1422 // SetContentsOpaqueIsFixed is ignored.
1423 if (video_weblayer_)
1424 video_weblayer_->layer()->SetContentsOpaque(opaque_);
1425}
1426
sandersd35d2c3f2017-01-14 02:04:421427void WebMediaPlayerImpl::OnFrameHidden() {
sandersd1e49fb62015-12-12 01:18:061428 DCHECK(main_task_runner_->BelongsToCurrentThread());
avayvod39c102402016-11-23 21:43:131429
dalecurtis04bdb582016-08-17 22:15:231430 if (watch_time_reporter_)
1431 watch_time_reporter_->OnHidden();
avayvod48a8be52016-08-04 19:52:501432
avayvod5f91d1752017-01-25 00:11:031433 // OnFrameHidden() can be called when frame is closed, then IsHidden() will
1434 // return false, so check explicitly.
1435 if (IsHidden()) {
1436 if (ShouldPauseVideoWhenHidden()) {
1437 PauseVideoIfNeeded();
1438 return;
1439 } else {
1440 DisableVideoTrackIfNeeded();
1441 }
avayvodeb9098d2017-01-07 00:33:031442 }
1443
sandersd50a635e2016-04-04 22:50:091444 UpdatePlayState();
dalecurtis8b8505e72016-06-10 21:59:171445
1446 // Schedule suspended playing media to be paused if the user doesn't come back
1447 // to it within some timeout period to avoid any autoplay surprises.
1448 ScheduleIdlePauseTimer();
sandersd1e49fb62015-12-12 01:18:061449}
1450
sandersd35d2c3f2017-01-14 02:04:421451void WebMediaPlayerImpl::OnFrameClosed() {
sandersd1e49fb62015-12-12 01:18:061452 DCHECK(main_task_runner_->BelongsToCurrentThread());
sandersd35d2c3f2017-01-14 02:04:421453 UpdatePlayState();
1454}
1455
1456void WebMediaPlayerImpl::OnFrameShown() {
1457 DCHECK(main_task_runner_->BelongsToCurrentThread());
1458 background_pause_timer_.Stop();
1459
dalecurtis04bdb582016-08-17 22:15:231460 if (watch_time_reporter_)
1461 watch_time_reporter_->OnShown();
1462
avayvodcc273dd2017-01-19 19:35:121463 // Only track the time to the first frame if playing or about to play because
1464 // of being shown and only for videos we would optimize background playback
1465 // for.
1466 if ((!paused_ && IsBackgroundOptimizationCandidate()) ||
1467 paused_when_hidden_) {
1468 VideoFrameCompositor::OnNewProcessedFrameCB new_processed_frame_cb =
dcheng37b415b92017-01-27 20:17:431469 BindToCurrentLoop(base::Bind(
avayvodcc273dd2017-01-19 19:35:121470 &WebMediaPlayerImpl::ReportTimeFromForegroundToFirstFrame,
dcheng37b415b92017-01-27 20:17:431471 AsWeakPtr(), base::TimeTicks::Now()));
avayvodcc273dd2017-01-19 19:35:121472 compositor_task_runner_->PostTask(
1473 FROM_HERE,
1474 base::Bind(&VideoFrameCompositor::SetOnNewProcessedFrameCallback,
1475 base::Unretained(compositor_), new_processed_frame_cb));
1476 }
avayvodac607d652017-01-06 03:16:431477
avayvod2135a642017-01-13 00:17:141478 if (paused_when_hidden_) {
1479 paused_when_hidden_ = false;
1480 OnPlay(); // Calls UpdatePlayState() so return afterwards.
1481 return;
1482 }
1483
1484 EnableVideoTrackIfNeeded();
1485
sandersd50a635e2016-04-04 22:50:091486 UpdatePlayState();
sandersd1e49fb62015-12-12 01:18:061487}
1488
sandersd35d2c3f2017-01-14 02:04:421489void WebMediaPlayerImpl::OnIdleTimeout() {
dalecurtis0431cbf2016-03-12 01:19:431490 DCHECK(main_task_runner_->BelongsToCurrentThread());
1491
sandersd35d2c3f2017-01-14 02:04:421492 // If we are attempting preroll, clear the stale flag.
1493 if (IsPrerollAttemptNeeded()) {
tguilbert1bb1c782017-01-23 21:15:111494 delegate_->ClearStaleFlag(delegate_id_);
sandersd35d2c3f2017-01-14 02:04:421495 return;
watkd026f792016-11-05 00:28:511496 }
sandersd50a635e2016-04-04 22:50:091497
sandersd35d2c3f2017-01-14 02:04:421498 UpdatePlayState();
dalecurtis0431cbf2016-03-12 01:19:431499}
1500
dalecurtisbb3eaac2016-01-27 21:10:251501void WebMediaPlayerImpl::OnPlay() {
1502 play();
1503 client_->playbackStateChanged();
1504}
1505
1506void WebMediaPlayerImpl::OnPause() {
1507 pause();
1508 client_->playbackStateChanged();
1509}
1510
1511void WebMediaPlayerImpl::OnVolumeMultiplierUpdate(double multiplier) {
1512 volume_multiplier_ = multiplier;
1513 setVolume(volume_);
1514}
1515
watkdee516f2016-02-18 02:22:191516void WebMediaPlayerImpl::ScheduleRestart() {
sandersd50a635e2016-04-04 22:50:091517 // TODO(watk): All restart logic should be moved into PipelineController.
1518 if (pipeline_.IsRunning() && !pipeline_controller_.IsPipelineSuspended()) {
watkdee516f2016-02-18 02:22:191519 pending_suspend_resume_cycle_ = true;
sandersd50a635e2016-04-04 22:50:091520 UpdatePlayState();
watkdee516f2016-02-18 02:22:191521 }
1522}
1523
miu77f914c2016-11-19 23:56:181524void WebMediaPlayerImpl::requestRemotePlaybackDisabled(bool disabled) {
1525 if (observer_)
1526 observer_->OnRemotePlaybackDisabled(disabled);
1527}
1528
hubbed5f36882016-01-15 22:40:371529#if defined(OS_ANDROID) // WMPI_CAST
hubbed5f36882016-01-15 22:40:371530bool WebMediaPlayerImpl::isRemote() const {
1531 return cast_impl_.isRemote();
1532}
1533
1534void WebMediaPlayerImpl::SetMediaPlayerManager(
1535 RendererMediaPlayerManagerInterface* media_player_manager) {
1536 cast_impl_.SetMediaPlayerManager(media_player_manager);
1537}
1538
1539void WebMediaPlayerImpl::requestRemotePlayback() {
1540 cast_impl_.requestRemotePlayback();
1541}
1542
1543void WebMediaPlayerImpl::requestRemotePlaybackControl() {
1544 cast_impl_.requestRemotePlaybackControl();
1545}
1546
avayvod8d8c53b2016-11-04 16:10:301547void WebMediaPlayerImpl::requestRemotePlaybackStop() {
1548 cast_impl_.requestRemotePlaybackStop();
1549}
1550
hubbed5f36882016-01-15 22:40:371551void WebMediaPlayerImpl::OnRemotePlaybackEnded() {
pkastingf5279482016-07-27 02:18:201552 DVLOG(1) << __func__;
hubbed5f36882016-01-15 22:40:371553 DCHECK(main_task_runner_->BelongsToCurrentThread());
1554
1555 ended_ = true;
1556 client_->timeChanged();
1557}
1558
1559void WebMediaPlayerImpl::OnDisconnectedFromRemoteDevice(double t) {
sandersd1c0bba02016-03-04 23:14:081560 DoSeek(base::TimeDelta::FromSecondsD(t), false);
hubbed5f36882016-01-15 22:40:371561
hubbed5f36882016-01-15 22:40:371562 // We already told the delegate we're paused when remoting started.
1563 client_->playbackStateChanged();
1564 client_->disconnectedFromRemoteDevice();
sandersd50a635e2016-04-04 22:50:091565
1566 UpdatePlayState();
hubbed5f36882016-01-15 22:40:371567}
1568
1569void WebMediaPlayerImpl::SuspendForRemote() {
sandersd50a635e2016-04-04 22:50:091570 if (pipeline_controller_.IsPipelineSuspended()) {
hubbed5f36882016-01-15 22:40:371571 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner();
sandersd50a635e2016-04-04 22:50:091572 if (frame)
dalecurtise9c89e92016-05-20 19:38:001573 compositor_->PaintSingleFrame(frame);
hubbed5f36882016-01-15 22:40:371574 }
sandersd50a635e2016-04-04 22:50:091575
1576 UpdatePlayState();
hubbed5f36882016-01-15 22:40:371577}
1578
1579gfx::Size WebMediaPlayerImpl::GetCanvasSize() const {
1580 if (!video_weblayer_)
1581 return pipeline_metadata_.natural_size;
1582
1583 return video_weblayer_->bounds();
1584}
1585
1586void WebMediaPlayerImpl::SetDeviceScaleFactor(float scale_factor) {
1587 cast_impl_.SetDeviceScaleFactor(scale_factor);
1588}
hubbee4027f92016-05-19 05:18:131589
tguilbert25a4d112016-10-13 21:56:511590void WebMediaPlayerImpl::SetUseFallbackPath(bool use_fallback_path) {
1591 use_fallback_path_ = use_fallback_path;
1592}
hubbed5f36882016-01-15 22:40:371593#endif // defined(OS_ANDROID) // WMPI_CAST
1594
xjzc102fd82017-01-04 20:13:531595void WebMediaPlayerImpl::setPoster(const blink::WebURL& poster) {
1596#if defined(OS_ANDROID)
1597 cast_impl_.setPoster(poster);
1598#endif
1599
1600 if (observer_)
1601 observer_->OnSetPoster(poster);
1602}
1603
[email protected]fee8a902014-06-03 13:43:361604void WebMediaPlayerImpl::DataSourceInitialized(bool success) {
pkastingf5279482016-07-27 02:18:201605 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:431606 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]a9415292012-01-19 19:55:201607
dalecurtisea27a3ed2016-06-24 01:41:301608#if defined(OS_ANDROID)
1609 // We can't play HLS URLs with WebMediaPlayerImpl, so in cases where they are
1610 // encountered, instruct the HTML media element to create a new WebMediaPlayer
1611 // instance with the correct URL to trigger WebMediaPlayerAndroid creation.
1612 //
1613 // TODO(tguilbert): Remove this code path once we have the ability to host a
1614 // MediaPlayer within a Mojo media renderer. http://crbug.com/580626
tguilbert25a4d112016-10-13 21:56:511615 if (data_source_ && !use_fallback_path_) {
dalecurtisea27a3ed2016-06-24 01:41:301616 const GURL url_after_redirects = data_source_->GetUrlAfterRedirects();
qinmin0d9521272016-10-10 20:43:191617 if (MediaCodecUtil::IsHLSURL(url_after_redirects)) {
dalecurtisea27a3ed2016-06-24 01:41:301618 client_->requestReload(url_after_redirects);
1619 // |this| may be destructed, do nothing after this.
1620 return;
1621 }
1622 }
1623#endif
1624
[email protected]d250190da3b2012-07-23 22:57:301625 if (!success) {
[email protected]ef405f66b2012-04-18 02:39:551626 SetNetworkState(WebMediaPlayer::NetworkStateFormatError);
sandersd50a635e2016-04-04 22:50:091627
1628 // Not really necessary, since the pipeline was never started, but it at
1629 // least this makes sure that the error handling code is in sync.
1630 UpdatePlayState();
1631
[email protected]a9415292012-01-19 19:55:201632 return;
1633 }
1634
[email protected]ef8394c2013-08-21 20:26:301635 StartPipeline();
[email protected]a9415292012-01-19 19:55:201636}
1637
[email protected]122f40252012-06-12 05:01:561638void WebMediaPlayerImpl::NotifyDownloading(bool is_downloading) {
pkastingf5279482016-07-27 02:18:201639 DVLOG(1) << __func__;
[email protected]122f40252012-06-12 05:01:561640 if (!is_downloading && network_state_ == WebMediaPlayer::NetworkStateLoading)
1641 SetNetworkState(WebMediaPlayer::NetworkStateIdle);
1642 else if (is_downloading && network_state_ == WebMediaPlayer::NetworkStateIdle)
1643 SetNetworkState(WebMediaPlayer::NetworkStateLoading);
1644 media_log_->AddEvent(
1645 media_log_->CreateBooleanEvent(
acolwell9e0840d2014-09-06 19:01:321646 MediaLogEvent::NETWORK_ACTIVITY_SET,
[email protected]122f40252012-06-12 05:01:561647 "is_downloading_data", is_downloading));
1648}
1649
watkf835a792016-06-24 23:24:401650void WebMediaPlayerImpl::OnSurfaceCreated(int surface_id) {
tsunghungee562e92016-07-20 18:03:311651 overlay_surface_id_ = surface_id;
dalecurtis4b632fce22016-11-10 00:52:171652 if (!set_surface_cb_.is_null()) {
1653 // If restart is required, the callback is one-shot only.
1654 if (decoder_requires_restart_for_overlay_)
1655 base::ResetAndReturn(&set_surface_cb_).Run(surface_id);
1656 else
1657 set_surface_cb_.Run(surface_id);
1658 }
watkf835a792016-06-24 23:24:401659}
1660
watkdee516f2016-02-18 02:22:191661void WebMediaPlayerImpl::OnSurfaceRequested(
dalecurtis4b632fce22016-11-10 00:52:171662 bool decoder_requires_restart_for_overlay,
1663 const SurfaceCreatedCB& set_surface_cb) {
watkdee516f2016-02-18 02:22:191664 DCHECK(main_task_runner_->BelongsToCurrentThread());
1665 DCHECK(surface_manager_);
tguilbert25a4d112016-10-13 21:56:511666 DCHECK(!use_fallback_path_);
watkdee516f2016-02-18 02:22:191667
1668 // A null callback indicates that the decoder is going away.
dalecurtis4b632fce22016-11-10 00:52:171669 if (set_surface_cb.is_null()) {
tsunghungee562e92016-07-20 18:03:311670 decoder_requires_restart_for_overlay_ = false;
dalecurtis4b632fce22016-11-10 00:52:171671 set_surface_cb_.Reset();
watkdee516f2016-02-18 02:22:191672 return;
1673 }
1674
dalecurtis4b632fce22016-11-10 00:52:171675 // If we get a surface request it means GpuVideoDecoder is initializing, so
1676 // until we get a null surface request, GVD is the active decoder.
1677 //
1678 // If |decoder_requires_restart_for_overlay| is true, we must restart the
1679 // pipeline for fullscreen transitions. The decoder is unable to switch
1680 // surfaces otherwise. If false, we simply need to tell the decoder about the
1681 // new surface and it will handle things seamlessly.
1682 decoder_requires_restart_for_overlay_ = decoder_requires_restart_for_overlay;
1683 set_surface_cb_ = set_surface_cb;
1684
1685 // If we're waiting for the surface to arrive, OnSurfaceCreated() will be
1686 // called later when it arrives; so do nothing for now.
1687 if (overlay_enabled_ && overlay_surface_id_ == SurfaceManager::kNoSurfaceID)
1688 return;
1689
1690 OnSurfaceCreated(overlay_surface_id_);
watkdee516f2016-02-18 02:22:191691}
1692
dcheng3076abbf2016-04-22 20:42:391693std::unique_ptr<Renderer> WebMediaPlayerImpl::CreateRenderer() {
dcheng37b415b92017-01-27 20:17:431694 DCHECK(main_task_runner_->BelongsToCurrentThread());
1695
tsunghungee562e92016-07-20 18:03:311696 if (force_video_overlays_)
1697 EnableOverlay();
1698
watkdee516f2016-02-18 02:22:191699 RequestSurfaceCB request_surface_cb;
1700#if defined(OS_ANDROID)
dcheng37b415b92017-01-27 20:17:431701 request_surface_cb = BindToCurrentLoop(
1702 base::Bind(&WebMediaPlayerImpl::OnSurfaceRequested, AsWeakPtr()));
watkdee516f2016-02-18 02:22:191703#endif
sandersd1e49fb62015-12-12 01:18:061704 return renderer_factory_->CreateRenderer(
1705 media_task_runner_, worker_task_runner_, audio_source_provider_.get(),
watkdee516f2016-02-18 02:22:191706 compositor_, request_surface_cb);
sandersd1e49fb62015-12-12 01:18:061707}
1708
[email protected]ef8394c2013-08-21 20:26:301709void WebMediaPlayerImpl::StartPipeline() {
acolwellb4034942014-08-28 15:42:431710 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]ddbc6ff2013-04-19 15:28:331711
xhwange8c4181a2014-12-06 08:10:011712 Demuxer::EncryptedMediaInitDataCB encrypted_media_init_data_cb =
dcheng37b415b92017-01-27 20:17:431713 BindToCurrentLoop(base::Bind(
1714 &WebMediaPlayerImpl::OnEncryptedMediaInitData, AsWeakPtr()));
[email protected]2b57e2e2014-05-09 11:07:251715
tguilbert25a4d112016-10-13 21:56:511716 if (use_fallback_path_) {
tguilbert9881bc22016-10-27 03:13:411717 demuxer_.reset(
1718 new MediaUrlDemuxer(media_task_runner_, fallback_url_,
1719 frame_->document().firstPartyForCookies()));
tguilbert25a4d112016-10-13 21:56:511720 pipeline_controller_.Start(demuxer_.get(), this, false, false);
1721 return;
1722 }
1723
[email protected]ddbc6ff2013-04-19 15:28:331724 // Figure out which demuxer to use.
[email protected]ef8394c2013-08-21 20:26:301725 if (load_type_ != LoadTypeMediaSource) {
[email protected]ddbc6ff2013-04-19 15:28:331726 DCHECK(!chunk_demuxer_);
[email protected]f5443ef72013-04-22 04:03:381727 DCHECK(data_source_);
1728
j.isorcef6778e652015-11-16 17:14:251729#if !defined(MEDIA_DISABLE_FFMPEG)
servolk81e01e02016-03-05 03:29:151730 Demuxer::MediaTracksUpdatedCB media_tracks_updated_cb =
dcheng37b415b92017-01-27 20:17:431731 BindToCurrentLoop(base::Bind(
1732 &WebMediaPlayerImpl::OnFFmpegMediaTracksUpdated, AsWeakPtr()));
servolk81e01e02016-03-05 03:29:151733
xhwange8c4181a2014-12-06 08:10:011734 demuxer_.reset(new FFmpegDemuxer(media_task_runner_, data_source_.get(),
servolk81e01e02016-03-05 03:29:151735 encrypted_media_init_data_cb,
1736 media_tracks_updated_cb, media_log_));
j.isorcef6778e652015-11-16 17:14:251737#else
alokp967c902452016-05-06 05:21:371738 OnError(PipelineStatus::DEMUXER_ERROR_COULD_NOT_OPEN);
j.isorcef6778e652015-11-16 17:14:251739 return;
1740#endif
[email protected]ddbc6ff2013-04-19 15:28:331741 } else {
[email protected]f5443ef72013-04-22 04:03:381742 DCHECK(!chunk_demuxer_);
1743 DCHECK(!data_source_);
1744
acolwell9e0840d2014-09-06 19:01:321745 chunk_demuxer_ = new ChunkDemuxer(
dcheng37b415b92017-01-27 20:17:431746 BindToCurrentLoop(
1747 base::Bind(&WebMediaPlayerImpl::OnDemuxerOpened, AsWeakPtr())),
chcunningham967db2f2016-11-02 20:47:171748 encrypted_media_init_data_cb, media_log_);
[email protected]f5443ef72013-04-22 04:03:381749 demuxer_.reset(chunk_demuxer_);
servolkf94b4602017-01-31 16:44:271750
1751 if (base::FeatureList::IsEnabled(kMemoryPressureBasedSourceBufferGC)) {
1752 // base::Unretained is safe because |this| owns memory_pressure_listener_.
1753 memory_pressure_listener_ =
1754 base::MakeUnique<base::MemoryPressureListener>(base::Bind(
1755 &WebMediaPlayerImpl::OnMemoryPressure, base::Unretained(this)));
1756 }
[email protected]ddbc6ff2013-04-19 15:28:331757 }
1758
sandersdb5e21462016-03-09 01:49:071759 // TODO(sandersd): FileSystem objects may also be non-static, but due to our
1760 // caching layer such situations are broken already. http://crbug.com/593159
1761 bool is_static = !chunk_demuxer_;
avayvod102cdb62017-01-07 03:11:091762 bool is_streaming = IsStreaming();
sandersdb8eb5f1d2016-11-19 04:04:021763 UMA_HISTOGRAM_BOOLEAN("Media.IsStreaming", is_streaming);
sandersdb5e21462016-03-09 01:49:071764
[email protected]f5443ef72013-04-22 04:03:381765 // ... and we're ready to go!
sandersd1e49fb62015-12-12 01:18:061766 // TODO(sandersd): On Android, defer Start() if the tab is not visible.
sandersdb8eb5f1d2016-11-19 04:04:021767 seeking_ = true;
alokp967c902452016-05-06 05:21:371768 pipeline_controller_.Start(demuxer_.get(), this, is_streaming, is_static);
[email protected]f5443ef72013-04-22 04:03:381769}
1770
1771void WebMediaPlayerImpl::SetNetworkState(WebMediaPlayer::NetworkState state) {
pkastingf5279482016-07-27 02:18:201772 DVLOG(1) << __func__ << "(" << state << ")";
acolwellb4034942014-08-28 15:42:431773 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]f5443ef72013-04-22 04:03:381774 network_state_ = state;
1775 // Always notify to ensure client has the latest value.
[email protected]ce70c982013-12-20 17:04:321776 client_->networkStateChanged();
[email protected]f5443ef72013-04-22 04:03:381777}
1778
1779void WebMediaPlayerImpl::SetReadyState(WebMediaPlayer::ReadyState state) {
pkastingf5279482016-07-27 02:18:201780 DVLOG(1) << __func__ << "(" << state << ")";
acolwellb4034942014-08-28 15:42:431781 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]f5443ef72013-04-22 04:03:381782
[email protected]fee8a902014-06-03 13:43:361783 if (state == WebMediaPlayer::ReadyStateHaveEnoughData && data_source_ &&
1784 data_source_->assume_fully_buffered() &&
[email protected]f5443ef72013-04-22 04:03:381785 network_state_ == WebMediaPlayer::NetworkStateLoading)
1786 SetNetworkState(WebMediaPlayer::NetworkStateLoaded);
1787
1788 ready_state_ = state;
sandersd50a635e2016-04-04 22:50:091789 highest_ready_state_ = std::max(highest_ready_state_, ready_state_);
1790
[email protected]f5443ef72013-04-22 04:03:381791 // Always notify to ensure client has the latest value.
[email protected]ce70c982013-12-20 17:04:321792 client_->readyStateChanged();
[email protected]f5443ef72013-04-22 04:03:381793}
1794
Dana Jansens71331252016-03-09 20:57:221795blink::WebAudioSourceProvider* WebMediaPlayerImpl::getAudioSourceProvider() {
[email protected]ff875be52013-06-02 23:47:381796 return audio_source_provider_.get();
[email protected]f5443ef72013-04-22 04:03:381797}
1798
[email protected]dd061e12014-05-06 19:21:221799static void GetCurrentFrameAndSignal(
1800 VideoFrameCompositor* compositor,
acolwell9e0840d2014-09-06 19:01:321801 scoped_refptr<VideoFrame>* video_frame_out,
[email protected]dd061e12014-05-06 19:21:221802 base::WaitableEvent* event) {
1803 TRACE_EVENT0("media", "GetCurrentFrameAndSignal");
dalecurtis44ce4de2015-05-11 18:42:071804 *video_frame_out = compositor->GetCurrentFrameAndUpdateIfStale();
[email protected]dd061e12014-05-06 19:21:221805 event->Signal();
1806}
1807
acolwell9e0840d2014-09-06 19:01:321808scoped_refptr<VideoFrame>
[email protected]dd061e12014-05-06 19:21:221809WebMediaPlayerImpl::GetCurrentFrameFromCompositor() {
xhwang213e50c2016-10-10 23:56:311810 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]dd061e12014-05-06 19:21:221811 TRACE_EVENT0("media", "WebMediaPlayerImpl::GetCurrentFrameFromCompositor");
xhwang213e50c2016-10-10 23:56:311812
1813 // Needed when the |main_task_runner_| and |compositor_task_runner_| are the
1814 // same to avoid deadlock in the Wait() below.
[email protected]dd061e12014-05-06 19:21:221815 if (compositor_task_runner_->BelongsToCurrentThread())
dalecurtis44ce4de2015-05-11 18:42:071816 return compositor_->GetCurrentFrameAndUpdateIfStale();
[email protected]dd061e12014-05-06 19:21:221817
1818 // Use a posted task and waitable event instead of a lock otherwise
1819 // WebGL/Canvas can see different content than what the compositor is seeing.
acolwell9e0840d2014-09-06 19:01:321820 scoped_refptr<VideoFrame> video_frame;
gab0d77c7cb2016-06-02 00:00:231821 base::WaitableEvent event(base::WaitableEvent::ResetPolicy::AUTOMATIC,
1822 base::WaitableEvent::InitialState::NOT_SIGNALED);
[email protected]dd061e12014-05-06 19:21:221823 compositor_task_runner_->PostTask(FROM_HERE,
1824 base::Bind(&GetCurrentFrameAndSignal,
1825 base::Unretained(compositor_),
1826 &video_frame,
1827 &event));
1828 event.Wait();
1829 return video_frame;
1830}
1831
sandersd50a635e2016-04-04 22:50:091832void WebMediaPlayerImpl::UpdatePlayState() {
xhwang213e50c2016-10-10 23:56:311833 DCHECK(main_task_runner_->BelongsToCurrentThread());
1834
hubbed5f36882016-01-15 22:40:371835#if defined(OS_ANDROID) // WMPI_CAST
sandersd50a635e2016-04-04 22:50:091836 bool is_remote = isRemote();
sandersdaaff1a652016-11-17 01:47:251837 bool is_streaming = false;
sandersd50a635e2016-04-04 22:50:091838#else
1839 bool is_remote = false;
avayvod102cdb62017-01-07 03:11:091840 bool is_streaming = IsStreaming();
hubbed5f36882016-01-15 22:40:371841#endif
xhwang213e50c2016-10-10 23:56:311842
dalecurtis8b8505e72016-06-10 21:59:171843 bool is_suspended = pipeline_controller_.IsSuspended();
avayvod39c102402016-11-23 21:43:131844 bool is_backgrounded = IsBackgroundedSuspendEnabled() && IsHidden();
sandersdaaff1a652016-11-17 01:47:251845 PlayState state = UpdatePlayState_ComputePlayState(
1846 is_remote, is_streaming, is_suspended, is_backgrounded);
sandersd35d2c3f2017-01-14 02:04:421847 SetDelegateState(state.delegate_state, state.is_idle);
sandersd50a635e2016-04-04 22:50:091848 SetMemoryReportingState(state.is_memory_reporting_enabled);
1849 SetSuspendState(state.is_suspended || pending_suspend_resume_cycle_);
1850}
dalecurtis5bbc487e2016-02-27 04:15:051851
sandersd35d2c3f2017-01-14 02:04:421852void WebMediaPlayerImpl::SetDelegateState(DelegateState new_state,
1853 bool is_idle) {
tguilbert1bb1c782017-01-23 21:15:111854 DCHECK(delegate_);
dalecurtis5bbc487e2016-02-27 04:15:051855
sandersd35d2c3f2017-01-14 02:04:421856 // Prevent duplicate delegate calls.
1857 // TODO(sandersd): Move this deduplication into the delegate itself.
1858 // TODO(sandersd): WebContentsObserverSanityChecker does not allow sending the
1859 // 'playing' IPC more than once in a row, even if the metadata has changed.
1860 // Figure out whether it should.
1861 bool has_audio = hasAudio() && !client_->isAutoplayingMuted();
1862 if (delegate_state_ == new_state &&
1863 (delegate_state_ != DelegateState::PLAYING ||
1864 delegate_has_audio_ == has_audio)) {
1865 return;
mlamouri910111362016-11-04 11:28:241866 }
sandersd50a635e2016-04-04 22:50:091867 delegate_state_ = new_state;
sandersd35d2c3f2017-01-14 02:04:421868 delegate_has_audio_ = has_audio;
sandersd50a635e2016-04-04 22:50:091869
sandersd35d2c3f2017-01-14 02:04:421870 switch (new_state) {
sandersd50a635e2016-04-04 22:50:091871 case DelegateState::GONE:
1872 delegate_->PlayerGone(delegate_id_);
1873 break;
mlamouri910111362016-11-04 11:28:241874 case DelegateState::PLAYING: {
zqzhang5d8eab72016-08-26 20:34:301875 delegate_->DidPlay(
sandersd35d2c3f2017-01-14 02:04:421876 delegate_id_, hasVideo(), has_audio,
avayvodcc273dd2017-01-19 19:35:121877 media::DurationToMediaContentType(GetPipelineMediaDuration()));
sandersd50a635e2016-04-04 22:50:091878 break;
mlamouri910111362016-11-04 11:28:241879 }
sandersd50a635e2016-04-04 22:50:091880 case DelegateState::PAUSED:
sandersd35d2c3f2017-01-14 02:04:421881 delegate_->DidPause(delegate_id_);
sandersd50a635e2016-04-04 22:50:091882 break;
dalecurtis0f0097a2015-12-01 17:40:471883 }
sandersd35d2c3f2017-01-14 02:04:421884
1885 delegate_->SetIdle(delegate_id_, is_idle);
dalecurtis0f0097a2015-12-01 17:40:471886}
1887
sandersd50a635e2016-04-04 22:50:091888void WebMediaPlayerImpl::SetMemoryReportingState(
1889 bool is_memory_reporting_enabled) {
1890 if (memory_usage_reporting_timer_.IsRunning() ==
1891 is_memory_reporting_enabled) {
hubbed5f36882016-01-15 22:40:371892 return;
sandersd50a635e2016-04-04 22:50:091893 }
sandersd1c0bba02016-03-04 23:14:081894
sandersd50a635e2016-04-04 22:50:091895 if (is_memory_reporting_enabled) {
1896 memory_usage_reporting_timer_.Start(FROM_HERE,
1897 base::TimeDelta::FromSeconds(2), this,
1898 &WebMediaPlayerImpl::ReportMemoryUsage);
1899 } else {
1900 memory_usage_reporting_timer_.Stop();
1901 ReportMemoryUsage();
1902 }
1903}
1904
1905void WebMediaPlayerImpl::SetSuspendState(bool is_suspended) {
xhwang213e50c2016-10-10 23:56:311906 DCHECK(main_task_runner_->BelongsToCurrentThread());
jameswest451a5bb2017-01-27 03:59:391907 if (!suspend_enabled_) {
1908 DCHECK(!pipeline_controller_.IsSuspended());
1909 return;
1910 }
xhwang213e50c2016-10-10 23:56:311911
sandersd50a635e2016-04-04 22:50:091912 // Do not change the state after an error has occurred.
1913 // TODO(sandersd): Update PipelineController to remove the need for this.
1914 if (IsNetworkStateError(network_state_))
sandersd1c0bba02016-03-04 23:14:081915 return;
1916
jameswest451a5bb2017-01-27 03:59:391917 if (is_suspended) {
sandersd35d2c3f2017-01-14 02:04:421918 // If we were not resumed for long enough to satisfy the preroll attempt,
1919 // reset the clock.
1920 if (!preroll_attempt_pending_ && IsPrerollAttemptNeeded()) {
1921 preroll_attempt_pending_ = true;
1922 preroll_attempt_start_time_ = base::TimeTicks();
1923 }
sandersd50a635e2016-04-04 22:50:091924 pipeline_controller_.Suspend();
1925 } else {
sandersd35d2c3f2017-01-14 02:04:421926 // When resuming, start the preroll attempt clock.
1927 if (preroll_attempt_pending_) {
1928 preroll_attempt_pending_ = false;
1929 preroll_attempt_start_time_ = tick_clock_->NowTicks();
1930 }
sandersd50a635e2016-04-04 22:50:091931 pipeline_controller_.Resume();
1932 }
1933}
1934
1935WebMediaPlayerImpl::PlayState
1936WebMediaPlayerImpl::UpdatePlayState_ComputePlayState(bool is_remote,
sandersdaaff1a652016-11-17 01:47:251937 bool is_streaming,
dalecurtis8b8505e72016-06-10 21:59:171938 bool is_suspended,
sandersd50a635e2016-04-04 22:50:091939 bool is_backgrounded) {
1940 PlayState result;
1941
tguilbert1bb1c782017-01-23 21:15:111942 bool must_suspend = delegate_->IsFrameClosed();
1943 bool is_stale = delegate_->IsStale(delegate_id_);
sandersd35d2c3f2017-01-14 02:04:421944
sandersd50a635e2016-04-04 22:50:091945 // This includes both data source (before pipeline startup) and pipeline
1946 // errors.
1947 bool has_error = IsNetworkStateError(network_state_);
1948
1949 // After HaveMetadata, we know which tracks are present and the duration.
1950 bool have_metadata = ready_state_ >= WebMediaPlayer::ReadyStateHaveMetadata;
1951
dalecurtiscc8baf72016-10-27 01:49:441952 // After HaveFutureData, Blink will call play() if the state is not paused;
1953 // prior to this point |paused_| is not accurate.
sandersd50a635e2016-04-04 22:50:091954 bool have_future_data =
1955 highest_ready_state_ >= WebMediaPlayer::ReadyStateHaveFutureData;
1956
dalecurtis8b8505e72016-06-10 21:59:171957 // Background suspend is not enabled for audio-only players unless paused,
1958 // though in the case of audio-only the session should be kept.
avayvod48a8be52016-08-04 19:52:501959 // Videos are not suspended if the user resumed the playback via the remote
1960 // controls earlier and it's still playing.
1961 bool is_backgrounded_video = is_backgrounded && have_metadata && hasVideo();
1962 bool can_play_backgrounded = is_backgrounded_video && !is_remote &&
1963 hasAudio() && IsResumeBackgroundVideosEnabled();
tguilbert1bb1c782017-01-23 21:15:111964 bool is_background_playing = delegate_->IsBackgroundVideoPlaybackUnlocked();
sandersdaaff1a652016-11-17 01:47:251965 bool background_suspended = !is_streaming && is_backgrounded_video &&
avayvod48a8be52016-08-04 19:52:501966 !(can_play_backgrounded && is_background_playing);
dalecurtiscc8baf72016-10-27 01:49:441967 bool background_pause_suspended =
sandersdaaff1a652016-11-17 01:47:251968 !is_streaming && is_backgrounded && paused_ && have_future_data;
sandersd50a635e2016-04-04 22:50:091969
dalecurtiscc8baf72016-10-27 01:49:441970 // Idle suspension is allowed prior to have future data since there exist
1971 // mechanisms to exit the idle state when the player is capable of reaching
1972 // the have future data state; see didLoadingProgress().
1973 //
sandersd50a635e2016-04-04 22:50:091974 // TODO(sandersd): Make the delegate suspend idle players immediately when
1975 // hidden.
sandersdaaff1a652016-11-17 01:47:251976 bool idle_suspended =
sandersd35d2c3f2017-01-14 02:04:421977 !is_streaming && is_stale && paused_ && !seeking_ && !overlay_enabled_;
dalecurtise7120dc2016-09-03 02:54:351978
1979 // If we're already suspended, see if we can wait for user interaction. Prior
sandersd35d2c3f2017-01-14 02:04:421980 // to HaveFutureData, we require |is_stale| to remain suspended. |is_stale|
dalecurtise7120dc2016-09-03 02:54:351981 // will be cleared when we receive data which may take us to HaveFutureData.
1982 bool can_stay_suspended =
sandersd35d2c3f2017-01-14 02:04:421983 (is_stale || have_future_data) && is_suspended && paused_ && !seeking_;
sandersd50a635e2016-04-04 22:50:091984
1985 // Combined suspend state.
sandersd35d2c3f2017-01-14 02:04:421986 result.is_suspended = is_remote || must_suspend || idle_suspended ||
dalecurtise7120dc2016-09-03 02:54:351987 background_suspended || background_pause_suspended ||
1988 can_stay_suspended;
sandersd50a635e2016-04-04 22:50:091989
1990 // We do not treat |playback_rate_| == 0 as paused. For the media session,
1991 // being paused implies displaying a play button, which is incorrect in this
1992 // case. For memory usage reporting, we just use the same definition (but we
1993 // don't have to).
1994 //
1995 // Similarly, we don't consider |ended_| to be paused. Blink will immediately
1996 // call pause() or seek(), so |ended_| should not affect the computation.
1997 // Despite that, |ended_| does result in a separate paused state, to simplfy
1998 // the contract for SetDelegateState().
1999 //
2000 // |has_session| is used to decide when to create a media session. Idle
2001 // suspension does not destroy the media session, because we expect that the
2002 // notification controls (and audio focus) remain. We also require:
2003 // - |have_metadata|, since the tracks and duration are passed to DidPlay().
2004 // - |have_future_data|, since we need to know whether we are paused to
2005 // correctly configure the session.
2006 //
2007 // TODO(sandersd): If Blink told us the paused state sooner, we could create
2008 // the media session sooner.
2009 bool can_play = !has_error && !is_remote && have_future_data;
sandersd35d2c3f2017-01-14 02:04:422010 bool has_session_playing = can_play && !must_suspend && !background_suspended;
avayvod48a8be52016-08-04 19:52:502011
2012 // |has_session_suspended| means the player is suspended from the media
2013 // element point of view but paused and can be resumed from the delegate point
2014 // of view. Therefore it behaves like |paused_| for the delegate.
sandersd35d2c3f2017-01-14 02:04:422015 bool has_session_suspended = can_play && !must_suspend &&
avayvod48a8be52016-08-04 19:52:502016 background_suspended && can_play_backgrounded;
2017
2018 bool has_session = has_session_playing || has_session_suspended;
sandersd50a635e2016-04-04 22:50:092019
2020 if (!has_session) {
2021 result.delegate_state = DelegateState::GONE;
tguilbert1bb1c782017-01-23 21:15:112022 result.is_idle = delegate_->IsIdle(delegate_id_);
avayvod48a8be52016-08-04 19:52:502023 } else if (paused_ || has_session_suspended) {
sandersd35d2c3f2017-01-14 02:04:422024 // TODO(sandersd): Is it possible to have a suspended session, be ended,
2025 // and not be paused? If so we should be in a PLAYING state.
dalecurtise7120dc2016-09-03 02:54:352026 result.delegate_state =
sandersd35d2c3f2017-01-14 02:04:422027 ended_ ? DelegateState::GONE : DelegateState::PAUSED;
2028 result.is_idle = !seeking_;
sandersd50a635e2016-04-04 22:50:092029 } else {
2030 result.delegate_state = DelegateState::PLAYING;
sandersd35d2c3f2017-01-14 02:04:422031 result.is_idle = false;
sandersd50a635e2016-04-04 22:50:092032 }
2033
dalecurtis8b8505e72016-06-10 21:59:172034 // It's not critical if some cases where memory usage can change are missed,
sandersd50a635e2016-04-04 22:50:092035 // since media memory changes are usually gradual.
2036 result.is_memory_reporting_enabled =
sandersd35d2c3f2017-01-14 02:04:422037 can_play && !result.is_suspended && (!paused_ || seeking_);
sandersd50a635e2016-04-04 22:50:092038
2039 return result;
dalecurtis0f0097a2015-12-01 17:40:472040}
2041
dalecurtis83266c72015-10-29 18:43:202042void WebMediaPlayerImpl::ReportMemoryUsage() {
2043 DCHECK(main_task_runner_->BelongsToCurrentThread());
2044
wdzierzanowskifd4cd91c52015-12-02 23:50:202045 // About base::Unretained() usage below: We destroy |demuxer_| on the main
2046 // thread. Before that, however, ~WebMediaPlayerImpl() posts a task to the
2047 // media thread and waits for it to finish. Hence, the GetMemoryUsage() task
2048 // posted here must finish earlier.
2049
2050 if (demuxer_) {
2051 base::PostTaskAndReplyWithResult(
2052 media_task_runner_.get(), FROM_HERE,
2053 base::Bind(&Demuxer::GetMemoryUsage, base::Unretained(demuxer_.get())),
2054 base::Bind(&WebMediaPlayerImpl::FinishMemoryUsageReport, AsWeakPtr()));
2055 } else {
2056 FinishMemoryUsageReport(0);
2057 }
2058}
2059
2060void WebMediaPlayerImpl::FinishMemoryUsageReport(int64_t demuxer_memory_usage) {
2061 DCHECK(main_task_runner_->BelongsToCurrentThread());
2062
avayvodc4bfb0e62017-01-13 01:07:012063 const PipelineStatistics stats = GetPipelineStatistics();
servolk639473e492016-12-15 04:14:202064 const int64_t data_source_memory_usage =
2065 data_source_ ? data_source_->GetMemoryUsage() : 0;
dalecurtis83266c72015-10-29 18:43:202066 const int64_t current_memory_usage =
2067 stats.audio_memory_usage + stats.video_memory_usage +
servolk639473e492016-12-15 04:14:202068 data_source_memory_usage + demuxer_memory_usage;
dalecurtis83266c72015-10-29 18:43:202069
dalecurtis3a7d38f42016-03-07 21:17:132070 // Note, this isn't entirely accurate, there may be VideoFrames held by the
2071 // compositor or other resources that we're unaware of.
2072
dalecurtis83266c72015-10-29 18:43:202073 DVLOG(2) << "Memory Usage -- Audio: " << stats.audio_memory_usage
servolk639473e492016-12-15 04:14:202074 << ", Video: " << stats.video_memory_usage
2075 << ", DataSource: " << data_source_memory_usage
wdzierzanowskifd4cd91c52015-12-02 23:50:202076 << ", Demuxer: " << demuxer_memory_usage;
dalecurtis83266c72015-10-29 18:43:202077
2078 const int64_t delta = current_memory_usage - last_reported_memory_usage_;
2079 last_reported_memory_usage_ = current_memory_usage;
2080 adjust_allocated_memory_cb_.Run(delta);
servolk639473e492016-12-15 04:14:202081
2082 if (hasAudio()) {
2083 UMA_HISTOGRAM_MEMORY_KB("Media.WebMediaPlayerImpl.Memory.Audio",
2084 stats.audio_memory_usage / 1024);
2085 }
2086 if (hasVideo()) {
2087 UMA_HISTOGRAM_MEMORY_KB("Media.WebMediaPlayerImpl.Memory.Video",
2088 stats.video_memory_usage / 1024);
2089 }
2090 if (data_source_) {
2091 UMA_HISTOGRAM_MEMORY_KB("Media.WebMediaPlayerImpl.Memory.DataSource",
2092 data_source_memory_usage / 1024);
2093 }
2094 if (demuxer_) {
2095 UMA_HISTOGRAM_MEMORY_KB("Media.WebMediaPlayerImpl.Memory.Demuxer",
2096 demuxer_memory_usage / 1024);
2097 }
dalecurtis83266c72015-10-29 18:43:202098}
2099
dalecurtis8b8505e72016-06-10 21:59:172100void WebMediaPlayerImpl::ScheduleIdlePauseTimer() {
dalecurtise7120dc2016-09-03 02:54:352101 // Only schedule the pause timer if we're playing and are suspended.
2102 if (paused_ || !pipeline_controller_.IsSuspended())
dalecurtis8b8505e72016-06-10 21:59:172103 return;
2104
2105#if defined(OS_ANDROID)
2106 // Remote players will be suspended and locally paused.
2107 if (isRemote())
2108 return;
2109#endif
2110
2111 // Idle timeout chosen arbitrarily.
2112 background_pause_timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(5),
2113 this, &WebMediaPlayerImpl::OnPause);
2114}
2115
dalecurtis04bdb582016-08-17 22:15:232116void WebMediaPlayerImpl::CreateWatchTimeReporter() {
2117 // Create the watch time reporter and synchronize its initial state.
2118 watch_time_reporter_.reset(new WatchTimeReporter(
2119 hasAudio(), hasVideo(), !!chunk_demuxer_, is_encrypted_, media_log_,
2120 pipeline_metadata_.natural_size,
2121 base::Bind(&GetCurrentTimeInternal, this)));
2122 watch_time_reporter_->OnVolumeChange(volume_);
tguilbert1bb1c782017-01-23 21:15:112123 if (delegate_->IsFrameHidden())
dalecurtis04bdb582016-08-17 22:15:232124 watch_time_reporter_->OnHidden();
2125 else
2126 watch_time_reporter_->OnShown();
2127}
2128
avayvod39c102402016-11-23 21:43:132129bool WebMediaPlayerImpl::IsHidden() const {
2130 DCHECK(main_task_runner_->BelongsToCurrentThread());
2131
tguilbert1bb1c782017-01-23 21:15:112132 return delegate_->IsFrameHidden() && !delegate_->IsFrameClosed();
avayvod39c102402016-11-23 21:43:132133}
2134
avayvod102cdb62017-01-07 03:11:092135bool WebMediaPlayerImpl::IsStreaming() const {
2136 return data_source_ && data_source_->IsStreaming();
2137}
2138
liberato2fd111be2017-01-04 00:25:062139bool WebMediaPlayerImpl::DoesOverlaySupportMetadata() const {
2140 return pipeline_metadata_.video_rotation == VIDEO_ROTATION_0;
2141}
2142
xjzaf29d4182016-12-16 01:52:322143void WebMediaPlayerImpl::ActivateViewportIntersectionMonitoring(bool activate) {
2144 DCHECK(main_task_runner_->BelongsToCurrentThread());
2145
2146 client_->activateViewportIntersectionMonitoring(activate);
2147}
2148
avayvodcc273dd2017-01-19 19:35:122149bool WebMediaPlayerImpl::ShouldPauseVideoWhenHidden() const {
2150#if !defined(OS_ANDROID)
2151 // On desktop, this behavior is behind the feature flag.
avayvod2135a642017-01-13 00:17:142152 if (!IsBackgroundVideoTrackOptimizationEnabled())
2153 return false;
avayvodcc273dd2017-01-19 19:35:122154#endif
avayvodeb9098d2017-01-07 00:33:032155
avayvodcc273dd2017-01-19 19:35:122156 // Pause video-only players that match the criteria for being optimized.
2157 return !hasAudio() && IsBackgroundOptimizationCandidate();
avayvodeb9098d2017-01-07 00:33:032158}
2159
avayvod2135a642017-01-13 00:17:142160bool WebMediaPlayerImpl::ShouldDisableVideoWhenHidden() const {
avayvodcc273dd2017-01-19 19:35:122161 // This optimization is behind the flag on all platforms.
2162 if (!IsBackgroundVideoTrackOptimizationEnabled())
avayvodc4bfb0e62017-01-13 01:07:012163 return false;
avayvodc4bfb0e62017-01-13 01:07:012164
avayvodcc273dd2017-01-19 19:35:122165 // Disable video track only for players with audio that match the criteria for
2166 // being optimized.
2167 return hasAudio() && IsBackgroundOptimizationCandidate();
2168}
2169
2170bool WebMediaPlayerImpl::IsBackgroundOptimizationCandidate() const {
2171 DCHECK(main_task_runner_->BelongsToCurrentThread());
2172
avayvodcc273dd2017-01-19 19:35:122173#if defined(OS_ANDROID) // WMPI_CAST
avayvodac1a8522017-01-20 19:02:502174 // Don't optimize players being Cast.
avayvodcc273dd2017-01-19 19:35:122175 if (isRemote())
2176 return false;
avayvodac1a8522017-01-20 19:02:502177
2178 // Video-only players are always optimized (paused) on Android.
2179 // Don't check the keyframe distance and duration.
2180 if (!hasAudio() && hasVideo())
2181 return true;
avayvodcc273dd2017-01-19 19:35:122182#endif // defined(OS_ANDROID)
2183
2184 // Don't optimize audio-only or streaming players.
2185 if (!hasVideo() || IsStreaming())
2186 return false;
2187
2188 // Videos shorter than the maximum allowed keyframe distance can be optimized.
2189 base::TimeDelta duration = GetPipelineMediaDuration();
2190 if (duration < max_keyframe_distance_to_disable_background_video_)
2191 return true;
2192
2193 // Otherwise, only optimize videos with shorter average keyframe distance.
avayvodc4bfb0e62017-01-13 01:07:012194 PipelineStatistics stats = GetPipelineStatistics();
2195 return stats.video_keyframe_distance_average <
2196 max_keyframe_distance_to_disable_background_video_;
avayvod2135a642017-01-13 00:17:142197}
2198
avayvod56e1f3942017-01-21 02:06:312199void WebMediaPlayerImpl::UpdateBackgroundVideoOptimizationState() {
2200 if (IsHidden()) {
2201 if (ShouldPauseVideoWhenHidden())
2202 PauseVideoIfNeeded();
2203 else
2204 DisableVideoTrackIfNeeded();
2205 } else {
2206 EnableVideoTrackIfNeeded();
2207 }
2208}
2209
2210void WebMediaPlayerImpl::PauseVideoIfNeeded() {
2211 DCHECK(IsHidden());
2212
2213 // Don't pause video while the pipeline is stopped, resuming or seeking.
2214 // Also if the video is paused already.
2215 if (!pipeline_.IsRunning() || is_pipeline_resuming_ || seeking_ || paused_)
2216 return;
2217
2218 // OnPause() will set |paused_when_hidden_| to false and call
2219 // UpdatePlayState(), so set the flag to true after and then return.
2220 OnPause();
2221 paused_when_hidden_ = true;
2222}
2223
avayvod2135a642017-01-13 00:17:142224void WebMediaPlayerImpl::EnableVideoTrackIfNeeded() {
avayvod56e1f3942017-01-21 02:06:312225 // Don't change video track while the pipeline is stopped, resuming or
2226 // seeking.
2227 if (!pipeline_.IsRunning() || is_pipeline_resuming_ || seeking_)
avayvod2135a642017-01-13 00:17:142228 return;
2229
2230 if (video_track_disabled_) {
2231 video_track_disabled_ = false;
2232 if (client_->hasSelectedVideoTrack()) {
2233 WebMediaPlayer::TrackId trackId = client_->getSelectedVideoTrackId();
2234 selectedVideoTrackChanged(&trackId);
2235 }
2236 }
2237}
2238
2239void WebMediaPlayerImpl::DisableVideoTrackIfNeeded() {
2240 DCHECK(IsHidden());
2241
2242 // Don't change video track while the pipeline is resuming or seeking.
2243 if (is_pipeline_resuming_ || seeking_)
2244 return;
2245
2246 if (!video_track_disabled_ && ShouldDisableVideoWhenHidden()) {
2247 video_track_disabled_ = true;
2248 selectedVideoTrackChanged(nullptr);
2249 }
2250}
2251
avayvodc4bfb0e62017-01-13 01:07:012252void WebMediaPlayerImpl::SetPipelineStatisticsForTest(
2253 const PipelineStatistics& stats) {
2254 pipeline_statistics_for_test_ = base::make_optional(stats);
2255}
2256
2257PipelineStatistics WebMediaPlayerImpl::GetPipelineStatistics() const {
2258 DCHECK(main_task_runner_->BelongsToCurrentThread());
2259
2260 return pipeline_statistics_for_test_.value_or(pipeline_.GetStatistics());
2261}
2262
avayvodcc273dd2017-01-19 19:35:122263void WebMediaPlayerImpl::SetPipelineMediaDurationForTest(
2264 base::TimeDelta duration) {
2265 pipeline_media_duration_for_test_ = base::make_optional(duration);
2266}
2267
2268base::TimeDelta WebMediaPlayerImpl::GetPipelineMediaDuration() const {
2269 DCHECK(main_task_runner_->BelongsToCurrentThread());
2270
2271 return pipeline_media_duration_for_test_.value_or(
2272 pipeline_.GetMediaDuration());
2273}
2274
2275void WebMediaPlayerImpl::ReportTimeFromForegroundToFirstFrame(
2276 base::TimeTicks foreground_time,
2277 base::TimeTicks new_frame_time) {
2278 base::TimeDelta time_to_first_frame = new_frame_time - foreground_time;
2279 if (hasAudio()) {
2280 UMA_HISTOGRAM_TIMES(
2281 "Media.Video.TimeFromForegroundToFirstFrame.DisableTrack",
2282 time_to_first_frame);
2283 } else {
2284 UMA_HISTOGRAM_TIMES("Media.Video.TimeFromForegroundToFirstFrame.Paused",
2285 time_to_first_frame);
2286 }
2287}
2288
acolwell9e0840d2014-09-06 19:01:322289} // namespace media