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_controller_( | |
148 &pipeline_, | |
149 base::Bind(&WebMediaPlayerImpl::CreateRenderer, | |
150 base::Unretained(this)), | |
DaleCurtis
2016/02/24 01:48:24
Why the mix of unretained w/ AsWeakPtr() here?
sandersd (OOO until July 31)
2016/02/25 00:16:26
CreateRenderer() is a factory method; you can't bi
xhwang
2016/02/25 18:00:10
The CDM creation in CdmFactory::Create() is async,
| |
151 base::Bind(&WebMediaPlayerImpl::OnPipelineSeeked, AsWeakPtr()), | |
152 base::Bind(&WebMediaPlayerImpl::OnPipelineSuspended, AsWeakPtr()), | |
153 base::Bind(&WebMediaPlayerImpl::OnPipelineError, AsWeakPtr())), | |
146 load_type_(LoadTypeURL), | 154 load_type_(LoadTypeURL), |
147 opaque_(false), | 155 opaque_(false), |
148 playback_rate_(0.0), | 156 playback_rate_(0.0), |
149 paused_(true), | 157 paused_(true), |
150 seeking_(false), | 158 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 pending_suspend_resume_cycle_(false), | 159 pending_suspend_resume_cycle_(false), |
158 ended_(false), | 160 ended_(false), |
159 pending_seek_(false), | |
160 should_notify_time_changed_(false), | |
161 fullscreen_(false), | 161 fullscreen_(false), |
162 decoder_requires_restart_for_fullscreen_(false), | 162 decoder_requires_restart_for_fullscreen_(false), |
163 client_(client), | 163 client_(client), |
164 encrypted_client_(encrypted_client), | 164 encrypted_client_(encrypted_client), |
165 delegate_(delegate), | 165 delegate_(delegate), |
166 delegate_id_(0), | 166 delegate_id_(0), |
167 defer_load_cb_(params.defer_load_cb()), | 167 defer_load_cb_(params.defer_load_cb()), |
168 context_3d_cb_(params.context_3d_cb()), | 168 context_3d_cb_(params.context_3d_cb()), |
169 adjust_allocated_memory_cb_(params.adjust_allocated_memory_cb()), | 169 adjust_allocated_memory_cb_(params.adjust_allocated_memory_cb()), |
170 last_reported_memory_usage_(0), | 170 last_reported_memory_usage_(0), |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
221 if (delegate_) { | 221 if (delegate_) { |
222 delegate_->PlayerGone(delegate_id_); | 222 delegate_->PlayerGone(delegate_id_); |
223 delegate_->RemoveObserver(delegate_id_); | 223 delegate_->RemoveObserver(delegate_id_); |
224 } | 224 } |
225 | 225 |
226 // Abort any pending IO so stopping the pipeline doesn't get blocked. | 226 // Abort any pending IO so stopping the pipeline doesn't get blocked. |
227 if (data_source_) | 227 if (data_source_) |
228 data_source_->Abort(); | 228 data_source_->Abort(); |
229 if (chunk_demuxer_) { | 229 if (chunk_demuxer_) { |
230 chunk_demuxer_->Shutdown(); | 230 chunk_demuxer_->Shutdown(); |
231 chunk_demuxer_ = NULL; | 231 chunk_demuxer_ = nullptr; |
232 } | 232 } |
233 | 233 |
234 renderer_factory_.reset(); | 234 renderer_factory_.reset(); |
235 | 235 |
236 // Make sure to kill the pipeline so there's no more media threads running. | 236 // Make sure to kill the pipeline so there's no more media threads running. |
237 // Note: stopping the pipeline might block for a long time. | 237 // Note: stopping the pipeline might block for a long time. |
238 base::WaitableEvent waiter(false, false); | 238 base::WaitableEvent waiter(false, false); |
239 pipeline_.Stop( | 239 pipeline_.Stop( |
240 base::Bind(&base::WaitableEvent::Signal, base::Unretained(&waiter))); | 240 base::Bind(&base::WaitableEvent::Signal, base::Unretained(&waiter))); |
241 waiter.Wait(); | 241 waiter.Wait(); |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
333 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 333 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
334 | 334 |
335 #if defined(OS_ANDROID) // WMPI_CAST | 335 #if defined(OS_ANDROID) // WMPI_CAST |
336 if (isRemote()) { | 336 if (isRemote()) { |
337 cast_impl_.play(); | 337 cast_impl_.play(); |
338 return; | 338 return; |
339 } | 339 } |
340 #endif | 340 #endif |
341 | 341 |
342 paused_ = false; | 342 paused_ = false; |
343 pipeline_.SetPlaybackRate(playback_rate_); | |
343 | 344 |
344 pipeline_.SetPlaybackRate(playback_rate_); | |
345 if (data_source_) | 345 if (data_source_) |
346 data_source_->MediaIsPlaying(); | 346 data_source_->MediaIsPlaying(); |
347 | 347 |
348 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PLAY)); | 348 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PLAY)); |
349 | 349 |
350 if (playback_rate_ > 0) | 350 if (playback_rate_ > 0) |
351 NotifyPlaybackStarted(); | 351 NotifyPlaybackStarted(); |
352 } | 352 } |
353 | 353 |
354 void WebMediaPlayerImpl::pause() { | 354 void WebMediaPlayerImpl::pause() { |
355 DVLOG(1) << __FUNCTION__; | 355 DVLOG(1) << __FUNCTION__; |
356 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 356 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
357 | 357 |
358 const bool was_already_paused = paused_ || playback_rate_ == 0; | 358 const bool was_already_paused = paused_ || playback_rate_ == 0; |
359 paused_ = true; | 359 paused_ = true; |
360 | 360 |
361 #if defined(OS_ANDROID) // WMPI_CAST | 361 #if defined(OS_ANDROID) // WMPI_CAST |
362 if (isRemote()) { | 362 if (isRemote()) { |
363 cast_impl_.pause(); | 363 cast_impl_.pause(); |
364 return; | 364 return; |
365 } | 365 } |
366 #endif | 366 #endif |
367 | 367 |
368 pipeline_.SetPlaybackRate(0.0); | 368 pipeline_.SetPlaybackRate(0.0); |
369 UpdatePausedTime(); | 369 |
370 // pause() may be called after playback has ended and the HTMLMediaElement | |
371 // requires that currentTime() == duration() after ending. We want to ensure | |
372 // |paused_time_| matches currentTime() in this case or a future seek() may | |
373 // incorrectly discard what it thinks is a seek to the existing time. | |
374 paused_time_ = | |
375 ended_ ? pipeline_.GetMediaDuration() : pipeline_.GetMediaTime(); | |
370 | 376 |
371 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PAUSE)); | 377 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PAUSE)); |
372 | 378 |
373 if (!was_already_paused) | 379 if (!was_already_paused) |
374 NotifyPlaybackPaused(); | 380 NotifyPlaybackPaused(); |
375 } | 381 } |
376 | 382 |
377 bool WebMediaPlayerImpl::supportsSave() const { | 383 bool WebMediaPlayerImpl::supportsSave() const { |
378 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 384 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
379 return supports_save_; | 385 return supports_save_; |
380 } | 386 } |
381 | 387 |
382 void WebMediaPlayerImpl::seek(double seconds) { | 388 void WebMediaPlayerImpl::seek(double seconds) { |
383 DVLOG(1) << __FUNCTION__ << "(" << seconds << "s)"; | 389 DVLOG(1) << __FUNCTION__ << "(" << seconds << "s)"; |
384 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 390 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
391 DoSeek(base::TimeDelta::FromSecondsD(seconds), true); | |
392 } | |
393 | |
394 void WebMediaPlayerImpl::DoSeek(base::TimeDelta time, bool time_updated) { | |
395 DCHECK(main_task_runner_->BelongsToCurrentThread()); | |
385 | 396 |
386 ended_ = false; | 397 ended_ = false; |
387 | 398 |
388 base::TimeDelta new_seek_time = base::TimeDelta::FromSecondsD(seconds); | |
389 | |
390 #if defined(OS_ANDROID) // WMPI_CAST | 399 #if defined(OS_ANDROID) // WMPI_CAST |
391 if (isRemote()) { | 400 if (isRemote()) { |
392 cast_impl_.seek(new_seek_time); | 401 cast_impl_.seek(time); |
393 return; | 402 return; |
394 } | 403 } |
395 #endif | 404 #endif |
396 | 405 |
397 ReadyState old_state = ready_state_; | 406 ReadyState old_state = ready_state_; |
398 if (ready_state_ > WebMediaPlayer::ReadyStateHaveMetadata) | 407 if (ready_state_ > WebMediaPlayer::ReadyStateHaveMetadata) |
399 SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata); | 408 SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata); |
400 | 409 |
401 if (seeking_ || suspended_) { | 410 // When paused, we know exactly what the current time is and can elide seeks |
402 // Once resuming, it's too late to change the resume time and so the | 411 // to it. However, there are two cases that are not elided: |
403 // implementation is a little different. | 412 // 1) When the pipeline state is not stable. |
404 bool is_suspended = suspended_ && !resuming_; | 413 // In this case we just let |pipeline_controller_| decide what to do, as |
405 | 414 // it has complete information. |
406 // If we are currently seeking or resuming to |new_seek_time|, skip the | 415 // 2) For MSE. |
407 // seek (except for MSE, which always seeks). | 416 // Because the buffers may have changed between seeks, MSE seeks are |
408 if (!is_suspended && new_seek_time == seek_time_) { | 417 // never elided. |
409 if (chunk_demuxer_) { | 418 if (paused_ && pipeline_controller_.IsStable() && paused_time_ == time && |
410 // Don't suppress any redundant in-progress MSE seek. There could have | 419 !chunk_demuxer_) { |
411 // been changes to the underlying buffers after seeking the demuxer and | 420 // If the ready state was high enough before, we can indicate that the seek |
412 // before receiving OnPipelineSeeked() for the currently in-progress | 421 // completed just by restoring it. Otherwise we will just wait for the real |
413 // seek. | 422 // ready state change to eventually happen. |
414 MEDIA_LOG(DEBUG, media_log_) | 423 if (old_state == ReadyStateHaveEnoughData) { |
415 << "Detected MediaSource seek to same time as in-progress seek to " | |
416 << seek_time_ << "."; | |
417 } else { | |
418 // Suppress all redundant seeks if unrestricted by media source demuxer | |
419 // API. | |
420 pending_seek_ = false; | |
421 pending_seek_time_ = base::TimeDelta(); | |
422 return; | |
423 } | |
424 } | |
425 | |
426 // If |chunk_demuxer_| is already seeking, cancel that seek and schedule the | |
427 // new one. | |
428 if (!is_suspended && chunk_demuxer_) | |
429 chunk_demuxer_->CancelPendingSeek(new_seek_time); | |
430 | |
431 // Schedule a seek once the current suspend or seek finishes. | |
432 pending_seek_ = true; | |
433 pending_seek_time_ = new_seek_time; | |
434 | |
435 // In the case of seeking while suspended, the seek is considered to have | |
436 // started immediately (but won't complete until the pipeline is resumed). | |
437 if (is_suspended) { | |
438 seeking_ = true; | |
439 seek_time_ = new_seek_time; | |
440 } | |
441 | |
442 return; | |
443 } | |
444 | |
445 media_log_->AddEvent(media_log_->CreateSeekEvent(seconds)); | |
446 | |
447 // Update our paused time. | |
448 // For non-MSE playbacks, in paused state ignore the seek operations to | |
449 // current time if the loading is completed and generate | |
450 // OnPipelineBufferingStateChanged event to eventually fire seeking and seeked | |
451 // events. We don't short-circuit MSE seeks in this logic because the | |
452 // underlying buffers around the seek time might have changed (or even been | |
453 // removed) since previous seek/preroll/pause action, and the pipeline might | |
454 // need to flush so the new buffers are decoded and rendered instead of the | |
455 // old ones. | |
456 if (paused_) { | |
457 if (paused_time_ != new_seek_time || chunk_demuxer_) { | |
458 paused_time_ = new_seek_time; | |
459 } else if (old_state == ReadyStateHaveEnoughData) { | |
460 main_task_runner_->PostTask( | 424 main_task_runner_->PostTask( |
461 FROM_HERE, | 425 FROM_HERE, |
462 base::Bind(&WebMediaPlayerImpl::OnPipelineBufferingStateChanged, | 426 base::Bind(&WebMediaPlayerImpl::OnPipelineBufferingStateChanged, |
463 AsWeakPtr(), BUFFERING_HAVE_ENOUGH)); | 427 AsWeakPtr(), BUFFERING_HAVE_ENOUGH)); |
464 return; | |
465 } | 428 } |
429 return; | |
466 } | 430 } |
467 | 431 |
468 seeking_ = true; | 432 seeking_ = true; |
469 seek_time_ = new_seek_time; | 433 seek_time_ = time; |
470 | 434 if (paused_) |
471 if (chunk_demuxer_) | 435 paused_time_ = time; |
472 chunk_demuxer_->StartWaitingForSeek(seek_time_); | 436 pipeline_controller_.Seek(time, time_updated); |
473 | |
474 pipeline_.Seek(seek_time_, BIND_TO_RENDER_LOOP1( | |
475 &WebMediaPlayerImpl::OnPipelineSeeked, true)); | |
476 } | 437 } |
477 | 438 |
478 void WebMediaPlayerImpl::setRate(double rate) { | 439 void WebMediaPlayerImpl::setRate(double rate) { |
479 DVLOG(1) << __FUNCTION__ << "(" << rate << ")"; | 440 DVLOG(1) << __FUNCTION__ << "(" << rate << ")"; |
480 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 441 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
481 | 442 |
482 // TODO(kylep): Remove when support for negatives is added. Also, modify the | 443 // TODO(kylep): Remove when support for negatives is added. Also, modify the |
483 // following checks so rewind uses reasonable values also. | 444 // following checks so rewind uses reasonable values also. |
484 if (rate < 0.0) | 445 if (rate < 0.0) |
485 return; | 446 return; |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
614 | 575 |
615 double WebMediaPlayerImpl::currentTime() const { | 576 double WebMediaPlayerImpl::currentTime() const { |
616 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 577 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
617 DCHECK_NE(ready_state_, WebMediaPlayer::ReadyStateHaveNothing); | 578 DCHECK_NE(ready_state_, WebMediaPlayer::ReadyStateHaveNothing); |
618 | 579 |
619 // TODO(scherkus): Replace with an explicit ended signal to HTMLMediaElement, | 580 // TODO(scherkus): Replace with an explicit ended signal to HTMLMediaElement, |
620 // see http://crbug.com/409280 | 581 // see http://crbug.com/409280 |
621 if (ended_) | 582 if (ended_) |
622 return duration(); | 583 return duration(); |
623 | 584 |
624 // We know the current seek time better than pipeline: pipeline may processing | 585 if (seeking()) |
625 // an earlier seek before a pending seek has been started, or it might not yet | 586 return seek_time_.InSecondsF(); |
626 // have the current seek time returnable via GetMediaTime(). | |
627 if (seeking()) { | |
628 return pending_seek_ ? pending_seek_time_.InSecondsF() | |
629 : seek_time_.InSecondsF(); | |
630 } | |
631 | 587 |
632 #if defined(OS_ANDROID) // WMPI_CAST | 588 #if defined(OS_ANDROID) // WMPI_CAST |
633 if (isRemote()) { | 589 if (isRemote()) |
634 return cast_impl_.currentTime(); | 590 return cast_impl_.currentTime(); |
635 } | |
636 #endif | 591 #endif |
637 | 592 |
638 if (paused_) { | 593 if (paused_) |
639 return paused_time_.InSecondsF(); | 594 return paused_time_.InSecondsF(); |
640 } | |
641 | 595 |
642 return pipeline_.GetMediaTime().InSecondsF(); | 596 return pipeline_.GetMediaTime().InSecondsF(); |
643 } | 597 } |
644 | 598 |
645 WebMediaPlayer::NetworkState WebMediaPlayerImpl::networkState() const { | 599 WebMediaPlayer::NetworkState WebMediaPlayerImpl::networkState() const { |
646 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 600 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
647 return network_state_; | 601 return network_state_; |
648 } | 602 } |
649 | 603 |
650 WebMediaPlayer::ReadyState WebMediaPlayerImpl::readyState() const { | 604 WebMediaPlayer::ReadyState WebMediaPlayerImpl::readyState() const { |
(...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
870 is_cdm_attached_ = true; | 824 is_cdm_attached_ = true; |
871 return; | 825 return; |
872 } | 826 } |
873 | 827 |
874 set_cdm_result_->completeWithError( | 828 set_cdm_result_->completeWithError( |
875 blink::WebContentDecryptionModuleExceptionNotSupportedError, 0, | 829 blink::WebContentDecryptionModuleExceptionNotSupportedError, 0, |
876 "Unable to set MediaKeys object"); | 830 "Unable to set MediaKeys object"); |
877 set_cdm_result_.reset(); | 831 set_cdm_result_.reset(); |
878 } | 832 } |
879 | 833 |
880 void WebMediaPlayerImpl::OnPipelineSeeked(bool time_changed, | 834 void WebMediaPlayerImpl::OnPipelineSeeked(bool time_updated) { |
881 PipelineStatus status) { | |
882 DVLOG(1) << __FUNCTION__ << "(" << time_changed << ", " << status << ")"; | |
883 DCHECK(main_task_runner_->BelongsToCurrentThread()); | |
884 | |
885 if (status != PIPELINE_OK) { | |
886 OnPipelineError(status); | |
887 return; | |
888 } | |
889 | |
890 // If we we're resuming into the playing state, notify the delegate. | |
891 if (resuming_ && playback_rate_ > 0 && !paused_) | |
892 NotifyPlaybackStarted(); | |
893 | |
894 // Whether or not the seek was caused by a resume, we're not suspended now. | |
895 resuming_ = false; | |
896 suspended_ = false; | |
897 | |
898 // If there is a pending suspend, the seek does not complete until after the | |
899 // next resume. | |
900 if (pending_suspend_) { | |
901 pending_suspend_ = false; | |
902 pending_time_change_ = time_changed; | |
903 Suspend(); | |
904 return; | |
905 } | |
906 | |
907 // Clear seek state. Note that if the seek was caused by a resume, then | |
908 // |seek_time_| is always set but |seeking_| is only set if there was a | |
909 // pending seek at the time. | |
910 seeking_ = false; | 835 seeking_ = false; |
911 seek_time_ = base::TimeDelta(); | 836 seek_time_ = base::TimeDelta(); |
912 | |
913 if (pending_seek_) { | |
914 double pending_seek_seconds = pending_seek_time_.InSecondsF(); | |
915 pending_seek_ = false; | |
916 pending_seek_time_ = base::TimeDelta(); | |
917 seek(pending_seek_seconds); | |
918 return; | |
919 } | |
920 | |
921 // Update our paused time. | |
922 if (paused_) | 837 if (paused_) |
923 UpdatePausedTime(); | 838 paused_time_ = pipeline_.GetMediaTime(); |
924 | 839 if (time_updated) |
925 should_notify_time_changed_ = time_changed; | 840 should_notify_time_changed_ = true; |
926 } | 841 } |
927 | 842 |
928 void WebMediaPlayerImpl::OnPipelineSuspended(PipelineStatus status) { | 843 void WebMediaPlayerImpl::OnPipelineSuspended() { |
929 DVLOG(1) << __FUNCTION__ << "(" << status << ")"; | |
930 DCHECK(main_task_runner_->BelongsToCurrentThread()); | |
931 | |
932 if (status != PIPELINE_OK) { | |
933 OnPipelineError(status); | |
934 return; | |
935 } | |
936 | |
937 suspending_ = false; | |
938 if (delegate_) | |
939 delegate_->PlayerGone(delegate_id_); | |
940 | |
941 #if defined(OS_ANDROID) | 844 #if defined(OS_ANDROID) |
942 if (isRemote()) { | 845 if (isRemote()) { |
943 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner(); | 846 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner(); |
944 if (frame) { | 847 if (frame) { |
945 compositor_->PaintFrameUsingOldRenderingPath(frame); | 848 compositor_->PaintFrameUsingOldRenderingPath(frame); |
946 } | 849 } |
947 } | 850 } |
948 #endif | 851 #endif |
949 | 852 |
950 if (pending_resume_ || pending_suspend_resume_cycle_) { | 853 if (pending_suspend_resume_cycle_) { |
951 pending_resume_ = false; | |
952 pending_suspend_resume_cycle_ = false; | 854 pending_suspend_resume_cycle_ = false; |
953 Resume(); | 855 pipeline_controller_.Resume(); |
954 return; | 856 return; |
955 } | 857 } |
956 } | 858 } |
957 | 859 |
958 void WebMediaPlayerImpl::OnPipelineEnded() { | 860 void WebMediaPlayerImpl::OnPipelineEnded() { |
959 DVLOG(1) << __FUNCTION__; | 861 DVLOG(1) << __FUNCTION__; |
960 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 862 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
961 | 863 |
962 // Ignore state changes until we've completed all outstanding seeks. | 864 // Ignore state changes until we've completed all outstanding operations. |
963 if (seeking_ || pending_seek_) | 865 if (!pipeline_controller_.IsStable()) |
964 return; | 866 return; |
965 | 867 |
966 ended_ = true; | 868 ended_ = true; |
967 client_->timeChanged(); | 869 client_->timeChanged(); |
968 } | 870 } |
969 | 871 |
970 void WebMediaPlayerImpl::OnPipelineError(PipelineStatus error) { | 872 void WebMediaPlayerImpl::OnPipelineError(PipelineStatus error) { |
971 DVLOG(1) << __FUNCTION__; | 873 DVLOG(1) << __FUNCTION__; |
972 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 874 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
973 DCHECK_NE(error, PIPELINE_OK); | 875 DCHECK_NE(error, PIPELINE_OK); |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1013 // playback. | 915 // playback. |
1014 if (delegate_ && delegate_->IsHidden()) | 916 if (delegate_ && delegate_->IsHidden()) |
1015 OnHidden(false); | 917 OnHidden(false); |
1016 } | 918 } |
1017 } | 919 } |
1018 | 920 |
1019 void WebMediaPlayerImpl::OnPipelineBufferingStateChanged( | 921 void WebMediaPlayerImpl::OnPipelineBufferingStateChanged( |
1020 BufferingState buffering_state) { | 922 BufferingState buffering_state) { |
1021 DVLOG(1) << __FUNCTION__ << "(" << buffering_state << ")"; | 923 DVLOG(1) << __FUNCTION__ << "(" << buffering_state << ")"; |
1022 | 924 |
1023 // Ignore buffering state changes until we've completed all outstanding seeks. | 925 // Ignore buffering state changes until we've completed all outstanding |
1024 if (seeking_ || pending_seek_) | 926 // operations. |
927 if (!pipeline_controller_.IsStable()) | |
1025 return; | 928 return; |
1026 | 929 |
1027 // TODO(scherkus): Handle other buffering states when Pipeline starts using | 930 // TODO(scherkus): Handle other buffering states when Pipeline starts using |
1028 // them and translate them ready state changes http://crbug.com/144683 | 931 // them and translate them ready state changes http://crbug.com/144683 |
1029 DCHECK_EQ(buffering_state, BUFFERING_HAVE_ENOUGH); | 932 DCHECK_EQ(buffering_state, BUFFERING_HAVE_ENOUGH); |
1030 SetReadyState(WebMediaPlayer::ReadyStateHaveEnoughData); | 933 SetReadyState(WebMediaPlayer::ReadyStateHaveEnoughData); |
1031 | 934 |
1032 // Let the DataSource know we have enough data. It may use this information to | 935 // Let the DataSource know we have enough data. It may use this information to |
1033 // release unused network connections. | 936 // release unused network connections. |
1034 if (data_source_) | 937 if (data_source_) |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1088 return; | 991 return; |
1089 } | 992 } |
1090 | 993 |
1091 #if defined(OS_ANDROID) | 994 #if defined(OS_ANDROID) |
1092 // If we're remote, the pipeline should already be suspended. | 995 // If we're remote, the pipeline should already be suspended. |
1093 if (isRemote()) | 996 if (isRemote()) |
1094 return; | 997 return; |
1095 #endif | 998 #endif |
1096 | 999 |
1097 if (must_suspend || paused_ || hasVideo()) | 1000 if (must_suspend || paused_ || hasVideo()) |
1098 ScheduleSuspend(); | 1001 pipeline_controller_.Suspend(); |
1099 } | |
1100 | |
1101 void WebMediaPlayerImpl::ScheduleSuspend() { | |
1102 if (!pipeline_.IsRunning()) | |
1103 return; | |
1104 | |
1105 if (resuming_ || seeking_) { | |
1106 pending_suspend_ = true; | |
1107 return; | |
1108 } | |
1109 | |
1110 if (pending_resume_) { | |
1111 pending_resume_ = false; | |
1112 return; | |
1113 } | |
1114 | |
1115 Suspend(); | |
1116 } | |
1117 | |
1118 void WebMediaPlayerImpl::Suspend() { | |
1119 DCHECK(main_task_runner_->BelongsToCurrentThread()); | |
1120 | |
1121 // Since Pipeline::IsRunning() may be set on the media thread there are cases | |
1122 // where two suspends might be issued concurrently. | |
1123 if (suspended_) | |
1124 return; | |
1125 | |
1126 suspended_ = true; | |
1127 suspending_ = true; | |
1128 pipeline_.Suspend( | |
1129 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineSuspended)); | |
1130 } | 1002 } |
1131 | 1003 |
1132 void WebMediaPlayerImpl::OnShown() { | 1004 void WebMediaPlayerImpl::OnShown() { |
1133 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 1005 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
1134 | 1006 |
1135 #if !defined(OS_ANDROID) | 1007 #if !defined(OS_ANDROID) |
1136 // Suspend/Resume is enabled by default on Android. | 1008 // Suspend/Resume is enabled by default on Android. |
1137 if (!base::CommandLine::ForCurrentProcess()->HasSwitch( | 1009 if (!base::CommandLine::ForCurrentProcess()->HasSwitch( |
1138 switches::kEnableMediaSuspend)) { | 1010 switches::kEnableMediaSuspend)) { |
1139 return; | 1011 return; |
1140 } | 1012 } |
1141 #endif // !defined(OS_ANDROID) | 1013 #endif // !defined(OS_ANDROID) |
1142 | 1014 |
1143 if (base::CommandLine::ForCurrentProcess()->HasSwitch( | 1015 if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
1144 switches::kDisableMediaSuspend)) { | 1016 switches::kDisableMediaSuspend)) { |
1145 return; | 1017 return; |
1146 } | 1018 } |
1147 | 1019 |
1148 #if defined(OS_ANDROID) | 1020 #if defined(OS_ANDROID) |
1149 // If we're remote, the pipeline should stay suspended. | 1021 // If we're remote, the pipeline should stay suspended. |
1150 if (isRemote()) | 1022 if (isRemote()) |
1151 return; | 1023 return; |
1152 #endif | 1024 #endif |
1153 | 1025 |
1154 ScheduleResume(); | 1026 pipeline_controller_.Resume(); |
1155 } | |
1156 | |
1157 void WebMediaPlayerImpl::ScheduleResume() { | |
1158 if (!pipeline_.IsRunning()) | |
1159 return; | |
1160 | |
1161 if (suspending_) { | |
1162 pending_resume_ = true; | |
1163 return; | |
1164 } | |
1165 | |
1166 if (pending_suspend_) { | |
1167 pending_suspend_ = false; | |
1168 return; | |
1169 } | |
1170 | |
1171 // Might already be resuming iff we came back from remote playback recently. | |
1172 if (suspended_ && !resuming_) | |
1173 Resume(); | |
1174 } | 1027 } |
1175 | 1028 |
1176 void WebMediaPlayerImpl::OnPlay() { | 1029 void WebMediaPlayerImpl::OnPlay() { |
1177 play(); | 1030 play(); |
1178 client_->playbackStateChanged(); | 1031 client_->playbackStateChanged(); |
1179 } | 1032 } |
1180 | 1033 |
1181 void WebMediaPlayerImpl::OnPause() { | 1034 void WebMediaPlayerImpl::OnPause() { |
1182 pause(); | 1035 pause(); |
1183 client_->playbackStateChanged(); | 1036 client_->playbackStateChanged(); |
1184 } | 1037 } |
1185 | 1038 |
1186 void WebMediaPlayerImpl::OnVolumeMultiplierUpdate(double multiplier) { | 1039 void WebMediaPlayerImpl::OnVolumeMultiplierUpdate(double multiplier) { |
1187 volume_multiplier_ = multiplier; | 1040 volume_multiplier_ = multiplier; |
1188 setVolume(volume_); | 1041 setVolume(volume_); |
1189 } | 1042 } |
1190 | 1043 |
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. Use the pipeline time if there's no video. | |
1212 if (!data_source_ || !data_source_->IsStreaming()) { | |
1213 seek_time_ = hasVideo() ? compositor_->GetCurrentFrameTimestamp() | |
1214 : pipeline_.GetMediaTime(); | |
1215 } else { | |
1216 // Resume from zero if a resource does not support range requests; this | |
1217 // avoids a painful "read-the-whole-file" seek penalty. | |
1218 seek_time_ = base::TimeDelta(); | |
1219 } | |
1220 } | |
1221 | |
1222 if (chunk_demuxer_) | |
1223 chunk_demuxer_->StartWaitingForSeek(seek_time_); | |
1224 | |
1225 resuming_ = true; | |
1226 pipeline_.Resume(CreateRenderer(), seek_time_, | |
1227 BIND_TO_RENDER_LOOP1(&WebMediaPlayerImpl::OnPipelineSeeked, | |
1228 time_changed)); | |
1229 } | |
1230 | |
1231 void WebMediaPlayerImpl::ScheduleRestart() { | 1044 void WebMediaPlayerImpl::ScheduleRestart() { |
1232 // If we're suspended but not resuming there is no need to restart because | 1045 if (!pipeline_controller_.IsSuspended()) { |
1233 // there is no renderer to kill. | |
1234 if (!suspended_ || resuming_) { | |
1235 pending_suspend_resume_cycle_ = true; | 1046 pending_suspend_resume_cycle_ = true; |
1236 ScheduleSuspend(); | 1047 pipeline_controller_.Suspend(); |
1237 } | 1048 } |
1238 } | 1049 } |
1239 | 1050 |
1240 #if defined(OS_ANDROID) // WMPI_CAST | 1051 #if defined(OS_ANDROID) // WMPI_CAST |
1241 | |
1242 bool WebMediaPlayerImpl::isRemote() const { | 1052 bool WebMediaPlayerImpl::isRemote() const { |
1243 return cast_impl_.isRemote(); | 1053 return cast_impl_.isRemote(); |
1244 } | 1054 } |
1245 | 1055 |
1246 void WebMediaPlayerImpl::SetMediaPlayerManager( | 1056 void WebMediaPlayerImpl::SetMediaPlayerManager( |
1247 RendererMediaPlayerManagerInterface* media_player_manager) { | 1057 RendererMediaPlayerManagerInterface* media_player_manager) { |
1248 cast_impl_.SetMediaPlayerManager(media_player_manager); | 1058 cast_impl_.SetMediaPlayerManager(media_player_manager); |
1249 } | 1059 } |
1250 | 1060 |
1251 void WebMediaPlayerImpl::requestRemotePlayback() { | 1061 void WebMediaPlayerImpl::requestRemotePlayback() { |
1252 cast_impl_.requestRemotePlayback(); | 1062 cast_impl_.requestRemotePlayback(); |
1253 } | 1063 } |
1254 | 1064 |
1255 void WebMediaPlayerImpl::requestRemotePlaybackControl() { | 1065 void WebMediaPlayerImpl::requestRemotePlaybackControl() { |
1256 cast_impl_.requestRemotePlaybackControl(); | 1066 cast_impl_.requestRemotePlaybackControl(); |
1257 } | 1067 } |
1258 | 1068 |
1259 void WebMediaPlayerImpl::OnRemotePlaybackEnded() { | 1069 void WebMediaPlayerImpl::OnRemotePlaybackEnded() { |
1260 DVLOG(1) << __FUNCTION__; | 1070 DVLOG(1) << __FUNCTION__; |
1261 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 1071 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
1262 | 1072 |
1263 ended_ = true; | 1073 ended_ = true; |
1264 client_->timeChanged(); | 1074 client_->timeChanged(); |
1265 } | 1075 } |
1266 | 1076 |
1267 void WebMediaPlayerImpl::OnDisconnectedFromRemoteDevice(double t) { | 1077 void WebMediaPlayerImpl::OnDisconnectedFromRemoteDevice(double t) { |
1268 paused_time_ = base::TimeDelta::FromSecondsD(t); | 1078 DoSeek(base::TimeDelta::FromSecondsD(t), false); |
1269 pending_seek_ = true; | 1079 if (delegate_ && !delegate_->IsHidden()) |
1270 pending_seek_time_ = paused_time_; | 1080 pipeline_controller_.Resume(); |
1271 | 1081 |
1272 ScheduleResume(); | |
1273 | |
1274 if (paused_time_ == pipeline_.GetMediaDuration()) { | |
1275 ended_ = true; | |
1276 } | |
1277 // We already told the delegate we're paused when remoting started. | 1082 // We already told the delegate we're paused when remoting started. |
1278 client_->playbackStateChanged(); | 1083 client_->playbackStateChanged(); |
1279 client_->disconnectedFromRemoteDevice(); | 1084 client_->disconnectedFromRemoteDevice(); |
1280 } | 1085 } |
1281 | 1086 |
1282 void WebMediaPlayerImpl::SuspendForRemote() { | 1087 void WebMediaPlayerImpl::SuspendForRemote() { |
1283 if (suspended_ && !suspending_) { | 1088 if (!pipeline_controller_.IsSuspended()) { |
1089 pipeline_controller_.Suspend(); | |
1090 } else { | |
1091 // TODO(sandersd): If PipelineController::Suspend() called |suspended_cb| | |
1092 // when already suspended, we wouldn't need this case. | |
1284 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner(); | 1093 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner(); |
1285 if (frame) { | 1094 if (frame) { |
1286 compositor_->PaintFrameUsingOldRenderingPath(frame); | 1095 compositor_->PaintFrameUsingOldRenderingPath(frame); |
1287 } | 1096 } |
1288 } | 1097 } |
1289 ScheduleSuspend(); | |
1290 } | 1098 } |
1291 | 1099 |
1292 gfx::Size WebMediaPlayerImpl::GetCanvasSize() const { | 1100 gfx::Size WebMediaPlayerImpl::GetCanvasSize() const { |
1293 if (!video_weblayer_) | 1101 if (!video_weblayer_) |
1294 return pipeline_metadata_.natural_size; | 1102 return pipeline_metadata_.natural_size; |
1295 | 1103 |
1296 return video_weblayer_->bounds(); | 1104 return video_weblayer_->bounds(); |
1297 } | 1105 } |
1298 | 1106 |
1299 void WebMediaPlayerImpl::SetDeviceScaleFactor(float scale_factor) { | 1107 void WebMediaPlayerImpl::SetDeviceScaleFactor(float scale_factor) { |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1390 chunk_demuxer_ = new ChunkDemuxer( | 1198 chunk_demuxer_ = new ChunkDemuxer( |
1391 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnDemuxerOpened), | 1199 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnDemuxerOpened), |
1392 encrypted_media_init_data_cb, media_log_, true); | 1200 encrypted_media_init_data_cb, media_log_, true); |
1393 demuxer_.reset(chunk_demuxer_); | 1201 demuxer_.reset(chunk_demuxer_); |
1394 } | 1202 } |
1395 | 1203 |
1396 // ... and we're ready to go! | 1204 // ... and we're ready to go! |
1397 seeking_ = true; | 1205 seeking_ = true; |
1398 | 1206 |
1399 // TODO(sandersd): On Android, defer Start() if the tab is not visible. | 1207 // TODO(sandersd): On Android, defer Start() if the tab is not visible. |
1400 pipeline_.Start( | 1208 bool is_streaming = (data_source_ && data_source_->IsStreaming()); |
1401 demuxer_.get(), CreateRenderer(), | 1209 pipeline_controller_.Start( |
1210 chunk_demuxer_, demuxer_.get(), is_streaming, | |
1402 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineEnded), | 1211 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineEnded), |
1403 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineError), | |
1404 BIND_TO_RENDER_LOOP1(&WebMediaPlayerImpl::OnPipelineSeeked, false), | |
1405 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineMetadata), | 1212 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineMetadata), |
1406 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineBufferingStateChanged), | 1213 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineBufferingStateChanged), |
1407 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnDurationChanged), | 1214 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnDurationChanged), |
1408 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnAddTextTrack), | 1215 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnAddTextTrack), |
1409 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnWaitingForDecryptionKey)); | 1216 BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnWaitingForDecryptionKey)); |
1410 } | 1217 } |
1411 | 1218 |
1412 void WebMediaPlayerImpl::SetNetworkState(WebMediaPlayer::NetworkState state) { | 1219 void WebMediaPlayerImpl::SetNetworkState(WebMediaPlayer::NetworkState state) { |
1413 DVLOG(1) << __FUNCTION__ << "(" << state << ")"; | 1220 DVLOG(1) << __FUNCTION__ << "(" << state << ")"; |
1414 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 1221 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1502 base::WaitableEvent event(false, false); | 1309 base::WaitableEvent event(false, false); |
1503 compositor_task_runner_->PostTask(FROM_HERE, | 1310 compositor_task_runner_->PostTask(FROM_HERE, |
1504 base::Bind(&GetCurrentFrameAndSignal, | 1311 base::Bind(&GetCurrentFrameAndSignal, |
1505 base::Unretained(compositor_), | 1312 base::Unretained(compositor_), |
1506 &video_frame, | 1313 &video_frame, |
1507 &event)); | 1314 &event)); |
1508 event.Wait(); | 1315 event.Wait(); |
1509 return video_frame; | 1316 return video_frame; |
1510 } | 1317 } |
1511 | 1318 |
1512 void WebMediaPlayerImpl::UpdatePausedTime() { | |
1513 DCHECK(main_task_runner_->BelongsToCurrentThread()); | |
1514 | |
1515 // pause() may be called after playback has ended and the HTMLMediaElement | |
1516 // requires that currentTime() == duration() after ending. We want to ensure | |
1517 // |paused_time_| matches currentTime() in this case or a future seek() may | |
1518 // incorrectly discard what it thinks is a seek to the existing time. | |
1519 paused_time_ = | |
1520 ended_ ? pipeline_.GetMediaDuration() : pipeline_.GetMediaTime(); | |
1521 } | |
1522 | |
1523 void WebMediaPlayerImpl::NotifyPlaybackStarted() { | 1319 void WebMediaPlayerImpl::NotifyPlaybackStarted() { |
1524 #if defined(OS_ANDROID) // WMPI_CAST | 1320 #if defined(OS_ANDROID) // WMPI_CAST |
1525 // We do not tell our delegates about remote playback, becuase that would | 1321 // We do not tell our delegates about remote playback, becuase that would |
1526 // keep the device awake, which is not what we want. | 1322 // keep the device awake, which is not what we want. |
1527 if (isRemote()) | 1323 if (isRemote()) |
1528 return; | 1324 return; |
1529 #endif | 1325 #endif |
1530 if (delegate_) { | 1326 if (delegate_) { |
1531 delegate_->DidPlay(delegate_id_, hasVideo(), hasAudio(), false, | 1327 delegate_->DidPlay(delegate_id_, hasVideo(), hasAudio(), false, |
1532 pipeline_.GetMediaDuration()); | 1328 pipeline_.GetMediaDuration()); |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1580 << ", Video: " << stats.video_memory_usage << ", DataSource: " | 1376 << ", Video: " << stats.video_memory_usage << ", DataSource: " |
1581 << (data_source_ ? data_source_->GetMemoryUsage() : 0) | 1377 << (data_source_ ? data_source_->GetMemoryUsage() : 0) |
1582 << ", Demuxer: " << demuxer_memory_usage; | 1378 << ", Demuxer: " << demuxer_memory_usage; |
1583 | 1379 |
1584 const int64_t delta = current_memory_usage - last_reported_memory_usage_; | 1380 const int64_t delta = current_memory_usage - last_reported_memory_usage_; |
1585 last_reported_memory_usage_ = current_memory_usage; | 1381 last_reported_memory_usage_ = current_memory_usage; |
1586 adjust_allocated_memory_cb_.Run(delta); | 1382 adjust_allocated_memory_cb_.Run(delta); |
1587 } | 1383 } |
1588 | 1384 |
1589 } // namespace media | 1385 } // namespace media |
OLD | NEW |