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 61 using WebKit::WebCanvas; 62 using WebKit::WebMediaPlayer; 63 using WebKit::WebRect; 64 using WebKit::WebSize; 65 using WebKit::WebString; 66 using media::PipelineStatus; 67 68 namespace { 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...) 78 const 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. 96 const double kMinRate = 0.0625; 97 const double kMaxRate = 16.0; 98 99 // Prefix for histograms related to Encrypted Media Extensions. 100 const char* kMediaEme = "Media.EME."; 101 102 } // namespace 103 104 namespace 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) 110 COMPILE_ASSERT_MATCHING_ENUM(Unspecified); 111 COMPILE_ASSERT_MATCHING_ENUM(Anonymous); 112 COMPILE_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 124 static void LogMediaSourceError(const scoped_refptr<media::MediaLog>& media_log, 125 const std::string& error) { 126 media_log->AddEvent(media_log->CreateMediaSourceErrorEvent(error)); 127 } 128 129 WebMediaPlayerImpl::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 196 WebMediaPlayerImpl::~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 215 namespace { 216 217 // Helper enum for reporting scheme histograms. 218 enum 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 233 URLSchemeForHistogram 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 249 void WebMediaPlayerImpl::load(const WebKit::WebURL& url, CORSMode cors_mode) { 250 load(url, NULL, cors_mode); 251 } 252 253 void 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 265 void 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 306 void 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 318 void 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 331 bool WebMediaPlayerImpl::supportsFullscreen() const { 332 DCHECK(main_loop_->BelongsToCurrentThread()); 333 return true; 334 } 335 336 bool WebMediaPlayerImpl::supportsSave() const { 337 DCHECK(main_loop_->BelongsToCurrentThread()); 338 return supports_save_; 339 } 340 341 void 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 371 void 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 393 void 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) 403 COMPILE_ASSERT_MATCHING_ENUM(PreloadNone, NONE); 404 COMPILE_ASSERT_MATCHING_ENUM(PreloadMetaData, METADATA); 405 COMPILE_ASSERT_MATCHING_ENUM(PreloadAuto, AUTO); 406 #undef COMPILE_ASSERT_MATCHING_ENUM 407 408 void 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 415 bool WebMediaPlayerImpl::hasVideo() const { 416 DCHECK(main_loop_->BelongsToCurrentThread()); 417 418 return pipeline_->HasVideo(); 419 } 420 421 bool WebMediaPlayerImpl::hasAudio() const { 422 DCHECK(main_loop_->BelongsToCurrentThread()); 423 424 return pipeline_->HasAudio(); 425 } 426 427 WebKit::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 435 bool WebMediaPlayerImpl::paused() const { 436 DCHECK(main_loop_->BelongsToCurrentThread()); 437 438 return pipeline_->GetPlaybackRate() == 0.0f; 439 } 440 441 bool WebMediaPlayerImpl::seeking() const { 442 DCHECK(main_loop_->BelongsToCurrentThread()); 443 444 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing) 445 return false; 446 447 return seeking_; 448 } 449 450 double 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 459 double WebMediaPlayerImpl::currentTime() const { 460 DCHECK(main_loop_->BelongsToCurrentThread()); 461 return (paused_ ? paused_time_ : pipeline_->GetMediaTime()).InSecondsF(); 462 } 463 464 WebMediaPlayer::NetworkState WebMediaPlayerImpl::networkState() const { 465 DCHECK(main_loop_->BelongsToCurrentThread()); 466 return network_state_; 467 } 468 469 WebMediaPlayer::ReadyState WebMediaPlayerImpl::readyState() const { 470 DCHECK(main_loop_->BelongsToCurrentThread()); 471 return ready_state_; 472 } 473 474 const 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 482 double 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 496 bool WebMediaPlayerImpl::didLoadingProgress() const { 497 DCHECK(main_loop_->BelongsToCurrentThread()); 498 return pipeline_->DidLoadingProgress(); 499 } 500 501 void 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 527 bool WebMediaPlayerImpl::hasSingleSecurityOrigin() const { 528 if (data_source_) 529 return data_source_->HasSingleOrigin(); 530 return true; 531 } 532 533 bool WebMediaPlayerImpl::didPassCORSAccessCheck() const { 534 if (data_source_) 535 return data_source_->DidPassCORSAccessCheck(); 536 return false; 537 } 538 539 double WebMediaPlayerImpl::mediaTimeForTimeValue(double timeValue) const { 540 return ConvertSecondsToTimestamp(timeValue).InSecondsF(); 541 } 542 543 unsigned WebMediaPlayerImpl::decodedFrameCount() const { 544 DCHECK(main_loop_->BelongsToCurrentThread()); 545 546 media::PipelineStatistics stats = pipeline_->GetStatistics(); 547 return stats.video_frames_decoded; 548 } 549 550 unsigned WebMediaPlayerImpl::droppedFrameCount() const { 551 DCHECK(main_loop_->BelongsToCurrentThread()); 552 553 media::PipelineStatistics stats = pipeline_->GetStatistics(); 554 return stats.video_frames_dropped; 555 } 556 557 unsigned WebMediaPlayerImpl::audioDecodedByteCount() const { 558 DCHECK(main_loop_->BelongsToCurrentThread()); 559 560 media::PipelineStatistics stats = pipeline_->GetStatistics(); 561 return stats.audio_bytes_decoded; 562 } 563 564 unsigned WebMediaPlayerImpl::videoDecodedByteCount() const { 565 DCHECK(main_loop_->BelongsToCurrentThread()); 566 567 media::PipelineStatistics stats = pipeline_->GetStatistics(); 568 return stats.video_bytes_decoded; 569 } 570 571 void 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 580 scoped_refptr<media::VideoFrame> WebMediaPlayerImpl::GetCurrentFrame() { 581 base::AutoLock auto_lock(lock_); 582 return current_frame_; 583 } 584 585 void 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 594 bool 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. 657 static 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 667 static 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. 677 enum MediaKeyException { 678 kUnknownResultId, 679 kSuccess, 680 kKeySystemNotSupported, 681 kInvalidPlayerState, 682 kMaxMediaKeyException 683 }; 684 685 static 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. 701 static 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 711 WebMediaPlayer::MediaKeyException 712 WebMediaPlayerImpl::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 721 WebMediaPlayer::MediaKeyException 722 WebMediaPlayerImpl::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 755 WebMediaPlayer::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 768 WebMediaPlayer::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 796 WebMediaPlayer::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 805 WebMediaPlayer::MediaKeyException 806 WebMediaPlayerImpl::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 819 void WebMediaPlayerImpl::WillDestroyCurrentMessageLoop() { 820 Destroy(); 821 } 822 823 void 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 839 void 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 861 void WebMediaPlayerImpl::OnPipelineEnded() { 862 DCHECK(main_loop_->BelongsToCurrentThread()); 863 GetClient()->timeChanged(); 864 } 865 866 void 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 887 void 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 915 void 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 922 void 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 929 void 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 951 scoped_ptr<media::TextTrack> 952 WebMediaPlayerImpl::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 968 void 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 983 void 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 999 void WebMediaPlayerImpl::SetOpaque(bool opaque) { 1000 DCHECK(main_loop_->BelongsToCurrentThread()); 1001 1002 GetClient()->setOpaque(opaque); 1003 } 1004 1005 void 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 1017 void 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 1028 void 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 1139 void 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 1147 void 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 1161 void 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 1196 WebKit::WebMediaPlayerClient* WebMediaPlayerImpl::GetClient() { 1197 DCHECK(main_loop_->BelongsToCurrentThread()); 1198 DCHECK(client_); 1199 return client_; 1200 } 1201 1202 WebKit::WebAudioSourceProvider* WebMediaPlayerImpl::audioSourceProvider() { 1203 return audio_source_provider_.get(); 1204 } 1205 1206 void WebMediaPlayerImpl::IncrementExternallyAllocatedMemory() { 1207 DCHECK(main_loop_->BelongsToCurrentThread()); 1208 incremented_externally_allocated_memory_ = true; 1209 v8::V8::AdjustAmountOfExternalAllocatedMemory(kPlayerExtraMemory); 1210 } 1211 1212 double 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 1223 void WebMediaPlayerImpl::OnDurationChange() { 1224 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing) 1225 return; 1226 1227 GetClient()->durationChanged(); 1228 } 1229 1230 void 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