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