| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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/base/pipeline.h" | 5 #include "media/base/pipeline.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/callback.h" | 10 #include "base/callback.h" |
| 11 #include "base/callback_helpers.h" | 11 #include "base/callback_helpers.h" |
| 12 #include "base/compiler_specific.h" | 12 #include "base/compiler_specific.h" |
| 13 #include "base/metrics/histogram.h" | 13 #include "base/metrics/histogram.h" |
| 14 #include "base/message_loop.h" | 14 #include "base/message_loop.h" |
| 15 #include "base/stl_util.h" | 15 #include "base/stl_util.h" |
| 16 #include "base/string_util.h" | 16 #include "base/string_util.h" |
| 17 #include "base/synchronization/condition_variable.h" | 17 #include "base/synchronization/condition_variable.h" |
| 18 #include "media/base/audio_decoder.h" | 18 #include "media/base/audio_decoder.h" |
| 19 #include "media/base/audio_renderer.h" | 19 #include "media/base/audio_renderer.h" |
| 20 #include "media/base/callback_util.h" |
| 20 #include "media/base/clock.h" | 21 #include "media/base/clock.h" |
| 21 #include "media/base/composite_filter.h" | 22 #include "media/base/composite_filter.h" |
| 22 #include "media/base/filter_collection.h" | 23 #include "media/base/filter_collection.h" |
| 23 #include "media/base/media_log.h" | 24 #include "media/base/media_log.h" |
| 24 #include "media/base/video_decoder.h" | 25 #include "media/base/video_decoder.h" |
| 25 #include "media/base/video_renderer.h" | 26 #include "media/base/video_renderer.h" |
| 26 | 27 |
| 27 using base::TimeDelta; | 28 using base::TimeDelta; |
| 28 | 29 |
| 29 namespace media { | 30 namespace media { |
| (...skipping 27 matching lines...) Expand all Loading... |
| 57 | 58 |
| 58 media::PipelineStatus PipelineStatusNotification::status() { | 59 media::PipelineStatus PipelineStatusNotification::status() { |
| 59 base::AutoLock auto_lock(lock_); | 60 base::AutoLock auto_lock(lock_); |
| 60 DCHECK(notified_); | 61 DCHECK(notified_); |
| 61 return status_; | 62 return status_; |
| 62 } | 63 } |
| 63 | 64 |
| 64 struct Pipeline::PipelineInitState { | 65 struct Pipeline::PipelineInitState { |
| 65 scoped_refptr<AudioDecoder> audio_decoder; | 66 scoped_refptr<AudioDecoder> audio_decoder; |
| 66 scoped_refptr<VideoDecoder> video_decoder; | 67 scoped_refptr<VideoDecoder> video_decoder; |
| 67 scoped_refptr<AudioRenderer> audio_renderer; | |
| 68 scoped_refptr<VideoRenderer> video_renderer; | 68 scoped_refptr<VideoRenderer> video_renderer; |
| 69 scoped_refptr<CompositeFilter> composite; | 69 scoped_refptr<CompositeFilter> composite; |
| 70 }; | 70 }; |
| 71 | 71 |
| 72 Pipeline::Pipeline(MessageLoop* message_loop, MediaLog* media_log) | 72 Pipeline::Pipeline(MessageLoop* message_loop, MediaLog* media_log) |
| 73 : message_loop_(message_loop->message_loop_proxy()), | 73 : message_loop_(message_loop->message_loop_proxy()), |
| 74 media_log_(media_log), | 74 media_log_(media_log), |
| 75 clock_(new Clock(&base::Time::Now)), | 75 clock_(new Clock(&base::Time::Now)), |
| 76 waiting_for_clock_update_(false), | 76 waiting_for_clock_update_(false), |
| 77 state_(kCreated), | 77 state_(kCreated), |
| (...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 310 DCHECK(message_loop_->BelongsToCurrentThread()); | 310 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 311 if (!seek_pending_) | 311 if (!seek_pending_) |
| 312 return false; | 312 return false; |
| 313 DCHECK(kSeeking == state_ || kPausing == state_ || | 313 DCHECK(kSeeking == state_ || kPausing == state_ || |
| 314 kFlushing == state_ || kStarting == state_) | 314 kFlushing == state_ || kStarting == state_) |
| 315 << "Current state : " << state_; | 315 << "Current state : " << state_; |
| 316 return true; | 316 return true; |
| 317 } | 317 } |
| 318 | 318 |
| 319 void Pipeline::ReportStatus(const PipelineStatusCB& cb, PipelineStatus status) { | 319 void Pipeline::ReportStatus(const PipelineStatusCB& cb, PipelineStatus status) { |
| 320 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 320 if (cb.is_null()) | 321 if (cb.is_null()) |
| 321 return; | 322 return; |
| 322 cb.Run(status); | 323 cb.Run(status); |
| 323 // Prevent double-reporting of errors to clients. | 324 // Prevent double-reporting of errors to clients. |
| 324 if (status != PIPELINE_OK) | 325 if (status != PIPELINE_OK) |
| 325 error_cb_.Reset(); | 326 error_cb_.Reset(); |
| 326 } | 327 } |
| 327 | 328 |
| 328 void Pipeline::FinishInitialization() { | 329 void Pipeline::FinishInitialization() { |
| 329 DCHECK(message_loop_->BelongsToCurrentThread()); | 330 DCHECK(message_loop_->BelongsToCurrentThread()); |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 383 TimeDelta Pipeline::GetTime() const { | 384 TimeDelta Pipeline::GetTime() const { |
| 384 DCHECK(IsRunning()); | 385 DCHECK(IsRunning()); |
| 385 return GetCurrentTime(); | 386 return GetCurrentTime(); |
| 386 } | 387 } |
| 387 | 388 |
| 388 TimeDelta Pipeline::GetDuration() const { | 389 TimeDelta Pipeline::GetDuration() const { |
| 389 DCHECK(IsRunning()); | 390 DCHECK(IsRunning()); |
| 390 return GetMediaDuration(); | 391 return GetMediaDuration(); |
| 391 } | 392 } |
| 392 | 393 |
| 394 void Pipeline::OnAudioDisabled() { |
| 395 DCHECK(IsRunning()); |
| 396 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 397 &Pipeline::AudioDisabledTask, this)); |
| 398 media_log_->AddEvent( |
| 399 media_log_->CreateEvent(MediaLogEvent::AUDIO_RENDERER_DISABLED)); |
| 400 } |
| 401 |
| 393 void Pipeline::OnAudioTimeUpdate(TimeDelta time, TimeDelta max_time) { | 402 void Pipeline::OnAudioTimeUpdate(TimeDelta time, TimeDelta max_time) { |
| 394 DCHECK(time <= max_time); | 403 DCHECK(time <= max_time); |
| 395 DCHECK(IsRunning()); | 404 DCHECK(IsRunning()); |
| 396 base::AutoLock auto_lock(lock_); | 405 base::AutoLock auto_lock(lock_); |
| 397 | 406 |
| 398 if (!has_audio_) | 407 if (!has_audio_) |
| 399 return; | 408 return; |
| 400 if (waiting_for_clock_update_ && time < clock_->Elapsed()) | 409 if (waiting_for_clock_update_ && time < clock_->Elapsed()) |
| 401 return; | 410 return; |
| 402 | 411 |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 453 // Since the byte->time calculation is approximate, fudge the beginning & | 462 // Since the byte->time calculation is approximate, fudge the beginning & |
| 454 // ending areas to look better. | 463 // ending areas to look better. |
| 455 TimeDelta epsilon = clock_->Duration() / 100; | 464 TimeDelta epsilon = clock_->Duration() / 100; |
| 456 if (time_offset < epsilon) | 465 if (time_offset < epsilon) |
| 457 return TimeDelta(); | 466 return TimeDelta(); |
| 458 if (time_offset + epsilon > clock_->Duration()) | 467 if (time_offset + epsilon > clock_->Duration()) |
| 459 return clock_->Duration(); | 468 return clock_->Duration(); |
| 460 return time_offset; | 469 return time_offset; |
| 461 } | 470 } |
| 462 | 471 |
| 472 void Pipeline::DoPause(const base::Closure& done_cb) { |
| 473 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 474 scoped_ptr<std::queue<ClosureFunc> > closures(new std::queue<ClosureFunc>); |
| 475 |
| 476 if (audio_renderer_) |
| 477 closures->push(base::Bind(&AudioRenderer::Pause, audio_renderer_)); |
| 478 |
| 479 if (pipeline_filter_) |
| 480 closures->push(base::Bind(&Filter::Pause, pipeline_filter_)); |
| 481 |
| 482 RunInSeries(closures.Pass(), done_cb); |
| 483 } |
| 484 |
| 485 void Pipeline::DoFlush(const base::Closure& done_cb) { |
| 486 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 487 scoped_ptr<std::queue<ClosureFunc> > closures(new std::queue<ClosureFunc>); |
| 488 |
| 489 if (audio_renderer_) |
| 490 closures->push(base::Bind(&AudioRenderer::Flush, audio_renderer_)); |
| 491 |
| 492 if (pipeline_filter_) |
| 493 closures->push(base::Bind(&Filter::Flush, pipeline_filter_)); |
| 494 |
| 495 RunInParallel(closures.Pass(), done_cb); |
| 496 } |
| 497 |
| 498 void Pipeline::DoPlay(const base::Closure& done_cb) { |
| 499 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 500 scoped_ptr<std::queue<ClosureFunc> > closures(new std::queue<ClosureFunc>); |
| 501 |
| 502 if (audio_renderer_) |
| 503 closures->push(base::Bind(&AudioRenderer::Play, audio_renderer_)); |
| 504 |
| 505 if (pipeline_filter_) |
| 506 closures->push(base::Bind(&Filter::Play, pipeline_filter_)); |
| 507 |
| 508 RunInSeries(closures.Pass(), done_cb); |
| 509 } |
| 510 |
| 511 void Pipeline::DoStop(const base::Closure& done_cb) { |
| 512 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 513 scoped_ptr<std::queue<ClosureFunc> > closures(new std::queue<ClosureFunc>); |
| 514 |
| 515 if (demuxer_) |
| 516 closures->push(base::Bind(&Demuxer::Stop, demuxer_)); |
| 517 |
| 518 if (audio_renderer_) |
| 519 closures->push(base::Bind(&AudioRenderer::Stop, audio_renderer_)); |
| 520 |
| 521 if (pipeline_filter_) |
| 522 closures->push(base::Bind(&Filter::Stop, pipeline_filter_)); |
| 523 |
| 524 RunInSeries(closures.Pass(), done_cb); |
| 525 } |
| 526 |
| 463 void Pipeline::AddBufferedByteRange(int64 start, int64 end) { | 527 void Pipeline::AddBufferedByteRange(int64 start, int64 end) { |
| 464 DCHECK(IsRunning()); | 528 DCHECK(IsRunning()); |
| 465 base::AutoLock auto_lock(lock_); | 529 base::AutoLock auto_lock(lock_); |
| 466 buffered_byte_ranges_.Add(start, end); | 530 buffered_byte_ranges_.Add(start, end); |
| 467 did_loading_progress_ = true; | 531 did_loading_progress_ = true; |
| 468 } | 532 } |
| 469 | 533 |
| 470 void Pipeline::AddBufferedTimeRange(base::TimeDelta start, | 534 void Pipeline::AddBufferedTimeRange(base::TimeDelta start, |
| 471 base::TimeDelta end) { | 535 base::TimeDelta end) { |
| 472 DCHECK(IsRunning()); | 536 DCHECK(IsRunning()); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 484 natural_size_ = size; | 548 natural_size_ = size; |
| 485 } | 549 } |
| 486 | 550 |
| 487 void Pipeline::NotifyEnded() { | 551 void Pipeline::NotifyEnded() { |
| 488 DCHECK(IsRunning()); | 552 DCHECK(IsRunning()); |
| 489 message_loop_->PostTask(FROM_HERE, base::Bind( | 553 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 490 &Pipeline::NotifyEndedTask, this)); | 554 &Pipeline::NotifyEndedTask, this)); |
| 491 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::ENDED)); | 555 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::ENDED)); |
| 492 } | 556 } |
| 493 | 557 |
| 494 void Pipeline::DisableAudioRenderer() { | |
| 495 DCHECK(IsRunning()); | |
| 496 | |
| 497 // Disable renderer on the message loop. | |
| 498 message_loop_->PostTask(FROM_HERE, base::Bind( | |
| 499 &Pipeline::DisableAudioRendererTask, this)); | |
| 500 media_log_->AddEvent( | |
| 501 media_log_->CreateEvent(MediaLogEvent::AUDIO_RENDERER_DISABLED)); | |
| 502 } | |
| 503 | |
| 504 // Called from any thread. | 558 // Called from any thread. |
| 505 void Pipeline::OnFilterInitialize(PipelineStatus status) { | 559 void Pipeline::OnFilterInitialize(PipelineStatus status) { |
| 506 // Continue the initialize task by proceeding to the next stage. | 560 // Continue the initialize task by proceeding to the next stage. |
| 507 message_loop_->PostTask(FROM_HERE, base::Bind( | 561 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 508 &Pipeline::InitializeTask, this, status)); | 562 &Pipeline::InitializeTask, this, status)); |
| 509 } | 563 } |
| 510 | 564 |
| 511 // Called from any thread. | 565 // Called from any thread. |
| 512 void Pipeline::OnFilterStateTransition() { | 566 void Pipeline::OnFilterStateTransition() { |
| 513 message_loop_->PostTask(FROM_HERE, base::Bind( | 567 message_loop_->PostTask(FROM_HERE, base::Bind( |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 651 pipeline_filter_ = pipeline_init_state_->composite; | 705 pipeline_filter_ = pipeline_init_state_->composite; |
| 652 | 706 |
| 653 // Clear init state since we're done initializing. | 707 // Clear init state since we're done initializing. |
| 654 pipeline_init_state_.reset(); | 708 pipeline_init_state_.reset(); |
| 655 | 709 |
| 656 // Initialization was successful, we are now considered paused, so it's safe | 710 // Initialization was successful, we are now considered paused, so it's safe |
| 657 // to set the initial playback rate and volume. | 711 // to set the initial playback rate and volume. |
| 658 PlaybackRateChangedTask(GetPlaybackRate()); | 712 PlaybackRateChangedTask(GetPlaybackRate()); |
| 659 VolumeChangedTask(GetVolume()); | 713 VolumeChangedTask(GetVolume()); |
| 660 | 714 |
| 661 // Fire a seek request to get the renderers to preroll. We don't need to | 715 // Fire a seek request to get the renderers to preroll. We can skip a seek |
| 662 // tell the demuxer to seek since it should already be at the start. | 716 // here as the demuxer should be at the start of the stream. |
| 663 seek_pending_ = true; | 717 seek_pending_ = true; |
| 664 SetState(kSeeking); | 718 SetState(kSeeking); |
| 665 seek_timestamp_ = demuxer_->GetStartTime(); | 719 seek_timestamp_ = demuxer_->GetStartTime(); |
| 666 OnDemuxerSeekDone(seek_timestamp_, PIPELINE_OK); | 720 DoSeek(seek_timestamp_, true, |
| 721 base::Bind(&Pipeline::OnFilterStateTransitionWithStatus, this)); |
| 667 } | 722 } |
| 668 } | 723 } |
| 669 | 724 |
| 670 // This method is called as a result of the client calling Pipeline::Stop() or | 725 // This method is called as a result of the client calling Pipeline::Stop() or |
| 671 // as the result of an error condition. | 726 // as the result of an error condition. |
| 672 // We stop the filters in the reverse order. | 727 // We stop the filters in the reverse order. |
| 673 // | 728 // |
| 674 // TODO(scherkus): beware! this can get posted multiple times since we post | 729 // TODO(scherkus): beware! this can get posted multiple times since we post |
| 675 // Stop() tasks even if we've already stopped. Perhaps this should no-op for | 730 // Stop() tasks even if we've already stopped. Perhaps this should no-op for |
| 676 // additional calls, however most of this logic will be changing. | 731 // additional calls, however most of this logic will be changing. |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 745 | 800 |
| 746 { | 801 { |
| 747 base::AutoLock auto_lock(lock_); | 802 base::AutoLock auto_lock(lock_); |
| 748 clock_->SetPlaybackRate(playback_rate); | 803 clock_->SetPlaybackRate(playback_rate); |
| 749 } | 804 } |
| 750 | 805 |
| 751 // Notify |pipeline_filter_| if it has been initialized. If initialization | 806 // Notify |pipeline_filter_| if it has been initialized. If initialization |
| 752 // hasn't completed yet, the playback rate will be set when initialization | 807 // hasn't completed yet, the playback rate will be set when initialization |
| 753 // completes. | 808 // completes. |
| 754 if (pipeline_filter_) { | 809 if (pipeline_filter_) { |
| 755 DCHECK(demuxer_); | |
| 756 demuxer_->SetPlaybackRate(playback_rate); | 810 demuxer_->SetPlaybackRate(playback_rate); |
| 757 pipeline_filter_->SetPlaybackRate(playback_rate); | 811 pipeline_filter_->SetPlaybackRate(playback_rate); |
| 812 |
| 813 if (audio_renderer_) |
| 814 audio_renderer_->SetPlaybackRate(playback_rate_); |
| 758 } | 815 } |
| 759 } | 816 } |
| 760 | 817 |
| 761 void Pipeline::VolumeChangedTask(float volume) { | 818 void Pipeline::VolumeChangedTask(float volume) { |
| 762 DCHECK(message_loop_->BelongsToCurrentThread()); | 819 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 763 if (!running_ || tearing_down_) | 820 if (!running_ || tearing_down_) |
| 764 return; | 821 return; |
| 765 | 822 |
| 766 if (audio_renderer_) | 823 if (audio_renderer_) |
| 767 audio_renderer_->SetVolume(volume); | 824 audio_renderer_->SetVolume(volume); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 793 SetState(kPausing); | 850 SetState(kPausing); |
| 794 seek_timestamp_ = std::max(time, demuxer_->GetStartTime()); | 851 seek_timestamp_ = std::max(time, demuxer_->GetStartTime()); |
| 795 seek_cb_ = seek_cb; | 852 seek_cb_ = seek_cb; |
| 796 | 853 |
| 797 // Kick off seeking! | 854 // Kick off seeking! |
| 798 { | 855 { |
| 799 base::AutoLock auto_lock(lock_); | 856 base::AutoLock auto_lock(lock_); |
| 800 if (clock_->IsPlaying()) | 857 if (clock_->IsPlaying()) |
| 801 clock_->Pause(); | 858 clock_->Pause(); |
| 802 } | 859 } |
| 803 pipeline_filter_->Pause( | 860 DoPause(base::Bind(&Pipeline::OnFilterStateTransition, this)); |
| 804 base::Bind(&Pipeline::OnFilterStateTransition, this)); | |
| 805 } | 861 } |
| 806 | 862 |
| 807 void Pipeline::NotifyEndedTask() { | 863 void Pipeline::NotifyEndedTask() { |
| 808 DCHECK(message_loop_->BelongsToCurrentThread()); | 864 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 809 | 865 |
| 810 // We can only end if we were actually playing. | 866 // We can only end if we were actually playing. |
| 811 if (state_ != kStarted) { | 867 if (state_ != kStarted) { |
| 812 return; | 868 return; |
| 813 } | 869 } |
| 814 | 870 |
| (...skipping 19 matching lines...) Expand all Loading... |
| 834 // Transition to ended, executing the callback if present. | 890 // Transition to ended, executing the callback if present. |
| 835 SetState(kEnded); | 891 SetState(kEnded); |
| 836 { | 892 { |
| 837 base::AutoLock auto_lock(lock_); | 893 base::AutoLock auto_lock(lock_); |
| 838 clock_->EndOfStream(); | 894 clock_->EndOfStream(); |
| 839 } | 895 } |
| 840 | 896 |
| 841 ReportStatus(ended_cb_, status_); | 897 ReportStatus(ended_cb_, status_); |
| 842 } | 898 } |
| 843 | 899 |
| 844 void Pipeline::DisableAudioRendererTask() { | 900 void Pipeline::AudioDisabledTask() { |
| 845 DCHECK(message_loop_->BelongsToCurrentThread()); | 901 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 846 | 902 |
| 847 base::AutoLock auto_lock(lock_); | 903 base::AutoLock auto_lock(lock_); |
| 848 has_audio_ = false; | 904 has_audio_ = false; |
| 849 audio_disabled_ = true; | 905 audio_disabled_ = true; |
| 850 | 906 |
| 851 // Notify our demuxer that we're no longer rendering audio. | 907 // Notify our demuxer that we're no longer rendering audio. |
| 852 demuxer_->OnAudioRendererDisabled(); | 908 demuxer_->OnAudioRendererDisabled(); |
| 853 | 909 |
| 854 // Start clock since there is no more audio to | 910 // Start clock since there is no more audio to |
| (...skipping 26 matching lines...) Expand all Loading... |
| 881 // to the next state if needed. | 937 // to the next state if needed. |
| 882 SetState(FindNextState(state_)); | 938 SetState(FindNextState(state_)); |
| 883 if (state_ == kSeeking) { | 939 if (state_ == kSeeking) { |
| 884 base::AutoLock auto_lock(lock_); | 940 base::AutoLock auto_lock(lock_); |
| 885 clock_->SetTime(seek_timestamp_, seek_timestamp_); | 941 clock_->SetTime(seek_timestamp_, seek_timestamp_); |
| 886 } | 942 } |
| 887 | 943 |
| 888 // Carry out the action for the current state. | 944 // Carry out the action for the current state. |
| 889 if (TransientState(state_)) { | 945 if (TransientState(state_)) { |
| 890 if (state_ == kPausing) { | 946 if (state_ == kPausing) { |
| 891 pipeline_filter_->Pause( | 947 DoPause(base::Bind(&Pipeline::OnFilterStateTransition, this)); |
| 892 base::Bind(&Pipeline::OnFilterStateTransition, this)); | |
| 893 } else if (state_ == kFlushing) { | 948 } else if (state_ == kFlushing) { |
| 894 pipeline_filter_->Flush( | 949 DoFlush(base::Bind(&Pipeline::OnFilterStateTransition, this)); |
| 895 base::Bind(&Pipeline::OnFilterStateTransition, this)); | |
| 896 } else if (state_ == kSeeking) { | 950 } else if (state_ == kSeeking) { |
| 897 DoSeek(seek_timestamp_); | 951 DoSeek(seek_timestamp_, false, |
| 952 base::Bind(&Pipeline::OnFilterStateTransitionWithStatus, this)); |
| 898 } else if (state_ == kStarting) { | 953 } else if (state_ == kStarting) { |
| 899 pipeline_filter_->Play( | 954 DoPlay(base::Bind(&Pipeline::OnFilterStateTransition, this)); |
| 900 base::Bind(&Pipeline::OnFilterStateTransition, this)); | |
| 901 } else if (state_ == kStopping) { | 955 } else if (state_ == kStopping) { |
| 902 DoStop(base::Bind(&Pipeline::OnFilterStateTransition, this)); | 956 DoStop(base::Bind(&Pipeline::OnFilterStateTransition, this)); |
| 903 } else { | 957 } else { |
| 904 NOTREACHED() << "Unexpected state: " << state_; | 958 NOTREACHED() << "Unexpected state: " << state_; |
| 905 } | 959 } |
| 906 } else if (state_ == kStarted) { | 960 } else if (state_ == kStarted) { |
| 907 FinishInitialization(); | 961 FinishInitialization(); |
| 908 | 962 |
| 909 // Finally, complete the seek. | 963 // Finally, complete the seek. |
| 910 seek_pending_ = false; | 964 seek_pending_ = false; |
| (...skipping 25 matching lines...) Expand all Loading... |
| 936 | 990 |
| 937 void Pipeline::TeardownStateTransitionTask() { | 991 void Pipeline::TeardownStateTransitionTask() { |
| 938 DCHECK(IsPipelineTearingDown()); | 992 DCHECK(IsPipelineTearingDown()); |
| 939 switch (state_) { | 993 switch (state_) { |
| 940 case kStopping: | 994 case kStopping: |
| 941 SetState(error_caused_teardown_ ? kError : kStopped); | 995 SetState(error_caused_teardown_ ? kError : kStopped); |
| 942 FinishDestroyingFiltersTask(); | 996 FinishDestroyingFiltersTask(); |
| 943 break; | 997 break; |
| 944 case kPausing: | 998 case kPausing: |
| 945 SetState(kFlushing); | 999 SetState(kFlushing); |
| 946 pipeline_filter_->Flush( | 1000 DoFlush(base::Bind(&Pipeline::OnTeardownStateTransition, this)); |
| 947 base::Bind(&Pipeline::OnTeardownStateTransition, this)); | |
| 948 break; | 1001 break; |
| 949 case kFlushing: | 1002 case kFlushing: |
| 950 SetState(kStopping); | 1003 SetState(kStopping); |
| 951 DoStop(base::Bind(&Pipeline::OnTeardownStateTransition, this)); | 1004 DoStop(base::Bind(&Pipeline::OnTeardownStateTransition, this)); |
| 952 break; | 1005 break; |
| 953 | 1006 |
| 954 case kCreated: | 1007 case kCreated: |
| 955 case kError: | 1008 case kError: |
| 956 case kInitDemuxer: | 1009 case kInitDemuxer: |
| 957 case kInitAudioDecoder: | 1010 case kInitAudioDecoder: |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1085 } | 1138 } |
| 1086 | 1139 |
| 1087 bool Pipeline::InitializeAudioRenderer( | 1140 bool Pipeline::InitializeAudioRenderer( |
| 1088 const scoped_refptr<AudioDecoder>& decoder) { | 1141 const scoped_refptr<AudioDecoder>& decoder) { |
| 1089 DCHECK(message_loop_->BelongsToCurrentThread()); | 1142 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 1090 DCHECK(IsPipelineOk()); | 1143 DCHECK(IsPipelineOk()); |
| 1091 | 1144 |
| 1092 if (!decoder) | 1145 if (!decoder) |
| 1093 return false; | 1146 return false; |
| 1094 | 1147 |
| 1095 filter_collection_->SelectAudioRenderer( | 1148 filter_collection_->SelectAudioRenderer(&audio_renderer_); |
| 1096 &pipeline_init_state_->audio_renderer); | 1149 if (!audio_renderer_) { |
| 1097 if (!pipeline_init_state_->audio_renderer) { | |
| 1098 SetError(PIPELINE_ERROR_REQUIRED_FILTER_MISSING); | 1150 SetError(PIPELINE_ERROR_REQUIRED_FILTER_MISSING); |
| 1099 return false; | 1151 return false; |
| 1100 } | 1152 } |
| 1101 | 1153 |
| 1102 pipeline_init_state_->composite->AddFilter( | 1154 audio_renderer_->Initialize( |
| 1103 pipeline_init_state_->audio_renderer); | |
| 1104 | |
| 1105 pipeline_init_state_->audio_renderer->Initialize( | |
| 1106 decoder, | 1155 decoder, |
| 1107 base::Bind(&Pipeline::OnFilterInitialize, this), | 1156 base::Bind(&Pipeline::OnFilterInitialize, this), |
| 1108 base::Bind(&Pipeline::OnAudioUnderflow, this), | 1157 base::Bind(&Pipeline::OnAudioUnderflow, this), |
| 1109 base::Bind(&Pipeline::OnAudioTimeUpdate, this)); | 1158 base::Bind(&Pipeline::OnAudioTimeUpdate, this), |
| 1110 | 1159 base::Bind(&Pipeline::NotifyEnded, this), |
| 1111 audio_renderer_ = pipeline_init_state_->audio_renderer; | 1160 base::Bind(&Pipeline::OnAudioDisabled, this), |
| 1161 base::Bind(&Pipeline::SetError, this)); |
| 1112 return true; | 1162 return true; |
| 1113 } | 1163 } |
| 1114 | 1164 |
| 1115 bool Pipeline::InitializeVideoRenderer( | 1165 bool Pipeline::InitializeVideoRenderer( |
| 1116 const scoped_refptr<VideoDecoder>& decoder) { | 1166 const scoped_refptr<VideoDecoder>& decoder) { |
| 1117 DCHECK(message_loop_->BelongsToCurrentThread()); | 1167 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 1118 DCHECK(IsPipelineOk()); | 1168 DCHECK(IsPipelineOk()); |
| 1119 | 1169 |
| 1120 if (!decoder) | 1170 if (!decoder) |
| 1121 return false; | 1171 return false; |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1187 if (seek_pending_) { | 1237 if (seek_pending_) { |
| 1188 seek_pending_ = false; | 1238 seek_pending_ = false; |
| 1189 FinishInitialization(); | 1239 FinishInitialization(); |
| 1190 } | 1240 } |
| 1191 | 1241 |
| 1192 break; | 1242 break; |
| 1193 | 1243 |
| 1194 case kStarted: | 1244 case kStarted: |
| 1195 case kEnded: | 1245 case kEnded: |
| 1196 SetState(kPausing); | 1246 SetState(kPausing); |
| 1197 pipeline_filter_->Pause( | 1247 DoPause(base::Bind(&Pipeline::OnTeardownStateTransition, this)); |
| 1198 base::Bind(&Pipeline::OnTeardownStateTransition, this)); | |
| 1199 break; | 1248 break; |
| 1200 | 1249 |
| 1201 case kStopping: | 1250 case kStopping: |
| 1202 case kStopped: | 1251 case kStopped: |
| 1203 NOTREACHED() << "Unexpected state for teardown: " << state_; | 1252 NOTREACHED() << "Unexpected state for teardown: " << state_; |
| 1204 break; | 1253 break; |
| 1205 // default: intentionally left out to force new states to cause compiler | 1254 // default: intentionally left out to force new states to cause compiler |
| 1206 // errors. | 1255 // errors. |
| 1207 }; | 1256 }; |
| 1208 } | 1257 } |
| 1209 | 1258 |
| 1210 void Pipeline::DoStop(const base::Closure& callback) { | 1259 void Pipeline::DoSeek(base::TimeDelta seek_timestamp, |
| 1211 if (demuxer_) { | 1260 bool skip_demuxer_seek, |
| 1212 demuxer_->Stop(base::Bind( | 1261 const PipelineStatusCB& done_cb) { |
| 1213 &Pipeline::OnDemuxerStopDone, this, callback)); | 1262 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 1214 return; | 1263 scoped_ptr<std::queue<PipelineStatusCBFunc> > status_cbs( |
| 1215 } | 1264 new std::queue<PipelineStatusCBFunc>()); |
| 1216 | 1265 |
| 1217 OnDemuxerStopDone(callback); | 1266 if (!skip_demuxer_seek) |
| 1218 } | 1267 status_cbs->push(base::Bind(&Demuxer::Seek, demuxer_, seek_timestamp)); |
| 1219 | 1268 |
| 1220 void Pipeline::OnDemuxerStopDone(const base::Closure& callback) { | 1269 if (audio_renderer_) |
| 1221 if (!message_loop_->BelongsToCurrentThread()) { | 1270 status_cbs->push(base::Bind( |
| 1222 message_loop_->PostTask(FROM_HERE, base::Bind( | 1271 &AudioRenderer::Seek, audio_renderer_, seek_timestamp)); |
| 1223 &Pipeline::OnDemuxerStopDone, this, callback)); | |
| 1224 return; | |
| 1225 } | |
| 1226 | 1272 |
| 1227 if (pipeline_filter_) { | 1273 if (pipeline_filter_) |
| 1228 pipeline_filter_->Stop(callback); | 1274 status_cbs->push(base::Bind( |
| 1229 return; | 1275 &Filter::Seek, pipeline_filter_, seek_timestamp)); |
| 1230 } | |
| 1231 | 1276 |
| 1232 callback.Run(); | 1277 RunInSeriesWithStatus(status_cbs.Pass(), base::Bind( |
| 1233 } | 1278 &Pipeline::ReportStatus, this, done_cb)); |
| 1234 | |
| 1235 void Pipeline::DoSeek(TimeDelta seek_timestamp) { | |
| 1236 demuxer_->Seek(seek_timestamp, base::Bind( | |
| 1237 &Pipeline::OnDemuxerSeekDone, this, seek_timestamp)); | |
| 1238 } | |
| 1239 | |
| 1240 void Pipeline::OnDemuxerSeekDone(TimeDelta seek_timestamp, | |
| 1241 PipelineStatus status) { | |
| 1242 if (!message_loop_->BelongsToCurrentThread()) { | |
| 1243 message_loop_->PostTask(FROM_HERE, base::Bind( | |
| 1244 &Pipeline::OnDemuxerSeekDone, this, seek_timestamp, status)); | |
| 1245 return; | |
| 1246 } | |
| 1247 | |
| 1248 PipelineStatusCB done_cb = | |
| 1249 base::Bind(&Pipeline::OnFilterStateTransitionWithStatus, this); | |
| 1250 | |
| 1251 if (status == PIPELINE_OK && pipeline_filter_) { | |
| 1252 pipeline_filter_->Seek(seek_timestamp, done_cb); | |
| 1253 return; | |
| 1254 } | |
| 1255 | |
| 1256 ReportStatus(done_cb, status); | |
| 1257 } | 1279 } |
| 1258 | 1280 |
| 1259 void Pipeline::OnAudioUnderflow() { | 1281 void Pipeline::OnAudioUnderflow() { |
| 1260 if (!message_loop_->BelongsToCurrentThread()) { | 1282 if (!message_loop_->BelongsToCurrentThread()) { |
| 1261 message_loop_->PostTask(FROM_HERE, base::Bind( | 1283 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 1262 &Pipeline::OnAudioUnderflow, this)); | 1284 &Pipeline::OnAudioUnderflow, this)); |
| 1263 return; | 1285 return; |
| 1264 } | 1286 } |
| 1265 | 1287 |
| 1266 if (state_ != kStarted) | 1288 if (state_ != kStarted) |
| 1267 return; | 1289 return; |
| 1268 | 1290 |
| 1269 if (audio_renderer_) | 1291 if (audio_renderer_) |
| 1270 audio_renderer_->ResumeAfterUnderflow(true); | 1292 audio_renderer_->ResumeAfterUnderflow(true); |
| 1271 } | 1293 } |
| 1272 | 1294 |
| 1273 void Pipeline::StartClockIfWaitingForTimeUpdate_Locked() { | 1295 void Pipeline::StartClockIfWaitingForTimeUpdate_Locked() { |
| 1274 lock_.AssertAcquired(); | 1296 lock_.AssertAcquired(); |
| 1275 if (!waiting_for_clock_update_) | 1297 if (!waiting_for_clock_update_) |
| 1276 return; | 1298 return; |
| 1277 | 1299 |
| 1278 waiting_for_clock_update_ = false; | 1300 waiting_for_clock_update_ = false; |
| 1279 clock_->Play(); | 1301 clock_->Play(); |
| 1280 } | 1302 } |
| 1281 | 1303 |
| 1282 } // namespace media | 1304 } // namespace media |
| OLD | NEW |