blob: 9edb70ce58d87153c63cb9fa31e06ffac7d4d94b [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;
hubbed5f36882016-01-15 22:40:3767using gpu::gles2::GLES2Interface;
68
69namespace media {
[email protected]ec9212f2008-12-18 21:40:3670
[email protected]8931c41a2009-07-07 17:31:4971namespace {
72
[email protected]378f0b72009-08-11 17:11:4273// Limits the range of playback rate.
74//
75// TODO(kylep): Revisit these.
76//
77// Vista has substantially lower performance than XP or Windows7. If you speed
78// up a video too much, it can't keep up, and rendering stops updating except on
79// the time bar. For really high speeds, audio becomes a bottleneck and we just
80// use up the data we have, which may not achieve the speed requested, but will
81// not crash the tab.
82//
83// A very slow speed, ie 0.00000001x, causes the machine to lock up. (It seems
84// like a busy loop). It gets unresponsive, although its not completely dead.
85//
86// Also our timers are not very accurate (especially for ogg), which becomes
87// evident at low speeds and on Vista. Since other speeds are risky and outside
88// the norms, we think 1/16x to 16x is a safe and useful range for now.
[email protected]39bdde32013-04-17 17:44:2089const double kMinRate = 0.0625;
90const double kMaxRate = 16.0;
[email protected]378f0b72009-08-11 17:11:4291
hubbed5f36882016-01-15 22:40:3792void SetSinkIdOnMediaThread(scoped_refptr<WebAudioSourceProviderImpl> sink,
93 const std::string& device_id,
94 const url::Origin& security_origin,
95 const SwitchOutputDeviceCB& callback) {
guidouc7babef2015-10-22 00:42:3596 if (sink->GetOutputDevice()) {
97 sink->GetOutputDevice()->SwitchOutputDevice(device_id, security_origin,
98 callback);
99 } else {
hubbed5f36882016-01-15 22:40:37100 callback.Run(OUTPUT_DEVICE_STATUS_ERROR_INTERNAL);
guidouc7babef2015-10-22 00:42:35101 }
102}
103
[email protected]8931c41a2009-07-07 17:31:49104} // namespace
105
[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))),
xhwang80739452016-01-13 00:48:00184 is_cdm_attached_(false),
hubbed5f36882016-01-15 22:40:37185#if defined(OS_ANDROID) // WMPI_CAST
186 cast_impl_(this, client_, params.context_3d_cb(), delegate),
187#endif
dcheng652f5ff2015-12-27 08:54:00188 renderer_factory_(std::move(renderer_factory)) {
dalecurtis83266c72015-10-29 18:43:20189 DCHECK(!adjust_allocated_memory_cb_.is_null());
xhwang59d4175a2016-01-14 03:19:30190 DCHECK(renderer_factory_);
dalecurtis83266c72015-10-29 18:43:20191
sandersd1e49fb62015-12-12 01:18:06192 if (delegate)
193 delegate->AddObserver(this);
194
[email protected]c93eb0a62011-08-09 22:47:24195 media_log_->AddEvent(
acolwell9e0840d2014-09-06 19:01:32196 media_log_->CreateEvent(MediaLogEvent::WEBMEDIAPLAYER_CREATED));
[email protected]4e6be3f2009-05-07 02:24:44197
xhwang0ad11e512014-11-25 23:43:09198 if (params.initial_cdm()) {
xhwang9bd8c732015-04-13 23:27:53199 SetCdm(base::Bind(&IgnoreCdmAttached),
200 ToWebContentDecryptionModuleImpl(params.initial_cdm())
201 ->GetCdmContext());
xhwang0ad11e512014-11-25 23:43:09202 }
203
xhwangf94a634d2014-10-22 22:07:27204 // TODO(xhwang): When we use an external Renderer, many methods won't work,
xhwang6fa356202014-12-11 00:44:12205 // e.g. GetCurrentFrameFromCompositor(). See http://crbug.com/434861
[email protected]c50edb962013-10-19 18:05:07206
[email protected]ddbc6ff2013-04-19 15:28:33207 // Use the null sink if no sink was provided.
[email protected]4a914882013-01-10 00:43:48208 audio_source_provider_ = new WebAudioSourceProviderImpl(
[email protected]ff875be52013-06-02 23:47:38209 params.audio_renderer_sink().get()
210 ? params.audio_renderer_sink()
acolwell9e0840d2014-09-06 19:01:32211 : new NullAudioSink(media_task_runner_));
[email protected]ec9212f2008-12-18 21:40:36212}
213
[email protected]4e6be3f2009-05-07 02:24:44214WebMediaPlayerImpl::~WebMediaPlayerImpl() {
[email protected]ce70c982013-12-20 17:04:32215 client_->setWebLayer(NULL);
[email protected]21c3f7502013-03-23 03:29:51216
acolwellb4034942014-08-28 15:42:43217 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53218
sandersd1e49fb62015-12-12 01:18:06219 if (delegate_) {
220 delegate_->RemoveObserver(this);
[email protected]baff4512011-10-19 18:21:07221 delegate_->PlayerGone(this);
sandersd1e49fb62015-12-12 01:18:06222 }
[email protected]baff4512011-10-19 18:21:07223
[email protected]f6af7592014-02-28 10:09:11224 // Abort any pending IO so stopping the pipeline doesn't get blocked.
225 if (data_source_)
226 data_source_->Abort();
227 if (chunk_demuxer_) {
228 chunk_demuxer_->Shutdown();
229 chunk_demuxer_ = NULL;
230 }
231
xhwang6fa356202014-12-11 00:44:12232 renderer_factory_.reset();
[email protected]f6af7592014-02-28 10:09:11233
234 // Make sure to kill the pipeline so there's no more media threads running.
235 // Note: stopping the pipeline might block for a long time.
236 base::WaitableEvent waiter(false, false);
237 pipeline_.Stop(
238 base::Bind(&base::WaitableEvent::Signal, base::Unretained(&waiter)));
239 waiter.Wait();
240
dalecurtis83266c72015-10-29 18:43:20241 if (last_reported_memory_usage_)
242 adjust_allocated_memory_cb_.Run(-last_reported_memory_usage_);
243
[email protected]dd061e12014-05-06 19:21:22244 compositor_task_runner_->DeleteSoon(FROM_HERE, compositor_);
xhwangea8bb3562015-06-08 21:18:37245
246 media_log_->AddEvent(
247 media_log_->CreateEvent(MediaLogEvent::WEBMEDIAPLAYER_DESTROYED));
[email protected]ec9212f2008-12-18 21:40:36248}
249
[email protected]180ef242013-11-07 06:50:46250void WebMediaPlayerImpl::load(LoadType load_type, const blink::WebURL& url,
[email protected]62e5e682013-03-07 23:53:24251 CORSMode cors_mode) {
[email protected]2a06ca62014-06-04 13:59:52252 DVLOG(1) << __FUNCTION__ << "(" << load_type << ", " << url << ", "
253 << cors_mode << ")";
[email protected]d726eddc2013-07-02 22:25:55254 if (!defer_load_cb_.is_null()) {
255 defer_load_cb_.Run(base::Bind(
[email protected]ef8394c2013-08-21 20:26:30256 &WebMediaPlayerImpl::DoLoad, AsWeakPtr(), load_type, url, cors_mode));
[email protected]d726eddc2013-07-02 22:25:55257 return;
258 }
[email protected]ef8394c2013-08-21 20:26:30259 DoLoad(load_type, url, cors_mode);
[email protected]62e5e682013-03-07 23:53:24260}
261
[email protected]ef8394c2013-08-21 20:26:30262void WebMediaPlayerImpl::DoLoad(LoadType load_type,
[email protected]180ef242013-11-07 06:50:46263 const blink::WebURL& url,
[email protected]d726eddc2013-07-02 22:25:55264 CORSMode cors_mode) {
hubbed82bed52015-12-15 23:07:16265 DVLOG(1) << __FUNCTION__;
acolwellb4034942014-08-28 15:42:43266 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d726eddc2013-07-02 22:25:55267
[email protected]62e5e682013-03-07 23:53:24268 GURL gurl(url);
xhwang0acca44b2015-06-18 00:43:31269 ReportMetrics(load_type, gurl,
270 GURL(frame_->document().securityOrigin().toString()));
[email protected]62e5e682013-03-07 23:53:24271
[email protected]926f8fd2013-04-12 20:27:53272 // Set subresource URL for crash reporting.
273 base::debug::SetCrashKeyValue("subresource_url", gurl.spec());
274
[email protected]ef8394c2013-08-21 20:26:30275 load_type_ = load_type;
276
[email protected]62e5e682013-03-07 23:53:24277 SetNetworkState(WebMediaPlayer::NetworkStateLoading);
278 SetReadyState(WebMediaPlayer::ReadyStateHaveNothing);
kinukof19cde72015-12-18 23:15:25279 media_log_->AddEvent(media_log_->CreateLoadEvent(url.string().utf8()));
[email protected]d726eddc2013-07-02 22:25:55280
281 // Media source pipelines can start immediately.
[email protected]ef8394c2013-08-21 20:26:30282 if (load_type == LoadTypeMediaSource) {
[email protected]d726eddc2013-07-02 22:25:55283 supports_save_ = false;
[email protected]ef8394c2013-08-21 20:26:30284 StartPipeline();
[email protected]d726eddc2013-07-02 22:25:55285 return;
286 }
287
288 // Otherwise it's a regular request which requires resolving the URL first.
hubbe5f0ad43b2015-12-14 20:57:26289 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
290 switches::kUseNewMediaCache)) {
291 // Remove this when MultiBufferDataSource becomes default.
292 LOG(WARNING) << "Using MultibufferDataSource";
293 data_source_.reset(new MultibufferDataSource(
294 url, static_cast<UrlData::CORSMode>(cors_mode), main_task_runner_,
295 url_index_, frame_, media_log_.get(), &buffered_data_source_host_,
296 base::Bind(&WebMediaPlayerImpl::NotifyDownloading, AsWeakPtr())));
297 } else {
298 data_source_.reset(new BufferedDataSource(
299 url, static_cast<BufferedResourceLoader::CORSMode>(cors_mode),
300 main_task_runner_, frame_, media_log_.get(),
301 &buffered_data_source_host_,
302 base::Bind(&WebMediaPlayerImpl::NotifyDownloading, AsWeakPtr())));
303 }
dalecurtis9157fc9e2015-01-16 01:09:11304 data_source_->SetPreload(preload_);
sandersdc6ab163a2015-12-12 03:56:13305 data_source_->SetBufferingStrategy(buffering_strategy_);
[email protected]d726eddc2013-07-02 22:25:55306 data_source_->Initialize(
[email protected]fee8a902014-06-03 13:43:36307 base::Bind(&WebMediaPlayerImpl::DataSourceInitialized, AsWeakPtr()));
hubbed5f36882016-01-15 22:40:37308
309#if defined(OS_ANDROID) // WMPI_CAST
310 cast_impl_.Initialize(url, frame_);
311#endif
[email protected]62e5e682013-03-07 23:53:24312}
313
[email protected]4e6be3f2009-05-07 02:24:44314void WebMediaPlayerImpl::play() {
[email protected]2a06ca62014-06-04 13:59:52315 DVLOG(1) << __FUNCTION__;
acolwellb4034942014-08-28 15:42:43316 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53317
hubbed5f36882016-01-15 22:40:37318#if defined(OS_ANDROID) // WMPI_CAST
319 if (isRemote()) {
320 cast_impl_.play();
321 return;
322 }
323#endif
324
[email protected]49480902009-07-14 20:23:43325 paused_ = false;
hubbed5f36882016-01-15 22:40:37326
[email protected]f6af7592014-02-28 10:09:11327 pipeline_.SetPlaybackRate(playback_rate_);
[email protected]039b7542013-10-17 22:06:25328 if (data_source_)
329 data_source_->MediaIsPlaying();
[email protected]090f7312011-08-05 23:26:40330
acolwell9e0840d2014-09-06 19:01:32331 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PLAY));
[email protected]baff4512011-10-19 18:21:07332
dalecurtis6d269ed2014-09-11 21:18:13333 if (delegate_ && playback_rate_ > 0)
dalecurtis0f0097a2015-12-01 17:40:47334 NotifyPlaybackStarted();
[email protected]ec9212f2008-12-18 21:40:36335}
336
[email protected]4e6be3f2009-05-07 02:24:44337void WebMediaPlayerImpl::pause() {
[email protected]2a06ca62014-06-04 13:59:52338 DVLOG(1) << __FUNCTION__;
acolwellb4034942014-08-28 15:42:43339 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53340
dalecurtis6d269ed2014-09-11 21:18:13341 const bool was_already_paused = paused_ || playback_rate_ == 0;
[email protected]49480902009-07-14 20:23:43342 paused_ = true;
hubbed5f36882016-01-15 22:40:37343
344#if defined(OS_ANDROID) // WMPI_CAST
345 if (isRemote()) {
346 cast_impl_.pause();
347 return;
348 }
349#endif
350
a.berwal338bf002015-04-22 11:14:50351 pipeline_.SetPlaybackRate(0.0);
dalecurtis2e50e6f62015-01-09 02:42:52352 UpdatePausedTime();
[email protected]090f7312011-08-05 23:26:40353
acolwell9e0840d2014-09-06 19:01:32354 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PAUSE));
[email protected]baff4512011-10-19 18:21:07355
dalecurtis6d269ed2014-09-11 21:18:13356 if (!was_already_paused && delegate_)
dalecurtis0f0097a2015-12-01 17:40:47357 NotifyPlaybackPaused();
[email protected]ec9212f2008-12-18 21:40:36358}
359
[email protected]574a1d62009-07-17 03:23:46360bool WebMediaPlayerImpl::supportsSave() const {
acolwellb4034942014-08-28 15:42:43361 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]132dd57c2012-08-10 23:24:34362 return supports_save_;
[email protected]574a1d62009-07-17 03:23:46363}
364
[email protected]39bdde32013-04-17 17:44:20365void WebMediaPlayerImpl::seek(double seconds) {
xhwang12d8d042014-12-01 21:48:57366 DVLOG(1) << __FUNCTION__ << "(" << seconds << "s)";
acolwellb4034942014-08-28 15:42:43367 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53368
scherkusd2c745b2014-09-04 05:03:40369 ended_ = false;
370
hubbed5f36882016-01-15 22:40:37371 base::TimeDelta new_seek_time = base::TimeDelta::FromSecondsD(seconds);
372
373#if defined(OS_ANDROID) // WMPI_CAST
374 if (isRemote()) {
375 cast_impl_.seek(new_seek_time);
376 return;
377 }
378#endif
379
srirama.mccf671812015-01-08 11:59:13380 ReadyState old_state = ready_state_;
[email protected]1bb666802013-11-28 06:12:08381 if (ready_state_ > WebMediaPlayer::ReadyStateHaveMetadata)
382 SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata);
383
sandersd1e49fb62015-12-12 01:18:06384 if (seeking_ || suspended_) {
385 // Once resuming, it's too late to change the resume time and so the
386 // implementation is a little different.
387 bool is_suspended = suspended_ && !resuming_;
388
389 // If we are currently seeking or resuming to |new_seek_time|, skip the
390 // seek (except for MSE, which always seeks).
391 if (!is_suspended && new_seek_time == seek_time_) {
wolenetz1b2ae7d2015-06-10 00:44:21392 if (chunk_demuxer_) {
wolenetza6097972015-09-01 05:37:56393 // Don't suppress any redundant in-progress MSE seek. There could have
394 // been changes to the underlying buffers after seeking the demuxer and
395 // before receiving OnPipelineSeeked() for the currently in-progress
396 // seek.
397 MEDIA_LOG(DEBUG, media_log_)
398 << "Detected MediaSource seek to same time as in-progress seek to "
399 << seek_time_ << ".";
wolenetz1b2ae7d2015-06-10 00:44:21400 } else {
401 // Suppress all redundant seeks if unrestricted by media source demuxer
402 // API.
403 pending_seek_ = false;
404 pending_seek_time_ = base::TimeDelta();
405 return;
406 }
407 }
408
sandersd1e49fb62015-12-12 01:18:06409 // If |chunk_demuxer_| is already seeking, cancel that seek and schedule the
410 // new one.
411 if (!is_suspended && chunk_demuxer_)
412 chunk_demuxer_->CancelPendingSeek(new_seek_time);
413
414 // Schedule a seek once the current suspend or seek finishes.
[email protected]5d11eff2011-09-15 00:06:06415 pending_seek_ = true;
wolenetz1b2ae7d2015-06-10 00:44:21416 pending_seek_time_ = new_seek_time;
sandersd1e49fb62015-12-12 01:18:06417
418 // In the case of seeking while suspended, the seek is considered to have
419 // started immediately (but won't complete until the pipeline is resumed).
420 if (is_suspended) {
421 seeking_ = true;
422 seek_time_ = new_seek_time;
423 }
424
[email protected]5d11eff2011-09-15 00:06:06425 return;
426 }
427
[email protected]c93eb0a62011-08-09 22:47:24428 media_log_->AddEvent(media_log_->CreateSeekEvent(seconds));
429
[email protected]44ff37c02009-10-24 01:03:03430 // Update our paused time.
wolenetza6097972015-09-01 05:37:56431 // For non-MSE playbacks, in paused state ignore the seek operations to
432 // current time if the loading is completed and generate
433 // OnPipelineBufferingStateChanged event to eventually fire seeking and seeked
434 // events. We don't short-circuit MSE seeks in this logic because the
435 // underlying buffers around the seek time might have changed (or even been
436 // removed) since previous seek/preroll/pause action, and the pipeline might
437 // need to flush so the new buffers are decoded and rendered instead of the
438 // old ones.
srirama.m36ab2682014-12-11 04:20:01439 if (paused_) {
wolenetza6097972015-09-01 05:37:56440 if (paused_time_ != new_seek_time || chunk_demuxer_) {
wolenetz1b2ae7d2015-06-10 00:44:21441 paused_time_ = new_seek_time;
srirama.mccf671812015-01-08 11:59:13442 } else if (old_state == ReadyStateHaveEnoughData) {
srirama.m8f4a37562014-12-13 08:16:18443 main_task_runner_->PostTask(
srirama.m36ab2682014-12-11 04:20:01444 FROM_HERE,
445 base::Bind(&WebMediaPlayerImpl::OnPipelineBufferingStateChanged,
srirama.m8f4a37562014-12-13 08:16:18446 AsWeakPtr(), BUFFERING_HAVE_ENOUGH));
srirama.m36ab2682014-12-11 04:20:01447 return;
448 }
449 }
[email protected]44ff37c02009-10-24 01:03:03450
[email protected]b3766a22010-12-22 17:34:13451 seeking_ = true;
wolenetz1b2ae7d2015-06-10 00:44:21452 seek_time_ = new_seek_time;
[email protected]b3766a22010-12-22 17:34:13453
[email protected]efe7cd22012-09-12 23:55:01454 if (chunk_demuxer_)
wolenetz1b2ae7d2015-06-10 00:44:21455 chunk_demuxer_->StartWaitingForSeek(seek_time_);
[email protected]020fba32011-06-29 16:37:46456
wolenetz1b2ae7d2015-06-10 00:44:21457 pipeline_.Seek(seek_time_, BIND_TO_RENDER_LOOP1(
458 &WebMediaPlayerImpl::OnPipelineSeeked, true));
[email protected]ec9212f2008-12-18 21:40:36459}
460
[email protected]39bdde32013-04-17 17:44:20461void WebMediaPlayerImpl::setRate(double rate) {
[email protected]2a06ca62014-06-04 13:59:52462 DVLOG(1) << __FUNCTION__ << "(" << rate << ")";
acolwellb4034942014-08-28 15:42:43463 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53464
[email protected]378f0b72009-08-11 17:11:42465 // TODO(kylep): Remove when support for negatives is added. Also, modify the
466 // following checks so rewind uses reasonable values also.
[email protected]39bdde32013-04-17 17:44:20467 if (rate < 0.0)
[email protected]378f0b72009-08-11 17:11:42468 return;
469
470 // Limit rates to reasonable values by clamping.
[email protected]39bdde32013-04-17 17:44:20471 if (rate != 0.0) {
[email protected]378f0b72009-08-11 17:11:42472 if (rate < kMinRate)
473 rate = kMinRate;
474 else if (rate > kMaxRate)
475 rate = kMaxRate;
dalecurtisbb761e12014-09-12 01:16:35476 if (playback_rate_ == 0 && !paused_ && delegate_)
dalecurtis0f0097a2015-12-01 17:40:47477 NotifyPlaybackStarted();
dalecurtisbb761e12014-09-12 01:16:35478 } else if (playback_rate_ != 0 && !paused_ && delegate_) {
dalecurtis0f0097a2015-12-01 17:40:47479 NotifyPlaybackPaused();
[email protected]378f0b72009-08-11 17:11:42480 }
481
[email protected]49480902009-07-14 20:23:43482 playback_rate_ = rate;
483 if (!paused_) {
[email protected]f6af7592014-02-28 10:09:11484 pipeline_.SetPlaybackRate(rate);
[email protected]039b7542013-10-17 22:06:25485 if (data_source_)
486 data_source_->MediaPlaybackRateChanged(rate);
[email protected]49480902009-07-14 20:23:43487 }
[email protected]ec9212f2008-12-18 21:40:36488}
489
[email protected]39bdde32013-04-17 17:44:20490void WebMediaPlayerImpl::setVolume(double volume) {
[email protected]2a06ca62014-06-04 13:59:52491 DVLOG(1) << __FUNCTION__ << "(" << volume << ")";
acolwellb4034942014-08-28 15:42:43492 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53493
[email protected]f6af7592014-02-28 10:09:11494 pipeline_.SetVolume(volume);
[email protected]ec9212f2008-12-18 21:40:36495}
[email protected]f0a51fb52009-03-05 12:46:38496
guidouc7babef2015-10-22 00:42:35497void WebMediaPlayerImpl::setSinkId(
498 const blink::WebString& sink_id,
499 const blink::WebSecurityOrigin& security_origin,
500 blink::WebSetSinkIdCallbacks* web_callback) {
guidou69223ce2015-06-16 10:36:19501 DCHECK(main_task_runner_->BelongsToCurrentThread());
guidou5754e612015-07-31 08:09:41502 DVLOG(1) << __FUNCTION__;
guidouc7babef2015-10-22 00:42:35503
guidou5754e612015-07-31 08:09:41504 media::SwitchOutputDeviceCB callback =
505 media::ConvertToSwitchOutputDeviceCB(web_callback);
guidouc7babef2015-10-22 00:42:35506 media_task_runner_->PostTask(
507 FROM_HERE,
508 base::Bind(&SetSinkIdOnMediaThread, audio_source_provider_,
509 sink_id.utf8(), static_cast<url::Origin>(security_origin),
510 callback));
guidou69223ce2015-06-16 10:36:19511}
512
mostynb502b00b2015-01-05 23:43:40513#define STATIC_ASSERT_MATCHING_ENUM(webkit_name, chromium_name) \
514 static_assert(static_cast<int>(WebMediaPlayer::webkit_name) == \
515 static_cast<int>(BufferedDataSource::chromium_name), \
516 "mismatching enum values: " #webkit_name)
517STATIC_ASSERT_MATCHING_ENUM(PreloadNone, NONE);
518STATIC_ASSERT_MATCHING_ENUM(PreloadMetaData, METADATA);
519STATIC_ASSERT_MATCHING_ENUM(PreloadAuto, AUTO);
520#undef STATIC_ASSERT_MATCHING_ENUM
[email protected]23a8b1d82011-04-05 16:28:20521
[email protected]ef405f66b2012-04-18 02:39:55522void WebMediaPlayerImpl::setPreload(WebMediaPlayer::Preload preload) {
[email protected]2a06ca62014-06-04 13:59:52523 DVLOG(1) << __FUNCTION__ << "(" << preload << ")";
acolwellb4034942014-08-28 15:42:43524 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]4e6be3f2009-05-07 02:24:44525
acolwella5081a42014-08-28 23:42:52526 preload_ = static_cast<BufferedDataSource::Preload>(preload);
[email protected]b49beeb2013-03-01 20:04:00527 if (data_source_)
[email protected]09c60222014-08-07 16:42:31528 data_source_->SetPreload(preload_);
[email protected]4e6be3f2009-05-07 02:24:44529}
530
sandersdc6ab163a2015-12-12 03:56:13531#define STATIC_ASSERT_MATCHING_ENUM(webkit_name, chromium_name) \
532 static_assert(static_cast<int>(WebMediaPlayer::webkit_name) == \
533 static_cast<int>(BufferedDataSource::chromium_name), \
534 "mismatching enum values: " #webkit_name)
535STATIC_ASSERT_MATCHING_ENUM(BufferingStrategy::Normal,
536 BUFFERING_STRATEGY_NORMAL);
537STATIC_ASSERT_MATCHING_ENUM(BufferingStrategy::Aggressive,
538 BUFFERING_STRATEGY_AGGRESSIVE);
539#undef STATIC_ASSERT_MATCHING_ENUM
540
541void WebMediaPlayerImpl::setBufferingStrategy(
542 WebMediaPlayer::BufferingStrategy buffering_strategy) {
543 DVLOG(1) << __FUNCTION__;
544 DCHECK(main_task_runner_->BelongsToCurrentThread());
545
546 buffering_strategy_ =
547 static_cast<BufferedDataSource::BufferingStrategy>(buffering_strategy);
548 if (data_source_)
549 data_source_->SetBufferingStrategy(buffering_strategy_);
550}
551
[email protected]4e6be3f2009-05-07 02:24:44552bool WebMediaPlayerImpl::hasVideo() const {
acolwellb4034942014-08-28 15:42:43553 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53554
[email protected]b8877772014-03-26 20:17:15555 return pipeline_metadata_.has_video;
[email protected]d43ed912009-02-03 04:52:53556}
557
[email protected]fc367af2009-08-14 23:06:35558bool WebMediaPlayerImpl::hasAudio() const {
acolwellb4034942014-08-28 15:42:43559 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]fc367af2009-08-14 23:06:35560
[email protected]b8877772014-03-26 20:17:15561 return pipeline_metadata_.has_audio;
[email protected]fc367af2009-08-14 23:06:35562}
563
[email protected]180ef242013-11-07 06:50:46564blink::WebSize WebMediaPlayerImpl::naturalSize() const {
acolwellb4034942014-08-28 15:42:43565 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53566
[email protected]b8877772014-03-26 20:17:15567 return blink::WebSize(pipeline_metadata_.natural_size);
[email protected]d43ed912009-02-03 04:52:53568}
569
[email protected]4e6be3f2009-05-07 02:24:44570bool WebMediaPlayerImpl::paused() const {
acolwellb4034942014-08-28 15:42:43571 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53572
hubbed5f36882016-01-15 22:40:37573#if defined(OS_ANDROID) // WMPI_CAST
574 if (isRemote())
575 return cast_impl_.paused();
576#endif
[email protected]f6af7592014-02-28 10:09:11577 return pipeline_.GetPlaybackRate() == 0.0f;
[email protected]d43ed912009-02-03 04:52:53578}
579
[email protected]4e6be3f2009-05-07 02:24:44580bool WebMediaPlayerImpl::seeking() const {
acolwellb4034942014-08-28 15:42:43581 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53582
[email protected]ef405f66b2012-04-18 02:39:55583 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing)
[email protected]0acebfa2009-08-21 22:45:40584 return false;
[email protected]67cd5052009-09-10 21:53:22585
[email protected]b3766a22010-12-22 17:34:13586 return seeking_;
[email protected]ec9212f2008-12-18 21:40:36587}
588
[email protected]39bdde32013-04-17 17:44:20589double WebMediaPlayerImpl::duration() const {
acolwellb4034942014-08-28 15:42:43590 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]39bdde32013-04-17 17:44:20591
592 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing)
593 return std::numeric_limits<double>::quiet_NaN();
594
[email protected]39bdde32013-04-17 17:44:20595 return GetPipelineDuration();
[email protected]d43ed912009-02-03 04:52:53596}
597
[email protected]db66d0092014-04-16 07:15:12598double WebMediaPlayerImpl::timelineOffset() const {
acolwellb4034942014-08-28 15:42:43599 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]db66d0092014-04-16 07:15:12600
601 if (pipeline_metadata_.timeline_offset.is_null())
602 return std::numeric_limits<double>::quiet_NaN();
603
604 return pipeline_metadata_.timeline_offset.ToJsTime();
605}
606
[email protected]39bdde32013-04-17 17:44:20607double WebMediaPlayerImpl::currentTime() const {
acolwellb4034942014-08-28 15:42:43608 DCHECK(main_task_runner_->BelongsToCurrentThread());
scherkusd2c745b2014-09-04 05:03:40609 DCHECK_NE(ready_state_, WebMediaPlayer::ReadyStateHaveNothing);
610
611 // TODO(scherkus): Replace with an explicit ended signal to HTMLMediaElement,
612 // see http://crbug.com/409280
613 if (ended_)
614 return duration();
615
wolenetz1b2ae7d2015-06-10 00:44:21616 // We know the current seek time better than pipeline: pipeline may processing
617 // an earlier seek before a pending seek has been started, or it might not yet
618 // have the current seek time returnable via GetMediaTime().
619 if (seeking()) {
620 return pending_seek_ ? pending_seek_time_.InSecondsF()
621 : seek_time_.InSecondsF();
622 }
623
hubbed5f36882016-01-15 22:40:37624#if defined(OS_ANDROID) // WMPI_CAST
625 if (isRemote()) {
626 return cast_impl_.currentTime();
627 }
628#endif
629
630 if (paused_) {
631 return paused_time_.InSecondsF();
632 }
633
634 return pipeline_.GetMediaTime().InSecondsF();
[email protected]d43ed912009-02-03 04:52:53635}
636
[email protected]ef405f66b2012-04-18 02:39:55637WebMediaPlayer::NetworkState WebMediaPlayerImpl::networkState() const {
acolwellb4034942014-08-28 15:42:43638 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]ddb1e5a2010-12-13 20:10:45639 return network_state_;
640}
641
[email protected]ef405f66b2012-04-18 02:39:55642WebMediaPlayer::ReadyState WebMediaPlayerImpl::readyState() const {
acolwellb4034942014-08-28 15:42:43643 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]ddb1e5a2010-12-13 20:10:45644 return ready_state_;
645}
646
[email protected]02022fc2014-05-16 00:05:31647blink::WebTimeRanges WebMediaPlayerImpl::buffered() const {
acolwellb4034942014-08-28 15:42:43648 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]779a8322014-08-22 21:28:37649
acolwell9e0840d2014-09-06 19:01:32650 Ranges<base::TimeDelta> buffered_time_ranges =
[email protected]02022fc2014-05-16 00:05:31651 pipeline_.GetBufferedTimeRanges();
[email protected]779a8322014-08-22 21:28:37652
653 const base::TimeDelta duration = pipeline_.GetMediaDuration();
acolwell9e0840d2014-09-06 19:01:32654 if (duration != kInfiniteDuration()) {
[email protected]779a8322014-08-22 21:28:37655 buffered_data_source_host_.AddBufferedTimeRanges(
656 &buffered_time_ranges, duration);
657 }
[email protected]02022fc2014-05-16 00:05:31658 return ConvertToWebTimeRanges(buffered_time_ranges);
659}
660
philipjb0e6f3f2014-09-30 09:51:53661blink::WebTimeRanges WebMediaPlayerImpl::seekable() const {
acolwellb4034942014-08-28 15:42:43662 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]39bdde32013-04-17 17:44:20663
dalecurtis56359cb2014-10-28 00:06:29664 if (ready_state_ < WebMediaPlayer::ReadyStateHaveMetadata)
philipjb0e6f3f2014-09-30 09:51:53665 return blink::WebTimeRanges();
666
dalecurtis56359cb2014-10-28 00:06:29667 const double seekable_end = duration();
668
669 // Allow a special exception for seeks to zero for streaming sources with a
670 // finite duration; this allows looping to work.
671 const bool allow_seek_to_zero = data_source_ && data_source_->IsStreaming() &&
mateuszs3371ab02015-04-24 13:20:23672 std::isfinite(seekable_end);
dalecurtis56359cb2014-10-28 00:06:29673
674 // TODO(dalecurtis): Technically this allows seeking on media which return an
675 // infinite duration so long as DataSource::IsStreaming() is false. While not
676 // expected, disabling this breaks semi-live players, http://crbug.com/427412.
677 const blink::WebTimeRange seekable_range(
678 0.0, allow_seek_to_zero ? 0.0 : seekable_end);
philipjb0e6f3f2014-09-30 09:51:53679 return blink::WebTimeRanges(&seekable_range, 1);
[email protected]ec9212f2008-12-18 21:40:36680}
681
[email protected]5d2b3e4c2014-05-12 23:27:30682bool WebMediaPlayerImpl::didLoadingProgress() {
acolwellb4034942014-08-28 15:42:43683 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]6683e1b2014-04-10 01:45:38684 bool pipeline_progress = pipeline_.DidLoadingProgress();
685 bool data_progress = buffered_data_source_host_.DidLoadingProgress();
686 return pipeline_progress || data_progress;
[email protected]d43ed912009-02-03 04:52:53687}
688
[email protected]dd5c7972014-08-21 15:00:37689void WebMediaPlayerImpl::paint(blink::WebCanvas* canvas,
690 const blink::WebRect& rect,
[email protected]dd5c7972014-08-21 15:00:37691 unsigned char alpha,
692 SkXfermode::Mode mode) {
acolwellb4034942014-08-28 15:42:43693 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]dd061e12014-05-06 19:21:22694 TRACE_EVENT0("media", "WebMediaPlayerImpl:paint");
[email protected]4e6be3f2009-05-07 02:24:44695
xhwang80739452016-01-13 00:48:00696 if (is_cdm_attached_)
697 return;
698
mcasasf1236fc22015-05-29 22:38:56699 scoped_refptr<VideoFrame> video_frame = GetCurrentFrameFromCompositor();
[email protected]0fe5d43b2014-01-24 23:32:45700
[email protected]b49beeb2013-03-01 20:04:00701 gfx::Rect gfx_rect(rect);
dongseong.hwang0c4e9d82015-01-08 20:11:13702 Context3D context_3d;
mcasas265bdbf82015-06-12 18:44:07703 if (video_frame.get() && video_frame->HasTextures()) {
mcasasf1236fc22015-05-29 22:38:56704 if (!context_3d_cb_.is_null())
dongseong.hwang0c4e9d82015-01-08 20:11:13705 context_3d = context_3d_cb_.Run();
dongseong.hwang0c4e9d82015-01-08 20:11:13706 // GPU Process crashed.
707 if (!context_3d.gl)
708 return;
709 }
danakj795f1732015-08-31 23:40:22710 skcanvas_video_renderer_.Paint(video_frame, canvas, gfx::RectF(gfx_rect),
711 alpha, mode, pipeline_metadata_.video_rotation,
712 context_3d);
[email protected]ec9212f2008-12-18 21:40:36713}
[email protected]5df51652009-01-17 00:03:00714
[email protected]38259a7a82009-07-29 21:49:49715bool WebMediaPlayerImpl::hasSingleSecurityOrigin() const {
[email protected]b49beeb2013-03-01 20:04:00716 if (data_source_)
717 return data_source_->HasSingleOrigin();
[email protected]fcdb7462009-10-21 21:05:11718 return true;
[email protected]38259a7a82009-07-29 21:49:49719}
720
[email protected]3fe27112012-06-07 04:00:01721bool WebMediaPlayerImpl::didPassCORSAccessCheck() const {
[email protected]b49beeb2013-03-01 20:04:00722 if (data_source_)
723 return data_source_->DidPassCORSAccessCheck();
724 return false;
[email protected]3fe27112012-06-07 04:00:01725}
726
[email protected]39bdde32013-04-17 17:44:20727double WebMediaPlayerImpl::mediaTimeForTimeValue(double timeValue) const {
qinminb4c39782015-08-10 18:43:24728 return base::TimeDelta::FromSecondsD(timeValue).InSecondsF();
[email protected]e06e16d82011-05-26 22:13:33729}
730
[email protected]d82b18ae2011-03-23 21:28:59731unsigned WebMediaPlayerImpl::decodedFrameCount() const {
acolwellb4034942014-08-28 15:42:43732 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]4c51bc662011-02-16 02:03:16733
acolwell9e0840d2014-09-06 19:01:32734 PipelineStatistics stats = pipeline_.GetStatistics();
[email protected]4c51bc662011-02-16 02:03:16735 return stats.video_frames_decoded;
736}
737
[email protected]d82b18ae2011-03-23 21:28:59738unsigned WebMediaPlayerImpl::droppedFrameCount() const {
acolwellb4034942014-08-28 15:42:43739 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]4c51bc662011-02-16 02:03:16740
acolwell9e0840d2014-09-06 19:01:32741 PipelineStatistics stats = pipeline_.GetStatistics();
[email protected]dd061e12014-05-06 19:21:22742 return stats.video_frames_dropped;
[email protected]4c51bc662011-02-16 02:03:16743}
744
[email protected]d82b18ae2011-03-23 21:28:59745unsigned WebMediaPlayerImpl::audioDecodedByteCount() const {
acolwellb4034942014-08-28 15:42:43746 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]4c51bc662011-02-16 02:03:16747
acolwell9e0840d2014-09-06 19:01:32748 PipelineStatistics stats = pipeline_.GetStatistics();
[email protected]4c51bc662011-02-16 02:03:16749 return stats.audio_bytes_decoded;
750}
751
[email protected]d82b18ae2011-03-23 21:28:59752unsigned WebMediaPlayerImpl::videoDecodedByteCount() const {
acolwellb4034942014-08-28 15:42:43753 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]4c51bc662011-02-16 02:03:16754
acolwell9e0840d2014-09-06 19:01:32755 PipelineStatistics stats = pipeline_.GetStatistics();
[email protected]4c51bc662011-02-16 02:03:16756 return stats.video_bytes_decoded;
757}
758
[email protected]6523b242013-03-13 11:10:07759bool WebMediaPlayerImpl::copyVideoTextureToPlatformTexture(
[email protected]180ef242013-11-07 06:50:46760 blink::WebGraphicsContext3D* web_graphics_context,
zmo57d577a2015-10-30 18:28:59761 unsigned int texture,
762 unsigned int internal_format,
763 unsigned int type,
764 bool premultiply_alpha,
765 bool flip_y) {
[email protected]bfc05f22013-10-19 17:55:16766 TRACE_EVENT0("media", "WebMediaPlayerImpl:copyVideoTextureToPlatformTexture");
767
mcasasf1236fc22015-05-29 22:38:56768 scoped_refptr<VideoFrame> video_frame = GetCurrentFrameFromCompositor();
[email protected]dd061e12014-05-06 19:21:22769
mcasas265bdbf82015-06-12 18:44:07770 if (!video_frame.get() || !video_frame->HasTextures() ||
dcastagna31a65d432015-06-11 19:01:00771 media::VideoFrame::NumPlanes(video_frame->format()) != 1) {
[email protected]e56f88c72013-06-25 22:31:29772 return false;
dongseong.hwang0c4e9d82015-01-08 20:11:13773 }
[email protected]df41e252014-02-03 23:39:50774
dongseong.hwang0c4e9d82015-01-08 20:11:13775 // TODO(dshwang): need more elegant way to convert WebGraphicsContext3D to
776 // GLES2Interface.
777 gpu::gles2::GLES2Interface* gl =
778 static_cast<gpu_blink::WebGraphicsContext3DImpl*>(web_graphics_context)
779 ->GetGLInterface();
dcastagna31a65d432015-06-11 19:01:00780 SkCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture(
zmo57d577a2015-10-30 18:28:59781 gl, video_frame.get(), texture, internal_format, type, premultiply_alpha,
782 flip_y);
[email protected]e56f88c72013-06-25 22:31:29783 return true;
[email protected]6523b242013-03-13 11:10:07784}
785
[email protected]2ca7d5c2012-10-23 07:30:54786WebMediaPlayer::MediaKeyException
[email protected]f7a6b992012-04-19 09:45:56787WebMediaPlayerImpl::generateKeyRequest(const WebString& key_system,
788 const unsigned char* init_data,
789 unsigned init_data_length) {
acolwellb4034942014-08-28 15:42:43790 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]7502ef12014-01-25 01:19:27791
xhwang16ff1362014-11-19 00:16:34792 return encrypted_media_support_.GenerateKeyRequest(
acolwelle2ea5182014-08-25 23:01:07793 frame_, key_system, init_data, init_data_length);
[email protected]f7a6b992012-04-19 09:45:56794}
795
[email protected]2ca7d5c2012-10-23 07:30:54796WebMediaPlayer::MediaKeyException WebMediaPlayerImpl::addKey(
797 const WebString& key_system,
798 const unsigned char* key,
799 unsigned key_length,
800 const unsigned char* init_data,
801 unsigned init_data_length,
802 const WebString& session_id) {
acolwellb4034942014-08-28 15:42:43803 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]f7a6b992012-04-19 09:45:56804
xhwang16ff1362014-11-19 00:16:34805 return encrypted_media_support_.AddKey(
acolwelle2ea5182014-08-25 23:01:07806 key_system, key, key_length, init_data, init_data_length, session_id);
[email protected]f7a6b992012-04-19 09:45:56807}
808
[email protected]2ca7d5c2012-10-23 07:30:54809WebMediaPlayer::MediaKeyException WebMediaPlayerImpl::cancelKeyRequest(
810 const WebString& key_system,
811 const WebString& session_id) {
acolwellb4034942014-08-28 15:42:43812 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]0b9999d2014-02-20 02:16:11813
xhwang16ff1362014-11-19 00:16:34814 return encrypted_media_support_.CancelKeyRequest(key_system, session_id);
[email protected]f7a6b992012-04-19 09:45:56815}
816
[email protected]7bce1832014-01-09 00:01:22817void WebMediaPlayerImpl::setContentDecryptionModule(
[email protected]9ebc3b03f2014-08-13 04:01:23818 blink::WebContentDecryptionModule* cdm,
819 blink::WebContentDecryptionModuleResult result) {
acolwellb4034942014-08-28 15:42:43820 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]9ebc3b03f2014-08-13 04:01:23821
jrummell06f27072015-06-08 18:12:38822 // Once the CDM is set it can't be cleared as there may be frames being
823 // decrypted on other threads. So fail this request.
824 // http://crbug.com/462365#c7.
xhwang97de4202014-11-25 08:44:01825 if (!cdm) {
826 result.completeWithError(
jrummell06f27072015-06-08 18:12:38827 blink::WebContentDecryptionModuleExceptionInvalidStateError, 0,
828 "The existing MediaKeys object cannot be removed at this time.");
xhwang97de4202014-11-25 08:44:01829 return;
830 }
831
jrummell89e61d82015-07-23 20:03:34832 // Although unlikely, it is possible that multiple calls happen
833 // simultaneously, so fail this call if there is already one pending.
834 if (set_cdm_result_) {
835 result.completeWithError(
836 blink::WebContentDecryptionModuleExceptionInvalidStateError, 0,
837 "Unable to set MediaKeys object at this time.");
838 return;
839 }
840
841 // Create a local copy of |result| to avoid problems with the callback
842 // getting passed to the media thread and causing |result| to be destructed
843 // on the wrong thread in some failure conditions.
844 set_cdm_result_.reset(new blink::WebContentDecryptionModuleResult(result));
845
846 SetCdm(BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnCdmAttached),
xhwang9bd8c732015-04-13 23:27:53847 ToWebContentDecryptionModuleImpl(cdm)->GetCdmContext());
xhwang97de4202014-11-25 08:44:01848}
849
xhwange8c4181a2014-12-06 08:10:01850void WebMediaPlayerImpl::OnEncryptedMediaInitData(
jrummellcf78967c2015-04-03 05:03:58851 EmeInitDataType init_data_type,
Avi Drissman97785ea2015-12-19 01:11:31852 const std::vector<uint8_t>& init_data) {
jrummellcf78967c2015-04-03 05:03:58853 DCHECK(init_data_type != EmeInitDataType::UNKNOWN);
xhwangbab66f52014-12-02 23:49:50854
xhwange8c4181a2014-12-06 08:10:01855 // Do not fire "encrypted" event if encrypted media is not enabled.
xhwangbab66f52014-12-02 23:49:50856 // TODO(xhwang): Handle this in |client_|.
857 if (!blink::WebRuntimeFeatures::isPrefixedEncryptedMediaEnabled() &&
858 !blink::WebRuntimeFeatures::isEncryptedMediaEnabled()) {
859 return;
860 }
861
xhwange8c4181a2014-12-06 08:10:01862 // TODO(xhwang): Update this UMA name.
xhwangbab66f52014-12-02 23:49:50863 UMA_HISTOGRAM_COUNTS("Media.EME.NeedKey", 1);
864
865 encrypted_media_support_.SetInitDataType(init_data_type);
866
srirama.m26f864d02015-07-14 05:21:46867 encrypted_client_->encrypted(
davidbenb50f00c2015-12-01 00:01:50868 ConvertToWebInitDataType(init_data_type), init_data.data(),
srirama.m26f864d02015-07-14 05:21:46869 base::saturated_cast<unsigned int>(init_data.size()));
xhwangbab66f52014-12-02 23:49:50870}
871
jrummell74fc4f942015-03-02 22:48:27872void WebMediaPlayerImpl::OnWaitingForDecryptionKey() {
srirama.m26f864d02015-07-14 05:21:46873 encrypted_client_->didBlockPlaybackWaitingForKey();
jrummell74fc4f942015-03-02 22:48:27874
875 // TODO(jrummell): didResumePlaybackBlockedForKey() should only be called
876 // when a key has been successfully added (e.g. OnSessionKeysChange() with
877 // |has_additional_usable_key| = true). http://crbug.com/461903
srirama.m26f864d02015-07-14 05:21:46878 encrypted_client_->didResumePlaybackBlockedForKey();
jrummell74fc4f942015-03-02 22:48:27879}
880
xhwang9bd8c732015-04-13 23:27:53881void WebMediaPlayerImpl::SetCdm(const CdmAttachedCB& cdm_attached_cb,
882 CdmContext* cdm_context) {
xhwang80739452016-01-13 00:48:00883 if (!cdm_context) {
884 cdm_attached_cb.Run(false);
885 return;
886 }
887
jrummell87a2db52015-05-05 22:27:18888 // If CDM initialization succeeded, tell the pipeline about it.
xhwang80739452016-01-13 00:48:00889 pipeline_.SetCdm(cdm_context, cdm_attached_cb);
xhwang97de4202014-11-25 08:44:01890}
891
jrummell89e61d82015-07-23 20:03:34892void WebMediaPlayerImpl::OnCdmAttached(bool success) {
xhwang97de4202014-11-25 08:44:01893 if (success) {
jrummell89e61d82015-07-23 20:03:34894 set_cdm_result_->complete();
895 set_cdm_result_.reset();
xhwang80739452016-01-13 00:48:00896 is_cdm_attached_ = true;
xhwang97de4202014-11-25 08:44:01897 return;
898 }
899
jrummell89e61d82015-07-23 20:03:34900 set_cdm_result_->completeWithError(
xhwang97de4202014-11-25 08:44:01901 blink::WebContentDecryptionModuleExceptionNotSupportedError, 0,
902 "Unable to set MediaKeys object");
jrummell89e61d82015-07-23 20:03:34903 set_cdm_result_.reset();
[email protected]9ebc3b03f2014-08-13 04:01:23904}
905
[email protected]4e982192014-06-21 13:35:45906void WebMediaPlayerImpl::OnPipelineSeeked(bool time_changed,
907 PipelineStatus status) {
908 DVLOG(1) << __FUNCTION__ << "(" << time_changed << ", " << status << ")";
acolwellb4034942014-08-28 15:42:43909 DCHECK(main_task_runner_->BelongsToCurrentThread());
sandersd1e49fb62015-12-12 01:18:06910
911 if (status != PIPELINE_OK) {
912 OnPipelineError(status);
913 return;
914 }
915
916 // Whether or not the seek was caused by a resume, we're not suspended now.
917 resuming_ = false;
918 suspended_ = false;
919
920 // If there is a pending suspend, the seek does not complete until after the
921 // next resume.
922 if (pending_suspend_) {
923 pending_suspend_ = false;
924 pending_time_change_ = time_changed;
925 Suspend();
926 return;
927 }
928
929 // Clear seek state. Note that if the seek was caused by a resume, then
930 // |seek_time_| is always set but |seeking_| is only set if there was a
931 // pending seek at the time.
[email protected]5d11eff2011-09-15 00:06:06932 seeking_ = false;
wolenetz1b2ae7d2015-06-10 00:44:21933 seek_time_ = base::TimeDelta();
sandersd1e49fb62015-12-12 01:18:06934
[email protected]5d11eff2011-09-15 00:06:06935 if (pending_seek_) {
wolenetz1b2ae7d2015-06-10 00:44:21936 double pending_seek_seconds = pending_seek_time_.InSecondsF();
[email protected]5d11eff2011-09-15 00:06:06937 pending_seek_ = false;
wolenetz1b2ae7d2015-06-10 00:44:21938 pending_seek_time_ = base::TimeDelta();
939 seek(pending_seek_seconds);
[email protected]5d11eff2011-09-15 00:06:06940 return;
941 }
942
[email protected]10a64d92012-04-10 21:08:02943 // Update our paused time.
944 if (paused_)
dalecurtis2e50e6f62015-01-09 02:42:52945 UpdatePausedTime();
[email protected]10a64d92012-04-10 21:08:02946
[email protected]ba7d5f92014-06-24 05:37:40947 should_notify_time_changed_ = time_changed;
[email protected]8931c41a2009-07-07 17:31:49948}
949
sandersd1e49fb62015-12-12 01:18:06950void WebMediaPlayerImpl::OnPipelineSuspended(PipelineStatus status) {
951 DVLOG(1) << __FUNCTION__ << "(" << status << ")";
952 DCHECK(main_task_runner_->BelongsToCurrentThread());
953
954 if (status != PIPELINE_OK) {
955 OnPipelineError(status);
956 return;
957 }
958
959 suspending_ = false;
960
hubbed5f36882016-01-15 22:40:37961#if defined(OS_ANDROID)
962 if (isRemote()) {
963 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner();
964 if (frame) {
965 compositor_->PaintFrameUsingOldRenderingPath(frame);
966 }
967 }
968#endif
969
sandersd1e49fb62015-12-12 01:18:06970 if (pending_resume_) {
971 pending_resume_ = false;
972 Resume();
973 return;
974 }
975}
976
[email protected]6954fe12013-01-03 03:22:32977void WebMediaPlayerImpl::OnPipelineEnded() {
[email protected]2a06ca62014-06-04 13:59:52978 DVLOG(1) << __FUNCTION__;
acolwellb4034942014-08-28 15:42:43979 DCHECK(main_task_runner_->BelongsToCurrentThread());
scherkusd2c745b2014-09-04 05:03:40980
981 // Ignore state changes until we've completed all outstanding seeks.
982 if (seeking_ || pending_seek_)
983 return;
984
985 ended_ = true;
[email protected]ce70c982013-12-20 17:04:32986 client_->timeChanged();
[email protected]576537842009-08-12 23:52:05987}
988
[email protected]a9590c22011-03-16 16:57:02989void WebMediaPlayerImpl::OnPipelineError(PipelineStatus error) {
hubbed82bed52015-12-15 23:07:16990 DVLOG(1) << __FUNCTION__;
acolwellb4034942014-08-28 15:42:43991 DCHECK(main_task_runner_->BelongsToCurrentThread());
acolwell9e0840d2014-09-06 19:01:32992 DCHECK_NE(error, PIPELINE_OK);
[email protected]a8e2cb82012-08-17 00:02:39993
994 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing) {
995 // Any error that occurs before reaching ReadyStateHaveMetadata should
996 // be considered a format error.
997 SetNetworkState(WebMediaPlayer::NetworkStateFormatError);
[email protected]a8e2cb82012-08-17 00:02:39998 return;
999 }
1000
[email protected]be57ee52013-05-28 22:27:271001 SetNetworkState(PipelineErrorToNetworkState(error));
[email protected]db190487d2009-07-30 18:51:521002}
1003
[email protected]b8877772014-03-26 20:17:151004void WebMediaPlayerImpl::OnPipelineMetadata(
acolwell9e0840d2014-09-06 19:01:321005 PipelineMetadata metadata) {
[email protected]2a06ca62014-06-04 13:59:521006 DVLOG(1) << __FUNCTION__;
[email protected]a8e2cb82012-08-17 00:02:391007
[email protected]b8877772014-03-26 20:17:151008 pipeline_metadata_ = metadata;
[email protected]739847c02014-01-16 00:12:251009
dalecurtis849cf4b22015-03-27 18:35:451010 UMA_HISTOGRAM_ENUMERATION("Media.VideoRotation", metadata.video_rotation,
acolwell9e0840d2014-09-06 19:01:321011 VIDEO_ROTATION_MAX + 1);
[email protected]b8877772014-03-26 20:17:151012 SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata);
[email protected]21c3f7502013-03-23 03:29:511013
[email protected]b8877772014-03-26 20:17:151014 if (hasVideo()) {
1015 DCHECK(!video_weblayer_);
[email protected]f78c3e82014-08-08 01:24:471016 scoped_refptr<cc::VideoLayer> layer =
loysoa6edaaff2015-05-25 03:26:441017 cc::VideoLayer::Create(cc_blink::WebLayerImpl::LayerSettings(),
1018 compositor_, pipeline_metadata_.video_rotation);
[email protected]f78c3e82014-08-08 01:24:471019
acolwell9e0840d2014-09-06 19:01:321020 if (pipeline_metadata_.video_rotation == VIDEO_ROTATION_90 ||
1021 pipeline_metadata_.video_rotation == VIDEO_ROTATION_270) {
[email protected]f78c3e82014-08-08 01:24:471022 gfx::Size size = pipeline_metadata_.natural_size;
1023 pipeline_metadata_.natural_size = gfx::Size(size.height(), size.width());
1024 }
1025
[email protected]38564622014-08-19 02:47:181026 video_weblayer_.reset(new cc_blink::WebLayerImpl(layer));
jbauman952274d2015-09-10 23:23:361027 video_weblayer_->layer()->SetContentsOpaque(opaque_);
1028 video_weblayer_->SetContentsOpaqueIsFixed(true);
[email protected]a7c4f582014-04-16 18:44:491029 client_->setWebLayer(video_weblayer_.get());
sandersdb96662f2016-01-09 00:46:061030
1031 // If there is video and the frame is hidden, then it may be time to suspend
1032 // playback.
1033 if (delegate_ && delegate_->IsHidden())
1034 OnHidden();
[email protected]a8e2cb82012-08-17 00:02:391035 }
[email protected]a8e2cb82012-08-17 00:02:391036}
1037
[email protected]ba7d5f92014-06-24 05:37:401038void WebMediaPlayerImpl::OnPipelineBufferingStateChanged(
acolwell9e0840d2014-09-06 19:01:321039 BufferingState buffering_state) {
[email protected]ba7d5f92014-06-24 05:37:401040 DVLOG(1) << __FUNCTION__ << "(" << buffering_state << ")";
[email protected]b8877772014-03-26 20:17:151041
[email protected]ba7d5f92014-06-24 05:37:401042 // Ignore buffering state changes until we've completed all outstanding seeks.
1043 if (seeking_ || pending_seek_)
1044 return;
[email protected]b8877772014-03-26 20:17:151045
[email protected]ba7d5f92014-06-24 05:37:401046 // TODO(scherkus): Handle other buffering states when Pipeline starts using
1047 // them and translate them ready state changes http://crbug.com/144683
acolwell9e0840d2014-09-06 19:01:321048 DCHECK_EQ(buffering_state, BUFFERING_HAVE_ENOUGH);
[email protected]ba7d5f92014-06-24 05:37:401049 SetReadyState(WebMediaPlayer::ReadyStateHaveEnoughData);
1050
dalecurtis849cf4b22015-03-27 18:35:451051 // Let the DataSource know we have enough data. It may use this information to
1052 // release unused network connections.
1053 if (data_source_)
1054 data_source_->OnBufferingHaveEnough();
1055
[email protected]ba7d5f92014-06-24 05:37:401056 // Blink expects a timeChanged() in response to a seek().
1057 if (should_notify_time_changed_)
1058 client_->timeChanged();
dalecurtis0f0097a2015-12-01 17:40:471059
1060 // Once we have enough, start reporting the total memory usage. We'll also
1061 // report once playback starts.
1062 ReportMemoryUsage();
[email protected]b8877772014-03-26 20:17:151063}
1064
[email protected]ef8394c2013-08-21 20:26:301065void WebMediaPlayerImpl::OnDemuxerOpened() {
acolwellb4034942014-08-28 15:42:431066 DCHECK(main_task_runner_->BelongsToCurrentThread());
wolenetz1fb319d2015-07-14 17:49:041067 client_->mediaSourceOpened(
1068 new WebMediaSourceImpl(chunk_demuxer_, media_log_));
[email protected]81bb3322011-07-21 15:55:501069}
1070
[email protected]8a561062013-11-22 01:19:311071void WebMediaPlayerImpl::OnAddTextTrack(
acolwell9e0840d2014-09-06 19:01:321072 const TextTrackConfig& config,
1073 const AddTextTrackDoneCB& done_cb) {
acolwellb4034942014-08-28 15:42:431074 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]71537722013-05-23 06:47:531075
[email protected]8a561062013-11-22 01:19:311076 const WebInbandTextTrackImpl::Kind web_kind =
1077 static_cast<WebInbandTextTrackImpl::Kind>(config.kind());
1078 const blink::WebString web_label =
1079 blink::WebString::fromUTF8(config.label());
1080 const blink::WebString web_language =
1081 blink::WebString::fromUTF8(config.language());
[email protected]427ff102013-11-26 23:45:401082 const blink::WebString web_id =
1083 blink::WebString::fromUTF8(config.id());
[email protected]71537722013-05-23 06:47:531084
[email protected]8a561062013-11-22 01:19:311085 scoped_ptr<WebInbandTextTrackImpl> web_inband_text_track(
henriks9cce5fa2014-12-12 09:35:301086 new WebInbandTextTrackImpl(web_kind, web_label, web_language, web_id));
[email protected]8a561062013-11-22 01:19:311087
acolwell9e0840d2014-09-06 19:01:321088 scoped_ptr<TextTrack> text_track(new TextTrackImpl(
dcheng652f5ff2015-12-27 08:54:001089 main_task_runner_, client_, std::move(web_inband_text_track)));
[email protected]8a561062013-11-22 01:19:311090
dcheng652f5ff2015-12-27 08:54:001091 done_cb.Run(std::move(text_track));
[email protected]71537722013-05-23 06:47:531092}
1093
sandersd1e49fb62015-12-12 01:18:061094void WebMediaPlayerImpl::OnHidden() {
1095 DCHECK(main_task_runner_->BelongsToCurrentThread());
1096
1097#if !defined(OS_ANDROID)
1098 // Suspend/Resume is enabled by default on Android.
1099 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
1100 switches::kEnableMediaSuspend)) {
1101 return;
1102 }
1103#endif // !defined(OS_ANDROID)
1104
1105 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1106 switches::kDisableMediaSuspend)) {
1107 return;
1108 }
1109
hubbed5f36882016-01-15 22:40:371110#if defined(OS_ANDROID)
1111 // If we're remote, the pipeline should already be suspended.
1112 if (isRemote())
1113 return;
1114#endif
1115
1116 ScheduleSuspend();
1117}
1118
1119void WebMediaPlayerImpl::ScheduleSuspend() {
sandersdb96662f2016-01-09 00:46:061120 if (!pipeline_.IsRunning() || !hasVideo())
sandersd1e49fb62015-12-12 01:18:061121 return;
1122
1123 if (resuming_ || seeking_) {
1124 pending_suspend_ = true;
1125 return;
1126 }
1127
1128 if (pending_resume_) {
1129 pending_resume_ = false;
1130 return;
1131 }
1132
1133 Suspend();
1134}
1135
1136void WebMediaPlayerImpl::Suspend() {
1137 DCHECK(main_task_runner_->BelongsToCurrentThread());
1138 CHECK(!suspended_);
1139 suspended_ = true;
1140 suspending_ = true;
1141 pipeline_.Suspend(
1142 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineSuspended));
1143}
1144
1145void WebMediaPlayerImpl::OnShown() {
1146 DCHECK(main_task_runner_->BelongsToCurrentThread());
1147
1148#if !defined(OS_ANDROID)
1149 // Suspend/Resume is enabled by default on Android.
1150 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
1151 switches::kEnableMediaSuspend)) {
1152 return;
1153 }
1154#endif // !defined(OS_ANDROID)
1155
1156 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1157 switches::kDisableMediaSuspend)) {
1158 return;
1159 }
1160
hubbed5f36882016-01-15 22:40:371161#if defined(OS_ANDROID)
1162 // If we're remote, the pipeline should stay suspended.
1163 if (isRemote())
1164 return;
1165#endif
1166
1167 ScheduleResume();
1168}
1169
1170void WebMediaPlayerImpl::ScheduleResume() {
sandersd1e49fb62015-12-12 01:18:061171 if (!pipeline_.IsRunning())
1172 return;
1173
1174 if (suspending_) {
1175 pending_resume_ = true;
1176 return;
1177 }
1178
1179 if (pending_suspend_) {
1180 pending_suspend_ = false;
1181 return;
1182 }
1183
hubbed5f36882016-01-15 22:40:371184 // Might already be resuming iff we came back from remote playback recently.
1185 if (suspended_ && !resuming_)
1186 Resume();
sandersd1e49fb62015-12-12 01:18:061187}
1188
1189void WebMediaPlayerImpl::Resume() {
1190 DCHECK(main_task_runner_->BelongsToCurrentThread());
1191 CHECK(suspended_);
1192 CHECK(!resuming_);
1193
1194 // If there was a time change pending when we suspended (which can happen when
1195 // we suspend immediately after a seek), surface it after resuming.
1196 bool time_changed = pending_time_change_;
1197 pending_time_change_ = false;
1198
1199 if (seeking_ || pending_seek_) {
1200 if (pending_seek_) {
1201 seek_time_ = pending_seek_time_;
1202 pending_seek_ = false;
1203 pending_seek_time_ = base::TimeDelta();
1204 }
1205 time_changed = true;
1206 } else {
1207 // It is safe to call GetCurrentFrameTimestamp() because VFC is stopped
1208 // during Suspend(). It won't be started again until after Resume() is
1209 // called.
1210 seek_time_ = compositor_->GetCurrentFrameTimestamp();
1211 }
1212
1213 if (chunk_demuxer_)
1214 chunk_demuxer_->StartWaitingForSeek(seek_time_);
1215
1216 resuming_ = true;
1217 pipeline_.Resume(CreateRenderer(), seek_time_,
1218 BIND_TO_RENDER_LOOP1(&WebMediaPlayerImpl::OnPipelineSeeked,
1219 time_changed));
1220}
1221
hubbed5f36882016-01-15 22:40:371222#if defined(OS_ANDROID) // WMPI_CAST
1223
1224bool WebMediaPlayerImpl::isRemote() const {
1225 return cast_impl_.isRemote();
1226}
1227
1228void WebMediaPlayerImpl::SetMediaPlayerManager(
1229 RendererMediaPlayerManagerInterface* media_player_manager) {
1230 cast_impl_.SetMediaPlayerManager(media_player_manager);
1231}
1232
1233void WebMediaPlayerImpl::requestRemotePlayback() {
1234 cast_impl_.requestRemotePlayback();
1235}
1236
1237void WebMediaPlayerImpl::requestRemotePlaybackControl() {
1238 cast_impl_.requestRemotePlaybackControl();
1239}
1240
1241void WebMediaPlayerImpl::OnRemotePlaybackEnded() {
1242 DVLOG(1) << __FUNCTION__;
1243 DCHECK(main_task_runner_->BelongsToCurrentThread());
1244
1245 ended_ = true;
1246 client_->timeChanged();
1247}
1248
1249void WebMediaPlayerImpl::OnDisconnectedFromRemoteDevice(double t) {
1250 paused_time_ = base::TimeDelta::FromSecondsD(t);
1251 pending_seek_ = true;
1252 pending_seek_time_ = paused_time_;
1253
1254 ScheduleResume();
1255
1256 if (paused_time_ == pipeline_.GetMediaDuration()) {
1257 ended_ = true;
1258 }
1259 // We already told the delegate we're paused when remoting started.
1260 client_->playbackStateChanged();
1261 client_->disconnectedFromRemoteDevice();
1262}
1263
1264void WebMediaPlayerImpl::SuspendForRemote() {
1265 if (suspended_ && !suspending_) {
1266 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner();
1267 if (frame) {
1268 compositor_->PaintFrameUsingOldRenderingPath(frame);
1269 }
1270 }
1271 ScheduleSuspend();
1272}
1273
1274gfx::Size WebMediaPlayerImpl::GetCanvasSize() const {
1275 if (!video_weblayer_)
1276 return pipeline_metadata_.natural_size;
1277
1278 return video_weblayer_->bounds();
1279}
1280
1281void WebMediaPlayerImpl::SetDeviceScaleFactor(float scale_factor) {
1282 cast_impl_.SetDeviceScaleFactor(scale_factor);
1283}
1284#endif // defined(OS_ANDROID) // WMPI_CAST
1285
[email protected]fee8a902014-06-03 13:43:361286void WebMediaPlayerImpl::DataSourceInitialized(bool success) {
hubbed82bed52015-12-15 23:07:161287 DVLOG(1) << __FUNCTION__;
acolwellb4034942014-08-28 15:42:431288 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]a9415292012-01-19 19:55:201289
[email protected]d250190da3b2012-07-23 22:57:301290 if (!success) {
[email protected]ef405f66b2012-04-18 02:39:551291 SetNetworkState(WebMediaPlayer::NetworkStateFormatError);
[email protected]a9415292012-01-19 19:55:201292 return;
1293 }
1294
[email protected]ef8394c2013-08-21 20:26:301295 StartPipeline();
[email protected]a9415292012-01-19 19:55:201296}
1297
[email protected]122f40252012-06-12 05:01:561298void WebMediaPlayerImpl::NotifyDownloading(bool is_downloading) {
hubbed82bed52015-12-15 23:07:161299 DVLOG(1) << __FUNCTION__;
[email protected]122f40252012-06-12 05:01:561300 if (!is_downloading && network_state_ == WebMediaPlayer::NetworkStateLoading)
1301 SetNetworkState(WebMediaPlayer::NetworkStateIdle);
1302 else if (is_downloading && network_state_ == WebMediaPlayer::NetworkStateIdle)
1303 SetNetworkState(WebMediaPlayer::NetworkStateLoading);
1304 media_log_->AddEvent(
1305 media_log_->CreateBooleanEvent(
acolwell9e0840d2014-09-06 19:01:321306 MediaLogEvent::NETWORK_ACTIVITY_SET,
[email protected]122f40252012-06-12 05:01:561307 "is_downloading_data", is_downloading));
1308}
1309
sandersd1e49fb62015-12-12 01:18:061310scoped_ptr<Renderer> WebMediaPlayerImpl::CreateRenderer() {
1311 return renderer_factory_->CreateRenderer(
1312 media_task_runner_, worker_task_runner_, audio_source_provider_.get(),
1313 compositor_);
1314}
1315
[email protected]ef8394c2013-08-21 20:26:301316void WebMediaPlayerImpl::StartPipeline() {
acolwellb4034942014-08-28 15:42:431317 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]ddbc6ff2013-04-19 15:28:331318
xhwange8c4181a2014-12-06 08:10:011319 Demuxer::EncryptedMediaInitDataCB encrypted_media_init_data_cb =
1320 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnEncryptedMediaInitData);
[email protected]2b57e2e2014-05-09 11:07:251321
[email protected]ddbc6ff2013-04-19 15:28:331322 // Figure out which demuxer to use.
[email protected]ef8394c2013-08-21 20:26:301323 if (load_type_ != LoadTypeMediaSource) {
[email protected]ddbc6ff2013-04-19 15:28:331324 DCHECK(!chunk_demuxer_);
[email protected]f5443ef72013-04-22 04:03:381325 DCHECK(data_source_);
1326
j.isorcef6778e652015-11-16 17:14:251327#if !defined(MEDIA_DISABLE_FFMPEG)
xhwange8c4181a2014-12-06 08:10:011328 demuxer_.reset(new FFmpegDemuxer(media_task_runner_, data_source_.get(),
1329 encrypted_media_init_data_cb, media_log_));
j.isorcef6778e652015-11-16 17:14:251330#else
1331 OnPipelineError(PipelineStatus::DEMUXER_ERROR_COULD_NOT_OPEN);
1332 return;
1333#endif
[email protected]ddbc6ff2013-04-19 15:28:331334 } else {
[email protected]f5443ef72013-04-22 04:03:381335 DCHECK(!chunk_demuxer_);
1336 DCHECK(!data_source_);
1337
acolwell9e0840d2014-09-06 19:01:321338 chunk_demuxer_ = new ChunkDemuxer(
[email protected]ef8394c2013-08-21 20:26:301339 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnDemuxerOpened),
wolenetz1fb319d2015-07-14 17:49:041340 encrypted_media_init_data_cb, media_log_, true);
[email protected]f5443ef72013-04-22 04:03:381341 demuxer_.reset(chunk_demuxer_);
[email protected]ddbc6ff2013-04-19 15:28:331342 }
1343
[email protected]f5443ef72013-04-22 04:03:381344 // ... and we're ready to go!
[email protected]d228aeec2014-06-20 19:16:491345 seeking_ = true;
xhwangf94a634d2014-10-22 22:07:271346
sandersd1e49fb62015-12-12 01:18:061347 // TODO(sandersd): On Android, defer Start() if the tab is not visible.
[email protected]f6af7592014-02-28 10:09:111348 pipeline_.Start(
sandersd1e49fb62015-12-12 01:18:061349 demuxer_.get(), CreateRenderer(),
[email protected]f5443ef72013-04-22 04:03:381350 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineEnded),
1351 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineError),
[email protected]4e982192014-06-21 13:35:451352 BIND_TO_RENDER_LOOP1(&WebMediaPlayerImpl::OnPipelineSeeked, false),
[email protected]b8877772014-03-26 20:17:151353 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineMetadata),
[email protected]ba7d5f92014-06-24 05:37:401354 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineBufferingStateChanged),
xhwang59805902014-08-29 01:44:151355 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnDurationChanged),
jrummell74fc4f942015-03-02 22:48:271356 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnAddTextTrack),
1357 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnWaitingForDecryptionKey));
[email protected]f5443ef72013-04-22 04:03:381358}
1359
1360void WebMediaPlayerImpl::SetNetworkState(WebMediaPlayer::NetworkState state) {
[email protected]2a06ca62014-06-04 13:59:521361 DVLOG(1) << __FUNCTION__ << "(" << state << ")";
acolwellb4034942014-08-28 15:42:431362 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]f5443ef72013-04-22 04:03:381363 network_state_ = state;
1364 // Always notify to ensure client has the latest value.
[email protected]ce70c982013-12-20 17:04:321365 client_->networkStateChanged();
[email protected]f5443ef72013-04-22 04:03:381366}
1367
1368void WebMediaPlayerImpl::SetReadyState(WebMediaPlayer::ReadyState state) {
[email protected]2a06ca62014-06-04 13:59:521369 DVLOG(1) << __FUNCTION__ << "(" << state << ")";
acolwellb4034942014-08-28 15:42:431370 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]f5443ef72013-04-22 04:03:381371
[email protected]fee8a902014-06-03 13:43:361372 if (state == WebMediaPlayer::ReadyStateHaveEnoughData && data_source_ &&
1373 data_source_->assume_fully_buffered() &&
[email protected]f5443ef72013-04-22 04:03:381374 network_state_ == WebMediaPlayer::NetworkStateLoading)
1375 SetNetworkState(WebMediaPlayer::NetworkStateLoaded);
1376
1377 ready_state_ = state;
1378 // Always notify to ensure client has the latest value.
[email protected]ce70c982013-12-20 17:04:321379 client_->readyStateChanged();
[email protected]f5443ef72013-04-22 04:03:381380}
1381
[email protected]180ef242013-11-07 06:50:461382blink::WebAudioSourceProvider* WebMediaPlayerImpl::audioSourceProvider() {
[email protected]ff875be52013-06-02 23:47:381383 return audio_source_provider_.get();
[email protected]f5443ef72013-04-22 04:03:381384}
1385
[email protected]f5443ef72013-04-22 04:03:381386double WebMediaPlayerImpl::GetPipelineDuration() const {
[email protected]f6af7592014-02-28 10:09:111387 base::TimeDelta duration = pipeline_.GetMediaDuration();
[email protected]f5443ef72013-04-22 04:03:381388
1389 // Return positive infinity if the resource is unbounded.
1390 // http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html#dom-media-duration
acolwell9e0840d2014-09-06 19:01:321391 if (duration == kInfiniteDuration())
[email protected]f5443ef72013-04-22 04:03:381392 return std::numeric_limits<double>::infinity();
1393
1394 return duration.InSecondsF();
1395}
1396
[email protected]75e145a2014-04-15 17:44:321397void WebMediaPlayerImpl::OnDurationChanged() {
[email protected]f5443ef72013-04-22 04:03:381398 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing)
1399 return;
1400
[email protected]ce70c982013-12-20 17:04:321401 client_->durationChanged();
[email protected]f5443ef72013-04-22 04:03:381402}
1403
[email protected]75e145a2014-04-15 17:44:321404void WebMediaPlayerImpl::OnNaturalSizeChanged(gfx::Size size) {
acolwellb4034942014-08-28 15:42:431405 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]739847c02014-01-16 00:12:251406 DCHECK_NE(ready_state_, WebMediaPlayer::ReadyStateHaveNothing);
1407 TRACE_EVENT0("media", "WebMediaPlayerImpl::OnNaturalSizeChanged");
1408
1409 media_log_->AddEvent(
1410 media_log_->CreateVideoSizeSetEvent(size.width(), size.height()));
[email protected]b8877772014-03-26 20:17:151411 pipeline_metadata_.natural_size = size;
[email protected]739847c02014-01-16 00:12:251412
1413 client_->sizeChanged();
1414}
1415
[email protected]75e145a2014-04-15 17:44:321416void WebMediaPlayerImpl::OnOpacityChanged(bool opaque) {
acolwellb4034942014-08-28 15:42:431417 DCHECK(main_task_runner_->BelongsToCurrentThread());
[email protected]75e145a2014-04-15 17:44:321418 DCHECK_NE(ready_state_, WebMediaPlayer::ReadyStateHaveNothing);
1419
1420 opaque_ = opaque;
jbauman952274d2015-09-10 23:23:361421 // Modify content opaqueness of cc::Layer directly so that
1422 // SetContentsOpaqueIsFixed is ignored.
[email protected]75e145a2014-04-15 17:44:321423 if (video_weblayer_)
jbauman952274d2015-09-10 23:23:361424 video_weblayer_->layer()->SetContentsOpaque(opaque_);
[email protected]75e145a2014-04-15 17:44:321425}
1426
[email protected]dd061e12014-05-06 19:21:221427static void GetCurrentFrameAndSignal(
1428 VideoFrameCompositor* compositor,
acolwell9e0840d2014-09-06 19:01:321429 scoped_refptr<VideoFrame>* video_frame_out,
[email protected]dd061e12014-05-06 19:21:221430 base::WaitableEvent* event) {
1431 TRACE_EVENT0("media", "GetCurrentFrameAndSignal");
dalecurtis44ce4de2015-05-11 18:42:071432 *video_frame_out = compositor->GetCurrentFrameAndUpdateIfStale();
[email protected]dd061e12014-05-06 19:21:221433 event->Signal();
1434}
1435
acolwell9e0840d2014-09-06 19:01:321436scoped_refptr<VideoFrame>
[email protected]dd061e12014-05-06 19:21:221437WebMediaPlayerImpl::GetCurrentFrameFromCompositor() {
1438 TRACE_EVENT0("media", "WebMediaPlayerImpl::GetCurrentFrameFromCompositor");
1439 if (compositor_task_runner_->BelongsToCurrentThread())
dalecurtis44ce4de2015-05-11 18:42:071440 return compositor_->GetCurrentFrameAndUpdateIfStale();
[email protected]dd061e12014-05-06 19:21:221441
1442 // Use a posted task and waitable event instead of a lock otherwise
1443 // WebGL/Canvas can see different content than what the compositor is seeing.
acolwell9e0840d2014-09-06 19:01:321444 scoped_refptr<VideoFrame> video_frame;
[email protected]dd061e12014-05-06 19:21:221445 base::WaitableEvent event(false, false);
1446 compositor_task_runner_->PostTask(FROM_HERE,
1447 base::Bind(&GetCurrentFrameAndSignal,
1448 base::Unretained(compositor_),
1449 &video_frame,
1450 &event));
1451 event.Wait();
1452 return video_frame;
1453}
1454
dalecurtis2e50e6f62015-01-09 02:42:521455void WebMediaPlayerImpl::UpdatePausedTime() {
1456 DCHECK(main_task_runner_->BelongsToCurrentThread());
1457
1458 // pause() may be called after playback has ended and the HTMLMediaElement
1459 // requires that currentTime() == duration() after ending. We want to ensure
1460 // |paused_time_| matches currentTime() in this case or a future seek() may
1461 // incorrectly discard what it thinks is a seek to the existing time.
1462 paused_time_ =
1463 ended_ ? pipeline_.GetMediaDuration() : pipeline_.GetMediaTime();
1464}
1465
dalecurtis0f0097a2015-12-01 17:40:471466void WebMediaPlayerImpl::NotifyPlaybackStarted() {
hubbed5f36882016-01-15 22:40:371467#if defined(OS_ANDROID) // WMPI_CAST
1468 // We do not tell our delegates about remote playback, becuase that would
1469 // keep the device awake, which is not what we want.
1470 if (isRemote())
1471 return;
1472#endif
dalecurtis0f0097a2015-12-01 17:40:471473 if (delegate_)
1474 delegate_->DidPlay(this);
1475 if (!memory_usage_reporting_timer_.IsRunning()) {
1476 memory_usage_reporting_timer_.Start(FROM_HERE,
1477 base::TimeDelta::FromSeconds(2), this,
1478 &WebMediaPlayerImpl::ReportMemoryUsage);
1479 }
1480}
1481
1482void WebMediaPlayerImpl::NotifyPlaybackPaused() {
hubbed5f36882016-01-15 22:40:371483#if defined(OS_ANDROID) // WMPI_CAST
1484 if (isRemote())
1485 return;
1486#endif
dalecurtis0f0097a2015-12-01 17:40:471487 if (delegate_)
1488 delegate_->DidPause(this);
1489 memory_usage_reporting_timer_.Stop();
1490 ReportMemoryUsage();
1491}
1492
dalecurtis83266c72015-10-29 18:43:201493void WebMediaPlayerImpl::ReportMemoryUsage() {
1494 DCHECK(main_task_runner_->BelongsToCurrentThread());
1495
wdzierzanowskifd4cd91c52015-12-02 23:50:201496 // About base::Unretained() usage below: We destroy |demuxer_| on the main
1497 // thread. Before that, however, ~WebMediaPlayerImpl() posts a task to the
1498 // media thread and waits for it to finish. Hence, the GetMemoryUsage() task
1499 // posted here must finish earlier.
1500
1501 if (demuxer_) {
1502 base::PostTaskAndReplyWithResult(
1503 media_task_runner_.get(), FROM_HERE,
1504 base::Bind(&Demuxer::GetMemoryUsage, base::Unretained(demuxer_.get())),
1505 base::Bind(&WebMediaPlayerImpl::FinishMemoryUsageReport, AsWeakPtr()));
1506 } else {
1507 FinishMemoryUsageReport(0);
1508 }
1509}
1510
1511void WebMediaPlayerImpl::FinishMemoryUsageReport(int64_t demuxer_memory_usage) {
1512 DCHECK(main_task_runner_->BelongsToCurrentThread());
1513
dalecurtis83266c72015-10-29 18:43:201514 const PipelineStatistics stats = pipeline_.GetStatistics();
1515 const int64_t current_memory_usage =
1516 stats.audio_memory_usage + stats.video_memory_usage +
1517 (data_source_ ? data_source_->GetMemoryUsage() : 0) +
wdzierzanowskifd4cd91c52015-12-02 23:50:201518 demuxer_memory_usage;
dalecurtis83266c72015-10-29 18:43:201519
1520 DVLOG(2) << "Memory Usage -- Audio: " << stats.audio_memory_usage
1521 << ", Video: " << stats.video_memory_usage << ", DataSource: "
1522 << (data_source_ ? data_source_->GetMemoryUsage() : 0)
wdzierzanowskifd4cd91c52015-12-02 23:50:201523 << ", Demuxer: " << demuxer_memory_usage;
dalecurtis83266c72015-10-29 18:43:201524
1525 const int64_t delta = current_memory_usage - last_reported_memory_usage_;
1526 last_reported_memory_usage_ = current_memory_usage;
1527 adjust_allocated_memory_cb_.Run(delta);
1528}
1529
acolwell9e0840d2014-09-06 19:01:321530} // namespace media