1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552 |
- // 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 <memory>
- #include <utility>
- #include <vector>
- #include "base/bind.h"
- #include "base/callback_helpers.h"
- #include "base/memory/raw_ptr.h"
- #include "base/run_loop.h"
- #include "base/strings/string_number_conversions.h"
- #include "base/test/gmock_callback_support.h"
- #include "base/test/mock_callback.h"
- #include "base/test/task_environment.h"
- #include "build/build_config.h"
- #include "media/base/fake_demuxer_stream.h"
- #include "media/base/mock_filters.h"
- #include "media/base/mock_media_log.h"
- #include "media/base/test_helpers.h"
- #include "media/base/timestamp_constants.h"
- #include "media/filters/decoder_stream.h"
- #include "media/filters/fake_video_decoder.h"
- #include "testing/gtest/include/gtest/gtest.h"
- #if !BUILDFLAG(IS_ANDROID)
- #include "media/filters/decrypting_video_decoder.h"
- #endif
- #include <iostream>
- using ::base::test::RunCallback;
- using ::base::test::RunOnceCallback;
- using ::testing::_;
- using ::testing::AnyNumber;
- using ::testing::Assign;
- using ::testing::HasSubstr;
- using ::testing::InSequence;
- using ::testing::Invoke;
- using ::testing::InvokeWithoutArgs;
- using ::testing::NiceMock;
- using ::testing::Return;
- using ::testing::SaveArg;
- using ::testing::StrictMock;
- namespace media {
- namespace {
- const int kNumConfigs = 4;
- const int kNumBuffersInOneConfig = 5;
- constexpr base::TimeDelta kPrepareDelay = base::Milliseconds(5);
- static int GetDecoderId(int i) {
- return i;
- }
- DecoderPriority MockDecoderPriority(const VideoDecoderConfig& config,
- const VideoDecoder& decoder) {
- auto const at_or_above_cutoff = config.visible_rect().height() >=
- TestVideoConfig::LargeCodedSize().height();
- return at_or_above_cutoff == decoder.IsPlatformDecoder()
- ? DecoderPriority::kNormal
- : DecoderPriority::kDeprioritized;
- }
- } // namespace
- struct VideoDecoderStreamTestParams {
- VideoDecoderStreamTestParams(bool is_encrypted,
- bool has_decryptor,
- bool has_prepare,
- int decoding_delay,
- int parallel_decoding)
- : is_encrypted(is_encrypted),
- has_decryptor(has_decryptor),
- has_prepare(has_prepare),
- decoding_delay(decoding_delay),
- parallel_decoding(parallel_decoding) {}
- bool is_encrypted;
- bool has_decryptor;
- bool has_prepare;
- int decoding_delay;
- int parallel_decoding;
- };
- class VideoDecoderStreamTest
- : public testing::Test,
- public testing::WithParamInterface<VideoDecoderStreamTestParams> {
- public:
- VideoDecoderStreamTest()
- : is_initialized_(false),
- num_decoded_frames_(0),
- pending_initialize_(false),
- pending_read_(false),
- pending_reset_(false),
- pending_stop_(false),
- num_decoded_bytes_unreported_(0),
- has_no_key_(false) {
- video_decoder_stream_ = std::make_unique<VideoDecoderStream>(
- std::make_unique<VideoDecoderStream::StreamTraits>(&media_log_),
- task_environment_.GetMainThreadTaskRunner(),
- base::BindRepeating(&VideoDecoderStreamTest::CreateVideoDecodersForTest,
- base::Unretained(this)),
- &media_log_);
- video_decoder_stream_->set_decoder_change_observer(base::BindRepeating(
- &VideoDecoderStreamTest::OnDecoderChanged, base::Unretained(this)));
- video_decoder_stream_
- ->GetDecoderSelectorForTesting(base::PassKey<VideoDecoderStreamTest>())
- .OverrideDecoderPriorityCBForTesting(
- base::BindRepeating(MockDecoderPriority));
- if (GetParam().has_prepare) {
- video_decoder_stream_->SetPrepareCB(base::BindRepeating(
- &VideoDecoderStreamTest::PrepareFrame, base::Unretained(this)));
- }
- if (GetParam().is_encrypted && GetParam().has_decryptor) {
- decryptor_ = std::make_unique<NiceMock<MockDecryptor>>();
- // Decryptor can only decrypt (not decrypt-and-decode) so that
- // DecryptingDemuxerStream will be used.
- EXPECT_CALL(*decryptor_, InitializeVideoDecoder(_, _))
- .WillRepeatedly(RunOnceCallback<1>(false));
- EXPECT_CALL(*decryptor_, Decrypt(_, _, _))
- .WillRepeatedly(Invoke(this, &VideoDecoderStreamTest::Decrypt));
- }
- if (GetParam().is_encrypted) {
- cdm_context_ = std::make_unique<StrictMock<MockCdmContext>>();
- EXPECT_CALL(*cdm_context_, RegisterEventCB(_)).Times(AnyNumber());
- EXPECT_CALL(*cdm_context_, GetDecryptor())
- .WillRepeatedly(Return(decryptor_.get()));
- }
- // Covering most MediaLog messages for now.
- // TODO(wolenetz/xhwang): Fix tests to have better MediaLog checking.
- EXPECT_MEDIA_LOG(HasSubstr("video")).Times(AnyNumber());
- EXPECT_MEDIA_LOG(HasSubstr("Video")).Times(AnyNumber());
- EXPECT_MEDIA_LOG(HasSubstr("audio")).Times(AnyNumber());
- EXPECT_MEDIA_LOG(HasSubstr("Audio")).Times(AnyNumber());
- EXPECT_MEDIA_LOG(HasSubstr("decryptor")).Times(AnyNumber());
- }
- VideoDecoderStreamTest(const VideoDecoderStreamTest&) = delete;
- VideoDecoderStreamTest& operator=(const VideoDecoderStreamTest&) = delete;
- ~VideoDecoderStreamTest() {
- // Check that the pipeline statistics callback was fired correctly.
- EXPECT_EQ(num_decoded_bytes_unreported_, 0);
- is_initialized_ = false;
- decoders_.clear();
- video_decoder_stream_.reset();
- base::RunLoop().RunUntilIdle();
- DCHECK(!pending_initialize_);
- DCHECK(!pending_read_);
- DCHECK(!pending_reset_);
- DCHECK(!pending_stop_);
- }
- void CreateDemuxerStream(gfx::Size start_size, gfx::Vector2dF size_delta) {
- DCHECK(!demuxer_stream_);
- demuxer_stream_ = std::make_unique<FakeDemuxerStream>(
- kNumConfigs, kNumBuffersInOneConfig, GetParam().is_encrypted,
- start_size, size_delta);
- }
- void PrepareFrame(scoped_refptr<VideoFrame> frame,
- VideoDecoderStream::OutputReadyCB output_ready_cb) {
- // Simulate some delay in return of the output.
- task_environment_.GetMainThreadTaskRunner()->PostTask(
- FROM_HERE,
- base::BindOnce(std::move(output_ready_cb), std::move(frame)));
- }
- void PrepareFrameWithDelay(
- scoped_refptr<VideoFrame> frame,
- VideoDecoderStream::OutputReadyCB output_ready_cb) {
- task_environment_.FastForwardBy(kPrepareDelay);
- task_environment_.GetMainThreadTaskRunner()->PostTask(
- FROM_HERE,
- base::BindOnce(std::move(output_ready_cb), std::move(frame)));
- }
- void OnBytesDecoded(int count) { num_decoded_bytes_unreported_ += count; }
- // Callback to create a list of decoders for the DecoderSelector to select
- // from. Decoder selection happens
- // - on the initial selection in Initialize(),
- // - on decoder reinitialization failure, which can be simulated by calling
- // decoder_->SimulateFailureToInit(), and
- // - on decode error of the first buffer, which can be simulated by calling
- // decoder_->SimulateError() before reading the first frame.
- std::vector<std::unique_ptr<VideoDecoder>> CreateVideoDecodersForTest() {
- // Previously decoders could have been destroyed on decoder reselection.
- decoders_.clear();
- // Provide 3 decoders to test fallback cases.
- // TODO(xhwang): We should test the case where only certain decoder
- // supports encrypted streams. Currently this is hard to test because we use
- // parameterized tests which need to pass in all combinations.
- std::vector<std::unique_ptr<VideoDecoder>> decoders;
- #if !BUILDFLAG(IS_ANDROID)
- // Note this is _not_ inserted into |decoders_| below, so we don't need to
- // adjust the indices used below to compensate.
- decoders.push_back(std::make_unique<DecryptingVideoDecoder>(
- task_environment_.GetMainThreadTaskRunner(), &media_log_));
- #endif
- for (int i = 0; i < 3; ++i) {
- auto decoder = std::make_unique<FakeVideoDecoder>(
- GetDecoderId(i), GetParam().decoding_delay,
- GetParam().parallel_decoding,
- base::BindRepeating(&VideoDecoderStreamTest::OnBytesDecoded,
- base::Unretained(this)));
- if (GetParam().is_encrypted && !GetParam().has_decryptor)
- decoder->EnableEncryptedConfigSupport();
- // Keep a reference so we can change the behavior of each decoder.
- decoders_.push_back(decoder->GetWeakPtr());
- decoders.push_back(std::move(decoder));
- }
- for (const auto i : decoder_indices_to_fail_init_)
- decoders_[i]->SimulateFailureToInit();
- for (const auto i : decoder_indices_to_hold_init_)
- decoders_[i]->HoldNextInit();
- for (const auto i : decoder_indices_to_hold_decode_)
- decoders_[i]->HoldDecode();
- for (const auto i : platform_decoder_indices_)
- decoders_[i]->SetIsPlatformDecoder(true);
- return decoders;
- }
- void ClearDecoderInitExpectations() {
- decoder_indices_to_fail_init_.clear();
- decoder_indices_to_hold_init_.clear();
- decoder_indices_to_hold_decode_.clear();
- platform_decoder_indices_.clear();
- }
- // On next decoder selection, fail initialization on decoders specified by
- // |decoder_indices|.
- void FailDecoderInitOnSelection(std::vector<int> decoder_indices) {
- decoder_indices_to_fail_init_ = std::move(decoder_indices);
- for (int i : decoder_indices_to_fail_init_) {
- if (!decoders_.empty() && decoders_[i] && decoders_[i].get() != decoder_)
- decoders_[i]->SimulateFailureToInit();
- }
- }
- // On next decoder selection, hold initialization on decoders specified by
- // |decoder_indices|.
- void HoldDecoderInitOnSelection(std::vector<int> decoder_indices) {
- decoder_indices_to_hold_init_ = std::move(decoder_indices);
- for (int i : decoder_indices_to_hold_init_) {
- if (!decoders_.empty() && decoders_[i] && decoders_[i].get() != decoder_)
- decoders_[i]->HoldNextInit();
- }
- }
- // After next decoder selection, hold decode on decoders specified by
- // |decoder_indices|. This is needed because after decoder selection decode
- // may be resumed immediately and it'll be too late to hold decode then.
- void HoldDecodeAfterSelection(std::vector<int> decoder_indices) {
- decoder_indices_to_hold_decode_ = std::move(decoder_indices);
- for (int i : decoder_indices_to_hold_decode_) {
- if (!decoders_.empty() && decoders_[i] && decoders_[i].get() != decoder_)
- decoders_[i]->HoldDecode();
- }
- }
- void EnablePlatformDecoders(std::vector<int> decoder_indices) {
- platform_decoder_indices_ = std::move(decoder_indices);
- for (int i : platform_decoder_indices_) {
- if (!decoders_.empty() && decoders_[i] && decoders_[i].get() != decoder_)
- decoders_[i]->SetIsPlatformDecoder(true);
- }
- }
- // Updates the |decoder_| currently being used by VideoDecoderStream.
- void OnDecoderChanged(VideoDecoder* decoder) {
- if (!decoder) {
- decoder_ = nullptr;
- return;
- }
- // Ensure there's a media log created whenever selecting a decoder.
- EXPECT_MEDIA_LOG(HasSubstr("for video decoding, config"));
- decoder_ = static_cast<FakeVideoDecoder*>(decoder);
- ASSERT_TRUE(decoder_->GetDecoderId() == GetDecoderId(0) ||
- decoder_->GetDecoderId() == GetDecoderId(1) ||
- decoder_->GetDecoderId() == GetDecoderId(2));
- }
- MOCK_METHOD1(OnWaiting, void(WaitingReason));
- void OnStatistics(const PipelineStatistics& statistics) {
- num_decoded_bytes_unreported_ -= statistics.video_bytes_decoded;
- }
- void OnInitialized(bool success) {
- DCHECK(!pending_read_);
- DCHECK(!pending_reset_);
- DCHECK(pending_initialize_);
- pending_initialize_ = false;
- is_initialized_ = success;
- if (!success)
- decoders_.clear();
- }
- void Initialize() {
- if (!demuxer_stream_) {
- demuxer_stream_ = std::make_unique<FakeDemuxerStream>(
- kNumConfigs, kNumBuffersInOneConfig, GetParam().is_encrypted);
- }
- pending_initialize_ = true;
- video_decoder_stream_->Initialize(
- demuxer_stream_.get(),
- base::BindOnce(&VideoDecoderStreamTest::OnInitialized,
- base::Unretained(this)),
- cdm_context_.get(),
- base::BindRepeating(&VideoDecoderStreamTest::OnStatistics,
- base::Unretained(this)),
- base::BindRepeating(&VideoDecoderStreamTest::OnWaiting,
- base::Unretained(this)));
- EXPECT_MEDIA_LOG(HasSubstr("video")).Times(AnyNumber());
- EXPECT_MEDIA_LOG(HasSubstr("Video")).Times(AnyNumber());
- EXPECT_MEDIA_LOG(HasSubstr("audio")).Times(AnyNumber());
- EXPECT_MEDIA_LOG(HasSubstr("Audio")).Times(AnyNumber());
- base::RunLoop().RunUntilIdle();
- }
- // Fake Decrypt() function used by DecryptingDemuxerStream. It does nothing
- // but removes the DecryptConfig to make the buffer unencrypted.
- void Decrypt(Decryptor::StreamType stream_type,
- scoped_refptr<DecoderBuffer> encrypted,
- Decryptor::DecryptCB decrypt_cb) {
- DCHECK(encrypted->decrypt_config());
- if (has_no_key_) {
- std::move(decrypt_cb).Run(Decryptor::kNoKey, nullptr);
- return;
- }
- DCHECK_EQ(stream_type, Decryptor::kVideo);
- scoped_refptr<DecoderBuffer> decrypted =
- DecoderBuffer::CopyFrom(encrypted->data(), encrypted->data_size());
- if (encrypted->is_key_frame())
- decrypted->set_is_key_frame(true);
- decrypted->set_timestamp(encrypted->timestamp());
- decrypted->set_duration(encrypted->duration());
- std::move(decrypt_cb).Run(Decryptor::kSuccess, decrypted);
- }
- // Callback for VideoDecoderStream::Read().
- void FrameReady(VideoDecoderStream::ReadResult result) {
- DCHECK(pending_read_);
- last_read_status_code_ = result.code();
- scoped_refptr<VideoFrame> frame =
- last_read_status_code_ == DecoderStatus::Codes::kOk
- ? std::move(result).value()
- : nullptr;
- frame_read_ = frame;
- if (frame && !frame->metadata().end_of_stream) {
- EXPECT_EQ(*frame->metadata().frame_duration, demuxer_stream_->duration());
- num_decoded_frames_++;
- }
- pending_read_ = false;
- }
- void OnReset() {
- DCHECK(!pending_read_);
- DCHECK(pending_reset_);
- pending_reset_ = false;
- }
- void ReadOneFrame() {
- frame_read_ = nullptr;
- pending_read_ = true;
- video_decoder_stream_->Read(base::BindOnce(
- &VideoDecoderStreamTest::FrameReady, base::Unretained(this)));
- base::RunLoop().RunUntilIdle();
- }
- void ReadUntilPending() {
- do {
- ReadOneFrame();
- } while (!pending_read_);
- }
- void ReadAllFrames(int expected_decoded_frames) {
- // Reading all frames reinitializes the demuxer.
- do {
- ReadOneFrame();
- } while (frame_read_.get() && !frame_read_->metadata().end_of_stream);
- DCHECK_EQ(expected_decoded_frames, num_decoded_frames_);
- }
- void ReadAllFrames() {
- // No frames should have been dropped.
- ReadAllFrames(kNumConfigs * kNumBuffersInOneConfig);
- }
- enum PendingState {
- NOT_PENDING,
- DEMUXER_READ_NORMAL,
- DEMUXER_READ_CONFIG_CHANGE,
- DECRYPTOR_NO_KEY,
- DECODER_REINIT,
- DECODER_DECODE,
- DECODER_RESET
- };
- void EnterPendingState(PendingState state) {
- DCHECK_NE(state, NOT_PENDING);
- switch (state) {
- case DEMUXER_READ_NORMAL:
- demuxer_stream_->HoldNextRead();
- ReadUntilPending();
- break;
- case DEMUXER_READ_CONFIG_CHANGE:
- demuxer_stream_->HoldNextConfigChangeRead();
- ReadUntilPending();
- break;
- case DECRYPTOR_NO_KEY:
- if (GetParam().is_encrypted && GetParam().has_decryptor) {
- EXPECT_MEDIA_LOG(HasSubstr("no key for key ID"));
- EXPECT_CALL(*this, OnWaiting(WaitingReason::kNoDecryptionKey));
- has_no_key_ = true;
- }
- ReadOneFrame();
- break;
- case DECODER_REINIT:
- decoder_->HoldNextInit();
- ReadUntilPending();
- break;
- case DECODER_DECODE:
- decoder_->HoldDecode();
- ReadUntilPending();
- break;
- case DECODER_RESET:
- decoder_->HoldNextReset();
- pending_reset_ = true;
- video_decoder_stream_->Reset(base::BindOnce(
- &VideoDecoderStreamTest::OnReset, base::Unretained(this)));
- base::RunLoop().RunUntilIdle();
- break;
- case NOT_PENDING:
- NOTREACHED();
- break;
- }
- }
- void SatisfyPendingCallback(PendingState state) {
- DCHECK_NE(state, NOT_PENDING);
- switch (state) {
- case DEMUXER_READ_CONFIG_CHANGE:
- EXPECT_MEDIA_LOG(HasSubstr("decoder config changed"))
- .Times(testing::AtLeast(1));
- [[fallthrough]];
- case DEMUXER_READ_NORMAL:
- demuxer_stream_->SatisfyRead();
- break;
- // This is only interesting to test during VideoDecoderStream destruction.
- // There's no need to satisfy a callback.
- case DECRYPTOR_NO_KEY:
- NOTREACHED();
- break;
- case DECODER_REINIT:
- decoder_->SatisfyInit();
- break;
- case DECODER_DECODE:
- decoder_->SatisfyDecode();
- break;
- case DECODER_RESET:
- decoder_->SatisfyReset();
- break;
- case NOT_PENDING:
- NOTREACHED();
- break;
- }
- base::RunLoop().RunUntilIdle();
- }
- void Read() {
- EnterPendingState(DECODER_DECODE);
- SatisfyPendingCallback(DECODER_DECODE);
- }
- void Reset() {
- EnterPendingState(DECODER_RESET);
- SatisfyPendingCallback(DECODER_RESET);
- }
- void ReadUntilDecoderReinitialized() {
- EnterPendingState(DECODER_REINIT);
- SatisfyPendingCallback(DECODER_REINIT);
- }
- base::test::SingleThreadTaskEnvironment task_environment_{
- base::test::TaskEnvironment::TimeSource::MOCK_TIME};
- StrictMock<MockMediaLog> media_log_;
- std::unique_ptr<VideoDecoderStream> video_decoder_stream_;
- std::unique_ptr<FakeDemuxerStream> demuxer_stream_;
- std::unique_ptr<StrictMock<MockCdmContext>> cdm_context_;
- // Use NiceMock since we don't care about most of calls on the decryptor.
- std::unique_ptr<NiceMock<MockDecryptor>> decryptor_;
- // References to the list of decoders to be select from by DecoderSelector.
- // Three decoders are needed to test that decoder fallback can occur more than
- // once on a config change. They are owned by |video_decoder_stream_|.
- std::vector<base::WeakPtr<FakeVideoDecoder>> decoders_;
- std::vector<int> decoder_indices_to_fail_init_;
- std::vector<int> decoder_indices_to_hold_init_;
- std::vector<int> decoder_indices_to_hold_decode_;
- std::vector<int> platform_decoder_indices_;
- // The current decoder used by |video_decoder_stream_|.
- raw_ptr<FakeVideoDecoder> decoder_ = nullptr;
- bool is_initialized_;
- int num_decoded_frames_;
- bool pending_initialize_;
- bool pending_read_;
- bool pending_reset_;
- bool pending_stop_;
- int num_decoded_bytes_unreported_;
- scoped_refptr<VideoFrame> frame_read_;
- DecoderStatus::Codes last_read_status_code_;
- // Decryptor has no key to decrypt a frame.
- bool has_no_key_;
- };
- INSTANTIATE_TEST_SUITE_P(
- Clear,
- VideoDecoderStreamTest,
- ::testing::Values(VideoDecoderStreamTestParams(false, false, false, 0, 1),
- VideoDecoderStreamTestParams(false, false, false, 3, 1),
- VideoDecoderStreamTestParams(false, false, false, 7, 1),
- VideoDecoderStreamTestParams(false, false, true, 0, 1),
- VideoDecoderStreamTestParams(false, false, true, 3, 1)));
- INSTANTIATE_TEST_SUITE_P(
- EncryptedWithDecryptor,
- VideoDecoderStreamTest,
- ::testing::Values(VideoDecoderStreamTestParams(true, true, false, 7, 1),
- VideoDecoderStreamTestParams(true, true, true, 7, 1)));
- INSTANTIATE_TEST_SUITE_P(
- EncryptedWithoutDecryptor,
- VideoDecoderStreamTest,
- ::testing::Values(VideoDecoderStreamTestParams(true, false, false, 7, 1),
- VideoDecoderStreamTestParams(true, false, true, 7, 1)));
- INSTANTIATE_TEST_SUITE_P(
- Clear_Parallel,
- VideoDecoderStreamTest,
- ::testing::Values(VideoDecoderStreamTestParams(false, false, false, 0, 3),
- VideoDecoderStreamTestParams(false, false, false, 2, 3),
- VideoDecoderStreamTestParams(false, false, true, 0, 3),
- VideoDecoderStreamTestParams(false, false, true, 2, 3)));
- TEST_P(VideoDecoderStreamTest, CanReadWithoutStallingAtAnyTime) {
- ASSERT_FALSE(video_decoder_stream_->CanReadWithoutStalling());
- }
- TEST_P(VideoDecoderStreamTest, Initialization) {
- Initialize();
- EXPECT_TRUE(is_initialized_);
- }
- TEST_P(VideoDecoderStreamTest, AllDecoderInitializationFails) {
- FailDecoderInitOnSelection({0, 1, 2});
- Initialize();
- EXPECT_FALSE(is_initialized_);
- }
- TEST_P(VideoDecoderStreamTest, PartialDecoderInitializationFails) {
- FailDecoderInitOnSelection({0, 1});
- Initialize();
- EXPECT_TRUE(is_initialized_);
- }
- TEST_P(VideoDecoderStreamTest, ReadOneFrame) {
- Initialize();
- Read();
- }
- TEST_P(VideoDecoderStreamTest, ReadAllFrames) {
- Initialize();
- ReadAllFrames();
- }
- TEST_P(VideoDecoderStreamTest, Read_AfterReset) {
- Initialize();
- Reset();
- Read();
- Reset();
- Read();
- }
- // Tests that the decoder stream will switch from a software decoder to a
- // hardware decoder if the config size increases
- TEST_P(VideoDecoderStreamTest, ConfigChangeSwToHw) {
- EnablePlatformDecoders({1});
- // Create a demuxer stream with a config that increases in size
- auto const size_delta =
- TestVideoConfig::LargeCodedSize() - TestVideoConfig::NormalCodedSize();
- auto const width_delta = size_delta.width() / (kNumConfigs - 1);
- auto const height_delta = size_delta.height() / (kNumConfigs - 1);
- CreateDemuxerStream(TestVideoConfig::NormalCodedSize(),
- gfx::Vector2dF(width_delta, height_delta));
- Initialize();
- // Initially we should be using a software decoder
- EXPECT_TRUE(decoder_);
- EXPECT_FALSE(decoder_->IsPlatformDecoder());
- ReadAllFrames();
- // We should end up on a hardware decoder
- EXPECT_TRUE(decoder_->IsPlatformDecoder());
- }
- // Tests that the decoder stream will switch from a hardware decoder to a
- // software decoder if the config size decreases
- TEST_P(VideoDecoderStreamTest, ConfigChangeHwToSw) {
- EnablePlatformDecoders({1});
- // Create a demuxer stream with a config that progressively decreases in size
- auto const size_delta =
- TestVideoConfig::LargeCodedSize() - TestVideoConfig::NormalCodedSize();
- auto const width_delta = size_delta.width() / kNumConfigs;
- auto const height_delta = size_delta.height() / kNumConfigs;
- CreateDemuxerStream(TestVideoConfig::LargeCodedSize(),
- gfx::Vector2dF(-width_delta, -height_delta));
- Initialize();
- // We should initially be using a hardware decoder
- EXPECT_TRUE(decoder_);
- EXPECT_TRUE(decoder_->IsPlatformDecoder());
- ReadAllFrames();
- // We should end up on a software decoder
- EXPECT_FALSE(decoder_->IsPlatformDecoder());
- }
- TEST_P(VideoDecoderStreamTest, Read_ProperMetadata) {
- // For testing simplicity, omit parallel decode tests with a delay in frames.
- if (GetParam().parallel_decoding > 1 && GetParam().decoding_delay > 0)
- return;
- if (GetParam().has_prepare) {
- // Override the basic PrepareFrame() for a version that moves the MockTime
- // by kPrepareDelay. This simulates real work done (e.g. YUV conversion).
- video_decoder_stream_->SetPrepareCB(
- base::BindRepeating(&VideoDecoderStreamTest::PrepareFrameWithDelay,
- base::Unretained(this)));
- }
- constexpr base::TimeDelta kDecodeDelay = base::Milliseconds(10);
- Initialize();
- // Simulate time elapsed by the decoder.
- EnterPendingState(DECODER_DECODE);
- task_environment_.FastForwardBy(kDecodeDelay);
- SatisfyPendingCallback(DECODER_DECODE);
- EXPECT_TRUE(frame_read_);
- const VideoFrameMetadata& metadata = frame_read_->metadata();
- // Verify the decoding metadata is accurate.
- EXPECT_EQ(*metadata.decode_end_time - *metadata.decode_begin_time,
- kDecodeDelay);
- // Verify the processing metadata is accurate.
- const base::TimeDelta expected_processing_time =
- GetParam().has_prepare ? (kDecodeDelay + kPrepareDelay) : kDecodeDelay;
- EXPECT_EQ(*metadata.processing_time, expected_processing_time);
- }
- TEST_P(VideoDecoderStreamTest, Read_BlockedDemuxer) {
- Initialize();
- demuxer_stream_->HoldNextRead();
- ReadOneFrame();
- EXPECT_TRUE(pending_read_);
- int demuxed_buffers = 0;
- // Pass frames from the demuxer to the VideoDecoderStream until the first read
- // request is satisfied.
- while (pending_read_) {
- ++demuxed_buffers;
- demuxer_stream_->SatisfyReadAndHoldNext();
- base::RunLoop().RunUntilIdle();
- }
- EXPECT_EQ(std::min(GetParam().decoding_delay + 1, kNumBuffersInOneConfig + 1),
- demuxed_buffers);
- // At this point the stream is waiting on read from the demuxer, but there is
- // no pending read from the stream. The stream should be blocked if we try
- // reading from it again.
- ReadUntilPending();
- demuxer_stream_->SatisfyRead();
- base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(pending_read_);
- }
- TEST_P(VideoDecoderStreamTest, Read_BlockedDemuxerAndDecoder) {
- // Test applies only when the decoder allows multiple parallel requests.
- if (GetParam().parallel_decoding == 1)
- return;
- Initialize();
- demuxer_stream_->HoldNextRead();
- decoder_->HoldDecode();
- ReadOneFrame();
- EXPECT_TRUE(pending_read_);
- int demuxed_buffers = 0;
- // Pass frames from the demuxer to the VideoDecoderStream until the first read
- // request is satisfied, while always keeping one decode request pending.
- while (pending_read_) {
- ++demuxed_buffers;
- demuxer_stream_->SatisfyReadAndHoldNext();
- base::RunLoop().RunUntilIdle();
- // Always keep one decode request pending.
- if (demuxed_buffers > 1) {
- decoder_->SatisfySingleDecode();
- base::RunLoop().RunUntilIdle();
- }
- }
- ReadUntilPending();
- EXPECT_TRUE(pending_read_);
- // Unblocking one decode request should unblock read even when demuxer is
- // still blocked.
- decoder_->SatisfySingleDecode();
- base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(pending_read_);
- // Stream should still be blocked on the demuxer after unblocking the decoder.
- decoder_->SatisfyDecode();
- ReadUntilPending();
- EXPECT_TRUE(pending_read_);
- // Verify that the stream has returned all frames that have been demuxed,
- // accounting for the decoder delay.
- EXPECT_EQ(demuxed_buffers - GetParam().decoding_delay, num_decoded_frames_);
- // Unblocking the demuxer will unblock the stream.
- demuxer_stream_->SatisfyRead();
- base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(pending_read_);
- }
- TEST_P(VideoDecoderStreamTest, Read_DuringEndOfStreamDecode) {
- // Test applies only when the decoder allows multiple parallel requests, and
- // they are not satisfied in a single batch.
- if (GetParam().parallel_decoding == 1 || GetParam().decoding_delay != 0)
- return;
- Initialize();
- decoder_->HoldDecode();
- // Read all of the frames up to end of stream. Since parallel decoding is
- // enabled, the end of stream buffer will be sent to the decoder immediately,
- // but we don't satisfy it yet.
- for (int configuration = 0; configuration < kNumConfigs; configuration++) {
- for (int frame = 0; frame < kNumBuffersInOneConfig; frame++) {
- ReadOneFrame();
- while (pending_read_) {
- decoder_->SatisfySingleDecode();
- base::RunLoop().RunUntilIdle();
- }
- }
- }
- // Read() again. The callback must be delayed until the decode completes.
- ReadOneFrame();
- ASSERT_TRUE(pending_read_);
- // Satisfy decoding of the end of stream buffer. The read should complete.
- decoder_->SatisfySingleDecode();
- base::RunLoop().RunUntilIdle();
- ASSERT_FALSE(pending_read_);
- EXPECT_EQ(last_read_status_code_, DecoderStatus::Codes::kOk);
- // The read output should indicate end of stream.
- ASSERT_TRUE(frame_read_.get());
- EXPECT_TRUE(frame_read_->metadata().end_of_stream);
- }
- TEST_P(VideoDecoderStreamTest, Read_DemuxerStreamReadError) {
- Initialize();
- EnterPendingState(DEMUXER_READ_NORMAL);
- InSequence s;
- if (GetParam().is_encrypted && GetParam().has_decryptor) {
- EXPECT_MEDIA_LOG(
- HasSubstr("DecryptingDemuxerStream: demuxer stream read error"));
- }
- EXPECT_MEDIA_LOG(HasSubstr("video demuxer stream read error"));
- demuxer_stream_->Error();
- base::RunLoop().RunUntilIdle();
- ASSERT_FALSE(pending_read_);
- EXPECT_NE(last_read_status_code_, DecoderStatus::Codes::kOk);
- EXPECT_NE(last_read_status_code_, DecoderStatus::Codes::kAborted);
- }
- // No Reset() before initialization is successfully completed.
- TEST_P(VideoDecoderStreamTest, Reset_AfterInitialization) {
- Initialize();
- Reset();
- Read();
- }
- TEST_P(VideoDecoderStreamTest, Reset_DuringReinitialization) {
- Initialize();
- EnterPendingState(DECODER_REINIT);
- // VideoDecoder::Reset() is not called when we reset during reinitialization.
- pending_reset_ = true;
- video_decoder_stream_->Reset(
- base::BindOnce(&VideoDecoderStreamTest::OnReset, base::Unretained(this)));
- SatisfyPendingCallback(DECODER_REINIT);
- Read();
- }
- TEST_P(VideoDecoderStreamTest, Reset_AfterReinitialization) {
- Initialize();
- EnterPendingState(DECODER_REINIT);
- SatisfyPendingCallback(DECODER_REINIT);
- Reset();
- Read();
- }
- TEST_P(VideoDecoderStreamTest, Reset_DuringDemuxerRead_Normal) {
- Initialize();
- EnterPendingState(DEMUXER_READ_NORMAL);
- EnterPendingState(DECODER_RESET);
- SatisfyPendingCallback(DEMUXER_READ_NORMAL);
- SatisfyPendingCallback(DECODER_RESET);
- Read();
- }
- TEST_P(VideoDecoderStreamTest, Reset_DuringDemuxerRead_ConfigChange) {
- Initialize();
- EnterPendingState(DEMUXER_READ_CONFIG_CHANGE);
- EnterPendingState(DECODER_RESET);
- SatisfyPendingCallback(DEMUXER_READ_CONFIG_CHANGE);
- SatisfyPendingCallback(DECODER_RESET);
- Read();
- }
- TEST_P(VideoDecoderStreamTest, Reset_DuringNormalDecoderDecode) {
- Initialize();
- EnterPendingState(DECODER_DECODE);
- EnterPendingState(DECODER_RESET);
- SatisfyPendingCallback(DECODER_DECODE);
- SatisfyPendingCallback(DECODER_RESET);
- Read();
- }
- TEST_P(VideoDecoderStreamTest, Reset_AfterNormalRead) {
- Initialize();
- Read();
- Reset();
- Read();
- }
- TEST_P(VideoDecoderStreamTest, Reset_AfterDemuxerRead_ConfigChange) {
- Initialize();
- EnterPendingState(DEMUXER_READ_CONFIG_CHANGE);
- SatisfyPendingCallback(DEMUXER_READ_CONFIG_CHANGE);
- Reset();
- Read();
- }
- TEST_P(VideoDecoderStreamTest, Reset_AfterEndOfStream) {
- Initialize();
- ReadAllFrames();
- Reset();
- num_decoded_frames_ = 0;
- demuxer_stream_->SeekToStart();
- ReadAllFrames();
- }
- TEST_P(VideoDecoderStreamTest, Reset_DuringNoKeyRead) {
- Initialize();
- EnterPendingState(DECRYPTOR_NO_KEY);
- Reset();
- }
- // In the following Destroy_* tests, |video_decoder_stream_| is destroyed in
- // VideoDecoderStreamTest destructor.
- TEST_P(VideoDecoderStreamTest, Destroy_BeforeInitialization) {}
- TEST_P(VideoDecoderStreamTest, Destroy_DuringInitialization) {
- HoldDecoderInitOnSelection({0});
- Initialize();
- }
- TEST_P(VideoDecoderStreamTest, Destroy_AfterInitialization) {
- Initialize();
- }
- TEST_P(VideoDecoderStreamTest, Destroy_DuringReinitialization) {
- Initialize();
- EnterPendingState(DECODER_REINIT);
- }
- TEST_P(VideoDecoderStreamTest, Destroy_AfterReinitialization) {
- Initialize();
- EnterPendingState(DECODER_REINIT);
- SatisfyPendingCallback(DECODER_REINIT);
- }
- TEST_P(VideoDecoderStreamTest, Destroy_DuringDemuxerRead_Normal) {
- Initialize();
- EnterPendingState(DEMUXER_READ_NORMAL);
- }
- TEST_P(VideoDecoderStreamTest, Destroy_DuringDemuxerRead_ConfigChange) {
- Initialize();
- EnterPendingState(DEMUXER_READ_CONFIG_CHANGE);
- }
- TEST_P(VideoDecoderStreamTest, Destroy_DuringNormalDecoderDecode) {
- Initialize();
- EnterPendingState(DECODER_DECODE);
- }
- TEST_P(VideoDecoderStreamTest, Destroy_AfterNormalRead) {
- Initialize();
- Read();
- }
- TEST_P(VideoDecoderStreamTest, Destroy_AfterConfigChangeRead) {
- Initialize();
- EnterPendingState(DEMUXER_READ_CONFIG_CHANGE);
- SatisfyPendingCallback(DEMUXER_READ_CONFIG_CHANGE);
- }
- TEST_P(VideoDecoderStreamTest, Destroy_DuringDecoderReinitialization) {
- Initialize();
- EnterPendingState(DECODER_REINIT);
- }
- TEST_P(VideoDecoderStreamTest, Destroy_DuringNoKeyRead) {
- Initialize();
- EnterPendingState(DECRYPTOR_NO_KEY);
- }
- TEST_P(VideoDecoderStreamTest, Destroy_DuringReset) {
- Initialize();
- EnterPendingState(DECODER_RESET);
- }
- TEST_P(VideoDecoderStreamTest, Destroy_AfterReset) {
- Initialize();
- Reset();
- }
- TEST_P(VideoDecoderStreamTest, Destroy_DuringRead_DuringReset) {
- Initialize();
- EnterPendingState(DECODER_DECODE);
- EnterPendingState(DECODER_RESET);
- }
- TEST_P(VideoDecoderStreamTest, Destroy_AfterRead_DuringReset) {
- Initialize();
- EnterPendingState(DECODER_DECODE);
- EnterPendingState(DECODER_RESET);
- SatisfyPendingCallback(DECODER_DECODE);
- }
- TEST_P(VideoDecoderStreamTest, Destroy_AfterRead_AfterReset) {
- Initialize();
- Read();
- Reset();
- }
- // The following tests cover the fallback logic after reinitialization error or
- // decode error of the first buffer after initialization.
- TEST_P(VideoDecoderStreamTest, FallbackDecoder_DecodeError) {
- Initialize();
- decoder_->SimulateError();
- ReadOneFrame();
- // |video_decoder_stream_| should have fallen back to a new decoder.
- ASSERT_EQ(GetDecoderId(1), decoder_->GetDecoderId());
- ASSERT_FALSE(pending_read_);
- ASSERT_EQ(last_read_status_code_, DecoderStatus::Codes::kOk);
- // Check that we fell back to Decoder2.
- ASSERT_GT(decoder_->total_bytes_decoded(), 0);
- // Verify no frame was dropped.
- ReadAllFrames();
- }
- TEST_P(VideoDecoderStreamTest,
- FallbackDecoder_EndOfStreamReachedBeforeFallback) {
- // Only consider cases where there is a decoder delay. For test simplicity,
- // omit the parallel case.
- if (GetParam().decoding_delay == 0 || GetParam().parallel_decoding > 1)
- return;
- Initialize();
- decoder_->HoldDecode();
- ReadOneFrame();
- // One buffer should have already pulled from the demuxer stream. Set the next
- // one to be an EOS.
- demuxer_stream_->SeekToEndOfStream();
- decoder_->SatisfySingleDecode();
- base::RunLoop().RunUntilIdle();
- // |video_decoder_stream_| should not have emitted a frame.
- EXPECT_TRUE(pending_read_);
- // Pending buffers should contain a regular buffer and an EOS buffer.
- EXPECT_EQ(video_decoder_stream_->get_pending_buffers_size_for_testing(), 2);
- decoder_->SimulateError();
- base::RunLoop().RunUntilIdle();
- ASSERT_EQ(GetDecoderId(1), decoder_->GetDecoderId());
- // A frame should have been emitted.
- EXPECT_FALSE(pending_read_);
- EXPECT_EQ(last_read_status_code_, DecoderStatus::Codes::kOk);
- EXPECT_FALSE(frame_read_->metadata().end_of_stream);
- EXPECT_GT(decoder_->total_bytes_decoded(), 0);
- ReadOneFrame();
- EXPECT_FALSE(pending_read_);
- EXPECT_EQ(0, video_decoder_stream_->get_fallback_buffers_size_for_testing());
- EXPECT_TRUE(frame_read_->metadata().end_of_stream);
- }
- TEST_P(VideoDecoderStreamTest,
- FallbackDecoder_DoesReinitializeStompPendingRead) {
- // Test only the case where there is no decoding delay and parallel decoding.
- if (GetParam().decoding_delay != 0 || GetParam().parallel_decoding <= 1)
- return;
- Initialize();
- decoder_->HoldDecode();
- // Queue one read, defer the second.
- frame_read_ = nullptr;
- pending_read_ = true;
- video_decoder_stream_->Read(base::BindOnce(
- &VideoDecoderStreamTest::FrameReady, base::Unretained(this)));
- demuxer_stream_->HoldNextRead();
- // Force an error to occur on the first decode, but ensure it isn't propagated
- // until after the next read has been started.
- decoder_->SimulateError();
- HoldDecodeAfterSelection({1});
- // Complete the fallback to the second decoder with the read still pending.
- base::RunLoop().RunUntilIdle();
- ASSERT_EQ(GetDecoderId(1), decoder_->GetDecoderId());
- // Can't check the original decoder right now, it might have been destroyed
- // already. Verify that there was nothing decoded until we kicked the decoder.
- EXPECT_EQ(decoder_->total_bytes_decoded(), 0);
- decoder_->SatisfyDecode();
- const int first_decoded_bytes = decoder_->total_bytes_decoded();
- ASSERT_GT(first_decoded_bytes, 0);
- // Satisfy the previously pending read and ensure it is decoded.
- demuxer_stream_->SatisfyRead();
- base::RunLoop().RunUntilIdle();
- ASSERT_GT(decoder_->total_bytes_decoded(), first_decoded_bytes);
- }
- TEST_P(VideoDecoderStreamTest, FallbackDecoder_DecodeErrorRepeated) {
- Initialize();
- // Hold other decoders to simulate errors.
- HoldDecodeAfterSelection({1, 2});
- // Simulate decode error to trigger the fallback path.
- decoder_->SimulateError();
- ReadOneFrame();
- base::RunLoop().RunUntilIdle();
- // Expect decoder 1 to be tried.
- ASSERT_EQ(GetDecoderId(1), decoder_->GetDecoderId());
- decoder_->SimulateError();
- base::RunLoop().RunUntilIdle();
- // Then decoder 2.
- ASSERT_EQ(GetDecoderId(2), decoder_->GetDecoderId());
- decoder_->SimulateError();
- base::RunLoop().RunUntilIdle();
- // No decoders left, expect failure.
- EXPECT_EQ(decoder_, nullptr);
- EXPECT_FALSE(pending_read_);
- EXPECT_NE(last_read_status_code_, DecoderStatus::Codes::kOk);
- EXPECT_NE(last_read_status_code_, DecoderStatus::Codes::kAborted);
- }
- // This tests verifies that we properly fallback to a new decoder if the first
- // decode after a config change fails.
- TEST_P(VideoDecoderStreamTest,
- FallbackDecoder_SelectedOnMidstreamDecodeErrorAfterReinitialization) {
- // For simplicity of testing, this test applies only when there is no decoder
- // delay and parallel decoding is disabled.
- if (GetParam().decoding_delay != 0 || GetParam().parallel_decoding > 1)
- return;
- Initialize();
- // Note: Completes decoding one frame, results in Decode() being called with
- // second frame that is not completed.
- ReadOneFrame();
- // Verify that the first frame was decoded successfully.
- EXPECT_FALSE(pending_read_);
- EXPECT_GT(decoder_->total_bytes_decoded(), 0);
- EXPECT_EQ(last_read_status_code_, DecoderStatus::Codes::kOk);
- // Continue up to the point of reinitialization.
- EnterPendingState(DEMUXER_READ_CONFIG_CHANGE);
- // Hold decodes to prevent a frame from being outputted upon reinitialization.
- decoder_->HoldDecode();
- SatisfyPendingCallback(DEMUXER_READ_CONFIG_CHANGE);
- // DecoderStream sends an EOS to flush the decoder during config changes.
- // Let the EOS decode be satisfied to properly complete the decoder reinit.
- decoder_->SatisfySingleDecode();
- base::RunLoop().RunUntilIdle();
- EXPECT_TRUE(pending_read_);
- // Fail the first decode, before a frame can be outputted.
- decoder_->SimulateError();
- base::RunLoop().RunUntilIdle();
- ReadOneFrame();
- // Verify that fallback happened.
- EXPECT_EQ(GetDecoderId(0), decoder_->GetDecoderId());
- EXPECT_FALSE(pending_read_);
- EXPECT_EQ(last_read_status_code_, DecoderStatus::Codes::kOk);
- EXPECT_GT(decoder_->total_bytes_decoded(), 0);
- }
- TEST_P(VideoDecoderStreamTest,
- FallbackDecoder_DecodeErrorRepeated_AfterReinitialization) {
- Initialize();
- // Simulate decode error to trigger fallback.
- decoder_->SimulateError();
- ReadOneFrame();
- base::RunLoop().RunUntilIdle();
- // Simulate reinitialize error of decoder 1.
- ASSERT_EQ(GetDecoderId(1), decoder_->GetDecoderId());
- decoder_->SimulateFailureToInit();
- HoldDecodeAfterSelection({0, 1, 2});
- ReadUntilDecoderReinitialized();
- // Decoder 0 should be selected again.
- ASSERT_EQ(GetDecoderId(0), decoder_->GetDecoderId());
- decoder_->SimulateError();
- base::RunLoop().RunUntilIdle();
- // Decoder 1.
- ASSERT_EQ(GetDecoderId(1), decoder_->GetDecoderId());
- decoder_->SimulateError();
- base::RunLoop().RunUntilIdle();
- // Decoder 2.
- ASSERT_EQ(GetDecoderId(2), decoder_->GetDecoderId());
- decoder_->SimulateError();
- base::RunLoop().RunUntilIdle();
- // No decoders left.
- EXPECT_EQ(decoder_, nullptr);
- EXPECT_FALSE(pending_read_);
- EXPECT_NE(last_read_status_code_, DecoderStatus::Codes::kOk);
- EXPECT_NE(last_read_status_code_, DecoderStatus::Codes::kAborted);
- }
- TEST_P(VideoDecoderStreamTest,
- FallbackDecoder_ConfigChangeClearsPendingBuffers) {
- // Test case is only interesting if the decoder can receive a config change
- // before returning its first frame.
- if (GetParam().decoding_delay < kNumBuffersInOneConfig)
- return;
- Initialize();
- EnterPendingState(DEMUXER_READ_CONFIG_CHANGE);
- ASSERT_GT(video_decoder_stream_->get_pending_buffers_size_for_testing(), 0);
- SatisfyPendingCallback(DEMUXER_READ_CONFIG_CHANGE);
- ASSERT_EQ(video_decoder_stream_->get_pending_buffers_size_for_testing(), 0);
- EXPECT_FALSE(pending_read_);
- ReadAllFrames();
- }
- TEST_P(VideoDecoderStreamTest,
- FallbackDecoder_ErrorDuringConfigChangeFlushing) {
- // Test case is only interesting if the decoder can receive a config change
- // before returning its first frame.
- if (GetParam().decoding_delay < kNumBuffersInOneConfig)
- return;
- Initialize();
- EnterPendingState(DEMUXER_READ_CONFIG_CHANGE);
- EXPECT_GT(video_decoder_stream_->get_pending_buffers_size_for_testing(), 0);
- decoder_->HoldDecode();
- SatisfyPendingCallback(DEMUXER_READ_CONFIG_CHANGE);
- // The flush request should have been sent and held.
- EXPECT_EQ(video_decoder_stream_->get_pending_buffers_size_for_testing(), 0);
- EXPECT_TRUE(pending_read_);
- // Triggering an error here will cause the frames in selected decoder to be
- // lost. There are no pending buffers to give to |decoders_[1]| due to
- // http://crbug.com/603713
- decoder_->SimulateError();
- base::RunLoop().RunUntilIdle();
- // We want to make sure the fallback decoder can decode the rest of the frames
- // in the demuxer stream.
- ReadAllFrames(kNumBuffersInOneConfig * (kNumConfigs - 1));
- }
- TEST_P(VideoDecoderStreamTest,
- FallbackDecoder_PendingBuffersIsFilledAndCleared) {
- // Test applies only when there is a decoder delay, and the decoder will not
- // receive a config change before outputting its first frame. Parallel
- // decoding is also disabled in this test case, for readability and simplicity
- // of the unit test.
- if (GetParam().decoding_delay == 0 ||
- GetParam().decoding_delay > kNumBuffersInOneConfig ||
- GetParam().parallel_decoding > 1) {
- return;
- }
- Initialize();
- // Block on demuxer read and decoder decode so we can step through.
- demuxer_stream_->HoldNextRead();
- decoder_->HoldDecode();
- ReadOneFrame();
- int demuxer_reads_satisfied = 0;
- // Send back and requests buffers until the next one would fill the decoder
- // delay.
- while (demuxer_reads_satisfied < GetParam().decoding_delay - 1) {
- // Send a buffer back.
- demuxer_stream_->SatisfyReadAndHoldNext();
- base::RunLoop().RunUntilIdle();
- ++demuxer_reads_satisfied;
- // Decode one buffer.
- decoder_->SatisfySingleDecode();
- base::RunLoop().RunUntilIdle();
- EXPECT_TRUE(pending_read_);
- EXPECT_EQ(demuxer_reads_satisfied,
- video_decoder_stream_->get_pending_buffers_size_for_testing());
- // No fallback buffers should be queued up yet.
- EXPECT_EQ(0,
- video_decoder_stream_->get_fallback_buffers_size_for_testing());
- }
- // Hold the init before triggering the error, to verify internal state.
- demuxer_stream_->SatisfyReadAndHoldNext();
- ++demuxer_reads_satisfied;
- decoder_->SimulateError();
- HoldDecoderInitOnSelection({1});
- HoldDecodeAfterSelection({1});
- base::RunLoop().RunUntilIdle();
- EXPECT_TRUE(pending_read_);
- EXPECT_EQ(demuxer_reads_satisfied,
- video_decoder_stream_->get_pending_buffers_size_for_testing());
- decoders_[1]->SatisfyInit();
- base::RunLoop().RunUntilIdle();
- ASSERT_EQ(GetDecoderId(1), decoder_->GetDecoderId());
- // Make sure the pending buffers have been transferred to fallback buffers.
- // One call to Decode() during the initialization process, so we expect one
- // buffer to already have been consumed from the fallback buffers.
- // Pending buffers should never go down (unless we encounter a config change)
- EXPECT_EQ(demuxer_reads_satisfied - 1,
- video_decoder_stream_->get_fallback_buffers_size_for_testing());
- EXPECT_EQ(demuxer_reads_satisfied,
- video_decoder_stream_->get_pending_buffers_size_for_testing());
- decoder_->SatisfyDecode();
- base::RunLoop().RunUntilIdle();
- // Make sure all buffers consumed by |decoders_| have come from the fallback.
- // Pending buffers should not have been cleared yet.
- EXPECT_EQ(0, video_decoder_stream_->get_fallback_buffers_size_for_testing());
- EXPECT_EQ(demuxer_reads_satisfied,
- video_decoder_stream_->get_pending_buffers_size_for_testing());
- EXPECT_TRUE(pending_read_);
- // Give the decoder one more buffer, enough to release a frame.
- demuxer_stream_->SatisfyReadAndHoldNext();
- base::RunLoop().RunUntilIdle();
- // New buffers should not have been added after the frame was released.
- EXPECT_EQ(video_decoder_stream_->get_pending_buffers_size_for_testing(), 0);
- EXPECT_FALSE(pending_read_);
- demuxer_stream_->SatisfyRead();
- // Confirm no frames were dropped.
- ReadAllFrames();
- }
- TEST_P(VideoDecoderStreamTest, FallbackDecoder_SelectedOnDecodeThenInitErrors) {
- Initialize();
- decoder_->SimulateError();
- FailDecoderInitOnSelection({1});
- ReadOneFrame();
- // Decoder 0 should be blocked, and decoder 1 fails to initialize, so
- // |video_decoder_stream_| should have fallen back to decoder 2.
- ASSERT_EQ(GetDecoderId(2), decoder_->GetDecoderId());
- ASSERT_FALSE(pending_read_);
- ASSERT_EQ(last_read_status_code_, DecoderStatus::Codes::kOk);
- // Can't check previously selected decoder(s) right now, they might have been
- // destroyed already.
- ASSERT_GT(decoder_->total_bytes_decoded(), 0);
- // Verify no frame was dropped.
- ReadAllFrames();
- }
- TEST_P(VideoDecoderStreamTest, FallbackDecoder_SelectedOnInitThenDecodeErrors) {
- FailDecoderInitOnSelection({0});
- Initialize();
- ASSERT_EQ(GetDecoderId(1), decoder_->GetDecoderId());
- ClearDecoderInitExpectations();
- decoder_->HoldDecode();
- ReadOneFrame();
- decoder_->SimulateError();
- base::RunLoop().RunUntilIdle();
- // |video_decoder_stream_| should have fallen back to decoder 2.
- ASSERT_EQ(GetDecoderId(2), decoder_->GetDecoderId());
- ASSERT_FALSE(pending_read_);
- ASSERT_EQ(last_read_status_code_, DecoderStatus::Codes::kOk);
- // Can't check previously selected decoder(s) right now, they might have been
- // destroyed already.
- ASSERT_GT(decoder_->total_bytes_decoded(), 0);
- // Verify no frame was dropped.
- ReadAllFrames();
- }
- TEST_P(VideoDecoderStreamTest,
- FallbackDecoder_NotSelectedOnMidstreamDecodeError) {
- Initialize();
- ReadOneFrame();
- // Successfully received a frame.
- EXPECT_FALSE(pending_read_);
- ASSERT_GT(decoder_->total_bytes_decoded(), 0);
- decoder_->SimulateError();
- // The error must surface from Read() as DECODE_ERROR.
- while (last_read_status_code_ == DecoderStatus::Codes::kOk) {
- ReadOneFrame();
- base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(pending_read_);
- }
- // Verify the error was surfaced, rather than falling back to other decoders.
- ASSERT_EQ(GetDecoderId(0), decoder_->GetDecoderId());
- EXPECT_FALSE(pending_read_);
- EXPECT_NE(last_read_status_code_, DecoderStatus::Codes::kOk);
- EXPECT_NE(last_read_status_code_, DecoderStatus::Codes::kAborted);
- }
- TEST_P(VideoDecoderStreamTest, DecoderErrorWhenNotReading) {
- Initialize();
- decoder_->HoldDecode();
- ReadOneFrame();
- EXPECT_TRUE(pending_read_);
- // Satisfy decode requests until we get the first frame out.
- while (pending_read_) {
- decoder_->SatisfySingleDecode();
- base::RunLoop().RunUntilIdle();
- }
- // Trigger an error in the decoding.
- decoder_->SimulateError();
- // The error must surface from Read() as DECODE_ERROR.
- while (last_read_status_code_ == DecoderStatus::Codes::kOk) {
- ReadOneFrame();
- base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(pending_read_);
- }
- EXPECT_NE(last_read_status_code_, DecoderStatus::Codes::kOk);
- EXPECT_NE(last_read_status_code_, DecoderStatus::Codes::kAborted);
- }
- TEST_P(VideoDecoderStreamTest, ReinitializeFailure_Once) {
- Initialize();
- decoder_->SimulateFailureToInit();
- ReadUntilDecoderReinitialized();
- // Should have fallen back to a new instance of decoder 0.
- ASSERT_EQ(GetDecoderId(0), decoder_->GetDecoderId());
- ReadAllFrames();
- ASSERT_GT(decoder_->total_bytes_decoded(), 0);
- }
- TEST_P(VideoDecoderStreamTest, ReinitializeFailure_Twice) {
- Initialize();
- // Trigger reinitialization error, and fallback to a new instance.
- decoder_->SimulateFailureToInit();
- ReadUntilDecoderReinitialized();
- ASSERT_EQ(GetDecoderId(0), decoder_->GetDecoderId());
- ReadOneFrame();
- // Trigger reinitialization error again. Since a frame was output, this will
- // be a new instance of decoder 0 again.
- decoder_->SimulateFailureToInit();
- ReadUntilDecoderReinitialized();
- ASSERT_EQ(GetDecoderId(0), decoder_->GetDecoderId());
- ReadAllFrames();
- }
- TEST_P(VideoDecoderStreamTest, ReinitializeFailure_OneUnsupportedDecoder) {
- Initialize();
- // The current decoder will fail to reinitialize.
- decoder_->SimulateFailureToInit();
- // Decoder 1 will also fail to initialize on decoder selection.
- FailDecoderInitOnSelection({0, 1});
- ReadUntilDecoderReinitialized();
- // As a result, decoder 2 will be selected.
- ASSERT_EQ(GetDecoderId(2), decoder_->GetDecoderId());
- ReadAllFrames();
- }
- TEST_P(VideoDecoderStreamTest, ReinitializeFailure_NoSupportedDecoder) {
- Initialize();
- // The current decoder will fail to reinitialize, triggering decoder
- // selection.
- decoder_->SimulateFailureToInit();
- // All of the decoders will fail in decoder selection.
- FailDecoderInitOnSelection({0, 1, 2});
- ReadUntilDecoderReinitialized();
- // The error will surface from Read() as DECODE_ERROR.
- while (last_read_status_code_ == DecoderStatus::Codes::kOk) {
- ReadOneFrame();
- base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(pending_read_);
- }
- EXPECT_NE(last_read_status_code_, DecoderStatus::Codes::kOk);
- EXPECT_NE(last_read_status_code_, DecoderStatus::Codes::kAborted);
- }
- TEST_P(VideoDecoderStreamTest, Destroy_DuringFallbackDecoderSelection) {
- Initialize();
- decoder_->SimulateFailureToInit();
- EnterPendingState(DECODER_REINIT);
- HoldDecoderInitOnSelection({1});
- SatisfyPendingCallback(DECODER_REINIT);
- }
- } // namespace media
|