Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(35)

Side by Side Diff: media/blink/webmediaplayer_impl.cc

Issue 1641423002: Re-land extract state management from WebMediaPlayerImpl. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Add a message loop to the test. Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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)),
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
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
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
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
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_)
DaleCurtis 2016/02/26 02:54:24 See https://codereview.chromium.org/1739473003 --
sandersd (OOO until July 31) 2016/02/26 22:10:48 Done.
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.
wolenetz 2016/02/26 02:30:11 What if the pipeline ends while suspending or resu
sandersd (OOO until July 31) 2016/02/26 22:10:48 Summary of offline discussion: This is okay for tw
wolenetz 2016/02/26 23:21:06 Acknowledged.
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698