Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 71 | 71 |
| 72 PipelineImpl::~PipelineImpl() { | 72 PipelineImpl::~PipelineImpl() { |
| 73 DCHECK(!pipeline_internal_) | 73 DCHECK(!pipeline_internal_) |
| 74 << "Stop() must complete before destroying object"; | 74 << "Stop() must complete before destroying object"; |
| 75 } | 75 } |
| 76 | 76 |
| 77 // Creates the PipelineInternal and calls it's start method. | 77 // Creates the PipelineInternal and calls it's start method. |
| 78 bool PipelineImpl::Start(FilterFactory* factory, | 78 bool PipelineImpl::Start(FilterFactory* factory, |
| 79 const std::string& url, | 79 const std::string& url, |
| 80 PipelineCallback* start_callback) { | 80 PipelineCallback* start_callback) { |
| 81 DCHECK(!pipeline_internal_); | 81 DCHECK(!pipeline_internal_) << "PipelineInternal already exists"; |
| 82 DCHECK(factory); | 82 scoped_ptr<PipelineCallback> callback(start_callback); |
|
Alpha Left Google
2009/07/11 02:05:36
good catch on leak! :)
| |
| 83 if (pipeline_internal_ || !factory) { | 83 if (pipeline_internal_ || !factory) { |
| 84 return false; | 84 return false; |
| 85 } | 85 } |
| 86 | 86 |
| 87 // Create and start the PipelineInternal. | 87 // Create and start the PipelineInternal. |
| 88 pipeline_internal_ = new PipelineInternal(this, message_loop_); | 88 pipeline_internal_ = new PipelineInternal(this, message_loop_); |
| 89 if (!pipeline_internal_) { | 89 if (!pipeline_internal_) { |
| 90 NOTREACHED() << "Could not create PipelineInternal"; | 90 NOTREACHED() << "Could not create PipelineInternal"; |
| 91 return false; | 91 return false; |
| 92 } | 92 } |
| 93 pipeline_internal_->Start(factory, url, start_callback); | 93 pipeline_internal_->Start(factory, url, callback.release()); |
| 94 return true; | 94 return true; |
| 95 } | 95 } |
| 96 | 96 |
| 97 // Stop the PipelineInternal who will NULL our reference to it and reset our | 97 // Stop the PipelineInternal who will NULL our reference to it and reset our |
| 98 // state to a newly created PipelineImpl object. | 98 // state to a newly created PipelineImpl object. |
| 99 void PipelineImpl::Stop(PipelineCallback* stop_callback) { | 99 void PipelineImpl::Stop(PipelineCallback* stop_callback) { |
| 100 scoped_ptr<PipelineCallback> callback(stop_callback); | |
| 100 if (pipeline_internal_) { | 101 if (pipeline_internal_) { |
| 101 pipeline_internal_->Stop(stop_callback); | 102 pipeline_internal_->Stop(callback.release()); |
| 102 } | 103 } |
| 103 } | 104 } |
| 104 | 105 |
| 105 void PipelineImpl::Seek(base::TimeDelta time, | 106 void PipelineImpl::Seek(base::TimeDelta time, |
| 106 PipelineCallback* seek_callback) { | 107 PipelineCallback* seek_callback) { |
| 107 if (IsPipelineOk()) { | 108 scoped_ptr<PipelineCallback> callback(seek_callback); |
| 108 pipeline_internal_->Seek(time, seek_callback); | 109 if (pipeline_internal_) { |
| 109 } else { | 110 pipeline_internal_->Seek(time, callback.release()); |
| 110 NOTREACHED(); | |
| 111 } | 111 } |
| 112 } | 112 } |
| 113 | 113 |
| 114 bool PipelineImpl::IsRunning() const { | 114 bool PipelineImpl::IsRunning() const { |
| 115 AutoLock auto_lock(const_cast<Lock&>(lock_)); | 115 AutoLock auto_lock(lock_); |
| 116 return pipeline_internal_ != NULL; | 116 return pipeline_internal_ != NULL; |
| 117 } | 117 } |
| 118 | 118 |
| 119 bool PipelineImpl::IsInitialized() const { | 119 bool PipelineImpl::IsInitialized() const { |
| 120 AutoLock auto_lock(lock_); | 120 AutoLock auto_lock(lock_); |
| 121 return pipeline_internal_ && pipeline_internal_->IsInitialized(); | 121 return pipeline_internal_ && pipeline_internal_->IsInitialized(); |
| 122 } | 122 } |
| 123 | 123 |
| 124 bool PipelineImpl::IsRendered(const std::string& major_mime_type) const { | 124 bool PipelineImpl::IsRendered(const std::string& major_mime_type) const { |
| 125 AutoLock auto_lock(lock_); | 125 AutoLock auto_lock(lock_); |
| 126 bool is_rendered = (rendered_mime_types_.find(major_mime_type) != | 126 bool is_rendered = (rendered_mime_types_.find(major_mime_type) != |
| 127 rendered_mime_types_.end()); | 127 rendered_mime_types_.end()); |
| 128 return is_rendered; | 128 return is_rendered; |
| 129 } | 129 } |
| 130 | 130 |
| 131 float PipelineImpl::GetPlaybackRate() const { | 131 float PipelineImpl::GetPlaybackRate() const { |
| 132 AutoLock auto_lock(lock_); | 132 AutoLock auto_lock(lock_); |
| 133 return playback_rate_; | 133 return playback_rate_; |
| 134 } | 134 } |
| 135 | 135 |
| 136 void PipelineImpl::SetPlaybackRate(float rate) { | 136 void PipelineImpl::SetPlaybackRate(float playback_rate) { |
| 137 if (IsPipelineOk() && rate >= 0.0f) { | 137 if (playback_rate < 0.0f) { |
| 138 pipeline_internal_->SetPlaybackRate(rate); | 138 return; |
| 139 } else { | 139 } |
| 140 // It's OK for a client to call SetPlaybackRate(0.0f) if we're stopped. | 140 |
| 141 DCHECK(rate == 0.0f && playback_rate_ == 0.0f); | 141 AutoLock auto_lock(lock_); |
| 142 playback_rate_ = playback_rate; | |
| 143 if (pipeline_internal_) { | |
| 144 pipeline_internal_->PlaybackRateChanged(playback_rate); | |
| 142 } | 145 } |
| 143 } | 146 } |
| 144 | 147 |
| 145 float PipelineImpl::GetVolume() const { | 148 float PipelineImpl::GetVolume() const { |
| 146 AutoLock auto_lock(lock_); | 149 AutoLock auto_lock(lock_); |
| 147 return volume_; | 150 return volume_; |
| 148 } | 151 } |
| 149 | 152 |
| 150 void PipelineImpl::SetVolume(float volume) { | 153 void PipelineImpl::SetVolume(float volume) { |
| 151 if (IsPipelineOk() && volume >= 0.0f && volume <= 1.0f) { | 154 if (volume < 0.0f || volume > 1.0f) { |
| 152 pipeline_internal_->SetVolume(volume); | 155 return; |
| 153 } else { | 156 } |
| 154 NOTREACHED(); | 157 |
| 158 AutoLock auto_lock(lock_); | |
| 159 volume_ = volume; | |
| 160 if (pipeline_internal_) { | |
| 161 pipeline_internal_->VolumeChanged(volume); | |
| 155 } | 162 } |
| 156 } | 163 } |
| 157 | 164 |
| 158 base::TimeDelta PipelineImpl::GetTime() const { | 165 base::TimeDelta PipelineImpl::GetTime() const { |
| 159 AutoLock auto_lock(lock_); | 166 AutoLock auto_lock(lock_); |
| 160 return time_; | 167 return time_; |
| 161 } | 168 } |
| 162 | 169 |
| 163 base::TimeDelta PipelineImpl::GetBufferedTime() const { | 170 base::TimeDelta PipelineImpl::GetBufferedTime() const { |
| 164 AutoLock auto_lock(lock_); | 171 AutoLock auto_lock(lock_); |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 237 AutoLock auto_lock(lock_); | 244 AutoLock auto_lock(lock_); |
| 238 video_width_ = width; | 245 video_width_ = width; |
| 239 video_height_ = height; | 246 video_height_ = height; |
| 240 } | 247 } |
| 241 | 248 |
| 242 void PipelineImpl::SetTime(base::TimeDelta time) { | 249 void PipelineImpl::SetTime(base::TimeDelta time) { |
| 243 AutoLock auto_lock(lock_); | 250 AutoLock auto_lock(lock_); |
| 244 time_ = time; | 251 time_ = time; |
| 245 } | 252 } |
| 246 | 253 |
| 247 void PipelineImpl::InternalSetPlaybackRate(float rate) { | |
| 248 AutoLock auto_lock(lock_); | |
| 249 playback_rate_ = rate; | |
| 250 } | |
| 251 | |
| 252 bool PipelineImpl::InternalSetError(PipelineError error) { | 254 bool PipelineImpl::InternalSetError(PipelineError error) { |
| 253 // Don't want callers to set an error of "OK". STOPPING is a special value | 255 // Don't want callers to set an error of "OK". STOPPING is a special value |
| 254 // that should only be used internally by the StopTask() method. | 256 // that should only be used internally by the StopTask() method. |
| 255 DCHECK(PIPELINE_OK != error && PIPELINE_STOPPING != error); | 257 DCHECK(PIPELINE_OK != error && PIPELINE_STOPPING != error); |
| 256 AutoLock auto_lock(lock_); | 258 AutoLock auto_lock(lock_); |
| 257 bool changed_error = false; | 259 bool changed_error = false; |
| 258 if (PIPELINE_OK == error_) { | 260 if (PIPELINE_OK == error_) { |
| 259 error_ = error; | 261 error_ = error; |
| 260 changed_error = true; | 262 changed_error = true; |
| 261 } | 263 } |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 299 | 301 |
| 300 // Called on client's thread. | 302 // Called on client's thread. |
| 301 void PipelineInternal::Seek(base::TimeDelta time, | 303 void PipelineInternal::Seek(base::TimeDelta time, |
| 302 PipelineCallback* seek_callback) { | 304 PipelineCallback* seek_callback) { |
| 303 message_loop_->PostTask(FROM_HERE, | 305 message_loop_->PostTask(FROM_HERE, |
| 304 NewRunnableMethod(this, &PipelineInternal::SeekTask, time, | 306 NewRunnableMethod(this, &PipelineInternal::SeekTask, time, |
| 305 seek_callback)); | 307 seek_callback)); |
| 306 } | 308 } |
| 307 | 309 |
| 308 // Called on client's thread. | 310 // Called on client's thread. |
| 309 void PipelineInternal::SetPlaybackRate(float rate) { | 311 void PipelineInternal::PlaybackRateChanged(float playback_rate) { |
| 310 message_loop_->PostTask(FROM_HERE, | 312 message_loop_->PostTask(FROM_HERE, |
| 311 NewRunnableMethod(this, &PipelineInternal::SetPlaybackRateTask, rate)); | 313 NewRunnableMethod(this, &PipelineInternal::PlaybackRateChangedTask, |
| 314 playback_rate)); | |
| 312 } | 315 } |
| 313 | 316 |
| 314 // Called on client's thread. | 317 // Called on client's thread. |
| 315 void PipelineInternal::SetVolume(float volume) { | 318 void PipelineInternal::VolumeChanged(float volume) { |
| 316 message_loop_->PostTask(FROM_HERE, | 319 message_loop_->PostTask(FROM_HERE, |
| 317 NewRunnableMethod(this, &PipelineInternal::SetVolumeTask, volume)); | 320 NewRunnableMethod(this, &PipelineInternal::VolumeChangedTask, volume)); |
| 318 } | 321 } |
| 319 | 322 |
| 320 // Called from any thread. | 323 // Called from any thread. |
| 321 void PipelineInternal::InitializationComplete(FilterHostImpl* host) { | 324 void PipelineInternal::InitializationComplete(FilterHostImpl* host) { |
| 322 if (IsPipelineOk()) { | 325 if (IsPipelineOk()) { |
| 323 // Continue the initialize task by proceeding to the next stage. | 326 // Continue the initialize task by proceeding to the next stage. |
| 324 message_loop_->PostTask(FROM_HERE, | 327 message_loop_->PostTask(FROM_HERE, |
| 325 NewRunnableMethod(this, &PipelineInternal::InitializeTask)); | 328 NewRunnableMethod(this, &PipelineInternal::InitializeTask)); |
| 326 } | 329 } |
| 327 } | 330 } |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 429 return; | 432 return; |
| 430 } | 433 } |
| 431 } | 434 } |
| 432 | 435 |
| 433 if (state_ == kInitVideoRenderer) { | 436 if (state_ == kInitVideoRenderer) { |
| 434 if (!IsPipelineOk() || pipeline_->rendered_mime_types_.empty()) { | 437 if (!IsPipelineOk() || pipeline_->rendered_mime_types_.empty()) { |
| 435 Error(PIPELINE_ERROR_COULD_NOT_RENDER); | 438 Error(PIPELINE_ERROR_COULD_NOT_RENDER); |
| 436 return; | 439 return; |
| 437 } | 440 } |
| 438 | 441 |
| 442 // Initialization was successful, set the volume and playback rate. | |
| 443 PlaybackRateChangedTask(pipeline_->GetPlaybackRate()); | |
| 444 VolumeChangedTask(pipeline_->GetVolume()); | |
| 445 | |
| 439 state_ = kStarted; | 446 state_ = kStarted; |
| 440 filter_factory_ = NULL; | 447 filter_factory_ = NULL; |
| 441 if (start_callback_.get()) { | 448 if (start_callback_.get()) { |
| 442 start_callback_->Run(true); | 449 start_callback_->Run(true); |
| 443 start_callback_.reset(); | 450 start_callback_.reset(); |
| 444 } | 451 } |
| 445 } | 452 } |
| 446 } | 453 } |
| 447 | 454 |
| 448 // This method is called as a result of the client calling Pipeline::Stop() or | 455 // This method is called as a result of the client calling Pipeline::Stop() or |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 499 start_callback_.reset(); | 506 start_callback_.reset(); |
| 500 filter_factory_ = NULL; | 507 filter_factory_ = NULL; |
| 501 | 508 |
| 502 // We no longer need to examine our previous state, set it to stopped. | 509 // We no longer need to examine our previous state, set it to stopped. |
| 503 state_ = kError; | 510 state_ = kError; |
| 504 | 511 |
| 505 // Destroy every filter and reset the pipeline as well. | 512 // Destroy every filter and reset the pipeline as well. |
| 506 DestroyFilters(); | 513 DestroyFilters(); |
| 507 } | 514 } |
| 508 | 515 |
| 509 void PipelineInternal::SetPlaybackRateTask(float rate) { | 516 void PipelineInternal::PlaybackRateChangedTask(float playback_rate) { |
| 510 DCHECK_EQ(MessageLoop::current(), message_loop_); | 517 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 511 | 518 |
| 512 pipeline_->InternalSetPlaybackRate(rate); | |
| 513 for (FilterHostVector::iterator iter = filter_hosts_.begin(); | 519 for (FilterHostVector::iterator iter = filter_hosts_.begin(); |
| 514 iter != filter_hosts_.end(); | 520 iter != filter_hosts_.end(); |
| 515 ++iter) { | 521 ++iter) { |
| 516 (*iter)->media_filter()->SetPlaybackRate(rate); | 522 (*iter)->media_filter()->SetPlaybackRate(playback_rate); |
| 517 } | 523 } |
| 518 } | 524 } |
| 519 | 525 |
| 526 void PipelineInternal::VolumeChangedTask(float volume) { | |
| 527 DCHECK_EQ(MessageLoop::current(), message_loop_); | |
| 528 | |
| 529 scoped_refptr<AudioRenderer> audio_renderer; | |
| 530 GetFilter(&audio_renderer); | |
| 531 if (audio_renderer) { | |
| 532 audio_renderer->SetVolume(volume); | |
| 533 } | |
| 534 } | |
| 535 | |
| 520 void PipelineInternal::SeekTask(base::TimeDelta time, | 536 void PipelineInternal::SeekTask(base::TimeDelta time, |
| 521 PipelineCallback* seek_callback) { | 537 PipelineCallback* seek_callback) { |
| 522 DCHECK_EQ(MessageLoop::current(), message_loop_); | 538 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 523 seek_callback_.reset(seek_callback); | 539 seek_callback_.reset(seek_callback); |
| 524 | 540 |
| 541 // Supress seeking if we haven't fully started. | |
| 542 if (state_ != kStarted) { | |
| 543 return; | |
| 544 } | |
| 545 | |
| 525 for (FilterHostVector::iterator iter = filter_hosts_.begin(); | 546 for (FilterHostVector::iterator iter = filter_hosts_.begin(); |
| 526 iter != filter_hosts_.end(); | 547 iter != filter_hosts_.end(); |
| 527 ++iter) { | 548 ++iter) { |
| 528 (*iter)->media_filter()->Seek(time); | 549 (*iter)->media_filter()->Seek(time); |
| 529 } | 550 } |
| 530 | 551 |
| 531 // TODO(hclam): we should set the time when the above seek operations were all | 552 // TODO(hclam): we should set the time when the above seek operations were all |
| 532 // successful and first frame/packet at the desired time is decoded. I'm | 553 // successful and first frame/packet at the desired time is decoded. I'm |
| 533 // setting the time here because once we do the callback the user can ask for | 554 // setting the time here because once we do the callback the user can ask for |
| 534 // current time immediately, which is the old time. In order to get rid this | 555 // current time immediately, which is the old time. In order to get rid this |
| 535 // little glitch, we either assume the seek was successful and time is updated | 556 // little glitch, we either assume the seek was successful and time is updated |
| 536 // immediately here or we set time and do callback when we have new | 557 // immediately here or we set time and do callback when we have new |
| 537 // frames/packets. | 558 // frames/packets. |
| 538 SetTime(time); | 559 SetTime(time); |
| 539 if (seek_callback_.get()) { | 560 if (seek_callback_.get()) { |
| 540 seek_callback_->Run(true); | 561 seek_callback_->Run(true); |
| 541 seek_callback_.reset(); | 562 seek_callback_.reset(); |
| 542 } | 563 } |
| 543 } | 564 } |
| 544 | 565 |
| 545 void PipelineInternal::SetVolumeTask(float volume) { | |
| 546 DCHECK_EQ(MessageLoop::current(), message_loop_); | |
| 547 | |
| 548 pipeline_->volume_ = volume; | |
| 549 scoped_refptr<AudioRenderer> audio_renderer; | |
| 550 GetFilter(&audio_renderer); | |
| 551 if (audio_renderer) { | |
| 552 audio_renderer->SetVolume(volume); | |
| 553 } | |
| 554 } | |
| 555 | |
| 556 template <class Filter, class Source> | 566 template <class Filter, class Source> |
| 557 void PipelineInternal::CreateFilter(FilterFactory* filter_factory, | 567 void PipelineInternal::CreateFilter(FilterFactory* filter_factory, |
| 558 Source source, | 568 Source source, |
| 559 const MediaFormat& media_format) { | 569 const MediaFormat& media_format) { |
| 560 DCHECK_EQ(MessageLoop::current(), message_loop_); | 570 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 561 DCHECK(IsPipelineOk()); | 571 DCHECK(IsPipelineOk()); |
| 562 | 572 |
| 563 // Create the filter. | 573 // Create the filter. |
| 564 scoped_refptr<Filter> filter = filter_factory->Create<Filter>(media_format); | 574 scoped_refptr<Filter> filter = filter_factory->Create<Filter>(media_format); |
| 565 if (!filter) { | 575 if (!filter) { |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 707 } | 717 } |
| 708 | 718 |
| 709 // Reset the pipeline, which will decrement a reference to this object. | 719 // Reset the pipeline, which will decrement a reference to this object. |
| 710 // We will get destroyed as soon as the remaining tasks finish executing. | 720 // We will get destroyed as soon as the remaining tasks finish executing. |
| 711 // To be safe, we'll set our pipeline reference to NULL. | 721 // To be safe, we'll set our pipeline reference to NULL. |
| 712 STLDeleteElements(&filter_hosts_); | 722 STLDeleteElements(&filter_hosts_); |
| 713 STLDeleteElements(&filter_threads_); | 723 STLDeleteElements(&filter_threads_); |
| 714 } | 724 } |
| 715 | 725 |
| 716 } // namespace media | 726 } // namespace media |
| OLD | NEW |