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_) { | |
chcunningham
2016/06/24 23:32:55
For both audio and video, my previous comments sti
servolk
2016/06/25 00:36:33
Well, I have looked into this some more after your
chcunningham
2016/06/27 20:31:52
This is true, but its also a bug that I'm soon fix
servolk
2016/06/28 00:15:58
Ok, sure, if you are fixing the delivery of HAVE_N
| |
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); | |
chcunningham
2016/06/24 23:32:55
Re-posting discussion from earlier - ping xhwang o
servolk
2016/06/25 00:36:33
Acknowledged. Should we open a separate bug for th
chcunningham
2016/06/27 20:31:52
Since xhwang is AFK and wolenetz is just CC, I rea
servolk
2016/06/28 00:15:58
Done.
| |
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); | |
chcunningham
2016/06/24 23:32:55
My previous comment is not addressed. Reposting
W
servolk
2016/06/25 00:36:33
Prior to this point only the audio renderer is pau
chcunningham
2016/06/27 20:31:52
Can you instead try to audio_renderer_->SetMediaTi
servolk
2016/06/28 00:15:58
We need to be very careful here. audio_renderer_->
servolk
2016/06/28 02:05:43
Btw, just FYI: When I tried to set audio_renderer_
servolk
2016/06/28 18:51:44
I think we can make this better by allowing PauseP
servolk
2016/06/28 23:03:40
Ok, and patchset #48 implements deferred reporting
| |
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 |