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"
16 using ::testing::DoAll
;
17 using ::testing::Return
;
18 using ::testing::ReturnNull
;
19 using ::testing::SetArgumentPointee
;
20 using ::testing::StrictMock
;
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
{
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
,
78 ~FFmpegVideoDecodeEngineTest() {
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_
))
91 EXPECT_CALL(mock_ffmpeg_
, AVCodecClose(&codec_context_
))
93 EXPECT_CALL(mock_ffmpeg_
, AVFree(&yuv_frame_
))
95 EXPECT_CALL(mock_ffmpeg_
, AVFree(&codec_context_
))
98 EXPECT_CALL(*this, OnInitializeComplete(_
))
99 .WillOnce(SaveInitializeResult(this));
100 test_engine_
->Initialize(MessageLoop::current(), this, NULL
, config_
);
101 EXPECT_TRUE(info_
.success
);
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.
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
) {
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_
;
157 AVCodecContext codec_context_
;
159 scoped_refptr
<DataBuffer
> buffer_
;
162 DISALLOW_COPY_AND_ASSIGN(FFmpegVideoDecodeEngineTest
);
165 TEST_F(FFmpegVideoDecodeEngineTest
, Initialize_Normal
) {
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_
))
181 EXPECT_CALL(mock_ffmpeg_
, AVFree(&codec_context_
))
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_
))
204 EXPECT_CALL(mock_ffmpeg_
, AVFree(&codec_context_
))
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
) {
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.
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
) {
236 // Expect a bunch of avcodec calls.
237 EXPECT_CALL(mock_ffmpeg_
, AVInitPacket(_
))
239 EXPECT_CALL(mock_ffmpeg_
,
240 AVCodecDecodeVideo2(&codec_context_
, &yuv_frame_
, _
, _
))
241 .WillOnce(DoAll(SetArgumentPointee
<2>(0), // Simulate 0 byte frame.
243 .WillOnce(DoAll(SetArgumentPointee
<2>(1), // Simulate 1 byte frame.
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
) {
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
) {
274 ChangeDimensions(kWidth
* 2, kHeight
);
278 TEST_F(FFmpegVideoDecodeEngineTest
, DecodeFrame_SmallerWidth
) {
280 ChangeDimensions(kWidth
/ 2, kHeight
);
284 TEST_F(FFmpegVideoDecodeEngineTest
, DecodeFrame_LargerHeight
) {
286 ChangeDimensions(kWidth
, kHeight
* 2);
290 TEST_F(FFmpegVideoDecodeEngineTest
, DecodeFrame_SmallerHeight
) {
292 ChangeDimensions(kWidth
, kHeight
/ 2);
296 TEST_F(FFmpegVideoDecodeEngineTest
, GetSurfaceFormat
) {
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());
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());
312 codec_context_
.pix_fmt
= PIX_FMT_NONE
;
313 EXPECT_EQ(VideoFrame::INVALID
, test_engine_
->GetSurfaceFormat());