Index: media/filters/ffmpeg_video_decoder_unittest.cc |
diff --git a/media/filters/ffmpeg_video_decoder_unittest.cc b/media/filters/ffmpeg_video_decoder_unittest.cc |
index 24627f2874bd2677b36b86eff17e73b857f98d91..e64b6df4d1b6b5755d86c4565ba06a318368d9f0 100644 |
--- a/media/filters/ffmpeg_video_decoder_unittest.cc |
+++ b/media/filters/ffmpeg_video_decoder_unittest.cc |
@@ -2,6 +2,7 @@ |
// Use of this source code is governed by a BSD-style license that can be |
// found in the LICENSE file. |
+#include <list> |
#include <string> |
#include <vector> |
@@ -26,6 +27,7 @@ |
using ::testing::_; |
using ::testing::AtLeast; |
+using ::testing::AtMost; |
using ::testing::InSequence; |
using ::testing::IsNull; |
using ::testing::Return; |
@@ -47,7 +49,7 @@ class FFmpegVideoDecoderTest : public testing::Test { |
public: |
FFmpegVideoDecoderTest() |
: decoder_(new FFmpegVideoDecoder(message_loop_.message_loop_proxy())), |
- decode_cb_(base::Bind(&FFmpegVideoDecoderTest::FrameReady, |
+ decode_cb_(base::Bind(&FFmpegVideoDecoderTest::DecodeDone, |
base::Unretained(this))) { |
FFmpegGlue::InitializeFFmpeg(); |
@@ -68,7 +70,9 @@ class FFmpegVideoDecoderTest : public testing::Test { |
void InitializeWithConfigAndStatus(const VideoDecoderConfig& config, |
PipelineStatus status) { |
- decoder_->Initialize(config, false, NewExpectedStatusCB(status)); |
+ decoder_->Initialize(config, false, NewExpectedStatusCB(status), |
+ base::Bind(&FFmpegVideoDecoderTest::FrameReady, |
+ base::Unretained(this))); |
message_loop_.RunUntilIdle(); |
} |
@@ -93,24 +97,18 @@ class FFmpegVideoDecoderTest : public testing::Test { |
// Sets up expectations and actions to put FFmpegVideoDecoder in an active |
// decoding state. |
void EnterDecodingState() { |
- VideoDecoder::Status status; |
- scoped_refptr<VideoFrame> video_frame; |
- DecodeSingleFrame(i_frame_buffer_, &status, &video_frame); |
- |
- EXPECT_EQ(VideoDecoder::kOk, status); |
- ASSERT_TRUE(video_frame.get()); |
- EXPECT_FALSE(video_frame->end_of_stream()); |
+ EXPECT_EQ(VideoDecoder::kOk, DecodeSingleFrame(i_frame_buffer_)); |
+ ASSERT_EQ(2U, output_frames_.size()); |
+ EXPECT_FALSE(output_frames_[0]->end_of_stream()); |
+ EXPECT_TRUE(output_frames_[1]->end_of_stream()); |
} |
// Sets up expectations and actions to put FFmpegVideoDecoder in an end |
// of stream state. |
void EnterEndOfStreamState() { |
- VideoDecoder::Status status; |
- scoped_refptr<VideoFrame> video_frame; |
- DecodeSingleFrame(end_of_stream_buffer_, &status, &video_frame); |
- EXPECT_EQ(VideoDecoder::kOk, status); |
- ASSERT_TRUE(video_frame.get()); |
- EXPECT_TRUE(video_frame->end_of_stream()); |
+ EXPECT_EQ(VideoDecoder::kOk, DecodeSingleFrame(end_of_stream_buffer_)); |
+ ASSERT_FALSE(output_frames_.empty()); |
+ EXPECT_TRUE(output_frames_.back()->end_of_stream()); |
} |
typedef std::vector<scoped_refptr<DecoderBuffer> > InputBuffers; |
@@ -119,11 +117,10 @@ class FFmpegVideoDecoderTest : public testing::Test { |
// Decodes all buffers in |input_buffers| and push all successfully decoded |
// output frames (excluding EOS frames) into |output_frames|. |
// Returns the last decode status returned by the decoder. |
- VideoDecoder::Status DecodeMultipleFrames(const InputBuffers& input_buffers, |
- OutputFrames* output_frames) { |
+ VideoDecoder::Status DecodeMultipleFrames(const InputBuffers& input_buffers) { |
InputBuffers::const_iterator input_iter = input_buffers.begin(); |
- for (;;) { |
+ while (output_frames_.empty() || !output_frames_.back()->end_of_stream()) { |
// Prepare input buffer. |
scoped_refptr<DecoderBuffer> buffer; |
if (input_iter != input_buffers.end()) { |
@@ -133,53 +130,33 @@ class FFmpegVideoDecoderTest : public testing::Test { |
buffer = end_of_stream_buffer_; |
} |
- VideoDecoder::Status status; |
- scoped_refptr<VideoFrame> frame; |
- Decode(buffer, &status, &frame); |
+ VideoDecoder::Status status = Decode(buffer); |
switch (status) { |
case VideoDecoder::kOk: |
- DCHECK(frame); |
- if (!frame->end_of_stream()) { |
- output_frames->push_back(frame); |
- continue; |
- } else { // EOS |
- return status; |
- } |
- case VideoDecoder::kNotEnoughData: |
- DCHECK(!frame); |
- continue; |
+ break; |
case VideoDecoder::kAborted: |
NOTREACHED(); |
case VideoDecoder::kDecodeError: |
case VideoDecoder::kDecryptError: |
- DCHECK(!frame); |
+ DCHECK(output_frames_.empty()); |
return status; |
} |
} |
+ |
+ return VideoDecoder::kOk; |
} |
// Decodes the single compressed frame in |buffer| and writes the |
// uncompressed output to |video_frame|. This method works with single |
// and multithreaded decoders. End of stream buffers are used to trigger |
// the frame to be returned in the multithreaded decoder case. |
- void DecodeSingleFrame(const scoped_refptr<DecoderBuffer>& buffer, |
- VideoDecoder::Status* status, |
- scoped_refptr<VideoFrame>* video_frame) { |
+ VideoDecoder::Status DecodeSingleFrame( |
+ const scoped_refptr<DecoderBuffer>& buffer) { |
InputBuffers input_buffers; |
input_buffers.push_back(buffer); |
- OutputFrames output_frames; |
- *status = DecodeMultipleFrames(input_buffers, &output_frames); |
- |
- if (*status != VideoDecoder::kOk) |
- return; |
- |
- ASSERT_LE(output_frames.size(), 1U); |
- if (output_frames.size() == 1U) |
- *video_frame = output_frames[0]; |
- else |
- *video_frame = VideoFrame::CreateEOSFrame(); |
+ return DecodeMultipleFrames(input_buffers); |
} |
// Decodes |i_frame_buffer_| and then decodes the data contained in |
@@ -195,37 +172,40 @@ class FFmpegVideoDecoderTest : public testing::Test { |
input_buffers.push_back(i_frame_buffer_); |
input_buffers.push_back(buffer); |
- OutputFrames output_frames; |
VideoDecoder::Status status = |
- DecodeMultipleFrames(input_buffers, &output_frames); |
+ DecodeMultipleFrames(input_buffers); |
EXPECT_EQ(VideoDecoder::kOk, status); |
- ASSERT_EQ(2U, output_frames.size()); |
+ ASSERT_EQ(3U, output_frames_.size()); |
gfx::Size original_size = kVisibleRect.size(); |
EXPECT_EQ(original_size.width(), |
- output_frames[0]->visible_rect().size().width()); |
+ output_frames_[0]->visible_rect().size().width()); |
EXPECT_EQ(original_size.height(), |
- output_frames[0]->visible_rect().size().height()); |
+ output_frames_[0]->visible_rect().size().height()); |
EXPECT_EQ(expected_width, |
- output_frames[1]->visible_rect().size().width()); |
+ output_frames_[1]->visible_rect().size().width()); |
EXPECT_EQ(expected_height, |
- output_frames[1]->visible_rect().size().height()); |
+ output_frames_[1]->visible_rect().size().height()); |
+ EXPECT_TRUE(output_frames_[2]->end_of_stream()); |
} |
- void Decode(const scoped_refptr<DecoderBuffer>& buffer, |
- VideoDecoder::Status* status, |
- scoped_refptr<VideoFrame>* video_frame) { |
- EXPECT_CALL(*this, FrameReady(_, _)) |
- .WillOnce(DoAll(SaveArg<0>(status), SaveArg<1>(video_frame))); |
+ VideoDecoder::Status Decode(const scoped_refptr<DecoderBuffer>& buffer) { |
+ VideoDecoder::Status status; |
+ EXPECT_CALL(*this, DecodeDone(_)).WillOnce(SaveArg<0>(&status)); |
decoder_->Decode(buffer, decode_cb_); |
message_loop_.RunUntilIdle(); |
+ |
+ return status; |
+ } |
+ |
+ void FrameReady(const scoped_refptr<VideoFrame>& frame) { |
+ output_frames_.push_back(frame); |
} |
- MOCK_METHOD2(FrameReady, void(VideoDecoder::Status, |
- const scoped_refptr<VideoFrame>&)); |
+ MOCK_METHOD1(DecodeDone, void(VideoDecoder::Status)); |
base::MessageLoop message_loop_; |
scoped_ptr<FFmpegVideoDecoder> decoder_; |
@@ -238,6 +218,8 @@ class FFmpegVideoDecoderTest : public testing::Test { |
scoped_refptr<DecoderBuffer> i_frame_buffer_; |
scoped_refptr<DecoderBuffer> corrupt_i_frame_buffer_; |
+ OutputFrames output_frames_; |
+ |
private: |
DISALLOW_COPY_AND_ASSIGN(FFmpegVideoDecoderTest); |
}; |
@@ -355,13 +337,10 @@ TEST_F(FFmpegVideoDecoderTest, DecodeFrame_Normal) { |
Initialize(); |
// Simulate decoding a single frame. |
- VideoDecoder::Status status; |
- scoped_refptr<VideoFrame> video_frame; |
- DecodeSingleFrame(i_frame_buffer_, &status, &video_frame); |
- |
- EXPECT_EQ(VideoDecoder::kOk, status); |
- ASSERT_TRUE(video_frame.get()); |
- EXPECT_FALSE(video_frame->end_of_stream()); |
+ EXPECT_EQ(VideoDecoder::kOk, DecodeSingleFrame(i_frame_buffer_)); |
+ ASSERT_EQ(2U, output_frames_.size()); |
+ EXPECT_FALSE(output_frames_[0]->end_of_stream()); |
+ EXPECT_TRUE(output_frames_[1]->end_of_stream()); |
} |
// Verify current behavior for 0 byte frames. FFmpeg simply ignores |
@@ -376,38 +355,31 @@ TEST_F(FFmpegVideoDecoderTest, DecodeFrame_0ByteFrame) { |
input_buffers.push_back(zero_byte_buffer); |
input_buffers.push_back(i_frame_buffer_); |
- OutputFrames output_frames; |
- VideoDecoder::Status status = |
- DecodeMultipleFrames(input_buffers, &output_frames); |
+ VideoDecoder::Status status = DecodeMultipleFrames(input_buffers); |
EXPECT_EQ(VideoDecoder::kOk, status); |
- ASSERT_EQ(2U, output_frames.size()); |
+ ASSERT_EQ(3U, output_frames_.size()); |
- EXPECT_FALSE(output_frames[0]->end_of_stream()); |
- EXPECT_FALSE(output_frames[1]->end_of_stream()); |
+ EXPECT_FALSE(output_frames_[0]->end_of_stream()); |
+ EXPECT_FALSE(output_frames_[1]->end_of_stream()); |
+ EXPECT_TRUE(output_frames_[2]->end_of_stream()); |
} |
TEST_F(FFmpegVideoDecoderTest, DecodeFrame_DecodeError) { |
Initialize(); |
- VideoDecoder::Status status; |
- scoped_refptr<VideoFrame> frame; |
- |
// The error is only raised on the second decode attempt, so we expect at |
// least one successful decode but we don't expect valid frame to be decoded. |
// During the second decode attempt an error is raised. |
- Decode(corrupt_i_frame_buffer_, &status, &frame); |
- DCHECK(!frame); |
- DCHECK_EQ(VideoDecoder::kNotEnoughData, status); |
- Decode(i_frame_buffer_, &status, &frame); |
- DCHECK(!frame); |
- DCHECK_EQ(VideoDecoder::kDecodeError, status); |
+ EXPECT_EQ(VideoDecoder::kOk, Decode(corrupt_i_frame_buffer_)); |
+ EXPECT_TRUE(output_frames_.empty()); |
+ EXPECT_EQ(VideoDecoder::kDecodeError, Decode(i_frame_buffer_)); |
+ EXPECT_TRUE(output_frames_.empty()); |
// After a decode error occurred, all following decodes will return |
// kDecodeError. |
- Decode(i_frame_buffer_, &status, &frame); |
- DCHECK(!frame); |
- DCHECK_EQ(VideoDecoder::kDecodeError, status); |
+ EXPECT_EQ(VideoDecoder::kDecodeError, Decode(i_frame_buffer_)); |
+ EXPECT_TRUE(output_frames_.empty()); |
} |
// Multi-threaded decoders have different behavior than single-threaded |
@@ -418,13 +390,9 @@ TEST_F(FFmpegVideoDecoderTest, DecodeFrame_DecodeError) { |
TEST_F(FFmpegVideoDecoderTest, DecodeFrame_DecodeErrorAtEndOfStream) { |
Initialize(); |
- VideoDecoder::Status status; |
- scoped_refptr<VideoFrame> video_frame; |
- DecodeSingleFrame(corrupt_i_frame_buffer_, &status, &video_frame); |
- |
- EXPECT_EQ(VideoDecoder::kOk, status); |
- ASSERT_TRUE(video_frame.get()); |
- EXPECT_TRUE(video_frame->end_of_stream()); |
+ EXPECT_EQ(VideoDecoder::kOk, DecodeSingleFrame(corrupt_i_frame_buffer_)); |
+ ASSERT_FALSE(output_frames_.empty()); |
+ EXPECT_TRUE(output_frames_.back()->end_of_stream()); |
} |
// Decode |i_frame_buffer_| and then a frame with a larger width and verify |