| 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 |