| 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 9c0963bc52e1f741229ec43621e801bb733061ac..7bb05a913a7eb4219a9df09b37bca75c771810bb 100644
|
| --- a/media/filters/ffmpeg_video_decoder_unittest.cc
|
| +++ b/media/filters/ffmpeg_video_decoder_unittest.cc
|
| @@ -5,11 +5,13 @@
|
| #include <deque>
|
|
|
| #include "base/singleton.h"
|
| +#include "base/string_util.h"
|
| #include "media/base/data_buffer.h"
|
| #include "media/base/filters.h"
|
| #include "media/base/mock_ffmpeg.h"
|
| #include "media/base/mock_filter_host.h"
|
| #include "media/base/mock_filters.h"
|
| +#include "media/base/mock_task.h"
|
| #include "media/filters/ffmpeg_common.h"
|
| #include "media/filters/ffmpeg_interfaces.h"
|
| #include "media/filters/ffmpeg_video_decoder.h"
|
| @@ -17,10 +19,12 @@
|
|
|
| using ::testing::_;
|
| using ::testing::DoAll;
|
| +using ::testing::Message;
|
| using ::testing::Return;
|
| using ::testing::ReturnNull;
|
| using ::testing::SetArgumentPointee;
|
| using ::testing::StrictMock;
|
| +using ::testing::WithArg;
|
|
|
| namespace media {
|
|
|
| @@ -39,20 +43,29 @@ class MockFFmpegDemuxerStream : public MockDemuxerStream,
|
| DISALLOW_COPY_AND_ASSIGN(MockFFmpegDemuxerStream);
|
| };
|
|
|
| +class MockVideoDecodeEngine : public VideoDecodeEngine {
|
| + public:
|
| + MOCK_METHOD2(Initialize, void(AVStream* stream, Task* done_cb));
|
| + MOCK_METHOD4(DecodeFrame, void(const Buffer& buffer, AVFrame* yuv_frame,
|
| + bool* got_result, Task* done_cb));
|
| + MOCK_METHOD1(Flush, void(Task* done_cb));
|
| + MOCK_CONST_METHOD0(state, State());
|
| + MOCK_CONST_METHOD0(GetSurfaceFormat, VideoSurface::Format());
|
| +};
|
| +
|
| // Class that just mocks the private functions.
|
| class DecoderPrivateMock : public FFmpegVideoDecoder {
|
| public:
|
| + DecoderPrivateMock(VideoDecodeEngine* engine)
|
| + : FFmpegVideoDecoder(engine) {
|
| + }
|
| +
|
| MOCK_METHOD3(EnqueueVideoFrame, bool(VideoSurface::Format surface_format,
|
| const TimeTuple& time,
|
| const AVFrame* frame));
|
| MOCK_METHOD0(EnqueueEmptyFrame, void());
|
| MOCK_METHOD3(CopyPlane, void(size_t plane, const VideoSurface& surface,
|
| const AVFrame* frame));
|
| - MOCK_METHOD1(GetSurfaceFormat,
|
| - VideoSurface::Format(const AVCodecContext& codec_context));
|
| - MOCK_METHOD3(DecodeFrame, bool(const Buffer& buffer,
|
| - AVCodecContext* codec_context,
|
| - AVFrame* yuv_frame));
|
| MOCK_METHOD4(FindPtsAndDuration, TimeTuple(const AVRational& time_base,
|
| const PtsHeap& pts_heap,
|
| const TimeTuple& last_pts,
|
| @@ -73,14 +86,17 @@ class FFmpegVideoDecoderTest : public testing::Test {
|
| MediaFormat media_format;
|
| media_format.SetAsString(MediaFormat::kMimeType, mime_type::kFFmpegVideo);
|
|
|
| - // Create an FFmpegVideoDecoder.
|
| + // Create an FFmpegVideoDecoder, and MockVideoDecodeEngine.
|
| factory_ = FFmpegVideoDecoder::CreateFactory();
|
| decoder_ = factory_->Create<FFmpegVideoDecoder>(media_format);
|
| + engine_ = new StrictMock<MockVideoDecodeEngine>();
|
| +
|
| DCHECK(decoder_);
|
|
|
| - // Inject a filter host and message loop and prepare a demuxer stream.
|
| + // Inject mocks and prepare a demuxer stream.
|
| decoder_->set_host(&host_);
|
| decoder_->set_message_loop(&message_loop_);
|
| + decoder_->SetVideoDecodeEngineForTest(engine_);
|
| demuxer_ = new StrictMock<MockFFmpegDemuxerStream>();
|
|
|
| // Initialize FFmpeg fixtures.
|
| @@ -112,6 +128,7 @@ class FFmpegVideoDecoderTest : public testing::Test {
|
|
|
| // Fixture members.
|
| scoped_refptr<FilterFactory> factory_;
|
| + MockVideoDecodeEngine* engine_; // Owned by |decoder_|.
|
| scoped_refptr<FFmpegVideoDecoder> decoder_;
|
| scoped_refptr<StrictMock<MockFFmpegDemuxerStream> > demuxer_;
|
| scoped_refptr<DataBuffer> buffer_;
|
| @@ -169,56 +186,21 @@ TEST_F(FFmpegVideoDecoderTest, Initialize_QueryInterfaceFails) {
|
| message_loop_.RunAllPending();
|
| }
|
|
|
| -TEST_F(FFmpegVideoDecoderTest, Initialize_FindDecoderFails) {
|
| - // Test avcodec_find_decoder() returning NULL.
|
| +TEST_F(FFmpegVideoDecoderTest, Initialize_EngineFails) {
|
| + // Test successful initialization.
|
| AVStreamProvider* av_stream_provider = demuxer_;
|
| EXPECT_CALL(*demuxer_, QueryInterface(AVStreamProvider::interface_id()))
|
| .WillOnce(Return(av_stream_provider));
|
| EXPECT_CALL(*demuxer_, GetAVStream())
|
| .WillOnce(Return(&stream_));
|
| - EXPECT_CALL(*MockFFmpeg::get(), AVCodecFindDecoder(CODEC_ID_NONE))
|
| - .WillOnce(ReturnNull());
|
| - EXPECT_CALL(host_, SetError(PIPELINE_ERROR_DECODE));
|
| - EXPECT_CALL(callback_, OnFilterCallback());
|
| - EXPECT_CALL(callback_, OnCallbackDestroyed());
|
|
|
| - decoder_->Initialize(demuxer_, callback_.NewCallback());
|
| - message_loop_.RunAllPending();
|
| -}
|
| + EXPECT_CALL(*engine_, Initialize(_, _))
|
| + .WillOnce(WithArg<1>(InvokeRunnable()));
|
| + EXPECT_CALL(*engine_, state())
|
| + .WillOnce(Return(VideoDecodeEngine::kError));
|
|
|
| -TEST_F(FFmpegVideoDecoderTest, Initialize_InitThreadFails) {
|
| - // Test avcodec_thread_init() failing.
|
| - AVStreamProvider* av_stream_provider = demuxer_;
|
| - EXPECT_CALL(*demuxer_, QueryInterface(AVStreamProvider::interface_id()))
|
| - .WillOnce(Return(av_stream_provider));
|
| - EXPECT_CALL(*demuxer_, GetAVStream())
|
| - .WillOnce(Return(&stream_));
|
| - EXPECT_CALL(*MockFFmpeg::get(), AVCodecFindDecoder(CODEC_ID_NONE))
|
| - .WillOnce(Return(&codec_));
|
| - EXPECT_CALL(*MockFFmpeg::get(), AVCodecThreadInit(&codec_context_, 2))
|
| - .WillOnce(Return(-1));
|
| EXPECT_CALL(host_, SetError(PIPELINE_ERROR_DECODE));
|
| - EXPECT_CALL(callback_, OnFilterCallback());
|
| - EXPECT_CALL(callback_, OnCallbackDestroyed());
|
| -
|
| - decoder_->Initialize(demuxer_, callback_.NewCallback());
|
| - message_loop_.RunAllPending();
|
| -}
|
|
|
| -TEST_F(FFmpegVideoDecoderTest, Initialize_OpenDecoderFails) {
|
| - // Test avcodec_open() failing.
|
| - AVStreamProvider* av_stream_provider = demuxer_;
|
| - EXPECT_CALL(*demuxer_, QueryInterface(AVStreamProvider::interface_id()))
|
| - .WillOnce(Return(av_stream_provider));
|
| - EXPECT_CALL(*demuxer_, GetAVStream())
|
| - .WillOnce(Return(&stream_));
|
| - EXPECT_CALL(*MockFFmpeg::get(), AVCodecFindDecoder(CODEC_ID_NONE))
|
| - .WillOnce(Return(&codec_));
|
| - EXPECT_CALL(*MockFFmpeg::get(), AVCodecThreadInit(&codec_context_, 2))
|
| - .WillOnce(Return(0));
|
| - EXPECT_CALL(*MockFFmpeg::get(), AVCodecOpen(&codec_context_, &codec_))
|
| - .WillOnce(Return(-1));
|
| - EXPECT_CALL(host_, SetError(PIPELINE_ERROR_DECODE));
|
| EXPECT_CALL(callback_, OnFilterCallback());
|
| EXPECT_CALL(callback_, OnCallbackDestroyed());
|
|
|
| @@ -233,12 +215,12 @@ TEST_F(FFmpegVideoDecoderTest, Initialize_Successful) {
|
| .WillOnce(Return(av_stream_provider));
|
| EXPECT_CALL(*demuxer_, GetAVStream())
|
| .WillOnce(Return(&stream_));
|
| - EXPECT_CALL(*MockFFmpeg::get(), AVCodecFindDecoder(CODEC_ID_NONE))
|
| - .WillOnce(Return(&codec_));
|
| - EXPECT_CALL(*MockFFmpeg::get(), AVCodecThreadInit(&codec_context_, 2))
|
| - .WillOnce(Return(0));
|
| - EXPECT_CALL(*MockFFmpeg::get(), AVCodecOpen(&codec_context_, &codec_))
|
| - .WillOnce(Return(0));
|
| +
|
| + EXPECT_CALL(*engine_, Initialize(_, _))
|
| + .WillOnce(WithArg<1>(InvokeRunnable()));
|
| + EXPECT_CALL(*engine_, state())
|
| + .WillOnce(Return(VideoDecodeEngine::kNormal));
|
| +
|
| EXPECT_CALL(callback_, OnFilterCallback());
|
| EXPECT_CALL(callback_, OnCallbackDestroyed());
|
|
|
| @@ -259,66 +241,9 @@ TEST_F(FFmpegVideoDecoderTest, Initialize_Successful) {
|
| EXPECT_EQ(kHeight, height);
|
| }
|
|
|
| -TEST_F(FFmpegVideoDecoderTest, DecodeFrame_Normal) {
|
| - // Expect a bunch of avcodec calls.
|
| - EXPECT_CALL(mock_ffmpeg_, AVInitPacket(_));
|
| - EXPECT_CALL(mock_ffmpeg_,
|
| - AVCodecDecodeVideo2(&codec_context_, &yuv_frame_, _, _))
|
| - .WillOnce(DoAll(SetArgumentPointee<2>(1), // Simulate 1 byte frame.
|
| - Return(0)));
|
| -
|
| - scoped_refptr<FFmpegVideoDecoder> decoder = new FFmpegVideoDecoder();
|
| - EXPECT_TRUE(decoder->DecodeFrame(*buffer_, &codec_context_, &yuv_frame_));
|
| -}
|
| -
|
| -TEST_F(FFmpegVideoDecoderTest, DecodeFrame_0ByteFrame) {
|
| - // Expect a bunch of avcodec calls.
|
| - EXPECT_CALL(mock_ffmpeg_, AVInitPacket(_));
|
| - EXPECT_CALL(mock_ffmpeg_,
|
| - AVCodecDecodeVideo2(&codec_context_, &yuv_frame_, _, _))
|
| - .WillOnce(DoAll(SetArgumentPointee<2>(0), // Simulate 0 byte frame.
|
| - Return(0)));
|
| -
|
| - scoped_refptr<FFmpegVideoDecoder> decoder = new FFmpegVideoDecoder();
|
| - EXPECT_FALSE(decoder->DecodeFrame(*buffer_, &codec_context_, &yuv_frame_));
|
| -}
|
| -
|
| -TEST_F(FFmpegVideoDecoderTest, DecodeFrame_DecodeError) {
|
| - // Expect a bunch of avcodec calls.
|
| - EXPECT_CALL(mock_ffmpeg_, AVInitPacket(_));
|
| - EXPECT_CALL(mock_ffmpeg_,
|
| - AVCodecDecodeVideo2(&codec_context_, &yuv_frame_, _, _))
|
| - .WillOnce(Return(-1));
|
| -
|
| - scoped_refptr<FFmpegVideoDecoder> decoder = new FFmpegVideoDecoder();
|
| - EXPECT_FALSE(decoder->DecodeFrame(*buffer_, &codec_context_, &yuv_frame_));
|
| -}
|
| -
|
| -TEST_F(FFmpegVideoDecoderTest, GetSurfaceFormat) {
|
| - AVCodecContext context;
|
| - scoped_refptr<FFmpegVideoDecoder> decoder = new FFmpegVideoDecoder();
|
| -
|
| - // YV12 formats.
|
| - context.pix_fmt = PIX_FMT_YUV420P;
|
| - EXPECT_EQ(VideoSurface::YV12, decoder->GetSurfaceFormat(context));
|
| - context.pix_fmt = PIX_FMT_YUVJ420P;
|
| - EXPECT_EQ(VideoSurface::YV12, decoder->GetSurfaceFormat(context));
|
| -
|
| - // YV16 formats.
|
| - context.pix_fmt = PIX_FMT_YUV422P;
|
| - EXPECT_EQ(VideoSurface::YV16, decoder->GetSurfaceFormat(context));
|
| - context.pix_fmt = PIX_FMT_YUVJ422P;
|
| - EXPECT_EQ(VideoSurface::YV16, decoder->GetSurfaceFormat(context));
|
| -
|
| - // Invalid value.
|
| - context.pix_fmt = PIX_FMT_NONE;
|
| - EXPECT_EQ(VideoSurface::INVALID, decoder->GetSurfaceFormat(context));
|
| -}
|
| -
|
| TEST_F(FFmpegVideoDecoderTest, FindPtsAndDuration) {
|
| // Start with an empty timestamp queue.
|
| PtsHeap pts_heap;
|
| - scoped_refptr<FFmpegVideoDecoder> decoder = new FFmpegVideoDecoder();
|
|
|
| // Use 1/2 second for simple results. Thus, calculated Durations should be
|
| // 500000 microseconds.
|
| @@ -333,16 +258,16 @@ TEST_F(FFmpegVideoDecoderTest, FindPtsAndDuration) {
|
| // Simulate an uninitialized yuv_frame.
|
| yuv_frame_.pts = AV_NOPTS_VALUE;
|
| FFmpegVideoDecoder::TimeTuple result_pts =
|
| - decoder->FindPtsAndDuration(time_base, pts_heap, last_pts, &yuv_frame_);
|
| + decoder_->FindPtsAndDuration(time_base, pts_heap, last_pts, &yuv_frame_);
|
| EXPECT_EQ(116, result_pts.timestamp.InMicroseconds());
|
| EXPECT_EQ(500000, result_pts.duration.InMicroseconds());
|
|
|
| // Test that providing no frame has the same result as an uninitialized
|
| // frame.
|
| - result_pts = decoder->FindPtsAndDuration(time_base,
|
| - pts_heap,
|
| - last_pts,
|
| - NULL);
|
| + result_pts = decoder_->FindPtsAndDuration(time_base,
|
| + pts_heap,
|
| + last_pts,
|
| + NULL);
|
| EXPECT_EQ(116, result_pts.timestamp.InMicroseconds());
|
| EXPECT_EQ(500000, result_pts.duration.InMicroseconds());
|
|
|
| @@ -351,33 +276,33 @@ TEST_F(FFmpegVideoDecoderTest, FindPtsAndDuration) {
|
| // data for the frame, which means that value is useless to us.
|
| yuv_frame_.pts = 0;
|
| result_pts =
|
| - decoder->FindPtsAndDuration(time_base, pts_heap, last_pts, &yuv_frame_);
|
| + decoder_->FindPtsAndDuration(time_base, pts_heap, last_pts, &yuv_frame_);
|
| EXPECT_EQ(116, result_pts.timestamp.InMicroseconds());
|
| EXPECT_EQ(500000, result_pts.duration.InMicroseconds());
|
|
|
| // Add a pts to the timequeue and make sure it overrides estimation.
|
| pts_heap.Push(base::TimeDelta::FromMicroseconds(123));
|
| - result_pts = decoder->FindPtsAndDuration(time_base,
|
| - pts_heap,
|
| - last_pts,
|
| - &yuv_frame_);
|
| + result_pts = decoder_->FindPtsAndDuration(time_base,
|
| + pts_heap,
|
| + last_pts,
|
| + &yuv_frame_);
|
| EXPECT_EQ(123, result_pts.timestamp.InMicroseconds());
|
| EXPECT_EQ(500000, result_pts.duration.InMicroseconds());
|
|
|
| // Add a pts into the frame and make sure it overrides the timequeue.
|
| yuv_frame_.pts = 333;
|
| yuv_frame_.repeat_pict = 2;
|
| - result_pts = decoder->FindPtsAndDuration(time_base,
|
| - pts_heap,
|
| - last_pts,
|
| - &yuv_frame_);
|
| + result_pts = decoder_->FindPtsAndDuration(time_base,
|
| + pts_heap,
|
| + last_pts,
|
| + &yuv_frame_);
|
| EXPECT_EQ(166500000, result_pts.timestamp.InMicroseconds());
|
| EXPECT_EQ(1500000, result_pts.duration.InMicroseconds());
|
| }
|
|
|
| -TEST_F(FFmpegVideoDecoderTest, OnDecode_TestStateTransition) {
|
| +TEST_F(FFmpegVideoDecoderTest, DoDecode_TestStateTransition) {
|
| // Simulates a input sequence of three buffers, and six decode requests to
|
| - // exercise the state transitions, and bookkeeping logic of OnDecode.
|
| + // exercise the state transitions, and bookkeeping logic of DoDecode.
|
| //
|
| // We try to verify the following:
|
| // 1) Non-EoS buffer timestamps are pushed into the pts_heap.
|
| @@ -386,28 +311,38 @@ TEST_F(FFmpegVideoDecoderTest, OnDecode_TestStateTransition) {
|
| // 4) kDecodeFinished is never left regardless of what kind of buffer is
|
| // given.
|
| // 5) All state transitions happen as expected.
|
| + MockVideoDecodeEngine* mock_engine = new StrictMock<MockVideoDecodeEngine>();
|
| scoped_refptr<DecoderPrivateMock> mock_decoder =
|
| - new StrictMock<DecoderPrivateMock>();
|
| + new StrictMock<DecoderPrivateMock>(mock_engine);
|
|
|
| // Setup decoder to buffer one frame, decode one frame, fail one frame,
|
| // decode one more, and then fail the last one to end decoding.
|
| - EXPECT_CALL(*mock_decoder, DecodeFrame(_, _, _))
|
| - .WillOnce(Return(false))
|
| - .WillOnce(DoAll(SetArgumentPointee<2>(yuv_frame_), Return(true)))
|
| - .WillOnce(Return(false))
|
| - .WillOnce(DoAll(SetArgumentPointee<2>(yuv_frame_), Return(true)))
|
| - .WillOnce(DoAll(SetArgumentPointee<2>(yuv_frame_), Return(true)))
|
| - .WillOnce(Return(false));
|
| - EXPECT_CALL(*mock_decoder, GetSurfaceFormat(_))
|
| + EXPECT_CALL(*mock_engine, DecodeFrame(_, _, _,_))
|
| + .WillOnce(DoAll(SetArgumentPointee<2>(false),
|
| + WithArg<3>(InvokeRunnable())))
|
| + .WillOnce(DoAll(SetArgumentPointee<1>(yuv_frame_),
|
| + SetArgumentPointee<2>(true),
|
| + WithArg<3>(InvokeRunnable())))
|
| + .WillOnce(DoAll(SetArgumentPointee<2>(false),
|
| + WithArg<3>(InvokeRunnable())))
|
| + .WillOnce(DoAll(SetArgumentPointee<1>(yuv_frame_),
|
| + SetArgumentPointee<2>(true),
|
| + WithArg<3>(InvokeRunnable())))
|
| + .WillOnce(DoAll(SetArgumentPointee<1>(yuv_frame_),
|
| + SetArgumentPointee<2>(true),
|
| + WithArg<3>(InvokeRunnable())))
|
| + .WillOnce(DoAll(SetArgumentPointee<2>(false),
|
| + WithArg<3>(InvokeRunnable())));
|
| + EXPECT_CALL(*mock_engine, GetSurfaceFormat())
|
| .Times(3)
|
| .WillRepeatedly(Return(VideoSurface::YV16));
|
| - EXPECT_CALL(*mock_decoder, EnqueueVideoFrame(_, _, _))
|
| - .Times(3)
|
| - .WillRepeatedly(Return(true));
|
| EXPECT_CALL(*mock_decoder, FindPtsAndDuration(_, _, _, _))
|
| .WillOnce(Return(kTestPts1))
|
| .WillOnce(Return(kTestPts2))
|
| .WillOnce(Return(kTestPts1));
|
| + EXPECT_CALL(*mock_decoder, EnqueueVideoFrame(_, _, _))
|
| + .Times(3)
|
| + .WillRepeatedly(Return(true));
|
| EXPECT_CALL(*mock_decoder, EnqueueEmptyFrame())
|
| .Times(1);
|
|
|
| @@ -419,21 +354,24 @@ TEST_F(FFmpegVideoDecoderTest, OnDecode_TestStateTransition) {
|
| EXPECT_CALL(mock_ffmpeg_, AVFree(&yuv_frame_))
|
| .Times(6);
|
|
|
| + // Setup callbacks to be executed 6 times.
|
| + TaskMocker done_cb;
|
| + EXPECT_CALL(done_cb, Run()).Times(6);
|
| +
|
| // Setup initial state and check that it is sane.
|
| - mock_decoder->codec_context_ = &codec_context_;
|
| ASSERT_EQ(FFmpegVideoDecoder::kNormal, mock_decoder->state_);
|
| ASSERT_TRUE(base::TimeDelta() == mock_decoder->last_pts_.timestamp);
|
| ASSERT_TRUE(base::TimeDelta() == mock_decoder->last_pts_.duration);
|
|
|
| // Decode once, which should simulate a buffering call.
|
| - mock_decoder->OnDecode(buffer_);
|
| + mock_decoder->DoDecode(buffer_, done_cb.CreateTask());
|
| EXPECT_EQ(FFmpegVideoDecoder::kNormal, mock_decoder->state_);
|
| ASSERT_TRUE(base::TimeDelta() == mock_decoder->last_pts_.timestamp);
|
| ASSERT_TRUE(base::TimeDelta() == mock_decoder->last_pts_.duration);
|
| EXPECT_FALSE(mock_decoder->pts_heap_.IsEmpty());
|
|
|
| // Decode a second time, which should yield the first frame.
|
| - mock_decoder->OnDecode(buffer_);
|
| + mock_decoder->DoDecode(buffer_, done_cb.CreateTask());
|
| EXPECT_EQ(FFmpegVideoDecoder::kNormal, mock_decoder->state_);
|
| EXPECT_TRUE(kTestPts1.timestamp == mock_decoder->last_pts_.timestamp);
|
| EXPECT_TRUE(kTestPts1.duration == mock_decoder->last_pts_.duration);
|
| @@ -441,7 +379,7 @@ TEST_F(FFmpegVideoDecoderTest, OnDecode_TestStateTransition) {
|
|
|
| // Decode a third time, with a regular buffer. The decode will error
|
| // out, but the state should be the same.
|
| - mock_decoder->OnDecode(buffer_);
|
| + mock_decoder->DoDecode(buffer_, done_cb.CreateTask());
|
| EXPECT_EQ(FFmpegVideoDecoder::kNormal, mock_decoder->state_);
|
| EXPECT_TRUE(kTestPts1.timestamp == mock_decoder->last_pts_.timestamp);
|
| EXPECT_TRUE(kTestPts1.duration == mock_decoder->last_pts_.duration);
|
| @@ -449,7 +387,7 @@ TEST_F(FFmpegVideoDecoderTest, OnDecode_TestStateTransition) {
|
|
|
| // Decode a fourth time, with an end of stream buffer. This should
|
| // yield the second frame, and stay in flushing mode.
|
| - mock_decoder->OnDecode(end_of_stream_buffer_);
|
| + mock_decoder->DoDecode(end_of_stream_buffer_, done_cb.CreateTask());
|
| EXPECT_EQ(FFmpegVideoDecoder::kFlushCodec, mock_decoder->state_);
|
| EXPECT_TRUE(kTestPts2.timestamp == mock_decoder->last_pts_.timestamp);
|
| EXPECT_TRUE(kTestPts2.duration == mock_decoder->last_pts_.duration);
|
| @@ -457,7 +395,7 @@ TEST_F(FFmpegVideoDecoderTest, OnDecode_TestStateTransition) {
|
|
|
| // Decode a fifth time with an end of stream buffer. this should
|
| // yield the third frame.
|
| - mock_decoder->OnDecode(end_of_stream_buffer_);
|
| + mock_decoder->DoDecode(end_of_stream_buffer_, done_cb.CreateTask());
|
| EXPECT_EQ(FFmpegVideoDecoder::kFlushCodec, mock_decoder->state_);
|
| EXPECT_TRUE(kTestPts1.timestamp == mock_decoder->last_pts_.timestamp);
|
| EXPECT_TRUE(kTestPts1.duration == mock_decoder->last_pts_.duration);
|
| @@ -465,61 +403,71 @@ TEST_F(FFmpegVideoDecoderTest, OnDecode_TestStateTransition) {
|
|
|
| // Decode a sixth time with an end of stream buffer. This should
|
| // Move into kDecodeFinished.
|
| - mock_decoder->OnDecode(end_of_stream_buffer_);
|
| + mock_decoder->DoDecode(end_of_stream_buffer_, done_cb.CreateTask());
|
| EXPECT_EQ(FFmpegVideoDecoder::kDecodeFinished, mock_decoder->state_);
|
| EXPECT_TRUE(kTestPts1.timestamp == mock_decoder->last_pts_.timestamp);
|
| EXPECT_TRUE(kTestPts1.duration == mock_decoder->last_pts_.duration);
|
| EXPECT_TRUE(mock_decoder->pts_heap_.IsEmpty());
|
| }
|
|
|
| -TEST_F(FFmpegVideoDecoderTest, OnDecode_EnqueueVideoFrameError) {
|
| +TEST_F(FFmpegVideoDecoderTest, DoDecode_EnqueueVideoFrameError) {
|
| + MockVideoDecodeEngine* mock_engine = new StrictMock<MockVideoDecodeEngine>();
|
| scoped_refptr<DecoderPrivateMock> mock_decoder =
|
| - new StrictMock<DecoderPrivateMock>();
|
| + new StrictMock<DecoderPrivateMock>(mock_engine);
|
|
|
| // Setup decoder to decode one frame, but then fail on enqueue.
|
| - EXPECT_CALL(*mock_decoder, DecodeFrame(_, _, _))
|
| - .WillOnce(DoAll(SetArgumentPointee<2>(yuv_frame_), Return(true)));
|
| - EXPECT_CALL(*mock_decoder, GetSurfaceFormat(_))
|
| + EXPECT_CALL(*mock_engine, DecodeFrame(_, _, _,_))
|
| + .WillOnce(DoAll(SetArgumentPointee<1>(yuv_frame_),
|
| + SetArgumentPointee<2>(true),
|
| + WithArg<3>(InvokeRunnable())));
|
| + EXPECT_CALL(*mock_engine, GetSurfaceFormat())
|
| .WillOnce(Return(VideoSurface::YV16));
|
| - EXPECT_CALL(*mock_decoder, EnqueueVideoFrame(_, _, _))
|
| - .WillOnce(Return(false));
|
| EXPECT_CALL(*mock_decoder, FindPtsAndDuration(_, _, _, _))
|
| .WillOnce(Return(kTestPts1));
|
| + EXPECT_CALL(*mock_decoder, EnqueueVideoFrame(_, _, _))
|
| + .WillOnce(Return(false));
|
| EXPECT_CALL(*mock_decoder, SignalPipelineError());
|
|
|
| + // Count the callback invoked.
|
| + TaskMocker done_cb;
|
| + EXPECT_CALL(done_cb, Run()).Times(1);
|
| +
|
| // Setup FFmpeg expectations for frame allocations.
|
| EXPECT_CALL(mock_ffmpeg_, AVCodecAllocFrame())
|
| .WillOnce(Return(&yuv_frame_));
|
| EXPECT_CALL(mock_ffmpeg_, AVFree(&yuv_frame_));
|
|
|
| // Attempt the decode.
|
| - mock_decoder->codec_context_ = &codec_context_;
|
| - mock_decoder->OnDecode(buffer_);
|
| + mock_decoder->DoDecode(buffer_, done_cb.CreateTask());
|
| }
|
|
|
| -TEST_F(FFmpegVideoDecoderTest, OnDecode_FinishEnqueuesEmptyFrames) {
|
| +TEST_F(FFmpegVideoDecoderTest, DoDecode_FinishEnqueuesEmptyFrames) {
|
| + MockVideoDecodeEngine* mock_engine = new StrictMock<MockVideoDecodeEngine>();
|
| scoped_refptr<DecoderPrivateMock> mock_decoder =
|
| - new StrictMock<DecoderPrivateMock>();
|
| + new StrictMock<DecoderPrivateMock>(mock_engine);
|
|
|
| // Move the decoder into the finished state for this test.
|
| mock_decoder->state_ = FFmpegVideoDecoder::kDecodeFinished;
|
|
|
| - // Expect 2 calls, make two calls.
|
| + // Expect 2 calls, make two calls. If kDecodeFinished is set, the buffer is
|
| + // not even examined.
|
| EXPECT_CALL(*mock_decoder, EnqueueEmptyFrame()).Times(3);
|
| - mock_decoder->OnDecode(NULL);
|
| - mock_decoder->OnDecode(buffer_);
|
| - mock_decoder->OnDecode(end_of_stream_buffer_);
|
| +
|
| + // Setup callbacks to be executed 3 times.
|
| + TaskMocker done_cb;
|
| + EXPECT_CALL(done_cb, Run()).Times(3);
|
| +
|
| + mock_decoder->DoDecode(NULL, done_cb.CreateTask());
|
| + mock_decoder->DoDecode(buffer_, done_cb.CreateTask());
|
| + mock_decoder->DoDecode(end_of_stream_buffer_, done_cb.CreateTask());
|
| +
|
| EXPECT_EQ(FFmpegVideoDecoder::kDecodeFinished, mock_decoder->state_);
|
| }
|
|
|
| -TEST_F(FFmpegVideoDecoderTest, OnSeek) {
|
| - // Simulates receiving a call to OnSeek() while in every possible state. In
|
| +TEST_F(FFmpegVideoDecoderTest, DoSeek) {
|
| + // Simulates receiving a call to DoSeek() while in every possible state. In
|
| // every case, it should clear the timestamp queue, flush the decoder and
|
| // reset the state to kNormal.
|
| - scoped_refptr<DecoderPrivateMock> mock_decoder =
|
| - new StrictMock<DecoderPrivateMock>();
|
| - mock_decoder->codec_context_ = &codec_context_;
|
| -
|
| const base::TimeDelta kZero;
|
| const FFmpegVideoDecoder::DecoderState kStates[] = {
|
| FFmpegVideoDecoder::kNormal,
|
| @@ -528,6 +476,13 @@ TEST_F(FFmpegVideoDecoderTest, OnSeek) {
|
| };
|
|
|
| for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kStates); ++i) {
|
| + SCOPED_TRACE(Message() << "Iteration " << i);
|
| +
|
| + MockVideoDecodeEngine* mock_engine =
|
| + new StrictMock<MockVideoDecodeEngine>();
|
| + scoped_refptr<DecoderPrivateMock> mock_decoder =
|
| + new StrictMock<DecoderPrivateMock>(mock_engine);
|
| +
|
| // Push in some timestamps.
|
| mock_decoder->pts_heap_.Push(kTestPts1.timestamp);
|
| mock_decoder->pts_heap_.Push(kTestPts2.timestamp);
|
| @@ -535,10 +490,14 @@ TEST_F(FFmpegVideoDecoderTest, OnSeek) {
|
|
|
| // Expect a flush.
|
| mock_decoder->state_ = kStates[i];
|
| - EXPECT_CALL(mock_ffmpeg_, AVCodecFlushBuffers(&codec_context_));
|
| + EXPECT_CALL(*mock_engine, Flush(_))
|
| + .WillOnce(WithArg<0>(InvokeRunnable()));
|
| +
|
| + TaskMocker done_cb;
|
| + EXPECT_CALL(done_cb, Run()).Times(1);
|
|
|
| // Seek and verify the results.
|
| - mock_decoder->OnSeek(kZero);
|
| + mock_decoder->DoSeek(kZero, done_cb.CreateTask());
|
| EXPECT_TRUE(mock_decoder->pts_heap_.IsEmpty());
|
| EXPECT_EQ(FFmpegVideoDecoder::kNormal, mock_decoder->state_);
|
| }
|
|
|