blob: 653f04985d419750acbb0794df55bc074e434896 [file] [log] [blame]
[email protected]85a37afd2013-05-30 22:51:151// Copyright 2013 The Chromium Authors. All rights reserved.
[email protected]891acc92009-04-27 19:56:412// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
[email protected]ec9212f2008-12-18 21:40:364
acolwell9e0840d2014-09-06 19:01:325#include "media/blink/webmediaplayer_impl.h"
[email protected]8931c41a2009-07-07 17:31:496
[email protected]c2a45e242013-02-15 20:24:587#include <algorithm>
mateuszs3371ab02015-04-24 13:20:238#include <cmath>
[email protected]47b06ceb2010-08-04 22:41:119#include <limits>
guidouc7babef2015-10-22 00:42:3510#include <string>
dcheng652f5ff2015-12-27 08:54:0011#include <utility>
[email protected]47b06ceb2010-08-04 22:41:1112
[email protected]08273c7b2011-09-17 00:33:5113#include "base/bind.h"
sandersd1c0bba02016-03-04 23:14:0814#include "base/bind_helpers.h"
[email protected]2041cf342010-02-19 03:15:5915#include "base/callback.h"
[email protected]7502ef12014-01-25 01:19:2716#include "base/callback_helpers.h"
sandersd1e49fb62015-12-12 01:18:0617#include "base/command_line.h"
[email protected]ca04095f2014-02-07 10:23:5618#include "base/debug/alias.h"
[email protected]926f8fd2013-04-12 20:27:5319#include "base/debug/crash_logging.h"
fdoraydb3ef7d2016-06-09 15:42:3820#include "base/location.h"
servolkf94b4602017-01-31 16:44:2721#include "base/memory/ptr_util.h"
asvitkine30330812016-08-30 04:01:0822#include "base/metrics/histogram_macros.h"
acolwellb4034942014-08-28 15:42:4323#include "base/single_thread_task_runner.h"
servolka233f832016-06-10 20:39:0424#include "base/strings/string_number_conversions.h"
wdzierzanowskifd4cd91c52015-12-02 23:50:2025#include "base/task_runner_util.h"
gabba14a442016-05-11 20:10:2026#include "base/threading/thread_task_runner_handle.h"
ssid9525f4672015-01-28 12:13:1527#include "base/trace_event/trace_event.h"
sandersd1e49fb62015-12-12 01:18:0628#include "build/build_config.h"
[email protected]38564622014-08-19 02:47:1829#include "cc/blink/web_layer_impl.h"
[email protected]21c3f7502013-03-23 03:29:5130#include "cc/layers/video_layer.h"
[email protected]e4fc09e2012-04-06 03:17:4431#include "media/audio/null_audio_sink.h"
[email protected]2eccbed2014-01-10 05:15:5332#include "media/base/bind_to_current_loop.h"
xhwang0ad11e512014-11-25 23:43:0933#include "media/base/cdm_context.h"
xhwang79b193042016-12-13 18:52:4334#include "media/base/content_decryption_module.h"
[email protected]32da1002010-03-03 21:57:3535#include "media/base/limits.h"
zqzhang5d8eab72016-08-26 20:34:3036#include "media/base/media_content_type.h"
[email protected]090f7312011-08-05 23:26:4037#include "media/base/media_log.h"
sandersd1e49fb62015-12-12 01:18:0638#include "media/base/media_switches.h"
tguilbert25a4d112016-10-13 21:56:5139#include "media/base/media_url_demuxer.h"
[email protected]8a561062013-11-22 01:19:3140#include "media/base/text_renderer.h"
watk9f9dfdc92015-09-04 21:33:2941#include "media/base/timestamp_constants.h"
[email protected]e81283bb2010-08-31 18:01:2142#include "media/base/video_frame.h"
acolwell9e0840d2014-09-06 19:01:3243#include "media/blink/texttrack_impl.h"
dalecurtis04bdb582016-08-17 22:15:2344#include "media/blink/watch_time_reporter.h"
acolwell9e0840d2014-09-06 19:01:3245#include "media/blink/webaudiosourceprovider_impl.h"
xhwang97de4202014-11-25 08:44:0146#include "media/blink/webcontentdecryptionmodule_impl.h"
acolwell9e0840d2014-09-06 19:01:3247#include "media/blink/webinbandtexttrack_impl.h"
48#include "media/blink/webmediaplayer_delegate.h"
acolwell9e0840d2014-09-06 19:01:3249#include "media/blink/webmediaplayer_util.h"
50#include "media/blink/webmediasource_impl.h"
[email protected]efe7cd22012-09-12 23:55:0151#include "media/filters/chunk_demuxer.h"
[email protected]ddbc6ff2013-04-19 15:28:3352#include "media/filters/ffmpeg_demuxer.h"
jrummellc9d8e532015-02-26 18:38:1953#include "third_party/WebKit/public/platform/WebEncryptedMediaTypes.h"
srirama.m26f864d02015-07-14 05:21:4654#include "third_party/WebKit/public/platform/WebMediaPlayerClient.h"
55#include "third_party/WebKit/public/platform/WebMediaPlayerEncryptedMediaClient.h"
guidou9bfe4e2f2016-04-09 08:31:1956#include "third_party/WebKit/public/platform/WebMediaPlayerSource.h"
[email protected]745746d2013-08-23 02:09:1657#include "third_party/WebKit/public/platform/WebMediaSource.h"
[email protected]c10884462013-05-30 00:22:0958#include "third_party/WebKit/public/platform/WebRect.h"
nverne61d2da872017-05-24 10:15:3059#include "third_party/WebKit/public/platform/WebRuntimeFeatures.h"
mek966863c2016-02-04 23:39:0560#include "third_party/WebKit/public/platform/WebSecurityOrigin.h"
[email protected]c10884462013-05-30 00:22:0961#include "third_party/WebKit/public/platform/WebSize.h"
62#include "third_party/WebKit/public/platform/WebString.h"
lethalantidote7f6009d2017-07-07 21:47:3963#include "third_party/WebKit/public/platform/WebSurfaceLayerBridge.h"
[email protected]c10884462013-05-30 00:22:0964#include "third_party/WebKit/public/platform/WebURL.h"
tguilbert9881bc22016-10-27 03:13:4165#include "third_party/WebKit/public/web/WebDocument.h"
xhwang0acca44b2015-06-18 00:43:3166#include "third_party/WebKit/public/web/WebFrame.h"
[email protected]80504652014-04-18 04:41:5067#include "third_party/WebKit/public/web/WebLocalFrame.h"
avayvod65fad272017-02-24 01:00:4868#include "third_party/WebKit/public/web/WebUserGestureIndicator.h"
[email protected]2255a9332013-06-17 05:12:3169#include "third_party/WebKit/public/web/WebView.h"
[email protected]b3f2b912009-04-09 16:18:5270
dalecurtisea27a3ed2016-06-24 01:41:3071#if defined(OS_ANDROID)
72#include "media/base/android/media_codec_util.h"
73#endif
74
[email protected]180ef242013-11-07 06:50:4675using blink::WebCanvas;
76using blink::WebMediaPlayer;
77using blink::WebRect;
78using blink::WebSize;
79using blink::WebString;
hubbed5f36882016-01-15 22:40:3780using gpu::gles2::GLES2Interface;
81
danakj365175c2016-02-06 00:37:3782#define STATIC_ASSERT_ENUM(a, b) \
83 static_assert(static_cast<int>(a) == static_cast<int>(b), \
84 "mismatching enums: " #a)
85
hubbed5f36882016-01-15 22:40:3786namespace media {
[email protected]ec9212f2008-12-18 21:40:3687
[email protected]8931c41a2009-07-07 17:31:4988namespace {
89
[email protected]378f0b72009-08-11 17:11:4290// Limits the range of playback rate.
91//
92// TODO(kylep): Revisit these.
93//
94// Vista has substantially lower performance than XP or Windows7. If you speed
95// up a video too much, it can't keep up, and rendering stops updating except on
96// the time bar. For really high speeds, audio becomes a bottleneck and we just
97// use up the data we have, which may not achieve the speed requested, but will
98// not crash the tab.
99//
100// A very slow speed, ie 0.00000001x, causes the machine to lock up. (It seems
101// like a busy loop). It gets unresponsive, although its not completely dead.
102//
103// Also our timers are not very accurate (especially for ogg), which becomes
104// evident at low speeds and on Vista. Since other speeds are risky and outside
105// the norms, we think 1/16x to 16x is a safe and useful range for now.
[email protected]39bdde32013-04-17 17:44:20106const double kMinRate = 0.0625;
107const double kMaxRate = 16.0;
[email protected]378f0b72009-08-11 17:11:42108
hubbed5f36882016-01-15 22:40:37109void SetSinkIdOnMediaThread(scoped_refptr<WebAudioSourceProviderImpl> sink,
110 const std::string& device_id,
111 const url::Origin& security_origin,
olka68b69392016-04-01 11:42:12112 const OutputDeviceStatusCB& callback) {
113 sink->SwitchOutputDevice(device_id, security_origin, callback);
guidouc7babef2015-10-22 00:42:35114}
115
sandersd50a635e2016-04-04 22:50:09116bool IsBackgroundedSuspendEnabled() {
dalecurtis0431cbf2016-03-12 01:19:43117#if !defined(OS_ANDROID)
118 // Suspend/Resume is only enabled by default on Android.
119 return base::CommandLine::ForCurrentProcess()->HasSwitch(
120 switches::kEnableMediaSuspend);
121#else
122 return !base::CommandLine::ForCurrentProcess()->HasSwitch(
123 switches::kDisableMediaSuspend);
124#endif
125}
126
avayvod48a8be52016-08-04 19:52:50127bool IsResumeBackgroundVideosEnabled() {
128 return base::FeatureList::IsEnabled(kResumeBackgroundVideo);
129}
130
avayvod39c102402016-11-23 21:43:13131bool IsBackgroundVideoTrackOptimizationEnabled() {
132 return base::FeatureList::IsEnabled(kBackgroundVideoTrackOptimization);
133}
134
avayvod01201332017-04-14 00:27:15135bool IsBackgroundVideoPauseOptimizationEnabled() {
136 return base::FeatureList::IsEnabled(kBackgroundVideoPauseOptimization);
137}
138
avayvod82729272017-05-29 21:58:39139bool IsNewRemotePlaybackPipelineEnabled() {
140 return base::FeatureList::IsEnabled(kNewRemotePlaybackPipeline);
141}
142
sandersd50a635e2016-04-04 22:50:09143bool IsNetworkStateError(blink::WebMediaPlayer::NetworkState state) {
Blink Reformat1c4d759e2017-04-09 16:34:54144 bool result = state == blink::WebMediaPlayer::kNetworkStateFormatError ||
145 state == blink::WebMediaPlayer::kNetworkStateNetworkError ||
146 state == blink::WebMediaPlayer::kNetworkStateDecodeError;
147 DCHECK_EQ(state > blink::WebMediaPlayer::kNetworkStateLoaded, result);
sandersd50a635e2016-04-04 22:50:09148 return result;
149}
150
sandersd2c478422016-08-02 01:19:25151gfx::Size GetRotatedVideoSize(VideoRotation rotation, gfx::Size natural_size) {
152 if (rotation == VIDEO_ROTATION_90 || rotation == VIDEO_ROTATION_270)
153 return gfx::Size(natural_size.height(), natural_size.width());
154 return natural_size;
155}
156
dalecurtis04bdb582016-08-17 22:15:23157base::TimeDelta GetCurrentTimeInternal(WebMediaPlayerImpl* p_this) {
tguilbert350936ff2017-02-24 05:39:27158 // We wrap currentTime() instead of using pipeline_controller_.GetMediaTime()
159 // since there are a variety of cases in which that time is not accurate;
160 // e.g., while remoting and during a pause or seek.
Blink Reformat1c4d759e2017-04-09 16:34:54161 return base::TimeDelta::FromSecondsD(p_this->CurrentTime());
dalecurtis04bdb582016-08-17 22:15:23162}
163
sandersd35d2c3f2017-01-14 02:04:42164// How much time must have elapsed since loading last progressed before we
165// assume that the decoder will have had time to complete preroll.
166constexpr base::TimeDelta kPrerollAttemptTimeout =
watkd026f792016-11-05 00:28:51167 base::TimeDelta::FromSeconds(3);
168
[email protected]8931c41a2009-07-07 17:31:49169} // namespace
170
[email protected]6683e1b2014-04-10 01:45:38171class BufferedDataSourceHostImpl;
172
Blink Reformat1c4d759e2017-04-09 16:34:54173STATIC_ASSERT_ENUM(WebMediaPlayer::kCORSModeUnspecified,
danakj365175c2016-02-06 00:37:37174 UrlData::CORS_UNSPECIFIED);
Blink Reformat1c4d759e2017-04-09 16:34:54175STATIC_ASSERT_ENUM(WebMediaPlayer::kCORSModeAnonymous, UrlData::CORS_ANONYMOUS);
176STATIC_ASSERT_ENUM(WebMediaPlayer::kCORSModeUseCredentials,
danakj365175c2016-02-06 00:37:37177 UrlData::CORS_USE_CREDENTIALS);
[email protected]a5a01102012-06-06 17:01:24178
[email protected]5b5bb9d2010-10-22 19:57:36179WebMediaPlayerImpl::WebMediaPlayerImpl(
[email protected]35b2a972014-04-04 15:50:22180 blink::WebLocalFrame* frame,
[email protected]180ef242013-11-07 06:50:46181 blink::WebMediaPlayerClient* client,
srirama.m26f864d02015-07-14 05:21:46182 blink::WebMediaPlayerEncryptedMediaClient* encrypted_client,
tguilbert1bb1c782017-01-23 21:15:11183 WebMediaPlayerDelegate* delegate,
tguilbert70d2a00a2017-04-25 00:30:44184 std::unique_ptr<RendererFactorySelector> renderer_factory_selector,
Alok Priyadarshi7166d4d2017-07-29 04:04:25185 UrlIndex* url_index,
dalecurtis9cddc0b2017-04-19 21:23:38186 std::unique_ptr<WebMediaPlayerParams> params)
[email protected]f6af7592014-02-28 10:09:11187 : frame_(frame),
sandersd50a635e2016-04-04 22:50:09188 delegate_state_(DelegateState::GONE),
sandersd35d2c3f2017-01-14 02:04:42189 delegate_has_audio_(false),
Blink Reformat1c4d759e2017-04-09 16:34:54190 network_state_(WebMediaPlayer::kNetworkStateEmpty),
191 ready_state_(WebMediaPlayer::kReadyStateHaveNothing),
192 highest_ready_state_(WebMediaPlayer::kReadyStateHaveNothing),
dalecurtisb6e052f52016-08-25 00:35:55193 preload_(MultibufferDataSource::AUTO),
Blink Reformat1c4d759e2017-04-09 16:34:54194 main_task_runner_(frame->LoadingTaskRunner()),
dalecurtis9cddc0b2017-04-19 21:23:38195 media_task_runner_(params->media_task_runner()),
196 worker_task_runner_(params->worker_task_runner()),
197 media_log_(params->take_media_log()),
sandersd1c0bba02016-03-04 23:14:08198 pipeline_controller_(
tguilbert350936ff2017-02-24 05:39:27199 base::MakeUnique<PipelineImpl>(media_task_runner_, media_log_.get()),
sandersd1c0bba02016-03-04 23:14:08200 base::Bind(&WebMediaPlayerImpl::CreateRenderer,
201 base::Unretained(this)),
202 base::Bind(&WebMediaPlayerImpl::OnPipelineSeeked, AsWeakPtr()),
203 base::Bind(&WebMediaPlayerImpl::OnPipelineSuspended, AsWeakPtr()),
avayvod2135a642017-01-13 00:17:14204 base::Bind(&WebMediaPlayerImpl::OnBeforePipelineResume, AsWeakPtr()),
205 base::Bind(&WebMediaPlayerImpl::OnPipelineResumed, AsWeakPtr()),
alokp967c902452016-05-06 05:21:37206 base::Bind(&WebMediaPlayerImpl::OnError, AsWeakPtr())),
Blink Reformat1c4d759e2017-04-09 16:34:54207 load_type_(kLoadTypeURL),
[email protected]75e145a2014-04-15 17:44:32208 opaque_(false),
wolenetz1b2ae7d2015-06-10 00:44:21209 playback_rate_(0.0),
[email protected]49480902009-07-14 20:23:43210 paused_(true),
avayvodeb9098d2017-01-07 00:33:03211 paused_when_hidden_(false),
[email protected]b3766a22010-12-22 17:34:13212 seeking_(false),
watkdee516f2016-02-18 02:22:19213 pending_suspend_resume_cycle_(false),
scherkusd2c745b2014-09-04 05:03:40214 ended_(false),
yoichio863bebf2016-03-04 07:56:58215 should_notify_time_changed_(false),
tsunghungee562e92016-07-20 18:03:31216 overlay_enabled_(false),
217 decoder_requires_restart_for_overlay_(false),
[email protected]5badb082010-06-11 17:40:15218 client_(client),
srirama.m26f864d02015-07-14 05:21:46219 encrypted_client_(encrypted_client),
[email protected]baff4512011-10-19 18:21:07220 delegate_(delegate),
dalecurtisbb3eaac2016-01-27 21:10:25221 delegate_id_(0),
dalecurtis9cddc0b2017-04-19 21:23:38222 defer_load_cb_(params->defer_load_cb()),
223 context_3d_cb_(params->context_3d_cb()),
224 adjust_allocated_memory_cb_(params->adjust_allocated_memory_cb()),
dalecurtis83266c72015-10-29 18:43:20225 last_reported_memory_usage_(0),
[email protected]132dd57c2012-08-10 23:24:34226 supports_save_(true),
[email protected]f5443ef72013-04-22 04:03:38227 chunk_demuxer_(NULL),
hubbeb2d3efd2017-05-05 23:26:38228 tick_clock_(new base::DefaultTickClock()),
229 buffered_data_source_host_(
230 base::Bind(&WebMediaPlayerImpl::OnProgress, AsWeakPtr()),
231 tick_clock_.get()),
hubbe5f0ad43b2015-12-14 20:57:26232 url_index_(url_index),
Bartosz Fabianowski85a823812015-04-16 10:27:51233 // Threaded compositing isn't enabled universally yet.
dalecurtis9cddc0b2017-04-19 21:23:38234 compositor_task_runner_(params->compositor_task_runner()
235 ? params->compositor_task_runner()
fdoraydb3ef7d2016-06-09 15:42:38236 : base::ThreadTaskRunnerHandle::Get()),
alokp5d86e9b2016-05-17 20:20:41237 compositor_(new VideoFrameCompositor(compositor_task_runner_)),
hubbed5f36882016-01-15 22:40:37238#if defined(OS_ANDROID) // WMPI_CAST
dalecurtis9cddc0b2017-04-19 21:23:38239 cast_impl_(this, client_, params->context_3d_cb()),
hubbed5f36882016-01-15 22:40:37240#endif
dalecurtisbb3eaac2016-01-27 21:10:25241 volume_(1.0),
242 volume_multiplier_(1.0),
tguilbert70d2a00a2017-04-25 00:30:44243 renderer_factory_selector_(std::move(renderer_factory_selector)),
dalecurtis9cddc0b2017-04-19 21:23:38244 surface_manager_(params->surface_manager()),
tsunghungee562e92016-07-20 18:03:31245 overlay_surface_id_(SurfaceManager::kNoSurfaceID),
dalecurtis7f366b2242016-04-13 01:16:17246 suppress_destruction_errors_(false),
dalecurtis9d638a12016-08-30 06:20:55247 is_encrypted_(false),
sandersd35d2c3f2017-01-14 02:04:42248 preroll_attempt_pending_(false),
dalecurtis9cddc0b2017-04-19 21:23:38249 observer_(params->media_observer()),
avayvod590011e32017-01-20 02:01:00250 max_keyframe_distance_to_disable_background_video_(
dalecurtis9cddc0b2017-04-19 21:23:38251 params->max_keyframe_distance_to_disable_background_video()),
avayvode85ec422017-04-14 00:11:33252 max_keyframe_distance_to_disable_background_video_mse_(
dalecurtis9cddc0b2017-04-19 21:23:38253 params->max_keyframe_distance_to_disable_background_video_mse()),
servolkf94b4602017-01-31 16:44:27254 enable_instant_source_buffer_gc_(
dalecurtis9cddc0b2017-04-19 21:23:38255 params->enable_instant_source_buffer_gc()),
shaktisahu24189c12017-03-11 17:42:55256 embedded_media_experience_enabled_(
liberato2ff93ad2017-05-17 07:28:24257 params->embedded_media_experience_enabled()),
lethalantidote7f6009d2017-07-07 21:47:39258 surface_layer_for_video_enabled_(
259 base::FeatureList::IsEnabled(media::kUseSurfaceLayerForVideo)),
liberato2ff93ad2017-05-17 07:28:24260 request_routing_token_cb_(params->request_routing_token_cb()),
Dale Curtis1adbe6a2017-08-02 02:09:13261 overlay_routing_token_(OverlayInfo::RoutingToken()),
262 watch_time_recorder_provider_(params->watch_time_recorder_provider()) {
xhwang51139732017-02-24 19:36:08263 DVLOG(1) << __func__;
dalecurtis83266c72015-10-29 18:43:20264 DCHECK(!adjust_allocated_memory_cb_.is_null());
tguilbert70d2a00a2017-04-25 00:30:44265 DCHECK(renderer_factory_selector_);
servolkef1e5ef2016-03-25 04:55:26266 DCHECK(client_);
tguilbert1bb1c782017-01-23 21:15:11267 DCHECK(delegate_);
dalecurtis83266c72015-10-29 18:43:20268
lethalantidote7f6009d2017-07-07 21:47:39269 if (surface_layer_for_video_enabled_)
270 bridge_ = base::WrapUnique(blink::WebSurfaceLayerBridge::Create());
271
tsunghungee562e92016-07-20 18:03:31272 force_video_overlays_ = base::CommandLine::ForCurrentProcess()->HasSwitch(
273 switches::kForceVideoOverlays);
274
liberato2ff93ad2017-05-17 07:28:24275 if (base::FeatureList::IsEnabled(media::kOverlayFullscreenVideo)) {
276 bool use_android_overlay =
277 base::FeatureList::IsEnabled(media::kUseAndroidOverlay);
278 overlay_mode_ = use_android_overlay ? OverlayMode::kUseAndroidOverlay
279 : OverlayMode::kUseContentVideoView;
280 } else {
281 overlay_mode_ = OverlayMode::kNoOverlays;
282 }
ampea73f792017-01-19 04:05:39283
tguilbert1bb1c782017-01-23 21:15:11284 delegate_id_ = delegate_->AddObserver(this);
285 delegate_->SetIdle(delegate_id_, true);
sandersd1e49fb62015-12-12 01:18:06286
dalecurtis2cff7f372017-05-24 08:30:08287 media_log_->AddEvent(media_log_->CreateCreatedEvent(
288 url::Origin(frame_->GetSecurityOrigin()).GetURL().spec()));
sandersd72683f252017-07-07 23:20:46289 media_log_->SetStringProperty("frame_url",
290 frame_->GetDocument().Url().GetString().Utf8());
291 media_log_->SetStringProperty("frame_title",
292 frame_->GetDocument().Title().Utf8());
[email protected]4e6be3f2009-05-07 02:24:44293
dalecurtis9cddc0b2017-04-19 21:23:38294 if (params->initial_cdm())
295 SetCdm(params->initial_cdm());
xhwang0ad11e512014-11-25 23:43:09296
xhwangf94a634d2014-10-22 22:07:27297 // TODO(xhwang): When we use an external Renderer, many methods won't work,
xhwang6fa356202014-12-11 00:44:12298 // e.g. GetCurrentFrameFromCompositor(). See http://crbug.com/434861
dalecurtis9cddc0b2017-04-19 21:23:38299 audio_source_provider_ = new WebAudioSourceProviderImpl(
300 params->audio_renderer_sink(), media_log_.get());
xjz4e5d4bf32017-02-15 21:26:35301
302 if (observer_)
303 observer_->SetClient(this);
[email protected]ec9212f2008-12-18 21:40:36304}
305
[email protected]4e6be3f2009-05-07 02:24:44306WebMediaPlayerImpl::~WebMediaPlayerImpl() {
xhwang51139732017-02-24 19:36:08307 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:43308 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53309
xhwang51139732017-02-24 19:36:08310 if (set_cdm_result_) {
311 DVLOG(2) << "Resolve pending SetCdm() when media player is destroyed.";
Blink Reformat1c4d759e2017-04-09 16:34:54312 set_cdm_result_->Complete();
xhwang51139732017-02-24 19:36:08313 set_cdm_result_.reset();
314 }
315
alokp1116967f2016-06-11 17:30:56316 suppress_destruction_errors_ = true;
tguilbert1bb1c782017-01-23 21:15:11317
318 delegate_->PlayerGone(delegate_id_);
319 delegate_->RemoveObserver(delegate_id_);
[email protected]baff4512011-10-19 18:21:07320
dalecurtis04bdb582016-08-17 22:15:23321 // Finalize any watch time metrics before destroying the pipeline.
322 watch_time_reporter_.reset();
323
tguilbert350936ff2017-02-24 05:39:27324 // The underlying Pipeline must be stopped before it is destroyed.
325 pipeline_controller_.Stop();
[email protected]f6af7592014-02-28 10:09:11326
dalecurtis83266c72015-10-29 18:43:20327 if (last_reported_memory_usage_)
328 adjust_allocated_memory_cb_.Run(-last_reported_memory_usage_);
329
dalecurtise1edb312016-06-22 02:33:21330 // Destruct compositor resources in the proper order.
Blink Reformat1c4d759e2017-04-09 16:34:54331 client_->SetWebLayer(nullptr);
lethalantidote7f6009d2017-07-07 21:47:39332 if (!surface_layer_for_video_enabled_ && video_weblayer_) {
dalecurtise1edb312016-06-22 02:33:21333 static_cast<cc::VideoLayer*>(video_weblayer_->layer())->StopUsingProvider();
lethalantidote7f6009d2017-07-07 21:47:39334 }
335 // TODO(lethalantidote): Handle destruction of compositor for surface layer.
336 // https://crbug/739854.
[email protected]dd061e12014-05-06 19:21:22337 compositor_task_runner_->DeleteSoon(FROM_HERE, compositor_);
xhwangea8bb3562015-06-08 21:18:37338
339 media_log_->AddEvent(
340 media_log_->CreateEvent(MediaLogEvent::WEBMEDIAPLAYER_DESTROYED));
[email protected]ec9212f2008-12-18 21:40:36341}
342
Blink Reformat1c4d759e2017-04-09 16:34:54343void WebMediaPlayerImpl::Load(LoadType load_type,
guidou9bfe4e2f2016-04-09 08:31:19344 const blink::WebMediaPlayerSource& source,
[email protected]62e5e682013-03-07 23:53:24345 CORSMode cors_mode) {
xhwang51139732017-02-24 19:36:08346 DVLOG(1) << __func__;
guidou9bfe4e2f2016-04-09 08:31:19347 // Only URL or MSE blob URL is supported.
Blink Reformat1c4d759e2017-04-09 16:34:54348 DCHECK(source.IsURL());
349 blink::WebURL url = source.GetAsURL();
Xiaohan Wang81fd0022017-07-11 17:45:24350 DVLOG(1) << __func__ << "(" << load_type << ", " << GURL(url) << ", "
351 << cors_mode << ")";
[email protected]d726eddc2013-07-02 22:25:55352 if (!defer_load_cb_.is_null()) {
tguilbert350936ff2017-02-24 05:39:27353 defer_load_cb_.Run(base::Bind(&WebMediaPlayerImpl::DoLoad, AsWeakPtr(),
354 load_type, url, cors_mode));
[email protected]d726eddc2013-07-02 22:25:55355 return;
356 }
[email protected]ef8394c2013-08-21 20:26:30357 DoLoad(load_type, url, cors_mode);
[email protected]62e5e682013-03-07 23:53:24358}
359
Blink Reformat1c4d759e2017-04-09 16:34:54360bool WebMediaPlayerImpl::SupportsOverlayFullscreenVideo() {
watk9c87c6fa2016-05-06 20:36:51361#if defined(OS_ANDROID)
[email protected]68ec57f2017-06-27 22:10:05362 return !using_media_player_renderer_ &&
363 overlay_mode_ == OverlayMode::kUseContentVideoView;
watk9c87c6fa2016-05-06 20:36:51364#else
365 return false;
366#endif
367}
368
tsunghungee562e92016-07-20 18:03:31369void WebMediaPlayerImpl::EnableOverlay() {
370 overlay_enabled_ = true;
liberato2ff93ad2017-05-17 07:28:24371 if (surface_manager_ && overlay_mode_ == OverlayMode::kUseContentVideoView) {
liberatoe8e3f43d2017-05-01 22:23:11372 overlay_surface_id_.reset();
watkf835a792016-06-24 23:24:40373 surface_created_cb_.Reset(
374 base::Bind(&WebMediaPlayerImpl::OnSurfaceCreated, AsWeakPtr()));
375 surface_manager_->CreateFullscreenSurface(pipeline_metadata_.natural_size,
376 surface_created_cb_.callback());
liberato2ff93ad2017-05-17 07:28:24377 } else if (request_routing_token_cb_ &&
378 overlay_mode_ == OverlayMode::kUseAndroidOverlay) {
liberatofe8f9692017-06-08 19:17:36379 overlay_routing_token_is_pending_ = true;
liberato2ff93ad2017-05-17 07:28:24380 token_available_cb_.Reset(
381 base::Bind(&WebMediaPlayerImpl::OnOverlayRoutingToken, AsWeakPtr()));
382 request_routing_token_cb_.Run(token_available_cb_.callback());
watkf835a792016-06-24 23:24:40383 }
tsunghungee562e92016-07-20 18:03:31384
liberato2ff93ad2017-05-17 07:28:24385 // We have requested (and maybe already have) overlay information. If the
386 // restarted decoder requests overlay information, then we'll defer providing
387 // it if it hasn't arrived yet. Otherwise, this would be a race, since we
388 // don't know if the request for overlay info or restart will complete first.
tsunghungee562e92016-07-20 18:03:31389 if (decoder_requires_restart_for_overlay_)
watkdee516f2016-02-18 02:22:19390 ScheduleRestart();
391}
392
tsunghungee562e92016-07-20 18:03:31393void WebMediaPlayerImpl::DisableOverlay() {
394 overlay_enabled_ = false;
liberato2ff93ad2017-05-17 07:28:24395 if (overlay_mode_ == OverlayMode::kUseContentVideoView) {
396 surface_created_cb_.Cancel();
397 overlay_surface_id_ = SurfaceManager::kNoSurfaceID;
398 } else if (overlay_mode_ == OverlayMode::kUseAndroidOverlay) {
399 token_available_cb_.Cancel();
liberatofe8f9692017-06-08 19:17:36400 overlay_routing_token_is_pending_ = false;
401 overlay_routing_token_ = OverlayInfo::RoutingToken();
liberato2ff93ad2017-05-17 07:28:24402 }
tsunghungee562e92016-07-20 18:03:31403
404 if (decoder_requires_restart_for_overlay_)
watkdee516f2016-02-18 02:22:19405 ScheduleRestart();
liberato2ff93ad2017-05-17 07:28:24406 else
407 MaybeSendOverlayInfoToDecoder();
watkdee516f2016-02-18 02:22:19408}
409
Blink Reformat1c4d759e2017-04-09 16:34:54410void WebMediaPlayerImpl::EnteredFullscreen() {
liberatofe8f9692017-06-08 19:17:36411 overlay_info_.is_fullscreen = true;
412
liberato2fd111be2017-01-04 00:25:06413 // |force_video_overlays_| implies that we're already in overlay mode, so take
414 // no action here. Otherwise, switch to an overlay if it's allowed and if
415 // it will display properly.
liberato2ff93ad2017-05-17 07:28:24416 if (!force_video_overlays_ && overlay_mode_ != OverlayMode::kNoOverlays &&
liberato2fd111be2017-01-04 00:25:06417 DoesOverlaySupportMetadata()) {
tsunghungee562e92016-07-20 18:03:31418 EnableOverlay();
liberato2fd111be2017-01-04 00:25:06419 }
liberato2ff93ad2017-05-17 07:28:24420
liberatofe8f9692017-06-08 19:17:36421 // We send this only if we can send multiple calls. Otherwise, either (a)
422 // we already sent it and we don't have a callback anyway (we reset it when
423 // it's called in restart mode), or (b) we'll send this later when the surface
424 // actually arrives. GVD assumes that the first overlay info will have the
425 // routing information. Note that we set |is_fullscreen_| earlier, so that
426 // if EnableOverlay() can include fullscreen info in case it sends the overlay
427 // info before returning.
428 if (!decoder_requires_restart_for_overlay_)
429 MaybeSendOverlayInfoToDecoder();
tsunghungee562e92016-07-20 18:03:31430}
431
Blink Reformat1c4d759e2017-04-09 16:34:54432void WebMediaPlayerImpl::ExitedFullscreen() {
liberatofe8f9692017-06-08 19:17:36433 overlay_info_.is_fullscreen = false;
434
liberato2fd111be2017-01-04 00:25:06435 // If we're in overlay mode, then exit it unless we're supposed to be in
436 // overlay mode all the time.
437 if (!force_video_overlays_ && overlay_enabled_)
tsunghungee562e92016-07-20 18:03:31438 DisableOverlay();
liberato2ff93ad2017-05-17 07:28:24439
liberatofe8f9692017-06-08 19:17:36440 // See EnteredFullscreen for why we do this.
441 if (!decoder_requires_restart_for_overlay_)
442 MaybeSendOverlayInfoToDecoder();
tsunghungee562e92016-07-20 18:03:31443}
444
Blink Reformat1c4d759e2017-04-09 16:34:54445void WebMediaPlayerImpl::BecameDominantVisibleContent(bool isDominant) {
xjzcdbbe732016-12-03 20:47:42446 if (observer_)
447 observer_->OnBecameDominantVisibleContent(isDominant);
448}
449
Blink Reformat1c4d759e2017-04-09 16:34:54450void WebMediaPlayerImpl::SetIsEffectivelyFullscreen(
zqzhangabc08242017-03-02 16:07:14451 bool isEffectivelyFullscreen) {
452 delegate_->SetIsEffectivelyFullscreen(delegate_id_, isEffectivelyFullscreen);
453}
454
Mounir Lamouri41a79c62017-06-06 12:53:16455void WebMediaPlayerImpl::OnHasNativeControlsChanged(bool has_native_controls) {
456 if (!watch_time_reporter_)
457 return;
458
459 if (has_native_controls)
460 watch_time_reporter_->OnNativeControlsEnabled();
461 else
462 watch_time_reporter_->OnNativeControlsDisabled();
463}
464
Mounir Lamourif9af74e72017-06-19 19:31:45465void WebMediaPlayerImpl::OnDisplayTypeChanged(
466 WebMediaPlayer::DisplayType display_type) {
467 if (!watch_time_reporter_)
468 return;
469
470 switch (display_type) {
471 case WebMediaPlayer::DisplayType::kInline:
472 watch_time_reporter_->OnDisplayTypeInline();
473 break;
474 case WebMediaPlayer::DisplayType::kFullscreen:
475 watch_time_reporter_->OnDisplayTypeFullscreen();
476 break;
477 case WebMediaPlayer::DisplayType::kPictureInPicture:
478 watch_time_reporter_->OnDisplayTypePictureInPicture();
479 break;
480 }
481}
482
[email protected]ef8394c2013-08-21 20:26:30483void WebMediaPlayerImpl::DoLoad(LoadType load_type,
[email protected]180ef242013-11-07 06:50:46484 const blink::WebURL& url,
[email protected]d726eddc2013-07-02 22:25:55485 CORSMode cors_mode) {
pkastingf5279482016-07-27 02:18:20486 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:43487 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d726eddc2013-07-02 22:25:55488
[email protected]62e5e682013-03-07 23:53:24489 GURL gurl(url);
dalecurtis9cddc0b2017-04-19 21:23:38490 ReportMetrics(load_type, gurl, frame_->GetSecurityOrigin(), media_log_.get());
[email protected]62e5e682013-03-07 23:53:24491
[email protected]926f8fd2013-04-12 20:27:53492 // Set subresource URL for crash reporting.
493 base::debug::SetCrashKeyValue("subresource_url", gurl.spec());
494
tguilbert75e2bf62017-04-26 20:13:12495 // Used for HLS playback.
496 loaded_url_ = gurl;
tguilbert25a4d112016-10-13 21:56:51497
[email protected]ef8394c2013-08-21 20:26:30498 load_type_ = load_type;
499
Blink Reformat1c4d759e2017-04-09 16:34:54500 SetNetworkState(WebMediaPlayer::kNetworkStateLoading);
501 SetReadyState(WebMediaPlayer::kReadyStateHaveNothing);
502 media_log_->AddEvent(media_log_->CreateLoadEvent(url.GetString().Utf8()));
[email protected]d726eddc2013-07-02 22:25:55503
504 // Media source pipelines can start immediately.
Blink Reformat1c4d759e2017-04-09 16:34:54505 if (load_type == kLoadTypeMediaSource) {
[email protected]d726eddc2013-07-02 22:25:55506 supports_save_ = false;
[email protected]ef8394c2013-08-21 20:26:30507 StartPipeline();
hubbe5f0ad43b2015-12-14 20:57:26508 } else {
dalecurtisb6e052f52016-08-25 00:35:55509 data_source_.reset(new MultibufferDataSource(
Alok Priyadarshib8f30542017-07-22 00:16:25510 main_task_runner_,
511 url_index_->GetByUrl(url, static_cast<UrlData::CORSMode>(cors_mode)),
512 media_log_.get(), &buffered_data_source_host_,
dalecurtisb6e052f52016-08-25 00:35:55513 base::Bind(&WebMediaPlayerImpl::NotifyDownloading, AsWeakPtr())));
avayvode46d7bef2016-03-30 23:18:26514 data_source_->SetPreload(preload_);
avayvode46d7bef2016-03-30 23:18:26515 data_source_->Initialize(
516 base::Bind(&WebMediaPlayerImpl::DataSourceInitialized, AsWeakPtr()));
hubbe5f0ad43b2015-12-14 20:57:26517 }
hubbed5f36882016-01-15 22:40:37518
519#if defined(OS_ANDROID) // WMPI_CAST
dalecurtisbb3eaac2016-01-27 21:10:25520 cast_impl_.Initialize(url, frame_, delegate_id_);
hubbed5f36882016-01-15 22:40:37521#endif
[email protected]62e5e682013-03-07 23:53:24522}
523
Blink Reformat1c4d759e2017-04-09 16:34:54524void WebMediaPlayerImpl::Play() {
pkastingf5279482016-07-27 02:18:20525 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:43526 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53527
avayvod65fad272017-02-24 01:00:48528 // User initiated play unlocks background video playback.
Blink Reformat1c4d759e2017-04-09 16:34:54529 if (blink::WebUserGestureIndicator::IsProcessingUserGesture())
avayvod65fad272017-02-24 01:00:48530 video_locked_when_paused_when_hidden_ = false;
531
hubbed5f36882016-01-15 22:40:37532#if defined(OS_ANDROID) // WMPI_CAST
Blink Reformat1c4d759e2017-04-09 16:34:54533 if (IsRemote()) {
dalecurtis6e2716d2016-01-21 04:49:15534 cast_impl_.play();
hubbed5f36882016-01-15 22:40:37535 return;
536 }
537#endif
sandersd35d2c3f2017-01-14 02:04:42538 // TODO(sandersd): Do we want to reset the idle timer here?
tguilbert1bb1c782017-01-23 21:15:11539 delegate_->SetIdle(delegate_id_, false);
[email protected]49480902009-07-14 20:23:43540 paused_ = false;
tguilbert350936ff2017-02-24 05:39:27541 pipeline_controller_.SetPlaybackRate(playback_rate_);
dalecurtis4619cd02016-09-22 21:39:10542 background_pause_timer_.Stop();
sandersd1c0bba02016-03-04 23:14:08543
[email protected]039b7542013-10-17 22:06:25544 if (data_source_)
545 data_source_->MediaIsPlaying();
[email protected]090f7312011-08-05 23:26:40546
xjz48a9cb72016-12-20 04:02:49547 if (observer_)
548 observer_->OnPlaying();
549
dalecurtis04bdb582016-08-17 22:15:23550 DCHECK(watch_time_reporter_);
551 watch_time_reporter_->OnPlaying();
acolwell9e0840d2014-09-06 19:01:32552 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PLAY));
sandersd50a635e2016-04-04 22:50:09553 UpdatePlayState();
[email protected]ec9212f2008-12-18 21:40:36554}
555
Blink Reformat1c4d759e2017-04-09 16:34:54556void WebMediaPlayerImpl::Pause() {
pkastingf5279482016-07-27 02:18:20557 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:43558 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53559
sandersd50a635e2016-04-04 22:50:09560 // We update the paused state even when casting, since we expect pause() to be
561 // called when casting begins, and when we exit casting we should end up in a
562 // paused state.
[email protected]49480902009-07-14 20:23:43563 paused_ = true;
hubbed5f36882016-01-15 22:40:37564
avayvodeb9098d2017-01-07 00:33:03565 // No longer paused because it was hidden.
566 paused_when_hidden_ = false;
567
avayvod65fad272017-02-24 01:00:48568 // User initiated pause locks background videos.
Blink Reformat1c4d759e2017-04-09 16:34:54569 if (blink::WebUserGestureIndicator::IsProcessingUserGesture())
avayvod65fad272017-02-24 01:00:48570 video_locked_when_paused_when_hidden_ = true;
571
hubbed5f36882016-01-15 22:40:37572#if defined(OS_ANDROID) // WMPI_CAST
Blink Reformat1c4d759e2017-04-09 16:34:54573 if (IsRemote()) {
dalecurtis6e2716d2016-01-21 04:49:15574 cast_impl_.pause();
hubbed5f36882016-01-15 22:40:37575 return;
576 }
577#endif
578
tguilbert350936ff2017-02-24 05:39:27579 pipeline_controller_.SetPlaybackRate(0.0);
sandersd1c0bba02016-03-04 23:14:08580
581 // pause() may be called after playback has ended and the HTMLMediaElement
582 // requires that currentTime() == duration() after ending. We want to ensure
583 // |paused_time_| matches currentTime() in this case or a future seek() may
584 // incorrectly discard what it thinks is a seek to the existing time.
tguilbert350936ff2017-02-24 05:39:27585 paused_time_ =
586 ended_ ? GetPipelineMediaDuration() : pipeline_controller_.GetMediaTime();
[email protected]090f7312011-08-05 23:26:40587
xjz48a9cb72016-12-20 04:02:49588 if (observer_)
589 observer_->OnPaused();
590
dalecurtis04bdb582016-08-17 22:15:23591 DCHECK(watch_time_reporter_);
592 watch_time_reporter_->OnPaused();
acolwell9e0840d2014-09-06 19:01:32593 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PAUSE));
avayvod2135a642017-01-13 00:17:14594
sandersd50a635e2016-04-04 22:50:09595 UpdatePlayState();
[email protected]ec9212f2008-12-18 21:40:36596}
597
Blink Reformat1c4d759e2017-04-09 16:34:54598bool WebMediaPlayerImpl::SupportsSave() const {
acolwellb4034942014-08-28 15:42:43599 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]132dd57c2012-08-10 23:24:34600 return supports_save_;
[email protected]574a1d62009-07-17 03:23:46601}
602
Blink Reformat1c4d759e2017-04-09 16:34:54603void WebMediaPlayerImpl::Seek(double seconds) {
pkastingf5279482016-07-27 02:18:20604 DVLOG(1) << __func__ << "(" << seconds << "s)";
acolwellb4034942014-08-28 15:42:43605 DCHECK(main_task_runner_->BelongsToCurrentThread());
servolk86b3d88fb2017-03-18 02:50:28606 media_log_->AddEvent(media_log_->CreateSeekEvent(seconds));
sandersd1c0bba02016-03-04 23:14:08607 DoSeek(base::TimeDelta::FromSecondsD(seconds), true);
608}
609
610void WebMediaPlayerImpl::DoSeek(base::TimeDelta time, bool time_updated) {
611 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53612
hubbed5f36882016-01-15 22:40:37613#if defined(OS_ANDROID) // WMPI_CAST
Blink Reformat1c4d759e2017-04-09 16:34:54614 if (IsRemote()) {
sandersd1c0bba02016-03-04 23:14:08615 cast_impl_.seek(time);
hubbed5f36882016-01-15 22:40:37616 return;
617 }
618#endif
619
srirama.mccf671812015-01-08 11:59:13620 ReadyState old_state = ready_state_;
Blink Reformat1c4d759e2017-04-09 16:34:54621 if (ready_state_ > WebMediaPlayer::kReadyStateHaveMetadata)
622 SetReadyState(WebMediaPlayer::kReadyStateHaveMetadata);
[email protected]1bb666802013-11-28 06:12:08623
sandersd1c0bba02016-03-04 23:14:08624 // When paused, we know exactly what the current time is and can elide seeks
625 // to it. However, there are two cases that are not elided:
626 // 1) When the pipeline state is not stable.
627 // In this case we just let |pipeline_controller_| decide what to do, as
628 // it has complete information.
629 // 2) For MSE.
630 // Because the buffers may have changed between seeks, MSE seeks are
631 // never elided.
632 if (paused_ && pipeline_controller_.IsStable() && paused_time_ == time &&
633 !chunk_demuxer_) {
634 // If the ready state was high enough before, we can indicate that the seek
635 // completed just by restoring it. Otherwise we will just wait for the real
636 // ready state change to eventually happen.
Blink Reformat1c4d759e2017-04-09 16:34:54637 if (old_state == kReadyStateHaveEnoughData) {
srirama.m8f4a37562014-12-13 08:16:18638 main_task_runner_->PostTask(
alokp967c902452016-05-06 05:21:37639 FROM_HERE, base::Bind(&WebMediaPlayerImpl::OnBufferingStateChange,
640 AsWeakPtr(), BUFFERING_HAVE_ENOUGH));
srirama.m36ab2682014-12-11 04:20:01641 }
sandersd1c0bba02016-03-04 23:14:08642 return;
srirama.m36ab2682014-12-11 04:20:01643 }
[email protected]44ff37c02009-10-24 01:03:03644
dalecurtis04bdb582016-08-17 22:15:23645 // Call this before setting |seeking_| so that the current media time can be
646 // recorded by the reporter.
647 if (watch_time_reporter_)
648 watch_time_reporter_->OnSeeking();
649
dalecurtis1af3c1a2017-04-11 00:53:49650 // Clear any new frame processed callbacks on seek; otherwise we'll end up
651 // logging a time long after the seek completes.
652 frame_time_report_cb_.Cancel();
653
sandersd35d2c3f2017-01-14 02:04:42654 // TODO(sandersd): Move |seeking_| to PipelineController.
655 // TODO(sandersd): Do we want to reset the idle timer here?
tguilbert1bb1c782017-01-23 21:15:11656 delegate_->SetIdle(delegate_id_, false);
sandersd50a635e2016-04-04 22:50:09657 ended_ = false;
[email protected]b3766a22010-12-22 17:34:13658 seeking_ = true;
sandersd1c0bba02016-03-04 23:14:08659 seek_time_ = time;
660 if (paused_)
661 paused_time_ = time;
662 pipeline_controller_.Seek(time, time_updated);
[email protected]b3766a22010-12-22 17:34:13663
sandersd50a635e2016-04-04 22:50:09664 // This needs to be called after Seek() so that if a resume is triggered, it
665 // is to the correct time.
666 UpdatePlayState();
[email protected]ec9212f2008-12-18 21:40:36667}
668
Blink Reformat1c4d759e2017-04-09 16:34:54669void WebMediaPlayerImpl::SetRate(double rate) {
pkastingf5279482016-07-27 02:18:20670 DVLOG(1) << __func__ << "(" << rate << ")";
acolwellb4034942014-08-28 15:42:43671 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53672
[email protected]378f0b72009-08-11 17:11:42673 // TODO(kylep): Remove when support for negatives is added. Also, modify the
674 // following checks so rewind uses reasonable values also.
[email protected]39bdde32013-04-17 17:44:20675 if (rate < 0.0)
[email protected]378f0b72009-08-11 17:11:42676 return;
677
678 // Limit rates to reasonable values by clamping.
[email protected]39bdde32013-04-17 17:44:20679 if (rate != 0.0) {
[email protected]378f0b72009-08-11 17:11:42680 if (rate < kMinRate)
681 rate = kMinRate;
682 else if (rate > kMaxRate)
683 rate = kMaxRate;
684 }
685
[email protected]49480902009-07-14 20:23:43686 playback_rate_ = rate;
687 if (!paused_) {
tguilbert350936ff2017-02-24 05:39:27688 pipeline_controller_.SetPlaybackRate(rate);
[email protected]039b7542013-10-17 22:06:25689 if (data_source_)
690 data_source_->MediaPlaybackRateChanged(rate);
[email protected]49480902009-07-14 20:23:43691 }
[email protected]ec9212f2008-12-18 21:40:36692}
693
Blink Reformat1c4d759e2017-04-09 16:34:54694void WebMediaPlayerImpl::SetVolume(double volume) {
pkastingf5279482016-07-27 02:18:20695 DVLOG(1) << __func__ << "(" << volume << ")";
acolwellb4034942014-08-28 15:42:43696 DCHECK(main_task_runner_->BelongsToCurrentThread());
dalecurtisbb3eaac2016-01-27 21:10:25697 volume_ = volume;
tguilbert350936ff2017-02-24 05:39:27698 pipeline_controller_.SetVolume(volume_ * volume_multiplier_);
dalecurtis04bdb582016-08-17 22:15:23699 if (watch_time_reporter_)
700 watch_time_reporter_->OnVolumeChange(volume);
Becca Hughes9f6fd4b82017-06-15 10:01:40701 delegate_->DidPlayerMutedStatusChange(delegate_id_, volume == 0.0);
mlamouri910111362016-11-04 11:28:24702
703 // The play state is updated because the player might have left the autoplay
704 // muted state.
705 UpdatePlayState();
[email protected]ec9212f2008-12-18 21:40:36706}
[email protected]f0a51fb52009-03-05 12:46:38707
Blink Reformat1c4d759e2017-04-09 16:34:54708void WebMediaPlayerImpl::SetSinkId(
guidouc7babef2015-10-22 00:42:35709 const blink::WebString& sink_id,
710 const blink::WebSecurityOrigin& security_origin,
711 blink::WebSetSinkIdCallbacks* web_callback) {
guidou69223ce2015-06-16 10:36:19712 DCHECK(main_task_runner_->BelongsToCurrentThread());
pkastingf5279482016-07-27 02:18:20713 DVLOG(1) << __func__;
guidouc7babef2015-10-22 00:42:35714
olka68b69392016-04-01 11:42:12715 media::OutputDeviceStatusCB callback =
716 media::ConvertToOutputDeviceStatusCB(web_callback);
guidouc7babef2015-10-22 00:42:35717 media_task_runner_->PostTask(
718 FROM_HERE,
719 base::Bind(&SetSinkIdOnMediaThread, audio_source_provider_,
Blink Reformat1c4d759e2017-04-09 16:34:54720 sink_id.Utf8(), static_cast<url::Origin>(security_origin),
guidouc7babef2015-10-22 00:42:35721 callback));
guidou69223ce2015-06-16 10:36:19722}
723
Blink Reformat1c4d759e2017-04-09 16:34:54724STATIC_ASSERT_ENUM(WebMediaPlayer::kPreloadNone, MultibufferDataSource::NONE);
725STATIC_ASSERT_ENUM(WebMediaPlayer::kPreloadMetaData,
dalecurtisb6e052f52016-08-25 00:35:55726 MultibufferDataSource::METADATA);
Blink Reformat1c4d759e2017-04-09 16:34:54727STATIC_ASSERT_ENUM(WebMediaPlayer::kPreloadAuto, MultibufferDataSource::AUTO);
[email protected]23a8b1d82011-04-05 16:28:20728
Blink Reformat1c4d759e2017-04-09 16:34:54729void WebMediaPlayerImpl::SetPreload(WebMediaPlayer::Preload preload) {
pkastingf5279482016-07-27 02:18:20730 DVLOG(1) << __func__ << "(" << preload << ")";
acolwellb4034942014-08-28 15:42:43731 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]4e6be3f2009-05-07 02:24:44732
dalecurtisb6e052f52016-08-25 00:35:55733 preload_ = static_cast<MultibufferDataSource::Preload>(preload);
[email protected]b49beeb2013-03-01 20:04:00734 if (data_source_)
[email protected]09c60222014-08-07 16:42:31735 data_source_->SetPreload(preload_);
[email protected]4e6be3f2009-05-07 02:24:44736}
737
Blink Reformat1c4d759e2017-04-09 16:34:54738bool WebMediaPlayerImpl::HasVideo() const {
acolwellb4034942014-08-28 15:42:43739 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53740
[email protected]b8877772014-03-26 20:17:15741 return pipeline_metadata_.has_video;
[email protected]d43ed912009-02-03 04:52:53742}
743
Blink Reformat1c4d759e2017-04-09 16:34:54744bool WebMediaPlayerImpl::HasAudio() const {
acolwellb4034942014-08-28 15:42:43745 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]fc367af2009-08-14 23:06:35746
[email protected]b8877772014-03-26 20:17:15747 return pipeline_metadata_.has_audio;
[email protected]fc367af2009-08-14 23:06:35748}
749
Blink Reformat1c4d759e2017-04-09 16:34:54750void WebMediaPlayerImpl::EnabledAudioTracksChanged(
servolkf25ceed2016-07-01 03:44:38751 const blink::WebVector<blink::WebMediaPlayer::TrackId>& enabledTrackIds) {
752 DCHECK(main_task_runner_->BelongsToCurrentThread());
753
754 std::ostringstream logstr;
755 std::vector<MediaTrack::Id> enabledMediaTrackIds;
756 for (const auto& blinkTrackId : enabledTrackIds) {
Blink Reformat1c4d759e2017-04-09 16:34:54757 MediaTrack::Id track_id = blinkTrackId.Utf8().data();
servolkf25ceed2016-07-01 03:44:38758 logstr << track_id << " ";
759 enabledMediaTrackIds.push_back(track_id);
760 }
dalecurtis9cddc0b2017-04-19 21:23:38761 MEDIA_LOG(INFO, media_log_.get())
762 << "Enabled audio tracks: [" << logstr.str() << "]";
tguilbert350936ff2017-02-24 05:39:27763 pipeline_controller_.OnEnabledAudioTracksChanged(enabledMediaTrackIds);
servolkf25ceed2016-07-01 03:44:38764}
765
Blink Reformat1c4d759e2017-04-09 16:34:54766void WebMediaPlayerImpl::SelectedVideoTrackChanged(
servolkf25ceed2016-07-01 03:44:38767 blink::WebMediaPlayer::TrackId* selectedTrackId) {
768 DCHECK(main_task_runner_->BelongsToCurrentThread());
769
servolk9bed6602017-02-24 01:20:11770 base::Optional<MediaTrack::Id> selected_video_track_id;
771 if (selectedTrackId && !video_track_disabled_)
Blink Reformat1c4d759e2017-04-09 16:34:54772 selected_video_track_id = MediaTrack::Id(selectedTrackId->Utf8().data());
dalecurtis9cddc0b2017-04-19 21:23:38773 MEDIA_LOG(INFO, media_log_.get())
774 << "Selected video track: [" << selected_video_track_id.value_or("")
775 << "]";
tguilbert350936ff2017-02-24 05:39:27776 pipeline_controller_.OnSelectedVideoTrackChanged(selected_video_track_id);
servolkf25ceed2016-07-01 03:44:38777}
778
Blink Reformat1c4d759e2017-04-09 16:34:54779bool WebMediaPlayerImpl::GetLastUploadedFrameInfo(unsigned* width,
kainino36eeff82017-03-30 00:55:30780 unsigned* height,
781 double* timestamp) {
782 *width = last_uploaded_frame_size_.width();
783 *height = last_uploaded_frame_size_.height();
784 *timestamp = last_uploaded_frame_timestamp_.InSecondsF();
785 return true;
786}
787
Blink Reformat1c4d759e2017-04-09 16:34:54788blink::WebSize WebMediaPlayerImpl::NaturalSize() const {
acolwellb4034942014-08-28 15:42:43789 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53790
[email protected]b8877772014-03-26 20:17:15791 return blink::WebSize(pipeline_metadata_.natural_size);
[email protected]d43ed912009-02-03 04:52:53792}
793
Jiajia Qin82acdc02017-07-31 09:55:14794blink::WebSize WebMediaPlayerImpl::VisibleRect() const {
795 DCHECK(main_task_runner_->BelongsToCurrentThread());
796 scoped_refptr<VideoFrame> video_frame = GetCurrentFrameFromCompositor();
797 if (!video_frame)
798 return blink::WebSize();
799
800 const gfx::Rect& visible_rect = video_frame->visible_rect();
801 return blink::WebSize(visible_rect.width(), visible_rect.height());
802}
803
Blink Reformat1c4d759e2017-04-09 16:34:54804bool WebMediaPlayerImpl::Paused() const {
acolwellb4034942014-08-28 15:42:43805 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53806
hubbed5f36882016-01-15 22:40:37807#if defined(OS_ANDROID) // WMPI_CAST
Blink Reformat1c4d759e2017-04-09 16:34:54808 if (IsRemote())
danakj4f1fd6a2017-01-06 21:15:17809 return cast_impl_.IsPaused();
hubbed5f36882016-01-15 22:40:37810#endif
sandersd50a635e2016-04-04 22:50:09811
tguilbert350936ff2017-02-24 05:39:27812 return pipeline_controller_.GetPlaybackRate() == 0.0f;
[email protected]d43ed912009-02-03 04:52:53813}
814
Blink Reformat1c4d759e2017-04-09 16:34:54815bool WebMediaPlayerImpl::Seeking() const {
acolwellb4034942014-08-28 15:42:43816 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53817
Blink Reformat1c4d759e2017-04-09 16:34:54818 if (ready_state_ == WebMediaPlayer::kReadyStateHaveNothing)
[email protected]0acebfa2009-08-21 22:45:40819 return false;
[email protected]67cd5052009-09-10 21:53:22820
[email protected]b3766a22010-12-22 17:34:13821 return seeking_;
[email protected]ec9212f2008-12-18 21:40:36822}
823
Blink Reformat1c4d759e2017-04-09 16:34:54824double WebMediaPlayerImpl::Duration() const {
acolwellb4034942014-08-28 15:42:43825 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]39bdde32013-04-17 17:44:20826
Blink Reformat1c4d759e2017-04-09 16:34:54827 if (ready_state_ == WebMediaPlayer::kReadyStateHaveNothing)
[email protected]39bdde32013-04-17 17:44:20828 return std::numeric_limits<double>::quiet_NaN();
829
chcunninghamb92d5062017-01-10 21:50:22830 // Use duration from ChunkDemuxer when present. MSE allows users to specify
831 // duration as a double. This propagates to the rest of the pipeline as a
832 // TimeDelta with potentially reduced precision (limited to Microseconds).
833 // ChunkDemuxer returns the full-precision user-specified double. This ensures
834 // users can "get" the exact duration they "set".
835 if (chunk_demuxer_)
836 return chunk_demuxer_->GetDuration();
837
avayvodcc273dd2017-01-19 19:35:12838 base::TimeDelta pipeline_duration = GetPipelineMediaDuration();
chcunninghamb92d5062017-01-10 21:50:22839 return pipeline_duration == kInfiniteDuration
840 ? std::numeric_limits<double>::infinity()
841 : pipeline_duration.InSecondsF();
[email protected]d43ed912009-02-03 04:52:53842}
843
[email protected]db66d0092014-04-16 07:15:12844double WebMediaPlayerImpl::timelineOffset() const {
acolwellb4034942014-08-28 15:42:43845 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]db66d0092014-04-16 07:15:12846
847 if (pipeline_metadata_.timeline_offset.is_null())
848 return std::numeric_limits<double>::quiet_NaN();
849
850 return pipeline_metadata_.timeline_offset.ToJsTime();
851}
852
Blink Reformat1c4d759e2017-04-09 16:34:54853double WebMediaPlayerImpl::CurrentTime() const {
acolwellb4034942014-08-28 15:42:43854 DCHECK(main_task_runner_->BelongsToCurrentThread());
Blink Reformat1c4d759e2017-04-09 16:34:54855 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
scherkusd2c745b2014-09-04 05:03:40856
857 // TODO(scherkus): Replace with an explicit ended signal to HTMLMediaElement,
858 // see http://crbug.com/409280
859 if (ended_)
Blink Reformat1c4d759e2017-04-09 16:34:54860 return Duration();
scherkusd2c745b2014-09-04 05:03:40861
Blink Reformat1c4d759e2017-04-09 16:34:54862 if (Seeking())
sandersd1c0bba02016-03-04 23:14:08863 return seek_time_.InSecondsF();
wolenetz1b2ae7d2015-06-10 00:44:21864
hubbed5f36882016-01-15 22:40:37865#if defined(OS_ANDROID) // WMPI_CAST
Blink Reformat1c4d759e2017-04-09 16:34:54866 if (IsRemote())
hubbed5f36882016-01-15 22:40:37867 return cast_impl_.currentTime();
hubbed5f36882016-01-15 22:40:37868#endif
869
sandersd1c0bba02016-03-04 23:14:08870 if (paused_)
hubbed5f36882016-01-15 22:40:37871 return paused_time_.InSecondsF();
hubbed5f36882016-01-15 22:40:37872
tguilbert350936ff2017-02-24 05:39:27873 return pipeline_controller_.GetMediaTime().InSecondsF();
[email protected]d43ed912009-02-03 04:52:53874}
875
Blink Reformat1c4d759e2017-04-09 16:34:54876WebMediaPlayer::NetworkState WebMediaPlayerImpl::GetNetworkState() const {
acolwellb4034942014-08-28 15:42:43877 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]ddb1e5a2010-12-13 20:10:45878 return network_state_;
879}
880
Blink Reformat1c4d759e2017-04-09 16:34:54881WebMediaPlayer::ReadyState WebMediaPlayerImpl::GetReadyState() const {
acolwellb4034942014-08-28 15:42:43882 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]ddb1e5a2010-12-13 20:10:45883 return ready_state_;
884}
885
wolenetzed8e7092017-04-21 16:28:59886blink::WebString WebMediaPlayerImpl::GetErrorMessage() const {
wolenetz4d39cc02016-04-05 19:54:41887 DCHECK(main_task_runner_->BelongsToCurrentThread());
wolenetzed8e7092017-04-21 16:28:59888 return blink::WebString::FromUTF8(media_log_->GetErrorMessage());
wolenetz4d39cc02016-04-05 19:54:41889}
890
Blink Reformat1c4d759e2017-04-09 16:34:54891blink::WebTimeRanges WebMediaPlayerImpl::Buffered() const {
acolwellb4034942014-08-28 15:42:43892 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]779a8322014-08-22 21:28:37893
acolwell9e0840d2014-09-06 19:01:32894 Ranges<base::TimeDelta> buffered_time_ranges =
tguilbert350936ff2017-02-24 05:39:27895 pipeline_controller_.GetBufferedTimeRanges();
[email protected]779a8322014-08-22 21:28:37896
avayvodcc273dd2017-01-19 19:35:12897 const base::TimeDelta duration = GetPipelineMediaDuration();
dalecurtis39a7f932016-07-19 18:34:59898 if (duration != kInfiniteDuration) {
tguilbert350936ff2017-02-24 05:39:27899 buffered_data_source_host_.AddBufferedTimeRanges(&buffered_time_ranges,
900 duration);
[email protected]779a8322014-08-22 21:28:37901 }
[email protected]02022fc2014-05-16 00:05:31902 return ConvertToWebTimeRanges(buffered_time_ranges);
903}
904
Blink Reformat1c4d759e2017-04-09 16:34:54905blink::WebTimeRanges WebMediaPlayerImpl::Seekable() const {
acolwellb4034942014-08-28 15:42:43906 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]39bdde32013-04-17 17:44:20907
Blink Reformat1c4d759e2017-04-09 16:34:54908 if (ready_state_ < WebMediaPlayer::kReadyStateHaveMetadata)
philipjb0e6f3f2014-09-30 09:51:53909 return blink::WebTimeRanges();
910
Blink Reformat1c4d759e2017-04-09 16:34:54911 const double seekable_end = Duration();
dalecurtis56359cb2014-10-28 00:06:29912
913 // Allow a special exception for seeks to zero for streaming sources with a
914 // finite duration; this allows looping to work.
tguilbertade2bcb2017-01-07 02:57:45915 const bool is_finite_stream = data_source_ && data_source_->IsStreaming() &&
916 std::isfinite(seekable_end);
917
tguilbert75e2bf62017-04-26 20:13:12918 // Do not change the seekable range when using the MediaPlayerRenderer. It
919 // will take care of dropping invalid seeks.
920 const bool force_seeks_to_zero =
921 !using_media_player_renderer_ && is_finite_stream;
dalecurtis56359cb2014-10-28 00:06:29922
923 // TODO(dalecurtis): Technically this allows seeking on media which return an
tguilbertade2bcb2017-01-07 02:57:45924 // infinite duration so long as DataSource::IsStreaming() is false. While not
dalecurtis56359cb2014-10-28 00:06:29925 // expected, disabling this breaks semi-live players, http://crbug.com/427412.
926 const blink::WebTimeRange seekable_range(
tguilbertade2bcb2017-01-07 02:57:45927 0.0, force_seeks_to_zero ? 0.0 : seekable_end);
philipjb0e6f3f2014-09-30 09:51:53928 return blink::WebTimeRanges(&seekable_range, 1);
[email protected]ec9212f2008-12-18 21:40:36929}
930
sandersd35d2c3f2017-01-14 02:04:42931bool WebMediaPlayerImpl::IsPrerollAttemptNeeded() {
932 // TODO(sandersd): Replace with |highest_ready_state_since_seek_| if we need
933 // to ensure that preroll always gets a chance to complete.
934 // See http://crbug.com/671525.
Blink Reformat1c4d759e2017-04-09 16:34:54935 if (highest_ready_state_ >= ReadyState::kReadyStateHaveFutureData)
sandersd35d2c3f2017-01-14 02:04:42936 return false;
937
938 if (preroll_attempt_pending_)
939 return true;
940
941 // Freshly initialized; there has never been any loading progress. (Otherwise
942 // |preroll_attempt_pending_| would be true when the start time is null.)
943 if (preroll_attempt_start_time_.is_null())
944 return false;
945
946 base::TimeDelta preroll_attempt_duration =
947 tick_clock_->NowTicks() - preroll_attempt_start_time_;
948 return preroll_attempt_duration < kPrerollAttemptTimeout;
949}
950
Blink Reformat1c4d759e2017-04-09 16:34:54951bool WebMediaPlayerImpl::DidLoadingProgress() {
acolwellb4034942014-08-28 15:42:43952 DCHECK(main_task_runner_->BelongsToCurrentThread());
dalecurtise7120dc2016-09-03 02:54:35953
954 // Note: Separate variables used to ensure both methods are called every time.
tguilbert350936ff2017-02-24 05:39:27955 const bool pipeline_progress = pipeline_controller_.DidLoadingProgress();
dalecurtise7120dc2016-09-03 02:54:35956 const bool data_progress = buffered_data_source_host_.DidLoadingProgress();
hubbeb2d3efd2017-05-05 23:26:38957 return pipeline_progress || data_progress;
[email protected]d43ed912009-02-03 04:52:53958}
959
Blink Reformat1c4d759e2017-04-09 16:34:54960void WebMediaPlayerImpl::Paint(blink::WebCanvas* canvas,
[email protected]dd5c7972014-08-21 15:00:37961 const blink::WebRect& rect,
enne11266b82017-03-02 01:43:47962 cc::PaintFlags& flags) {
acolwellb4034942014-08-28 15:42:43963 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]dd061e12014-05-06 19:21:22964 TRACE_EVENT0("media", "WebMediaPlayerImpl:paint");
[email protected]4e6be3f2009-05-07 02:24:44965
watkd16bb3e2017-04-25 01:18:31966 // We can't copy from protected frames.
jrummelle616ee92016-10-08 02:15:44967 if (cdm_)
xhwang80739452016-01-13 00:48:00968 return;
969
mcasasf1236fc22015-05-29 22:38:56970 scoped_refptr<VideoFrame> video_frame = GetCurrentFrameFromCompositor();
[email protected]0fe5d43b2014-01-24 23:32:45971
[email protected]b49beeb2013-03-01 20:04:00972 gfx::Rect gfx_rect(rect);
dongseong.hwang0c4e9d82015-01-08 20:11:13973 Context3D context_3d;
mcasas265bdbf82015-06-12 18:44:07974 if (video_frame.get() && video_frame->HasTextures()) {
mcasasf1236fc22015-05-29 22:38:56975 if (!context_3d_cb_.is_null())
dongseong.hwang0c4e9d82015-01-08 20:11:13976 context_3d = context_3d_cb_.Run();
dongseong.hwang0c4e9d82015-01-08 20:11:13977 if (!context_3d.gl)
danakj53f7ec902016-05-21 01:30:10978 return; // Unable to get/create a shared main thread context.
979 if (!context_3d.gr_context)
980 return; // The context has been lost since and can't setup a GrContext.
dongseong.hwang0c4e9d82015-01-08 20:11:13981 }
danakj795f1732015-08-31 23:40:22982 skcanvas_video_renderer_.Paint(video_frame, canvas, gfx::RectF(gfx_rect),
enne11266b82017-03-02 01:43:47983 flags, pipeline_metadata_.video_rotation,
danakj795f1732015-08-31 23:40:22984 context_3d);
[email protected]ec9212f2008-12-18 21:40:36985}
[email protected]5df51652009-01-17 00:03:00986
Blink Reformat1c4d759e2017-04-09 16:34:54987bool WebMediaPlayerImpl::HasSingleSecurityOrigin() const {
[email protected]b49beeb2013-03-01 20:04:00988 if (data_source_)
989 return data_source_->HasSingleOrigin();
[email protected]fcdb7462009-10-21 21:05:11990 return true;
[email protected]38259a7a82009-07-29 21:49:49991}
992
Blink Reformat1c4d759e2017-04-09 16:34:54993bool WebMediaPlayerImpl::DidPassCORSAccessCheck() const {
[email protected]b49beeb2013-03-01 20:04:00994 if (data_source_)
995 return data_source_->DidPassCORSAccessCheck();
996 return false;
[email protected]3fe27112012-06-07 04:00:01997}
998
Blink Reformat1c4d759e2017-04-09 16:34:54999double WebMediaPlayerImpl::MediaTimeForTimeValue(double timeValue) const {
qinminb4c39782015-08-10 18:43:241000 return base::TimeDelta::FromSecondsD(timeValue).InSecondsF();
[email protected]e06e16d82011-05-26 22:13:331001}
1002
Blink Reformat1c4d759e2017-04-09 16:34:541003unsigned WebMediaPlayerImpl::DecodedFrameCount() const {
acolwellb4034942014-08-28 15:42:431004 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]4c51bc662011-02-16 02:03:161005
avayvodc4bfb0e62017-01-13 01:07:011006 PipelineStatistics stats = GetPipelineStatistics();
[email protected]4c51bc662011-02-16 02:03:161007 return stats.video_frames_decoded;
1008}
1009
Blink Reformat1c4d759e2017-04-09 16:34:541010unsigned WebMediaPlayerImpl::DroppedFrameCount() const {
acolwellb4034942014-08-28 15:42:431011 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]4c51bc662011-02-16 02:03:161012
avayvodc4bfb0e62017-01-13 01:07:011013 PipelineStatistics stats = GetPipelineStatistics();
[email protected]dd061e12014-05-06 19:21:221014 return stats.video_frames_dropped;
[email protected]4c51bc662011-02-16 02:03:161015}
1016
Blink Reformat1c4d759e2017-04-09 16:34:541017size_t WebMediaPlayerImpl::AudioDecodedByteCount() const {
acolwellb4034942014-08-28 15:42:431018 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]4c51bc662011-02-16 02:03:161019
avayvodc4bfb0e62017-01-13 01:07:011020 PipelineStatistics stats = GetPipelineStatistics();
[email protected]4c51bc662011-02-16 02:03:161021 return stats.audio_bytes_decoded;
1022}
1023
Blink Reformat1c4d759e2017-04-09 16:34:541024size_t WebMediaPlayerImpl::VideoDecodedByteCount() const {
acolwellb4034942014-08-28 15:42:431025 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]4c51bc662011-02-16 02:03:161026
avayvodc4bfb0e62017-01-13 01:07:011027 PipelineStatistics stats = GetPipelineStatistics();
[email protected]4c51bc662011-02-16 02:03:161028 return stats.video_bytes_decoded;
1029}
1030
Blink Reformat1c4d759e2017-04-09 16:34:541031bool WebMediaPlayerImpl::CopyVideoTextureToPlatformTexture(
danakj46070b02016-03-28 21:54:111032 gpu::gles2::GLES2Interface* gl,
jiajia.qinc2943162017-05-12 01:34:391033 unsigned int target,
zmo57d577a2015-10-30 18:28:591034 unsigned int texture,
kbr0986e622017-04-13 02:34:581035 unsigned internal_format,
1036 unsigned format,
1037 unsigned type,
jiajia.qinc2943162017-05-12 01:34:391038 int level,
zmo57d577a2015-10-30 18:28:591039 bool premultiply_alpha,
1040 bool flip_y) {
xhwang213e50c2016-10-10 23:56:311041 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]bfc05f22013-10-19 17:55:161042 TRACE_EVENT0("media", "WebMediaPlayerImpl:copyVideoTextureToPlatformTexture");
1043
watkd16bb3e2017-04-25 01:18:311044 // We can't copy from protected frames.
xhwang213e50c2016-10-10 23:56:311045 if (cdm_)
1046 return false;
[email protected]dd061e12014-05-06 19:21:221047
xhwang213e50c2016-10-10 23:56:311048 scoped_refptr<VideoFrame> video_frame = GetCurrentFrameFromCompositor();
jbauman581d041c2016-07-21 01:01:031049 if (!video_frame.get() || !video_frame->HasTextures()) {
[email protected]e56f88c72013-06-25 22:31:291050 return false;
dongseong.hwang0c4e9d82015-01-08 20:11:131051 }
[email protected]df41e252014-02-03 23:39:501052
jbauman581d041c2016-07-21 01:01:031053 Context3D context_3d;
1054 if (!context_3d_cb_.is_null())
1055 context_3d = context_3d_cb_.Run();
1056 return skcanvas_video_renderer_.CopyVideoFrameTexturesToGLTexture(
jiajia.qinc2943162017-05-12 01:34:391057 context_3d, gl, video_frame.get(), target, texture, internal_format,
1058 format, type, level, premultiply_alpha, flip_y);
[email protected]6523b242013-03-13 11:10:071059}
1060
Blink Reformat1c4d759e2017-04-09 16:34:541061void WebMediaPlayerImpl::SetContentDecryptionModule(
[email protected]9ebc3b03f2014-08-13 04:01:231062 blink::WebContentDecryptionModule* cdm,
1063 blink::WebContentDecryptionModuleResult result) {
xhwang51139732017-02-24 19:36:081064 DVLOG(1) << __func__ << ": cdm = " << cdm;
acolwellb4034942014-08-28 15:42:431065 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]9ebc3b03f2014-08-13 04:01:231066
jrummell06f27072015-06-08 18:12:381067 // Once the CDM is set it can't be cleared as there may be frames being
1068 // decrypted on other threads. So fail this request.
1069 // http://crbug.com/462365#c7.
xhwang97de4202014-11-25 08:44:011070 if (!cdm) {
Blink Reformat1c4d759e2017-04-09 16:34:541071 result.CompleteWithError(
1072 blink::kWebContentDecryptionModuleExceptionInvalidStateError, 0,
xhwang79b193042016-12-13 18:52:431073 "The existing ContentDecryptionModule object cannot be removed at this "
1074 "time.");
xhwang97de4202014-11-25 08:44:011075 return;
1076 }
1077
jrummell89e61d82015-07-23 20:03:341078 // Create a local copy of |result| to avoid problems with the callback
1079 // getting passed to the media thread and causing |result| to be destructed
jrummell4acbec912016-02-27 02:45:031080 // on the wrong thread in some failure conditions. Blink should prevent
1081 // multiple simultaneous calls.
1082 DCHECK(!set_cdm_result_);
jrummell89e61d82015-07-23 20:03:341083 set_cdm_result_.reset(new blink::WebContentDecryptionModuleResult(result));
1084
dalecurtis04bdb582016-08-17 22:15:231085 // Recreate the watch time reporter if necessary.
1086 const bool was_encrypted = is_encrypted_;
1087 is_encrypted_ = true;
1088 if (!was_encrypted && watch_time_reporter_)
1089 CreateWatchTimeReporter();
1090
jrummelle616ee92016-10-08 02:15:441091 SetCdm(cdm);
xhwang97de4202014-11-25 08:44:011092}
1093
xhwange8c4181a2014-12-06 08:10:011094void WebMediaPlayerImpl::OnEncryptedMediaInitData(
jrummellcf78967c2015-04-03 05:03:581095 EmeInitDataType init_data_type,
Avi Drissman97785ea2015-12-19 01:11:311096 const std::vector<uint8_t>& init_data) {
jrummellcf78967c2015-04-03 05:03:581097 DCHECK(init_data_type != EmeInitDataType::UNKNOWN);
xhwangbab66f52014-12-02 23:49:501098
ddorwin301ccdb2016-02-25 02:39:171099 // TODO(xhwang): Update this UMA name. https://crbug.com/589251
xhwangbab66f52014-12-02 23:49:501100 UMA_HISTOGRAM_COUNTS("Media.EME.NeedKey", 1);
1101
dalecurtis04bdb582016-08-17 22:15:231102 // Recreate the watch time reporter if necessary.
1103 const bool was_encrypted = is_encrypted_;
1104 is_encrypted_ = true;
1105 if (!was_encrypted && watch_time_reporter_)
1106 CreateWatchTimeReporter();
1107
Blink Reformat1c4d759e2017-04-09 16:34:541108 encrypted_client_->Encrypted(
davidbenb50f00c2015-12-01 00:01:501109 ConvertToWebInitDataType(init_data_type), init_data.data(),
srirama.m26f864d02015-07-14 05:21:461110 base::saturated_cast<unsigned int>(init_data.size()));
xhwangbab66f52014-12-02 23:49:501111}
1112
servolk81e01e02016-03-05 03:29:151113void WebMediaPlayerImpl::OnFFmpegMediaTracksUpdated(
dcheng3076abbf2016-04-22 20:42:391114 std::unique_ptr<MediaTracks> tracks) {
servolk81e01e02016-03-05 03:29:151115 // For MSE/chunk_demuxer case the media track updates are handled by
1116 // WebSourceBufferImpl.
1117 DCHECK(demuxer_.get());
1118 DCHECK(!chunk_demuxer_);
servolkef1e5ef2016-03-25 04:55:261119
servolk16e8bdf82017-04-11 17:00:391120 // Report the media track information to blink. Only the first audio track and
1121 // the first video track are enabled by default to match blink logic.
1122 bool is_first_audio_track = true;
1123 bool is_first_video_track = true;
servolkef1e5ef2016-03-25 04:55:261124 for (const auto& track : tracks->tracks()) {
1125 if (track->type() == MediaTrack::Audio) {
Blink Reformat1c4d759e2017-04-09 16:34:541126 client_->AddAudioTrack(blink::WebString::FromUTF8(track->id()),
1127 blink::WebMediaPlayerClient::kAudioTrackKindMain,
1128 blink::WebString::FromUTF8(track->label()),
1129 blink::WebString::FromUTF8(track->language()),
servolk16e8bdf82017-04-11 17:00:391130 is_first_audio_track);
1131 is_first_audio_track = false;
servolkef1e5ef2016-03-25 04:55:261132 } else if (track->type() == MediaTrack::Video) {
Blink Reformat1c4d759e2017-04-09 16:34:541133 client_->AddVideoTrack(blink::WebString::FromUTF8(track->id()),
1134 blink::WebMediaPlayerClient::kVideoTrackKindMain,
1135 blink::WebString::FromUTF8(track->label()),
1136 blink::WebString::FromUTF8(track->language()),
servolk16e8bdf82017-04-11 17:00:391137 is_first_video_track);
1138 is_first_video_track = false;
servolkef1e5ef2016-03-25 04:55:261139 } else {
1140 // Text tracks are not supported through this code path yet.
1141 NOTREACHED();
1142 }
1143 }
servolk81e01e02016-03-05 03:29:151144}
1145
jrummelle616ee92016-10-08 02:15:441146void WebMediaPlayerImpl::SetCdm(blink::WebContentDecryptionModule* cdm) {
1147 DCHECK(main_task_runner_->BelongsToCurrentThread());
1148 DCHECK(cdm);
xhwang79b193042016-12-13 18:52:431149 scoped_refptr<ContentDecryptionModule> cdm_reference =
jrummelle616ee92016-10-08 02:15:441150 ToWebContentDecryptionModuleImpl(cdm)->GetCdm();
1151 if (!cdm_reference) {
1152 NOTREACHED();
1153 OnCdmAttached(false);
xhwang80739452016-01-13 00:48:001154 return;
1155 }
1156
jrummelle616ee92016-10-08 02:15:441157 CdmContext* cdm_context = cdm_reference->GetCdmContext();
1158 if (!cdm_context) {
1159 OnCdmAttached(false);
1160 return;
1161 }
1162
xjzd3fe45a2016-10-12 18:26:371163 if (observer_)
1164 observer_->OnSetCdm(cdm_context);
1165
jrummelle616ee92016-10-08 02:15:441166 // Keep the reference to the CDM, as it shouldn't be destroyed until
1167 // after the pipeline is done with the |cdm_context|.
1168 pending_cdm_ = std::move(cdm_reference);
tguilbert350936ff2017-02-24 05:39:271169 pipeline_controller_.SetCdm(
1170 cdm_context, base::Bind(&WebMediaPlayerImpl::OnCdmAttached, AsWeakPtr()));
xhwang97de4202014-11-25 08:44:011171}
1172
jrummell89e61d82015-07-23 20:03:341173void WebMediaPlayerImpl::OnCdmAttached(bool success) {
xhwang51139732017-02-24 19:36:081174 DVLOG(1) << __func__ << ": success = " << success;
jrummelle616ee92016-10-08 02:15:441175 DCHECK(main_task_runner_->BelongsToCurrentThread());
1176 DCHECK(pending_cdm_);
1177
1178 // If the CDM is set from the constructor there is no promise
1179 // (|set_cdm_result_|) to fulfill.
xhwang97de4202014-11-25 08:44:011180 if (success) {
xhwang29c5ad202017-04-14 07:02:191181 media_log_->SetBooleanProperty("has_cdm", true);
1182
jrummelle616ee92016-10-08 02:15:441183 // This will release the previously attached CDM (if any).
1184 cdm_ = std::move(pending_cdm_);
1185 if (set_cdm_result_) {
Blink Reformat1c4d759e2017-04-09 16:34:541186 set_cdm_result_->Complete();
jrummelle616ee92016-10-08 02:15:441187 set_cdm_result_.reset();
1188 }
1189
xhwang97de4202014-11-25 08:44:011190 return;
1191 }
1192
jrummelle616ee92016-10-08 02:15:441193 pending_cdm_ = nullptr;
1194 if (set_cdm_result_) {
Blink Reformat1c4d759e2017-04-09 16:34:541195 set_cdm_result_->CompleteWithError(
1196 blink::kWebContentDecryptionModuleExceptionNotSupportedError, 0,
xhwang79b193042016-12-13 18:52:431197 "Unable to set ContentDecryptionModule object");
jrummelle616ee92016-10-08 02:15:441198 set_cdm_result_.reset();
1199 }
[email protected]9ebc3b03f2014-08-13 04:01:231200}
1201
sandersd1c0bba02016-03-04 23:14:081202void WebMediaPlayerImpl::OnPipelineSeeked(bool time_updated) {
[email protected]5d11eff2011-09-15 00:06:061203 seeking_ = false;
wolenetz1b2ae7d2015-06-10 00:44:211204 seek_time_ = base::TimeDelta();
avayvod2135a642017-01-13 00:17:141205
hubbe5a2dec022016-03-17 01:14:231206 if (paused_) {
1207#if defined(OS_ANDROID) // WMPI_CAST
Blink Reformat1c4d759e2017-04-09 16:34:541208 if (IsRemote()) {
hubbe5a2dec022016-03-17 01:14:231209 paused_time_ = base::TimeDelta::FromSecondsD(cast_impl_.currentTime());
1210 } else {
tguilbert350936ff2017-02-24 05:39:271211 paused_time_ = pipeline_controller_.GetMediaTime();
hubbe5a2dec022016-03-17 01:14:231212 }
1213#else
tguilbert350936ff2017-02-24 05:39:271214 paused_time_ = pipeline_controller_.GetMediaTime();
hubbe5a2dec022016-03-17 01:14:231215#endif
dalecurtis04bdb582016-08-17 22:15:231216 } else {
1217 DCHECK(watch_time_reporter_);
1218 watch_time_reporter_->OnPlaying();
hubbe5a2dec022016-03-17 01:14:231219 }
sandersd1c0bba02016-03-04 23:14:081220 if (time_updated)
1221 should_notify_time_changed_ = true;
dalecurtisaf34d8712016-09-20 04:32:261222
dalecurtis4f6d14d2017-02-22 17:42:221223 // Reset underflow duration upon seek; this prevents looping videos and user
1224 // actions from artificially inflating the duration.
1225 underflow_timer_.reset();
avayvod56e1f3942017-01-21 02:06:311226
1227 // Background video optimizations are delayed when shown/hidden if pipeline
1228 // is seeking.
1229 UpdateBackgroundVideoOptimizationState();
[email protected]8931c41a2009-07-07 17:31:491230}
1231
sandersd1c0bba02016-03-04 23:14:081232void WebMediaPlayerImpl::OnPipelineSuspended() {
hubbed5f36882016-01-15 22:40:371233#if defined(OS_ANDROID)
avayvod82729272017-05-29 21:58:391234 if (IsRemote() && !IsNewRemotePlaybackPipelineEnabled()) {
hubbed5f36882016-01-15 22:40:371235 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner();
sandersd50a635e2016-04-04 22:50:091236 if (frame)
dalecurtise9c89e92016-05-20 19:38:001237 compositor_->PaintSingleFrame(frame);
hubbed5f36882016-01-15 22:40:371238 }
1239#endif
1240
sandersd2f5bb6152017-03-29 22:57:531241 // Tell the data source we have enough data so that it may release the
1242 // connection.
1243 if (data_source_)
1244 data_source_->OnBufferingHaveEnough(true);
dalecurtis37fe5862016-03-15 19:29:091245
sandersd50a635e2016-04-04 22:50:091246 ReportMemoryUsage();
1247
sandersd1c0bba02016-03-04 23:14:081248 if (pending_suspend_resume_cycle_) {
watkdee516f2016-02-18 02:22:191249 pending_suspend_resume_cycle_ = false;
sandersd50a635e2016-04-04 22:50:091250 UpdatePlayState();
dalecurtis0431cbf2016-03-12 01:19:431251 }
sandersd1c0bba02016-03-04 23:14:081252}
1253
avayvod2135a642017-01-13 00:17:141254void WebMediaPlayerImpl::OnBeforePipelineResume() {
1255 // Enable video track if we disabled it in the background - this way the new
1256 // renderer will attach its callbacks to the video stream properly.
1257 // TODO(avayvod): Remove this when disabling and enabling video tracks in
1258 // non-playing state works correctly. See https://crbug.com/678374.
1259 EnableVideoTrackIfNeeded();
1260 is_pipeline_resuming_ = true;
1261}
1262
1263void WebMediaPlayerImpl::OnPipelineResumed() {
1264 is_pipeline_resuming_ = false;
1265
avayvod56e1f3942017-01-21 02:06:311266 UpdateBackgroundVideoOptimizationState();
avayvod2135a642017-01-13 00:17:141267}
1268
alokp967c902452016-05-06 05:21:371269void WebMediaPlayerImpl::OnDemuxerOpened() {
1270 DCHECK(main_task_runner_->BelongsToCurrentThread());
dalecurtis9cddc0b2017-04-19 21:23:381271 client_->MediaSourceOpened(new WebMediaSourceImpl(chunk_demuxer_));
alokp967c902452016-05-06 05:21:371272}
1273
servolkf94b4602017-01-31 16:44:271274void WebMediaPlayerImpl::OnMemoryPressure(
1275 base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
1276 DVLOG(2) << __func__ << " memory_pressure_level=" << memory_pressure_level;
1277 DCHECK(main_task_runner_->BelongsToCurrentThread());
1278 DCHECK(base::FeatureList::IsEnabled(kMemoryPressureBasedSourceBufferGC));
1279 DCHECK(chunk_demuxer_);
1280
1281 // The new value of |memory_pressure_level| will take effect on the next
1282 // garbage collection. Typically this means the next SourceBuffer append()
1283 // operation, since per MSE spec, the garbage collection must only occur
1284 // during SourceBuffer append(). But if memory pressure is critical it might
1285 // be better to perform GC immediately rather than wait for the next append
1286 // and potentially get killed due to out-of-memory.
1287 // So if this experiment is enabled and pressure level is critical, we'll pass
1288 // down force_instant_gc==true, which will force immediate GC on
1289 // SourceBufferStreams.
1290 bool force_instant_gc =
1291 (enable_instant_source_buffer_gc_ &&
1292 memory_pressure_level ==
1293 base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
1294
1295 // base::Unretained is safe, since chunk_demuxer_ is actually owned by
1296 // |this| via this->demuxer_.
1297 media_task_runner_->PostTask(
1298 FROM_HERE, base::Bind(&ChunkDemuxer::OnMemoryPressure,
1299 base::Unretained(chunk_demuxer_),
Blink Reformat1c4d759e2017-04-09 16:34:541300 base::TimeDelta::FromSecondsD(CurrentTime()),
servolkf94b4602017-01-31 16:44:271301 memory_pressure_level, force_instant_gc));
1302}
1303
alokp967c902452016-05-06 05:21:371304void WebMediaPlayerImpl::OnError(PipelineStatus status) {
pkastingf5279482016-07-27 02:18:201305 DVLOG(1) << __func__;
alokp967c902452016-05-06 05:21:371306 DCHECK(main_task_runner_->BelongsToCurrentThread());
1307 DCHECK_NE(status, PIPELINE_OK);
1308
1309 if (suppress_destruction_errors_)
1310 return;
1311
dalecurtis9cddc0b2017-04-19 21:23:381312 ReportPipelineError(load_type_, status, media_log_.get());
alokp967c902452016-05-06 05:21:371313 media_log_->AddEvent(media_log_->CreatePipelineErrorEvent(status));
1314
Blink Reformat1c4d759e2017-04-09 16:34:541315 if (ready_state_ == WebMediaPlayer::kReadyStateHaveNothing) {
alokp967c902452016-05-06 05:21:371316 // Any error that occurs before reaching ReadyStateHaveMetadata should
1317 // be considered a format error.
Blink Reformat1c4d759e2017-04-09 16:34:541318 SetNetworkState(WebMediaPlayer::kNetworkStateFormatError);
alokp967c902452016-05-06 05:21:371319 } else {
1320 SetNetworkState(PipelineErrorToNetworkState(status));
1321 }
1322
1323 UpdatePlayState();
1324}
1325
1326void WebMediaPlayerImpl::OnEnded() {
pkastingf5279482016-07-27 02:18:201327 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:431328 DCHECK(main_task_runner_->BelongsToCurrentThread());
scherkusd2c745b2014-09-04 05:03:401329
sandersd1c0bba02016-03-04 23:14:081330 // Ignore state changes until we've completed all outstanding operations.
1331 if (!pipeline_controller_.IsStable())
scherkusd2c745b2014-09-04 05:03:401332 return;
1333
1334 ended_ = true;
Blink Reformat1c4d759e2017-04-09 16:34:541335 client_->TimeChanged();
sandersd50a635e2016-04-04 22:50:091336
dalecurtis1af3c1a2017-04-11 00:53:491337 // Clear any new frame processed callbacks on end; otherwise we'll end up
1338 // logging a time long after playback ends.
1339 frame_time_report_cb_.Cancel();
1340
sandersd50a635e2016-04-04 22:50:091341 // We don't actually want this to run until |client_| calls seek() or pause(),
1342 // but that should have already happened in timeChanged() and so this is
1343 // expected to be a no-op.
1344 UpdatePlayState();
[email protected]576537842009-08-12 23:52:051345}
1346
alokp967c902452016-05-06 05:21:371347void WebMediaPlayerImpl::OnMetadata(PipelineMetadata metadata) {
pkastingf5279482016-07-27 02:18:201348 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:431349 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]a8e2cb82012-08-17 00:02:391350
[email protected]b8877772014-03-26 20:17:151351 pipeline_metadata_ = metadata;
[email protected]739847c02014-01-16 00:12:251352
Blink Reformat1c4d759e2017-04-09 16:34:541353 SetReadyState(WebMediaPlayer::kReadyStateHaveMetadata);
dalecurtis849cf4b22015-03-27 18:35:451354 UMA_HISTOGRAM_ENUMERATION("Media.VideoRotation", metadata.video_rotation,
acolwell9e0840d2014-09-06 19:01:321355 VIDEO_ROTATION_MAX + 1);
[email protected]21c3f7502013-03-23 03:29:511356
Blink Reformat1c4d759e2017-04-09 16:34:541357 if (HasVideo()) {
liberato2fd111be2017-01-04 00:25:061358 if (overlay_enabled_) {
1359 // SurfaceView doesn't support rotated video, so transition back if
1360 // the video is now rotated. If |force_video_overlays_|, we keep the
1361 // overlay anyway so that the state machine keeps working.
1362 if (!force_video_overlays_ && !DoesOverlaySupportMetadata())
1363 DisableOverlay();
1364 else if (surface_manager_)
1365 surface_manager_->NaturalSizeChanged(pipeline_metadata_.natural_size);
1366 }
watkf835a792016-06-24 23:24:401367
lethalantidote7f6009d2017-07-07 21:47:391368 if (!surface_layer_for_video_enabled_) {
1369 DCHECK(!video_weblayer_);
1370 video_weblayer_.reset(new cc_blink::WebLayerImpl(cc::VideoLayer::Create(
1371 compositor_, pipeline_metadata_.video_rotation)));
1372 video_weblayer_->layer()->SetContentsOpaque(opaque_);
1373 video_weblayer_->SetContentsOpaqueIsFixed(true);
1374 client_->SetWebLayer(video_weblayer_.get());
1375 } else if (bridge_->GetWebLayer()) {
1376 bridge_->GetWebLayer()->CcLayer()->SetContentsOpaque(opaque_);
1377 // TODO(lethalantidote): Figure out how to persist opaque setting
1378 // without calling WebLayerImpl's SetContentsOpaueIsFixed;
1379 // https://crbug/739859.
1380 client_->SetWebLayer(bridge_->GetWebLayer());
1381 }
[email protected]a8e2cb82012-08-17 00:02:391382 }
dalecurtis8e4dc682016-03-15 02:30:301383
xjzd3fe45a2016-10-12 18:26:371384 if (observer_)
xjz15b483f2017-01-12 00:21:361385 observer_->OnMetadataChanged(pipeline_metadata_);
xjzd3fe45a2016-10-12 18:26:371386
dalecurtis04bdb582016-08-17 22:15:231387 CreateWatchTimeReporter();
sandersd50a635e2016-04-04 22:50:091388 UpdatePlayState();
[email protected]a8e2cb82012-08-17 00:02:391389}
1390
hubbeb2d3efd2017-05-05 23:26:381391void WebMediaPlayerImpl::OnProgress() {
Chris Watkins1ffabc5f2017-05-10 20:52:091392 DVLOG(4) << __func__;
hubbeb2d3efd2017-05-05 23:26:381393 if (highest_ready_state_ < ReadyState::kReadyStateHaveFutureData) {
1394 // Reset the preroll attempt clock.
1395 preroll_attempt_pending_ = true;
1396 preroll_attempt_start_time_ = base::TimeTicks();
1397
1398 // Clear any 'stale' flag and give the pipeline a chance to resume. If we
1399 // are already resumed, this will cause |preroll_attempt_start_time_| to
1400 // be set.
1401 delegate_->ClearStaleFlag(delegate_id_);
1402 UpdatePlayState();
1403 } else if (ready_state_ == ReadyState::kReadyStateHaveFutureData &&
1404 CanPlayThrough()) {
1405 SetReadyState(WebMediaPlayer::kReadyStateHaveEnoughData);
1406 }
1407}
1408
1409bool WebMediaPlayerImpl::CanPlayThrough() {
1410 if (!base::FeatureList::IsEnabled(kSpecCompliantCanPlayThrough))
1411 return true;
1412 if (chunk_demuxer_)
1413 return true;
1414 if (data_source_ && data_source_->assume_fully_buffered())
1415 return true;
1416 // If we're not currently downloading, we have as much buffer as
1417 // we're ever going to get, which means we say we can play through.
1418 if (network_state_ == WebMediaPlayer::kNetworkStateIdle)
1419 return true;
1420 return buffered_data_source_host_.CanPlayThrough(
1421 base::TimeDelta::FromSecondsD(CurrentTime()),
1422 base::TimeDelta::FromSecondsD(Duration()),
1423 playback_rate_ == 0.0 ? 1.0 : playback_rate_);
1424}
1425
alokp967c902452016-05-06 05:21:371426void WebMediaPlayerImpl::OnBufferingStateChange(BufferingState state) {
pkastingf5279482016-07-27 02:18:201427 DVLOG(1) << __func__ << "(" << state << ")";
alokp967c902452016-05-06 05:21:371428 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]b8877772014-03-26 20:17:151429
sandersd1c0bba02016-03-04 23:14:081430 // Ignore buffering state changes until we've completed all outstanding
1431 // operations.
1432 if (!pipeline_controller_.IsStable())
[email protected]ba7d5f92014-06-24 05:37:401433 return;
[email protected]b8877772014-03-26 20:17:151434
dalecurtis869bf2f2017-01-10 18:01:101435 media_log_->AddEvent(media_log_->CreateBufferingStateChangedEvent(
1436 "pipeline_buffering_state", state));
1437
chcunninghameb270c92016-07-15 01:00:451438 if (state == BUFFERING_HAVE_ENOUGH) {
Blink Reformat1c4d759e2017-04-09 16:34:541439 if (highest_ready_state_ < WebMediaPlayer::kReadyStateHaveEnoughData) {
dalecurtis4f6d14d2017-02-22 17:42:221440 // Record a zero value for underflow histogram so that the histogram
dalecurtis821e803f2016-09-01 18:44:151441 // includes playbacks which never encounter an underflow event.
dalecurtis4f6d14d2017-02-22 17:42:221442 RecordUnderflowDuration(base::TimeDelta());
dalecurtis821e803f2016-09-01 18:44:151443 }
1444
hubbeb2d3efd2017-05-05 23:26:381445 SetReadyState(CanPlayThrough() ? WebMediaPlayer::kReadyStateHaveEnoughData
1446 : WebMediaPlayer::kReadyStateHaveFutureData);
[email protected]ba7d5f92014-06-24 05:37:401447
chcunninghameb270c92016-07-15 01:00:451448 // Let the DataSource know we have enough data. It may use this information
1449 // to release unused network connections.
1450 if (data_source_)
1451 data_source_->OnBufferingHaveEnough(false);
dalecurtis849cf4b22015-03-27 18:35:451452
chcunninghameb270c92016-07-15 01:00:451453 // Blink expects a timeChanged() in response to a seek().
sandersd35d2c3f2017-01-14 02:04:421454 if (should_notify_time_changed_) {
1455 should_notify_time_changed_ = false;
Blink Reformat1c4d759e2017-04-09 16:34:541456 client_->TimeChanged();
sandersd35d2c3f2017-01-14 02:04:421457 }
dalecurtis0f0097a2015-12-01 17:40:471458
chcunninghameb270c92016-07-15 01:00:451459 // Once we have enough, start reporting the total memory usage. We'll also
1460 // report once playback starts.
1461 ReportMemoryUsage();
dalecurtis9d638a12016-08-30 06:20:551462
dalecurtis4f6d14d2017-02-22 17:42:221463 // Report the amount of time it took to leave the underflow state.
1464 if (underflow_timer_) {
1465 RecordUnderflowDuration(underflow_timer_->Elapsed());
dalecurtis9d638a12016-08-30 06:20:551466 underflow_timer_.reset();
1467 }
chcunninghameb270c92016-07-15 01:00:451468 } else {
1469 // Buffering has underflowed.
1470 DCHECK_EQ(state, BUFFERING_HAVE_NOTHING);
dalecurtisacd77d62016-09-09 23:23:141471
dalecurtisd06eabc2017-02-24 23:43:291472 // Report the number of times we've entered the underflow state. Ensure we
1473 // only report the value when transitioning from HAVE_ENOUGH to
1474 // HAVE_NOTHING.
Dale Curtis6995b862017-05-31 22:20:081475 if (ready_state_ == WebMediaPlayer::kReadyStateHaveEnoughData &&
1476 !seeking_) {
dalecurtisacd77d62016-09-09 23:23:141477 underflow_timer_.reset(new base::ElapsedTimer());
Dale Curtis6995b862017-05-31 22:20:081478 watch_time_reporter_->OnUnderflow();
1479 }
dalecurtisacd77d62016-09-09 23:23:141480
chcunninghameb270c92016-07-15 01:00:451481 // It shouldn't be possible to underflow if we've not advanced past
1482 // HAVE_CURRENT_DATA.
Blink Reformat1c4d759e2017-04-09 16:34:541483 DCHECK_GT(highest_ready_state_, WebMediaPlayer::kReadyStateHaveCurrentData);
1484 SetReadyState(WebMediaPlayer::kReadyStateHaveCurrentData);
chcunninghameb270c92016-07-15 01:00:451485 }
sandersd50a635e2016-04-04 22:50:091486
1487 UpdatePlayState();
[email protected]b8877772014-03-26 20:17:151488}
1489
alokp967c902452016-05-06 05:21:371490void WebMediaPlayerImpl::OnDurationChange() {
acolwellb4034942014-08-28 15:42:431491 DCHECK(main_task_runner_->BelongsToCurrentThread());
alokp967c902452016-05-06 05:21:371492
1493 // TODO(sandersd): We should call delegate_->DidPlay() with the new duration,
1494 // especially if it changed from <5s to >5s.
Blink Reformat1c4d759e2017-04-09 16:34:541495 if (ready_state_ == WebMediaPlayer::kReadyStateHaveNothing)
alokp967c902452016-05-06 05:21:371496 return;
1497
Blink Reformat1c4d759e2017-04-09 16:34:541498 client_->DurationChanged();
[email protected]81bb3322011-07-21 15:55:501499}
1500
alokp967c902452016-05-06 05:21:371501void WebMediaPlayerImpl::OnAddTextTrack(const TextTrackConfig& config,
1502 const AddTextTrackDoneCB& done_cb) {
acolwellb4034942014-08-28 15:42:431503 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]71537722013-05-23 06:47:531504
[email protected]8a561062013-11-22 01:19:311505 const WebInbandTextTrackImpl::Kind web_kind =
1506 static_cast<WebInbandTextTrackImpl::Kind>(config.kind());
Blink Reformat1c4d759e2017-04-09 16:34:541507 const blink::WebString web_label = blink::WebString::FromUTF8(config.label());
[email protected]8a561062013-11-22 01:19:311508 const blink::WebString web_language =
Blink Reformat1c4d759e2017-04-09 16:34:541509 blink::WebString::FromUTF8(config.language());
1510 const blink::WebString web_id = blink::WebString::FromUTF8(config.id());
[email protected]71537722013-05-23 06:47:531511
dcheng3076abbf2016-04-22 20:42:391512 std::unique_ptr<WebInbandTextTrackImpl> web_inband_text_track(
henriks9cce5fa2014-12-12 09:35:301513 new WebInbandTextTrackImpl(web_kind, web_label, web_language, web_id));
[email protected]8a561062013-11-22 01:19:311514
dcheng3076abbf2016-04-22 20:42:391515 std::unique_ptr<media::TextTrack> text_track(new TextTrackImpl(
dcheng652f5ff2015-12-27 08:54:001516 main_task_runner_, client_, std::move(web_inband_text_track)));
[email protected]8a561062013-11-22 01:19:311517
dcheng652f5ff2015-12-27 08:54:001518 done_cb.Run(std::move(text_track));
[email protected]71537722013-05-23 06:47:531519}
1520
alokp967c902452016-05-06 05:21:371521void WebMediaPlayerImpl::OnWaitingForDecryptionKey() {
1522 DCHECK(main_task_runner_->BelongsToCurrentThread());
1523
Blink Reformat1c4d759e2017-04-09 16:34:541524 encrypted_client_->DidBlockPlaybackWaitingForKey();
alokp967c902452016-05-06 05:21:371525 // TODO(jrummell): didResumePlaybackBlockedForKey() should only be called
1526 // when a key has been successfully added (e.g. OnSessionKeysChange() with
1527 // |has_additional_usable_key| = true). http://crbug.com/461903
Blink Reformat1c4d759e2017-04-09 16:34:541528 encrypted_client_->DidResumePlaybackBlockedForKey();
alokp967c902452016-05-06 05:21:371529}
1530
alokp5d86e9b2016-05-17 20:20:411531void WebMediaPlayerImpl::OnVideoNaturalSizeChange(const gfx::Size& size) {
1532 DCHECK(main_task_runner_->BelongsToCurrentThread());
Blink Reformat1c4d759e2017-04-09 16:34:541533 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
alokp5d86e9b2016-05-17 20:20:411534
Chris Cunningham038548b2017-07-10 22:36:301535 TRACE_EVENT0("media", "WebMediaPlayerImpl::OnVideoNaturalSizeChange");
xhwang60802652017-04-19 07:29:581536
xjz15b483f2017-01-12 00:21:361537 // The input |size| is from the decoded video frame, which is the original
1538 // natural size and need to be rotated accordingly.
sandersd2c478422016-08-02 01:19:251539 gfx::Size rotated_size =
1540 GetRotatedVideoSize(pipeline_metadata_.video_rotation, size);
1541
xhwang60802652017-04-19 07:29:581542 RecordVideoNaturalSize(rotated_size);
1543
1544 gfx::Size old_size = pipeline_metadata_.natural_size;
1545 if (rotated_size == old_size)
alokp5d86e9b2016-05-17 20:20:411546 return;
1547
xjz516ef6d2017-01-07 00:23:061548 pipeline_metadata_.natural_size = rotated_size;
dalecurtis25405562017-04-14 23:35:111549
1550 // Re-create |watch_time_reporter_| if we didn't originally know the video
1551 // size or the previous size was too small for reporting.
1552 if (!watch_time_reporter_->IsSizeLargeEnoughToReportWatchTime())
tguilbert796a40e2016-11-09 01:11:421553 CreateWatchTimeReporter();
dalecurtis25405562017-04-14 23:35:111554
liberato2ff93ad2017-05-17 07:28:241555 if (overlay_enabled_ && surface_manager_ &&
1556 overlay_mode_ == OverlayMode::kUseContentVideoView) {
xhwang60802652017-04-19 07:29:581557 surface_manager_->NaturalSizeChanged(rotated_size);
liberato2ff93ad2017-05-17 07:28:241558 }
xhwang60802652017-04-19 07:29:581559
Blink Reformat1c4d759e2017-04-09 16:34:541560 client_->SizeChanged();
xjz516ef6d2017-01-07 00:23:061561
xjz15b483f2017-01-12 00:21:361562 if (observer_)
1563 observer_->OnMetadataChanged(pipeline_metadata_);
peconn257951522017-06-09 18:24:591564
1565 delegate_->DidPlayerSizeChange(delegate_id_, NaturalSize());
alokp5d86e9b2016-05-17 20:20:411566}
1567
1568void WebMediaPlayerImpl::OnVideoOpacityChange(bool opaque) {
1569 DCHECK(main_task_runner_->BelongsToCurrentThread());
Blink Reformat1c4d759e2017-04-09 16:34:541570 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
alokp5d86e9b2016-05-17 20:20:411571
1572 opaque_ = opaque;
1573 // Modify content opaqueness of cc::Layer directly so that
1574 // SetContentsOpaqueIsFixed is ignored.
lethalantidote7f6009d2017-07-07 21:47:391575 if (!surface_layer_for_video_enabled_) {
1576 if (video_weblayer_)
1577 video_weblayer_->layer()->SetContentsOpaque(opaque_);
1578 } else if (bridge_->GetWebLayer()) {
1579 bridge_->GetWebLayer()->CcLayer()->SetContentsOpaque(opaque_);
1580 }
alokp5d86e9b2016-05-17 20:20:411581}
1582
Chris Cunningham038548b2017-07-10 22:36:301583void WebMediaPlayerImpl::OnAudioConfigChange(const AudioDecoderConfig& config) {
1584 DCHECK(main_task_runner_->BelongsToCurrentThread());
1585 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
1586
1587 pipeline_metadata_.audio_decoder_config = config;
1588
1589 if (observer_)
1590 observer_->OnMetadataChanged(pipeline_metadata_);
1591}
1592
1593void WebMediaPlayerImpl::OnVideoConfigChange(const VideoDecoderConfig& config) {
1594 DCHECK(main_task_runner_->BelongsToCurrentThread());
1595 DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
1596
1597 // TODO(chcunningham): Observe changes to video codec profile to signal
1598 // beginning of a new Media Capabilities playback report.
1599 pipeline_metadata_.video_decoder_config = config;
1600
1601 if (observer_)
1602 observer_->OnMetadataChanged(pipeline_metadata_);
1603}
1604
avayvodeecec52c2017-02-14 01:25:091605void WebMediaPlayerImpl::OnVideoAverageKeyframeDistanceUpdate() {
1606 UpdateBackgroundVideoOptimizationState();
1607}
1608
sandersd35d2c3f2017-01-14 02:04:421609void WebMediaPlayerImpl::OnFrameHidden() {
sandersd1e49fb62015-12-12 01:18:061610 DCHECK(main_task_runner_->BelongsToCurrentThread());
avayvod39c102402016-11-23 21:43:131611
avayvod65fad272017-02-24 01:00:481612 // Backgrounding a video requires a user gesture to resume playback.
1613 if (IsHidden())
1614 video_locked_when_paused_when_hidden_ = true;
1615
[email protected]28347e72017-06-27 17:30:111616 overlay_info_.is_frame_hidden = true;
1617 MaybeSendOverlayInfoToDecoder();
1618
dalecurtis04bdb582016-08-17 22:15:231619 if (watch_time_reporter_)
1620 watch_time_reporter_->OnHidden();
avayvod48a8be52016-08-04 19:52:501621
avayvod65fad272017-02-24 01:00:481622 UpdateBackgroundVideoOptimizationState();
sandersd50a635e2016-04-04 22:50:091623 UpdatePlayState();
dalecurtis8b8505e72016-06-10 21:59:171624
1625 // Schedule suspended playing media to be paused if the user doesn't come back
1626 // to it within some timeout period to avoid any autoplay surprises.
1627 ScheduleIdlePauseTimer();
sandersd1e49fb62015-12-12 01:18:061628}
1629
sandersd35d2c3f2017-01-14 02:04:421630void WebMediaPlayerImpl::OnFrameClosed() {
sandersd1e49fb62015-12-12 01:18:061631 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]28347e72017-06-27 17:30:111632
1633 // Re-use |is_hidden| since nothing cares about the difference anyway.
1634 overlay_info_.is_frame_hidden = true;
1635 MaybeSendOverlayInfoToDecoder();
1636
sandersd35d2c3f2017-01-14 02:04:421637 UpdatePlayState();
1638}
1639
1640void WebMediaPlayerImpl::OnFrameShown() {
1641 DCHECK(main_task_runner_->BelongsToCurrentThread());
1642 background_pause_timer_.Stop();
1643
avayvod65fad272017-02-24 01:00:481644 // Foreground videos don't require user gesture to continue playback.
1645 video_locked_when_paused_when_hidden_ = false;
1646
[email protected]28347e72017-06-27 17:30:111647 overlay_info_.is_frame_hidden = false;
1648 MaybeSendOverlayInfoToDecoder();
1649
dalecurtis04bdb582016-08-17 22:15:231650 if (watch_time_reporter_)
1651 watch_time_reporter_->OnShown();
1652
avayvodcc273dd2017-01-19 19:35:121653 // Only track the time to the first frame if playing or about to play because
1654 // of being shown and only for videos we would optimize background playback
1655 // for.
1656 if ((!paused_ && IsBackgroundOptimizationCandidate()) ||
1657 paused_when_hidden_) {
dalecurtis1af3c1a2017-04-11 00:53:491658 frame_time_report_cb_.Reset(
1659 base::Bind(&WebMediaPlayerImpl::ReportTimeFromForegroundToFirstFrame,
1660 AsWeakPtr(), base::TimeTicks::Now()));
avayvodcc273dd2017-01-19 19:35:121661 compositor_task_runner_->PostTask(
1662 FROM_HERE,
1663 base::Bind(&VideoFrameCompositor::SetOnNewProcessedFrameCallback,
dalecurtis1af3c1a2017-04-11 00:53:491664 base::Unretained(compositor_),
1665 BindToCurrentLoop(frame_time_report_cb_.callback())));
avayvodcc273dd2017-01-19 19:35:121666 }
avayvodac607d652017-01-06 03:16:431667
avayvod65fad272017-02-24 01:00:481668 EnableVideoTrackIfNeeded();
1669
avayvod2135a642017-01-13 00:17:141670 if (paused_when_hidden_) {
1671 paused_when_hidden_ = false;
1672 OnPlay(); // Calls UpdatePlayState() so return afterwards.
1673 return;
1674 }
1675
sandersd50a635e2016-04-04 22:50:091676 UpdatePlayState();
sandersd1e49fb62015-12-12 01:18:061677}
1678
sandersd35d2c3f2017-01-14 02:04:421679void WebMediaPlayerImpl::OnIdleTimeout() {
dalecurtis0431cbf2016-03-12 01:19:431680 DCHECK(main_task_runner_->BelongsToCurrentThread());
1681
sandersd35d2c3f2017-01-14 02:04:421682 // If we are attempting preroll, clear the stale flag.
1683 if (IsPrerollAttemptNeeded()) {
tguilbert1bb1c782017-01-23 21:15:111684 delegate_->ClearStaleFlag(delegate_id_);
sandersd35d2c3f2017-01-14 02:04:421685 return;
watkd026f792016-11-05 00:28:511686 }
sandersd50a635e2016-04-04 22:50:091687
sandersd35d2c3f2017-01-14 02:04:421688 UpdatePlayState();
dalecurtis0431cbf2016-03-12 01:19:431689}
1690
dalecurtisbb3eaac2016-01-27 21:10:251691void WebMediaPlayerImpl::OnPlay() {
Blink Reformat1c4d759e2017-04-09 16:34:541692 Play();
1693 client_->PlaybackStateChanged();
dalecurtisbb3eaac2016-01-27 21:10:251694}
1695
1696void WebMediaPlayerImpl::OnPause() {
Blink Reformat1c4d759e2017-04-09 16:34:541697 Pause();
1698 client_->PlaybackStateChanged();
dalecurtisbb3eaac2016-01-27 21:10:251699}
1700
1701void WebMediaPlayerImpl::OnVolumeMultiplierUpdate(double multiplier) {
1702 volume_multiplier_ = multiplier;
Blink Reformat1c4d759e2017-04-09 16:34:541703 SetVolume(volume_);
dalecurtisbb3eaac2016-01-27 21:10:251704}
1705
zqzhang8ac49002017-03-16 21:51:351706void WebMediaPlayerImpl::OnBecamePersistentVideo(bool value) {
Blink Reformat1c4d759e2017-04-09 16:34:541707 client_->OnBecamePersistentVideo(value);
zqzhang8ac49002017-03-16 21:51:351708}
1709
watkdee516f2016-02-18 02:22:191710void WebMediaPlayerImpl::ScheduleRestart() {
sandersd50a635e2016-04-04 22:50:091711 // TODO(watk): All restart logic should be moved into PipelineController.
tguilbert350936ff2017-02-24 05:39:271712 if (pipeline_controller_.IsPipelineRunning() &&
1713 !pipeline_controller_.IsPipelineSuspended()) {
watkdee516f2016-02-18 02:22:191714 pending_suspend_resume_cycle_ = true;
sandersd50a635e2016-04-04 22:50:091715 UpdatePlayState();
watkdee516f2016-02-18 02:22:191716 }
1717}
1718
Blink Reformat1c4d759e2017-04-09 16:34:541719void WebMediaPlayerImpl::RequestRemotePlaybackDisabled(bool disabled) {
miu77f914c2016-11-19 23:56:181720 if (observer_)
1721 observer_->OnRemotePlaybackDisabled(disabled);
1722}
1723
hubbed5f36882016-01-15 22:40:371724#if defined(OS_ANDROID) // WMPI_CAST
Blink Reformat1c4d759e2017-04-09 16:34:541725bool WebMediaPlayerImpl::IsRemote() const {
hubbed5f36882016-01-15 22:40:371726 return cast_impl_.isRemote();
1727}
1728
1729void WebMediaPlayerImpl::SetMediaPlayerManager(
1730 RendererMediaPlayerManagerInterface* media_player_manager) {
1731 cast_impl_.SetMediaPlayerManager(media_player_manager);
1732}
1733
Blink Reformat1c4d759e2017-04-09 16:34:541734void WebMediaPlayerImpl::RequestRemotePlayback() {
hubbed5f36882016-01-15 22:40:371735 cast_impl_.requestRemotePlayback();
1736}
1737
Blink Reformat1c4d759e2017-04-09 16:34:541738void WebMediaPlayerImpl::RequestRemotePlaybackControl() {
hubbed5f36882016-01-15 22:40:371739 cast_impl_.requestRemotePlaybackControl();
1740}
1741
Blink Reformat1c4d759e2017-04-09 16:34:541742void WebMediaPlayerImpl::RequestRemotePlaybackStop() {
avayvod8d8c53b2016-11-04 16:10:301743 cast_impl_.requestRemotePlaybackStop();
1744}
1745
hubbed5f36882016-01-15 22:40:371746void WebMediaPlayerImpl::OnRemotePlaybackEnded() {
pkastingf5279482016-07-27 02:18:201747 DVLOG(1) << __func__;
hubbed5f36882016-01-15 22:40:371748 DCHECK(main_task_runner_->BelongsToCurrentThread());
1749
1750 ended_ = true;
Blink Reformat1c4d759e2017-04-09 16:34:541751 client_->TimeChanged();
hubbed5f36882016-01-15 22:40:371752}
1753
1754void WebMediaPlayerImpl::OnDisconnectedFromRemoteDevice(double t) {
sandersd1c0bba02016-03-04 23:14:081755 DoSeek(base::TimeDelta::FromSecondsD(t), false);
hubbed5f36882016-01-15 22:40:371756
Anton Vayvodfad2f3ea2017-07-19 21:45:271757 // |client_| might destroy us in methods below.
1758 UpdatePlayState();
1759
hubbed5f36882016-01-15 22:40:371760 // We already told the delegate we're paused when remoting started.
Blink Reformat1c4d759e2017-04-09 16:34:541761 client_->PlaybackStateChanged();
1762 client_->DisconnectedFromRemoteDevice();
hubbed5f36882016-01-15 22:40:371763}
1764
1765void WebMediaPlayerImpl::SuspendForRemote() {
avayvod82729272017-05-29 21:58:391766 if (pipeline_controller_.IsPipelineSuspended() &&
1767 !IsNewRemotePlaybackPipelineEnabled()) {
hubbed5f36882016-01-15 22:40:371768 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner();
sandersd50a635e2016-04-04 22:50:091769 if (frame)
dalecurtise9c89e92016-05-20 19:38:001770 compositor_->PaintSingleFrame(frame);
hubbed5f36882016-01-15 22:40:371771 }
sandersd50a635e2016-04-04 22:50:091772
1773 UpdatePlayState();
hubbed5f36882016-01-15 22:40:371774}
1775
1776gfx::Size WebMediaPlayerImpl::GetCanvasSize() const {
lethalantidote7f6009d2017-07-07 21:47:391777 if (!surface_layer_for_video_enabled_) {
1778 if (!video_weblayer_)
1779 return pipeline_metadata_.natural_size;
1780
1781 return video_weblayer_->Bounds();
1782 }
1783 if (!bridge_->GetWebLayer())
hubbed5f36882016-01-15 22:40:371784 return pipeline_metadata_.natural_size;
1785
lethalantidote7f6009d2017-07-07 21:47:391786 return bridge_->GetWebLayer()->Bounds();
hubbed5f36882016-01-15 22:40:371787}
1788
1789void WebMediaPlayerImpl::SetDeviceScaleFactor(float scale_factor) {
1790 cast_impl_.SetDeviceScaleFactor(scale_factor);
1791}
hubbee4027f92016-05-19 05:18:131792
Blink Reformat1c4d759e2017-04-09 16:34:541793void WebMediaPlayerImpl::SetPoster(const blink::WebURL& poster) {
xjzc102fd82017-01-04 20:13:531794 cast_impl_.setPoster(poster);
xjzc102fd82017-01-04 20:13:531795}
xjz2504c4da2017-04-18 18:50:141796#endif // defined(OS_ANDROID) // WMPI_CAST
xjzc102fd82017-01-04 20:13:531797
[email protected]fee8a902014-06-03 13:43:361798void WebMediaPlayerImpl::DataSourceInitialized(bool success) {
pkastingf5279482016-07-27 02:18:201799 DVLOG(1) << __func__;
acolwellb4034942014-08-28 15:42:431800 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]a9415292012-01-19 19:55:201801
Anton Vayvod09fa66e2017-07-20 23:02:121802 if (observer_ && IsNewRemotePlaybackPipelineEnabled() && data_source_)
1803 observer_->OnDataSourceInitialized(data_source_->GetUrlAfterRedirects());
1804
dalecurtisea27a3ed2016-06-24 01:41:301805#if defined(OS_ANDROID)
1806 // We can't play HLS URLs with WebMediaPlayerImpl, so in cases where they are
tguilbert75e2bf62017-04-26 20:13:121807 // encountered, instruct the HTML media element to use the MediaPlayerRenderer
1808 // instead.
dalecurtisea27a3ed2016-06-24 01:41:301809 //
tguilbert75e2bf62017-04-26 20:13:121810 // TODO(tguilbert): Detect the presence of HLS based on demuxing results,
1811 // rather than the URL string. See crbug.com/663503.
1812 if (data_source_) {
dalecurtisea27a3ed2016-06-24 01:41:301813 const GURL url_after_redirects = data_source_->GetUrlAfterRedirects();
qinmin0d9521272016-10-10 20:43:191814 if (MediaCodecUtil::IsHLSURL(url_after_redirects)) {
tguilbert75e2bf62017-04-26 20:13:121815 renderer_factory_selector_->SetUseMediaPlayer(true);
dalecurtisea27a3ed2016-06-24 01:41:301816 }
1817 }
1818#endif
1819
[email protected]d250190da3b2012-07-23 22:57:301820 if (!success) {
Blink Reformat1c4d759e2017-04-09 16:34:541821 SetNetworkState(WebMediaPlayer::kNetworkStateFormatError);
sandersd50a635e2016-04-04 22:50:091822
1823 // Not really necessary, since the pipeline was never started, but it at
1824 // least this makes sure that the error handling code is in sync.
1825 UpdatePlayState();
1826
[email protected]a9415292012-01-19 19:55:201827 return;
1828 }
1829
hubbee2cc88c092017-07-14 23:10:411830 // No point in preloading data as we'll probably just throw it away anyways.
1831 if (IsStreaming() && preload_ > MultibufferDataSource::METADATA) {
1832 data_source_->SetPreload(MultibufferDataSource::METADATA);
1833 }
1834
[email protected]ef8394c2013-08-21 20:26:301835 StartPipeline();
[email protected]a9415292012-01-19 19:55:201836}
1837
[email protected]122f40252012-06-12 05:01:561838void WebMediaPlayerImpl::NotifyDownloading(bool is_downloading) {
hubbeb2d3efd2017-05-05 23:26:381839 DVLOG(1) << __func__ << "(" << is_downloading << ")";
Blink Reformat1c4d759e2017-04-09 16:34:541840 if (!is_downloading && network_state_ == WebMediaPlayer::kNetworkStateLoading)
1841 SetNetworkState(WebMediaPlayer::kNetworkStateIdle);
1842 else if (is_downloading &&
1843 network_state_ == WebMediaPlayer::kNetworkStateIdle)
1844 SetNetworkState(WebMediaPlayer::kNetworkStateLoading);
hubbeb2d3efd2017-05-05 23:26:381845 if (ready_state_ == ReadyState::kReadyStateHaveFutureData && !is_downloading)
1846 SetReadyState(WebMediaPlayer::kReadyStateHaveEnoughData);
[email protected]122f40252012-06-12 05:01:561847}
1848
watkf835a792016-06-24 23:24:401849void WebMediaPlayerImpl::OnSurfaceCreated(int surface_id) {
liberato2ff93ad2017-05-17 07:28:241850 DCHECK(overlay_mode_ == OverlayMode::kUseContentVideoView);
tsunghungee562e92016-07-20 18:03:311851 overlay_surface_id_ = surface_id;
liberato2ff93ad2017-05-17 07:28:241852 MaybeSendOverlayInfoToDecoder();
watkf835a792016-06-24 23:24:401853}
1854
liberato2ff93ad2017-05-17 07:28:241855void WebMediaPlayerImpl::OnOverlayRoutingToken(
1856 const base::UnguessableToken& token) {
1857 DCHECK(overlay_mode_ == OverlayMode::kUseAndroidOverlay);
liberatofe8f9692017-06-08 19:17:361858 // TODO(liberato): |token| should already be a RoutingToken.
1859 overlay_routing_token_is_pending_ = false;
1860 overlay_routing_token_ = OverlayInfo::RoutingToken(token);
liberato2ff93ad2017-05-17 07:28:241861 MaybeSendOverlayInfoToDecoder();
1862}
1863
1864void WebMediaPlayerImpl::OnOverlayInfoRequested(
dalecurtis4b632fce22016-11-10 00:52:171865 bool decoder_requires_restart_for_overlay,
liberato2ff93ad2017-05-17 07:28:241866 const ProvideOverlayInfoCB& provide_overlay_info_cb) {
watkdee516f2016-02-18 02:22:191867 DCHECK(main_task_runner_->BelongsToCurrentThread());
1868 DCHECK(surface_manager_);
1869
1870 // A null callback indicates that the decoder is going away.
liberato2ff93ad2017-05-17 07:28:241871 if (provide_overlay_info_cb.is_null()) {
tsunghungee562e92016-07-20 18:03:311872 decoder_requires_restart_for_overlay_ = false;
liberato2ff93ad2017-05-17 07:28:241873 provide_overlay_info_cb_.Reset();
watkdee516f2016-02-18 02:22:191874 return;
1875 }
1876
[email protected]5036eb22017-07-27 02:18:541877 // For encrypted video on pre-M, we pretend that the decoder doesn't require a
1878 // restart. This is because it needs an overlay all the time anyway. We'll
1879 // switch into |force_video_overlays_| mode below.
1880 if (overlay_mode_ == OverlayMode::kUseAndroidOverlay && is_encrypted_)
1881 decoder_requires_restart_for_overlay = false;
1882
dalecurtis4b632fce22016-11-10 00:52:171883 // If we get a surface request it means GpuVideoDecoder is initializing, so
1884 // until we get a null surface request, GVD is the active decoder.
1885 //
1886 // If |decoder_requires_restart_for_overlay| is true, we must restart the
1887 // pipeline for fullscreen transitions. The decoder is unable to switch
1888 // surfaces otherwise. If false, we simply need to tell the decoder about the
1889 // new surface and it will handle things seamlessly.
1890 decoder_requires_restart_for_overlay_ = decoder_requires_restart_for_overlay;
liberato2ff93ad2017-05-17 07:28:241891 provide_overlay_info_cb_ = provide_overlay_info_cb;
dalecurtis4b632fce22016-11-10 00:52:171892
[email protected]77568482017-06-21 21:16:521893 // We always force (allow, actually) video overlays in AndroidOverlayMode.
1894 // AVDA figures out when to use them. If the decoder requires restart, then
1895 // we still want to restart the decoder on the fullscreen transitions anyway.
1896 if (overlay_mode_ == OverlayMode::kUseAndroidOverlay &&
1897 !decoder_requires_restart_for_overlay) {
1898 force_video_overlays_ = true;
1899 if (!overlay_enabled_)
1900 EnableOverlay();
1901 }
1902
dalecurtis4b632fce22016-11-10 00:52:171903 // If we're waiting for the surface to arrive, OnSurfaceCreated() will be
liberato2ff93ad2017-05-17 07:28:241904 // called later when it arrives; so do nothing for now. For AndroidOverlay,
1905 // if we're waiting for the token then... OnOverlayRoutingToken()...
1906 // We do this so that a request for a surface will block if we're in the
1907 // process of getting one. Otherwise, on pre-M, the decoder would be stuck
1908 // without an overlay if the restart that happens on entering fullscreen
1909 // succeeds before we have the overlay info. Post-M, we could send what we
1910 // have unconditionally. When the info arrives, it will be sent.
1911 MaybeSendOverlayInfoToDecoder();
1912}
1913
1914void WebMediaPlayerImpl::MaybeSendOverlayInfoToDecoder() {
1915 // If the decoder didn't request overlay info, then don't send it.
1916 if (!provide_overlay_info_cb_)
dalecurtis4b632fce22016-11-10 00:52:171917 return;
1918
liberato2ff93ad2017-05-17 07:28:241919 // We should send the overlay info as long as we know it. This includes the
1920 // case where |!overlay_enabled_|, since we want to tell the decoder to avoid
1921 // using overlays. Assuming that the decoder has requested info, the only
1922 // case in which we don't want to send something is if we've requested the
1923 // info but not received it yet. Then, we should wait until we do.
liberatofe8f9692017-06-08 19:17:361924 //
1925 // Initialization requires this; AVDA should start with enough info to make an
1926 // overlay, so that (pre-M) the initial codec is created with the right output
1927 // surface; it can't switch later.
liberato2ff93ad2017-05-17 07:28:241928 if (overlay_mode_ == OverlayMode::kUseContentVideoView) {
1929 if (!overlay_surface_id_.has_value())
1930 return;
liberatofe8f9692017-06-08 19:17:361931
1932 overlay_info_.surface_id = *overlay_surface_id_;
liberato2ff93ad2017-05-17 07:28:241933 } else if (overlay_mode_ == OverlayMode::kUseAndroidOverlay) {
liberatofe8f9692017-06-08 19:17:361934 if (overlay_routing_token_is_pending_)
liberato2ff93ad2017-05-17 07:28:241935 return;
liberatofe8f9692017-06-08 19:17:361936
1937 overlay_info_.routing_token = overlay_routing_token_;
liberato2ff93ad2017-05-17 07:28:241938 }
1939
liberato2ff93ad2017-05-17 07:28:241940 // If restart is required, the callback is one-shot only.
1941 if (decoder_requires_restart_for_overlay_) {
liberatofe8f9692017-06-08 19:17:361942 base::ResetAndReturn(&provide_overlay_info_cb_).Run(overlay_info_);
liberato2ff93ad2017-05-17 07:28:241943 } else {
liberatofe8f9692017-06-08 19:17:361944 provide_overlay_info_cb_.Run(overlay_info_);
liberato2ff93ad2017-05-17 07:28:241945 }
watkdee516f2016-02-18 02:22:191946}
1947
dcheng3076abbf2016-04-22 20:42:391948std::unique_ptr<Renderer> WebMediaPlayerImpl::CreateRenderer() {
dcheng37b415b92017-01-27 20:17:431949 DCHECK(main_task_runner_->BelongsToCurrentThread());
1950
liberato2ff93ad2017-05-17 07:28:241951 // TODO(liberato): Re-evaluate this as AndroidVideoSurfaceChooser gets smarter
1952 // about turning off overlays. Either we should verify that it is not
1953 // breaking this use-case if it does so, or we should notify it that using
1954 // the overlay is required.
tsunghungee562e92016-07-20 18:03:311955 if (force_video_overlays_)
1956 EnableOverlay();
1957
liberato2ff93ad2017-05-17 07:28:241958 RequestOverlayInfoCB request_overlay_info_cb;
watkdee516f2016-02-18 02:22:191959#if defined(OS_ANDROID)
liberato2ff93ad2017-05-17 07:28:241960 request_overlay_info_cb = BindToCurrentLoop(
1961 base::Bind(&WebMediaPlayerImpl::OnOverlayInfoRequested, AsWeakPtr()));
watkdee516f2016-02-18 02:22:191962#endif
tguilbert70d2a00a2017-04-25 00:30:441963 return renderer_factory_selector_->GetCurrentFactory()->CreateRenderer(
sandersd1e49fb62015-12-12 01:18:061964 media_task_runner_, worker_task_runner_, audio_source_provider_.get(),
liberato2ff93ad2017-05-17 07:28:241965 compositor_, request_overlay_info_cb);
sandersd1e49fb62015-12-12 01:18:061966}
1967
[email protected]ef8394c2013-08-21 20:26:301968void WebMediaPlayerImpl::StartPipeline() {
acolwellb4034942014-08-28 15:42:431969 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]ddbc6ff2013-04-19 15:28:331970
xhwange8c4181a2014-12-06 08:10:011971 Demuxer::EncryptedMediaInitDataCB encrypted_media_init_data_cb =
dcheng37b415b92017-01-27 20:17:431972 BindToCurrentLoop(base::Bind(
1973 &WebMediaPlayerImpl::OnEncryptedMediaInitData, AsWeakPtr()));
[email protected]2b57e2e2014-05-09 11:07:251974
tguilbert75e2bf62017-04-26 20:13:121975 if (renderer_factory_selector_->GetCurrentFactory()
1976 ->GetRequiredMediaResourceType() == MediaResource::Type::URL) {
1977 if (data_source_)
1978 loaded_url_ = data_source_->GetUrlAfterRedirects();
1979
1980 // MediaPlayerRendererClient factory is the only factory that a
1981 // MediaResource::Type::URL for the moment. This might no longer be true
1982 // when we remove WebMediaPlayerCast.
1983 //
1984 // TODO(tguilbert/avayvod): Update this flag when removing |cast_impl_|.
1985 using_media_player_renderer_ = true;
1986
tguilbert9881bc22016-10-27 03:13:411987 demuxer_.reset(
tguilbert75e2bf62017-04-26 20:13:121988 new MediaUrlDemuxer(media_task_runner_, loaded_url_,
Blink Reformat1c4d759e2017-04-09 16:34:541989 frame_->GetDocument().FirstPartyForCookies()));
tguilbert25a4d112016-10-13 21:56:511990 pipeline_controller_.Start(demuxer_.get(), this, false, false);
1991 return;
1992 }
1993
[email protected]ddbc6ff2013-04-19 15:28:331994 // Figure out which demuxer to use.
Blink Reformat1c4d759e2017-04-09 16:34:541995 if (load_type_ != kLoadTypeMediaSource) {
[email protected]ddbc6ff2013-04-19 15:28:331996 DCHECK(!chunk_demuxer_);
[email protected]f5443ef72013-04-22 04:03:381997 DCHECK(data_source_);
1998
j.isorcef6778e652015-11-16 17:14:251999#if !defined(MEDIA_DISABLE_FFMPEG)
servolk81e01e02016-03-05 03:29:152000 Demuxer::MediaTracksUpdatedCB media_tracks_updated_cb =
dcheng37b415b92017-01-27 20:17:432001 BindToCurrentLoop(base::Bind(
2002 &WebMediaPlayerImpl::OnFFmpegMediaTracksUpdated, AsWeakPtr()));
servolk81e01e02016-03-05 03:29:152003
dalecurtis9cddc0b2017-04-19 21:23:382004 demuxer_.reset(new FFmpegDemuxer(
2005 media_task_runner_, data_source_.get(), encrypted_media_init_data_cb,
2006 media_tracks_updated_cb, media_log_.get()));
j.isorcef6778e652015-11-16 17:14:252007#else
alokp967c902452016-05-06 05:21:372008 OnError(PipelineStatus::DEMUXER_ERROR_COULD_NOT_OPEN);
j.isorcef6778e652015-11-16 17:14:252009 return;
2010#endif
[email protected]ddbc6ff2013-04-19 15:28:332011 } else {
[email protected]f5443ef72013-04-22 04:03:382012 DCHECK(!chunk_demuxer_);
2013 DCHECK(!data_source_);
2014
acolwell9e0840d2014-09-06 19:01:322015 chunk_demuxer_ = new ChunkDemuxer(
dcheng37b415b92017-01-27 20:17:432016 BindToCurrentLoop(
2017 base::Bind(&WebMediaPlayerImpl::OnDemuxerOpened, AsWeakPtr())),
dalecurtis9cddc0b2017-04-19 21:23:382018 encrypted_media_init_data_cb, media_log_.get());
[email protected]f5443ef72013-04-22 04:03:382019 demuxer_.reset(chunk_demuxer_);
servolkf94b4602017-01-31 16:44:272020
2021 if (base::FeatureList::IsEnabled(kMemoryPressureBasedSourceBufferGC)) {
2022 // base::Unretained is safe because |this| owns memory_pressure_listener_.
2023 memory_pressure_listener_ =
2024 base::MakeUnique<base::MemoryPressureListener>(base::Bind(
2025 &WebMediaPlayerImpl::OnMemoryPressure, base::Unretained(this)));
2026 }
[email protected]ddbc6ff2013-04-19 15:28:332027 }
2028
sandersdb5e21462016-03-09 01:49:072029 // TODO(sandersd): FileSystem objects may also be non-static, but due to our
2030 // caching layer such situations are broken already. http://crbug.com/593159
2031 bool is_static = !chunk_demuxer_;
avayvod102cdb62017-01-07 03:11:092032 bool is_streaming = IsStreaming();
sandersdb8eb5f1d2016-11-19 04:04:022033 UMA_HISTOGRAM_BOOLEAN("Media.IsStreaming", is_streaming);
sandersdb5e21462016-03-09 01:49:072034
[email protected]f5443ef72013-04-22 04:03:382035 // ... and we're ready to go!
sandersd1e49fb62015-12-12 01:18:062036 // TODO(sandersd): On Android, defer Start() if the tab is not visible.
sandersdb8eb5f1d2016-11-19 04:04:022037 seeking_ = true;
alokp967c902452016-05-06 05:21:372038 pipeline_controller_.Start(demuxer_.get(), this, is_streaming, is_static);
[email protected]f5443ef72013-04-22 04:03:382039}
2040
2041void WebMediaPlayerImpl::SetNetworkState(WebMediaPlayer::NetworkState state) {
pkastingf5279482016-07-27 02:18:202042 DVLOG(1) << __func__ << "(" << state << ")";
acolwellb4034942014-08-28 15:42:432043 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]f5443ef72013-04-22 04:03:382044 network_state_ = state;
2045 // Always notify to ensure client has the latest value.
Blink Reformat1c4d759e2017-04-09 16:34:542046 client_->NetworkStateChanged();
[email protected]f5443ef72013-04-22 04:03:382047}
2048
2049void WebMediaPlayerImpl::SetReadyState(WebMediaPlayer::ReadyState state) {
pkastingf5279482016-07-27 02:18:202050 DVLOG(1) << __func__ << "(" << state << ")";
acolwellb4034942014-08-28 15:42:432051 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]f5443ef72013-04-22 04:03:382052
Blink Reformat1c4d759e2017-04-09 16:34:542053 if (state == WebMediaPlayer::kReadyStateHaveEnoughData && data_source_ &&
[email protected]fee8a902014-06-03 13:43:362054 data_source_->assume_fully_buffered() &&
Blink Reformat1c4d759e2017-04-09 16:34:542055 network_state_ == WebMediaPlayer::kNetworkStateLoading)
2056 SetNetworkState(WebMediaPlayer::kNetworkStateLoaded);
[email protected]f5443ef72013-04-22 04:03:382057
2058 ready_state_ = state;
sandersd50a635e2016-04-04 22:50:092059 highest_ready_state_ = std::max(highest_ready_state_, ready_state_);
2060
[email protected]f5443ef72013-04-22 04:03:382061 // Always notify to ensure client has the latest value.
Blink Reformat1c4d759e2017-04-09 16:34:542062 client_->ReadyStateChanged();
[email protected]f5443ef72013-04-22 04:03:382063}
2064
Blink Reformat1c4d759e2017-04-09 16:34:542065blink::WebAudioSourceProvider* WebMediaPlayerImpl::GetAudioSourceProvider() {
[email protected]ff875be52013-06-02 23:47:382066 return audio_source_provider_.get();
[email protected]f5443ef72013-04-22 04:03:382067}
2068
tguilbert350936ff2017-02-24 05:39:272069static void GetCurrentFrameAndSignal(VideoFrameCompositor* compositor,
2070 scoped_refptr<VideoFrame>* video_frame_out,
2071 base::WaitableEvent* event) {
[email protected]dd061e12014-05-06 19:21:222072 TRACE_EVENT0("media", "GetCurrentFrameAndSignal");
dalecurtis44ce4de2015-05-11 18:42:072073 *video_frame_out = compositor->GetCurrentFrameAndUpdateIfStale();
[email protected]dd061e12014-05-06 19:21:222074 event->Signal();
2075}
2076
Jiajia Qin82acdc02017-07-31 09:55:142077scoped_refptr<VideoFrame> WebMediaPlayerImpl::GetCurrentFrameFromCompositor()
2078 const {
xhwang213e50c2016-10-10 23:56:312079 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]dd061e12014-05-06 19:21:222080 TRACE_EVENT0("media", "WebMediaPlayerImpl::GetCurrentFrameFromCompositor");
xhwang213e50c2016-10-10 23:56:312081
2082 // Needed when the |main_task_runner_| and |compositor_task_runner_| are the
2083 // same to avoid deadlock in the Wait() below.
kainino36eeff82017-03-30 00:55:302084 if (compositor_task_runner_->BelongsToCurrentThread()) {
2085 scoped_refptr<VideoFrame> video_frame =
2086 compositor_->GetCurrentFrameAndUpdateIfStale();
2087 if (!video_frame) {
2088 return nullptr;
2089 }
2090 last_uploaded_frame_size_ = video_frame->natural_size();
2091 last_uploaded_frame_timestamp_ = video_frame->timestamp();
2092 return video_frame;
2093 }
[email protected]dd061e12014-05-06 19:21:222094
2095 // Use a posted task and waitable event instead of a lock otherwise
2096 // WebGL/Canvas can see different content than what the compositor is seeing.
acolwell9e0840d2014-09-06 19:01:322097 scoped_refptr<VideoFrame> video_frame;
gab0d77c7cb2016-06-02 00:00:232098 base::WaitableEvent event(base::WaitableEvent::ResetPolicy::AUTOMATIC,
2099 base::WaitableEvent::InitialState::NOT_SIGNALED);
tguilbert350936ff2017-02-24 05:39:272100 compositor_task_runner_->PostTask(
2101 FROM_HERE,
2102 base::Bind(&GetCurrentFrameAndSignal, base::Unretained(compositor_),
2103 &video_frame, &event));
[email protected]dd061e12014-05-06 19:21:222104 event.Wait();
kainino36eeff82017-03-30 00:55:302105
2106 if (!video_frame) {
2107 return nullptr;
2108 }
2109 last_uploaded_frame_size_ = video_frame->natural_size();
2110 last_uploaded_frame_timestamp_ = video_frame->timestamp();
[email protected]dd061e12014-05-06 19:21:222111 return video_frame;
2112}
2113
sandersd50a635e2016-04-04 22:50:092114void WebMediaPlayerImpl::UpdatePlayState() {
xhwang213e50c2016-10-10 23:56:312115 DCHECK(main_task_runner_->BelongsToCurrentThread());
2116
hubbed5f36882016-01-15 22:40:372117#if defined(OS_ANDROID) // WMPI_CAST
Blink Reformat1c4d759e2017-04-09 16:34:542118 bool is_remote = IsRemote();
xjz4e5d4bf32017-02-15 21:26:352119 bool can_auto_suspend = true;
sandersd50a635e2016-04-04 22:50:092120#else
2121 bool is_remote = false;
hubbee2cc88c092017-07-14 23:10:412122 bool can_auto_suspend = !disable_pipeline_auto_suspend_;
2123 // For streaming videos, we only allow suspending at the very beginning of the
2124 // video, and only if we know the length of the video. (If we don't know
2125 // the length, it might be a dynamically generated video, and suspending
2126 // will not work at all.)
2127 if (IsStreaming()) {
2128 bool at_beginning =
2129 ready_state_ == WebMediaPlayer::kReadyStateHaveNothing ||
2130 CurrentTime() == 0.0;
2131 if (!at_beginning || GetPipelineMediaDuration() == kInfiniteDuration)
2132 can_auto_suspend = false;
2133 }
hubbed5f36882016-01-15 22:40:372134#endif
xhwang213e50c2016-10-10 23:56:312135
dalecurtis8b8505e72016-06-10 21:59:172136 bool is_suspended = pipeline_controller_.IsSuspended();
avayvod39c102402016-11-23 21:43:132137 bool is_backgrounded = IsBackgroundedSuspendEnabled() && IsHidden();
sandersdaaff1a652016-11-17 01:47:252138 PlayState state = UpdatePlayState_ComputePlayState(
xjz4e5d4bf32017-02-15 21:26:352139 is_remote, can_auto_suspend, is_suspended, is_backgrounded);
sandersd35d2c3f2017-01-14 02:04:422140 SetDelegateState(state.delegate_state, state.is_idle);
sandersd50a635e2016-04-04 22:50:092141 SetMemoryReportingState(state.is_memory_reporting_enabled);
2142 SetSuspendState(state.is_suspended || pending_suspend_resume_cycle_);
2143}
dalecurtis5bbc487e2016-02-27 04:15:052144
sandersd35d2c3f2017-01-14 02:04:422145void WebMediaPlayerImpl::SetDelegateState(DelegateState new_state,
2146 bool is_idle) {
tguilbert1bb1c782017-01-23 21:15:112147 DCHECK(delegate_);
dalecurtis5bbc487e2016-02-27 04:15:052148
sandersd35d2c3f2017-01-14 02:04:422149 // Prevent duplicate delegate calls.
2150 // TODO(sandersd): Move this deduplication into the delegate itself.
2151 // TODO(sandersd): WebContentsObserverSanityChecker does not allow sending the
2152 // 'playing' IPC more than once in a row, even if the metadata has changed.
2153 // Figure out whether it should.
Blink Reformat1c4d759e2017-04-09 16:34:542154 bool has_audio = HasAudio() && !client_->IsAutoplayingMuted();
sandersd35d2c3f2017-01-14 02:04:422155 if (delegate_state_ == new_state &&
2156 (delegate_state_ != DelegateState::PLAYING ||
2157 delegate_has_audio_ == has_audio)) {
2158 return;
mlamouri910111362016-11-04 11:28:242159 }
sandersd50a635e2016-04-04 22:50:092160 delegate_state_ = new_state;
sandersd35d2c3f2017-01-14 02:04:422161 delegate_has_audio_ = has_audio;
sandersd50a635e2016-04-04 22:50:092162
sandersd35d2c3f2017-01-14 02:04:422163 switch (new_state) {
sandersd50a635e2016-04-04 22:50:092164 case DelegateState::GONE:
2165 delegate_->PlayerGone(delegate_id_);
2166 break;
mlamouri910111362016-11-04 11:28:242167 case DelegateState::PLAYING: {
peconn257951522017-06-09 18:24:592168 if (HasVideo())
2169 delegate_->DidPlayerSizeChange(delegate_id_, NaturalSize());
zqzhang5d8eab72016-08-26 20:34:302170 delegate_->DidPlay(
Blink Reformat1c4d759e2017-04-09 16:34:542171 delegate_id_, HasVideo(), has_audio,
avayvodcc273dd2017-01-19 19:35:122172 media::DurationToMediaContentType(GetPipelineMediaDuration()));
sandersd50a635e2016-04-04 22:50:092173 break;
mlamouri910111362016-11-04 11:28:242174 }
sandersd50a635e2016-04-04 22:50:092175 case DelegateState::PAUSED:
sandersd35d2c3f2017-01-14 02:04:422176 delegate_->DidPause(delegate_id_);
sandersd50a635e2016-04-04 22:50:092177 break;
dalecurtis0f0097a2015-12-01 17:40:472178 }
sandersd35d2c3f2017-01-14 02:04:422179
2180 delegate_->SetIdle(delegate_id_, is_idle);
dalecurtis0f0097a2015-12-01 17:40:472181}
2182
sandersd50a635e2016-04-04 22:50:092183void WebMediaPlayerImpl::SetMemoryReportingState(
2184 bool is_memory_reporting_enabled) {
2185 if (memory_usage_reporting_timer_.IsRunning() ==
2186 is_memory_reporting_enabled) {
hubbed5f36882016-01-15 22:40:372187 return;
sandersd50a635e2016-04-04 22:50:092188 }
sandersd1c0bba02016-03-04 23:14:082189
sandersd50a635e2016-04-04 22:50:092190 if (is_memory_reporting_enabled) {
2191 memory_usage_reporting_timer_.Start(FROM_HERE,
2192 base::TimeDelta::FromSeconds(2), this,
2193 &WebMediaPlayerImpl::ReportMemoryUsage);
2194 } else {
2195 memory_usage_reporting_timer_.Stop();
2196 ReportMemoryUsage();
2197 }
2198}
2199
2200void WebMediaPlayerImpl::SetSuspendState(bool is_suspended) {
xhwang213e50c2016-10-10 23:56:312201 DCHECK(main_task_runner_->BelongsToCurrentThread());
2202
sandersd50a635e2016-04-04 22:50:092203 // Do not change the state after an error has occurred.
2204 // TODO(sandersd): Update PipelineController to remove the need for this.
2205 if (IsNetworkStateError(network_state_))
sandersd1c0bba02016-03-04 23:14:082206 return;
2207
jameswest451a5bb2017-01-27 03:59:392208 if (is_suspended) {
sandersd35d2c3f2017-01-14 02:04:422209 // If we were not resumed for long enough to satisfy the preroll attempt,
2210 // reset the clock.
2211 if (!preroll_attempt_pending_ && IsPrerollAttemptNeeded()) {
2212 preroll_attempt_pending_ = true;
2213 preroll_attempt_start_time_ = base::TimeTicks();
2214 }
sandersd50a635e2016-04-04 22:50:092215 pipeline_controller_.Suspend();
2216 } else {
sandersd35d2c3f2017-01-14 02:04:422217 // When resuming, start the preroll attempt clock.
2218 if (preroll_attempt_pending_) {
2219 preroll_attempt_pending_ = false;
2220 preroll_attempt_start_time_ = tick_clock_->NowTicks();
2221 }
sandersd50a635e2016-04-04 22:50:092222 pipeline_controller_.Resume();
2223 }
2224}
2225
2226WebMediaPlayerImpl::PlayState
2227WebMediaPlayerImpl::UpdatePlayState_ComputePlayState(bool is_remote,
xjz4e5d4bf32017-02-15 21:26:352228 bool can_auto_suspend,
dalecurtis8b8505e72016-06-10 21:59:172229 bool is_suspended,
sandersd50a635e2016-04-04 22:50:092230 bool is_backgrounded) {
2231 PlayState result;
2232
tguilbert1bb1c782017-01-23 21:15:112233 bool must_suspend = delegate_->IsFrameClosed();
2234 bool is_stale = delegate_->IsStale(delegate_id_);
sandersd35d2c3f2017-01-14 02:04:422235
sandersd50a635e2016-04-04 22:50:092236 // This includes both data source (before pipeline startup) and pipeline
2237 // errors.
2238 bool has_error = IsNetworkStateError(network_state_);
2239
dalecurtiscc8baf72016-10-27 01:49:442240 // After HaveFutureData, Blink will call play() if the state is not paused;
2241 // prior to this point |paused_| is not accurate.
sandersd50a635e2016-04-04 22:50:092242 bool have_future_data =
Blink Reformat1c4d759e2017-04-09 16:34:542243 highest_ready_state_ >= WebMediaPlayer::kReadyStateHaveFutureData;
sandersd50a635e2016-04-04 22:50:092244
avayvod65fad272017-02-24 01:00:482245 // Background suspend is only enabled for paused players.
2246 // In the case of players with audio the session should be kept.
2247 bool background_suspended =
xjz4e5d4bf32017-02-15 21:26:352248 can_auto_suspend && is_backgrounded && paused_ && have_future_data;
sandersd50a635e2016-04-04 22:50:092249
dalecurtiscc8baf72016-10-27 01:49:442250 // Idle suspension is allowed prior to have future data since there exist
2251 // mechanisms to exit the idle state when the player is capable of reaching
2252 // the have future data state; see didLoadingProgress().
2253 //
sandersd50a635e2016-04-04 22:50:092254 // TODO(sandersd): Make the delegate suspend idle players immediately when
2255 // hidden.
sandersdaaff1a652016-11-17 01:47:252256 bool idle_suspended =
xjz4e5d4bf32017-02-15 21:26:352257 can_auto_suspend && is_stale && paused_ && !seeking_ && !overlay_enabled_;
dalecurtise7120dc2016-09-03 02:54:352258
2259 // If we're already suspended, see if we can wait for user interaction. Prior
sandersd35d2c3f2017-01-14 02:04:422260 // to HaveFutureData, we require |is_stale| to remain suspended. |is_stale|
dalecurtise7120dc2016-09-03 02:54:352261 // will be cleared when we receive data which may take us to HaveFutureData.
2262 bool can_stay_suspended =
sandersd35d2c3f2017-01-14 02:04:422263 (is_stale || have_future_data) && is_suspended && paused_ && !seeking_;
sandersd50a635e2016-04-04 22:50:092264
2265 // Combined suspend state.
sandersd35d2c3f2017-01-14 02:04:422266 result.is_suspended = is_remote || must_suspend || idle_suspended ||
avayvod65fad272017-02-24 01:00:482267 background_suspended || can_stay_suspended;
sandersd50a635e2016-04-04 22:50:092268
2269 // We do not treat |playback_rate_| == 0 as paused. For the media session,
2270 // being paused implies displaying a play button, which is incorrect in this
2271 // case. For memory usage reporting, we just use the same definition (but we
2272 // don't have to).
2273 //
2274 // Similarly, we don't consider |ended_| to be paused. Blink will immediately
2275 // call pause() or seek(), so |ended_| should not affect the computation.
2276 // Despite that, |ended_| does result in a separate paused state, to simplfy
2277 // the contract for SetDelegateState().
2278 //
avayvod65fad272017-02-24 01:00:482279 // |has_remote_controls| indicates if the player can be controlled outside the
2280 // page (e.g. via the notification controls or by audio focus events). Idle
sandersd50a635e2016-04-04 22:50:092281 // suspension does not destroy the media session, because we expect that the
avayvod5f34b642017-03-23 03:14:042282 // notification controls (and audio focus) remain. With some exceptions for
2283 // background videos, the player only needs to have audio to have controls
2284 // (requires |have_future_data|).
2285 //
2286 // |alive| indicates if the player should be present (not |GONE|) to the
2287 // delegate, either paused or playing. The following must be true for the
2288 // player:
sandersd50a635e2016-04-04 22:50:092289 // - |have_future_data|, since we need to know whether we are paused to
avayvod65fad272017-02-24 01:00:482290 // correctly configure the session and also because the tracks and
avayvod5f34b642017-03-23 03:14:042291 // duration are passed to DidPlay(),
2292 // - |is_remote| is false as remote playback is not handled by the delegate,
2293 // - |has_error| is false as player should have no errors,
2294 // - |background_suspended| is false, otherwise |has_remote_controls| must
2295 // be true.
sandersd50a635e2016-04-04 22:50:092296 //
avayvod65fad272017-02-24 01:00:482297 // TODO(sandersd): If Blink told us the paused state sooner, we could detect
2298 // if the remote controls are available sooner.
2299
2300 // Background videos with audio don't have remote controls if background
2301 // suspend is enabled and resuming background videos is not (original Android
2302 // behavior).
2303 bool backgrounded_video_has_no_remote_controls =
2304 IsBackgroundedSuspendEnabled() && !IsResumeBackgroundVideosEnabled() &&
Blink Reformat1c4d759e2017-04-09 16:34:542305 is_backgrounded && HasVideo();
sandersd50a635e2016-04-04 22:50:092306 bool can_play = !has_error && !is_remote && have_future_data;
avayvod5f34b642017-03-23 03:14:042307 bool has_remote_controls =
Blink Reformat1c4d759e2017-04-09 16:34:542308 HasAudio() && !backgrounded_video_has_no_remote_controls;
avayvod5f34b642017-03-23 03:14:042309 bool alive = can_play && !must_suspend &&
2310 (!background_suspended || has_remote_controls);
2311 if (!alive) {
sandersd50a635e2016-04-04 22:50:092312 result.delegate_state = DelegateState::GONE;
tguilbert1bb1c782017-01-23 21:15:112313 result.is_idle = delegate_->IsIdle(delegate_id_);
avayvod65fad272017-02-24 01:00:482314 } else if (paused_) {
sandersd35d2c3f2017-01-14 02:04:422315 // TODO(sandersd): Is it possible to have a suspended session, be ended,
2316 // and not be paused? If so we should be in a PLAYING state.
dalecurtise7120dc2016-09-03 02:54:352317 result.delegate_state =
sandersd35d2c3f2017-01-14 02:04:422318 ended_ ? DelegateState::GONE : DelegateState::PAUSED;
2319 result.is_idle = !seeking_;
sandersd50a635e2016-04-04 22:50:092320 } else {
2321 result.delegate_state = DelegateState::PLAYING;
sandersd35d2c3f2017-01-14 02:04:422322 result.is_idle = false;
sandersd50a635e2016-04-04 22:50:092323 }
2324
dalecurtis8b8505e72016-06-10 21:59:172325 // It's not critical if some cases where memory usage can change are missed,
sandersd50a635e2016-04-04 22:50:092326 // since media memory changes are usually gradual.
2327 result.is_memory_reporting_enabled =
sandersd35d2c3f2017-01-14 02:04:422328 can_play && !result.is_suspended && (!paused_ || seeking_);
sandersd50a635e2016-04-04 22:50:092329
2330 return result;
dalecurtis0f0097a2015-12-01 17:40:472331}
2332
dalecurtis83266c72015-10-29 18:43:202333void WebMediaPlayerImpl::ReportMemoryUsage() {
2334 DCHECK(main_task_runner_->BelongsToCurrentThread());
2335
wdzierzanowskifd4cd91c52015-12-02 23:50:202336 // About base::Unretained() usage below: We destroy |demuxer_| on the main
2337 // thread. Before that, however, ~WebMediaPlayerImpl() posts a task to the
2338 // media thread and waits for it to finish. Hence, the GetMemoryUsage() task
2339 // posted here must finish earlier.
2340
2341 if (demuxer_) {
2342 base::PostTaskAndReplyWithResult(
2343 media_task_runner_.get(), FROM_HERE,
2344 base::Bind(&Demuxer::GetMemoryUsage, base::Unretained(demuxer_.get())),
2345 base::Bind(&WebMediaPlayerImpl::FinishMemoryUsageReport, AsWeakPtr()));
2346 } else {
2347 FinishMemoryUsageReport(0);
2348 }
2349}
2350
2351void WebMediaPlayerImpl::FinishMemoryUsageReport(int64_t demuxer_memory_usage) {
2352 DCHECK(main_task_runner_->BelongsToCurrentThread());
2353
avayvodc4bfb0e62017-01-13 01:07:012354 const PipelineStatistics stats = GetPipelineStatistics();
servolk639473e492016-12-15 04:14:202355 const int64_t data_source_memory_usage =
2356 data_source_ ? data_source_->GetMemoryUsage() : 0;
dalecurtisecc76612017-04-19 00:31:202357
2358 // If we have video and no video memory usage, assume the VideoFrameCompositor
2359 // is holding onto the last frame after we've suspended the pipeline; which
2360 // thus reports zero memory usage from the video renderer.
2361 //
2362 // Technically this should use the coded size, but that requires us to hop to
2363 // the compositor to get and byte-perfect accuracy isn't important here.
2364 const int64_t video_memory_usage =
2365 stats.video_memory_usage +
2366 (pipeline_metadata_.has_video && !stats.video_memory_usage
2367 ? VideoFrame::AllocationSize(PIXEL_FORMAT_YV12,
2368 pipeline_metadata_.natural_size)
2369 : 0);
2370
dalecurtis83266c72015-10-29 18:43:202371 const int64_t current_memory_usage =
dalecurtisecc76612017-04-19 00:31:202372 stats.audio_memory_usage + video_memory_usage + data_source_memory_usage +
2373 demuxer_memory_usage;
dalecurtis83266c72015-10-29 18:43:202374
dalecurtisecc76612017-04-19 00:31:202375 DVLOG(2) << "Memory Usage -- Total: " << current_memory_usage
2376 << " Audio: " << stats.audio_memory_usage
2377 << ", Video: " << video_memory_usage
servolk639473e492016-12-15 04:14:202378 << ", DataSource: " << data_source_memory_usage
wdzierzanowskifd4cd91c52015-12-02 23:50:202379 << ", Demuxer: " << demuxer_memory_usage;
dalecurtis83266c72015-10-29 18:43:202380
2381 const int64_t delta = current_memory_usage - last_reported_memory_usage_;
2382 last_reported_memory_usage_ = current_memory_usage;
2383 adjust_allocated_memory_cb_.Run(delta);
servolk639473e492016-12-15 04:14:202384
Blink Reformat1c4d759e2017-04-09 16:34:542385 if (HasAudio()) {
servolk639473e492016-12-15 04:14:202386 UMA_HISTOGRAM_MEMORY_KB("Media.WebMediaPlayerImpl.Memory.Audio",
2387 stats.audio_memory_usage / 1024);
2388 }
Blink Reformat1c4d759e2017-04-09 16:34:542389 if (HasVideo()) {
servolk639473e492016-12-15 04:14:202390 UMA_HISTOGRAM_MEMORY_KB("Media.WebMediaPlayerImpl.Memory.Video",
dalecurtisecc76612017-04-19 00:31:202391 video_memory_usage / 1024);
servolk639473e492016-12-15 04:14:202392 }
2393 if (data_source_) {
2394 UMA_HISTOGRAM_MEMORY_KB("Media.WebMediaPlayerImpl.Memory.DataSource",
2395 data_source_memory_usage / 1024);
2396 }
2397 if (demuxer_) {
2398 UMA_HISTOGRAM_MEMORY_KB("Media.WebMediaPlayerImpl.Memory.Demuxer",
2399 demuxer_memory_usage / 1024);
2400 }
dalecurtis83266c72015-10-29 18:43:202401}
2402
dalecurtis8b8505e72016-06-10 21:59:172403void WebMediaPlayerImpl::ScheduleIdlePauseTimer() {
avayvod65fad272017-02-24 01:00:482404 // Only schedule the pause timer if we're not paused or paused but going to
avayvod52efd282017-03-07 21:13:042405 // resume when foregrounded, and are suspended and have audio.
2406 if ((paused_ && !paused_when_hidden_) ||
Blink Reformat1c4d759e2017-04-09 16:34:542407 !pipeline_controller_.IsSuspended() || !HasAudio()) {
dalecurtis8b8505e72016-06-10 21:59:172408 return;
avayvod52efd282017-03-07 21:13:042409 }
dalecurtis8b8505e72016-06-10 21:59:172410
2411#if defined(OS_ANDROID)
2412 // Remote players will be suspended and locally paused.
Blink Reformat1c4d759e2017-04-09 16:34:542413 if (IsRemote())
dalecurtis8b8505e72016-06-10 21:59:172414 return;
2415#endif
2416
2417 // Idle timeout chosen arbitrarily.
2418 background_pause_timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(5),
2419 this, &WebMediaPlayerImpl::OnPause);
2420}
2421
dalecurtis04bdb582016-08-17 22:15:232422void WebMediaPlayerImpl::CreateWatchTimeReporter() {
wdzierzanowskia78fa9b2017-06-13 18:12:102423 if (!HasVideo() && !HasAudio())
2424 return;
2425
dalecurtis04bdb582016-08-17 22:15:232426 // Create the watch time reporter and synchronize its initial state.
Dale Curtis1adbe6a2017-08-02 02:09:132427 watch_time_reporter_.reset(new WatchTimeReporter(
2428 mojom::PlaybackProperties::New(
2429 pipeline_metadata_.audio_decoder_config.codec(),
2430 pipeline_metadata_.video_decoder_config.codec(),
2431 pipeline_metadata_.has_audio, pipeline_metadata_.has_video,
2432 !!chunk_demuxer_, is_encrypted_, embedded_media_experience_enabled_,
2433 pipeline_metadata_.natural_size,
2434 url::Origin(frame_->GetSecurityOrigin())),
2435 base::BindRepeating(&GetCurrentTimeInternal, this),
2436 watch_time_recorder_provider_));
dalecurtis04bdb582016-08-17 22:15:232437 watch_time_reporter_->OnVolumeChange(volume_);
Mounir Lamourif9af74e72017-06-19 19:31:452438
tguilbert1bb1c782017-01-23 21:15:112439 if (delegate_->IsFrameHidden())
dalecurtis04bdb582016-08-17 22:15:232440 watch_time_reporter_->OnHidden();
2441 else
2442 watch_time_reporter_->OnShown();
Mounir Lamourif9af74e72017-06-19 19:31:452443
Mounir Lamouri41a79c62017-06-06 12:53:162444 if (client_->HasNativeControls())
2445 watch_time_reporter_->OnNativeControlsEnabled();
2446 else
2447 watch_time_reporter_->OnNativeControlsDisabled();
Mounir Lamourif9af74e72017-06-19 19:31:452448
2449 switch (client_->DisplayType()) {
2450 case WebMediaPlayer::DisplayType::kInline:
2451 watch_time_reporter_->OnDisplayTypeInline();
2452 break;
2453 case WebMediaPlayer::DisplayType::kFullscreen:
2454 watch_time_reporter_->OnDisplayTypeFullscreen();
2455 break;
2456 case WebMediaPlayer::DisplayType::kPictureInPicture:
2457 watch_time_reporter_->OnDisplayTypePictureInPicture();
2458 break;
2459 }
dalecurtis04bdb582016-08-17 22:15:232460}
2461
avayvod39c102402016-11-23 21:43:132462bool WebMediaPlayerImpl::IsHidden() const {
2463 DCHECK(main_task_runner_->BelongsToCurrentThread());
2464
tguilbert1bb1c782017-01-23 21:15:112465 return delegate_->IsFrameHidden() && !delegate_->IsFrameClosed();
avayvod39c102402016-11-23 21:43:132466}
2467
avayvod102cdb62017-01-07 03:11:092468bool WebMediaPlayerImpl::IsStreaming() const {
2469 return data_source_ && data_source_->IsStreaming();
2470}
2471
liberato2fd111be2017-01-04 00:25:062472bool WebMediaPlayerImpl::DoesOverlaySupportMetadata() const {
2473 return pipeline_metadata_.video_rotation == VIDEO_ROTATION_0;
2474}
2475
xjzaf29d4182016-12-16 01:52:322476void WebMediaPlayerImpl::ActivateViewportIntersectionMonitoring(bool activate) {
2477 DCHECK(main_task_runner_->BelongsToCurrentThread());
2478
Blink Reformat1c4d759e2017-04-09 16:34:542479 client_->ActivateViewportIntersectionMonitoring(activate);
xjzaf29d4182016-12-16 01:52:322480}
2481
Anton Vayvod09fa66e2017-07-20 23:02:122482void WebMediaPlayerImpl::UpdateRemotePlaybackCompatibility(bool is_compatible) {
2483 DCHECK(main_task_runner_->BelongsToCurrentThread());
2484
2485 client_->RemotePlaybackCompatibilityChanged(loaded_url_, is_compatible);
2486}
2487
avayvodcc273dd2017-01-19 19:35:122488bool WebMediaPlayerImpl::ShouldPauseVideoWhenHidden() const {
avayvod65fad272017-02-24 01:00:482489 // If suspending background video, pause any video that's not remoted or
2490 // not unlocked to play in the background.
2491 if (IsBackgroundedSuspendEnabled()) {
Blink Reformat1c4d759e2017-04-09 16:34:542492 if (!HasVideo())
avayvod65fad272017-02-24 01:00:482493 return false;
2494
2495#if defined(OS_ANDROID)
Blink Reformat1c4d759e2017-04-09 16:34:542496 if (IsRemote())
avayvod65fad272017-02-24 01:00:482497 return false;
avayvodcc273dd2017-01-19 19:35:122498#endif
avayvodeb9098d2017-01-07 00:33:032499
Blink Reformat1c4d759e2017-04-09 16:34:542500 return !HasAudio() || (IsResumeBackgroundVideosEnabled() &&
2501 video_locked_when_paused_when_hidden_);
avayvod65fad272017-02-24 01:00:482502 }
2503
2504 // Otherwise only pause if the optimization is on and it's a video-only
2505 // optimization candidate.
avayvod01201332017-04-14 00:27:152506 return IsBackgroundVideoPauseOptimizationEnabled() && !HasAudio() &&
avayvod65fad272017-02-24 01:00:482507 IsBackgroundOptimizationCandidate();
avayvodeb9098d2017-01-07 00:33:032508}
2509
avayvod2135a642017-01-13 00:17:142510bool WebMediaPlayerImpl::ShouldDisableVideoWhenHidden() const {
avayvodcc273dd2017-01-19 19:35:122511 // This optimization is behind the flag on all platforms.
2512 if (!IsBackgroundVideoTrackOptimizationEnabled())
avayvodc4bfb0e62017-01-13 01:07:012513 return false;
avayvodc4bfb0e62017-01-13 01:07:012514
avayvodcc273dd2017-01-19 19:35:122515 // Disable video track only for players with audio that match the criteria for
2516 // being optimized.
Blink Reformat1c4d759e2017-04-09 16:34:542517 return HasAudio() && IsBackgroundOptimizationCandidate();
avayvodcc273dd2017-01-19 19:35:122518}
2519
2520bool WebMediaPlayerImpl::IsBackgroundOptimizationCandidate() const {
2521 DCHECK(main_task_runner_->BelongsToCurrentThread());
2522
avayvodcc273dd2017-01-19 19:35:122523#if defined(OS_ANDROID) // WMPI_CAST
avayvodac1a8522017-01-20 19:02:502524 // Don't optimize players being Cast.
Blink Reformat1c4d759e2017-04-09 16:34:542525 if (IsRemote())
avayvodcc273dd2017-01-19 19:35:122526 return false;
avayvodac1a8522017-01-20 19:02:502527
2528 // Video-only players are always optimized (paused) on Android.
2529 // Don't check the keyframe distance and duration.
Blink Reformat1c4d759e2017-04-09 16:34:542530 if (!HasAudio() && HasVideo())
avayvodac1a8522017-01-20 19:02:502531 return true;
avayvodcc273dd2017-01-19 19:35:122532#endif // defined(OS_ANDROID)
2533
2534 // Don't optimize audio-only or streaming players.
Blink Reformat1c4d759e2017-04-09 16:34:542535 if (!HasVideo() || IsStreaming())
avayvodcc273dd2017-01-19 19:35:122536 return false;
2537
2538 // Videos shorter than the maximum allowed keyframe distance can be optimized.
2539 base::TimeDelta duration = GetPipelineMediaDuration();
avayvode85ec422017-04-14 00:11:332540 base::TimeDelta max_keyframe_distance =
2541 (load_type_ == kLoadTypeMediaSource)
2542 ? max_keyframe_distance_to_disable_background_video_mse_
2543 : max_keyframe_distance_to_disable_background_video_;
2544 if (duration < max_keyframe_distance)
avayvodcc273dd2017-01-19 19:35:122545 return true;
2546
2547 // Otherwise, only optimize videos with shorter average keyframe distance.
avayvodc4bfb0e62017-01-13 01:07:012548 PipelineStatistics stats = GetPipelineStatistics();
avayvode85ec422017-04-14 00:11:332549 return stats.video_keyframe_distance_average < max_keyframe_distance;
avayvod2135a642017-01-13 00:17:142550}
2551
avayvod56e1f3942017-01-21 02:06:312552void WebMediaPlayerImpl::UpdateBackgroundVideoOptimizationState() {
2553 if (IsHidden()) {
2554 if (ShouldPauseVideoWhenHidden())
2555 PauseVideoIfNeeded();
2556 else
2557 DisableVideoTrackIfNeeded();
2558 } else {
2559 EnableVideoTrackIfNeeded();
2560 }
2561}
2562
2563void WebMediaPlayerImpl::PauseVideoIfNeeded() {
2564 DCHECK(IsHidden());
2565
2566 // Don't pause video while the pipeline is stopped, resuming or seeking.
2567 // Also if the video is paused already.
tguilbert350936ff2017-02-24 05:39:272568 if (!pipeline_controller_.IsPipelineRunning() || is_pipeline_resuming_ ||
2569 seeking_ || paused_)
avayvod56e1f3942017-01-21 02:06:312570 return;
2571
2572 // OnPause() will set |paused_when_hidden_| to false and call
2573 // UpdatePlayState(), so set the flag to true after and then return.
2574 OnPause();
2575 paused_when_hidden_ = true;
2576}
2577
avayvod2135a642017-01-13 00:17:142578void WebMediaPlayerImpl::EnableVideoTrackIfNeeded() {
avayvod56e1f3942017-01-21 02:06:312579 // Don't change video track while the pipeline is stopped, resuming or
2580 // seeking.
tguilbert350936ff2017-02-24 05:39:272581 if (!pipeline_controller_.IsPipelineRunning() || is_pipeline_resuming_ ||
2582 seeking_)
avayvod2135a642017-01-13 00:17:142583 return;
2584
2585 if (video_track_disabled_) {
2586 video_track_disabled_ = false;
Blink Reformat1c4d759e2017-04-09 16:34:542587 if (client_->HasSelectedVideoTrack()) {
2588 WebMediaPlayer::TrackId trackId = client_->GetSelectedVideoTrackId();
2589 SelectedVideoTrackChanged(&trackId);
avayvod2135a642017-01-13 00:17:142590 }
2591 }
2592}
2593
2594void WebMediaPlayerImpl::DisableVideoTrackIfNeeded() {
2595 DCHECK(IsHidden());
2596
2597 // Don't change video track while the pipeline is resuming or seeking.
2598 if (is_pipeline_resuming_ || seeking_)
2599 return;
2600
2601 if (!video_track_disabled_ && ShouldDisableVideoWhenHidden()) {
2602 video_track_disabled_ = true;
Blink Reformat1c4d759e2017-04-09 16:34:542603 SelectedVideoTrackChanged(nullptr);
avayvod2135a642017-01-13 00:17:142604 }
2605}
2606
avayvodc4bfb0e62017-01-13 01:07:012607void WebMediaPlayerImpl::SetPipelineStatisticsForTest(
2608 const PipelineStatistics& stats) {
2609 pipeline_statistics_for_test_ = base::make_optional(stats);
2610}
2611
2612PipelineStatistics WebMediaPlayerImpl::GetPipelineStatistics() const {
2613 DCHECK(main_task_runner_->BelongsToCurrentThread());
2614
tguilbert350936ff2017-02-24 05:39:272615 return pipeline_statistics_for_test_.value_or(
2616 pipeline_controller_.GetStatistics());
avayvodc4bfb0e62017-01-13 01:07:012617}
2618
avayvodcc273dd2017-01-19 19:35:122619void WebMediaPlayerImpl::SetPipelineMediaDurationForTest(
2620 base::TimeDelta duration) {
2621 pipeline_media_duration_for_test_ = base::make_optional(duration);
2622}
2623
2624base::TimeDelta WebMediaPlayerImpl::GetPipelineMediaDuration() const {
2625 DCHECK(main_task_runner_->BelongsToCurrentThread());
2626
2627 return pipeline_media_duration_for_test_.value_or(
tguilbert350936ff2017-02-24 05:39:272628 pipeline_controller_.GetMediaDuration());
avayvodcc273dd2017-01-19 19:35:122629}
2630
2631void WebMediaPlayerImpl::ReportTimeFromForegroundToFirstFrame(
2632 base::TimeTicks foreground_time,
2633 base::TimeTicks new_frame_time) {
2634 base::TimeDelta time_to_first_frame = new_frame_time - foreground_time;
Blink Reformat1c4d759e2017-04-09 16:34:542635 if (HasAudio()) {
avayvodcc273dd2017-01-19 19:35:122636 UMA_HISTOGRAM_TIMES(
2637 "Media.Video.TimeFromForegroundToFirstFrame.DisableTrack",
2638 time_to_first_frame);
2639 } else {
2640 UMA_HISTOGRAM_TIMES("Media.Video.TimeFromForegroundToFirstFrame.Paused",
2641 time_to_first_frame);
2642 }
2643}
Xiangjun Zhangba8724f482017-08-03 06:43:252644
2645void WebMediaPlayerImpl::SwitchToRemoteRenderer(
2646 const std::string& remote_device_friendly_name) {
xjz4e5d4bf32017-02-15 21:26:352647 DCHECK(main_task_runner_->BelongsToCurrentThread());
Xiangjun Zhangba8724f482017-08-03 06:43:252648 disable_pipeline_auto_suspend_ = true;
2649 // Requests to restart media pipeline. A remote renderer will be created via
2650 // the |renderer_factory_selector_|.
xjz4e5d4bf32017-02-15 21:26:352651 ScheduleRestart();
xjzdf9b67e2017-04-13 23:28:252652 if (client_) {
Xiangjun Zhangba8724f482017-08-03 06:43:252653 client_->MediaRemotingStarted(
2654 WebString::FromUTF8(remote_device_friendly_name));
xjzdf9b67e2017-04-13 23:28:252655 }
xjz4e5d4bf32017-02-15 21:26:352656}
2657
Xiangjun Zhangba8724f482017-08-03 06:43:252658void WebMediaPlayerImpl::SwitchToLocalRenderer() {
2659 DCHECK(main_task_runner_->BelongsToCurrentThread());
2660 disable_pipeline_auto_suspend_ = false;
2661 // Requests to restart media pipeline. A local renderer will be created via
2662 // the |renderer_factory_selector_|.
2663 ScheduleRestart();
2664 if (client_)
2665 client_->MediaRemotingStopped();
2666}
2667
dalecurtis4f6d14d2017-02-22 17:42:222668void WebMediaPlayerImpl::RecordUnderflowDuration(base::TimeDelta duration) {
2669 DCHECK(data_source_ || chunk_demuxer_);
xhwang68b3fab82017-05-17 21:31:462670
dalecurtis4f6d14d2017-02-22 17:42:222671 if (data_source_)
2672 UMA_HISTOGRAM_TIMES("Media.UnderflowDuration", duration);
2673 else
2674 UMA_HISTOGRAM_TIMES("Media.UnderflowDuration.MSE", duration);
xhwang68b3fab82017-05-17 21:31:462675
2676 if (is_encrypted_)
2677 UMA_HISTOGRAM_TIMES("Media.UnderflowDuration.EME", duration);
dalecurtis4f6d14d2017-02-22 17:42:222678}
2679
xhwang60802652017-04-19 07:29:582680#define UMA_HISTOGRAM_VIDEO_HEIGHT(name, sample) \
2681 UMA_HISTOGRAM_CUSTOM_COUNTS(name, sample, 100, 10000, 50)
2682
2683void WebMediaPlayerImpl::RecordVideoNaturalSize(const gfx::Size& natural_size) {
2684 // Always report video natural size to MediaLog.
2685 media_log_->AddEvent(media_log_->CreateVideoSizeSetEvent(
2686 natural_size.width(), natural_size.height()));
2687
2688 if (initial_video_height_recorded_)
2689 return;
2690
2691 initial_video_height_recorded_ = true;
2692
2693 int height = natural_size.height();
2694
2695 if (load_type_ == kLoadTypeURL)
2696 UMA_HISTOGRAM_VIDEO_HEIGHT("Media.VideoHeight.Initial.SRC", height);
2697 else if (load_type_ == kLoadTypeMediaSource)
2698 UMA_HISTOGRAM_VIDEO_HEIGHT("Media.VideoHeight.Initial.MSE", height);
2699
2700 if (is_encrypted_)
2701 UMA_HISTOGRAM_VIDEO_HEIGHT("Media.VideoHeight.Initial.EME", height);
2702
2703 UMA_HISTOGRAM_VIDEO_HEIGHT("Media.VideoHeight.Initial.All", height);
2704}
2705
2706#undef UMA_HISTOGRAM_VIDEO_HEIGHT
2707
hubbeb2d3efd2017-05-05 23:26:382708void WebMediaPlayerImpl::SetTickClockForTest(base::TickClock* tick_clock) {
2709 tick_clock_.reset(tick_clock);
2710 buffered_data_source_host_.SetTickClockForTest(tick_clock);
2711}
2712
acolwell9e0840d2014-09-06 19:01:322713} // namespace media