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

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: Rebase and minor fix 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
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 168 matching lines...) Expand 10 before | Expand all | Expand 10 after
179 base::AutoLock auto_lock(lock_); 179 base::AutoLock auto_lock(lock_);
180 return has_video_; 180 return has_video_;
181 } 181 }
182 182
183 float PipelineImpl::GetPlaybackRate() const { 183 float PipelineImpl::GetPlaybackRate() const {
184 base::AutoLock auto_lock(lock_); 184 base::AutoLock auto_lock(lock_);
185 return playback_rate_; 185 return playback_rate_;
186 } 186 }
187 187
188 void PipelineImpl::SetPlaybackRate(float playback_rate) { 188 void PipelineImpl::SetPlaybackRate(float playback_rate) {
189 if (playback_rate < 0.0f) { 189 if (playback_rate < 0.0f)
190 return; 190 return;
191 }
192 191
193 base::AutoLock auto_lock(lock_); 192 base::AutoLock auto_lock(lock_);
194 playback_rate_ = playback_rate; 193 playback_rate_ = playback_rate;
195 if (running_ && !tearing_down_) { 194 if (running_ && !tearing_down_) {
196 message_loop_->PostTask(FROM_HERE, base::Bind( 195 message_loop_->PostTask(FROM_HERE, base::Bind(
197 &PipelineImpl::PlaybackRateChangedTask, this, playback_rate)); 196 &PipelineImpl::PlaybackRateChangedTask, this, playback_rate));
198 } 197 }
199 } 198 }
200 199
201 float PipelineImpl::GetVolume() const { 200 float PipelineImpl::GetVolume() const {
202 base::AutoLock auto_lock(lock_); 201 base::AutoLock auto_lock(lock_);
203 return volume_; 202 return volume_;
204 } 203 }
205 204
206 void PipelineImpl::SetVolume(float volume) { 205 void PipelineImpl::SetVolume(float volume) {
207 if (volume < 0.0f || volume > 1.0f) { 206 if (volume < 0.0f || volume > 1.0f)
208 return; 207 return;
209 }
210 208
211 base::AutoLock auto_lock(lock_); 209 base::AutoLock auto_lock(lock_);
212 volume_ = volume; 210 volume_ = volume;
213 if (running_ && !tearing_down_) { 211 if (running_ && !tearing_down_) {
214 message_loop_->PostTask(FROM_HERE, base::Bind( 212 message_loop_->PostTask(FROM_HERE, base::Bind(
215 &PipelineImpl::VolumeChangedTask, this, volume)); 213 &PipelineImpl::VolumeChangedTask, this, volume));
216 } 214 }
217 } 215 }
218 216
219 Preload PipelineImpl::GetPreload() const { 217 Preload PipelineImpl::GetPreload() const {
(...skipping 12 matching lines...) Expand all
232 230
233 base::TimeDelta PipelineImpl::GetCurrentTime() const { 231 base::TimeDelta PipelineImpl::GetCurrentTime() const {
234 // TODO(scherkus): perhaps replace checking state_ == kEnded with a bool that 232 // 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 233 // is set/get under the lock, because this is breaching the contract that
236 // |state_| is only accessed on |message_loop_|. 234 // |state_| is only accessed on |message_loop_|.
237 base::AutoLock auto_lock(lock_); 235 base::AutoLock auto_lock(lock_);
238 return GetCurrentTime_Locked(); 236 return GetCurrentTime_Locked();
239 } 237 }
240 238
241 base::TimeDelta PipelineImpl::GetCurrentTime_Locked() const { 239 base::TimeDelta PipelineImpl::GetCurrentTime_Locked() const {
240 lock_.AssertAcquired();
242 base::TimeDelta elapsed = clock_->Elapsed(); 241 base::TimeDelta elapsed = clock_->Elapsed();
243 if (state_ == kEnded || elapsed > duration_) { 242 if (state_ == kEnded || elapsed > duration_) {
244 return duration_; 243 return duration_;
245 } 244 }
246 return elapsed; 245 return elapsed;
247 } 246 }
248 247
249 base::TimeDelta PipelineImpl::GetBufferedTime() { 248 base::TimeDelta PipelineImpl::GetBufferedTime() {
250 base::AutoLock auto_lock(lock_); 249 base::AutoLock auto_lock(lock_);
251 250
252 // If media is fully loaded, then return duration. 251 // If media is fully loaded, then return duration.
253 if (loaded_ || total_bytes_ == buffered_bytes_) { 252 if (loaded_ || total_bytes_ == buffered_bytes_) {
254 max_buffered_time_ = duration_; 253 max_buffered_time_ = duration_;
255 return duration_; 254 return duration_;
256 } 255 }
257 256
258 base::TimeDelta current_time = GetCurrentTime_Locked(); 257 base::TimeDelta current_time = GetCurrentTime_Locked();
259 258
260 // If buffered time was set, we report that value directly. 259 // If buffered time was set, we report that value directly.
261 if (buffered_time_.ToInternalValue() > 0) { 260 if (buffered_time_.ToInternalValue() > 0)
262 return std::max(buffered_time_, current_time); 261 return std::max(buffered_time_, current_time);
263 }
264 262
265 if (total_bytes_ == 0) 263 if (total_bytes_ == 0)
266 return base::TimeDelta(); 264 return base::TimeDelta();
267 265
268 // If buffered time was not set, we use current time, current bytes, and 266 // If buffered time was not set, we use current time, current bytes, and
269 // buffered bytes to estimate the buffered time. 267 // buffered bytes to estimate the buffered time.
270 double estimated_rate = duration_.InMillisecondsF() / total_bytes_; 268 double estimated_rate = duration_.InMillisecondsF() / total_bytes_;
271 double estimated_current_time = estimated_rate * current_bytes_; 269 double estimated_current_time = estimated_rate * current_bytes_;
272 DCHECK_GE(buffered_bytes_, current_bytes_); 270 DCHECK_GE(buffered_bytes_, current_bytes_);
273 base::TimeDelta buffered_time = base::TimeDelta::FromMilliseconds( 271 base::TimeDelta buffered_time = base::TimeDelta::FromMilliseconds(
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
364 volume_ = 1.0f; 362 volume_ = 1.0f;
365 preload_ = AUTO; 363 preload_ = AUTO;
366 playback_rate_ = 0.0f; 364 playback_rate_ = 0.0f;
367 pending_playback_rate_ = 0.0f; 365 pending_playback_rate_ = 0.0f;
368 status_ = PIPELINE_OK; 366 status_ = PIPELINE_OK;
369 has_audio_ = false; 367 has_audio_ = false;
370 has_video_ = false; 368 has_video_ = false;
371 waiting_for_clock_update_ = false; 369 waiting_for_clock_update_ = false;
372 audio_disabled_ = false; 370 audio_disabled_ = false;
373 clock_->SetTime(kZero); 371 clock_->SetTime(kZero);
372 is_downloading_data_ = false;
acolwell GONE FROM CHROMIUM 2011/11/09 00:50:22 Does download_rate_monitor_ need to be reset here?
vrk (LEFT CHROMIUM) 2011/11/11 02:51:06 Yes, done.
374 } 373 }
375 374
376 void PipelineImpl::SetState(State next_state) { 375 void PipelineImpl::SetState(State next_state) {
377 if (state_ != kStarted && next_state == kStarted && 376 if (state_ != kStarted && next_state == kStarted &&
378 !creation_time_.is_null()) { 377 !creation_time_.is_null()) {
379 UMA_HISTOGRAM_TIMES( 378 UMA_HISTOGRAM_TIMES(
380 "Media.TimeToPipelineStarted", base::Time::Now() - creation_time_); 379 "Media.TimeToPipelineStarted", base::Time::Now() - creation_time_);
381 creation_time_ = base::Time(); 380 creation_time_ = base::Time();
382 } 381 }
383 state_ = next_state; 382 state_ = next_state;
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
415 } 414 }
416 415
417 void PipelineImpl::FinishInitialization() { 416 void PipelineImpl::FinishInitialization() {
418 DCHECK_EQ(MessageLoop::current(), message_loop_); 417 DCHECK_EQ(MessageLoop::current(), message_loop_);
419 // Execute the seek callback, if present. Note that this might be the 418 // Execute the seek callback, if present. Note that this might be the
420 // initial callback passed into Start(). 419 // initial callback passed into Start().
421 if (!seek_callback_.is_null()) { 420 if (!seek_callback_.is_null()) {
422 seek_callback_.Run(status_); 421 seek_callback_.Run(status_);
423 seek_callback_.Reset(); 422 seek_callback_.Reset();
424 } 423 }
424
425 base::AutoLock auto_lock(lock_);
acolwell GONE FROM CHROMIUM 2011/11/09 00:50:22 This is neaded because the SetXXXBytes() calls are
vrk (LEFT CHROMIUM) 2011/11/11 02:51:06 Actually the SetXXXBytes method calls (and SetLoad
426 int bitrate = 0;
427 if (demuxer_.get())
428 bitrate = demuxer_->GetBitrate();
429 download_rate_monitor_.Start(
430 base::Bind(&PipelineImpl::OnCanPlayThrough, this), bitrate);
425 } 431 }
426 432
427 // static 433 // static
428 bool PipelineImpl::TransientState(State state) { 434 bool PipelineImpl::TransientState(State state) {
429 return state == kPausing || 435 return state == kPausing ||
430 state == kFlushing || 436 state == kFlushing ||
431 state == kSeeking || 437 state == kSeeking ||
432 state == kStarting || 438 state == kStarting ||
433 state == kStopping; 439 state == kStopping;
434 } 440 }
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
517 media_log_->CreateIntegerEvent( 523 media_log_->CreateIntegerEvent(
518 MediaLogEvent::TOTAL_BYTES_SET, "total_bytes", total_bytes)); 524 MediaLogEvent::TOTAL_BYTES_SET, "total_bytes", total_bytes));
519 int64 total_mbytes = total_bytes >> 20; 525 int64 total_mbytes = total_bytes >> 20;
520 if (total_mbytes > kint32max) 526 if (total_mbytes > kint32max)
521 total_mbytes = kint32max; 527 total_mbytes = kint32max;
522 UMA_HISTOGRAM_CUSTOM_COUNTS( 528 UMA_HISTOGRAM_CUSTOM_COUNTS(
523 "Media.TotalMBytes", static_cast<int32>(total_mbytes), 1, kint32max, 50); 529 "Media.TotalMBytes", static_cast<int32>(total_mbytes), 1, kint32max, 50);
524 530
525 base::AutoLock auto_lock(lock_); 531 base::AutoLock auto_lock(lock_);
526 total_bytes_ = total_bytes; 532 total_bytes_ = total_bytes;
533 download_rate_monitor_.SetTotalBytes(total_bytes_);
527 } 534 }
528 535
529 void PipelineImpl::SetBufferedBytes(int64 buffered_bytes) { 536 void PipelineImpl::SetBufferedBytes(int64 buffered_bytes) {
530 DCHECK(IsRunning()); 537 DCHECK(IsRunning());
531 base::AutoLock auto_lock(lock_); 538 base::AutoLock auto_lock(lock_);
532
533 // See comments in SetCurrentReadPosition() about capping. 539 // See comments in SetCurrentReadPosition() about capping.
534 if (buffered_bytes < current_bytes_) 540 if (buffered_bytes < current_bytes_)
535 current_bytes_ = buffered_bytes; 541 current_bytes_ = buffered_bytes;
536 buffered_bytes_ = buffered_bytes; 542 buffered_bytes_ = buffered_bytes;
543 download_rate_monitor_.SetBufferedBytes(buffered_bytes, base::Time::Now());
537 } 544 }
538 545
539 void PipelineImpl::SetNaturalVideoSize(const gfx::Size& size) { 546 void PipelineImpl::SetNaturalVideoSize(const gfx::Size& size) {
540 DCHECK(IsRunning()); 547 DCHECK(IsRunning());
541 media_log_->AddEvent(media_log_->CreateVideoSizeSetEvent( 548 media_log_->AddEvent(media_log_->CreateVideoSizeSetEvent(
542 size.width(), size.height())); 549 size.width(), size.height()));
543 550
544 base::AutoLock auto_lock(lock_); 551 base::AutoLock auto_lock(lock_);
545 natural_size_ = size; 552 natural_size_ = size;
546 } 553 }
(...skipping 16 matching lines...) Expand all
563 } 570 }
564 571
565 void PipelineImpl::SetLoaded(bool loaded) { 572 void PipelineImpl::SetLoaded(bool loaded) {
566 DCHECK(IsRunning()); 573 DCHECK(IsRunning());
567 media_log_->AddEvent( 574 media_log_->AddEvent(
568 media_log_->CreateBooleanEvent( 575 media_log_->CreateBooleanEvent(
569 MediaLogEvent::LOADED_SET, "loaded", loaded)); 576 MediaLogEvent::LOADED_SET, "loaded", loaded));
570 577
571 base::AutoLock auto_lock(lock_); 578 base::AutoLock auto_lock(lock_);
572 loaded_ = loaded; 579 loaded_ = loaded;
580 download_rate_monitor_.SetLoaded(loaded_);
573 } 581 }
574 582
575 void PipelineImpl::SetNetworkActivity(bool is_downloading_data) { 583 void PipelineImpl::SetNetworkActivity(bool is_downloading_data) {
576 DCHECK(IsRunning()); 584 DCHECK(IsRunning());
585
586 NetworkEvent type = DOWNLOAD_PAUSED;
587 if (is_downloading_data)
588 type = DOWNLOAD_CONTINUED;
589
590 {
591 base::AutoLock auto_lock(lock_);
592 download_rate_monitor_.SetNetworkActivity(is_downloading_data);
593 }
594
577 message_loop_->PostTask(FROM_HERE, 595 message_loop_->PostTask(FROM_HERE,
578 base::Bind( 596 base::Bind(
579 &PipelineImpl::NotifyNetworkEventTask, this, is_downloading_data)); 597 &PipelineImpl::NotifyNetworkEventTask, this, type,
598 is_downloading_data));
acolwell GONE FROM CHROMIUM 2011/11/09 00:50:22 Is is_downloading_data still needed given that it'
vrk (LEFT CHROMIUM) 2011/11/11 02:51:06 AH oops, you're right! It served a purpose when th
580 media_log_->AddEvent( 599 media_log_->AddEvent(
581 media_log_->CreateBooleanEvent( 600 media_log_->CreateBooleanEvent(
582 MediaLogEvent::NETWORK_ACTIVITY_SET, 601 MediaLogEvent::NETWORK_ACTIVITY_SET,
583 "is_downloading_data", is_downloading_data)); 602 "is_downloading_data", is_downloading_data));
584 } 603 }
585 604
586 void PipelineImpl::DisableAudioRenderer() { 605 void PipelineImpl::DisableAudioRenderer() {
587 DCHECK(IsRunning()); 606 DCHECK(IsRunning());
588 607
589 // Disable renderer on the message loop. 608 // 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. 694 // If we have received the stop or error signal, return immediately.
676 if (IsPipelineStopPending() || IsPipelineStopped() || !IsPipelineOk()) 695 if (IsPipelineStopPending() || IsPipelineStopped() || !IsPipelineOk())
677 return; 696 return;
678 697
679 DCHECK(state_ == kInitDemuxer || 698 DCHECK(state_ == kInitDemuxer ||
680 state_ == kInitAudioDecoder || 699 state_ == kInitAudioDecoder ||
681 state_ == kInitAudioRenderer || 700 state_ == kInitAudioRenderer ||
682 state_ == kInitVideoDecoder || 701 state_ == kInitVideoDecoder ||
683 state_ == kInitVideoRenderer); 702 state_ == kInitVideoRenderer);
684 703
685
686 // Demuxer created, create audio decoder. 704 // Demuxer created, create audio decoder.
687 if (state_ == kInitDemuxer) { 705 if (state_ == kInitDemuxer) {
688 SetState(kInitAudioDecoder); 706 SetState(kInitAudioDecoder);
689 // If this method returns false, then there's no audio stream. 707 // If this method returns false, then there's no audio stream.
690 if (InitializeAudioDecoder(demuxer_)) 708 if (InitializeAudioDecoder(demuxer_))
691 return; 709 return;
692 } 710 }
693 711
694 // Assuming audio decoder was created, create audio renderer. 712 // Assuming audio decoder was created, create audio renderer.
695 if (state_ == kInitAudioDecoder) { 713 if (state_ == kInitAudioDecoder) {
(...skipping 237 matching lines...) Expand 10 before | Expand all | Expand 10 after
933 return; 951 return;
934 } 952 }
935 953
936 // Transition to ended, executing the callback if present. 954 // Transition to ended, executing the callback if present.
937 SetState(kEnded); 955 SetState(kEnded);
938 if (!ended_callback_.is_null()) { 956 if (!ended_callback_.is_null()) {
939 ended_callback_.Run(status_); 957 ended_callback_.Run(status_);
940 } 958 }
941 } 959 }
942 960
943 void PipelineImpl::NotifyNetworkEventTask(bool is_downloading_data) { 961 void PipelineImpl::NotifyNetworkEventTask(NetworkEvent type,
962 bool is_downloading_data) {
944 DCHECK_EQ(MessageLoop::current(), message_loop_); 963 DCHECK_EQ(MessageLoop::current(), message_loop_);
964 is_downloading_data_ = is_downloading_data;
945 if (!network_callback_.is_null()) 965 if (!network_callback_.is_null())
946 network_callback_.Run(is_downloading_data); 966 network_callback_.Run(type);
947 } 967 }
948 968
949 void PipelineImpl::DisableAudioRendererTask() { 969 void PipelineImpl::DisableAudioRendererTask() {
950 DCHECK_EQ(MessageLoop::current(), message_loop_); 970 DCHECK_EQ(MessageLoop::current(), message_loop_);
951 971
952 base::AutoLock auto_lock(lock_); 972 base::AutoLock auto_lock(lock_);
953 has_audio_ = false; 973 has_audio_ = false;
954 audio_disabled_ = true; 974 audio_disabled_ = true;
955 975
956 // Notify all filters of disabled audio renderer. If the filter isn't 976 // Notify all filters of disabled audio renderer. If the filter isn't
(...skipping 441 matching lines...) Expand 10 before | Expand all | Expand 10 after
1398 return; 1418 return;
1399 } 1419 }
1400 1420
1401 if (state_ != kStarted) 1421 if (state_ != kStarted)
1402 return; 1422 return;
1403 1423
1404 if (audio_renderer_) 1424 if (audio_renderer_)
1405 audio_renderer_->ResumeAfterUnderflow(true); 1425 audio_renderer_->ResumeAfterUnderflow(true);
1406 } 1426 }
1407 1427
1428 void PipelineImpl::OnCanPlayThrough() {
1429 message_loop_->PostTask(FROM_HERE,
1430 base::Bind(
1431 &PipelineImpl::NotifyCanPlayThrough, this));
scherkus (not reviewing) 2011/11/09 02:55:15 nit: can put this on previous line
vrk (LEFT CHROMIUM) 2011/11/11 02:51:06 Done.
1432 }
1433
1434 void PipelineImpl::NotifyCanPlayThrough() {
1435 DCHECK_EQ(MessageLoop::current(), message_loop_);
1436 NotifyNetworkEventTask(CAN_PLAY_THROUGH, is_downloading_data_);
1437 }
1438
1408 } // namespace media 1439 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698