OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 // TODO(scherkus): clean up PipelineImpl... too many crazy function names, | 5 // TODO(scherkus): clean up PipelineImpl... too many crazy function names, |
6 // potential deadlocks, etc... | 6 // potential deadlocks, etc... |
7 | 7 |
8 #include "media/base/pipeline_impl.h" | 8 #include "media/base/pipeline_impl.h" |
9 | 9 |
10 #include <algorithm> | 10 #include <algorithm> |
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
136 } | 136 } |
137 | 137 |
138 void PipelineImpl::Seek(base::TimeDelta time, | 138 void PipelineImpl::Seek(base::TimeDelta time, |
139 const PipelineStatusCB& seek_callback) { | 139 const PipelineStatusCB& seek_callback) { |
140 base::AutoLock auto_lock(lock_); | 140 base::AutoLock auto_lock(lock_); |
141 if (!running_) { | 141 if (!running_) { |
142 VLOG(1) << "Media pipeline must be running"; | 142 VLOG(1) << "Media pipeline must be running"; |
143 return; | 143 return; |
144 } | 144 } |
145 | 145 |
| 146 download_rate_monitor_.Stop(); |
| 147 |
146 message_loop_->PostTask(FROM_HERE, | 148 message_loop_->PostTask(FROM_HERE, |
147 base::Bind(&PipelineImpl::SeekTask, this, time, seek_callback)); | 149 base::Bind(&PipelineImpl::SeekTask, this, time, seek_callback)); |
148 } | 150 } |
149 | 151 |
150 bool PipelineImpl::IsRunning() const { | 152 bool PipelineImpl::IsRunning() const { |
151 base::AutoLock auto_lock(lock_); | 153 base::AutoLock auto_lock(lock_); |
152 return running_; | 154 return running_; |
153 } | 155 } |
154 | 156 |
155 bool PipelineImpl::IsInitialized() const { | 157 bool PipelineImpl::IsInitialized() const { |
(...skipping 23 matching lines...) Expand all Loading... |
179 base::AutoLock auto_lock(lock_); | 181 base::AutoLock auto_lock(lock_); |
180 return has_video_; | 182 return has_video_; |
181 } | 183 } |
182 | 184 |
183 float PipelineImpl::GetPlaybackRate() const { | 185 float PipelineImpl::GetPlaybackRate() const { |
184 base::AutoLock auto_lock(lock_); | 186 base::AutoLock auto_lock(lock_); |
185 return playback_rate_; | 187 return playback_rate_; |
186 } | 188 } |
187 | 189 |
188 void PipelineImpl::SetPlaybackRate(float playback_rate) { | 190 void PipelineImpl::SetPlaybackRate(float playback_rate) { |
189 if (playback_rate < 0.0f) { | 191 if (playback_rate < 0.0f) |
190 return; | 192 return; |
191 } | |
192 | 193 |
193 base::AutoLock auto_lock(lock_); | 194 base::AutoLock auto_lock(lock_); |
194 playback_rate_ = playback_rate; | 195 playback_rate_ = playback_rate; |
195 if (running_ && !tearing_down_) { | 196 if (running_ && !tearing_down_) { |
196 message_loop_->PostTask(FROM_HERE, base::Bind( | 197 message_loop_->PostTask(FROM_HERE, base::Bind( |
197 &PipelineImpl::PlaybackRateChangedTask, this, playback_rate)); | 198 &PipelineImpl::PlaybackRateChangedTask, this, playback_rate)); |
198 } | 199 } |
199 } | 200 } |
200 | 201 |
201 float PipelineImpl::GetVolume() const { | 202 float PipelineImpl::GetVolume() const { |
202 base::AutoLock auto_lock(lock_); | 203 base::AutoLock auto_lock(lock_); |
203 return volume_; | 204 return volume_; |
204 } | 205 } |
205 | 206 |
206 void PipelineImpl::SetVolume(float volume) { | 207 void PipelineImpl::SetVolume(float volume) { |
207 if (volume < 0.0f || volume > 1.0f) { | 208 if (volume < 0.0f || volume > 1.0f) |
208 return; | 209 return; |
209 } | |
210 | 210 |
211 base::AutoLock auto_lock(lock_); | 211 base::AutoLock auto_lock(lock_); |
212 volume_ = volume; | 212 volume_ = volume; |
213 if (running_ && !tearing_down_) { | 213 if (running_ && !tearing_down_) { |
214 message_loop_->PostTask(FROM_HERE, base::Bind( | 214 message_loop_->PostTask(FROM_HERE, base::Bind( |
215 &PipelineImpl::VolumeChangedTask, this, volume)); | 215 &PipelineImpl::VolumeChangedTask, this, volume)); |
216 } | 216 } |
217 } | 217 } |
218 | 218 |
219 Preload PipelineImpl::GetPreload() const { | 219 Preload PipelineImpl::GetPreload() const { |
(...skipping 12 matching lines...) Expand all Loading... |
232 | 232 |
233 base::TimeDelta PipelineImpl::GetCurrentTime() const { | 233 base::TimeDelta PipelineImpl::GetCurrentTime() const { |
234 // TODO(scherkus): perhaps replace checking state_ == kEnded with a bool that | 234 // TODO(scherkus): perhaps replace checking state_ == kEnded with a bool that |
235 // is set/get under the lock, because this is breaching the contract that | 235 // is set/get under the lock, because this is breaching the contract that |
236 // |state_| is only accessed on |message_loop_|. | 236 // |state_| is only accessed on |message_loop_|. |
237 base::AutoLock auto_lock(lock_); | 237 base::AutoLock auto_lock(lock_); |
238 return GetCurrentTime_Locked(); | 238 return GetCurrentTime_Locked(); |
239 } | 239 } |
240 | 240 |
241 base::TimeDelta PipelineImpl::GetCurrentTime_Locked() const { | 241 base::TimeDelta PipelineImpl::GetCurrentTime_Locked() const { |
| 242 lock_.AssertAcquired(); |
242 base::TimeDelta elapsed = clock_->Elapsed(); | 243 base::TimeDelta elapsed = clock_->Elapsed(); |
243 if (state_ == kEnded || elapsed > duration_) { | 244 if (state_ == kEnded || elapsed > duration_) { |
244 return duration_; | 245 return duration_; |
245 } | 246 } |
246 return elapsed; | 247 return elapsed; |
247 } | 248 } |
248 | 249 |
249 base::TimeDelta PipelineImpl::GetBufferedTime() { | 250 base::TimeDelta PipelineImpl::GetBufferedTime() { |
250 base::AutoLock auto_lock(lock_); | 251 base::AutoLock auto_lock(lock_); |
251 | 252 |
252 // If media is fully loaded, then return duration. | 253 // If media is fully loaded, then return duration. |
253 if (loaded_ || total_bytes_ == buffered_bytes_) { | 254 if (loaded_ || total_bytes_ == buffered_bytes_) { |
254 max_buffered_time_ = duration_; | 255 max_buffered_time_ = duration_; |
255 return duration_; | 256 return duration_; |
256 } | 257 } |
257 | 258 |
258 base::TimeDelta current_time = GetCurrentTime_Locked(); | 259 base::TimeDelta current_time = GetCurrentTime_Locked(); |
259 | 260 |
260 // If buffered time was set, we report that value directly. | 261 // If buffered time was set, we report that value directly. |
261 if (buffered_time_.ToInternalValue() > 0) { | 262 if (buffered_time_.ToInternalValue() > 0) |
262 return std::max(buffered_time_, current_time); | 263 return std::max(buffered_time_, current_time); |
263 } | |
264 | 264 |
265 if (total_bytes_ == 0) | 265 if (total_bytes_ == 0) |
266 return base::TimeDelta(); | 266 return base::TimeDelta(); |
267 | 267 |
268 // If buffered time was not set, we use current time, current bytes, and | 268 // If buffered time was not set, we use current time, current bytes, and |
269 // buffered bytes to estimate the buffered time. | 269 // buffered bytes to estimate the buffered time. |
270 double estimated_rate = duration_.InMillisecondsF() / total_bytes_; | 270 double estimated_rate = duration_.InMillisecondsF() / total_bytes_; |
271 double estimated_current_time = estimated_rate * current_bytes_; | 271 double estimated_current_time = estimated_rate * current_bytes_; |
272 DCHECK_GE(buffered_bytes_, current_bytes_); | 272 DCHECK_GE(buffered_bytes_, current_bytes_); |
273 base::TimeDelta buffered_time = base::TimeDelta::FromMilliseconds( | 273 base::TimeDelta buffered_time = base::TimeDelta::FromMilliseconds( |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
364 volume_ = 1.0f; | 364 volume_ = 1.0f; |
365 preload_ = AUTO; | 365 preload_ = AUTO; |
366 playback_rate_ = 0.0f; | 366 playback_rate_ = 0.0f; |
367 pending_playback_rate_ = 0.0f; | 367 pending_playback_rate_ = 0.0f; |
368 status_ = PIPELINE_OK; | 368 status_ = PIPELINE_OK; |
369 has_audio_ = false; | 369 has_audio_ = false; |
370 has_video_ = false; | 370 has_video_ = false; |
371 waiting_for_clock_update_ = false; | 371 waiting_for_clock_update_ = false; |
372 audio_disabled_ = false; | 372 audio_disabled_ = false; |
373 clock_->SetTime(kZero); | 373 clock_->SetTime(kZero); |
| 374 download_rate_monitor_.Reset(); |
374 } | 375 } |
375 | 376 |
376 void PipelineImpl::SetState(State next_state) { | 377 void PipelineImpl::SetState(State next_state) { |
377 if (state_ != kStarted && next_state == kStarted && | 378 if (state_ != kStarted && next_state == kStarted && |
378 !creation_time_.is_null()) { | 379 !creation_time_.is_null()) { |
379 UMA_HISTOGRAM_TIMES( | 380 UMA_HISTOGRAM_TIMES( |
380 "Media.TimeToPipelineStarted", base::Time::Now() - creation_time_); | 381 "Media.TimeToPipelineStarted", base::Time::Now() - creation_time_); |
381 creation_time_ = base::Time(); | 382 creation_time_ = base::Time(); |
382 } | 383 } |
383 state_ = next_state; | 384 state_ = next_state; |
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
517 media_log_->CreateIntegerEvent( | 518 media_log_->CreateIntegerEvent( |
518 MediaLogEvent::TOTAL_BYTES_SET, "total_bytes", total_bytes)); | 519 MediaLogEvent::TOTAL_BYTES_SET, "total_bytes", total_bytes)); |
519 int64 total_mbytes = total_bytes >> 20; | 520 int64 total_mbytes = total_bytes >> 20; |
520 if (total_mbytes > kint32max) | 521 if (total_mbytes > kint32max) |
521 total_mbytes = kint32max; | 522 total_mbytes = kint32max; |
522 UMA_HISTOGRAM_CUSTOM_COUNTS( | 523 UMA_HISTOGRAM_CUSTOM_COUNTS( |
523 "Media.TotalMBytes", static_cast<int32>(total_mbytes), 1, kint32max, 50); | 524 "Media.TotalMBytes", static_cast<int32>(total_mbytes), 1, kint32max, 50); |
524 | 525 |
525 base::AutoLock auto_lock(lock_); | 526 base::AutoLock auto_lock(lock_); |
526 total_bytes_ = total_bytes; | 527 total_bytes_ = total_bytes; |
| 528 download_rate_monitor_.set_total_bytes(total_bytes_); |
527 } | 529 } |
528 | 530 |
529 void PipelineImpl::SetBufferedBytes(int64 buffered_bytes) { | 531 void PipelineImpl::SetBufferedBytes(int64 buffered_bytes) { |
530 DCHECK(IsRunning()); | 532 DCHECK(IsRunning()); |
531 base::AutoLock auto_lock(lock_); | 533 base::AutoLock auto_lock(lock_); |
532 | |
533 // See comments in SetCurrentReadPosition() about capping. | 534 // See comments in SetCurrentReadPosition() about capping. |
534 if (buffered_bytes < current_bytes_) | 535 if (buffered_bytes < current_bytes_) |
535 current_bytes_ = buffered_bytes; | 536 current_bytes_ = buffered_bytes; |
536 buffered_bytes_ = buffered_bytes; | 537 buffered_bytes_ = buffered_bytes; |
| 538 download_rate_monitor_.SetBufferedBytes(buffered_bytes, base::Time::Now()); |
537 } | 539 } |
538 | 540 |
539 void PipelineImpl::SetNaturalVideoSize(const gfx::Size& size) { | 541 void PipelineImpl::SetNaturalVideoSize(const gfx::Size& size) { |
540 DCHECK(IsRunning()); | 542 DCHECK(IsRunning()); |
541 media_log_->AddEvent(media_log_->CreateVideoSizeSetEvent( | 543 media_log_->AddEvent(media_log_->CreateVideoSizeSetEvent( |
542 size.width(), size.height())); | 544 size.width(), size.height())); |
543 | 545 |
544 base::AutoLock auto_lock(lock_); | 546 base::AutoLock auto_lock(lock_); |
545 natural_size_ = size; | 547 natural_size_ = size; |
546 } | 548 } |
(...skipping 16 matching lines...) Expand all Loading... |
563 } | 565 } |
564 | 566 |
565 void PipelineImpl::SetLoaded(bool loaded) { | 567 void PipelineImpl::SetLoaded(bool loaded) { |
566 DCHECK(IsRunning()); | 568 DCHECK(IsRunning()); |
567 media_log_->AddEvent( | 569 media_log_->AddEvent( |
568 media_log_->CreateBooleanEvent( | 570 media_log_->CreateBooleanEvent( |
569 MediaLogEvent::LOADED_SET, "loaded", loaded)); | 571 MediaLogEvent::LOADED_SET, "loaded", loaded)); |
570 | 572 |
571 base::AutoLock auto_lock(lock_); | 573 base::AutoLock auto_lock(lock_); |
572 loaded_ = loaded; | 574 loaded_ = loaded; |
| 575 download_rate_monitor_.set_loaded(loaded_); |
573 } | 576 } |
574 | 577 |
575 void PipelineImpl::SetNetworkActivity(bool is_downloading_data) { | 578 void PipelineImpl::SetNetworkActivity(bool is_downloading_data) { |
576 DCHECK(IsRunning()); | 579 DCHECK(IsRunning()); |
| 580 |
| 581 NetworkEvent type = DOWNLOAD_PAUSED; |
| 582 if (is_downloading_data) |
| 583 type = DOWNLOAD_CONTINUED; |
| 584 |
| 585 { |
| 586 base::AutoLock auto_lock(lock_); |
| 587 download_rate_monitor_.SetNetworkActivity(is_downloading_data); |
| 588 } |
| 589 |
577 message_loop_->PostTask(FROM_HERE, | 590 message_loop_->PostTask(FROM_HERE, |
578 base::Bind( | 591 base::Bind( |
579 &PipelineImpl::NotifyNetworkEventTask, this, is_downloading_data)); | 592 &PipelineImpl::NotifyNetworkEventTask, this, type)); |
580 media_log_->AddEvent( | 593 media_log_->AddEvent( |
581 media_log_->CreateBooleanEvent( | 594 media_log_->CreateBooleanEvent( |
582 MediaLogEvent::NETWORK_ACTIVITY_SET, | 595 MediaLogEvent::NETWORK_ACTIVITY_SET, |
583 "is_downloading_data", is_downloading_data)); | 596 "is_downloading_data", is_downloading_data)); |
584 } | 597 } |
585 | 598 |
586 void PipelineImpl::DisableAudioRenderer() { | 599 void PipelineImpl::DisableAudioRenderer() { |
587 DCHECK(IsRunning()); | 600 DCHECK(IsRunning()); |
588 | 601 |
589 // Disable renderer on the message loop. | 602 // Disable renderer on the message loop. |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
675 // If we have received the stop or error signal, return immediately. | 688 // If we have received the stop or error signal, return immediately. |
676 if (IsPipelineStopPending() || IsPipelineStopped() || !IsPipelineOk()) | 689 if (IsPipelineStopPending() || IsPipelineStopped() || !IsPipelineOk()) |
677 return; | 690 return; |
678 | 691 |
679 DCHECK(state_ == kInitDemuxer || | 692 DCHECK(state_ == kInitDemuxer || |
680 state_ == kInitAudioDecoder || | 693 state_ == kInitAudioDecoder || |
681 state_ == kInitAudioRenderer || | 694 state_ == kInitAudioRenderer || |
682 state_ == kInitVideoDecoder || | 695 state_ == kInitVideoDecoder || |
683 state_ == kInitVideoRenderer); | 696 state_ == kInitVideoRenderer); |
684 | 697 |
685 | |
686 // Demuxer created, create audio decoder. | 698 // Demuxer created, create audio decoder. |
687 if (state_ == kInitDemuxer) { | 699 if (state_ == kInitDemuxer) { |
688 SetState(kInitAudioDecoder); | 700 SetState(kInitAudioDecoder); |
689 // If this method returns false, then there's no audio stream. | 701 // If this method returns false, then there's no audio stream. |
690 if (InitializeAudioDecoder(demuxer_)) | 702 if (InitializeAudioDecoder(demuxer_)) |
691 return; | 703 return; |
692 } | 704 } |
693 | 705 |
694 // Assuming audio decoder was created, create audio renderer. | 706 // Assuming audio decoder was created, create audio renderer. |
695 if (state_ == kInitAudioDecoder) { | 707 if (state_ == kInitAudioDecoder) { |
(...skipping 237 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
933 return; | 945 return; |
934 } | 946 } |
935 | 947 |
936 // Transition to ended, executing the callback if present. | 948 // Transition to ended, executing the callback if present. |
937 SetState(kEnded); | 949 SetState(kEnded); |
938 if (!ended_callback_.is_null()) { | 950 if (!ended_callback_.is_null()) { |
939 ended_callback_.Run(status_); | 951 ended_callback_.Run(status_); |
940 } | 952 } |
941 } | 953 } |
942 | 954 |
943 void PipelineImpl::NotifyNetworkEventTask(bool is_downloading_data) { | 955 void PipelineImpl::NotifyNetworkEventTask(NetworkEvent type) { |
944 DCHECK_EQ(MessageLoop::current(), message_loop_); | 956 DCHECK_EQ(MessageLoop::current(), message_loop_); |
945 if (!network_callback_.is_null()) | 957 if (!network_callback_.is_null()) |
946 network_callback_.Run(is_downloading_data); | 958 network_callback_.Run(type); |
947 } | 959 } |
948 | 960 |
949 void PipelineImpl::DisableAudioRendererTask() { | 961 void PipelineImpl::DisableAudioRendererTask() { |
950 DCHECK_EQ(MessageLoop::current(), message_loop_); | 962 DCHECK_EQ(MessageLoop::current(), message_loop_); |
951 | 963 |
952 base::AutoLock auto_lock(lock_); | 964 base::AutoLock auto_lock(lock_); |
953 has_audio_ = false; | 965 has_audio_ = false; |
954 audio_disabled_ = true; | 966 audio_disabled_ = true; |
955 | 967 |
956 // Notify all filters of disabled audio renderer. If the filter isn't | 968 // Notify all filters of disabled audio renderer. If the filter isn't |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1023 PlaybackRateChangedTask(pending_playback_rate_); | 1035 PlaybackRateChangedTask(pending_playback_rate_); |
1024 } | 1036 } |
1025 | 1037 |
1026 base::AutoLock auto_lock(lock_); | 1038 base::AutoLock auto_lock(lock_); |
1027 // We use audio stream to update the clock. So if there is such a stream, | 1039 // We use audio stream to update the clock. So if there is such a stream, |
1028 // we pause the clock until we receive a valid timestamp. | 1040 // we pause the clock until we receive a valid timestamp. |
1029 waiting_for_clock_update_ = has_audio_; | 1041 waiting_for_clock_update_ = has_audio_; |
1030 if (!waiting_for_clock_update_) | 1042 if (!waiting_for_clock_update_) |
1031 clock_->Play(); | 1043 clock_->Play(); |
1032 | 1044 |
| 1045 // Start monitoring rate of downloading. |
| 1046 int bitrate = 0; |
| 1047 if (demuxer_.get()) |
| 1048 bitrate = demuxer_->GetBitrate(); |
| 1049 // Needs to be locked because most other calls to |download_rate_monitor_| |
| 1050 // occur on the renderer thread. |
| 1051 download_rate_monitor_.Start( |
| 1052 base::Bind(&PipelineImpl::OnCanPlayThrough, this), bitrate); |
| 1053 download_rate_monitor_.SetBufferedBytes(buffered_bytes_, base::Time::Now()); |
| 1054 |
1033 if (IsPipelineStopPending()) { | 1055 if (IsPipelineStopPending()) { |
1034 // We had a pending stop request need to be honored right now. | 1056 // We had a pending stop request need to be honored right now. |
1035 TearDownPipeline(); | 1057 TearDownPipeline(); |
1036 } | 1058 } |
1037 } else { | 1059 } else { |
1038 NOTREACHED() << "Unexpected state: " << state_; | 1060 NOTREACHED() << "Unexpected state: " << state_; |
1039 } | 1061 } |
1040 } | 1062 } |
1041 | 1063 |
1042 void PipelineImpl::TeardownStateTransitionTask() { | 1064 void PipelineImpl::TeardownStateTransitionTask() { |
(...skipping 355 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1398 return; | 1420 return; |
1399 } | 1421 } |
1400 | 1422 |
1401 if (state_ != kStarted) | 1423 if (state_ != kStarted) |
1402 return; | 1424 return; |
1403 | 1425 |
1404 if (audio_renderer_) | 1426 if (audio_renderer_) |
1405 audio_renderer_->ResumeAfterUnderflow(true); | 1427 audio_renderer_->ResumeAfterUnderflow(true); |
1406 } | 1428 } |
1407 | 1429 |
| 1430 void PipelineImpl::OnCanPlayThrough() { |
| 1431 message_loop_->PostTask(FROM_HERE, |
| 1432 base::Bind(&PipelineImpl::NotifyCanPlayThrough, this)); |
| 1433 } |
| 1434 |
| 1435 void PipelineImpl::NotifyCanPlayThrough() { |
| 1436 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 1437 NotifyNetworkEventTask(CAN_PLAY_THROUGH); |
| 1438 } |
| 1439 |
1408 } // namespace media | 1440 } // namespace media |
OLD | NEW |