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 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 54 while (!notified_) | 54 while (!notified_) |
| 55 cv_.Wait(); | 55 cv_.Wait(); |
| 56 } | 56 } |
| 57 | 57 |
| 58 media::PipelineStatus PipelineStatusNotification::status() { | 58 media::PipelineStatus PipelineStatusNotification::status() { |
| 59 base::AutoLock auto_lock(lock_); | 59 base::AutoLock auto_lock(lock_); |
| 60 DCHECK(notified_); | 60 DCHECK(notified_); |
| 61 return status_; | 61 return status_; |
| 62 } | 62 } |
| 63 | 63 |
| 64 struct Pipeline::PipelineInitState { | 64 struct Pipeline::PipelineInitState { |
|
Ami GONE FROM CHROMIUM
2012/08/09 20:30:18
drop this struct now (and bind the audio decoder i
acolwell GONE FROM CHROMIUM
2012/08/09 22:23:32
I can't really do this w/o moving the kInitAudioDe
| |
| 65 scoped_refptr<AudioDecoder> audio_decoder; | 65 scoped_refptr<AudioDecoder> audio_decoder; |
| 66 scoped_refptr<VideoDecoder> video_decoder; | |
| 67 }; | 66 }; |
| 68 | 67 |
| 69 Pipeline::Pipeline(MessageLoop* message_loop, MediaLog* media_log) | 68 Pipeline::Pipeline(MessageLoop* message_loop, MediaLog* media_log) |
| 70 : message_loop_(message_loop->message_loop_proxy()), | 69 : message_loop_(message_loop->message_loop_proxy()), |
| 71 media_log_(media_log), | 70 media_log_(media_log), |
| 72 running_(false), | 71 running_(false), |
| 73 seek_pending_(false), | 72 seek_pending_(false), |
| 74 stop_pending_(false), | 73 stop_pending_(false), |
| 75 tearing_down_(false), | 74 tearing_down_(false), |
| 76 error_caused_teardown_(false), | 75 error_caused_teardown_(false), |
| (...skipping 525 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 602 // FilterHost's InitializationComplete() method, the pipeline will update its | 601 // FilterHost's InitializationComplete() method, the pipeline will update its |
| 603 // state to kStarted and |init_cb_|, will be executed. | 602 // state to kStarted and |init_cb_|, will be executed. |
| 604 // | 603 // |
| 605 // TODO(hclam): InitializeTask() is now starting the pipeline asynchronously. It | 604 // TODO(hclam): InitializeTask() is now starting the pipeline asynchronously. It |
| 606 // works like a big state change table. If we no longer need to start filters | 605 // works like a big state change table. If we no longer need to start filters |
| 607 // in order, we need to get rid of all the state change. | 606 // in order, we need to get rid of all the state change. |
| 608 void Pipeline::InitializeTask(PipelineStatus last_stage_status) { | 607 void Pipeline::InitializeTask(PipelineStatus last_stage_status) { |
| 609 DCHECK(message_loop_->BelongsToCurrentThread()); | 608 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 610 | 609 |
| 611 if (last_stage_status != PIPELINE_OK) { | 610 if (last_stage_status != PIPELINE_OK) { |
| 612 // Currently only VideoDecoders have a recoverable error code. | 611 SetError(last_stage_status); |
| 613 if (state_ == kInitVideoDecoder && | 612 return; |
| 614 last_stage_status == DECODER_ERROR_NOT_SUPPORTED) { | |
| 615 state_ = kInitAudioRenderer; | |
| 616 } else { | |
| 617 SetError(last_stage_status); | |
| 618 return; | |
| 619 } | |
| 620 } | 613 } |
| 621 | 614 |
| 622 // If we have received the stop or error signal, return immediately. | 615 // If we have received the stop or error signal, return immediately. |
| 623 if (IsPipelineStopPending() || IsPipelineStopped() || !IsPipelineOk()) | 616 if (IsPipelineStopPending() || IsPipelineStopped() || !IsPipelineOk()) |
| 624 return; | 617 return; |
| 625 | 618 |
| 626 DCHECK(state_ == kInitDemuxer || | 619 DCHECK(state_ == kInitDemuxer || |
| 627 state_ == kInitAudioDecoder || | 620 state_ == kInitAudioDecoder || |
| 628 state_ == kInitAudioRenderer || | 621 state_ == kInitAudioRenderer || |
| 629 state_ == kInitVideoDecoder || | |
| 630 state_ == kInitVideoRenderer); | 622 state_ == kInitVideoRenderer); |
| 631 | 623 |
| 632 // Demuxer created, create audio decoder. | 624 // Demuxer created, create audio decoder. |
| 633 if (state_ == kInitDemuxer) { | 625 if (state_ == kInitDemuxer) { |
| 634 SetState(kInitAudioDecoder); | 626 SetState(kInitAudioDecoder); |
| 635 // If this method returns false, then there's no audio stream. | 627 // If this method returns false, then there's no audio stream. |
| 636 if (InitializeAudioDecoder(demuxer_)) | 628 if (InitializeAudioDecoder(demuxer_)) |
| 637 return; | 629 return; |
| 638 } | 630 } |
| 639 | 631 |
| 640 // Assuming audio decoder was created, create audio renderer. | 632 // Assuming audio decoder was created, create audio renderer. |
| 641 if (state_ == kInitAudioDecoder) { | 633 if (state_ == kInitAudioDecoder) { |
| 642 SetState(kInitAudioRenderer); | 634 SetState(kInitAudioRenderer); |
| 643 | 635 |
| 644 // Returns false if there's no audio stream. | 636 // Returns false if there's no audio stream. |
| 645 if (InitializeAudioRenderer(pipeline_init_state_->audio_decoder)) { | 637 if (InitializeAudioRenderer(pipeline_init_state_->audio_decoder)) { |
| 646 base::AutoLock auto_lock(lock_); | 638 base::AutoLock auto_lock(lock_); |
| 647 has_audio_ = true; | 639 has_audio_ = true; |
| 648 return; | 640 return; |
| 649 } | 641 } |
| 650 } | 642 } |
| 651 | 643 |
| 652 // Assuming audio renderer was created, create video decoder. | 644 // Assuming audio renderer was created, create video decoder. |
|
Ami GONE FROM CHROMIUM
2012/08/09 20:30:18
s/decoder/renderer/
acolwell GONE FROM CHROMIUM
2012/08/09 22:23:32
Done.
| |
| 653 if (state_ == kInitAudioRenderer) { | 645 if (state_ == kInitAudioRenderer) { |
| 654 // Then perform the stage of initialization, i.e. initialize video decoder. | |
| 655 SetState(kInitVideoDecoder); | |
| 656 if (InitializeVideoDecoder(demuxer_)) | |
| 657 return; | |
| 658 } | |
| 659 | |
| 660 // Assuming video decoder was created, create video renderer. | |
| 661 if (state_ == kInitVideoDecoder) { | |
| 662 SetState(kInitVideoRenderer); | 646 SetState(kInitVideoRenderer); |
| 663 if (InitializeVideoRenderer(pipeline_init_state_->video_decoder)) { | 647 if (InitializeVideoRenderer(demuxer_->GetStream(DemuxerStream::VIDEO))) { |
| 664 base::AutoLock auto_lock(lock_); | 648 base::AutoLock auto_lock(lock_); |
| 665 has_video_ = true; | 649 has_video_ = true; |
| 666 return; | 650 return; |
| 667 } | 651 } |
| 668 } | 652 } |
| 669 | 653 |
| 670 if (state_ == kInitVideoRenderer) { | 654 if (state_ == kInitVideoRenderer) { |
| 671 if (!IsPipelineOk() || !(HasAudio() || HasVideo())) { | 655 if (!IsPipelineOk() || !(HasAudio() || HasVideo())) { |
| 672 SetError(PIPELINE_ERROR_COULD_NOT_RENDER); | 656 SetError(PIPELINE_ERROR_COULD_NOT_RENDER); |
| 673 return; | 657 return; |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 697 // We stop the filters in the reverse order. | 681 // We stop the filters in the reverse order. |
| 698 // | 682 // |
| 699 // TODO(scherkus): beware! this can get posted multiple times since we post | 683 // TODO(scherkus): beware! this can get posted multiple times since we post |
| 700 // Stop() tasks even if we've already stopped. Perhaps this should no-op for | 684 // Stop() tasks even if we've already stopped. Perhaps this should no-op for |
| 701 // additional calls, however most of this logic will be changing. | 685 // additional calls, however most of this logic will be changing. |
| 702 void Pipeline::StopTask(const base::Closure& stop_cb) { | 686 void Pipeline::StopTask(const base::Closure& stop_cb) { |
| 703 DCHECK(message_loop_->BelongsToCurrentThread()); | 687 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 704 DCHECK(!IsPipelineStopPending()); | 688 DCHECK(!IsPipelineStopPending()); |
| 705 DCHECK_NE(state_, kStopped); | 689 DCHECK_NE(state_, kStopped); |
| 706 | 690 |
| 707 if (video_decoder_) { | 691 if (video_renderer_) |
| 708 video_decoder_->PrepareForShutdownHack(); | 692 video_renderer_->PrepareForShutdownHack(); |
| 709 video_decoder_ = NULL; | |
| 710 } | |
| 711 | 693 |
| 712 if (IsPipelineTearingDown() && error_caused_teardown_) { | 694 if (IsPipelineTearingDown() && error_caused_teardown_) { |
| 713 // If we are stopping due to SetError(), stop normally instead of | 695 // If we are stopping due to SetError(), stop normally instead of |
| 714 // going to error state and calling |error_cb_|. This converts | 696 // going to error state and calling |error_cb_|. This converts |
| 715 // the teardown in progress from an error teardown into one that acts | 697 // the teardown in progress from an error teardown into one that acts |
| 716 // like the error never occurred. | 698 // like the error never occurred. |
| 717 base::AutoLock auto_lock(lock_); | 699 base::AutoLock auto_lock(lock_); |
| 718 status_ = PIPELINE_OK; | 700 status_ = PIPELINE_OK; |
| 719 error_caused_teardown_ = false; | 701 error_caused_teardown_ = false; |
| 720 } | 702 } |
| (...skipping 257 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 978 case kFlushing: | 960 case kFlushing: |
| 979 SetState(kStopping); | 961 SetState(kStopping); |
| 980 DoStop(base::Bind(&Pipeline::OnTeardownStateTransition, this)); | 962 DoStop(base::Bind(&Pipeline::OnTeardownStateTransition, this)); |
| 981 break; | 963 break; |
| 982 | 964 |
| 983 case kCreated: | 965 case kCreated: |
| 984 case kError: | 966 case kError: |
| 985 case kInitDemuxer: | 967 case kInitDemuxer: |
| 986 case kInitAudioDecoder: | 968 case kInitAudioDecoder: |
| 987 case kInitAudioRenderer: | 969 case kInitAudioRenderer: |
| 988 case kInitVideoDecoder: | |
| 989 case kInitVideoRenderer: | 970 case kInitVideoRenderer: |
| 990 case kSeeking: | 971 case kSeeking: |
| 991 case kStarting: | 972 case kStarting: |
| 992 case kStopped: | 973 case kStopped: |
| 993 case kStarted: | 974 case kStarted: |
| 994 case kEnded: | 975 case kEnded: |
| 995 NOTREACHED() << "Unexpected state for teardown: " << state_; | 976 NOTREACHED() << "Unexpected state for teardown: " << state_; |
| 996 break; | 977 break; |
| 997 // default: intentionally left out to force new states to cause compiler | 978 // default: intentionally left out to force new states to cause compiler |
| 998 // errors. | 979 // errors. |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1079 return false; | 1060 return false; |
| 1080 } | 1061 } |
| 1081 | 1062 |
| 1082 pipeline_init_state_->audio_decoder->Initialize( | 1063 pipeline_init_state_->audio_decoder->Initialize( |
| 1083 stream, | 1064 stream, |
| 1084 base::Bind(&Pipeline::OnFilterInitialize, this), | 1065 base::Bind(&Pipeline::OnFilterInitialize, this), |
| 1085 base::Bind(&Pipeline::OnUpdateStatistics, this)); | 1066 base::Bind(&Pipeline::OnUpdateStatistics, this)); |
| 1086 return true; | 1067 return true; |
| 1087 } | 1068 } |
| 1088 | 1069 |
| 1089 bool Pipeline::InitializeVideoDecoder( | |
| 1090 const scoped_refptr<Demuxer>& demuxer) { | |
| 1091 DCHECK(message_loop_->BelongsToCurrentThread()); | |
| 1092 DCHECK(IsPipelineOk()); | |
| 1093 DCHECK(demuxer); | |
| 1094 | |
| 1095 scoped_refptr<DemuxerStream> stream = | |
| 1096 demuxer->GetStream(DemuxerStream::VIDEO); | |
| 1097 | |
| 1098 if (!stream) | |
| 1099 return false; | |
| 1100 | |
| 1101 filter_collection_->SelectVideoDecoder(&pipeline_init_state_->video_decoder); | |
| 1102 | |
| 1103 if (!pipeline_init_state_->video_decoder) { | |
| 1104 SetError(PIPELINE_ERROR_REQUIRED_FILTER_MISSING); | |
| 1105 return false; | |
| 1106 } | |
| 1107 | |
| 1108 pipeline_init_state_->video_decoder->Initialize( | |
| 1109 stream, | |
| 1110 base::Bind(&Pipeline::OnFilterInitialize, this), | |
| 1111 base::Bind(&Pipeline::OnUpdateStatistics, this)); | |
| 1112 | |
| 1113 video_decoder_ = pipeline_init_state_->video_decoder; | |
| 1114 return true; | |
| 1115 } | |
| 1116 | |
| 1117 bool Pipeline::InitializeAudioRenderer( | 1070 bool Pipeline::InitializeAudioRenderer( |
| 1118 const scoped_refptr<AudioDecoder>& decoder) { | 1071 const scoped_refptr<AudioDecoder>& decoder) { |
| 1119 DCHECK(message_loop_->BelongsToCurrentThread()); | 1072 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 1120 DCHECK(IsPipelineOk()); | 1073 DCHECK(IsPipelineOk()); |
| 1121 | 1074 |
| 1122 if (!decoder) | 1075 if (!decoder) |
| 1123 return false; | 1076 return false; |
| 1124 | 1077 |
| 1125 filter_collection_->SelectAudioRenderer(&audio_renderer_); | 1078 filter_collection_->SelectAudioRenderer(&audio_renderer_); |
| 1126 if (!audio_renderer_) { | 1079 if (!audio_renderer_) { |
| 1127 SetError(PIPELINE_ERROR_REQUIRED_FILTER_MISSING); | 1080 SetError(PIPELINE_ERROR_REQUIRED_FILTER_MISSING); |
| 1128 return false; | 1081 return false; |
| 1129 } | 1082 } |
| 1130 | 1083 |
| 1131 audio_renderer_->Initialize( | 1084 audio_renderer_->Initialize( |
| 1132 decoder, | 1085 decoder, |
| 1133 base::Bind(&Pipeline::OnFilterInitialize, this), | 1086 base::Bind(&Pipeline::OnFilterInitialize, this), |
| 1134 base::Bind(&Pipeline::OnAudioUnderflow, this), | 1087 base::Bind(&Pipeline::OnAudioUnderflow, this), |
| 1135 base::Bind(&Pipeline::OnAudioTimeUpdate, this), | 1088 base::Bind(&Pipeline::OnAudioTimeUpdate, this), |
| 1136 base::Bind(&Pipeline::OnRendererEnded, this), | 1089 base::Bind(&Pipeline::OnRendererEnded, this), |
| 1137 base::Bind(&Pipeline::OnAudioDisabled, this), | 1090 base::Bind(&Pipeline::OnAudioDisabled, this), |
| 1138 base::Bind(&Pipeline::SetError, this)); | 1091 base::Bind(&Pipeline::SetError, this)); |
| 1139 return true; | 1092 return true; |
| 1140 } | 1093 } |
| 1141 | 1094 |
| 1142 bool Pipeline::InitializeVideoRenderer( | 1095 bool Pipeline::InitializeVideoRenderer( |
| 1143 const scoped_refptr<VideoDecoder>& decoder) { | 1096 const scoped_refptr<DemuxerStream>& stream) { |
| 1144 DCHECK(message_loop_->BelongsToCurrentThread()); | 1097 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 1145 DCHECK(IsPipelineOk()); | 1098 DCHECK(IsPipelineOk()); |
| 1146 | 1099 |
| 1147 if (!decoder) | 1100 if (!stream) |
| 1148 return false; | 1101 return false; |
| 1149 | 1102 |
| 1150 filter_collection_->SelectVideoRenderer(&video_renderer_); | 1103 filter_collection_->SelectVideoRenderer(&video_renderer_); |
| 1151 if (!video_renderer_) { | 1104 if (!video_renderer_) { |
| 1152 SetError(PIPELINE_ERROR_REQUIRED_FILTER_MISSING); | 1105 SetError(PIPELINE_ERROR_REQUIRED_FILTER_MISSING); |
| 1153 return false; | 1106 return false; |
| 1154 } | 1107 } |
| 1155 | 1108 |
| 1156 video_renderer_->Initialize( | 1109 video_renderer_->Initialize( |
| 1157 decoder, | 1110 stream, |
| 1111 filter_collection_->GetVideoDecoders(), | |
| 1158 base::Bind(&Pipeline::OnFilterInitialize, this), | 1112 base::Bind(&Pipeline::OnFilterInitialize, this), |
| 1159 base::Bind(&Pipeline::OnUpdateStatistics, this), | 1113 base::Bind(&Pipeline::OnUpdateStatistics, this), |
| 1160 base::Bind(&Pipeline::OnVideoTimeUpdate, this), | 1114 base::Bind(&Pipeline::OnVideoTimeUpdate, this), |
| 1161 base::Bind(&Pipeline::OnNaturalVideoSizeChanged, this), | 1115 base::Bind(&Pipeline::OnNaturalVideoSizeChanged, this), |
| 1162 base::Bind(&Pipeline::OnRendererEnded, this), | 1116 base::Bind(&Pipeline::OnRendererEnded, this), |
| 1163 base::Bind(&Pipeline::SetError, this), | 1117 base::Bind(&Pipeline::SetError, this), |
| 1164 base::Bind(&Pipeline::GetMediaTime, this), | 1118 base::Bind(&Pipeline::GetMediaTime, this), |
| 1165 base::Bind(&Pipeline::GetMediaDuration, this)); | 1119 base::Bind(&Pipeline::GetMediaDuration, this)); |
| 1120 filter_collection_->GetVideoDecoders().clear(); | |
| 1166 return true; | 1121 return true; |
| 1167 } | 1122 } |
| 1168 | 1123 |
| 1169 void Pipeline::TearDownPipeline() { | 1124 void Pipeline::TearDownPipeline() { |
| 1170 DCHECK(message_loop_->BelongsToCurrentThread()); | 1125 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 1171 DCHECK_NE(kStopped, state_); | 1126 DCHECK_NE(kStopped, state_); |
| 1172 | 1127 |
| 1173 DCHECK(!tearing_down_ || // Teardown on Stop(). | 1128 DCHECK(!tearing_down_ || // Teardown on Stop(). |
| 1174 (tearing_down_ && error_caused_teardown_) || // Teardown on error. | 1129 (tearing_down_ && error_caused_teardown_) || // Teardown on error. |
| 1175 (tearing_down_ && stop_pending_)); // Stop during teardown by error. | 1130 (tearing_down_ && stop_pending_)); // Stop during teardown by error. |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 1186 SetState(kStopped); | 1141 SetState(kStopped); |
| 1187 // Need to put this in the message loop to make sure that it comes | 1142 // Need to put this in the message loop to make sure that it comes |
| 1188 // after any pending callback tasks that are already queued. | 1143 // after any pending callback tasks that are already queued. |
| 1189 message_loop_->PostTask(FROM_HERE, base::Bind( | 1144 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 1190 &Pipeline::FinishDestroyingFiltersTask, this)); | 1145 &Pipeline::FinishDestroyingFiltersTask, this)); |
| 1191 break; | 1146 break; |
| 1192 | 1147 |
| 1193 case kInitDemuxer: | 1148 case kInitDemuxer: |
| 1194 case kInitAudioDecoder: | 1149 case kInitAudioDecoder: |
| 1195 case kInitAudioRenderer: | 1150 case kInitAudioRenderer: |
| 1196 case kInitVideoDecoder: | |
| 1197 case kInitVideoRenderer: | 1151 case kInitVideoRenderer: |
| 1198 // Make it look like initialization was successful. | 1152 // Make it look like initialization was successful. |
| 1199 filter_collection_.reset(); | 1153 filter_collection_.reset(); |
| 1200 pipeline_init_state_.reset(); | 1154 pipeline_init_state_.reset(); |
| 1201 | 1155 |
| 1202 SetState(kStopping); | 1156 SetState(kStopping); |
| 1203 DoStop(base::Bind(&Pipeline::OnTeardownStateTransition, this)); | 1157 DoStop(base::Bind(&Pipeline::OnTeardownStateTransition, this)); |
| 1204 | 1158 |
| 1205 FinishInitialization(); | 1159 FinishInitialization(); |
| 1206 break; | 1160 break; |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1276 void Pipeline::StartClockIfWaitingForTimeUpdate_Locked() { | 1230 void Pipeline::StartClockIfWaitingForTimeUpdate_Locked() { |
| 1277 lock_.AssertAcquired(); | 1231 lock_.AssertAcquired(); |
| 1278 if (!waiting_for_clock_update_) | 1232 if (!waiting_for_clock_update_) |
| 1279 return; | 1233 return; |
| 1280 | 1234 |
| 1281 waiting_for_clock_update_ = false; | 1235 waiting_for_clock_update_ = false; |
| 1282 clock_->Play(); | 1236 clock_->Play(); |
| 1283 } | 1237 } |
| 1284 | 1238 |
| 1285 } // namespace media | 1239 } // namespace media |
| OLD | NEW |