diff options
Diffstat (limited to 'dom/media/gtest/TestMediaFormatReader.cpp')
-rw-r--r-- | dom/media/gtest/TestMediaFormatReader.cpp | 248 |
1 files changed, 248 insertions, 0 deletions
diff --git a/dom/media/gtest/TestMediaFormatReader.cpp b/dom/media/gtest/TestMediaFormatReader.cpp new file mode 100644 index 000000000..ad222e8b8 --- /dev/null +++ b/dom/media/gtest/TestMediaFormatReader.cpp @@ -0,0 +1,248 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "gtest/gtest.h" +#include "mozilla/dom/HTMLMediaElement.h" +#include "mozilla/Preferences.h" +#include "mozilla/TaskQueue.h" +#include "ImageContainer.h" +#include "Layers.h" +#include "MediaData.h" +#include "MediaFormatReader.h" +#include "MP4Decoder.h" +#include "MockMediaDecoderOwner.h" +#include "MockMediaResource.h" +#include "VideoFrameContainer.h" + +using namespace mozilla; +using namespace mozilla::dom; + +class MockMP4Decoder : public MP4Decoder +{ +public: + MockMP4Decoder() + : MP4Decoder(new MockMediaDecoderOwner()) + {} + + // Avoid the assertion. + AbstractCanonical<media::NullableTimeUnit>* CanonicalDurationOrNull() override + { + return nullptr; + } +}; + +class MediaFormatReaderBinding +{ +public: + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaFormatReaderBinding); + RefPtr<MockMP4Decoder> mDecoder; + RefPtr<MockMediaResource> mResource; + RefPtr<MediaDecoderReader> mReader; + RefPtr<TaskQueue> mTaskQueue; + explicit MediaFormatReaderBinding(const char* aFileName = "gizmo.mp4") + : mDecoder(new MockMP4Decoder()) + , mResource(new MockMediaResource(aFileName)) + , mReader(new MediaFormatReader(mDecoder, + new MP4Demuxer(mResource), + new VideoFrameContainer( + (HTMLMediaElement*)(0x1), + layers::LayerManager::CreateImageContainer( + layers::ImageContainer::ASYNCHRONOUS)) + )) + , mTaskQueue(new TaskQueue(GetMediaThreadPool(MediaThreadType::PLAYBACK))) + { + } + + bool Init() { + // Init Resource. + nsresult rv = mResource->Open(nullptr); + if (NS_FAILED(rv)) { + return false; + } + mDecoder->SetResource(mResource); + // Init Reader. + rv = mReader->Init(); + if (NS_FAILED(rv)) { + return false; + } + return true; + } + + void OnMetadataReadAudio(MetadataHolder* aMetadata) + { + EXPECT_TRUE(aMetadata); + mReader->RequestAudioData() + ->Then(mReader->OwnerThread(), __func__, this, + &MediaFormatReaderBinding::OnAudioRawDataDemuxed, + &MediaFormatReaderBinding::OnNotDemuxed); + } + + void OnMetadataReadVideo(MetadataHolder* aMetadata) + { + EXPECT_TRUE(aMetadata); + mReader->RequestVideoData(true, 0) + ->Then(mReader->OwnerThread(), __func__, this, + &MediaFormatReaderBinding::OnVideoRawDataDemuxed, + &MediaFormatReaderBinding::OnNotDemuxed); + } + + void OnMetadataNotRead(const MediaResult& aError) { + EXPECT_TRUE(false); + ReaderShutdown(); + } + + void OnAudioRawDataDemuxed(MediaData* aAudioSample) + { + EXPECT_TRUE(aAudioSample); + EXPECT_EQ(MediaData::RAW_DATA, aAudioSample->mType); + ReaderShutdown(); + } + + void OnVideoRawDataDemuxed(MediaData* aVideoSample) + { + EXPECT_TRUE(aVideoSample); + EXPECT_EQ(MediaData::RAW_DATA, aVideoSample->mType); + ReaderShutdown(); + } + + void OnNotDemuxed(const MediaResult& aReason) + { + EXPECT_TRUE(false); + ReaderShutdown(); + } + + void ReaderShutdown() + { + RefPtr<MediaFormatReaderBinding> self = this; + mReader->Shutdown() + ->Then(mTaskQueue, __func__, + [self]() { + self->mTaskQueue->BeginShutdown(); + }, + [self]() { + EXPECT_TRUE(false); + self->mTaskQueue->BeginShutdown(); + }); //Then + } + template<class Function> + void RunTestAndWait(Function&& aFunction) + { + RefPtr<Runnable> r = NS_NewRunnableFunction(Forward<Function>(aFunction)); + mTaskQueue->Dispatch(r.forget()); + mTaskQueue->AwaitShutdownAndIdle(); + } +private: + ~MediaFormatReaderBinding() + { + mDecoder->Shutdown(); + } +}; + + +template <typename T> +T GetPref(const char* aPrefKey); + +template <> +bool GetPref<bool>(const char* aPrefKey) +{ + return Preferences::GetBool(aPrefKey); +} + +template <typename T> +void SetPref(const char* a, T value); + +template <> +void SetPref<bool>(const char* aPrefKey, bool aValue) +{ + Unused << Preferences::SetBool(aPrefKey, aValue); +} + +template <typename T> +class PreferencesRAII +{ +public: + explicit PreferencesRAII(const char* aPrefKey, T aValue) + : mPrefKey(aPrefKey) + { + mDefaultPref = GetPref<T>(aPrefKey); + SetPref(aPrefKey, aValue); + } + ~PreferencesRAII() + { + SetPref(mPrefKey, mDefaultPref); + } +private: + T mDefaultPref; + const char* mPrefKey; +}; + +TEST(MediaFormatReader, RequestAudioRawData) +{ + PreferencesRAII<bool> pref = + PreferencesRAII<bool>("media.use-blank-decoder", + true); + RefPtr<MediaFormatReaderBinding> b = new MediaFormatReaderBinding(); + if (!b->Init()) + { + EXPECT_TRUE(false); + // Stop the test since initialization failed. + return; + } + if (!b->mReader->IsDemuxOnlySupported()) + { + EXPECT_TRUE(false); + // Stop the test since the reader cannot support demuxed-only demand. + return; + } + // Switch to demuxed-only mode. + b->mReader->SetDemuxOnly(true); + // To ensure the MediaDecoderReader::InitializationTask and + // MediaDecoderReader::SetDemuxOnly can be done. + NS_ProcessNextEvent(); + auto testCase = [b]() { + InvokeAsync(b->mReader->OwnerThread(), + b->mReader.get(), + __func__, + &MediaDecoderReader::AsyncReadMetadata) + ->Then(b->mReader->OwnerThread(), __func__, b.get(), + &MediaFormatReaderBinding::OnMetadataReadAudio, + &MediaFormatReaderBinding::OnMetadataNotRead); + }; + b->RunTestAndWait(testCase); +} +TEST(MediaFormatReader, RequestVideoRawData) +{ + PreferencesRAII<bool> pref = + PreferencesRAII<bool>("media.use-blank-decoder", + true); + RefPtr<MediaFormatReaderBinding> b = new MediaFormatReaderBinding(); + if (!b->Init()) + { + EXPECT_TRUE(false); + // Stop the test since initialization failed. + return; + } + if (!b->mReader->IsDemuxOnlySupported()) + { + EXPECT_TRUE(false); + // Stop the test since the reader cannot support demuxed-only demand. + return; + } + // Switch to demuxed-only mode. + b->mReader->SetDemuxOnly(true); + // To ensure the MediaDecoderReader::InitializationTask and + // MediaDecoderReader::SetDemuxOnly can be done. + NS_ProcessNextEvent(); + auto testCase = [b]() { + InvokeAsync(b->mReader->OwnerThread(), + b->mReader.get(), + __func__, + &MediaDecoderReader::AsyncReadMetadata) + ->Then(b->mReader->OwnerThread(), __func__, b.get(), + &MediaFormatReaderBinding::OnMetadataReadVideo, + &MediaFormatReaderBinding::OnMetadataNotRead); + }; + b->RunTestAndWait(testCase); +} |