OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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/renderers/renderer_impl.h" | 5 #include "media/renderers/renderer_impl.h" |
6 | 6 |
7 #include <utility> | 7 #include <utility> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/callback.h" | 10 #include "base/callback.h" |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
122 DCHECK_EQ(state_, STATE_UNINITIALIZED); | 122 DCHECK_EQ(state_, STATE_UNINITIALIZED); |
123 DCHECK(!init_cb.is_null()); | 123 DCHECK(!init_cb.is_null()); |
124 DCHECK(client); | 124 DCHECK(client); |
125 DCHECK(demuxer_stream_provider->GetStream(DemuxerStream::AUDIO) || | 125 DCHECK(demuxer_stream_provider->GetStream(DemuxerStream::AUDIO) || |
126 demuxer_stream_provider->GetStream(DemuxerStream::VIDEO)); | 126 demuxer_stream_provider->GetStream(DemuxerStream::VIDEO)); |
127 | 127 |
128 client_ = client; | 128 client_ = client; |
129 demuxer_stream_provider_ = demuxer_stream_provider; | 129 demuxer_stream_provider_ = demuxer_stream_provider; |
130 init_cb_ = init_cb; | 130 init_cb_ = init_cb; |
131 | 131 |
| 132 DemuxerStream* audio_stream = |
| 133 demuxer_stream_provider->GetStream(DemuxerStream::AUDIO); |
| 134 if (audio_stream) |
| 135 audio_stream->SetStreamRestartedCB( |
| 136 base::Bind(&RendererImpl::RestartStreamPlayback, weak_this_)); |
| 137 DemuxerStream* video_stream = |
| 138 demuxer_stream_provider->GetStream(DemuxerStream::VIDEO); |
| 139 if (video_stream) |
| 140 video_stream->SetStreamRestartedCB( |
| 141 base::Bind(&RendererImpl::RestartStreamPlayback, weak_this_)); |
| 142 |
132 if (HasEncryptedStream() && !cdm_context_) { | 143 if (HasEncryptedStream() && !cdm_context_) { |
133 state_ = STATE_INIT_PENDING_CDM; | 144 state_ = STATE_INIT_PENDING_CDM; |
134 return; | 145 return; |
135 } | 146 } |
136 | 147 |
137 state_ = STATE_INITIALIZING; | 148 state_ = STATE_INITIALIZING; |
138 InitializeAudioRenderer(); | 149 InitializeAudioRenderer(); |
139 } | 150 } |
140 | 151 |
141 void RendererImpl::SetCdm(CdmContext* cdm_context, | 152 void RendererImpl::SetCdm(CdmContext* cdm_context, |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
194 } | 205 } |
195 | 206 |
196 time_source_->SetMediaTime(time); | 207 time_source_->SetMediaTime(time); |
197 | 208 |
198 if (audio_renderer_) | 209 if (audio_renderer_) |
199 audio_renderer_->StartPlaying(); | 210 audio_renderer_->StartPlaying(); |
200 if (video_renderer_) | 211 if (video_renderer_) |
201 video_renderer_->StartPlayingFrom(time); | 212 video_renderer_->StartPlayingFrom(time); |
202 } | 213 } |
203 | 214 |
| 215 void RendererImpl::RestartStreamPlayback(DemuxerStream* stream, |
| 216 base::TimeDelta time) { |
| 217 DVLOG(1) << __FUNCTION__ << " stream=" << stream |
| 218 << " time=" << time.InSecondsF(); |
| 219 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 220 if (stream->type() == DemuxerStream::VIDEO) { |
| 221 DCHECK(video_renderer_); |
| 222 DCHECK(video_ended_); |
| 223 video_ended_ = false; |
| 224 restarting_video_ = true; |
| 225 video_renderer_->Flush( |
| 226 base::Bind(&RendererImpl::RestartVideoRenderer, weak_this_, time)); |
| 227 } else if (stream->type() == DemuxerStream::AUDIO) { |
| 228 DCHECK(audio_renderer_); |
| 229 DCHECK(time_source_); |
| 230 DCHECK(audio_ended_); |
| 231 audio_ended_ = false; |
| 232 restarting_audio_ = true; |
| 233 // Stop ticking (transition into paused state) in audio renderer before |
| 234 // calling Flush, since after Flush we are going to restart playback by |
| 235 // calling audio renderer StartPlaying which would fail in playing state. |
| 236 time_ticking_ = false; |
| 237 time_source_->StopTicking(); |
| 238 audio_renderer_->Flush( |
| 239 base::Bind(&RendererImpl::RestartAudioRenderer, weak_this_, time)); |
| 240 } |
| 241 } |
| 242 |
| 243 void RendererImpl::RestartVideoRenderer(base::TimeDelta time) { |
| 244 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 245 if (state_ == STATE_PLAYING) { |
| 246 DCHECK(video_renderer_); |
| 247 video_renderer_->StartPlayingFrom(time); |
| 248 } |
| 249 } |
| 250 |
| 251 void RendererImpl::RestartAudioRenderer(base::TimeDelta time) { |
| 252 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 253 if (state_ == STATE_PLAYING) { |
| 254 DCHECK(time_source_); |
| 255 DCHECK(audio_renderer_); |
| 256 audio_renderer_->StartPlaying(); |
| 257 } |
| 258 } |
| 259 |
204 void RendererImpl::SetPlaybackRate(double playback_rate) { | 260 void RendererImpl::SetPlaybackRate(double playback_rate) { |
205 DVLOG(1) << __FUNCTION__ << "(" << playback_rate << ")"; | 261 DVLOG(1) << __FUNCTION__ << "(" << playback_rate << ")"; |
206 DCHECK(task_runner_->BelongsToCurrentThread()); | 262 DCHECK(task_runner_->BelongsToCurrentThread()); |
207 | 263 |
208 // Playback rate changes are only carried out while playing. | 264 // Playback rate changes are only carried out while playing. |
209 if (state_ != STATE_PLAYING) | 265 if (state_ != STATE_PLAYING) |
210 return; | 266 return; |
211 | 267 |
212 time_source_->SetPlaybackRate(playback_rate); | 268 time_source_->SetPlaybackRate(playback_rate); |
213 | 269 |
(...skipping 281 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
495 ? &audio_buffering_state_ | 551 ? &audio_buffering_state_ |
496 : &video_buffering_state_; | 552 : &video_buffering_state_; |
497 | 553 |
498 DVLOG(1) << __FUNCTION__ << "(" << *buffering_state << ", " | 554 DVLOG(1) << __FUNCTION__ << "(" << *buffering_state << ", " |
499 << new_buffering_state << ") " | 555 << new_buffering_state << ") " |
500 << (type == DemuxerStream::AUDIO ? "audio" : "video"); | 556 << (type == DemuxerStream::AUDIO ? "audio" : "video"); |
501 DCHECK(task_runner_->BelongsToCurrentThread()); | 557 DCHECK(task_runner_->BelongsToCurrentThread()); |
502 | 558 |
503 bool was_waiting_for_enough_data = WaitingForEnoughData(); | 559 bool was_waiting_for_enough_data = WaitingForEnoughData(); |
504 | 560 |
| 561 // When restarting playback we want to ignore the BUFFERING_HAVE_NOTHING for |
| 562 // the stream being restarted, to allow continuing uninterrupted playback on |
| 563 // the other stream. |
| 564 if (type == DemuxerStream::VIDEO && restarting_video_) { |
| 565 if (new_buffering_state == BUFFERING_HAVE_NOTHING) { |
| 566 DVLOG(1) << __FUNCTION__ << " Ignoring BUFFERING_HAVE_NOTHING for video " |
| 567 "stream which is being restarted."; |
| 568 } else if (new_buffering_state == BUFFERING_HAVE_ENOUGH) { |
| 569 DVLOG(1) << __FUNCTION__ << " Got BUFFERING_HAVE_ENOUGH for video stream," |
| 570 " resuming playback."; |
| 571 restarting_video_ = false; |
| 572 if (playback_rate_ > 0) |
| 573 video_renderer_->OnTimeStateChanged(true); |
| 574 } |
| 575 return; |
| 576 } |
| 577 |
| 578 if (type == DemuxerStream::AUDIO && restarting_audio_) { |
| 579 if (new_buffering_state == BUFFERING_HAVE_NOTHING) { |
| 580 DVLOG(1) << __FUNCTION__ << " Ignoring BUFFERING_HAVE_NOTHING for audio " |
| 581 "stream which is being restarted."; |
| 582 } else if (new_buffering_state == BUFFERING_HAVE_ENOUGH) { |
| 583 DVLOG(1) << __FUNCTION__ << " Got BUFFERING_HAVE_ENOUGH for audio stream," |
| 584 " resuming playback."; |
| 585 |
| 586 restarting_audio_ = false; |
| 587 |
| 588 // Now that we have decoded enough audio, pause and unpause playback |
| 589 // momentarily to ensure video renderer is synchronised with audio. |
| 590 double curr_playback_rate = playback_rate_; |
| 591 SetPlaybackRate(0); |
| 592 SetPlaybackRate(curr_playback_rate); |
| 593 |
| 594 time_ticking_ = true; |
| 595 time_source_->StartTicking(); |
| 596 } |
| 597 return; |
| 598 } |
| 599 |
505 // When audio is present and has enough data, defer video underflow callbacks | 600 // When audio is present and has enough data, defer video underflow callbacks |
506 // for some time to avoid unnecessary glitches in audio; see | 601 // for some time to avoid unnecessary glitches in audio; see |
507 // http://crbug.com/144683#c53. | 602 // http://crbug.com/144683#c53. |
508 if (audio_renderer_ && type == DemuxerStream::VIDEO && | 603 if (audio_renderer_ && type == DemuxerStream::VIDEO && |
509 state_ == STATE_PLAYING) { | 604 state_ == STATE_PLAYING) { |
510 if (video_buffering_state_ == BUFFERING_HAVE_ENOUGH && | 605 if (video_buffering_state_ == BUFFERING_HAVE_ENOUGH && |
511 audio_buffering_state_ == BUFFERING_HAVE_ENOUGH && | 606 audio_buffering_state_ == BUFFERING_HAVE_ENOUGH && |
512 new_buffering_state == BUFFERING_HAVE_NOTHING && | 607 new_buffering_state == BUFFERING_HAVE_NOTHING && |
513 deferred_underflow_cb_.IsCancelled()) { | 608 deferred_underflow_cb_.IsCancelled()) { |
514 deferred_underflow_cb_.Reset( | 609 deferred_underflow_cb_.Reset( |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
605 DCHECK(!time_ticking_); | 700 DCHECK(!time_ticking_); |
606 DCHECK(!WaitingForEnoughData()); | 701 DCHECK(!WaitingForEnoughData()); |
607 | 702 |
608 time_ticking_ = true; | 703 time_ticking_ = true; |
609 time_source_->StartTicking(); | 704 time_source_->StartTicking(); |
610 if (playback_rate_ > 0 && video_renderer_) | 705 if (playback_rate_ > 0 && video_renderer_) |
611 video_renderer_->OnTimeStateChanged(true); | 706 video_renderer_->OnTimeStateChanged(true); |
612 } | 707 } |
613 | 708 |
614 void RendererImpl::OnRendererEnded(DemuxerStream::Type type) { | 709 void RendererImpl::OnRendererEnded(DemuxerStream::Type type) { |
615 DVLOG(1) << __FUNCTION__; | 710 DVLOG(1) << __FUNCTION__ |
| 711 << (type == DemuxerStream::AUDIO ? " audio" : " video"); |
616 DCHECK(task_runner_->BelongsToCurrentThread()); | 712 DCHECK(task_runner_->BelongsToCurrentThread()); |
617 DCHECK((type == DemuxerStream::AUDIO) || (type == DemuxerStream::VIDEO)); | 713 DCHECK((type == DemuxerStream::AUDIO) || (type == DemuxerStream::VIDEO)); |
618 | 714 |
619 if (state_ != STATE_PLAYING) | 715 if (state_ != STATE_PLAYING) |
620 return; | 716 return; |
621 | 717 |
622 if (type == DemuxerStream::AUDIO) { | 718 if (type == DemuxerStream::AUDIO) { |
623 DCHECK(!audio_ended_); | 719 DCHECK(!audio_ended_); |
624 audio_ended_ = true; | 720 audio_ended_ = true; |
625 } else { | 721 } else { |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
691 DCHECK(task_runner_->BelongsToCurrentThread()); | 787 DCHECK(task_runner_->BelongsToCurrentThread()); |
692 client_->OnVideoNaturalSizeChange(size); | 788 client_->OnVideoNaturalSizeChange(size); |
693 } | 789 } |
694 | 790 |
695 void RendererImpl::OnVideoOpacityChange(bool opaque) { | 791 void RendererImpl::OnVideoOpacityChange(bool opaque) { |
696 DCHECK(task_runner_->BelongsToCurrentThread()); | 792 DCHECK(task_runner_->BelongsToCurrentThread()); |
697 client_->OnVideoOpacityChange(opaque); | 793 client_->OnVideoOpacityChange(opaque); |
698 } | 794 } |
699 | 795 |
700 } // namespace media | 796 } // namespace media |
OLD | NEW |