Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(73)

Side by Side Diff: webkit/renderer/media/webmediaplayer_impl.cc

Issue 18261007: Migrate webkit/renderer/media/ to content/renderer/media/. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix win64 AGAIN Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « webkit/renderer/media/webmediaplayer_impl.h ('k') | webkit/renderer/media/webmediaplayer_ms.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "webkit/renderer/media/webmediaplayer_impl.h"
6
7 #include <algorithm>
8 #include <limits>
9 #include <string>
10 #include <vector>
11
12 #include "base/bind.h"
13 #include "base/callback.h"
14 #include "base/command_line.h"
15 #include "base/debug/crash_logging.h"
16 #include "base/message_loop/message_loop_proxy.h"
17 #include "base/metrics/histogram.h"
18 #include "base/strings/string_number_conversions.h"
19 #include "base/synchronization/waitable_event.h"
20 #include "cc/layers/video_layer.h"
21 #include "gpu/GLES2/gl2extchromium.h"
22 #include "media/audio/null_audio_sink.h"
23 #include "media/base/bind_to_loop.h"
24 #include "media/base/filter_collection.h"
25 #include "media/base/limits.h"
26 #include "media/base/media_log.h"
27 #include "media/base/media_switches.h"
28 #include "media/base/pipeline.h"
29 #include "media/base/video_frame.h"
30 #include "media/filters/audio_renderer_impl.h"
31 #include "media/filters/chunk_demuxer.h"
32 #include "media/filters/ffmpeg_audio_decoder.h"
33 #include "media/filters/ffmpeg_demuxer.h"
34 #include "media/filters/ffmpeg_video_decoder.h"
35 #include "media/filters/opus_audio_decoder.h"
36 #include "media/filters/video_renderer_base.h"
37 #include "media/filters/vpx_video_decoder.h"
38 #include "third_party/WebKit/public/platform/WebRect.h"
39 #include "third_party/WebKit/public/platform/WebSize.h"
40 #include "third_party/WebKit/public/platform/WebString.h"
41 #include "third_party/WebKit/public/platform/WebURL.h"
42 #include "third_party/WebKit/public/web/WebMediaSource.h"
43 #include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
44 #include "third_party/WebKit/public/web/WebView.h"
45 #include "v8/include/v8.h"
46 #include "webkit/plugins/ppapi/ppapi_webplugin_impl.h"
47 #include "webkit/renderer/compositor_bindings/web_layer_impl.h"
48 #include "webkit/renderer/media/buffered_data_source.h"
49 #include "webkit/renderer/media/crypto/key_systems.h"
50 #include "webkit/renderer/media/texttrack_impl.h"
51 #include "webkit/renderer/media/webaudiosourceprovider_impl.h"
52 #include "webkit/renderer/media/webinbandtexttrack_impl.h"
53 #include "webkit/renderer/media/webmediaplayer_delegate.h"
54 #include "webkit/renderer/media/webmediaplayer_params.h"
55 #include "webkit/renderer/media/webmediaplayer_util.h"
56 #include "webkit/renderer/media/webmediasourceclient_impl.h"
57
58 using WebKit::WebCanvas;
59 using WebKit::WebMediaPlayer;
60 using WebKit::WebRect;
61 using WebKit::WebSize;
62 using WebKit::WebString;
63 using media::PipelineStatus;
64
65 namespace {
66
67 // Amount of extra memory used by each player instance reported to V8.
68 // It is not exact number -- first, it differs on different platforms,
69 // and second, it is very hard to calculate. Instead, use some arbitrary
70 // value that will cause garbage collection from time to time. We don't want
71 // it to happen on every allocation, but don't want 5k players to sit in memory
72 // either. Looks that chosen constant achieves both goals, at least for audio
73 // objects. (Do not worry about video objects yet, JS programs do not create
74 // thousands of them...)
75 const int kPlayerExtraMemory = 1024 * 1024;
76
77 // Limits the range of playback rate.
78 //
79 // TODO(kylep): Revisit these.
80 //
81 // Vista has substantially lower performance than XP or Windows7. If you speed
82 // up a video too much, it can't keep up, and rendering stops updating except on
83 // the time bar. For really high speeds, audio becomes a bottleneck and we just
84 // use up the data we have, which may not achieve the speed requested, but will
85 // not crash the tab.
86 //
87 // A very slow speed, ie 0.00000001x, causes the machine to lock up. (It seems
88 // like a busy loop). It gets unresponsive, although its not completely dead.
89 //
90 // Also our timers are not very accurate (especially for ogg), which becomes
91 // evident at low speeds and on Vista. Since other speeds are risky and outside
92 // the norms, we think 1/16x to 16x is a safe and useful range for now.
93 const double kMinRate = 0.0625;
94 const double kMaxRate = 16.0;
95
96 // Prefix for histograms related to Encrypted Media Extensions.
97 const char* kMediaEme = "Media.EME.";
98 } // namespace
99
100 namespace webkit_media {
101
102 #define COMPILE_ASSERT_MATCHING_ENUM(name) \
103 COMPILE_ASSERT(static_cast<int>(WebMediaPlayer::CORSMode ## name) == \
104 static_cast<int>(BufferedResourceLoader::k ## name), \
105 mismatching_enums)
106 COMPILE_ASSERT_MATCHING_ENUM(Unspecified);
107 COMPILE_ASSERT_MATCHING_ENUM(Anonymous);
108 COMPILE_ASSERT_MATCHING_ENUM(UseCredentials);
109 #undef COMPILE_ASSERT_MATCHING_ENUM
110
111 #define BIND_TO_RENDER_LOOP(function) \
112 media::BindToLoop(main_loop_, base::Bind(function, AsWeakPtr()))
113
114 #define BIND_TO_RENDER_LOOP_1(function, arg1) \
115 media::BindToLoop(main_loop_, base::Bind(function, AsWeakPtr(), arg1))
116
117 #define BIND_TO_RENDER_LOOP_2(function, arg1, arg2) \
118 media::BindToLoop(main_loop_, base::Bind(function, AsWeakPtr(), arg1, arg2))
119
120 static void LogMediaSourceError(const scoped_refptr<media::MediaLog>& media_log,
121 const std::string& error) {
122 media_log->AddEvent(media_log->CreateMediaSourceErrorEvent(error));
123 }
124
125 WebMediaPlayerImpl::WebMediaPlayerImpl(
126 WebKit::WebFrame* frame,
127 WebKit::WebMediaPlayerClient* client,
128 base::WeakPtr<WebMediaPlayerDelegate> delegate,
129 const WebMediaPlayerParams& params)
130 : frame_(frame),
131 network_state_(WebMediaPlayer::NetworkStateEmpty),
132 ready_state_(WebMediaPlayer::ReadyStateHaveNothing),
133 main_loop_(base::MessageLoopProxy::current()),
134 media_loop_(params.message_loop_proxy()),
135 paused_(true),
136 seeking_(false),
137 playback_rate_(0.0f),
138 pending_seek_(false),
139 pending_seek_seconds_(0.0f),
140 client_(client),
141 delegate_(delegate),
142 defer_load_cb_(params.defer_load_cb()),
143 media_log_(params.media_log()),
144 accelerated_compositing_reported_(false),
145 incremented_externally_allocated_memory_(false),
146 gpu_factories_(params.gpu_factories()),
147 is_local_source_(false),
148 supports_save_(true),
149 starting_(false),
150 chunk_demuxer_(NULL),
151 pending_repaint_(false),
152 pending_size_change_(false),
153 video_frame_provider_client_(NULL),
154 text_track_index_(0) {
155 media_log_->AddEvent(
156 media_log_->CreateEvent(media::MediaLogEvent::WEBMEDIAPLAYER_CREATED));
157
158 pipeline_.reset(new media::Pipeline(media_loop_, media_log_.get()));
159
160 // Let V8 know we started new thread if we did not do it yet.
161 // Made separate task to avoid deletion of player currently being created.
162 // Also, delaying GC until after player starts gets rid of starting lag --
163 // collection happens in parallel with playing.
164 //
165 // TODO(enal): remove when we get rid of per-audio-stream thread.
166 main_loop_->PostTask(
167 FROM_HERE,
168 base::Bind(&WebMediaPlayerImpl::IncrementExternallyAllocatedMemory,
169 AsWeakPtr()));
170
171 // Also we want to be notified of |main_loop_| destruction.
172 base::MessageLoop::current()->AddDestructionObserver(this);
173
174 if (WebKit::WebRuntimeFeatures::isLegacyEncryptedMediaEnabled()) {
175 decryptor_.reset(new ProxyDecryptor(
176 #if defined(ENABLE_PEPPER_CDMS)
177 client,
178 frame,
179 #endif
180 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnKeyAdded),
181 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnKeyError),
182 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnKeyMessage)));
183 }
184
185 // Use the null sink if no sink was provided.
186 audio_source_provider_ = new WebAudioSourceProviderImpl(
187 params.audio_renderer_sink().get()
188 ? params.audio_renderer_sink()
189 : new media::NullAudioSink(media_loop_));
190 }
191
192 WebMediaPlayerImpl::~WebMediaPlayerImpl() {
193 SetVideoFrameProviderClient(NULL);
194 GetClient()->setWebLayer(NULL);
195
196 DCHECK(main_loop_->BelongsToCurrentThread());
197 media_log_->AddEvent(
198 media_log_->CreateEvent(media::MediaLogEvent::WEBMEDIAPLAYER_DESTROYED));
199
200 if (delegate_.get())
201 delegate_->PlayerGone(this);
202
203 Destroy();
204
205 // Remove destruction observer if we're being destroyed but the main thread is
206 // still running.
207 if (base::MessageLoop::current())
208 base::MessageLoop::current()->RemoveDestructionObserver(this);
209 }
210
211 namespace {
212
213 // Helper enum for reporting scheme histograms.
214 enum URLSchemeForHistogram {
215 kUnknownURLScheme,
216 kMissingURLScheme,
217 kHttpURLScheme,
218 kHttpsURLScheme,
219 kFtpURLScheme,
220 kChromeExtensionURLScheme,
221 kJavascriptURLScheme,
222 kFileURLScheme,
223 kBlobURLScheme,
224 kDataURLScheme,
225 kFileSystemScheme,
226 kMaxURLScheme = kFileSystemScheme // Must be equal to highest enum value.
227 };
228
229 URLSchemeForHistogram URLScheme(const GURL& url) {
230 if (!url.has_scheme()) return kMissingURLScheme;
231 if (url.SchemeIs("http")) return kHttpURLScheme;
232 if (url.SchemeIs("https")) return kHttpsURLScheme;
233 if (url.SchemeIs("ftp")) return kFtpURLScheme;
234 if (url.SchemeIs("chrome-extension")) return kChromeExtensionURLScheme;
235 if (url.SchemeIs("javascript")) return kJavascriptURLScheme;
236 if (url.SchemeIs("file")) return kFileURLScheme;
237 if (url.SchemeIs("blob")) return kBlobURLScheme;
238 if (url.SchemeIs("data")) return kDataURLScheme;
239 if (url.SchemeIs("filesystem")) return kFileSystemScheme;
240 return kUnknownURLScheme;
241 }
242
243 } // anonymous namespace
244
245 void WebMediaPlayerImpl::load(const WebKit::WebURL& url, CORSMode cors_mode) {
246 load(url, NULL, cors_mode);
247 }
248
249 void WebMediaPlayerImpl::load(const WebKit::WebURL& url,
250 WebKit::WebMediaSource* media_source,
251 CORSMode cors_mode) {
252 if (!defer_load_cb_.is_null()) {
253 defer_load_cb_.Run(base::Bind(
254 &WebMediaPlayerImpl::DoLoad, AsWeakPtr(), url, media_source,
255 cors_mode));
256 return;
257 }
258 DoLoad(url, media_source, cors_mode);
259 }
260
261 void WebMediaPlayerImpl::DoLoad(const WebKit::WebURL& url,
262 WebKit::WebMediaSource* media_source,
263 CORSMode cors_mode) {
264 DCHECK(main_loop_->BelongsToCurrentThread());
265
266 GURL gurl(url);
267 UMA_HISTOGRAM_ENUMERATION("Media.URLScheme", URLScheme(gurl), kMaxURLScheme);
268
269 // Set subresource URL for crash reporting.
270 base::debug::SetCrashKeyValue("subresource_url", gurl.spec());
271
272 // Handle any volume/preload changes that occurred before load().
273 setVolume(GetClient()->volume());
274 setPreload(GetClient()->preload());
275
276 SetNetworkState(WebMediaPlayer::NetworkStateLoading);
277 SetReadyState(WebMediaPlayer::ReadyStateHaveNothing);
278 media_log_->AddEvent(media_log_->CreateLoadEvent(url.spec()));
279
280 // Media source pipelines can start immediately.
281 if (media_source) {
282 supports_save_ = false;
283 StartPipeline(media_source);
284 return;
285 }
286
287 // Otherwise it's a regular request which requires resolving the URL first.
288 data_source_.reset(new BufferedDataSource(
289 main_loop_,
290 frame_,
291 media_log_.get(),
292 base::Bind(&WebMediaPlayerImpl::NotifyDownloading, AsWeakPtr())));
293 data_source_->Initialize(
294 url, static_cast<BufferedResourceLoader::CORSMode>(cors_mode),
295 base::Bind(
296 &WebMediaPlayerImpl::DataSourceInitialized,
297 AsWeakPtr(), gurl));
298
299 is_local_source_ = !gurl.SchemeIs("http") && !gurl.SchemeIs("https");
300 }
301
302 void WebMediaPlayerImpl::play() {
303 DCHECK(main_loop_->BelongsToCurrentThread());
304
305 paused_ = false;
306 pipeline_->SetPlaybackRate(playback_rate_);
307
308 media_log_->AddEvent(media_log_->CreateEvent(media::MediaLogEvent::PLAY));
309
310 if (delegate_.get())
311 delegate_->DidPlay(this);
312 }
313
314 void WebMediaPlayerImpl::pause() {
315 DCHECK(main_loop_->BelongsToCurrentThread());
316
317 paused_ = true;
318 pipeline_->SetPlaybackRate(0.0f);
319 paused_time_ = pipeline_->GetMediaTime();
320
321 media_log_->AddEvent(media_log_->CreateEvent(media::MediaLogEvent::PAUSE));
322
323 if (delegate_.get())
324 delegate_->DidPause(this);
325 }
326
327 bool WebMediaPlayerImpl::supportsFullscreen() const {
328 DCHECK(main_loop_->BelongsToCurrentThread());
329 return true;
330 }
331
332 bool WebMediaPlayerImpl::supportsSave() const {
333 DCHECK(main_loop_->BelongsToCurrentThread());
334 return supports_save_;
335 }
336
337 void WebMediaPlayerImpl::seek(double seconds) {
338 DCHECK(main_loop_->BelongsToCurrentThread());
339
340 base::TimeDelta seek_time = ConvertSecondsToTimestamp(seconds);
341
342 if (starting_ || seeking_) {
343 pending_seek_ = true;
344 pending_seek_seconds_ = seconds;
345 if (chunk_demuxer_)
346 chunk_demuxer_->CancelPendingSeek(seek_time);
347 return;
348 }
349
350 media_log_->AddEvent(media_log_->CreateSeekEvent(seconds));
351
352 // Update our paused time.
353 if (paused_)
354 paused_time_ = seek_time;
355
356 seeking_ = true;
357
358 if (chunk_demuxer_)
359 chunk_demuxer_->StartWaitingForSeek(seek_time);
360
361 // Kick off the asynchronous seek!
362 pipeline_->Seek(
363 seek_time,
364 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineSeek));
365 }
366
367 void WebMediaPlayerImpl::setRate(double rate) {
368 DCHECK(main_loop_->BelongsToCurrentThread());
369
370 // TODO(kylep): Remove when support for negatives is added. Also, modify the
371 // following checks so rewind uses reasonable values also.
372 if (rate < 0.0)
373 return;
374
375 // Limit rates to reasonable values by clamping.
376 if (rate != 0.0) {
377 if (rate < kMinRate)
378 rate = kMinRate;
379 else if (rate > kMaxRate)
380 rate = kMaxRate;
381 }
382
383 playback_rate_ = rate;
384 if (!paused_) {
385 pipeline_->SetPlaybackRate(rate);
386 }
387 }
388
389 void WebMediaPlayerImpl::setVolume(double volume) {
390 DCHECK(main_loop_->BelongsToCurrentThread());
391
392 pipeline_->SetVolume(volume);
393 }
394
395 #define COMPILE_ASSERT_MATCHING_ENUM(webkit_name, chromium_name) \
396 COMPILE_ASSERT(static_cast<int>(WebMediaPlayer::webkit_name) == \
397 static_cast<int>(webkit_media::chromium_name), \
398 mismatching_enums)
399 COMPILE_ASSERT_MATCHING_ENUM(PreloadNone, NONE);
400 COMPILE_ASSERT_MATCHING_ENUM(PreloadMetaData, METADATA);
401 COMPILE_ASSERT_MATCHING_ENUM(PreloadAuto, AUTO);
402 #undef COMPILE_ASSERT_MATCHING_ENUM
403
404 void WebMediaPlayerImpl::setPreload(WebMediaPlayer::Preload preload) {
405 DCHECK(main_loop_->BelongsToCurrentThread());
406
407 if (data_source_)
408 data_source_->SetPreload(static_cast<webkit_media::Preload>(preload));
409 }
410
411 bool WebMediaPlayerImpl::hasVideo() const {
412 DCHECK(main_loop_->BelongsToCurrentThread());
413
414 return pipeline_->HasVideo();
415 }
416
417 bool WebMediaPlayerImpl::hasAudio() const {
418 DCHECK(main_loop_->BelongsToCurrentThread());
419
420 return pipeline_->HasAudio();
421 }
422
423 WebKit::WebSize WebMediaPlayerImpl::naturalSize() const {
424 DCHECK(main_loop_->BelongsToCurrentThread());
425
426 gfx::Size size;
427 pipeline_->GetNaturalVideoSize(&size);
428 return WebKit::WebSize(size);
429 }
430
431 bool WebMediaPlayerImpl::paused() const {
432 DCHECK(main_loop_->BelongsToCurrentThread());
433
434 return pipeline_->GetPlaybackRate() == 0.0f;
435 }
436
437 bool WebMediaPlayerImpl::seeking() const {
438 DCHECK(main_loop_->BelongsToCurrentThread());
439
440 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing)
441 return false;
442
443 return seeking_;
444 }
445
446 double WebMediaPlayerImpl::duration() const {
447 DCHECK(main_loop_->BelongsToCurrentThread());
448
449 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing)
450 return std::numeric_limits<double>::quiet_NaN();
451
452 return GetPipelineDuration();
453 }
454
455 double WebMediaPlayerImpl::currentTime() const {
456 DCHECK(main_loop_->BelongsToCurrentThread());
457 return (paused_ ? paused_time_ : pipeline_->GetMediaTime()).InSecondsF();
458 }
459
460 WebMediaPlayer::NetworkState WebMediaPlayerImpl::networkState() const {
461 DCHECK(main_loop_->BelongsToCurrentThread());
462 return network_state_;
463 }
464
465 WebMediaPlayer::ReadyState WebMediaPlayerImpl::readyState() const {
466 DCHECK(main_loop_->BelongsToCurrentThread());
467 return ready_state_;
468 }
469
470 const WebKit::WebTimeRanges& WebMediaPlayerImpl::buffered() {
471 DCHECK(main_loop_->BelongsToCurrentThread());
472 WebKit::WebTimeRanges web_ranges(
473 ConvertToWebTimeRanges(pipeline_->GetBufferedTimeRanges()));
474 buffered_.swap(web_ranges);
475 return buffered_;
476 }
477
478 double WebMediaPlayerImpl::maxTimeSeekable() const {
479 DCHECK(main_loop_->BelongsToCurrentThread());
480
481 // If we haven't even gotten to ReadyStateHaveMetadata yet then just
482 // return 0 so that the seekable range is empty.
483 if (ready_state_ < WebMediaPlayer::ReadyStateHaveMetadata)
484 return 0.0;
485
486 // We don't support seeking in streaming media.
487 if (data_source_ && data_source_->IsStreaming())
488 return 0.0;
489 return duration();
490 }
491
492 bool WebMediaPlayerImpl::didLoadingProgress() const {
493 DCHECK(main_loop_->BelongsToCurrentThread());
494 return pipeline_->DidLoadingProgress();
495 }
496
497 void WebMediaPlayerImpl::paint(WebCanvas* canvas,
498 const WebRect& rect,
499 unsigned char alpha) {
500 DCHECK(main_loop_->BelongsToCurrentThread());
501
502 if (!accelerated_compositing_reported_) {
503 accelerated_compositing_reported_ = true;
504 // Normally paint() is only called in non-accelerated rendering, but there
505 // are exceptions such as webgl where compositing is used in the WebView but
506 // video frames are still rendered to a canvas.
507 UMA_HISTOGRAM_BOOLEAN(
508 "Media.AcceleratedCompositingActive",
509 frame_->view()->isAcceleratedCompositingActive());
510 }
511
512 // Avoid locking and potentially blocking the video rendering thread while
513 // painting in software.
514 scoped_refptr<media::VideoFrame> video_frame;
515 {
516 base::AutoLock auto_lock(lock_);
517 video_frame = current_frame_;
518 }
519 gfx::Rect gfx_rect(rect);
520 skcanvas_video_renderer_.Paint(video_frame.get(), canvas, gfx_rect, alpha);
521 }
522
523 bool WebMediaPlayerImpl::hasSingleSecurityOrigin() const {
524 if (data_source_)
525 return data_source_->HasSingleOrigin();
526 return true;
527 }
528
529 bool WebMediaPlayerImpl::didPassCORSAccessCheck() const {
530 if (data_source_)
531 return data_source_->DidPassCORSAccessCheck();
532 return false;
533 }
534
535 double WebMediaPlayerImpl::mediaTimeForTimeValue(double timeValue) const {
536 return ConvertSecondsToTimestamp(timeValue).InSecondsF();
537 }
538
539 unsigned WebMediaPlayerImpl::decodedFrameCount() const {
540 DCHECK(main_loop_->BelongsToCurrentThread());
541
542 media::PipelineStatistics stats = pipeline_->GetStatistics();
543 return stats.video_frames_decoded;
544 }
545
546 unsigned WebMediaPlayerImpl::droppedFrameCount() const {
547 DCHECK(main_loop_->BelongsToCurrentThread());
548
549 media::PipelineStatistics stats = pipeline_->GetStatistics();
550 return stats.video_frames_dropped;
551 }
552
553 unsigned WebMediaPlayerImpl::audioDecodedByteCount() const {
554 DCHECK(main_loop_->BelongsToCurrentThread());
555
556 media::PipelineStatistics stats = pipeline_->GetStatistics();
557 return stats.audio_bytes_decoded;
558 }
559
560 unsigned WebMediaPlayerImpl::videoDecodedByteCount() const {
561 DCHECK(main_loop_->BelongsToCurrentThread());
562
563 media::PipelineStatistics stats = pipeline_->GetStatistics();
564 return stats.video_bytes_decoded;
565 }
566
567 void WebMediaPlayerImpl::SetVideoFrameProviderClient(
568 cc::VideoFrameProvider::Client* client) {
569 // This is called from both the main renderer thread and the compositor
570 // thread (when the main thread is blocked).
571 if (video_frame_provider_client_)
572 video_frame_provider_client_->StopUsingProvider();
573 video_frame_provider_client_ = client;
574 }
575
576 scoped_refptr<media::VideoFrame> WebMediaPlayerImpl::GetCurrentFrame() {
577 base::AutoLock auto_lock(lock_);
578 return current_frame_;
579 }
580
581 void WebMediaPlayerImpl::PutCurrentFrame(
582 const scoped_refptr<media::VideoFrame>& frame) {
583 if (!accelerated_compositing_reported_) {
584 accelerated_compositing_reported_ = true;
585 DCHECK(frame_->view()->isAcceleratedCompositingActive());
586 UMA_HISTOGRAM_BOOLEAN("Media.AcceleratedCompositingActive", true);
587 }
588 }
589
590 bool WebMediaPlayerImpl::copyVideoTextureToPlatformTexture(
591 WebKit::WebGraphicsContext3D* web_graphics_context,
592 unsigned int texture,
593 unsigned int level,
594 unsigned int internal_format,
595 unsigned int type,
596 bool premultiply_alpha,
597 bool flip_y) {
598 scoped_refptr<media::VideoFrame> video_frame;
599 {
600 base::AutoLock auto_lock(lock_);
601 video_frame = current_frame_;
602 }
603
604 if (!video_frame.get())
605 return false;
606 if (video_frame->format() != media::VideoFrame::NATIVE_TEXTURE)
607 return false;
608 if (video_frame->texture_target() != GL_TEXTURE_2D)
609 return false;
610
611 scoped_refptr<media::VideoFrame::MailboxHolder> mailbox_holder =
612 video_frame->texture_mailbox();
613
614 uint32 source_texture = web_graphics_context->createTexture();
615
616 web_graphics_context->waitSyncPoint(mailbox_holder->sync_point());
617 web_graphics_context->bindTexture(GL_TEXTURE_2D, source_texture);
618 web_graphics_context->consumeTextureCHROMIUM(GL_TEXTURE_2D,
619 mailbox_holder->mailbox().name);
620
621 // The video is stored in a unmultiplied format, so premultiply
622 // if necessary.
623 web_graphics_context->pixelStorei(GL_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM,
624 premultiply_alpha);
625 // Application itself needs to take care of setting the right flip_y
626 // value down to get the expected result.
627 // flip_y==true means to reverse the video orientation while
628 // flip_y==false means to keep the intrinsic orientation.
629 web_graphics_context->pixelStorei(GL_UNPACK_FLIP_Y_CHROMIUM, flip_y);
630 web_graphics_context->copyTextureCHROMIUM(GL_TEXTURE_2D,
631 source_texture,
632 texture,
633 level,
634 internal_format,
635 type);
636 web_graphics_context->pixelStorei(GL_UNPACK_FLIP_Y_CHROMIUM, false);
637 web_graphics_context->pixelStorei(GL_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM,
638 false);
639
640 web_graphics_context->deleteTexture(source_texture);
641
642 // The flush() operation is not necessary here. It is kept since the
643 // performance will be better when it is added than not.
644 web_graphics_context->flush();
645 return true;
646 }
647
648 // Helper functions to report media EME related stats to UMA. They follow the
649 // convention of more commonly used macros UMA_HISTOGRAM_ENUMERATION and
650 // UMA_HISTOGRAM_COUNTS. The reason that we cannot use those macros directly is
651 // that UMA_* macros require the names to be constant throughout the process'
652 // lifetime.
653 static void EmeUMAHistogramEnumeration(const WebKit::WebString& key_system,
654 const std::string& method,
655 int sample,
656 int boundary_value) {
657 base::LinearHistogram::FactoryGet(
658 kMediaEme + KeySystemNameForUMA(key_system) + "." + method,
659 1, boundary_value, boundary_value + 1,
660 base::Histogram::kUmaTargetedHistogramFlag)->Add(sample);
661 }
662
663 static void EmeUMAHistogramCounts(const WebKit::WebString& key_system,
664 const std::string& method,
665 int sample) {
666 // Use the same parameters as UMA_HISTOGRAM_COUNTS.
667 base::Histogram::FactoryGet(
668 kMediaEme + KeySystemNameForUMA(key_system) + "." + method,
669 1, 1000000, 50, base::Histogram::kUmaTargetedHistogramFlag)->Add(sample);
670 }
671
672 // Helper enum for reporting generateKeyRequest/addKey histograms.
673 enum MediaKeyException {
674 kUnknownResultId,
675 kSuccess,
676 kKeySystemNotSupported,
677 kInvalidPlayerState,
678 kMaxMediaKeyException
679 };
680
681 static MediaKeyException MediaKeyExceptionForUMA(
682 WebMediaPlayer::MediaKeyException e) {
683 switch (e) {
684 case WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported:
685 return kKeySystemNotSupported;
686 case WebMediaPlayer::MediaKeyExceptionInvalidPlayerState:
687 return kInvalidPlayerState;
688 case WebMediaPlayer::MediaKeyExceptionNoError:
689 return kSuccess;
690 default:
691 return kUnknownResultId;
692 }
693 }
694
695 // Helper for converting |key_system| name and exception |e| to a pair of enum
696 // values from above, for reporting to UMA.
697 static void ReportMediaKeyExceptionToUMA(
698 const std::string& method,
699 const WebString& key_system,
700 WebMediaPlayer::MediaKeyException e) {
701 MediaKeyException result_id = MediaKeyExceptionForUMA(e);
702 DCHECK_NE(result_id, kUnknownResultId) << e;
703 EmeUMAHistogramEnumeration(
704 key_system, method, result_id, kMaxMediaKeyException);
705 }
706
707 WebMediaPlayer::MediaKeyException
708 WebMediaPlayerImpl::generateKeyRequest(const WebString& key_system,
709 const unsigned char* init_data,
710 unsigned init_data_length) {
711 WebMediaPlayer::MediaKeyException e =
712 GenerateKeyRequestInternal(key_system, init_data, init_data_length);
713 ReportMediaKeyExceptionToUMA("generateKeyRequest", key_system, e);
714 return e;
715 }
716
717 WebMediaPlayer::MediaKeyException
718 WebMediaPlayerImpl::GenerateKeyRequestInternal(
719 const WebString& key_system,
720 const unsigned char* init_data,
721 unsigned init_data_length) {
722 DVLOG(1) << "generateKeyRequest: " << key_system.utf8().data() << ": "
723 << std::string(reinterpret_cast<const char*>(init_data),
724 static_cast<size_t>(init_data_length));
725
726 if (!IsSupportedKeySystem(key_system))
727 return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported;
728
729 // We do not support run-time switching between key systems for now.
730 if (current_key_system_.isEmpty()) {
731 if (!decryptor_->InitializeCDM(key_system.utf8()))
732 return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported;
733 current_key_system_ = key_system;
734 }
735 else if (key_system != current_key_system_) {
736 return WebMediaPlayer::MediaKeyExceptionInvalidPlayerState;
737 }
738
739 // TODO(xhwang): We assume all streams are from the same container (thus have
740 // the same "type") for now. In the future, the "type" should be passed down
741 // from the application.
742 if (!decryptor_->GenerateKeyRequest(init_data_type_,
743 init_data, init_data_length)) {
744 current_key_system_.reset();
745 return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported;
746 }
747
748 return WebMediaPlayer::MediaKeyExceptionNoError;
749 }
750
751 WebMediaPlayer::MediaKeyException WebMediaPlayerImpl::addKey(
752 const WebString& key_system,
753 const unsigned char* key,
754 unsigned key_length,
755 const unsigned char* init_data,
756 unsigned init_data_length,
757 const WebString& session_id) {
758 WebMediaPlayer::MediaKeyException e = AddKeyInternal(
759 key_system, key, key_length, init_data, init_data_length, session_id);
760 ReportMediaKeyExceptionToUMA("addKey", key_system, e);
761 return e;
762 }
763
764 WebMediaPlayer::MediaKeyException WebMediaPlayerImpl::AddKeyInternal(
765 const WebString& key_system,
766 const unsigned char* key,
767 unsigned key_length,
768 const unsigned char* init_data,
769 unsigned init_data_length,
770 const WebString& session_id) {
771 DCHECK(key);
772 DCHECK_GT(key_length, 0u);
773 DVLOG(1) << "addKey: " << key_system.utf8().data() << ": "
774 << std::string(reinterpret_cast<const char*>(key),
775 static_cast<size_t>(key_length)) << ", "
776 << std::string(reinterpret_cast<const char*>(init_data),
777 static_cast<size_t>(init_data_length))
778 << " [" << session_id.utf8().data() << "]";
779
780
781 if (!IsSupportedKeySystem(key_system))
782 return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported;
783
784 if (current_key_system_.isEmpty() || key_system != current_key_system_)
785 return WebMediaPlayer::MediaKeyExceptionInvalidPlayerState;
786
787 decryptor_->AddKey(key, key_length,
788 init_data, init_data_length, session_id.utf8());
789 return WebMediaPlayer::MediaKeyExceptionNoError;
790 }
791
792 WebMediaPlayer::MediaKeyException WebMediaPlayerImpl::cancelKeyRequest(
793 const WebString& key_system,
794 const WebString& session_id) {
795 WebMediaPlayer::MediaKeyException e =
796 CancelKeyRequestInternal(key_system, session_id);
797 ReportMediaKeyExceptionToUMA("cancelKeyRequest", key_system, e);
798 return e;
799 }
800
801 WebMediaPlayer::MediaKeyException
802 WebMediaPlayerImpl::CancelKeyRequestInternal(
803 const WebString& key_system,
804 const WebString& session_id) {
805 if (!IsSupportedKeySystem(key_system))
806 return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported;
807
808 if (current_key_system_.isEmpty() || key_system != current_key_system_)
809 return WebMediaPlayer::MediaKeyExceptionInvalidPlayerState;
810
811 decryptor_->CancelKeyRequest(session_id.utf8());
812 return WebMediaPlayer::MediaKeyExceptionNoError;
813 }
814
815 void WebMediaPlayerImpl::WillDestroyCurrentMessageLoop() {
816 Destroy();
817 }
818
819 void WebMediaPlayerImpl::Repaint() {
820 DCHECK(main_loop_->BelongsToCurrentThread());
821
822 bool size_changed = false;
823 {
824 base::AutoLock auto_lock(lock_);
825 std::swap(pending_size_change_, size_changed);
826 pending_repaint_ = false;
827 }
828
829 if (size_changed)
830 GetClient()->sizeChanged();
831
832 GetClient()->repaint();
833 }
834
835 void WebMediaPlayerImpl::OnPipelineSeek(PipelineStatus status) {
836 DCHECK(main_loop_->BelongsToCurrentThread());
837 starting_ = false;
838 seeking_ = false;
839 if (pending_seek_) {
840 pending_seek_ = false;
841 seek(pending_seek_seconds_);
842 return;
843 }
844
845 if (status != media::PIPELINE_OK) {
846 OnPipelineError(status);
847 return;
848 }
849
850 // Update our paused time.
851 if (paused_)
852 paused_time_ = pipeline_->GetMediaTime();
853
854 GetClient()->timeChanged();
855 }
856
857 void WebMediaPlayerImpl::OnPipelineEnded() {
858 DCHECK(main_loop_->BelongsToCurrentThread());
859 GetClient()->timeChanged();
860 }
861
862 void WebMediaPlayerImpl::OnPipelineError(PipelineStatus error) {
863 DCHECK(main_loop_->BelongsToCurrentThread());
864 DCHECK_NE(error, media::PIPELINE_OK);
865
866 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing) {
867 // Any error that occurs before reaching ReadyStateHaveMetadata should
868 // be considered a format error.
869 SetNetworkState(WebMediaPlayer::NetworkStateFormatError);
870 Repaint();
871 return;
872 }
873
874 SetNetworkState(PipelineErrorToNetworkState(error));
875
876 if (error == media::PIPELINE_ERROR_DECRYPT)
877 EmeUMAHistogramCounts(current_key_system_, "DecryptError", 1);
878
879 // Repaint to trigger UI update.
880 Repaint();
881 }
882
883 void WebMediaPlayerImpl::OnPipelineBufferingState(
884 media::Pipeline::BufferingState buffering_state) {
885 DVLOG(1) << "OnPipelineBufferingState(" << buffering_state << ")";
886
887 switch (buffering_state) {
888 case media::Pipeline::kHaveMetadata:
889 SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata);
890
891 if (hasVideo() && GetClient()->needsWebLayerForVideo()) {
892 DCHECK(!video_weblayer_);
893 video_weblayer_.reset(
894 new webkit::WebLayerImpl(cc::VideoLayer::Create(this)));
895 GetClient()->setWebLayer(video_weblayer_.get());
896 }
897 break;
898 case media::Pipeline::kPrerollCompleted:
899 // Only transition to ReadyStateHaveEnoughData if we don't have
900 // any pending seeks because the transition can cause Blink to
901 // report that the most recent seek has completed.
902 if (!pending_seek_)
903 SetReadyState(WebMediaPlayer::ReadyStateHaveEnoughData);
904 break;
905 }
906
907 // Repaint to trigger UI update.
908 Repaint();
909 }
910
911 void WebMediaPlayerImpl::OnDemuxerOpened(
912 scoped_ptr<WebKit::WebMediaSource> media_source) {
913 DCHECK(main_loop_->BelongsToCurrentThread());
914 media_source->open(new WebMediaSourceClientImpl(
915 chunk_demuxer_, base::Bind(&LogMediaSourceError, media_log_)));
916 }
917
918 void WebMediaPlayerImpl::OnKeyAdded(const std::string& session_id) {
919 DCHECK(main_loop_->BelongsToCurrentThread());
920 EmeUMAHistogramCounts(current_key_system_, "KeyAdded", 1);
921 GetClient()->keyAdded(current_key_system_,
922 WebString::fromUTF8(session_id));
923 }
924
925 void WebMediaPlayerImpl::OnNeedKey(const std::string& session_id,
926 const std::string& type,
927 scoped_ptr<uint8[]> init_data,
928 int init_data_size) {
929 DCHECK(main_loop_->BelongsToCurrentThread());
930
931 // Do not fire NeedKey event if encrypted media is not enabled.
932 if (!decryptor_)
933 return;
934
935 UMA_HISTOGRAM_COUNTS(kMediaEme + std::string("NeedKey"), 1);
936
937 DCHECK(init_data_type_.empty() || type.empty() || type == init_data_type_);
938 if (init_data_type_.empty())
939 init_data_type_ = type;
940
941 GetClient()->keyNeeded(WebString(),
942 WebString::fromUTF8(session_id),
943 init_data.get(),
944 init_data_size);
945 }
946
947 scoped_ptr<media::TextTrack>
948 WebMediaPlayerImpl::OnTextTrack(media::TextKind kind,
949 const std::string& label,
950 const std::string& language) {
951 typedef WebInbandTextTrackImpl::Kind webkind_t;
952 const webkind_t webkind = static_cast<webkind_t>(kind);
953 const WebKit::WebString weblabel = WebKit::WebString::fromUTF8(label);
954 const WebKit::WebString weblanguage = WebKit::WebString::fromUTF8(language);
955
956 WebInbandTextTrackImpl* const text_track =
957 new WebInbandTextTrackImpl(webkind, weblabel, weblanguage,
958 text_track_index_++);
959
960 return scoped_ptr<media::TextTrack>(new TextTrackImpl(GetClient(),
961 text_track));
962 }
963
964 void WebMediaPlayerImpl::OnKeyError(const std::string& session_id,
965 media::MediaKeys::KeyError error_code,
966 int system_code) {
967 DCHECK(main_loop_->BelongsToCurrentThread());
968
969 EmeUMAHistogramEnumeration(current_key_system_, "KeyError",
970 error_code, media::MediaKeys::kMaxKeyError);
971
972 GetClient()->keyError(
973 current_key_system_,
974 WebString::fromUTF8(session_id),
975 static_cast<WebKit::WebMediaPlayerClient::MediaKeyErrorCode>(error_code),
976 system_code);
977 }
978
979 void WebMediaPlayerImpl::OnKeyMessage(const std::string& session_id,
980 const std::vector<uint8>& message,
981 const std::string& default_url) {
982 DCHECK(main_loop_->BelongsToCurrentThread());
983
984 const GURL default_url_gurl(default_url);
985 DLOG_IF(WARNING, !default_url.empty() && !default_url_gurl.is_valid())
986 << "Invalid URL in default_url: " << default_url;
987
988 GetClient()->keyMessage(current_key_system_,
989 WebString::fromUTF8(session_id),
990 message.empty() ? NULL : &message[0],
991 message.size(),
992 default_url_gurl);
993 }
994
995 void WebMediaPlayerImpl::SetOpaque(bool opaque) {
996 DCHECK(main_loop_->BelongsToCurrentThread());
997
998 GetClient()->setOpaque(opaque);
999 }
1000
1001 void WebMediaPlayerImpl::DataSourceInitialized(const GURL& gurl, bool success) {
1002 DCHECK(main_loop_->BelongsToCurrentThread());
1003
1004 if (!success) {
1005 SetNetworkState(WebMediaPlayer::NetworkStateFormatError);
1006 Repaint();
1007 return;
1008 }
1009
1010 StartPipeline(NULL);
1011 }
1012
1013 void WebMediaPlayerImpl::NotifyDownloading(bool is_downloading) {
1014 if (!is_downloading && network_state_ == WebMediaPlayer::NetworkStateLoading)
1015 SetNetworkState(WebMediaPlayer::NetworkStateIdle);
1016 else if (is_downloading && network_state_ == WebMediaPlayer::NetworkStateIdle)
1017 SetNetworkState(WebMediaPlayer::NetworkStateLoading);
1018 media_log_->AddEvent(
1019 media_log_->CreateBooleanEvent(
1020 media::MediaLogEvent::NETWORK_ACTIVITY_SET,
1021 "is_downloading_data", is_downloading));
1022 }
1023
1024 void WebMediaPlayerImpl::StartPipeline(WebKit::WebMediaSource* media_source) {
1025 const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
1026 bool increase_preroll_on_underflow = true;
1027
1028 // Keep track if this is a MSE or non-MSE playback.
1029 UMA_HISTOGRAM_BOOLEAN("Media.MSE.Playback", (media_source != NULL));
1030
1031 // Figure out which demuxer to use.
1032 if (!media_source) {
1033 DCHECK(!chunk_demuxer_);
1034 DCHECK(data_source_);
1035
1036 demuxer_.reset(new media::FFmpegDemuxer(
1037 media_loop_, data_source_.get(),
1038 BIND_TO_RENDER_LOOP_1(&WebMediaPlayerImpl::OnNeedKey, "")));
1039 } else {
1040 DCHECK(!chunk_demuxer_);
1041 DCHECK(!data_source_);
1042
1043 media::AddTextTrackCB add_text_track_cb;
1044
1045 if (cmd_line->HasSwitch(switches::kEnableInbandTextTracks)) {
1046 add_text_track_cb =
1047 base::Bind(&WebMediaPlayerImpl::OnTextTrack, base::Unretained(this));
1048 }
1049
1050 scoped_ptr<WebKit::WebMediaSource> ms(media_source);
1051 chunk_demuxer_ = new media::ChunkDemuxer(
1052 BIND_TO_RENDER_LOOP_1(&WebMediaPlayerImpl::OnDemuxerOpened,
1053 base::Passed(&ms)),
1054 BIND_TO_RENDER_LOOP_1(&WebMediaPlayerImpl::OnNeedKey, ""),
1055 add_text_track_cb,
1056 base::Bind(&LogMediaSourceError, media_log_));
1057 demuxer_.reset(chunk_demuxer_);
1058
1059 // Disable GpuVideoDecoder creation until it supports codec config changes.
1060 // TODO(acolwell): Remove this once http://crbug.com/151045 is fixed.
1061 gpu_factories_ = NULL;
1062
1063 // Disable preroll increases on underflow since the web application has no
1064 // way to detect that this is happening and runs the risk of triggering
1065 // unwanted garbage collection if it is to aggressive about appending data.
1066 // TODO(acolwell): Remove this once http://crbug.com/144683 is fixed.
1067 increase_preroll_on_underflow = false;
1068 }
1069
1070 scoped_ptr<media::FilterCollection> filter_collection(
1071 new media::FilterCollection());
1072 filter_collection->SetDemuxer(demuxer_.get());
1073
1074 // Figure out if EME is enabled.
1075 media::SetDecryptorReadyCB set_decryptor_ready_cb;
1076 if (decryptor_) {
1077 set_decryptor_ready_cb = base::Bind(&ProxyDecryptor::SetDecryptorReadyCB,
1078 base::Unretained(decryptor_.get()));
1079 }
1080
1081 // Create our audio decoders and renderer.
1082 ScopedVector<media::AudioDecoder> audio_decoders;
1083 audio_decoders.push_back(new media::FFmpegAudioDecoder(media_loop_));
1084 if (cmd_line->HasSwitch(switches::kEnableOpusPlayback)) {
1085 audio_decoders.push_back(new media::OpusAudioDecoder(media_loop_));
1086 }
1087
1088 scoped_ptr<media::AudioRenderer> audio_renderer(
1089 new media::AudioRendererImpl(media_loop_,
1090 audio_source_provider_.get(),
1091 audio_decoders.Pass(),
1092 set_decryptor_ready_cb,
1093 increase_preroll_on_underflow));
1094 filter_collection->SetAudioRenderer(audio_renderer.Pass());
1095
1096 // Create our video decoders and renderer.
1097 ScopedVector<media::VideoDecoder> video_decoders;
1098
1099 if (gpu_factories_.get()) {
1100 video_decoders.push_back(new media::GpuVideoDecoder(
1101 media_loop_, gpu_factories_));
1102 }
1103
1104 // TODO(phajdan.jr): Remove ifdefs when libvpx with vp9 support is released
1105 // (http://crbug.com/174287) .
1106 #if !defined(MEDIA_DISABLE_LIBVPX)
1107 video_decoders.push_back(new media::VpxVideoDecoder(media_loop_));
1108 #endif // !defined(MEDIA_DISABLE_LIBVPX)
1109
1110 video_decoders.push_back(new media::FFmpegVideoDecoder(media_loop_));
1111
1112 scoped_ptr<media::VideoRenderer> video_renderer(
1113 new media::VideoRendererBase(
1114 media_loop_,
1115 video_decoders.Pass(),
1116 set_decryptor_ready_cb,
1117 base::Bind(&WebMediaPlayerImpl::FrameReady, base::Unretained(this)),
1118 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::SetOpaque),
1119 true));
1120 filter_collection->SetVideoRenderer(video_renderer.Pass());
1121
1122 // ... and we're ready to go!
1123 starting_ = true;
1124 pipeline_->Start(
1125 filter_collection.Pass(),
1126 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineEnded),
1127 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineError),
1128 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineSeek),
1129 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineBufferingState),
1130 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnDurationChange));
1131 }
1132
1133 void WebMediaPlayerImpl::SetNetworkState(WebMediaPlayer::NetworkState state) {
1134 DCHECK(main_loop_->BelongsToCurrentThread());
1135 DVLOG(1) << "SetNetworkState: " << state;
1136 network_state_ = state;
1137 // Always notify to ensure client has the latest value.
1138 GetClient()->networkStateChanged();
1139 }
1140
1141 void WebMediaPlayerImpl::SetReadyState(WebMediaPlayer::ReadyState state) {
1142 DCHECK(main_loop_->BelongsToCurrentThread());
1143 DVLOG(1) << "SetReadyState: " << state;
1144
1145 if (state == WebMediaPlayer::ReadyStateHaveEnoughData &&
1146 is_local_source_ &&
1147 network_state_ == WebMediaPlayer::NetworkStateLoading)
1148 SetNetworkState(WebMediaPlayer::NetworkStateLoaded);
1149
1150 ready_state_ = state;
1151 // Always notify to ensure client has the latest value.
1152 GetClient()->readyStateChanged();
1153 }
1154
1155 void WebMediaPlayerImpl::Destroy() {
1156 DCHECK(main_loop_->BelongsToCurrentThread());
1157
1158 // Abort any pending IO so stopping the pipeline doesn't get blocked.
1159 if (data_source_)
1160 data_source_->Abort();
1161 if (chunk_demuxer_) {
1162 chunk_demuxer_->Shutdown();
1163 chunk_demuxer_ = NULL;
1164 }
1165
1166 if (gpu_factories_.get()) {
1167 gpu_factories_->Abort();
1168 gpu_factories_ = NULL;
1169 }
1170
1171 // Make sure to kill the pipeline so there's no more media threads running.
1172 // Note: stopping the pipeline might block for a long time.
1173 base::WaitableEvent waiter(false, false);
1174 pipeline_->Stop(base::Bind(
1175 &base::WaitableEvent::Signal, base::Unretained(&waiter)));
1176 waiter.Wait();
1177
1178 // Let V8 know we are not using extra resources anymore.
1179 if (incremented_externally_allocated_memory_) {
1180 v8::V8::AdjustAmountOfExternalAllocatedMemory(-kPlayerExtraMemory);
1181 incremented_externally_allocated_memory_ = false;
1182 }
1183
1184 // Release any final references now that everything has stopped.
1185 pipeline_.reset();
1186 demuxer_.reset();
1187 data_source_.reset();
1188 }
1189
1190 WebKit::WebMediaPlayerClient* WebMediaPlayerImpl::GetClient() {
1191 DCHECK(main_loop_->BelongsToCurrentThread());
1192 DCHECK(client_);
1193 return client_;
1194 }
1195
1196 WebKit::WebAudioSourceProvider* WebMediaPlayerImpl::audioSourceProvider() {
1197 return audio_source_provider_.get();
1198 }
1199
1200 void WebMediaPlayerImpl::IncrementExternallyAllocatedMemory() {
1201 DCHECK(main_loop_->BelongsToCurrentThread());
1202 incremented_externally_allocated_memory_ = true;
1203 v8::V8::AdjustAmountOfExternalAllocatedMemory(kPlayerExtraMemory);
1204 }
1205
1206 double WebMediaPlayerImpl::GetPipelineDuration() const {
1207 base::TimeDelta duration = pipeline_->GetMediaDuration();
1208
1209 // Return positive infinity if the resource is unbounded.
1210 // http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html#dom- media-duration
1211 if (duration == media::kInfiniteDuration())
1212 return std::numeric_limits<double>::infinity();
1213
1214 return duration.InSecondsF();
1215 }
1216
1217 void WebMediaPlayerImpl::OnDurationChange() {
1218 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing)
1219 return;
1220
1221 GetClient()->durationChanged();
1222 }
1223
1224 void WebMediaPlayerImpl::FrameReady(
1225 const scoped_refptr<media::VideoFrame>& frame) {
1226 base::AutoLock auto_lock(lock_);
1227
1228 if (current_frame_.get() &&
1229 current_frame_->natural_size() != frame->natural_size() &&
1230 !pending_size_change_) {
1231 pending_size_change_ = true;
1232 }
1233
1234 current_frame_ = frame;
1235
1236 if (pending_repaint_)
1237 return;
1238
1239 pending_repaint_ = true;
1240 main_loop_->PostTask(FROM_HERE, base::Bind(
1241 &WebMediaPlayerImpl::Repaint, AsWeakPtr()));
1242 }
1243
1244 } // namespace webkit_media
OLDNEW
« no previous file with comments | « webkit/renderer/media/webmediaplayer_impl.h ('k') | webkit/renderer/media/webmediaplayer_ms.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698