blob: 5dd65d08719b7a279d88dca947fdb3f0d3ec82f9 [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"
[email protected]2041cf342010-02-19 03:15:5914#include "base/callback.h"
[email protected]7502ef12014-01-25 01:19:2715#include "base/callback_helpers.h"
sandersd1e49fb62015-12-12 01:18:0616#include "base/command_line.h"
[email protected]ca04095f2014-02-07 10:23:5617#include "base/debug/alias.h"
[email protected]926f8fd2013-04-12 20:27:5318#include "base/debug/crash_logging.h"
[email protected]b0b258f2011-11-08 00:34:2319#include "base/metrics/histogram.h"
acolwellb4034942014-08-28 15:42:4320#include "base/single_thread_task_runner.h"
[email protected]cf02541b2012-04-11 08:02:1721#include "base/synchronization/waitable_event.h"
wdzierzanowskifd4cd91c52015-12-02 23:50:2022#include "base/task_runner_util.h"
anujk.sharma2fa37a02015-04-30 05:51:3223#include "base/thread_task_runner_handle.h"
ssid9525f4672015-01-28 12:13:1524#include "base/trace_event/trace_event.h"
sandersd1e49fb62015-12-12 01:18:0625#include "build/build_config.h"
[email protected]38564622014-08-19 02:47:1826#include "cc/blink/web_layer_impl.h"
[email protected]21c3f7502013-03-23 03:29:5127#include "cc/layers/video_layer.h"
dongseong.hwang0c4e9d82015-01-08 20:11:1328#include "gpu/blink/webgraphicscontext3d_impl.h"
[email protected]e4fc09e2012-04-06 03:17:4429#include "media/audio/null_audio_sink.h"
[email protected]2eccbed2014-01-10 05:15:5330#include "media/base/bind_to_current_loop.h"
xhwang0ad11e512014-11-25 23:43:0931#include "media/base/cdm_context.h"
[email protected]32da1002010-03-03 21:57:3532#include "media/base/limits.h"
[email protected]090f7312011-08-05 23:26:4033#include "media/base/media_log.h"
sandersd1e49fb62015-12-12 01:18:0634#include "media/base/media_switches.h"
[email protected]8a561062013-11-22 01:19:3135#include "media/base/text_renderer.h"
watk9f9dfdc92015-09-04 21:33:2936#include "media/base/timestamp_constants.h"
[email protected]e81283bb2010-08-31 18:01:2137#include "media/base/video_frame.h"
acolwell9e0840d2014-09-06 19:01:3238#include "media/blink/texttrack_impl.h"
39#include "media/blink/webaudiosourceprovider_impl.h"
xhwang97de4202014-11-25 08:44:0140#include "media/blink/webcontentdecryptionmodule_impl.h"
acolwell9e0840d2014-09-06 19:01:3241#include "media/blink/webinbandtexttrack_impl.h"
42#include "media/blink/webmediaplayer_delegate.h"
acolwell9e0840d2014-09-06 19:01:3243#include "media/blink/webmediaplayer_util.h"
44#include "media/blink/webmediasource_impl.h"
[email protected]efe7cd22012-09-12 23:55:0145#include "media/filters/chunk_demuxer.h"
[email protected]ddbc6ff2013-04-19 15:28:3346#include "media/filters/ffmpeg_demuxer.h"
jrummellc9d8e532015-02-26 18:38:1947#include "third_party/WebKit/public/platform/WebEncryptedMediaTypes.h"
srirama.m26f864d02015-07-14 05:21:4648#include "third_party/WebKit/public/platform/WebMediaPlayerClient.h"
49#include "third_party/WebKit/public/platform/WebMediaPlayerEncryptedMediaClient.h"
[email protected]745746d2013-08-23 02:09:1650#include "third_party/WebKit/public/platform/WebMediaSource.h"
[email protected]c10884462013-05-30 00:22:0951#include "third_party/WebKit/public/platform/WebRect.h"
52#include "third_party/WebKit/public/platform/WebSize.h"
53#include "third_party/WebKit/public/platform/WebString.h"
54#include "third_party/WebKit/public/platform/WebURL.h"
xhwang0acca44b2015-06-18 00:43:3155#include "third_party/WebKit/public/web/WebDocument.h"
56#include "third_party/WebKit/public/web/WebFrame.h"
[email protected]80504652014-04-18 04:41:5057#include "third_party/WebKit/public/web/WebLocalFrame.h"
xhwangbab66f52014-12-02 23:49:5058#include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
[email protected]65b85282014-03-31 23:32:3159#include "third_party/WebKit/public/web/WebSecurityOrigin.h"
[email protected]2255a9332013-06-17 05:12:3160#include "third_party/WebKit/public/web/WebView.h"
[email protected]b3f2b912009-04-09 16:18:5261
[email protected]180ef242013-11-07 06:50:4662using blink::WebCanvas;
63using blink::WebMediaPlayer;
64using blink::WebRect;
65using blink::WebSize;
66using blink::WebString;
[email protected]ec9212f2008-12-18 21:40:3667
[email protected]8931c41a2009-07-07 17:31:4968namespace {
69
[email protected]378f0b72009-08-11 17:11:4270// Limits the range of playback rate.
71//
72// TODO(kylep): Revisit these.
73//
74// Vista has substantially lower performance than XP or Windows7. If you speed
75// up a video too much, it can't keep up, and rendering stops updating except on
76// the time bar. For really high speeds, audio becomes a bottleneck and we just
77// use up the data we have, which may not achieve the speed requested, but will
78// not crash the tab.
79//
80// A very slow speed, ie 0.00000001x, causes the machine to lock up. (It seems
81// like a busy loop). It gets unresponsive, although its not completely dead.
82//
83// Also our timers are not very accurate (especially for ogg), which becomes
84// evident at low speeds and on Vista. Since other speeds are risky and outside
85// the norms, we think 1/16x to 16x is a safe and useful range for now.
[email protected]39bdde32013-04-17 17:44:2086const double kMinRate = 0.0625;
87const double kMaxRate = 16.0;
[email protected]378f0b72009-08-11 17:11:4288
guidouc7babef2015-10-22 00:42:3589void SetSinkIdOnMediaThread(
90 scoped_refptr<media::WebAudioSourceProviderImpl> sink,
91 const std::string& device_id,
92 const url::Origin& security_origin,
93 const media::SwitchOutputDeviceCB& callback) {
94 if (sink->GetOutputDevice()) {
95 sink->GetOutputDevice()->SwitchOutputDevice(device_id, security_origin,
96 callback);
97 } else {
98 callback.Run(media::OUTPUT_DEVICE_STATUS_ERROR_INTERNAL);
99 }
100}
101
[email protected]8931c41a2009-07-07 17:31:49102} // namespace
103
acolwell9e0840d2014-09-06 19:01:32104namespace media {
[email protected]add51772009-06-11 18:25:17105
[email protected]6683e1b2014-04-10 01:45:38106class BufferedDataSourceHostImpl;
107
hubbe5f0ad43b2015-12-14 20:57:26108#define STATIC_ASSERT_MATCHING_ENUM(name, name2) \
109 static_assert(static_cast<int>(WebMediaPlayer::CORSMode##name) == \
110 static_cast<int>(UrlData::name2), \
mostynb502b00b2015-01-05 23:43:40111 "mismatching enum values: " #name)
hubbe5f0ad43b2015-12-14 20:57:26112STATIC_ASSERT_MATCHING_ENUM(Unspecified, CORS_UNSPECIFIED);
113STATIC_ASSERT_MATCHING_ENUM(Anonymous, CORS_ANONYMOUS);
114STATIC_ASSERT_MATCHING_ENUM(UseCredentials, CORS_USE_CREDENTIALS);
mostynb502b00b2015-01-05 23:43:40115#undef STATIC_ASSERT_MATCHING_ENUM
[email protected]a5a01102012-06-06 17:01:24116
[email protected]2c539b82012-08-18 04:10:19117#define BIND_TO_RENDER_LOOP(function) \
acolwellb4034942014-08-28 15:42:43118 (DCHECK(main_task_runner_->BelongsToCurrentThread()), \
acolwell9e0840d2014-09-06 19:01:32119 BindToCurrentLoop(base::Bind(function, AsWeakPtr())))
[email protected]5983adb2012-10-24 00:12:00120
[email protected]4e982192014-06-21 13:35:45121#define BIND_TO_RENDER_LOOP1(function, arg1) \
acolwellb4034942014-08-28 15:42:43122 (DCHECK(main_task_runner_->BelongsToCurrentThread()), \
acolwell9e0840d2014-09-06 19:01:32123 BindToCurrentLoop(base::Bind(function, AsWeakPtr(), arg1)))
[email protected]4e982192014-06-21 13:35:45124
[email protected]5b5bb9d2010-10-22 19:57:36125WebMediaPlayerImpl::WebMediaPlayerImpl(
[email protected]35b2a972014-04-04 15:50:22126 blink::WebLocalFrame* frame,
[email protected]180ef242013-11-07 06:50:46127 blink::WebMediaPlayerClient* client,
srirama.m26f864d02015-07-14 05:21:46128 blink::WebMediaPlayerEncryptedMediaClient* encrypted_client,
[email protected]b8976652011-10-26 23:46:55129 base::WeakPtr<WebMediaPlayerDelegate> delegate,
xhwang6fa356202014-12-11 00:44:12130 scoped_ptr<RendererFactory> renderer_factory,
xhwangd7180832015-04-03 05:38:15131 CdmFactory* cdm_factory,
hubbe5f0ad43b2015-12-14 20:57:26132 linked_ptr<UrlIndex> url_index,
[email protected]e82b2bd2013-01-02 17:47:57133 const WebMediaPlayerParams& params)
[email protected]f6af7592014-02-28 10:09:11134 : frame_(frame),
[email protected]ef405f66b2012-04-18 02:39:55135 network_state_(WebMediaPlayer::NetworkStateEmpty),
136 ready_state_(WebMediaPlayer::ReadyStateHaveNothing),
acolwella5081a42014-08-28 23:42:52137 preload_(BufferedDataSource::AUTO),
sandersdc6ab163a2015-12-12 03:56:13138 buffering_strategy_(
139 BufferedDataSourceInterface::BUFFERING_STRATEGY_NORMAL),
anujk.sharma2fa37a02015-04-30 05:51:32140 main_task_runner_(base::ThreadTaskRunnerHandle::Get()),
acolwell755d12d2014-08-30 01:09:19141 media_task_runner_(params.media_task_runner()),
dcastagna617d086b2015-08-20 01:39:30142 worker_task_runner_(params.worker_task_runner()),
acolwell755d12d2014-08-30 01:09:19143 media_log_(params.media_log()),
acolwellb4034942014-08-28 15:42:43144 pipeline_(media_task_runner_, media_log_.get()),
[email protected]f988d9b2014-07-25 00:35:43145 load_type_(LoadTypeURL),
[email protected]75e145a2014-04-15 17:44:32146 opaque_(false),
wolenetz1b2ae7d2015-06-10 00:44:21147 playback_rate_(0.0),
[email protected]49480902009-07-14 20:23:43148 paused_(true),
[email protected]b3766a22010-12-22 17:34:13149 seeking_(false),
sandersd1e49fb62015-12-12 01:18:06150 pending_suspend_(false),
151 pending_time_change_(false),
152 pending_resume_(false),
153 suspending_(false),
154 suspended_(false),
155 resuming_(false),
scherkusd2c745b2014-09-04 05:03:40156 ended_(false),
[email protected]5d11eff2011-09-15 00:06:06157 pending_seek_(false),
[email protected]ba7d5f92014-06-24 05:37:40158 should_notify_time_changed_(false),
[email protected]5badb082010-06-11 17:40:15159 client_(client),
srirama.m26f864d02015-07-14 05:21:46160 encrypted_client_(encrypted_client),
[email protected]baff4512011-10-19 18:21:07161 delegate_(delegate),
[email protected]d726eddc2013-07-02 22:25:55162 defer_load_cb_(params.defer_load_cb()),
dongseong.hwang0c4e9d82015-01-08 20:11:13163 context_3d_cb_(params.context_3d_cb()),
dalecurtis83266c72015-10-29 18:43:20164 adjust_allocated_memory_cb_(params.adjust_allocated_memory_cb()),
165 last_reported_memory_usage_(0),
[email protected]132dd57c2012-08-10 23:24:34166 supports_save_(true),
[email protected]f5443ef72013-04-22 04:03:38167 chunk_demuxer_(NULL),
hubbe5f0ad43b2015-12-14 20:57:26168 url_index_(url_index),
Bartosz Fabianowski85a823812015-04-16 10:27:51169 // Threaded compositing isn't enabled universally yet.
170 compositor_task_runner_(
171 params.compositor_task_runner()
172 ? params.compositor_task_runner()
173 : base::MessageLoop::current()->task_runner()),
[email protected]dd061e12014-05-06 19:21:22174 compositor_(new VideoFrameCompositor(
Bartosz Fabianowski85a823812015-04-16 10:27:51175 compositor_task_runner_,
[email protected]75e145a2014-04-15 17:44:32176 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnNaturalSizeChanged),
[email protected]dd061e12014-05-06 19:21:22177 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnOpacityChanged))),
xhwang9bd8c732015-04-13 23:27:53178 encrypted_media_support_(cdm_factory,
srirama.m26f864d02015-07-14 05:21:46179 encrypted_client,
xhwang9bd8c732015-04-13 23:27:53180 params.media_permission(),
181 base::Bind(&WebMediaPlayerImpl::SetCdm,
182 AsWeakPtr(),
183 base::Bind(&IgnoreCdmAttached))),
dcheng652f5ff2015-12-27 08:54:00184 renderer_factory_(std::move(renderer_factory)) {
dalecurtis83266c72015-10-29 18:43:20185 DCHECK(!adjust_allocated_memory_cb_.is_null());
186
sandersd1e49fb62015-12-12 01:18:06187 if (delegate)
188 delegate->AddObserver(this);
189
[email protected]c93eb0a62011-08-09 22:47:24190 media_log_->AddEvent(
acolwell9e0840d2014-09-06 19:01:32191 media_log_->CreateEvent(MediaLogEvent::WEBMEDIAPLAYER_CREATED));
[email protected]4e6be3f2009-05-07 02:24:44192
xhwang0ad11e512014-11-25 23:43:09193 if (params.initial_cdm()) {
xhwang9bd8c732015-04-13 23:27:53194 SetCdm(base::Bind(&IgnoreCdmAttached),
195 ToWebContentDecryptionModuleImpl(params.initial_cdm())
196 ->GetCdmContext());
xhwang0ad11e512014-11-25 23:43:09197 }
198
xhwangf94a634d2014-10-22 22:07:27199 // TODO(xhwang): When we use an external Renderer, many methods won't work,
xhwang6fa356202014-12-11 00:44:12200 // e.g. GetCurrentFrameFromCompositor(). See http://crbug.com/434861
[email protected]c50edb962013-10-19 18:05:07201
[email protected]ddbc6ff2013-04-19 15:28:33202 // Use the null sink if no sink was provided.
[email protected]4a914882013-01-10 00:43:48203 audio_source_provider_ = new WebAudioSourceProviderImpl(
[email protected]ff875be52013-06-02 23:47:38204 params.audio_renderer_sink().get()
205 ? params.audio_renderer_sink()
acolwell9e0840d2014-09-06 19:01:32206 : new NullAudioSink(media_task_runner_));
[email protected]ec9212f2008-12-18 21:40:36207}
208
[email protected]4e6be3f2009-05-07 02:24:44209WebMediaPlayerImpl::~WebMediaPlayerImpl() {
[email protected]ce70c982013-12-20 17:04:32210 client_->setWebLayer(NULL);
[email protected]21c3f7502013-03-23 03:29:51211
acolwellb4034942014-08-28 15:42:43212 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53213
sandersd1e49fb62015-12-12 01:18:06214 if (delegate_) {
215 delegate_->RemoveObserver(this);
[email protected]baff4512011-10-19 18:21:07216 delegate_->PlayerGone(this);
sandersd1e49fb62015-12-12 01:18:06217 }
[email protected]baff4512011-10-19 18:21:07218
[email protected]f6af7592014-02-28 10:09:11219 // Abort any pending IO so stopping the pipeline doesn't get blocked.
220 if (data_source_)
221 data_source_->Abort();
222 if (chunk_demuxer_) {
223 chunk_demuxer_->Shutdown();
224 chunk_demuxer_ = NULL;
225 }
226
xhwang6fa356202014-12-11 00:44:12227 renderer_factory_.reset();
[email protected]f6af7592014-02-28 10:09:11228
229 // Make sure to kill the pipeline so there's no more media threads running.
230 // Note: stopping the pipeline might block for a long time.
231 base::WaitableEvent waiter(false, false);
232 pipeline_.Stop(
233 base::Bind(&base::WaitableEvent::Signal, base::Unretained(&waiter)));
234 waiter.Wait();
235
dalecurtis83266c72015-10-29 18:43:20236 if (last_reported_memory_usage_)
237 adjust_allocated_memory_cb_.Run(-last_reported_memory_usage_);
238
[email protected]dd061e12014-05-06 19:21:22239 compositor_task_runner_->DeleteSoon(FROM_HERE, compositor_);
xhwangea8bb3562015-06-08 21:18:37240
241 media_log_->AddEvent(
242 media_log_->CreateEvent(MediaLogEvent::WEBMEDIAPLAYER_DESTROYED));
[email protected]ec9212f2008-12-18 21:40:36243}
244
[email protected]180ef242013-11-07 06:50:46245void WebMediaPlayerImpl::load(LoadType load_type, const blink::WebURL& url,
[email protected]62e5e682013-03-07 23:53:24246 CORSMode cors_mode) {
[email protected]2a06ca62014-06-04 13:59:52247 DVLOG(1) << __FUNCTION__ << "(" << load_type << ", " << url << ", "
248 << cors_mode << ")";
[email protected]d726eddc2013-07-02 22:25:55249 if (!defer_load_cb_.is_null()) {
250 defer_load_cb_.Run(base::Bind(
[email protected]ef8394c2013-08-21 20:26:30251 &WebMediaPlayerImpl::DoLoad, AsWeakPtr(), load_type, url, cors_mode));
[email protected]d726eddc2013-07-02 22:25:55252 return;
253 }
[email protected]ef8394c2013-08-21 20:26:30254 DoLoad(load_type, url, cors_mode);
[email protected]62e5e682013-03-07 23:53:24255}
256
[email protected]ef8394c2013-08-21 20:26:30257void WebMediaPlayerImpl::DoLoad(LoadType load_type,
[email protected]180ef242013-11-07 06:50:46258 const blink::WebURL& url,
[email protected]d726eddc2013-07-02 22:25:55259 CORSMode cors_mode) {
hubbed82bed52015-12-15 23:07:16260 DVLOG(1) << __FUNCTION__;
acolwellb4034942014-08-28 15:42:43261 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d726eddc2013-07-02 22:25:55262
[email protected]62e5e682013-03-07 23:53:24263 GURL gurl(url);
xhwang0acca44b2015-06-18 00:43:31264 ReportMetrics(load_type, gurl,
265 GURL(frame_->document().securityOrigin().toString()));
[email protected]62e5e682013-03-07 23:53:24266
[email protected]926f8fd2013-04-12 20:27:53267 // Set subresource URL for crash reporting.
268 base::debug::SetCrashKeyValue("subresource_url", gurl.spec());
269
[email protected]ef8394c2013-08-21 20:26:30270 load_type_ = load_type;
271
[email protected]62e5e682013-03-07 23:53:24272 SetNetworkState(WebMediaPlayer::NetworkStateLoading);
273 SetReadyState(WebMediaPlayer::ReadyStateHaveNothing);
kinukof19cde72015-12-18 23:15:25274 media_log_->AddEvent(media_log_->CreateLoadEvent(url.string().utf8()));
[email protected]d726eddc2013-07-02 22:25:55275
276 // Media source pipelines can start immediately.
[email protected]ef8394c2013-08-21 20:26:30277 if (load_type == LoadTypeMediaSource) {
[email protected]d726eddc2013-07-02 22:25:55278 supports_save_ = false;
[email protected]ef8394c2013-08-21 20:26:30279 StartPipeline();
[email protected]d726eddc2013-07-02 22:25:55280 return;
281 }
282
283 // Otherwise it's a regular request which requires resolving the URL first.
hubbe5f0ad43b2015-12-14 20:57:26284 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
285 switches::kUseNewMediaCache)) {
286 // Remove this when MultiBufferDataSource becomes default.
287 LOG(WARNING) << "Using MultibufferDataSource";
288 data_source_.reset(new MultibufferDataSource(
289 url, static_cast<UrlData::CORSMode>(cors_mode), main_task_runner_,
290 url_index_, frame_, media_log_.get(), &buffered_data_source_host_,
291 base::Bind(&WebMediaPlayerImpl::NotifyDownloading, AsWeakPtr())));
292 } else {
293 data_source_.reset(new BufferedDataSource(
294 url, static_cast<BufferedResourceLoader::CORSMode>(cors_mode),
295 main_task_runner_, frame_, media_log_.get(),
296 &buffered_data_source_host_,
297 base::Bind(&WebMediaPlayerImpl::NotifyDownloading, AsWeakPtr())));
298 }
dalecurtis9157fc9e2015-01-16 01:09:11299 data_source_->SetPreload(preload_);
sandersdc6ab163a2015-12-12 03:56:13300 data_source_->SetBufferingStrategy(buffering_strategy_);
[email protected]d726eddc2013-07-02 22:25:55301 data_source_->Initialize(
[email protected]fee8a902014-06-03 13:43:36302 base::Bind(&WebMediaPlayerImpl::DataSourceInitialized, AsWeakPtr()));
[email protected]62e5e682013-03-07 23:53:24303}
304
[email protected]4e6be3f2009-05-07 02:24:44305void WebMediaPlayerImpl::play() {
[email protected]2a06ca62014-06-04 13:59:52306 DVLOG(1) << __FUNCTION__;
acolwellb4034942014-08-28 15:42:43307 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53308
[email protected]49480902009-07-14 20:23:43309 paused_ = false;
[email protected]f6af7592014-02-28 10:09:11310 pipeline_.SetPlaybackRate(playback_rate_);
[email protected]039b7542013-10-17 22:06:25311 if (data_source_)
312 data_source_->MediaIsPlaying();
[email protected]090f7312011-08-05 23:26:40313
acolwell9e0840d2014-09-06 19:01:32314 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PLAY));
[email protected]baff4512011-10-19 18:21:07315
dalecurtis6d269ed2014-09-11 21:18:13316 if (delegate_ && playback_rate_ > 0)
dalecurtis0f0097a2015-12-01 17:40:47317 NotifyPlaybackStarted();
[email protected]ec9212f2008-12-18 21:40:36318}
319
[email protected]4e6be3f2009-05-07 02:24:44320void WebMediaPlayerImpl::pause() {
[email protected]2a06ca62014-06-04 13:59:52321 DVLOG(1) << __FUNCTION__;
acolwellb4034942014-08-28 15:42:43322 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53323
dalecurtis6d269ed2014-09-11 21:18:13324 const bool was_already_paused = paused_ || playback_rate_ == 0;
[email protected]49480902009-07-14 20:23:43325 paused_ = true;
a.berwal338bf002015-04-22 11:14:50326 pipeline_.SetPlaybackRate(0.0);
dalecurtis2e50e6f62015-01-09 02:42:52327 UpdatePausedTime();
[email protected]090f7312011-08-05 23:26:40328
acolwell9e0840d2014-09-06 19:01:32329 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PAUSE));
[email protected]baff4512011-10-19 18:21:07330
dalecurtis6d269ed2014-09-11 21:18:13331 if (!was_already_paused && delegate_)
dalecurtis0f0097a2015-12-01 17:40:47332 NotifyPlaybackPaused();
[email protected]ec9212f2008-12-18 21:40:36333}
334
[email protected]574a1d62009-07-17 03:23:46335bool WebMediaPlayerImpl::supportsSave() const {
acolwellb4034942014-08-28 15:42:43336 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]132dd57c2012-08-10 23:24:34337 return supports_save_;
[email protected]574a1d62009-07-17 03:23:46338}
339
[email protected]39bdde32013-04-17 17:44:20340void WebMediaPlayerImpl::seek(double seconds) {
xhwang12d8d042014-12-01 21:48:57341 DVLOG(1) << __FUNCTION__ << "(" << seconds << "s)";
acolwellb4034942014-08-28 15:42:43342 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53343
scherkusd2c745b2014-09-04 05:03:40344 ended_ = false;
345
srirama.mccf671812015-01-08 11:59:13346 ReadyState old_state = ready_state_;
[email protected]1bb666802013-11-28 06:12:08347 if (ready_state_ > WebMediaPlayer::ReadyStateHaveMetadata)
348 SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata);
349
qinminb4c39782015-08-10 18:43:24350 base::TimeDelta new_seek_time = base::TimeDelta::FromSecondsD(seconds);
[email protected]bb8a70b2013-06-26 06:23:35351
sandersd1e49fb62015-12-12 01:18:06352 if (seeking_ || suspended_) {
353 // Once resuming, it's too late to change the resume time and so the
354 // implementation is a little different.
355 bool is_suspended = suspended_ && !resuming_;
356
357 // If we are currently seeking or resuming to |new_seek_time|, skip the
358 // seek (except for MSE, which always seeks).
359 if (!is_suspended && new_seek_time == seek_time_) {
wolenetz1b2ae7d2015-06-10 00:44:21360 if (chunk_demuxer_) {
wolenetza6097972015-09-01 05:37:56361 // Don't suppress any redundant in-progress MSE seek. There could have
362 // been changes to the underlying buffers after seeking the demuxer and
363 // before receiving OnPipelineSeeked() for the currently in-progress
364 // seek.
365 MEDIA_LOG(DEBUG, media_log_)
366 << "Detected MediaSource seek to same time as in-progress seek to "
367 << seek_time_ << ".";
wolenetz1b2ae7d2015-06-10 00:44:21368 } else {
369 // Suppress all redundant seeks if unrestricted by media source demuxer
370 // API.
371 pending_seek_ = false;
372 pending_seek_time_ = base::TimeDelta();
373 return;
374 }
375 }
376
sandersd1e49fb62015-12-12 01:18:06377 // If |chunk_demuxer_| is already seeking, cancel that seek and schedule the
378 // new one.
379 if (!is_suspended && chunk_demuxer_)
380 chunk_demuxer_->CancelPendingSeek(new_seek_time);
381
382 // Schedule a seek once the current suspend or seek finishes.
[email protected]5d11eff2011-09-15 00:06:06383 pending_seek_ = true;
wolenetz1b2ae7d2015-06-10 00:44:21384 pending_seek_time_ = new_seek_time;
sandersd1e49fb62015-12-12 01:18:06385
386 // In the case of seeking while suspended, the seek is considered to have
387 // started immediately (but won't complete until the pipeline is resumed).
388 if (is_suspended) {
389 seeking_ = true;
390 seek_time_ = new_seek_time;
391 }
392
[email protected]5d11eff2011-09-15 00:06:06393 return;
394 }
395
[email protected]c93eb0a62011-08-09 22:47:24396 media_log_->AddEvent(media_log_->CreateSeekEvent(seconds));
397
[email protected]44ff37c02009-10-24 01:03:03398 // Update our paused time.
wolenetza6097972015-09-01 05:37:56399 // For non-MSE playbacks, in paused state ignore the seek operations to
400 // current time if the loading is completed and generate
401 // OnPipelineBufferingStateChanged event to eventually fire seeking and seeked
402 // events. We don't short-circuit MSE seeks in this logic because the
403 // underlying buffers around the seek time might have changed (or even been
404 // removed) since previous seek/preroll/pause action, and the pipeline might
405 // need to flush so the new buffers are decoded and rendered instead of the
406 // old ones.
srirama.m36ab2682014-12-11 04:20:01407 if (paused_) {
wolenetza6097972015-09-01 05:37:56408 if (paused_time_ != new_seek_time || chunk_demuxer_) {
wolenetz1b2ae7d2015-06-10 00:44:21409 paused_time_ = new_seek_time;
srirama.mccf671812015-01-08 11:59:13410 } else if (old_state == ReadyStateHaveEnoughData) {
srirama.m8f4a37562014-12-13 08:16:18411 main_task_runner_->PostTask(
srirama.m36ab2682014-12-11 04:20:01412 FROM_HERE,
413 base::Bind(&WebMediaPlayerImpl::OnPipelineBufferingStateChanged,
srirama.m8f4a37562014-12-13 08:16:18414 AsWeakPtr(), BUFFERING_HAVE_ENOUGH));
srirama.m36ab2682014-12-11 04:20:01415 return;
416 }
417 }
[email protected]44ff37c02009-10-24 01:03:03418
[email protected]b3766a22010-12-22 17:34:13419 seeking_ = true;
wolenetz1b2ae7d2015-06-10 00:44:21420 seek_time_ = new_seek_time;
[email protected]b3766a22010-12-22 17:34:13421
[email protected]efe7cd22012-09-12 23:55:01422 if (chunk_demuxer_)
wolenetz1b2ae7d2015-06-10 00:44:21423 chunk_demuxer_->StartWaitingForSeek(seek_time_);
[email protected]020fba32011-06-29 16:37:46424
[email protected]44ff37c02009-10-24 01:03:03425 // Kick off the asynchronous seek!
wolenetz1b2ae7d2015-06-10 00:44:21426 pipeline_.Seek(seek_time_, BIND_TO_RENDER_LOOP1(
427 &WebMediaPlayerImpl::OnPipelineSeeked, true));
[email protected]ec9212f2008-12-18 21:40:36428}
429
[email protected]39bdde32013-04-17 17:44:20430void WebMediaPlayerImpl::setRate(double rate) {
[email protected]2a06ca62014-06-04 13:59:52431 DVLOG(1) << __FUNCTION__ << "(" << rate << ")";
acolwellb4034942014-08-28 15:42:43432 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53433
[email protected]378f0b72009-08-11 17:11:42434 // TODO(kylep): Remove when support for negatives is added. Also, modify the
435 // following checks so rewind uses reasonable values also.
[email protected]39bdde32013-04-17 17:44:20436 if (rate < 0.0)
[email protected]378f0b72009-08-11 17:11:42437 return;
438
439 // Limit rates to reasonable values by clamping.
[email protected]39bdde32013-04-17 17:44:20440 if (rate != 0.0) {
[email protected]378f0b72009-08-11 17:11:42441 if (rate < kMinRate)
442 rate = kMinRate;
443 else if (rate > kMaxRate)
444 rate = kMaxRate;
dalecurtisbb761e12014-09-12 01:16:35445 if (playback_rate_ == 0 && !paused_ && delegate_)
dalecurtis0f0097a2015-12-01 17:40:47446 NotifyPlaybackStarted();
dalecurtisbb761e12014-09-12 01:16:35447 } else if (playback_rate_ != 0 && !paused_ && delegate_) {
dalecurtis0f0097a2015-12-01 17:40:47448 NotifyPlaybackPaused();
[email protected]378f0b72009-08-11 17:11:42449 }
450
[email protected]49480902009-07-14 20:23:43451 playback_rate_ = rate;
452 if (!paused_) {
[email protected]f6af7592014-02-28 10:09:11453 pipeline_.SetPlaybackRate(rate);
[email protected]039b7542013-10-17 22:06:25454 if (data_source_)
455 data_source_->MediaPlaybackRateChanged(rate);
[email protected]49480902009-07-14 20:23:43456 }
[email protected]ec9212f2008-12-18 21:40:36457}
458
[email protected]39bdde32013-04-17 17:44:20459void WebMediaPlayerImpl::setVolume(double volume) {
[email protected]2a06ca62014-06-04 13:59:52460 DVLOG(1) << __FUNCTION__ << "(" << volume << ")";
acolwellb4034942014-08-28 15:42:43461 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53462
[email protected]f6af7592014-02-28 10:09:11463 pipeline_.SetVolume(volume);
[email protected]ec9212f2008-12-18 21:40:36464}
[email protected]f0a51fb52009-03-05 12:46:38465
guidouc7babef2015-10-22 00:42:35466void WebMediaPlayerImpl::setSinkId(
467 const blink::WebString& sink_id,
468 const blink::WebSecurityOrigin& security_origin,
469 blink::WebSetSinkIdCallbacks* web_callback) {
guidou69223ce2015-06-16 10:36:19470 DCHECK(main_task_runner_->BelongsToCurrentThread());
guidou5754e612015-07-31 08:09:41471 DVLOG(1) << __FUNCTION__;
guidouc7babef2015-10-22 00:42:35472
guidou5754e612015-07-31 08:09:41473 media::SwitchOutputDeviceCB callback =
474 media::ConvertToSwitchOutputDeviceCB(web_callback);
guidouc7babef2015-10-22 00:42:35475 media_task_runner_->PostTask(
476 FROM_HERE,
477 base::Bind(&SetSinkIdOnMediaThread, audio_source_provider_,
478 sink_id.utf8(), static_cast<url::Origin>(security_origin),
479 callback));
guidou69223ce2015-06-16 10:36:19480}
481
mostynb502b00b2015-01-05 23:43:40482#define STATIC_ASSERT_MATCHING_ENUM(webkit_name, chromium_name) \
483 static_assert(static_cast<int>(WebMediaPlayer::webkit_name) == \
484 static_cast<int>(BufferedDataSource::chromium_name), \
485 "mismatching enum values: " #webkit_name)
486STATIC_ASSERT_MATCHING_ENUM(PreloadNone, NONE);
487STATIC_ASSERT_MATCHING_ENUM(PreloadMetaData, METADATA);
488STATIC_ASSERT_MATCHING_ENUM(PreloadAuto, AUTO);
489#undef STATIC_ASSERT_MATCHING_ENUM
[email protected]23a8b1d82011-04-05 16:28:20490
[email protected]ef405f66b2012-04-18 02:39:55491void WebMediaPlayerImpl::setPreload(WebMediaPlayer::Preload preload) {
[email protected]2a06ca62014-06-04 13:59:52492 DVLOG(1) << __FUNCTION__ << "(" << preload << ")";
acolwellb4034942014-08-28 15:42:43493 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]4e6be3f2009-05-07 02:24:44494
acolwella5081a42014-08-28 23:42:52495 preload_ = static_cast<BufferedDataSource::Preload>(preload);
[email protected]b49beeb2013-03-01 20:04:00496 if (data_source_)
[email protected]09c60222014-08-07 16:42:31497 data_source_->SetPreload(preload_);
[email protected]4e6be3f2009-05-07 02:24:44498}
499
sandersdc6ab163a2015-12-12 03:56:13500#define STATIC_ASSERT_MATCHING_ENUM(webkit_name, chromium_name) \
501 static_assert(static_cast<int>(WebMediaPlayer::webkit_name) == \
502 static_cast<int>(BufferedDataSource::chromium_name), \
503 "mismatching enum values: " #webkit_name)
504STATIC_ASSERT_MATCHING_ENUM(BufferingStrategy::Normal,
505 BUFFERING_STRATEGY_NORMAL);
506STATIC_ASSERT_MATCHING_ENUM(BufferingStrategy::Aggressive,
507 BUFFERING_STRATEGY_AGGRESSIVE);
508#undef STATIC_ASSERT_MATCHING_ENUM
509
510void WebMediaPlayerImpl::setBufferingStrategy(
511 WebMediaPlayer::BufferingStrategy buffering_strategy) {
512 DVLOG(1) << __FUNCTION__;
513 DCHECK(main_task_runner_->BelongsToCurrentThread());
514
515 buffering_strategy_ =
516 static_cast<BufferedDataSource::BufferingStrategy>(buffering_strategy);
517 if (data_source_)
518 data_source_->SetBufferingStrategy(buffering_strategy_);
519}
520
[email protected]4e6be3f2009-05-07 02:24:44521bool WebMediaPlayerImpl::hasVideo() const {
acolwellb4034942014-08-28 15:42:43522 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53523
[email protected]b8877772014-03-26 20:17:15524 return pipeline_metadata_.has_video;
[email protected]d43ed912009-02-03 04:52:53525}
526
[email protected]fc367af2009-08-14 23:06:35527bool WebMediaPlayerImpl::hasAudio() const {
acolwellb4034942014-08-28 15:42:43528 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]fc367af2009-08-14 23:06:35529
[email protected]b8877772014-03-26 20:17:15530 return pipeline_metadata_.has_audio;
[email protected]fc367af2009-08-14 23:06:35531}
532
[email protected]180ef242013-11-07 06:50:46533blink::WebSize WebMediaPlayerImpl::naturalSize() const {
acolwellb4034942014-08-28 15:42:43534 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53535
[email protected]b8877772014-03-26 20:17:15536 return blink::WebSize(pipeline_metadata_.natural_size);
[email protected]d43ed912009-02-03 04:52:53537}
538
[email protected]4e6be3f2009-05-07 02:24:44539bool WebMediaPlayerImpl::paused() const {
acolwellb4034942014-08-28 15:42:43540 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53541
[email protected]f6af7592014-02-28 10:09:11542 return pipeline_.GetPlaybackRate() == 0.0f;
[email protected]d43ed912009-02-03 04:52:53543}
544
[email protected]4e6be3f2009-05-07 02:24:44545bool WebMediaPlayerImpl::seeking() const {
acolwellb4034942014-08-28 15:42:43546 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53547
[email protected]ef405f66b2012-04-18 02:39:55548 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing)
[email protected]0acebfa2009-08-21 22:45:40549 return false;
[email protected]67cd5052009-09-10 21:53:22550
[email protected]b3766a22010-12-22 17:34:13551 return seeking_;
[email protected]ec9212f2008-12-18 21:40:36552}
553
[email protected]39bdde32013-04-17 17:44:20554double WebMediaPlayerImpl::duration() const {
acolwellb4034942014-08-28 15:42:43555 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]39bdde32013-04-17 17:44:20556
557 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing)
558 return std::numeric_limits<double>::quiet_NaN();
559
[email protected]39bdde32013-04-17 17:44:20560 return GetPipelineDuration();
[email protected]d43ed912009-02-03 04:52:53561}
562
[email protected]db66d0092014-04-16 07:15:12563double WebMediaPlayerImpl::timelineOffset() const {
acolwellb4034942014-08-28 15:42:43564 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]db66d0092014-04-16 07:15:12565
566 if (pipeline_metadata_.timeline_offset.is_null())
567 return std::numeric_limits<double>::quiet_NaN();
568
569 return pipeline_metadata_.timeline_offset.ToJsTime();
570}
571
[email protected]39bdde32013-04-17 17:44:20572double WebMediaPlayerImpl::currentTime() const {
acolwellb4034942014-08-28 15:42:43573 DCHECK(main_task_runner_->BelongsToCurrentThread());
scherkusd2c745b2014-09-04 05:03:40574 DCHECK_NE(ready_state_, WebMediaPlayer::ReadyStateHaveNothing);
575
576 // TODO(scherkus): Replace with an explicit ended signal to HTMLMediaElement,
577 // see http://crbug.com/409280
578 if (ended_)
579 return duration();
580
wolenetz1b2ae7d2015-06-10 00:44:21581 // We know the current seek time better than pipeline: pipeline may processing
582 // an earlier seek before a pending seek has been started, or it might not yet
583 // have the current seek time returnable via GetMediaTime().
584 if (seeking()) {
585 return pending_seek_ ? pending_seek_time_.InSecondsF()
586 : seek_time_.InSecondsF();
587 }
588
[email protected]f6af7592014-02-28 10:09:11589 return (paused_ ? paused_time_ : pipeline_.GetMediaTime()).InSecondsF();
[email protected]d43ed912009-02-03 04:52:53590}
591
[email protected]ef405f66b2012-04-18 02:39:55592WebMediaPlayer::NetworkState WebMediaPlayerImpl::networkState() const {
acolwellb4034942014-08-28 15:42:43593 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]ddb1e5a2010-12-13 20:10:45594 return network_state_;
595}
596
[email protected]ef405f66b2012-04-18 02:39:55597WebMediaPlayer::ReadyState WebMediaPlayerImpl::readyState() const {
acolwellb4034942014-08-28 15:42:43598 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]ddb1e5a2010-12-13 20:10:45599 return ready_state_;
600}
601
[email protected]02022fc2014-05-16 00:05:31602blink::WebTimeRanges WebMediaPlayerImpl::buffered() const {
acolwellb4034942014-08-28 15:42:43603 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]779a8322014-08-22 21:28:37604
acolwell9e0840d2014-09-06 19:01:32605 Ranges<base::TimeDelta> buffered_time_ranges =
[email protected]02022fc2014-05-16 00:05:31606 pipeline_.GetBufferedTimeRanges();
[email protected]779a8322014-08-22 21:28:37607
608 const base::TimeDelta duration = pipeline_.GetMediaDuration();
acolwell9e0840d2014-09-06 19:01:32609 if (duration != kInfiniteDuration()) {
[email protected]779a8322014-08-22 21:28:37610 buffered_data_source_host_.AddBufferedTimeRanges(
611 &buffered_time_ranges, duration);
612 }
[email protected]02022fc2014-05-16 00:05:31613 return ConvertToWebTimeRanges(buffered_time_ranges);
614}
615
philipjb0e6f3f2014-09-30 09:51:53616blink::WebTimeRanges WebMediaPlayerImpl::seekable() const {
acolwellb4034942014-08-28 15:42:43617 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]39bdde32013-04-17 17:44:20618
dalecurtis56359cb2014-10-28 00:06:29619 if (ready_state_ < WebMediaPlayer::ReadyStateHaveMetadata)
philipjb0e6f3f2014-09-30 09:51:53620 return blink::WebTimeRanges();
621
dalecurtis56359cb2014-10-28 00:06:29622 const double seekable_end = duration();
623
624 // Allow a special exception for seeks to zero for streaming sources with a
625 // finite duration; this allows looping to work.
626 const bool allow_seek_to_zero = data_source_ && data_source_->IsStreaming() &&
mateuszs3371ab02015-04-24 13:20:23627 std::isfinite(seekable_end);
dalecurtis56359cb2014-10-28 00:06:29628
629 // TODO(dalecurtis): Technically this allows seeking on media which return an
630 // infinite duration so long as DataSource::IsStreaming() is false. While not
631 // expected, disabling this breaks semi-live players, http://crbug.com/427412.
632 const blink::WebTimeRange seekable_range(
633 0.0, allow_seek_to_zero ? 0.0 : seekable_end);
philipjb0e6f3f2014-09-30 09:51:53634 return blink::WebTimeRanges(&seekable_range, 1);
[email protected]ec9212f2008-12-18 21:40:36635}
636
[email protected]5d2b3e4c2014-05-12 23:27:30637bool WebMediaPlayerImpl::didLoadingProgress() {
acolwellb4034942014-08-28 15:42:43638 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]6683e1b2014-04-10 01:45:38639 bool pipeline_progress = pipeline_.DidLoadingProgress();
640 bool data_progress = buffered_data_source_host_.DidLoadingProgress();
641 return pipeline_progress || data_progress;
[email protected]d43ed912009-02-03 04:52:53642}
643
[email protected]dd5c7972014-08-21 15:00:37644void WebMediaPlayerImpl::paint(blink::WebCanvas* canvas,
645 const blink::WebRect& rect,
[email protected]dd5c7972014-08-21 15:00:37646 unsigned char alpha,
647 SkXfermode::Mode mode) {
acolwellb4034942014-08-28 15:42:43648 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]dd061e12014-05-06 19:21:22649 TRACE_EVENT0("media", "WebMediaPlayerImpl:paint");
[email protected]4e6be3f2009-05-07 02:24:44650
[email protected]5e1502e2014-03-24 22:48:44651 // TODO(scherkus): Clarify paint() API contract to better understand when and
652 // why it's being called. For example, today paint() is called when:
653 // - We haven't reached HAVE_CURRENT_DATA and need to paint black
654 // - We're painting to a canvas
655 // See http://crbug.com/341225 http://crbug.com/342621 for details.
mcasasf1236fc22015-05-29 22:38:56656 scoped_refptr<VideoFrame> video_frame = GetCurrentFrameFromCompositor();
[email protected]0fe5d43b2014-01-24 23:32:45657
[email protected]b49beeb2013-03-01 20:04:00658 gfx::Rect gfx_rect(rect);
dongseong.hwang0c4e9d82015-01-08 20:11:13659 Context3D context_3d;
mcasas265bdbf82015-06-12 18:44:07660 if (video_frame.get() && video_frame->HasTextures()) {
mcasasf1236fc22015-05-29 22:38:56661 if (!context_3d_cb_.is_null())
dongseong.hwang0c4e9d82015-01-08 20:11:13662 context_3d = context_3d_cb_.Run();
dongseong.hwang0c4e9d82015-01-08 20:11:13663 // GPU Process crashed.
664 if (!context_3d.gl)
665 return;
666 }
danakj795f1732015-08-31 23:40:22667 skcanvas_video_renderer_.Paint(video_frame, canvas, gfx::RectF(gfx_rect),
668 alpha, mode, pipeline_metadata_.video_rotation,
669 context_3d);
[email protected]ec9212f2008-12-18 21:40:36670}
[email protected]5df51652009-01-17 00:03:00671
[email protected]38259a7a82009-07-29 21:49:49672bool WebMediaPlayerImpl::hasSingleSecurityOrigin() const {
[email protected]b49beeb2013-03-01 20:04:00673 if (data_source_)
674 return data_source_->HasSingleOrigin();
[email protected]fcdb7462009-10-21 21:05:11675 return true;
[email protected]38259a7a82009-07-29 21:49:49676}
677
[email protected]3fe27112012-06-07 04:00:01678bool WebMediaPlayerImpl::didPassCORSAccessCheck() const {
[email protected]b49beeb2013-03-01 20:04:00679 if (data_source_)
680 return data_source_->DidPassCORSAccessCheck();
681 return false;
[email protected]3fe27112012-06-07 04:00:01682}
683
[email protected]39bdde32013-04-17 17:44:20684double WebMediaPlayerImpl::mediaTimeForTimeValue(double timeValue) const {
qinminb4c39782015-08-10 18:43:24685 return base::TimeDelta::FromSecondsD(timeValue).InSecondsF();
[email protected]e06e16d82011-05-26 22:13:33686}
687
[email protected]d82b18ae2011-03-23 21:28:59688unsigned WebMediaPlayerImpl::decodedFrameCount() const {
acolwellb4034942014-08-28 15:42:43689 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]4c51bc662011-02-16 02:03:16690
acolwell9e0840d2014-09-06 19:01:32691 PipelineStatistics stats = pipeline_.GetStatistics();
[email protected]4c51bc662011-02-16 02:03:16692 return stats.video_frames_decoded;
693}
694
[email protected]d82b18ae2011-03-23 21:28:59695unsigned WebMediaPlayerImpl::droppedFrameCount() const {
acolwellb4034942014-08-28 15:42:43696 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]4c51bc662011-02-16 02:03:16697
acolwell9e0840d2014-09-06 19:01:32698 PipelineStatistics stats = pipeline_.GetStatistics();
[email protected]dd061e12014-05-06 19:21:22699 return stats.video_frames_dropped;
[email protected]4c51bc662011-02-16 02:03:16700}
701
[email protected]d82b18ae2011-03-23 21:28:59702unsigned WebMediaPlayerImpl::audioDecodedByteCount() const {
acolwellb4034942014-08-28 15:42:43703 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]4c51bc662011-02-16 02:03:16704
acolwell9e0840d2014-09-06 19:01:32705 PipelineStatistics stats = pipeline_.GetStatistics();
[email protected]4c51bc662011-02-16 02:03:16706 return stats.audio_bytes_decoded;
707}
708
[email protected]d82b18ae2011-03-23 21:28:59709unsigned WebMediaPlayerImpl::videoDecodedByteCount() const {
acolwellb4034942014-08-28 15:42:43710 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]4c51bc662011-02-16 02:03:16711
acolwell9e0840d2014-09-06 19:01:32712 PipelineStatistics stats = pipeline_.GetStatistics();
[email protected]4c51bc662011-02-16 02:03:16713 return stats.video_bytes_decoded;
714}
715
[email protected]6523b242013-03-13 11:10:07716bool WebMediaPlayerImpl::copyVideoTextureToPlatformTexture(
[email protected]180ef242013-11-07 06:50:46717 blink::WebGraphicsContext3D* web_graphics_context,
zmo57d577a2015-10-30 18:28:59718 unsigned int texture,
719 unsigned int internal_format,
720 unsigned int type,
721 bool premultiply_alpha,
722 bool flip_y) {
[email protected]bfc05f22013-10-19 17:55:16723 TRACE_EVENT0("media", "WebMediaPlayerImpl:copyVideoTextureToPlatformTexture");
724
mcasasf1236fc22015-05-29 22:38:56725 scoped_refptr<VideoFrame> video_frame = GetCurrentFrameFromCompositor();
[email protected]dd061e12014-05-06 19:21:22726
mcasas265bdbf82015-06-12 18:44:07727 if (!video_frame.get() || !video_frame->HasTextures() ||
dcastagna31a65d432015-06-11 19:01:00728 media::VideoFrame::NumPlanes(video_frame->format()) != 1) {
[email protected]e56f88c72013-06-25 22:31:29729 return false;
dongseong.hwang0c4e9d82015-01-08 20:11:13730 }
[email protected]df41e252014-02-03 23:39:50731
dongseong.hwang0c4e9d82015-01-08 20:11:13732 // TODO(dshwang): need more elegant way to convert WebGraphicsContext3D to
733 // GLES2Interface.
734 gpu::gles2::GLES2Interface* gl =
735 static_cast<gpu_blink::WebGraphicsContext3DImpl*>(web_graphics_context)
736 ->GetGLInterface();
dcastagna31a65d432015-06-11 19:01:00737 SkCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture(
zmo57d577a2015-10-30 18:28:59738 gl, video_frame.get(), texture, internal_format, type, premultiply_alpha,
739 flip_y);
[email protected]e56f88c72013-06-25 22:31:29740 return true;
[email protected]6523b242013-03-13 11:10:07741}
742
[email protected]2ca7d5c2012-10-23 07:30:54743WebMediaPlayer::MediaKeyException
[email protected]f7a6b992012-04-19 09:45:56744WebMediaPlayerImpl::generateKeyRequest(const WebString& key_system,
745 const unsigned char* init_data,
746 unsigned init_data_length) {
acolwellb4034942014-08-28 15:42:43747 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]7502ef12014-01-25 01:19:27748
xhwang16ff1362014-11-19 00:16:34749 return encrypted_media_support_.GenerateKeyRequest(
acolwelle2ea5182014-08-25 23:01:07750 frame_, key_system, init_data, init_data_length);
[email protected]f7a6b992012-04-19 09:45:56751}
752
[email protected]2ca7d5c2012-10-23 07:30:54753WebMediaPlayer::MediaKeyException WebMediaPlayerImpl::addKey(
754 const WebString& key_system,
755 const unsigned char* key,
756 unsigned key_length,
757 const unsigned char* init_data,
758 unsigned init_data_length,
759 const WebString& session_id) {
acolwellb4034942014-08-28 15:42:43760 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]f7a6b992012-04-19 09:45:56761
xhwang16ff1362014-11-19 00:16:34762 return encrypted_media_support_.AddKey(
acolwelle2ea5182014-08-25 23:01:07763 key_system, key, key_length, init_data, init_data_length, session_id);
[email protected]f7a6b992012-04-19 09:45:56764}
765
[email protected]2ca7d5c2012-10-23 07:30:54766WebMediaPlayer::MediaKeyException WebMediaPlayerImpl::cancelKeyRequest(
767 const WebString& key_system,
768 const WebString& session_id) {
acolwellb4034942014-08-28 15:42:43769 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]0b9999d2014-02-20 02:16:11770
xhwang16ff1362014-11-19 00:16:34771 return encrypted_media_support_.CancelKeyRequest(key_system, session_id);
[email protected]f7a6b992012-04-19 09:45:56772}
773
[email protected]7bce1832014-01-09 00:01:22774void WebMediaPlayerImpl::setContentDecryptionModule(
[email protected]9ebc3b03f2014-08-13 04:01:23775 blink::WebContentDecryptionModule* cdm,
776 blink::WebContentDecryptionModuleResult result) {
acolwellb4034942014-08-28 15:42:43777 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]9ebc3b03f2014-08-13 04:01:23778
jrummell06f27072015-06-08 18:12:38779 // Once the CDM is set it can't be cleared as there may be frames being
780 // decrypted on other threads. So fail this request.
781 // http://crbug.com/462365#c7.
xhwang97de4202014-11-25 08:44:01782 if (!cdm) {
783 result.completeWithError(
jrummell06f27072015-06-08 18:12:38784 blink::WebContentDecryptionModuleExceptionInvalidStateError, 0,
785 "The existing MediaKeys object cannot be removed at this time.");
xhwang97de4202014-11-25 08:44:01786 return;
787 }
788
jrummell89e61d82015-07-23 20:03:34789 // Although unlikely, it is possible that multiple calls happen
790 // simultaneously, so fail this call if there is already one pending.
791 if (set_cdm_result_) {
792 result.completeWithError(
793 blink::WebContentDecryptionModuleExceptionInvalidStateError, 0,
794 "Unable to set MediaKeys object at this time.");
795 return;
796 }
797
798 // Create a local copy of |result| to avoid problems with the callback
799 // getting passed to the media thread and causing |result| to be destructed
800 // on the wrong thread in some failure conditions.
801 set_cdm_result_.reset(new blink::WebContentDecryptionModuleResult(result));
802
803 SetCdm(BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnCdmAttached),
xhwang9bd8c732015-04-13 23:27:53804 ToWebContentDecryptionModuleImpl(cdm)->GetCdmContext());
xhwang97de4202014-11-25 08:44:01805}
806
xhwange8c4181a2014-12-06 08:10:01807void WebMediaPlayerImpl::OnEncryptedMediaInitData(
jrummellcf78967c2015-04-03 05:03:58808 EmeInitDataType init_data_type,
Avi Drissman97785ea2015-12-19 01:11:31809 const std::vector<uint8_t>& init_data) {
jrummellcf78967c2015-04-03 05:03:58810 DCHECK(init_data_type != EmeInitDataType::UNKNOWN);
xhwangbab66f52014-12-02 23:49:50811
xhwange8c4181a2014-12-06 08:10:01812 // Do not fire "encrypted" event if encrypted media is not enabled.
xhwangbab66f52014-12-02 23:49:50813 // TODO(xhwang): Handle this in |client_|.
814 if (!blink::WebRuntimeFeatures::isPrefixedEncryptedMediaEnabled() &&
815 !blink::WebRuntimeFeatures::isEncryptedMediaEnabled()) {
816 return;
817 }
818
xhwange8c4181a2014-12-06 08:10:01819 // TODO(xhwang): Update this UMA name.
xhwangbab66f52014-12-02 23:49:50820 UMA_HISTOGRAM_COUNTS("Media.EME.NeedKey", 1);
821
822 encrypted_media_support_.SetInitDataType(init_data_type);
823
srirama.m26f864d02015-07-14 05:21:46824 encrypted_client_->encrypted(
davidbenb50f00c2015-12-01 00:01:50825 ConvertToWebInitDataType(init_data_type), init_data.data(),
srirama.m26f864d02015-07-14 05:21:46826 base::saturated_cast<unsigned int>(init_data.size()));
xhwangbab66f52014-12-02 23:49:50827}
828
jrummell74fc4f942015-03-02 22:48:27829void WebMediaPlayerImpl::OnWaitingForDecryptionKey() {
srirama.m26f864d02015-07-14 05:21:46830 encrypted_client_->didBlockPlaybackWaitingForKey();
jrummell74fc4f942015-03-02 22:48:27831
832 // TODO(jrummell): didResumePlaybackBlockedForKey() should only be called
833 // when a key has been successfully added (e.g. OnSessionKeysChange() with
834 // |has_additional_usable_key| = true). http://crbug.com/461903
srirama.m26f864d02015-07-14 05:21:46835 encrypted_client_->didResumePlaybackBlockedForKey();
jrummell74fc4f942015-03-02 22:48:27836}
837
xhwang9bd8c732015-04-13 23:27:53838void WebMediaPlayerImpl::SetCdm(const CdmAttachedCB& cdm_attached_cb,
839 CdmContext* cdm_context) {
jrummell87a2db52015-05-05 22:27:18840 // If CDM initialization succeeded, tell the pipeline about it.
841 if (cdm_context)
842 pipeline_.SetCdm(cdm_context, cdm_attached_cb);
xhwang97de4202014-11-25 08:44:01843}
844
jrummell89e61d82015-07-23 20:03:34845void WebMediaPlayerImpl::OnCdmAttached(bool success) {
xhwang97de4202014-11-25 08:44:01846 if (success) {
jrummell89e61d82015-07-23 20:03:34847 set_cdm_result_->complete();
848 set_cdm_result_.reset();
xhwang97de4202014-11-25 08:44:01849 return;
850 }
851
jrummell89e61d82015-07-23 20:03:34852 set_cdm_result_->completeWithError(
xhwang97de4202014-11-25 08:44:01853 blink::WebContentDecryptionModuleExceptionNotSupportedError, 0,
854 "Unable to set MediaKeys object");
jrummell89e61d82015-07-23 20:03:34855 set_cdm_result_.reset();
[email protected]9ebc3b03f2014-08-13 04:01:23856}
857
[email protected]4e982192014-06-21 13:35:45858void WebMediaPlayerImpl::OnPipelineSeeked(bool time_changed,
859 PipelineStatus status) {
860 DVLOG(1) << __FUNCTION__ << "(" << time_changed << ", " << status << ")";
acolwellb4034942014-08-28 15:42:43861 DCHECK(main_task_runner_->BelongsToCurrentThread());
sandersd1e49fb62015-12-12 01:18:06862
863 if (status != PIPELINE_OK) {
864 OnPipelineError(status);
865 return;
866 }
867
868 // Whether or not the seek was caused by a resume, we're not suspended now.
869 resuming_ = false;
870 suspended_ = false;
871
872 // If there is a pending suspend, the seek does not complete until after the
873 // next resume.
874 if (pending_suspend_) {
875 pending_suspend_ = false;
876 pending_time_change_ = time_changed;
877 Suspend();
878 return;
879 }
880
881 // Clear seek state. Note that if the seek was caused by a resume, then
882 // |seek_time_| is always set but |seeking_| is only set if there was a
883 // pending seek at the time.
[email protected]5d11eff2011-09-15 00:06:06884 seeking_ = false;
wolenetz1b2ae7d2015-06-10 00:44:21885 seek_time_ = base::TimeDelta();
sandersd1e49fb62015-12-12 01:18:06886
[email protected]5d11eff2011-09-15 00:06:06887 if (pending_seek_) {
wolenetz1b2ae7d2015-06-10 00:44:21888 double pending_seek_seconds = pending_seek_time_.InSecondsF();
[email protected]5d11eff2011-09-15 00:06:06889 pending_seek_ = false;
wolenetz1b2ae7d2015-06-10 00:44:21890 pending_seek_time_ = base::TimeDelta();
891 seek(pending_seek_seconds);
[email protected]5d11eff2011-09-15 00:06:06892 return;
893 }
894
[email protected]10a64d92012-04-10 21:08:02895 // Update our paused time.
896 if (paused_)
dalecurtis2e50e6f62015-01-09 02:42:52897 UpdatePausedTime();
[email protected]10a64d92012-04-10 21:08:02898
[email protected]ba7d5f92014-06-24 05:37:40899 should_notify_time_changed_ = time_changed;
[email protected]8931c41a2009-07-07 17:31:49900}
901
sandersd1e49fb62015-12-12 01:18:06902void WebMediaPlayerImpl::OnPipelineSuspended(PipelineStatus status) {
903 DVLOG(1) << __FUNCTION__ << "(" << status << ")";
904 DCHECK(main_task_runner_->BelongsToCurrentThread());
905
906 if (status != PIPELINE_OK) {
907 OnPipelineError(status);
908 return;
909 }
910
911 suspending_ = false;
912
913 if (pending_resume_) {
914 pending_resume_ = false;
915 Resume();
916 return;
917 }
918}
919
[email protected]6954fe12013-01-03 03:22:32920void WebMediaPlayerImpl::OnPipelineEnded() {
[email protected]2a06ca62014-06-04 13:59:52921 DVLOG(1) << __FUNCTION__;
acolwellb4034942014-08-28 15:42:43922 DCHECK(main_task_runner_->BelongsToCurrentThread());
scherkusd2c745b2014-09-04 05:03:40923
924 // Ignore state changes until we've completed all outstanding seeks.
925 if (seeking_ || pending_seek_)
926 return;
927
928 ended_ = true;
[email protected]ce70c982013-12-20 17:04:32929 client_->timeChanged();
[email protected]576537842009-08-12 23:52:05930}
931
[email protected]a9590c22011-03-16 16:57:02932void WebMediaPlayerImpl::OnPipelineError(PipelineStatus error) {
hubbed82bed52015-12-15 23:07:16933 DVLOG(1) << __FUNCTION__;
acolwellb4034942014-08-28 15:42:43934 DCHECK(main_task_runner_->BelongsToCurrentThread());
acolwell9e0840d2014-09-06 19:01:32935 DCHECK_NE(error, PIPELINE_OK);
[email protected]a8e2cb82012-08-17 00:02:39936
937 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing) {
938 // Any error that occurs before reaching ReadyStateHaveMetadata should
939 // be considered a format error.
940 SetNetworkState(WebMediaPlayer::NetworkStateFormatError);
[email protected]a8e2cb82012-08-17 00:02:39941 return;
942 }
943
[email protected]be57ee52013-05-28 22:27:27944 SetNetworkState(PipelineErrorToNetworkState(error));
[email protected]db190487d2009-07-30 18:51:52945}
946
[email protected]b8877772014-03-26 20:17:15947void WebMediaPlayerImpl::OnPipelineMetadata(
acolwell9e0840d2014-09-06 19:01:32948 PipelineMetadata metadata) {
[email protected]2a06ca62014-06-04 13:59:52949 DVLOG(1) << __FUNCTION__;
[email protected]a8e2cb82012-08-17 00:02:39950
[email protected]b8877772014-03-26 20:17:15951 pipeline_metadata_ = metadata;
[email protected]739847c02014-01-16 00:12:25952
dalecurtis849cf4b22015-03-27 18:35:45953 UMA_HISTOGRAM_ENUMERATION("Media.VideoRotation", metadata.video_rotation,
acolwell9e0840d2014-09-06 19:01:32954 VIDEO_ROTATION_MAX + 1);
[email protected]b8877772014-03-26 20:17:15955 SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata);
[email protected]21c3f7502013-03-23 03:29:51956
[email protected]b8877772014-03-26 20:17:15957 if (hasVideo()) {
958 DCHECK(!video_weblayer_);
[email protected]f78c3e82014-08-08 01:24:47959 scoped_refptr<cc::VideoLayer> layer =
loysoa6edaaff2015-05-25 03:26:44960 cc::VideoLayer::Create(cc_blink::WebLayerImpl::LayerSettings(),
961 compositor_, pipeline_metadata_.video_rotation);
[email protected]f78c3e82014-08-08 01:24:47962
acolwell9e0840d2014-09-06 19:01:32963 if (pipeline_metadata_.video_rotation == VIDEO_ROTATION_90 ||
964 pipeline_metadata_.video_rotation == VIDEO_ROTATION_270) {
[email protected]f78c3e82014-08-08 01:24:47965 gfx::Size size = pipeline_metadata_.natural_size;
966 pipeline_metadata_.natural_size = gfx::Size(size.height(), size.width());
967 }
968
[email protected]38564622014-08-19 02:47:18969 video_weblayer_.reset(new cc_blink::WebLayerImpl(layer));
jbauman952274d2015-09-10 23:23:36970 video_weblayer_->layer()->SetContentsOpaque(opaque_);
971 video_weblayer_->SetContentsOpaqueIsFixed(true);
[email protected]a7c4f582014-04-16 18:44:49972 client_->setWebLayer(video_weblayer_.get());
[email protected]a8e2cb82012-08-17 00:02:39973 }
[email protected]a8e2cb82012-08-17 00:02:39974}
975
[email protected]ba7d5f92014-06-24 05:37:40976void WebMediaPlayerImpl::OnPipelineBufferingStateChanged(
acolwell9e0840d2014-09-06 19:01:32977 BufferingState buffering_state) {
[email protected]ba7d5f92014-06-24 05:37:40978 DVLOG(1) << __FUNCTION__ << "(" << buffering_state << ")";
[email protected]b8877772014-03-26 20:17:15979
[email protected]ba7d5f92014-06-24 05:37:40980 // Ignore buffering state changes until we've completed all outstanding seeks.
981 if (seeking_ || pending_seek_)
982 return;
[email protected]b8877772014-03-26 20:17:15983
[email protected]ba7d5f92014-06-24 05:37:40984 // TODO(scherkus): Handle other buffering states when Pipeline starts using
985 // them and translate them ready state changes http://crbug.com/144683
acolwell9e0840d2014-09-06 19:01:32986 DCHECK_EQ(buffering_state, BUFFERING_HAVE_ENOUGH);
[email protected]ba7d5f92014-06-24 05:37:40987 SetReadyState(WebMediaPlayer::ReadyStateHaveEnoughData);
988
dalecurtis849cf4b22015-03-27 18:35:45989 // Let the DataSource know we have enough data. It may use this information to
990 // release unused network connections.
991 if (data_source_)
992 data_source_->OnBufferingHaveEnough();
993
[email protected]ba7d5f92014-06-24 05:37:40994 // Blink expects a timeChanged() in response to a seek().
995 if (should_notify_time_changed_)
996 client_->timeChanged();
dalecurtis0f0097a2015-12-01 17:40:47997
998 // Once we have enough, start reporting the total memory usage. We'll also
999 // report once playback starts.
1000 ReportMemoryUsage();
[email protected]b8877772014-03-26 20:17:151001}
1002
[email protected]ef8394c2013-08-21 20:26:301003void WebMediaPlayerImpl::OnDemuxerOpened() {
acolwellb4034942014-08-28 15:42:431004 DCHECK(main_task_runner_->BelongsToCurrentThread());
wolenetz1fb319d2015-07-14 17:49:041005 client_->mediaSourceOpened(
1006 new WebMediaSourceImpl(chunk_demuxer_, media_log_));
[email protected]81bb3322011-07-21 15:55:501007}
1008
[email protected]8a561062013-11-22 01:19:311009void WebMediaPlayerImpl::OnAddTextTrack(
acolwell9e0840d2014-09-06 19:01:321010 const TextTrackConfig& config,
1011 const AddTextTrackDoneCB& done_cb) {
acolwellb4034942014-08-28 15:42:431012 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]71537722013-05-23 06:47:531013
[email protected]8a561062013-11-22 01:19:311014 const WebInbandTextTrackImpl::Kind web_kind =
1015 static_cast<WebInbandTextTrackImpl::Kind>(config.kind());
1016 const blink::WebString web_label =
1017 blink::WebString::fromUTF8(config.label());
1018 const blink::WebString web_language =
1019 blink::WebString::fromUTF8(config.language());
[email protected]427ff102013-11-26 23:45:401020 const blink::WebString web_id =
1021 blink::WebString::fromUTF8(config.id());
[email protected]71537722013-05-23 06:47:531022
[email protected]8a561062013-11-22 01:19:311023 scoped_ptr<WebInbandTextTrackImpl> web_inband_text_track(
henriks9cce5fa2014-12-12 09:35:301024 new WebInbandTextTrackImpl(web_kind, web_label, web_language, web_id));
[email protected]8a561062013-11-22 01:19:311025
acolwell9e0840d2014-09-06 19:01:321026 scoped_ptr<TextTrack> text_track(new TextTrackImpl(
dcheng652f5ff2015-12-27 08:54:001027 main_task_runner_, client_, std::move(web_inband_text_track)));
[email protected]8a561062013-11-22 01:19:311028
dcheng652f5ff2015-12-27 08:54:001029 done_cb.Run(std::move(text_track));
[email protected]71537722013-05-23 06:47:531030}
1031
sandersd1e49fb62015-12-12 01:18:061032void WebMediaPlayerImpl::OnHidden() {
1033 DCHECK(main_task_runner_->BelongsToCurrentThread());
1034
1035#if !defined(OS_ANDROID)
1036 // Suspend/Resume is enabled by default on Android.
1037 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
1038 switches::kEnableMediaSuspend)) {
1039 return;
1040 }
1041#endif // !defined(OS_ANDROID)
1042
1043 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1044 switches::kDisableMediaSuspend)) {
1045 return;
1046 }
1047
1048 if (!pipeline_.IsRunning())
1049 return;
1050
1051 if (resuming_ || seeking_) {
1052 pending_suspend_ = true;
1053 return;
1054 }
1055
1056 if (pending_resume_) {
1057 pending_resume_ = false;
1058 return;
1059 }
1060
1061 Suspend();
1062}
1063
1064void WebMediaPlayerImpl::Suspend() {
1065 DCHECK(main_task_runner_->BelongsToCurrentThread());
1066 CHECK(!suspended_);
1067 suspended_ = true;
1068 suspending_ = true;
1069 pipeline_.Suspend(
1070 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineSuspended));
1071}
1072
1073void WebMediaPlayerImpl::OnShown() {
1074 DCHECK(main_task_runner_->BelongsToCurrentThread());
1075
1076#if !defined(OS_ANDROID)
1077 // Suspend/Resume is enabled by default on Android.
1078 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
1079 switches::kEnableMediaSuspend)) {
1080 return;
1081 }
1082#endif // !defined(OS_ANDROID)
1083
1084 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1085 switches::kDisableMediaSuspend)) {
1086 return;
1087 }
1088
1089 if (!pipeline_.IsRunning())
1090 return;
1091
1092 if (suspending_) {
1093 pending_resume_ = true;
1094 return;
1095 }
1096
1097 if (pending_suspend_) {
1098 pending_suspend_ = false;
1099 return;
1100 }
1101
1102 // We may not be suspended if we were not yet subscribed or the pipeline was
1103 // not yet started when OnHidden() fired.
1104 if (!suspended_)
1105 return;
1106
1107 Resume();
1108}
1109
1110void WebMediaPlayerImpl::Resume() {
1111 DCHECK(main_task_runner_->BelongsToCurrentThread());
1112 CHECK(suspended_);
1113 CHECK(!resuming_);
1114
1115 // If there was a time change pending when we suspended (which can happen when
1116 // we suspend immediately after a seek), surface it after resuming.
1117 bool time_changed = pending_time_change_;
1118 pending_time_change_ = false;
1119
1120 if (seeking_ || pending_seek_) {
1121 if (pending_seek_) {
1122 seek_time_ = pending_seek_time_;
1123 pending_seek_ = false;
1124 pending_seek_time_ = base::TimeDelta();
1125 }
1126 time_changed = true;
1127 } else {
1128 // It is safe to call GetCurrentFrameTimestamp() because VFC is stopped
1129 // during Suspend(). It won't be started again until after Resume() is
1130 // called.
1131 seek_time_ = compositor_->GetCurrentFrameTimestamp();
1132 }
1133
1134 if (chunk_demuxer_)
1135 chunk_demuxer_->StartWaitingForSeek(seek_time_);
1136
1137 resuming_ = true;
1138 pipeline_.Resume(CreateRenderer(), seek_time_,
1139 BIND_TO_RENDER_LOOP1(&WebMediaPlayerImpl::OnPipelineSeeked,
1140 time_changed));
1141}
1142
[email protected]fee8a902014-06-03 13:43:361143void WebMediaPlayerImpl::DataSourceInitialized(bool success) {
hubbed82bed52015-12-15 23:07:161144 DVLOG(1) << __FUNCTION__;
acolwellb4034942014-08-28 15:42:431145 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]a9415292012-01-19 19:55:201146
[email protected]d250190da3b2012-07-23 22:57:301147 if (!success) {
[email protected]ef405f66b2012-04-18 02:39:551148 SetNetworkState(WebMediaPlayer::NetworkStateFormatError);
[email protected]a9415292012-01-19 19:55:201149 return;
1150 }
1151
[email protected]ef8394c2013-08-21 20:26:301152 StartPipeline();
[email protected]a9415292012-01-19 19:55:201153}
1154
[email protected]122f40252012-06-12 05:01:561155void WebMediaPlayerImpl::NotifyDownloading(bool is_downloading) {
hubbed82bed52015-12-15 23:07:161156 DVLOG(1) << __FUNCTION__;
[email protected]122f40252012-06-12 05:01:561157 if (!is_downloading && network_state_ == WebMediaPlayer::NetworkStateLoading)
1158 SetNetworkState(WebMediaPlayer::NetworkStateIdle);
1159 else if (is_downloading && network_state_ == WebMediaPlayer::NetworkStateIdle)
1160 SetNetworkState(WebMediaPlayer::NetworkStateLoading);
1161 media_log_->AddEvent(
1162 media_log_->CreateBooleanEvent(
acolwell9e0840d2014-09-06 19:01:321163 MediaLogEvent::NETWORK_ACTIVITY_SET,
[email protected]122f40252012-06-12 05:01:561164 "is_downloading_data", is_downloading));
1165}
1166
sandersd1e49fb62015-12-12 01:18:061167scoped_ptr<Renderer> WebMediaPlayerImpl::CreateRenderer() {
1168 return renderer_factory_->CreateRenderer(
1169 media_task_runner_, worker_task_runner_, audio_source_provider_.get(),
1170 compositor_);
1171}
1172
[email protected]ef8394c2013-08-21 20:26:301173void WebMediaPlayerImpl::StartPipeline() {
acolwellb4034942014-08-28 15:42:431174 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]ddbc6ff2013-04-19 15:28:331175
xhwange8c4181a2014-12-06 08:10:011176 Demuxer::EncryptedMediaInitDataCB encrypted_media_init_data_cb =
1177 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnEncryptedMediaInitData);
[email protected]2b57e2e2014-05-09 11:07:251178
[email protected]ddbc6ff2013-04-19 15:28:331179 // Figure out which demuxer to use.
[email protected]ef8394c2013-08-21 20:26:301180 if (load_type_ != LoadTypeMediaSource) {
[email protected]ddbc6ff2013-04-19 15:28:331181 DCHECK(!chunk_demuxer_);
[email protected]f5443ef72013-04-22 04:03:381182 DCHECK(data_source_);
1183
j.isorcef6778e652015-11-16 17:14:251184#if !defined(MEDIA_DISABLE_FFMPEG)
xhwange8c4181a2014-12-06 08:10:011185 demuxer_.reset(new FFmpegDemuxer(media_task_runner_, data_source_.get(),
1186 encrypted_media_init_data_cb, media_log_));
j.isorcef6778e652015-11-16 17:14:251187#else
1188 OnPipelineError(PipelineStatus::DEMUXER_ERROR_COULD_NOT_OPEN);
1189 return;
1190#endif
[email protected]ddbc6ff2013-04-19 15:28:331191 } else {
[email protected]f5443ef72013-04-22 04:03:381192 DCHECK(!chunk_demuxer_);
1193 DCHECK(!data_source_);
1194
acolwell9e0840d2014-09-06 19:01:321195 chunk_demuxer_ = new ChunkDemuxer(
[email protected]ef8394c2013-08-21 20:26:301196 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnDemuxerOpened),
wolenetz1fb319d2015-07-14 17:49:041197 encrypted_media_init_data_cb, media_log_, true);
[email protected]f5443ef72013-04-22 04:03:381198 demuxer_.reset(chunk_demuxer_);
[email protected]ddbc6ff2013-04-19 15:28:331199 }
1200
[email protected]f5443ef72013-04-22 04:03:381201 // ... and we're ready to go!
[email protected]d228aeec2014-06-20 19:16:491202 seeking_ = true;
xhwangf94a634d2014-10-22 22:07:271203
sandersd1e49fb62015-12-12 01:18:061204 // TODO(sandersd): On Android, defer Start() if the tab is not visible.
[email protected]f6af7592014-02-28 10:09:111205 pipeline_.Start(
sandersd1e49fb62015-12-12 01:18:061206 demuxer_.get(), CreateRenderer(),
[email protected]f5443ef72013-04-22 04:03:381207 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineEnded),
1208 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineError),
[email protected]4e982192014-06-21 13:35:451209 BIND_TO_RENDER_LOOP1(&WebMediaPlayerImpl::OnPipelineSeeked, false),
[email protected]b8877772014-03-26 20:17:151210 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineMetadata),
[email protected]ba7d5f92014-06-24 05:37:401211 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineBufferingStateChanged),
xhwang59805902014-08-29 01:44:151212 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnDurationChanged),
jrummell74fc4f942015-03-02 22:48:271213 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnAddTextTrack),
1214 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnWaitingForDecryptionKey));
[email protected]f5443ef72013-04-22 04:03:381215}
1216
1217void WebMediaPlayerImpl::SetNetworkState(WebMediaPlayer::NetworkState state) {
[email protected]2a06ca62014-06-04 13:59:521218 DVLOG(1) << __FUNCTION__ << "(" << state << ")";
acolwellb4034942014-08-28 15:42:431219 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]f5443ef72013-04-22 04:03:381220 network_state_ = state;
1221 // Always notify to ensure client has the latest value.
[email protected]ce70c982013-12-20 17:04:321222 client_->networkStateChanged();
[email protected]f5443ef72013-04-22 04:03:381223}
1224
1225void WebMediaPlayerImpl::SetReadyState(WebMediaPlayer::ReadyState state) {
[email protected]2a06ca62014-06-04 13:59:521226 DVLOG(1) << __FUNCTION__ << "(" << state << ")";
acolwellb4034942014-08-28 15:42:431227 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]f5443ef72013-04-22 04:03:381228
[email protected]fee8a902014-06-03 13:43:361229 if (state == WebMediaPlayer::ReadyStateHaveEnoughData && data_source_ &&
1230 data_source_->assume_fully_buffered() &&
[email protected]f5443ef72013-04-22 04:03:381231 network_state_ == WebMediaPlayer::NetworkStateLoading)
1232 SetNetworkState(WebMediaPlayer::NetworkStateLoaded);
1233
1234 ready_state_ = state;
1235 // Always notify to ensure client has the latest value.
[email protected]ce70c982013-12-20 17:04:321236 client_->readyStateChanged();
[email protected]f5443ef72013-04-22 04:03:381237}
1238
[email protected]180ef242013-11-07 06:50:461239blink::WebAudioSourceProvider* WebMediaPlayerImpl::audioSourceProvider() {
[email protected]ff875be52013-06-02 23:47:381240 return audio_source_provider_.get();
[email protected]f5443ef72013-04-22 04:03:381241}
1242
[email protected]f5443ef72013-04-22 04:03:381243double WebMediaPlayerImpl::GetPipelineDuration() const {
[email protected]f6af7592014-02-28 10:09:111244 base::TimeDelta duration = pipeline_.GetMediaDuration();
[email protected]f5443ef72013-04-22 04:03:381245
1246 // Return positive infinity if the resource is unbounded.
1247 // http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html#dom-media-duration
acolwell9e0840d2014-09-06 19:01:321248 if (duration == kInfiniteDuration())
[email protected]f5443ef72013-04-22 04:03:381249 return std::numeric_limits<double>::infinity();
1250
1251 return duration.InSecondsF();
1252}
1253
[email protected]75e145a2014-04-15 17:44:321254void WebMediaPlayerImpl::OnDurationChanged() {
[email protected]f5443ef72013-04-22 04:03:381255 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing)
1256 return;
1257
[email protected]ce70c982013-12-20 17:04:321258 client_->durationChanged();
[email protected]f5443ef72013-04-22 04:03:381259}
1260
[email protected]75e145a2014-04-15 17:44:321261void WebMediaPlayerImpl::OnNaturalSizeChanged(gfx::Size size) {
acolwellb4034942014-08-28 15:42:431262 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]739847c02014-01-16 00:12:251263 DCHECK_NE(ready_state_, WebMediaPlayer::ReadyStateHaveNothing);
1264 TRACE_EVENT0("media", "WebMediaPlayerImpl::OnNaturalSizeChanged");
1265
1266 media_log_->AddEvent(
1267 media_log_->CreateVideoSizeSetEvent(size.width(), size.height()));
[email protected]b8877772014-03-26 20:17:151268 pipeline_metadata_.natural_size = size;
[email protected]739847c02014-01-16 00:12:251269
1270 client_->sizeChanged();
1271}
1272
[email protected]75e145a2014-04-15 17:44:321273void WebMediaPlayerImpl::OnOpacityChanged(bool opaque) {
acolwellb4034942014-08-28 15:42:431274 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]75e145a2014-04-15 17:44:321275 DCHECK_NE(ready_state_, WebMediaPlayer::ReadyStateHaveNothing);
1276
1277 opaque_ = opaque;
jbauman952274d2015-09-10 23:23:361278 // Modify content opaqueness of cc::Layer directly so that
1279 // SetContentsOpaqueIsFixed is ignored.
[email protected]75e145a2014-04-15 17:44:321280 if (video_weblayer_)
jbauman952274d2015-09-10 23:23:361281 video_weblayer_->layer()->SetContentsOpaque(opaque_);
[email protected]75e145a2014-04-15 17:44:321282}
1283
[email protected]dd061e12014-05-06 19:21:221284static void GetCurrentFrameAndSignal(
1285 VideoFrameCompositor* compositor,
acolwell9e0840d2014-09-06 19:01:321286 scoped_refptr<VideoFrame>* video_frame_out,
[email protected]dd061e12014-05-06 19:21:221287 base::WaitableEvent* event) {
1288 TRACE_EVENT0("media", "GetCurrentFrameAndSignal");
dalecurtis44ce4de2015-05-11 18:42:071289 *video_frame_out = compositor->GetCurrentFrameAndUpdateIfStale();
[email protected]dd061e12014-05-06 19:21:221290 event->Signal();
1291}
1292
acolwell9e0840d2014-09-06 19:01:321293scoped_refptr<VideoFrame>
[email protected]dd061e12014-05-06 19:21:221294WebMediaPlayerImpl::GetCurrentFrameFromCompositor() {
1295 TRACE_EVENT0("media", "WebMediaPlayerImpl::GetCurrentFrameFromCompositor");
1296 if (compositor_task_runner_->BelongsToCurrentThread())
dalecurtis44ce4de2015-05-11 18:42:071297 return compositor_->GetCurrentFrameAndUpdateIfStale();
[email protected]dd061e12014-05-06 19:21:221298
1299 // Use a posted task and waitable event instead of a lock otherwise
1300 // WebGL/Canvas can see different content than what the compositor is seeing.
acolwell9e0840d2014-09-06 19:01:321301 scoped_refptr<VideoFrame> video_frame;
[email protected]dd061e12014-05-06 19:21:221302 base::WaitableEvent event(false, false);
1303 compositor_task_runner_->PostTask(FROM_HERE,
1304 base::Bind(&GetCurrentFrameAndSignal,
1305 base::Unretained(compositor_),
1306 &video_frame,
1307 &event));
1308 event.Wait();
1309 return video_frame;
1310}
1311
dalecurtis2e50e6f62015-01-09 02:42:521312void WebMediaPlayerImpl::UpdatePausedTime() {
1313 DCHECK(main_task_runner_->BelongsToCurrentThread());
1314
1315 // pause() may be called after playback has ended and the HTMLMediaElement
1316 // requires that currentTime() == duration() after ending. We want to ensure
1317 // |paused_time_| matches currentTime() in this case or a future seek() may
1318 // incorrectly discard what it thinks is a seek to the existing time.
1319 paused_time_ =
1320 ended_ ? pipeline_.GetMediaDuration() : pipeline_.GetMediaTime();
1321}
1322
dalecurtis0f0097a2015-12-01 17:40:471323void WebMediaPlayerImpl::NotifyPlaybackStarted() {
1324 if (delegate_)
1325 delegate_->DidPlay(this);
1326 if (!memory_usage_reporting_timer_.IsRunning()) {
1327 memory_usage_reporting_timer_.Start(FROM_HERE,
1328 base::TimeDelta::FromSeconds(2), this,
1329 &WebMediaPlayerImpl::ReportMemoryUsage);
1330 }
1331}
1332
1333void WebMediaPlayerImpl::NotifyPlaybackPaused() {
1334 if (delegate_)
1335 delegate_->DidPause(this);
1336 memory_usage_reporting_timer_.Stop();
1337 ReportMemoryUsage();
1338}
1339
dalecurtis83266c72015-10-29 18:43:201340void WebMediaPlayerImpl::ReportMemoryUsage() {
1341 DCHECK(main_task_runner_->BelongsToCurrentThread());
1342
wdzierzanowskifd4cd91c52015-12-02 23:50:201343 // About base::Unretained() usage below: We destroy |demuxer_| on the main
1344 // thread. Before that, however, ~WebMediaPlayerImpl() posts a task to the
1345 // media thread and waits for it to finish. Hence, the GetMemoryUsage() task
1346 // posted here must finish earlier.
1347
1348 if (demuxer_) {
1349 base::PostTaskAndReplyWithResult(
1350 media_task_runner_.get(), FROM_HERE,
1351 base::Bind(&Demuxer::GetMemoryUsage, base::Unretained(demuxer_.get())),
1352 base::Bind(&WebMediaPlayerImpl::FinishMemoryUsageReport, AsWeakPtr()));
1353 } else {
1354 FinishMemoryUsageReport(0);
1355 }
1356}
1357
1358void WebMediaPlayerImpl::FinishMemoryUsageReport(int64_t demuxer_memory_usage) {
1359 DCHECK(main_task_runner_->BelongsToCurrentThread());
1360
dalecurtis83266c72015-10-29 18:43:201361 const PipelineStatistics stats = pipeline_.GetStatistics();
1362 const int64_t current_memory_usage =
1363 stats.audio_memory_usage + stats.video_memory_usage +
1364 (data_source_ ? data_source_->GetMemoryUsage() : 0) +
wdzierzanowskifd4cd91c52015-12-02 23:50:201365 demuxer_memory_usage;
dalecurtis83266c72015-10-29 18:43:201366
1367 DVLOG(2) << "Memory Usage -- Audio: " << stats.audio_memory_usage
1368 << ", Video: " << stats.video_memory_usage << ", DataSource: "
1369 << (data_source_ ? data_source_->GetMemoryUsage() : 0)
wdzierzanowskifd4cd91c52015-12-02 23:50:201370 << ", Demuxer: " << demuxer_memory_usage;
dalecurtis83266c72015-10-29 18:43:201371
1372 const int64_t delta = current_memory_usage - last_reported_memory_usage_;
1373 last_reported_memory_usage_ = current_memory_usage;
1374 adjust_allocated_memory_cb_.Run(delta);
1375}
1376
acolwell9e0840d2014-09-06 19:01:321377} // namespace media