blob: 637c89dcda742f247742952e0a2ead1d7d317386 [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"
Chris Cunninghamd9df58e2017-08-29 00:04:2344#include "media/blink/video_decode_stats_reporter.h"
dalecurtis04bdb582016-08-17 22:15:2345#include "media/blink/watch_time_reporter.h"
acolwell9e0840d2014-09-06 19:01:3246#include "media/blink/webaudiosourceprovider_impl.h"
xhwang97de4202014-11-25 08:44:0147#include "media/blink/webcontentdecryptionmodule_impl.h"
acolwell9e0840d2014-09-06 19:01:3248#include "media/blink/webinbandtexttrack_impl.h"
49#include "media/blink/webmediaplayer_delegate.h"
acolwell9e0840d2014-09-06 19:01:3250#include "media/blink/webmediaplayer_util.h"
51#include "media/blink/webmediasource_impl.h"
[email protected]efe7cd22012-09-12 23:55:0152#include "media/filters/chunk_demuxer.h"
[email protected]ddbc6ff2013-04-19 15:28:3353#include "media/filters/ffmpeg_demuxer.h"
jrummellc9d8e532015-02-26 18:38:1954#include "third_party/WebKit/public/platform/WebEncryptedMediaTypes.h"
srirama.m26f864d02015-07-14 05:21:4655#include "third_party/WebKit/public/platform/WebMediaPlayerClient.h"
56#include "third_party/WebKit/public/platform/WebMediaPlayerEncryptedMediaClient.h"
guidou9bfe4e2f2016-04-09 08:31:1957#include "third_party/WebKit/public/platform/WebMediaPlayerSource.h"
[email protected]745746d2013-08-23 02:09:1658#include "third_party/WebKit/public/platform/WebMediaSource.h"
[email protected]c10884462013-05-30 00:22:0959#include "third_party/WebKit/public/platform/WebRect.h"
nverne61d2da872017-05-24 10:15:3060#include "third_party/WebKit/public/platform/WebRuntimeFeatures.h"
mek966863c2016-02-04 23:39:0561#include "third_party/WebKit/public/platform/WebSecurityOrigin.h"
[email protected]c10884462013-05-30 00:22:0962#include "third_party/WebKit/public/platform/WebSize.h"
63#include "third_party/WebKit/public/platform/WebString.h"
lethalantidote7f6009d2017-07-07 21:47:3964#include "third_party/WebKit/public/platform/WebSurfaceLayerBridge.h"
[email protected]c10884462013-05-30 00:22:0965#include "third_party/WebKit/public/platform/WebURL.h"
tguilbert9881bc22016-10-27 03:13:4166#include "third_party/WebKit/public/web/WebDocument.h"
xhwang0acca44b2015-06-18 00:43:3167#include "third_party/WebKit/public/web/WebFrame.h"
[email protected]80504652014-04-18 04:41:5068#include "third_party/WebKit/public/web/WebLocalFrame.h"
avayvod65fad272017-02-24 01:00:4869#include "third_party/WebKit/public/web/WebUserGestureIndicator.h"
[email protected]2255a9332013-06-17 05:12:3170#include "third_party/WebKit/public/web/WebView.h"
[email protected]b3f2b912009-04-09 16:18:5271
dalecurtisea27a3ed2016-06-24 01:41:3072#if defined(OS_ANDROID)
73#include "media/base/android/media_codec_util.h"
74#endif
75
[email protected]180ef242013-11-07 06:50:4676using blink::WebCanvas;
77using blink::WebMediaPlayer;
78using blink::WebRect;
79using blink::WebSize;
80using blink::WebString;
hubbed5f36882016-01-15 22:40:3781using gpu::gles2::GLES2Interface;
82
danakj365175c2016-02-06 00:37:3783#define STATIC_ASSERT_ENUM(a, b) \
84 static_assert(static_cast<int>(a) == static_cast<int>(b), \
85 "mismatching enums: " #a)
86
hubbed5f36882016-01-15 22:40:3787namespace media {
[email protected]ec9212f2008-12-18 21:40:3688
[email protected]8931c41a2009-07-07 17:31:4989namespace {
90
[email protected]378f0b72009-08-11 17:11:4291// Limits the range of playback rate.
92//
93// TODO(kylep): Revisit these.
94//
95// Vista has substantially lower performance than XP or Windows7. If you speed
96// up a video too much, it can't keep up, and rendering stops updating except on
97// the time bar. For really high speeds, audio becomes a bottleneck and we just
98// use up the data we have, which may not achieve the speed requested, but will
99// not crash the tab.
100//
101// A very slow speed, ie 0.00000001x, causes the machine to lock up. (It seems
102// like a busy loop). It gets unresponsive, although its not completely dead.
103//
104// Also our timers are not very accurate (especially for ogg), which becomes
105// evident at low speeds and on Vista. Since other speeds are risky and outside
106// the norms, we think 1/16x to 16x is a safe and useful range for now.
[email protected]39bdde32013-04-17 17:44:20107const double kMinRate = 0.0625;
108const double kMaxRate = 16.0;
[email protected]378f0b72009-08-11 17:11:42109
hubbed5f36882016-01-15 22:40:37110void SetSinkIdOnMediaThread(scoped_refptr<WebAudioSourceProviderImpl> sink,
111 const std::string& device_id,
112 const url::Origin& security_origin,
olka68b69392016-04-01 11:42:12113 const OutputDeviceStatusCB& callback) {
114 sink->SwitchOutputDevice(device_id, security_origin, callback);
guidouc7babef2015-10-22 00:42:35115}
116
sandersd50a635e2016-04-04 22:50:09117bool IsBackgroundedSuspendEnabled() {
dalecurtis0431cbf2016-03-12 01:19:43118#if !defined(OS_ANDROID)
119 // Suspend/Resume is only enabled by default on Android.
120 return base::CommandLine::ForCurrentProcess()->HasSwitch(
121 switches::kEnableMediaSuspend);
122#else
123 return !base::CommandLine::ForCurrentProcess()->HasSwitch(
124 switches::kDisableMediaSuspend);
125#endif
126}
127
avayvod48a8be52016-08-04 19:52:50128bool IsResumeBackgroundVideosEnabled() {
129 return base::FeatureList::IsEnabled(kResumeBackgroundVideo);
130}
131
avayvod39c102402016-11-23 21:43:13132bool IsBackgroundVideoTrackOptimizationEnabled() {
133 return base::FeatureList::IsEnabled(kBackgroundVideoTrackOptimization);
134}
135
avayvod01201332017-04-14 00:27:15136bool IsBackgroundVideoPauseOptimizationEnabled() {
137 return base::FeatureList::IsEnabled(kBackgroundVideoPauseOptimization);
138}
139
avayvod82729272017-05-29 21:58:39140bool IsNewRemotePlaybackPipelineEnabled() {
141 return base::FeatureList::IsEnabled(kNewRemotePlaybackPipeline);
142}
143
sandersd50a635e2016-04-04 22:50:09144bool IsNetworkStateError(blink::WebMediaPlayer::NetworkState state) {
Blink Reformat1c4d759e2017-04-09 16:34:54145 bool result = state == blink::WebMediaPlayer::kNetworkStateFormatError ||
146 state == blink::WebMediaPlayer::kNetworkStateNetworkError ||
147 state == blink::WebMediaPlayer::kNetworkStateDecodeError;
148 DCHECK_EQ(state > blink::WebMediaPlayer::kNetworkStateLoaded, result);
sandersd50a635e2016-04-04 22:50:09149 return result;
150}
151
sandersd2c478422016-08-02 01:19:25152gfx::Size GetRotatedVideoSize(VideoRotation rotation, gfx::Size natural_size) {
153 if (rotation == VIDEO_ROTATION_90 || rotation == VIDEO_ROTATION_270)
154 return gfx::Size(natural_size.height(), natural_size.width());
155 return natural_size;
156}
157
sandersd35d2c3f2017-01-14 02:04:42158// How much time must have elapsed since loading last progressed before we
159// assume that the decoder will have had time to complete preroll.
160constexpr base::TimeDelta kPrerollAttemptTimeout =
watkd026f792016-11-05 00:28:51161 base::TimeDelta::FromSeconds(3);
162
[email protected]8931c41a2009-07-07 17:31:49163} // namespace
164
[email protected]6683e1b2014-04-10 01:45:38165class BufferedDataSourceHostImpl;
166
Blink Reformat1c4d759e2017-04-09 16:34:54167STATIC_ASSERT_ENUM(WebMediaPlayer::kCORSModeUnspecified,
danakj365175c2016-02-06 00:37:37168 UrlData::CORS_UNSPECIFIED);
Blink Reformat1c4d759e2017-04-09 16:34:54169STATIC_ASSERT_ENUM(WebMediaPlayer::kCORSModeAnonymous, UrlData::CORS_ANONYMOUS);
170STATIC_ASSERT_ENUM(WebMediaPlayer::kCORSModeUseCredentials,
danakj365175c2016-02-06 00:37:37171 UrlData::CORS_USE_CREDENTIALS);
[email protected]a5a01102012-06-06 17:01:24172
[email protected]5b5bb9d2010-10-22 19:57:36173WebMediaPlayerImpl::WebMediaPlayerImpl(
[email protected]35b2a972014-04-04 15:50:22174 blink::WebLocalFrame* frame,
[email protected]180ef242013-11-07 06:50:46175 blink::WebMediaPlayerClient* client,
srirama.m26f864d02015-07-14 05:21:46176 blink::WebMediaPlayerEncryptedMediaClient* encrypted_client,
tguilbert1bb1c782017-01-23 21:15:11177 WebMediaPlayerDelegate* delegate,
tguilbert70d2a00a2017-04-25 00:30:44178 std::unique_ptr<RendererFactorySelector> renderer_factory_selector,
Alok Priyadarshi7166d4d2017-07-29 04:04:25179 UrlIndex* url_index,
dalecurtis9cddc0b2017-04-19 21:23:38180 std::unique_ptr<WebMediaPlayerParams> params)
[email protected]f6af7592014-02-28 10:09:11181 : frame_(frame),
sandersd50a635e2016-04-04 22:50:09182 delegate_state_(DelegateState::GONE),
sandersd35d2c3f2017-01-14 02:04:42183 delegate_has_audio_(false),
Blink Reformat1c4d759e2017-04-09 16:34:54184 network_state_(WebMediaPlayer::kNetworkStateEmpty),
185 ready_state_(WebMediaPlayer::kReadyStateHaveNothing),
186 highest_ready_state_(WebMediaPlayer::kReadyStateHaveNothing),
Jennifer Apacible66a53db2017-08-28 20:45:03187 preload_(base::FeatureList::IsEnabled(kPreloadDefaultIsMetadata)
188 ? MultibufferDataSource::METADATA
189 : MultibufferDataSource::AUTO),
Blink Reformat1c4d759e2017-04-09 16:34:54190 main_task_runner_(frame->LoadingTaskRunner()),
dalecurtis9cddc0b2017-04-19 21:23:38191 media_task_runner_(params->media_task_runner()),
192 worker_task_runner_(params->worker_task_runner()),
193 media_log_(params->take_media_log()),
sandersd1c0bba02016-03-04 23:14:08194 pipeline_controller_(
tguilbert350936ff2017-02-24 05:39:27195 base::MakeUnique<PipelineImpl>(media_task_runner_, media_log_.get()),
sandersd1c0bba02016-03-04 23:14:08196 base::Bind(&WebMediaPlayerImpl::CreateRenderer,
197 base::Unretained(this)),
198 base::Bind(&WebMediaPlayerImpl::OnPipelineSeeked, AsWeakPtr()),
199 base::Bind(&WebMediaPlayerImpl::OnPipelineSuspended, AsWeakPtr()),
avayvod2135a642017-01-13 00:17:14200 base::Bind(&WebMediaPlayerImpl::OnBeforePipelineResume, AsWeakPtr()),
201 base::Bind(&WebMediaPlayerImpl::OnPipelineResumed, AsWeakPtr()),
alokp967c902452016-05-06 05:21:37202 base::Bind(&WebMediaPlayerImpl::OnError, AsWeakPtr())),
Blink Reformat1c4d759e2017-04-09 16:34:54203 load_type_(kLoadTypeURL),
[email protected]75e145a2014-04-15 17:44:32204 opaque_(false),
wolenetz1b2ae7d2015-06-10 00:44:21205 playback_rate_(0.0),
[email protected]49480902009-07-14 20:23:43206 paused_(true),
avayvodeb9098d2017-01-07 00:33:03207 paused_when_hidden_(false),
[email protected]b3766a22010-12-22 17:34:13208 seeking_(false),
watkdee516f2016-02-18 02:22:19209 pending_suspend_resume_cycle_(false),
scherkusd2c745b2014-09-04 05:03:40210 ended_(false),
yoichio863bebf2016-03-04 07:56:58211 should_notify_time_changed_(false),
tsunghungee562e92016-07-20 18:03:31212 overlay_enabled_(false),
213 decoder_requires_restart_for_overlay_(false),
[email protected]5badb082010-06-11 17:40:15214 client_(client),
srirama.m26f864d02015-07-14 05:21:46215 encrypted_client_(encrypted_client),
[email protected]baff4512011-10-19 18:21:07216 delegate_(delegate),
dalecurtisbb3eaac2016-01-27 21:10:25217 delegate_id_(0),
dalecurtis9cddc0b2017-04-19 21:23:38218 defer_load_cb_(params->defer_load_cb()),
219 context_3d_cb_(params->context_3d_cb()),
220 adjust_allocated_memory_cb_(params->adjust_allocated_memory_cb()),
dalecurtis83266c72015-10-29 18:43:20221 last_reported_memory_usage_(0),
[email protected]132dd57c2012-08-10 23:24:34222 supports_save_(true),
[email protected]f5443ef72013-04-22 04:03:38223 chunk_demuxer_(NULL),
hubbeb2d3efd2017-05-05 23:26:38224 tick_clock_(new base::DefaultTickClock()),
225 buffered_data_source_host_(
226 base::Bind(&WebMediaPlayerImpl::OnProgress, AsWeakPtr()),
227 tick_clock_.get()),
hubbe5f0ad43b2015-12-14 20:57:26228 url_index_(url_index),
Bartosz Fabianowski85a823812015-04-16 10:27:51229 // Threaded compositing isn't enabled universally yet.
dalecurtis9cddc0b2017-04-19 21:23:38230 compositor_task_runner_(params->compositor_task_runner()
231 ? params->compositor_task_runner()
fdoraydb3ef7d2016-06-09 15:42:38232 : base::ThreadTaskRunnerHandle::Get()),
alokp5d86e9b2016-05-17 20:20:41233 compositor_(new VideoFrameCompositor(compositor_task_runner_)),
hubbed5f36882016-01-15 22:40:37234#if defined(OS_ANDROID) // WMPI_CAST
dalecurtis9cddc0b2017-04-19 21:23:38235 cast_impl_(this, client_, params->context_3d_cb()),
hubbed5f36882016-01-15 22:40:37236#endif
dalecurtisbb3eaac2016-01-27 21:10:25237 volume_(1.0),
238 volume_multiplier_(1.0),
tguilbert70d2a00a2017-04-25 00:30:44239 renderer_factory_selector_(std::move(renderer_factory_selector)),
dalecurtis9cddc0b2017-04-19 21:23:38240 surface_manager_(params->surface_manager()),
tsunghungee562e92016-07-20 18:03:31241 overlay_surface_id_(SurfaceManager::kNoSurfaceID),
dalecurtis7f366b2242016-04-13 01:16:17242 suppress_destruction_errors_(false),
dalecurtis9d638a12016-08-30 06:20:55243 is_encrypted_(false),
sandersd35d2c3f2017-01-14 02:04:42244 preroll_attempt_pending_(false),
dalecurtis9cddc0b2017-04-19 21:23:38245 observer_(params->media_observer()),
avayvod590011e32017-01-20 02:01:00246 max_keyframe_distance_to_disable_background_video_(
dalecurtis9cddc0b2017-04-19 21:23:38247 params->max_keyframe_distance_to_disable_background_video()),
avayvode85ec422017-04-14 00:11:33248 max_keyframe_distance_to_disable_background_video_mse_(
dalecurtis9cddc0b2017-04-19 21:23:38249 params->max_keyframe_distance_to_disable_background_video_mse()),
servolkf94b4602017-01-31 16:44:27250 enable_instant_source_buffer_gc_(
dalecurtis9cddc0b2017-04-19 21:23:38251 params->enable_instant_source_buffer_gc()),
shaktisahu24189c12017-03-11 17:42:55252 embedded_media_experience_enabled_(
liberato2ff93ad2017-05-17 07:28:24253 params->embedded_media_experience_enabled()),
lethalantidote7f6009d2017-07-07 21:47:39254 surface_layer_for_video_enabled_(
255 base::FeatureList::IsEnabled(media::kUseSurfaceLayerForVideo)),
liberato2ff93ad2017-05-17 07:28:24256 request_routing_token_cb_(params->request_routing_token_cb()),
Dale Curtis1adbe6a2017-08-02 02:09:13257 overlay_routing_token_(OverlayInfo::RoutingToken()),
Chris Cunninghamd9df58e2017-08-29 00:04:23258 watch_time_recorder_provider_(params->watch_time_recorder_provider()),
259 create_decode_stats_recorder_cb_(
260 params->create_capabilities_recorder_cb()) {
xhwang51139732017-02-24 19:36:08261 DVLOG(1) << __func__;
dalecurtis83266c72015-10-29 18:43:20262 DCHECK(!adjust_allocated_memory_cb_.is_null());
tguilbert70d2a00a2017-04-25 00:30:44263 DCHECK(renderer_factory_selector_);
servolkef1e5ef2016-03-25 04:55:26264 DCHECK(client_);
tguilbert1bb1c782017-01-23 21:15:11265 DCHECK(delegate_);
dalecurtis83266c72015-10-29 18:43:20266
lethalantidote7f6009d2017-07-07 21:47:39267 if (surface_layer_for_video_enabled_)
268 bridge_ = base::WrapUnique(blink::WebSurfaceLayerBridge::Create());
269
tsunghungee562e92016-07-20 18:03:31270 force_video_overlays_ = base::CommandLine::ForCurrentProcess()->HasSwitch(
271 switches::kForceVideoOverlays);
272
liberato2ff93ad2017-05-17 07:28:24273 if (base::FeatureList::IsEnabled(media::kOverlayFullscreenVideo)) {
274 bool use_android_overlay =
275 base::FeatureList::IsEnabled(media::kUseAndroidOverlay);
276 overlay_mode_ = use_android_overlay ? OverlayMode::kUseAndroidOverlay
277 : OverlayMode::kUseContentVideoView;
278 } else {
279 overlay_mode_ = OverlayMode::kNoOverlays;
280 }
ampea73f792017-01-19 04:05:39281
tguilbert1bb1c782017-01-23 21:15:11282 delegate_id_ = delegate_->AddObserver(this);
283 delegate_->SetIdle(delegate_id_, true);
sandersd1e49fb62015-12-12 01:18:06284
dalecurtis2cff7f372017-05-24 08:30:08285 media_log_->AddEvent(media_log_->CreateCreatedEvent(
286 url::Origin(frame_->GetSecurityOrigin()).GetURL().spec()));
sandersd72683f252017-07-07 23:20:46287 media_log_->SetStringProperty("frame_url",
288 frame_->GetDocument().Url().GetString().Utf8());
289 media_log_->SetStringProperty("frame_title",
290 frame_->GetDocument().Title().Utf8());
[email protected]4e6be3f2009-05-07 02:24:44291
dalecurtis9cddc0b2017-04-19 21:23:38292 if (params->initial_cdm())
293 SetCdm(params->initial_cdm());
xhwang0ad11e512014-11-25 23:43:09294
xhwangf94a634d2014-10-22 22:07:27295 // TODO(xhwang): When we use an external Renderer, many methods won't work,
xhwang6fa356202014-12-11 00:44:12296 // e.g. GetCurrentFrameFromCompositor(). See http://crbug.com/434861
dalecurtis9cddc0b2017-04-19 21:23:38297 audio_source_provider_ = new WebAudioSourceProviderImpl(
298 params->audio_renderer_sink(), media_log_.get());
xjz4e5d4bf32017-02-15 21:26:35299
300 if (observer_)
301 observer_->SetClient(this);
[email protected]ec9212f2008-12-18 21:40:36302}
303
[email protected]4e6be3f2009-05-07 02:24:44304WebMediaPlayerImpl::~WebMediaPlayerImpl() {
xhwang51139732017-02-24 19:36:08305 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:43306 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53307
xhwang51139732017-02-24 19:36:08308 if (set_cdm_result_) {
309 DVLOG(2) << "Resolve pending SetCdm() when media player is destroyed.";
Blink Reformat1c4d759e2017-04-09 16:34:54310 set_cdm_result_->Complete();
xhwang51139732017-02-24 19:36:08311 set_cdm_result_.reset();
312 }
313
alokp1116967f2016-06-11 17:30:56314 suppress_destruction_errors_ = true;
tguilbert1bb1c782017-01-23 21:15:11315
316 delegate_->PlayerGone(delegate_id_);
317 delegate_->RemoveObserver(delegate_id_);
[email protected]baff4512011-10-19 18:21:07318
dalecurtis04bdb582016-08-17 22:15:23319 // Finalize any watch time metrics before destroying the pipeline.
320 watch_time_reporter_.reset();
321
tguilbert350936ff2017-02-24 05:39:27322 // The underlying Pipeline must be stopped before it is destroyed.
323 pipeline_controller_.Stop();
[email protected]f6af7592014-02-28 10:09:11324
dalecurtis83266c72015-10-29 18:43:20325 if (last_reported_memory_usage_)
326 adjust_allocated_memory_cb_.Run(-last_reported_memory_usage_);
327
dalecurtise1edb312016-06-22 02:33:21328 // Destruct compositor resources in the proper order.
Blink Reformat1c4d759e2017-04-09 16:34:54329 client_->SetWebLayer(nullptr);
lethalantidote7f6009d2017-07-07 21:47:39330 if (!surface_layer_for_video_enabled_ && video_weblayer_) {
dalecurtise1edb312016-06-22 02:33:21331 static_cast<cc::VideoLayer*>(video_weblayer_->layer())->StopUsingProvider();
lethalantidote7f6009d2017-07-07 21:47:39332 }
333 // TODO(lethalantidote): Handle destruction of compositor for surface layer.
334 // https://crbug/739854.
[email protected]dd061e12014-05-06 19:21:22335 compositor_task_runner_->DeleteSoon(FROM_HERE, compositor_);
xhwangea8bb3562015-06-08 21:18:37336
337 media_log_->AddEvent(
338 media_log_->CreateEvent(MediaLogEvent::WEBMEDIAPLAYER_DESTROYED));
[email protected]ec9212f2008-12-18 21:40:36339}
340
Blink Reformat1c4d759e2017-04-09 16:34:54341void WebMediaPlayerImpl::Load(LoadType load_type,
guidou9bfe4e2f2016-04-09 08:31:19342 const blink::WebMediaPlayerSource& source,
[email protected]62e5e682013-03-07 23:53:24343 CORSMode cors_mode) {
xhwang51139732017-02-24 19:36:08344 DVLOG(1) << __func__;
guidou9bfe4e2f2016-04-09 08:31:19345 // Only URL or MSE blob URL is supported.
Blink Reformat1c4d759e2017-04-09 16:34:54346 DCHECK(source.IsURL());
347 blink::WebURL url = source.GetAsURL();
Xiaohan Wang81fd0022017-07-11 17:45:24348 DVLOG(1) << __func__ << "(" << load_type << ", " << GURL(url) << ", "
349 << cors_mode << ")";
[email protected]d726eddc2013-07-02 22:25:55350 if (!defer_load_cb_.is_null()) {
tguilbert350936ff2017-02-24 05:39:27351 defer_load_cb_.Run(base::Bind(&WebMediaPlayerImpl::DoLoad, AsWeakPtr(),
352 load_type, url, cors_mode));
[email protected]d726eddc2013-07-02 22:25:55353 return;
354 }
[email protected]ef8394c2013-08-21 20:26:30355 DoLoad(load_type, url, cors_mode);
[email protected]62e5e682013-03-07 23:53:24356}
357
Blink Reformat1c4d759e2017-04-09 16:34:54358bool WebMediaPlayerImpl::SupportsOverlayFullscreenVideo() {
watk9c87c6fa2016-05-06 20:36:51359#if defined(OS_ANDROID)
[email protected]68ec57f2017-06-27 22:10:05360 return !using_media_player_renderer_ &&
361 overlay_mode_ == OverlayMode::kUseContentVideoView;
watk9c87c6fa2016-05-06 20:36:51362#else
363 return false;
364#endif
365}
366
tsunghungee562e92016-07-20 18:03:31367void WebMediaPlayerImpl::EnableOverlay() {
368 overlay_enabled_ = true;
liberato2ff93ad2017-05-17 07:28:24369 if (surface_manager_ && overlay_mode_ == OverlayMode::kUseContentVideoView) {
liberatoe8e3f43d2017-05-01 22:23:11370 overlay_surface_id_.reset();
watkf835a792016-06-24 23:24:40371 surface_created_cb_.Reset(
372 base::Bind(&WebMediaPlayerImpl::OnSurfaceCreated, AsWeakPtr()));
373 surface_manager_->CreateFullscreenSurface(pipeline_metadata_.natural_size,
374 surface_created_cb_.callback());
liberato2ff93ad2017-05-17 07:28:24375 } else if (request_routing_token_cb_ &&
376 overlay_mode_ == OverlayMode::kUseAndroidOverlay) {
liberatofe8f9692017-06-08 19:17:36377 overlay_routing_token_is_pending_ = true;
liberato2ff93ad2017-05-17 07:28:24378 token_available_cb_.Reset(
379 base::Bind(&WebMediaPlayerImpl::OnOverlayRoutingToken, AsWeakPtr()));
380 request_routing_token_cb_.Run(token_available_cb_.callback());
watkf835a792016-06-24 23:24:40381 }
tsunghungee562e92016-07-20 18:03:31382
liberato2ff93ad2017-05-17 07:28:24383 // We have requested (and maybe already have) overlay information. If the
384 // restarted decoder requests overlay information, then we'll defer providing
385 // it if it hasn't arrived yet. Otherwise, this would be a race, since we
386 // don't know if the request for overlay info or restart will complete first.
tsunghungee562e92016-07-20 18:03:31387 if (decoder_requires_restart_for_overlay_)
watkdee516f2016-02-18 02:22:19388 ScheduleRestart();
389}
390
tsunghungee562e92016-07-20 18:03:31391void WebMediaPlayerImpl::DisableOverlay() {
392 overlay_enabled_ = false;
liberato2ff93ad2017-05-17 07:28:24393 if (overlay_mode_ == OverlayMode::kUseContentVideoView) {
394 surface_created_cb_.Cancel();
395 overlay_surface_id_ = SurfaceManager::kNoSurfaceID;
396 } else if (overlay_mode_ == OverlayMode::kUseAndroidOverlay) {
397 token_available_cb_.Cancel();
liberatofe8f9692017-06-08 19:17:36398 overlay_routing_token_is_pending_ = false;
399 overlay_routing_token_ = OverlayInfo::RoutingToken();
liberato2ff93ad2017-05-17 07:28:24400 }
tsunghungee562e92016-07-20 18:03:31401
402 if (decoder_requires_restart_for_overlay_)
watkdee516f2016-02-18 02:22:19403 ScheduleRestart();
liberato2ff93ad2017-05-17 07:28:24404 else
405 MaybeSendOverlayInfoToDecoder();
watkdee516f2016-02-18 02:22:19406}
407
Blink Reformat1c4d759e2017-04-09 16:34:54408void WebMediaPlayerImpl::EnteredFullscreen() {
liberatofe8f9692017-06-08 19:17:36409 overlay_info_.is_fullscreen = true;
410
liberato2fd111be2017-01-04 00:25:06411 // |force_video_overlays_| implies that we're already in overlay mode, so take
412 // no action here. Otherwise, switch to an overlay if it's allowed and if
413 // it will display properly.
liberato2ff93ad2017-05-17 07:28:24414 if (!force_video_overlays_ && overlay_mode_ != OverlayMode::kNoOverlays &&
liberato2fd111be2017-01-04 00:25:06415 DoesOverlaySupportMetadata()) {
tsunghungee562e92016-07-20 18:03:31416 EnableOverlay();
liberato2fd111be2017-01-04 00:25:06417 }
liberato2ff93ad2017-05-17 07:28:24418
liberatofe8f9692017-06-08 19:17:36419 // We send this only if we can send multiple calls. Otherwise, either (a)
420 // we already sent it and we don't have a callback anyway (we reset it when
421 // it's called in restart mode), or (b) we'll send this later when the surface
422 // actually arrives. GVD assumes that the first overlay info will have the
423 // routing information. Note that we set |is_fullscreen_| earlier, so that
424 // if EnableOverlay() can include fullscreen info in case it sends the overlay
425 // info before returning.
426 if (!decoder_requires_restart_for_overlay_)
427 MaybeSendOverlayInfoToDecoder();
tsunghungee562e92016-07-20 18:03:31428}
429
Blink Reformat1c4d759e2017-04-09 16:34:54430void WebMediaPlayerImpl::ExitedFullscreen() {
liberatofe8f9692017-06-08 19:17:36431 overlay_info_.is_fullscreen = false;
432
liberato2fd111be2017-01-04 00:25:06433 // If we're in overlay mode, then exit it unless we're supposed to be in
434 // overlay mode all the time.
435 if (!force_video_overlays_ && overlay_enabled_)
tsunghungee562e92016-07-20 18:03:31436 DisableOverlay();
liberato2ff93ad2017-05-17 07:28:24437
liberatofe8f9692017-06-08 19:17:36438 // See EnteredFullscreen for why we do this.
439 if (!decoder_requires_restart_for_overlay_)
440 MaybeSendOverlayInfoToDecoder();
tsunghungee562e92016-07-20 18:03:31441}
442
Blink Reformat1c4d759e2017-04-09 16:34:54443void WebMediaPlayerImpl::BecameDominantVisibleContent(bool isDominant) {
xjzcdbbe732016-12-03 20:47:42444 if (observer_)
445 observer_->OnBecameDominantVisibleContent(isDominant);
446}
447
Blink Reformat1c4d759e2017-04-09 16:34:54448void WebMediaPlayerImpl::SetIsEffectivelyFullscreen(
zqzhangabc08242017-03-02 16:07:14449 bool isEffectivelyFullscreen) {
450 delegate_->SetIsEffectivelyFullscreen(delegate_id_, isEffectivelyFullscreen);
451}
452
Mounir Lamouri41a79c62017-06-06 12:53:16453void WebMediaPlayerImpl::OnHasNativeControlsChanged(bool has_native_controls) {
454 if (!watch_time_reporter_)
455 return;
456
457 if (has_native_controls)
458 watch_time_reporter_->OnNativeControlsEnabled();
459 else
460 watch_time_reporter_->OnNativeControlsDisabled();
461}
462
Mounir Lamourif9af74e72017-06-19 19:31:45463void WebMediaPlayerImpl::OnDisplayTypeChanged(
464 WebMediaPlayer::DisplayType display_type) {
465 if (!watch_time_reporter_)
466 return;
467
468 switch (display_type) {
469 case WebMediaPlayer::DisplayType::kInline:
470 watch_time_reporter_->OnDisplayTypeInline();
471 break;
472 case WebMediaPlayer::DisplayType::kFullscreen:
473 watch_time_reporter_->OnDisplayTypeFullscreen();
474 break;
475 case WebMediaPlayer::DisplayType::kPictureInPicture:
476 watch_time_reporter_->OnDisplayTypePictureInPicture();
477 break;
478 }
479}
480
[email protected]ef8394c2013-08-21 20:26:30481void WebMediaPlayerImpl::DoLoad(LoadType load_type,
[email protected]180ef242013-11-07 06:50:46482 const blink::WebURL& url,
[email protected]d726eddc2013-07-02 22:25:55483 CORSMode cors_mode) {
pkastingf5279482016-07-27 02:18:20484 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:43485 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d726eddc2013-07-02 22:25:55486
[email protected]62e5e682013-03-07 23:53:24487 GURL gurl(url);
dalecurtis9cddc0b2017-04-19 21:23:38488 ReportMetrics(load_type, gurl, frame_->GetSecurityOrigin(), media_log_.get());
[email protected]62e5e682013-03-07 23:53:24489
[email protected]926f8fd2013-04-12 20:27:53490 // Set subresource URL for crash reporting.
491 base::debug::SetCrashKeyValue("subresource_url", gurl.spec());
492
tguilbert75e2bf62017-04-26 20:13:12493 // Used for HLS playback.
494 loaded_url_ = gurl;
tguilbert25a4d112016-10-13 21:56:51495
[email protected]ef8394c2013-08-21 20:26:30496 load_type_ = load_type;
497
Blink Reformat1c4d759e2017-04-09 16:34:54498 SetNetworkState(WebMediaPlayer::kNetworkStateLoading);
499 SetReadyState(WebMediaPlayer::kReadyStateHaveNothing);
500 media_log_->AddEvent(media_log_->CreateLoadEvent(url.GetString().Utf8()));
[email protected]d726eddc2013-07-02 22:25:55501
502 // Media source pipelines can start immediately.
Blink Reformat1c4d759e2017-04-09 16:34:54503 if (load_type == kLoadTypeMediaSource) {
[email protected]d726eddc2013-07-02 22:25:55504 supports_save_ = false;
[email protected]ef8394c2013-08-21 20:26:30505 StartPipeline();
hubbe5f0ad43b2015-12-14 20:57:26506 } else {
dalecurtisb6e052f52016-08-25 00:35:55507 data_source_.reset(new MultibufferDataSource(
Alok Priyadarshib8f30542017-07-22 00:16:25508 main_task_runner_,
509 url_index_->GetByUrl(url, static_cast<UrlData::CORSMode>(cors_mode)),
510 media_log_.get(), &buffered_data_source_host_,
dalecurtisb6e052f52016-08-25 00:35:55511 base::Bind(&WebMediaPlayerImpl::NotifyDownloading, AsWeakPtr())));
avayvode46d7bef2016-03-30 23:18:26512 data_source_->SetPreload(preload_);
avayvode46d7bef2016-03-30 23:18:26513 data_source_->Initialize(
514 base::Bind(&WebMediaPlayerImpl::DataSourceInitialized, AsWeakPtr()));
hubbe5f0ad43b2015-12-14 20:57:26515 }
hubbed5f36882016-01-15 22:40:37516
517#if defined(OS_ANDROID) // WMPI_CAST
dalecurtisbb3eaac2016-01-27 21:10:25518 cast_impl_.Initialize(url, frame_, delegate_id_);
hubbed5f36882016-01-15 22:40:37519#endif
[email protected]62e5e682013-03-07 23:53:24520}
521
Blink Reformat1c4d759e2017-04-09 16:34:54522void WebMediaPlayerImpl::Play() {
pkastingf5279482016-07-27 02:18:20523 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:43524 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53525
avayvod65fad272017-02-24 01:00:48526 // User initiated play unlocks background video playback.
Blink Reformat1c4d759e2017-04-09 16:34:54527 if (blink::WebUserGestureIndicator::IsProcessingUserGesture())
avayvod65fad272017-02-24 01:00:48528 video_locked_when_paused_when_hidden_ = false;
529
hubbed5f36882016-01-15 22:40:37530#if defined(OS_ANDROID) // WMPI_CAST
Blink Reformat1c4d759e2017-04-09 16:34:54531 if (IsRemote()) {
dalecurtis6e2716d2016-01-21 04:49:15532 cast_impl_.play();
hubbed5f36882016-01-15 22:40:37533 return;
534 }
535#endif
sandersd35d2c3f2017-01-14 02:04:42536 // TODO(sandersd): Do we want to reset the idle timer here?
tguilbert1bb1c782017-01-23 21:15:11537 delegate_->SetIdle(delegate_id_, false);
[email protected]49480902009-07-14 20:23:43538 paused_ = false;
tguilbert350936ff2017-02-24 05:39:27539 pipeline_controller_.SetPlaybackRate(playback_rate_);
dalecurtis4619cd02016-09-22 21:39:10540 background_pause_timer_.Stop();
sandersd1c0bba02016-03-04 23:14:08541
[email protected]039b7542013-10-17 22:06:25542 if (data_source_)
543 data_source_->MediaIsPlaying();
[email protected]090f7312011-08-05 23:26:40544
xjz48a9cb72016-12-20 04:02:49545 if (observer_)
546 observer_->OnPlaying();
547
Dale Curtis051fdf62017-08-05 00:21:13548 // If we're seeking we'll trigger the watch time reporter upon seek completed;
549 // we don't want to start it here since the seek time is unstable. E.g., when
550 // playing content with a positive start time we would have a zero seek time.
551 if (!Seeking()) {
552 DCHECK(watch_time_reporter_);
553 watch_time_reporter_->OnPlaying();
554 }
555
Chris Cunninghamd9df58e2017-08-29 00:04:23556 if (video_decode_stats_reporter_)
557 video_decode_stats_reporter_->OnPlaying();
558
acolwell9e0840d2014-09-06 19:01:32559 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PLAY));
sandersd50a635e2016-04-04 22:50:09560 UpdatePlayState();
[email protected]ec9212f2008-12-18 21:40:36561}
562
Blink Reformat1c4d759e2017-04-09 16:34:54563void WebMediaPlayerImpl::Pause() {
pkastingf5279482016-07-27 02:18:20564 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:43565 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53566
sandersd50a635e2016-04-04 22:50:09567 // We update the paused state even when casting, since we expect pause() to be
568 // called when casting begins, and when we exit casting we should end up in a
569 // paused state.
[email protected]49480902009-07-14 20:23:43570 paused_ = true;
hubbed5f36882016-01-15 22:40:37571
avayvodeb9098d2017-01-07 00:33:03572 // No longer paused because it was hidden.
573 paused_when_hidden_ = false;
574
avayvod65fad272017-02-24 01:00:48575 // User initiated pause locks background videos.
Blink Reformat1c4d759e2017-04-09 16:34:54576 if (blink::WebUserGestureIndicator::IsProcessingUserGesture())
avayvod65fad272017-02-24 01:00:48577 video_locked_when_paused_when_hidden_ = true;
578
hubbed5f36882016-01-15 22:40:37579#if defined(OS_ANDROID) // WMPI_CAST
Blink Reformat1c4d759e2017-04-09 16:34:54580 if (IsRemote()) {
dalecurtis6e2716d2016-01-21 04:49:15581 cast_impl_.pause();
hubbed5f36882016-01-15 22:40:37582 return;
583 }
584#endif
585
tguilbert350936ff2017-02-24 05:39:27586 pipeline_controller_.SetPlaybackRate(0.0);
Dale Curtis051fdf62017-08-05 00:21:13587 paused_time_ = pipeline_controller_.GetMediaTime();
[email protected]090f7312011-08-05 23:26:40588
xjz48a9cb72016-12-20 04:02:49589 if (observer_)
590 observer_->OnPaused();
591
dalecurtis04bdb582016-08-17 22:15:23592 DCHECK(watch_time_reporter_);
593 watch_time_reporter_->OnPaused();
Chris Cunninghamd9df58e2017-08-29 00:04:23594
595 if (video_decode_stats_reporter_)
596 video_decode_stats_reporter_->OnPaused();
597
acolwell9e0840d2014-09-06 19:01:32598 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PAUSE));
avayvod2135a642017-01-13 00:17:14599
sandersd50a635e2016-04-04 22:50:09600 UpdatePlayState();
[email protected]ec9212f2008-12-18 21:40:36601}
602
Blink Reformat1c4d759e2017-04-09 16:34:54603bool WebMediaPlayerImpl::SupportsSave() const {
acolwellb4034942014-08-28 15:42:43604 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]132dd57c2012-08-10 23:24:34605 return supports_save_;
[email protected]574a1d62009-07-17 03:23:46606}
607
Blink Reformat1c4d759e2017-04-09 16:34:54608void WebMediaPlayerImpl::Seek(double seconds) {
pkastingf5279482016-07-27 02:18:20609 DVLOG(1) << __func__ << "(" << seconds << "s)";
acolwellb4034942014-08-28 15:42:43610 DCHECK(main_task_runner_->BelongsToCurrentThread());
servolk86b3d88fb2017-03-18 02:50:28611 media_log_->AddEvent(media_log_->CreateSeekEvent(seconds));
sandersd1c0bba02016-03-04 23:14:08612 DoSeek(base::TimeDelta::FromSecondsD(seconds), true);
613}
614
615void WebMediaPlayerImpl::DoSeek(base::TimeDelta time, bool time_updated) {
616 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53617
hubbed5f36882016-01-15 22:40:37618#if defined(OS_ANDROID) // WMPI_CAST
Blink Reformat1c4d759e2017-04-09 16:34:54619 if (IsRemote()) {
sandersd1c0bba02016-03-04 23:14:08620 cast_impl_.seek(time);
hubbed5f36882016-01-15 22:40:37621 return;
622 }
623#endif
624
srirama.mccf671812015-01-08 11:59:13625 ReadyState old_state = ready_state_;
Blink Reformat1c4d759e2017-04-09 16:34:54626 if (ready_state_ > WebMediaPlayer::kReadyStateHaveMetadata)
627 SetReadyState(WebMediaPlayer::kReadyStateHaveMetadata);
[email protected]1bb666802013-11-28 06:12:08628
Dale Curtis051fdf62017-08-05 00:21:13629 // When paused or ended, we know exactly what the current time is and can
630 // elide seeks to it. However, there are two cases that are not elided:
sandersd1c0bba02016-03-04 23:14:08631 // 1) When the pipeline state is not stable.
632 // In this case we just let |pipeline_controller_| decide what to do, as
633 // it has complete information.
634 // 2) For MSE.
635 // Because the buffers may have changed between seeks, MSE seeks are
636 // never elided.
Dale Curtis051fdf62017-08-05 00:21:13637 if (paused_ && pipeline_controller_.IsStable() &&
638 (paused_time_ == time ||
639 (ended_ && time == base::TimeDelta::FromSecondsD(Duration()))) &&
sandersd1c0bba02016-03-04 23:14:08640 !chunk_demuxer_) {
641 // If the ready state was high enough before, we can indicate that the seek
642 // completed just by restoring it. Otherwise we will just wait for the real
643 // ready state change to eventually happen.
Blink Reformat1c4d759e2017-04-09 16:34:54644 if (old_state == kReadyStateHaveEnoughData) {
srirama.m8f4a37562014-12-13 08:16:18645 main_task_runner_->PostTask(
alokp967c902452016-05-06 05:21:37646 FROM_HERE, base::Bind(&WebMediaPlayerImpl::OnBufferingStateChange,
647 AsWeakPtr(), BUFFERING_HAVE_ENOUGH));
srirama.m36ab2682014-12-11 04:20:01648 }
sandersd1c0bba02016-03-04 23:14:08649 return;
srirama.m36ab2682014-12-11 04:20:01650 }
[email protected]44ff37c02009-10-24 01:03:03651
dalecurtis04bdb582016-08-17 22:15:23652 // Call this before setting |seeking_| so that the current media time can be
653 // recorded by the reporter.
654 if (watch_time_reporter_)
655 watch_time_reporter_->OnSeeking();
656
dalecurtis1af3c1a2017-04-11 00:53:49657 // Clear any new frame processed callbacks on seek; otherwise we'll end up
658 // logging a time long after the seek completes.
659 frame_time_report_cb_.Cancel();
660
sandersd35d2c3f2017-01-14 02:04:42661 // TODO(sandersd): Move |seeking_| to PipelineController.
662 // TODO(sandersd): Do we want to reset the idle timer here?
tguilbert1bb1c782017-01-23 21:15:11663 delegate_->SetIdle(delegate_id_, false);
sandersd50a635e2016-04-04 22:50:09664 ended_ = false;
[email protected]b3766a22010-12-22 17:34:13665 seeking_ = true;
sandersd1c0bba02016-03-04 23:14:08666 seek_time_ = time;
667 if (paused_)
668 paused_time_ = time;
669 pipeline_controller_.Seek(time, time_updated);
[email protected]b3766a22010-12-22 17:34:13670
sandersd50a635e2016-04-04 22:50:09671 // This needs to be called after Seek() so that if a resume is triggered, it
672 // is to the correct time.
673 UpdatePlayState();
[email protected]ec9212f2008-12-18 21:40:36674}
675
Blink Reformat1c4d759e2017-04-09 16:34:54676void WebMediaPlayerImpl::SetRate(double rate) {
pkastingf5279482016-07-27 02:18:20677 DVLOG(1) << __func__ << "(" << rate << ")";
acolwellb4034942014-08-28 15:42:43678 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53679
[email protected]378f0b72009-08-11 17:11:42680 // TODO(kylep): Remove when support for negatives is added. Also, modify the
681 // following checks so rewind uses reasonable values also.
[email protected]39bdde32013-04-17 17:44:20682 if (rate < 0.0)
[email protected]378f0b72009-08-11 17:11:42683 return;
684
685 // Limit rates to reasonable values by clamping.
[email protected]39bdde32013-04-17 17:44:20686 if (rate != 0.0) {
[email protected]378f0b72009-08-11 17:11:42687 if (rate < kMinRate)
688 rate = kMinRate;
689 else if (rate > kMaxRate)
690 rate = kMaxRate;
691 }
692
[email protected]49480902009-07-14 20:23:43693 playback_rate_ = rate;
694 if (!paused_) {
tguilbert350936ff2017-02-24 05:39:27695 pipeline_controller_.SetPlaybackRate(rate);
[email protected]039b7542013-10-17 22:06:25696 if (data_source_)
697 data_source_->MediaPlaybackRateChanged(rate);
[email protected]49480902009-07-14 20:23:43698 }
[email protected]ec9212f2008-12-18 21:40:36699}
700
Blink Reformat1c4d759e2017-04-09 16:34:54701void WebMediaPlayerImpl::SetVolume(double volume) {
pkastingf5279482016-07-27 02:18:20702 DVLOG(1) << __func__ << "(" << volume << ")";
acolwellb4034942014-08-28 15:42:43703 DCHECK(main_task_runner_->BelongsToCurrentThread());
dalecurtisbb3eaac2016-01-27 21:10:25704 volume_ = volume;
tguilbert350936ff2017-02-24 05:39:27705 pipeline_controller_.SetVolume(volume_ * volume_multiplier_);
dalecurtis04bdb582016-08-17 22:15:23706 if (watch_time_reporter_)
707 watch_time_reporter_->OnVolumeChange(volume);
Becca Hughes9f6fd4b82017-06-15 10:01:40708 delegate_->DidPlayerMutedStatusChange(delegate_id_, volume == 0.0);
mlamouri910111362016-11-04 11:28:24709
710 // The play state is updated because the player might have left the autoplay
711 // muted state.
712 UpdatePlayState();
[email protected]ec9212f2008-12-18 21:40:36713}
[email protected]f0a51fb52009-03-05 12:46:38714
Blink Reformat1c4d759e2017-04-09 16:34:54715void WebMediaPlayerImpl::SetSinkId(
guidouc7babef2015-10-22 00:42:35716 const blink::WebString& sink_id,
717 const blink::WebSecurityOrigin& security_origin,
718 blink::WebSetSinkIdCallbacks* web_callback) {
guidou69223ce2015-06-16 10:36:19719 DCHECK(main_task_runner_->BelongsToCurrentThread());
pkastingf5279482016-07-27 02:18:20720 DVLOG(1) << __func__;
guidouc7babef2015-10-22 00:42:35721
olka68b69392016-04-01 11:42:12722 media::OutputDeviceStatusCB callback =
723 media::ConvertToOutputDeviceStatusCB(web_callback);
guidouc7babef2015-10-22 00:42:35724 media_task_runner_->PostTask(
725 FROM_HERE,
726 base::Bind(&SetSinkIdOnMediaThread, audio_source_provider_,
Blink Reformat1c4d759e2017-04-09 16:34:54727 sink_id.Utf8(), static_cast<url::Origin>(security_origin),
guidouc7babef2015-10-22 00:42:35728 callback));
guidou69223ce2015-06-16 10:36:19729}
730
Blink Reformat1c4d759e2017-04-09 16:34:54731STATIC_ASSERT_ENUM(WebMediaPlayer::kPreloadNone, MultibufferDataSource::NONE);
732STATIC_ASSERT_ENUM(WebMediaPlayer::kPreloadMetaData,
dalecurtisb6e052f52016-08-25 00:35:55733 MultibufferDataSource::METADATA);
Blink Reformat1c4d759e2017-04-09 16:34:54734STATIC_ASSERT_ENUM(WebMediaPlayer::kPreloadAuto, MultibufferDataSource::AUTO);
[email protected]23a8b1d82011-04-05 16:28:20735
Blink Reformat1c4d759e2017-04-09 16:34:54736void WebMediaPlayerImpl::SetPreload(WebMediaPlayer::Preload preload) {
pkastingf5279482016-07-27 02:18:20737 DVLOG(1) << __func__ << "(" << preload << ")";
acolwellb4034942014-08-28 15:42:43738 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]4e6be3f2009-05-07 02:24:44739
dalecurtisb6e052f52016-08-25 00:35:55740 preload_ = static_cast<MultibufferDataSource::Preload>(preload);
[email protected]b49beeb2013-03-01 20:04:00741 if (data_source_)
[email protected]09c60222014-08-07 16:42:31742 data_source_->SetPreload(preload_);
[email protected]4e6be3f2009-05-07 02:24:44743}
744
Blink Reformat1c4d759e2017-04-09 16:34:54745bool WebMediaPlayerImpl::HasVideo() const {
acolwellb4034942014-08-28 15:42:43746 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53747
[email protected]b8877772014-03-26 20:17:15748 return pipeline_metadata_.has_video;
[email protected]d43ed912009-02-03 04:52:53749}
750
Blink Reformat1c4d759e2017-04-09 16:34:54751bool WebMediaPlayerImpl::HasAudio() const {
acolwellb4034942014-08-28 15:42:43752 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]fc367af2009-08-14 23:06:35753
[email protected]b8877772014-03-26 20:17:15754 return pipeline_metadata_.has_audio;
[email protected]fc367af2009-08-14 23:06:35755}
756
Blink Reformat1c4d759e2017-04-09 16:34:54757void WebMediaPlayerImpl::EnabledAudioTracksChanged(
servolkf25ceed2016-07-01 03:44:38758 const blink::WebVector<blink::WebMediaPlayer::TrackId>& enabledTrackIds) {
759 DCHECK(main_task_runner_->BelongsToCurrentThread());
760
761 std::ostringstream logstr;
762 std::vector<MediaTrack::Id> enabledMediaTrackIds;
763 for (const auto& blinkTrackId : enabledTrackIds) {
Blink Reformat1c4d759e2017-04-09 16:34:54764 MediaTrack::Id track_id = blinkTrackId.Utf8().data();
servolkf25ceed2016-07-01 03:44:38765 logstr << track_id << " ";
766 enabledMediaTrackIds.push_back(track_id);
767 }
dalecurtis9cddc0b2017-04-19 21:23:38768 MEDIA_LOG(INFO, media_log_.get())
769 << "Enabled audio tracks: [" << logstr.str() << "]";
tguilbert350936ff2017-02-24 05:39:27770 pipeline_controller_.OnEnabledAudioTracksChanged(enabledMediaTrackIds);
servolkf25ceed2016-07-01 03:44:38771}
772
Blink Reformat1c4d759e2017-04-09 16:34:54773void WebMediaPlayerImpl::SelectedVideoTrackChanged(
servolkf25ceed2016-07-01 03:44:38774 blink::WebMediaPlayer::TrackId* selectedTrackId) {
775 DCHECK(main_task_runner_->BelongsToCurrentThread());
776
servolk9bed6602017-02-24 01:20:11777 base::Optional<MediaTrack::Id> selected_video_track_id;
778 if (selectedTrackId && !video_track_disabled_)
Blink Reformat1c4d759e2017-04-09 16:34:54779 selected_video_track_id = MediaTrack::Id(selectedTrackId->Utf8().data());
dalecurtis9cddc0b2017-04-19 21:23:38780 MEDIA_LOG(INFO, media_log_.get())
781 << "Selected video track: [" << selected_video_track_id.value_or("")
782 << "]";
tguilbert350936ff2017-02-24 05:39:27783 pipeline_controller_.OnSelectedVideoTrackChanged(selected_video_track_id);
servolkf25ceed2016-07-01 03:44:38784}
785
Blink Reformat1c4d759e2017-04-09 16:34:54786bool WebMediaPlayerImpl::GetLastUploadedFrameInfo(unsigned* width,
kainino36eeff82017-03-30 00:55:30787 unsigned* height,
788 double* timestamp) {
789 *width = last_uploaded_frame_size_.width();
790 *height = last_uploaded_frame_size_.height();
791 *timestamp = last_uploaded_frame_timestamp_.InSecondsF();
792 return true;
793}
794
Blink Reformat1c4d759e2017-04-09 16:34:54795blink::WebSize WebMediaPlayerImpl::NaturalSize() const {
acolwellb4034942014-08-28 15:42:43796 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53797
[email protected]b8877772014-03-26 20:17:15798 return blink::WebSize(pipeline_metadata_.natural_size);
[email protected]d43ed912009-02-03 04:52:53799}
800
Jiajia Qin82acdc02017-07-31 09:55:14801blink::WebSize WebMediaPlayerImpl::VisibleRect() const {
802 DCHECK(main_task_runner_->BelongsToCurrentThread());
803 scoped_refptr<VideoFrame> video_frame = GetCurrentFrameFromCompositor();
804 if (!video_frame)
805 return blink::WebSize();
806
807 const gfx::Rect& visible_rect = video_frame->visible_rect();
808 return blink::WebSize(visible_rect.width(), visible_rect.height());
809}
810
Blink Reformat1c4d759e2017-04-09 16:34:54811bool WebMediaPlayerImpl::Paused() const {
acolwellb4034942014-08-28 15:42:43812 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53813
hubbed5f36882016-01-15 22:40:37814#if defined(OS_ANDROID) // WMPI_CAST
Blink Reformat1c4d759e2017-04-09 16:34:54815 if (IsRemote())
danakj4f1fd6a2017-01-06 21:15:17816 return cast_impl_.IsPaused();
hubbed5f36882016-01-15 22:40:37817#endif
sandersd50a635e2016-04-04 22:50:09818
tguilbert350936ff2017-02-24 05:39:27819 return pipeline_controller_.GetPlaybackRate() == 0.0f;
[email protected]d43ed912009-02-03 04:52:53820}
821
Blink Reformat1c4d759e2017-04-09 16:34:54822bool WebMediaPlayerImpl::Seeking() const {
acolwellb4034942014-08-28 15:42:43823 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53824
Blink Reformat1c4d759e2017-04-09 16:34:54825 if (ready_state_ == WebMediaPlayer::kReadyStateHaveNothing)
[email protected]0acebfa2009-08-21 22:45:40826 return false;
[email protected]67cd5052009-09-10 21:53:22827
[email protected]b3766a22010-12-22 17:34:13828 return seeking_;
[email protected]ec9212f2008-12-18 21:40:36829}
830
Blink Reformat1c4d759e2017-04-09 16:34:54831double WebMediaPlayerImpl::Duration() const {
acolwellb4034942014-08-28 15:42:43832 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]39bdde32013-04-17 17:44:20833
Blink Reformat1c4d759e2017-04-09 16:34:54834 if (ready_state_ == WebMediaPlayer::kReadyStateHaveNothing)
[email protected]39bdde32013-04-17 17:44:20835 return std::numeric_limits<double>::quiet_NaN();
836
chcunninghamb92d5062017-01-10 21:50:22837 // Use duration from ChunkDemuxer when present. MSE allows users to specify
838 // duration as a double. This propagates to the rest of the pipeline as a
839 // TimeDelta with potentially reduced precision (limited to Microseconds).
840 // ChunkDemuxer returns the full-precision user-specified double. This ensures
841 // users can "get" the exact duration they "set".
842 if (chunk_demuxer_)
843 return chunk_demuxer_->GetDuration();
844
avayvodcc273dd2017-01-19 19:35:12845 base::TimeDelta pipeline_duration = GetPipelineMediaDuration();
chcunninghamb92d5062017-01-10 21:50:22846 return pipeline_duration == kInfiniteDuration
847 ? std::numeric_limits<double>::infinity()
848 : pipeline_duration.InSecondsF();
[email protected]d43ed912009-02-03 04:52:53849}
850
[email protected]db66d0092014-04-16 07:15:12851double WebMediaPlayerImpl::timelineOffset() const {
acolwellb4034942014-08-28 15:42:43852 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]db66d0092014-04-16 07:15:12853
854 if (pipeline_metadata_.timeline_offset.is_null())
855 return std::numeric_limits<double>::quiet_NaN();
856
857 return pipeline_metadata_.timeline_offset.ToJsTime();
858}
859
Dale Curtis051fdf62017-08-05 00:21:13860base::TimeDelta WebMediaPlayerImpl::GetCurrentTimeInternal() const {
861 DCHECK(main_task_runner_->BelongsToCurrentThread());
862 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
863
864 base::TimeDelta current_time;
865 if (Seeking())
866 current_time = seek_time_;
867#if defined(OS_ANDROID) // WMPI_CAST
868 else if (IsRemote())
869 current_time = cast_impl_.currentTime();
870#endif
871 else if (paused_)
872 current_time = paused_time_;
873 else
874 current_time = pipeline_controller_.GetMediaTime();
875
876 DCHECK_NE(current_time, kInfiniteDuration);
877 DCHECK_GE(current_time, base::TimeDelta());
878 return current_time;
879}
880
Blink Reformat1c4d759e2017-04-09 16:34:54881double WebMediaPlayerImpl::CurrentTime() const {
acolwellb4034942014-08-28 15:42:43882 DCHECK(main_task_runner_->BelongsToCurrentThread());
Blink Reformat1c4d759e2017-04-09 16:34:54883 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
scherkusd2c745b2014-09-04 05:03:40884
885 // TODO(scherkus): Replace with an explicit ended signal to HTMLMediaElement,
886 // see http://crbug.com/409280
Dale Curtis051fdf62017-08-05 00:21:13887 // Note: Duration() may be infinity.
888 return ended_ ? Duration() : GetCurrentTimeInternal().InSecondsF();
[email protected]d43ed912009-02-03 04:52:53889}
890
Blink Reformat1c4d759e2017-04-09 16:34:54891WebMediaPlayer::NetworkState WebMediaPlayerImpl::GetNetworkState() const {
acolwellb4034942014-08-28 15:42:43892 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]ddb1e5a2010-12-13 20:10:45893 return network_state_;
894}
895
Blink Reformat1c4d759e2017-04-09 16:34:54896WebMediaPlayer::ReadyState WebMediaPlayerImpl::GetReadyState() const {
acolwellb4034942014-08-28 15:42:43897 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]ddb1e5a2010-12-13 20:10:45898 return ready_state_;
899}
900
wolenetzed8e7092017-04-21 16:28:59901blink::WebString WebMediaPlayerImpl::GetErrorMessage() const {
wolenetz4d39cc02016-04-05 19:54:41902 DCHECK(main_task_runner_->BelongsToCurrentThread());
wolenetzed8e7092017-04-21 16:28:59903 return blink::WebString::FromUTF8(media_log_->GetErrorMessage());
wolenetz4d39cc02016-04-05 19:54:41904}
905
Blink Reformat1c4d759e2017-04-09 16:34:54906blink::WebTimeRanges WebMediaPlayerImpl::Buffered() const {
acolwellb4034942014-08-28 15:42:43907 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]779a8322014-08-22 21:28:37908
acolwell9e0840d2014-09-06 19:01:32909 Ranges<base::TimeDelta> buffered_time_ranges =
tguilbert350936ff2017-02-24 05:39:27910 pipeline_controller_.GetBufferedTimeRanges();
[email protected]779a8322014-08-22 21:28:37911
avayvodcc273dd2017-01-19 19:35:12912 const base::TimeDelta duration = GetPipelineMediaDuration();
dalecurtis39a7f932016-07-19 18:34:59913 if (duration != kInfiniteDuration) {
tguilbert350936ff2017-02-24 05:39:27914 buffered_data_source_host_.AddBufferedTimeRanges(&buffered_time_ranges,
915 duration);
[email protected]779a8322014-08-22 21:28:37916 }
[email protected]02022fc2014-05-16 00:05:31917 return ConvertToWebTimeRanges(buffered_time_ranges);
918}
919
Blink Reformat1c4d759e2017-04-09 16:34:54920blink::WebTimeRanges WebMediaPlayerImpl::Seekable() const {
acolwellb4034942014-08-28 15:42:43921 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]39bdde32013-04-17 17:44:20922
Blink Reformat1c4d759e2017-04-09 16:34:54923 if (ready_state_ < WebMediaPlayer::kReadyStateHaveMetadata)
philipjb0e6f3f2014-09-30 09:51:53924 return blink::WebTimeRanges();
925
Blink Reformat1c4d759e2017-04-09 16:34:54926 const double seekable_end = Duration();
dalecurtis56359cb2014-10-28 00:06:29927
928 // Allow a special exception for seeks to zero for streaming sources with a
929 // finite duration; this allows looping to work.
tguilbertade2bcb2017-01-07 02:57:45930 const bool is_finite_stream = data_source_ && data_source_->IsStreaming() &&
931 std::isfinite(seekable_end);
932
tguilbert75e2bf62017-04-26 20:13:12933 // Do not change the seekable range when using the MediaPlayerRenderer. It
934 // will take care of dropping invalid seeks.
935 const bool force_seeks_to_zero =
936 !using_media_player_renderer_ && is_finite_stream;
dalecurtis56359cb2014-10-28 00:06:29937
938 // TODO(dalecurtis): Technically this allows seeking on media which return an
tguilbertade2bcb2017-01-07 02:57:45939 // infinite duration so long as DataSource::IsStreaming() is false. While not
dalecurtis56359cb2014-10-28 00:06:29940 // expected, disabling this breaks semi-live players, http://crbug.com/427412.
941 const blink::WebTimeRange seekable_range(
tguilbertade2bcb2017-01-07 02:57:45942 0.0, force_seeks_to_zero ? 0.0 : seekable_end);
philipjb0e6f3f2014-09-30 09:51:53943 return blink::WebTimeRanges(&seekable_range, 1);
[email protected]ec9212f2008-12-18 21:40:36944}
945
sandersd35d2c3f2017-01-14 02:04:42946bool WebMediaPlayerImpl::IsPrerollAttemptNeeded() {
947 // TODO(sandersd): Replace with |highest_ready_state_since_seek_| if we need
948 // to ensure that preroll always gets a chance to complete.
949 // See http://crbug.com/671525.
Blink Reformat1c4d759e2017-04-09 16:34:54950 if (highest_ready_state_ >= ReadyState::kReadyStateHaveFutureData)
sandersd35d2c3f2017-01-14 02:04:42951 return false;
952
Fredrik Hubinette4cfb4412017-08-23 00:03:07953 // To suspend before we reach kReadyStateHaveCurrentData is only ok
954 // if we know we're going to get woken up when we get more data, which
955 // will only happen if the network is in the "Loading" state.
956 // This happens when the network is fast, but multiple videos are loading
957 // and multiplexing gets held up waiting for available threads.
958 if (highest_ready_state_ <= ReadyState::kReadyStateHaveMetadata &&
959 network_state_ != WebMediaPlayer::kNetworkStateLoading) {
960 return true;
961 }
962
sandersd35d2c3f2017-01-14 02:04:42963 if (preroll_attempt_pending_)
964 return true;
965
966 // Freshly initialized; there has never been any loading progress. (Otherwise
967 // |preroll_attempt_pending_| would be true when the start time is null.)
968 if (preroll_attempt_start_time_.is_null())
969 return false;
970
971 base::TimeDelta preroll_attempt_duration =
972 tick_clock_->NowTicks() - preroll_attempt_start_time_;
973 return preroll_attempt_duration < kPrerollAttemptTimeout;
974}
975
Blink Reformat1c4d759e2017-04-09 16:34:54976bool WebMediaPlayerImpl::DidLoadingProgress() {
acolwellb4034942014-08-28 15:42:43977 DCHECK(main_task_runner_->BelongsToCurrentThread());
dalecurtise7120dc2016-09-03 02:54:35978
979 // Note: Separate variables used to ensure both methods are called every time.
tguilbert350936ff2017-02-24 05:39:27980 const bool pipeline_progress = pipeline_controller_.DidLoadingProgress();
dalecurtise7120dc2016-09-03 02:54:35981 const bool data_progress = buffered_data_source_host_.DidLoadingProgress();
hubbeb2d3efd2017-05-05 23:26:38982 return pipeline_progress || data_progress;
[email protected]d43ed912009-02-03 04:52:53983}
984
Blink Reformat1c4d759e2017-04-09 16:34:54985void WebMediaPlayerImpl::Paint(blink::WebCanvas* canvas,
[email protected]dd5c7972014-08-21 15:00:37986 const blink::WebRect& rect,
enne11266b82017-03-02 01:43:47987 cc::PaintFlags& flags) {
acolwellb4034942014-08-28 15:42:43988 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]dd061e12014-05-06 19:21:22989 TRACE_EVENT0("media", "WebMediaPlayerImpl:paint");
[email protected]4e6be3f2009-05-07 02:24:44990
watkd16bb3e2017-04-25 01:18:31991 // We can't copy from protected frames.
jrummelle616ee92016-10-08 02:15:44992 if (cdm_)
xhwang80739452016-01-13 00:48:00993 return;
994
mcasasf1236fc22015-05-29 22:38:56995 scoped_refptr<VideoFrame> video_frame = GetCurrentFrameFromCompositor();
[email protected]0fe5d43b2014-01-24 23:32:45996
[email protected]b49beeb2013-03-01 20:04:00997 gfx::Rect gfx_rect(rect);
dongseong.hwang0c4e9d82015-01-08 20:11:13998 Context3D context_3d;
mcasas265bdbf82015-06-12 18:44:07999 if (video_frame.get() && video_frame->HasTextures()) {
mcasasf1236fc22015-05-29 22:38:561000 if (!context_3d_cb_.is_null())
dongseong.hwang0c4e9d82015-01-08 20:11:131001 context_3d = context_3d_cb_.Run();
dongseong.hwang0c4e9d82015-01-08 20:11:131002 if (!context_3d.gl)
danakj53f7ec902016-05-21 01:30:101003 return; // Unable to get/create a shared main thread context.
1004 if (!context_3d.gr_context)
1005 return; // The context has been lost since and can't setup a GrContext.
dongseong.hwang0c4e9d82015-01-08 20:11:131006 }
danakj795f1732015-08-31 23:40:221007 skcanvas_video_renderer_.Paint(video_frame, canvas, gfx::RectF(gfx_rect),
enne11266b82017-03-02 01:43:471008 flags, pipeline_metadata_.video_rotation,
danakj795f1732015-08-31 23:40:221009 context_3d);
[email protected]ec9212f2008-12-18 21:40:361010}
[email protected]5df51652009-01-17 00:03:001011
Blink Reformat1c4d759e2017-04-09 16:34:541012bool WebMediaPlayerImpl::HasSingleSecurityOrigin() const {
[email protected]b49beeb2013-03-01 20:04:001013 if (data_source_)
1014 return data_source_->HasSingleOrigin();
[email protected]fcdb7462009-10-21 21:05:111015 return true;
[email protected]38259a7a82009-07-29 21:49:491016}
1017
Blink Reformat1c4d759e2017-04-09 16:34:541018bool WebMediaPlayerImpl::DidPassCORSAccessCheck() const {
[email protected]b49beeb2013-03-01 20:04:001019 if (data_source_)
1020 return data_source_->DidPassCORSAccessCheck();
1021 return false;
[email protected]3fe27112012-06-07 04:00:011022}
1023
Blink Reformat1c4d759e2017-04-09 16:34:541024double WebMediaPlayerImpl::MediaTimeForTimeValue(double timeValue) const {
qinminb4c39782015-08-10 18:43:241025 return base::TimeDelta::FromSecondsD(timeValue).InSecondsF();
[email protected]e06e16d82011-05-26 22:13:331026}
1027
Blink Reformat1c4d759e2017-04-09 16:34:541028unsigned WebMediaPlayerImpl::DecodedFrameCount() const {
acolwellb4034942014-08-28 15:42:431029 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]4c51bc662011-02-16 02:03:161030
avayvodc4bfb0e62017-01-13 01:07:011031 PipelineStatistics stats = GetPipelineStatistics();
[email protected]4c51bc662011-02-16 02:03:161032 return stats.video_frames_decoded;
1033}
1034
Blink Reformat1c4d759e2017-04-09 16:34:541035unsigned WebMediaPlayerImpl::DroppedFrameCount() const {
acolwellb4034942014-08-28 15:42:431036 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]4c51bc662011-02-16 02:03:161037
avayvodc4bfb0e62017-01-13 01:07:011038 PipelineStatistics stats = GetPipelineStatistics();
[email protected]dd061e12014-05-06 19:21:221039 return stats.video_frames_dropped;
[email protected]4c51bc662011-02-16 02:03:161040}
1041
Blink Reformat1c4d759e2017-04-09 16:34:541042size_t WebMediaPlayerImpl::AudioDecodedByteCount() const {
acolwellb4034942014-08-28 15:42:431043 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]4c51bc662011-02-16 02:03:161044
avayvodc4bfb0e62017-01-13 01:07:011045 PipelineStatistics stats = GetPipelineStatistics();
[email protected]4c51bc662011-02-16 02:03:161046 return stats.audio_bytes_decoded;
1047}
1048
Blink Reformat1c4d759e2017-04-09 16:34:541049size_t WebMediaPlayerImpl::VideoDecodedByteCount() const {
acolwellb4034942014-08-28 15:42:431050 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]4c51bc662011-02-16 02:03:161051
avayvodc4bfb0e62017-01-13 01:07:011052 PipelineStatistics stats = GetPipelineStatistics();
[email protected]4c51bc662011-02-16 02:03:161053 return stats.video_bytes_decoded;
1054}
1055
Blink Reformat1c4d759e2017-04-09 16:34:541056bool WebMediaPlayerImpl::CopyVideoTextureToPlatformTexture(
danakj46070b02016-03-28 21:54:111057 gpu::gles2::GLES2Interface* gl,
jiajia.qinc2943162017-05-12 01:34:391058 unsigned int target,
zmo57d577a2015-10-30 18:28:591059 unsigned int texture,
kbr0986e622017-04-13 02:34:581060 unsigned internal_format,
1061 unsigned format,
1062 unsigned type,
jiajia.qinc2943162017-05-12 01:34:391063 int level,
zmo57d577a2015-10-30 18:28:591064 bool premultiply_alpha,
1065 bool flip_y) {
xhwang213e50c2016-10-10 23:56:311066 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]bfc05f22013-10-19 17:55:161067 TRACE_EVENT0("media", "WebMediaPlayerImpl:copyVideoTextureToPlatformTexture");
1068
watkd16bb3e2017-04-25 01:18:311069 // We can't copy from protected frames.
xhwang213e50c2016-10-10 23:56:311070 if (cdm_)
1071 return false;
[email protected]dd061e12014-05-06 19:21:221072
xhwang213e50c2016-10-10 23:56:311073 scoped_refptr<VideoFrame> video_frame = GetCurrentFrameFromCompositor();
jbauman581d041c2016-07-21 01:01:031074 if (!video_frame.get() || !video_frame->HasTextures()) {
[email protected]e56f88c72013-06-25 22:31:291075 return false;
dongseong.hwang0c4e9d82015-01-08 20:11:131076 }
[email protected]df41e252014-02-03 23:39:501077
jbauman581d041c2016-07-21 01:01:031078 Context3D context_3d;
1079 if (!context_3d_cb_.is_null())
1080 context_3d = context_3d_cb_.Run();
1081 return skcanvas_video_renderer_.CopyVideoFrameTexturesToGLTexture(
jiajia.qinc2943162017-05-12 01:34:391082 context_3d, gl, video_frame.get(), target, texture, internal_format,
1083 format, type, level, premultiply_alpha, flip_y);
[email protected]6523b242013-03-13 11:10:071084}
1085
Blink Reformat1c4d759e2017-04-09 16:34:541086void WebMediaPlayerImpl::SetContentDecryptionModule(
[email protected]9ebc3b03f2014-08-13 04:01:231087 blink::WebContentDecryptionModule* cdm,
1088 blink::WebContentDecryptionModuleResult result) {
xhwang51139732017-02-24 19:36:081089 DVLOG(1) << __func__ << ": cdm = " << cdm;
acolwellb4034942014-08-28 15:42:431090 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]9ebc3b03f2014-08-13 04:01:231091
jrummell06f27072015-06-08 18:12:381092 // Once the CDM is set it can't be cleared as there may be frames being
1093 // decrypted on other threads. So fail this request.
1094 // http://crbug.com/462365#c7.
xhwang97de4202014-11-25 08:44:011095 if (!cdm) {
Blink Reformat1c4d759e2017-04-09 16:34:541096 result.CompleteWithError(
1097 blink::kWebContentDecryptionModuleExceptionInvalidStateError, 0,
xhwang79b193042016-12-13 18:52:431098 "The existing ContentDecryptionModule object cannot be removed at this "
1099 "time.");
xhwang97de4202014-11-25 08:44:011100 return;
1101 }
1102
jrummell89e61d82015-07-23 20:03:341103 // Create a local copy of |result| to avoid problems with the callback
1104 // getting passed to the media thread and causing |result| to be destructed
jrummell4acbec912016-02-27 02:45:031105 // on the wrong thread in some failure conditions. Blink should prevent
1106 // multiple simultaneous calls.
1107 DCHECK(!set_cdm_result_);
jrummell89e61d82015-07-23 20:03:341108 set_cdm_result_.reset(new blink::WebContentDecryptionModuleResult(result));
1109
dalecurtis04bdb582016-08-17 22:15:231110 // Recreate the watch time reporter if necessary.
1111 const bool was_encrypted = is_encrypted_;
1112 is_encrypted_ = true;
1113 if (!was_encrypted && watch_time_reporter_)
1114 CreateWatchTimeReporter();
1115
Chris Cunninghamd9df58e2017-08-29 00:04:231116 // For now MediaCapabilities only handles clear content.
1117 video_decode_stats_reporter_.reset();
1118
jrummelle616ee92016-10-08 02:15:441119 SetCdm(cdm);
xhwang97de4202014-11-25 08:44:011120}
1121
xhwange8c4181a2014-12-06 08:10:011122void WebMediaPlayerImpl::OnEncryptedMediaInitData(
jrummellcf78967c2015-04-03 05:03:581123 EmeInitDataType init_data_type,
Avi Drissman97785ea2015-12-19 01:11:311124 const std::vector<uint8_t>& init_data) {
jrummellcf78967c2015-04-03 05:03:581125 DCHECK(init_data_type != EmeInitDataType::UNKNOWN);
xhwangbab66f52014-12-02 23:49:501126
ddorwin301ccdb2016-02-25 02:39:171127 // TODO(xhwang): Update this UMA name. https://crbug.com/589251
xhwangbab66f52014-12-02 23:49:501128 UMA_HISTOGRAM_COUNTS("Media.EME.NeedKey", 1);
1129
dalecurtis04bdb582016-08-17 22:15:231130 // Recreate the watch time reporter if necessary.
1131 const bool was_encrypted = is_encrypted_;
1132 is_encrypted_ = true;
1133 if (!was_encrypted && watch_time_reporter_)
1134 CreateWatchTimeReporter();
1135
Chris Cunninghamd9df58e2017-08-29 00:04:231136 // For now MediaCapabilities only handles clear content.
1137 video_decode_stats_reporter_.reset();
1138
Blink Reformat1c4d759e2017-04-09 16:34:541139 encrypted_client_->Encrypted(
davidbenb50f00c2015-12-01 00:01:501140 ConvertToWebInitDataType(init_data_type), init_data.data(),
srirama.m26f864d02015-07-14 05:21:461141 base::saturated_cast<unsigned int>(init_data.size()));
xhwangbab66f52014-12-02 23:49:501142}
1143
servolk81e01e02016-03-05 03:29:151144void WebMediaPlayerImpl::OnFFmpegMediaTracksUpdated(
dcheng3076abbf2016-04-22 20:42:391145 std::unique_ptr<MediaTracks> tracks) {
servolk81e01e02016-03-05 03:29:151146 // For MSE/chunk_demuxer case the media track updates are handled by
1147 // WebSourceBufferImpl.
1148 DCHECK(demuxer_.get());
1149 DCHECK(!chunk_demuxer_);
servolkef1e5ef2016-03-25 04:55:261150
servolk16e8bdf82017-04-11 17:00:391151 // Report the media track information to blink. Only the first audio track and
1152 // the first video track are enabled by default to match blink logic.
1153 bool is_first_audio_track = true;
1154 bool is_first_video_track = true;
servolkef1e5ef2016-03-25 04:55:261155 for (const auto& track : tracks->tracks()) {
1156 if (track->type() == MediaTrack::Audio) {
Blink Reformat1c4d759e2017-04-09 16:34:541157 client_->AddAudioTrack(blink::WebString::FromUTF8(track->id()),
1158 blink::WebMediaPlayerClient::kAudioTrackKindMain,
1159 blink::WebString::FromUTF8(track->label()),
1160 blink::WebString::FromUTF8(track->language()),
servolk16e8bdf82017-04-11 17:00:391161 is_first_audio_track);
1162 is_first_audio_track = false;
servolkef1e5ef2016-03-25 04:55:261163 } else if (track->type() == MediaTrack::Video) {
Blink Reformat1c4d759e2017-04-09 16:34:541164 client_->AddVideoTrack(blink::WebString::FromUTF8(track->id()),
1165 blink::WebMediaPlayerClient::kVideoTrackKindMain,
1166 blink::WebString::FromUTF8(track->label()),
1167 blink::WebString::FromUTF8(track->language()),
servolk16e8bdf82017-04-11 17:00:391168 is_first_video_track);
1169 is_first_video_track = false;
servolkef1e5ef2016-03-25 04:55:261170 } else {
1171 // Text tracks are not supported through this code path yet.
1172 NOTREACHED();
1173 }
1174 }
servolk81e01e02016-03-05 03:29:151175}
1176
jrummelle616ee92016-10-08 02:15:441177void WebMediaPlayerImpl::SetCdm(blink::WebContentDecryptionModule* cdm) {
1178 DCHECK(main_task_runner_->BelongsToCurrentThread());
1179 DCHECK(cdm);
xhwang79b193042016-12-13 18:52:431180 scoped_refptr<ContentDecryptionModule> cdm_reference =
jrummelle616ee92016-10-08 02:15:441181 ToWebContentDecryptionModuleImpl(cdm)->GetCdm();
1182 if (!cdm_reference) {
1183 NOTREACHED();
1184 OnCdmAttached(false);
xhwang80739452016-01-13 00:48:001185 return;
1186 }
1187
jrummelle616ee92016-10-08 02:15:441188 CdmContext* cdm_context = cdm_reference->GetCdmContext();
1189 if (!cdm_context) {
1190 OnCdmAttached(false);
1191 return;
1192 }
1193
xjzd3fe45a2016-10-12 18:26:371194 if (observer_)
1195 observer_->OnSetCdm(cdm_context);
1196
jrummelle616ee92016-10-08 02:15:441197 // Keep the reference to the CDM, as it shouldn't be destroyed until
1198 // after the pipeline is done with the |cdm_context|.
1199 pending_cdm_ = std::move(cdm_reference);
tguilbert350936ff2017-02-24 05:39:271200 pipeline_controller_.SetCdm(
1201 cdm_context, base::Bind(&WebMediaPlayerImpl::OnCdmAttached, AsWeakPtr()));
xhwang97de4202014-11-25 08:44:011202}
1203
jrummell89e61d82015-07-23 20:03:341204void WebMediaPlayerImpl::OnCdmAttached(bool success) {
xhwang51139732017-02-24 19:36:081205 DVLOG(1) << __func__ << ": success = " << success;
jrummelle616ee92016-10-08 02:15:441206 DCHECK(main_task_runner_->BelongsToCurrentThread());
1207 DCHECK(pending_cdm_);
1208
1209 // If the CDM is set from the constructor there is no promise
1210 // (|set_cdm_result_|) to fulfill.
xhwang97de4202014-11-25 08:44:011211 if (success) {
xhwang29c5ad202017-04-14 07:02:191212 media_log_->SetBooleanProperty("has_cdm", true);
1213
jrummelle616ee92016-10-08 02:15:441214 // This will release the previously attached CDM (if any).
1215 cdm_ = std::move(pending_cdm_);
1216 if (set_cdm_result_) {
Blink Reformat1c4d759e2017-04-09 16:34:541217 set_cdm_result_->Complete();
jrummelle616ee92016-10-08 02:15:441218 set_cdm_result_.reset();
1219 }
1220
xhwang97de4202014-11-25 08:44:011221 return;
1222 }
1223
jrummelle616ee92016-10-08 02:15:441224 pending_cdm_ = nullptr;
1225 if (set_cdm_result_) {
Blink Reformat1c4d759e2017-04-09 16:34:541226 set_cdm_result_->CompleteWithError(
1227 blink::kWebContentDecryptionModuleExceptionNotSupportedError, 0,
xhwang79b193042016-12-13 18:52:431228 "Unable to set ContentDecryptionModule object");
jrummelle616ee92016-10-08 02:15:441229 set_cdm_result_.reset();
1230 }
[email protected]9ebc3b03f2014-08-13 04:01:231231}
1232
sandersd1c0bba02016-03-04 23:14:081233void WebMediaPlayerImpl::OnPipelineSeeked(bool time_updated) {
[email protected]5d11eff2011-09-15 00:06:061234 seeking_ = false;
wolenetz1b2ae7d2015-06-10 00:44:211235 seek_time_ = base::TimeDelta();
avayvod2135a642017-01-13 00:17:141236
hubbe5a2dec022016-03-17 01:14:231237 if (paused_) {
1238#if defined(OS_ANDROID) // WMPI_CAST
Blink Reformat1c4d759e2017-04-09 16:34:541239 if (IsRemote()) {
Dale Curtis051fdf62017-08-05 00:21:131240 paused_time_ = cast_impl_.currentTime();
hubbe5a2dec022016-03-17 01:14:231241 } else {
tguilbert350936ff2017-02-24 05:39:271242 paused_time_ = pipeline_controller_.GetMediaTime();
hubbe5a2dec022016-03-17 01:14:231243 }
1244#else
tguilbert350936ff2017-02-24 05:39:271245 paused_time_ = pipeline_controller_.GetMediaTime();
hubbe5a2dec022016-03-17 01:14:231246#endif
dalecurtis04bdb582016-08-17 22:15:231247 } else {
1248 DCHECK(watch_time_reporter_);
1249 watch_time_reporter_->OnPlaying();
hubbe5a2dec022016-03-17 01:14:231250 }
sandersd1c0bba02016-03-04 23:14:081251 if (time_updated)
1252 should_notify_time_changed_ = true;
dalecurtisaf34d8712016-09-20 04:32:261253
dalecurtis4f6d14d2017-02-22 17:42:221254 // Reset underflow duration upon seek; this prevents looping videos and user
1255 // actions from artificially inflating the duration.
1256 underflow_timer_.reset();
avayvod56e1f3942017-01-21 02:06:311257
1258 // Background video optimizations are delayed when shown/hidden if pipeline
1259 // is seeking.
1260 UpdateBackgroundVideoOptimizationState();
[email protected]8931c41a2009-07-07 17:31:491261}
1262
sandersd1c0bba02016-03-04 23:14:081263void WebMediaPlayerImpl::OnPipelineSuspended() {
hubbed5f36882016-01-15 22:40:371264#if defined(OS_ANDROID)
avayvod82729272017-05-29 21:58:391265 if (IsRemote() && !IsNewRemotePlaybackPipelineEnabled()) {
hubbed5f36882016-01-15 22:40:371266 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner();
sandersd50a635e2016-04-04 22:50:091267 if (frame)
dalecurtise9c89e92016-05-20 19:38:001268 compositor_->PaintSingleFrame(frame);
hubbed5f36882016-01-15 22:40:371269 }
1270#endif
1271
sandersd2f5bb6152017-03-29 22:57:531272 // Tell the data source we have enough data so that it may release the
1273 // connection.
1274 if (data_source_)
1275 data_source_->OnBufferingHaveEnough(true);
dalecurtis37fe5862016-03-15 19:29:091276
sandersd50a635e2016-04-04 22:50:091277 ReportMemoryUsage();
1278
sandersd1c0bba02016-03-04 23:14:081279 if (pending_suspend_resume_cycle_) {
watkdee516f2016-02-18 02:22:191280 pending_suspend_resume_cycle_ = false;
sandersd50a635e2016-04-04 22:50:091281 UpdatePlayState();
dalecurtis0431cbf2016-03-12 01:19:431282 }
sandersd1c0bba02016-03-04 23:14:081283}
1284
avayvod2135a642017-01-13 00:17:141285void WebMediaPlayerImpl::OnBeforePipelineResume() {
1286 // Enable video track if we disabled it in the background - this way the new
1287 // renderer will attach its callbacks to the video stream properly.
1288 // TODO(avayvod): Remove this when disabling and enabling video tracks in
1289 // non-playing state works correctly. See https://crbug.com/678374.
1290 EnableVideoTrackIfNeeded();
1291 is_pipeline_resuming_ = true;
1292}
1293
1294void WebMediaPlayerImpl::OnPipelineResumed() {
1295 is_pipeline_resuming_ = false;
1296
avayvod56e1f3942017-01-21 02:06:311297 UpdateBackgroundVideoOptimizationState();
avayvod2135a642017-01-13 00:17:141298}
1299
alokp967c902452016-05-06 05:21:371300void WebMediaPlayerImpl::OnDemuxerOpened() {
1301 DCHECK(main_task_runner_->BelongsToCurrentThread());
dalecurtis9cddc0b2017-04-19 21:23:381302 client_->MediaSourceOpened(new WebMediaSourceImpl(chunk_demuxer_));
alokp967c902452016-05-06 05:21:371303}
1304
servolkf94b4602017-01-31 16:44:271305void WebMediaPlayerImpl::OnMemoryPressure(
1306 base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
1307 DVLOG(2) << __func__ << " memory_pressure_level=" << memory_pressure_level;
1308 DCHECK(main_task_runner_->BelongsToCurrentThread());
1309 DCHECK(base::FeatureList::IsEnabled(kMemoryPressureBasedSourceBufferGC));
1310 DCHECK(chunk_demuxer_);
1311
1312 // The new value of |memory_pressure_level| will take effect on the next
1313 // garbage collection. Typically this means the next SourceBuffer append()
1314 // operation, since per MSE spec, the garbage collection must only occur
1315 // during SourceBuffer append(). But if memory pressure is critical it might
1316 // be better to perform GC immediately rather than wait for the next append
1317 // and potentially get killed due to out-of-memory.
1318 // So if this experiment is enabled and pressure level is critical, we'll pass
1319 // down force_instant_gc==true, which will force immediate GC on
1320 // SourceBufferStreams.
1321 bool force_instant_gc =
1322 (enable_instant_source_buffer_gc_ &&
1323 memory_pressure_level ==
1324 base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
1325
1326 // base::Unretained is safe, since chunk_demuxer_ is actually owned by
1327 // |this| via this->demuxer_.
1328 media_task_runner_->PostTask(
1329 FROM_HERE, base::Bind(&ChunkDemuxer::OnMemoryPressure,
1330 base::Unretained(chunk_demuxer_),
Blink Reformat1c4d759e2017-04-09 16:34:541331 base::TimeDelta::FromSecondsD(CurrentTime()),
servolkf94b4602017-01-31 16:44:271332 memory_pressure_level, force_instant_gc));
1333}
1334
alokp967c902452016-05-06 05:21:371335void WebMediaPlayerImpl::OnError(PipelineStatus status) {
pkastingf5279482016-07-27 02:18:201336 DVLOG(1) << __func__;
alokp967c902452016-05-06 05:21:371337 DCHECK(main_task_runner_->BelongsToCurrentThread());
1338 DCHECK_NE(status, PIPELINE_OK);
1339
1340 if (suppress_destruction_errors_)
1341 return;
1342
Thomas Guilbert6b6be3d2017-08-18 03:17:271343#if defined(OS_ANDROID)
1344 if (status == PipelineStatus::DEMUXER_ERROR_DETECTED_HLS) {
1345 renderer_factory_selector_->SetUseMediaPlayer(true);
1346
1347 pipeline_controller_.Stop();
1348
1349 main_task_runner_->PostTask(
1350 FROM_HERE, base::Bind(&WebMediaPlayerImpl::StartPipeline, AsWeakPtr()));
1351 return;
1352 }
1353#endif
1354
dalecurtis9cddc0b2017-04-19 21:23:381355 ReportPipelineError(load_type_, status, media_log_.get());
alokp967c902452016-05-06 05:21:371356 media_log_->AddEvent(media_log_->CreatePipelineErrorEvent(status));
1357
Blink Reformat1c4d759e2017-04-09 16:34:541358 if (ready_state_ == WebMediaPlayer::kReadyStateHaveNothing) {
alokp967c902452016-05-06 05:21:371359 // Any error that occurs before reaching ReadyStateHaveMetadata should
1360 // be considered a format error.
Blink Reformat1c4d759e2017-04-09 16:34:541361 SetNetworkState(WebMediaPlayer::kNetworkStateFormatError);
alokp967c902452016-05-06 05:21:371362 } else {
1363 SetNetworkState(PipelineErrorToNetworkState(status));
1364 }
1365
Thomas Guilbert2e591392017-08-12 00:56:381366 // PipelineController::Stop() is idempotent.
1367 pipeline_controller_.Stop();
1368
alokp967c902452016-05-06 05:21:371369 UpdatePlayState();
1370}
1371
1372void WebMediaPlayerImpl::OnEnded() {
pkastingf5279482016-07-27 02:18:201373 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:431374 DCHECK(main_task_runner_->BelongsToCurrentThread());
scherkusd2c745b2014-09-04 05:03:401375
sandersd1c0bba02016-03-04 23:14:081376 // Ignore state changes until we've completed all outstanding operations.
1377 if (!pipeline_controller_.IsStable())
scherkusd2c745b2014-09-04 05:03:401378 return;
1379
1380 ended_ = true;
Blink Reformat1c4d759e2017-04-09 16:34:541381 client_->TimeChanged();
sandersd50a635e2016-04-04 22:50:091382
dalecurtis1af3c1a2017-04-11 00:53:491383 // Clear any new frame processed callbacks on end; otherwise we'll end up
1384 // logging a time long after playback ends.
1385 frame_time_report_cb_.Cancel();
1386
sandersd50a635e2016-04-04 22:50:091387 // We don't actually want this to run until |client_| calls seek() or pause(),
1388 // but that should have already happened in timeChanged() and so this is
1389 // expected to be a no-op.
1390 UpdatePlayState();
[email protected]576537842009-08-12 23:52:051391}
1392
alokp967c902452016-05-06 05:21:371393void WebMediaPlayerImpl::OnMetadata(PipelineMetadata metadata) {
pkastingf5279482016-07-27 02:18:201394 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:431395 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]a8e2cb82012-08-17 00:02:391396
[email protected]b8877772014-03-26 20:17:151397 pipeline_metadata_ = metadata;
[email protected]739847c02014-01-16 00:12:251398
Blink Reformat1c4d759e2017-04-09 16:34:541399 SetReadyState(WebMediaPlayer::kReadyStateHaveMetadata);
dalecurtis849cf4b22015-03-27 18:35:451400 UMA_HISTOGRAM_ENUMERATION("Media.VideoRotation", metadata.video_rotation,
acolwell9e0840d2014-09-06 19:01:321401 VIDEO_ROTATION_MAX + 1);
[email protected]21c3f7502013-03-23 03:29:511402
Blink Reformat1c4d759e2017-04-09 16:34:541403 if (HasVideo()) {
liberato2fd111be2017-01-04 00:25:061404 if (overlay_enabled_) {
1405 // SurfaceView doesn't support rotated video, so transition back if
1406 // the video is now rotated. If |force_video_overlays_|, we keep the
1407 // overlay anyway so that the state machine keeps working.
1408 if (!force_video_overlays_ && !DoesOverlaySupportMetadata())
1409 DisableOverlay();
1410 else if (surface_manager_)
1411 surface_manager_->NaturalSizeChanged(pipeline_metadata_.natural_size);
1412 }
watkf835a792016-06-24 23:24:401413
lethalantidote7f6009d2017-07-07 21:47:391414 if (!surface_layer_for_video_enabled_) {
1415 DCHECK(!video_weblayer_);
1416 video_weblayer_.reset(new cc_blink::WebLayerImpl(cc::VideoLayer::Create(
1417 compositor_, pipeline_metadata_.video_rotation)));
1418 video_weblayer_->layer()->SetContentsOpaque(opaque_);
1419 video_weblayer_->SetContentsOpaqueIsFixed(true);
1420 client_->SetWebLayer(video_weblayer_.get());
1421 } else if (bridge_->GetWebLayer()) {
1422 bridge_->GetWebLayer()->CcLayer()->SetContentsOpaque(opaque_);
1423 // TODO(lethalantidote): Figure out how to persist opaque setting
1424 // without calling WebLayerImpl's SetContentsOpaueIsFixed;
1425 // https://crbug/739859.
1426 client_->SetWebLayer(bridge_->GetWebLayer());
1427 }
[email protected]a8e2cb82012-08-17 00:02:391428 }
dalecurtis8e4dc682016-03-15 02:30:301429
xjzd3fe45a2016-10-12 18:26:371430 if (observer_)
xjz15b483f2017-01-12 00:21:361431 observer_->OnMetadataChanged(pipeline_metadata_);
xjzd3fe45a2016-10-12 18:26:371432
dalecurtis04bdb582016-08-17 22:15:231433 CreateWatchTimeReporter();
Chris Cunninghamd9df58e2017-08-29 00:04:231434 CreateVideoDecodeStatsReporter();
sandersd50a635e2016-04-04 22:50:091435 UpdatePlayState();
[email protected]a8e2cb82012-08-17 00:02:391436}
1437
Chris Cunninghamd9df58e2017-08-29 00:04:231438void WebMediaPlayerImpl::CreateVideoDecodeStatsReporter() {
1439 // TODO(chcunningham): destroy reporter if we initially have video but the
1440 // track gets disabled. Currently not possible in default desktop Chrome.
1441 if (!HasVideo())
1442 return;
1443
1444 // Stats reporter requires a valid config. We may not have one for HLS cases
1445 // where URL demuxer doesn't know details of the stream.
1446 if (!pipeline_metadata_.video_decoder_config.IsValidConfig())
1447 return;
1448
1449 // For now MediaCapabilities only handles clear content.
1450 // TODO(chcunningham): Report encrypted stats.
1451 if (is_encrypted_)
1452 return;
1453
1454 // Create capabilities reporter and synchronize its initial state.
1455 video_decode_stats_reporter_.reset(new VideoDecodeStatsReporter(
1456 create_decode_stats_recorder_cb_.Run(),
1457 base::Bind(&WebMediaPlayerImpl::GetPipelineStatistics,
1458 base::Unretained(this)),
1459 pipeline_metadata_.video_decoder_config));
1460
1461 if (delegate_->IsFrameHidden())
1462 video_decode_stats_reporter_->OnHidden();
1463 else
1464 video_decode_stats_reporter_->OnShown();
1465
1466 if (paused_)
1467 video_decode_stats_reporter_->OnPaused();
1468 else
1469 video_decode_stats_reporter_->OnPlaying();
1470}
1471
hubbeb2d3efd2017-05-05 23:26:381472void WebMediaPlayerImpl::OnProgress() {
Chris Watkins1ffabc5f2017-05-10 20:52:091473 DVLOG(4) << __func__;
hubbeb2d3efd2017-05-05 23:26:381474 if (highest_ready_state_ < ReadyState::kReadyStateHaveFutureData) {
1475 // Reset the preroll attempt clock.
1476 preroll_attempt_pending_ = true;
1477 preroll_attempt_start_time_ = base::TimeTicks();
1478
1479 // Clear any 'stale' flag and give the pipeline a chance to resume. If we
1480 // are already resumed, this will cause |preroll_attempt_start_time_| to
1481 // be set.
1482 delegate_->ClearStaleFlag(delegate_id_);
1483 UpdatePlayState();
1484 } else if (ready_state_ == ReadyState::kReadyStateHaveFutureData &&
1485 CanPlayThrough()) {
1486 SetReadyState(WebMediaPlayer::kReadyStateHaveEnoughData);
1487 }
1488}
1489
1490bool WebMediaPlayerImpl::CanPlayThrough() {
1491 if (!base::FeatureList::IsEnabled(kSpecCompliantCanPlayThrough))
1492 return true;
1493 if (chunk_demuxer_)
1494 return true;
1495 if (data_source_ && data_source_->assume_fully_buffered())
1496 return true;
1497 // If we're not currently downloading, we have as much buffer as
1498 // we're ever going to get, which means we say we can play through.
1499 if (network_state_ == WebMediaPlayer::kNetworkStateIdle)
1500 return true;
1501 return buffered_data_source_host_.CanPlayThrough(
1502 base::TimeDelta::FromSecondsD(CurrentTime()),
1503 base::TimeDelta::FromSecondsD(Duration()),
1504 playback_rate_ == 0.0 ? 1.0 : playback_rate_);
1505}
1506
alokp967c902452016-05-06 05:21:371507void WebMediaPlayerImpl::OnBufferingStateChange(BufferingState state) {
pkastingf5279482016-07-27 02:18:201508 DVLOG(1) << __func__ << "(" << state << ")";
alokp967c902452016-05-06 05:21:371509 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]b8877772014-03-26 20:17:151510
sandersd1c0bba02016-03-04 23:14:081511 // Ignore buffering state changes until we've completed all outstanding
1512 // operations.
1513 if (!pipeline_controller_.IsStable())
[email protected]ba7d5f92014-06-24 05:37:401514 return;
[email protected]b8877772014-03-26 20:17:151515
dalecurtis869bf2f2017-01-10 18:01:101516 media_log_->AddEvent(media_log_->CreateBufferingStateChangedEvent(
1517 "pipeline_buffering_state", state));
1518
chcunninghameb270c92016-07-15 01:00:451519 if (state == BUFFERING_HAVE_ENOUGH) {
hubbeb2d3efd2017-05-05 23:26:381520 SetReadyState(CanPlayThrough() ? WebMediaPlayer::kReadyStateHaveEnoughData
1521 : WebMediaPlayer::kReadyStateHaveFutureData);
[email protected]ba7d5f92014-06-24 05:37:401522
chcunninghameb270c92016-07-15 01:00:451523 // Let the DataSource know we have enough data. It may use this information
1524 // to release unused network connections.
1525 if (data_source_)
1526 data_source_->OnBufferingHaveEnough(false);
dalecurtis849cf4b22015-03-27 18:35:451527
chcunninghameb270c92016-07-15 01:00:451528 // Blink expects a timeChanged() in response to a seek().
sandersd35d2c3f2017-01-14 02:04:421529 if (should_notify_time_changed_) {
1530 should_notify_time_changed_ = false;
Blink Reformat1c4d759e2017-04-09 16:34:541531 client_->TimeChanged();
sandersd35d2c3f2017-01-14 02:04:421532 }
dalecurtis0f0097a2015-12-01 17:40:471533
chcunninghameb270c92016-07-15 01:00:451534 // Once we have enough, start reporting the total memory usage. We'll also
1535 // report once playback starts.
1536 ReportMemoryUsage();
dalecurtis9d638a12016-08-30 06:20:551537
dalecurtis4f6d14d2017-02-22 17:42:221538 // Report the amount of time it took to leave the underflow state.
1539 if (underflow_timer_) {
1540 RecordUnderflowDuration(underflow_timer_->Elapsed());
dalecurtis9d638a12016-08-30 06:20:551541 underflow_timer_.reset();
1542 }
chcunninghameb270c92016-07-15 01:00:451543 } else {
1544 // Buffering has underflowed.
1545 DCHECK_EQ(state, BUFFERING_HAVE_NOTHING);
dalecurtisacd77d62016-09-09 23:23:141546
dalecurtisd06eabc2017-02-24 23:43:291547 // Report the number of times we've entered the underflow state. Ensure we
1548 // only report the value when transitioning from HAVE_ENOUGH to
1549 // HAVE_NOTHING.
Dale Curtis6995b862017-05-31 22:20:081550 if (ready_state_ == WebMediaPlayer::kReadyStateHaveEnoughData &&
1551 !seeking_) {
dalecurtisacd77d62016-09-09 23:23:141552 underflow_timer_.reset(new base::ElapsedTimer());
Dale Curtis6995b862017-05-31 22:20:081553 watch_time_reporter_->OnUnderflow();
1554 }
dalecurtisacd77d62016-09-09 23:23:141555
chcunninghameb270c92016-07-15 01:00:451556 // It shouldn't be possible to underflow if we've not advanced past
1557 // HAVE_CURRENT_DATA.
Blink Reformat1c4d759e2017-04-09 16:34:541558 DCHECK_GT(highest_ready_state_, WebMediaPlayer::kReadyStateHaveCurrentData);
1559 SetReadyState(WebMediaPlayer::kReadyStateHaveCurrentData);
chcunninghameb270c92016-07-15 01:00:451560 }
sandersd50a635e2016-04-04 22:50:091561
1562 UpdatePlayState();
[email protected]b8877772014-03-26 20:17:151563}
1564
alokp967c902452016-05-06 05:21:371565void WebMediaPlayerImpl::OnDurationChange() {
acolwellb4034942014-08-28 15:42:431566 DCHECK(main_task_runner_->BelongsToCurrentThread());
alokp967c902452016-05-06 05:21:371567
1568 // TODO(sandersd): We should call delegate_->DidPlay() with the new duration,
1569 // especially if it changed from <5s to >5s.
Blink Reformat1c4d759e2017-04-09 16:34:541570 if (ready_state_ == WebMediaPlayer::kReadyStateHaveNothing)
alokp967c902452016-05-06 05:21:371571 return;
1572
Blink Reformat1c4d759e2017-04-09 16:34:541573 client_->DurationChanged();
[email protected]81bb3322011-07-21 15:55:501574}
1575
alokp967c902452016-05-06 05:21:371576void WebMediaPlayerImpl::OnAddTextTrack(const TextTrackConfig& config,
1577 const AddTextTrackDoneCB& done_cb) {
acolwellb4034942014-08-28 15:42:431578 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]71537722013-05-23 06:47:531579
[email protected]8a561062013-11-22 01:19:311580 const WebInbandTextTrackImpl::Kind web_kind =
1581 static_cast<WebInbandTextTrackImpl::Kind>(config.kind());
Blink Reformat1c4d759e2017-04-09 16:34:541582 const blink::WebString web_label = blink::WebString::FromUTF8(config.label());
[email protected]8a561062013-11-22 01:19:311583 const blink::WebString web_language =
Blink Reformat1c4d759e2017-04-09 16:34:541584 blink::WebString::FromUTF8(config.language());
1585 const blink::WebString web_id = blink::WebString::FromUTF8(config.id());
[email protected]71537722013-05-23 06:47:531586
dcheng3076abbf2016-04-22 20:42:391587 std::unique_ptr<WebInbandTextTrackImpl> web_inband_text_track(
henriks9cce5fa2014-12-12 09:35:301588 new WebInbandTextTrackImpl(web_kind, web_label, web_language, web_id));
[email protected]8a561062013-11-22 01:19:311589
dcheng3076abbf2016-04-22 20:42:391590 std::unique_ptr<media::TextTrack> text_track(new TextTrackImpl(
dcheng652f5ff2015-12-27 08:54:001591 main_task_runner_, client_, std::move(web_inband_text_track)));
[email protected]8a561062013-11-22 01:19:311592
dcheng652f5ff2015-12-27 08:54:001593 done_cb.Run(std::move(text_track));
[email protected]71537722013-05-23 06:47:531594}
1595
alokp967c902452016-05-06 05:21:371596void WebMediaPlayerImpl::OnWaitingForDecryptionKey() {
1597 DCHECK(main_task_runner_->BelongsToCurrentThread());
1598
Blink Reformat1c4d759e2017-04-09 16:34:541599 encrypted_client_->DidBlockPlaybackWaitingForKey();
alokp967c902452016-05-06 05:21:371600 // TODO(jrummell): didResumePlaybackBlockedForKey() should only be called
1601 // when a key has been successfully added (e.g. OnSessionKeysChange() with
1602 // |has_additional_usable_key| = true). http://crbug.com/461903
Blink Reformat1c4d759e2017-04-09 16:34:541603 encrypted_client_->DidResumePlaybackBlockedForKey();
alokp967c902452016-05-06 05:21:371604}
1605
alokp5d86e9b2016-05-17 20:20:411606void WebMediaPlayerImpl::OnVideoNaturalSizeChange(const gfx::Size& size) {
1607 DCHECK(main_task_runner_->BelongsToCurrentThread());
Blink Reformat1c4d759e2017-04-09 16:34:541608 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
alokp5d86e9b2016-05-17 20:20:411609
Chris Cunningham038548b2017-07-10 22:36:301610 TRACE_EVENT0("media", "WebMediaPlayerImpl::OnVideoNaturalSizeChange");
xhwang60802652017-04-19 07:29:581611
xjz15b483f2017-01-12 00:21:361612 // The input |size| is from the decoded video frame, which is the original
1613 // natural size and need to be rotated accordingly.
sandersd2c478422016-08-02 01:19:251614 gfx::Size rotated_size =
1615 GetRotatedVideoSize(pipeline_metadata_.video_rotation, size);
1616
xhwang60802652017-04-19 07:29:581617 RecordVideoNaturalSize(rotated_size);
1618
1619 gfx::Size old_size = pipeline_metadata_.natural_size;
1620 if (rotated_size == old_size)
alokp5d86e9b2016-05-17 20:20:411621 return;
1622
xjz516ef6d2017-01-07 00:23:061623 pipeline_metadata_.natural_size = rotated_size;
dalecurtis25405562017-04-14 23:35:111624
1625 // Re-create |watch_time_reporter_| if we didn't originally know the video
1626 // size or the previous size was too small for reporting.
1627 if (!watch_time_reporter_->IsSizeLargeEnoughToReportWatchTime())
tguilbert796a40e2016-11-09 01:11:421628 CreateWatchTimeReporter();
dalecurtis25405562017-04-14 23:35:111629
Chris Cunninghamd9df58e2017-08-29 00:04:231630 if (video_decode_stats_reporter_)
1631 video_decode_stats_reporter_->OnNaturalSizeChanged(rotated_size);
1632
liberato2ff93ad2017-05-17 07:28:241633 if (overlay_enabled_ && surface_manager_ &&
1634 overlay_mode_ == OverlayMode::kUseContentVideoView) {
xhwang60802652017-04-19 07:29:581635 surface_manager_->NaturalSizeChanged(rotated_size);
liberato2ff93ad2017-05-17 07:28:241636 }
xhwang60802652017-04-19 07:29:581637
Blink Reformat1c4d759e2017-04-09 16:34:541638 client_->SizeChanged();
xjz516ef6d2017-01-07 00:23:061639
xjz15b483f2017-01-12 00:21:361640 if (observer_)
1641 observer_->OnMetadataChanged(pipeline_metadata_);
peconn257951522017-06-09 18:24:591642
1643 delegate_->DidPlayerSizeChange(delegate_id_, NaturalSize());
alokp5d86e9b2016-05-17 20:20:411644}
1645
1646void WebMediaPlayerImpl::OnVideoOpacityChange(bool opaque) {
1647 DCHECK(main_task_runner_->BelongsToCurrentThread());
Blink Reformat1c4d759e2017-04-09 16:34:541648 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
alokp5d86e9b2016-05-17 20:20:411649
1650 opaque_ = opaque;
1651 // Modify content opaqueness of cc::Layer directly so that
1652 // SetContentsOpaqueIsFixed is ignored.
lethalantidote7f6009d2017-07-07 21:47:391653 if (!surface_layer_for_video_enabled_) {
1654 if (video_weblayer_)
1655 video_weblayer_->layer()->SetContentsOpaque(opaque_);
1656 } else if (bridge_->GetWebLayer()) {
1657 bridge_->GetWebLayer()->CcLayer()->SetContentsOpaque(opaque_);
1658 }
alokp5d86e9b2016-05-17 20:20:411659}
1660
Chris Cunningham038548b2017-07-10 22:36:301661void WebMediaPlayerImpl::OnAudioConfigChange(const AudioDecoderConfig& config) {
1662 DCHECK(main_task_runner_->BelongsToCurrentThread());
1663 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
1664
1665 pipeline_metadata_.audio_decoder_config = config;
1666
1667 if (observer_)
1668 observer_->OnMetadataChanged(pipeline_metadata_);
1669}
1670
1671void WebMediaPlayerImpl::OnVideoConfigChange(const VideoDecoderConfig& config) {
1672 DCHECK(main_task_runner_->BelongsToCurrentThread());
1673 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
1674
1675 // TODO(chcunningham): Observe changes to video codec profile to signal
1676 // beginning of a new Media Capabilities playback report.
1677 pipeline_metadata_.video_decoder_config = config;
1678
1679 if (observer_)
1680 observer_->OnMetadataChanged(pipeline_metadata_);
Chris Cunninghamd9df58e2017-08-29 00:04:231681
1682 if (video_decode_stats_reporter_)
1683 video_decode_stats_reporter_->OnVideoConfigChanged(config);
Chris Cunningham038548b2017-07-10 22:36:301684}
1685
avayvodeecec52c2017-02-14 01:25:091686void WebMediaPlayerImpl::OnVideoAverageKeyframeDistanceUpdate() {
1687 UpdateBackgroundVideoOptimizationState();
1688}
1689
sandersd35d2c3f2017-01-14 02:04:421690void WebMediaPlayerImpl::OnFrameHidden() {
sandersd1e49fb62015-12-12 01:18:061691 DCHECK(main_task_runner_->BelongsToCurrentThread());
avayvod39c102402016-11-23 21:43:131692
avayvod65fad272017-02-24 01:00:481693 // Backgrounding a video requires a user gesture to resume playback.
1694 if (IsHidden())
1695 video_locked_when_paused_when_hidden_ = true;
1696
[email protected]28347e72017-06-27 17:30:111697 overlay_info_.is_frame_hidden = true;
1698 MaybeSendOverlayInfoToDecoder();
1699
dalecurtis04bdb582016-08-17 22:15:231700 if (watch_time_reporter_)
1701 watch_time_reporter_->OnHidden();
avayvod48a8be52016-08-04 19:52:501702
Chris Cunninghamd9df58e2017-08-29 00:04:231703 if (video_decode_stats_reporter_)
1704 video_decode_stats_reporter_->OnHidden();
1705
avayvod65fad272017-02-24 01:00:481706 UpdateBackgroundVideoOptimizationState();
sandersd50a635e2016-04-04 22:50:091707 UpdatePlayState();
dalecurtis8b8505e72016-06-10 21:59:171708
1709 // Schedule suspended playing media to be paused if the user doesn't come back
1710 // to it within some timeout period to avoid any autoplay surprises.
1711 ScheduleIdlePauseTimer();
sandersd1e49fb62015-12-12 01:18:061712}
1713
sandersd35d2c3f2017-01-14 02:04:421714void WebMediaPlayerImpl::OnFrameClosed() {
sandersd1e49fb62015-12-12 01:18:061715 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]28347e72017-06-27 17:30:111716
1717 // Re-use |is_hidden| since nothing cares about the difference anyway.
1718 overlay_info_.is_frame_hidden = true;
1719 MaybeSendOverlayInfoToDecoder();
1720
sandersd35d2c3f2017-01-14 02:04:421721 UpdatePlayState();
1722}
1723
1724void WebMediaPlayerImpl::OnFrameShown() {
1725 DCHECK(main_task_runner_->BelongsToCurrentThread());
1726 background_pause_timer_.Stop();
1727
avayvod65fad272017-02-24 01:00:481728 // Foreground videos don't require user gesture to continue playback.
1729 video_locked_when_paused_when_hidden_ = false;
1730
[email protected]28347e72017-06-27 17:30:111731 overlay_info_.is_frame_hidden = false;
1732 MaybeSendOverlayInfoToDecoder();
1733
dalecurtis04bdb582016-08-17 22:15:231734 if (watch_time_reporter_)
1735 watch_time_reporter_->OnShown();
1736
Chris Cunninghamd9df58e2017-08-29 00:04:231737 if (video_decode_stats_reporter_)
1738 video_decode_stats_reporter_->OnShown();
1739
avayvodcc273dd2017-01-19 19:35:121740 // Only track the time to the first frame if playing or about to play because
1741 // of being shown and only for videos we would optimize background playback
1742 // for.
1743 if ((!paused_ && IsBackgroundOptimizationCandidate()) ||
1744 paused_when_hidden_) {
dalecurtis1af3c1a2017-04-11 00:53:491745 frame_time_report_cb_.Reset(
1746 base::Bind(&WebMediaPlayerImpl::ReportTimeFromForegroundToFirstFrame,
1747 AsWeakPtr(), base::TimeTicks::Now()));
avayvodcc273dd2017-01-19 19:35:121748 compositor_task_runner_->PostTask(
1749 FROM_HERE,
1750 base::Bind(&VideoFrameCompositor::SetOnNewProcessedFrameCallback,
dalecurtis1af3c1a2017-04-11 00:53:491751 base::Unretained(compositor_),
1752 BindToCurrentLoop(frame_time_report_cb_.callback())));
avayvodcc273dd2017-01-19 19:35:121753 }
avayvodac607d652017-01-06 03:16:431754
Dale Curtisdcbb81a2017-08-18 01:06:121755 UpdateBackgroundVideoOptimizationState();
avayvod65fad272017-02-24 01:00:481756
avayvod2135a642017-01-13 00:17:141757 if (paused_when_hidden_) {
1758 paused_when_hidden_ = false;
1759 OnPlay(); // Calls UpdatePlayState() so return afterwards.
1760 return;
1761 }
1762
sandersd50a635e2016-04-04 22:50:091763 UpdatePlayState();
sandersd1e49fb62015-12-12 01:18:061764}
1765
sandersd35d2c3f2017-01-14 02:04:421766void WebMediaPlayerImpl::OnIdleTimeout() {
dalecurtis0431cbf2016-03-12 01:19:431767 DCHECK(main_task_runner_->BelongsToCurrentThread());
1768
sandersd35d2c3f2017-01-14 02:04:421769 // If we are attempting preroll, clear the stale flag.
1770 if (IsPrerollAttemptNeeded()) {
tguilbert1bb1c782017-01-23 21:15:111771 delegate_->ClearStaleFlag(delegate_id_);
sandersd35d2c3f2017-01-14 02:04:421772 return;
watkd026f792016-11-05 00:28:511773 }
sandersd50a635e2016-04-04 22:50:091774
sandersd35d2c3f2017-01-14 02:04:421775 UpdatePlayState();
dalecurtis0431cbf2016-03-12 01:19:431776}
1777
dalecurtisbb3eaac2016-01-27 21:10:251778void WebMediaPlayerImpl::OnPlay() {
Blink Reformat1c4d759e2017-04-09 16:34:541779 Play();
1780 client_->PlaybackStateChanged();
dalecurtisbb3eaac2016-01-27 21:10:251781}
1782
1783void WebMediaPlayerImpl::OnPause() {
Blink Reformat1c4d759e2017-04-09 16:34:541784 Pause();
1785 client_->PlaybackStateChanged();
dalecurtisbb3eaac2016-01-27 21:10:251786}
1787
1788void WebMediaPlayerImpl::OnVolumeMultiplierUpdate(double multiplier) {
1789 volume_multiplier_ = multiplier;
Blink Reformat1c4d759e2017-04-09 16:34:541790 SetVolume(volume_);
dalecurtisbb3eaac2016-01-27 21:10:251791}
1792
zqzhang8ac49002017-03-16 21:51:351793void WebMediaPlayerImpl::OnBecamePersistentVideo(bool value) {
Blink Reformat1c4d759e2017-04-09 16:34:541794 client_->OnBecamePersistentVideo(value);
zqzhang8ac49002017-03-16 21:51:351795}
1796
watkdee516f2016-02-18 02:22:191797void WebMediaPlayerImpl::ScheduleRestart() {
sandersd50a635e2016-04-04 22:50:091798 // TODO(watk): All restart logic should be moved into PipelineController.
tguilbert350936ff2017-02-24 05:39:271799 if (pipeline_controller_.IsPipelineRunning() &&
1800 !pipeline_controller_.IsPipelineSuspended()) {
watkdee516f2016-02-18 02:22:191801 pending_suspend_resume_cycle_ = true;
sandersd50a635e2016-04-04 22:50:091802 UpdatePlayState();
watkdee516f2016-02-18 02:22:191803 }
1804}
1805
Blink Reformat1c4d759e2017-04-09 16:34:541806void WebMediaPlayerImpl::RequestRemotePlaybackDisabled(bool disabled) {
miu77f914c2016-11-19 23:56:181807 if (observer_)
1808 observer_->OnRemotePlaybackDisabled(disabled);
1809}
1810
hubbed5f36882016-01-15 22:40:371811#if defined(OS_ANDROID) // WMPI_CAST
Blink Reformat1c4d759e2017-04-09 16:34:541812bool WebMediaPlayerImpl::IsRemote() const {
hubbed5f36882016-01-15 22:40:371813 return cast_impl_.isRemote();
1814}
1815
1816void WebMediaPlayerImpl::SetMediaPlayerManager(
1817 RendererMediaPlayerManagerInterface* media_player_manager) {
1818 cast_impl_.SetMediaPlayerManager(media_player_manager);
1819}
1820
Blink Reformat1c4d759e2017-04-09 16:34:541821void WebMediaPlayerImpl::RequestRemotePlayback() {
hubbed5f36882016-01-15 22:40:371822 cast_impl_.requestRemotePlayback();
1823}
1824
Blink Reformat1c4d759e2017-04-09 16:34:541825void WebMediaPlayerImpl::RequestRemotePlaybackControl() {
hubbed5f36882016-01-15 22:40:371826 cast_impl_.requestRemotePlaybackControl();
1827}
1828
Blink Reformat1c4d759e2017-04-09 16:34:541829void WebMediaPlayerImpl::RequestRemotePlaybackStop() {
avayvod8d8c53b2016-11-04 16:10:301830 cast_impl_.requestRemotePlaybackStop();
1831}
1832
hubbed5f36882016-01-15 22:40:371833void WebMediaPlayerImpl::OnRemotePlaybackEnded() {
pkastingf5279482016-07-27 02:18:201834 DVLOG(1) << __func__;
hubbed5f36882016-01-15 22:40:371835 DCHECK(main_task_runner_->BelongsToCurrentThread());
1836
1837 ended_ = true;
Blink Reformat1c4d759e2017-04-09 16:34:541838 client_->TimeChanged();
hubbed5f36882016-01-15 22:40:371839}
1840
1841void WebMediaPlayerImpl::OnDisconnectedFromRemoteDevice(double t) {
sandersd1c0bba02016-03-04 23:14:081842 DoSeek(base::TimeDelta::FromSecondsD(t), false);
hubbed5f36882016-01-15 22:40:371843
Chris Cunninghamd9df58e2017-08-29 00:04:231844 // Capabilities reporting can resume now that playback is local.
1845 CreateVideoDecodeStatsReporter();
1846
Anton Vayvodfad2f3ea2017-07-19 21:45:271847 // |client_| might destroy us in methods below.
1848 UpdatePlayState();
1849
hubbed5f36882016-01-15 22:40:371850 // We already told the delegate we're paused when remoting started.
Blink Reformat1c4d759e2017-04-09 16:34:541851 client_->PlaybackStateChanged();
1852 client_->DisconnectedFromRemoteDevice();
hubbed5f36882016-01-15 22:40:371853}
1854
1855void WebMediaPlayerImpl::SuspendForRemote() {
Chris Cunninghamd9df58e2017-08-29 00:04:231856 // Capabilities reporting should only be performed for local playbacks.
1857 video_decode_stats_reporter_.reset();
1858
avayvod82729272017-05-29 21:58:391859 if (pipeline_controller_.IsPipelineSuspended() &&
1860 !IsNewRemotePlaybackPipelineEnabled()) {
hubbed5f36882016-01-15 22:40:371861 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner();
sandersd50a635e2016-04-04 22:50:091862 if (frame)
dalecurtise9c89e92016-05-20 19:38:001863 compositor_->PaintSingleFrame(frame);
hubbed5f36882016-01-15 22:40:371864 }
sandersd50a635e2016-04-04 22:50:091865
1866 UpdatePlayState();
hubbed5f36882016-01-15 22:40:371867}
1868
1869gfx::Size WebMediaPlayerImpl::GetCanvasSize() const {
lethalantidote7f6009d2017-07-07 21:47:391870 if (!surface_layer_for_video_enabled_) {
1871 if (!video_weblayer_)
1872 return pipeline_metadata_.natural_size;
1873
1874 return video_weblayer_->Bounds();
1875 }
1876 if (!bridge_->GetWebLayer())
hubbed5f36882016-01-15 22:40:371877 return pipeline_metadata_.natural_size;
1878
lethalantidote7f6009d2017-07-07 21:47:391879 return bridge_->GetWebLayer()->Bounds();
hubbed5f36882016-01-15 22:40:371880}
1881
1882void WebMediaPlayerImpl::SetDeviceScaleFactor(float scale_factor) {
1883 cast_impl_.SetDeviceScaleFactor(scale_factor);
1884}
hubbee4027f92016-05-19 05:18:131885
Blink Reformat1c4d759e2017-04-09 16:34:541886void WebMediaPlayerImpl::SetPoster(const blink::WebURL& poster) {
xjzc102fd82017-01-04 20:13:531887 cast_impl_.setPoster(poster);
xjzc102fd82017-01-04 20:13:531888}
xjz2504c4da2017-04-18 18:50:141889#endif // defined(OS_ANDROID) // WMPI_CAST
xjzc102fd82017-01-04 20:13:531890
[email protected]fee8a902014-06-03 13:43:361891void WebMediaPlayerImpl::DataSourceInitialized(bool success) {
pkastingf5279482016-07-27 02:18:201892 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:431893 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]a9415292012-01-19 19:55:201894
Anton Vayvod09fa66e2017-07-20 23:02:121895 if (observer_ && IsNewRemotePlaybackPipelineEnabled() && data_source_)
1896 observer_->OnDataSourceInitialized(data_source_->GetUrlAfterRedirects());
1897
[email protected]d250190da3b2012-07-23 22:57:301898 if (!success) {
Blink Reformat1c4d759e2017-04-09 16:34:541899 SetNetworkState(WebMediaPlayer::kNetworkStateFormatError);
sandersd50a635e2016-04-04 22:50:091900
1901 // Not really necessary, since the pipeline was never started, but it at
1902 // least this makes sure that the error handling code is in sync.
1903 UpdatePlayState();
1904
[email protected]a9415292012-01-19 19:55:201905 return;
1906 }
1907
hubbee2cc88c092017-07-14 23:10:411908 // No point in preloading data as we'll probably just throw it away anyways.
1909 if (IsStreaming() && preload_ > MultibufferDataSource::METADATA) {
1910 data_source_->SetPreload(MultibufferDataSource::METADATA);
1911 }
1912
[email protected]ef8394c2013-08-21 20:26:301913 StartPipeline();
[email protected]a9415292012-01-19 19:55:201914}
1915
[email protected]122f40252012-06-12 05:01:561916void WebMediaPlayerImpl::NotifyDownloading(bool is_downloading) {
hubbeb2d3efd2017-05-05 23:26:381917 DVLOG(1) << __func__ << "(" << is_downloading << ")";
Blink Reformat1c4d759e2017-04-09 16:34:541918 if (!is_downloading && network_state_ == WebMediaPlayer::kNetworkStateLoading)
1919 SetNetworkState(WebMediaPlayer::kNetworkStateIdle);
1920 else if (is_downloading &&
1921 network_state_ == WebMediaPlayer::kNetworkStateIdle)
1922 SetNetworkState(WebMediaPlayer::kNetworkStateLoading);
hubbeb2d3efd2017-05-05 23:26:381923 if (ready_state_ == ReadyState::kReadyStateHaveFutureData && !is_downloading)
1924 SetReadyState(WebMediaPlayer::kReadyStateHaveEnoughData);
[email protected]122f40252012-06-12 05:01:561925}
1926
watkf835a792016-06-24 23:24:401927void WebMediaPlayerImpl::OnSurfaceCreated(int surface_id) {
liberato2ff93ad2017-05-17 07:28:241928 DCHECK(overlay_mode_ == OverlayMode::kUseContentVideoView);
tsunghungee562e92016-07-20 18:03:311929 overlay_surface_id_ = surface_id;
liberato2ff93ad2017-05-17 07:28:241930 MaybeSendOverlayInfoToDecoder();
watkf835a792016-06-24 23:24:401931}
1932
liberato2ff93ad2017-05-17 07:28:241933void WebMediaPlayerImpl::OnOverlayRoutingToken(
1934 const base::UnguessableToken& token) {
1935 DCHECK(overlay_mode_ == OverlayMode::kUseAndroidOverlay);
liberatofe8f9692017-06-08 19:17:361936 // TODO(liberato): |token| should already be a RoutingToken.
1937 overlay_routing_token_is_pending_ = false;
1938 overlay_routing_token_ = OverlayInfo::RoutingToken(token);
liberato2ff93ad2017-05-17 07:28:241939 MaybeSendOverlayInfoToDecoder();
1940}
1941
1942void WebMediaPlayerImpl::OnOverlayInfoRequested(
dalecurtis4b632fce22016-11-10 00:52:171943 bool decoder_requires_restart_for_overlay,
liberato2ff93ad2017-05-17 07:28:241944 const ProvideOverlayInfoCB& provide_overlay_info_cb) {
watkdee516f2016-02-18 02:22:191945 DCHECK(main_task_runner_->BelongsToCurrentThread());
1946 DCHECK(surface_manager_);
1947
1948 // A null callback indicates that the decoder is going away.
liberato2ff93ad2017-05-17 07:28:241949 if (provide_overlay_info_cb.is_null()) {
tsunghungee562e92016-07-20 18:03:311950 decoder_requires_restart_for_overlay_ = false;
liberato2ff93ad2017-05-17 07:28:241951 provide_overlay_info_cb_.Reset();
watkdee516f2016-02-18 02:22:191952 return;
1953 }
1954
[email protected]5036eb22017-07-27 02:18:541955 // For encrypted video on pre-M, we pretend that the decoder doesn't require a
1956 // restart. This is because it needs an overlay all the time anyway. We'll
1957 // switch into |force_video_overlays_| mode below.
1958 if (overlay_mode_ == OverlayMode::kUseAndroidOverlay && is_encrypted_)
1959 decoder_requires_restart_for_overlay = false;
1960
dalecurtis4b632fce22016-11-10 00:52:171961 // If we get a surface request it means GpuVideoDecoder is initializing, so
1962 // until we get a null surface request, GVD is the active decoder.
1963 //
1964 // If |decoder_requires_restart_for_overlay| is true, we must restart the
1965 // pipeline for fullscreen transitions. The decoder is unable to switch
1966 // surfaces otherwise. If false, we simply need to tell the decoder about the
1967 // new surface and it will handle things seamlessly.
1968 decoder_requires_restart_for_overlay_ = decoder_requires_restart_for_overlay;
liberato2ff93ad2017-05-17 07:28:241969 provide_overlay_info_cb_ = provide_overlay_info_cb;
dalecurtis4b632fce22016-11-10 00:52:171970
[email protected]77568482017-06-21 21:16:521971 // We always force (allow, actually) video overlays in AndroidOverlayMode.
1972 // AVDA figures out when to use them. If the decoder requires restart, then
1973 // we still want to restart the decoder on the fullscreen transitions anyway.
1974 if (overlay_mode_ == OverlayMode::kUseAndroidOverlay &&
1975 !decoder_requires_restart_for_overlay) {
1976 force_video_overlays_ = true;
1977 if (!overlay_enabled_)
1978 EnableOverlay();
1979 }
1980
dalecurtis4b632fce22016-11-10 00:52:171981 // If we're waiting for the surface to arrive, OnSurfaceCreated() will be
liberato2ff93ad2017-05-17 07:28:241982 // called later when it arrives; so do nothing for now. For AndroidOverlay,
1983 // if we're waiting for the token then... OnOverlayRoutingToken()...
1984 // We do this so that a request for a surface will block if we're in the
1985 // process of getting one. Otherwise, on pre-M, the decoder would be stuck
1986 // without an overlay if the restart that happens on entering fullscreen
1987 // succeeds before we have the overlay info. Post-M, we could send what we
1988 // have unconditionally. When the info arrives, it will be sent.
1989 MaybeSendOverlayInfoToDecoder();
1990}
1991
1992void WebMediaPlayerImpl::MaybeSendOverlayInfoToDecoder() {
1993 // If the decoder didn't request overlay info, then don't send it.
1994 if (!provide_overlay_info_cb_)
dalecurtis4b632fce22016-11-10 00:52:171995 return;
1996
liberato2ff93ad2017-05-17 07:28:241997 // We should send the overlay info as long as we know it. This includes the
1998 // case where |!overlay_enabled_|, since we want to tell the decoder to avoid
1999 // using overlays. Assuming that the decoder has requested info, the only
2000 // case in which we don't want to send something is if we've requested the
2001 // info but not received it yet. Then, we should wait until we do.
liberatofe8f9692017-06-08 19:17:362002 //
2003 // Initialization requires this; AVDA should start with enough info to make an
2004 // overlay, so that (pre-M) the initial codec is created with the right output
2005 // surface; it can't switch later.
liberato2ff93ad2017-05-17 07:28:242006 if (overlay_mode_ == OverlayMode::kUseContentVideoView) {
2007 if (!overlay_surface_id_.has_value())
2008 return;
liberatofe8f9692017-06-08 19:17:362009
2010 overlay_info_.surface_id = *overlay_surface_id_;
liberato2ff93ad2017-05-17 07:28:242011 } else if (overlay_mode_ == OverlayMode::kUseAndroidOverlay) {
liberatofe8f9692017-06-08 19:17:362012 if (overlay_routing_token_is_pending_)
liberato2ff93ad2017-05-17 07:28:242013 return;
liberatofe8f9692017-06-08 19:17:362014
2015 overlay_info_.routing_token = overlay_routing_token_;
liberato2ff93ad2017-05-17 07:28:242016 }
2017
liberato2ff93ad2017-05-17 07:28:242018 // If restart is required, the callback is one-shot only.
2019 if (decoder_requires_restart_for_overlay_) {
liberatofe8f9692017-06-08 19:17:362020 base::ResetAndReturn(&provide_overlay_info_cb_).Run(overlay_info_);
liberato2ff93ad2017-05-17 07:28:242021 } else {
liberatofe8f9692017-06-08 19:17:362022 provide_overlay_info_cb_.Run(overlay_info_);
liberato2ff93ad2017-05-17 07:28:242023 }
watkdee516f2016-02-18 02:22:192024}
2025
dcheng3076abbf2016-04-22 20:42:392026std::unique_ptr<Renderer> WebMediaPlayerImpl::CreateRenderer() {
dcheng37b415b92017-01-27 20:17:432027 DCHECK(main_task_runner_->BelongsToCurrentThread());
2028
liberato2ff93ad2017-05-17 07:28:242029 // TODO(liberato): Re-evaluate this as AndroidVideoSurfaceChooser gets smarter
2030 // about turning off overlays. Either we should verify that it is not
2031 // breaking this use-case if it does so, or we should notify it that using
2032 // the overlay is required.
tsunghungee562e92016-07-20 18:03:312033 if (force_video_overlays_)
2034 EnableOverlay();
2035
liberato2ff93ad2017-05-17 07:28:242036 RequestOverlayInfoCB request_overlay_info_cb;
watkdee516f2016-02-18 02:22:192037#if defined(OS_ANDROID)
liberato2ff93ad2017-05-17 07:28:242038 request_overlay_info_cb = BindToCurrentLoop(
2039 base::Bind(&WebMediaPlayerImpl::OnOverlayInfoRequested, AsWeakPtr()));
watkdee516f2016-02-18 02:22:192040#endif
tguilbert70d2a00a2017-04-25 00:30:442041 return renderer_factory_selector_->GetCurrentFactory()->CreateRenderer(
sandersd1e49fb62015-12-12 01:18:062042 media_task_runner_, worker_task_runner_, audio_source_provider_.get(),
Fredrik Hubinette2f7e4ff2017-08-11 00:34:492043 compositor_, request_overlay_info_cb, client_->TargetColorSpace());
sandersd1e49fb62015-12-12 01:18:062044}
2045
[email protected]ef8394c2013-08-21 20:26:302046void WebMediaPlayerImpl::StartPipeline() {
acolwellb4034942014-08-28 15:42:432047 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]ddbc6ff2013-04-19 15:28:332048
xhwange8c4181a2014-12-06 08:10:012049 Demuxer::EncryptedMediaInitDataCB encrypted_media_init_data_cb =
dcheng37b415b92017-01-27 20:17:432050 BindToCurrentLoop(base::Bind(
2051 &WebMediaPlayerImpl::OnEncryptedMediaInitData, AsWeakPtr()));
[email protected]2b57e2e2014-05-09 11:07:252052
tguilbert75e2bf62017-04-26 20:13:122053 if (renderer_factory_selector_->GetCurrentFactory()
2054 ->GetRequiredMediaResourceType() == MediaResource::Type::URL) {
2055 if (data_source_)
2056 loaded_url_ = data_source_->GetUrlAfterRedirects();
2057
2058 // MediaPlayerRendererClient factory is the only factory that a
2059 // MediaResource::Type::URL for the moment. This might no longer be true
2060 // when we remove WebMediaPlayerCast.
2061 //
2062 // TODO(tguilbert/avayvod): Update this flag when removing |cast_impl_|.
2063 using_media_player_renderer_ = true;
2064
Chris Cunninghamd9df58e2017-08-29 00:04:232065 // MediaPlayerRenderer does not provide pipeline stats, so nuke capabilities
2066 // reporter.
2067 video_decode_stats_reporter_.reset();
2068
Mike Westb85da8ed2017-08-10 14:16:462069 demuxer_.reset(new MediaUrlDemuxer(media_task_runner_, loaded_url_,
2070 frame_->GetDocument().SiteForCookies()));
tguilbert25a4d112016-10-13 21:56:512071 pipeline_controller_.Start(demuxer_.get(), this, false, false);
2072 return;
2073 }
2074
[email protected]ddbc6ff2013-04-19 15:28:332075 // Figure out which demuxer to use.
Blink Reformat1c4d759e2017-04-09 16:34:542076 if (load_type_ != kLoadTypeMediaSource) {
[email protected]ddbc6ff2013-04-19 15:28:332077 DCHECK(!chunk_demuxer_);
[email protected]f5443ef72013-04-22 04:03:382078 DCHECK(data_source_);
2079
j.isorcef6778e652015-11-16 17:14:252080#if !defined(MEDIA_DISABLE_FFMPEG)
servolk81e01e02016-03-05 03:29:152081 Demuxer::MediaTracksUpdatedCB media_tracks_updated_cb =
dcheng37b415b92017-01-27 20:17:432082 BindToCurrentLoop(base::Bind(
2083 &WebMediaPlayerImpl::OnFFmpegMediaTracksUpdated, AsWeakPtr()));
servolk81e01e02016-03-05 03:29:152084
dalecurtis9cddc0b2017-04-19 21:23:382085 demuxer_.reset(new FFmpegDemuxer(
2086 media_task_runner_, data_source_.get(), encrypted_media_init_data_cb,
2087 media_tracks_updated_cb, media_log_.get()));
j.isorcef6778e652015-11-16 17:14:252088#else
alokp967c902452016-05-06 05:21:372089 OnError(PipelineStatus::DEMUXER_ERROR_COULD_NOT_OPEN);
j.isorcef6778e652015-11-16 17:14:252090 return;
2091#endif
[email protected]ddbc6ff2013-04-19 15:28:332092 } else {
[email protected]f5443ef72013-04-22 04:03:382093 DCHECK(!chunk_demuxer_);
2094 DCHECK(!data_source_);
2095
acolwell9e0840d2014-09-06 19:01:322096 chunk_demuxer_ = new ChunkDemuxer(
dcheng37b415b92017-01-27 20:17:432097 BindToCurrentLoop(
2098 base::Bind(&WebMediaPlayerImpl::OnDemuxerOpened, AsWeakPtr())),
Dan Sanders42311b52017-08-10 23:41:032099 BindToCurrentLoop(
2100 base::Bind(&WebMediaPlayerImpl::OnProgress, AsWeakPtr())),
dalecurtis9cddc0b2017-04-19 21:23:382101 encrypted_media_init_data_cb, media_log_.get());
[email protected]f5443ef72013-04-22 04:03:382102 demuxer_.reset(chunk_demuxer_);
servolkf94b4602017-01-31 16:44:272103
2104 if (base::FeatureList::IsEnabled(kMemoryPressureBasedSourceBufferGC)) {
2105 // base::Unretained is safe because |this| owns memory_pressure_listener_.
2106 memory_pressure_listener_ =
2107 base::MakeUnique<base::MemoryPressureListener>(base::Bind(
2108 &WebMediaPlayerImpl::OnMemoryPressure, base::Unretained(this)));
2109 }
[email protected]ddbc6ff2013-04-19 15:28:332110 }
2111
sandersdb5e21462016-03-09 01:49:072112 // TODO(sandersd): FileSystem objects may also be non-static, but due to our
2113 // caching layer such situations are broken already. http://crbug.com/593159
2114 bool is_static = !chunk_demuxer_;
avayvod102cdb62017-01-07 03:11:092115 bool is_streaming = IsStreaming();
sandersdb8eb5f1d2016-11-19 04:04:022116 UMA_HISTOGRAM_BOOLEAN("Media.IsStreaming", is_streaming);
sandersdb5e21462016-03-09 01:49:072117
[email protected]f5443ef72013-04-22 04:03:382118 // ... and we're ready to go!
sandersd1e49fb62015-12-12 01:18:062119 // TODO(sandersd): On Android, defer Start() if the tab is not visible.
sandersdb8eb5f1d2016-11-19 04:04:022120 seeking_ = true;
alokp967c902452016-05-06 05:21:372121 pipeline_controller_.Start(demuxer_.get(), this, is_streaming, is_static);
[email protected]f5443ef72013-04-22 04:03:382122}
2123
2124void WebMediaPlayerImpl::SetNetworkState(WebMediaPlayer::NetworkState state) {
pkastingf5279482016-07-27 02:18:202125 DVLOG(1) << __func__ << "(" << state << ")";
acolwellb4034942014-08-28 15:42:432126 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]f5443ef72013-04-22 04:03:382127 network_state_ = state;
2128 // Always notify to ensure client has the latest value.
Blink Reformat1c4d759e2017-04-09 16:34:542129 client_->NetworkStateChanged();
[email protected]f5443ef72013-04-22 04:03:382130}
2131
2132void WebMediaPlayerImpl::SetReadyState(WebMediaPlayer::ReadyState state) {
pkastingf5279482016-07-27 02:18:202133 DVLOG(1) << __func__ << "(" << state << ")";
acolwellb4034942014-08-28 15:42:432134 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]f5443ef72013-04-22 04:03:382135
Blink Reformat1c4d759e2017-04-09 16:34:542136 if (state == WebMediaPlayer::kReadyStateHaveEnoughData && data_source_ &&
[email protected]fee8a902014-06-03 13:43:362137 data_source_->assume_fully_buffered() &&
Blink Reformat1c4d759e2017-04-09 16:34:542138 network_state_ == WebMediaPlayer::kNetworkStateLoading)
2139 SetNetworkState(WebMediaPlayer::kNetworkStateLoaded);
[email protected]f5443ef72013-04-22 04:03:382140
2141 ready_state_ = state;
sandersd50a635e2016-04-04 22:50:092142 highest_ready_state_ = std::max(highest_ready_state_, ready_state_);
2143
[email protected]f5443ef72013-04-22 04:03:382144 // Always notify to ensure client has the latest value.
Blink Reformat1c4d759e2017-04-09 16:34:542145 client_->ReadyStateChanged();
[email protected]f5443ef72013-04-22 04:03:382146}
2147
Blink Reformat1c4d759e2017-04-09 16:34:542148blink::WebAudioSourceProvider* WebMediaPlayerImpl::GetAudioSourceProvider() {
[email protected]ff875be52013-06-02 23:47:382149 return audio_source_provider_.get();
[email protected]f5443ef72013-04-22 04:03:382150}
2151
tguilbert350936ff2017-02-24 05:39:272152static void GetCurrentFrameAndSignal(VideoFrameCompositor* compositor,
2153 scoped_refptr<VideoFrame>* video_frame_out,
2154 base::WaitableEvent* event) {
[email protected]dd061e12014-05-06 19:21:222155 TRACE_EVENT0("media", "GetCurrentFrameAndSignal");
dalecurtis44ce4de2015-05-11 18:42:072156 *video_frame_out = compositor->GetCurrentFrameAndUpdateIfStale();
[email protected]dd061e12014-05-06 19:21:222157 event->Signal();
2158}
2159
Jiajia Qin82acdc02017-07-31 09:55:142160scoped_refptr<VideoFrame> WebMediaPlayerImpl::GetCurrentFrameFromCompositor()
2161 const {
xhwang213e50c2016-10-10 23:56:312162 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]dd061e12014-05-06 19:21:222163 TRACE_EVENT0("media", "WebMediaPlayerImpl::GetCurrentFrameFromCompositor");
xhwang213e50c2016-10-10 23:56:312164
2165 // Needed when the |main_task_runner_| and |compositor_task_runner_| are the
2166 // same to avoid deadlock in the Wait() below.
kainino36eeff82017-03-30 00:55:302167 if (compositor_task_runner_->BelongsToCurrentThread()) {
2168 scoped_refptr<VideoFrame> video_frame =
2169 compositor_->GetCurrentFrameAndUpdateIfStale();
2170 if (!video_frame) {
2171 return nullptr;
2172 }
2173 last_uploaded_frame_size_ = video_frame->natural_size();
2174 last_uploaded_frame_timestamp_ = video_frame->timestamp();
2175 return video_frame;
2176 }
[email protected]dd061e12014-05-06 19:21:222177
2178 // Use a posted task and waitable event instead of a lock otherwise
2179 // WebGL/Canvas can see different content than what the compositor is seeing.
acolwell9e0840d2014-09-06 19:01:322180 scoped_refptr<VideoFrame> video_frame;
gab0d77c7cb2016-06-02 00:00:232181 base::WaitableEvent event(base::WaitableEvent::ResetPolicy::AUTOMATIC,
2182 base::WaitableEvent::InitialState::NOT_SIGNALED);
tguilbert350936ff2017-02-24 05:39:272183 compositor_task_runner_->PostTask(
2184 FROM_HERE,
2185 base::Bind(&GetCurrentFrameAndSignal, base::Unretained(compositor_),
2186 &video_frame, &event));
[email protected]dd061e12014-05-06 19:21:222187 event.Wait();
kainino36eeff82017-03-30 00:55:302188
2189 if (!video_frame) {
2190 return nullptr;
2191 }
2192 last_uploaded_frame_size_ = video_frame->natural_size();
2193 last_uploaded_frame_timestamp_ = video_frame->timestamp();
[email protected]dd061e12014-05-06 19:21:222194 return video_frame;
2195}
2196
sandersd50a635e2016-04-04 22:50:092197void WebMediaPlayerImpl::UpdatePlayState() {
xhwang213e50c2016-10-10 23:56:312198 DCHECK(main_task_runner_->BelongsToCurrentThread());
2199
hubbed5f36882016-01-15 22:40:372200#if defined(OS_ANDROID) // WMPI_CAST
Blink Reformat1c4d759e2017-04-09 16:34:542201 bool is_remote = IsRemote();
xjz4e5d4bf32017-02-15 21:26:352202 bool can_auto_suspend = true;
sandersd50a635e2016-04-04 22:50:092203#else
2204 bool is_remote = false;
hubbee2cc88c092017-07-14 23:10:412205 bool can_auto_suspend = !disable_pipeline_auto_suspend_;
2206 // For streaming videos, we only allow suspending at the very beginning of the
2207 // video, and only if we know the length of the video. (If we don't know
2208 // the length, it might be a dynamically generated video, and suspending
2209 // will not work at all.)
2210 if (IsStreaming()) {
2211 bool at_beginning =
2212 ready_state_ == WebMediaPlayer::kReadyStateHaveNothing ||
2213 CurrentTime() == 0.0;
2214 if (!at_beginning || GetPipelineMediaDuration() == kInfiniteDuration)
2215 can_auto_suspend = false;
2216 }
hubbed5f36882016-01-15 22:40:372217#endif
xhwang213e50c2016-10-10 23:56:312218
dalecurtis8b8505e72016-06-10 21:59:172219 bool is_suspended = pipeline_controller_.IsSuspended();
avayvod39c102402016-11-23 21:43:132220 bool is_backgrounded = IsBackgroundedSuspendEnabled() && IsHidden();
sandersdaaff1a652016-11-17 01:47:252221 PlayState state = UpdatePlayState_ComputePlayState(
xjz4e5d4bf32017-02-15 21:26:352222 is_remote, can_auto_suspend, is_suspended, is_backgrounded);
sandersd35d2c3f2017-01-14 02:04:422223 SetDelegateState(state.delegate_state, state.is_idle);
sandersd50a635e2016-04-04 22:50:092224 SetMemoryReportingState(state.is_memory_reporting_enabled);
2225 SetSuspendState(state.is_suspended || pending_suspend_resume_cycle_);
2226}
dalecurtis5bbc487e2016-02-27 04:15:052227
sandersd35d2c3f2017-01-14 02:04:422228void WebMediaPlayerImpl::SetDelegateState(DelegateState new_state,
2229 bool is_idle) {
tguilbert1bb1c782017-01-23 21:15:112230 DCHECK(delegate_);
dalecurtis5bbc487e2016-02-27 04:15:052231
sandersd35d2c3f2017-01-14 02:04:422232 // Prevent duplicate delegate calls.
2233 // TODO(sandersd): Move this deduplication into the delegate itself.
2234 // TODO(sandersd): WebContentsObserverSanityChecker does not allow sending the
2235 // 'playing' IPC more than once in a row, even if the metadata has changed.
2236 // Figure out whether it should.
Blink Reformat1c4d759e2017-04-09 16:34:542237 bool has_audio = HasAudio() && !client_->IsAutoplayingMuted();
sandersd35d2c3f2017-01-14 02:04:422238 if (delegate_state_ == new_state &&
2239 (delegate_state_ != DelegateState::PLAYING ||
2240 delegate_has_audio_ == has_audio)) {
2241 return;
mlamouri910111362016-11-04 11:28:242242 }
sandersd50a635e2016-04-04 22:50:092243 delegate_state_ = new_state;
sandersd35d2c3f2017-01-14 02:04:422244 delegate_has_audio_ = has_audio;
sandersd50a635e2016-04-04 22:50:092245
sandersd35d2c3f2017-01-14 02:04:422246 switch (new_state) {
sandersd50a635e2016-04-04 22:50:092247 case DelegateState::GONE:
2248 delegate_->PlayerGone(delegate_id_);
2249 break;
mlamouri910111362016-11-04 11:28:242250 case DelegateState::PLAYING: {
peconn257951522017-06-09 18:24:592251 if (HasVideo())
2252 delegate_->DidPlayerSizeChange(delegate_id_, NaturalSize());
zqzhang5d8eab72016-08-26 20:34:302253 delegate_->DidPlay(
Blink Reformat1c4d759e2017-04-09 16:34:542254 delegate_id_, HasVideo(), has_audio,
avayvodcc273dd2017-01-19 19:35:122255 media::DurationToMediaContentType(GetPipelineMediaDuration()));
sandersd50a635e2016-04-04 22:50:092256 break;
mlamouri910111362016-11-04 11:28:242257 }
sandersd50a635e2016-04-04 22:50:092258 case DelegateState::PAUSED:
sandersd35d2c3f2017-01-14 02:04:422259 delegate_->DidPause(delegate_id_);
sandersd50a635e2016-04-04 22:50:092260 break;
dalecurtis0f0097a2015-12-01 17:40:472261 }
sandersd35d2c3f2017-01-14 02:04:422262
2263 delegate_->SetIdle(delegate_id_, is_idle);
dalecurtis0f0097a2015-12-01 17:40:472264}
2265
sandersd50a635e2016-04-04 22:50:092266void WebMediaPlayerImpl::SetMemoryReportingState(
2267 bool is_memory_reporting_enabled) {
2268 if (memory_usage_reporting_timer_.IsRunning() ==
2269 is_memory_reporting_enabled) {
hubbed5f36882016-01-15 22:40:372270 return;
sandersd50a635e2016-04-04 22:50:092271 }
sandersd1c0bba02016-03-04 23:14:082272
sandersd50a635e2016-04-04 22:50:092273 if (is_memory_reporting_enabled) {
2274 memory_usage_reporting_timer_.Start(FROM_HERE,
2275 base::TimeDelta::FromSeconds(2), this,
2276 &WebMediaPlayerImpl::ReportMemoryUsage);
2277 } else {
2278 memory_usage_reporting_timer_.Stop();
2279 ReportMemoryUsage();
2280 }
2281}
2282
2283void WebMediaPlayerImpl::SetSuspendState(bool is_suspended) {
xhwang213e50c2016-10-10 23:56:312284 DCHECK(main_task_runner_->BelongsToCurrentThread());
2285
sandersd50a635e2016-04-04 22:50:092286 // Do not change the state after an error has occurred.
2287 // TODO(sandersd): Update PipelineController to remove the need for this.
2288 if (IsNetworkStateError(network_state_))
sandersd1c0bba02016-03-04 23:14:082289 return;
2290
jameswest451a5bb2017-01-27 03:59:392291 if (is_suspended) {
sandersd35d2c3f2017-01-14 02:04:422292 // If we were not resumed for long enough to satisfy the preroll attempt,
2293 // reset the clock.
2294 if (!preroll_attempt_pending_ && IsPrerollAttemptNeeded()) {
2295 preroll_attempt_pending_ = true;
2296 preroll_attempt_start_time_ = base::TimeTicks();
2297 }
sandersd50a635e2016-04-04 22:50:092298 pipeline_controller_.Suspend();
2299 } else {
sandersd35d2c3f2017-01-14 02:04:422300 // When resuming, start the preroll attempt clock.
2301 if (preroll_attempt_pending_) {
2302 preroll_attempt_pending_ = false;
2303 preroll_attempt_start_time_ = tick_clock_->NowTicks();
2304 }
sandersd50a635e2016-04-04 22:50:092305 pipeline_controller_.Resume();
2306 }
2307}
2308
2309WebMediaPlayerImpl::PlayState
2310WebMediaPlayerImpl::UpdatePlayState_ComputePlayState(bool is_remote,
xjz4e5d4bf32017-02-15 21:26:352311 bool can_auto_suspend,
dalecurtis8b8505e72016-06-10 21:59:172312 bool is_suspended,
sandersd50a635e2016-04-04 22:50:092313 bool is_backgrounded) {
2314 PlayState result;
2315
tguilbert1bb1c782017-01-23 21:15:112316 bool must_suspend = delegate_->IsFrameClosed();
2317 bool is_stale = delegate_->IsStale(delegate_id_);
sandersd35d2c3f2017-01-14 02:04:422318
sandersd50a635e2016-04-04 22:50:092319 // This includes both data source (before pipeline startup) and pipeline
2320 // errors.
2321 bool has_error = IsNetworkStateError(network_state_);
2322
dalecurtiscc8baf72016-10-27 01:49:442323 // After HaveFutureData, Blink will call play() if the state is not paused;
2324 // prior to this point |paused_| is not accurate.
sandersd50a635e2016-04-04 22:50:092325 bool have_future_data =
Blink Reformat1c4d759e2017-04-09 16:34:542326 highest_ready_state_ >= WebMediaPlayer::kReadyStateHaveFutureData;
sandersd50a635e2016-04-04 22:50:092327
avayvod65fad272017-02-24 01:00:482328 // Background suspend is only enabled for paused players.
2329 // In the case of players with audio the session should be kept.
2330 bool background_suspended =
xjz4e5d4bf32017-02-15 21:26:352331 can_auto_suspend && is_backgrounded && paused_ && have_future_data;
sandersd50a635e2016-04-04 22:50:092332
dalecurtiscc8baf72016-10-27 01:49:442333 // Idle suspension is allowed prior to have future data since there exist
2334 // mechanisms to exit the idle state when the player is capable of reaching
2335 // the have future data state; see didLoadingProgress().
2336 //
sandersd50a635e2016-04-04 22:50:092337 // TODO(sandersd): Make the delegate suspend idle players immediately when
2338 // hidden.
sandersdaaff1a652016-11-17 01:47:252339 bool idle_suspended =
xjz4e5d4bf32017-02-15 21:26:352340 can_auto_suspend && is_stale && paused_ && !seeking_ && !overlay_enabled_;
dalecurtise7120dc2016-09-03 02:54:352341
2342 // If we're already suspended, see if we can wait for user interaction. Prior
sandersd35d2c3f2017-01-14 02:04:422343 // to HaveFutureData, we require |is_stale| to remain suspended. |is_stale|
dalecurtise7120dc2016-09-03 02:54:352344 // will be cleared when we receive data which may take us to HaveFutureData.
2345 bool can_stay_suspended =
sandersd35d2c3f2017-01-14 02:04:422346 (is_stale || have_future_data) && is_suspended && paused_ && !seeking_;
sandersd50a635e2016-04-04 22:50:092347
2348 // Combined suspend state.
sandersd35d2c3f2017-01-14 02:04:422349 result.is_suspended = is_remote || must_suspend || idle_suspended ||
avayvod65fad272017-02-24 01:00:482350 background_suspended || can_stay_suspended;
sandersd50a635e2016-04-04 22:50:092351
2352 // We do not treat |playback_rate_| == 0 as paused. For the media session,
2353 // being paused implies displaying a play button, which is incorrect in this
2354 // case. For memory usage reporting, we just use the same definition (but we
2355 // don't have to).
2356 //
2357 // Similarly, we don't consider |ended_| to be paused. Blink will immediately
2358 // call pause() or seek(), so |ended_| should not affect the computation.
2359 // Despite that, |ended_| does result in a separate paused state, to simplfy
2360 // the contract for SetDelegateState().
2361 //
avayvod65fad272017-02-24 01:00:482362 // |has_remote_controls| indicates if the player can be controlled outside the
2363 // page (e.g. via the notification controls or by audio focus events). Idle
sandersd50a635e2016-04-04 22:50:092364 // suspension does not destroy the media session, because we expect that the
avayvod5f34b642017-03-23 03:14:042365 // notification controls (and audio focus) remain. With some exceptions for
2366 // background videos, the player only needs to have audio to have controls
2367 // (requires |have_future_data|).
2368 //
2369 // |alive| indicates if the player should be present (not |GONE|) to the
2370 // delegate, either paused or playing. The following must be true for the
2371 // player:
sandersd50a635e2016-04-04 22:50:092372 // - |have_future_data|, since we need to know whether we are paused to
avayvod65fad272017-02-24 01:00:482373 // correctly configure the session and also because the tracks and
avayvod5f34b642017-03-23 03:14:042374 // duration are passed to DidPlay(),
2375 // - |is_remote| is false as remote playback is not handled by the delegate,
2376 // - |has_error| is false as player should have no errors,
2377 // - |background_suspended| is false, otherwise |has_remote_controls| must
2378 // be true.
sandersd50a635e2016-04-04 22:50:092379 //
avayvod65fad272017-02-24 01:00:482380 // TODO(sandersd): If Blink told us the paused state sooner, we could detect
2381 // if the remote controls are available sooner.
2382
2383 // Background videos with audio don't have remote controls if background
2384 // suspend is enabled and resuming background videos is not (original Android
2385 // behavior).
2386 bool backgrounded_video_has_no_remote_controls =
2387 IsBackgroundedSuspendEnabled() && !IsResumeBackgroundVideosEnabled() &&
Blink Reformat1c4d759e2017-04-09 16:34:542388 is_backgrounded && HasVideo();
sandersd50a635e2016-04-04 22:50:092389 bool can_play = !has_error && !is_remote && have_future_data;
avayvod5f34b642017-03-23 03:14:042390 bool has_remote_controls =
Blink Reformat1c4d759e2017-04-09 16:34:542391 HasAudio() && !backgrounded_video_has_no_remote_controls;
avayvod5f34b642017-03-23 03:14:042392 bool alive = can_play && !must_suspend &&
2393 (!background_suspended || has_remote_controls);
2394 if (!alive) {
sandersd50a635e2016-04-04 22:50:092395 result.delegate_state = DelegateState::GONE;
tguilbert1bb1c782017-01-23 21:15:112396 result.is_idle = delegate_->IsIdle(delegate_id_);
avayvod65fad272017-02-24 01:00:482397 } else if (paused_) {
sandersd35d2c3f2017-01-14 02:04:422398 // TODO(sandersd): Is it possible to have a suspended session, be ended,
2399 // and not be paused? If so we should be in a PLAYING state.
dalecurtise7120dc2016-09-03 02:54:352400 result.delegate_state =
sandersd35d2c3f2017-01-14 02:04:422401 ended_ ? DelegateState::GONE : DelegateState::PAUSED;
2402 result.is_idle = !seeking_;
sandersd50a635e2016-04-04 22:50:092403 } else {
2404 result.delegate_state = DelegateState::PLAYING;
sandersd35d2c3f2017-01-14 02:04:422405 result.is_idle = false;
sandersd50a635e2016-04-04 22:50:092406 }
2407
dalecurtis8b8505e72016-06-10 21:59:172408 // It's not critical if some cases where memory usage can change are missed,
sandersd50a635e2016-04-04 22:50:092409 // since media memory changes are usually gradual.
2410 result.is_memory_reporting_enabled =
sandersd35d2c3f2017-01-14 02:04:422411 can_play && !result.is_suspended && (!paused_ || seeking_);
sandersd50a635e2016-04-04 22:50:092412
2413 return result;
dalecurtis0f0097a2015-12-01 17:40:472414}
2415
dalecurtis83266c72015-10-29 18:43:202416void WebMediaPlayerImpl::ReportMemoryUsage() {
2417 DCHECK(main_task_runner_->BelongsToCurrentThread());
2418
wdzierzanowskifd4cd91c52015-12-02 23:50:202419 // About base::Unretained() usage below: We destroy |demuxer_| on the main
2420 // thread. Before that, however, ~WebMediaPlayerImpl() posts a task to the
2421 // media thread and waits for it to finish. Hence, the GetMemoryUsage() task
2422 // posted here must finish earlier.
2423
2424 if (demuxer_) {
2425 base::PostTaskAndReplyWithResult(
2426 media_task_runner_.get(), FROM_HERE,
2427 base::Bind(&Demuxer::GetMemoryUsage, base::Unretained(demuxer_.get())),
2428 base::Bind(&WebMediaPlayerImpl::FinishMemoryUsageReport, AsWeakPtr()));
2429 } else {
2430 FinishMemoryUsageReport(0);
2431 }
2432}
2433
2434void WebMediaPlayerImpl::FinishMemoryUsageReport(int64_t demuxer_memory_usage) {
2435 DCHECK(main_task_runner_->BelongsToCurrentThread());
2436
avayvodc4bfb0e62017-01-13 01:07:012437 const PipelineStatistics stats = GetPipelineStatistics();
servolk639473e492016-12-15 04:14:202438 const int64_t data_source_memory_usage =
2439 data_source_ ? data_source_->GetMemoryUsage() : 0;
dalecurtisecc76612017-04-19 00:31:202440
2441 // If we have video and no video memory usage, assume the VideoFrameCompositor
2442 // is holding onto the last frame after we've suspended the pipeline; which
2443 // thus reports zero memory usage from the video renderer.
2444 //
2445 // Technically this should use the coded size, but that requires us to hop to
2446 // the compositor to get and byte-perfect accuracy isn't important here.
2447 const int64_t video_memory_usage =
2448 stats.video_memory_usage +
2449 (pipeline_metadata_.has_video && !stats.video_memory_usage
2450 ? VideoFrame::AllocationSize(PIXEL_FORMAT_YV12,
2451 pipeline_metadata_.natural_size)
2452 : 0);
2453
dalecurtis83266c72015-10-29 18:43:202454 const int64_t current_memory_usage =
dalecurtisecc76612017-04-19 00:31:202455 stats.audio_memory_usage + video_memory_usage + data_source_memory_usage +
2456 demuxer_memory_usage;
dalecurtis83266c72015-10-29 18:43:202457
dalecurtisecc76612017-04-19 00:31:202458 DVLOG(2) << "Memory Usage -- Total: " << current_memory_usage
2459 << " Audio: " << stats.audio_memory_usage
2460 << ", Video: " << video_memory_usage
servolk639473e492016-12-15 04:14:202461 << ", DataSource: " << data_source_memory_usage
wdzierzanowskifd4cd91c52015-12-02 23:50:202462 << ", Demuxer: " << demuxer_memory_usage;
dalecurtis83266c72015-10-29 18:43:202463
2464 const int64_t delta = current_memory_usage - last_reported_memory_usage_;
2465 last_reported_memory_usage_ = current_memory_usage;
2466 adjust_allocated_memory_cb_.Run(delta);
servolk639473e492016-12-15 04:14:202467
Blink Reformat1c4d759e2017-04-09 16:34:542468 if (HasAudio()) {
servolk639473e492016-12-15 04:14:202469 UMA_HISTOGRAM_MEMORY_KB("Media.WebMediaPlayerImpl.Memory.Audio",
2470 stats.audio_memory_usage / 1024);
2471 }
Blink Reformat1c4d759e2017-04-09 16:34:542472 if (HasVideo()) {
servolk639473e492016-12-15 04:14:202473 UMA_HISTOGRAM_MEMORY_KB("Media.WebMediaPlayerImpl.Memory.Video",
dalecurtisecc76612017-04-19 00:31:202474 video_memory_usage / 1024);
servolk639473e492016-12-15 04:14:202475 }
2476 if (data_source_) {
2477 UMA_HISTOGRAM_MEMORY_KB("Media.WebMediaPlayerImpl.Memory.DataSource",
2478 data_source_memory_usage / 1024);
2479 }
2480 if (demuxer_) {
2481 UMA_HISTOGRAM_MEMORY_KB("Media.WebMediaPlayerImpl.Memory.Demuxer",
2482 demuxer_memory_usage / 1024);
2483 }
dalecurtis83266c72015-10-29 18:43:202484}
2485
dalecurtis8b8505e72016-06-10 21:59:172486void WebMediaPlayerImpl::ScheduleIdlePauseTimer() {
avayvod65fad272017-02-24 01:00:482487 // Only schedule the pause timer if we're not paused or paused but going to
avayvod52efd282017-03-07 21:13:042488 // resume when foregrounded, and are suspended and have audio.
2489 if ((paused_ && !paused_when_hidden_) ||
Blink Reformat1c4d759e2017-04-09 16:34:542490 !pipeline_controller_.IsSuspended() || !HasAudio()) {
dalecurtis8b8505e72016-06-10 21:59:172491 return;
avayvod52efd282017-03-07 21:13:042492 }
dalecurtis8b8505e72016-06-10 21:59:172493
2494#if defined(OS_ANDROID)
2495 // Remote players will be suspended and locally paused.
Blink Reformat1c4d759e2017-04-09 16:34:542496 if (IsRemote())
dalecurtis8b8505e72016-06-10 21:59:172497 return;
2498#endif
2499
2500 // Idle timeout chosen arbitrarily.
2501 background_pause_timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(5),
2502 this, &WebMediaPlayerImpl::OnPause);
2503}
2504
dalecurtis04bdb582016-08-17 22:15:232505void WebMediaPlayerImpl::CreateWatchTimeReporter() {
wdzierzanowskia78fa9b2017-06-13 18:12:102506 if (!HasVideo() && !HasAudio())
2507 return;
2508
dalecurtis04bdb582016-08-17 22:15:232509 // Create the watch time reporter and synchronize its initial state.
Dale Curtis1adbe6a2017-08-02 02:09:132510 watch_time_reporter_.reset(new WatchTimeReporter(
2511 mojom::PlaybackProperties::New(
2512 pipeline_metadata_.audio_decoder_config.codec(),
2513 pipeline_metadata_.video_decoder_config.codec(),
2514 pipeline_metadata_.has_audio, pipeline_metadata_.has_video,
2515 !!chunk_demuxer_, is_encrypted_, embedded_media_experience_enabled_,
2516 pipeline_metadata_.natural_size,
2517 url::Origin(frame_->GetSecurityOrigin())),
Dale Curtis051fdf62017-08-05 00:21:132518 base::BindRepeating(&WebMediaPlayerImpl::GetCurrentTimeInternal,
2519 base::Unretained(this)),
Dale Curtis1adbe6a2017-08-02 02:09:132520 watch_time_recorder_provider_));
dalecurtis04bdb582016-08-17 22:15:232521 watch_time_reporter_->OnVolumeChange(volume_);
Mounir Lamourif9af74e72017-06-19 19:31:452522
tguilbert1bb1c782017-01-23 21:15:112523 if (delegate_->IsFrameHidden())
dalecurtis04bdb582016-08-17 22:15:232524 watch_time_reporter_->OnHidden();
2525 else
2526 watch_time_reporter_->OnShown();
Mounir Lamourif9af74e72017-06-19 19:31:452527
Mounir Lamouri41a79c62017-06-06 12:53:162528 if (client_->HasNativeControls())
2529 watch_time_reporter_->OnNativeControlsEnabled();
2530 else
2531 watch_time_reporter_->OnNativeControlsDisabled();
Mounir Lamourif9af74e72017-06-19 19:31:452532
2533 switch (client_->DisplayType()) {
2534 case WebMediaPlayer::DisplayType::kInline:
2535 watch_time_reporter_->OnDisplayTypeInline();
2536 break;
2537 case WebMediaPlayer::DisplayType::kFullscreen:
2538 watch_time_reporter_->OnDisplayTypeFullscreen();
2539 break;
2540 case WebMediaPlayer::DisplayType::kPictureInPicture:
2541 watch_time_reporter_->OnDisplayTypePictureInPicture();
2542 break;
2543 }
dalecurtis04bdb582016-08-17 22:15:232544}
2545
avayvod39c102402016-11-23 21:43:132546bool WebMediaPlayerImpl::IsHidden() const {
2547 DCHECK(main_task_runner_->BelongsToCurrentThread());
2548
tguilbert1bb1c782017-01-23 21:15:112549 return delegate_->IsFrameHidden() && !delegate_->IsFrameClosed();
avayvod39c102402016-11-23 21:43:132550}
2551
avayvod102cdb62017-01-07 03:11:092552bool WebMediaPlayerImpl::IsStreaming() const {
2553 return data_source_ && data_source_->IsStreaming();
2554}
2555
liberato2fd111be2017-01-04 00:25:062556bool WebMediaPlayerImpl::DoesOverlaySupportMetadata() const {
2557 return pipeline_metadata_.video_rotation == VIDEO_ROTATION_0;
2558}
2559
xjzaf29d4182016-12-16 01:52:322560void WebMediaPlayerImpl::ActivateViewportIntersectionMonitoring(bool activate) {
2561 DCHECK(main_task_runner_->BelongsToCurrentThread());
2562
Blink Reformat1c4d759e2017-04-09 16:34:542563 client_->ActivateViewportIntersectionMonitoring(activate);
xjzaf29d4182016-12-16 01:52:322564}
2565
Anton Vayvod09fa66e2017-07-20 23:02:122566void WebMediaPlayerImpl::UpdateRemotePlaybackCompatibility(bool is_compatible) {
2567 DCHECK(main_task_runner_->BelongsToCurrentThread());
2568
2569 client_->RemotePlaybackCompatibilityChanged(loaded_url_, is_compatible);
2570}
2571
avayvodcc273dd2017-01-19 19:35:122572bool WebMediaPlayerImpl::ShouldPauseVideoWhenHidden() const {
avayvod65fad272017-02-24 01:00:482573 // If suspending background video, pause any video that's not remoted or
2574 // not unlocked to play in the background.
2575 if (IsBackgroundedSuspendEnabled()) {
Blink Reformat1c4d759e2017-04-09 16:34:542576 if (!HasVideo())
avayvod65fad272017-02-24 01:00:482577 return false;
2578
2579#if defined(OS_ANDROID)
Blink Reformat1c4d759e2017-04-09 16:34:542580 if (IsRemote())
avayvod65fad272017-02-24 01:00:482581 return false;
avayvodcc273dd2017-01-19 19:35:122582#endif
avayvodeb9098d2017-01-07 00:33:032583
Blink Reformat1c4d759e2017-04-09 16:34:542584 return !HasAudio() || (IsResumeBackgroundVideosEnabled() &&
2585 video_locked_when_paused_when_hidden_);
avayvod65fad272017-02-24 01:00:482586 }
2587
2588 // Otherwise only pause if the optimization is on and it's a video-only
2589 // optimization candidate.
avayvod01201332017-04-14 00:27:152590 return IsBackgroundVideoPauseOptimizationEnabled() && !HasAudio() &&
avayvod65fad272017-02-24 01:00:482591 IsBackgroundOptimizationCandidate();
avayvodeb9098d2017-01-07 00:33:032592}
2593
avayvod2135a642017-01-13 00:17:142594bool WebMediaPlayerImpl::ShouldDisableVideoWhenHidden() const {
avayvodcc273dd2017-01-19 19:35:122595 // This optimization is behind the flag on all platforms.
2596 if (!IsBackgroundVideoTrackOptimizationEnabled())
avayvodc4bfb0e62017-01-13 01:07:012597 return false;
avayvodc4bfb0e62017-01-13 01:07:012598
avayvodcc273dd2017-01-19 19:35:122599 // Disable video track only for players with audio that match the criteria for
2600 // being optimized.
Blink Reformat1c4d759e2017-04-09 16:34:542601 return HasAudio() && IsBackgroundOptimizationCandidate();
avayvodcc273dd2017-01-19 19:35:122602}
2603
2604bool WebMediaPlayerImpl::IsBackgroundOptimizationCandidate() const {
2605 DCHECK(main_task_runner_->BelongsToCurrentThread());
2606
avayvodcc273dd2017-01-19 19:35:122607#if defined(OS_ANDROID) // WMPI_CAST
avayvodac1a8522017-01-20 19:02:502608 // Don't optimize players being Cast.
Blink Reformat1c4d759e2017-04-09 16:34:542609 if (IsRemote())
avayvodcc273dd2017-01-19 19:35:122610 return false;
avayvodac1a8522017-01-20 19:02:502611
2612 // Video-only players are always optimized (paused) on Android.
2613 // Don't check the keyframe distance and duration.
Blink Reformat1c4d759e2017-04-09 16:34:542614 if (!HasAudio() && HasVideo())
avayvodac1a8522017-01-20 19:02:502615 return true;
avayvodcc273dd2017-01-19 19:35:122616#endif // defined(OS_ANDROID)
2617
2618 // Don't optimize audio-only or streaming players.
Blink Reformat1c4d759e2017-04-09 16:34:542619 if (!HasVideo() || IsStreaming())
avayvodcc273dd2017-01-19 19:35:122620 return false;
2621
2622 // Videos shorter than the maximum allowed keyframe distance can be optimized.
2623 base::TimeDelta duration = GetPipelineMediaDuration();
avayvode85ec422017-04-14 00:11:332624 base::TimeDelta max_keyframe_distance =
2625 (load_type_ == kLoadTypeMediaSource)
2626 ? max_keyframe_distance_to_disable_background_video_mse_
2627 : max_keyframe_distance_to_disable_background_video_;
2628 if (duration < max_keyframe_distance)
avayvodcc273dd2017-01-19 19:35:122629 return true;
2630
2631 // Otherwise, only optimize videos with shorter average keyframe distance.
avayvodc4bfb0e62017-01-13 01:07:012632 PipelineStatistics stats = GetPipelineStatistics();
avayvode85ec422017-04-14 00:11:332633 return stats.video_keyframe_distance_average < max_keyframe_distance;
avayvod2135a642017-01-13 00:17:142634}
2635
avayvod56e1f3942017-01-21 02:06:312636void WebMediaPlayerImpl::UpdateBackgroundVideoOptimizationState() {
2637 if (IsHidden()) {
Dale Curtisa75a7892017-08-09 20:21:512638 if (ShouldPauseVideoWhenHidden()) {
avayvod56e1f3942017-01-21 02:06:312639 PauseVideoIfNeeded();
Dale Curtisa75a7892017-08-09 20:21:512640 } else if (update_background_status_cb_.IsCancelled()) {
2641 // Only trigger updates when we don't have one already scheduled.
2642 update_background_status_cb_.Reset(
2643 base::Bind(&WebMediaPlayerImpl::DisableVideoTrackIfNeeded,
2644 base::Unretained(this)));
2645
2646 // Defer disable track until we're sure the clip will be backgrounded for
2647 // some time. Resuming may take half a second, so frequent tab switches
2648 // will yield a poor user experience otherwise. http://crbug.com/709302
2649 // may also cause AV sync issues if disable/enable happens too fast.
2650 main_task_runner_->PostDelayedTask(
2651 FROM_HERE, update_background_status_cb_.callback(),
2652 base::TimeDelta::FromSeconds(10));
2653 }
avayvod56e1f3942017-01-21 02:06:312654 } else {
Dale Curtisa75a7892017-08-09 20:21:512655 update_background_status_cb_.Cancel();
avayvod56e1f3942017-01-21 02:06:312656 EnableVideoTrackIfNeeded();
2657 }
2658}
2659
2660void WebMediaPlayerImpl::PauseVideoIfNeeded() {
2661 DCHECK(IsHidden());
2662
2663 // Don't pause video while the pipeline is stopped, resuming or seeking.
2664 // Also if the video is paused already.
tguilbert350936ff2017-02-24 05:39:272665 if (!pipeline_controller_.IsPipelineRunning() || is_pipeline_resuming_ ||
2666 seeking_ || paused_)
avayvod56e1f3942017-01-21 02:06:312667 return;
2668
2669 // OnPause() will set |paused_when_hidden_| to false and call
2670 // UpdatePlayState(), so set the flag to true after and then return.
2671 OnPause();
2672 paused_when_hidden_ = true;
2673}
2674
avayvod2135a642017-01-13 00:17:142675void WebMediaPlayerImpl::EnableVideoTrackIfNeeded() {
avayvod56e1f3942017-01-21 02:06:312676 // Don't change video track while the pipeline is stopped, resuming or
2677 // seeking.
tguilbert350936ff2017-02-24 05:39:272678 if (!pipeline_controller_.IsPipelineRunning() || is_pipeline_resuming_ ||
2679 seeking_)
avayvod2135a642017-01-13 00:17:142680 return;
2681
2682 if (video_track_disabled_) {
2683 video_track_disabled_ = false;
Blink Reformat1c4d759e2017-04-09 16:34:542684 if (client_->HasSelectedVideoTrack()) {
2685 WebMediaPlayer::TrackId trackId = client_->GetSelectedVideoTrackId();
2686 SelectedVideoTrackChanged(&trackId);
avayvod2135a642017-01-13 00:17:142687 }
2688 }
2689}
2690
2691void WebMediaPlayerImpl::DisableVideoTrackIfNeeded() {
2692 DCHECK(IsHidden());
2693
2694 // Don't change video track while the pipeline is resuming or seeking.
2695 if (is_pipeline_resuming_ || seeking_)
2696 return;
2697
2698 if (!video_track_disabled_ && ShouldDisableVideoWhenHidden()) {
2699 video_track_disabled_ = true;
Blink Reformat1c4d759e2017-04-09 16:34:542700 SelectedVideoTrackChanged(nullptr);
avayvod2135a642017-01-13 00:17:142701 }
2702}
2703
avayvodc4bfb0e62017-01-13 01:07:012704void WebMediaPlayerImpl::SetPipelineStatisticsForTest(
2705 const PipelineStatistics& stats) {
2706 pipeline_statistics_for_test_ = base::make_optional(stats);
2707}
2708
2709PipelineStatistics WebMediaPlayerImpl::GetPipelineStatistics() const {
2710 DCHECK(main_task_runner_->BelongsToCurrentThread());
2711
tguilbert350936ff2017-02-24 05:39:272712 return pipeline_statistics_for_test_.value_or(
2713 pipeline_controller_.GetStatistics());
avayvodc4bfb0e62017-01-13 01:07:012714}
2715
avayvodcc273dd2017-01-19 19:35:122716void WebMediaPlayerImpl::SetPipelineMediaDurationForTest(
2717 base::TimeDelta duration) {
2718 pipeline_media_duration_for_test_ = base::make_optional(duration);
2719}
2720
2721base::TimeDelta WebMediaPlayerImpl::GetPipelineMediaDuration() const {
2722 DCHECK(main_task_runner_->BelongsToCurrentThread());
2723
2724 return pipeline_media_duration_for_test_.value_or(
tguilbert350936ff2017-02-24 05:39:272725 pipeline_controller_.GetMediaDuration());
avayvodcc273dd2017-01-19 19:35:122726}
2727
2728void WebMediaPlayerImpl::ReportTimeFromForegroundToFirstFrame(
2729 base::TimeTicks foreground_time,
2730 base::TimeTicks new_frame_time) {
2731 base::TimeDelta time_to_first_frame = new_frame_time - foreground_time;
Blink Reformat1c4d759e2017-04-09 16:34:542732 if (HasAudio()) {
avayvodcc273dd2017-01-19 19:35:122733 UMA_HISTOGRAM_TIMES(
2734 "Media.Video.TimeFromForegroundToFirstFrame.DisableTrack",
2735 time_to_first_frame);
2736 } else {
2737 UMA_HISTOGRAM_TIMES("Media.Video.TimeFromForegroundToFirstFrame.Paused",
2738 time_to_first_frame);
2739 }
2740}
Xiangjun Zhangba8724f482017-08-03 06:43:252741
2742void WebMediaPlayerImpl::SwitchToRemoteRenderer(
2743 const std::string& remote_device_friendly_name) {
xjz4e5d4bf32017-02-15 21:26:352744 DCHECK(main_task_runner_->BelongsToCurrentThread());
Xiangjun Zhangba8724f482017-08-03 06:43:252745 disable_pipeline_auto_suspend_ = true;
Chris Cunninghamd9df58e2017-08-29 00:04:232746
2747 // Capabilities reporting should only be performed for local playbacks.
2748 video_decode_stats_reporter_.reset();
2749
Xiangjun Zhangba8724f482017-08-03 06:43:252750 // Requests to restart media pipeline. A remote renderer will be created via
2751 // the |renderer_factory_selector_|.
xjz4e5d4bf32017-02-15 21:26:352752 ScheduleRestart();
xjzdf9b67e2017-04-13 23:28:252753 if (client_) {
Xiangjun Zhangba8724f482017-08-03 06:43:252754 client_->MediaRemotingStarted(
2755 WebString::FromUTF8(remote_device_friendly_name));
xjzdf9b67e2017-04-13 23:28:252756 }
xjz4e5d4bf32017-02-15 21:26:352757}
2758
Xiangjun Zhangba8724f482017-08-03 06:43:252759void WebMediaPlayerImpl::SwitchToLocalRenderer() {
2760 DCHECK(main_task_runner_->BelongsToCurrentThread());
2761 disable_pipeline_auto_suspend_ = false;
Chris Cunninghamd9df58e2017-08-29 00:04:232762
2763 // Capabilities reporting may resume now that playback is local.
2764 CreateVideoDecodeStatsReporter();
2765
Xiangjun Zhangba8724f482017-08-03 06:43:252766 // Requests to restart media pipeline. A local renderer will be created via
2767 // the |renderer_factory_selector_|.
2768 ScheduleRestart();
2769 if (client_)
2770 client_->MediaRemotingStopped();
2771}
2772
dalecurtis4f6d14d2017-02-22 17:42:222773void WebMediaPlayerImpl::RecordUnderflowDuration(base::TimeDelta duration) {
2774 DCHECK(data_source_ || chunk_demuxer_);
xhwang68b3fab82017-05-17 21:31:462775
dalecurtis4f6d14d2017-02-22 17:42:222776 if (data_source_)
Jennifer Apacible82e25c92017-08-07 18:15:272777 UMA_HISTOGRAM_TIMES("Media.UnderflowDuration2.SRC", duration);
dalecurtis4f6d14d2017-02-22 17:42:222778 else
Jennifer Apacible82e25c92017-08-07 18:15:272779 UMA_HISTOGRAM_TIMES("Media.UnderflowDuration2.MSE", duration);
xhwang68b3fab82017-05-17 21:31:462780
2781 if (is_encrypted_)
Jennifer Apacible82e25c92017-08-07 18:15:272782 UMA_HISTOGRAM_TIMES("Media.UnderflowDuration2.EME", duration);
dalecurtis4f6d14d2017-02-22 17:42:222783}
2784
xhwang60802652017-04-19 07:29:582785#define UMA_HISTOGRAM_VIDEO_HEIGHT(name, sample) \
2786 UMA_HISTOGRAM_CUSTOM_COUNTS(name, sample, 100, 10000, 50)
2787
2788void WebMediaPlayerImpl::RecordVideoNaturalSize(const gfx::Size& natural_size) {
2789 // Always report video natural size to MediaLog.
2790 media_log_->AddEvent(media_log_->CreateVideoSizeSetEvent(
2791 natural_size.width(), natural_size.height()));
2792
2793 if (initial_video_height_recorded_)
2794 return;
2795
2796 initial_video_height_recorded_ = true;
2797
2798 int height = natural_size.height();
2799
2800 if (load_type_ == kLoadTypeURL)
2801 UMA_HISTOGRAM_VIDEO_HEIGHT("Media.VideoHeight.Initial.SRC", height);
2802 else if (load_type_ == kLoadTypeMediaSource)
2803 UMA_HISTOGRAM_VIDEO_HEIGHT("Media.VideoHeight.Initial.MSE", height);
2804
2805 if (is_encrypted_)
2806 UMA_HISTOGRAM_VIDEO_HEIGHT("Media.VideoHeight.Initial.EME", height);
2807
2808 UMA_HISTOGRAM_VIDEO_HEIGHT("Media.VideoHeight.Initial.All", height);
2809}
2810
2811#undef UMA_HISTOGRAM_VIDEO_HEIGHT
2812
hubbeb2d3efd2017-05-05 23:26:382813void WebMediaPlayerImpl::SetTickClockForTest(base::TickClock* tick_clock) {
2814 tick_clock_.reset(tick_clock);
2815 buffered_data_source_host_.SetTickClockForTest(tick_clock);
2816}
2817
acolwell9e0840d2014-09-06 19:01:322818} // namespace media