Home | History | Annotate | Download | only in filters
      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->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::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::CreateEOSFrame();
    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->end_of_stream());
    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]->end_of_stream());
    385   EXPECT_FALSE(output_frames[1]->end_of_stream());
    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->end_of_stream());
    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
    495