1 // Copyright (c) 2012 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.
9 #include "base/callback_helpers.h"
10 #include "base/memory/singleton.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/strings/string_util.h"
13 #include "media/base/decoder_buffer.h"
14 #include "media/base/gmock_callback_support.h"
15 #include "media/base/limits.h"
16 #include "media/base/mock_filters.h"
17 #include "media/base/test_data_util.h"
18 #include "media/base/test_helpers.h"
19 #include "media/base/video_decoder.h"
20 #include "media/base/video_frame.h"
21 #include "media/base/video_util.h"
22 #include "media/ffmpeg/ffmpeg_common.h"
23 #include "media/filters/ffmpeg_glue.h"
24 #include "media/filters/ffmpeg_video_decoder.h"
25 #include "testing/gmock/include/gmock/gmock.h"
28 using ::testing::AtLeast;
29 using ::testing::InSequence;
30 using ::testing::IsNull;
31 using ::testing::Return;
32 using ::testing::SaveArg;
33 using ::testing::StrictMock;
37 static const VideoFrame::Format kVideoFormat = VideoFrame::YV12;
38 static const gfx::Size kCodedSize(320, 240);
39 static const gfx::Rect kVisibleRect(320, 240);
40 static const gfx::Size kNaturalSize(320, 240);
42 ACTION_P(ReturnBuffer, buffer) {
43 arg0.Run(buffer.get() ? DemuxerStream::kOk : DemuxerStream::kAborted, buffer);
46 class FFmpegVideoDecoderTest : public testing::Test {
48 FFmpegVideoDecoderTest()
49 : decoder_(new FFmpegVideoDecoder(message_loop_.message_loop_proxy())),
50 decode_cb_(base::Bind(&FFmpegVideoDecoderTest::FrameReady,
51 base::Unretained(this))) {
52 FFmpegGlue::InitializeFFmpeg();
54 // Initialize various test buffers.
55 frame_buffer_.reset(new uint8[kCodedSize.GetArea()]);
56 end_of_stream_buffer_ = DecoderBuffer::CreateEOSBuffer();
57 i_frame_buffer_ = ReadTestDataFile("vp8-I-frame-320x240");
58 corrupt_i_frame_buffer_ = ReadTestDataFile("vp8-corrupt-I-frame");
61 virtual ~FFmpegVideoDecoderTest() {
66 InitializeWithConfig(TestVideoConfig::Normal());
69 void InitializeWithConfigAndStatus(const VideoDecoderConfig& config,
70 PipelineStatus status) {
71 decoder_->Initialize(config, false, NewExpectedStatusCB(status));
72 message_loop_.RunUntilIdle();
75 void InitializeWithConfig(const VideoDecoderConfig& config) {
76 InitializeWithConfigAndStatus(config, PIPELINE_OK);
80 InitializeWithConfig(TestVideoConfig::Large());
84 decoder_->Reset(NewExpectedClosure());
85 message_loop_.RunUntilIdle();
90 message_loop_.RunUntilIdle();
93 // Sets up expectations and actions to put FFmpegVideoDecoder in an active
95 void EnterDecodingState() {
96 VideoDecoder::Status status;
97 scoped_refptr<VideoFrame> video_frame;
98 DecodeSingleFrame(i_frame_buffer_, &status, &video_frame);
100 EXPECT_EQ(VideoDecoder::kOk, status);
101 ASSERT_TRUE(video_frame.get());
102 EXPECT_FALSE(video_frame->end_of_stream());
105 // Sets up expectations and actions to put FFmpegVideoDecoder in an end
107 void EnterEndOfStreamState() {
108 VideoDecoder::Status status;
109 scoped_refptr<VideoFrame> video_frame;
110 DecodeSingleFrame(end_of_stream_buffer_, &status, &video_frame);
111 EXPECT_EQ(VideoDecoder::kOk, status);
112 ASSERT_TRUE(video_frame.get());
113 EXPECT_TRUE(video_frame->end_of_stream());
116 typedef std::vector<scoped_refptr<DecoderBuffer> > InputBuffers;
117 typedef std::vector<scoped_refptr<VideoFrame> > OutputFrames;
119 // Decodes all buffers in |input_buffers| and push all successfully decoded
120 // output frames (excluding EOS frames) into |output_frames|.
121 // Returns the last decode status returned by the decoder.
122 VideoDecoder::Status DecodeMultipleFrames(const InputBuffers& input_buffers,
123 OutputFrames* output_frames) {
124 InputBuffers::const_iterator input_iter = input_buffers.begin();
127 // Prepare input buffer.
128 scoped_refptr<DecoderBuffer> buffer;
129 if (input_iter != input_buffers.end()) {
130 buffer = *input_iter;
133 buffer = end_of_stream_buffer_;
136 VideoDecoder::Status status;
137 scoped_refptr<VideoFrame> frame;
138 Decode(buffer, &status, &frame);
141 case VideoDecoder::kOk:
143 if (!frame->end_of_stream()) {
144 output_frames->push_back(frame);
149 case VideoDecoder::kNotEnoughData:
152 case VideoDecoder::kAborted:
154 case VideoDecoder::kDecodeError:
155 case VideoDecoder::kDecryptError:
162 // Decodes the single compressed frame in |buffer| and writes the
163 // uncompressed output to |video_frame|. This method works with single
164 // and multithreaded decoders. End of stream buffers are used to trigger
165 // the frame to be returned in the multithreaded decoder case.
166 void DecodeSingleFrame(const scoped_refptr<DecoderBuffer>& buffer,
167 VideoDecoder::Status* status,
168 scoped_refptr<VideoFrame>* video_frame) {
169 InputBuffers input_buffers;
170 input_buffers.push_back(buffer);
172 OutputFrames output_frames;
173 *status = DecodeMultipleFrames(input_buffers, &output_frames);
175 if (*status != VideoDecoder::kOk)
178 ASSERT_LE(output_frames.size(), 1U);
179 if (output_frames.size() == 1U)
180 *video_frame = output_frames[0];
182 *video_frame = VideoFrame::CreateEOSFrame();
185 // Decodes |i_frame_buffer_| and then decodes the data contained in
186 // the file named |test_file_name|. This function expects both buffers
187 // to decode to frames that are the same size.
188 void DecodeIFrameThenTestFile(const std::string& test_file_name,
190 int expected_height) {
192 scoped_refptr<DecoderBuffer> buffer = ReadTestDataFile(test_file_name);
194 InputBuffers input_buffers;
195 input_buffers.push_back(i_frame_buffer_);
196 input_buffers.push_back(buffer);
198 OutputFrames output_frames;
199 VideoDecoder::Status status =
200 DecodeMultipleFrames(input_buffers, &output_frames);
202 EXPECT_EQ(VideoDecoder::kOk, status);
203 ASSERT_EQ(2U, output_frames.size());
205 gfx::Size original_size = kVisibleRect.size();
206 EXPECT_EQ(original_size.width(),
207 output_frames[0]->visible_rect().size().width());
208 EXPECT_EQ(original_size.height(),
209 output_frames[0]->visible_rect().size().height());
210 EXPECT_EQ(expected_width,
211 output_frames[1]->visible_rect().size().width());
212 EXPECT_EQ(expected_height,
213 output_frames[1]->visible_rect().size().height());
216 void Decode(const scoped_refptr<DecoderBuffer>& buffer,
217 VideoDecoder::Status* status,
218 scoped_refptr<VideoFrame>* video_frame) {
219 EXPECT_CALL(*this, FrameReady(_, _))
220 .WillOnce(DoAll(SaveArg<0>(status), SaveArg<1>(video_frame)));
222 decoder_->Decode(buffer, decode_cb_);
224 message_loop_.RunUntilIdle();
227 MOCK_METHOD2(FrameReady, void(VideoDecoder::Status,
228 const scoped_refptr<VideoFrame>&));
230 base::MessageLoop message_loop_;
231 scoped_ptr<FFmpegVideoDecoder> decoder_;
233 VideoDecoder::DecodeCB decode_cb_;
235 // Various buffers for testing.
236 scoped_ptr<uint8_t[]> frame_buffer_;
237 scoped_refptr<DecoderBuffer> end_of_stream_buffer_;
238 scoped_refptr<DecoderBuffer> i_frame_buffer_;
239 scoped_refptr<DecoderBuffer> corrupt_i_frame_buffer_;
242 DISALLOW_COPY_AND_ASSIGN(FFmpegVideoDecoderTest);
245 TEST_F(FFmpegVideoDecoderTest, Initialize_Normal) {
249 TEST_F(FFmpegVideoDecoderTest, Initialize_UnsupportedDecoder) {
250 // Test avcodec_find_decoder() returning NULL.
251 InitializeWithConfigAndStatus(TestVideoConfig::Invalid(),
252 DECODER_ERROR_NOT_SUPPORTED);
255 TEST_F(FFmpegVideoDecoderTest, Initialize_UnsupportedPixelFormat) {
256 // Ensure decoder handles unsupported pixel formats without crashing.
257 VideoDecoderConfig config(kCodecVP8, VIDEO_CODEC_PROFILE_UNKNOWN,
259 kCodedSize, kVisibleRect, kNaturalSize,
261 InitializeWithConfigAndStatus(config, DECODER_ERROR_NOT_SUPPORTED);
264 TEST_F(FFmpegVideoDecoderTest, Initialize_OpenDecoderFails) {
265 // Specify Theora w/o extra data so that avcodec_open2() fails.
266 VideoDecoderConfig config(kCodecTheora, VIDEO_CODEC_PROFILE_UNKNOWN,
268 kCodedSize, kVisibleRect, kNaturalSize,
270 InitializeWithConfigAndStatus(config, DECODER_ERROR_NOT_SUPPORTED);
273 TEST_F(FFmpegVideoDecoderTest, Initialize_AspectRatioNumeratorZero) {
274 gfx::Size natural_size = GetNaturalSize(kVisibleRect.size(), 0, 1);
275 VideoDecoderConfig config(kCodecVP8, VP8PROFILE_MAIN,
277 kCodedSize, kVisibleRect, natural_size,
279 InitializeWithConfigAndStatus(config, DECODER_ERROR_NOT_SUPPORTED);
282 TEST_F(FFmpegVideoDecoderTest, Initialize_AspectRatioDenominatorZero) {
283 gfx::Size natural_size = GetNaturalSize(kVisibleRect.size(), 1, 0);
284 VideoDecoderConfig config(kCodecVP8, VP8PROFILE_MAIN,
286 kCodedSize, kVisibleRect, natural_size,
288 InitializeWithConfigAndStatus(config, DECODER_ERROR_NOT_SUPPORTED);
291 TEST_F(FFmpegVideoDecoderTest, Initialize_AspectRatioNumeratorNegative) {
292 gfx::Size natural_size = GetNaturalSize(kVisibleRect.size(), -1, 1);
293 VideoDecoderConfig config(kCodecVP8, VP8PROFILE_MAIN,
295 kCodedSize, kVisibleRect, natural_size,
297 InitializeWithConfigAndStatus(config, DECODER_ERROR_NOT_SUPPORTED);
300 TEST_F(FFmpegVideoDecoderTest, Initialize_AspectRatioDenominatorNegative) {
301 gfx::Size natural_size = GetNaturalSize(kVisibleRect.size(), 1, -1);
302 VideoDecoderConfig config(kCodecVP8, VP8PROFILE_MAIN,
304 kCodedSize, kVisibleRect, natural_size,
306 InitializeWithConfigAndStatus(config, DECODER_ERROR_NOT_SUPPORTED);
309 TEST_F(FFmpegVideoDecoderTest, Initialize_AspectRatioNumeratorTooLarge) {
310 int width = kVisibleRect.size().width();
311 int num = ceil(static_cast<double>(limits::kMaxDimension + 1) / width);
312 gfx::Size natural_size = GetNaturalSize(kVisibleRect.size(), num, 1);
313 VideoDecoderConfig config(kCodecVP8, VP8PROFILE_MAIN,
315 kCodedSize, kVisibleRect, natural_size,
317 InitializeWithConfigAndStatus(config, DECODER_ERROR_NOT_SUPPORTED);
320 TEST_F(FFmpegVideoDecoderTest, Initialize_AspectRatioDenominatorTooLarge) {
321 int den = kVisibleRect.size().width() + 1;
322 gfx::Size natural_size = GetNaturalSize(kVisibleRect.size(), 1, den);
323 VideoDecoderConfig config(kCodecVP8, VP8PROFILE_MAIN,
325 kCodedSize, kVisibleRect, natural_size,
327 InitializeWithConfigAndStatus(config, DECODER_ERROR_NOT_SUPPORTED);
330 TEST_F(FFmpegVideoDecoderTest, Reinitialize_Normal) {
335 TEST_F(FFmpegVideoDecoderTest, Reinitialize_Failure) {
337 InitializeWithConfigAndStatus(TestVideoConfig::Invalid(),
338 DECODER_ERROR_NOT_SUPPORTED);
341 TEST_F(FFmpegVideoDecoderTest, Reinitialize_AfterDecodeFrame) {
343 EnterDecodingState();
347 TEST_F(FFmpegVideoDecoderTest, Reinitialize_AfterReset) {
349 EnterDecodingState();
354 TEST_F(FFmpegVideoDecoderTest, DecodeFrame_Normal) {
357 // Simulate decoding a single frame.
358 VideoDecoder::Status status;
359 scoped_refptr<VideoFrame> video_frame;
360 DecodeSingleFrame(i_frame_buffer_, &status, &video_frame);
362 EXPECT_EQ(VideoDecoder::kOk, status);
363 ASSERT_TRUE(video_frame.get());
364 EXPECT_FALSE(video_frame->end_of_stream());
367 // Verify current behavior for 0 byte frames. FFmpeg simply ignores
368 // the 0 byte frames.
369 TEST_F(FFmpegVideoDecoderTest, DecodeFrame_0ByteFrame) {
372 scoped_refptr<DecoderBuffer> zero_byte_buffer = new DecoderBuffer(0);
374 InputBuffers input_buffers;
375 input_buffers.push_back(i_frame_buffer_);
376 input_buffers.push_back(zero_byte_buffer);
377 input_buffers.push_back(i_frame_buffer_);
379 OutputFrames output_frames;
380 VideoDecoder::Status status =
381 DecodeMultipleFrames(input_buffers, &output_frames);
383 EXPECT_EQ(VideoDecoder::kOk, status);
384 ASSERT_EQ(2U, output_frames.size());
386 EXPECT_FALSE(output_frames[0]->end_of_stream());
387 EXPECT_FALSE(output_frames[1]->end_of_stream());
390 TEST_F(FFmpegVideoDecoderTest, DecodeFrame_DecodeError) {
393 VideoDecoder::Status status;
394 scoped_refptr<VideoFrame> frame;
396 // The error is only raised on the second decode attempt, so we expect at
397 // least one successful decode but we don't expect valid frame to be decoded.
398 // During the second decode attempt an error is raised.
399 Decode(corrupt_i_frame_buffer_, &status, &frame);
401 DCHECK_EQ(VideoDecoder::kNotEnoughData, status);
402 Decode(i_frame_buffer_, &status, &frame);
404 DCHECK_EQ(VideoDecoder::kDecodeError, status);
406 // After a decode error occurred, all following decodes will return
408 Decode(i_frame_buffer_, &status, &frame);
410 DCHECK_EQ(VideoDecoder::kDecodeError, status);
413 // Multi-threaded decoders have different behavior than single-threaded
414 // decoders at the end of the stream. Multithreaded decoders hide errors
415 // that happen on the last |codec_context_->thread_count| frames to avoid
416 // prematurely signalling EOS. This test just exposes that behavior so we can
417 // detect if it changes.
418 TEST_F(FFmpegVideoDecoderTest, DecodeFrame_DecodeErrorAtEndOfStream) {
421 VideoDecoder::Status status;
422 scoped_refptr<VideoFrame> video_frame;
423 DecodeSingleFrame(corrupt_i_frame_buffer_, &status, &video_frame);
425 EXPECT_EQ(VideoDecoder::kOk, status);
426 ASSERT_TRUE(video_frame.get());
427 EXPECT_TRUE(video_frame->end_of_stream());
430 // Decode |i_frame_buffer_| and then a frame with a larger width and verify
431 // the output size was adjusted.
432 TEST_F(FFmpegVideoDecoderTest, DecodeFrame_LargerWidth) {
433 DecodeIFrameThenTestFile("vp8-I-frame-640x240", 640, 240);
436 // Decode |i_frame_buffer_| and then a frame with a smaller width and verify
437 // the output size was adjusted.
438 TEST_F(FFmpegVideoDecoderTest, DecodeFrame_SmallerWidth) {
439 DecodeIFrameThenTestFile("vp8-I-frame-160x240", 160, 240);
442 // Decode |i_frame_buffer_| and then a frame with a larger height and verify
443 // the output size was adjusted.
444 TEST_F(FFmpegVideoDecoderTest, DecodeFrame_LargerHeight) {
445 DecodeIFrameThenTestFile("vp8-I-frame-320x480", 320, 480);
448 // Decode |i_frame_buffer_| and then a frame with a smaller height and verify
449 // the output size was adjusted.
450 TEST_F(FFmpegVideoDecoderTest, DecodeFrame_SmallerHeight) {
451 DecodeIFrameThenTestFile("vp8-I-frame-320x120", 320, 120);
454 // Test resetting when decoder has initialized but not decoded.
455 TEST_F(FFmpegVideoDecoderTest, Reset_Initialized) {
460 // Test resetting when decoder has decoded single frame.
461 TEST_F(FFmpegVideoDecoderTest, Reset_Decoding) {
463 EnterDecodingState();
467 // Test resetting when decoder has hit end of stream.
468 TEST_F(FFmpegVideoDecoderTest, Reset_EndOfStream) {
470 EnterDecodingState();
471 EnterEndOfStreamState();
475 // Test stopping when decoder has initialized but not decoded.
476 TEST_F(FFmpegVideoDecoderTest, Stop_Initialized) {
481 // Test stopping when decoder has decoded single frame.
482 TEST_F(FFmpegVideoDecoderTest, Stop_Decoding) {
484 EnterDecodingState();
488 // Test stopping when decoder has hit end of stream.
489 TEST_F(FFmpegVideoDecoderTest, Stop_EndOfStream) {
491 EnterDecodingState();
492 EnterEndOfStreamState();