Chromium Code Reviews| 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" | |
| 14 #include "base/callback.h" | 15 #include "base/callback.h" |
| 15 #include "base/callback_helpers.h" | 16 #include "base/callback_helpers.h" |
| 16 #include "base/command_line.h" | 17 #include "base/command_line.h" |
| 17 #include "base/debug/alias.h" | 18 #include "base/debug/alias.h" |
| 18 #include "base/debug/crash_logging.h" | 19 #include "base/debug/crash_logging.h" |
| 19 #include "base/metrics/histogram.h" | 20 #include "base/metrics/histogram.h" |
| 20 #include "base/single_thread_task_runner.h" | 21 #include "base/single_thread_task_runner.h" |
| 21 #include "base/synchronization/waitable_event.h" | 22 #include "base/synchronization/waitable_event.h" |
| 22 #include "base/task_runner_util.h" | 23 #include "base/task_runner_util.h" |
| 23 #include "base/thread_task_runner_handle.h" | 24 #include "base/thread_task_runner_handle.h" |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 136 network_state_(WebMediaPlayer::NetworkStateEmpty), | 137 network_state_(WebMediaPlayer::NetworkStateEmpty), |
| 137 ready_state_(WebMediaPlayer::ReadyStateHaveNothing), | 138 ready_state_(WebMediaPlayer::ReadyStateHaveNothing), |
| 138 preload_(BufferedDataSource::AUTO), | 139 preload_(BufferedDataSource::AUTO), |
| 139 buffering_strategy_( | 140 buffering_strategy_( |
| 140 BufferedDataSourceInterface::BUFFERING_STRATEGY_NORMAL), | 141 BufferedDataSourceInterface::BUFFERING_STRATEGY_NORMAL), |
| 141 main_task_runner_(base::ThreadTaskRunnerHandle::Get()), | 142 main_task_runner_(base::ThreadTaskRunnerHandle::Get()), |
| 142 media_task_runner_(params.media_task_runner()), | 143 media_task_runner_(params.media_task_runner()), |
| 143 worker_task_runner_(params.worker_task_runner()), | 144 worker_task_runner_(params.worker_task_runner()), |
| 144 media_log_(params.media_log()), | 145 media_log_(params.media_log()), |
| 145 pipeline_(media_task_runner_, media_log_.get()), | 146 pipeline_(media_task_runner_, media_log_.get()), |
| 147 pipeline_state_(&pipeline_, | |
| 148 base::Bind(&WebMediaPlayerImpl::CreateRenderer, | |
| 149 base::Unretained(this)), | |
| 150 base::Bind(&WebMediaPlayerImpl::OnPipelineSeeked, | |
| 151 base::Unretained(this)), | |
| 152 base::Bind(&WebMediaPlayerImpl::OnPipelineSuspended, | |
| 153 base::Unretained(this)), | |
| 154 base::Bind(&WebMediaPlayerImpl::OnPipelineError, | |
| 155 base::Unretained(this))), | |
| 146 load_type_(LoadTypeURL), | 156 load_type_(LoadTypeURL), |
| 147 opaque_(false), | 157 opaque_(false), |
| 148 playback_rate_(0.0), | 158 playback_rate_(0.0), |
| 149 paused_(true), | 159 paused_(true), |
| 150 seeking_(false), | 160 seeking_(false), |
| 151 pending_suspend_(false), | |
| 152 pending_time_change_(false), | |
| 153 pending_resume_(false), | |
| 154 suspending_(false), | |
| 155 suspended_(false), | |
| 156 resuming_(false), | |
| 157 ended_(false), | 161 ended_(false), |
| 158 pending_seek_(false), | |
| 159 should_notify_time_changed_(false), | |
| 160 client_(client), | 162 client_(client), |
| 161 encrypted_client_(encrypted_client), | 163 encrypted_client_(encrypted_client), |
| 162 delegate_(delegate), | 164 delegate_(delegate), |
| 163 defer_load_cb_(params.defer_load_cb()), | 165 defer_load_cb_(params.defer_load_cb()), |
| 164 context_3d_cb_(params.context_3d_cb()), | 166 context_3d_cb_(params.context_3d_cb()), |
| 165 adjust_allocated_memory_cb_(params.adjust_allocated_memory_cb()), | 167 adjust_allocated_memory_cb_(params.adjust_allocated_memory_cb()), |
| 166 last_reported_memory_usage_(0), | 168 last_reported_memory_usage_(0), |
| 167 supports_save_(true), | 169 supports_save_(true), |
| 168 chunk_demuxer_(NULL), | 170 chunk_demuxer_(NULL), |
| 169 url_index_(url_index), | 171 url_index_(url_index), |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 220 if (delegate_) { | 222 if (delegate_) { |
| 221 delegate_->RemoveObserver(this); | 223 delegate_->RemoveObserver(this); |
| 222 delegate_->PlayerGone(this); | 224 delegate_->PlayerGone(this); |
| 223 } | 225 } |
| 224 | 226 |
| 225 // 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. |
| 226 if (data_source_) | 228 if (data_source_) |
| 227 data_source_->Abort(); | 229 data_source_->Abort(); |
| 228 if (chunk_demuxer_) { | 230 if (chunk_demuxer_) { |
| 229 chunk_demuxer_->Shutdown(); | 231 chunk_demuxer_->Shutdown(); |
| 230 chunk_demuxer_ = NULL; | 232 chunk_demuxer_ = nullptr; |
| 231 } | 233 } |
| 232 | 234 |
| 233 renderer_factory_.reset(); | 235 renderer_factory_.reset(); |
| 234 | 236 |
| 235 // Make sure to kill the pipeline so there's no more media threads running. | 237 // Make sure to kill the pipeline so there's no more media threads running. |
| 236 // Note: stopping the pipeline might block for a long time. | 238 // Note: stopping the pipeline might block for a long time. |
| 237 base::WaitableEvent waiter(false, false); | 239 base::WaitableEvent waiter(false, false); |
| 238 pipeline_.Stop( | 240 pipeline_.Stop( |
| 239 base::Bind(&base::WaitableEvent::Signal, base::Unretained(&waiter))); | 241 base::Bind(&base::WaitableEvent::Signal, base::Unretained(&waiter))); |
| 240 waiter.Wait(); | 242 waiter.Wait(); |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 318 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 320 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 319 | 321 |
| 320 #if defined(OS_ANDROID) // WMPI_CAST | 322 #if defined(OS_ANDROID) // WMPI_CAST |
| 321 if (isRemote()) { | 323 if (isRemote()) { |
| 322 cast_impl_.play(); | 324 cast_impl_.play(); |
| 323 return; | 325 return; |
| 324 } | 326 } |
| 325 #endif | 327 #endif |
| 326 | 328 |
| 327 paused_ = false; | 329 paused_ = false; |
| 330 pipeline_.SetPlaybackRate(playback_rate_); | |
| 328 | 331 |
| 329 pipeline_.SetPlaybackRate(playback_rate_); | |
| 330 if (data_source_) | 332 if (data_source_) |
| 331 data_source_->MediaIsPlaying(); | 333 data_source_->MediaIsPlaying(); |
| 332 | 334 |
| 333 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PLAY)); | 335 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PLAY)); |
| 334 | 336 |
| 335 if (delegate_ && playback_rate_ > 0) | 337 if (delegate_ && playback_rate_ > 0) |
| 336 NotifyPlaybackStarted(); | 338 NotifyPlaybackStarted(); |
| 337 } | 339 } |
| 338 | 340 |
| 339 void WebMediaPlayerImpl::pause() { | 341 void WebMediaPlayerImpl::pause() { |
| 340 DVLOG(1) << __FUNCTION__; | 342 DVLOG(1) << __FUNCTION__; |
| 341 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 343 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 342 | 344 |
| 343 const bool was_already_paused = paused_ || playback_rate_ == 0; | 345 const bool was_already_paused = paused_ || playback_rate_ == 0; |
| 344 paused_ = true; | 346 paused_ = true; |
| 345 | 347 |
| 346 #if defined(OS_ANDROID) // WMPI_CAST | 348 #if defined(OS_ANDROID) // WMPI_CAST |
| 347 if (isRemote()) { | 349 if (isRemote()) { |
| 348 cast_impl_.pause(); | 350 cast_impl_.pause(); |
| 349 return; | 351 return; |
| 350 } | 352 } |
| 351 #endif | 353 #endif |
| 352 | 354 |
| 353 pipeline_.SetPlaybackRate(0.0); | 355 pipeline_.SetPlaybackRate(0.0); |
| 354 UpdatePausedTime(); | 356 |
| 357 // pause() may be called after playback has ended and the HTMLMediaElement | |
| 358 // requires that currentTime() == duration() after ending. We want to ensure | |
| 359 // |paused_time_| matches currentTime() in this case or a future seek() may | |
| 360 // incorrectly discard what it thinks is a seek to the existing time. | |
| 361 paused_time_ = | |
| 362 ended_ ? pipeline_.GetMediaDuration() : pipeline_.GetMediaTime(); | |
| 355 | 363 |
| 356 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PAUSE)); | 364 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PAUSE)); |
| 357 | 365 |
| 358 if (!was_already_paused && delegate_) | 366 if (!was_already_paused && delegate_) |
| 359 NotifyPlaybackPaused(); | 367 NotifyPlaybackPaused(); |
| 360 } | 368 } |
| 361 | 369 |
| 362 bool WebMediaPlayerImpl::supportsSave() const { | 370 bool WebMediaPlayerImpl::supportsSave() const { |
| 363 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 371 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 364 return supports_save_; | 372 return supports_save_; |
| 365 } | 373 } |
| 366 | 374 |
| 367 void WebMediaPlayerImpl::seek(double seconds) { | 375 void WebMediaPlayerImpl::seek(double seconds) { |
| 368 DVLOG(1) << __FUNCTION__ << "(" << seconds << "s)"; | 376 DVLOG(1) << __FUNCTION__ << "(" << seconds << "s)"; |
| 369 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 377 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 378 DoSeek(base::TimeDelta::FromSecondsD(seconds), true); | |
| 379 } | |
| 380 | |
| 381 void WebMediaPlayerImpl::DoSeek(base::TimeDelta time, bool time_updated) { | |
| 382 DCHECK(main_task_runner_->BelongsToCurrentThread()); | |
| 370 | 383 |
| 371 ended_ = false; | 384 ended_ = false; |
| 372 | 385 |
| 373 base::TimeDelta new_seek_time = base::TimeDelta::FromSecondsD(seconds); | |
| 374 | |
| 375 #if defined(OS_ANDROID) // WMPI_CAST | 386 #if defined(OS_ANDROID) // WMPI_CAST |
| 376 if (isRemote()) { | 387 if (isRemote()) { |
| 377 cast_impl_.seek(new_seek_time); | 388 cast_impl_.seek(time); |
| 378 return; | 389 return; |
| 379 } | 390 } |
| 380 #endif | 391 #endif |
| 381 | 392 |
| 382 ReadyState old_state = ready_state_; | 393 ReadyState old_state = ready_state_; |
| 383 if (ready_state_ > WebMediaPlayer::ReadyStateHaveMetadata) | 394 if (ready_state_ > WebMediaPlayer::ReadyStateHaveMetadata) |
| 384 SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata); | 395 SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata); |
| 385 | 396 |
| 386 if (seeking_ || suspended_) { | 397 // When paused, we know exactly what the current time is and can elide seeks |
| 387 // Once resuming, it's too late to change the resume time and so the | 398 // to it. However, there are two cases that are not elided: |
| 388 // implementation is a little different. | 399 // 1) When the pipeline state is not stable. |
| 389 bool is_suspended = suspended_ && !resuming_; | 400 // In this case we just let |pipeline_state_| decide what to do, as it |
| 390 | 401 // has complete information. |
| 391 // If we are currently seeking or resuming to |new_seek_time|, skip the | 402 // 2) For MSE. |
| 392 // seek (except for MSE, which always seeks). | 403 // Because the buffers may have changed between seeks, MSE seeks are |
| 393 if (!is_suspended && new_seek_time == seek_time_) { | 404 // never elided. |
| 394 if (chunk_demuxer_) { | 405 if (paused_ && pipeline_state_.IsPlaying() && paused_time_ == time && |
| 395 // Don't suppress any redundant in-progress MSE seek. There could have | 406 !chunk_demuxer_) { |
| 396 // been changes to the underlying buffers after seeking the demuxer and | 407 // If the ready state was high enough before, we can indicate that the seek |
| 397 // before receiving OnPipelineSeeked() for the currently in-progress | 408 // completed just by restoring it. Otherwise we will just wait for the real |
| 398 // seek. | 409 // ready state change to eventually happen. |
| 399 MEDIA_LOG(DEBUG, media_log_) | 410 if (old_state == ReadyStateHaveEnoughData) { |
| 400 << "Detected MediaSource seek to same time as in-progress seek to " | |
| 401 << seek_time_ << "."; | |
| 402 } else { | |
| 403 // Suppress all redundant seeks if unrestricted by media source demuxer | |
| 404 // API. | |
| 405 pending_seek_ = false; | |
| 406 pending_seek_time_ = base::TimeDelta(); | |
| 407 return; | |
| 408 } | |
| 409 } | |
| 410 | |
| 411 // If |chunk_demuxer_| is already seeking, cancel that seek and schedule the | |
| 412 // new one. | |
| 413 if (!is_suspended && chunk_demuxer_) | |
| 414 chunk_demuxer_->CancelPendingSeek(new_seek_time); | |
| 415 | |
| 416 // Schedule a seek once the current suspend or seek finishes. | |
| 417 pending_seek_ = true; | |
| 418 pending_seek_time_ = new_seek_time; | |
| 419 | |
| 420 // In the case of seeking while suspended, the seek is considered to have | |
| 421 // started immediately (but won't complete until the pipeline is resumed). | |
| 422 if (is_suspended) { | |
| 423 seeking_ = true; | |
| 424 seek_time_ = new_seek_time; | |
| 425 } | |
| 426 | |
| 427 return; | |
| 428 } | |
| 429 | |
| 430 media_log_->AddEvent(media_log_->CreateSeekEvent(seconds)); | |
| 431 | |
| 432 // Update our paused time. | |
| 433 // For non-MSE playbacks, in paused state ignore the seek operations to | |
| 434 // current time if the loading is completed and generate | |
| 435 // OnPipelineBufferingStateChanged event to eventually fire seeking and seeked | |
| 436 // events. We don't short-circuit MSE seeks in this logic because the | |
| 437 // underlying buffers around the seek time might have changed (or even been | |
| 438 // removed) since previous seek/preroll/pause action, and the pipeline might | |
| 439 // need to flush so the new buffers are decoded and rendered instead of the | |
| 440 // old ones. | |
| 441 if (paused_) { | |
| 442 if (paused_time_ != new_seek_time || chunk_demuxer_) { | |
| 443 paused_time_ = new_seek_time; | |
| 444 } else if (old_state == ReadyStateHaveEnoughData) { | |
| 445 main_task_runner_->PostTask( | 411 main_task_runner_->PostTask( |
| 446 FROM_HERE, | 412 FROM_HERE, |
| 447 base::Bind(&WebMediaPlayerImpl::OnPipelineBufferingStateChanged, | 413 base::Bind(&WebMediaPlayerImpl::OnPipelineBufferingStateChanged, |
| 448 AsWeakPtr(), BUFFERING_HAVE_ENOUGH)); | 414 AsWeakPtr(), BUFFERING_HAVE_ENOUGH)); |
| 449 return; | |
| 450 } | 415 } |
| 416 return; | |
| 451 } | 417 } |
| 452 | 418 |
| 453 seeking_ = true; | 419 seeking_ = true; |
| 454 seek_time_ = new_seek_time; | 420 seek_time_ = time; |
| 455 | 421 if (paused_) |
| 456 if (chunk_demuxer_) | 422 paused_time_ = time; |
| 457 chunk_demuxer_->StartWaitingForSeek(seek_time_); | 423 pipeline_state_.Seek(time, time_updated); |
| 458 | |
| 459 pipeline_.Seek(seek_time_, BIND_TO_RENDER_LOOP1( | |
| 460 &WebMediaPlayerImpl::OnPipelineSeeked, true)); | |
| 461 } | 424 } |
| 462 | 425 |
| 463 void WebMediaPlayerImpl::setRate(double rate) { | 426 void WebMediaPlayerImpl::setRate(double rate) { |
| 464 DVLOG(1) << __FUNCTION__ << "(" << rate << ")"; | 427 DVLOG(1) << __FUNCTION__ << "(" << rate << ")"; |
| 465 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 428 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 466 | 429 |
| 467 // TODO(kylep): Remove when support for negatives is added. Also, modify the | 430 // TODO(kylep): Remove when support for negatives is added. Also, modify the |
| 468 // following checks so rewind uses reasonable values also. | 431 // following checks so rewind uses reasonable values also. |
| 469 if (rate < 0.0) | 432 if (rate < 0.0) |
| 470 return; | 433 return; |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 608 | 571 |
| 609 double WebMediaPlayerImpl::currentTime() const { | 572 double WebMediaPlayerImpl::currentTime() const { |
| 610 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 573 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 611 DCHECK_NE(ready_state_, WebMediaPlayer::ReadyStateHaveNothing); | 574 DCHECK_NE(ready_state_, WebMediaPlayer::ReadyStateHaveNothing); |
| 612 | 575 |
| 613 // TODO(scherkus): Replace with an explicit ended signal to HTMLMediaElement, | 576 // TODO(scherkus): Replace with an explicit ended signal to HTMLMediaElement, |
| 614 // see http://crbug.com/409280 | 577 // see http://crbug.com/409280 |
| 615 if (ended_) | 578 if (ended_) |
| 616 return duration(); | 579 return duration(); |
| 617 | 580 |
| 618 // We know the current seek time better than pipeline: pipeline may processing | 581 if (seeking()) |
| 619 // an earlier seek before a pending seek has been started, or it might not yet | 582 return seek_time_.InSecondsF(); |
| 620 // have the current seek time returnable via GetMediaTime(). | |
| 621 if (seeking()) { | |
| 622 return pending_seek_ ? pending_seek_time_.InSecondsF() | |
| 623 : seek_time_.InSecondsF(); | |
| 624 } | |
| 625 | 583 |
| 626 #if defined(OS_ANDROID) // WMPI_CAST | 584 #if defined(OS_ANDROID) // WMPI_CAST |
| 627 if (isRemote()) { | 585 if (isRemote()) |
| 628 return cast_impl_.currentTime(); | 586 return cast_impl_.currentTime(); |
| 629 } | |
| 630 #endif | 587 #endif |
| 631 | 588 |
| 632 if (paused_) { | 589 if (paused_) |
| 633 return paused_time_.InSecondsF(); | 590 return paused_time_.InSecondsF(); |
| 634 } | |
| 635 | 591 |
| 636 return pipeline_.GetMediaTime().InSecondsF(); | 592 return pipeline_.GetMediaTime().InSecondsF(); |
| 637 } | 593 } |
| 638 | 594 |
| 639 WebMediaPlayer::NetworkState WebMediaPlayerImpl::networkState() const { | 595 WebMediaPlayer::NetworkState WebMediaPlayerImpl::networkState() const { |
| 640 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 596 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 641 return network_state_; | 597 return network_state_; |
| 642 } | 598 } |
| 643 | 599 |
| 644 WebMediaPlayer::ReadyState WebMediaPlayerImpl::readyState() const { | 600 WebMediaPlayer::ReadyState WebMediaPlayerImpl::readyState() const { |
| (...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 898 is_cdm_attached_ = true; | 854 is_cdm_attached_ = true; |
| 899 return; | 855 return; |
| 900 } | 856 } |
| 901 | 857 |
| 902 set_cdm_result_->completeWithError( | 858 set_cdm_result_->completeWithError( |
| 903 blink::WebContentDecryptionModuleExceptionNotSupportedError, 0, | 859 blink::WebContentDecryptionModuleExceptionNotSupportedError, 0, |
| 904 "Unable to set MediaKeys object"); | 860 "Unable to set MediaKeys object"); |
| 905 set_cdm_result_.reset(); | 861 set_cdm_result_.reset(); |
| 906 } | 862 } |
| 907 | 863 |
| 908 void WebMediaPlayerImpl::OnPipelineSeeked(bool time_changed, | 864 void WebMediaPlayerImpl::OnPipelineSeeked(bool time_updated) { |
| 909 PipelineStatus status) { | |
| 910 DVLOG(1) << __FUNCTION__ << "(" << time_changed << ", " << status << ")"; | |
| 911 DCHECK(main_task_runner_->BelongsToCurrentThread()); | |
| 912 | |
| 913 if (status != PIPELINE_OK) { | |
| 914 OnPipelineError(status); | |
| 915 return; | |
| 916 } | |
| 917 | |
| 918 // Whether or not the seek was caused by a resume, we're not suspended now. | |
| 919 resuming_ = false; | |
| 920 suspended_ = false; | |
| 921 | |
| 922 // If there is a pending suspend, the seek does not complete until after the | |
| 923 // next resume. | |
| 924 if (pending_suspend_) { | |
| 925 pending_suspend_ = false; | |
| 926 pending_time_change_ = time_changed; | |
| 927 Suspend(); | |
| 928 return; | |
| 929 } | |
| 930 | |
| 931 // Clear seek state. Note that if the seek was caused by a resume, then | |
| 932 // |seek_time_| is always set but |seeking_| is only set if there was a | |
| 933 // pending seek at the time. | |
| 934 seeking_ = false; | 865 seeking_ = false; |
| 935 seek_time_ = base::TimeDelta(); | 866 seek_time_ = base::TimeDelta(); |
| 936 | |
| 937 if (pending_seek_) { | |
| 938 double pending_seek_seconds = pending_seek_time_.InSecondsF(); | |
| 939 pending_seek_ = false; | |
| 940 pending_seek_time_ = base::TimeDelta(); | |
| 941 seek(pending_seek_seconds); | |
| 942 return; | |
| 943 } | |
| 944 | |
| 945 // Update our paused time. | |
| 946 if (paused_) | 867 if (paused_) |
| 947 UpdatePausedTime(); | 868 paused_time_ = pipeline_.GetMediaTime(); |
| 948 | 869 if (time_updated) |
| 949 should_notify_time_changed_ = time_changed; | 870 should_notify_time_changed_ = true; |
| 950 } | 871 } |
| 951 | 872 |
| 952 void WebMediaPlayerImpl::OnPipelineSuspended(PipelineStatus status) { | 873 void WebMediaPlayerImpl::OnPipelineSuspended() { |
| 953 DVLOG(1) << __FUNCTION__ << "(" << status << ")"; | |
| 954 DCHECK(main_task_runner_->BelongsToCurrentThread()); | |
| 955 | |
| 956 if (status != PIPELINE_OK) { | |
| 957 OnPipelineError(status); | |
| 958 return; | |
| 959 } | |
| 960 | |
| 961 suspending_ = false; | |
| 962 | |
| 963 #if defined(OS_ANDROID) | 874 #if defined(OS_ANDROID) |
| 964 if (isRemote()) { | 875 if (isRemote()) { |
| 965 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner(); | 876 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner(); |
| 966 if (frame) { | 877 if (frame) { |
| 967 compositor_->PaintFrameUsingOldRenderingPath(frame); | 878 compositor_->PaintFrameUsingOldRenderingPath(frame); |
| 968 } | 879 } |
| 969 } | 880 } |
| 970 #endif | 881 #endif |
| 971 | |
| 972 if (pending_resume_) { | |
| 973 pending_resume_ = false; | |
| 974 Resume(); | |
| 975 return; | |
| 976 } | |
| 977 } | 882 } |
| 978 | 883 |
| 979 void WebMediaPlayerImpl::OnPipelineEnded() { | 884 void WebMediaPlayerImpl::OnPipelineEnded() { |
| 980 DVLOG(1) << __FUNCTION__; | 885 DVLOG(1) << __FUNCTION__; |
| 981 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 886 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 982 | 887 |
| 983 // Ignore state changes until we've completed all outstanding seeks. | 888 // Ignore state changes until we've completed all outstanding operations. |
| 984 if (seeking_ || pending_seek_) | 889 if (!pipeline_state_.IsPlaying()) |
| 985 return; | 890 return; |
| 986 | 891 |
| 987 ended_ = true; | 892 ended_ = true; |
| 988 client_->timeChanged(); | 893 client_->timeChanged(); |
| 989 } | 894 } |
| 990 | 895 |
| 991 void WebMediaPlayerImpl::OnPipelineError(PipelineStatus error) { | 896 void WebMediaPlayerImpl::OnPipelineError(PipelineStatus error) { |
| 992 DVLOG(1) << __FUNCTION__; | 897 DVLOG(1) << __FUNCTION__; |
| 993 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 898 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 994 DCHECK_NE(error, PIPELINE_OK); | 899 DCHECK_NE(error, PIPELINE_OK); |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1034 // playback. | 939 // playback. |
| 1035 if (delegate_ && delegate_->IsHidden()) | 940 if (delegate_ && delegate_->IsHidden()) |
| 1036 OnHidden(); | 941 OnHidden(); |
| 1037 } | 942 } |
| 1038 } | 943 } |
| 1039 | 944 |
| 1040 void WebMediaPlayerImpl::OnPipelineBufferingStateChanged( | 945 void WebMediaPlayerImpl::OnPipelineBufferingStateChanged( |
| 1041 BufferingState buffering_state) { | 946 BufferingState buffering_state) { |
| 1042 DVLOG(1) << __FUNCTION__ << "(" << buffering_state << ")"; | 947 DVLOG(1) << __FUNCTION__ << "(" << buffering_state << ")"; |
| 1043 | 948 |
| 1044 // Ignore buffering state changes until we've completed all outstanding seeks. | 949 // Ignore buffering state changes until we've completed all outstanding |
| 1045 if (seeking_ || pending_seek_) | 950 // operations. |
| 951 if (!pipeline_state_.IsPlaying()) | |
| 1046 return; | 952 return; |
| 1047 | 953 |
| 1048 // TODO(scherkus): Handle other buffering states when Pipeline starts using | 954 // TODO(scherkus): Handle other buffering states when Pipeline starts using |
| 1049 // them and translate them ready state changes http://crbug.com/144683 | 955 // them and translate them ready state changes http://crbug.com/144683 |
| 1050 DCHECK_EQ(buffering_state, BUFFERING_HAVE_ENOUGH); | 956 DCHECK_EQ(buffering_state, BUFFERING_HAVE_ENOUGH); |
| 1051 SetReadyState(WebMediaPlayer::ReadyStateHaveEnoughData); | 957 SetReadyState(WebMediaPlayer::ReadyStateHaveEnoughData); |
| 1052 | 958 |
| 1053 // Let the DataSource know we have enough data. It may use this information to | 959 // Let the DataSource know we have enough data. It may use this information to |
| 1054 // release unused network connections. | 960 // release unused network connections. |
| 1055 if (data_source_) | 961 if (data_source_) |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1108 switches::kDisableMediaSuspend)) { | 1014 switches::kDisableMediaSuspend)) { |
| 1109 return; | 1015 return; |
| 1110 } | 1016 } |
| 1111 | 1017 |
| 1112 #if defined(OS_ANDROID) | 1018 #if defined(OS_ANDROID) |
| 1113 // If we're remote, the pipeline should already be suspended. | 1019 // If we're remote, the pipeline should already be suspended. |
| 1114 if (isRemote()) | 1020 if (isRemote()) |
| 1115 return; | 1021 return; |
| 1116 #endif | 1022 #endif |
| 1117 | 1023 |
| 1118 ScheduleSuspend(); | 1024 if (pipeline_.IsRunning() && hasVideo()) |
| 1119 } | 1025 pipeline_state_.Suspend(); |
| 1120 | |
| 1121 void WebMediaPlayerImpl::ScheduleSuspend() { | |
| 1122 if (!pipeline_.IsRunning() || !hasVideo()) | |
| 1123 return; | |
| 1124 | |
| 1125 if (resuming_ || seeking_) { | |
| 1126 pending_suspend_ = true; | |
| 1127 return; | |
| 1128 } | |
| 1129 | |
| 1130 if (pending_resume_) { | |
| 1131 pending_resume_ = false; | |
| 1132 return; | |
| 1133 } | |
| 1134 | |
| 1135 Suspend(); | |
| 1136 } | |
| 1137 | |
| 1138 void WebMediaPlayerImpl::Suspend() { | |
| 1139 DCHECK(main_task_runner_->BelongsToCurrentThread()); | |
| 1140 CHECK(!suspended_); | |
| 1141 suspended_ = true; | |
| 1142 suspending_ = true; | |
| 1143 pipeline_.Suspend( | |
| 1144 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineSuspended)); | |
| 1145 } | 1026 } |
| 1146 | 1027 |
| 1147 void WebMediaPlayerImpl::OnShown() { | 1028 void WebMediaPlayerImpl::OnShown() { |
| 1148 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 1029 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 1149 | 1030 |
| 1150 #if !defined(OS_ANDROID) | 1031 #if !defined(OS_ANDROID) |
| 1151 // Suspend/Resume is enabled by default on Android. | 1032 // Suspend/Resume is enabled by default on Android. |
| 1152 if (!base::CommandLine::ForCurrentProcess()->HasSwitch( | 1033 if (!base::CommandLine::ForCurrentProcess()->HasSwitch( |
| 1153 switches::kEnableMediaSuspend)) { | 1034 switches::kEnableMediaSuspend)) { |
| 1154 return; | 1035 return; |
| 1155 } | 1036 } |
| 1156 #endif // !defined(OS_ANDROID) | 1037 #endif // !defined(OS_ANDROID) |
| 1157 | 1038 |
| 1158 if (base::CommandLine::ForCurrentProcess()->HasSwitch( | 1039 if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
| 1159 switches::kDisableMediaSuspend)) { | 1040 switches::kDisableMediaSuspend)) { |
| 1160 return; | 1041 return; |
| 1161 } | 1042 } |
| 1162 | 1043 |
| 1163 #if defined(OS_ANDROID) | 1044 #if defined(OS_ANDROID) |
| 1164 // If we're remote, the pipeline should stay suspended. | 1045 // If we're remote, the pipeline should stay suspended. |
| 1165 if (isRemote()) | 1046 if (isRemote()) |
| 1166 return; | 1047 return; |
| 1167 #endif | 1048 #endif |
| 1168 | 1049 |
| 1169 ScheduleResume(); | 1050 if (pipeline_.IsRunning()) |
| 1170 } | 1051 pipeline_state_.Resume(); |
| 1171 | |
| 1172 void WebMediaPlayerImpl::ScheduleResume() { | |
| 1173 if (!pipeline_.IsRunning()) | |
| 1174 return; | |
| 1175 | |
| 1176 if (suspending_) { | |
| 1177 pending_resume_ = true; | |
| 1178 return; | |
| 1179 } | |
| 1180 | |
| 1181 if (pending_suspend_) { | |
| 1182 pending_suspend_ = false; | |
| 1183 return; | |
| 1184 } | |
| 1185 | |
| 1186 // Might already be resuming iff we came back from remote playback recently. | |
| 1187 if (suspended_ && !resuming_) | |
| 1188 Resume(); | |
| 1189 } | |
| 1190 | |
| 1191 void WebMediaPlayerImpl::Resume() { | |
| 1192 DCHECK(main_task_runner_->BelongsToCurrentThread()); | |
| 1193 CHECK(suspended_); | |
| 1194 CHECK(!resuming_); | |
| 1195 | |
| 1196 // If there was a time change pending when we suspended (which can happen when | |
| 1197 // we suspend immediately after a seek), surface it after resuming. | |
| 1198 bool time_changed = pending_time_change_; | |
| 1199 pending_time_change_ = false; | |
| 1200 | |
| 1201 if (seeking_ || pending_seek_) { | |
| 1202 if (pending_seek_) { | |
| 1203 seek_time_ = pending_seek_time_; | |
| 1204 pending_seek_ = false; | |
| 1205 pending_seek_time_ = base::TimeDelta(); | |
| 1206 } | |
| 1207 time_changed = true; | |
| 1208 } else { | |
| 1209 // It is safe to call GetCurrentFrameTimestamp() because VFC is stopped | |
| 1210 // during Suspend(). It won't be started again until after Resume() is | |
| 1211 // called. | |
| 1212 seek_time_ = compositor_->GetCurrentFrameTimestamp(); | |
| 1213 } | |
| 1214 | |
| 1215 if (chunk_demuxer_) | |
| 1216 chunk_demuxer_->StartWaitingForSeek(seek_time_); | |
| 1217 | |
| 1218 resuming_ = true; | |
| 1219 pipeline_.Resume(CreateRenderer(), seek_time_, | |
| 1220 BIND_TO_RENDER_LOOP1(&WebMediaPlayerImpl::OnPipelineSeeked, | |
| 1221 time_changed)); | |
| 1222 } | 1052 } |
| 1223 | 1053 |
| 1224 #if defined(OS_ANDROID) // WMPI_CAST | 1054 #if defined(OS_ANDROID) // WMPI_CAST |
| 1225 | 1055 |
| 1226 bool WebMediaPlayerImpl::isRemote() const { | 1056 bool WebMediaPlayerImpl::isRemote() const { |
| 1227 return cast_impl_.isRemote(); | 1057 return cast_impl_.isRemote(); |
| 1228 } | 1058 } |
| 1229 | 1059 |
| 1230 void WebMediaPlayerImpl::SetMediaPlayerManager( | 1060 void WebMediaPlayerImpl::SetMediaPlayerManager( |
| 1231 RendererMediaPlayerManagerInterface* media_player_manager) { | 1061 RendererMediaPlayerManagerInterface* media_player_manager) { |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 1242 | 1072 |
| 1243 void WebMediaPlayerImpl::OnRemotePlaybackEnded() { | 1073 void WebMediaPlayerImpl::OnRemotePlaybackEnded() { |
| 1244 DVLOG(1) << __FUNCTION__; | 1074 DVLOG(1) << __FUNCTION__; |
| 1245 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 1075 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 1246 | 1076 |
| 1247 ended_ = true; | 1077 ended_ = true; |
| 1248 client_->timeChanged(); | 1078 client_->timeChanged(); |
| 1249 } | 1079 } |
| 1250 | 1080 |
| 1251 void WebMediaPlayerImpl::OnDisconnectedFromRemoteDevice(double t) { | 1081 void WebMediaPlayerImpl::OnDisconnectedFromRemoteDevice(double t) { |
| 1252 paused_time_ = base::TimeDelta::FromSecondsD(t); | 1082 DoSeek(base::TimeDelta::FromSecondsD(t), false); |
|
wolenetz
2016/01/29 21:42:30
Do we need to do anything with paused_time_/seek_t
sandersd (OOO until July 31)
2016/02/01 23:19:26
We do; it should be done correctly by DoSeek().
I
wolenetz
2016/02/26 02:30:11
Acknowledged.
| |
| 1253 pending_seek_ = true; | 1083 if (delegate_ && !delegate_->IsHidden()) |
|
wolenetz
2016/01/29 21:42:30
I confess I don't understand what's going on here
sandersd (OOO until July 31)
2016/02/01 23:19:26
This just says that we want to resume playback whe
wolenetz
2016/02/26 02:30:11
Acknowledged.
| |
| 1254 pending_seek_time_ = paused_time_; | 1084 pipeline_state_.Resume(); |
| 1255 | 1085 |
| 1256 ScheduleResume(); | |
| 1257 | |
| 1258 if (paused_time_ == pipeline_.GetMediaDuration()) { | |
| 1259 ended_ = true; | |
| 1260 } | |
| 1261 // We already told the delegate we're paused when remoting started. | 1086 // We already told the delegate we're paused when remoting started. |
| 1262 client_->playbackStateChanged(); | 1087 client_->playbackStateChanged(); |
| 1263 client_->disconnectedFromRemoteDevice(); | 1088 client_->disconnectedFromRemoteDevice(); |
| 1264 } | 1089 } |
| 1265 | 1090 |
| 1266 void WebMediaPlayerImpl::SuspendForRemote() { | 1091 void WebMediaPlayerImpl::SuspendForRemote() { |
| 1267 if (suspended_ && !suspending_) { | 1092 if (pipeline_state_.IsSuspended()) { |
| 1268 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner(); | 1093 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner(); |
| 1269 if (frame) { | 1094 if (frame) { |
| 1270 compositor_->PaintFrameUsingOldRenderingPath(frame); | 1095 compositor_->PaintFrameUsingOldRenderingPath(frame); |
| 1271 } | 1096 } |
| 1272 } | 1097 } |
| 1273 ScheduleSuspend(); | 1098 pipeline_state_.Suspend(); |
| 1274 } | 1099 } |
| 1275 | 1100 |
| 1276 gfx::Size WebMediaPlayerImpl::GetCanvasSize() const { | 1101 gfx::Size WebMediaPlayerImpl::GetCanvasSize() const { |
| 1277 if (!video_weblayer_) | 1102 if (!video_weblayer_) |
| 1278 return pipeline_metadata_.natural_size; | 1103 return pipeline_metadata_.natural_size; |
| 1279 | 1104 |
| 1280 return video_weblayer_->bounds(); | 1105 return video_weblayer_->bounds(); |
| 1281 } | 1106 } |
| 1282 | 1107 |
| 1283 void WebMediaPlayerImpl::SetDeviceScaleFactor(float scale_factor) { | 1108 void WebMediaPlayerImpl::SetDeviceScaleFactor(float scale_factor) { |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1338 DCHECK(!data_source_); | 1163 DCHECK(!data_source_); |
| 1339 | 1164 |
| 1340 chunk_demuxer_ = new ChunkDemuxer( | 1165 chunk_demuxer_ = new ChunkDemuxer( |
| 1341 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnDemuxerOpened), | 1166 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnDemuxerOpened), |
| 1342 encrypted_media_init_data_cb, media_log_, true); | 1167 encrypted_media_init_data_cb, media_log_, true); |
| 1343 demuxer_.reset(chunk_demuxer_); | 1168 demuxer_.reset(chunk_demuxer_); |
| 1344 } | 1169 } |
| 1345 | 1170 |
| 1346 // ... and we're ready to go! | 1171 // ... and we're ready to go! |
| 1347 seeking_ = true; | 1172 seeking_ = true; |
| 1348 | 1173 pipeline_state_.Start( |
| 1349 // TODO(sandersd): On Android, defer Start() if the tab is not visible. | 1174 chunk_demuxer_, demuxer_.get(), |
| 1350 pipeline_.Start( | |
| 1351 demuxer_.get(), CreateRenderer(), | |
| 1352 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineEnded), | 1175 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineEnded), |
| 1353 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineError), | |
| 1354 BIND_TO_RENDER_LOOP1(&WebMediaPlayerImpl::OnPipelineSeeked, false), | |
| 1355 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineMetadata), | 1176 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineMetadata), |
| 1356 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineBufferingStateChanged), | 1177 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineBufferingStateChanged), |
| 1357 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnDurationChanged), | 1178 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnDurationChanged), |
| 1358 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnAddTextTrack), | 1179 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnAddTextTrack), |
| 1359 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnWaitingForDecryptionKey)); | 1180 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnWaitingForDecryptionKey)); |
| 1360 } | 1181 } |
| 1361 | 1182 |
| 1362 void WebMediaPlayerImpl::SetNetworkState(WebMediaPlayer::NetworkState state) { | 1183 void WebMediaPlayerImpl::SetNetworkState(WebMediaPlayer::NetworkState state) { |
| 1363 DVLOG(1) << __FUNCTION__ << "(" << state << ")"; | 1184 DVLOG(1) << __FUNCTION__ << "(" << state << ")"; |
| 1364 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 1185 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1447 base::WaitableEvent event(false, false); | 1268 base::WaitableEvent event(false, false); |
| 1448 compositor_task_runner_->PostTask(FROM_HERE, | 1269 compositor_task_runner_->PostTask(FROM_HERE, |
| 1449 base::Bind(&GetCurrentFrameAndSignal, | 1270 base::Bind(&GetCurrentFrameAndSignal, |
| 1450 base::Unretained(compositor_), | 1271 base::Unretained(compositor_), |
| 1451 &video_frame, | 1272 &video_frame, |
| 1452 &event)); | 1273 &event)); |
| 1453 event.Wait(); | 1274 event.Wait(); |
| 1454 return video_frame; | 1275 return video_frame; |
| 1455 } | 1276 } |
| 1456 | 1277 |
| 1457 void WebMediaPlayerImpl::UpdatePausedTime() { | |
| 1458 DCHECK(main_task_runner_->BelongsToCurrentThread()); | |
| 1459 | |
| 1460 // pause() may be called after playback has ended and the HTMLMediaElement | |
| 1461 // requires that currentTime() == duration() after ending. We want to ensure | |
| 1462 // |paused_time_| matches currentTime() in this case or a future seek() may | |
| 1463 // incorrectly discard what it thinks is a seek to the existing time. | |
| 1464 paused_time_ = | |
| 1465 ended_ ? pipeline_.GetMediaDuration() : pipeline_.GetMediaTime(); | |
| 1466 } | |
| 1467 | |
| 1468 void WebMediaPlayerImpl::NotifyPlaybackStarted() { | 1278 void WebMediaPlayerImpl::NotifyPlaybackStarted() { |
| 1469 #if defined(OS_ANDROID) // WMPI_CAST | 1279 #if defined(OS_ANDROID) // WMPI_CAST |
| 1470 // We do not tell our delegates about remote playback, becuase that would | 1280 // We do not tell our delegates about remote playback, becuase that would |
| 1471 // keep the device awake, which is not what we want. | 1281 // keep the device awake, which is not what we want. |
| 1472 if (isRemote()) | 1282 if (isRemote()) |
| 1473 return; | 1283 return; |
| 1474 #endif | 1284 #endif |
| 1475 if (delegate_) | 1285 if (delegate_) |
| 1476 delegate_->DidPlay(this); | 1286 delegate_->DidPlay(this); |
| 1477 if (!memory_usage_reporting_timer_.IsRunning()) { | 1287 if (!memory_usage_reporting_timer_.IsRunning()) { |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1523 << ", Video: " << stats.video_memory_usage << ", DataSource: " | 1333 << ", Video: " << stats.video_memory_usage << ", DataSource: " |
| 1524 << (data_source_ ? data_source_->GetMemoryUsage() : 0) | 1334 << (data_source_ ? data_source_->GetMemoryUsage() : 0) |
| 1525 << ", Demuxer: " << demuxer_memory_usage; | 1335 << ", Demuxer: " << demuxer_memory_usage; |
| 1526 | 1336 |
| 1527 const int64_t delta = current_memory_usage - last_reported_memory_usage_; | 1337 const int64_t delta = current_memory_usage - last_reported_memory_usage_; |
| 1528 last_reported_memory_usage_ = current_memory_usage; | 1338 last_reported_memory_usage_ = current_memory_usage; |
| 1529 adjust_allocated_memory_cb_.Run(delta); | 1339 adjust_allocated_memory_cb_.Run(delta); |
| 1530 } | 1340 } |
| 1531 | 1341 |
| 1532 } // namespace media | 1342 } // namespace media |
| OLD | NEW |