root/media/filters/fake_video_decoder_unittest.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. is_reset_pending_
  2. InitializeWithConfig
  3. Initialize
  4. EnterPendingInitState
  5. SatisfyInit
  6. FrameReady
  7. ExpectReadResult
  8. Decode
  9. ReadOneFrame
  10. ReadUntilEOS
  11. EnterPendingReadState
  12. SatisfyReadAndExpect
  13. SatisfyRead
  14. OnDecoderReset
  15. ExpectResetResult
  16. ResetAndExpect
  17. EnterPendingResetState
  18. SatisfyReset
  19. Stop
  20. TEST_F
  21. TEST_F
  22. TEST_F
  23. TEST_F
  24. TEST_F
  25. TEST_F
  26. TEST_F
  27. TEST_F
  28. TEST_F
  29. TEST_F
  30. TEST_F
  31. TEST_F
  32. TEST_F
  33. TEST_F
  34. TEST_F
  35. TEST_F
  36. TEST_F
  37. TEST_F

// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/basictypes.h"
#include "base/bind.h"
#include "base/message_loop/message_loop.h"
#include "media/base/decoder_buffer.h"
#include "media/base/mock_filters.h"
#include "media/base/test_helpers.h"
#include "media/base/video_frame.h"
#include "media/filters/fake_video_decoder.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace media {

static const int kDecodingDelay = 9;
static const int kTotalBuffers = 12;
static const int kDurationMs = 30;

class FakeVideoDecoderTest : public testing::Test {
 public:
  FakeVideoDecoderTest()
      : decoder_(new FakeVideoDecoder(kDecodingDelay, false)),
        num_input_buffers_(0),
        num_decoded_frames_(0),
        decode_status_(VideoDecoder::kNotEnoughData),
        is_decode_pending_(false),
        is_reset_pending_(false) {}

  virtual ~FakeVideoDecoderTest() {
    Stop();
  }

  void InitializeWithConfig(const VideoDecoderConfig& config) {
    decoder_->Initialize(config, NewExpectedStatusCB(PIPELINE_OK));
    message_loop_.RunUntilIdle();
    current_config_ = config;
  }

  void Initialize() {
    InitializeWithConfig(TestVideoConfig::Normal());
  }

  void EnterPendingInitState() {
    decoder_->HoldNextInit();
    Initialize();
  }

  void SatisfyInit() {
    decoder_->SatisfyInit();
    message_loop_.RunUntilIdle();
  }

  // Callback for VideoDecoder::Read().
  void FrameReady(VideoDecoder::Status status,
                  const scoped_refptr<VideoFrame>& frame) {
    DCHECK(is_decode_pending_);
    ASSERT_TRUE(status == VideoDecoder::kOk ||
                status == VideoDecoder::kNotEnoughData);
    is_decode_pending_ = false;
    decode_status_ = status;
    frame_decoded_ = frame;

    if (frame && !frame->end_of_stream())
      num_decoded_frames_++;
  }

  enum CallbackResult {
    PENDING,
    OK,
    NOT_ENOUGH_DATA,
    ABROTED,
    EOS
  };

  void ExpectReadResult(CallbackResult result) {
    switch (result) {
      case PENDING:
        EXPECT_TRUE(is_decode_pending_);
        ASSERT_FALSE(frame_decoded_);
        break;
      case OK:
        EXPECT_FALSE(is_decode_pending_);
        ASSERT_EQ(VideoDecoder::kOk, decode_status_);
        ASSERT_TRUE(frame_decoded_);
        EXPECT_FALSE(frame_decoded_->end_of_stream());
        break;
      case NOT_ENOUGH_DATA:
        EXPECT_FALSE(is_decode_pending_);
        ASSERT_EQ(VideoDecoder::kNotEnoughData, decode_status_);
        ASSERT_FALSE(frame_decoded_);
        break;
      case ABROTED:
        EXPECT_FALSE(is_decode_pending_);
        ASSERT_EQ(VideoDecoder::kOk, decode_status_);
        EXPECT_FALSE(frame_decoded_);
        break;
      case EOS:
        EXPECT_FALSE(is_decode_pending_);
        ASSERT_EQ(VideoDecoder::kOk, decode_status_);
        ASSERT_TRUE(frame_decoded_);
        EXPECT_TRUE(frame_decoded_->end_of_stream());
        break;
    }
  }

  void Decode() {
    scoped_refptr<DecoderBuffer> buffer;

    if (num_input_buffers_ < kTotalBuffers) {
      buffer = CreateFakeVideoBufferForTest(
          current_config_,
          base::TimeDelta::FromMilliseconds(kDurationMs * num_input_buffers_),
          base::TimeDelta::FromMilliseconds(kDurationMs));
      num_input_buffers_++;
    } else {
      buffer = DecoderBuffer::CreateEOSBuffer();
    }

    decode_status_ = VideoDecoder::kDecodeError;
    frame_decoded_ = NULL;
    is_decode_pending_ = true;

    decoder_->Decode(
        buffer,
        base::Bind(&FakeVideoDecoderTest::FrameReady, base::Unretained(this)));
    message_loop_.RunUntilIdle();
  }

  void ReadOneFrame() {
    do {
      Decode();
    } while (decode_status_ == VideoDecoder::kNotEnoughData &&
             !is_decode_pending_);
  }

  void ReadUntilEOS() {
    do {
      ReadOneFrame();
    } while (frame_decoded_ && !frame_decoded_->end_of_stream());
  }

  void EnterPendingReadState() {
    // Pass the initial NOT_ENOUGH_DATA stage.
    ReadOneFrame();
    decoder_->HoldNextDecode();
    ReadOneFrame();
    ExpectReadResult(PENDING);
  }

  void SatisfyReadAndExpect(CallbackResult result) {
    decoder_->SatisfyDecode();
    message_loop_.RunUntilIdle();
    ExpectReadResult(result);
  }

  void SatisfyRead() {
    SatisfyReadAndExpect(OK);
  }

  // Callback for VideoDecoder::Reset().
  void OnDecoderReset() {
    DCHECK(is_reset_pending_);
    is_reset_pending_ = false;
  }

  void ExpectResetResult(CallbackResult result) {
    switch (result) {
      case PENDING:
        EXPECT_TRUE(is_reset_pending_);
        break;
      case OK:
        EXPECT_FALSE(is_reset_pending_);
        break;
      default:
        NOTREACHED();
    }
  }

  void ResetAndExpect(CallbackResult result) {
    is_reset_pending_ = true;
    decoder_->Reset(base::Bind(&FakeVideoDecoderTest::OnDecoderReset,
                               base::Unretained(this)));
    message_loop_.RunUntilIdle();
    ExpectResetResult(result);
  }

  void EnterPendingResetState() {
    decoder_->HoldNextReset();
    ResetAndExpect(PENDING);
  }

  void SatisfyReset() {
    decoder_->SatisfyReset();
    message_loop_.RunUntilIdle();
    ExpectResetResult(OK);
  }

  void Stop() {
    decoder_->Stop();
    message_loop_.RunUntilIdle();

    // All pending callbacks must have been fired.
    DCHECK(!is_decode_pending_);
    DCHECK(!is_reset_pending_);
  }

  base::MessageLoop message_loop_;
  VideoDecoderConfig current_config_;

  scoped_ptr<FakeVideoDecoder> decoder_;

  int num_input_buffers_;
  int num_decoded_frames_;

  // Callback result/status.
  VideoDecoder::Status decode_status_;
  scoped_refptr<VideoFrame> frame_decoded_;
  bool is_decode_pending_;
  bool is_reset_pending_;

 private:
  DISALLOW_COPY_AND_ASSIGN(FakeVideoDecoderTest);
};

TEST_F(FakeVideoDecoderTest, Initialize) {
  Initialize();
}

TEST_F(FakeVideoDecoderTest, Read_AllFrames) {
  Initialize();
  ReadUntilEOS();
  EXPECT_EQ(kTotalBuffers, num_decoded_frames_);
}

TEST_F(FakeVideoDecoderTest, Read_DecodingDelay) {
  Initialize();

  while (num_input_buffers_ < kTotalBuffers) {
    ReadOneFrame();
    EXPECT_EQ(num_input_buffers_, num_decoded_frames_ + kDecodingDelay);
  }
}

TEST_F(FakeVideoDecoderTest, Read_ZeroDelay) {
  decoder_.reset(new FakeVideoDecoder(0, false));
  Initialize();

  while (num_input_buffers_ < kTotalBuffers) {
    ReadOneFrame();
    EXPECT_EQ(num_input_buffers_, num_decoded_frames_);
  }
}

TEST_F(FakeVideoDecoderTest, Read_Pending_NotEnoughData) {
  Initialize();
  decoder_->HoldNextDecode();
  ReadOneFrame();
  ExpectReadResult(PENDING);
  SatisfyReadAndExpect(NOT_ENOUGH_DATA);
}

TEST_F(FakeVideoDecoderTest, Read_Pending_OK) {
  Initialize();
  ReadOneFrame();
  EnterPendingReadState();
  SatisfyReadAndExpect(OK);
}

TEST_F(FakeVideoDecoderTest, Reinitialize) {
  Initialize();
  ReadOneFrame();
  InitializeWithConfig(TestVideoConfig::Large());
  ReadOneFrame();
}

// Reinitializing the decoder during the middle of the decoding process can
// cause dropped frames.
TEST_F(FakeVideoDecoderTest, Reinitialize_FrameDropped) {
  Initialize();
  ReadOneFrame();
  Initialize();
  ReadUntilEOS();
  EXPECT_LT(num_decoded_frames_, kTotalBuffers);
}

TEST_F(FakeVideoDecoderTest, Reset) {
  Initialize();
  ReadOneFrame();
  ResetAndExpect(OK);
}

TEST_F(FakeVideoDecoderTest, Reset_DuringPendingRead) {
  Initialize();
  EnterPendingReadState();
  ResetAndExpect(PENDING);
  SatisfyRead();
}

TEST_F(FakeVideoDecoderTest, Reset_Pending) {
  Initialize();
  EnterPendingResetState();
  SatisfyReset();
}

TEST_F(FakeVideoDecoderTest, Reset_PendingDuringPendingRead) {
  Initialize();
  EnterPendingReadState();
  EnterPendingResetState();
  SatisfyRead();
  SatisfyReset();
}

TEST_F(FakeVideoDecoderTest, Stop) {
  Initialize();
  ReadOneFrame();
  ExpectReadResult(OK);
  Stop();
}

TEST_F(FakeVideoDecoderTest, Stop_DuringPendingInitialization) {
  EnterPendingInitState();
  Stop();
}

TEST_F(FakeVideoDecoderTest, Stop_DuringPendingRead) {
  Initialize();
  EnterPendingReadState();
  Stop();
}

TEST_F(FakeVideoDecoderTest, Stop_DuringPendingReset) {
  Initialize();
  EnterPendingResetState();
  Stop();
}

TEST_F(FakeVideoDecoderTest, Stop_DuringPendingReadAndPendingReset) {
  Initialize();
  EnterPendingReadState();
  EnterPendingResetState();
  Stop();
}

TEST_F(FakeVideoDecoderTest, GetDecodeOutput) {
  decoder_.reset(new FakeVideoDecoder(kDecodingDelay, true));
  Initialize();

  while (num_input_buffers_ < kTotalBuffers) {
    ReadOneFrame();
    while (decoder_->GetDecodeOutput())
      ++num_decoded_frames_;
    EXPECT_EQ(num_input_buffers_, num_decoded_frames_);
  }
}

}  // namespace media

/* [<][>][^][v][top][bottom][index][help] */