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

Side by Side Diff: media/renderers/renderer_impl.cc

Issue 2684103005: Allow media track switching. (Closed)
Patch Set: Updated GpuMemoryBufferVideoFramePool comment Created 3 years, 8 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 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 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
73 }; 73 };
74 74
75 RendererImpl::RendererImpl( 75 RendererImpl::RendererImpl(
76 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, 76 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
77 std::unique_ptr<AudioRenderer> audio_renderer, 77 std::unique_ptr<AudioRenderer> audio_renderer,
78 std::unique_ptr<VideoRenderer> video_renderer) 78 std::unique_ptr<VideoRenderer> video_renderer)
79 : state_(STATE_UNINITIALIZED), 79 : state_(STATE_UNINITIALIZED),
80 task_runner_(task_runner), 80 task_runner_(task_runner),
81 audio_renderer_(std::move(audio_renderer)), 81 audio_renderer_(std::move(audio_renderer)),
82 video_renderer_(std::move(video_renderer)), 82 video_renderer_(std::move(video_renderer)),
83 current_audio_stream_(nullptr),
84 current_video_stream_(nullptr),
83 time_source_(NULL), 85 time_source_(NULL),
84 time_ticking_(false), 86 time_ticking_(false),
85 playback_rate_(0.0), 87 playback_rate_(0.0),
86 audio_buffering_state_(BUFFERING_HAVE_NOTHING), 88 audio_buffering_state_(BUFFERING_HAVE_NOTHING),
87 video_buffering_state_(BUFFERING_HAVE_NOTHING), 89 video_buffering_state_(BUFFERING_HAVE_NOTHING),
88 audio_ended_(false), 90 audio_ended_(false),
89 video_ended_(false), 91 video_ended_(false),
90 cdm_context_(nullptr), 92 cdm_context_(nullptr),
91 underflow_disabled_for_testing_(false), 93 underflow_disabled_for_testing_(false),
92 clockless_video_playback_enabled_for_testing_(false), 94 clockless_video_playback_enabled_for_testing_(false),
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
185 DCHECK(flush_cb_.is_null()); 187 DCHECK(flush_cb_.is_null());
186 188
187 if (state_ != STATE_PLAYING) { 189 if (state_ != STATE_PLAYING) {
188 DCHECK_EQ(state_, STATE_ERROR); 190 DCHECK_EQ(state_, STATE_ERROR);
189 return; 191 return;
190 } 192 }
191 193
192 flush_cb_ = flush_cb; 194 flush_cb_ = flush_cb;
193 state_ = STATE_FLUSHING; 195 state_ = STATE_FLUSHING;
194 196
197 // If we are currently handling a media stream status change, then postpone
198 // Flush until after that's done (because stream status changes also flush
199 // audio_renderer_/video_renderer_ and they need to be restarted before they
200 // can be flushed again). OnStreamRestartCompleted will resume Flush
201 // processing after audio/video restart has completed and there are no other
202 // pending stream status changes.
203 if (restarting_audio_ || restarting_video_)
204 return;
205
195 if (time_ticking_) 206 if (time_ticking_)
196 PausePlayback(); 207 PausePlayback();
197 208
198 FlushAudioRenderer(); 209 FlushAudioRenderer();
199 } 210 }
200 211
201 void RendererImpl::StartPlayingFrom(base::TimeDelta time) { 212 void RendererImpl::StartPlayingFrom(base::TimeDelta time) {
202 DVLOG(1) << __func__; 213 DVLOG(1) << __func__;
203 DCHECK(task_runner_->BelongsToCurrentThread()); 214 DCHECK(task_runner_->BelongsToCurrentThread());
204 215
205 if (state_ != STATE_PLAYING) { 216 if (state_ != STATE_PLAYING) {
206 DCHECK_EQ(state_, STATE_ERROR); 217 DCHECK_EQ(state_, STATE_ERROR);
207 return; 218 return;
208 } 219 }
209 220
210 time_source_->SetMediaTime(time); 221 time_source_->SetMediaTime(time);
211 222
212 if (audio_renderer_) 223 if (audio_renderer_)
213 audio_renderer_->StartPlaying(); 224 audio_renderer_->StartPlaying();
214 if (video_renderer_) 225 if (video_renderer_)
215 video_renderer_->StartPlayingFrom(time); 226 video_renderer_->StartPlayingFrom(time);
216 } 227 }
217 228
218 void RendererImpl::OnStreamStatusChanged(DemuxerStream* stream, 229 void RendererImpl::OnStreamStatusChanged(DemuxerStream* stream,
xhwang 2017/03/31 23:38:11 nit: method definition order should match declarat
servolk 2017/03/31 23:53:55 Will do
servolk 2017/04/03 21:32:33 I've rearranged the methods to match declaration o
219 bool enabled, 230 bool enabled,
220 base::TimeDelta time) { 231 base::TimeDelta time) {
221 DCHECK(task_runner_->BelongsToCurrentThread()); 232 DCHECK(task_runner_->BelongsToCurrentThread());
222 DCHECK(stream); 233 DCHECK(stream);
223 bool video = (stream->type() == DemuxerStream::VIDEO); 234 bool video = (stream->type() == DemuxerStream::VIDEO);
224 DVLOG(1) << __func__ << (video ? " video" : " audio") << " stream=" << stream 235 DVLOG(1) << __func__ << (video ? " video" : " audio") << " stream=" << stream
225 << " enabled=" << enabled << " time=" << time.InSecondsF(); 236 << " enabled=" << enabled << " time=" << time.InSecondsF();
226 if ((state_ != STATE_PLAYING) || (audio_ended_ && video_ended_)) 237 if ((state_ != STATE_PLAYING) || (audio_ended_ && video_ended_))
DaleCurtis 2017/03/31 21:22:08 Does this prevent the stream status change from oc
servolk 2017/03/31 23:53:55 Fixed in the latest patchset (by postponing flush
227 return; 238 return;
xhwang 2017/03/31 23:38:11 nit: Add a comment why it's safe to drop this noti
servolk 2017/03/31 23:53:55 Actually was only safe until we allowed track swit
228 if (restarting_audio_ || restarting_video_) { 239 if (restarting_audio_ || restarting_video_) {
229 DVLOG(3) << __func__ << ": postponed stream " << stream 240 DVLOG(3) << __func__ << ": postponed stream " << stream
230 << " status change handling."; 241 << " status change handling.";
231 pending_stream_status_notifications_.push_back( 242 pending_stream_status_notifications_.push_back(
232 base::Bind(&RendererImpl::OnStreamStatusChanged, weak_this_, stream, 243 base::Bind(&RendererImpl::OnStreamStatusChanged, weak_this_, stream,
233 enabled, time)); 244 enabled, time));
234 return; 245 return;
235 } 246 }
236 if (stream->type() == DemuxerStream::VIDEO) { 247 if (stream->type() == DemuxerStream::VIDEO) {
237 DCHECK(video_renderer_); 248 DCHECK(video_renderer_);
238 restarting_video_ = true; 249 restarting_video_ = true;
239 video_renderer_->Flush( 250 video_renderer_->Flush(
240 base::Bind(&RendererImpl::RestartVideoRenderer, weak_this_, time)); 251 base::Bind((stream == current_video_stream_)
DaleCurtis 2017/03/31 21:22:08 Unnecessary parens.
servolk 2017/03/31 23:53:55 Done.
252 ? &RendererImpl::RestartVideoRenderer
253 : &RendererImpl::ReinitializeVideoRenderer,
254 weak_this_, stream, time));
241 } else if (stream->type() == DemuxerStream::AUDIO) { 255 } else if (stream->type() == DemuxerStream::AUDIO) {
242 DCHECK(audio_renderer_); 256 DCHECK(audio_renderer_);
243 DCHECK(time_source_); 257 DCHECK(time_source_);
244 restarting_audio_ = true; 258 restarting_audio_ = true;
245 // Stop ticking (transition into paused state) in audio renderer before 259 // Stop ticking (transition into paused state) in audio renderer before
246 // calling Flush, since after Flush we are going to restart playback by 260 // calling Flush, since after Flush we are going to restart playback by
247 // calling audio renderer StartPlaying which would fail in playing state. 261 // calling audio renderer StartPlaying which would fail in playing state.
248 if (time_ticking_) { 262 if (time_ticking_) {
249 time_ticking_ = false; 263 time_ticking_ = false;
250 time_source_->StopTicking(); 264 time_source_->StopTicking();
251 } 265 }
252 audio_renderer_->Flush( 266 audio_renderer_->Flush(
253 base::Bind(&RendererImpl::RestartAudioRenderer, weak_this_, time)); 267 base::Bind((stream == current_audio_stream_)
DaleCurtis 2017/03/31 21:22:08 Ditto.
servolk 2017/03/31 23:53:55 Done.
268 ? &RendererImpl::RestartAudioRenderer
269 : &RendererImpl::ReinitializeAudioRenderer,
270 weak_this_, stream, time));
254 } 271 }
255 } 272 }
256 273
257 void RendererImpl::RestartVideoRenderer(base::TimeDelta time) { 274 void RendererImpl::ReinitializeVideoRenderer(DemuxerStream* stream,
258 DVLOG(3) << __func__; 275 base::TimeDelta time) {
276 DVLOG(2) << __func__ << " stream=" << stream << " time=" << time.InSecondsF();
277 DCHECK(task_runner_->BelongsToCurrentThread());
278 DCHECK_NE(stream, current_video_stream_);
279
280 current_video_stream_ = stream;
281 video_renderer_->OnTimeStopped();
282 video_renderer_->Initialize(
283 stream, cdm_context_, video_renderer_client_.get(),
284 base::Bind(&RendererImpl::GetWallClockTimes, base::Unretained(this)),
285 base::Bind(&RendererImpl::OnVideoRendererReinitialized, weak_this_,
286 stream, time));
287 }
288
289 void RendererImpl::OnVideoRendererReinitialized(DemuxerStream* stream,
290 base::TimeDelta time,
291 PipelineStatus status) {
292 DVLOG(2) << __func__ << ": status=" << status;
293 DCHECK_EQ(stream, current_video_stream_);
294
295 if (status != PIPELINE_OK) {
296 OnError(status);
297 return;
298 }
299 RestartVideoRenderer(stream, time);
300 }
301
302 void RendererImpl::RestartVideoRenderer(DemuxerStream* stream,
303 base::TimeDelta time) {
304 DVLOG(2) << __func__ << " stream=" << stream << " time=" << time.InSecondsF();
259 DCHECK(task_runner_->BelongsToCurrentThread()); 305 DCHECK(task_runner_->BelongsToCurrentThread());
260 DCHECK(video_renderer_); 306 DCHECK(video_renderer_);
261 DCHECK_EQ(state_, STATE_PLAYING); 307 DCHECK(state_ == STATE_PLAYING || state_ == STATE_FLUSHING);
308 DCHECK_EQ(stream, current_video_stream_);
309
262 video_ended_ = false; 310 video_ended_ = false;
263 video_renderer_->StartPlayingFrom(time); 311 video_renderer_->StartPlayingFrom(time);
DaleCurtis 2017/03/31 21:22:08 This doesn't seem to toggle OnTimeProgressing?
servolk 2017/03/31 23:53:55 Yes, this simply tells video renderer to start rea
264 } 312 }
265 313
266 void RendererImpl::RestartAudioRenderer(base::TimeDelta time) { 314 void RendererImpl::ReinitializeAudioRenderer(DemuxerStream* stream,
267 DVLOG(3) << __func__; 315 base::TimeDelta time) {
316 DVLOG(2) << __func__ << " stream=" << stream << " time=" << time.InSecondsF();
268 DCHECK(task_runner_->BelongsToCurrentThread()); 317 DCHECK(task_runner_->BelongsToCurrentThread());
269 DCHECK_EQ(state_, STATE_PLAYING); 318 DCHECK_NE(stream, current_audio_stream_);
319
320 current_audio_stream_ = stream;
321 audio_renderer_->Initialize(
322 stream, cdm_context_, audio_renderer_client_.get(),
323 base::Bind(&RendererImpl::OnAudioRendererReinitialized, weak_this_,
324 stream, time));
325 }
326
327 void RendererImpl::OnAudioRendererReinitialized(DemuxerStream* stream,
328 base::TimeDelta time,
329 PipelineStatus status) {
330 DVLOG(2) << __func__ << ": status=" << status;
331 DCHECK_EQ(stream, current_audio_stream_);
332
333 if (status != PIPELINE_OK) {
334 OnError(status);
335 return;
336 }
337 RestartAudioRenderer(stream, time);
338 }
339
340 void RendererImpl::RestartAudioRenderer(DemuxerStream* stream,
341 base::TimeDelta time) {
342 DVLOG(2) << __func__ << " stream=" << stream << " time=" << time.InSecondsF();
343 DCHECK(task_runner_->BelongsToCurrentThread());
344 DCHECK(state_ == STATE_PLAYING || state_ == STATE_FLUSHING);
270 DCHECK(time_source_); 345 DCHECK(time_source_);
271 DCHECK(audio_renderer_); 346 DCHECK(audio_renderer_);
347 DCHECK_EQ(stream, current_audio_stream_);
348
272 audio_ended_ = false; 349 audio_ended_ = false;
273 audio_renderer_->StartPlaying(); 350 audio_renderer_->StartPlaying();
xhwang 2017/03/31 23:38:11 Not for this CL and I think we discussed this befo
servolk 2017/03/31 23:53:55 Because a. We don't know if the pending stream sta
274 } 351 }
275 352
276 void RendererImpl::SetPlaybackRate(double playback_rate) { 353 void RendererImpl::SetPlaybackRate(double playback_rate) {
277 DVLOG(1) << __func__ << "(" << playback_rate << ")"; 354 DVLOG(1) << __func__ << "(" << playback_rate << ")";
278 DCHECK(task_runner_->BelongsToCurrentThread()); 355 DCHECK(task_runner_->BelongsToCurrentThread());
279 356
280 // Playback rate changes are only carried out while playing. 357 // Playback rate changes are only carried out while playing.
281 if (state_ != STATE_PLAYING) 358 if (state_ != STATE_PLAYING)
282 return; 359 return;
283 360
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
387 // TODO(servolk): Implement proper support for multiple streams. But for now 464 // TODO(servolk): Implement proper support for multiple streams. But for now
388 // pick the first enabled stream to preserve the existing behavior. 465 // pick the first enabled stream to preserve the existing behavior.
389 DemuxerStream* audio_stream = 466 DemuxerStream* audio_stream =
390 media_resource_->GetFirstStream(DemuxerStream::AUDIO); 467 media_resource_->GetFirstStream(DemuxerStream::AUDIO);
391 if (!audio_stream) { 468 if (!audio_stream) {
392 audio_renderer_.reset(); 469 audio_renderer_.reset();
393 task_runner_->PostTask(FROM_HERE, base::Bind(done_cb, PIPELINE_OK)); 470 task_runner_->PostTask(FROM_HERE, base::Bind(done_cb, PIPELINE_OK));
394 return; 471 return;
395 } 472 }
396 473
474 current_audio_stream_ = audio_stream;
475
397 audio_renderer_client_.reset( 476 audio_renderer_client_.reset(
398 new RendererClientInternal(DemuxerStream::AUDIO, this)); 477 new RendererClientInternal(DemuxerStream::AUDIO, this));
399 // Note: After the initialization of a renderer, error events from it may 478 // Note: After the initialization of a renderer, error events from it may
400 // happen at any time and all future calls must guard against STATE_ERROR. 479 // happen at any time and all future calls must guard against STATE_ERROR.
401 audio_renderer_->Initialize(audio_stream, cdm_context_, 480 audio_renderer_->Initialize(audio_stream, cdm_context_,
402 audio_renderer_client_.get(), done_cb); 481 audio_renderer_client_.get(), done_cb);
403 } 482 }
404 483
405 void RendererImpl::OnAudioRendererInitializeDone(PipelineStatus status) { 484 void RendererImpl::OnAudioRendererInitializeDone(PipelineStatus status) {
406 DVLOG(1) << __func__ << ": " << status; 485 DVLOG(1) << __func__ << ": " << status;
(...skipping 28 matching lines...) Expand all
435 // TODO(servolk): Implement proper support for multiple streams. But for now 514 // TODO(servolk): Implement proper support for multiple streams. But for now
436 // pick the first enabled stream to preserve the existing behavior. 515 // pick the first enabled stream to preserve the existing behavior.
437 DemuxerStream* video_stream = 516 DemuxerStream* video_stream =
438 media_resource_->GetFirstStream(DemuxerStream::VIDEO); 517 media_resource_->GetFirstStream(DemuxerStream::VIDEO);
439 if (!video_stream) { 518 if (!video_stream) {
440 video_renderer_.reset(); 519 video_renderer_.reset();
441 task_runner_->PostTask(FROM_HERE, base::Bind(done_cb, PIPELINE_OK)); 520 task_runner_->PostTask(FROM_HERE, base::Bind(done_cb, PIPELINE_OK));
442 return; 521 return;
443 } 522 }
444 523
524 current_video_stream_ = video_stream;
525
445 video_renderer_client_.reset( 526 video_renderer_client_.reset(
446 new RendererClientInternal(DemuxerStream::VIDEO, this)); 527 new RendererClientInternal(DemuxerStream::VIDEO, this));
447 video_renderer_->Initialize( 528 video_renderer_->Initialize(
448 video_stream, cdm_context_, video_renderer_client_.get(), 529 video_stream, cdm_context_, video_renderer_client_.get(),
449 base::Bind(&RendererImpl::GetWallClockTimes, base::Unretained(this)), 530 base::Bind(&RendererImpl::GetWallClockTimes, base::Unretained(this)),
450 done_cb); 531 done_cb);
451 } 532 }
452 533
453 void RendererImpl::OnVideoRendererInitializeDone(PipelineStatus status) { 534 void RendererImpl::OnVideoRendererInitializeDone(PipelineStatus status) {
454 DVLOG(1) << __func__ << ": " << status; 535 DVLOG(1) << __func__ << ": " << status;
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after
621 PausePlayback(); 702 PausePlayback();
622 task_runner_->PostTask( 703 task_runner_->PostTask(
623 FROM_HERE, 704 FROM_HERE,
624 base::Bind(&RendererImpl::OnStreamRestartCompleted, weak_this_)); 705 base::Bind(&RendererImpl::OnStreamRestartCompleted, weak_this_));
625 } 706 }
626 } 707 }
627 return false; 708 return false;
628 } 709 }
629 710
630 void RendererImpl::OnStreamRestartCompleted() { 711 void RendererImpl::OnStreamRestartCompleted() {
712 DVLOG(3) << __func__ << " a=" << restarting_audio_
713 << " v=" << restarting_video_;
xhwang 2017/03/31 23:38:11 nit: it's gonna be hard to understand what a=1 mea
servolk 2017/03/31 23:53:55 Done.
631 DCHECK(restarting_audio_ || restarting_video_); 714 DCHECK(restarting_audio_ || restarting_video_);
632 restarting_audio_ = false; 715 restarting_audio_ = false;
633 restarting_video_ = false; 716 restarting_video_ = false;
634 if (!pending_stream_status_notifications_.empty()) { 717 if (!pending_stream_status_notifications_.empty()) {
635 pending_stream_status_notifications_.front().Run(); 718 pending_stream_status_notifications_.front().Run();
636 pending_stream_status_notifications_.pop_front(); 719 pending_stream_status_notifications_.pop_front();
xhwang 2017/03/31 23:38:11 nit: The Run() part calls OnStreamStatusChanged()
servolk 2017/03/31 23:53:55 Done.
720 } else if (flush_cb_) {
721 DCHECK_EQ(state_, STATE_FLUSHING);
722 DVLOG(3) << __func__ << " completing pending Flush";
723 // Resume pending Flush processing.
724 if (time_ticking_)
725 PausePlayback();
726
727 FlushAudioRenderer();
637 } 728 }
638 } 729 }
639 730
640 void RendererImpl::OnBufferingStateChange(DemuxerStream::Type type, 731 void RendererImpl::OnBufferingStateChange(DemuxerStream::Type type,
641 BufferingState new_buffering_state) { 732 BufferingState new_buffering_state) {
642 DCHECK((type == DemuxerStream::AUDIO) || (type == DemuxerStream::VIDEO)); 733 DCHECK((type == DemuxerStream::AUDIO) || (type == DemuxerStream::VIDEO));
643 BufferingState* buffering_state = type == DemuxerStream::AUDIO 734 BufferingState* buffering_state = type == DemuxerStream::AUDIO
644 ? &audio_buffering_state_ 735 ? &audio_buffering_state_
645 : &video_buffering_state_; 736 : &video_buffering_state_;
646 737
(...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after
849 DCHECK(task_runner_->BelongsToCurrentThread()); 940 DCHECK(task_runner_->BelongsToCurrentThread());
850 client_->OnVideoNaturalSizeChange(size); 941 client_->OnVideoNaturalSizeChange(size);
851 } 942 }
852 943
853 void RendererImpl::OnVideoOpacityChange(bool opaque) { 944 void RendererImpl::OnVideoOpacityChange(bool opaque) {
854 DCHECK(task_runner_->BelongsToCurrentThread()); 945 DCHECK(task_runner_->BelongsToCurrentThread());
855 client_->OnVideoOpacityChange(opaque); 946 client_->OnVideoOpacityChange(opaque);
856 } 947 }
857 948
858 } // namespace media 949 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698