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 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
81 volume_(1.0f), | 81 volume_(1.0f), |
82 playback_rate_(0.0f), | 82 playback_rate_(0.0f), |
83 pending_playback_rate_(0.0f), | 83 pending_playback_rate_(0.0f), |
84 clock_(new Clock(&base::Time::Now)), | 84 clock_(new Clock(&base::Time::Now)), |
85 waiting_for_clock_update_(false), | 85 waiting_for_clock_update_(false), |
86 status_(PIPELINE_OK), | 86 status_(PIPELINE_OK), |
87 has_audio_(false), | 87 has_audio_(false), |
88 has_video_(false), | 88 has_video_(false), |
89 state_(kCreated), | 89 state_(kCreated), |
90 seek_timestamp_(kNoTimestamp()), | 90 seek_timestamp_(kNoTimestamp()), |
| 91 audio_ended_(false), |
| 92 video_ended_(false), |
91 audio_disabled_(false), | 93 audio_disabled_(false), |
92 creation_time_(base::Time::Now()) { | 94 creation_time_(base::Time::Now()) { |
93 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(kCreated)); | 95 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(kCreated)); |
94 media_log_->AddEvent( | 96 media_log_->AddEvent( |
95 media_log_->CreateEvent(MediaLogEvent::PIPELINE_CREATED)); | 97 media_log_->CreateEvent(MediaLogEvent::PIPELINE_CREATED)); |
96 } | 98 } |
97 | 99 |
98 Pipeline::~Pipeline() { | 100 Pipeline::~Pipeline() { |
99 base::AutoLock auto_lock(lock_); | 101 base::AutoLock auto_lock(lock_); |
100 DCHECK(!running_) << "Stop() must complete before destroying object"; | 102 DCHECK(!running_) << "Stop() must complete before destroying object"; |
(...skipping 43 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 | 146 // 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 | 147 // lock, because this is breaching the contract that |state_| is only accessed |
146 // on |message_loop_|. | 148 // on |message_loop_|. |
147 base::AutoLock auto_lock(lock_); | 149 base::AutoLock auto_lock(lock_); |
148 switch (state_) { | 150 switch (state_) { |
149 case kPausing: | 151 case kPausing: |
150 case kFlushing: | 152 case kFlushing: |
151 case kSeeking: | 153 case kSeeking: |
152 case kStarting: | 154 case kStarting: |
153 case kStarted: | 155 case kStarted: |
154 case kEnded: | |
155 return true; | 156 return true; |
156 default: | 157 default: |
157 return false; | 158 return false; |
158 } | 159 } |
159 } | 160 } |
160 | 161 |
161 bool Pipeline::HasAudio() const { | 162 bool Pipeline::HasAudio() const { |
162 base::AutoLock auto_lock(lock_); | 163 base::AutoLock auto_lock(lock_); |
163 return has_audio_; | 164 return has_audio_; |
164 } | 165 } |
(...skipping 355 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
520 | 521 |
521 void Pipeline::OnNaturalVideoSizeChanged(const gfx::Size& size) { | 522 void Pipeline::OnNaturalVideoSizeChanged(const gfx::Size& size) { |
522 DCHECK(IsRunning()); | 523 DCHECK(IsRunning()); |
523 media_log_->AddEvent(media_log_->CreateVideoSizeSetEvent( | 524 media_log_->AddEvent(media_log_->CreateVideoSizeSetEvent( |
524 size.width(), size.height())); | 525 size.width(), size.height())); |
525 | 526 |
526 base::AutoLock auto_lock(lock_); | 527 base::AutoLock auto_lock(lock_); |
527 natural_size_ = size; | 528 natural_size_ = size; |
528 } | 529 } |
529 | 530 |
530 void Pipeline::OnRendererEnded() { | 531 void Pipeline::OnAudioRendererEnded() { |
531 DCHECK(IsRunning()); | 532 // Force post to process ended messages after current execution frame. |
532 message_loop_->PostTask(FROM_HERE, base::Bind( | 533 message_loop_->PostTask(FROM_HERE, base::Bind( |
533 &Pipeline::OnRendererEndedTask, this)); | 534 &Pipeline::DoAudioRendererEnded, this)); |
534 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::ENDED)); | 535 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::AUDIO_ENDED)); |
| 536 } |
| 537 |
| 538 void Pipeline::OnVideoRendererEnded() { |
| 539 // Force post to process ended messages after current execution frame. |
| 540 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 541 &Pipeline::DoVideoRendererEnded, this)); |
| 542 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::VIDEO_ENDED)); |
535 } | 543 } |
536 | 544 |
537 // Called from any thread. | 545 // Called from any thread. |
538 void Pipeline::OnFilterInitialize(PipelineStatus status) { | 546 void Pipeline::OnFilterInitialize(PipelineStatus status) { |
539 // Continue the initialize task by proceeding to the next stage. | 547 // Continue the initialize task by proceeding to the next stage. |
540 message_loop_->PostTask(FROM_HERE, base::Bind( | 548 message_loop_->PostTask(FROM_HERE, base::Bind( |
541 &Pipeline::InitializeTask, this, status)); | 549 &Pipeline::InitializeTask, this, status)); |
542 } | 550 } |
543 | 551 |
544 // Called from any thread. | 552 // Called from any thread. |
(...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
789 | 797 |
790 if (audio_renderer_) | 798 if (audio_renderer_) |
791 audio_renderer_->SetVolume(volume); | 799 audio_renderer_->SetVolume(volume); |
792 } | 800 } |
793 | 801 |
794 void Pipeline::SeekTask(TimeDelta time, const PipelineStatusCB& seek_cb) { | 802 void Pipeline::SeekTask(TimeDelta time, const PipelineStatusCB& seek_cb) { |
795 DCHECK(message_loop_->BelongsToCurrentThread()); | 803 DCHECK(message_loop_->BelongsToCurrentThread()); |
796 DCHECK(!IsPipelineStopPending()); | 804 DCHECK(!IsPipelineStopPending()); |
797 | 805 |
798 // Suppress seeking if we're not fully started. | 806 // Suppress seeking if we're not fully started. |
799 if (state_ != kStarted && state_ != kEnded) { | 807 if (state_ != kStarted) { |
800 // TODO(scherkus): should we run the callback? I'm tempted to say the API | 808 // TODO(scherkus): should we run the callback? I'm tempted to say the API |
801 // will only execute the first Seek() request. | 809 // will only execute the first Seek() request. |
802 DVLOG(1) << "Media pipeline has not started, ignoring seek to " | 810 DVLOG(1) << "Media pipeline has not started, ignoring seek to " |
803 << time.InMicroseconds() << " (current state: " << state_ << ")"; | 811 << time.InMicroseconds() << " (current state: " << state_ << ")"; |
804 return; | 812 return; |
805 } | 813 } |
806 | 814 |
807 DCHECK(!seek_pending_); | 815 DCHECK(!seek_pending_); |
808 seek_pending_ = true; | 816 seek_pending_ = true; |
809 | 817 |
810 // We'll need to pause every filter before seeking. The state transition | 818 // We'll need to pause every filter before seeking. The state transition |
811 // is as follows: | 819 // is as follows: |
812 // kStarted/kEnded | 820 // kStarted |
813 // kPausing (for each filter) | 821 // kPausing (for each filter) |
814 // kSeeking (for each filter) | 822 // kSeeking (for each filter) |
815 // kStarting (for each filter) | 823 // kStarting (for each filter) |
816 // kStarted | 824 // kStarted |
817 SetState(kPausing); | 825 SetState(kPausing); |
| 826 audio_ended_ = false; |
| 827 video_ended_ = false; |
818 seek_timestamp_ = std::max(time, demuxer_->GetStartTime()); | 828 seek_timestamp_ = std::max(time, demuxer_->GetStartTime()); |
819 seek_cb_ = seek_cb; | 829 seek_cb_ = seek_cb; |
820 | 830 |
821 // Kick off seeking! | 831 // Kick off seeking! |
822 { | 832 { |
823 base::AutoLock auto_lock(lock_); | 833 base::AutoLock auto_lock(lock_); |
824 if (clock_->IsPlaying()) | 834 if (clock_->IsPlaying()) |
825 clock_->Pause(); | 835 clock_->Pause(); |
826 } | 836 } |
827 DoPause(base::Bind(&Pipeline::OnFilterStateTransition, this)); | 837 DoPause(base::Bind(&Pipeline::OnFilterStateTransition, this)); |
828 } | 838 } |
829 | 839 |
830 void Pipeline::OnRendererEndedTask() { | 840 void Pipeline::DoAudioRendererEnded() { |
831 DCHECK(message_loop_->BelongsToCurrentThread()); | 841 DCHECK(message_loop_->BelongsToCurrentThread()); |
832 | 842 |
833 // We can only end if we were actually playing. | 843 if (state_ != kStarted) |
834 if (state_ != kStarted) { | |
835 return; | 844 return; |
836 } | |
837 | 845 |
838 DCHECK(audio_renderer_ || video_renderer_); | 846 DCHECK(!audio_ended_); |
| 847 audio_ended_ = true; |
839 | 848 |
840 // Make sure every extant renderer has ended. | 849 // Start clock since there is no more audio to trigger clock updates. |
841 if (audio_renderer_ && !audio_disabled_) { | 850 if (!audio_disabled_) { |
842 if (!audio_renderer_->HasEnded()) { | |
843 return; | |
844 } | |
845 | |
846 // Start clock since there is no more audio to | |
847 // trigger clock updates. | |
848 base::AutoLock auto_lock(lock_); | 851 base::AutoLock auto_lock(lock_); |
849 clock_->SetMaxTime(clock_->Duration()); | 852 clock_->SetMaxTime(clock_->Duration()); |
850 StartClockIfWaitingForTimeUpdate_Locked(); | 853 StartClockIfWaitingForTimeUpdate_Locked(); |
851 } | 854 } |
852 | 855 |
853 if (video_renderer_ && !video_renderer_->HasEnded()) { | 856 RunEndedCallbackIfNeeded(); |
| 857 } |
| 858 |
| 859 void Pipeline::DoVideoRendererEnded() { |
| 860 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 861 |
| 862 if (state_ != kStarted) |
854 return; | 863 return; |
855 } | |
856 | 864 |
857 // Transition to ended, executing the callback if present. | 865 DCHECK(!video_ended_); |
858 SetState(kEnded); | 866 video_ended_ = true; |
| 867 |
| 868 RunEndedCallbackIfNeeded(); |
| 869 } |
| 870 |
| 871 void Pipeline::RunEndedCallbackIfNeeded() { |
| 872 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 873 |
| 874 if (audio_renderer_ && !audio_ended_ && !audio_disabled_) |
| 875 return; |
| 876 |
| 877 if (video_renderer_ && !video_ended_) |
| 878 return; |
| 879 |
859 { | 880 { |
860 base::AutoLock auto_lock(lock_); | 881 base::AutoLock auto_lock(lock_); |
861 clock_->EndOfStream(); | 882 clock_->EndOfStream(); |
862 } | 883 } |
863 | 884 |
864 ReportStatus(ended_cb_, status_); | 885 ReportStatus(ended_cb_, status_); |
865 } | 886 } |
866 | 887 |
867 void Pipeline::AudioDisabledTask() { | 888 void Pipeline::AudioDisabledTask() { |
868 DCHECK(message_loop_->BelongsToCurrentThread()); | 889 DCHECK(message_loop_->BelongsToCurrentThread()); |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
983 case kError: | 1004 case kError: |
984 case kInitDemuxer: | 1005 case kInitDemuxer: |
985 case kInitAudioDecoder: | 1006 case kInitAudioDecoder: |
986 case kInitAudioRenderer: | 1007 case kInitAudioRenderer: |
987 case kInitVideoDecoder: | 1008 case kInitVideoDecoder: |
988 case kInitVideoRenderer: | 1009 case kInitVideoRenderer: |
989 case kSeeking: | 1010 case kSeeking: |
990 case kStarting: | 1011 case kStarting: |
991 case kStopped: | 1012 case kStopped: |
992 case kStarted: | 1013 case kStarted: |
993 case kEnded: | |
994 NOTREACHED() << "Unexpected state for teardown: " << state_; | 1014 NOTREACHED() << "Unexpected state for teardown: " << state_; |
995 break; | 1015 break; |
996 // default: intentionally left out to force new states to cause compiler | 1016 // default: intentionally left out to force new states to cause compiler |
997 // errors. | 1017 // errors. |
998 }; | 1018 }; |
999 } | 1019 } |
1000 | 1020 |
1001 void Pipeline::FinishDestroyingFiltersTask() { | 1021 void Pipeline::FinishDestroyingFiltersTask() { |
1002 DCHECK(message_loop_->BelongsToCurrentThread()); | 1022 DCHECK(message_loop_->BelongsToCurrentThread()); |
1003 DCHECK(IsPipelineStopped()); | 1023 DCHECK(IsPipelineStopped()); |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1125 if (!audio_renderer_) { | 1145 if (!audio_renderer_) { |
1126 SetError(PIPELINE_ERROR_REQUIRED_FILTER_MISSING); | 1146 SetError(PIPELINE_ERROR_REQUIRED_FILTER_MISSING); |
1127 return false; | 1147 return false; |
1128 } | 1148 } |
1129 | 1149 |
1130 audio_renderer_->Initialize( | 1150 audio_renderer_->Initialize( |
1131 decoder, | 1151 decoder, |
1132 base::Bind(&Pipeline::OnFilterInitialize, this), | 1152 base::Bind(&Pipeline::OnFilterInitialize, this), |
1133 base::Bind(&Pipeline::OnAudioUnderflow, this), | 1153 base::Bind(&Pipeline::OnAudioUnderflow, this), |
1134 base::Bind(&Pipeline::OnAudioTimeUpdate, this), | 1154 base::Bind(&Pipeline::OnAudioTimeUpdate, this), |
1135 base::Bind(&Pipeline::OnRendererEnded, this), | 1155 base::Bind(&Pipeline::OnAudioRendererEnded, this), |
1136 base::Bind(&Pipeline::OnAudioDisabled, this), | 1156 base::Bind(&Pipeline::OnAudioDisabled, this), |
1137 base::Bind(&Pipeline::SetError, this)); | 1157 base::Bind(&Pipeline::SetError, this)); |
1138 return true; | 1158 return true; |
1139 } | 1159 } |
1140 | 1160 |
1141 bool Pipeline::InitializeVideoRenderer( | 1161 bool Pipeline::InitializeVideoRenderer( |
1142 const scoped_refptr<VideoDecoder>& decoder) { | 1162 const scoped_refptr<VideoDecoder>& decoder) { |
1143 DCHECK(message_loop_->BelongsToCurrentThread()); | 1163 DCHECK(message_loop_->BelongsToCurrentThread()); |
1144 DCHECK(IsPipelineOk()); | 1164 DCHECK(IsPipelineOk()); |
1145 | 1165 |
1146 if (!decoder) | 1166 if (!decoder) |
1147 return false; | 1167 return false; |
1148 | 1168 |
1149 filter_collection_->SelectVideoRenderer(&video_renderer_); | 1169 filter_collection_->SelectVideoRenderer(&video_renderer_); |
1150 if (!video_renderer_) { | 1170 if (!video_renderer_) { |
1151 SetError(PIPELINE_ERROR_REQUIRED_FILTER_MISSING); | 1171 SetError(PIPELINE_ERROR_REQUIRED_FILTER_MISSING); |
1152 return false; | 1172 return false; |
1153 } | 1173 } |
1154 | 1174 |
1155 video_renderer_->Initialize( | 1175 video_renderer_->Initialize( |
1156 decoder, | 1176 decoder, |
1157 base::Bind(&Pipeline::OnFilterInitialize, this), | 1177 base::Bind(&Pipeline::OnFilterInitialize, this), |
1158 base::Bind(&Pipeline::OnUpdateStatistics, this), | 1178 base::Bind(&Pipeline::OnUpdateStatistics, this), |
1159 base::Bind(&Pipeline::OnVideoTimeUpdate, this), | 1179 base::Bind(&Pipeline::OnVideoTimeUpdate, this), |
1160 base::Bind(&Pipeline::OnNaturalVideoSizeChanged, this), | 1180 base::Bind(&Pipeline::OnNaturalVideoSizeChanged, this), |
1161 base::Bind(&Pipeline::OnRendererEnded, this), | 1181 base::Bind(&Pipeline::OnVideoRendererEnded, this), |
1162 base::Bind(&Pipeline::SetError, this), | 1182 base::Bind(&Pipeline::SetError, this), |
1163 base::Bind(&Pipeline::GetMediaTime, this), | 1183 base::Bind(&Pipeline::GetMediaTime, this), |
1164 base::Bind(&Pipeline::GetMediaDuration, this)); | 1184 base::Bind(&Pipeline::GetMediaDuration, this)); |
1165 return true; | 1185 return true; |
1166 } | 1186 } |
1167 | 1187 |
1168 void Pipeline::TearDownPipeline() { | 1188 void Pipeline::TearDownPipeline() { |
1169 DCHECK(message_loop_->BelongsToCurrentThread()); | 1189 DCHECK(message_loop_->BelongsToCurrentThread()); |
1170 DCHECK_NE(kStopped, state_); | 1190 DCHECK_NE(kStopped, state_); |
1171 | 1191 |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1212 DoStop(base::Bind(&Pipeline::OnTeardownStateTransition, this)); | 1232 DoStop(base::Bind(&Pipeline::OnTeardownStateTransition, this)); |
1213 | 1233 |
1214 if (seek_pending_) { | 1234 if (seek_pending_) { |
1215 seek_pending_ = false; | 1235 seek_pending_ = false; |
1216 FinishInitialization(); | 1236 FinishInitialization(); |
1217 } | 1237 } |
1218 | 1238 |
1219 break; | 1239 break; |
1220 | 1240 |
1221 case kStarted: | 1241 case kStarted: |
1222 case kEnded: | |
1223 SetState(kPausing); | 1242 SetState(kPausing); |
1224 DoPause(base::Bind(&Pipeline::OnTeardownStateTransition, this)); | 1243 DoPause(base::Bind(&Pipeline::OnTeardownStateTransition, this)); |
1225 break; | 1244 break; |
1226 | 1245 |
1227 case kStopping: | 1246 case kStopping: |
1228 case kStopped: | 1247 case kStopped: |
1229 NOTREACHED() << "Unexpected state for teardown: " << state_; | 1248 NOTREACHED() << "Unexpected state for teardown: " << state_; |
1230 break; | 1249 break; |
1231 // default: intentionally left out to force new states to cause compiler | 1250 // default: intentionally left out to force new states to cause compiler |
1232 // errors. | 1251 // errors. |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1275 void Pipeline::StartClockIfWaitingForTimeUpdate_Locked() { | 1294 void Pipeline::StartClockIfWaitingForTimeUpdate_Locked() { |
1276 lock_.AssertAcquired(); | 1295 lock_.AssertAcquired(); |
1277 if (!waiting_for_clock_update_) | 1296 if (!waiting_for_clock_update_) |
1278 return; | 1297 return; |
1279 | 1298 |
1280 waiting_for_clock_update_ = false; | 1299 waiting_for_clock_update_ = false; |
1281 clock_->Play(); | 1300 clock_->Play(); |
1282 } | 1301 } |
1283 | 1302 |
1284 } // namespace media | 1303 } // namespace media |
OLD | NEW |