Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(202)

Side by Side Diff: media/base/pipeline_impl.cc

Issue 8399023: Fire canplaythrough event at the proper time for audio/video (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: . Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « media/base/pipeline_impl.h ('k') | media/filters/chunk_demuxer.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « media/base/pipeline_impl.h ('k') | media/filters/chunk_demuxer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698