Upstream version 7.36.149.0
[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, false, 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();
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->end_of_stream());
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->end_of_stream());
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->end_of_stream()) {
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::kAborted:
153           NOTREACHED();
154         case VideoDecoder::kDecodeError:
155         case VideoDecoder::kDecryptError:
156           DCHECK(!frame);
157           return status;
158       }
159     }
160   }
161
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);
171
172     OutputFrames output_frames;
173     *status = DecodeMultipleFrames(input_buffers, &output_frames);
174
175     if (*status != VideoDecoder::kOk)
176       return;
177
178     ASSERT_LE(output_frames.size(), 1U);
179     if (output_frames.size() == 1U)
180       *video_frame = output_frames[0];
181     else
182       *video_frame = VideoFrame::CreateEOSFrame();
183   }
184
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,
189                                 int expected_width,
190                                 int expected_height) {
191     Initialize();
192     scoped_refptr<DecoderBuffer> buffer = ReadTestDataFile(test_file_name);
193
194     InputBuffers input_buffers;
195     input_buffers.push_back(i_frame_buffer_);
196     input_buffers.push_back(buffer);
197
198     OutputFrames output_frames;
199     VideoDecoder::Status status =
200         DecodeMultipleFrames(input_buffers, &output_frames);
201
202     EXPECT_EQ(VideoDecoder::kOk, status);
203     ASSERT_EQ(2U, output_frames.size());
204
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());
214   }
215
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)));
221
222     decoder_->Decode(buffer, decode_cb_);
223
224     message_loop_.RunUntilIdle();
225   }
226
227   MOCK_METHOD2(FrameReady, void(VideoDecoder::Status,
228                                 const scoped_refptr<VideoFrame>&));
229
230   base::MessageLoop message_loop_;
231   scoped_ptr<FFmpegVideoDecoder> decoder_;
232
233   VideoDecoder::DecodeCB decode_cb_;
234
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_;
240
241  private:
242   DISALLOW_COPY_AND_ASSIGN(FFmpegVideoDecoderTest);
243 };
244
245 TEST_F(FFmpegVideoDecoderTest, Initialize_Normal) {
246   Initialize();
247 }
248
249 TEST_F(FFmpegVideoDecoderTest, Initialize_UnsupportedDecoder) {
250   // Test avcodec_find_decoder() returning NULL.
251   InitializeWithConfigAndStatus(TestVideoConfig::Invalid(),
252                                 DECODER_ERROR_NOT_SUPPORTED);
253 }
254
255 TEST_F(FFmpegVideoDecoderTest, Initialize_UnsupportedPixelFormat) {
256   // Ensure decoder handles unsupported pixel formats without crashing.
257   VideoDecoderConfig config(kCodecVP8, VIDEO_CODEC_PROFILE_UNKNOWN,
258                             VideoFrame::UNKNOWN,
259                             kCodedSize, kVisibleRect, kNaturalSize,
260                             NULL, 0, false);
261   InitializeWithConfigAndStatus(config, DECODER_ERROR_NOT_SUPPORTED);
262 }
263
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,
267                             kVideoFormat,
268                             kCodedSize, kVisibleRect, kNaturalSize,
269                             NULL, 0, false);
270   InitializeWithConfigAndStatus(config, DECODER_ERROR_NOT_SUPPORTED);
271 }
272
273 TEST_F(FFmpegVideoDecoderTest, Initialize_AspectRatioNumeratorZero) {
274   gfx::Size natural_size = GetNaturalSize(kVisibleRect.size(), 0, 1);
275   VideoDecoderConfig config(kCodecVP8, VP8PROFILE_MAIN,
276                             kVideoFormat,
277                             kCodedSize, kVisibleRect, natural_size,
278                             NULL, 0, false);
279   InitializeWithConfigAndStatus(config, DECODER_ERROR_NOT_SUPPORTED);
280 }
281
282 TEST_F(FFmpegVideoDecoderTest, Initialize_AspectRatioDenominatorZero) {
283   gfx::Size natural_size = GetNaturalSize(kVisibleRect.size(), 1, 0);
284   VideoDecoderConfig config(kCodecVP8, VP8PROFILE_MAIN,
285                             kVideoFormat,
286                             kCodedSize, kVisibleRect, natural_size,
287                             NULL, 0, false);
288   InitializeWithConfigAndStatus(config, DECODER_ERROR_NOT_SUPPORTED);
289 }
290
291 TEST_F(FFmpegVideoDecoderTest, Initialize_AspectRatioNumeratorNegative) {
292   gfx::Size natural_size = GetNaturalSize(kVisibleRect.size(), -1, 1);
293   VideoDecoderConfig config(kCodecVP8, VP8PROFILE_MAIN,
294                             kVideoFormat,
295                             kCodedSize, kVisibleRect, natural_size,
296                             NULL, 0, false);
297   InitializeWithConfigAndStatus(config, DECODER_ERROR_NOT_SUPPORTED);
298 }
299
300 TEST_F(FFmpegVideoDecoderTest, Initialize_AspectRatioDenominatorNegative) {
301   gfx::Size natural_size = GetNaturalSize(kVisibleRect.size(), 1, -1);
302   VideoDecoderConfig config(kCodecVP8, VP8PROFILE_MAIN,
303                             kVideoFormat,
304                             kCodedSize, kVisibleRect, natural_size,
305                             NULL, 0, false);
306   InitializeWithConfigAndStatus(config, DECODER_ERROR_NOT_SUPPORTED);
307 }
308
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,
314                             kVideoFormat,
315                             kCodedSize, kVisibleRect, natural_size,
316                             NULL, 0, false);
317   InitializeWithConfigAndStatus(config, DECODER_ERROR_NOT_SUPPORTED);
318 }
319
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,
324                             kVideoFormat,
325                             kCodedSize, kVisibleRect, natural_size,
326                             NULL, 0, false);
327   InitializeWithConfigAndStatus(config, DECODER_ERROR_NOT_SUPPORTED);
328 }
329
330 TEST_F(FFmpegVideoDecoderTest, Reinitialize_Normal) {
331   Initialize();
332   Reinitialize();
333 }
334
335 TEST_F(FFmpegVideoDecoderTest, Reinitialize_Failure) {
336   Initialize();
337   InitializeWithConfigAndStatus(TestVideoConfig::Invalid(),
338                                 DECODER_ERROR_NOT_SUPPORTED);
339 }
340
341 TEST_F(FFmpegVideoDecoderTest, Reinitialize_AfterDecodeFrame) {
342   Initialize();
343   EnterDecodingState();
344   Reinitialize();
345 }
346
347 TEST_F(FFmpegVideoDecoderTest, Reinitialize_AfterReset) {
348   Initialize();
349   EnterDecodingState();
350   Reset();
351   Reinitialize();
352 }
353
354 TEST_F(FFmpegVideoDecoderTest, DecodeFrame_Normal) {
355   Initialize();
356
357   // Simulate decoding a single frame.
358   VideoDecoder::Status status;
359   scoped_refptr<VideoFrame> video_frame;
360   DecodeSingleFrame(i_frame_buffer_, &status, &video_frame);
361
362   EXPECT_EQ(VideoDecoder::kOk, status);
363   ASSERT_TRUE(video_frame.get());
364   EXPECT_FALSE(video_frame->end_of_stream());
365 }
366
367 // Verify current behavior for 0 byte frames. FFmpeg simply ignores
368 // the 0 byte frames.
369 TEST_F(FFmpegVideoDecoderTest, DecodeFrame_0ByteFrame) {
370   Initialize();
371
372   scoped_refptr<DecoderBuffer> zero_byte_buffer = new DecoderBuffer(0);
373
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_);
378
379   OutputFrames output_frames;
380   VideoDecoder::Status status =
381       DecodeMultipleFrames(input_buffers, &output_frames);
382
383   EXPECT_EQ(VideoDecoder::kOk, status);
384   ASSERT_EQ(2U, output_frames.size());
385
386   EXPECT_FALSE(output_frames[0]->end_of_stream());
387   EXPECT_FALSE(output_frames[1]->end_of_stream());
388 }
389
390 TEST_F(FFmpegVideoDecoderTest, DecodeFrame_DecodeError) {
391   Initialize();
392
393   VideoDecoder::Status status;
394   scoped_refptr<VideoFrame> frame;
395
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);
400   DCHECK(!frame);
401   DCHECK_EQ(VideoDecoder::kNotEnoughData, status);
402   Decode(i_frame_buffer_, &status, &frame);
403   DCHECK(!frame);
404   DCHECK_EQ(VideoDecoder::kDecodeError, status);
405
406   // After a decode error occurred, all following decodes will return
407   // kDecodeError.
408   Decode(i_frame_buffer_, &status, &frame);
409   DCHECK(!frame);
410   DCHECK_EQ(VideoDecoder::kDecodeError, status);
411 }
412
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) {
419   Initialize();
420
421   VideoDecoder::Status status;
422   scoped_refptr<VideoFrame> video_frame;
423   DecodeSingleFrame(corrupt_i_frame_buffer_, &status, &video_frame);
424
425   EXPECT_EQ(VideoDecoder::kOk, status);
426   ASSERT_TRUE(video_frame.get());
427   EXPECT_TRUE(video_frame->end_of_stream());
428 }
429
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);
434 }
435
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);
440 }
441
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);
446 }
447
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);
452 }
453
454 // Test resetting when decoder has initialized but not decoded.
455 TEST_F(FFmpegVideoDecoderTest, Reset_Initialized) {
456   Initialize();
457   Reset();
458 }
459
460 // Test resetting when decoder has decoded single frame.
461 TEST_F(FFmpegVideoDecoderTest, Reset_Decoding) {
462   Initialize();
463   EnterDecodingState();
464   Reset();
465 }
466
467 // Test resetting when decoder has hit end of stream.
468 TEST_F(FFmpegVideoDecoderTest, Reset_EndOfStream) {
469   Initialize();
470   EnterDecodingState();
471   EnterEndOfStreamState();
472   Reset();
473 }
474
475 // Test stopping when decoder has initialized but not decoded.
476 TEST_F(FFmpegVideoDecoderTest, Stop_Initialized) {
477   Initialize();
478   Stop();
479 }
480
481 // Test stopping when decoder has decoded single frame.
482 TEST_F(FFmpegVideoDecoderTest, Stop_Decoding) {
483   Initialize();
484   EnterDecodingState();
485   Stop();
486 }
487
488 // Test stopping when decoder has hit end of stream.
489 TEST_F(FFmpegVideoDecoderTest, Stop_EndOfStream) {
490   Initialize();
491   EnterDecodingState();
492   EnterEndOfStreamState();
493   Stop();
494 }
495
496 }  // namespace media