| 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 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 142 bool PipelineImpl::IsInitialized() const { | 142 bool PipelineImpl::IsInitialized() const { |
| 143 // TODO(scherkus): perhaps replace this with a bool that is set/get under the | 143 // TODO(scherkus): perhaps replace this with a bool that is set/get under the |
| 144 // lock, because this is breaching the contract that |state_| is only accessed | 144 // lock, because this is breaching the contract that |state_| is only accessed |
| 145 // on |message_loop_|. | 145 // on |message_loop_|. |
| 146 AutoLock auto_lock(lock_); | 146 AutoLock auto_lock(lock_); |
| 147 switch (state_) { | 147 switch (state_) { |
| 148 case kPausing: | 148 case kPausing: |
| 149 case kSeeking: | 149 case kSeeking: |
| 150 case kStarting: | 150 case kStarting: |
| 151 case kStarted: | 151 case kStarted: |
| 152 case kEnded: |
| 152 return true; | 153 return true; |
| 153 default: | 154 default: |
| 154 return false; | 155 return false; |
| 155 } | 156 } |
| 156 } | 157 } |
| 157 | 158 |
| 158 bool PipelineImpl::IsRendered(const std::string& major_mime_type) const { | 159 bool PipelineImpl::IsRendered(const std::string& major_mime_type) const { |
| 159 AutoLock auto_lock(lock_); | 160 AutoLock auto_lock(lock_); |
| 160 bool is_rendered = (rendered_mime_types_.find(major_mime_type) != | 161 bool is_rendered = (rendered_mime_types_.find(major_mime_type) != |
| 161 rendered_mime_types_.end()); | 162 rendered_mime_types_.end()); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 194 AutoLock auto_lock(lock_); | 195 AutoLock auto_lock(lock_); |
| 195 volume_ = volume; | 196 volume_ = volume; |
| 196 if (running_) { | 197 if (running_) { |
| 197 message_loop_->PostTask(FROM_HERE, | 198 message_loop_->PostTask(FROM_HERE, |
| 198 NewRunnableMethod(this, &PipelineImpl::VolumeChangedTask, | 199 NewRunnableMethod(this, &PipelineImpl::VolumeChangedTask, |
| 199 volume)); | 200 volume)); |
| 200 } | 201 } |
| 201 } | 202 } |
| 202 | 203 |
| 203 base::TimeDelta PipelineImpl::GetCurrentTime() const { | 204 base::TimeDelta PipelineImpl::GetCurrentTime() const { |
| 205 // TODO(scherkus): perhaps replace checking state_ == kEnded with a bool that |
| 206 // is set/get under the lock, because this is breaching the contract that |
| 207 // |state_| is only accessed on |message_loop_|. |
| 204 AutoLock auto_lock(lock_); | 208 AutoLock auto_lock(lock_); |
| 205 base::TimeDelta elapsed = clock_.Elapsed(); | 209 base::TimeDelta elapsed = clock_.Elapsed(); |
| 206 if (elapsed > duration_) { | 210 if (state_ == kEnded || elapsed > duration_) { |
| 207 return duration_; | 211 return duration_; |
| 208 } | 212 } |
| 209 return elapsed; | 213 return elapsed; |
| 210 } | 214 } |
| 211 | 215 |
| 212 base::TimeDelta PipelineImpl::GetBufferedTime() const { | 216 base::TimeDelta PipelineImpl::GetBufferedTime() const { |
| 213 AutoLock auto_lock(lock_); | 217 AutoLock auto_lock(lock_); |
| 214 | 218 |
| 215 // If buffered time was set, we report that value directly. | 219 // If buffered time was set, we report that value directly. |
| 216 if (buffered_time_.ToInternalValue() > 0) | 220 if (buffered_time_.ToInternalValue() > 0) |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 255 bool PipelineImpl::IsStreaming() const { | 259 bool PipelineImpl::IsStreaming() const { |
| 256 AutoLock auto_lock(lock_); | 260 AutoLock auto_lock(lock_); |
| 257 return streaming_; | 261 return streaming_; |
| 258 } | 262 } |
| 259 | 263 |
| 260 PipelineError PipelineImpl::GetError() const { | 264 PipelineError PipelineImpl::GetError() const { |
| 261 AutoLock auto_lock(lock_); | 265 AutoLock auto_lock(lock_); |
| 262 return error_; | 266 return error_; |
| 263 } | 267 } |
| 264 | 268 |
| 269 void PipelineImpl::SetPipelineEndedCallback(PipelineCallback* ended_callback) { |
| 270 DCHECK(!IsRunning()) |
| 271 << "Permanent callbacks should be set before the pipeline has started"; |
| 272 ended_callback_.reset(ended_callback); |
| 273 } |
| 274 |
| 265 void PipelineImpl::SetPipelineErrorCallback(PipelineCallback* error_callback) { | 275 void PipelineImpl::SetPipelineErrorCallback(PipelineCallback* error_callback) { |
| 276 DCHECK(!IsRunning()) |
| 277 << "Permanent callbacks should be set before the pipeline has started"; |
| 266 error_callback_.reset(error_callback); | 278 error_callback_.reset(error_callback); |
| 267 } | 279 } |
| 268 | 280 |
| 269 void PipelineImpl::ResetState() { | 281 void PipelineImpl::ResetState() { |
| 270 AutoLock auto_lock(lock_); | 282 AutoLock auto_lock(lock_); |
| 271 const base::TimeDelta kZero; | 283 const base::TimeDelta kZero; |
| 272 running_ = false; | 284 running_ = false; |
| 273 duration_ = kZero; | 285 duration_ = kZero; |
| 274 buffered_time_ = kZero; | 286 buffered_time_ = kZero; |
| 275 buffered_bytes_ = 0; | 287 buffered_bytes_ = 0; |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 367 video_width_ = width; | 379 video_width_ = width; |
| 368 video_height_ = height; | 380 video_height_ = height; |
| 369 } | 381 } |
| 370 | 382 |
| 371 void PipelineImpl::SetStreaming(bool streaming) { | 383 void PipelineImpl::SetStreaming(bool streaming) { |
| 372 DCHECK(IsRunning()); | 384 DCHECK(IsRunning()); |
| 373 AutoLock auto_lock(lock_); | 385 AutoLock auto_lock(lock_); |
| 374 streaming_ = streaming; | 386 streaming_ = streaming; |
| 375 } | 387 } |
| 376 | 388 |
| 389 void PipelineImpl::NotifyEnded() { |
| 390 DCHECK(IsRunning()); |
| 391 message_loop_->PostTask(FROM_HERE, |
| 392 NewRunnableMethod(this, &PipelineImpl::NotifyEndedTask)); |
| 393 } |
| 394 |
| 377 void PipelineImpl::BroadcastMessage(FilterMessage message) { | 395 void PipelineImpl::BroadcastMessage(FilterMessage message) { |
| 378 DCHECK(IsRunning()); | 396 DCHECK(IsRunning()); |
| 379 | 397 |
| 380 // Broadcast the message on the message loop. | 398 // Broadcast the message on the message loop. |
| 381 message_loop_->PostTask(FROM_HERE, | 399 message_loop_->PostTask(FROM_HERE, |
| 382 NewRunnableMethod(this, &PipelineImpl::BroadcastMessageTask, | 400 NewRunnableMethod(this, &PipelineImpl::BroadcastMessageTask, |
| 383 message)); | 401 message)); |
| 384 } | 402 } |
| 385 | 403 |
| 386 void PipelineImpl::InsertRenderedMimeType(const std::string& major_mime_type) { | 404 void PipelineImpl::InsertRenderedMimeType(const std::string& major_mime_type) { |
| (...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 605 if (audio_renderer) { | 623 if (audio_renderer) { |
| 606 audio_renderer->SetVolume(volume); | 624 audio_renderer->SetVolume(volume); |
| 607 } | 625 } |
| 608 } | 626 } |
| 609 | 627 |
| 610 void PipelineImpl::SeekTask(base::TimeDelta time, | 628 void PipelineImpl::SeekTask(base::TimeDelta time, |
| 611 PipelineCallback* seek_callback) { | 629 PipelineCallback* seek_callback) { |
| 612 DCHECK_EQ(MessageLoop::current(), message_loop_); | 630 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 613 | 631 |
| 614 // Suppress seeking if we're not fully started. | 632 // Suppress seeking if we're not fully started. |
| 615 if (state_ != kStarted) { | 633 if (state_ != kStarted && state_ != kEnded) { |
| 616 // TODO(scherkus): should we run the callback? I'm tempted to say the API | 634 // TODO(scherkus): should we run the callback? I'm tempted to say the API |
| 617 // will only execute the first Seek() request. | 635 // will only execute the first Seek() request. |
| 618 LOG(INFO) << "Media pipeline is not in started state, ignoring seek to " | 636 LOG(INFO) << "Media pipeline has not started, ignoring seek to " |
| 619 << time.InMicroseconds(); | 637 << time.InMicroseconds(); |
| 620 delete seek_callback; | 638 delete seek_callback; |
| 621 return; | 639 return; |
| 622 } | 640 } |
| 623 | 641 |
| 624 // We'll need to pause every filter before seeking. The state transition | 642 // We'll need to pause every filter before seeking. The state transition |
| 625 // is as follows: | 643 // is as follows: |
| 626 // kStarted | 644 // kStarted/kEnded |
| 627 // kPausing (for each filter) | 645 // kPausing (for each filter) |
| 628 // kSeeking (for each filter) | 646 // kSeeking (for each filter) |
| 629 // kStarting (for each filter) | 647 // kStarting (for each filter) |
| 630 // kStarted | 648 // kStarted |
| 631 state_ = kPausing; | 649 state_ = kPausing; |
| 632 seek_timestamp_ = time; | 650 seek_timestamp_ = time; |
| 633 seek_callback_.reset(seek_callback); | 651 seek_callback_.reset(seek_callback); |
| 634 remaining_transitions_ = filters_.size(); | 652 remaining_transitions_ = filters_.size(); |
| 635 | 653 |
| 636 // Kick off seeking! | 654 // Kick off seeking! |
| 637 clock_.Pause(); | 655 clock_.Pause(); |
| 638 filters_.front()->Pause( | 656 filters_.front()->Pause( |
| 639 NewCallback(this, &PipelineImpl::OnFilterStateTransition)); | 657 NewCallback(this, &PipelineImpl::OnFilterStateTransition)); |
| 640 } | 658 } |
| 641 | 659 |
| 660 void PipelineImpl::NotifyEndedTask() { |
| 661 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 662 |
| 663 // We can only end if we were actually playing. |
| 664 if (state_ != kStarted) { |
| 665 return; |
| 666 } |
| 667 |
| 668 // Grab the renderers, if they exist. |
| 669 scoped_refptr<AudioRenderer> audio_renderer; |
| 670 scoped_refptr<VideoRenderer> video_renderer; |
| 671 GetFilter(&audio_renderer); |
| 672 GetFilter(&video_renderer); |
| 673 DCHECK(audio_renderer || video_renderer); |
| 674 |
| 675 // Make sure every extant renderer has ended. |
| 676 if ((audio_renderer && !audio_renderer->HasEnded()) || |
| 677 (video_renderer && !video_renderer->HasEnded())) { |
| 678 return; |
| 679 } |
| 680 |
| 681 // Transition to ended, executing the callback if present. |
| 682 state_ = kEnded; |
| 683 if (ended_callback_.get()) { |
| 684 ended_callback_->Run(); |
| 685 } |
| 686 } |
| 687 |
| 642 void PipelineImpl::BroadcastMessageTask(FilterMessage message) { | 688 void PipelineImpl::BroadcastMessageTask(FilterMessage message) { |
| 643 DCHECK_EQ(MessageLoop::current(), message_loop_); | 689 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 644 | 690 |
| 645 // Broadcast the message to all filters. | 691 // Broadcast the message to all filters. |
| 646 for (FilterVector::iterator iter = filters_.begin(); | 692 for (FilterVector::iterator iter = filters_.begin(); |
| 647 iter != filters_.end(); | 693 iter != filters_.end(); |
| 648 ++iter) { | 694 ++iter) { |
| 649 (*iter)->OnReceivedMessage(message); | 695 (*iter)->OnReceivedMessage(message); |
| 650 } | 696 } |
| 651 } | 697 } |
| (...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 865 | 911 |
| 866 // Reset the pipeline, which will decrement a reference to this object. | 912 // Reset the pipeline, which will decrement a reference to this object. |
| 867 // We will get destroyed as soon as the remaining tasks finish executing. | 913 // We will get destroyed as soon as the remaining tasks finish executing. |
| 868 // To be safe, we'll set our pipeline reference to NULL. | 914 // To be safe, we'll set our pipeline reference to NULL. |
| 869 filters_.clear(); | 915 filters_.clear(); |
| 870 filter_types_.clear(); | 916 filter_types_.clear(); |
| 871 STLDeleteElements(&filter_threads_); | 917 STLDeleteElements(&filter_threads_); |
| 872 } | 918 } |
| 873 | 919 |
| 874 } // namespace media | 920 } // namespace media |
| OLD | NEW |