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

Unified Diff: media/filters/ffmpeg_video_decoder.cc

Issue 3014059: media: recycle buffers/direct rendering etc. (third patch) (Closed)
Patch Set: code review Created 10 years, 4 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
« no previous file with comments | « media/filters/ffmpeg_video_decoder.h ('k') | media/filters/omx_video_decode_engine.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: media/filters/ffmpeg_video_decoder.cc
diff --git a/media/filters/ffmpeg_video_decoder.cc b/media/filters/ffmpeg_video_decoder.cc
index 8b673dc868971d296b5f1e144953f024e60cb3fe..46e4036005e293e7f148ca63acdffa1f8a340552 100644
--- a/media/filters/ffmpeg_video_decoder.cc
+++ b/media/filters/ffmpeg_video_decoder.cc
@@ -26,9 +26,7 @@ FFmpegVideoDecoder::FFmpegVideoDecoder(VideoDecodeEngine* engine)
height_(0),
time_base_(new AVRational()),
state_(kUnInitialized),
- decode_engine_(engine),
- pending_reads_(0),
- pending_requests_(0) {
+ decode_engine_(engine) {
memset(&info_, 0, sizeof(info_));
}
@@ -150,6 +148,19 @@ void FFmpegVideoDecoder::OnUninitializeComplete() {
state_ = kStopped;
}
+void FFmpegVideoDecoder::Pause(FilterCallback* callback) {
+ if (MessageLoop::current() != message_loop()) {
+ message_loop()->PostTask(FROM_HERE,
+ NewRunnableMethod(this,
+ &FFmpegVideoDecoder::Pause,
+ callback));
+ return;
+ }
+
+ AutoCallbackRunner done_runner(callback);
+ state_ = kPausing;
+}
+
void FFmpegVideoDecoder::Flush(FilterCallback* callback) {
if (MessageLoop::current() != message_loop()) {
message_loop()->PostTask(FROM_HERE,
@@ -162,11 +173,11 @@ void FFmpegVideoDecoder::Flush(FilterCallback* callback) {
DCHECK_EQ(MessageLoop::current(), message_loop());
DCHECK(!flush_callback_.get());
- flush_callback_.reset(callback);
+ state_ = kFlushing;
- // Everything in the presentation time queue is invalid, clear the queue.
- while (!pts_heap_.IsEmpty())
- pts_heap_.Pop();
+ FlushBuffers();
+
+ flush_callback_.reset(callback);
decode_engine_->Flush();
}
@@ -176,6 +187,13 @@ void FFmpegVideoDecoder::OnFlushComplete() {
DCHECK(flush_callback_.get());
AutoCallbackRunner done_runner(flush_callback_.release());
+
+ // Everything in the presentation time queue is invalid, clear the queue.
+ while (!pts_heap_.IsEmpty())
+ pts_heap_.Pop();
+
+ // Mark flush operation had been done.
+ state_ = kNormal;
}
void FFmpegVideoDecoder::Seek(base::TimeDelta time,
@@ -192,10 +210,6 @@ void FFmpegVideoDecoder::Seek(base::TimeDelta time,
DCHECK_EQ(MessageLoop::current(), message_loop());
DCHECK(!seek_callback_.get());
- // TODO(jiesun): when we move to parallel Flush, we should remove this.
- DCHECK_EQ(0u, pending_reads_) << "Pending reads should have completed";
- DCHECK_EQ(0u, pending_requests_) << "Pending requests should be empty";
-
seek_callback_.reset(callback);
decode_engine_->Seek();
}
@@ -205,7 +219,6 @@ void FFmpegVideoDecoder::OnSeekComplete() {
DCHECK(seek_callback_.get());
AutoCallbackRunner done_runner(seek_callback_.release());
- state_ = kNormal;
}
void FFmpegVideoDecoder::OnError() {
@@ -227,9 +240,7 @@ void FFmpegVideoDecoder::OnReadComplete(Buffer* buffer_in) {
void FFmpegVideoDecoder::OnReadCompleteTask(scoped_refptr<Buffer> buffer) {
DCHECK_EQ(MessageLoop::current(), message_loop());
- DCHECK_GT(pending_reads_, 0u);
-
- --pending_reads_;
+ DCHECK_NE(state_, kStopped); // because of Flush() before Stop().
// During decode, because reads are issued asynchronously, it is possible to
// receive multiple end of stream buffers since each read is acked. When the
@@ -255,18 +266,6 @@ void FFmpegVideoDecoder::OnReadCompleteTask(scoped_refptr<Buffer> buffer) {
// When avcodec_decode_video2() returns 0 data or errors out.
// (any state) -> kNormal:
// Any time buffer->IsDiscontinuous() is true.
- //
- // If the decoding is finished, we just always return empty frames.
- if (state_ == kDecodeFinished || state_ == kStopped) {
- DCHECK(buffer->IsEndOfStream());
-
- --pending_requests_;
- // Signal VideoRenderer the end of the stream event.
- scoped_refptr<VideoFrame> video_frame;
- VideoFrame::CreateEmptyFrame(&video_frame);
- fill_buffer_done_callback()->Run(video_frame);
- return;
- }
// Transition to kFlushCodec on the first end of stream buffer.
if (state_ == kNormal && buffer->IsEndOfStream()) {
@@ -302,23 +301,35 @@ void FFmpegVideoDecoder::FillThisBuffer(
DCHECK_EQ(MessageLoop::current(), message_loop());
// Synchronized flushing before stop should prevent this.
- if (state_ == kStopped)
- return; // Discard the video frame.
+ DCHECK_NE(state_, kStopped);
+
+ // If the decoding is finished, we just always return empty frames.
+ if (state_ == kDecodeFinished) {
+ // Signal VideoRenderer the end of the stream event.
+ scoped_refptr<VideoFrame> empty_frame;
+ VideoFrame::CreateEmptyFrame(&empty_frame);
+ fill_buffer_done_callback()->Run(empty_frame);
+
+ // Fall through, because we still need to keep record of this frame.
+ }
// Notify decode engine the available of new frame.
- ++pending_requests_;
decode_engine_->FillThisBuffer(video_frame);
}
void FFmpegVideoDecoder::OnFillBufferCallback(
scoped_refptr<VideoFrame> video_frame) {
DCHECK_EQ(MessageLoop::current(), message_loop());
-
- // TODO(jiesun): Flush before stop will prevent this from happening.
- if (state_ == kStopped)
- return; // Discard the video frame.
+ DCHECK_NE(state_, kStopped);
if (video_frame.get()) {
+ if (kPausing == state_ || kFlushing == state_) {
+ frame_queue_flushed_.push_back(video_frame);
+ if (kFlushing == state_)
+ FlushBuffers();
+ return;
+ }
+
// If we actually got data back, enqueue a frame.
last_pts_ = FindPtsAndDuration(*time_base_, &pts_heap_, last_pts_,
video_frame.get());
@@ -326,8 +337,6 @@ void FFmpegVideoDecoder::OnFillBufferCallback(
video_frame->SetTimestamp(last_pts_.timestamp);
video_frame->SetDuration(last_pts_.duration);
- // Deliver this frame to VideoRenderer.
- --pending_requests_;
fill_buffer_done_callback()->Run(video_frame);
} else {
// When in kFlushCodec, any errored decode, or a 0-lengthed frame,
@@ -335,7 +344,6 @@ void FFmpegVideoDecoder::OnFillBufferCallback(
if (state_ == kFlushCodec) {
state_ = kDecodeFinished;
- --pending_requests_;
// Signal VideoRenderer the end of the stream event.
scoped_refptr<VideoFrame> video_frame;
VideoFrame::CreateEmptyFrame(&video_frame);
@@ -347,11 +355,10 @@ void FFmpegVideoDecoder::OnFillBufferCallback(
void FFmpegVideoDecoder::OnEmptyBufferCallback(
scoped_refptr<Buffer> buffer) {
DCHECK_EQ(MessageLoop::current(), message_loop());
- DCHECK_LE(pending_reads_, pending_requests_);
+ DCHECK_NE(state_, kStopped);
demuxer_stream_->Read(
NewCallback(this, &FFmpegVideoDecoder::OnReadComplete));
- ++pending_reads_;
}
FFmpegVideoDecoder::TimeTuple FFmpegVideoDecoder::FindPtsAndDuration(
@@ -408,6 +415,21 @@ bool FFmpegVideoDecoder::ProvidesBuffer() {
return info_.provides_buffers_;
}
+void FFmpegVideoDecoder::FlushBuffers() {
+ while (!frame_queue_flushed_.empty()) {
+ scoped_refptr<VideoFrame> video_frame;
+ video_frame = frame_queue_flushed_.front();
+ frame_queue_flushed_.pop_front();
+
+ // Depends on who own the buffers, we either return it to the renderer
+ // or return it to the decode engine.
+ if (ProvidesBuffer())
+ decode_engine_->FillThisBuffer(video_frame);
+ else
+ fill_buffer_done_callback()->Run(video_frame);
+ }
+}
+
void FFmpegVideoDecoder::SetVideoDecodeEngineForTest(
VideoDecodeEngine* engine) {
decode_engine_ = engine;
« no previous file with comments | « media/filters/ffmpeg_video_decoder.h ('k') | media/filters/omx_video_decode_engine.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698