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: |
154 return true; | 155 return true; |
155 default: | 156 default: |
156 return false; | 157 return false; |
157 } | 158 } |
158 } | 159 } |
159 | 160 |
160 bool Pipeline::HasAudio() const { | 161 bool Pipeline::HasAudio() const { |
161 base::AutoLock auto_lock(lock_); | 162 base::AutoLock auto_lock(lock_); |
162 return has_audio_; | 163 return has_audio_; |
163 } | 164 } |
(...skipping 624 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
788 | 789 |
789 if (audio_renderer_) | 790 if (audio_renderer_) |
790 audio_renderer_->SetVolume(volume); | 791 audio_renderer_->SetVolume(volume); |
791 } | 792 } |
792 | 793 |
793 void Pipeline::SeekTask(TimeDelta time, const PipelineStatusCB& seek_cb) { | 794 void Pipeline::SeekTask(TimeDelta time, const PipelineStatusCB& seek_cb) { |
794 DCHECK(message_loop_->BelongsToCurrentThread()); | 795 DCHECK(message_loop_->BelongsToCurrentThread()); |
795 DCHECK(!IsPipelineStopPending()); | 796 DCHECK(!IsPipelineStopPending()); |
796 | 797 |
797 // Suppress seeking if we're not fully started. | 798 // Suppress seeking if we're not fully started. |
798 if (state_ != kStarted) { | 799 if (state_ != kStarted && state_ != kEnded) { |
799 // TODO(scherkus): should we run the callback? I'm tempted to say the API | 800 // TODO(scherkus): should we run the callback? I'm tempted to say the API |
800 // will only execute the first Seek() request. | 801 // will only execute the first Seek() request. |
801 DVLOG(1) << "Media pipeline has not started, ignoring seek to " | 802 DVLOG(1) << "Media pipeline has not started, ignoring seek to " |
802 << time.InMicroseconds() << " (current state: " << state_ << ")"; | 803 << time.InMicroseconds() << " (current state: " << state_ << ")"; |
803 return; | 804 return; |
804 } | 805 } |
805 | 806 |
806 DCHECK(!seek_pending_); | 807 DCHECK(!seek_pending_); |
807 seek_pending_ = true; | 808 seek_pending_ = true; |
808 | 809 |
809 // We'll need to pause every filter before seeking. The state transition | 810 // We'll need to pause every filter before seeking. The state transition |
810 // is as follows: | 811 // is as follows: |
811 // kStarted | 812 // kStarted/kEnded |
812 // kPausing (for each filter) | 813 // kPausing (for each filter) |
813 // kSeeking (for each filter) | 814 // kSeeking (for each filter) |
814 // kStarting (for each filter) | 815 // kStarting (for each filter) |
815 // kStarted | 816 // kStarted |
816 SetState(kPausing); | 817 SetState(kPausing); |
817 seek_timestamp_ = std::max(time, demuxer_->GetStartTime()); | 818 seek_timestamp_ = std::max(time, demuxer_->GetStartTime()); |
818 seek_cb_ = seek_cb; | 819 seek_cb_ = seek_cb; |
819 | 820 |
820 // Kick off seeking! | 821 // Kick off seeking! |
821 { | 822 { |
(...skipping 24 matching lines...) Expand all Loading... |
846 // trigger clock updates. | 847 // trigger clock updates. |
847 base::AutoLock auto_lock(lock_); | 848 base::AutoLock auto_lock(lock_); |
848 clock_->SetMaxTime(clock_->Duration()); | 849 clock_->SetMaxTime(clock_->Duration()); |
849 StartClockIfWaitingForTimeUpdate_Locked(); | 850 StartClockIfWaitingForTimeUpdate_Locked(); |
850 } | 851 } |
851 | 852 |
852 if (video_renderer_ && !video_renderer_->HasEnded()) { | 853 if (video_renderer_ && !video_renderer_->HasEnded()) { |
853 return; | 854 return; |
854 } | 855 } |
855 | 856 |
| 857 // Transition to ended, executing the callback if present. |
| 858 SetState(kEnded); |
856 { | 859 { |
857 base::AutoLock auto_lock(lock_); | 860 base::AutoLock auto_lock(lock_); |
858 clock_->EndOfStream(); | 861 clock_->EndOfStream(); |
859 } | 862 } |
860 | 863 |
861 ReportStatus(ended_cb_, status_); | 864 ReportStatus(ended_cb_, status_); |
862 } | 865 } |
863 | 866 |
864 void Pipeline::AudioDisabledTask() { | 867 void Pipeline::AudioDisabledTask() { |
865 DCHECK(message_loop_->BelongsToCurrentThread()); | 868 DCHECK(message_loop_->BelongsToCurrentThread()); |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
980 case kError: | 983 case kError: |
981 case kInitDemuxer: | 984 case kInitDemuxer: |
982 case kInitAudioDecoder: | 985 case kInitAudioDecoder: |
983 case kInitAudioRenderer: | 986 case kInitAudioRenderer: |
984 case kInitVideoDecoder: | 987 case kInitVideoDecoder: |
985 case kInitVideoRenderer: | 988 case kInitVideoRenderer: |
986 case kSeeking: | 989 case kSeeking: |
987 case kStarting: | 990 case kStarting: |
988 case kStopped: | 991 case kStopped: |
989 case kStarted: | 992 case kStarted: |
| 993 case kEnded: |
990 NOTREACHED() << "Unexpected state for teardown: " << state_; | 994 NOTREACHED() << "Unexpected state for teardown: " << state_; |
991 break; | 995 break; |
992 // default: intentionally left out to force new states to cause compiler | 996 // default: intentionally left out to force new states to cause compiler |
993 // errors. | 997 // errors. |
994 }; | 998 }; |
995 } | 999 } |
996 | 1000 |
997 void Pipeline::FinishDestroyingFiltersTask() { | 1001 void Pipeline::FinishDestroyingFiltersTask() { |
998 DCHECK(message_loop_->BelongsToCurrentThread()); | 1002 DCHECK(message_loop_->BelongsToCurrentThread()); |
999 DCHECK(IsPipelineStopped()); | 1003 DCHECK(IsPipelineStopped()); |
(...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1208 DoStop(base::Bind(&Pipeline::OnTeardownStateTransition, this)); | 1212 DoStop(base::Bind(&Pipeline::OnTeardownStateTransition, this)); |
1209 | 1213 |
1210 if (seek_pending_) { | 1214 if (seek_pending_) { |
1211 seek_pending_ = false; | 1215 seek_pending_ = false; |
1212 FinishInitialization(); | 1216 FinishInitialization(); |
1213 } | 1217 } |
1214 | 1218 |
1215 break; | 1219 break; |
1216 | 1220 |
1217 case kStarted: | 1221 case kStarted: |
| 1222 case kEnded: |
1218 SetState(kPausing); | 1223 SetState(kPausing); |
1219 DoPause(base::Bind(&Pipeline::OnTeardownStateTransition, this)); | 1224 DoPause(base::Bind(&Pipeline::OnTeardownStateTransition, this)); |
1220 break; | 1225 break; |
1221 | 1226 |
1222 case kStopping: | 1227 case kStopping: |
1223 case kStopped: | 1228 case kStopped: |
1224 NOTREACHED() << "Unexpected state for teardown: " << state_; | 1229 NOTREACHED() << "Unexpected state for teardown: " << state_; |
1225 break; | 1230 break; |
1226 // default: intentionally left out to force new states to cause compiler | 1231 // default: intentionally left out to force new states to cause compiler |
1227 // errors. | 1232 // errors. |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1270 void Pipeline::StartClockIfWaitingForTimeUpdate_Locked() { | 1275 void Pipeline::StartClockIfWaitingForTimeUpdate_Locked() { |
1271 lock_.AssertAcquired(); | 1276 lock_.AssertAcquired(); |
1272 if (!waiting_for_clock_update_) | 1277 if (!waiting_for_clock_update_) |
1273 return; | 1278 return; |
1274 | 1279 |
1275 waiting_for_clock_update_ = false; | 1280 waiting_for_clock_update_ = false; |
1276 clock_->Play(); | 1281 clock_->Play(); |
1277 } | 1282 } |
1278 | 1283 |
1279 } // namespace media | 1284 } // namespace media |
OLD | NEW |