- add sources.
[platform/framework/web/crosswalk.git] / src / media / filters / ffmpeg_video_decoder_unittest.cc
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.
4
5 #include <string>
6 #include <vector>
7
8 #include "base/bind.h"
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"
26
27 using ::testing::_;
28 using ::testing::AtLeast;
29 using ::testing::InSequence;
30 using ::testing::IsNull;
31 using ::testing::Return;
32 using ::testing::SaveArg;
33 using ::testing::StrictMock;
34
35 namespace media {
36
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);
41
42 ACTION_P(ReturnBuffer, buffer) {
43   arg0.Run(buffer.get() ? DemuxerStream::kOk : DemuxerStream::kAborted, buffer);
44 }
45
46 class FFmpegVideoDecoderTest : public testing::Test {
47  public:
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();
53
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");
59   }
60
61   virtual ~FFmpegVideoDecoderTest() {
62     Stop();
63   }
64
65   void Initialize() {
66     InitializeWithConfig(TestVideoConfig::Normal());
67   }
68
69   void InitializeWithConfigAndStatus(const VideoDecoderConfig& config,
70                                      PipelineStatus status) {
71     decoder_->Initialize(config, NewExpectedStatusCB(status));
72     message_loop_.RunUntilIdle();
73   }
74
75   void InitializeWithConfig(const VideoDecoderConfig& config) {
76     InitializeWithConfigAndStatus(config, PIPELINE_OK);
77   }
78
79   void Reinitialize() {
80     InitializeWithConfig(TestVideoConfig::Large());
81   }
82
83   void Reset() {
84     decoder_->Reset(NewExpectedClosure());
85     message_loop_.RunUntilIdle();
86   }
87
88   void Stop() {
89     decoder_->Stop(NewExpectedClosure());
90     message_loop_.RunUntilIdle();
91   }
92
93   // Sets up expectations and actions to put FFmpegVideoDecoder in an active
94   // decoding state.
95   void EnterDecodingState() {
96     VideoDecoder::Status status;
97     scoped_refptr<VideoFrame> video_frame;
98     DecodeSingleFrame(i_frame_buffer_, &status, &video_frame);
99
100     EXPECT_EQ(VideoDecoder::kOk, status);
101     ASSERT_TRUE(video_frame.get());
102     EXPECT_FALSE(video_frame->IsEndOfStream());
103   }
104
105   // Sets up expectations and actions to put FFmpegVideoDecoder in an end
106   // of stream state.
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());
114   }
115
116   typedef std::vector<scoped_refptr<DecoderBuffer> > InputBuffers;
117   typedef std::vector<scoped_refptr<VideoFrame> > OutputFrames;
118
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();
125
126     for (;;) {
127       // Prepare input buffer.
128       scoped_refptr<DecoderBuffer> buffer;
129       if (input_iter != input_buffers.end()) {
130         buffer = *input_iter;
131         ++input_iter;
132       } else {
133         buffer = end_of_stream_buffer_;
134       }
135
136       VideoDecoder::Status status;
137       scoped_refptr<VideoFrame> frame;
138       Decode(buffer, &status, &frame);
139
140       switch (status) {
141         case VideoDecoder::kOk:
142           DCHECK(frame);
143           if (!frame->IsEndOfStream()) {
144             output_frames->push_back(frame);
145             continue;
146           } else {  // EOS
147             return status;
148           }
149         case VideoDecoder::kNotEnoughData:
150           DCHECK(!frame);
151           continue;
152         case VideoDecoder::kDecodeError:
153         case VideoDecoder::kDecryptError:
154           DCHECK(!frame);
155           return status;
156       }
157     }
158   }
159
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);
169
170     OutputFrames output_frames;
171     *status = DecodeMultipleFrames(input_buffers, &output_frames);
172
173     if (*status != VideoDecoder::kOk)
174       return;
175
176     ASSERT_LE(output_frames.size(), 1U);
177     if (output_frames.size() == 1U)
178       *video_frame = output_frames[0];
179     else
180       *video_frame = VideoFrame::CreateEmptyFrame();
181   }
182
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,
187                                 int expected_width,
188                                 int expected_height) {
189     Initialize();
190     scoped_refptr<DecoderBuffer> buffer = ReadTestDataFile(test_file_name);
191
192     InputBuffers input_buffers;
193     input_buffers.push_back(i_frame_buffer_);
194     input_buffers.push_back(buffer);
195
196     OutputFrames output_frames;
197     VideoDecoder::Status status =
198         DecodeMultipleFrames(input_buffers, &output_frames);
199
200     EXPECT_EQ(VideoDecoder::kOk, status);
201     ASSERT_EQ(2U, output_frames.size());
202
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());
212   }
213
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)));
219
220     decoder_->Decode(buffer, decode_cb_);
221
222     message_loop_.RunUntilIdle();
223   }
224
225   MOCK_METHOD2(FrameReady, void(VideoDecoder::Status,
226                                 const scoped_refptr<VideoFrame>&));
227
228   base::MessageLoop message_loop_;
229   scoped_ptr<FFmpegVideoDecoder> decoder_;
230
231   VideoDecoder::DecodeCB decode_cb_;
232
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_;
238
239  private:
240   DISALLOW_COPY_AND_ASSIGN(FFmpegVideoDecoderTest);
241 };
242
243 TEST_F(FFmpegVideoDecoderTest, Initialize_Normal) {
244   Initialize();
245 }
246
247 TEST_F(FFmpegVideoDecoderTest, Initialize_UnsupportedDecoder) {
248   // Test avcodec_find_decoder() returning NULL.
249   InitializeWithConfigAndStatus(TestVideoConfig::Invalid(),
250                                 DECODER_ERROR_NOT_SUPPORTED);
251 }
252
253 TEST_F(FFmpegVideoDecoderTest, Initialize_UnsupportedPixelFormat) {
254   // Ensure decoder handles unsupported pixel formats without crashing.
255   VideoDecoderConfig config(kCodecVP8, VIDEO_CODEC_PROFILE_UNKNOWN,
256                             VideoFrame::UNKNOWN,
257                             kCodedSize, kVisibleRect, kNaturalSize,
258                             NULL, 0, false);
259   InitializeWithConfigAndStatus(config, DECODER_ERROR_NOT_SUPPORTED);
260 }
261
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,
265                             kVideoFormat,
266                             kCodedSize, kVisibleRect, kNaturalSize,
267                             NULL, 0, false);
268   InitializeWithConfigAndStatus(config, DECODER_ERROR_NOT_SUPPORTED);
269 }
270
271 TEST_F(FFmpegVideoDecoderTest, Initialize_AspectRatioNumeratorZero) {
272   gfx::Size natural_size = GetNaturalSize(kVisibleRect.size(), 0, 1);
273   VideoDecoderConfig config(kCodecVP8, VP8PROFILE_MAIN,
274                             kVideoFormat,
275                             kCodedSize, kVisibleRect, natural_size,
276                             NULL, 0, false);
277   InitializeWithConfigAndStatus(config, DECODER_ERROR_NOT_SUPPORTED);
278 }
279
280 TEST_F(FFmpegVideoDecoderTest, Initialize_AspectRatioDenominatorZero) {
281   gfx::Size natural_size = GetNaturalSize(kVisibleRect.size(), 1, 0);
282   VideoDecoderConfig config(kCodecVP8, VP8PROFILE_MAIN,
283                             kVideoFormat,
284                             kCodedSize, kVisibleRect, natural_size,
285                             NULL, 0, false);
286   InitializeWithConfigAndStatus(config, DECODER_ERROR_NOT_SUPPORTED);
287 }
288
289 TEST_F(FFmpegVideoDecoderTest, Initialize_AspectRatioNumeratorNegative) {
290   gfx::Size natural_size = GetNaturalSize(kVisibleRect.size(), -1, 1);
291   VideoDecoderConfig config(kCodecVP8, VP8PROFILE_MAIN,
292                             kVideoFormat,
293                             kCodedSize, kVisibleRect, natural_size,
294                             NULL, 0, false);
295   InitializeWithConfigAndStatus(config, DECODER_ERROR_NOT_SUPPORTED);
296 }
297
298 TEST_F(FFmpegVideoDecoderTest, Initialize_AspectRatioDenominatorNegative) {
299   gfx::Size natural_size = GetNaturalSize(kVisibleRect.size(), 1, -1);
300   VideoDecoderConfig config(kCodecVP8, VP8PROFILE_MAIN,
301                             kVideoFormat,
302                             kCodedSize, kVisibleRect, natural_size,
303                             NULL, 0, false);
304   InitializeWithConfigAndStatus(config, DECODER_ERROR_NOT_SUPPORTED);
305 }
306
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,
312                             kVideoFormat,
313                             kCodedSize, kVisibleRect, natural_size,
314                             NULL, 0, false);
315   InitializeWithConfigAndStatus(config, DECODER_ERROR_NOT_SUPPORTED);
316 }
317
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,
322                             kVideoFormat,
323                             kCodedSize, kVisibleRect, natural_size,
324                             NULL, 0, false);
325   InitializeWithConfigAndStatus(config, DECODER_ERROR_NOT_SUPPORTED);
326 }
327
328 TEST_F(FFmpegVideoDecoderTest, Reinitialize_Normal) {
329   Initialize();
330   Reinitialize();
331 }
332
333 TEST_F(FFmpegVideoDecoderTest, Reinitialize_Failure) {
334   Initialize();
335   InitializeWithConfigAndStatus(TestVideoConfig::Invalid(),
336                                 DECODER_ERROR_NOT_SUPPORTED);
337 }
338
339 TEST_F(FFmpegVideoDecoderTest, Reinitialize_AfterDecodeFrame) {
340   Initialize();
341   EnterDecodingState();
342   Reinitialize();
343 }
344
345 TEST_F(FFmpegVideoDecoderTest, Reinitialize_AfterReset) {
346   Initialize();
347   EnterDecodingState();
348   Reset();
349   Reinitialize();
350 }
351
352 TEST_F(FFmpegVideoDecoderTest, DecodeFrame_Normal) {
353   Initialize();
354
355   // Simulate decoding a single frame.
356   VideoDecoder::Status status;
357   scoped_refptr<VideoFrame> video_frame;
358   DecodeSingleFrame(i_frame_buffer_, &status, &video_frame);
359
360   EXPECT_EQ(VideoDecoder::kOk, status);
361   ASSERT_TRUE(video_frame.get());
362   EXPECT_FALSE(video_frame->IsEndOfStream());
363 }
364
365 // Verify current behavior for 0 byte frames. FFmpeg simply ignores
366 // the 0 byte frames.
367 TEST_F(FFmpegVideoDecoderTest, DecodeFrame_0ByteFrame) {
368   Initialize();
369
370   scoped_refptr<DecoderBuffer> zero_byte_buffer = new DecoderBuffer(0);
371
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_);
376
377   OutputFrames output_frames;
378   VideoDecoder::Status status =
379       DecodeMultipleFrames(input_buffers, &output_frames);
380
381   EXPECT_EQ(VideoDecoder::kOk, status);
382   ASSERT_EQ(2U, output_frames.size());
383
384   EXPECT_FALSE(output_frames[0]->IsEndOfStream());
385   EXPECT_FALSE(output_frames[1]->IsEndOfStream());
386 }
387
388 TEST_F(FFmpegVideoDecoderTest, DecodeFrame_DecodeError) {
389   Initialize();
390
391   VideoDecoder::Status status;
392   scoped_refptr<VideoFrame> frame;
393
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);
398   DCHECK(!frame);
399   DCHECK_EQ(VideoDecoder::kNotEnoughData, status);
400   Decode(i_frame_buffer_, &status, &frame);
401   DCHECK(!frame);
402   DCHECK_EQ(VideoDecoder::kDecodeError, status);
403
404   // After a decode error occurred, all following decodes will return
405   // kDecodeError.
406   Decode(i_frame_buffer_, &status, &frame);
407   DCHECK(!frame);
408   DCHECK_EQ(VideoDecoder::kDecodeError, status);
409 }
410
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) {
417   Initialize();
418
419   VideoDecoder::Status status;
420   scoped_refptr<VideoFrame> video_frame;
421   DecodeSingleFrame(corrupt_i_frame_buffer_, &status, &video_frame);
422
423   EXPECT_EQ(VideoDecoder::kOk, status);
424   ASSERT_TRUE(video_frame.get());
425   EXPECT_TRUE(video_frame->IsEndOfStream());
426 }
427
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);
432 }
433
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);
438 }
439
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);
444 }
445
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);
450 }
451
452 // Test resetting when decoder has initialized but not decoded.
453 TEST_F(FFmpegVideoDecoderTest, Reset_Initialized) {
454   Initialize();
455   Reset();
456 }
457
458 // Test resetting when decoder has decoded single frame.
459 TEST_F(FFmpegVideoDecoderTest, Reset_Decoding) {
460   Initialize();
461   EnterDecodingState();
462   Reset();
463 }
464
465 // Test resetting when decoder has hit end of stream.
466 TEST_F(FFmpegVideoDecoderTest, Reset_EndOfStream) {
467   Initialize();
468   EnterDecodingState();
469   EnterEndOfStreamState();
470   Reset();
471 }
472
473 // Test stopping when decoder has initialized but not decoded.
474 TEST_F(FFmpegVideoDecoderTest, Stop_Initialized) {
475   Initialize();
476   Stop();
477 }
478
479 // Test stopping when decoder has decoded single frame.
480 TEST_F(FFmpegVideoDecoderTest, Stop_Decoding) {
481   Initialize();
482   EnterDecodingState();
483   Stop();
484 }
485
486 // Test stopping when decoder has hit end of stream.
487 TEST_F(FFmpegVideoDecoderTest, Stop_EndOfStream) {
488   Initialize();
489   EnterDecodingState();
490   EnterEndOfStreamState();
491   Stop();
492 }
493
494 }  // namespace media