Chromium Code Reviews| 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::ENDED)); |
|
Ami GONE FROM CHROMIUM
2012/08/08 21:48:26
Why is it useful to media_log this twice?
Alternat
scherkus (not reviewing)
2012/08/08 22:28:34
Done by dup'ing the the events (I find adding a pa
| |
| 535 } | 536 } |
| 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::ENDED)); | |
| 543 } | |
| 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. |
| 545 // This method makes the PipelineStatusCB behave like a Closure. It | 553 // This method makes the PipelineStatusCB behave like a Closure. It |
| 546 // makes it look like a host()->SetError() call followed by a call to | 554 // makes it look like a host()->SetError() call followed by a call to |
| (...skipping 242 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; | |
|
scherkus (not reviewing)
2012/08/08 20:59:58
FYI I think this is the only spot where we need to
| |
| 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 |