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, 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();
89 decoder_->Stop(NewExpectedClosure());
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->IsEndOfStream());
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->IsEndOfStream());
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->IsEndOfStream()) {
144 output_frames->push_back(frame);
149 case VideoDecoder::kNotEnoughData:
152 case VideoDecoder::kDecodeError:
153 case VideoDecoder::kDecryptError:
160 // Decodes the single compressed frame in |buffer| and writes the
161 // uncompressed output to |video_frame|. This method works with single
162 // and multithreaded decoders. End of stream buffers are used to trigger
163 // the frame to be returned in the multithreaded decoder case.
164 void DecodeSingleFrame(const scoped_refptr<DecoderBuffer>& buffer,
165 VideoDecoder::Status* status,
166 scoped_refptr<VideoFrame>* video_frame) {
167 InputBuffers input_buffers;
168 input_buffers.push_back(buffer);
170 OutputFrames output_frames;
171 *status = DecodeMultipleFrames(input_buffers, &output_frames);
173 if (*status != VideoDecoder::kOk)
176 ASSERT_LE(output_frames.size(), 1U);
177 if (output_frames.size() == 1U)
178 *video_frame = output_frames[0];
180 *video_frame = VideoFrame::CreateEmptyFrame();
183 // Decodes |i_frame_buffer_| and then decodes the data contained in
184 // the file named |test_file_name|. This function expects both buffers
185 // to decode to frames that are the same size.
186 void DecodeIFrameThenTestFile(const std::string& test_file_name,
188 int expected_height) {
190 scoped_refptr<DecoderBuffer> buffer = ReadTestDataFile(test_file_name);
192 InputBuffers input_buffers;
193 input_buffers.push_back(i_frame_buffer_);
194 input_buffers.push_back(buffer);
196 OutputFrames output_frames;
197 VideoDecoder::Status status =
198 DecodeMultipleFrames(input_buffers, &output_frames);
200 EXPECT_EQ(VideoDecoder::kOk, status);
201 ASSERT_EQ(2U, output_frames.size());
203 gfx::Size original_size = kVisibleRect.size();
204 EXPECT_EQ(original_size.width(),
205 output_frames[0]->visible_rect().size().width());
206 EXPECT_EQ(original_size.height(),
207 output_frames[0]->visible_rect().size().height());
208 EXPECT_EQ(expected_width,
209 output_frames[1]->visible_rect().size().width());
210 EXPECT_EQ(expected_height,
211 output_frames[1]->visible_rect().size().height());
214 void Decode(const scoped_refptr<DecoderBuffer>& buffer,
215 VideoDecoder::Status* status,
216 scoped_refptr<VideoFrame>* video_frame) {
217 EXPECT_CALL(*this, FrameReady(_, _))
218 .WillOnce(DoAll(SaveArg<0>(status), SaveArg<1>(video_frame)));
220 decoder_->Decode(buffer, decode_cb_);
222 message_loop_.RunUntilIdle();
225 MOCK_METHOD2(FrameReady, void(VideoDecoder::Status,
226 const scoped_refptr<VideoFrame>&));
228 base::MessageLoop message_loop_;
229 scoped_ptr<FFmpegVideoDecoder> decoder_;
231 VideoDecoder::DecodeCB decode_cb_;
233 // Various buffers for testing.
234 scoped_ptr<uint8_t[]> frame_buffer_;
235 scoped_refptr<DecoderBuffer> end_of_stream_buffer_;
236 scoped_refptr<DecoderBuffer> i_frame_buffer_;
237 scoped_refptr<DecoderBuffer> corrupt_i_frame_buffer_;
240 DISALLOW_COPY_AND_ASSIGN(FFmpegVideoDecoderTest);
243 TEST_F(FFmpegVideoDecoderTest, Initialize_Normal) {
247 TEST_F(FFmpegVideoDecoderTest, Initialize_UnsupportedDecoder) {
248 // Test avcodec_find_decoder() returning NULL.
249 InitializeWithConfigAndStatus(TestVideoConfig::Invalid(),
250 DECODER_ERROR_NOT_SUPPORTED);
253 TEST_F(FFmpegVideoDecoderTest, Initialize_UnsupportedPixelFormat) {
254 // Ensure decoder handles unsupported pixel formats without crashing.
255 VideoDecoderConfig config(kCodecVP8, VIDEO_CODEC_PROFILE_UNKNOWN,
257 kCodedSize, kVisibleRect, kNaturalSize,
259 InitializeWithConfigAndStatus(config, DECODER_ERROR_NOT_SUPPORTED);
262 TEST_F(FFmpegVideoDecoderTest, Initialize_OpenDecoderFails) {
263 // Specify Theora w/o extra data so that avcodec_open2() fails.
264 VideoDecoderConfig config(kCodecTheora, VIDEO_CODEC_PROFILE_UNKNOWN,
266 kCodedSize, kVisibleRect, kNaturalSize,
268 InitializeWithConfigAndStatus(config, DECODER_ERROR_NOT_SUPPORTED);
271 TEST_F(FFmpegVideoDecoderTest, Initialize_AspectRatioNumeratorZero) {
272 gfx::Size natural_size = GetNaturalSize(kVisibleRect.size(), 0, 1);
273 VideoDecoderConfig config(kCodecVP8, VP8PROFILE_MAIN,
275 kCodedSize, kVisibleRect, natural_size,
277 InitializeWithConfigAndStatus(config, DECODER_ERROR_NOT_SUPPORTED);
280 TEST_F(FFmpegVideoDecoderTest, Initialize_AspectRatioDenominatorZero) {
281 gfx::Size natural_size = GetNaturalSize(kVisibleRect.size(), 1, 0);
282 VideoDecoderConfig config(kCodecVP8, VP8PROFILE_MAIN,
284 kCodedSize, kVisibleRect, natural_size,
286 InitializeWithConfigAndStatus(config, DECODER_ERROR_NOT_SUPPORTED);
289 TEST_F(FFmpegVideoDecoderTest, Initialize_AspectRatioNumeratorNegative) {
290 gfx::Size natural_size = GetNaturalSize(kVisibleRect.size(), -1, 1);
291 VideoDecoderConfig config(kCodecVP8, VP8PROFILE_MAIN,
293 kCodedSize, kVisibleRect, natural_size,
295 InitializeWithConfigAndStatus(config, DECODER_ERROR_NOT_SUPPORTED);
298 TEST_F(FFmpegVideoDecoderTest, Initialize_AspectRatioDenominatorNegative) {
299 gfx::Size natural_size = GetNaturalSize(kVisibleRect.size(), 1, -1);
300 VideoDecoderConfig config(kCodecVP8, VP8PROFILE_MAIN,
302 kCodedSize, kVisibleRect, natural_size,
304 InitializeWithConfigAndStatus(config, DECODER_ERROR_NOT_SUPPORTED);
307 TEST_F(FFmpegVideoDecoderTest, Initialize_AspectRatioNumeratorTooLarge) {
308 int width = kVisibleRect.size().width();
309 int num = ceil(static_cast<double>(limits::kMaxDimension + 1) / width);
310 gfx::Size natural_size = GetNaturalSize(kVisibleRect.size(), num, 1);
311 VideoDecoderConfig config(kCodecVP8, VP8PROFILE_MAIN,
313 kCodedSize, kVisibleRect, natural_size,
315 InitializeWithConfigAndStatus(config, DECODER_ERROR_NOT_SUPPORTED);
318 TEST_F(FFmpegVideoDecoderTest, Initialize_AspectRatioDenominatorTooLarge) {
319 int den = kVisibleRect.size().width() + 1;
320 gfx::Size natural_size = GetNaturalSize(kVisibleRect.size(), 1, den);
321 VideoDecoderConfig config(kCodecVP8, VP8PROFILE_MAIN,
323 kCodedSize, kVisibleRect, natural_size,
325 InitializeWithConfigAndStatus(config, DECODER_ERROR_NOT_SUPPORTED);
328 TEST_F(FFmpegVideoDecoderTest, Reinitialize_Normal) {
333 TEST_F(FFmpegVideoDecoderTest, Reinitialize_Failure) {
335 InitializeWithConfigAndStatus(TestVideoConfig::Invalid(),
336 DECODER_ERROR_NOT_SUPPORTED);
339 TEST_F(FFmpegVideoDecoderTest, Reinitialize_AfterDecodeFrame) {
341 EnterDecodingState();
345 TEST_F(FFmpegVideoDecoderTest, Reinitialize_AfterReset) {
347 EnterDecodingState();
352 TEST_F(FFmpegVideoDecoderTest, DecodeFrame_Normal) {
355 // Simulate decoding a single frame.
356 VideoDecoder::Status status;
357 scoped_refptr<VideoFrame> video_frame;
358 DecodeSingleFrame(i_frame_buffer_, &status, &video_frame);
360 EXPECT_EQ(VideoDecoder::kOk, status);
361 ASSERT_TRUE(video_frame.get());
362 EXPECT_FALSE(video_frame->IsEndOfStream());
365 // Verify current behavior for 0 byte frames. FFmpeg simply ignores
366 // the 0 byte frames.
367 TEST_F(FFmpegVideoDecoderTest, DecodeFrame_0ByteFrame) {
370 scoped_refptr<DecoderBuffer> zero_byte_buffer = new DecoderBuffer(0);
372 InputBuffers input_buffers;
373 input_buffers.push_back(i_frame_buffer_);
374 input_buffers.push_back(zero_byte_buffer);
375 input_buffers.push_back(i_frame_buffer_);
377 OutputFrames output_frames;
378 VideoDecoder::Status status =
379 DecodeMultipleFrames(input_buffers, &output_frames);
381 EXPECT_EQ(VideoDecoder::kOk, status);
382 ASSERT_EQ(2U, output_frames.size());
384 EXPECT_FALSE(output_frames[0]->IsEndOfStream());
385 EXPECT_FALSE(output_frames[1]->IsEndOfStream());
388 TEST_F(FFmpegVideoDecoderTest, DecodeFrame_DecodeError) {
391 VideoDecoder::Status status;
392 scoped_refptr<VideoFrame> frame;
394 // The error is only raised on the second decode attempt, so we expect at
395 // least one successful decode but we don't expect valid frame to be decoded.
396 // During the second decode attempt an error is raised.
397 Decode(corrupt_i_frame_buffer_, &status, &frame);
399 DCHECK_EQ(VideoDecoder::kNotEnoughData, status);
400 Decode(i_frame_buffer_, &status, &frame);
402 DCHECK_EQ(VideoDecoder::kDecodeError, status);
404 // After a decode error occurred, all following decodes will return
406 Decode(i_frame_buffer_, &status, &frame);
408 DCHECK_EQ(VideoDecoder::kDecodeError, status);
411 // Multi-threaded decoders have different behavior than single-threaded
412 // decoders at the end of the stream. Multithreaded decoders hide errors
413 // that happen on the last |codec_context_->thread_count| frames to avoid
414 // prematurely signalling EOS. This test just exposes that behavior so we can
415 // detect if it changes.
416 TEST_F(FFmpegVideoDecoderTest, DecodeFrame_DecodeErrorAtEndOfStream) {
419 VideoDecoder::Status status;
420 scoped_refptr<VideoFrame> video_frame;
421 DecodeSingleFrame(corrupt_i_frame_buffer_, &status, &video_frame);
423 EXPECT_EQ(VideoDecoder::kOk, status);
424 ASSERT_TRUE(video_frame.get());
425 EXPECT_TRUE(video_frame->IsEndOfStream());
428 // Decode |i_frame_buffer_| and then a frame with a larger width and verify
429 // the output size was adjusted.
430 TEST_F(FFmpegVideoDecoderTest, DecodeFrame_LargerWidth) {
431 DecodeIFrameThenTestFile("vp8-I-frame-640x240", 640, 240);
434 // Decode |i_frame_buffer_| and then a frame with a smaller width and verify
435 // the output size was adjusted.
436 TEST_F(FFmpegVideoDecoderTest, DecodeFrame_SmallerWidth) {
437 DecodeIFrameThenTestFile("vp8-I-frame-160x240", 160, 240);
440 // Decode |i_frame_buffer_| and then a frame with a larger height and verify
441 // the output size was adjusted.
442 TEST_F(FFmpegVideoDecoderTest, DecodeFrame_LargerHeight) {
443 DecodeIFrameThenTestFile("vp8-I-frame-320x480", 320, 480);
446 // Decode |i_frame_buffer_| and then a frame with a smaller height and verify
447 // the output size was adjusted.
448 TEST_F(FFmpegVideoDecoderTest, DecodeFrame_SmallerHeight) {
449 DecodeIFrameThenTestFile("vp8-I-frame-320x120", 320, 120);
452 // Test resetting when decoder has initialized but not decoded.
453 TEST_F(FFmpegVideoDecoderTest, Reset_Initialized) {
458 // Test resetting when decoder has decoded single frame.
459 TEST_F(FFmpegVideoDecoderTest, Reset_Decoding) {
461 EnterDecodingState();
465 // Test resetting when decoder has hit end of stream.
466 TEST_F(FFmpegVideoDecoderTest, Reset_EndOfStream) {
468 EnterDecodingState();
469 EnterEndOfStreamState();
473 // Test stopping when decoder has initialized but not decoded.
474 TEST_F(FFmpegVideoDecoderTest, Stop_Initialized) {
479 // Test stopping when decoder has decoded single frame.
480 TEST_F(FFmpegVideoDecoderTest, Stop_Decoding) {
482 EnterDecodingState();
486 // Test stopping when decoder has hit end of stream.
487 TEST_F(FFmpegVideoDecoderTest, Stop_EndOfStream) {
489 EnterDecodingState();
490 EnterEndOfStreamState();