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

Unified Diff: media/filters/ffmpeg_video_decoder.cc

Issue 331863004: Revert 276344 "Add callback in VideoDecoder and AudioDecoder to ..." (Closed) Base URL: svn://svn.chromium.org/chrome/branches/2049/src/
Patch Set: Created 6 years, 6 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/ffmpeg_video_decoder_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: media/filters/ffmpeg_video_decoder.cc
===================================================================
--- media/filters/ffmpeg_video_decoder.cc (revision 277175)
+++ media/filters/ffmpeg_video_decoder.cc (working copy)
@@ -151,11 +151,10 @@
void FFmpegVideoDecoder::Initialize(const VideoDecoderConfig& config,
bool low_delay,
- const PipelineStatusCB& status_cb,
- const OutputCB& output_cb) {
+ const PipelineStatusCB& status_cb) {
DCHECK(task_runner_->BelongsToCurrentThread());
+ DCHECK(decode_cb_.is_null());
DCHECK(!config.is_encrypted());
- DCHECK(!output_cb.is_null());
FFmpegGlue::InitializeFFmpeg();
@@ -167,8 +166,6 @@
return;
}
- output_cb_ = BindToCurrentLoop(output_cb);
-
// Success!
state_ = kNormal;
initialize_cb.Run(PIPELINE_OK);
@@ -177,25 +174,59 @@
void FFmpegVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer,
const DecodeCB& decode_cb) {
DCHECK(task_runner_->BelongsToCurrentThread());
- DCHECK(buffer);
DCHECK(!decode_cb.is_null());
CHECK_NE(state_, kUninitialized);
+ CHECK(decode_cb_.is_null()) << "Overlapping decodes are not supported.";
+ decode_cb_ = BindToCurrentLoop(decode_cb);
- DecodeCB decode_cb_bound = BindToCurrentLoop(decode_cb);
-
if (state_ == kError) {
- decode_cb_bound.Run(kDecodeError);
+ base::ResetAndReturn(&decode_cb_).Run(kDecodeError, NULL);
return;
}
+ // Return empty frames if decoding has finished.
if (state_ == kDecodeFinished) {
- output_cb_.Run(VideoFrame::CreateEOSFrame());
- decode_cb_bound.Run(kOk);
+ base::ResetAndReturn(&decode_cb_).Run(kOk, VideoFrame::CreateEOSFrame());
return;
}
- DCHECK_EQ(state_, kNormal);
+ DecodeBuffer(buffer);
+}
+void FFmpegVideoDecoder::Reset(const base::Closure& closure) {
+ DCHECK(task_runner_->BelongsToCurrentThread());
+ DCHECK(decode_cb_.is_null());
+
+ avcodec_flush_buffers(codec_context_.get());
+ state_ = kNormal;
+ task_runner_->PostTask(FROM_HERE, closure);
+}
+
+void FFmpegVideoDecoder::Stop() {
+ DCHECK(task_runner_->BelongsToCurrentThread());
+
+ if (state_ == kUninitialized)
+ return;
+
+ ReleaseFFmpegResources();
+ state_ = kUninitialized;
+}
+
+FFmpegVideoDecoder::~FFmpegVideoDecoder() {
+ DCHECK_EQ(kUninitialized, state_);
+ DCHECK(!codec_context_);
+ DCHECK(!av_frame_);
+}
+
+void FFmpegVideoDecoder::DecodeBuffer(
+ const scoped_refptr<DecoderBuffer>& buffer) {
+ DCHECK(task_runner_->BelongsToCurrentThread());
+ DCHECK_NE(state_, kUninitialized);
+ DCHECK_NE(state_, kDecodeFinished);
+ DCHECK_NE(state_, kError);
+ DCHECK(!decode_cb_.is_null());
+ DCHECK(buffer);
+
// During decode, because reads are issued asynchronously, it is possible to
// receive multiple end of stream buffers since each decode is acked. When the
// first end of stream buffer is read, FFmpeg may still have frames queued
@@ -205,65 +236,57 @@
//
// kNormal: This is the starting state. Buffers are decoded. Decode errors
// are discarded.
+ // kFlushCodec: There isn't any more input data. Call avcodec_decode_video2
+ // until no more data is returned to flush out remaining
+ // frames. The input buffer is ignored at this point.
// kDecodeFinished: All calls return empty frames.
// kError: Unexpected error happened.
//
// These are the possible state transitions.
//
- // kNormal -> kDecodeFinished:
- // When EOS buffer is received and the codec has been flushed.
+ // kNormal -> kFlushCodec:
+ // When buffer->end_of_stream() is first true.
// kNormal -> kError:
// A decoding error occurs and decoding needs to stop.
+ // kFlushCodec -> kDecodeFinished:
+ // When avcodec_decode_video2() returns 0 data.
+ // kFlushCodec -> kError:
+ // When avcodec_decode_video2() errors out.
// (any state) -> kNormal:
// Any time Reset() is called.
- bool has_produced_frame;
- do {
- has_produced_frame = false;
- if (!FFmpegDecode(buffer, &has_produced_frame)) {
- state_ = kError;
- decode_cb_bound.Run(kDecodeError);
- return;
- }
- // Repeat to flush the decoder after receiving EOS buffer.
- } while (buffer->end_of_stream() && has_produced_frame);
+ // Transition to kFlushCodec on the first end of stream buffer.
+ if (state_ == kNormal && buffer->end_of_stream()) {
+ state_ = kFlushCodec;
+ }
- if (buffer->end_of_stream()) {
- output_cb_.Run(VideoFrame::CreateEOSFrame());
- state_ = kDecodeFinished;
+ scoped_refptr<VideoFrame> video_frame;
+ if (!FFmpegDecode(buffer, &video_frame)) {
+ state_ = kError;
+ base::ResetAndReturn(&decode_cb_).Run(kDecodeError, NULL);
+ return;
}
- decode_cb_bound.Run(kOk);
-}
+ if (!video_frame.get()) {
+ if (state_ == kFlushCodec) {
+ DCHECK(buffer->end_of_stream());
+ state_ = kDecodeFinished;
+ base::ResetAndReturn(&decode_cb_)
+ .Run(kOk, VideoFrame::CreateEOSFrame());
+ return;
+ }
-void FFmpegVideoDecoder::Reset(const base::Closure& closure) {
- DCHECK(task_runner_->BelongsToCurrentThread());
-
- avcodec_flush_buffers(codec_context_.get());
- state_ = kNormal;
- task_runner_->PostTask(FROM_HERE, closure);
-}
-
-void FFmpegVideoDecoder::Stop() {
- DCHECK(task_runner_->BelongsToCurrentThread());
-
- if (state_ == kUninitialized)
+ base::ResetAndReturn(&decode_cb_).Run(kNotEnoughData, NULL);
return;
+ }
- ReleaseFFmpegResources();
- state_ = kUninitialized;
+ base::ResetAndReturn(&decode_cb_).Run(kOk, video_frame);
}
-FFmpegVideoDecoder::~FFmpegVideoDecoder() {
- DCHECK_EQ(kUninitialized, state_);
- DCHECK(!codec_context_);
- DCHECK(!av_frame_);
-}
-
bool FFmpegVideoDecoder::FFmpegDecode(
const scoped_refptr<DecoderBuffer>& buffer,
- bool* has_produced_frame) {
- DCHECK(!*has_produced_frame);
+ scoped_refptr<VideoFrame>* video_frame) {
+ DCHECK(video_frame);
// Create a packet for input data.
// Due to FFmpeg API changes we no longer have const read-only pointers.
@@ -288,6 +311,7 @@
// Log the problem if we can't decode a video frame and exit early.
if (result < 0) {
LOG(ERROR) << "Error decoding video: " << buffer->AsHumanReadableString();
+ *video_frame = NULL;
return false;
}
@@ -301,6 +325,7 @@
// 1) Decoder was recently initialized/flushed
// 2) End of stream was reached and all internal frames have been output
if (frame_decoded == 0) {
+ *video_frame = NULL;
return true;
}
@@ -311,16 +336,16 @@
!av_frame_->data[VideoFrame::kUPlane] ||
!av_frame_->data[VideoFrame::kVPlane]) {
LOG(ERROR) << "Video frame was produced yet has invalid frame data.";
+ *video_frame = NULL;
av_frame_unref(av_frame_.get());
return false;
}
- scoped_refptr<VideoFrame> frame =
+ *video_frame =
reinterpret_cast<VideoFrame*>(av_buffer_get_opaque(av_frame_->buf[0]));
- frame->set_timestamp(
+
+ (*video_frame)->set_timestamp(
base::TimeDelta::FromMicroseconds(av_frame_->reordered_opaque));
- *has_produced_frame = true;
- output_cb_.Run(frame);
av_frame_unref(av_frame_.get());
return true;
« no previous file with comments | « media/filters/ffmpeg_video_decoder.h ('k') | media/filters/ffmpeg_video_decoder_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698