| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/blink/webmediaplayer_impl.h" | 5 #include "media/blink/webmediaplayer_impl.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <cmath> | 8 #include <cmath> |
| 9 #include <limits> | 9 #include <limits> |
| 10 #include <string> | 10 #include <string> |
| 11 #include <utility> | 11 #include <utility> |
| 12 | 12 |
| 13 #include "base/bind.h" | 13 #include "base/bind.h" |
| 14 #include "base/bind_helpers.h" | |
| 15 #include "base/callback.h" | 14 #include "base/callback.h" |
| 16 #include "base/callback_helpers.h" | 15 #include "base/callback_helpers.h" |
| 17 #include "base/command_line.h" | 16 #include "base/command_line.h" |
| 18 #include "base/debug/alias.h" | 17 #include "base/debug/alias.h" |
| 19 #include "base/debug/crash_logging.h" | 18 #include "base/debug/crash_logging.h" |
| 20 #include "base/metrics/histogram.h" | 19 #include "base/metrics/histogram.h" |
| 21 #include "base/single_thread_task_runner.h" | 20 #include "base/single_thread_task_runner.h" |
| 22 #include "base/synchronization/waitable_event.h" | 21 #include "base/synchronization/waitable_event.h" |
| 23 #include "base/task_runner_util.h" | 22 #include "base/task_runner_util.h" |
| 24 #include "base/thread_task_runner_handle.h" | 23 #include "base/thread_task_runner_handle.h" |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 137 network_state_(WebMediaPlayer::NetworkStateEmpty), | 136 network_state_(WebMediaPlayer::NetworkStateEmpty), |
| 138 ready_state_(WebMediaPlayer::ReadyStateHaveNothing), | 137 ready_state_(WebMediaPlayer::ReadyStateHaveNothing), |
| 139 preload_(BufferedDataSource::AUTO), | 138 preload_(BufferedDataSource::AUTO), |
| 140 buffering_strategy_( | 139 buffering_strategy_( |
| 141 BufferedDataSourceInterface::BUFFERING_STRATEGY_NORMAL), | 140 BufferedDataSourceInterface::BUFFERING_STRATEGY_NORMAL), |
| 142 main_task_runner_(base::ThreadTaskRunnerHandle::Get()), | 141 main_task_runner_(base::ThreadTaskRunnerHandle::Get()), |
| 143 media_task_runner_(params.media_task_runner()), | 142 media_task_runner_(params.media_task_runner()), |
| 144 worker_task_runner_(params.worker_task_runner()), | 143 worker_task_runner_(params.worker_task_runner()), |
| 145 media_log_(params.media_log()), | 144 media_log_(params.media_log()), |
| 146 pipeline_(media_task_runner_, media_log_.get()), | 145 pipeline_(media_task_runner_, media_log_.get()), |
| 147 pipeline_controller_( | |
| 148 &pipeline_, | |
| 149 base::Bind(&WebMediaPlayerImpl::CreateRenderer, | |
| 150 base::Unretained(this)), | |
| 151 base::Bind(&WebMediaPlayerImpl::OnPipelineSeeked, AsWeakPtr()), | |
| 152 base::Bind(&WebMediaPlayerImpl::OnPipelineSuspended, AsWeakPtr()), | |
| 153 base::Bind(&WebMediaPlayerImpl::OnPipelineResumed, AsWeakPtr()), | |
| 154 base::Bind(&WebMediaPlayerImpl::OnPipelineError, AsWeakPtr())), | |
| 155 load_type_(LoadTypeURL), | 146 load_type_(LoadTypeURL), |
| 156 opaque_(false), | 147 opaque_(false), |
| 157 playback_rate_(0.0), | 148 playback_rate_(0.0), |
| 158 paused_(true), | 149 paused_(true), |
| 159 seeking_(false), | 150 seeking_(false), |
| 151 pending_suspend_(false), |
| 152 pending_time_change_(false), |
| 153 pending_resume_(false), |
| 154 suspending_(false), |
| 155 suspended_(false), |
| 156 resuming_(false), |
| 160 pending_suspend_resume_cycle_(false), | 157 pending_suspend_resume_cycle_(false), |
| 161 ended_(false), | 158 ended_(false), |
| 159 pending_seek_(false), |
| 160 should_notify_time_changed_(false), |
| 162 fullscreen_(false), | 161 fullscreen_(false), |
| 163 decoder_requires_restart_for_fullscreen_(false), | 162 decoder_requires_restart_for_fullscreen_(false), |
| 164 client_(client), | 163 client_(client), |
| 165 encrypted_client_(encrypted_client), | 164 encrypted_client_(encrypted_client), |
| 166 delegate_(delegate), | 165 delegate_(delegate), |
| 167 delegate_id_(0), | 166 delegate_id_(0), |
| 168 defer_load_cb_(params.defer_load_cb()), | 167 defer_load_cb_(params.defer_load_cb()), |
| 169 context_3d_cb_(params.context_3d_cb()), | 168 context_3d_cb_(params.context_3d_cb()), |
| 170 adjust_allocated_memory_cb_(params.adjust_allocated_memory_cb()), | 169 adjust_allocated_memory_cb_(params.adjust_allocated_memory_cb()), |
| 171 last_reported_memory_usage_(0), | 170 last_reported_memory_usage_(0), |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 224 delegate_->PlayerGone(delegate_id_); | 223 delegate_->PlayerGone(delegate_id_); |
| 225 delegate_->RemoveObserver(delegate_id_); | 224 delegate_->RemoveObserver(delegate_id_); |
| 226 } | 225 } |
| 227 | 226 |
| 228 // Abort any pending IO so stopping the pipeline doesn't get blocked. | 227 // Abort any pending IO so stopping the pipeline doesn't get blocked. |
| 229 suppress_destruction_errors_ = true; | 228 suppress_destruction_errors_ = true; |
| 230 if (data_source_) | 229 if (data_source_) |
| 231 data_source_->Abort(); | 230 data_source_->Abort(); |
| 232 if (chunk_demuxer_) { | 231 if (chunk_demuxer_) { |
| 233 chunk_demuxer_->Shutdown(); | 232 chunk_demuxer_->Shutdown(); |
| 234 chunk_demuxer_ = nullptr; | 233 chunk_demuxer_ = NULL; |
| 235 } | 234 } |
| 236 | 235 |
| 237 renderer_factory_.reset(); | 236 renderer_factory_.reset(); |
| 238 | 237 |
| 239 // Make sure to kill the pipeline so there's no more media threads running. | 238 // Make sure to kill the pipeline so there's no more media threads running. |
| 240 // Note: stopping the pipeline might block for a long time. | 239 // Note: stopping the pipeline might block for a long time. |
| 241 base::WaitableEvent waiter(false, false); | 240 base::WaitableEvent waiter(false, false); |
| 242 pipeline_.Stop( | 241 pipeline_.Stop( |
| 243 base::Bind(&base::WaitableEvent::Signal, base::Unretained(&waiter))); | 242 base::Bind(&base::WaitableEvent::Signal, base::Unretained(&waiter))); |
| 244 waiter.Wait(); | 243 waiter.Wait(); |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 336 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 335 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 337 | 336 |
| 338 #if defined(OS_ANDROID) // WMPI_CAST | 337 #if defined(OS_ANDROID) // WMPI_CAST |
| 339 if (isRemote()) { | 338 if (isRemote()) { |
| 340 cast_impl_.play(); | 339 cast_impl_.play(); |
| 341 return; | 340 return; |
| 342 } | 341 } |
| 343 #endif | 342 #endif |
| 344 | 343 |
| 345 paused_ = false; | 344 paused_ = false; |
| 345 |
| 346 pipeline_.SetPlaybackRate(playback_rate_); | 346 pipeline_.SetPlaybackRate(playback_rate_); |
| 347 | |
| 348 if (data_source_) | 347 if (data_source_) |
| 349 data_source_->MediaIsPlaying(); | 348 data_source_->MediaIsPlaying(); |
| 350 | 349 |
| 351 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PLAY)); | 350 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PLAY)); |
| 352 | 351 |
| 353 if (playback_rate_ > 0) { | 352 if (playback_rate_ > 0) { |
| 353 // Resume the player if playback was initiated in the foreground. |
| 354 if (suspended_ && !resuming_ && delegate_ && !delegate_->IsHidden()) { |
| 355 ScheduleResume(); |
| 356 return; |
| 357 } |
| 358 |
| 354 NotifyPlaybackStarted(); | 359 NotifyPlaybackStarted(); |
| 355 | |
| 356 // Resume the player if playback was initiated in the foreground. Resume() | |
| 357 // will do nothing if the pipeline is not suspended state, but will clear | |
| 358 // some internal pending state, so it should always be called. | |
| 359 if (delegate_ && !delegate_->IsHidden()) | |
| 360 pipeline_controller_.Resume(); | |
| 361 } | 360 } |
| 362 } | 361 } |
| 363 | 362 |
| 364 void WebMediaPlayerImpl::pause() { | 363 void WebMediaPlayerImpl::pause() { |
| 365 DVLOG(1) << __FUNCTION__; | 364 DVLOG(1) << __FUNCTION__; |
| 366 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 365 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 367 | 366 |
| 368 const bool was_already_paused = paused_ || playback_rate_ == 0; | 367 const bool was_already_paused = paused_ || playback_rate_ == 0; |
| 369 paused_ = true; | 368 paused_ = true; |
| 370 | 369 |
| 371 #if defined(OS_ANDROID) // WMPI_CAST | 370 #if defined(OS_ANDROID) // WMPI_CAST |
| 372 if (isRemote()) { | 371 if (isRemote()) { |
| 373 cast_impl_.pause(); | 372 cast_impl_.pause(); |
| 374 return; | 373 return; |
| 375 } | 374 } |
| 376 #endif | 375 #endif |
| 377 | 376 |
| 378 pipeline_.SetPlaybackRate(0.0); | 377 pipeline_.SetPlaybackRate(0.0); |
| 379 | 378 UpdatePausedTime(); |
| 380 // pause() may be called after playback has ended and the HTMLMediaElement | |
| 381 // requires that currentTime() == duration() after ending. We want to ensure | |
| 382 // |paused_time_| matches currentTime() in this case or a future seek() may | |
| 383 // incorrectly discard what it thinks is a seek to the existing time. | |
| 384 paused_time_ = | |
| 385 ended_ ? pipeline_.GetMediaDuration() : pipeline_.GetMediaTime(); | |
| 386 | 379 |
| 387 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PAUSE)); | 380 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PAUSE)); |
| 388 | 381 |
| 389 if (!was_already_paused) | 382 if (!was_already_paused) |
| 390 NotifyPlaybackPaused(); | 383 NotifyPlaybackPaused(); |
| 391 } | 384 } |
| 392 | 385 |
| 393 bool WebMediaPlayerImpl::supportsSave() const { | 386 bool WebMediaPlayerImpl::supportsSave() const { |
| 394 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 387 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 395 return supports_save_; | 388 return supports_save_; |
| 396 } | 389 } |
| 397 | 390 |
| 398 void WebMediaPlayerImpl::seek(double seconds) { | 391 void WebMediaPlayerImpl::seek(double seconds) { |
| 399 DVLOG(1) << __FUNCTION__ << "(" << seconds << "s)"; | 392 DVLOG(1) << __FUNCTION__ << "(" << seconds << "s)"; |
| 400 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 393 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 401 DoSeek(base::TimeDelta::FromSecondsD(seconds), true); | |
| 402 } | |
| 403 | |
| 404 void WebMediaPlayerImpl::DoSeek(base::TimeDelta time, bool time_updated) { | |
| 405 DCHECK(main_task_runner_->BelongsToCurrentThread()); | |
| 406 | 394 |
| 407 ended_ = false; | 395 ended_ = false; |
| 408 | 396 |
| 397 base::TimeDelta new_seek_time = base::TimeDelta::FromSecondsD(seconds); |
| 398 |
| 409 #if defined(OS_ANDROID) // WMPI_CAST | 399 #if defined(OS_ANDROID) // WMPI_CAST |
| 410 if (isRemote()) { | 400 if (isRemote()) { |
| 411 cast_impl_.seek(time); | 401 cast_impl_.seek(new_seek_time); |
| 412 return; | 402 return; |
| 413 } | 403 } |
| 414 #endif | 404 #endif |
| 415 | 405 |
| 416 ReadyState old_state = ready_state_; | 406 ReadyState old_state = ready_state_; |
| 417 if (ready_state_ > WebMediaPlayer::ReadyStateHaveMetadata) | 407 if (ready_state_ > WebMediaPlayer::ReadyStateHaveMetadata) |
| 418 SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata); | 408 SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata); |
| 419 | 409 |
| 420 // When paused, we know exactly what the current time is and can elide seeks | 410 if (seeking_ || suspended_) { |
| 421 // to it. However, there are two cases that are not elided: | 411 // Once resuming, it's too late to change the resume time and so the |
| 422 // 1) When the pipeline state is not stable. | 412 // implementation is a little different. |
| 423 // In this case we just let |pipeline_controller_| decide what to do, as | 413 bool is_suspended = suspended_ && !resuming_; |
| 424 // it has complete information. | 414 |
| 425 // 2) For MSE. | 415 // If we are currently seeking or resuming to |new_seek_time|, skip the |
| 426 // Because the buffers may have changed between seeks, MSE seeks are | 416 // seek (except for MSE, which always seeks). |
| 427 // never elided. | 417 if (!is_suspended && new_seek_time == seek_time_) { |
| 428 if (paused_ && pipeline_controller_.IsStable() && paused_time_ == time && | 418 if (chunk_demuxer_) { |
| 429 !chunk_demuxer_) { | 419 // Don't suppress any redundant in-progress MSE seek. There could have |
| 430 // If the ready state was high enough before, we can indicate that the seek | 420 // been changes to the underlying buffers after seeking the demuxer and |
| 431 // completed just by restoring it. Otherwise we will just wait for the real | 421 // before receiving OnPipelineSeeked() for the currently in-progress |
| 432 // ready state change to eventually happen. | 422 // seek. |
| 433 if (old_state == ReadyStateHaveEnoughData) { | 423 MEDIA_LOG(DEBUG, media_log_) |
| 424 << "Detected MediaSource seek to same time as in-progress seek to " |
| 425 << seek_time_ << "."; |
| 426 } else { |
| 427 // Suppress all redundant seeks if unrestricted by media source demuxer |
| 428 // API. |
| 429 pending_seek_ = false; |
| 430 pending_seek_time_ = base::TimeDelta(); |
| 431 return; |
| 432 } |
| 433 } |
| 434 |
| 435 // If |chunk_demuxer_| is already seeking, cancel that seek and schedule the |
| 436 // new one. |
| 437 if (!is_suspended && chunk_demuxer_) |
| 438 chunk_demuxer_->CancelPendingSeek(new_seek_time); |
| 439 |
| 440 // Schedule a seek once the current suspend or seek finishes. |
| 441 pending_seek_ = true; |
| 442 pending_seek_time_ = new_seek_time; |
| 443 |
| 444 // In the case of seeking while suspended, the seek is considered to have |
| 445 // started immediately (but won't complete until the pipeline is resumed). |
| 446 if (is_suspended) { |
| 447 seeking_ = true; |
| 448 seek_time_ = new_seek_time; |
| 449 |
| 450 // Resume the pipeline if the seek is initiated in the foreground so that |
| 451 // the correct frame is displayed. |
| 452 if (delegate_ && !delegate_->IsHidden()) |
| 453 ScheduleResume(); |
| 454 } |
| 455 |
| 456 return; |
| 457 } |
| 458 |
| 459 media_log_->AddEvent(media_log_->CreateSeekEvent(seconds)); |
| 460 |
| 461 // Update our paused time. |
| 462 // For non-MSE playbacks, in paused state ignore the seek operations to |
| 463 // current time if the loading is completed and generate |
| 464 // OnPipelineBufferingStateChanged event to eventually fire seeking and seeked |
| 465 // events. We don't short-circuit MSE seeks in this logic because the |
| 466 // underlying buffers around the seek time might have changed (or even been |
| 467 // removed) since previous seek/preroll/pause action, and the pipeline might |
| 468 // need to flush so the new buffers are decoded and rendered instead of the |
| 469 // old ones. |
| 470 if (paused_) { |
| 471 if (paused_time_ != new_seek_time || chunk_demuxer_) { |
| 472 paused_time_ = new_seek_time; |
| 473 } else if (old_state == ReadyStateHaveEnoughData) { |
| 434 main_task_runner_->PostTask( | 474 main_task_runner_->PostTask( |
| 435 FROM_HERE, | 475 FROM_HERE, |
| 436 base::Bind(&WebMediaPlayerImpl::OnPipelineBufferingStateChanged, | 476 base::Bind(&WebMediaPlayerImpl::OnPipelineBufferingStateChanged, |
| 437 AsWeakPtr(), BUFFERING_HAVE_ENOUGH)); | 477 AsWeakPtr(), BUFFERING_HAVE_ENOUGH)); |
| 478 return; |
| 438 } | 479 } |
| 439 return; | |
| 440 } | 480 } |
| 441 | 481 |
| 442 seeking_ = true; | 482 seeking_ = true; |
| 443 seek_time_ = time; | 483 seek_time_ = new_seek_time; |
| 444 if (paused_) | |
| 445 paused_time_ = time; | |
| 446 pipeline_controller_.Seek(time, time_updated); | |
| 447 | 484 |
| 448 // Resume the pipeline if the seek is initiated in the foreground so that | 485 if (chunk_demuxer_) |
| 449 // the correct frame is displayed. If the pipeline is not suspended, Resume() | 486 chunk_demuxer_->StartWaitingForSeek(seek_time_); |
| 450 // will do nothing but clear some pending state. | 487 |
| 451 if (delegate_ && !delegate_->IsHidden()) | 488 pipeline_.Seek(seek_time_, BIND_TO_RENDER_LOOP1( |
| 452 pipeline_controller_.Resume(); | 489 &WebMediaPlayerImpl::OnPipelineSeeked, true)); |
| 453 } | 490 } |
| 454 | 491 |
| 455 void WebMediaPlayerImpl::setRate(double rate) { | 492 void WebMediaPlayerImpl::setRate(double rate) { |
| 456 DVLOG(1) << __FUNCTION__ << "(" << rate << ")"; | 493 DVLOG(1) << __FUNCTION__ << "(" << rate << ")"; |
| 457 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 494 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 458 | 495 |
| 459 // TODO(kylep): Remove when support for negatives is added. Also, modify the | 496 // TODO(kylep): Remove when support for negatives is added. Also, modify the |
| 460 // following checks so rewind uses reasonable values also. | 497 // following checks so rewind uses reasonable values also. |
| 461 if (rate < 0.0) | 498 if (rate < 0.0) |
| 462 return; | 499 return; |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 591 | 628 |
| 592 double WebMediaPlayerImpl::currentTime() const { | 629 double WebMediaPlayerImpl::currentTime() const { |
| 593 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 630 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 594 DCHECK_NE(ready_state_, WebMediaPlayer::ReadyStateHaveNothing); | 631 DCHECK_NE(ready_state_, WebMediaPlayer::ReadyStateHaveNothing); |
| 595 | 632 |
| 596 // TODO(scherkus): Replace with an explicit ended signal to HTMLMediaElement, | 633 // TODO(scherkus): Replace with an explicit ended signal to HTMLMediaElement, |
| 597 // see http://crbug.com/409280 | 634 // see http://crbug.com/409280 |
| 598 if (ended_) | 635 if (ended_) |
| 599 return duration(); | 636 return duration(); |
| 600 | 637 |
| 601 if (seeking()) | 638 // We know the current seek time better than pipeline: pipeline may processing |
| 602 return seek_time_.InSecondsF(); | 639 // an earlier seek before a pending seek has been started, or it might not yet |
| 640 // have the current seek time returnable via GetMediaTime(). |
| 641 if (seeking()) { |
| 642 return pending_seek_ ? pending_seek_time_.InSecondsF() |
| 643 : seek_time_.InSecondsF(); |
| 644 } |
| 603 | 645 |
| 604 #if defined(OS_ANDROID) // WMPI_CAST | 646 #if defined(OS_ANDROID) // WMPI_CAST |
| 605 if (isRemote()) | 647 if (isRemote()) { |
| 606 return cast_impl_.currentTime(); | 648 return cast_impl_.currentTime(); |
| 649 } |
| 607 #endif | 650 #endif |
| 608 | 651 |
| 609 if (paused_) | 652 if (paused_) { |
| 610 return paused_time_.InSecondsF(); | 653 return paused_time_.InSecondsF(); |
| 654 } |
| 611 | 655 |
| 612 return pipeline_.GetMediaTime().InSecondsF(); | 656 return pipeline_.GetMediaTime().InSecondsF(); |
| 613 } | 657 } |
| 614 | 658 |
| 615 WebMediaPlayer::NetworkState WebMediaPlayerImpl::getNetworkState() const { | 659 WebMediaPlayer::NetworkState WebMediaPlayerImpl::getNetworkState() const { |
| 616 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 660 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 617 return network_state_; | 661 return network_state_; |
| 618 } | 662 } |
| 619 | 663 |
| 620 WebMediaPlayer::ReadyState WebMediaPlayerImpl::getReadyState() const { | 664 WebMediaPlayer::ReadyState WebMediaPlayerImpl::getReadyState() const { |
| (...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 833 is_cdm_attached_ = true; | 877 is_cdm_attached_ = true; |
| 834 return; | 878 return; |
| 835 } | 879 } |
| 836 | 880 |
| 837 set_cdm_result_->completeWithError( | 881 set_cdm_result_->completeWithError( |
| 838 blink::WebContentDecryptionModuleExceptionNotSupportedError, 0, | 882 blink::WebContentDecryptionModuleExceptionNotSupportedError, 0, |
| 839 "Unable to set MediaKeys object"); | 883 "Unable to set MediaKeys object"); |
| 840 set_cdm_result_.reset(); | 884 set_cdm_result_.reset(); |
| 841 } | 885 } |
| 842 | 886 |
| 843 void WebMediaPlayerImpl::OnPipelineSeeked(bool time_updated) { | 887 void WebMediaPlayerImpl::OnPipelineSeeked(bool time_changed, |
| 888 PipelineStatus status) { |
| 889 DVLOG(1) << __FUNCTION__ << "(" << time_changed << ", " << status << ")"; |
| 890 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 891 |
| 892 if (status != PIPELINE_OK) { |
| 893 OnPipelineError(status); |
| 894 return; |
| 895 } |
| 896 |
| 897 // Whether or not the seek was caused by a resume, we're not suspended now. |
| 898 const bool was_resuming = resuming_; |
| 899 resuming_ = false; |
| 900 suspended_ = false; |
| 901 |
| 902 // If we we're resuming into the playing state, notify the delegate. |
| 903 if (was_resuming && playback_rate_ > 0 && !paused_) |
| 904 NotifyPlaybackStarted(); |
| 905 |
| 906 // If there is a pending suspend, the seek does not complete until after the |
| 907 // next resume. |
| 908 if (pending_suspend_) { |
| 909 pending_suspend_ = false; |
| 910 pending_time_change_ = time_changed; |
| 911 Suspend(); |
| 912 return; |
| 913 } |
| 914 |
| 915 // Clear seek state. Note that if the seek was caused by a resume, then |
| 916 // |seek_time_| is always set but |seeking_| is only set if there was a |
| 917 // pending seek at the time. |
| 844 seeking_ = false; | 918 seeking_ = false; |
| 845 seek_time_ = base::TimeDelta(); | 919 seek_time_ = base::TimeDelta(); |
| 920 |
| 921 if (pending_seek_) { |
| 922 double pending_seek_seconds = pending_seek_time_.InSecondsF(); |
| 923 pending_seek_ = false; |
| 924 pending_seek_time_ = base::TimeDelta(); |
| 925 seek(pending_seek_seconds); |
| 926 return; |
| 927 } |
| 928 |
| 929 // Update our paused time. |
| 846 if (paused_) | 930 if (paused_) |
| 847 paused_time_ = pipeline_.GetMediaTime(); | 931 UpdatePausedTime(); |
| 848 if (time_updated) | 932 |
| 849 should_notify_time_changed_ = true; | 933 should_notify_time_changed_ = time_changed; |
| 850 } | 934 } |
| 851 | 935 |
| 852 void WebMediaPlayerImpl::OnPipelineSuspended() { | 936 void WebMediaPlayerImpl::OnPipelineSuspended(PipelineStatus status) { |
| 937 DVLOG(1) << __FUNCTION__ << "(" << status << ")"; |
| 938 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 939 |
| 940 if (status != PIPELINE_OK) { |
| 941 OnPipelineError(status); |
| 942 return; |
| 943 } |
| 944 |
| 945 suspending_ = false; |
| 946 if (delegate_) |
| 947 delegate_->PlayerGone(delegate_id_); |
| 948 |
| 853 #if defined(OS_ANDROID) | 949 #if defined(OS_ANDROID) |
| 854 if (isRemote()) { | 950 if (isRemote()) { |
| 855 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner(); | 951 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner(); |
| 856 if (frame) { | 952 if (frame) { |
| 857 compositor_->PaintFrameUsingOldRenderingPath(frame); | 953 compositor_->PaintFrameUsingOldRenderingPath(frame); |
| 858 } | 954 } |
| 859 } | 955 } |
| 860 #endif | 956 #endif |
| 861 | 957 |
| 862 if (delegate_) | 958 if (pending_resume_ || pending_suspend_resume_cycle_) { |
| 863 delegate_->PlayerGone(delegate_id_); | 959 pending_resume_ = false; |
| 864 | |
| 865 if (pending_suspend_resume_cycle_) { | |
| 866 pending_suspend_resume_cycle_ = false; | 960 pending_suspend_resume_cycle_ = false; |
| 867 pipeline_controller_.Resume(); | 961 Resume(); |
| 868 return; | 962 return; |
| 869 } | 963 } |
| 870 } | 964 } |
| 871 | 965 |
| 872 void WebMediaPlayerImpl::OnPipelineResumed() { | |
| 873 if (playback_rate_ > 0 && !paused_) | |
| 874 NotifyPlaybackStarted(); | |
| 875 } | |
| 876 | |
| 877 void WebMediaPlayerImpl::OnPipelineEnded() { | 966 void WebMediaPlayerImpl::OnPipelineEnded() { |
| 878 DVLOG(1) << __FUNCTION__; | 967 DVLOG(1) << __FUNCTION__; |
| 879 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 968 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 880 | 969 |
| 881 // Ignore state changes until we've completed all outstanding operations. | 970 // Ignore state changes until we've completed all outstanding seeks. |
| 882 if (!pipeline_controller_.IsStable()) | 971 if (seeking_ || pending_seek_) |
| 883 return; | 972 return; |
| 884 | 973 |
| 885 ended_ = true; | 974 ended_ = true; |
| 886 client_->timeChanged(); | 975 client_->timeChanged(); |
| 887 } | 976 } |
| 888 | 977 |
| 889 void WebMediaPlayerImpl::OnPipelineError(PipelineStatus error) { | 978 void WebMediaPlayerImpl::OnPipelineError(PipelineStatus error) { |
| 890 DVLOG(1) << __FUNCTION__; | 979 DVLOG(1) << __FUNCTION__; |
| 891 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 980 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 892 DCHECK_NE(error, PIPELINE_OK); | 981 DCHECK_NE(error, PIPELINE_OK); |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 936 // playback. | 1025 // playback. |
| 937 if (delegate_ && delegate_->IsHidden()) | 1026 if (delegate_ && delegate_->IsHidden()) |
| 938 OnHidden(false); | 1027 OnHidden(false); |
| 939 } | 1028 } |
| 940 } | 1029 } |
| 941 | 1030 |
| 942 void WebMediaPlayerImpl::OnPipelineBufferingStateChanged( | 1031 void WebMediaPlayerImpl::OnPipelineBufferingStateChanged( |
| 943 BufferingState buffering_state) { | 1032 BufferingState buffering_state) { |
| 944 DVLOG(1) << __FUNCTION__ << "(" << buffering_state << ")"; | 1033 DVLOG(1) << __FUNCTION__ << "(" << buffering_state << ")"; |
| 945 | 1034 |
| 946 // Ignore buffering state changes until we've completed all outstanding | 1035 // Ignore buffering state changes until we've completed all outstanding seeks. |
| 947 // operations. | 1036 if (seeking_ || pending_seek_) |
| 948 if (!pipeline_controller_.IsStable()) | |
| 949 return; | 1037 return; |
| 950 | 1038 |
| 951 // TODO(scherkus): Handle other buffering states when Pipeline starts using | 1039 // TODO(scherkus): Handle other buffering states when Pipeline starts using |
| 952 // them and translate them ready state changes http://crbug.com/144683 | 1040 // them and translate them ready state changes http://crbug.com/144683 |
| 953 DCHECK_EQ(buffering_state, BUFFERING_HAVE_ENOUGH); | 1041 DCHECK_EQ(buffering_state, BUFFERING_HAVE_ENOUGH); |
| 954 SetReadyState(WebMediaPlayer::ReadyStateHaveEnoughData); | 1042 SetReadyState(WebMediaPlayer::ReadyStateHaveEnoughData); |
| 955 | 1043 |
| 956 // Let the DataSource know we have enough data. It may use this information to | 1044 // Let the DataSource know we have enough data. It may use this information to |
| 957 // release unused network connections. | 1045 // release unused network connections. |
| 958 if (data_source_) | 1046 if (data_source_) |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1012 return; | 1100 return; |
| 1013 } | 1101 } |
| 1014 | 1102 |
| 1015 #if defined(OS_ANDROID) | 1103 #if defined(OS_ANDROID) |
| 1016 // If we're remote, the pipeline should already be suspended. | 1104 // If we're remote, the pipeline should already be suspended. |
| 1017 if (isRemote()) | 1105 if (isRemote()) |
| 1018 return; | 1106 return; |
| 1019 #endif | 1107 #endif |
| 1020 | 1108 |
| 1021 if (must_suspend || (paused_ && ended_) || hasVideo()) | 1109 if (must_suspend || (paused_ && ended_) || hasVideo()) |
| 1022 pipeline_controller_.Suspend(); | 1110 ScheduleSuspend(); |
| 1111 } |
| 1112 |
| 1113 void WebMediaPlayerImpl::ScheduleSuspend() { |
| 1114 if (!pipeline_.IsRunning()) |
| 1115 return; |
| 1116 |
| 1117 if (resuming_ || seeking_) { |
| 1118 pending_suspend_ = true; |
| 1119 return; |
| 1120 } |
| 1121 |
| 1122 if (pending_resume_) { |
| 1123 pending_resume_ = false; |
| 1124 return; |
| 1125 } |
| 1126 |
| 1127 Suspend(); |
| 1128 } |
| 1129 |
| 1130 void WebMediaPlayerImpl::Suspend() { |
| 1131 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 1132 |
| 1133 // Since Pipeline::IsRunning() may be set on the media thread there are cases |
| 1134 // where two suspends might be issued concurrently. |
| 1135 if (suspended_) |
| 1136 return; |
| 1137 |
| 1138 suspended_ = true; |
| 1139 suspending_ = true; |
| 1140 pipeline_.Suspend( |
| 1141 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineSuspended)); |
| 1023 } | 1142 } |
| 1024 | 1143 |
| 1025 void WebMediaPlayerImpl::OnShown() { | 1144 void WebMediaPlayerImpl::OnShown() { |
| 1026 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 1145 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 1027 | 1146 |
| 1028 #if !defined(OS_ANDROID) | 1147 #if !defined(OS_ANDROID) |
| 1029 // Suspend/Resume is enabled by default on Android. | 1148 // Suspend/Resume is enabled by default on Android. |
| 1030 if (!base::CommandLine::ForCurrentProcess()->HasSwitch( | 1149 if (!base::CommandLine::ForCurrentProcess()->HasSwitch( |
| 1031 switches::kEnableMediaSuspend)) { | 1150 switches::kEnableMediaSuspend)) { |
| 1032 return; | 1151 return; |
| 1033 } | 1152 } |
| 1034 #endif // !defined(OS_ANDROID) | 1153 #endif // !defined(OS_ANDROID) |
| 1035 | 1154 |
| 1036 if (base::CommandLine::ForCurrentProcess()->HasSwitch( | 1155 if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
| 1037 switches::kDisableMediaSuspend)) { | 1156 switches::kDisableMediaSuspend)) { |
| 1038 return; | 1157 return; |
| 1039 } | 1158 } |
| 1040 | 1159 |
| 1041 #if defined(OS_ANDROID) | 1160 #if defined(OS_ANDROID) |
| 1042 // If we're remote, the pipeline should stay suspended. | 1161 // If we're remote, the pipeline should stay suspended. |
| 1043 if (isRemote()) | 1162 if (isRemote()) |
| 1044 return; | 1163 return; |
| 1045 #endif | 1164 #endif |
| 1046 | 1165 |
| 1047 if (!ended_ && !paused_) | 1166 if (!ended_ && !paused_) |
| 1048 pipeline_controller_.Resume(); | 1167 ScheduleResume(); |
| 1168 } |
| 1169 |
| 1170 void WebMediaPlayerImpl::ScheduleResume() { |
| 1171 if (!pipeline_.IsRunning()) |
| 1172 return; |
| 1173 |
| 1174 if (suspending_) { |
| 1175 pending_resume_ = true; |
| 1176 return; |
| 1177 } |
| 1178 |
| 1179 if (pending_suspend_) { |
| 1180 pending_suspend_ = false; |
| 1181 return; |
| 1182 } |
| 1183 |
| 1184 // Might already be resuming iff we came back from remote playback recently. |
| 1185 if (suspended_ && !resuming_) |
| 1186 Resume(); |
| 1049 } | 1187 } |
| 1050 | 1188 |
| 1051 void WebMediaPlayerImpl::OnPlay() { | 1189 void WebMediaPlayerImpl::OnPlay() { |
| 1052 play(); | 1190 play(); |
| 1053 client_->playbackStateChanged(); | 1191 client_->playbackStateChanged(); |
| 1054 } | 1192 } |
| 1055 | 1193 |
| 1056 void WebMediaPlayerImpl::OnPause() { | 1194 void WebMediaPlayerImpl::OnPause() { |
| 1057 pause(); | 1195 pause(); |
| 1058 client_->playbackStateChanged(); | 1196 client_->playbackStateChanged(); |
| 1059 } | 1197 } |
| 1060 | 1198 |
| 1061 void WebMediaPlayerImpl::OnVolumeMultiplierUpdate(double multiplier) { | 1199 void WebMediaPlayerImpl::OnVolumeMultiplierUpdate(double multiplier) { |
| 1062 volume_multiplier_ = multiplier; | 1200 volume_multiplier_ = multiplier; |
| 1063 setVolume(volume_); | 1201 setVolume(volume_); |
| 1064 } | 1202 } |
| 1065 | 1203 |
| 1204 void WebMediaPlayerImpl::Resume() { |
| 1205 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 1206 CHECK(suspended_); |
| 1207 CHECK(!resuming_); |
| 1208 |
| 1209 // If there was a time change pending when we suspended (which can happen when |
| 1210 // we suspend immediately after a seek), surface it after resuming. |
| 1211 bool time_changed = pending_time_change_; |
| 1212 pending_time_change_ = false; |
| 1213 |
| 1214 if (seeking_ || pending_seek_) { |
| 1215 if (pending_seek_) { |
| 1216 seek_time_ = pending_seek_time_; |
| 1217 pending_seek_ = false; |
| 1218 pending_seek_time_ = base::TimeDelta(); |
| 1219 } |
| 1220 time_changed = true; |
| 1221 } else { |
| 1222 // It is safe to call GetCurrentFrameTimestamp() because VFC is stopped |
| 1223 // during Suspend(). It won't be started again until after Resume() is |
| 1224 // called. Use the pipeline time if there's no video. |
| 1225 if (!data_source_ || !data_source_->IsStreaming()) { |
| 1226 seek_time_ = hasVideo() ? compositor_->GetCurrentFrameTimestamp() |
| 1227 : pipeline_.GetMediaTime(); |
| 1228 } else { |
| 1229 // Resume from zero if a resource does not support range requests; this |
| 1230 // avoids a painful "read-the-whole-file" seek penalty. |
| 1231 seek_time_ = base::TimeDelta(); |
| 1232 } |
| 1233 } |
| 1234 |
| 1235 if (chunk_demuxer_) |
| 1236 chunk_demuxer_->StartWaitingForSeek(seek_time_); |
| 1237 |
| 1238 resuming_ = true; |
| 1239 pipeline_.Resume(CreateRenderer(), seek_time_, |
| 1240 BIND_TO_RENDER_LOOP1(&WebMediaPlayerImpl::OnPipelineSeeked, |
| 1241 time_changed)); |
| 1242 } |
| 1243 |
| 1066 void WebMediaPlayerImpl::ScheduleRestart() { | 1244 void WebMediaPlayerImpl::ScheduleRestart() { |
| 1067 if (!pipeline_controller_.IsSuspended()) { | 1245 // If we're suspended but not resuming there is no need to restart because |
| 1246 // there is no renderer to kill. |
| 1247 if (!suspended_ || resuming_) { |
| 1068 pending_suspend_resume_cycle_ = true; | 1248 pending_suspend_resume_cycle_ = true; |
| 1069 pipeline_controller_.Suspend(); | 1249 ScheduleSuspend(); |
| 1070 } | 1250 } |
| 1071 } | 1251 } |
| 1072 | 1252 |
| 1073 #if defined(OS_ANDROID) // WMPI_CAST | 1253 #if defined(OS_ANDROID) // WMPI_CAST |
| 1254 |
| 1074 bool WebMediaPlayerImpl::isRemote() const { | 1255 bool WebMediaPlayerImpl::isRemote() const { |
| 1075 return cast_impl_.isRemote(); | 1256 return cast_impl_.isRemote(); |
| 1076 } | 1257 } |
| 1077 | 1258 |
| 1078 void WebMediaPlayerImpl::SetMediaPlayerManager( | 1259 void WebMediaPlayerImpl::SetMediaPlayerManager( |
| 1079 RendererMediaPlayerManagerInterface* media_player_manager) { | 1260 RendererMediaPlayerManagerInterface* media_player_manager) { |
| 1080 cast_impl_.SetMediaPlayerManager(media_player_manager); | 1261 cast_impl_.SetMediaPlayerManager(media_player_manager); |
| 1081 } | 1262 } |
| 1082 | 1263 |
| 1083 void WebMediaPlayerImpl::requestRemotePlayback() { | 1264 void WebMediaPlayerImpl::requestRemotePlayback() { |
| 1084 cast_impl_.requestRemotePlayback(); | 1265 cast_impl_.requestRemotePlayback(); |
| 1085 } | 1266 } |
| 1086 | 1267 |
| 1087 void WebMediaPlayerImpl::requestRemotePlaybackControl() { | 1268 void WebMediaPlayerImpl::requestRemotePlaybackControl() { |
| 1088 cast_impl_.requestRemotePlaybackControl(); | 1269 cast_impl_.requestRemotePlaybackControl(); |
| 1089 } | 1270 } |
| 1090 | 1271 |
| 1091 void WebMediaPlayerImpl::OnRemotePlaybackEnded() { | 1272 void WebMediaPlayerImpl::OnRemotePlaybackEnded() { |
| 1092 DVLOG(1) << __FUNCTION__; | 1273 DVLOG(1) << __FUNCTION__; |
| 1093 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 1274 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 1094 | 1275 |
| 1095 ended_ = true; | 1276 ended_ = true; |
| 1096 client_->timeChanged(); | 1277 client_->timeChanged(); |
| 1097 } | 1278 } |
| 1098 | 1279 |
| 1099 void WebMediaPlayerImpl::OnDisconnectedFromRemoteDevice(double t) { | 1280 void WebMediaPlayerImpl::OnDisconnectedFromRemoteDevice(double t) { |
| 1100 DoSeek(base::TimeDelta::FromSecondsD(t), false); | 1281 paused_time_ = base::TimeDelta::FromSecondsD(t); |
| 1101 if (delegate_ && !delegate_->IsHidden()) | 1282 pending_seek_ = true; |
| 1102 pipeline_controller_.Resume(); | 1283 pending_seek_time_ = paused_time_; |
| 1103 | 1284 |
| 1285 ScheduleResume(); |
| 1286 |
| 1287 if (paused_time_ == pipeline_.GetMediaDuration()) { |
| 1288 ended_ = true; |
| 1289 } |
| 1104 // We already told the delegate we're paused when remoting started. | 1290 // We already told the delegate we're paused when remoting started. |
| 1105 client_->playbackStateChanged(); | 1291 client_->playbackStateChanged(); |
| 1106 client_->disconnectedFromRemoteDevice(); | 1292 client_->disconnectedFromRemoteDevice(); |
| 1107 } | 1293 } |
| 1108 | 1294 |
| 1109 void WebMediaPlayerImpl::SuspendForRemote() { | 1295 void WebMediaPlayerImpl::SuspendForRemote() { |
| 1110 if (!pipeline_controller_.IsSuspended()) { | 1296 if (suspended_ && !suspending_) { |
| 1111 pipeline_controller_.Suspend(); | |
| 1112 } else { | |
| 1113 // TODO(sandersd): If PipelineController::Suspend() called |suspended_cb| | |
| 1114 // when already suspended, we wouldn't need this case. | |
| 1115 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner(); | 1297 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner(); |
| 1116 if (frame) { | 1298 if (frame) { |
| 1117 compositor_->PaintFrameUsingOldRenderingPath(frame); | 1299 compositor_->PaintFrameUsingOldRenderingPath(frame); |
| 1118 } | 1300 } |
| 1119 } | 1301 } |
| 1302 ScheduleSuspend(); |
| 1120 } | 1303 } |
| 1121 | 1304 |
| 1122 gfx::Size WebMediaPlayerImpl::GetCanvasSize() const { | 1305 gfx::Size WebMediaPlayerImpl::GetCanvasSize() const { |
| 1123 if (!video_weblayer_) | 1306 if (!video_weblayer_) |
| 1124 return pipeline_metadata_.natural_size; | 1307 return pipeline_metadata_.natural_size; |
| 1125 | 1308 |
| 1126 return video_weblayer_->bounds(); | 1309 return video_weblayer_->bounds(); |
| 1127 } | 1310 } |
| 1128 | 1311 |
| 1129 void WebMediaPlayerImpl::SetDeviceScaleFactor(float scale_factor) { | 1312 void WebMediaPlayerImpl::SetDeviceScaleFactor(float scale_factor) { |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1220 chunk_demuxer_ = new ChunkDemuxer( | 1403 chunk_demuxer_ = new ChunkDemuxer( |
| 1221 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnDemuxerOpened), | 1404 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnDemuxerOpened), |
| 1222 encrypted_media_init_data_cb, media_log_, true); | 1405 encrypted_media_init_data_cb, media_log_, true); |
| 1223 demuxer_.reset(chunk_demuxer_); | 1406 demuxer_.reset(chunk_demuxer_); |
| 1224 } | 1407 } |
| 1225 | 1408 |
| 1226 // ... and we're ready to go! | 1409 // ... and we're ready to go! |
| 1227 seeking_ = true; | 1410 seeking_ = true; |
| 1228 | 1411 |
| 1229 // TODO(sandersd): On Android, defer Start() if the tab is not visible. | 1412 // TODO(sandersd): On Android, defer Start() if the tab is not visible. |
| 1230 bool is_streaming = (data_source_ && data_source_->IsStreaming()); | 1413 pipeline_.Start( |
| 1231 pipeline_controller_.Start( | 1414 demuxer_.get(), CreateRenderer(), |
| 1232 chunk_demuxer_, demuxer_.get(), is_streaming, | |
| 1233 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineEnded), | 1415 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineEnded), |
| 1416 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineError), |
| 1417 BIND_TO_RENDER_LOOP1(&WebMediaPlayerImpl::OnPipelineSeeked, false), |
| 1234 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineMetadata), | 1418 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineMetadata), |
| 1235 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineBufferingStateChanged), | 1419 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineBufferingStateChanged), |
| 1236 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnDurationChanged), | 1420 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnDurationChanged), |
| 1237 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnAddTextTrack), | 1421 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnAddTextTrack), |
| 1238 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnWaitingForDecryptionKey)); | 1422 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnWaitingForDecryptionKey)); |
| 1239 } | 1423 } |
| 1240 | 1424 |
| 1241 void WebMediaPlayerImpl::SetNetworkState(WebMediaPlayer::NetworkState state) { | 1425 void WebMediaPlayerImpl::SetNetworkState(WebMediaPlayer::NetworkState state) { |
| 1242 DVLOG(1) << __FUNCTION__ << "(" << state << ")"; | 1426 DVLOG(1) << __FUNCTION__ << "(" << state << ")"; |
| 1243 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 1427 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1331 base::WaitableEvent event(false, false); | 1515 base::WaitableEvent event(false, false); |
| 1332 compositor_task_runner_->PostTask(FROM_HERE, | 1516 compositor_task_runner_->PostTask(FROM_HERE, |
| 1333 base::Bind(&GetCurrentFrameAndSignal, | 1517 base::Bind(&GetCurrentFrameAndSignal, |
| 1334 base::Unretained(compositor_), | 1518 base::Unretained(compositor_), |
| 1335 &video_frame, | 1519 &video_frame, |
| 1336 &event)); | 1520 &event)); |
| 1337 event.Wait(); | 1521 event.Wait(); |
| 1338 return video_frame; | 1522 return video_frame; |
| 1339 } | 1523 } |
| 1340 | 1524 |
| 1525 void WebMediaPlayerImpl::UpdatePausedTime() { |
| 1526 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 1527 |
| 1528 // pause() may be called after playback has ended and the HTMLMediaElement |
| 1529 // requires that currentTime() == duration() after ending. We want to ensure |
| 1530 // |paused_time_| matches currentTime() in this case or a future seek() may |
| 1531 // incorrectly discard what it thinks is a seek to the existing time. |
| 1532 paused_time_ = |
| 1533 ended_ ? pipeline_.GetMediaDuration() : pipeline_.GetMediaTime(); |
| 1534 } |
| 1535 |
| 1341 void WebMediaPlayerImpl::NotifyPlaybackStarted() { | 1536 void WebMediaPlayerImpl::NotifyPlaybackStarted() { |
| 1342 #if defined(OS_ANDROID) // WMPI_CAST | 1537 #if defined(OS_ANDROID) // WMPI_CAST |
| 1343 // We do not tell our delegates about remote playback, because that would | 1538 // We do not tell our delegates about remote playback, because that would |
| 1344 // keep the device awake, which is not what we want. | 1539 // keep the device awake, which is not what we want. |
| 1345 if (isRemote()) | 1540 if (isRemote()) |
| 1346 return; | 1541 return; |
| 1347 #endif | 1542 #endif |
| 1348 | 1543 |
| 1349 // NotifyPlaybackStarted() may be called by interactions while suspended, | 1544 // Don't send delegate notifications when suspended; upon suspend we send |
| 1350 // (play/pause in particular). Those actions won't have any effect until the | 1545 // PlayerGone() to the delegate -- no more notifications should be sent until |
| 1351 // pipeline is resumed. | 1546 // after resume. |
| 1352 // TODO(dalecurtis): Should these be dropped at the call sites instead? | 1547 if (suspended_) |
| 1353 // Alternatively, rename this method to include Maybe or Changed, and handle | |
| 1354 // multiple calls safely. | |
| 1355 if (pipeline_controller_.IsSuspended()) | |
| 1356 return; | 1548 return; |
| 1357 | 1549 |
| 1358 if (delegate_) { | 1550 if (delegate_) { |
| 1359 delegate_->DidPlay(delegate_id_, hasVideo(), hasAudio(), false, | 1551 delegate_->DidPlay(delegate_id_, hasVideo(), hasAudio(), false, |
| 1360 pipeline_.GetMediaDuration()); | 1552 pipeline_.GetMediaDuration()); |
| 1361 } | 1553 } |
| 1362 if (!memory_usage_reporting_timer_.IsRunning()) { | 1554 if (!memory_usage_reporting_timer_.IsRunning()) { |
| 1363 memory_usage_reporting_timer_.Start(FROM_HERE, | 1555 memory_usage_reporting_timer_.Start(FROM_HERE, |
| 1364 base::TimeDelta::FromSeconds(2), this, | 1556 base::TimeDelta::FromSeconds(2), this, |
| 1365 &WebMediaPlayerImpl::ReportMemoryUsage); | 1557 &WebMediaPlayerImpl::ReportMemoryUsage); |
| 1366 } | 1558 } |
| 1367 } | 1559 } |
| 1368 | 1560 |
| 1369 void WebMediaPlayerImpl::NotifyPlaybackPaused() { | 1561 void WebMediaPlayerImpl::NotifyPlaybackPaused() { |
| 1370 #if defined(OS_ANDROID) // WMPI_CAST | 1562 #if defined(OS_ANDROID) // WMPI_CAST |
| 1371 if (isRemote()) | 1563 if (isRemote()) |
| 1372 return; | 1564 return; |
| 1373 #endif | 1565 #endif |
| 1374 | 1566 // Don't send delegate notifications when suspended; upon suspend we send |
| 1375 // Same as above, NotifyPlaybackPaused() may be called by interactions while | 1567 // PlayerGone() to the delegate -- no more notifications should be sent until |
| 1376 // suspended, but those actions won't have any effect until the pipeline is | 1568 // after resume. |
| 1377 // resumed. | 1569 if (!suspended_ && delegate_) |
| 1378 if (pipeline_controller_.IsSuspended()) | |
| 1379 return; | |
| 1380 | |
| 1381 if (delegate_) | |
| 1382 delegate_->DidPause(delegate_id_, ended_); | 1570 delegate_->DidPause(delegate_id_, ended_); |
| 1383 memory_usage_reporting_timer_.Stop(); | 1571 memory_usage_reporting_timer_.Stop(); |
| 1384 ReportMemoryUsage(); | 1572 ReportMemoryUsage(); |
| 1385 } | 1573 } |
| 1386 | 1574 |
| 1387 void WebMediaPlayerImpl::ReportMemoryUsage() { | 1575 void WebMediaPlayerImpl::ReportMemoryUsage() { |
| 1388 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 1576 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 1389 | 1577 |
| 1390 // About base::Unretained() usage below: We destroy |demuxer_| on the main | 1578 // About base::Unretained() usage below: We destroy |demuxer_| on the main |
| 1391 // thread. Before that, however, ~WebMediaPlayerImpl() posts a task to the | 1579 // thread. Before that, however, ~WebMediaPlayerImpl() posts a task to the |
| (...skipping 23 matching lines...) Expand all Loading... |
| 1415 << ", Video: " << stats.video_memory_usage << ", DataSource: " | 1603 << ", Video: " << stats.video_memory_usage << ", DataSource: " |
| 1416 << (data_source_ ? data_source_->GetMemoryUsage() : 0) | 1604 << (data_source_ ? data_source_->GetMemoryUsage() : 0) |
| 1417 << ", Demuxer: " << demuxer_memory_usage; | 1605 << ", Demuxer: " << demuxer_memory_usage; |
| 1418 | 1606 |
| 1419 const int64_t delta = current_memory_usage - last_reported_memory_usage_; | 1607 const int64_t delta = current_memory_usage - last_reported_memory_usage_; |
| 1420 last_reported_memory_usage_ = current_memory_usage; | 1608 last_reported_memory_usage_ = current_memory_usage; |
| 1421 adjust_allocated_memory_cb_.Run(delta); | 1609 adjust_allocated_memory_cb_.Run(delta); |
| 1422 } | 1610 } |
| 1423 | 1611 |
| 1424 } // namespace media | 1612 } // namespace media |
| OLD | NEW |