1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "media/base/pipeline.h" 6 7 #include <algorithm> 8 9 #include "base/bind.h" 10 #include "base/callback.h" 11 #include "base/callback_helpers.h" 12 #include "base/compiler_specific.h" 13 #include "base/location.h" 14 #include "base/metrics/histogram.h" 15 #include "base/single_thread_task_runner.h" 16 #include "base/stl_util.h" 17 #include "base/strings/string_number_conversions.h" 18 #include "base/strings/string_util.h" 19 #include "base/synchronization/condition_variable.h" 20 #include "media/base/audio_decoder.h" 21 #include "media/base/audio_renderer.h" 22 #include "media/base/clock.h" 23 #include "media/base/filter_collection.h" 24 #include "media/base/media_log.h" 25 #include "media/base/text_renderer.h" 26 #include "media/base/text_track_config.h" 27 #include "media/base/video_decoder.h" 28 #include "media/base/video_decoder_config.h" 29 #include "media/base/video_renderer.h" 30 31 using base::TimeDelta; 32 33 namespace media { 34 35 Pipeline::Pipeline( 36 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, 37 MediaLog* media_log) 38 : task_runner_(task_runner), 39 media_log_(media_log), 40 running_(false), 41 did_loading_progress_(false), 42 volume_(1.0f), 43 playback_rate_(0.0f), 44 clock_(new Clock(&default_tick_clock_)), 45 clock_state_(CLOCK_PAUSED), 46 status_(PIPELINE_OK), 47 state_(kCreated), 48 audio_ended_(false), 49 video_ended_(false), 50 text_ended_(false), 51 audio_buffering_state_(BUFFERING_HAVE_NOTHING), 52 video_buffering_state_(BUFFERING_HAVE_NOTHING), 53 demuxer_(NULL), 54 creation_time_(default_tick_clock_.NowTicks()) { 55 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(kCreated)); 56 media_log_->AddEvent( 57 media_log_->CreateEvent(MediaLogEvent::PIPELINE_CREATED)); 58 } 59 60 Pipeline::~Pipeline() { 61 DCHECK(thread_checker_.CalledOnValidThread()) 62 << "Pipeline must be destroyed on same thread that created it"; 63 DCHECK(!running_) << "Stop() must complete before destroying object"; 64 DCHECK(stop_cb_.is_null()); 65 DCHECK(seek_cb_.is_null()); 66 67 media_log_->AddEvent( 68 media_log_->CreateEvent(MediaLogEvent::PIPELINE_DESTROYED)); 69 } 70 71 void Pipeline::Start(scoped_ptr<FilterCollection> collection, 72 const base::Closure& ended_cb, 73 const PipelineStatusCB& error_cb, 74 const PipelineStatusCB& seek_cb, 75 const PipelineMetadataCB& metadata_cb, 76 const base::Closure& preroll_completed_cb, 77 const base::Closure& duration_change_cb) { 78 DCHECK(!ended_cb.is_null()); 79 DCHECK(!error_cb.is_null()); 80 DCHECK(!seek_cb.is_null()); 81 DCHECK(!metadata_cb.is_null()); 82 DCHECK(!preroll_completed_cb.is_null()); 83 84 base::AutoLock auto_lock(lock_); 85 CHECK(!running_) << "Media pipeline is already running"; 86 running_ = true; 87 88 filter_collection_ = collection.Pass(); 89 ended_cb_ = ended_cb; 90 error_cb_ = error_cb; 91 seek_cb_ = seek_cb; 92 metadata_cb_ = metadata_cb; 93 preroll_completed_cb_ = preroll_completed_cb; 94 duration_change_cb_ = duration_change_cb; 95 96 task_runner_->PostTask( 97 FROM_HERE, base::Bind(&Pipeline::StartTask, base::Unretained(this))); 98 } 99 100 void Pipeline::Stop(const base::Closure& stop_cb) { 101 base::AutoLock auto_lock(lock_); 102 task_runner_->PostTask(FROM_HERE, base::Bind( 103 &Pipeline::StopTask, base::Unretained(this), stop_cb)); 104 } 105 106 void Pipeline::Seek(TimeDelta time, const PipelineStatusCB& seek_cb) { 107 base::AutoLock auto_lock(lock_); 108 if (!running_) { 109 NOTREACHED() << "Media pipeline isn't running"; 110 return; 111 } 112 113 task_runner_->PostTask(FROM_HERE, base::Bind( 114 &Pipeline::SeekTask, base::Unretained(this), time, seek_cb)); 115 } 116 117 bool Pipeline::IsRunning() const { 118 base::AutoLock auto_lock(lock_); 119 return running_; 120 } 121 122 float Pipeline::GetPlaybackRate() const { 123 base::AutoLock auto_lock(lock_); 124 return playback_rate_; 125 } 126 127 void Pipeline::SetPlaybackRate(float playback_rate) { 128 if (playback_rate < 0.0f) 129 return; 130 131 base::AutoLock auto_lock(lock_); 132 playback_rate_ = playback_rate; 133 if (running_) { 134 task_runner_->PostTask(FROM_HERE, base::Bind( 135 &Pipeline::PlaybackRateChangedTask, base::Unretained(this), 136 playback_rate)); 137 } 138 } 139 140 float Pipeline::GetVolume() const { 141 base::AutoLock auto_lock(lock_); 142 return volume_; 143 } 144 145 void Pipeline::SetVolume(float volume) { 146 if (volume < 0.0f || volume > 1.0f) 147 return; 148 149 base::AutoLock auto_lock(lock_); 150 volume_ = volume; 151 if (running_) { 152 task_runner_->PostTask(FROM_HERE, base::Bind( 153 &Pipeline::VolumeChangedTask, base::Unretained(this), volume)); 154 } 155 } 156 157 TimeDelta Pipeline::GetMediaTime() const { 158 base::AutoLock auto_lock(lock_); 159 return clock_->Elapsed(); 160 } 161 162 Ranges<TimeDelta> Pipeline::GetBufferedTimeRanges() const { 163 base::AutoLock auto_lock(lock_); 164 return buffered_time_ranges_; 165 } 166 167 TimeDelta Pipeline::GetMediaDuration() const { 168 base::AutoLock auto_lock(lock_); 169 return clock_->Duration(); 170 } 171 172 bool Pipeline::DidLoadingProgress() { 173 base::AutoLock auto_lock(lock_); 174 bool ret = did_loading_progress_; 175 did_loading_progress_ = false; 176 return ret; 177 } 178 179 PipelineStatistics Pipeline::GetStatistics() const { 180 base::AutoLock auto_lock(lock_); 181 return statistics_; 182 } 183 184 void Pipeline::SetClockForTesting(Clock* clock) { 185 clock_.reset(clock); 186 } 187 188 void Pipeline::SetErrorForTesting(PipelineStatus status) { 189 SetError(status); 190 } 191 192 void Pipeline::SetState(State next_state) { 193 if (state_ != kPlaying && next_state == kPlaying && 194 !creation_time_.is_null()) { 195 UMA_HISTOGRAM_TIMES("Media.TimeToPipelineStarted", 196 default_tick_clock_.NowTicks() - creation_time_); 197 creation_time_ = base::TimeTicks(); 198 } 199 200 DVLOG(1) << GetStateString(state_) << " -> " << GetStateString(next_state); 201 202 state_ = next_state; 203 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(next_state)); 204 } 205 206 #define RETURN_STRING(state) case state: return #state; 207 208 const char* Pipeline::GetStateString(State state) { 209 switch (state) { 210 RETURN_STRING(kCreated); 211 RETURN_STRING(kInitDemuxer); 212 RETURN_STRING(kInitAudioRenderer); 213 RETURN_STRING(kInitVideoRenderer); 214 RETURN_STRING(kInitPrerolling); 215 RETURN_STRING(kSeeking); 216 RETURN_STRING(kPlaying); 217 RETURN_STRING(kStopping); 218 RETURN_STRING(kStopped); 219 } 220 NOTREACHED(); 221 return "INVALID"; 222 } 223 224 #undef RETURN_STRING 225 226 Pipeline::State Pipeline::GetNextState() const { 227 DCHECK(task_runner_->BelongsToCurrentThread()); 228 DCHECK(stop_cb_.is_null()) 229 << "State transitions don't happen when stopping"; 230 DCHECK_EQ(status_, PIPELINE_OK) 231 << "State transitions don't happen when there's an error: " << status_; 232 233 switch (state_) { 234 case kCreated: 235 return kInitDemuxer; 236 237 case kInitDemuxer: 238 if (demuxer_->GetStream(DemuxerStream::AUDIO)) 239 return kInitAudioRenderer; 240 if (demuxer_->GetStream(DemuxerStream::VIDEO)) 241 return kInitVideoRenderer; 242 return kInitPrerolling; 243 244 case kInitAudioRenderer: 245 if (demuxer_->GetStream(DemuxerStream::VIDEO)) 246 return kInitVideoRenderer; 247 return kInitPrerolling; 248 249 case kInitVideoRenderer: 250 return kInitPrerolling; 251 252 case kInitPrerolling: 253 return kPlaying; 254 255 case kSeeking: 256 return kPlaying; 257 258 case kPlaying: 259 case kStopping: 260 case kStopped: 261 break; 262 } 263 NOTREACHED() << "State has no transition: " << state_; 264 return state_; 265 } 266 267 void Pipeline::OnDemuxerError(PipelineStatus error) { 268 SetError(error); 269 } 270 271 void Pipeline::AddTextStream(DemuxerStream* text_stream, 272 const TextTrackConfig& config) { 273 task_runner_->PostTask(FROM_HERE, base::Bind( 274 &Pipeline::AddTextStreamTask, base::Unretained(this), 275 text_stream, config)); 276 } 277 278 void Pipeline::RemoveTextStream(DemuxerStream* text_stream) { 279 task_runner_->PostTask(FROM_HERE, base::Bind( 280 &Pipeline::RemoveTextStreamTask, base::Unretained(this), 281 text_stream)); 282 } 283 284 void Pipeline::SetError(PipelineStatus error) { 285 DCHECK(IsRunning()); 286 DCHECK_NE(PIPELINE_OK, error); 287 VLOG(1) << "Media pipeline error: " << error; 288 289 task_runner_->PostTask(FROM_HERE, base::Bind( 290 &Pipeline::ErrorChangedTask, base::Unretained(this), error)); 291 292 media_log_->AddEvent(media_log_->CreatePipelineErrorEvent(error)); 293 } 294 295 void Pipeline::OnAudioTimeUpdate(TimeDelta time, TimeDelta max_time) { 296 DCHECK(task_runner_->BelongsToCurrentThread()); 297 DCHECK_LE(time.InMicroseconds(), max_time.InMicroseconds()); 298 base::AutoLock auto_lock(lock_); 299 300 if (clock_state_ == CLOCK_WAITING_FOR_AUDIO_TIME_UPDATE && 301 time < clock_->Elapsed()) { 302 return; 303 } 304 305 if (state_ == kSeeking) 306 return; 307 308 clock_->SetTime(time, max_time); 309 StartClockIfWaitingForTimeUpdate_Locked(); 310 } 311 312 void Pipeline::OnVideoTimeUpdate(TimeDelta max_time) { 313 DCHECK(task_runner_->BelongsToCurrentThread()); 314 315 if (audio_renderer_) 316 return; 317 318 if (state_ == kSeeking) 319 return; 320 321 base::AutoLock auto_lock(lock_); 322 DCHECK_NE(clock_state_, CLOCK_WAITING_FOR_AUDIO_TIME_UPDATE); 323 clock_->SetMaxTime(max_time); 324 } 325 326 void Pipeline::SetDuration(TimeDelta duration) { 327 DCHECK(IsRunning()); 328 media_log_->AddEvent( 329 media_log_->CreateTimeEvent( 330 MediaLogEvent::DURATION_SET, "duration", duration)); 331 UMA_HISTOGRAM_LONG_TIMES("Media.Duration", duration); 332 333 base::AutoLock auto_lock(lock_); 334 clock_->SetDuration(duration); 335 if (!duration_change_cb_.is_null()) 336 duration_change_cb_.Run(); 337 } 338 339 void Pipeline::OnStateTransition(PipelineStatus status) { 340 // Force post to process state transitions after current execution frame. 341 task_runner_->PostTask(FROM_HERE, base::Bind( 342 &Pipeline::StateTransitionTask, base::Unretained(this), status)); 343 } 344 345 void Pipeline::StateTransitionTask(PipelineStatus status) { 346 DCHECK(task_runner_->BelongsToCurrentThread()); 347 348 // No-op any state transitions if we're stopping. 349 if (state_ == kStopping || state_ == kStopped) 350 return; 351 352 // Preserve existing abnormal status, otherwise update based on the result of 353 // the previous operation. 354 status_ = (status_ != PIPELINE_OK ? status_ : status); 355 356 if (status_ != PIPELINE_OK) { 357 ErrorChangedTask(status_); 358 return; 359 } 360 361 // Guard against accidentally clearing |pending_callbacks_| for states that 362 // use it as well as states that should not be using it. 363 DCHECK_EQ(pending_callbacks_.get() != NULL, 364 (state_ == kInitPrerolling || state_ == kSeeking)); 365 366 pending_callbacks_.reset(); 367 368 PipelineStatusCB done_cb = base::Bind( 369 &Pipeline::OnStateTransition, base::Unretained(this)); 370 371 // Switch states, performing any entrance actions for the new state as well. 372 SetState(GetNextState()); 373 switch (state_) { 374 case kInitDemuxer: 375 return InitializeDemuxer(done_cb); 376 377 case kInitAudioRenderer: 378 return InitializeAudioRenderer(done_cb); 379 380 case kInitVideoRenderer: 381 return InitializeVideoRenderer(done_cb); 382 383 case kInitPrerolling: 384 filter_collection_.reset(); 385 { 386 base::AutoLock l(lock_); 387 // We do not want to start the clock running. We only want to set the 388 // base media time so our timestamp calculations will be correct. 389 clock_->SetTime(demuxer_->GetStartTime(), demuxer_->GetStartTime()); 390 } 391 if (!audio_renderer_ && !video_renderer_) { 392 done_cb.Run(PIPELINE_ERROR_COULD_NOT_RENDER); 393 return; 394 } 395 396 { 397 PipelineMetadata metadata; 398 metadata.has_audio = audio_renderer_; 399 metadata.has_video = video_renderer_; 400 metadata.timeline_offset = demuxer_->GetTimelineOffset(); 401 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO); 402 if (stream) 403 metadata.natural_size = stream->video_decoder_config().natural_size(); 404 metadata_cb_.Run(metadata); 405 } 406 407 return DoInitialPreroll(done_cb); 408 409 case kPlaying: 410 PlaybackRateChangedTask(GetPlaybackRate()); 411 VolumeChangedTask(GetVolume()); 412 413 // We enter this state from either kInitPrerolling or kSeeking. As of now 414 // both those states call Preroll(), which means by time we enter this 415 // state we've already buffered enough data. Forcefully update the 416 // buffering state, which start the clock and renderers and transition 417 // into kPlaying state. 418 // 419 // TODO(scherkus): Remove after renderers are taught to fire buffering 420 // state callbacks http://crbug.com/144683 421 DCHECK(WaitingForEnoughData()); 422 if (audio_renderer_) 423 BufferingStateChanged(&audio_buffering_state_, BUFFERING_HAVE_ENOUGH); 424 if (video_renderer_) 425 BufferingStateChanged(&video_buffering_state_, BUFFERING_HAVE_ENOUGH); 426 return; 427 428 case kStopping: 429 case kStopped: 430 case kCreated: 431 case kSeeking: 432 NOTREACHED() << "State has no transition: " << state_; 433 return; 434 } 435 } 436 437 // Note that the usage of base::Unretained() with the audio/video renderers 438 // in the following DoXXX() functions is considered safe as they are owned by 439 // |pending_callbacks_| and share the same lifetime. 440 // 441 // That being said, deleting the renderers while keeping |pending_callbacks_| 442 // running on the media thread would result in crashes. 443 void Pipeline::DoInitialPreroll(const PipelineStatusCB& done_cb) { 444 DCHECK(task_runner_->BelongsToCurrentThread()); 445 DCHECK(!pending_callbacks_.get()); 446 SerialRunner::Queue bound_fns; 447 448 base::TimeDelta seek_timestamp = demuxer_->GetStartTime(); 449 450 // Preroll renderers. 451 if (audio_renderer_) { 452 bound_fns.Push(base::Bind( 453 &AudioRenderer::Preroll, base::Unretained(audio_renderer_.get()), 454 seek_timestamp)); 455 } 456 457 if (video_renderer_) { 458 bound_fns.Push(base::Bind( 459 &VideoRenderer::Preroll, base::Unretained(video_renderer_.get()), 460 seek_timestamp)); 461 462 // TODO(scherkus): Remove after VideoRenderer is taught to fire buffering 463 // state callbacks http://crbug.com/144683 464 bound_fns.Push(base::Bind(&VideoRenderer::Play, 465 base::Unretained(video_renderer_.get()))); 466 } 467 468 if (text_renderer_) { 469 bound_fns.Push(base::Bind( 470 &TextRenderer::Play, base::Unretained(text_renderer_.get()))); 471 } 472 473 pending_callbacks_ = SerialRunner::Run(bound_fns, done_cb); 474 } 475 476 void Pipeline::DoSeek( 477 base::TimeDelta seek_timestamp, 478 const PipelineStatusCB& done_cb) { 479 DCHECK(task_runner_->BelongsToCurrentThread()); 480 DCHECK(!pending_callbacks_.get()); 481 SerialRunner::Queue bound_fns; 482 483 // Pause. 484 if (text_renderer_) { 485 bound_fns.Push(base::Bind( 486 &TextRenderer::Pause, base::Unretained(text_renderer_.get()))); 487 } 488 489 // Flush. 490 if (audio_renderer_) { 491 bound_fns.Push(base::Bind( 492 &AudioRenderer::Flush, base::Unretained(audio_renderer_.get()))); 493 494 // TODO(scherkus): Remove after AudioRenderer is taught to fire buffering 495 // state callbacks http://crbug.com/144683 496 bound_fns.Push(base::Bind(&Pipeline::BufferingStateChanged, 497 base::Unretained(this), 498 &audio_buffering_state_, 499 BUFFERING_HAVE_NOTHING)); 500 } 501 if (video_renderer_) { 502 bound_fns.Push(base::Bind( 503 &VideoRenderer::Flush, base::Unretained(video_renderer_.get()))); 504 505 // TODO(scherkus): Remove after VideoRenderer is taught to fire buffering 506 // state callbacks http://crbug.com/144683 507 bound_fns.Push(base::Bind(&Pipeline::BufferingStateChanged, 508 base::Unretained(this), 509 &video_buffering_state_, 510 BUFFERING_HAVE_NOTHING)); 511 } 512 if (text_renderer_) { 513 bound_fns.Push(base::Bind( 514 &TextRenderer::Flush, base::Unretained(text_renderer_.get()))); 515 } 516 517 // Seek demuxer. 518 bound_fns.Push(base::Bind( 519 &Demuxer::Seek, base::Unretained(demuxer_), seek_timestamp)); 520 521 // Preroll renderers. 522 if (audio_renderer_) { 523 bound_fns.Push(base::Bind( 524 &AudioRenderer::Preroll, base::Unretained(audio_renderer_.get()), 525 seek_timestamp)); 526 } 527 528 if (video_renderer_) { 529 bound_fns.Push(base::Bind( 530 &VideoRenderer::Preroll, base::Unretained(video_renderer_.get()), 531 seek_timestamp)); 532 533 // TODO(scherkus): Remove after renderers are taught to fire buffering 534 // state callbacks http://crbug.com/144683 535 bound_fns.Push(base::Bind(&VideoRenderer::Play, 536 base::Unretained(video_renderer_.get()))); 537 } 538 539 if (text_renderer_) { 540 bound_fns.Push(base::Bind( 541 &TextRenderer::Play, base::Unretained(text_renderer_.get()))); 542 } 543 544 pending_callbacks_ = SerialRunner::Run(bound_fns, done_cb); 545 } 546 547 void Pipeline::DoStop(const PipelineStatusCB& done_cb) { 548 DCHECK(task_runner_->BelongsToCurrentThread()); 549 DCHECK(!pending_callbacks_.get()); 550 SerialRunner::Queue bound_fns; 551 552 if (demuxer_) { 553 bound_fns.Push(base::Bind( 554 &Demuxer::Stop, base::Unretained(demuxer_))); 555 } 556 557 if (audio_renderer_) { 558 bound_fns.Push(base::Bind( 559 &AudioRenderer::Stop, base::Unretained(audio_renderer_.get()))); 560 } 561 562 if (video_renderer_) { 563 bound_fns.Push(base::Bind( 564 &VideoRenderer::Stop, base::Unretained(video_renderer_.get()))); 565 } 566 567 if (text_renderer_) { 568 bound_fns.Push(base::Bind( 569 &TextRenderer::Stop, base::Unretained(text_renderer_.get()))); 570 } 571 572 pending_callbacks_ = SerialRunner::Run(bound_fns, done_cb); 573 } 574 575 void Pipeline::OnStopCompleted(PipelineStatus status) { 576 DCHECK(task_runner_->BelongsToCurrentThread()); 577 DCHECK_EQ(state_, kStopping); 578 { 579 base::AutoLock l(lock_); 580 running_ = false; 581 } 582 583 SetState(kStopped); 584 pending_callbacks_.reset(); 585 filter_collection_.reset(); 586 audio_renderer_.reset(); 587 video_renderer_.reset(); 588 text_renderer_.reset(); 589 demuxer_ = NULL; 590 591 // If we stop during initialization/seeking we want to run |seek_cb_| 592 // followed by |stop_cb_| so we don't leave outstanding callbacks around. 593 if (!seek_cb_.is_null()) { 594 base::ResetAndReturn(&seek_cb_).Run(status_); 595 error_cb_.Reset(); 596 } 597 if (!stop_cb_.is_null()) { 598 error_cb_.Reset(); 599 base::ResetAndReturn(&stop_cb_).Run(); 600 601 // NOTE: pipeline may be deleted at this point in time as a result of 602 // executing |stop_cb_|. 603 return; 604 } 605 if (!error_cb_.is_null()) { 606 DCHECK_NE(status_, PIPELINE_OK); 607 base::ResetAndReturn(&error_cb_).Run(status_); 608 } 609 } 610 611 void Pipeline::AddBufferedTimeRange(base::TimeDelta start, 612 base::TimeDelta end) { 613 DCHECK(IsRunning()); 614 base::AutoLock auto_lock(lock_); 615 buffered_time_ranges_.Add(start, end); 616 did_loading_progress_ = true; 617 } 618 619 void Pipeline::OnAudioRendererEnded() { 620 // Force post to process ended tasks after current execution frame. 621 task_runner_->PostTask(FROM_HERE, base::Bind( 622 &Pipeline::DoAudioRendererEnded, base::Unretained(this))); 623 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::AUDIO_ENDED)); 624 } 625 626 void Pipeline::OnVideoRendererEnded() { 627 // Force post to process ended tasks after current execution frame. 628 task_runner_->PostTask(FROM_HERE, base::Bind( 629 &Pipeline::DoVideoRendererEnded, base::Unretained(this))); 630 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::VIDEO_ENDED)); 631 } 632 633 void Pipeline::OnTextRendererEnded() { 634 // Force post to process ended messages after current execution frame. 635 task_runner_->PostTask(FROM_HERE, base::Bind( 636 &Pipeline::DoTextRendererEnded, base::Unretained(this))); 637 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::TEXT_ENDED)); 638 } 639 640 // Called from any thread. 641 void Pipeline::OnUpdateStatistics(const PipelineStatistics& stats) { 642 base::AutoLock auto_lock(lock_); 643 statistics_.audio_bytes_decoded += stats.audio_bytes_decoded; 644 statistics_.video_bytes_decoded += stats.video_bytes_decoded; 645 statistics_.video_frames_decoded += stats.video_frames_decoded; 646 statistics_.video_frames_dropped += stats.video_frames_dropped; 647 } 648 649 void Pipeline::StartTask() { 650 DCHECK(task_runner_->BelongsToCurrentThread()); 651 CHECK_EQ(kCreated, state_) 652 << "Media pipeline cannot be started more than once"; 653 654 text_renderer_ = filter_collection_->GetTextRenderer(); 655 656 if (text_renderer_) { 657 text_renderer_->Initialize( 658 base::Bind(&Pipeline::OnTextRendererEnded, base::Unretained(this))); 659 } 660 661 StateTransitionTask(PIPELINE_OK); 662 } 663 664 void Pipeline::StopTask(const base::Closure& stop_cb) { 665 DCHECK(task_runner_->BelongsToCurrentThread()); 666 DCHECK(stop_cb_.is_null()); 667 668 if (state_ == kStopped) { 669 stop_cb.Run(); 670 return; 671 } 672 673 stop_cb_ = stop_cb; 674 675 // We may already be stopping due to a runtime error. 676 if (state_ == kStopping) 677 return; 678 679 SetState(kStopping); 680 pending_callbacks_.reset(); 681 DoStop(base::Bind(&Pipeline::OnStopCompleted, base::Unretained(this))); 682 } 683 684 void Pipeline::ErrorChangedTask(PipelineStatus error) { 685 DCHECK(task_runner_->BelongsToCurrentThread()); 686 DCHECK_NE(PIPELINE_OK, error) << "PIPELINE_OK isn't an error!"; 687 688 if (state_ == kStopping || state_ == kStopped) 689 return; 690 691 SetState(kStopping); 692 pending_callbacks_.reset(); 693 status_ = error; 694 695 DoStop(base::Bind(&Pipeline::OnStopCompleted, base::Unretained(this))); 696 } 697 698 void Pipeline::PlaybackRateChangedTask(float playback_rate) { 699 DCHECK(task_runner_->BelongsToCurrentThread()); 700 701 // Playback rate changes are only carried out while playing. 702 if (state_ != kPlaying) 703 return; 704 705 { 706 base::AutoLock auto_lock(lock_); 707 clock_->SetPlaybackRate(playback_rate); 708 } 709 710 if (audio_renderer_) 711 audio_renderer_->SetPlaybackRate(playback_rate_); 712 if (video_renderer_) 713 video_renderer_->SetPlaybackRate(playback_rate_); 714 } 715 716 void Pipeline::VolumeChangedTask(float volume) { 717 DCHECK(task_runner_->BelongsToCurrentThread()); 718 719 // Volume changes are only carried out while playing. 720 if (state_ != kPlaying) 721 return; 722 723 if (audio_renderer_) 724 audio_renderer_->SetVolume(volume); 725 } 726 727 void Pipeline::SeekTask(TimeDelta time, const PipelineStatusCB& seek_cb) { 728 DCHECK(task_runner_->BelongsToCurrentThread()); 729 DCHECK(stop_cb_.is_null()); 730 731 // Suppress seeking if we're not fully started. 732 if (state_ != kPlaying) { 733 DCHECK(state_ == kStopping || state_ == kStopped) 734 << "Receive extra seek in unexpected state: " << state_; 735 736 // TODO(scherkus): should we run the callback? I'm tempted to say the API 737 // will only execute the first Seek() request. 738 DVLOG(1) << "Media pipeline has not started, ignoring seek to " 739 << time.InMicroseconds() << " (current state: " << state_ << ")"; 740 return; 741 } 742 743 DCHECK(seek_cb_.is_null()); 744 745 SetState(kSeeking); 746 base::TimeDelta seek_timestamp = std::max(time, demuxer_->GetStartTime()); 747 seek_cb_ = seek_cb; 748 audio_ended_ = false; 749 video_ended_ = false; 750 text_ended_ = false; 751 752 // Kick off seeking! 753 { 754 base::AutoLock auto_lock(lock_); 755 PauseClockAndStopRendering_Locked(); 756 clock_->SetTime(seek_timestamp, seek_timestamp); 757 } 758 DoSeek(seek_timestamp, base::Bind( 759 &Pipeline::OnStateTransition, base::Unretained(this))); 760 } 761 762 void Pipeline::DoAudioRendererEnded() { 763 DCHECK(task_runner_->BelongsToCurrentThread()); 764 765 if (state_ != kPlaying) 766 return; 767 768 DCHECK(!audio_ended_); 769 audio_ended_ = true; 770 771 // Start clock since there is no more audio to trigger clock updates. 772 { 773 base::AutoLock auto_lock(lock_); 774 clock_->SetMaxTime(clock_->Duration()); 775 StartClockIfWaitingForTimeUpdate_Locked(); 776 } 777 778 RunEndedCallbackIfNeeded(); 779 } 780 781 void Pipeline::DoVideoRendererEnded() { 782 DCHECK(task_runner_->BelongsToCurrentThread()); 783 784 if (state_ != kPlaying) 785 return; 786 787 DCHECK(!video_ended_); 788 video_ended_ = true; 789 790 RunEndedCallbackIfNeeded(); 791 } 792 793 void Pipeline::DoTextRendererEnded() { 794 DCHECK(task_runner_->BelongsToCurrentThread()); 795 796 if (state_ != kPlaying) 797 return; 798 799 DCHECK(!text_ended_); 800 text_ended_ = true; 801 802 RunEndedCallbackIfNeeded(); 803 } 804 805 void Pipeline::RunEndedCallbackIfNeeded() { 806 DCHECK(task_runner_->BelongsToCurrentThread()); 807 808 if (audio_renderer_ && !audio_ended_) 809 return; 810 811 if (video_renderer_ && !video_ended_) 812 return; 813 814 if (text_renderer_ && text_renderer_->HasTracks() && !text_ended_) 815 return; 816 817 { 818 base::AutoLock auto_lock(lock_); 819 PauseClockAndStopRendering_Locked(); 820 clock_->SetTime(clock_->Duration(), clock_->Duration()); 821 } 822 823 DCHECK_EQ(status_, PIPELINE_OK); 824 ended_cb_.Run(); 825 } 826 827 void Pipeline::AddTextStreamTask(DemuxerStream* text_stream, 828 const TextTrackConfig& config) { 829 DCHECK(task_runner_->BelongsToCurrentThread()); 830 // TODO(matthewjheaney): fix up text_ended_ when text stream 831 // is added (http://crbug.com/321446). 832 text_renderer_->AddTextStream(text_stream, config); 833 } 834 835 void Pipeline::RemoveTextStreamTask(DemuxerStream* text_stream) { 836 DCHECK(task_runner_->BelongsToCurrentThread()); 837 text_renderer_->RemoveTextStream(text_stream); 838 } 839 840 void Pipeline::InitializeDemuxer(const PipelineStatusCB& done_cb) { 841 DCHECK(task_runner_->BelongsToCurrentThread()); 842 843 demuxer_ = filter_collection_->GetDemuxer(); 844 demuxer_->Initialize(this, done_cb, text_renderer_); 845 } 846 847 void Pipeline::InitializeAudioRenderer(const PipelineStatusCB& done_cb) { 848 DCHECK(task_runner_->BelongsToCurrentThread()); 849 850 audio_renderer_ = filter_collection_->GetAudioRenderer(); 851 audio_renderer_->Initialize( 852 demuxer_->GetStream(DemuxerStream::AUDIO), 853 done_cb, 854 base::Bind(&Pipeline::OnUpdateStatistics, base::Unretained(this)), 855 base::Bind(&Pipeline::OnAudioUnderflow, base::Unretained(this)), 856 base::Bind(&Pipeline::OnAudioTimeUpdate, base::Unretained(this)), 857 base::Bind(&Pipeline::OnAudioRendererEnded, base::Unretained(this)), 858 base::Bind(&Pipeline::SetError, base::Unretained(this))); 859 } 860 861 void Pipeline::InitializeVideoRenderer(const PipelineStatusCB& done_cb) { 862 DCHECK(task_runner_->BelongsToCurrentThread()); 863 864 video_renderer_ = filter_collection_->GetVideoRenderer(); 865 video_renderer_->Initialize( 866 demuxer_->GetStream(DemuxerStream::VIDEO), 867 demuxer_->GetLiveness() == Demuxer::LIVENESS_LIVE, 868 done_cb, 869 base::Bind(&Pipeline::OnUpdateStatistics, base::Unretained(this)), 870 base::Bind(&Pipeline::OnVideoTimeUpdate, base::Unretained(this)), 871 base::Bind(&Pipeline::OnVideoRendererEnded, base::Unretained(this)), 872 base::Bind(&Pipeline::SetError, base::Unretained(this)), 873 base::Bind(&Pipeline::GetMediaTime, base::Unretained(this)), 874 base::Bind(&Pipeline::GetMediaDuration, base::Unretained(this))); 875 } 876 877 void Pipeline::OnAudioUnderflow() { 878 if (!task_runner_->BelongsToCurrentThread()) { 879 task_runner_->PostTask(FROM_HERE, base::Bind( 880 &Pipeline::OnAudioUnderflow, base::Unretained(this))); 881 return; 882 } 883 884 if (state_ != kPlaying) 885 return; 886 887 if (audio_renderer_) 888 audio_renderer_->ResumeAfterUnderflow(); 889 } 890 891 void Pipeline::BufferingStateChanged(BufferingState* buffering_state, 892 BufferingState new_buffering_state) { 893 DVLOG(1) << __FUNCTION__ << "(" << *buffering_state << ", " 894 << " " << new_buffering_state << ") " 895 << (buffering_state == &audio_buffering_state_ ? "audio" : "video"); 896 DCHECK(task_runner_->BelongsToCurrentThread()); 897 bool was_waiting_for_enough_data = WaitingForEnoughData(); 898 *buffering_state = new_buffering_state; 899 900 // Renderer underflowed. 901 if (!was_waiting_for_enough_data && WaitingForEnoughData()) { 902 StartWaitingForEnoughData(); 903 return; 904 } 905 906 // Renderer prerolled. 907 if (was_waiting_for_enough_data && !WaitingForEnoughData()) { 908 StartPlayback(); 909 return; 910 } 911 } 912 913 bool Pipeline::WaitingForEnoughData() const { 914 DCHECK(task_runner_->BelongsToCurrentThread()); 915 if (state_ != kPlaying) 916 return false; 917 if (audio_renderer_ && audio_buffering_state_ != BUFFERING_HAVE_ENOUGH) 918 return true; 919 if (video_renderer_ && video_buffering_state_ != BUFFERING_HAVE_ENOUGH) 920 return true; 921 return false; 922 } 923 924 void Pipeline::StartWaitingForEnoughData() { 925 DVLOG(1) << __FUNCTION__; 926 DCHECK_EQ(state_, kPlaying); 927 DCHECK(WaitingForEnoughData()); 928 929 base::AutoLock auto_lock(lock_); 930 PauseClockAndStopRendering_Locked(); 931 } 932 933 void Pipeline::StartPlayback() { 934 DVLOG(1) << __FUNCTION__; 935 DCHECK_EQ(state_, kPlaying); 936 DCHECK_EQ(clock_state_, CLOCK_PAUSED); 937 DCHECK(!WaitingForEnoughData()); 938 939 if (audio_renderer_) { 940 // We use audio stream to update the clock. So if there is such a 941 // stream, we pause the clock until we receive a valid timestamp. 942 base::AutoLock auto_lock(lock_); 943 clock_state_ = CLOCK_WAITING_FOR_AUDIO_TIME_UPDATE; 944 audio_renderer_->StartRendering(); 945 } else { 946 base::AutoLock auto_lock(lock_); 947 clock_state_ = CLOCK_PLAYING; 948 clock_->SetMaxTime(clock_->Duration()); 949 clock_->Play(); 950 } 951 952 preroll_completed_cb_.Run(); 953 if (!seek_cb_.is_null()) 954 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK); 955 } 956 957 void Pipeline::PauseClockAndStopRendering_Locked() { 958 lock_.AssertAcquired(); 959 switch (clock_state_) { 960 case CLOCK_PAUSED: 961 return; 962 963 case CLOCK_WAITING_FOR_AUDIO_TIME_UPDATE: 964 audio_renderer_->StopRendering(); 965 break; 966 967 case CLOCK_PLAYING: 968 if (audio_renderer_) 969 audio_renderer_->StopRendering(); 970 clock_->Pause(); 971 break; 972 } 973 974 clock_state_ = CLOCK_PAUSED; 975 } 976 977 void Pipeline::StartClockIfWaitingForTimeUpdate_Locked() { 978 lock_.AssertAcquired(); 979 if (clock_state_ != CLOCK_WAITING_FOR_AUDIO_TIME_UPDATE) 980 return; 981 982 clock_state_ = CLOCK_PLAYING; 983 clock_->Play(); 984 } 985 986 } // namespace media 987