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 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
137 network_state_(WebMediaPlayer::NetworkStateEmpty), | 138 network_state_(WebMediaPlayer::NetworkStateEmpty), |
138 ready_state_(WebMediaPlayer::ReadyStateHaveNothing), | 139 ready_state_(WebMediaPlayer::ReadyStateHaveNothing), |
139 preload_(BufferedDataSource::AUTO), | 140 preload_(BufferedDataSource::AUTO), |
140 buffering_strategy_( | 141 buffering_strategy_( |
141 BufferedDataSourceInterface::BUFFERING_STRATEGY_NORMAL), | 142 BufferedDataSourceInterface::BUFFERING_STRATEGY_NORMAL), |
142 main_task_runner_(base::ThreadTaskRunnerHandle::Get()), | 143 main_task_runner_(base::ThreadTaskRunnerHandle::Get()), |
143 media_task_runner_(params.media_task_runner()), | 144 media_task_runner_(params.media_task_runner()), |
144 worker_task_runner_(params.worker_task_runner()), | 145 worker_task_runner_(params.worker_task_runner()), |
145 media_log_(params.media_log()), | 146 media_log_(params.media_log()), |
146 pipeline_(media_task_runner_, media_log_.get()), | 147 pipeline_(media_task_runner_, media_log_.get()), |
148 pipeline_controller_(&pipeline_, | |
149 base::Bind(&WebMediaPlayerImpl::CreateRenderer, | |
150 base::Unretained(this)), | |
DaleCurtis
2016/02/19 23:28:30
These probably still need to be WeakPtrs unless it
sandersd (OOO until July 31)
2016/02/24 00:09:56
Done.
| |
151 base::Bind(&WebMediaPlayerImpl::OnPipelineSeeked, | |
152 base::Unretained(this)), | |
153 base::Bind(&WebMediaPlayerImpl::OnPipelineSuspended, | |
154 base::Unretained(this)), | |
155 base::Bind(&WebMediaPlayerImpl::OnPipelineError, | |
156 base::Unretained(this))), | |
147 load_type_(LoadTypeURL), | 157 load_type_(LoadTypeURL), |
148 opaque_(false), | 158 opaque_(false), |
149 playback_rate_(0.0), | 159 playback_rate_(0.0), |
150 paused_(true), | 160 paused_(true), |
151 seeking_(false), | 161 seeking_(false), |
152 pending_suspend_(false), | |
153 pending_time_change_(false), | |
154 pending_resume_(false), | |
155 suspending_(false), | |
156 suspended_(false), | |
157 resuming_(false), | |
158 pending_suspend_resume_cycle_(false), | 162 pending_suspend_resume_cycle_(false), |
159 ended_(false), | 163 ended_(false), |
160 pending_seek_(false), | |
161 should_notify_time_changed_(false), | |
162 fullscreen_(false), | 164 fullscreen_(false), |
163 decoder_requires_restart_for_fullscreen_(false), | 165 decoder_requires_restart_for_fullscreen_(false), |
164 client_(client), | 166 client_(client), |
165 encrypted_client_(encrypted_client), | 167 encrypted_client_(encrypted_client), |
166 delegate_(delegate), | 168 delegate_(delegate), |
167 delegate_id_(0), | 169 delegate_id_(0), |
168 defer_load_cb_(params.defer_load_cb()), | 170 defer_load_cb_(params.defer_load_cb()), |
169 context_3d_cb_(params.context_3d_cb()), | 171 context_3d_cb_(params.context_3d_cb()), |
170 adjust_allocated_memory_cb_(params.adjust_allocated_memory_cb()), | 172 adjust_allocated_memory_cb_(params.adjust_allocated_memory_cb()), |
171 last_reported_memory_usage_(0), | 173 last_reported_memory_usage_(0), |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
228 if (delegate_) { | 230 if (delegate_) { |
229 delegate_->PlayerGone(delegate_id_); | 231 delegate_->PlayerGone(delegate_id_); |
230 delegate_->RemoveObserver(delegate_id_); | 232 delegate_->RemoveObserver(delegate_id_); |
231 } | 233 } |
232 | 234 |
233 // Abort any pending IO so stopping the pipeline doesn't get blocked. | 235 // Abort any pending IO so stopping the pipeline doesn't get blocked. |
234 if (data_source_) | 236 if (data_source_) |
235 data_source_->Abort(); | 237 data_source_->Abort(); |
236 if (chunk_demuxer_) { | 238 if (chunk_demuxer_) { |
237 chunk_demuxer_->Shutdown(); | 239 chunk_demuxer_->Shutdown(); |
238 chunk_demuxer_ = NULL; | 240 chunk_demuxer_ = nullptr; |
239 } | 241 } |
240 | 242 |
241 renderer_factory_.reset(); | 243 renderer_factory_.reset(); |
242 | 244 |
243 // Make sure to kill the pipeline so there's no more media threads running. | 245 // Make sure to kill the pipeline so there's no more media threads running. |
244 // Note: stopping the pipeline might block for a long time. | 246 // Note: stopping the pipeline might block for a long time. |
245 base::WaitableEvent waiter(false, false); | 247 base::WaitableEvent waiter(false, false); |
246 pipeline_.Stop( | 248 pipeline_.Stop( |
247 base::Bind(&base::WaitableEvent::Signal, base::Unretained(&waiter))); | 249 base::Bind(&base::WaitableEvent::Signal, base::Unretained(&waiter))); |
248 waiter.Wait(); | 250 waiter.Wait(); |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
340 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 342 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
341 | 343 |
342 #if defined(OS_ANDROID) // WMPI_CAST | 344 #if defined(OS_ANDROID) // WMPI_CAST |
343 if (isRemote()) { | 345 if (isRemote()) { |
344 cast_impl_.play(); | 346 cast_impl_.play(); |
345 return; | 347 return; |
346 } | 348 } |
347 #endif | 349 #endif |
348 | 350 |
349 paused_ = false; | 351 paused_ = false; |
352 pipeline_.SetPlaybackRate(playback_rate_); | |
350 | 353 |
351 pipeline_.SetPlaybackRate(playback_rate_); | |
352 if (data_source_) | 354 if (data_source_) |
353 data_source_->MediaIsPlaying(); | 355 data_source_->MediaIsPlaying(); |
354 | 356 |
355 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PLAY)); | 357 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PLAY)); |
356 | 358 |
357 if (playback_rate_ > 0) | 359 if (playback_rate_ > 0) |
358 NotifyPlaybackStarted(); | 360 NotifyPlaybackStarted(); |
359 } | 361 } |
360 | 362 |
361 void WebMediaPlayerImpl::pause() { | 363 void WebMediaPlayerImpl::pause() { |
362 DVLOG(1) << __FUNCTION__; | 364 DVLOG(1) << __FUNCTION__; |
363 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 365 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
364 | 366 |
365 const bool was_already_paused = paused_ || playback_rate_ == 0; | 367 const bool was_already_paused = paused_ || playback_rate_ == 0; |
366 paused_ = true; | 368 paused_ = true; |
367 | 369 |
368 #if defined(OS_ANDROID) // WMPI_CAST | 370 #if defined(OS_ANDROID) // WMPI_CAST |
369 if (isRemote()) { | 371 if (isRemote()) { |
370 cast_impl_.pause(); | 372 cast_impl_.pause(); |
371 return; | 373 return; |
372 } | 374 } |
373 #endif | 375 #endif |
374 | 376 |
375 pipeline_.SetPlaybackRate(0.0); | 377 pipeline_.SetPlaybackRate(0.0); |
376 UpdatePausedTime(); | 378 |
379 // pause() may be called after playback has ended and the HTMLMediaElement | |
380 // requires that currentTime() == duration() after ending. We want to ensure | |
381 // |paused_time_| matches currentTime() in this case or a future seek() may | |
382 // incorrectly discard what it thinks is a seek to the existing time. | |
383 paused_time_ = | |
384 ended_ ? pipeline_.GetMediaDuration() : pipeline_.GetMediaTime(); | |
377 | 385 |
378 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PAUSE)); | 386 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PAUSE)); |
379 | 387 |
380 if (!was_already_paused) | 388 if (!was_already_paused) |
381 NotifyPlaybackPaused(); | 389 NotifyPlaybackPaused(); |
382 } | 390 } |
383 | 391 |
384 bool WebMediaPlayerImpl::supportsSave() const { | 392 bool WebMediaPlayerImpl::supportsSave() const { |
385 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 393 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
386 return supports_save_; | 394 return supports_save_; |
387 } | 395 } |
388 | 396 |
389 void WebMediaPlayerImpl::seek(double seconds) { | 397 void WebMediaPlayerImpl::seek(double seconds) { |
390 DVLOG(1) << __FUNCTION__ << "(" << seconds << "s)"; | 398 DVLOG(1) << __FUNCTION__ << "(" << seconds << "s)"; |
391 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 399 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
400 DoSeek(base::TimeDelta::FromSecondsD(seconds), true); | |
401 } | |
402 | |
403 void WebMediaPlayerImpl::DoSeek(base::TimeDelta time, bool time_updated) { | |
404 DCHECK(main_task_runner_->BelongsToCurrentThread()); | |
392 | 405 |
393 ended_ = false; | 406 ended_ = false; |
394 | 407 |
395 base::TimeDelta new_seek_time = base::TimeDelta::FromSecondsD(seconds); | |
396 | |
397 #if defined(OS_ANDROID) // WMPI_CAST | 408 #if defined(OS_ANDROID) // WMPI_CAST |
398 if (isRemote()) { | 409 if (isRemote()) { |
399 cast_impl_.seek(new_seek_time); | 410 cast_impl_.seek(time); |
400 return; | 411 return; |
401 } | 412 } |
402 #endif | 413 #endif |
403 | 414 |
404 ReadyState old_state = ready_state_; | 415 ReadyState old_state = ready_state_; |
405 if (ready_state_ > WebMediaPlayer::ReadyStateHaveMetadata) | 416 if (ready_state_ > WebMediaPlayer::ReadyStateHaveMetadata) |
406 SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata); | 417 SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata); |
407 | 418 |
408 if (seeking_ || suspended_) { | 419 // When paused, we know exactly what the current time is and can elide seeks |
409 // Once resuming, it's too late to change the resume time and so the | 420 // to it. However, there are two cases that are not elided: |
410 // implementation is a little different. | 421 // 1) When the pipeline state is not stable. |
411 bool is_suspended = suspended_ && !resuming_; | 422 // In this case we just let |pipeline_controller_| decide what to do, as |
412 | 423 // it has complete information. |
413 // If we are currently seeking or resuming to |new_seek_time|, skip the | 424 // 2) For MSE. |
414 // seek (except for MSE, which always seeks). | 425 // Because the buffers may have changed between seeks, MSE seeks are |
415 if (!is_suspended && new_seek_time == seek_time_) { | 426 // never elided. |
416 if (chunk_demuxer_) { | 427 if (paused_ && pipeline_controller_.IsStable() && paused_time_ == time && |
417 // Don't suppress any redundant in-progress MSE seek. There could have | 428 !chunk_demuxer_) { |
418 // been changes to the underlying buffers after seeking the demuxer and | 429 // If the ready state was high enough before, we can indicate that the seek |
419 // before receiving OnPipelineSeeked() for the currently in-progress | 430 // completed just by restoring it. Otherwise we will just wait for the real |
420 // seek. | 431 // ready state change to eventually happen. |
421 MEDIA_LOG(DEBUG, media_log_) | 432 if (old_state == ReadyStateHaveEnoughData) { |
422 << "Detected MediaSource seek to same time as in-progress seek to " | |
423 << seek_time_ << "."; | |
424 } else { | |
425 // Suppress all redundant seeks if unrestricted by media source demuxer | |
426 // API. | |
427 pending_seek_ = false; | |
428 pending_seek_time_ = base::TimeDelta(); | |
429 return; | |
430 } | |
431 } | |
432 | |
433 // If |chunk_demuxer_| is already seeking, cancel that seek and schedule the | |
434 // new one. | |
435 if (!is_suspended && chunk_demuxer_) | |
436 chunk_demuxer_->CancelPendingSeek(new_seek_time); | |
437 | |
438 // Schedule a seek once the current suspend or seek finishes. | |
439 pending_seek_ = true; | |
440 pending_seek_time_ = new_seek_time; | |
441 | |
442 // In the case of seeking while suspended, the seek is considered to have | |
443 // started immediately (but won't complete until the pipeline is resumed). | |
444 if (is_suspended) { | |
445 seeking_ = true; | |
446 seek_time_ = new_seek_time; | |
447 } | |
448 | |
449 return; | |
450 } | |
451 | |
452 media_log_->AddEvent(media_log_->CreateSeekEvent(seconds)); | |
453 | |
454 // Update our paused time. | |
455 // For non-MSE playbacks, in paused state ignore the seek operations to | |
456 // current time if the loading is completed and generate | |
457 // OnPipelineBufferingStateChanged event to eventually fire seeking and seeked | |
458 // events. We don't short-circuit MSE seeks in this logic because the | |
459 // underlying buffers around the seek time might have changed (or even been | |
460 // removed) since previous seek/preroll/pause action, and the pipeline might | |
461 // need to flush so the new buffers are decoded and rendered instead of the | |
462 // old ones. | |
463 if (paused_) { | |
464 if (paused_time_ != new_seek_time || chunk_demuxer_) { | |
465 paused_time_ = new_seek_time; | |
466 } else if (old_state == ReadyStateHaveEnoughData) { | |
467 main_task_runner_->PostTask( | 433 main_task_runner_->PostTask( |
468 FROM_HERE, | 434 FROM_HERE, |
469 base::Bind(&WebMediaPlayerImpl::OnPipelineBufferingStateChanged, | 435 base::Bind(&WebMediaPlayerImpl::OnPipelineBufferingStateChanged, |
470 AsWeakPtr(), BUFFERING_HAVE_ENOUGH)); | 436 AsWeakPtr(), BUFFERING_HAVE_ENOUGH)); |
471 return; | |
472 } | 437 } |
438 return; | |
473 } | 439 } |
474 | 440 |
475 seeking_ = true; | 441 seeking_ = true; |
476 seek_time_ = new_seek_time; | 442 seek_time_ = time; |
477 | 443 if (paused_) |
478 if (chunk_demuxer_) | 444 paused_time_ = time; |
479 chunk_demuxer_->StartWaitingForSeek(seek_time_); | 445 pipeline_controller_.Seek(time, time_updated); |
480 | |
481 pipeline_.Seek(seek_time_, BIND_TO_RENDER_LOOP1( | |
482 &WebMediaPlayerImpl::OnPipelineSeeked, true)); | |
483 } | 446 } |
484 | 447 |
485 void WebMediaPlayerImpl::setRate(double rate) { | 448 void WebMediaPlayerImpl::setRate(double rate) { |
486 DVLOG(1) << __FUNCTION__ << "(" << rate << ")"; | 449 DVLOG(1) << __FUNCTION__ << "(" << rate << ")"; |
487 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 450 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
488 | 451 |
489 // TODO(kylep): Remove when support for negatives is added. Also, modify the | 452 // TODO(kylep): Remove when support for negatives is added. Also, modify the |
490 // following checks so rewind uses reasonable values also. | 453 // following checks so rewind uses reasonable values also. |
491 if (rate < 0.0) | 454 if (rate < 0.0) |
492 return; | 455 return; |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
621 | 584 |
622 double WebMediaPlayerImpl::currentTime() const { | 585 double WebMediaPlayerImpl::currentTime() const { |
623 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 586 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
624 DCHECK_NE(ready_state_, WebMediaPlayer::ReadyStateHaveNothing); | 587 DCHECK_NE(ready_state_, WebMediaPlayer::ReadyStateHaveNothing); |
625 | 588 |
626 // TODO(scherkus): Replace with an explicit ended signal to HTMLMediaElement, | 589 // TODO(scherkus): Replace with an explicit ended signal to HTMLMediaElement, |
627 // see http://crbug.com/409280 | 590 // see http://crbug.com/409280 |
628 if (ended_) | 591 if (ended_) |
629 return duration(); | 592 return duration(); |
630 | 593 |
631 // We know the current seek time better than pipeline: pipeline may processing | 594 if (seeking()) |
632 // an earlier seek before a pending seek has been started, or it might not yet | 595 return seek_time_.InSecondsF(); |
633 // have the current seek time returnable via GetMediaTime(). | |
634 if (seeking()) { | |
635 return pending_seek_ ? pending_seek_time_.InSecondsF() | |
636 : seek_time_.InSecondsF(); | |
637 } | |
638 | 596 |
639 #if defined(OS_ANDROID) // WMPI_CAST | 597 #if defined(OS_ANDROID) // WMPI_CAST |
640 if (isRemote()) { | 598 if (isRemote()) |
641 return cast_impl_.currentTime(); | 599 return cast_impl_.currentTime(); |
642 } | |
643 #endif | 600 #endif |
644 | 601 |
645 if (paused_) { | 602 if (paused_) |
646 return paused_time_.InSecondsF(); | 603 return paused_time_.InSecondsF(); |
647 } | |
648 | 604 |
649 return pipeline_.GetMediaTime().InSecondsF(); | 605 return pipeline_.GetMediaTime().InSecondsF(); |
650 } | 606 } |
651 | 607 |
652 WebMediaPlayer::NetworkState WebMediaPlayerImpl::networkState() const { | 608 WebMediaPlayer::NetworkState WebMediaPlayerImpl::networkState() const { |
653 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 609 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
654 return network_state_; | 610 return network_state_; |
655 } | 611 } |
656 | 612 |
657 WebMediaPlayer::ReadyState WebMediaPlayerImpl::readyState() const { | 613 WebMediaPlayer::ReadyState WebMediaPlayerImpl::readyState() const { |
(...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
911 is_cdm_attached_ = true; | 867 is_cdm_attached_ = true; |
912 return; | 868 return; |
913 } | 869 } |
914 | 870 |
915 set_cdm_result_->completeWithError( | 871 set_cdm_result_->completeWithError( |
916 blink::WebContentDecryptionModuleExceptionNotSupportedError, 0, | 872 blink::WebContentDecryptionModuleExceptionNotSupportedError, 0, |
917 "Unable to set MediaKeys object"); | 873 "Unable to set MediaKeys object"); |
918 set_cdm_result_.reset(); | 874 set_cdm_result_.reset(); |
919 } | 875 } |
920 | 876 |
921 void WebMediaPlayerImpl::OnPipelineSeeked(bool time_changed, | 877 void WebMediaPlayerImpl::OnPipelineSeeked(bool time_updated) { |
922 PipelineStatus status) { | |
923 DVLOG(1) << __FUNCTION__ << "(" << time_changed << ", " << status << ")"; | |
924 DCHECK(main_task_runner_->BelongsToCurrentThread()); | |
925 | |
926 if (status != PIPELINE_OK) { | |
927 OnPipelineError(status); | |
928 return; | |
929 } | |
930 | |
931 // If we we're resuming into the playing state, notify the delegate. | |
932 if (resuming_ && playback_rate_ > 0 && !paused_) | |
933 NotifyPlaybackStarted(); | |
934 | |
935 // Whether or not the seek was caused by a resume, we're not suspended now. | |
936 resuming_ = false; | |
937 suspended_ = false; | |
938 | |
939 // If there is a pending suspend, the seek does not complete until after the | |
940 // next resume. | |
941 if (pending_suspend_) { | |
942 pending_suspend_ = false; | |
943 pending_time_change_ = time_changed; | |
944 Suspend(); | |
945 return; | |
946 } | |
947 | |
948 // Clear seek state. Note that if the seek was caused by a resume, then | |
949 // |seek_time_| is always set but |seeking_| is only set if there was a | |
950 // pending seek at the time. | |
951 seeking_ = false; | 878 seeking_ = false; |
952 seek_time_ = base::TimeDelta(); | 879 seek_time_ = base::TimeDelta(); |
953 | |
954 if (pending_seek_) { | |
955 double pending_seek_seconds = pending_seek_time_.InSecondsF(); | |
956 pending_seek_ = false; | |
957 pending_seek_time_ = base::TimeDelta(); | |
958 seek(pending_seek_seconds); | |
959 return; | |
960 } | |
961 | |
962 // Update our paused time. | |
963 if (paused_) | 880 if (paused_) |
964 UpdatePausedTime(); | 881 paused_time_ = pipeline_.GetMediaTime(); |
965 | 882 if (time_updated) |
966 should_notify_time_changed_ = time_changed; | 883 should_notify_time_changed_ = true; |
967 } | 884 } |
968 | 885 |
969 void WebMediaPlayerImpl::OnPipelineSuspended(PipelineStatus status) { | 886 void WebMediaPlayerImpl::OnPipelineSuspended() { |
970 DVLOG(1) << __FUNCTION__ << "(" << status << ")"; | |
971 DCHECK(main_task_runner_->BelongsToCurrentThread()); | |
972 | |
973 if (status != PIPELINE_OK) { | |
974 OnPipelineError(status); | |
975 return; | |
976 } | |
977 | |
978 suspending_ = false; | |
979 if (delegate_) | |
980 delegate_->PlayerGone(delegate_id_); | |
981 | |
982 #if defined(OS_ANDROID) | 887 #if defined(OS_ANDROID) |
983 if (isRemote()) { | 888 if (isRemote()) { |
984 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner(); | 889 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner(); |
985 if (frame) { | 890 if (frame) { |
986 compositor_->PaintFrameUsingOldRenderingPath(frame); | 891 compositor_->PaintFrameUsingOldRenderingPath(frame); |
987 } | 892 } |
988 } | 893 } |
989 #endif | 894 #endif |
990 | 895 |
991 if (pending_resume_ || pending_suspend_resume_cycle_) { | 896 if (pending_suspend_resume_cycle_) { |
992 pending_resume_ = false; | |
993 pending_suspend_resume_cycle_ = false; | 897 pending_suspend_resume_cycle_ = false; |
994 Resume(); | 898 pipeline_controller_.Resume(); |
995 return; | 899 return; |
996 } | 900 } |
997 } | 901 } |
998 | 902 |
999 void WebMediaPlayerImpl::OnPipelineEnded() { | 903 void WebMediaPlayerImpl::OnPipelineEnded() { |
1000 DVLOG(1) << __FUNCTION__; | 904 DVLOG(1) << __FUNCTION__; |
1001 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 905 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
1002 | 906 |
1003 // Ignore state changes until we've completed all outstanding seeks. | 907 // Ignore state changes until we've completed all outstanding operations. |
1004 if (seeking_ || pending_seek_) | 908 if (!pipeline_controller_.IsStable()) |
1005 return; | 909 return; |
1006 | 910 |
1007 ended_ = true; | 911 ended_ = true; |
1008 client_->timeChanged(); | 912 client_->timeChanged(); |
1009 } | 913 } |
1010 | 914 |
1011 void WebMediaPlayerImpl::OnPipelineError(PipelineStatus error) { | 915 void WebMediaPlayerImpl::OnPipelineError(PipelineStatus error) { |
1012 DVLOG(1) << __FUNCTION__; | 916 DVLOG(1) << __FUNCTION__; |
1013 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 917 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
1014 DCHECK_NE(error, PIPELINE_OK); | 918 DCHECK_NE(error, PIPELINE_OK); |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1054 // playback. | 958 // playback. |
1055 if (delegate_ && delegate_->IsHidden()) | 959 if (delegate_ && delegate_->IsHidden()) |
1056 OnHidden(false); | 960 OnHidden(false); |
1057 } | 961 } |
1058 } | 962 } |
1059 | 963 |
1060 void WebMediaPlayerImpl::OnPipelineBufferingStateChanged( | 964 void WebMediaPlayerImpl::OnPipelineBufferingStateChanged( |
1061 BufferingState buffering_state) { | 965 BufferingState buffering_state) { |
1062 DVLOG(1) << __FUNCTION__ << "(" << buffering_state << ")"; | 966 DVLOG(1) << __FUNCTION__ << "(" << buffering_state << ")"; |
1063 | 967 |
1064 // Ignore buffering state changes until we've completed all outstanding seeks. | 968 // Ignore buffering state changes until we've completed all outstanding |
1065 if (seeking_ || pending_seek_) | 969 // operations. |
970 if (!pipeline_controller_.IsStable()) | |
1066 return; | 971 return; |
1067 | 972 |
1068 // TODO(scherkus): Handle other buffering states when Pipeline starts using | 973 // TODO(scherkus): Handle other buffering states when Pipeline starts using |
1069 // them and translate them ready state changes http://crbug.com/144683 | 974 // them and translate them ready state changes http://crbug.com/144683 |
1070 DCHECK_EQ(buffering_state, BUFFERING_HAVE_ENOUGH); | 975 DCHECK_EQ(buffering_state, BUFFERING_HAVE_ENOUGH); |
1071 SetReadyState(WebMediaPlayer::ReadyStateHaveEnoughData); | 976 SetReadyState(WebMediaPlayer::ReadyStateHaveEnoughData); |
1072 | 977 |
1073 // Let the DataSource know we have enough data. It may use this information to | 978 // Let the DataSource know we have enough data. It may use this information to |
1074 // release unused network connections. | 979 // release unused network connections. |
1075 if (data_source_) | 980 if (data_source_) |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1129 return; | 1034 return; |
1130 } | 1035 } |
1131 | 1036 |
1132 #if defined(OS_ANDROID) | 1037 #if defined(OS_ANDROID) |
1133 // If we're remote, the pipeline should already be suspended. | 1038 // If we're remote, the pipeline should already be suspended. |
1134 if (isRemote()) | 1039 if (isRemote()) |
1135 return; | 1040 return; |
1136 #endif | 1041 #endif |
1137 | 1042 |
1138 if (must_suspend || hasVideo()) | 1043 if (must_suspend || hasVideo()) |
1139 ScheduleSuspend(); | 1044 pipeline_controller_.Suspend(); |
1140 } | |
1141 | |
1142 void WebMediaPlayerImpl::ScheduleSuspend() { | |
1143 if (!pipeline_.IsRunning()) | |
1144 return; | |
1145 | |
1146 if (resuming_ || seeking_) { | |
1147 pending_suspend_ = true; | |
1148 return; | |
1149 } | |
1150 | |
1151 if (pending_resume_) { | |
1152 pending_resume_ = false; | |
1153 return; | |
1154 } | |
1155 | |
1156 Suspend(); | |
1157 } | |
1158 | |
1159 void WebMediaPlayerImpl::Suspend() { | |
1160 DCHECK(main_task_runner_->BelongsToCurrentThread()); | |
1161 | |
1162 // Since Pipeline::IsRunning() may be set on the media thread there are cases | |
1163 // where two suspends might be issued concurrently. | |
1164 if (suspended_) | |
1165 return; | |
1166 | |
1167 suspended_ = true; | |
1168 suspending_ = true; | |
1169 pipeline_.Suspend( | |
1170 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineSuspended)); | |
1171 } | 1045 } |
1172 | 1046 |
1173 void WebMediaPlayerImpl::OnShown() { | 1047 void WebMediaPlayerImpl::OnShown() { |
1174 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 1048 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
1175 | 1049 |
1176 #if !defined(OS_ANDROID) | 1050 #if !defined(OS_ANDROID) |
1177 // Suspend/Resume is enabled by default on Android. | 1051 // Suspend/Resume is enabled by default on Android. |
1178 if (!base::CommandLine::ForCurrentProcess()->HasSwitch( | 1052 if (!base::CommandLine::ForCurrentProcess()->HasSwitch( |
1179 switches::kEnableMediaSuspend)) { | 1053 switches::kEnableMediaSuspend)) { |
1180 return; | 1054 return; |
1181 } | 1055 } |
1182 #endif // !defined(OS_ANDROID) | 1056 #endif // !defined(OS_ANDROID) |
1183 | 1057 |
1184 if (base::CommandLine::ForCurrentProcess()->HasSwitch( | 1058 if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
1185 switches::kDisableMediaSuspend)) { | 1059 switches::kDisableMediaSuspend)) { |
1186 return; | 1060 return; |
1187 } | 1061 } |
1188 | 1062 |
1189 #if defined(OS_ANDROID) | 1063 #if defined(OS_ANDROID) |
1190 // If we're remote, the pipeline should stay suspended. | 1064 // If we're remote, the pipeline should stay suspended. |
1191 if (isRemote()) | 1065 if (isRemote()) |
1192 return; | 1066 return; |
1193 #endif | 1067 #endif |
1194 | 1068 |
1195 ScheduleResume(); | 1069 pipeline_controller_.Resume(); |
1196 } | |
1197 | |
1198 void WebMediaPlayerImpl::ScheduleResume() { | |
1199 if (!pipeline_.IsRunning()) | |
1200 return; | |
1201 | |
1202 if (suspending_) { | |
1203 pending_resume_ = true; | |
1204 return; | |
1205 } | |
1206 | |
1207 if (pending_suspend_) { | |
1208 pending_suspend_ = false; | |
1209 return; | |
1210 } | |
1211 | |
1212 // Might already be resuming iff we came back from remote playback recently. | |
1213 if (suspended_ && !resuming_) | |
1214 Resume(); | |
1215 } | 1070 } |
1216 | 1071 |
1217 void WebMediaPlayerImpl::OnPlay() { | 1072 void WebMediaPlayerImpl::OnPlay() { |
1218 play(); | 1073 play(); |
1219 client_->playbackStateChanged(); | 1074 client_->playbackStateChanged(); |
1220 } | 1075 } |
1221 | 1076 |
1222 void WebMediaPlayerImpl::OnPause() { | 1077 void WebMediaPlayerImpl::OnPause() { |
1223 pause(); | 1078 pause(); |
1224 client_->playbackStateChanged(); | 1079 client_->playbackStateChanged(); |
1225 } | 1080 } |
1226 | 1081 |
1227 void WebMediaPlayerImpl::OnVolumeMultiplierUpdate(double multiplier) { | 1082 void WebMediaPlayerImpl::OnVolumeMultiplierUpdate(double multiplier) { |
1228 volume_multiplier_ = multiplier; | 1083 volume_multiplier_ = multiplier; |
1229 setVolume(volume_); | 1084 setVolume(volume_); |
1230 } | 1085 } |
1231 | 1086 |
1232 void WebMediaPlayerImpl::Resume() { | |
1233 DCHECK(main_task_runner_->BelongsToCurrentThread()); | |
1234 CHECK(suspended_); | |
1235 CHECK(!resuming_); | |
1236 | |
1237 // If there was a time change pending when we suspended (which can happen when | |
1238 // we suspend immediately after a seek), surface it after resuming. | |
1239 bool time_changed = pending_time_change_; | |
1240 pending_time_change_ = false; | |
1241 | |
1242 if (seeking_ || pending_seek_) { | |
1243 if (pending_seek_) { | |
1244 seek_time_ = pending_seek_time_; | |
1245 pending_seek_ = false; | |
1246 pending_seek_time_ = base::TimeDelta(); | |
1247 } | |
1248 time_changed = true; | |
1249 } else { | |
1250 // It is safe to call GetCurrentFrameTimestamp() because VFC is stopped | |
1251 // during Suspend(). It won't be started again until after Resume() is | |
1252 // called. Use the pipeline time if there's no video. | |
1253 seek_time_ = hasVideo() ? compositor_->GetCurrentFrameTimestamp() | |
1254 : pipeline_.GetMediaTime(); | |
1255 } | |
1256 | |
1257 if (chunk_demuxer_) | |
1258 chunk_demuxer_->StartWaitingForSeek(seek_time_); | |
1259 | |
1260 resuming_ = true; | |
1261 pipeline_.Resume(CreateRenderer(), seek_time_, | |
1262 BIND_TO_RENDER_LOOP1(&WebMediaPlayerImpl::OnPipelineSeeked, | |
1263 time_changed)); | |
1264 } | |
1265 | |
1266 void WebMediaPlayerImpl::ScheduleRestart() { | 1087 void WebMediaPlayerImpl::ScheduleRestart() { |
1267 // If we're suspended but not resuming there is no need to restart because | 1088 if (!pipeline_controller_.IsSuspended()) { |
1268 // there is no renderer to kill. | |
1269 if (!suspended_ || resuming_) { | |
1270 pending_suspend_resume_cycle_ = true; | 1089 pending_suspend_resume_cycle_ = true; |
1271 ScheduleSuspend(); | 1090 pipeline_controller_.Suspend(); |
1272 } | 1091 } |
1273 } | 1092 } |
1274 | 1093 |
1275 #if defined(OS_ANDROID) // WMPI_CAST | 1094 #if defined(OS_ANDROID) // WMPI_CAST |
1276 | |
1277 bool WebMediaPlayerImpl::isRemote() const { | 1095 bool WebMediaPlayerImpl::isRemote() const { |
1278 return cast_impl_.isRemote(); | 1096 return cast_impl_.isRemote(); |
1279 } | 1097 } |
1280 | 1098 |
1281 void WebMediaPlayerImpl::SetMediaPlayerManager( | 1099 void WebMediaPlayerImpl::SetMediaPlayerManager( |
1282 RendererMediaPlayerManagerInterface* media_player_manager) { | 1100 RendererMediaPlayerManagerInterface* media_player_manager) { |
1283 cast_impl_.SetMediaPlayerManager(media_player_manager); | 1101 cast_impl_.SetMediaPlayerManager(media_player_manager); |
1284 } | 1102 } |
1285 | 1103 |
1286 void WebMediaPlayerImpl::requestRemotePlayback() { | 1104 void WebMediaPlayerImpl::requestRemotePlayback() { |
1287 cast_impl_.requestRemotePlayback(); | 1105 cast_impl_.requestRemotePlayback(); |
1288 } | 1106 } |
1289 | 1107 |
1290 void WebMediaPlayerImpl::requestRemotePlaybackControl() { | 1108 void WebMediaPlayerImpl::requestRemotePlaybackControl() { |
1291 cast_impl_.requestRemotePlaybackControl(); | 1109 cast_impl_.requestRemotePlaybackControl(); |
1292 } | 1110 } |
1293 | 1111 |
1294 void WebMediaPlayerImpl::OnRemotePlaybackEnded() { | 1112 void WebMediaPlayerImpl::OnRemotePlaybackEnded() { |
1295 DVLOG(1) << __FUNCTION__; | 1113 DVLOG(1) << __FUNCTION__; |
1296 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 1114 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
1297 | 1115 |
1298 ended_ = true; | 1116 ended_ = true; |
1299 client_->timeChanged(); | 1117 client_->timeChanged(); |
1300 } | 1118 } |
1301 | 1119 |
1302 void WebMediaPlayerImpl::OnDisconnectedFromRemoteDevice(double t) { | 1120 void WebMediaPlayerImpl::OnDisconnectedFromRemoteDevice(double t) { |
1303 paused_time_ = base::TimeDelta::FromSecondsD(t); | 1121 DoSeek(base::TimeDelta::FromSecondsD(t), false); |
1304 pending_seek_ = true; | 1122 if (delegate_ && !delegate_->IsHidden()) |
1305 pending_seek_time_ = paused_time_; | 1123 pipeline_controller_.Resume(); |
1306 | 1124 |
1307 ScheduleResume(); | |
1308 | |
1309 if (paused_time_ == pipeline_.GetMediaDuration()) { | |
1310 ended_ = true; | |
1311 } | |
1312 // We already told the delegate we're paused when remoting started. | 1125 // We already told the delegate we're paused when remoting started. |
1313 client_->playbackStateChanged(); | 1126 client_->playbackStateChanged(); |
1314 client_->disconnectedFromRemoteDevice(); | 1127 client_->disconnectedFromRemoteDevice(); |
1315 } | 1128 } |
1316 | 1129 |
1317 void WebMediaPlayerImpl::SuspendForRemote() { | 1130 void WebMediaPlayerImpl::SuspendForRemote() { |
1318 if (suspended_ && !suspending_) { | 1131 if (!pipeline_controller_.IsSuspended()) { |
1132 pipeline_controller_.Suspend(); | |
1133 } else { | |
1134 // TODO(sandersd): If PipelineController::Suspend() called |suspended_cb| | |
1135 // when already suspended, we wouldn't need this case. | |
1319 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner(); | 1136 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner(); |
1320 if (frame) { | 1137 if (frame) { |
1321 compositor_->PaintFrameUsingOldRenderingPath(frame); | 1138 compositor_->PaintFrameUsingOldRenderingPath(frame); |
1322 } | 1139 } |
1323 } | 1140 } |
1324 ScheduleSuspend(); | |
1325 } | 1141 } |
1326 | 1142 |
1327 gfx::Size WebMediaPlayerImpl::GetCanvasSize() const { | 1143 gfx::Size WebMediaPlayerImpl::GetCanvasSize() const { |
1328 if (!video_weblayer_) | 1144 if (!video_weblayer_) |
1329 return pipeline_metadata_.natural_size; | 1145 return pipeline_metadata_.natural_size; |
1330 | 1146 |
1331 return video_weblayer_->bounds(); | 1147 return video_weblayer_->bounds(); |
1332 } | 1148 } |
1333 | 1149 |
1334 void WebMediaPlayerImpl::SetDeviceScaleFactor(float scale_factor) { | 1150 void WebMediaPlayerImpl::SetDeviceScaleFactor(float scale_factor) { |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1425 chunk_demuxer_ = new ChunkDemuxer( | 1241 chunk_demuxer_ = new ChunkDemuxer( |
1426 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnDemuxerOpened), | 1242 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnDemuxerOpened), |
1427 encrypted_media_init_data_cb, media_log_, true); | 1243 encrypted_media_init_data_cb, media_log_, true); |
1428 demuxer_.reset(chunk_demuxer_); | 1244 demuxer_.reset(chunk_demuxer_); |
1429 } | 1245 } |
1430 | 1246 |
1431 // ... and we're ready to go! | 1247 // ... and we're ready to go! |
1432 seeking_ = true; | 1248 seeking_ = true; |
1433 | 1249 |
1434 // TODO(sandersd): On Android, defer Start() if the tab is not visible. | 1250 // TODO(sandersd): On Android, defer Start() if the tab is not visible. |
1435 pipeline_.Start( | 1251 pipeline_controller_.Start( |
1436 demuxer_.get(), CreateRenderer(), | 1252 chunk_demuxer_, demuxer_.get(), |
1437 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineEnded), | 1253 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineEnded), |
1438 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineError), | |
1439 BIND_TO_RENDER_LOOP1(&WebMediaPlayerImpl::OnPipelineSeeked, false), | |
1440 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineMetadata), | 1254 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineMetadata), |
1441 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineBufferingStateChanged), | 1255 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineBufferingStateChanged), |
1442 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnDurationChanged), | 1256 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnDurationChanged), |
1443 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnAddTextTrack), | 1257 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnAddTextTrack), |
1444 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnWaitingForDecryptionKey)); | 1258 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnWaitingForDecryptionKey)); |
1445 } | 1259 } |
1446 | 1260 |
1447 void WebMediaPlayerImpl::SetNetworkState(WebMediaPlayer::NetworkState state) { | 1261 void WebMediaPlayerImpl::SetNetworkState(WebMediaPlayer::NetworkState state) { |
1448 DVLOG(1) << __FUNCTION__ << "(" << state << ")"; | 1262 DVLOG(1) << __FUNCTION__ << "(" << state << ")"; |
1449 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 1263 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1537 base::WaitableEvent event(false, false); | 1351 base::WaitableEvent event(false, false); |
1538 compositor_task_runner_->PostTask(FROM_HERE, | 1352 compositor_task_runner_->PostTask(FROM_HERE, |
1539 base::Bind(&GetCurrentFrameAndSignal, | 1353 base::Bind(&GetCurrentFrameAndSignal, |
1540 base::Unretained(compositor_), | 1354 base::Unretained(compositor_), |
1541 &video_frame, | 1355 &video_frame, |
1542 &event)); | 1356 &event)); |
1543 event.Wait(); | 1357 event.Wait(); |
1544 return video_frame; | 1358 return video_frame; |
1545 } | 1359 } |
1546 | 1360 |
1547 void WebMediaPlayerImpl::UpdatePausedTime() { | |
1548 DCHECK(main_task_runner_->BelongsToCurrentThread()); | |
1549 | |
1550 // pause() may be called after playback has ended and the HTMLMediaElement | |
1551 // requires that currentTime() == duration() after ending. We want to ensure | |
1552 // |paused_time_| matches currentTime() in this case or a future seek() may | |
1553 // incorrectly discard what it thinks is a seek to the existing time. | |
1554 paused_time_ = | |
1555 ended_ ? pipeline_.GetMediaDuration() : pipeline_.GetMediaTime(); | |
1556 } | |
1557 | |
1558 void WebMediaPlayerImpl::NotifyPlaybackStarted() { | 1361 void WebMediaPlayerImpl::NotifyPlaybackStarted() { |
1559 #if defined(OS_ANDROID) // WMPI_CAST | 1362 #if defined(OS_ANDROID) // WMPI_CAST |
1560 // We do not tell our delegates about remote playback, becuase that would | 1363 // We do not tell our delegates about remote playback, becuase that would |
1561 // keep the device awake, which is not what we want. | 1364 // keep the device awake, which is not what we want. |
1562 if (isRemote()) | 1365 if (isRemote()) |
1563 return; | 1366 return; |
1564 #endif | 1367 #endif |
1565 if (delegate_) { | 1368 if (delegate_) { |
1566 delegate_->DidPlay(delegate_id_, hasVideo(), hasAudio(), false, | 1369 delegate_->DidPlay(delegate_id_, hasVideo(), hasAudio(), false, |
1567 pipeline_.GetMediaDuration()); | 1370 pipeline_.GetMediaDuration()); |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1615 << ", Video: " << stats.video_memory_usage << ", DataSource: " | 1418 << ", Video: " << stats.video_memory_usage << ", DataSource: " |
1616 << (data_source_ ? data_source_->GetMemoryUsage() : 0) | 1419 << (data_source_ ? data_source_->GetMemoryUsage() : 0) |
1617 << ", Demuxer: " << demuxer_memory_usage; | 1420 << ", Demuxer: " << demuxer_memory_usage; |
1618 | 1421 |
1619 const int64_t delta = current_memory_usage - last_reported_memory_usage_; | 1422 const int64_t delta = current_memory_usage - last_reported_memory_usage_; |
1620 last_reported_memory_usage_ = current_memory_usage; | 1423 last_reported_memory_usage_ = current_memory_usage; |
1621 adjust_allocated_memory_cb_.Run(delta); | 1424 adjust_allocated_memory_cb_.Run(delta); |
1622 } | 1425 } |
1623 | 1426 |
1624 } // namespace media | 1427 } // namespace media |
OLD | NEW |