Index: media/filters/fake_video_decoder_unittest.cc |
diff --git a/media/filters/fake_video_decoder_unittest.cc b/media/filters/fake_video_decoder_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..91a6c77c9a0be76fed866266ae4675663d2eee6a |
--- /dev/null |
+++ b/media/filters/fake_video_decoder_unittest.cc |
@@ -0,0 +1,434 @@ |
+// Copyright (c) 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.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_demuxer_stream.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 kNumConfigs = 3; |
+static const int kNumBuffersInOneConfig = 9; |
+static const int kNumInputBuffers = kNumConfigs * kNumBuffersInOneConfig; |
+ |
+class FakeVideoDecoderTest : public testing::Test { |
+ public: |
+ FakeVideoDecoderTest() |
+ : decoder_(new FakeVideoDecoder(kDecodingDelay)), |
+ demuxer_stream_( |
+ new FakeDemuxerStream(kNumConfigs, kNumBuffersInOneConfig, false)), |
+ num_decoded_frames_(0), |
+ is_read_pending_(false), |
+ is_reset_pending_(false), |
+ is_stop_pending_(false) {} |
+ |
+ virtual ~FakeVideoDecoderTest() { |
+ StopAndExpect(OK); |
+ } |
+ |
+ void Initialize() { |
+ decoder_->Initialize(demuxer_stream_.get(), |
+ NewExpectedStatusCB(PIPELINE_OK), |
+ base::Bind(&MockStatisticsCB::OnStatistics, |
+ base::Unretained(&statistics_cb_))); |
+ message_loop_.RunUntilIdle(); |
+ } |
+ |
+ // Callback for VideoDecoder::Read(). |
+ void FrameReady(VideoDecoder::Status status, |
+ const scoped_refptr<VideoFrame>& frame) { |
+ DCHECK(is_read_pending_); |
+ ASSERT_EQ(VideoDecoder::kOk, status); |
+ |
+ is_read_pending_ = false; |
+ frame_read_ = frame; |
+ |
+ if (frame && !frame->IsEndOfStream()) |
+ num_decoded_frames_++; |
+ } |
+ |
+ enum CallbackResult { |
+ PENDING, |
+ OK, |
+ ABROTED, |
+ EOS |
+ }; |
+ |
+ void ExpectReadResult(CallbackResult result) { |
+ switch (result) { |
+ case PENDING: |
+ EXPECT_TRUE(is_read_pending_); |
+ ASSERT_FALSE(frame_read_); |
+ break; |
+ case OK: |
+ EXPECT_FALSE(is_read_pending_); |
+ ASSERT_TRUE(frame_read_); |
+ EXPECT_FALSE(frame_read_->IsEndOfStream()); |
+ break; |
+ case ABROTED: |
+ EXPECT_FALSE(is_read_pending_); |
+ EXPECT_FALSE(frame_read_); |
+ break; |
+ case EOS: |
+ EXPECT_FALSE(is_read_pending_); |
+ ASSERT_TRUE(frame_read_); |
+ EXPECT_TRUE(frame_read_->IsEndOfStream()); |
+ break; |
+ } |
+ } |
+ |
+ void ReadOneFrame() { |
+ frame_read_ = NULL; |
+ is_read_pending_ = true; |
+ decoder_->Read( |
+ base::Bind(&FakeVideoDecoderTest::FrameReady, base::Unretained(this))); |
+ message_loop_.RunUntilIdle(); |
+ } |
+ |
+ void ReadUntilEOS() { |
+ do { |
+ ReadOneFrame(); |
+ } while (frame_read_ && !frame_read_->IsEndOfStream()); |
+ } |
+ |
+ void EnterPendingReadState() { |
+ decoder_->HoldNextRead(); |
+ ReadOneFrame(); |
+ ExpectReadResult(PENDING); |
+ } |
+ |
+ void SatisfyRead() { |
+ decoder_->SatisfyRead(); |
+ message_loop_.RunUntilIdle(); |
+ ExpectReadResult(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); |
+ } |
+ |
+ // Callback for VideoDecoder::Stop(). |
+ void OnDecoderStopped() { |
+ DCHECK(is_stop_pending_); |
+ is_stop_pending_ = false; |
+ } |
+ |
+ void ExpectStopResult(CallbackResult result) { |
+ switch (result) { |
+ case PENDING: |
+ EXPECT_TRUE(is_stop_pending_); |
+ break; |
+ case OK: |
+ EXPECT_FALSE(is_stop_pending_); |
+ break; |
+ default: |
+ NOTREACHED(); |
+ } |
+ } |
+ |
+ void StopAndExpect(CallbackResult result) { |
+ is_stop_pending_ = true; |
+ decoder_->Stop(base::Bind(&FakeVideoDecoderTest::OnDecoderStopped, |
+ base::Unretained(this))); |
+ message_loop_.RunUntilIdle(); |
+ ExpectStopResult(result); |
+ } |
+ |
+ void EnterPendingStopState() { |
+ decoder_->HoldNextStop(); |
+ StopAndExpect(PENDING); |
+ } |
+ |
+ void SatisfyStop() { |
+ decoder_->SatisfyStop(); |
+ message_loop_.RunUntilIdle(); |
+ ExpectStopResult(OK); |
+ } |
+ |
+ // Callback for DemuxerStream::Read so that we can skip frames to trigger a |
+ // config change. |
+ void BufferReady(bool* config_changed, |
+ DemuxerStream::Status status, |
+ const scoped_refptr<DecoderBuffer>& buffer) { |
+ if (status == DemuxerStream::kConfigChanged) |
+ *config_changed = true; |
+ } |
+ |
+ void ChangeConfig() { |
+ bool config_changed = false; |
+ while (!config_changed) { |
+ demuxer_stream_->Read(base::Bind(&FakeVideoDecoderTest::BufferReady, |
+ base::Unretained(this), |
+ &config_changed)); |
+ message_loop_.RunUntilIdle(); |
+ } |
+ } |
+ |
+ void EnterPendingDemuxerReadState() { |
+ demuxer_stream_->HoldNextRead(); |
+ ReadOneFrame(); |
+ } |
+ |
+ void SatisfyDemuxerRead() { |
+ demuxer_stream_->SatisfyRead(); |
+ message_loop_.RunUntilIdle(); |
+ } |
+ |
+ void AbortDemuxerRead() { |
+ demuxer_stream_->Reset(); |
+ message_loop_.RunUntilIdle(); |
+ } |
+ |
+ base::MessageLoop message_loop_; |
+ scoped_ptr<FakeVideoDecoder> decoder_; |
+ scoped_ptr<FakeDemuxerStream> demuxer_stream_; |
+ MockStatisticsCB statistics_cb_; |
+ int num_decoded_frames_; |
+ |
+ // Callback result/status. |
+ scoped_refptr<VideoFrame> frame_read_; |
+ bool is_read_pending_; |
+ bool is_reset_pending_; |
+ bool is_stop_pending_; |
+ |
+ private: |
+ DISALLOW_COPY_AND_ASSIGN(FakeVideoDecoderTest); |
+}; |
+ |
+TEST_F(FakeVideoDecoderTest, Initialize) { |
+ Initialize(); |
+} |
+ |
+TEST_F(FakeVideoDecoderTest, Read_AllFrames) { |
+ Initialize(); |
+ ReadUntilEOS(); |
+ EXPECT_EQ(kNumInputBuffers, num_decoded_frames_); |
+} |
+ |
+TEST_F(FakeVideoDecoderTest, Read_AbortedDemuxerRead) { |
+ Initialize(); |
+ demuxer_stream_->HoldNextRead(); |
+ ReadOneFrame(); |
+ AbortDemuxerRead(); |
+ ExpectReadResult(ABROTED); |
+} |
+ |
+TEST_F(FakeVideoDecoderTest, Read_DecodingDelay) { |
+ Initialize(); |
+ |
+ while (demuxer_stream_->num_buffers_returned() < kNumInputBuffers) { |
+ ReadOneFrame(); |
+ EXPECT_EQ(demuxer_stream_->num_buffers_returned(), |
+ num_decoded_frames_ + kDecodingDelay); |
+ } |
+} |
+ |
+TEST_F(FakeVideoDecoderTest, Read_ZeroDelay) { |
+ decoder_.reset(new FakeVideoDecoder(0)); |
+ Initialize(); |
+ |
+ while (demuxer_stream_->num_buffers_returned() < kNumInputBuffers) { |
+ ReadOneFrame(); |
+ EXPECT_EQ(demuxer_stream_->num_buffers_returned(), num_decoded_frames_); |
+ } |
+} |
+ |
+TEST_F(FakeVideoDecoderTest, Read_Pending) { |
+ Initialize(); |
+ EnterPendingReadState(); |
+ SatisfyRead(); |
+} |
+ |
+TEST_F(FakeVideoDecoderTest, Reinitialize) { |
+ Initialize(); |
+ VideoDecoderConfig old_config = demuxer_stream_->video_decoder_config(); |
+ ChangeConfig(); |
+ VideoDecoderConfig new_config = demuxer_stream_->video_decoder_config(); |
+ EXPECT_FALSE(new_config.Matches(old_config)); |
+ Initialize(); |
+} |
+ |
+// 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_, kNumInputBuffers); |
+} |
+ |
+TEST_F(FakeVideoDecoderTest, Reset) { |
+ Initialize(); |
+ ReadOneFrame(); |
+ ResetAndExpect(OK); |
+} |
+ |
+TEST_F(FakeVideoDecoderTest, Reset_DuringPendingDemuxerRead) { |
+ Initialize(); |
+ EnterPendingDemuxerReadState(); |
+ ResetAndExpect(PENDING); |
+ SatisfyDemuxerRead(); |
+ ExpectReadResult(ABROTED); |
+} |
+ |
+TEST_F(FakeVideoDecoderTest, Reset_DuringPendingDemuxerRead_Aborted) { |
+ Initialize(); |
+ EnterPendingDemuxerReadState(); |
+ ResetAndExpect(PENDING); |
+ AbortDemuxerRead(); |
+ ExpectReadResult(ABROTED); |
+} |
+ |
+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); |
+ StopAndExpect(OK); |
+} |
+ |
+TEST_F(FakeVideoDecoderTest, Stop_DuringPendingDemuxerRead) { |
+ Initialize(); |
+ EnterPendingDemuxerReadState(); |
+ StopAndExpect(PENDING); |
+ SatisfyDemuxerRead(); |
+ ExpectReadResult(ABROTED); |
+} |
+ |
+TEST_F(FakeVideoDecoderTest, Stop_DuringPendingDemuxerRead_Aborted) { |
+ Initialize(); |
+ EnterPendingDemuxerReadState(); |
+ ResetAndExpect(PENDING); |
+ StopAndExpect(PENDING); |
+ SatisfyDemuxerRead(); |
+ ExpectReadResult(ABROTED); |
+ ExpectResetResult(OK); |
+ ExpectStopResult(OK); |
+} |
+ |
+TEST_F(FakeVideoDecoderTest, Stop_DuringPendingRead) { |
+ Initialize(); |
+ EnterPendingReadState(); |
+ StopAndExpect(PENDING); |
+ SatisfyRead(); |
+ ExpectStopResult(OK); |
+} |
+ |
+TEST_F(FakeVideoDecoderTest, Stop_DuringPendingReset) { |
+ Initialize(); |
+ EnterPendingResetState(); |
+ StopAndExpect(PENDING); |
+ SatisfyReset(); |
+ ExpectStopResult(OK); |
+} |
+ |
+TEST_F(FakeVideoDecoderTest, Stop_DuringPendingReadAndPendingReset) { |
+ Initialize(); |
+ EnterPendingReadState(); |
+ EnterPendingResetState(); |
+ StopAndExpect(PENDING); |
+ SatisfyRead(); |
+ SatisfyReset(); |
+ ExpectStopResult(OK); |
+} |
+ |
+TEST_F(FakeVideoDecoderTest, Stop_Pending) { |
+ Initialize(); |
+ decoder_->HoldNextStop(); |
+ StopAndExpect(PENDING); |
+ decoder_->SatisfyStop(); |
+ message_loop_.RunUntilIdle(); |
+ ExpectStopResult(OK); |
+} |
+ |
+TEST_F(FakeVideoDecoderTest, Stop_PendingDuringPendingRead) { |
+ Initialize(); |
+ EnterPendingReadState(); |
+ EnterPendingStopState(); |
+ SatisfyRead(); |
+ SatisfyStop(); |
+} |
+ |
+TEST_F(FakeVideoDecoderTest, Stop_PendingDuringPendingReset) { |
+ Initialize(); |
+ EnterPendingResetState(); |
+ EnterPendingStopState(); |
+ SatisfyReset(); |
+ SatisfyStop(); |
+} |
+ |
+TEST_F(FakeVideoDecoderTest, Stop_PendingDuringPendingReadAndPendingReset) { |
+ Initialize(); |
+ EnterPendingReadState(); |
+ EnterPendingResetState(); |
+ EnterPendingStopState(); |
+ SatisfyRead(); |
+ SatisfyReset(); |
+ SatisfyStop(); |
+} |
+ |
+} // namespace media |