The test fails due to a console messages arriving sometimes before the console evalua...
[chromium-blink-merge.git] / media / video / ffmpeg_video_decode_engine_unittest.cc
blob01016d46347f4e7970f75f463cef7ddfc65821ef
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/memory/scoped_ptr.h"
6 #include "base/message_loop.h"
7 #include "media/base/data_buffer.h"
8 #include "media/base/mock_ffmpeg.h"
9 #include "media/base/mock_task.h"
10 #include "media/base/pipeline.h"
11 #include "media/video/ffmpeg_video_decode_engine.h"
12 #include "testing/gmock/include/gmock/gmock.h"
13 #include "testing/gtest/include/gtest/gtest.h"
15 using ::testing::_;
16 using ::testing::DoAll;
17 using ::testing::Return;
18 using ::testing::ReturnNull;
19 using ::testing::SetArgumentPointee;
20 using ::testing::StrictMock;
22 namespace media {
24 static const int kWidth = 320;
25 static const int kHeight = 240;
26 static const int kSurfaceWidth = 522;
27 static const int kSurfaceHeight = 288;
28 static const AVRational kFrameRate = { 100, 1 };
30 static void InitializeFrame(uint8_t* data, int width, AVFrame* frame) {
31 frame->data[0] = data;
32 frame->data[1] = data;
33 frame->data[2] = data;
34 frame->linesize[0] = width;
35 frame->linesize[1] = width / 2;
36 frame->linesize[2] = width / 2;
39 ACTION_P(DecodeComplete, decoder) {
40 decoder->set_video_frame(arg0);
43 ACTION_P2(DemuxComplete, engine, buffer) {
44 engine->ConsumeVideoSample(buffer);
47 ACTION_P(SaveInitializeResult, engine) {
48 engine->set_video_codec_info(arg0);
51 class FFmpegVideoDecodeEngineTest
52 : public testing::Test,
53 public VideoDecodeEngine::EventHandler {
54 public:
55 FFmpegVideoDecodeEngineTest()
56 : config_(kCodecH264, kWidth, kHeight, kSurfaceWidth, kSurfaceHeight,
57 kFrameRate.num, kFrameRate.den, NULL, 0) {
59 // Setup FFmpeg structures.
60 frame_buffer_.reset(new uint8[kWidth * kHeight]);
61 memset(&yuv_frame_, 0, sizeof(yuv_frame_));
62 InitializeFrame(frame_buffer_.get(), kWidth, &yuv_frame_);
64 memset(&codec_context_, 0, sizeof(codec_context_));
65 memset(&codec_, 0, sizeof(codec_));
67 buffer_ = new DataBuffer(1);
69 test_engine_.reset(new FFmpegVideoDecodeEngine());
71 video_frame_ = VideoFrame::CreateFrame(VideoFrame::YV12,
72 kWidth,
73 kHeight,
74 kNoTimestamp,
75 kNoTimestamp);
78 ~FFmpegVideoDecodeEngineTest() {
79 test_engine_.reset();
82 void Initialize() {
83 EXPECT_CALL(mock_ffmpeg_, AVCodecAllocContext())
84 .WillOnce(Return(&codec_context_));
85 EXPECT_CALL(mock_ffmpeg_, AVCodecFindDecoder(CODEC_ID_H264))
86 .WillOnce(Return(&codec_));
87 EXPECT_CALL(mock_ffmpeg_, AVCodecAllocFrame())
88 .WillOnce(Return(&yuv_frame_));
89 EXPECT_CALL(mock_ffmpeg_, AVCodecOpen(&codec_context_, &codec_))
90 .WillOnce(Return(0));
91 EXPECT_CALL(mock_ffmpeg_, AVCodecClose(&codec_context_))
92 .WillOnce(Return(0));
93 EXPECT_CALL(mock_ffmpeg_, AVFree(&yuv_frame_))
94 .Times(1);
95 EXPECT_CALL(mock_ffmpeg_, AVFree(&codec_context_))
96 .Times(1);
98 EXPECT_CALL(*this, OnInitializeComplete(_))
99 .WillOnce(SaveInitializeResult(this));
100 test_engine_->Initialize(MessageLoop::current(), this, NULL, config_);
101 EXPECT_TRUE(info_.success);
104 void Decode() {
105 EXPECT_CALL(mock_ffmpeg_, AVInitPacket(_));
106 EXPECT_CALL(mock_ffmpeg_,
107 AVCodecDecodeVideo2(&codec_context_, &yuv_frame_, _, _))
108 .WillOnce(DoAll(SetArgumentPointee<2>(1), // Simulate 1 byte frame.
109 Return(0)));
111 EXPECT_CALL(*this, ProduceVideoSample(_))
112 .WillOnce(DemuxComplete(test_engine_.get(), buffer_));
113 EXPECT_CALL(*this, ConsumeVideoFrame(_, _))
114 .WillOnce(DecodeComplete(this));
115 test_engine_->ProduceVideoFrame(video_frame_);
118 void ChangeDimensions(int width, int height) {
119 frame_buffer_.reset(new uint8[width * height]);
120 InitializeFrame(frame_buffer_.get(), width, &yuv_frame_);
121 codec_context_.width = width;
122 codec_context_.height = height;
125 // VideoDecodeEngine::EventHandler implementation.
126 MOCK_METHOD2(ConsumeVideoFrame,
127 void(scoped_refptr<VideoFrame> video_frame,
128 const PipelineStatistics& statistics));
129 MOCK_METHOD1(ProduceVideoSample,
130 void(scoped_refptr<Buffer> buffer));
131 MOCK_METHOD1(OnInitializeComplete,
132 void(const VideoCodecInfo& info));
133 MOCK_METHOD0(OnUninitializeComplete, void());
134 MOCK_METHOD0(OnFlushComplete, void());
135 MOCK_METHOD0(OnSeekComplete, void());
136 MOCK_METHOD0(OnError, void());
137 MOCK_METHOD1(OnFormatChange, void(VideoStreamInfo stream_info));
139 // Used by gmock actions.
140 void set_video_frame(scoped_refptr<VideoFrame> video_frame) {
141 video_frame_ = video_frame;
144 void set_video_codec_info(const VideoCodecInfo& info) {
145 info_ = info;
148 protected:
149 VideoDecoderConfig config_;
150 VideoCodecInfo info_;
151 scoped_refptr<VideoFrame> video_frame_;
152 scoped_ptr<FFmpegVideoDecodeEngine> test_engine_;
153 scoped_array<uint8_t> frame_buffer_;
154 StrictMock<MockFFmpeg> mock_ffmpeg_;
156 AVFrame yuv_frame_;
157 AVCodecContext codec_context_;
158 AVCodec codec_;
159 scoped_refptr<DataBuffer> buffer_;
161 private:
162 DISALLOW_COPY_AND_ASSIGN(FFmpegVideoDecodeEngineTest);
165 TEST_F(FFmpegVideoDecodeEngineTest, Initialize_Normal) {
166 Initialize();
169 TEST_F(FFmpegVideoDecodeEngineTest, Initialize_FindDecoderFails) {
170 // Test avcodec_find_decoder() returning NULL.
171 EXPECT_CALL(mock_ffmpeg_, AVCodecAllocContext())
172 .WillOnce(Return(&codec_context_));
173 EXPECT_CALL(mock_ffmpeg_, AVCodecFindDecoder(CODEC_ID_H264))
174 .WillOnce(ReturnNull());
175 EXPECT_CALL(mock_ffmpeg_, AVCodecAllocFrame())
176 .WillOnce(Return(&yuv_frame_));
177 EXPECT_CALL(mock_ffmpeg_, AVCodecClose(&codec_context_))
178 .WillOnce(Return(0));
179 EXPECT_CALL(mock_ffmpeg_, AVFree(&yuv_frame_))
180 .Times(1);
181 EXPECT_CALL(mock_ffmpeg_, AVFree(&codec_context_))
182 .Times(1);
184 EXPECT_CALL(*this, OnInitializeComplete(_))
185 .WillOnce(SaveInitializeResult(this));
186 test_engine_->Initialize(MessageLoop::current(), this, NULL, config_);
187 EXPECT_FALSE(info_.success);
190 TEST_F(FFmpegVideoDecodeEngineTest, Initialize_OpenDecoderFails) {
191 // Test avcodec_open() failing.
192 EXPECT_CALL(mock_ffmpeg_, AVCodecAllocContext())
193 .WillOnce(Return(&codec_context_));
194 EXPECT_CALL(mock_ffmpeg_, AVCodecFindDecoder(CODEC_ID_H264))
195 .WillOnce(Return(&codec_));
196 EXPECT_CALL(mock_ffmpeg_, AVCodecAllocFrame())
197 .WillOnce(Return(&yuv_frame_));
198 EXPECT_CALL(mock_ffmpeg_, AVCodecOpen(&codec_context_, &codec_))
199 .WillOnce(Return(-1));
200 EXPECT_CALL(mock_ffmpeg_, AVCodecClose(&codec_context_))
201 .WillOnce(Return(0));
202 EXPECT_CALL(mock_ffmpeg_, AVFree(&yuv_frame_))
203 .Times(1);
204 EXPECT_CALL(mock_ffmpeg_, AVFree(&codec_context_))
205 .Times(1);
207 EXPECT_CALL(*this, OnInitializeComplete(_))
208 .WillOnce(SaveInitializeResult(this));
209 test_engine_->Initialize(MessageLoop::current(), this, NULL, config_);
210 EXPECT_FALSE(info_.success);
213 TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_Normal) {
214 Initialize();
216 // We rely on FFmpeg for timestamp and duration reporting. The one tricky
217 // bit is calculating the duration when |repeat_pict| > 0.
218 const base::TimeDelta kTimestamp = base::TimeDelta::FromMicroseconds(123);
219 const base::TimeDelta kDuration = base::TimeDelta::FromMicroseconds(15000);
220 yuv_frame_.repeat_pict = 1;
221 yuv_frame_.reordered_opaque = kTimestamp.InMicroseconds();
223 // Simulate decoding a single frame.
224 Decode();
226 // |video_frame_| timestamp is 0 because we set the timestamp based off
227 // the buffer timestamp.
228 EXPECT_EQ(0, video_frame_->GetTimestamp().ToInternalValue());
229 EXPECT_EQ(kDuration.ToInternalValue(),
230 video_frame_->GetDuration().ToInternalValue());
233 TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_0ByteFrame) {
234 Initialize();
236 // Expect a bunch of avcodec calls.
237 EXPECT_CALL(mock_ffmpeg_, AVInitPacket(_))
238 .Times(2);
239 EXPECT_CALL(mock_ffmpeg_,
240 AVCodecDecodeVideo2(&codec_context_, &yuv_frame_, _, _))
241 .WillOnce(DoAll(SetArgumentPointee<2>(0), // Simulate 0 byte frame.
242 Return(0)))
243 .WillOnce(DoAll(SetArgumentPointee<2>(1), // Simulate 1 byte frame.
244 Return(0)));
246 EXPECT_CALL(*this, ProduceVideoSample(_))
247 .WillOnce(DemuxComplete(test_engine_.get(), buffer_))
248 .WillOnce(DemuxComplete(test_engine_.get(), buffer_));
249 EXPECT_CALL(*this, ConsumeVideoFrame(_, _))
250 .WillOnce(DecodeComplete(this));
251 test_engine_->ProduceVideoFrame(video_frame_);
253 EXPECT_TRUE(video_frame_.get());
256 TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_DecodeError) {
257 Initialize();
259 // Expect a bunch of avcodec calls.
260 EXPECT_CALL(mock_ffmpeg_, AVInitPacket(_));
261 EXPECT_CALL(mock_ffmpeg_,
262 AVCodecDecodeVideo2(&codec_context_, &yuv_frame_, _, _))
263 .WillOnce(Return(-1));
265 EXPECT_CALL(*this, ProduceVideoSample(_))
266 .WillOnce(DemuxComplete(test_engine_.get(), buffer_));
267 EXPECT_CALL(*this, OnError());
269 test_engine_->ProduceVideoFrame(video_frame_);
272 TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_LargerWidth) {
273 Initialize();
274 ChangeDimensions(kWidth * 2, kHeight);
275 Decode();
278 TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_SmallerWidth) {
279 Initialize();
280 ChangeDimensions(kWidth / 2, kHeight);
281 Decode();
284 TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_LargerHeight) {
285 Initialize();
286 ChangeDimensions(kWidth, kHeight * 2);
287 Decode();
290 TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_SmallerHeight) {
291 Initialize();
292 ChangeDimensions(kWidth, kHeight / 2);
293 Decode();
296 TEST_F(FFmpegVideoDecodeEngineTest, GetSurfaceFormat) {
297 Initialize();
299 // YV12 formats.
300 codec_context_.pix_fmt = PIX_FMT_YUV420P;
301 EXPECT_EQ(VideoFrame::YV12, test_engine_->GetSurfaceFormat());
302 codec_context_.pix_fmt = PIX_FMT_YUVJ420P;
303 EXPECT_EQ(VideoFrame::YV12, test_engine_->GetSurfaceFormat());
305 // YV16 formats.
306 codec_context_.pix_fmt = PIX_FMT_YUV422P;
307 EXPECT_EQ(VideoFrame::YV16, test_engine_->GetSurfaceFormat());
308 codec_context_.pix_fmt = PIX_FMT_YUVJ422P;
309 EXPECT_EQ(VideoFrame::YV16, test_engine_->GetSurfaceFormat());
311 // Invalid value.
312 codec_context_.pix_fmt = PIX_FMT_NONE;
313 EXPECT_EQ(VideoFrame::INVALID, test_engine_->GetSurfaceFormat());
316 } // namespace media