Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 #include "base/bind.h" | 5 #include "base/bind.h" |
| 6 #include "base/callback.h" | 6 #include "base/callback.h" |
| 7 #include "base/threading/platform_thread.h" | 7 #include "base/threading/platform_thread.h" |
| 8 #include "media/base/buffers.h" | 8 #include "media/base/buffers.h" |
| 9 #include "media/base/callback.h" | 9 #include "media/base/callback.h" |
| 10 #include "media/base/filter_host.h" | 10 #include "media/base/filter_host.h" |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 122 | 122 |
| 123 // Signal the subclass we're stopping. | 123 // Signal the subclass we're stopping. |
| 124 OnStop(callback); | 124 OnStop(callback); |
| 125 } | 125 } |
| 126 | 126 |
| 127 void VideoRendererBase::SetPlaybackRate(float playback_rate) { | 127 void VideoRendererBase::SetPlaybackRate(float playback_rate) { |
| 128 base::AutoLock auto_lock(lock_); | 128 base::AutoLock auto_lock(lock_); |
| 129 playback_rate_ = playback_rate; | 129 playback_rate_ = playback_rate; |
| 130 } | 130 } |
| 131 | 131 |
| 132 void VideoRendererBase::Seek(base::TimeDelta time, FilterCallback* callback) { | 132 void VideoRendererBase::Seek(base::TimeDelta time, const FilterStatusCB& cb) { |
| 133 base::AutoLock auto_lock(lock_); | 133 bool run_callback = false; |
| 134 // There is a race condition between filters to receive SeekTask(). | |
| 135 // It turns out we could receive buffer from decoder before seek() | |
| 136 // is called on us. so we do the following: | |
| 137 // kFlushed => ( Receive first buffer or Seek() ) => kSeeking and | |
| 138 // kSeeking => ( Receive enough buffers) => kPrerolled. ) | |
| 139 DCHECK(kPrerolled == state_ || kFlushed == state_ || kSeeking == state_); | |
| 140 | 134 |
| 141 if (state_ == kPrerolled) { | 135 { |
| 142 // Already get enough buffers from decoder. | 136 base::AutoLock auto_lock(lock_); |
| 143 callback->Run(); | 137 // There is a race condition between filters to receive SeekTask(). |
| 144 delete callback; | 138 // It turns out we could receive buffer from decoder before seek() |
| 145 } else { | 139 // is called on us. so we do the following: |
| 146 // Otherwise we are either kFlushed or kSeeking, but without enough buffers; | 140 // kFlushed => ( Receive first buffer or Seek() ) => kSeeking and |
| 147 // we should save the callback function and call it later. | 141 // kSeeking => ( Receive enough buffers) => kPrerolled. ) |
| 148 state_ = kSeeking; | 142 DCHECK(kPrerolled == state_ || kFlushed == state_ || kSeeking == state_); |
| 149 seek_callback_.reset(callback); | 143 DCHECK(!cb.is_null()); |
| 144 DCHECK(seek_cb_.is_null()); | |
| 145 | |
| 146 if (state_ == kPrerolled) { | |
| 147 // Already get enough buffers from decoder. | |
| 148 run_callback = true; | |
| 149 | |
| 150 } else { | |
| 151 // Otherwise we are either kFlushed or kSeeking, but without enough | |
| 152 // buffers we should save the callback function and call it later. | |
| 153 state_ = kSeeking; | |
| 154 seek_cb_ = cb; | |
| 155 } | |
| 156 | |
| 157 seek_timestamp_ = time; | |
| 158 ScheduleRead_Locked(); | |
| 150 } | 159 } |
| 151 | 160 |
| 152 seek_timestamp_ = time; | 161 if (run_callback) |
| 153 ScheduleRead_Locked(); | 162 cb.Run(PIPELINE_OK); |
| 154 } | 163 } |
| 155 | 164 |
| 156 void VideoRendererBase::Initialize(VideoDecoder* decoder, | 165 void VideoRendererBase::Initialize(VideoDecoder* decoder, |
| 157 FilterCallback* callback, | 166 FilterCallback* callback, |
| 158 StatisticsCallback* stats_callback) { | 167 StatisticsCallback* stats_callback) { |
| 159 base::AutoLock auto_lock(lock_); | 168 base::AutoLock auto_lock(lock_); |
| 160 DCHECK(decoder); | 169 DCHECK(decoder); |
| 161 DCHECK(callback); | 170 DCHECK(callback); |
| 162 DCHECK(stats_callback); | 171 DCHECK(stats_callback); |
| 163 DCHECK_EQ(kUninitialized, state_); | 172 DCHECK_EQ(kUninitialized, state_); |
| (...skipping 291 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 455 first_frame = frames_queue_ready_.front(); | 464 first_frame = frames_queue_ready_.front(); |
| 456 if (!first_frame->IsEndOfStream()) { | 465 if (!first_frame->IsEndOfStream()) { |
| 457 frames_queue_ready_.pop_front(); | 466 frames_queue_ready_.pop_front(); |
| 458 current_frame_ = first_frame; | 467 current_frame_ = first_frame; |
| 459 } | 468 } |
| 460 new_frame_available = true; | 469 new_frame_available = true; |
| 461 | 470 |
| 462 // If we reach prerolled state before Seek() is called by pipeline, | 471 // If we reach prerolled state before Seek() is called by pipeline, |
| 463 // |seek_callback_| is not set, we will return immediately during | 472 // |seek_callback_| is not set, we will return immediately during |
| 464 // when Seek() is eventually called. | 473 // when Seek() is eventually called. |
| 465 if ((seek_callback_.get())) { | 474 if (!seek_cb_.is_null()) { |
| 466 seek_callback_->Run(); | 475 CopyAndResetCB(seek_cb_).Run(PIPELINE_OK); |
| 467 seek_callback_.reset(); | |
| 468 } | 476 } |
| 469 } | 477 } |
| 470 } else if (state_ == kFlushing && pending_reads_ == 0 && !pending_paint_) { | 478 } else if (state_ == kFlushing && pending_reads_ == 0 && !pending_paint_) { |
| 471 OnFlushDone(); | 479 OnFlushDone(); |
| 472 } | 480 } |
| 473 | 481 |
| 474 if (new_frame_available) { | 482 if (new_frame_available) { |
| 475 base::AutoUnlock auto_unlock(lock_); | 483 base::AutoUnlock auto_unlock(lock_); |
| 476 OnFrameAvailable(); | 484 OnFrameAvailable(); |
| 477 } | 485 } |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 570 | 578 |
| 571 // Scale our sleep based on the playback rate. | 579 // Scale our sleep based on the playback rate. |
| 572 // TODO(scherkus): floating point badness and degrade gracefully. | 580 // TODO(scherkus): floating point badness and degrade gracefully. |
| 573 return base::TimeDelta::FromMicroseconds( | 581 return base::TimeDelta::FromMicroseconds( |
| 574 static_cast<int64>(sleep.InMicroseconds() / playback_rate)); | 582 static_cast<int64>(sleep.InMicroseconds() / playback_rate)); |
| 575 } | 583 } |
| 576 | 584 |
| 577 void VideoRendererBase::EnterErrorState_Locked(PipelineStatus status) { | 585 void VideoRendererBase::EnterErrorState_Locked(PipelineStatus status) { |
| 578 lock_.AssertAcquired(); | 586 lock_.AssertAcquired(); |
| 579 | 587 |
| 580 scoped_ptr<FilterCallback> callback; | 588 scoped_ptr<FilterCallback> callback; |
|
Ami GONE FROM CHROMIUM
2011/05/12 20:42:16
Typically the reason we have this sort of stack va
acolwell GONE FROM CHROMIUM
2011/05/12 22:30:40
Done.
| |
| 589 FilterStatusCB status_cb; | |
| 590 | |
| 581 switch (state_) { | 591 switch (state_) { |
| 582 case kUninitialized: | 592 case kUninitialized: |
| 583 case kPrerolled: | 593 case kPrerolled: |
| 584 case kPaused: | 594 case kPaused: |
| 585 case kFlushed: | 595 case kFlushed: |
| 586 case kEnded: | 596 case kEnded: |
| 587 case kPlaying: | 597 case kPlaying: |
| 588 break; | 598 break; |
| 589 | 599 |
| 590 case kFlushing: | 600 case kFlushing: |
| 591 CHECK(flush_callback_.get()); | 601 CHECK(flush_callback_.get()); |
| 592 callback.swap(flush_callback_); | 602 callback.swap(flush_callback_); |
| 593 break; | 603 break; |
| 594 | 604 |
| 595 case kSeeking: | 605 case kSeeking: { |
| 596 CHECK(seek_callback_.get()); | 606 CHECK(!seek_cb_.is_null()); |
| 597 callback.swap(seek_callback_); | 607 status_cb = CopyAndResetCB(seek_cb_); |
|
Ami GONE FROM CHROMIUM
2011/05/12 20:42:16
std::swap() fits in better here, esp. if you take
acolwell GONE FROM CHROMIUM
2011/05/12 22:30:40
Done.
| |
| 598 break; | 608 } break; |
|
Ami GONE FROM CHROMIUM
2011/05/12 20:42:16
braces should be unnecessary.
acolwell GONE FROM CHROMIUM
2011/05/12 22:30:40
Done.
| |
| 599 | 609 |
| 600 case kStopped: | 610 case kStopped: |
| 601 NOTREACHED() << "Should not error if stopped."; | 611 NOTREACHED() << "Should not error if stopped."; |
| 602 return; | 612 return; |
| 603 | 613 |
| 604 case kError: | 614 case kError: |
| 605 return; | 615 return; |
| 606 } | 616 } |
| 607 state_ = kError; | 617 state_ = kError; |
| 618 | |
| 619 if (!status_cb.is_null()) { | |
| 620 status_cb.Run(status); | |
| 621 return; | |
| 622 } | |
| 623 | |
| 608 host()->SetError(status); | 624 host()->SetError(status); |
|
Ami GONE FROM CHROMIUM
2011/05/12 20:42:16
Is it really right to not set the host's error sta
acolwell GONE FROM CHROMIUM
2011/05/12 22:30:40
Yes. Calling host()->SetError() is the old style o
Ami GONE FROM CHROMIUM
2011/05/12 22:49:25
I understand this, but I'm questioning whether the
acolwell GONE FROM CHROMIUM
2011/05/13 00:49:10
Sorry I wasn't clear. Yes this is safe because in
| |
| 609 | 625 |
| 610 if (callback.get()) | 626 if (callback.get()) |
| 611 callback->Run(); | 627 callback->Run(); |
| 612 } | 628 } |
| 613 | 629 |
| 614 } // namespace media | 630 } // namespace media |
| OLD | NEW |