123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442 |
- // 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 "media/filters/fake_video_decoder.h"
- #include <memory>
- #include <utility>
- #include "base/bind.h"
- #include "base/callback_helpers.h"
- #include "base/run_loop.h"
- #include "base/test/task_environment.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 "testing/gtest/include/gtest/gtest.h"
- namespace media {
- static const int kTotalBuffers = 12;
- static const int kDurationMs = 30;
- struct FakeVideoDecoderTestParams {
- FakeVideoDecoderTestParams(int decoding_delay, int max_decode_requests)
- : decoding_delay(decoding_delay),
- max_decode_requests(max_decode_requests) {}
- int decoding_delay;
- int max_decode_requests;
- };
- class FakeVideoDecoderTest
- : public testing::Test,
- public testing::WithParamInterface<FakeVideoDecoderTestParams> {
- public:
- FakeVideoDecoderTest()
- : decoder_(new FakeVideoDecoder(
- 0xFACCE,
- GetParam().decoding_delay,
- GetParam().max_decode_requests,
- base::BindRepeating(&FakeVideoDecoderTest::OnBytesDecoded,
- base::Unretained(this)))),
- num_input_buffers_(0),
- num_decoded_frames_(0),
- num_bytes_decoded_(0),
- total_bytes_in_buffers_(0),
- last_decode_status_(DecoderStatus::Codes::kOk),
- pending_decode_requests_(0),
- is_reset_pending_(false) {}
- FakeVideoDecoderTest(const FakeVideoDecoderTest&) = delete;
- FakeVideoDecoderTest& operator=(const FakeVideoDecoderTest&) = delete;
- virtual ~FakeVideoDecoderTest() {
- Destroy();
- }
- void InitializeWithConfigAndExpectResult(const VideoDecoderConfig& config,
- bool success) {
- decoder_->Initialize(config, false, nullptr,
- base::BindOnce(
- [](bool success, DecoderStatus status) {
- EXPECT_EQ(status.is_ok(), success);
- },
- success),
- base::BindRepeating(&FakeVideoDecoderTest::FrameReady,
- base::Unretained(this)),
- base::NullCallback());
- base::RunLoop().RunUntilIdle();
- current_config_ = config;
- }
- void Initialize() {
- InitializeWithConfigAndExpectResult(TestVideoConfig::Normal(), true);
- }
- void EnterPendingInitState() {
- decoder_->HoldNextInit();
- Initialize();
- }
- void SatisfyInit() {
- decoder_->SatisfyInit();
- base::RunLoop().RunUntilIdle();
- }
- // Callback for VideoDecoder::Decode().
- void DecodeDone(DecoderStatus status) {
- DCHECK_GT(pending_decode_requests_, 0);
- --pending_decode_requests_;
- last_decode_status_ = std::move(status);
- }
- void FrameReady(scoped_refptr<VideoFrame> frame) {
- DCHECK(!frame->metadata().end_of_stream);
- last_decoded_frame_ = std::move(frame);
- num_decoded_frames_++;
- }
- void OnBytesDecoded(int count) {
- num_bytes_decoded_ += count;
- }
- enum CallbackResult {
- PENDING,
- OK,
- NOT_ENOUGH_DATA,
- ABORTED
- };
- void ExpectReadResult(CallbackResult result) {
- switch (result) {
- case PENDING:
- EXPECT_GT(pending_decode_requests_, 0);
- break;
- case OK:
- EXPECT_EQ(0, pending_decode_requests_);
- ASSERT_TRUE(last_decode_status_.is_ok());
- ASSERT_TRUE(last_decoded_frame_.get());
- break;
- case NOT_ENOUGH_DATA:
- EXPECT_EQ(0, pending_decode_requests_);
- ASSERT_TRUE(last_decode_status_.is_ok());
- ASSERT_FALSE(last_decoded_frame_.get());
- break;
- case ABORTED:
- EXPECT_EQ(0, pending_decode_requests_);
- ASSERT_EQ(DecoderStatus::Codes::kAborted, last_decode_status_.code());
- EXPECT_FALSE(last_decoded_frame_.get());
- break;
- }
- }
- void Decode() {
- scoped_refptr<DecoderBuffer> buffer;
- if (num_input_buffers_ < kTotalBuffers) {
- buffer = CreateFakeVideoBufferForTest(
- current_config_, base::Milliseconds(kDurationMs * num_input_buffers_),
- base::Milliseconds(kDurationMs));
- total_bytes_in_buffers_ += buffer->data_size();
- } else {
- buffer = DecoderBuffer::CreateEOSBuffer();
- }
- ++num_input_buffers_;
- ++pending_decode_requests_;
- decoder_->Decode(buffer, base::BindOnce(&FakeVideoDecoderTest::DecodeDone,
- base::Unretained(this)));
- base::RunLoop().RunUntilIdle();
- }
- void ReadOneFrame() {
- last_decoded_frame_.reset();
- do {
- Decode();
- } while (!last_decoded_frame_.get() && pending_decode_requests_ == 0);
- }
- void ReadAllFrames() {
- do {
- Decode();
- } while (num_input_buffers_ <= kTotalBuffers); // All input buffers + EOS.
- }
- void EnterPendingReadState() {
- // Pass the initial NOT_ENOUGH_DATA stage.
- ReadOneFrame();
- decoder_->HoldDecode();
- ReadOneFrame();
- ExpectReadResult(PENDING);
- }
- void SatisfyDecodeAndExpect(CallbackResult result) {
- decoder_->SatisfyDecode();
- base::RunLoop().RunUntilIdle();
- ExpectReadResult(result);
- }
- void SatisfyRead() {
- SatisfyDecodeAndExpect(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::BindOnce(&FakeVideoDecoderTest::OnDecoderReset,
- base::Unretained(this)));
- base::RunLoop().RunUntilIdle();
- ExpectResetResult(result);
- }
- void EnterPendingResetState() {
- decoder_->HoldNextReset();
- ResetAndExpect(PENDING);
- }
- void SatisfyReset() {
- decoder_->SatisfyReset();
- base::RunLoop().RunUntilIdle();
- ExpectResetResult(OK);
- }
- void Destroy() {
- decoder_.reset();
- base::RunLoop().RunUntilIdle();
- // All pending callbacks must have been fired.
- DCHECK_EQ(pending_decode_requests_, 0);
- DCHECK(!is_reset_pending_);
- }
- base::test::SingleThreadTaskEnvironment task_environment_;
- VideoDecoderConfig current_config_;
- std::unique_ptr<FakeVideoDecoder> decoder_;
- int num_input_buffers_;
- int num_decoded_frames_;
- int num_bytes_decoded_;
- int total_bytes_in_buffers_;
- // Callback result/status.
- DecoderStatus last_decode_status_;
- scoped_refptr<VideoFrame> last_decoded_frame_;
- int pending_decode_requests_;
- bool is_reset_pending_;
- };
- INSTANTIATE_TEST_SUITE_P(NoParallelDecode,
- FakeVideoDecoderTest,
- ::testing::Values(FakeVideoDecoderTestParams(9, 1),
- FakeVideoDecoderTestParams(0, 1)));
- INSTANTIATE_TEST_SUITE_P(ParallelDecode,
- FakeVideoDecoderTest,
- ::testing::Values(FakeVideoDecoderTestParams(9, 3),
- FakeVideoDecoderTestParams(0, 3)));
- TEST_P(FakeVideoDecoderTest, Initialize) {
- Initialize();
- }
- TEST_P(FakeVideoDecoderTest, SimulateFailureToInitialize) {
- decoder_->SimulateFailureToInit();
- InitializeWithConfigAndExpectResult(TestVideoConfig::Normal(), false);
- Decode();
- EXPECT_THAT(last_decode_status_, IsDecodeErrorStatus());
- }
- TEST_P(FakeVideoDecoderTest, Read_AllFrames) {
- Initialize();
- ReadAllFrames();
- EXPECT_EQ(kTotalBuffers, num_decoded_frames_);
- EXPECT_EQ(total_bytes_in_buffers_, num_bytes_decoded_);
- }
- TEST_P(FakeVideoDecoderTest, Read_DecodingDelay) {
- Initialize();
- while (num_input_buffers_ < kTotalBuffers) {
- ReadOneFrame();
- EXPECT_EQ(num_input_buffers_,
- num_decoded_frames_ + GetParam().decoding_delay);
- }
- }
- TEST_P(FakeVideoDecoderTest, Read_ZeroDelay) {
- decoder_ = std::make_unique<FakeVideoDecoder>(
- 999, 0, 1,
- base::BindRepeating(&FakeVideoDecoderTest::OnBytesDecoded,
- base::Unretained(this)));
- Initialize();
- while (num_input_buffers_ < kTotalBuffers) {
- ReadOneFrame();
- EXPECT_EQ(num_input_buffers_, num_decoded_frames_);
- }
- }
- TEST_P(FakeVideoDecoderTest, Read_Pending_NotEnoughData) {
- if (GetParam().decoding_delay < 1)
- return;
- Initialize();
- decoder_->HoldDecode();
- ReadOneFrame();
- ExpectReadResult(PENDING);
- SatisfyDecodeAndExpect(NOT_ENOUGH_DATA);
- // Verify that FrameReady() hasn't been called.
- EXPECT_FALSE(last_decoded_frame_.get());
- }
- TEST_P(FakeVideoDecoderTest, Read_Pending_OK) {
- Initialize();
- EnterPendingReadState();
- SatisfyDecodeAndExpect(OK);
- }
- TEST_P(FakeVideoDecoderTest, Read_Parallel) {
- if (GetParam().max_decode_requests < 2)
- return;
- Initialize();
- decoder_->HoldDecode();
- for (int i = 0; i < GetParam().max_decode_requests; ++i) {
- ReadOneFrame();
- ExpectReadResult(PENDING);
- }
- EXPECT_EQ(GetParam().max_decode_requests, pending_decode_requests_);
- SatisfyDecodeAndExpect(
- GetParam().max_decode_requests > GetParam().decoding_delay
- ? OK
- : NOT_ENOUGH_DATA);
- }
- TEST_P(FakeVideoDecoderTest, ReadWithHold_DecodingDelay) {
- Initialize();
- // Hold all decodes and satisfy one decode at a time.
- decoder_->HoldDecode();
- int num_decodes_satisfied = 0;
- while (num_decoded_frames_ == 0) {
- while (pending_decode_requests_ < decoder_->GetMaxDecodeRequests())
- Decode();
- decoder_->SatisfySingleDecode();
- ++num_decodes_satisfied;
- base::RunLoop().RunUntilIdle();
- }
- DCHECK_EQ(num_decoded_frames_, 1);
- DCHECK_EQ(num_decodes_satisfied, GetParam().decoding_delay + 1);
- }
- TEST_P(FakeVideoDecoderTest, Reinitialize) {
- Initialize();
- ReadOneFrame();
- InitializeWithConfigAndExpectResult(TestVideoConfig::Large(), true);
- ReadOneFrame();
- }
- TEST_P(FakeVideoDecoderTest, SimulateFailureToReinitialize) {
- Initialize();
- ReadOneFrame();
- decoder_->SimulateFailureToInit();
- InitializeWithConfigAndExpectResult(TestVideoConfig::Normal(), false);
- Decode();
- EXPECT_THAT(last_decode_status_, IsDecodeErrorStatus());
- }
- // Reinitializing the decoder during the middle of the decoding process can
- // cause dropped frames.
- TEST_P(FakeVideoDecoderTest, Reinitialize_FrameDropped) {
- if (GetParam().decoding_delay < 1)
- return;
- Initialize();
- ReadOneFrame();
- Initialize();
- ReadAllFrames();
- EXPECT_LT(num_decoded_frames_, kTotalBuffers);
- }
- TEST_P(FakeVideoDecoderTest, Reset) {
- Initialize();
- ReadOneFrame();
- ResetAndExpect(OK);
- }
- TEST_P(FakeVideoDecoderTest, Reset_DuringPendingRead) {
- Initialize();
- EnterPendingReadState();
- ResetAndExpect(PENDING);
- SatisfyDecodeAndExpect(ABORTED);
- }
- TEST_P(FakeVideoDecoderTest, Reset_Pending) {
- Initialize();
- EnterPendingResetState();
- SatisfyReset();
- }
- TEST_P(FakeVideoDecoderTest, Reset_PendingDuringPendingRead) {
- Initialize();
- EnterPendingReadState();
- EnterPendingResetState();
- SatisfyDecodeAndExpect(ABORTED);
- SatisfyReset();
- }
- TEST_P(FakeVideoDecoderTest, Destroy) {
- Initialize();
- ReadOneFrame();
- ExpectReadResult(OK);
- Destroy();
- }
- TEST_P(FakeVideoDecoderTest, Destroy_DuringPendingInitialization) {
- EnterPendingInitState();
- Destroy();
- }
- TEST_P(FakeVideoDecoderTest, Destroy_DuringPendingRead) {
- Initialize();
- EnterPendingReadState();
- Destroy();
- }
- TEST_P(FakeVideoDecoderTest, Destroy_DuringPendingReset) {
- Initialize();
- EnterPendingResetState();
- Destroy();
- }
- TEST_P(FakeVideoDecoderTest, Destroy_DuringPendingReadAndPendingReset) {
- Initialize();
- EnterPendingReadState();
- EnterPendingResetState();
- Destroy();
- }
- } // namespace media
|