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

Unified Diff: media/filters/video_renderer_base.cc

Issue 8417019: Simplify VideoDecodeEngine interface by making everything synchronous. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: recycling: vanquished Created 9 years, 2 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 side-by-side diff with in-line comments
Download patch
Index: media/filters/video_renderer_base.cc
diff --git a/media/filters/video_renderer_base.cc b/media/filters/video_renderer_base.cc
index fca51ca80f41cdd234075373512b8549d613c038..3752e080a850007e4323df1e859d276a04de67ac 100644
--- a/media/filters/video_renderer_base.cc
+++ b/media/filters/video_renderer_base.cc
@@ -30,10 +30,12 @@ VideoRendererBase::VideoRendererBase()
: frame_available_(&lock_),
state_(kUninitialized),
thread_(base::kNullThreadHandle),
- pending_reads_(0),
+ pending_read_(false),
pending_paint_(false),
pending_paint_with_last_available_(false),
- playback_rate_(0) {
+ playback_rate_(0),
+ frame_ready_cb_(base::Bind(&VideoRendererBase::FrameReady,
+ base::Unretained(this))) {
}
VideoRendererBase::~VideoRendererBase() {
@@ -61,8 +63,7 @@ void VideoRendererBase::Flush(const base::Closure& callback) {
flush_callback_ = callback;
state_ = kFlushing;
- if (!pending_paint_)
- FlushBuffers_Locked();
+ AttemptFlush_Locked();
}
void VideoRendererBase::Stop(const base::Closure& callback) {
@@ -72,7 +73,7 @@ void VideoRendererBase::Stop(const base::Closure& callback) {
state_ = kStopped;
if (!pending_paint_ && !pending_paint_with_last_available_)
- DoStopOrErrorFlush_Locked();
+ DoStopOrError_Locked();
// Clean up our thread if present.
if (thread_) {
acolwell GONE FROM CHROMIUM 2011/11/01 18:31:03 Given the code below shouldn't this be (thread_ !=
scherkus (not reviewing) 2011/11/03 04:55:59 Done.
@@ -120,7 +121,7 @@ void VideoRendererBase::Seek(base::TimeDelta time, const FilterStatusCB& cb) {
}
seek_timestamp_ = time;
- ScheduleRead_Locked();
+ AttemptRead_Locked();
}
if (run_callback)
@@ -139,10 +140,6 @@ void VideoRendererBase::Initialize(VideoDecoder* decoder,
statistics_callback_ = stats_callback;
- decoder_->set_consume_video_frame_callback(
- base::Bind(&VideoRendererBase::ConsumeVideoFrame,
- base::Unretained(this)));
-
// Notify the pipeline of the video dimensions.
host()->SetNaturalVideoSize(decoder_->natural_size());
@@ -269,7 +266,7 @@ void VideoRendererBase::ThreadMain() {
// 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
+ // 2. we do not have a current frame yet; 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
@@ -290,11 +287,10 @@ void VideoRendererBase::ThreadMain() {
if (remaining_time.InMicroseconds() > 0)
break;
- // Frame dropped: transfer ready frame into done queue and read again.
- frames_queue_done_.push_back(frames_queue_ready_.front());
- frames_queue_ready_.pop_front();
- ScheduleRead_Locked();
+ // Frame dropped: read again.
++frames_dropped;
+ frames_queue_ready_.pop_front();
+ AttemptRead_Locked();
}
// Continue waiting for the current paint to finish.
@@ -305,10 +301,9 @@ void VideoRendererBase::ThreadMain() {
//
// We can now safely update the current frame, request another frame, and
// signal to the client that a new frame is available.
- frames_queue_done_.push_back(current_frame_);
current_frame_ = frames_queue_ready_.front();
frames_queue_ready_.pop_front();
- ScheduleRead_Locked();
+ AttemptRead_Locked();
base::AutoUnlock auto_unlock(lock_);
OnFrameAvailable();
@@ -320,8 +315,7 @@ void VideoRendererBase::GetCurrentFrame(scoped_refptr<VideoFrame>* frame_out) {
DCHECK(!pending_paint_ && !pending_paint_with_last_available_);
if ((!current_frame_ || current_frame_->IsEndOfStream()) &&
- (!last_available_frame_ ||
- last_available_frame_->IsEndOfStream())) {
+ (!last_available_frame_ || last_available_frame_->IsEndOfStream())) {
*frame_out = NULL;
return;
}
@@ -364,161 +358,120 @@ void VideoRendererBase::PutCurrentFrame(scoped_refptr<VideoFrame> frame) {
// frame when this is true.
frame_available_.Signal();
if (state_ == kFlushing) {
- FlushBuffers_Locked();
+ AttemptFlush_Locked();
} else if (state_ == kError || state_ == kStopped) {
- DoStopOrErrorFlush_Locked();
+ DoStopOrError_Locked();
}
}
-void VideoRendererBase::ConsumeVideoFrame(scoped_refptr<VideoFrame> frame) {
- if (frame) {
- PipelineStatistics statistics;
- statistics.video_frames_decoded = 1;
- statistics_callback_.Run(statistics);
- }
+void VideoRendererBase::FrameReady(scoped_refptr<VideoFrame> frame) {
+ DCHECK(frame);
base::AutoLock auto_lock(lock_);
-
- if (!frame) {
- EnterErrorState_Locked(PIPELINE_ERROR_DECODE);
acolwell GONE FROM CHROMIUM 2011/11/01 18:31:03 Why not keep this?
- return;
- }
-
- // Decoder could reach seek state before our Seek() get called.
- // We will enter kSeeking
- if (state_ == kFlushed)
- state_ = kSeeking;
-
- // Synchronous flush between filters should prevent this from happening.
- DCHECK_NE(state_, kStopped);
- if (frame && !frame->IsEndOfStream())
- --pending_reads_;
-
DCHECK_NE(state_, kUninitialized);
DCHECK_NE(state_, kStopped);
DCHECK_NE(state_, kError);
+ CHECK(pending_read_);
Ami GONE FROM CHROMIUM 2011/11/01 22:17:40 DCHECK?
scherkus (not reviewing) 2011/11/03 04:55:59 Again this one of those things where a callback wa
- if (state_ == kPaused || state_ == kFlushing) {
- // Decoder are flushing rubbish video frame, we will not display them.
- if (frame && !frame->IsEndOfStream())
- frames_queue_done_.push_back(frame);
- DCHECK_LE(frames_queue_done_.size(),
- static_cast<size_t>(Limits::kMaxVideoFrames));
+ pending_read_ = false;
- // Excluding kPause here, because in pause state, we will never
- // 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_Locked();
+ // Decoder could reach seek state before our Seek() get called.
Ami GONE FROM CHROMIUM 2011/11/01 22:17:40 s/get/got/
+ // We will enter kSeeking
+ if (state_ == kFlushed) {
+ CHECK(false) << "I don't think this is possible";
Ami GONE FROM CHROMIUM 2011/11/01 22:17:40 CHECK(false) is always better spelled LOG(FATAL) B
scherkus (not reviewing) 2011/11/03 04:55:59 Left these CHECK()s in for local testing -- they w
+ //state_ = kSeeking;
+ return;
+ }
+ if (state_ == kPaused) {
acolwell GONE FROM CHROMIUM 2011/11/01 18:31:03 Can't this happen based on the "Prerolling while p
scherkus (not reviewing) 2011/11/03 04:55:59 I believe it can: T1: VRB holds lock inside FrameR
+ CHECK(false) << "I don't think this is possible";
+ //frame_queue_ready_.push_back(video_frame);
+ return;
+ }
+
+ if (state_ == kFlushing) {
+ AttemptFlush_Locked();
return;
}
// Discard frames until we reach our desired seek timestamp.
if (state_ == kSeeking && !frame->IsEndOfStream() &&
(frame->GetTimestamp() + frame->GetDuration()) <= seek_timestamp_) {
- frames_queue_done_.push_back(frame);
- ScheduleRead_Locked();
- } else {
- frames_queue_ready_.push_back(frame);
- DCHECK_LE(frames_queue_ready_.size(),
- static_cast<size_t>(Limits::kMaxVideoFrames));
- frame_available_.Signal();
+ AttemptRead_Locked();
+ return;
}
- // Check for our preroll complete condition.
- bool new_frame_available = false;
+ // This one's a keeper! Place it in the ready queue.
+ frames_queue_ready_.push_back(frame);
+ DCHECK_LE(frames_queue_ready_.size(),
+ static_cast<size_t>(Limits::kMaxVideoFrames));
+ frame_available_.Signal();
+
+ PipelineStatistics statistics;
+ statistics.video_frames_decoded = 1;
+ statistics_callback_.Run(statistics);
+
+ // Always request more decoded video if we have capacity. This serves two
+ // purposes:
+ // 1) Prerolling while paused
+ // 2) Keeps decoding going if video rendering thread starts falling behind
+ if (frames_queue_ready_.size() < Limits::kMaxVideoFrames &&
+ !frame->IsEndOfStream()) {
+ AttemptRead_Locked();
+ return;
+ }
+
+ // If we're at capacity or end of stream while seeking we need to transition
+ // to prerolled.
if (state_ == kSeeking) {
- if (frames_queue_ready_.size() == Limits::kMaxVideoFrames ||
- frame->IsEndOfStream()) {
- // We're paused, so make sure we update |current_frame_| to represent
- // our new location.
- state_ = kPrerolled;
-
- // Because we might remain paused (i.e., we were not playing before we
- // received a seek), we can't rely on ThreadMain() to notify the subclass
- // the frame has been updated.
- scoped_refptr<VideoFrame> first_frame;
- first_frame = frames_queue_ready_.front();
- if (!first_frame->IsEndOfStream()) {
- frames_queue_ready_.pop_front();
- current_frame_ = first_frame;
- }
- new_frame_available = true;
+ state_ = kPrerolled;
+
+ // Because we might remain in the prerolled state for an undetermined amount
+ // of time (i.e., we were not playing before we received a seek), we'll
+ // manually update the current frame and notify the subclass below.
+ if (!frames_queue_ready_.front()->IsEndOfStream()) {
+ current_frame_ = frames_queue_ready_.front();
+ frames_queue_ready_.pop_front();
+ }
- // If we reach prerolled state before Seek() is called by pipeline,
- // |seek_callback_| is not set, we will return immediately during
- // when Seek() is eventually called.
- if (!seek_cb_.is_null()) {
- ResetAndRunCB(&seek_cb_, PIPELINE_OK);
- }
+ // If we reach prerolled state before Seek() is called by pipeline,
+ // |seek_callback_| is not set, we will return immediately during
+ // when Seek() is eventually called.
Ami GONE FROM CHROMIUM 2011/11/01 22:17:40 English.
scherkus (not reviewing) 2011/11/03 04:55:59 this and the comments up in Seek() are crazy bizar
+ if (!seek_cb_.is_null()) {
+ ResetAndRunCB(&seek_cb_, PIPELINE_OK);
}
- } else if (state_ == kFlushing && pending_reads_ == 0 && !pending_paint_) {
- OnFlushDone_Locked();
- }
- if (new_frame_available) {
- base::AutoUnlock auto_unlock(lock_);
+ base::AutoUnlock ul(lock_);
OnFrameAvailable();
}
}
-void VideoRendererBase::ReadInput(scoped_refptr<VideoFrame> frame) {
- // We should never return empty frames or EOS frame.
- DCHECK(frame && !frame->IsEndOfStream());
-
- decoder_->ProduceVideoFrame(frame);
- ++pending_reads_;
-}
-
-void VideoRendererBase::ScheduleRead_Locked() {
+void VideoRendererBase::AttemptRead_Locked() {
lock_.AssertAcquired();
DCHECK_NE(kEnded, state_);
- // TODO(jiesun): We use dummy buffer to feed decoder to let decoder to
- // provide buffer pools. In the future, we may want to implement real
- // buffer pool to recycle buffers.
- while (!frames_queue_done_.empty()) {
- scoped_refptr<VideoFrame> video_frame = frames_queue_done_.front();
- frames_queue_done_.pop_front();
- ReadInput(video_frame);
+
+ if (pending_read_ || frames_queue_ready_.size() == Limits::kMaxVideoFrames) {
+ return;
}
+
+ pending_read_ = true;
+ decoder_->Read(frame_ready_cb_);
}
-void VideoRendererBase::FlushBuffers_Locked() {
+void VideoRendererBase::AttemptFlush_Locked() {
lock_.AssertAcquired();
- DCHECK(!pending_paint_);
+ DCHECK_EQ(kFlushing, state_);
- // We should never put EOF frame into "done queue".
+ // Get rid of any ready frames.
while (!frames_queue_ready_.empty()) {
- scoped_refptr<VideoFrame> video_frame = frames_queue_ready_.front();
- if (!video_frame->IsEndOfStream()) {
- frames_queue_done_.push_back(video_frame);
- }
frames_queue_ready_.pop_front();
}
- if (current_frame_ && !current_frame_->IsEndOfStream()) {
- frames_queue_done_.push_back(current_frame_);
- }
- current_frame_ = NULL;
-
- // Flush all buffers out to decoder.
- ScheduleRead_Locked();
-
- if (pending_reads_ == 0 && state_ == kFlushing)
- OnFlushDone_Locked();
-}
-
-void VideoRendererBase::OnFlushDone_Locked() {
- lock_.AssertAcquired();
- // Check all buffers are returned to owners.
- DCHECK_EQ(frames_queue_done_.size(), 0u);
- DCHECK(!current_frame_);
- DCHECK(frames_queue_ready_.empty());
- if (!flush_callback_.is_null()) // This ensures callback is invoked once.
+ if (!pending_paint_ && !pending_read_) {
acolwell GONE FROM CHROMIUM 2011/11/01 18:31:03 I think this may be where you can get into trouble
scherkus (not reviewing) 2011/11/03 04:55:59 Correct -- fixed + updated unit tests
+ state_ = kFlushed;
+ current_frame_ = NULL;
ResetAndRunCB(&flush_callback_);
-
- state_ = kFlushed;
+ }
}
base::TimeDelta VideoRendererBase::CalculateSleepDuration(
@@ -560,7 +513,7 @@ void VideoRendererBase::EnterErrorState_Locked(PipelineStatus status) {
// Flush frames if we aren't in the middle of a paint. If we
// are painting then flushing will happen when the paint completes.
if (!pending_paint_ && !pending_paint_with_last_available_)
- DoStopOrErrorFlush_Locked();
+ DoStopOrError_Locked();
switch (old_state) {
case kUninitialized:
@@ -596,13 +549,12 @@ void VideoRendererBase::EnterErrorState_Locked(PipelineStatus status) {
callback.Run();
}
-void VideoRendererBase::DoStopOrErrorFlush_Locked() {
+void VideoRendererBase::DoStopOrError_Locked() {
DCHECK(!pending_paint_);
DCHECK(!pending_paint_with_last_available_);
lock_.AssertAcquired();
- FlushBuffers_Locked();
last_available_frame_ = NULL;
- DCHECK_EQ(pending_reads_, 0);
+ DCHECK(!pending_read_);
acolwell GONE FROM CHROMIUM 2011/11/01 18:31:03 Looking at the code this doesn't seem like a safe
scherkus (not reviewing) 2011/11/03 04:55:59 I really don't know what this method does but the
}
} // namespace media

Powered by Google App Engine
This is Rietveld 408576698