blob: 60bd397b501974dd6c9e7e36c77662e022dd0b03 [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
[email protected]5e35a8d2013-07-10 19:37:215#include "content/renderer/media/webmediaplayer_impl.h"
[email protected]8931c41a2009-07-07 17:31:496
[email protected]c2a45e242013-02-15 20:24:587#include <algorithm>
[email protected]47b06ceb2010-08-04 22:41:118#include <limits>
[email protected]d82b18ae2011-03-23 21:28:599#include <string>
[email protected]cbdc8c2b2012-06-16 01:27:3610#include <vector>
[email protected]47b06ceb2010-08-04 22:41:1111
[email protected]08273c7b2011-09-17 00:33:5112#include "base/bind.h"
[email protected]2041cf342010-02-19 03:15:5913#include "base/callback.h"
[email protected]ddbc6ff2013-04-19 15:28:3314#include "base/command_line.h"
[email protected]926f8fd2013-04-12 20:27:5315#include "base/debug/crash_logging.h"
[email protected]bfc05f22013-10-19 17:55:1616#include "base/debug/trace_event.h"
[email protected]7ccb7072013-06-10 20:56:2817#include "base/message_loop/message_loop_proxy.h"
[email protected]b0b258f2011-11-08 00:34:2318#include "base/metrics/histogram.h"
[email protected]4ce532f2013-03-27 22:03:4019#include "base/strings/string_number_conversions.h"
[email protected]cf02541b2012-04-11 08:02:1720#include "base/synchronization/waitable_event.h"
[email protected]21c3f7502013-03-23 03:29:5121#include "cc/layers/video_layer.h"
[email protected]ca73adc72013-07-11 11:37:0222#include "content/public/common/content_switches.h"
[email protected]5e35a8d2013-07-10 19:37:2123#include "content/renderer/media/buffered_data_source.h"
[email protected]61582e8c2013-07-14 00:38:3324#include "content/renderer/media/crypto/key_systems.h"
[email protected]5e35a8d2013-07-10 19:37:2125#include "content/renderer/media/texttrack_impl.h"
26#include "content/renderer/media/webaudiosourceprovider_impl.h"
27#include "content/renderer/media/webinbandtexttrack_impl.h"
28#include "content/renderer/media/webmediaplayer_delegate.h"
29#include "content/renderer/media/webmediaplayer_params.h"
30#include "content/renderer/media/webmediaplayer_util.h"
[email protected]ef8394c2013-08-21 20:26:3031#include "content/renderer/media/webmediasource_impl.h"
[email protected]adab2332013-07-25 18:04:3232#include "content/renderer/pepper/pepper_webplugin_impl.h"
[email protected]6523b242013-03-13 11:10:0733#include "gpu/GLES2/gl2extchromium.h"
[email protected]e4fc09e2012-04-06 03:17:4434#include "media/audio/null_audio_sink.h"
[email protected]2c539b82012-08-18 04:10:1935#include "media/base/bind_to_loop.h"
[email protected]f8db8132010-12-03 00:27:4936#include "media/base/filter_collection.h"
[email protected]32da1002010-03-03 21:57:3537#include "media/base/limits.h"
[email protected]090f7312011-08-05 23:26:4038#include "media/base/media_log.h"
[email protected]ddbc6ff2013-04-19 15:28:3339#include "media/base/media_switches.h"
[email protected]d399866c2012-01-18 09:30:3240#include "media/base/pipeline.h"
[email protected]8a561062013-11-22 01:19:3141#include "media/base/text_renderer.h"
[email protected]e81283bb2010-08-31 18:01:2142#include "media/base/video_frame.h"
[email protected]37136d162012-04-09 23:39:1943#include "media/filters/audio_renderer_impl.h"
[email protected]efe7cd22012-09-12 23:55:0144#include "media/filters/chunk_demuxer.h"
[email protected]ddbc6ff2013-04-19 15:28:3345#include "media/filters/ffmpeg_audio_decoder.h"
46#include "media/filters/ffmpeg_demuxer.h"
47#include "media/filters/ffmpeg_video_decoder.h"
[email protected]1cad8802013-08-13 16:54:3248#include "media/filters/gpu_video_accelerator_factories.h"
[email protected]b9a407e2013-07-24 07:30:0249#include "media/filters/gpu_video_decoder.h"
[email protected]ddbc6ff2013-04-19 15:28:3350#include "media/filters/opus_audio_decoder.h"
[email protected]d4833b72012-01-13 22:16:1751#include "media/filters/video_renderer_base.h"
[email protected]ddbc6ff2013-04-19 15:28:3352#include "media/filters/vpx_video_decoder.h"
[email protected]745746d2013-08-23 02:09:1653#include "third_party/WebKit/public/platform/WebMediaSource.h"
[email protected]c10884462013-05-30 00:22:0954#include "third_party/WebKit/public/platform/WebRect.h"
55#include "third_party/WebKit/public/platform/WebSize.h"
56#include "third_party/WebKit/public/platform/WebString.h"
57#include "third_party/WebKit/public/platform/WebURL.h"
[email protected]f961a0f2013-09-23 04:15:4558#include "third_party/WebKit/public/web/WebDocument.h"
[email protected]2255a9332013-06-17 05:12:3159#include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
60#include "third_party/WebKit/public/web/WebView.h"
[email protected]38aefc312011-09-20 05:06:3761#include "v8/include/v8.h"
[email protected]799fd732013-05-15 21:18:5262#include "webkit/renderer/compositor_bindings/web_layer_impl.h"
[email protected]b3f2b912009-04-09 16:18:5263
[email protected]180ef242013-11-07 06:50:4664using blink::WebCanvas;
65using blink::WebMediaPlayer;
66using blink::WebRect;
67using blink::WebSize;
68using blink::WebString;
[email protected]a9590c22011-03-16 16:57:0269using media::PipelineStatus;
[email protected]ec9212f2008-12-18 21:40:3670
[email protected]8931c41a2009-07-07 17:31:4971namespace {
72
[email protected]38aefc312011-09-20 05:06:3773// Amount of extra memory used by each player instance reported to V8.
74// It is not exact number -- first, it differs on different platforms,
75// and second, it is very hard to calculate. Instead, use some arbitrary
76// value that will cause garbage collection from time to time. We don't want
77// it to happen on every allocation, but don't want 5k players to sit in memory
78// either. Looks that chosen constant achieves both goals, at least for audio
79// objects. (Do not worry about video objects yet, JS programs do not create
80// thousands of them...)
81const int kPlayerExtraMemory = 1024 * 1024;
82
[email protected]378f0b72009-08-11 17:11:4283// Limits the range of playback rate.
84//
85// TODO(kylep): Revisit these.
86//
87// Vista has substantially lower performance than XP or Windows7. If you speed
88// up a video too much, it can't keep up, and rendering stops updating except on
89// the time bar. For really high speeds, audio becomes a bottleneck and we just
90// use up the data we have, which may not achieve the speed requested, but will
91// not crash the tab.
92//
93// A very slow speed, ie 0.00000001x, causes the machine to lock up. (It seems
94// like a busy loop). It gets unresponsive, although its not completely dead.
95//
96// Also our timers are not very accurate (especially for ogg), which becomes
97// evident at low speeds and on Vista. Since other speeds are risky and outside
98// the norms, we think 1/16x to 16x is a safe and useful range for now.
[email protected]39bdde32013-04-17 17:44:2099const double kMinRate = 0.0625;
100const double kMaxRate = 16.0;
[email protected]378f0b72009-08-11 17:11:42101
[email protected]2ca7d5c2012-10-23 07:30:54102// Prefix for histograms related to Encrypted Media Extensions.
103const char* kMediaEme = "Media.EME.";
[email protected]61582e8c2013-07-14 00:38:33104
[email protected]8931c41a2009-07-07 17:31:49105} // namespace
106
[email protected]5e35a8d2013-07-10 19:37:21107namespace content {
[email protected]add51772009-06-11 18:25:17108
[email protected]a8884632012-06-29 03:05:34109#define COMPILE_ASSERT_MATCHING_ENUM(name) \
[email protected]2ca7d5c2012-10-23 07:30:54110 COMPILE_ASSERT(static_cast<int>(WebMediaPlayer::CORSMode ## name) == \
[email protected]a8884632012-06-29 03:05:34111 static_cast<int>(BufferedResourceLoader::k ## name), \
[email protected]a5a01102012-06-06 17:01:24112 mismatching_enums)
113COMPILE_ASSERT_MATCHING_ENUM(Unspecified);
114COMPILE_ASSERT_MATCHING_ENUM(Anonymous);
115COMPILE_ASSERT_MATCHING_ENUM(UseCredentials);
116#undef COMPILE_ASSERT_MATCHING_ENUM
117
[email protected]2c539b82012-08-18 04:10:19118#define BIND_TO_RENDER_LOOP(function) \
[email protected]e82c0e352013-03-01 01:53:46119 media::BindToLoop(main_loop_, base::Bind(function, AsWeakPtr()))
[email protected]2c539b82012-08-18 04:10:19120
[email protected]62e5e682013-03-07 23:53:24121#define BIND_TO_RENDER_LOOP_1(function, arg1) \
122 media::BindToLoop(main_loop_, base::Bind(function, AsWeakPtr(), arg1))
123
[email protected]5983adb2012-10-24 00:12:00124#define BIND_TO_RENDER_LOOP_2(function, arg1, arg2) \
[email protected]e82c0e352013-03-01 01:53:46125 media::BindToLoop(main_loop_, base::Bind(function, AsWeakPtr(), arg1, arg2))
[email protected]5983adb2012-10-24 00:12:00126
[email protected]2ef99602012-12-08 04:22:21127static void LogMediaSourceError(const scoped_refptr<media::MediaLog>& media_log,
128 const std::string& error) {
129 media_log->AddEvent(media_log->CreateMediaSourceErrorEvent(error));
130}
131
[email protected]5b5bb9d2010-10-22 19:57:36132WebMediaPlayerImpl::WebMediaPlayerImpl(
[email protected]180ef242013-11-07 06:50:46133 blink::WebFrame* frame,
134 blink::WebMediaPlayerClient* client,
[email protected]b8976652011-10-26 23:46:55135 base::WeakPtr<WebMediaPlayerDelegate> delegate,
[email protected]e82b2bd2013-01-02 17:47:57136 const WebMediaPlayerParams& params)
[email protected]a9415292012-01-19 19:55:20137 : frame_(frame),
[email protected]ef405f66b2012-04-18 02:39:55138 network_state_(WebMediaPlayer::NetworkStateEmpty),
139 ready_state_(WebMediaPlayer::ReadyStateHaveNothing),
[email protected]e82c0e352013-03-01 01:53:46140 main_loop_(base::MessageLoopProxy::current()),
[email protected]c1330c82013-06-06 02:23:25141 media_loop_(params.message_loop_proxy()),
[email protected]49480902009-07-14 20:23:43142 paused_(true),
[email protected]b3766a22010-12-22 17:34:13143 seeking_(false),
[email protected]49480902009-07-14 20:23:43144 playback_rate_(0.0f),
[email protected]5d11eff2011-09-15 00:06:06145 pending_seek_(false),
[email protected]b1a975e2011-12-21 00:12:39146 pending_seek_seconds_(0.0f),
[email protected]5badb082010-06-11 17:40:15147 client_(client),
[email protected]baff4512011-10-19 18:21:07148 delegate_(delegate),
[email protected]d726eddc2013-07-02 22:25:55149 defer_load_cb_(params.defer_load_cb()),
[email protected]e82b2bd2013-01-02 17:47:57150 media_log_(params.media_log()),
[email protected]c5b1b642012-03-26 19:40:51151 accelerated_compositing_reported_(false),
[email protected]9e2269d2012-01-07 00:06:21152 incremented_externally_allocated_memory_(false),
[email protected]ddbc6ff2013-04-19 15:28:33153 gpu_factories_(params.gpu_factories()),
[email protected]a8884632012-06-29 03:05:34154 is_local_source_(false),
[email protected]132dd57c2012-08-10 23:24:34155 supports_save_(true),
[email protected]b49beeb2013-03-01 20:04:00156 starting_(false),
[email protected]f5443ef72013-04-22 04:03:38157 chunk_demuxer_(NULL),
[email protected]c46a9f42013-10-16 03:28:18158 current_frame_painted_(false),
159 frames_dropped_before_paint_(0),
[email protected]21c3f7502013-03-23 03:29:51160 pending_repaint_(false),
[email protected]29037ce52013-05-06 22:44:16161 pending_size_change_(false),
[email protected]71537722013-05-23 06:47:53162 video_frame_provider_client_(NULL),
163 text_track_index_(0) {
[email protected]c93eb0a62011-08-09 22:47:24164 media_log_->AddEvent(
165 media_log_->CreateEvent(media::MediaLogEvent::WEBMEDIAPLAYER_CREATED));
[email protected]4e6be3f2009-05-07 02:24:44166
[email protected]cadac622013-06-11 16:46:36167 pipeline_.reset(new media::Pipeline(media_loop_, media_log_.get()));
[email protected]db190487d2009-07-30 18:51:52168
[email protected]c50edb962013-10-19 18:05:07169 // |gpu_factories_| requires that its entry points be called on its
170 // |GetMessageLoop()|. Since |pipeline_| will own decoders created from the
171 // factories, require that their message loops are identical.
172 DCHECK(!gpu_factories_ || (gpu_factories_->GetMessageLoop() == media_loop_));
173
[email protected]e82b2bd2013-01-02 17:47:57174 // Let V8 know we started new thread if we did not do it yet.
[email protected]da952fd2012-01-13 03:49:25175 // Made separate task to avoid deletion of player currently being created.
176 // Also, delaying GC until after player starts gets rid of starting lag --
177 // collection happens in parallel with playing.
178 //
179 // TODO(enal): remove when we get rid of per-audio-stream thread.
[email protected]e82c0e352013-03-01 01:53:46180 main_loop_->PostTask(
[email protected]da952fd2012-01-13 03:49:25181 FROM_HERE,
182 base::Bind(&WebMediaPlayerImpl::IncrementExternallyAllocatedMemory,
183 AsWeakPtr()));
184
[email protected]da952fd2012-01-13 03:49:25185 // Also we want to be notified of |main_loop_| destruction.
[email protected]fb5af232013-04-22 22:40:03186 base::MessageLoop::current()->AddDestructionObserver(this);
[email protected]da952fd2012-01-13 03:49:25187
[email protected]180ef242013-11-07 06:50:46188 if (blink::WebRuntimeFeatures::isPrefixedEncryptedMediaEnabled()) {
[email protected]abd36b3af2012-12-22 03:42:02189 decryptor_.reset(new ProxyDecryptor(
[email protected]04af49912013-06-21 22:09:01190#if defined(ENABLE_PEPPER_CDMS)
[email protected]abd36b3af2012-12-22 03:42:02191 client,
192 frame,
[email protected]04af49912013-06-21 22:09:01193#endif
[email protected]abd36b3af2012-12-22 03:42:02194 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnKeyAdded),
195 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnKeyError),
[email protected]7e06e6ac2013-06-20 21:34:15196 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnKeyMessage)));
[email protected]47ebb0e2012-11-30 08:28:29197 }
[email protected]893f28282012-12-14 22:51:35198
[email protected]ddbc6ff2013-04-19 15:28:33199 // Use the null sink if no sink was provided.
[email protected]4a914882013-01-10 00:43:48200 audio_source_provider_ = new WebAudioSourceProviderImpl(
[email protected]ff875be52013-06-02 23:47:38201 params.audio_renderer_sink().get()
202 ? params.audio_renderer_sink()
[email protected]c1330c82013-06-06 02:23:25203 : new media::NullAudioSink(media_loop_));
[email protected]ec9212f2008-12-18 21:40:36204}
205
[email protected]4e6be3f2009-05-07 02:24:44206WebMediaPlayerImpl::~WebMediaPlayerImpl() {
[email protected]21c3f7502013-03-23 03:29:51207 SetVideoFrameProviderClient(NULL);
208 GetClient()->setWebLayer(NULL);
[email protected]21c3f7502013-03-23 03:29:51209
[email protected]e82c0e352013-03-01 01:53:46210 DCHECK(main_loop_->BelongsToCurrentThread());
[email protected]c93eb0a62011-08-09 22:47:24211 media_log_->AddEvent(
212 media_log_->CreateEvent(media::MediaLogEvent::WEBMEDIAPLAYER_DESTROYED));
[email protected]d43ed912009-02-03 04:52:53213
[email protected]9b55d802013-06-04 02:39:46214 if (delegate_.get())
[email protected]baff4512011-10-19 18:21:07215 delegate_->PlayerGone(this);
216
[email protected]a3702c52013-05-09 05:40:30217 Destroy();
218
[email protected]e82c0e352013-03-01 01:53:46219 // Remove destruction observer if we're being destroyed but the main thread is
220 // still running.
[email protected]fb5af232013-04-22 22:40:03221 if (base::MessageLoop::current())
222 base::MessageLoop::current()->RemoveDestructionObserver(this);
[email protected]ec9212f2008-12-18 21:40:36223}
224
[email protected]daeae722011-11-15 23:00:58225namespace {
226
227// Helper enum for reporting scheme histograms.
228enum URLSchemeForHistogram {
229 kUnknownURLScheme,
230 kMissingURLScheme,
231 kHttpURLScheme,
232 kHttpsURLScheme,
233 kFtpURLScheme,
234 kChromeExtensionURLScheme,
235 kJavascriptURLScheme,
236 kFileURLScheme,
237 kBlobURLScheme,
238 kDataURLScheme,
[email protected]aacd4a42012-04-11 02:34:48239 kFileSystemScheme,
240 kMaxURLScheme = kFileSystemScheme // Must be equal to highest enum value.
[email protected]daeae722011-11-15 23:00:58241};
242
243URLSchemeForHistogram URLScheme(const GURL& url) {
244 if (!url.has_scheme()) return kMissingURLScheme;
245 if (url.SchemeIs("http")) return kHttpURLScheme;
246 if (url.SchemeIs("https")) return kHttpsURLScheme;
247 if (url.SchemeIs("ftp")) return kFtpURLScheme;
248 if (url.SchemeIs("chrome-extension")) return kChromeExtensionURLScheme;
249 if (url.SchemeIs("javascript")) return kJavascriptURLScheme;
250 if (url.SchemeIs("file")) return kFileURLScheme;
251 if (url.SchemeIs("blob")) return kBlobURLScheme;
252 if (url.SchemeIs("data")) return kDataURLScheme;
[email protected]aacd4a42012-04-11 02:34:48253 if (url.SchemeIs("filesystem")) return kFileSystemScheme;
[email protected]daeae722011-11-15 23:00:58254 return kUnknownURLScheme;
255}
256
257} // anonymous namespace
258
[email protected]180ef242013-11-07 06:50:46259void WebMediaPlayerImpl::load(LoadType load_type, const blink::WebURL& url,
[email protected]62e5e682013-03-07 23:53:24260 CORSMode cors_mode) {
[email protected]d726eddc2013-07-02 22:25:55261 if (!defer_load_cb_.is_null()) {
262 defer_load_cb_.Run(base::Bind(
[email protected]ef8394c2013-08-21 20:26:30263 &WebMediaPlayerImpl::DoLoad, AsWeakPtr(), load_type, url, cors_mode));
[email protected]d726eddc2013-07-02 22:25:55264 return;
265 }
[email protected]ef8394c2013-08-21 20:26:30266 DoLoad(load_type, url, cors_mode);
[email protected]62e5e682013-03-07 23:53:24267}
268
[email protected]ef8394c2013-08-21 20:26:30269void WebMediaPlayerImpl::DoLoad(LoadType load_type,
[email protected]180ef242013-11-07 06:50:46270 const blink::WebURL& url,
[email protected]d726eddc2013-07-02 22:25:55271 CORSMode cors_mode) {
272 DCHECK(main_loop_->BelongsToCurrentThread());
273
[email protected]62e5e682013-03-07 23:53:24274 GURL gurl(url);
275 UMA_HISTOGRAM_ENUMERATION("Media.URLScheme", URLScheme(gurl), kMaxURLScheme);
276
[email protected]926f8fd2013-04-12 20:27:53277 // Set subresource URL for crash reporting.
278 base::debug::SetCrashKeyValue("subresource_url", gurl.spec());
279
[email protected]ef8394c2013-08-21 20:26:30280 load_type_ = load_type;
281
[email protected]62e5e682013-03-07 23:53:24282 // Handle any volume/preload changes that occurred before load().
283 setVolume(GetClient()->volume());
284 setPreload(GetClient()->preload());
285
286 SetNetworkState(WebMediaPlayer::NetworkStateLoading);
287 SetReadyState(WebMediaPlayer::ReadyStateHaveNothing);
288 media_log_->AddEvent(media_log_->CreateLoadEvent(url.spec()));
[email protected]d726eddc2013-07-02 22:25:55289
290 // Media source pipelines can start immediately.
[email protected]ef8394c2013-08-21 20:26:30291 if (load_type == LoadTypeMediaSource) {
[email protected]d726eddc2013-07-02 22:25:55292 supports_save_ = false;
[email protected]ef8394c2013-08-21 20:26:30293 StartPipeline();
[email protected]d726eddc2013-07-02 22:25:55294 return;
295 }
296
297 // Otherwise it's a regular request which requires resolving the URL first.
298 data_source_.reset(new BufferedDataSource(
299 main_loop_,
300 frame_,
301 media_log_.get(),
302 base::Bind(&WebMediaPlayerImpl::NotifyDownloading, AsWeakPtr())));
303 data_source_->Initialize(
304 url, static_cast<BufferedResourceLoader::CORSMode>(cors_mode),
305 base::Bind(
306 &WebMediaPlayerImpl::DataSourceInitialized,
307 AsWeakPtr(), gurl));
308
[email protected]91f5689032013-08-22 01:43:33309 is_local_source_ = !gurl.SchemeIsHTTPOrHTTPS();
[email protected]62e5e682013-03-07 23:53:24310}
311
[email protected]4e6be3f2009-05-07 02:24:44312void WebMediaPlayerImpl::play() {
[email protected]e82c0e352013-03-01 01:53:46313 DCHECK(main_loop_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53314
[email protected]49480902009-07-14 20:23:43315 paused_ = false;
[email protected]039b7542013-10-17 22:06:25316 pipeline_->SetPlaybackRate(playback_rate_);
317 if (data_source_)
318 data_source_->MediaIsPlaying();
[email protected]090f7312011-08-05 23:26:40319
[email protected]24d75c72011-08-09 17:53:45320 media_log_->AddEvent(media_log_->CreateEvent(media::MediaLogEvent::PLAY));
[email protected]baff4512011-10-19 18:21:07321
[email protected]9b55d802013-06-04 02:39:46322 if (delegate_.get())
[email protected]baff4512011-10-19 18:21:07323 delegate_->DidPlay(this);
[email protected]ec9212f2008-12-18 21:40:36324}
325
[email protected]4e6be3f2009-05-07 02:24:44326void WebMediaPlayerImpl::pause() {
[email protected]e82c0e352013-03-01 01:53:46327 DCHECK(main_loop_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53328
[email protected]49480902009-07-14 20:23:43329 paused_ = true;
[email protected]039b7542013-10-17 22:06:25330 pipeline_->SetPlaybackRate(0.0f);
331 if (data_source_)
332 data_source_->MediaIsPaused();
[email protected]f7c0ada02012-07-23 08:42:50333 paused_time_ = pipeline_->GetMediaTime();
[email protected]090f7312011-08-05 23:26:40334
[email protected]24d75c72011-08-09 17:53:45335 media_log_->AddEvent(media_log_->CreateEvent(media::MediaLogEvent::PAUSE));
[email protected]baff4512011-10-19 18:21:07336
[email protected]9b55d802013-06-04 02:39:46337 if (delegate_.get())
[email protected]baff4512011-10-19 18:21:07338 delegate_->DidPause(this);
[email protected]ec9212f2008-12-18 21:40:36339}
340
[email protected]574a1d62009-07-17 03:23:46341bool WebMediaPlayerImpl::supportsFullscreen() const {
[email protected]e82c0e352013-03-01 01:53:46342 DCHECK(main_loop_->BelongsToCurrentThread());
[email protected]574a1d62009-07-17 03:23:46343 return true;
344}
345
346bool WebMediaPlayerImpl::supportsSave() const {
[email protected]e82c0e352013-03-01 01:53:46347 DCHECK(main_loop_->BelongsToCurrentThread());
[email protected]132dd57c2012-08-10 23:24:34348 return supports_save_;
[email protected]574a1d62009-07-17 03:23:46349}
350
[email protected]39bdde32013-04-17 17:44:20351void WebMediaPlayerImpl::seek(double seconds) {
[email protected]e82c0e352013-03-01 01:53:46352 DCHECK(main_loop_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53353
[email protected]bb8a70b2013-06-26 06:23:35354 base::TimeDelta seek_time = ConvertSecondsToTimestamp(seconds);
355
[email protected]a8e2cb82012-08-17 00:02:39356 if (starting_ || seeking_) {
[email protected]5d11eff2011-09-15 00:06:06357 pending_seek_ = true;
358 pending_seek_seconds_ = seconds;
[email protected]efe7cd22012-09-12 23:55:01359 if (chunk_demuxer_)
[email protected]bb8a70b2013-06-26 06:23:35360 chunk_demuxer_->CancelPendingSeek(seek_time);
[email protected]5d11eff2011-09-15 00:06:06361 return;
362 }
363
[email protected]c93eb0a62011-08-09 22:47:24364 media_log_->AddEvent(media_log_->CreateSeekEvent(seconds));
365
[email protected]44ff37c02009-10-24 01:03:03366 // Update our paused time.
[email protected]7b268b7a2011-11-18 19:52:08367 if (paused_)
[email protected]44ff37c02009-10-24 01:03:03368 paused_time_ = seek_time;
[email protected]44ff37c02009-10-24 01:03:03369
[email protected]b3766a22010-12-22 17:34:13370 seeking_ = true;
371
[email protected]efe7cd22012-09-12 23:55:01372 if (chunk_demuxer_)
[email protected]bb8a70b2013-06-26 06:23:35373 chunk_demuxer_->StartWaitingForSeek(seek_time);
[email protected]020fba32011-06-29 16:37:46374
[email protected]44ff37c02009-10-24 01:03:03375 // Kick off the asynchronous seek!
[email protected]3b4cbbf2009-07-11 00:16:19376 pipeline_->Seek(
[email protected]44ff37c02009-10-24 01:03:03377 seek_time,
[email protected]2c539b82012-08-18 04:10:19378 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineSeek));
[email protected]ec9212f2008-12-18 21:40:36379}
380
[email protected]39bdde32013-04-17 17:44:20381void WebMediaPlayerImpl::setRate(double rate) {
[email protected]e82c0e352013-03-01 01:53:46382 DCHECK(main_loop_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53383
[email protected]378f0b72009-08-11 17:11:42384 // TODO(kylep): Remove when support for negatives is added. Also, modify the
385 // following checks so rewind uses reasonable values also.
[email protected]39bdde32013-04-17 17:44:20386 if (rate < 0.0)
[email protected]378f0b72009-08-11 17:11:42387 return;
388
389 // Limit rates to reasonable values by clamping.
[email protected]39bdde32013-04-17 17:44:20390 if (rate != 0.0) {
[email protected]378f0b72009-08-11 17:11:42391 if (rate < kMinRate)
392 rate = kMinRate;
393 else if (rate > kMaxRate)
394 rate = kMaxRate;
395 }
396
[email protected]49480902009-07-14 20:23:43397 playback_rate_ = rate;
398 if (!paused_) {
[email protected]039b7542013-10-17 22:06:25399 pipeline_->SetPlaybackRate(rate);
400 if (data_source_)
401 data_source_->MediaPlaybackRateChanged(rate);
[email protected]49480902009-07-14 20:23:43402 }
[email protected]ec9212f2008-12-18 21:40:36403}
404
[email protected]39bdde32013-04-17 17:44:20405void WebMediaPlayerImpl::setVolume(double volume) {
[email protected]e82c0e352013-03-01 01:53:46406 DCHECK(main_loop_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53407
[email protected]3b4cbbf2009-07-11 00:16:19408 pipeline_->SetVolume(volume);
[email protected]ec9212f2008-12-18 21:40:36409}
[email protected]f0a51fb52009-03-05 12:46:38410
[email protected]23a8b1d82011-04-05 16:28:20411#define COMPILE_ASSERT_MATCHING_ENUM(webkit_name, chromium_name) \
[email protected]ef405f66b2012-04-18 02:39:55412 COMPILE_ASSERT(static_cast<int>(WebMediaPlayer::webkit_name) == \
[email protected]5e35a8d2013-07-10 19:37:21413 static_cast<int>(content::chromium_name), \
[email protected]474c37a2011-08-23 20:24:52414 mismatching_enums)
[email protected]ef405f66b2012-04-18 02:39:55415COMPILE_ASSERT_MATCHING_ENUM(PreloadNone, NONE);
416COMPILE_ASSERT_MATCHING_ENUM(PreloadMetaData, METADATA);
417COMPILE_ASSERT_MATCHING_ENUM(PreloadAuto, AUTO);
[email protected]a5a01102012-06-06 17:01:24418#undef COMPILE_ASSERT_MATCHING_ENUM
[email protected]23a8b1d82011-04-05 16:28:20419
[email protected]ef405f66b2012-04-18 02:39:55420void WebMediaPlayerImpl::setPreload(WebMediaPlayer::Preload preload) {
[email protected]e82c0e352013-03-01 01:53:46421 DCHECK(main_loop_->BelongsToCurrentThread());
[email protected]4e6be3f2009-05-07 02:24:44422
[email protected]b49beeb2013-03-01 20:04:00423 if (data_source_)
[email protected]5e35a8d2013-07-10 19:37:21424 data_source_->SetPreload(static_cast<content::Preload>(preload));
[email protected]4e6be3f2009-05-07 02:24:44425}
426
[email protected]4e6be3f2009-05-07 02:24:44427bool WebMediaPlayerImpl::hasVideo() const {
[email protected]e82c0e352013-03-01 01:53:46428 DCHECK(main_loop_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53429
[email protected]cee32342011-03-09 15:58:16430 return pipeline_->HasVideo();
[email protected]d43ed912009-02-03 04:52:53431}
432
[email protected]fc367af2009-08-14 23:06:35433bool WebMediaPlayerImpl::hasAudio() const {
[email protected]e82c0e352013-03-01 01:53:46434 DCHECK(main_loop_->BelongsToCurrentThread());
[email protected]fc367af2009-08-14 23:06:35435
[email protected]cee32342011-03-09 15:58:16436 return pipeline_->HasAudio();
[email protected]fc367af2009-08-14 23:06:35437}
438
[email protected]180ef242013-11-07 06:50:46439blink::WebSize WebMediaPlayerImpl::naturalSize() const {
[email protected]e82c0e352013-03-01 01:53:46440 DCHECK(main_loop_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53441
[email protected]2975fa532011-09-19 20:18:33442 gfx::Size size;
443 pipeline_->GetNaturalVideoSize(&size);
[email protected]180ef242013-11-07 06:50:46444 return blink::WebSize(size);
[email protected]d43ed912009-02-03 04:52:53445}
446
[email protected]4e6be3f2009-05-07 02:24:44447bool WebMediaPlayerImpl::paused() const {
[email protected]e82c0e352013-03-01 01:53:46448 DCHECK(main_loop_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53449
[email protected]3b4cbbf2009-07-11 00:16:19450 return pipeline_->GetPlaybackRate() == 0.0f;
[email protected]d43ed912009-02-03 04:52:53451}
452
[email protected]4e6be3f2009-05-07 02:24:44453bool WebMediaPlayerImpl::seeking() const {
[email protected]e82c0e352013-03-01 01:53:46454 DCHECK(main_loop_->BelongsToCurrentThread());
[email protected]d43ed912009-02-03 04:52:53455
[email protected]ef405f66b2012-04-18 02:39:55456 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing)
[email protected]0acebfa2009-08-21 22:45:40457 return false;
[email protected]67cd5052009-09-10 21:53:22458
[email protected]b3766a22010-12-22 17:34:13459 return seeking_;
[email protected]ec9212f2008-12-18 21:40:36460}
461
[email protected]39bdde32013-04-17 17:44:20462double WebMediaPlayerImpl::duration() const {
463 DCHECK(main_loop_->BelongsToCurrentThread());
464
465 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing)
466 return std::numeric_limits<double>::quiet_NaN();
467
[email protected]39bdde32013-04-17 17:44:20468 return GetPipelineDuration();
[email protected]d43ed912009-02-03 04:52:53469}
470
[email protected]39bdde32013-04-17 17:44:20471double WebMediaPlayerImpl::currentTime() const {
[email protected]e82c0e352013-03-01 01:53:46472 DCHECK(main_loop_->BelongsToCurrentThread());
[email protected]39bdde32013-04-17 17:44:20473 return (paused_ ? paused_time_ : pipeline_->GetMediaTime()).InSecondsF();
[email protected]d43ed912009-02-03 04:52:53474}
475
[email protected]ef405f66b2012-04-18 02:39:55476WebMediaPlayer::NetworkState WebMediaPlayerImpl::networkState() const {
[email protected]e82c0e352013-03-01 01:53:46477 DCHECK(main_loop_->BelongsToCurrentThread());
[email protected]ddb1e5a2010-12-13 20:10:45478 return network_state_;
479}
480
[email protected]ef405f66b2012-04-18 02:39:55481WebMediaPlayer::ReadyState WebMediaPlayerImpl::readyState() const {
[email protected]e82c0e352013-03-01 01:53:46482 DCHECK(main_loop_->BelongsToCurrentThread());
[email protected]ddb1e5a2010-12-13 20:10:45483 return ready_state_;
484}
485
[email protected]180ef242013-11-07 06:50:46486const blink::WebTimeRanges& WebMediaPlayerImpl::buffered() {
[email protected]e82c0e352013-03-01 01:53:46487 DCHECK(main_loop_->BelongsToCurrentThread());
[email protected]180ef242013-11-07 06:50:46488 blink::WebTimeRanges web_ranges(
[email protected]c566cb792012-06-20 00:51:52489 ConvertToWebTimeRanges(pipeline_->GetBufferedTimeRanges()));
[email protected]49f7b772012-05-10 00:45:35490 buffered_.swap(web_ranges);
[email protected]f70f8e12010-05-25 21:30:39491 return buffered_;
492}
493
[email protected]39bdde32013-04-17 17:44:20494double WebMediaPlayerImpl::maxTimeSeekable() const {
495 DCHECK(main_loop_->BelongsToCurrentThread());
496
497 // If we haven't even gotten to ReadyStateHaveMetadata yet then just
498 // return 0 so that the seekable range is empty.
499 if (ready_state_ < WebMediaPlayer::ReadyStateHaveMetadata)
500 return 0.0;
501
502 // We don't support seeking in streaming media.
503 if (data_source_ && data_source_->IsStreaming())
504 return 0.0;
[email protected]62b5897c2013-01-30 22:53:35505 return duration();
[email protected]ec9212f2008-12-18 21:40:36506}
507
[email protected]7ed21be2012-05-30 08:09:15508bool WebMediaPlayerImpl::didLoadingProgress() const {
[email protected]e82c0e352013-03-01 01:53:46509 DCHECK(main_loop_->BelongsToCurrentThread());
[email protected]7ed21be2012-05-30 08:09:15510 return pipeline_->DidLoadingProgress();
[email protected]d43ed912009-02-03 04:52:53511}
512
[email protected]df143bdc2009-06-16 17:34:19513void WebMediaPlayerImpl::paint(WebCanvas* canvas,
[email protected]4dc43be2012-03-27 14:05:07514 const WebRect& rect,
[email protected]98f60ed2013-05-24 23:20:54515 unsigned char alpha) {
[email protected]e82c0e352013-03-01 01:53:46516 DCHECK(main_loop_->BelongsToCurrentThread());
[email protected]4e6be3f2009-05-07 02:24:44517
[email protected]eaf7d9a2012-05-19 06:14:33518 if (!accelerated_compositing_reported_) {
519 accelerated_compositing_reported_ = true;
[email protected]3dc8f1b2012-05-21 22:54:32520 // Normally paint() is only called in non-accelerated rendering, but there
521 // are exceptions such as webgl where compositing is used in the WebView but
522 // video frames are still rendered to a canvas.
523 UMA_HISTOGRAM_BOOLEAN(
524 "Media.AcceleratedCompositingActive",
525 frame_->view()->isAcceleratedCompositingActive());
[email protected]eaf7d9a2012-05-19 06:14:33526 }
527
[email protected]b49beeb2013-03-01 20:04:00528 // Avoid locking and potentially blocking the video rendering thread while
529 // painting in software.
530 scoped_refptr<media::VideoFrame> video_frame;
531 {
532 base::AutoLock auto_lock(lock_);
[email protected]bfc05f22013-10-19 17:55:16533 DoneWaitingForPaint(true);
[email protected]b49beeb2013-03-01 20:04:00534 video_frame = current_frame_;
535 }
[email protected]bfc05f22013-10-19 17:55:16536 TRACE_EVENT0("media", "WebMediaPlayerImpl:paint");
[email protected]b49beeb2013-03-01 20:04:00537 gfx::Rect gfx_rect(rect);
[email protected]ff875be52013-06-02 23:47:38538 skcanvas_video_renderer_.Paint(video_frame.get(), canvas, gfx_rect, alpha);
[email protected]ec9212f2008-12-18 21:40:36539}
[email protected]5df51652009-01-17 00:03:00540
[email protected]38259a7a82009-07-29 21:49:49541bool WebMediaPlayerImpl::hasSingleSecurityOrigin() const {
[email protected]b49beeb2013-03-01 20:04:00542 if (data_source_)
543 return data_source_->HasSingleOrigin();
[email protected]fcdb7462009-10-21 21:05:11544 return true;
[email protected]38259a7a82009-07-29 21:49:49545}
546
[email protected]3fe27112012-06-07 04:00:01547bool WebMediaPlayerImpl::didPassCORSAccessCheck() const {
[email protected]b49beeb2013-03-01 20:04:00548 if (data_source_)
549 return data_source_->DidPassCORSAccessCheck();
550 return false;
[email protected]3fe27112012-06-07 04:00:01551}
552
[email protected]39bdde32013-04-17 17:44:20553double WebMediaPlayerImpl::mediaTimeForTimeValue(double timeValue) const {
[email protected]e06e16d82011-05-26 22:13:33554 return ConvertSecondsToTimestamp(timeValue).InSecondsF();
555}
556
[email protected]d82b18ae2011-03-23 21:28:59557unsigned WebMediaPlayerImpl::decodedFrameCount() const {
[email protected]e82c0e352013-03-01 01:53:46558 DCHECK(main_loop_->BelongsToCurrentThread());
[email protected]4c51bc662011-02-16 02:03:16559
560 media::PipelineStatistics stats = pipeline_->GetStatistics();
561 return stats.video_frames_decoded;
562}
563
[email protected]d82b18ae2011-03-23 21:28:59564unsigned WebMediaPlayerImpl::droppedFrameCount() const {
[email protected]e82c0e352013-03-01 01:53:46565 DCHECK(main_loop_->BelongsToCurrentThread());
[email protected]4c51bc662011-02-16 02:03:16566
567 media::PipelineStatistics stats = pipeline_->GetStatistics();
[email protected]c46a9f42013-10-16 03:28:18568
569 base::AutoLock auto_lock(lock_);
570 unsigned frames_dropped =
571 stats.video_frames_dropped + frames_dropped_before_paint_;
572 DCHECK_LE(frames_dropped, stats.video_frames_decoded);
573 return frames_dropped;
[email protected]4c51bc662011-02-16 02:03:16574}
575
[email protected]d82b18ae2011-03-23 21:28:59576unsigned WebMediaPlayerImpl::audioDecodedByteCount() const {
[email protected]e82c0e352013-03-01 01:53:46577 DCHECK(main_loop_->BelongsToCurrentThread());
[email protected]4c51bc662011-02-16 02:03:16578
579 media::PipelineStatistics stats = pipeline_->GetStatistics();
580 return stats.audio_bytes_decoded;
581}
582
[email protected]d82b18ae2011-03-23 21:28:59583unsigned WebMediaPlayerImpl::videoDecodedByteCount() const {
[email protected]e82c0e352013-03-01 01:53:46584 DCHECK(main_loop_->BelongsToCurrentThread());
[email protected]4c51bc662011-02-16 02:03:16585
586 media::PipelineStatistics stats = pipeline_->GetStatistics();
587 return stats.video_bytes_decoded;
588}
589
[email protected]21c3f7502013-03-23 03:29:51590void WebMediaPlayerImpl::SetVideoFrameProviderClient(
591 cc::VideoFrameProvider::Client* client) {
592 // This is called from both the main renderer thread and the compositor
593 // thread (when the main thread is blocked).
594 if (video_frame_provider_client_)
595 video_frame_provider_client_->StopUsingProvider();
596 video_frame_provider_client_ = client;
597}
598
599scoped_refptr<media::VideoFrame> WebMediaPlayerImpl::GetCurrentFrame() {
600 base::AutoLock auto_lock(lock_);
[email protected]bfc05f22013-10-19 17:55:16601 DoneWaitingForPaint(true);
602 TRACE_EVENT_ASYNC_BEGIN0(
603 "media", "WebMediaPlayerImpl:compositing", this);
[email protected]21c3f7502013-03-23 03:29:51604 return current_frame_;
605}
606
607void WebMediaPlayerImpl::PutCurrentFrame(
608 const scoped_refptr<media::VideoFrame>& frame) {
609 if (!accelerated_compositing_reported_) {
610 accelerated_compositing_reported_ = true;
611 DCHECK(frame_->view()->isAcceleratedCompositingActive());
612 UMA_HISTOGRAM_BOOLEAN("Media.AcceleratedCompositingActive", true);
613 }
[email protected]bfc05f22013-10-19 17:55:16614 TRACE_EVENT_ASYNC_END0("media", "WebMediaPlayerImpl:compositing", this);
[email protected]21c3f7502013-03-23 03:29:51615}
[email protected]e81283bb2010-08-31 18:01:21616
[email protected]6523b242013-03-13 11:10:07617bool WebMediaPlayerImpl::copyVideoTextureToPlatformTexture(
[email protected]180ef242013-11-07 06:50:46618 blink::WebGraphicsContext3D* web_graphics_context,
[email protected]6523b242013-03-13 11:10:07619 unsigned int texture,
620 unsigned int level,
621 unsigned int internal_format,
[email protected]9aa2b2782013-05-14 00:13:31622 unsigned int type,
[email protected]6523b242013-03-13 11:10:07623 bool premultiply_alpha,
624 bool flip_y) {
625 scoped_refptr<media::VideoFrame> video_frame;
626 {
627 base::AutoLock auto_lock(lock_);
628 video_frame = current_frame_;
629 }
[email protected]e56f88c72013-06-25 22:31:29630
[email protected]bfc05f22013-10-19 17:55:16631 TRACE_EVENT0("media", "WebMediaPlayerImpl:copyVideoTextureToPlatformTexture");
632
633 if (!video_frame)
[email protected]e56f88c72013-06-25 22:31:29634 return false;
635 if (video_frame->format() != media::VideoFrame::NATIVE_TEXTURE)
636 return false;
637 if (video_frame->texture_target() != GL_TEXTURE_2D)
638 return false;
639
[email protected]10c69e42013-10-20 05:27:36640 // Since this method changes which texture is bound to the TEXTURE_2D target,
641 // ideally it would restore the currently-bound texture before returning.
642 // The cost of getIntegerv is sufficiently high, however, that we want to
643 // avoid it in user builds. As a result assume (below) that |texture| is
644 // bound when this method is called, and only verify this fact when
645 // DCHECK_IS_ON.
646 if (DCHECK_IS_ON()) {
647 GLint bound_texture = 0;
648 web_graphics_context->getIntegerv(GL_TEXTURE_BINDING_2D, &bound_texture);
649 DCHECK_EQ(static_cast<GLuint>(bound_texture), texture);
650 }
651
[email protected]e56f88c72013-06-25 22:31:29652 scoped_refptr<media::VideoFrame::MailboxHolder> mailbox_holder =
653 video_frame->texture_mailbox();
654
655 uint32 source_texture = web_graphics_context->createTexture();
656
657 web_graphics_context->waitSyncPoint(mailbox_holder->sync_point());
658 web_graphics_context->bindTexture(GL_TEXTURE_2D, source_texture);
659 web_graphics_context->consumeTextureCHROMIUM(GL_TEXTURE_2D,
660 mailbox_holder->mailbox().name);
661
662 // The video is stored in a unmultiplied format, so premultiply
663 // if necessary.
664 web_graphics_context->pixelStorei(GL_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM,
665 premultiply_alpha);
666 // Application itself needs to take care of setting the right flip_y
667 // value down to get the expected result.
668 // flip_y==true means to reverse the video orientation while
669 // flip_y==false means to keep the intrinsic orientation.
670 web_graphics_context->pixelStorei(GL_UNPACK_FLIP_Y_CHROMIUM, flip_y);
671 web_graphics_context->copyTextureCHROMIUM(GL_TEXTURE_2D,
672 source_texture,
673 texture,
674 level,
675 internal_format,
676 type);
677 web_graphics_context->pixelStorei(GL_UNPACK_FLIP_Y_CHROMIUM, false);
678 web_graphics_context->pixelStorei(GL_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM,
679 false);
680
[email protected]10c69e42013-10-20 05:27:36681 // Restore the state for TEXTURE_2D binding point as mentioned above.
682 web_graphics_context->bindTexture(GL_TEXTURE_2D, texture);
683
[email protected]e56f88c72013-06-25 22:31:29684 web_graphics_context->deleteTexture(source_texture);
685
686 // The flush() operation is not necessary here. It is kept since the
687 // performance will be better when it is added than not.
688 web_graphics_context->flush();
689 return true;
[email protected]6523b242013-03-13 11:10:07690}
691
[email protected]49a097e2013-04-02 19:31:51692// Helper functions to report media EME related stats to UMA. They follow the
693// convention of more commonly used macros UMA_HISTOGRAM_ENUMERATION and
694// UMA_HISTOGRAM_COUNTS. The reason that we cannot use those macros directly is
695// that UMA_* macros require the names to be constant throughout the process'
696// lifetime.
[email protected]180ef242013-11-07 06:50:46697static void EmeUMAHistogramEnumeration(const blink::WebString& key_system,
[email protected]49a097e2013-04-02 19:31:51698 const std::string& method,
699 int sample,
700 int boundary_value) {
701 base::LinearHistogram::FactoryGet(
702 kMediaEme + KeySystemNameForUMA(key_system) + "." + method,
703 1, boundary_value, boundary_value + 1,
704 base::Histogram::kUmaTargetedHistogramFlag)->Add(sample);
705}
706
[email protected]180ef242013-11-07 06:50:46707static void EmeUMAHistogramCounts(const blink::WebString& key_system,
[email protected]49a097e2013-04-02 19:31:51708 const std::string& method,
709 int sample) {
710 // Use the same parameters as UMA_HISTOGRAM_COUNTS.
711 base::Histogram::FactoryGet(
712 kMediaEme + KeySystemNameForUMA(key_system) + "." + method,
713 1, 1000000, 50, base::Histogram::kUmaTargetedHistogramFlag)->Add(sample);
714}
715
[email protected]2ca7d5c2012-10-23 07:30:54716// Helper enum for reporting generateKeyRequest/addKey histograms.
717enum MediaKeyException {
718 kUnknownResultId,
719 kSuccess,
720 kKeySystemNotSupported,
721 kInvalidPlayerState,
722 kMaxMediaKeyException
723};
724
725static MediaKeyException MediaKeyExceptionForUMA(
726 WebMediaPlayer::MediaKeyException e) {
727 switch (e) {
728 case WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported:
729 return kKeySystemNotSupported;
730 case WebMediaPlayer::MediaKeyExceptionInvalidPlayerState:
731 return kInvalidPlayerState;
732 case WebMediaPlayer::MediaKeyExceptionNoError:
733 return kSuccess;
734 default:
735 return kUnknownResultId;
736 }
737}
738
739// Helper for converting |key_system| name and exception |e| to a pair of enum
740// values from above, for reporting to UMA.
741static void ReportMediaKeyExceptionToUMA(
742 const std::string& method,
743 const WebString& key_system,
744 WebMediaPlayer::MediaKeyException e) {
745 MediaKeyException result_id = MediaKeyExceptionForUMA(e);
746 DCHECK_NE(result_id, kUnknownResultId) << e;
[email protected]49a097e2013-04-02 19:31:51747 EmeUMAHistogramEnumeration(
[email protected]f3a1d40d2013-06-25 22:12:50748 key_system, method, result_id, kMaxMediaKeyException);
[email protected]2ca7d5c2012-10-23 07:30:54749}
750
751WebMediaPlayer::MediaKeyException
[email protected]f7a6b992012-04-19 09:45:56752WebMediaPlayerImpl::generateKeyRequest(const WebString& key_system,
753 const unsigned char* init_data,
754 unsigned init_data_length) {
[email protected]2ca7d5c2012-10-23 07:30:54755 WebMediaPlayer::MediaKeyException e =
756 GenerateKeyRequestInternal(key_system, init_data, init_data_length);
757 ReportMediaKeyExceptionToUMA("generateKeyRequest", key_system, e);
758 return e;
759}
760
761WebMediaPlayer::MediaKeyException
762WebMediaPlayerImpl::GenerateKeyRequestInternal(
763 const WebString& key_system,
764 const unsigned char* init_data,
765 unsigned init_data_length) {
[email protected]f7a6b992012-04-19 09:45:56766 DVLOG(1) << "generateKeyRequest: " << key_system.utf8().data() << ": "
767 << std::string(reinterpret_cast<const char*>(init_data),
[email protected]cbdc8c2b2012-06-16 01:27:36768 static_cast<size_t>(init_data_length));
[email protected]f7a6b992012-04-19 09:45:56769
[email protected]2a3d19b62013-08-28 05:34:04770 if (!IsConcreteSupportedKeySystem(key_system))
[email protected]fecb5fe2013-06-19 00:52:13771 return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported;
772
773 // We do not support run-time switching between key systems for now.
774 if (current_key_system_.isEmpty()) {
[email protected]f961a0f2013-09-23 04:15:45775 if (!decryptor_->InitializeCDM(key_system.utf8(), frame_->document().url()))
[email protected]fecb5fe2013-06-19 00:52:13776 return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported;
777 current_key_system_ = key_system;
778 }
779 else if (key_system != current_key_system_) {
780 return WebMediaPlayer::MediaKeyExceptionInvalidPlayerState;
781 }
782
[email protected]c8d40282012-10-27 07:23:13783 // TODO(xhwang): We assume all streams are from the same container (thus have
784 // the same "type") for now. In the future, the "type" should be passed down
785 // from the application.
[email protected]fecb5fe2013-06-19 00:52:13786 if (!decryptor_->GenerateKeyRequest(init_data_type_,
[email protected]83fdd992012-12-21 19:57:49787 init_data, init_data_length)) {
[email protected]6a206732012-08-29 01:14:40788 current_key_system_.reset();
[email protected]2ca7d5c2012-10-23 07:30:54789 return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported;
[email protected]6a206732012-08-29 01:14:40790 }
791
[email protected]2ca7d5c2012-10-23 07:30:54792 return WebMediaPlayer::MediaKeyExceptionNoError;
[email protected]f7a6b992012-04-19 09:45:56793}
794
[email protected]2ca7d5c2012-10-23 07:30:54795WebMediaPlayer::MediaKeyException WebMediaPlayerImpl::addKey(
796 const WebString& key_system,
797 const unsigned char* key,
798 unsigned key_length,
799 const unsigned char* init_data,
800 unsigned init_data_length,
801 const WebString& session_id) {
802 WebMediaPlayer::MediaKeyException e = AddKeyInternal(
803 key_system, key, key_length, init_data, init_data_length, session_id);
804 ReportMediaKeyExceptionToUMA("addKey", key_system, e);
805 return e;
806}
807
[email protected]2ca7d5c2012-10-23 07:30:54808WebMediaPlayer::MediaKeyException WebMediaPlayerImpl::AddKeyInternal(
[email protected]f7a6b992012-04-19 09:45:56809 const WebString& key_system,
810 const unsigned char* key,
811 unsigned key_length,
812 const unsigned char* init_data,
813 unsigned init_data_length,
814 const WebString& session_id) {
[email protected]a0149082012-04-19 17:33:41815 DCHECK(key);
816 DCHECK_GT(key_length, 0u);
[email protected]f7a6b992012-04-19 09:45:56817 DVLOG(1) << "addKey: " << key_system.utf8().data() << ": "
818 << std::string(reinterpret_cast<const char*>(key),
819 static_cast<size_t>(key_length)) << ", "
820 << std::string(reinterpret_cast<const char*>(init_data),
821 static_cast<size_t>(init_data_length))
822 << " [" << session_id.utf8().data() << "]";
823
[email protected]fecb5fe2013-06-19 00:52:13824
[email protected]2a3d19b62013-08-28 05:34:04825 if (!IsConcreteSupportedKeySystem(key_system))
[email protected]fecb5fe2013-06-19 00:52:13826 return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported;
827
828 if (current_key_system_.isEmpty() || key_system != current_key_system_)
829 return WebMediaPlayer::MediaKeyExceptionInvalidPlayerState;
830
831 decryptor_->AddKey(key, key_length,
[email protected]83fdd992012-12-21 19:57:49832 init_data, init_data_length, session_id.utf8());
[email protected]2ca7d5c2012-10-23 07:30:54833 return WebMediaPlayer::MediaKeyExceptionNoError;
[email protected]f7a6b992012-04-19 09:45:56834}
835
[email protected]2ca7d5c2012-10-23 07:30:54836WebMediaPlayer::MediaKeyException WebMediaPlayerImpl::cancelKeyRequest(
837 const WebString& key_system,
838 const WebString& session_id) {
839 WebMediaPlayer::MediaKeyException e =
840 CancelKeyRequestInternal(key_system, session_id);
841 ReportMediaKeyExceptionToUMA("cancelKeyRequest", key_system, e);
842 return e;
843}
844
845WebMediaPlayer::MediaKeyException
846WebMediaPlayerImpl::CancelKeyRequestInternal(
[email protected]f7a6b992012-04-19 09:45:56847 const WebString& key_system,
848 const WebString& session_id) {
[email protected]2a3d19b62013-08-28 05:34:04849 if (!IsConcreteSupportedKeySystem(key_system))
[email protected]2ca7d5c2012-10-23 07:30:54850 return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported;
[email protected]f7a6b992012-04-19 09:45:56851
[email protected]a8884632012-06-29 03:05:34852 if (current_key_system_.isEmpty() || key_system != current_key_system_)
[email protected]2ca7d5c2012-10-23 07:30:54853 return WebMediaPlayer::MediaKeyExceptionInvalidPlayerState;
[email protected]a8884632012-06-29 03:05:34854
[email protected]fecb5fe2013-06-19 00:52:13855 decryptor_->CancelKeyRequest(session_id.utf8());
[email protected]2ca7d5c2012-10-23 07:30:54856 return WebMediaPlayer::MediaKeyExceptionNoError;
[email protected]f7a6b992012-04-19 09:45:56857}
858
[email protected]4e6be3f2009-05-07 02:24:44859void WebMediaPlayerImpl::WillDestroyCurrentMessageLoop() {
[email protected]8931c41a2009-07-07 17:31:49860 Destroy();
[email protected]8931c41a2009-07-07 17:31:49861}
862
863void WebMediaPlayerImpl::Repaint() {
[email protected]e82c0e352013-03-01 01:53:46864 DCHECK(main_loop_->BelongsToCurrentThread());
[email protected]bfc05f22013-10-19 17:55:16865 TRACE_EVENT0("media", "WebMediaPlayerImpl:repaint");
[email protected]b49beeb2013-03-01 20:04:00866
[email protected]29037ce52013-05-06 22:44:16867 bool size_changed = false;
868 {
869 base::AutoLock auto_lock(lock_);
870 std::swap(pending_size_change_, size_changed);
[email protected]bfc05f22013-10-19 17:55:16871 if (pending_repaint_) {
872 TRACE_EVENT_ASYNC_END0(
873 "media", "WebMediaPlayerImpl:repaintPending", this);
874 pending_repaint_ = false;
875 }
[email protected]29037ce52013-05-06 22:44:16876 }
877
[email protected]bfc05f22013-10-19 17:55:16878 if (size_changed) {
879 TRACE_EVENT0("media", "WebMediaPlayerImpl:clientSizeChanged");
[email protected]29037ce52013-05-06 22:44:16880 GetClient()->sizeChanged();
[email protected]bfc05f22013-10-19 17:55:16881 }
[email protected]29037ce52013-05-06 22:44:16882
[email protected]bfc05f22013-10-19 17:55:16883 TRACE_EVENT0("media", "WebMediaPlayerImpl:clientRepaint");
[email protected]29037ce52013-05-06 22:44:16884 GetClient()->repaint();
[email protected]8931c41a2009-07-07 17:31:49885}
886
[email protected]a9590c22011-03-16 16:57:02887void WebMediaPlayerImpl::OnPipelineSeek(PipelineStatus status) {
[email protected]e82c0e352013-03-01 01:53:46888 DCHECK(main_loop_->BelongsToCurrentThread());
[email protected]a8e2cb82012-08-17 00:02:39889 starting_ = false;
[email protected]5d11eff2011-09-15 00:06:06890 seeking_ = false;
891 if (pending_seek_) {
892 pending_seek_ = false;
893 seek(pending_seek_seconds_);
894 return;
895 }
896
[email protected]10a64d92012-04-10 21:08:02897 if (status != media::PIPELINE_OK) {
898 OnPipelineError(status);
899 return;
[email protected]96706912009-07-15 17:18:05900 }
[email protected]10a64d92012-04-10 21:08:02901
902 // Update our paused time.
903 if (paused_)
[email protected]f7c0ada02012-07-23 08:42:50904 paused_time_ = pipeline_->GetMediaTime();
[email protected]10a64d92012-04-10 21:08:02905
906 GetClient()->timeChanged();
[email protected]8931c41a2009-07-07 17:31:49907}
908
[email protected]6954fe12013-01-03 03:22:32909void WebMediaPlayerImpl::OnPipelineEnded() {
[email protected]e82c0e352013-03-01 01:53:46910 DCHECK(main_loop_->BelongsToCurrentThread());
[email protected]10a64d92012-04-10 21:08:02911 GetClient()->timeChanged();
[email protected]576537842009-08-12 23:52:05912}
913
[email protected]a9590c22011-03-16 16:57:02914void WebMediaPlayerImpl::OnPipelineError(PipelineStatus error) {
[email protected]e82c0e352013-03-01 01:53:46915 DCHECK(main_loop_->BelongsToCurrentThread());
[email protected]be57ee52013-05-28 22:27:27916 DCHECK_NE(error, media::PIPELINE_OK);
[email protected]a8e2cb82012-08-17 00:02:39917
918 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing) {
919 // Any error that occurs before reaching ReadyStateHaveMetadata should
920 // be considered a format error.
921 SetNetworkState(WebMediaPlayer::NetworkStateFormatError);
922 Repaint();
923 return;
924 }
925
[email protected]be57ee52013-05-28 22:27:27926 SetNetworkState(PipelineErrorToNetworkState(error));
[email protected]a9590c22011-03-16 16:57:02927
[email protected]be57ee52013-05-28 22:27:27928 if (error == media::PIPELINE_ERROR_DECRYPT)
[email protected]f3a1d40d2013-06-25 22:12:50929 EmeUMAHistogramCounts(current_key_system_, "DecryptError", 1);
[email protected]bb2c1f32009-08-14 04:14:50930
931 // Repaint to trigger UI update.
932 Repaint();
[email protected]db190487d2009-07-30 18:51:52933}
934
[email protected]a8e2cb82012-08-17 00:02:39935void WebMediaPlayerImpl::OnPipelineBufferingState(
936 media::Pipeline::BufferingState buffering_state) {
937 DVLOG(1) << "OnPipelineBufferingState(" << buffering_state << ")";
938
939 switch (buffering_state) {
940 case media::Pipeline::kHaveMetadata:
941 SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata);
[email protected]21c3f7502013-03-23 03:29:51942
[email protected]21c3f7502013-03-23 03:29:51943 if (hasVideo() && GetClient()->needsWebLayerForVideo()) {
944 DCHECK(!video_weblayer_);
945 video_weblayer_.reset(
946 new webkit::WebLayerImpl(cc::VideoLayer::Create(this)));
947 GetClient()->setWebLayer(video_weblayer_.get());
948 }
[email protected]a8e2cb82012-08-17 00:02:39949 break;
950 case media::Pipeline::kPrerollCompleted:
[email protected]a06d9e972013-06-20 08:43:47951 // Only transition to ReadyStateHaveEnoughData if we don't have
952 // any pending seeks because the transition can cause Blink to
953 // report that the most recent seek has completed.
954 if (!pending_seek_)
955 SetReadyState(WebMediaPlayer::ReadyStateHaveEnoughData);
[email protected]a8e2cb82012-08-17 00:02:39956 break;
957 }
958
959 // Repaint to trigger UI update.
960 Repaint();
961}
962
[email protected]ef8394c2013-08-21 20:26:30963void WebMediaPlayerImpl::OnDemuxerOpened() {
[email protected]e82c0e352013-03-01 01:53:46964 DCHECK(main_loop_->BelongsToCurrentThread());
[email protected]ef8394c2013-08-21 20:26:30965 GetClient()->mediaSourceOpened(new WebMediaSourceImpl(
[email protected]5f811a2d2013-03-15 23:54:51966 chunk_demuxer_, base::Bind(&LogMediaSourceError, media_log_)));
[email protected]81bb3322011-07-21 15:55:50967}
968
[email protected]fecb5fe2013-06-19 00:52:13969void WebMediaPlayerImpl::OnKeyAdded(const std::string& session_id) {
[email protected]e82c0e352013-03-01 01:53:46970 DCHECK(main_loop_->BelongsToCurrentThread());
[email protected]f3a1d40d2013-06-25 22:12:50971 EmeUMAHistogramCounts(current_key_system_, "KeyAdded", 1);
[email protected]fecb5fe2013-06-19 00:52:13972 GetClient()->keyAdded(current_key_system_,
[email protected]cbdc8c2b2012-06-16 01:27:36973 WebString::fromUTF8(session_id));
974}
975
[email protected]3a41ebb2013-10-08 00:25:03976void WebMediaPlayerImpl::OnNeedKey(const std::string& type,
[email protected]322d22c2013-08-26 18:50:41977 const std::vector<uint8>& init_data) {
[email protected]e82c0e352013-03-01 01:53:46978 DCHECK(main_loop_->BelongsToCurrentThread());
[email protected]cbdc8c2b2012-06-16 01:27:36979
[email protected]47ebb0e2012-11-30 08:28:29980 // Do not fire NeedKey event if encrypted media is not enabled.
981 if (!decryptor_)
982 return;
983
[email protected]2ca7d5c2012-10-23 07:30:54984 UMA_HISTOGRAM_COUNTS(kMediaEme + std::string("NeedKey"), 1);
985
[email protected]c8d40282012-10-27 07:23:13986 DCHECK(init_data_type_.empty() || type.empty() || type == init_data_type_);
987 if (init_data_type_.empty())
988 init_data_type_ = type;
989
[email protected]322d22c2013-08-26 18:50:41990 const uint8* init_data_ptr = init_data.empty() ? NULL : &init_data[0];
[email protected]fecb5fe2013-06-19 00:52:13991 GetClient()->keyNeeded(WebString(),
[email protected]3a41ebb2013-10-08 00:25:03992 WebString(),
[email protected]322d22c2013-08-26 18:50:41993 init_data_ptr,
994 init_data.size());
[email protected]cbdc8c2b2012-06-16 01:27:36995}
996
[email protected]8a561062013-11-22 01:19:31997void WebMediaPlayerImpl::OnAddTextTrack(
998 const media::TextTrackConfig& config,
999 const media::AddTextTrackDoneCB& done_cb) {
1000 DCHECK(main_loop_->BelongsToCurrentThread());
[email protected]71537722013-05-23 06:47:531001
[email protected]8a561062013-11-22 01:19:311002 const WebInbandTextTrackImpl::Kind web_kind =
1003 static_cast<WebInbandTextTrackImpl::Kind>(config.kind());
1004 const blink::WebString web_label =
1005 blink::WebString::fromUTF8(config.label());
1006 const blink::WebString web_language =
1007 blink::WebString::fromUTF8(config.language());
[email protected]71537722013-05-23 06:47:531008
[email protected]8a561062013-11-22 01:19:311009 scoped_ptr<WebInbandTextTrackImpl> web_inband_text_track(
1010 new WebInbandTextTrackImpl(web_kind, web_label, web_language,
1011 text_track_index_++));
1012
1013 scoped_ptr<media::TextTrack> text_track(
1014 new TextTrackImpl(main_loop_, GetClient(), web_inband_text_track.Pass()));
1015
1016 done_cb.Run(text_track.Pass());
[email protected]71537722013-05-23 06:47:531017}
1018
[email protected]fecb5fe2013-06-19 00:52:131019void WebMediaPlayerImpl::OnKeyError(const std::string& session_id,
[email protected]15b05a72013-05-30 00:40:571020 media::MediaKeys::KeyError error_code,
[email protected]cbdc8c2b2012-06-16 01:27:361021 int system_code) {
[email protected]e82c0e352013-03-01 01:53:461022 DCHECK(main_loop_->BelongsToCurrentThread());
[email protected]cbdc8c2b2012-06-16 01:27:361023
[email protected]f3a1d40d2013-06-25 22:12:501024 EmeUMAHistogramEnumeration(current_key_system_, "KeyError",
[email protected]fecb5fe2013-06-19 00:52:131025 error_code, media::MediaKeys::kMaxKeyError);
[email protected]2ca7d5c2012-10-23 07:30:541026
[email protected]cbdc8c2b2012-06-16 01:27:361027 GetClient()->keyError(
[email protected]fecb5fe2013-06-19 00:52:131028 current_key_system_,
[email protected]cbdc8c2b2012-06-16 01:27:361029 WebString::fromUTF8(session_id),
[email protected]180ef242013-11-07 06:50:461030 static_cast<blink::WebMediaPlayerClient::MediaKeyErrorCode>(error_code),
[email protected]cbdc8c2b2012-06-16 01:27:361031 system_code);
1032}
1033
[email protected]fecb5fe2013-06-19 00:52:131034void WebMediaPlayerImpl::OnKeyMessage(const std::string& session_id,
[email protected]0a81bdb2013-06-29 23:18:061035 const std::vector<uint8>& message,
[email protected]abd36b3af2012-12-22 03:42:021036 const std::string& default_url) {
[email protected]e82c0e352013-03-01 01:53:461037 DCHECK(main_loop_->BelongsToCurrentThread());
[email protected]cbdc8c2b2012-06-16 01:27:361038
[email protected]abd36b3af2012-12-22 03:42:021039 const GURL default_url_gurl(default_url);
1040 DLOG_IF(WARNING, !default_url.empty() && !default_url_gurl.is_valid())
1041 << "Invalid URL in default_url: " << default_url;
1042
[email protected]fecb5fe2013-06-19 00:52:131043 GetClient()->keyMessage(current_key_system_,
[email protected]cbdc8c2b2012-06-16 01:27:361044 WebString::fromUTF8(session_id),
[email protected]33325ff2013-07-01 07:49:361045 message.empty() ? NULL : &message[0],
[email protected]65a8c102012-12-15 00:56:571046 message.size(),
[email protected]abd36b3af2012-12-22 03:42:021047 default_url_gurl);
[email protected]4205f0aab2012-04-26 04:33:061048}
1049
[email protected]5bb69ef2011-12-23 16:29:091050void WebMediaPlayerImpl::SetOpaque(bool opaque) {
[email protected]e82c0e352013-03-01 01:53:461051 DCHECK(main_loop_->BelongsToCurrentThread());
[email protected]5bb69ef2011-12-23 16:29:091052
1053 GetClient()->setOpaque(opaque);
1054}
1055
[email protected]d250190da3b2012-07-23 22:57:301056void WebMediaPlayerImpl::DataSourceInitialized(const GURL& gurl, bool success) {
[email protected]e82c0e352013-03-01 01:53:461057 DCHECK(main_loop_->BelongsToCurrentThread());
[email protected]a9415292012-01-19 19:55:201058
[email protected]d250190da3b2012-07-23 22:57:301059 if (!success) {
[email protected]ef405f66b2012-04-18 02:39:551060 SetNetworkState(WebMediaPlayer::NetworkStateFormatError);
[email protected]a9415292012-01-19 19:55:201061 Repaint();
1062 return;
1063 }
1064
[email protected]ef8394c2013-08-21 20:26:301065 StartPipeline();
[email protected]a9415292012-01-19 19:55:201066}
1067
[email protected]122f40252012-06-12 05:01:561068void WebMediaPlayerImpl::NotifyDownloading(bool is_downloading) {
1069 if (!is_downloading && network_state_ == WebMediaPlayer::NetworkStateLoading)
1070 SetNetworkState(WebMediaPlayer::NetworkStateIdle);
1071 else if (is_downloading && network_state_ == WebMediaPlayer::NetworkStateIdle)
1072 SetNetworkState(WebMediaPlayer::NetworkStateLoading);
1073 media_log_->AddEvent(
1074 media_log_->CreateBooleanEvent(
1075 media::MediaLogEvent::NETWORK_ACTIVITY_SET,
1076 "is_downloading_data", is_downloading));
1077}
1078
[email protected]ef8394c2013-08-21 20:26:301079void WebMediaPlayerImpl::StartPipeline() {
[email protected]ddbc6ff2013-04-19 15:28:331080 const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
[email protected]b573f952013-06-04 10:50:091081 bool increase_preroll_on_underflow = true;
[email protected]ddbc6ff2013-04-19 15:28:331082
[email protected]0814ac62013-06-07 21:01:291083 // Keep track if this is a MSE or non-MSE playback.
[email protected]ef8394c2013-08-21 20:26:301084 UMA_HISTOGRAM_BOOLEAN("Media.MSE.Playback",
1085 (load_type_ == LoadTypeMediaSource));
[email protected]0814ac62013-06-07 21:01:291086
[email protected]ddbc6ff2013-04-19 15:28:331087 // Figure out which demuxer to use.
[email protected]ef8394c2013-08-21 20:26:301088 if (load_type_ != LoadTypeMediaSource) {
[email protected]ddbc6ff2013-04-19 15:28:331089 DCHECK(!chunk_demuxer_);
[email protected]f5443ef72013-04-22 04:03:381090 DCHECK(data_source_);
1091
1092 demuxer_.reset(new media::FFmpegDemuxer(
[email protected]c1330c82013-06-06 02:23:251093 media_loop_, data_source_.get(),
[email protected]3a41ebb2013-10-08 00:25:031094 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnNeedKey),
[email protected]1e931f62013-07-31 23:25:521095 media_log_));
[email protected]ddbc6ff2013-04-19 15:28:331096 } else {
[email protected]f5443ef72013-04-22 04:03:381097 DCHECK(!chunk_demuxer_);
1098 DCHECK(!data_source_);
1099
[email protected]f5443ef72013-04-22 04:03:381100 chunk_demuxer_ = new media::ChunkDemuxer(
[email protected]ef8394c2013-08-21 20:26:301101 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnDemuxerOpened),
[email protected]3a41ebb2013-10-08 00:25:031102 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnNeedKey),
[email protected]f5443ef72013-04-22 04:03:381103 base::Bind(&LogMediaSourceError, media_log_));
1104 demuxer_.reset(chunk_demuxer_);
[email protected]ddbc6ff2013-04-19 15:28:331105
[email protected]6314f1b2013-08-12 11:14:011106#if !defined(OS_CHROMEOS)
1107 // Disable GpuVideoDecoder creation on platforms other than CrOS until
[email protected]67908292013-08-03 12:17:151108 // they support codec config changes.
[email protected]ddbc6ff2013-04-19 15:28:331109 // TODO(acolwell): Remove this once http://crbug.com/151045 is fixed.
1110 gpu_factories_ = NULL;
[email protected]67908292013-08-03 12:17:151111#endif
[email protected]b573f952013-06-04 10:50:091112
1113 // Disable preroll increases on underflow since the web application has no
1114 // way to detect that this is happening and runs the risk of triggering
1115 // unwanted garbage collection if it is to aggressive about appending data.
1116 // TODO(acolwell): Remove this once http://crbug.com/144683 is fixed.
1117 increase_preroll_on_underflow = false;
[email protected]ddbc6ff2013-04-19 15:28:331118 }
1119
[email protected]f5443ef72013-04-22 04:03:381120 scoped_ptr<media::FilterCollection> filter_collection(
1121 new media::FilterCollection());
1122 filter_collection->SetDemuxer(demuxer_.get());
1123
[email protected]ddbc6ff2013-04-19 15:28:331124 // Figure out if EME is enabled.
1125 media::SetDecryptorReadyCB set_decryptor_ready_cb;
1126 if (decryptor_) {
1127 set_decryptor_ready_cb = base::Bind(&ProxyDecryptor::SetDecryptorReadyCB,
1128 base::Unretained(decryptor_.get()));
1129 }
1130
1131 // Create our audio decoders and renderer.
1132 ScopedVector<media::AudioDecoder> audio_decoders;
[email protected]c1330c82013-06-06 02:23:251133 audio_decoders.push_back(new media::FFmpegAudioDecoder(media_loop_));
[email protected]173a67472013-11-15 21:42:301134 if (!cmd_line->HasSwitch(switches::kDisableOpusPlayback)) {
[email protected]c1330c82013-06-06 02:23:251135 audio_decoders.push_back(new media::OpusAudioDecoder(media_loop_));
[email protected]ddbc6ff2013-04-19 15:28:331136 }
1137
1138 scoped_ptr<media::AudioRenderer> audio_renderer(
[email protected]c1330c82013-06-06 02:23:251139 new media::AudioRendererImpl(media_loop_,
[email protected]ff875be52013-06-02 23:47:381140 audio_source_provider_.get(),
[email protected]ddbc6ff2013-04-19 15:28:331141 audio_decoders.Pass(),
[email protected]b573f952013-06-04 10:50:091142 set_decryptor_ready_cb,
1143 increase_preroll_on_underflow));
[email protected]ddbc6ff2013-04-19 15:28:331144 filter_collection->SetAudioRenderer(audio_renderer.Pass());
1145
1146 // Create our video decoders and renderer.
1147 ScopedVector<media::VideoDecoder> video_decoders;
1148
[email protected]96cb47d02013-08-16 07:34:521149 if (gpu_factories_.get()) {
1150 video_decoders.push_back(
1151 new media::GpuVideoDecoder(gpu_factories_, media_log_));
1152 }
[email protected]ddbc6ff2013-04-19 15:28:331153
[email protected]ddbc6ff2013-04-19 15:28:331154#if !defined(MEDIA_DISABLE_LIBVPX)
[email protected]b150b5532013-06-15 00:50:541155 video_decoders.push_back(new media::VpxVideoDecoder(media_loop_));
[email protected]ddbc6ff2013-04-19 15:28:331156#endif // !defined(MEDIA_DISABLE_LIBVPX)
1157
[email protected]c1330c82013-06-06 02:23:251158 video_decoders.push_back(new media::FFmpegVideoDecoder(media_loop_));
[email protected]6ac955b2013-04-19 23:43:321159
[email protected]ddbc6ff2013-04-19 15:28:331160 scoped_ptr<media::VideoRenderer> video_renderer(
1161 new media::VideoRendererBase(
[email protected]c1330c82013-06-06 02:23:251162 media_loop_,
[email protected]ddbc6ff2013-04-19 15:28:331163 video_decoders.Pass(),
1164 set_decryptor_ready_cb,
1165 base::Bind(&WebMediaPlayerImpl::FrameReady, base::Unretained(this)),
1166 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::SetOpaque),
1167 true));
1168 filter_collection->SetVideoRenderer(video_renderer.Pass());
1169
[email protected]8a561062013-11-22 01:19:311170 if (cmd_line->HasSwitch(switches::kEnableInbandTextTracks)) {
1171 scoped_ptr<media::TextRenderer> text_renderer(
1172 new media::TextRenderer(
1173 media_loop_,
1174 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnAddTextTrack)));
1175
1176 filter_collection->SetTextRenderer(text_renderer.Pass());
1177 }
1178
[email protected]f5443ef72013-04-22 04:03:381179 // ... and we're ready to go!
1180 starting_ = true;
1181 pipeline_->Start(
1182 filter_collection.Pass(),
1183 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineEnded),
1184 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineError),
1185 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineSeek),
1186 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineBufferingState),
1187 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnDurationChange));
1188}
1189
1190void WebMediaPlayerImpl::SetNetworkState(WebMediaPlayer::NetworkState state) {
1191 DCHECK(main_loop_->BelongsToCurrentThread());
1192 DVLOG(1) << "SetNetworkState: " << state;
1193 network_state_ = state;
1194 // Always notify to ensure client has the latest value.
1195 GetClient()->networkStateChanged();
1196}
1197
1198void WebMediaPlayerImpl::SetReadyState(WebMediaPlayer::ReadyState state) {
1199 DCHECK(main_loop_->BelongsToCurrentThread());
1200 DVLOG(1) << "SetReadyState: " << state;
1201
1202 if (state == WebMediaPlayer::ReadyStateHaveEnoughData &&
1203 is_local_source_ &&
1204 network_state_ == WebMediaPlayer::NetworkStateLoading)
1205 SetNetworkState(WebMediaPlayer::NetworkStateLoaded);
1206
1207 ready_state_ = state;
1208 // Always notify to ensure client has the latest value.
1209 GetClient()->readyStateChanged();
1210}
1211
1212void WebMediaPlayerImpl::Destroy() {
1213 DCHECK(main_loop_->BelongsToCurrentThread());
1214
1215 // Abort any pending IO so stopping the pipeline doesn't get blocked.
1216 if (data_source_)
1217 data_source_->Abort();
1218 if (chunk_demuxer_) {
1219 chunk_demuxer_->Shutdown();
1220 chunk_demuxer_ = NULL;
1221 }
1222
[email protected]ff875be52013-06-02 23:47:381223 if (gpu_factories_.get()) {
[email protected]f5443ef72013-04-22 04:03:381224 gpu_factories_->Abort();
1225 gpu_factories_ = NULL;
1226 }
1227
1228 // Make sure to kill the pipeline so there's no more media threads running.
1229 // Note: stopping the pipeline might block for a long time.
1230 base::WaitableEvent waiter(false, false);
1231 pipeline_->Stop(base::Bind(
1232 &base::WaitableEvent::Signal, base::Unretained(&waiter)));
1233 waiter.Wait();
1234
1235 // Let V8 know we are not using extra resources anymore.
1236 if (incremented_externally_allocated_memory_) {
1237 v8::V8::AdjustAmountOfExternalAllocatedMemory(-kPlayerExtraMemory);
1238 incremented_externally_allocated_memory_ = false;
1239 }
1240
[email protected]f5443ef72013-04-22 04:03:381241 // Release any final references now that everything has stopped.
[email protected]a3702c52013-05-09 05:40:301242 pipeline_.reset();
[email protected]f5443ef72013-04-22 04:03:381243 demuxer_.reset();
[email protected]cccbd0f62013-04-26 18:39:591244 data_source_.reset();
[email protected]f5443ef72013-04-22 04:03:381245}
1246
[email protected]180ef242013-11-07 06:50:461247blink::WebMediaPlayerClient* WebMediaPlayerImpl::GetClient() {
[email protected]f5443ef72013-04-22 04:03:381248 DCHECK(main_loop_->BelongsToCurrentThread());
1249 DCHECK(client_);
1250 return client_;
1251}
1252
[email protected]180ef242013-11-07 06:50:461253blink::WebAudioSourceProvider* WebMediaPlayerImpl::audioSourceProvider() {
[email protected]ff875be52013-06-02 23:47:381254 return audio_source_provider_.get();
[email protected]f5443ef72013-04-22 04:03:381255}
1256
1257void WebMediaPlayerImpl::IncrementExternallyAllocatedMemory() {
1258 DCHECK(main_loop_->BelongsToCurrentThread());
1259 incremented_externally_allocated_memory_ = true;
1260 v8::V8::AdjustAmountOfExternalAllocatedMemory(kPlayerExtraMemory);
1261}
1262
1263double WebMediaPlayerImpl::GetPipelineDuration() const {
1264 base::TimeDelta duration = pipeline_->GetMediaDuration();
1265
1266 // Return positive infinity if the resource is unbounded.
1267 // http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html#dom-media-duration
1268 if (duration == media::kInfiniteDuration())
1269 return std::numeric_limits<double>::infinity();
1270
1271 return duration.InSecondsF();
1272}
1273
1274void WebMediaPlayerImpl::OnDurationChange() {
1275 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing)
1276 return;
1277
1278 GetClient()->durationChanged();
1279}
1280
1281void WebMediaPlayerImpl::FrameReady(
1282 const scoped_refptr<media::VideoFrame>& frame) {
1283 base::AutoLock auto_lock(lock_);
[email protected]29037ce52013-05-06 22:44:161284
[email protected]bfc05f22013-10-19 17:55:161285 if (current_frame_ &&
[email protected]29037ce52013-05-06 22:44:161286 current_frame_->natural_size() != frame->natural_size() &&
1287 !pending_size_change_) {
1288 pending_size_change_ = true;
1289 }
1290
[email protected]bfc05f22013-10-19 17:55:161291 DoneWaitingForPaint(false);
[email protected]c46a9f42013-10-16 03:28:181292
[email protected]f5443ef72013-04-22 04:03:381293 current_frame_ = frame;
[email protected]c46a9f42013-10-16 03:28:181294 current_frame_painted_ = false;
[email protected]bfc05f22013-10-19 17:55:161295 TRACE_EVENT_FLOW_BEGIN0("media", "WebMediaPlayerImpl:waitingForPaint", this);
[email protected]f5443ef72013-04-22 04:03:381296
1297 if (pending_repaint_)
1298 return;
1299
[email protected]bfc05f22013-10-19 17:55:161300 TRACE_EVENT_ASYNC_BEGIN0("media", "WebMediaPlayerImpl:repaintPending", this);
[email protected]f5443ef72013-04-22 04:03:381301 pending_repaint_ = true;
1302 main_loop_->PostTask(FROM_HERE, base::Bind(
1303 &WebMediaPlayerImpl::Repaint, AsWeakPtr()));
[email protected]ddbc6ff2013-04-19 15:28:331304}
1305
[email protected]bfc05f22013-10-19 17:55:161306void WebMediaPlayerImpl::DoneWaitingForPaint(bool painting_frame) {
1307 lock_.AssertAcquired();
1308 if (!current_frame_ || current_frame_painted_)
1309 return;
1310
1311 TRACE_EVENT_FLOW_END0("media", "WebMediaPlayerImpl:waitingForPaint", this);
1312
1313 if (painting_frame) {
1314 current_frame_painted_ = true;
1315 return;
1316 }
1317
1318 // The frame wasn't painted, but we aren't waiting for a Repaint() call so
1319 // assume that the frame wasn't painted because the video wasn't visible.
1320 if (!pending_repaint_)
1321 return;
1322
1323 // The |current_frame_| wasn't painted, it is being replaced, and we haven't
1324 // even gotten the chance to request a repaint for it yet. Mark it as dropped.
1325 TRACE_EVENT0("media", "WebMediaPlayerImpl:frameDropped");
1326 DVLOG(1) << "Frame dropped before being painted: "
1327 << current_frame_->GetTimestamp().InSecondsF();
1328 if (frames_dropped_before_paint_ < kuint32max)
1329 frames_dropped_before_paint_++;
1330}
1331
[email protected]5e35a8d2013-07-10 19:37:211332} // namespace content