Index: media/filters/video_renderer_base.cc |
diff --git a/media/filters/video_renderer_base.cc b/media/filters/video_renderer_base.cc |
index ce94d33a261bb36cec255ad77da2b9ac2ebe463c..b40ec67f4e8c0e736e860c5cb14480754b5da661 100644 |
--- a/media/filters/video_renderer_base.cc |
+++ b/media/filters/video_renderer_base.cc |
@@ -58,14 +58,13 @@ void VideoRendererBase::Pause(FilterCallback* callback) { |
} |
void VideoRendererBase::Flush(FilterCallback* callback) { |
- DCHECK_EQ(state_, kPaused); |
- |
base::AutoLock auto_lock(lock_); |
+ DCHECK_EQ(state_, kPaused); |
flush_callback_.reset(callback); |
state_ = kFlushing; |
- if (pending_paint_ == false) |
- FlushBuffers(); |
+ if (!pending_paint_) |
+ FlushBuffers_Locked(); |
} |
void VideoRendererBase::Stop(FilterCallback* callback) { |
@@ -108,7 +107,7 @@ void VideoRendererBase::Seek(base::TimeDelta time, const FilterStatusCB& cb) { |
// is called on us. so we do the following: |
// kFlushed => ( Receive first buffer or Seek() ) => kSeeking and |
// kSeeking => ( Receive enough buffers) => kPrerolled. ) |
- DCHECK(kPrerolled == state_ || kFlushed == state_ || kSeeking == state_); |
+ DCHECK(state_ == kPrerolled || state_ == kFlushed || state_ == kSeeking); |
DCHECK(!cb.is_null()); |
DCHECK(seek_cb_.is_null()); |
@@ -261,48 +260,54 @@ void VideoRendererBase::ThreadMain() { |
continue; |
} |
- if (next_frame->GetTimestamp() <= host()->GetTime() + kIdleTimeDelta || |
- current_frame_.get() == NULL || |
- current_frame_->GetTimestamp() > host()->GetDuration()) { |
- // 1. either next frame's time-stamp is already current. |
- // 2. or we do not have any current frame yet anyway. |
- // 3. or a special case when the stream is badly formatted that |
- // we get video frame with time-stamp greater than the duration. |
- // In this case we should proceed anyway and try to obtain the |
- // end-of-stream packet. |
- scoped_refptr<VideoFrame> timeout_frame; |
- bool new_frame_available = false; |
- if (!pending_paint_) { |
- // In this case, current frame could be recycled. |
- timeout_frame = current_frame_; |
- current_frame_ = frames_queue_ready_.front(); |
+ // Normally we're ready to loop again at this point, but there are |
+ // exceptions that cause us to drop a frame and/or consider painting a |
+ // "next" frame. |
+ if (next_frame->GetTimestamp() > host()->GetTime() + kIdleTimeDelta && |
+ current_frame_ && |
+ current_frame_->GetTimestamp() <= host()->GetDuration()) { |
+ continue; |
+ } |
+ |
+ // If we got here then: |
+ // 1. next frame's timestamp is already current; or |
+ // 2. we do not have any current frame yet anyway; or |
+ // 3. a special case when the stream is badly formatted and |
+ // we got a frame with timestamp greater than overall duration. |
+ // In this case we should proceed anyway and try to obtain the |
+ // end-of-stream packet. |
+ scoped_refptr<VideoFrame> timeout_frame; |
+ bool new_frame_available = false; |
+ if (!pending_paint_) { |
+ // In this case, current frame could be recycled. |
+ timeout_frame = current_frame_; |
+ current_frame_ = frames_queue_ready_.front(); |
+ frames_queue_ready_.pop_front(); |
+ new_frame_available = true; |
+ } else if (pending_paint_ && frames_queue_ready_.size() >= 2 && |
+ !frames_queue_ready_[1]->IsEndOfStream()) { |
+ // Painter could be really slow, therefore we had to skip frames if |
+ // 1. We had not reached end of stream. |
+ // 2. The next frame of current frame is also out-dated. |
+ base::TimeDelta next_remaining_time = |
+ frames_queue_ready_[1]->GetTimestamp() - host()->GetTime(); |
+ if (next_remaining_time.InMicroseconds() <= 0) { |
+ // Since the current frame is still hold by painter/compositor, and |
+ // the next frame is already timed-out, we should skip the next frame |
+ // which is the first frame in the queue. |
+ timeout_frame = frames_queue_ready_.front(); |
frames_queue_ready_.pop_front(); |
- new_frame_available = true; |
- } else if (pending_paint_ && frames_queue_ready_.size() >= 2 && |
- !frames_queue_ready_[1]->IsEndOfStream()) { |
- // Painter could be really slow, therefore we had to skip frames if |
- // 1. We had not reached end of stream. |
- // 2. The next frame of current frame is also out-dated. |
- base::TimeDelta next_remaining_time = |
- frames_queue_ready_[1]->GetTimestamp() - host()->GetTime(); |
- if (next_remaining_time.InMicroseconds() <= 0) { |
- // Since the current frame is still hold by painter/compositor, and |
- // the next frame is already timed-out, we should skip the next frame |
- // which is the first frame in the queue. |
- timeout_frame = frames_queue_ready_.front(); |
- frames_queue_ready_.pop_front(); |
- ++frames_dropped; |
- } |
- } |
- if (timeout_frame.get()) { |
- frames_queue_done_.push_back(timeout_frame); |
- ScheduleRead_Locked(); |
- } |
- if (new_frame_available) { |
- base::AutoUnlock auto_unlock(lock_); |
- OnFrameAvailable(); |
+ ++frames_dropped; |
} |
} |
+ if (timeout_frame.get()) { |
+ frames_queue_done_.push_back(timeout_frame); |
+ ScheduleRead_Locked(); |
+ } |
+ if (new_frame_available) { |
+ base::AutoUnlock auto_unlock(lock_); |
+ OnFrameAvailable(); |
+ } |
} |
} |
@@ -342,6 +347,7 @@ void VideoRendererBase::PutCurrentFrame(scoped_refptr<VideoFrame> frame) { |
pending_paint_ = false; |
} else if (pending_paint_with_last_available_) { |
DCHECK(last_available_frame_.get() == frame.get()); |
+ DCHECK(!pending_paint_); |
pending_paint_with_last_available_ = false; |
} else { |
DCHECK(frame.get() == NULL); |
@@ -352,7 +358,7 @@ void VideoRendererBase::PutCurrentFrame(scoped_refptr<VideoFrame> frame) { |
// frame when this is true. |
frame_available_.Signal(); |
if (state_ == kFlushing) { |
- FlushBuffers(); |
+ FlushBuffers_Locked(); |
} else if (state_ == kError || state_ == kStopped) { |
DoStopOrErrorFlush_Locked(); |
} |
@@ -374,7 +380,7 @@ void VideoRendererBase::ConsumeVideoFrame(scoped_refptr<VideoFrame> frame) { |
// Decoder could reach seek state before our Seek() get called. |
// We will enter kSeeking |
- if (kFlushed == state_) |
+ if (state_ == kFlushed) |
state_ = kSeeking; |
// Synchronous flush between filters should prevent this from happening. |
@@ -395,7 +401,7 @@ void VideoRendererBase::ConsumeVideoFrame(scoped_refptr<VideoFrame> frame) { |
// transfer out-bounding buffer. We do not flush buffer when Compositor |
// hold reference to our video frame either. |
if (state_ == kFlushing && pending_paint_ == false) |
- FlushBuffers(); |
+ FlushBuffers_Locked(); |
return; |
} |
@@ -440,7 +446,7 @@ void VideoRendererBase::ConsumeVideoFrame(scoped_refptr<VideoFrame> frame) { |
} |
} |
} else if (state_ == kFlushing && pending_reads_ == 0 && !pending_paint_) { |
- OnFlushDone(); |
+ OnFlushDone_Locked(); |
} |
if (new_frame_available) { |
@@ -470,7 +476,8 @@ void VideoRendererBase::ScheduleRead_Locked() { |
} |
} |
-void VideoRendererBase::FlushBuffers() { |
+void VideoRendererBase::FlushBuffers_Locked() { |
+ lock_.AssertAcquired(); |
DCHECK(!pending_paint_); |
// We should never put EOF frame into "done queue". |
@@ -490,11 +497,12 @@ void VideoRendererBase::FlushBuffers() { |
ScheduleRead_Locked(); |
if (pending_reads_ == 0 && state_ == kFlushing) |
- OnFlushDone(); |
+ OnFlushDone_Locked(); |
} |
-void VideoRendererBase::OnFlushDone() { |
- // Check all buffers are return to owners. |
+void VideoRendererBase::OnFlushDone_Locked() { |
+ lock_.AssertAcquired(); |
+ // Check all buffers are returned to owners. |
DCHECK_EQ(frames_queue_done_.size(), 0u); |
DCHECK(!current_frame_.get()); |
DCHECK(frames_queue_ready_.empty()); |
@@ -585,7 +593,7 @@ void VideoRendererBase::DoStopOrErrorFlush_Locked() { |
DCHECK(!pending_paint_); |
DCHECK(!pending_paint_with_last_available_); |
lock_.AssertAcquired(); |
- FlushBuffers(); |
+ FlushBuffers_Locked(); |
last_available_frame_ = NULL; |
DCHECK_EQ(pending_reads_, 0); |
} |