| Index: media/filters/video_frame_stream_unittest.cc
|
| diff --git a/media/filters/video_frame_stream_unittest.cc b/media/filters/video_frame_stream_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..134becb12fc6d2cd143432f9165d41fda9d9946a
|
| --- /dev/null
|
| +++ b/media/filters/video_frame_stream_unittest.cc
|
| @@ -0,0 +1,332 @@
|
| +// Copyright (c) 2012 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/bind.h"
|
| +#include "base/callback_helpers.h"
|
| +#include "base/message_loop.h"
|
| +#include "media/base/gmock_callback_support.h"
|
| +#include "media/base/mock_filters.h"
|
| +#include "media/base/test_helpers.h"
|
| +#include "media/filters/video_frame_stream.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +
|
| +using ::testing::_;
|
| +using ::testing::Assign;
|
| +using ::testing::AtMost;
|
| +using ::testing::NiceMock;
|
| +using ::testing::NotNull;
|
| +using ::testing::Return;
|
| +using ::testing::ReturnRef;
|
| +using ::testing::SaveArg;
|
| +using ::testing::StrictMock;
|
| +
|
| +namespace media {
|
| +
|
| +static const VideoFrame::Format kVideoFormat = VideoFrame::YV12;
|
| +static const gfx::Size kCodedSize(320, 240);
|
| +static const gfx::Rect kVisibleRect(320, 240);
|
| +static const gfx::Size kNaturalSize(320, 240);
|
| +
|
| +class VideoFrameStreamTest : public testing::TestWithParam<bool> {
|
| + public:
|
| + VideoFrameStreamTest()
|
| + : video_frame_stream_(
|
| + message_loop_.message_loop_proxy(),
|
| + base::Bind(&VideoFrameStreamTest::SetDecryptorReadyCallback,
|
| + base::Unretained(this))),
|
| + video_config_(kCodecVP8, VIDEO_CODEC_PROFILE_UNKNOWN, kVideoFormat,
|
| + kCodedSize, kVisibleRect, kNaturalSize, NULL, 0,
|
| + GetParam()),
|
| + demuxer_stream_(new StrictMock<MockDemuxerStream>()),
|
| + decryptor_(new NiceMock<MockDecryptor>()),
|
| + decoder_(new StrictMock<MockVideoDecoder>()),
|
| + is_initialized_(false) {
|
| + decoders_.push_back(decoder_);
|
| +
|
| + EXPECT_CALL(*demuxer_stream_, type())
|
| + .WillRepeatedly(Return(DemuxerStream::VIDEO));
|
| + EXPECT_CALL(*demuxer_stream_, video_decoder_config())
|
| + .WillRepeatedly(ReturnRef(video_config_));
|
| +
|
| + EXPECT_CALL(*this, SetDecryptorReadyCallback(_))
|
| + .WillRepeatedly(RunCallback<0>(decryptor_.get()));
|
| +
|
| + // Decryptor can only decrypt (not decrypt-and-decode) so that
|
| + // DecryptingDemuxerStream will be used.
|
| + EXPECT_CALL(*decryptor_, InitializeVideoDecoder(_, _))
|
| + .WillRepeatedly(RunCallback<1>(false));
|
| + EXPECT_CALL(*decryptor_, Decrypt(_, _, _))
|
| + .WillRepeatedly(RunCallback<2>(Decryptor::kSuccess,
|
| + scoped_refptr<DecoderBuffer>()));
|
| + }
|
| +
|
| + ~VideoFrameStreamTest() {
|
| + if (is_initialized_)
|
| + Stop();
|
| +
|
| + EXPECT_FALSE(is_initialized_);
|
| + EXPECT_TRUE(decoder_init_cb_.is_null());
|
| + EXPECT_TRUE(decoder_read_cb_.is_null());
|
| + EXPECT_TRUE(decoder_reset_cb_.is_null());
|
| + EXPECT_TRUE(decoder_stop_cb_.is_null());
|
| + }
|
| +
|
| + MOCK_METHOD1(OnStatistics, void(const PipelineStatistics&));
|
| + MOCK_METHOD1(SetDecryptorReadyCallback, void(const media::DecryptorReadyCB&));
|
| + MOCK_METHOD2(OnInitialized, void(bool, bool));
|
| + MOCK_METHOD2(OnFrameRead, void(VideoDecoder::Status,
|
| + const scoped_refptr<VideoFrame>&));
|
| + MOCK_METHOD0(OnReset, void());
|
| + MOCK_METHOD0(OnStopped, void());
|
| +
|
| + void EnterPendingInitializationState() {
|
| + EXPECT_CALL(*decoder_, Initialize(_, _, _))
|
| + .WillOnce(SaveArg<1>(&decoder_init_cb_));
|
| + video_frame_stream_.Initialize(
|
| + demuxer_stream_,
|
| + decoders_,
|
| + base::Bind(&VideoFrameStreamTest::OnStatistics, base::Unretained(this)),
|
| + base::Bind(&VideoFrameStreamTest::OnInitialized,
|
| + base::Unretained(this)));
|
| + message_loop_.RunUntilIdle();
|
| + }
|
| +
|
| + void SatisfyPendingInitialization(bool success) {
|
| + EXPECT_CALL(*this, OnInitialized(success, false))
|
| + .WillOnce(SaveArg<0>(&is_initialized_));
|
| + base::ResetAndReturn(&decoder_init_cb_).Run(
|
| + success ? PIPELINE_OK : DECODER_ERROR_NOT_SUPPORTED);
|
| + message_loop_.RunUntilIdle();
|
| + }
|
| +
|
| + void EnterPendingReadFrameState() {
|
| + EXPECT_CALL(*decoder_, Read(_))
|
| + .WillOnce(SaveArg<0>(&decoder_read_cb_));
|
| + EXPECT_CALL(*this, OnFrameRead(VideoDecoder::kOk, _));
|
| + video_frame_stream_.ReadFrame(base::Bind(&VideoFrameStreamTest::OnFrameRead,
|
| + base::Unretained(this)));
|
| + message_loop_.RunUntilIdle();
|
| + }
|
| +
|
| + void SatisfyPendingReadFrame() {
|
| + base::ResetAndReturn(&decoder_read_cb_).Run(VideoDecoder::kOk,
|
| + scoped_refptr<VideoFrame>());
|
| + message_loop_.RunUntilIdle();
|
| + }
|
| +
|
| + void EnterPendingResetState() {
|
| + EXPECT_CALL(*decoder_, Reset(_))
|
| + .WillOnce(SaveArg<0>(&decoder_reset_cb_));
|
| + EXPECT_CALL(*this, OnReset());
|
| + video_frame_stream_.Reset(base::Bind(&VideoFrameStreamTest::OnReset,
|
| + base::Unretained(this)));
|
| + message_loop_.RunUntilIdle();
|
| + }
|
| +
|
| + void SatisfyPendingReset() {
|
| + base::ResetAndReturn(&decoder_reset_cb_).Run();
|
| + message_loop_.RunUntilIdle();
|
| + }
|
| +
|
| + void EnterPendingStopState() {
|
| + // If initialization failed, we won't call VideoDecoder::Stop() during
|
| + // the stopping process.
|
| + EXPECT_CALL(*decoder_, Stop(_))
|
| + .Times(AtMost(1))
|
| + .WillRepeatedly(SaveArg<0>(&decoder_stop_cb_));
|
| + EXPECT_CALL(*this, OnStopped())
|
| + .WillOnce(Assign(&is_initialized_, false));
|
| + video_frame_stream_.Stop(base::Bind(&VideoFrameStreamTest::OnStopped,
|
| + base::Unretained(this)));
|
| + message_loop_.RunUntilIdle();
|
| + }
|
| +
|
| + void SatisfyPendingStop() {
|
| + // If decoder is not initialized, |decoder_stop_cb_| can be null. In that
|
| + // case, we don't actually need to satisfy the stop callback.
|
| + if (decoder_stop_cb_.is_null())
|
| + return;
|
| + base::ResetAndReturn(&decoder_stop_cb_).Run();
|
| + message_loop_.RunUntilIdle();
|
| + }
|
| +
|
| + void Initialize() {
|
| + EnterPendingInitializationState();
|
| + SatisfyPendingInitialization(true);
|
| + }
|
| +
|
| + void InitializeAndFail() {
|
| + EnterPendingInitializationState();
|
| + SatisfyPendingInitialization(false);
|
| + }
|
| +
|
| + void ReadFrame() {
|
| + EnterPendingReadFrameState();
|
| + SatisfyPendingReadFrame();
|
| + }
|
| +
|
| + void Reset() {
|
| + EnterPendingResetState();
|
| + SatisfyPendingReset();
|
| + }
|
| +
|
| + void Stop() {
|
| + EnterPendingStopState();
|
| + SatisfyPendingStop();
|
| + }
|
| +
|
| + private:
|
| + MessageLoop message_loop_;
|
| +
|
| + VideoFrameStream video_frame_stream_;
|
| + VideoDecoderConfig video_config_;
|
| + scoped_refptr<StrictMock<MockDemuxerStream> > demuxer_stream_;
|
| + // Use NiceMock since we don't care about most of calls on the decryptor, e.g.
|
| + // RegisterNewKeyCB().
|
| + scoped_ptr<NiceMock<MockDecryptor> > decryptor_;
|
| + scoped_refptr<StrictMock<MockVideoDecoder> > decoder_;
|
| + VideoFrameStream::VideoDecoderList decoders_;
|
| +
|
| + // Callbacks to simulate pending decoder operations.
|
| + PipelineStatusCB decoder_init_cb_;
|
| + VideoDecoder::ReadCB decoder_read_cb_;
|
| + base::Closure decoder_reset_cb_;
|
| + base::Closure decoder_stop_cb_;
|
| +
|
| + bool is_initialized_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(VideoFrameStreamTest);
|
| +};
|
| +
|
| +INSTANTIATE_TEST_CASE_P(Clear, VideoFrameStreamTest, testing::Values(false));
|
| +INSTANTIATE_TEST_CASE_P(Encrypted, VideoFrameStreamTest, testing::Values(true));
|
| +
|
| +TEST_P(VideoFrameStreamTest, Initialization) {
|
| + Initialize();
|
| +}
|
| +
|
| +TEST_P(VideoFrameStreamTest, Initialization_Failed) {
|
| + InitializeAndFail();
|
| +}
|
| +
|
| +TEST_P(VideoFrameStreamTest, ReadFrame) {
|
| + Initialize();
|
| + ReadFrame();
|
| +}
|
| +
|
| +TEST_P(VideoFrameStreamTest, ReadFrame_Multiple) {
|
| + Initialize();
|
| + for (int i = 0; i < 10; ++i)
|
| + ReadFrame();
|
| +}
|
| +
|
| +TEST_P(VideoFrameStreamTest, ReadFrame_AfterReset) {
|
| + Initialize();
|
| + Reset();
|
| + ReadFrame();
|
| +}
|
| +
|
| +TEST_P(VideoFrameStreamTest, Reset_AfterInitialization) {
|
| + Initialize();
|
| + Reset();
|
| +}
|
| +
|
| +TEST_P(VideoFrameStreamTest, Reset_DuringReadFrame) {
|
| + Initialize();
|
| + EnterPendingReadFrameState();
|
| + EnterPendingResetState();
|
| + SatisfyPendingReadFrame();
|
| + SatisfyPendingReset();
|
| +}
|
| +
|
| +TEST_P(VideoFrameStreamTest, Reset_AfterReadFrame) {
|
| + Initialize();
|
| + ReadFrame();
|
| + Reset();
|
| +}
|
| +
|
| +TEST_P(VideoFrameStreamTest, Stop_BeforeInitialization) {
|
| + Stop();
|
| +}
|
| +
|
| +TEST_P(VideoFrameStreamTest, Stop_DuringInitialization) {
|
| + EnterPendingInitializationState();
|
| + EnterPendingStopState();
|
| + SatisfyPendingInitialization(true);
|
| + SatisfyPendingStop();
|
| +}
|
| +
|
| +TEST_P(VideoFrameStreamTest, Stop_DuringFailedInitialization) {
|
| + EnterPendingInitializationState();
|
| + EnterPendingStopState();
|
| + SatisfyPendingInitialization(false);
|
| + SatisfyPendingStop();
|
| +}
|
| +
|
| +TEST_P(VideoFrameStreamTest, Stop_AfterInitialization) {
|
| + Initialize();
|
| + Stop();
|
| +}
|
| +
|
| +TEST_P(VideoFrameStreamTest, Stop_AfterFailedInitialization) {
|
| + InitializeAndFail();
|
| + Stop();
|
| +}
|
| +
|
| +TEST_P(VideoFrameStreamTest, Stop_DuringReadFrame) {
|
| + Initialize();
|
| + EnterPendingReadFrameState();
|
| + EnterPendingStopState();
|
| + SatisfyPendingReadFrame();
|
| + SatisfyPendingStop();
|
| +}
|
| +
|
| +TEST_P(VideoFrameStreamTest, Stop_AfterReadFrame) {
|
| + Initialize();
|
| + ReadFrame();
|
| + Stop();
|
| +}
|
| +
|
| +TEST_P(VideoFrameStreamTest, Stop_DuringReset) {
|
| + Initialize();
|
| + EnterPendingResetState();
|
| + EnterPendingStopState();
|
| + SatisfyPendingReset();
|
| + SatisfyPendingStop();
|
| +}
|
| +
|
| +TEST_P(VideoFrameStreamTest, Stop_AfterReset) {
|
| + Initialize();
|
| + Reset();
|
| + Stop();
|
| +}
|
| +
|
| +TEST_P(VideoFrameStreamTest, Stop_DuringReadFrame_DuringReset) {
|
| + Initialize();
|
| + EnterPendingReadFrameState();
|
| + EnterPendingResetState();
|
| + EnterPendingStopState();
|
| + SatisfyPendingReadFrame();
|
| + SatisfyPendingReset();
|
| + SatisfyPendingStop();
|
| +}
|
| +
|
| +TEST_P(VideoFrameStreamTest, Stop_AfterReadFrame_DuringReset) {
|
| + Initialize();
|
| + EnterPendingReadFrameState();
|
| + EnterPendingResetState();
|
| + SatisfyPendingReadFrame();
|
| + EnterPendingStopState();
|
| + SatisfyPendingReset();
|
| + SatisfyPendingStop();
|
| +}
|
| +
|
| +TEST_P(VideoFrameStreamTest, Stop_AfterReadFrame_AfterReset) {
|
| + Initialize();
|
| + ReadFrame();
|
| + Reset();
|
| + Stop();
|
| +}
|
| +
|
| +} // namespace media
|
|
|