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

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

Issue 159517: Implemented a proper clock for audio/video synchronization. (Closed)
Patch Set: Now with convenience! Created 11 years, 4 months 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
« no previous file with comments | « media/base/pipeline_impl.h ('k') | media/filters/video_renderer_base.cc » ('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) 2008-2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2008-2009 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 "base/compiler_specific.h" 8 #include "base/compiler_specific.h"
9 #include "base/condition_variable.h" 9 #include "base/condition_variable.h"
10 #include "base/stl_util-inl.h" 10 #include "base/stl_util-inl.h"
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
66 CHECK(*count >= 0); 66 CHECK(*count >= 0);
67 if (*count == 0) { 67 if (*count == 0) {
68 cond_var->Signal(); 68 cond_var->Signal();
69 } 69 }
70 } 70 }
71 71
72 } // namespace 72 } // namespace
73 73
74 PipelineImpl::PipelineImpl(MessageLoop* message_loop) 74 PipelineImpl::PipelineImpl(MessageLoop* message_loop)
75 : message_loop_(message_loop), 75 : message_loop_(message_loop),
76 clock_(&base::Time::Now),
76 state_(kCreated), 77 state_(kCreated),
77 remaining_transitions_(0) { 78 remaining_transitions_(0) {
78 ResetState(); 79 ResetState();
79 } 80 }
80 81
81 PipelineImpl::~PipelineImpl() { 82 PipelineImpl::~PipelineImpl() {
82 AutoLock auto_lock(lock_); 83 AutoLock auto_lock(lock_);
83 DCHECK(!running_) << "Stop() must complete before destroying object"; 84 DCHECK(!running_) << "Stop() must complete before destroying object";
84 } 85 }
85 86
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after
194 volume_ = volume; 195 volume_ = volume;
195 if (running_) { 196 if (running_) {
196 message_loop_->PostTask(FROM_HERE, 197 message_loop_->PostTask(FROM_HERE,
197 NewRunnableMethod(this, &PipelineImpl::VolumeChangedTask, 198 NewRunnableMethod(this, &PipelineImpl::VolumeChangedTask,
198 volume)); 199 volume));
199 } 200 }
200 } 201 }
201 202
202 base::TimeDelta PipelineImpl::GetCurrentTime() const { 203 base::TimeDelta PipelineImpl::GetCurrentTime() const {
203 AutoLock auto_lock(lock_); 204 AutoLock auto_lock(lock_);
204 return time_; 205 return clock_.Elapsed();
205 } 206 }
206 207
207 base::TimeDelta PipelineImpl::GetBufferedTime() const { 208 base::TimeDelta PipelineImpl::GetBufferedTime() const {
208 AutoLock auto_lock(lock_); 209 AutoLock auto_lock(lock_);
209 return buffered_time_; 210 return buffered_time_;
210 } 211 }
211 212
212 base::TimeDelta PipelineImpl::GetDuration() const { 213 base::TimeDelta PipelineImpl::GetDuration() const {
213 AutoLock auto_lock(lock_); 214 AutoLock auto_lock(lock_);
214 return duration_; 215 return duration_;
(...skipping 17 matching lines...) Expand all
232 *height_out = video_height_; 233 *height_out = video_height_;
233 } 234 }
234 235
235 PipelineError PipelineImpl::GetError() const { 236 PipelineError PipelineImpl::GetError() const {
236 AutoLock auto_lock(lock_); 237 AutoLock auto_lock(lock_);
237 return error_; 238 return error_;
238 } 239 }
239 240
240 void PipelineImpl::ResetState() { 241 void PipelineImpl::ResetState() {
241 AutoLock auto_lock(lock_); 242 AutoLock auto_lock(lock_);
243 const base::TimeDelta kZero;
242 running_ = false; 244 running_ = false;
243 duration_ = base::TimeDelta(); 245 duration_ = kZero;
244 buffered_time_ = base::TimeDelta(); 246 buffered_time_ = kZero;
245 buffered_bytes_ = 0; 247 buffered_bytes_ = 0;
246 total_bytes_ = 0; 248 total_bytes_ = 0;
247 video_width_ = 0; 249 video_width_ = 0;
248 video_height_ = 0; 250 video_height_ = 0;
249 volume_ = 1.0f; 251 volume_ = 1.0f;
250 playback_rate_ = 0.0f; 252 playback_rate_ = 0.0f;
251 error_ = PIPELINE_OK; 253 error_ = PIPELINE_OK;
252 time_ = base::TimeDelta(); 254 clock_.SetTime(kZero);
253 rendered_mime_types_.clear(); 255 rendered_mime_types_.clear();
254 } 256 }
255 257
256 bool PipelineImpl::IsPipelineOk() { 258 bool PipelineImpl::IsPipelineOk() {
257 return PIPELINE_OK == GetError(); 259 return PIPELINE_OK == GetError();
258 } 260 }
259 261
260 bool PipelineImpl::IsPipelineInitializing() { 262 bool PipelineImpl::IsPipelineInitializing() {
261 DCHECK_EQ(MessageLoop::current(), message_loop_); 263 DCHECK_EQ(MessageLoop::current(), message_loop_);
262 return state_ == kInitDataSource || 264 return state_ == kInitDataSource ||
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
296 } 298 }
297 299
298 base::TimeDelta PipelineImpl::GetTime() const { 300 base::TimeDelta PipelineImpl::GetTime() const {
299 DCHECK(IsRunning()); 301 DCHECK(IsRunning());
300 return GetCurrentTime(); 302 return GetCurrentTime();
301 } 303 }
302 304
303 void PipelineImpl::SetTime(base::TimeDelta time) { 305 void PipelineImpl::SetTime(base::TimeDelta time) {
304 DCHECK(IsRunning()); 306 DCHECK(IsRunning());
305 AutoLock auto_lock(lock_); 307 AutoLock auto_lock(lock_);
306 time_ = time; 308 clock_.SetTime(time);
307 } 309 }
308 310
309 void PipelineImpl::SetDuration(base::TimeDelta duration) { 311 void PipelineImpl::SetDuration(base::TimeDelta duration) {
310 DCHECK(IsRunning()); 312 DCHECK(IsRunning());
311 AutoLock auto_lock(lock_); 313 AutoLock auto_lock(lock_);
312 duration_ = duration; 314 duration_ = duration;
313 } 315 }
314 316
315 void PipelineImpl::SetBufferedTime(base::TimeDelta buffered_time) { 317 void PipelineImpl::SetBufferedTime(base::TimeDelta buffered_time) {
316 DCHECK(IsRunning()); 318 DCHECK(IsRunning());
(...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after
530 532
531 // We no longer need to examine our previous state, set it to stopped. 533 // We no longer need to examine our previous state, set it to stopped.
532 state_ = kError; 534 state_ = kError;
533 535
534 // Destroy every filter and reset the pipeline as well. 536 // Destroy every filter and reset the pipeline as well.
535 DestroyFilters(); 537 DestroyFilters();
536 } 538 }
537 539
538 void PipelineImpl::PlaybackRateChangedTask(float playback_rate) { 540 void PipelineImpl::PlaybackRateChangedTask(float playback_rate) {
539 DCHECK_EQ(MessageLoop::current(), message_loop_); 541 DCHECK_EQ(MessageLoop::current(), message_loop_);
542 clock_.SetPlaybackRate(playback_rate);
540 for (FilterVector::iterator iter = filters_.begin(); 543 for (FilterVector::iterator iter = filters_.begin();
541 iter != filters_.end(); 544 iter != filters_.end();
542 ++iter) { 545 ++iter) {
543 (*iter)->SetPlaybackRate(playback_rate); 546 (*iter)->SetPlaybackRate(playback_rate);
544 } 547 }
545 } 548 }
546 549
547 void PipelineImpl::VolumeChangedTask(float volume) { 550 void PipelineImpl::VolumeChangedTask(float volume) {
548 DCHECK_EQ(MessageLoop::current(), message_loop_); 551 DCHECK_EQ(MessageLoop::current(), message_loop_);
549 552
(...skipping 24 matching lines...) Expand all
574 // kPausing (for each filter) 577 // kPausing (for each filter)
575 // kSeeking (for each filter) 578 // kSeeking (for each filter)
576 // kStarting (for each filter) 579 // kStarting (for each filter)
577 // kStarted 580 // kStarted
578 state_ = kPausing; 581 state_ = kPausing;
579 seek_timestamp_ = time; 582 seek_timestamp_ = time;
580 seek_callback_.reset(seek_callback); 583 seek_callback_.reset(seek_callback);
581 remaining_transitions_ = filters_.size(); 584 remaining_transitions_ = filters_.size();
582 585
583 // Kick off seeking! 586 // Kick off seeking!
587 clock_.Pause();
584 filters_.front()->Pause( 588 filters_.front()->Pause(
585 NewCallback(this, &PipelineImpl::OnFilterStateTransition)); 589 NewCallback(this, &PipelineImpl::OnFilterStateTransition));
586 } 590 }
587 591
588 void PipelineImpl::FilterStateTransitionTask() { 592 void PipelineImpl::FilterStateTransitionTask() {
589 DCHECK_EQ(MessageLoop::current(), message_loop_); 593 DCHECK_EQ(MessageLoop::current(), message_loop_);
590 594
591 if (!StateTransitionsToStarted(state_)) { 595 if (!StateTransitionsToStarted(state_)) {
592 NOTREACHED() << "Invalid current state: " << state_; 596 NOTREACHED() << "Invalid current state: " << state_;
593 SetError(PIPELINE_ERROR_ABORT); 597 SetError(PIPELINE_ERROR_ABORT);
594 return; 598 return;
595 } 599 }
596 600
597 // Decrement the number of remaining transitions, making sure to transition 601 // Decrement the number of remaining transitions, making sure to transition
598 // to the next state if needed. 602 // to the next state if needed.
599 CHECK(remaining_transitions_ <= filters_.size()); 603 CHECK(remaining_transitions_ <= filters_.size());
600 CHECK(remaining_transitions_ > 0u); 604 CHECK(remaining_transitions_ > 0u);
601 if (--remaining_transitions_ == 0) { 605 if (--remaining_transitions_ == 0) {
602 state_ = FindNextState(state_); 606 state_ = FindNextState(state_);
607 if (state_ == kSeeking) {
608 clock_.SetTime(seek_timestamp_);
609 } else if (state_ == kStarting) {
610 clock_.Play();
611 }
612
603 if (StateTransitionsToStarted(state_)) { 613 if (StateTransitionsToStarted(state_)) {
604 remaining_transitions_ = filters_.size(); 614 remaining_transitions_ = filters_.size();
605 } 615 }
606 } 616 }
607 617
608 // Carry out the action for the current state. 618 // Carry out the action for the current state.
609 if (StateTransitionsToStarted(state_)) { 619 if (StateTransitionsToStarted(state_)) {
610 MediaFilter* filter = filters_[filters_.size() - remaining_transitions_]; 620 MediaFilter* filter = filters_[filters_.size() - remaining_transitions_];
611 if (state_ == kPausing) { 621 if (state_ == kPausing) {
612 filter->Pause(NewCallback(this, &PipelineImpl::OnFilterStateTransition)); 622 filter->Pause(NewCallback(this, &PipelineImpl::OnFilterStateTransition));
613 } else if (state_ == kSeeking) { 623 } else if (state_ == kSeeking) {
614 filter->Seek(seek_timestamp_, 624 filter->Seek(seek_timestamp_,
615 NewCallback(this, &PipelineImpl::OnFilterStateTransition)); 625 NewCallback(this, &PipelineImpl::OnFilterStateTransition));
616 } else if (state_ == kStarting) { 626 } else if (state_ == kStarting) {
617 filter->Play(NewCallback(this, &PipelineImpl::OnFilterStateTransition)); 627 filter->Play(NewCallback(this, &PipelineImpl::OnFilterStateTransition));
618 } else { 628 } else {
619 NOTREACHED(); 629 NOTREACHED();
620 } 630 }
621 } else if (state_ == kStarted) { 631 } else if (state_ == kStarted) {
622 // We've completed the seek, update the time.
623 SetTime(seek_timestamp_);
624
625 // Execute the seek callback, if present. Note that this might be the 632 // Execute the seek callback, if present. Note that this might be the
626 // initial callback passed into Start(). 633 // initial callback passed into Start().
627 if (seek_callback_.get()) { 634 if (seek_callback_.get()) {
628 seek_callback_->Run(); 635 seek_callback_->Run();
629 seek_callback_.reset(); 636 seek_callback_.reset();
630 } 637 }
631 638
632 // Finally, reset our seeking timestamp back to zero. 639 // Finally, reset our seeking timestamp back to zero.
633 seek_timestamp_ = base::TimeDelta(); 640 seek_timestamp_ = base::TimeDelta();
634 } else { 641 } else {
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after
792 799
793 // Reset the pipeline, which will decrement a reference to this object. 800 // Reset the pipeline, which will decrement a reference to this object.
794 // We will get destroyed as soon as the remaining tasks finish executing. 801 // We will get destroyed as soon as the remaining tasks finish executing.
795 // To be safe, we'll set our pipeline reference to NULL. 802 // To be safe, we'll set our pipeline reference to NULL.
796 filters_.clear(); 803 filters_.clear();
797 filter_types_.clear(); 804 filter_types_.clear();
798 STLDeleteElements(&filter_threads_); 805 STLDeleteElements(&filter_threads_);
799 } 806 }
800 807
801 } // namespace media 808 } // namespace media
OLDNEW
« no previous file with comments | « media/base/pipeline_impl.h ('k') | media/filters/video_renderer_base.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698