 Chromium Code Reviews
 Chromium Code Reviews Issue 2684103005:
  Allow media track switching.  (Closed)
    
  
    Issue 2684103005:
  Allow media track switching.  (Closed) 
  | 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 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 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 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 230 << " status change handling."; | 232 << " status change handling."; | 
| 231 pending_stream_status_notifications_.push_back( | 233 pending_stream_status_notifications_.push_back( | 
| 232 base::Bind(&RendererImpl::OnStreamStatusChanged, weak_this_, stream, | 234 base::Bind(&RendererImpl::OnStreamStatusChanged, weak_this_, stream, | 
| 233 enabled, time)); | 235 enabled, time)); | 
| 234 return; | 236 return; | 
| 235 } | 237 } | 
| 236 if (stream->type() == DemuxerStream::VIDEO) { | 238 if (stream->type() == DemuxerStream::VIDEO) { | 
| 237 DCHECK(video_renderer_); | 239 DCHECK(video_renderer_); | 
| 238 restarting_video_ = true; | 240 restarting_video_ = true; | 
| 239 video_renderer_->Flush( | 241 video_renderer_->Flush( | 
| 240 base::Bind(&RendererImpl::RestartVideoRenderer, weak_this_, time)); | 242 base::Bind((stream == current_video_stream_) | 
| 243 ? &RendererImpl::RestartVideoRenderer | |
| 244 : &RendererImpl::ReinitializeVideoRenderer, | |
| 245 weak_this_, stream, time)); | |
| 241 } else if (stream->type() == DemuxerStream::AUDIO) { | 246 } else if (stream->type() == DemuxerStream::AUDIO) { | 
| 242 DCHECK(audio_renderer_); | 247 DCHECK(audio_renderer_); | 
| 243 DCHECK(time_source_); | 248 DCHECK(time_source_); | 
| 244 restarting_audio_ = true; | 249 restarting_audio_ = true; | 
| 245 // Stop ticking (transition into paused state) in audio renderer before | 250 // Stop ticking (transition into paused state) in audio renderer before | 
| 246 // calling Flush, since after Flush we are going to restart playback by | 251 // calling Flush, since after Flush we are going to restart playback by | 
| 247 // calling audio renderer StartPlaying which would fail in playing state. | 252 // calling audio renderer StartPlaying which would fail in playing state. | 
| 248 if (time_ticking_) { | 253 if (time_ticking_) { | 
| 249 time_ticking_ = false; | 254 time_ticking_ = false; | 
| 250 time_source_->StopTicking(); | 255 time_source_->StopTicking(); | 
| 251 } | 256 } | 
| 252 audio_renderer_->Flush( | 257 audio_renderer_->Flush( | 
| 253 base::Bind(&RendererImpl::RestartAudioRenderer, weak_this_, time)); | 258 base::Bind((stream == current_audio_stream_) | 
| 259 ? &RendererImpl::RestartAudioRenderer | |
| 260 : &RendererImpl::ReinitializeAudioRenderer, | |
| 261 weak_this_, stream, time)); | |
| 254 } | 262 } | 
| 255 } | 263 } | 
| 256 | 264 | 
| 257 void RendererImpl::RestartVideoRenderer(base::TimeDelta time) { | 265 void RendererImpl::ReinitializeVideoRenderer(DemuxerStream* stream, | 
| 258 DVLOG(3) << __func__; | 266 base::TimeDelta time) { | 
| 267 DVLOG(3) << __func__ << " stream=" << stream << " time=" << time.InSecondsF(); | |
| 
xhwang
2017/03/29 00:16:47
nit: here and everywhere else, media switching isn
 
servolk
2017/03/29 01:49:33
Done.
 | |
| 268 DCHECK(task_runner_->BelongsToCurrentThread()); | |
| 269 DCHECK_NE(stream, current_video_stream_); | |
| 270 | |
| 271 current_video_stream_ = stream; | |
| 272 video_renderer_->OnTimeStopped(); | |
| 273 video_renderer_->Initialize( | |
| 274 stream, cdm_context_, video_renderer_client_.get(), | |
| 275 base::Bind(&RendererImpl::GetWallClockTimes, base::Unretained(this)), | |
| 276 base::Bind(&RendererImpl::OnVideoRendererReinitialized, weak_this_, | |
| 277 stream, time)); | |
| 278 } | |
| 279 | |
| 280 void RendererImpl::OnVideoRendererReinitialized(DemuxerStream* stream, | |
| 
xhwang
2017/03/29 00:16:47
nit: Why do we need to pass in the |stream| here a
 
servolk
2017/03/29 01:49:33
Well, we could do without it, but it's just slight
 | |
| 281 base::TimeDelta time, | |
| 282 PipelineStatus status) { | |
| 283 DVLOG(3) << __func__ << ": status=" << status; | |
| 284 DCHECK_EQ(stream, current_video_stream_); | |
| 285 | |
| 286 if (status != PIPELINE_OK) { | |
| 287 OnError(status); | |
| 288 return; | |
| 289 } | |
| 290 RestartVideoRenderer(stream, time); | |
| 291 } | |
| 292 | |
| 293 void RendererImpl::RestartVideoRenderer(DemuxerStream* stream, | |
| 294 base::TimeDelta time) { | |
| 295 DVLOG(3) << __func__ << " stream=" << stream << " time=" << time.InSecondsF(); | |
| 259 DCHECK(task_runner_->BelongsToCurrentThread()); | 296 DCHECK(task_runner_->BelongsToCurrentThread()); | 
| 260 DCHECK(video_renderer_); | 297 DCHECK(video_renderer_); | 
| 261 DCHECK_EQ(state_, STATE_PLAYING); | 298 DCHECK_EQ(state_, STATE_PLAYING); | 
| 299 DCHECK_EQ(stream, current_video_stream_); | |
| 300 | |
| 262 video_ended_ = false; | 301 video_ended_ = false; | 
| 263 video_renderer_->StartPlayingFrom(time); | 302 video_renderer_->StartPlayingFrom(time); | 
| 264 } | 303 } | 
| 265 | 304 | 
| 266 void RendererImpl::RestartAudioRenderer(base::TimeDelta time) { | 305 void RendererImpl::ReinitializeAudioRenderer(DemuxerStream* stream, | 
| 267 DVLOG(3) << __func__; | 306 base::TimeDelta time) { | 
| 307 DVLOG(3) << __func__ << " stream=" << stream << " time=" << time.InSecondsF(); | |
| 308 DCHECK(task_runner_->BelongsToCurrentThread()); | |
| 309 DCHECK_NE(stream, current_audio_stream_); | |
| 310 | |
| 311 current_audio_stream_ = stream; | |
| 312 audio_renderer_->Initialize( | |
| 313 stream, cdm_context_, audio_renderer_client_.get(), | |
| 314 base::Bind(&RendererImpl::OnAudioRendererReinitialized, weak_this_, | |
| 315 stream, time)); | |
| 316 } | |
| 317 | |
| 318 void RendererImpl::OnAudioRendererReinitialized(DemuxerStream* stream, | |
| 319 base::TimeDelta time, | |
| 320 PipelineStatus status) { | |
| 321 DVLOG(3) << __func__ << ": status=" << status; | |
| 322 DCHECK_EQ(stream, current_audio_stream_); | |
| 323 | |
| 324 if (status != PIPELINE_OK) { | |
| 325 OnError(status); | |
| 326 return; | |
| 327 } | |
| 328 RestartAudioRenderer(stream, time); | |
| 329 } | |
| 330 | |
| 331 void RendererImpl::RestartAudioRenderer(DemuxerStream* stream, | |
| 332 base::TimeDelta time) { | |
| 333 DVLOG(3) << __func__ << " stream=" << stream << " time=" << time.InSecondsF(); | |
| 268 DCHECK(task_runner_->BelongsToCurrentThread()); | 334 DCHECK(task_runner_->BelongsToCurrentThread()); | 
| 269 DCHECK_EQ(state_, STATE_PLAYING); | 335 DCHECK_EQ(state_, STATE_PLAYING); | 
| 270 DCHECK(time_source_); | 336 DCHECK(time_source_); | 
| 271 DCHECK(audio_renderer_); | 337 DCHECK(audio_renderer_); | 
| 338 DCHECK_EQ(stream, current_audio_stream_); | |
| 339 | |
| 272 audio_ended_ = false; | 340 audio_ended_ = false; | 
| 273 audio_renderer_->StartPlaying(); | 341 audio_renderer_->StartPlaying(); | 
| 274 } | 342 } | 
| 275 | 343 | 
| 276 void RendererImpl::SetPlaybackRate(double playback_rate) { | 344 void RendererImpl::SetPlaybackRate(double playback_rate) { | 
| 277 DVLOG(1) << __func__ << "(" << playback_rate << ")"; | 345 DVLOG(1) << __func__ << "(" << playback_rate << ")"; | 
| 278 DCHECK(task_runner_->BelongsToCurrentThread()); | 346 DCHECK(task_runner_->BelongsToCurrentThread()); | 
| 279 | 347 | 
| 280 // Playback rate changes are only carried out while playing. | 348 // Playback rate changes are only carried out while playing. | 
| 281 if (state_ != STATE_PLAYING) | 349 if (state_ != STATE_PLAYING) | 
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 387 // TODO(servolk): Implement proper support for multiple streams. But for now | 455 // TODO(servolk): Implement proper support for multiple streams. But for now | 
| 388 // pick the first enabled stream to preserve the existing behavior. | 456 // pick the first enabled stream to preserve the existing behavior. | 
| 389 DemuxerStream* audio_stream = | 457 DemuxerStream* audio_stream = | 
| 390 media_resource_->GetFirstStream(DemuxerStream::AUDIO); | 458 media_resource_->GetFirstStream(DemuxerStream::AUDIO); | 
| 391 if (!audio_stream) { | 459 if (!audio_stream) { | 
| 392 audio_renderer_.reset(); | 460 audio_renderer_.reset(); | 
| 393 task_runner_->PostTask(FROM_HERE, base::Bind(done_cb, PIPELINE_OK)); | 461 task_runner_->PostTask(FROM_HERE, base::Bind(done_cb, PIPELINE_OK)); | 
| 394 return; | 462 return; | 
| 395 } | 463 } | 
| 396 | 464 | 
| 465 current_audio_stream_ = audio_stream; | |
| 466 | |
| 397 audio_renderer_client_.reset( | 467 audio_renderer_client_.reset( | 
| 398 new RendererClientInternal(DemuxerStream::AUDIO, this)); | 468 new RendererClientInternal(DemuxerStream::AUDIO, this)); | 
| 399 // Note: After the initialization of a renderer, error events from it may | 469 // 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. | 470 // happen at any time and all future calls must guard against STATE_ERROR. | 
| 401 audio_renderer_->Initialize(audio_stream, cdm_context_, | 471 audio_renderer_->Initialize(audio_stream, cdm_context_, | 
| 402 audio_renderer_client_.get(), done_cb); | 472 audio_renderer_client_.get(), done_cb); | 
| 403 } | 473 } | 
| 404 | 474 | 
| 405 void RendererImpl::OnAudioRendererInitializeDone(PipelineStatus status) { | 475 void RendererImpl::OnAudioRendererInitializeDone(PipelineStatus status) { | 
| 406 DVLOG(1) << __func__ << ": " << status; | 476 DVLOG(1) << __func__ << ": " << status; | 
| (...skipping 28 matching lines...) Expand all Loading... | |
| 435 // TODO(servolk): Implement proper support for multiple streams. But for now | 505 // TODO(servolk): Implement proper support for multiple streams. But for now | 
| 436 // pick the first enabled stream to preserve the existing behavior. | 506 // pick the first enabled stream to preserve the existing behavior. | 
| 437 DemuxerStream* video_stream = | 507 DemuxerStream* video_stream = | 
| 438 media_resource_->GetFirstStream(DemuxerStream::VIDEO); | 508 media_resource_->GetFirstStream(DemuxerStream::VIDEO); | 
| 439 if (!video_stream) { | 509 if (!video_stream) { | 
| 440 video_renderer_.reset(); | 510 video_renderer_.reset(); | 
| 441 task_runner_->PostTask(FROM_HERE, base::Bind(done_cb, PIPELINE_OK)); | 511 task_runner_->PostTask(FROM_HERE, base::Bind(done_cb, PIPELINE_OK)); | 
| 442 return; | 512 return; | 
| 443 } | 513 } | 
| 444 | 514 | 
| 515 current_video_stream_ = video_stream; | |
| 516 | |
| 445 video_renderer_client_.reset( | 517 video_renderer_client_.reset( | 
| 446 new RendererClientInternal(DemuxerStream::VIDEO, this)); | 518 new RendererClientInternal(DemuxerStream::VIDEO, this)); | 
| 447 video_renderer_->Initialize( | 519 video_renderer_->Initialize( | 
| 448 video_stream, cdm_context_, video_renderer_client_.get(), | 520 video_stream, cdm_context_, video_renderer_client_.get(), | 
| 449 base::Bind(&RendererImpl::GetWallClockTimes, base::Unretained(this)), | 521 base::Bind(&RendererImpl::GetWallClockTimes, base::Unretained(this)), | 
| 450 done_cb); | 522 done_cb); | 
| 451 } | 523 } | 
| 452 | 524 | 
| 453 void RendererImpl::OnVideoRendererInitializeDone(PipelineStatus status) { | 525 void RendererImpl::OnVideoRendererInitializeDone(PipelineStatus status) { | 
| 454 DVLOG(1) << __func__ << ": " << status; | 526 DVLOG(1) << __func__ << ": " << status; | 
| (...skipping 394 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 849 DCHECK(task_runner_->BelongsToCurrentThread()); | 921 DCHECK(task_runner_->BelongsToCurrentThread()); | 
| 850 client_->OnVideoNaturalSizeChange(size); | 922 client_->OnVideoNaturalSizeChange(size); | 
| 851 } | 923 } | 
| 852 | 924 | 
| 853 void RendererImpl::OnVideoOpacityChange(bool opaque) { | 925 void RendererImpl::OnVideoOpacityChange(bool opaque) { | 
| 854 DCHECK(task_runner_->BelongsToCurrentThread()); | 926 DCHECK(task_runner_->BelongsToCurrentThread()); | 
| 855 client_->OnVideoOpacityChange(opaque); | 927 client_->OnVideoOpacityChange(opaque); | 
| 856 } | 928 } | 
| 857 | 929 | 
| 858 } // namespace media | 930 } // namespace media | 
| OLD | NEW |