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