Chromium Code Reviews| Index: media/filters/ffmpeg_video_decoder.cc |
| diff --git a/media/filters/ffmpeg_video_decoder.cc b/media/filters/ffmpeg_video_decoder.cc |
| index bc2346ddf8843526fde8ae980e847488e7ba0b13..d55d82eed591d67e6e01f1bcce394fb5eb9ff3ad 100644 |
| --- a/media/filters/ffmpeg_video_decoder.cc |
| +++ b/media/filters/ffmpeg_video_decoder.cc |
| @@ -135,10 +135,11 @@ static void ReleaseVideoBufferImpl(AVCodecContext* s, AVFrame* frame) { |
| void FFmpegVideoDecoder::Initialize(const VideoDecoderConfig& config, |
| bool low_delay, |
| - const PipelineStatusCB& status_cb) { |
| + const PipelineStatusCB& status_cb, |
| + const OutputCB& output_cb) { |
| DCHECK(task_runner_->BelongsToCurrentThread()); |
| - DCHECK(decode_cb_.is_null()); |
| DCHECK(!config.is_encrypted()); |
| + DCHECK(!output_cb.is_null()); |
| FFmpegGlue::InitializeFFmpeg(); |
| @@ -150,6 +151,8 @@ void FFmpegVideoDecoder::Initialize(const VideoDecoderConfig& config, |
| return; |
| } |
| + output_cb_ = BindToCurrentLoop(output_cb); |
| + |
| // Success! |
| state_ = kNormal; |
| initialize_cb.Run(PIPELINE_OK); |
| @@ -158,58 +161,25 @@ void FFmpegVideoDecoder::Initialize(const VideoDecoderConfig& config, |
| 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) { |
| - base::ResetAndReturn(&decode_cb_).Run(kDecodeError, NULL); |
| + decode_cb_bound.Run(kDecodeError); |
| return; |
| } |
| // Return empty frames if decoding has finished. |
| if (state_ == kDecodeFinished) { |
| - base::ResetAndReturn(&decode_cb_).Run(kOk, VideoFrame::CreateEOSFrame()); |
| + output_cb_.Run(VideoFrame::CreateEOSFrame()); |
| + decode_cb_bound.Run(kOk); |
| return; |
| } |
| - 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); |
| + DCHECK_EQ(state_, kNormal); |
| // During decode, because reads are issued asynchronously, it is possible to |
| // receive multiple end of stream buffers since each decode is acked. When the |
| @@ -228,43 +198,63 @@ void FFmpegVideoDecoder::DecodeBuffer( |
| // |
| // These are the possible state transitions. |
| // |
| - // kNormal -> kFlushCodec: |
| - // When buffer->end_of_stream() is first true. |
| + // kNormal -> kDecodeFinished: |
| + // When EOS buffer is received. |
| // 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. |
| - // Transition to kFlushCodec on the first end of stream buffer. |
| - if (state_ == kNormal && buffer->end_of_stream()) { |
| - state_ = kFlushCodec; |
| + // Flush the decoder after receiving EOS buffer. |
| + if (buffer->end_of_stream()) { |
| + scoped_refptr<VideoFrame> video_frame; |
| + do { |
| + if (!FFmpegDecode(buffer, &video_frame)) { |
| + state_ = kError; |
| + decode_cb_bound.Run(kDecodeError); |
| + return; |
| + } |
| + if (video_frame) |
| + output_cb_.Run(video_frame); |
| + } while (video_frame); |
| + output_cb_.Run(VideoFrame::CreateEOSFrame()); |
| + state_ = kDecodeFinished; |
| + } else { |
| + scoped_refptr<VideoFrame> video_frame; |
| + if (!FFmpegDecode(buffer, &video_frame)) { |
| + state_ = kError; |
| + decode_cb_bound.Run(kDecodeError); |
| + return; |
| + } |
| + if (video_frame) |
| + output_cb_.Run(video_frame); |
|
xhwang
2014/05/29 22:15:14
You can probably wrap l.223-230 into a helper func
Sergey Ulanov
2014/06/03 00:08:11
Formatted this code to avoid duplication.
|
| } |
| - 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()); |
| - base::ResetAndReturn(&decode_cb_).Run(kNotEnoughData, NULL); |
| + if (state_ == kUninitialized) |
| return; |
| - } |
| - base::ResetAndReturn(&decode_cb_).Run(kOk, video_frame); |
| + ReleaseFFmpegResources(); |
| + state_ = kUninitialized; |
| +} |
| + |
| +FFmpegVideoDecoder::~FFmpegVideoDecoder() { |
| + DCHECK_EQ(kUninitialized, state_); |
| + DCHECK(!codec_context_); |
| + DCHECK(!av_frame_); |
| } |
| bool FFmpegVideoDecoder::FFmpegDecode( |