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" |
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
144 // TODO(scherkus): perhaps replace this with a bool that is set/get under the | 144 // TODO(scherkus): perhaps replace this with a bool that is set/get under the |
145 // lock, because this is breaching the contract that |state_| is only accessed | 145 // lock, because this is breaching the contract that |state_| is only accessed |
146 // on |message_loop_|. | 146 // on |message_loop_|. |
147 base::AutoLock auto_lock(lock_); | 147 base::AutoLock auto_lock(lock_); |
148 switch (state_) { | 148 switch (state_) { |
149 case kPausing: | 149 case kPausing: |
150 case kFlushing: | 150 case kFlushing: |
151 case kSeeking: | 151 case kSeeking: |
152 case kStarting: | 152 case kStarting: |
153 case kStarted: | 153 case kStarted: |
154 case kEnded: | |
155 return true; | 154 return true; |
156 default: | 155 default: |
157 return false; | 156 return false; |
158 } | 157 } |
159 } | 158 } |
160 | 159 |
161 bool Pipeline::HasAudio() const { | 160 bool Pipeline::HasAudio() const { |
162 base::AutoLock auto_lock(lock_); | 161 base::AutoLock auto_lock(lock_); |
163 return has_audio_; | 162 return has_audio_; |
164 } | 163 } |
(...skipping 623 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
788 | 787 |
789 if (audio_renderer_) | 788 if (audio_renderer_) |
790 audio_renderer_->SetVolume(volume); | 789 audio_renderer_->SetVolume(volume); |
791 } | 790 } |
792 | 791 |
793 void Pipeline::SeekTask(TimeDelta time, const PipelineStatusCB& seek_cb) { | 792 void Pipeline::SeekTask(TimeDelta time, const PipelineStatusCB& seek_cb) { |
794 DCHECK(message_loop_->BelongsToCurrentThread()); | 793 DCHECK(message_loop_->BelongsToCurrentThread()); |
795 DCHECK(!IsPipelineStopPending()); | 794 DCHECK(!IsPipelineStopPending()); |
796 | 795 |
797 // Suppress seeking if we're not fully started. | 796 // Suppress seeking if we're not fully started. |
798 if (state_ != kStarted && state_ != kEnded) { | 797 if (state_ != kStarted) { |
799 // TODO(scherkus): should we run the callback? I'm tempted to say the API | 798 // TODO(scherkus): should we run the callback? I'm tempted to say the API |
800 // will only execute the first Seek() request. | 799 // will only execute the first Seek() request. |
801 DVLOG(1) << "Media pipeline has not started, ignoring seek to " | 800 DVLOG(1) << "Media pipeline has not started, ignoring seek to " |
802 << time.InMicroseconds() << " (current state: " << state_ << ")"; | 801 << time.InMicroseconds() << " (current state: " << state_ << ")"; |
803 return; | 802 return; |
804 } | 803 } |
805 | 804 |
806 DCHECK(!seek_pending_); | 805 DCHECK(!seek_pending_); |
807 seek_pending_ = true; | 806 seek_pending_ = true; |
808 | 807 |
809 // We'll need to pause every filter before seeking. The state transition | 808 // We'll need to pause every filter before seeking. The state transition |
810 // is as follows: | 809 // is as follows: |
811 // kStarted/kEnded | 810 // kStarted |
812 // kPausing (for each filter) | 811 // kPausing (for each filter) |
813 // kSeeking (for each filter) | 812 // kSeeking (for each filter) |
814 // kStarting (for each filter) | 813 // kStarting (for each filter) |
815 // kStarted | 814 // kStarted |
816 SetState(kPausing); | 815 SetState(kPausing); |
817 seek_timestamp_ = std::max(time, demuxer_->GetStartTime()); | 816 seek_timestamp_ = std::max(time, demuxer_->GetStartTime()); |
818 seek_cb_ = seek_cb; | 817 seek_cb_ = seek_cb; |
819 | 818 |
820 // Kick off seeking! | 819 // Kick off seeking! |
821 { | 820 { |
822 base::AutoLock auto_lock(lock_); | 821 base::AutoLock auto_lock(lock_); |
823 if (clock_->IsPlaying()) | 822 if (clock_->IsPlaying()) |
824 clock_->Pause(); | 823 clock_->Pause(); |
825 } | 824 } |
826 DoPause(base::Bind(&Pipeline::OnFilterStateTransition, this)); | 825 DoPause(base::Bind(&Pipeline::OnFilterStateTransition, this)); |
827 } | 826 } |
828 | 827 |
829 void Pipeline::OnRendererEndedTask() { | 828 void Pipeline::OnRendererEndedTask() { |
830 DCHECK(message_loop_->BelongsToCurrentThread()); | 829 DCHECK(message_loop_->BelongsToCurrentThread()); |
831 | 830 |
832 // We can only end if we were actually playing. | 831 // We can only end if we were actually playing. |
833 if (state_ != kStarted) { | 832 if (state_ != kStarted) { |
acolwell GONE FROM CHROMIUM
2012/08/08 17:27:08
Looks like we won't be protected from extra ended
scherkus (not reviewing)
2012/08/08 17:34:31
Chatted offline -- it seems like that was the only
| |
834 return; | 833 return; |
835 } | 834 } |
836 | 835 |
837 DCHECK(audio_renderer_ || video_renderer_); | 836 DCHECK(audio_renderer_ || video_renderer_); |
838 | 837 |
839 // Make sure every extant renderer has ended. | 838 // Make sure every extant renderer has ended. |
840 if (audio_renderer_ && !audio_disabled_) { | 839 if (audio_renderer_ && !audio_disabled_) { |
841 if (!audio_renderer_->HasEnded()) { | 840 if (!audio_renderer_->HasEnded()) { |
842 return; | 841 return; |
843 } | 842 } |
844 | 843 |
845 // Start clock since there is no more audio to | 844 // Start clock since there is no more audio to |
846 // trigger clock updates. | 845 // trigger clock updates. |
847 base::AutoLock auto_lock(lock_); | 846 base::AutoLock auto_lock(lock_); |
848 clock_->SetMaxTime(clock_->Duration()); | 847 clock_->SetMaxTime(clock_->Duration()); |
849 StartClockIfWaitingForTimeUpdate_Locked(); | 848 StartClockIfWaitingForTimeUpdate_Locked(); |
850 } | 849 } |
851 | 850 |
852 if (video_renderer_ && !video_renderer_->HasEnded()) { | 851 if (video_renderer_ && !video_renderer_->HasEnded()) { |
853 return; | 852 return; |
854 } | 853 } |
855 | 854 |
856 // Transition to ended, executing the callback if present. | |
857 SetState(kEnded); | |
858 { | 855 { |
859 base::AutoLock auto_lock(lock_); | 856 base::AutoLock auto_lock(lock_); |
860 clock_->EndOfStream(); | 857 clock_->EndOfStream(); |
861 } | 858 } |
862 | 859 |
863 ReportStatus(ended_cb_, status_); | 860 ReportStatus(ended_cb_, status_); |
864 } | 861 } |
865 | 862 |
866 void Pipeline::AudioDisabledTask() { | 863 void Pipeline::AudioDisabledTask() { |
867 DCHECK(message_loop_->BelongsToCurrentThread()); | 864 DCHECK(message_loop_->BelongsToCurrentThread()); |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
981 case kError: | 978 case kError: |
982 case kInitDemuxer: | 979 case kInitDemuxer: |
983 case kInitAudioDecoder: | 980 case kInitAudioDecoder: |
984 case kInitAudioRenderer: | 981 case kInitAudioRenderer: |
985 case kInitVideoDecoder: | 982 case kInitVideoDecoder: |
986 case kInitVideoRenderer: | 983 case kInitVideoRenderer: |
987 case kSeeking: | 984 case kSeeking: |
988 case kStarting: | 985 case kStarting: |
989 case kStopped: | 986 case kStopped: |
990 case kStarted: | 987 case kStarted: |
991 case kEnded: | |
992 NOTREACHED() << "Unexpected state for teardown: " << state_; | 988 NOTREACHED() << "Unexpected state for teardown: " << state_; |
993 break; | 989 break; |
994 // default: intentionally left out to force new states to cause compiler | 990 // default: intentionally left out to force new states to cause compiler |
995 // errors. | 991 // errors. |
996 }; | 992 }; |
997 } | 993 } |
998 | 994 |
999 void Pipeline::FinishDestroyingFiltersTask() { | 995 void Pipeline::FinishDestroyingFiltersTask() { |
1000 DCHECK(message_loop_->BelongsToCurrentThread()); | 996 DCHECK(message_loop_->BelongsToCurrentThread()); |
1001 DCHECK(IsPipelineStopped()); | 997 DCHECK(IsPipelineStopped()); |
(...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1210 DoStop(base::Bind(&Pipeline::OnTeardownStateTransition, this)); | 1206 DoStop(base::Bind(&Pipeline::OnTeardownStateTransition, this)); |
1211 | 1207 |
1212 if (seek_pending_) { | 1208 if (seek_pending_) { |
1213 seek_pending_ = false; | 1209 seek_pending_ = false; |
1214 FinishInitialization(); | 1210 FinishInitialization(); |
1215 } | 1211 } |
1216 | 1212 |
1217 break; | 1213 break; |
1218 | 1214 |
1219 case kStarted: | 1215 case kStarted: |
1220 case kEnded: | |
1221 SetState(kPausing); | 1216 SetState(kPausing); |
1222 DoPause(base::Bind(&Pipeline::OnTeardownStateTransition, this)); | 1217 DoPause(base::Bind(&Pipeline::OnTeardownStateTransition, this)); |
1223 break; | 1218 break; |
1224 | 1219 |
1225 case kStopping: | 1220 case kStopping: |
1226 case kStopped: | 1221 case kStopped: |
1227 NOTREACHED() << "Unexpected state for teardown: " << state_; | 1222 NOTREACHED() << "Unexpected state for teardown: " << state_; |
1228 break; | 1223 break; |
1229 // default: intentionally left out to force new states to cause compiler | 1224 // default: intentionally left out to force new states to cause compiler |
1230 // errors. | 1225 // errors. |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1273 void Pipeline::StartClockIfWaitingForTimeUpdate_Locked() { | 1268 void Pipeline::StartClockIfWaitingForTimeUpdate_Locked() { |
1274 lock_.AssertAcquired(); | 1269 lock_.AssertAcquired(); |
1275 if (!waiting_for_clock_update_) | 1270 if (!waiting_for_clock_update_) |
1276 return; | 1271 return; |
1277 | 1272 |
1278 waiting_for_clock_update_ = false; | 1273 waiting_for_clock_update_ = false; |
1279 clock_->Play(); | 1274 clock_->Play(); |
1280 } | 1275 } |
1281 | 1276 |
1282 } // namespace media | 1277 } // namespace media |
OLD | NEW |