From 938025acb1293e2dd2b1c7860fbd6f5d2fa1a143 Mon Sep 17 00:00:00 2001 From: Thomas Goyne Date: Sun, 23 Mar 2014 19:30:03 -0700 Subject: [PATCH] Redesign AudioProviderFactory Register functions which create each type of provider rather than the provider types themselves so that the concrete types don't need to be publicly exposed, and use a static list of providers rather than registering them at runtime. --- build/Aegisub/Aegisub.vcxproj | 7 -- build/Aegisub/Aegisub.vcxproj.filters | 21 ---- src/audio_controller.cpp | 1 - src/audio_provider.cpp | 134 ++++++++++++++------------ src/audio_provider_avs.cpp | 24 ++++- src/audio_provider_avs.h | 53 ---------- src/audio_provider_convert.cpp | 3 +- src/audio_provider_convert.h | 27 ------ src/audio_provider_dummy.cpp | 50 ++++++---- src/audio_provider_dummy.h | 43 --------- src/audio_provider_ffmpegsource.cpp | 32 +++++- src/audio_provider_ffmpegsource.h | 57 ----------- src/audio_provider_hd.cpp | 74 ++++++++------ src/audio_provider_hd.h | 32 ------ src/audio_provider_lock.cpp | 32 ++++-- src/audio_provider_lock.h | 30 ------ src/audio_provider_ram.cpp | 66 ++++++++----- src/audio_provider_ram.h | 57 ----------- src/include/aegisub/audio_provider.h | 7 +- src/plugin_manager.cpp | 2 - 20 files changed, 263 insertions(+), 489 deletions(-) delete mode 100644 src/audio_provider_avs.h delete mode 100644 src/audio_provider_convert.h delete mode 100644 src/audio_provider_dummy.h delete mode 100644 src/audio_provider_ffmpegsource.h delete mode 100644 src/audio_provider_hd.h delete mode 100644 src/audio_provider_lock.h delete mode 100644 src/audio_provider_ram.h diff --git a/build/Aegisub/Aegisub.vcxproj b/build/Aegisub/Aegisub.vcxproj index b49eb637f..c27d76d5a 100644 --- a/build/Aegisub/Aegisub.vcxproj +++ b/build/Aegisub/Aegisub.vcxproj @@ -117,13 +117,6 @@ - - - - - - - diff --git a/build/Aegisub/Aegisub.vcxproj.filters b/build/Aegisub/Aegisub.vcxproj.filters index b65314ee3..74d10b631 100644 --- a/build/Aegisub/Aegisub.vcxproj.filters +++ b/build/Aegisub/Aegisub.vcxproj.filters @@ -177,24 +177,6 @@ ASS - - Audio\Providers - - - Audio\Providers - - - Audio\Providers - - - Audio\Providers - - - Audio\Providers - - - Audio\Providers - Audio\UI @@ -645,9 +627,6 @@ Main UI\Edit box - - Audio\Providers - Utilities\UI utilities diff --git a/src/audio_controller.cpp b/src/audio_controller.cpp index 5d35a6bca..011a06232 100644 --- a/src/audio_controller.cpp +++ b/src/audio_controller.cpp @@ -37,7 +37,6 @@ #include "audio_controller.h" #include "ass_file.h" -#include "audio_provider_dummy.h" #include "audio_timing.h" #include "compat.h" #include "include/aegisub/audio_player.h" diff --git a/src/audio_provider.cpp b/src/audio_provider.cpp index 6b013c1bf..577917bb5 100644 --- a/src/audio_provider.cpp +++ b/src/audio_provider.cpp @@ -34,13 +34,7 @@ #include "config.h" -#include "audio_provider_avs.h" -#include "audio_provider_convert.h" -#include "audio_provider_dummy.h" -#include "audio_provider_ffmpegsource.h" -#include "audio_provider_hd.h" -#include "audio_provider_lock.h" -#include "audio_provider_ram.h" +#include "include/aegisub/audio_provider.h" #include "audio_controller.h" #include "dialog_progress.h" @@ -53,9 +47,6 @@ #include #include -// Defined in audio_provider_pcm.cpp -std::unique_ptr CreatePCMAudioProvider(agi::fs::path const& filename); - void AudioProvider::GetAudioWithVolume(void *buf, int64_t start, int64_t count, double volume) const { GetAudio(buf, start, count); @@ -110,68 +101,96 @@ void AudioProvider::GetAudio(void *buf, int64_t start, int64_t count) const { } } +std::unique_ptr CreateDummyAudioProvider(agi::fs::path const& filename); +std::unique_ptr CreatePCMAudioProvider(agi::fs::path const& filename); +std::unique_ptr CreateAvisynthAudioProvider(agi::fs::path const& filename); +std::unique_ptr CreateFFmpegSourceAudioProvider(agi::fs::path const& filename); + +std::unique_ptr CreateConvertAudioProvider(std::unique_ptr source_provider); +std::unique_ptr CreateLockAudioProvider(std::unique_ptr source_provider); +std::unique_ptr CreateHDAudioProvider(std::unique_ptr source_provider, agi::BackgroundRunner *br); +std::unique_ptr CreateRAMAudioProvider(std::unique_ptr source_provider, agi::BackgroundRunner *br); + namespace { -struct provider_creator { + using factory_fn = std::unique_ptr (*)(agi::fs::path const&); + struct factory { + const char *name; + factory_fn create; + bool hidden; + }; + + const factory providers[] = { + {"Dummy", CreateDummyAudioProvider, true}, + {"PCM", CreatePCMAudioProvider, true}, +#ifdef WITH_FFMS2 + {"FFmpegSource", CreateFFmpegSourceAudioProvider, false}, +#endif +#ifdef WITH_AVISYNTH + {"Avisynth", CreateAvisynthAudioProvider, false}, +#endif + }; +} + +std::vector AudioProviderFactory::GetClasses() { + std::vector list; + for (auto const& provider : providers) { + if (!provider.hidden) + list.push_back(provider.name); + } + return list; +} + +std::unique_ptr AudioProviderFactory::GetProvider(agi::fs::path const& filename) { + auto preferred = OPT_GET("Audio/Provider")->GetString(); + std::vector sorted; + auto preferred_insertion_point = sorted.end(); + for (auto const& provider : providers) { + if (provider.hidden) + sorted.push_back(&provider); + else if (preferred_insertion_point == sorted.end()) { + sorted.push_back(&provider); + preferred_insertion_point = prev(sorted.end()); + } + else if (preferred == provider.name) + sorted.insert(preferred_insertion_point, &provider); + else + sorted.push_back(&provider); + } + + std::unique_ptr provider; bool found_file = false; bool found_audio = false; std::string msg; - template - std::unique_ptr try_create(std::string const& name, Factory&& create) { + for (auto const& factory : sorted) { try { - std::unique_ptr provider = create(); - if (provider) - LOG_I("audio_provider") << "Using audio provider: " << name; - return provider; + provider = factory->create(filename); + if (!provider) continue; + LOG_I("audio_provider") << "Using audio provider: " << factory->name; + break; } catch (agi::fs::FileNotFound const& err) { LOG_D("audio_provider") << err.GetChainedMessage(); - msg += name + ": " + err.GetMessage() + " not found.\n"; + msg += std::string(factory->name) + ": " + err.GetMessage() + " not found.\n"; } catch (agi::AudioDataNotFoundError const& err) { LOG_D("audio_provider") << err.GetChainedMessage(); found_file = true; - msg += name + ": " + err.GetChainedMessage() + "\n"; + msg += std::string(factory->name) + ": " + err.GetChainedMessage() + "\n"; } catch (agi::AudioOpenError const& err) { LOG_D("audio_provider") << err.GetChainedMessage(); found_audio = true; found_file = true; - msg += name + ": " + err.GetChainedMessage() + "\n"; - } - - return nullptr; - } -}; -} - -std::unique_ptr AudioProviderFactory::GetProvider(agi::fs::path const& filename) { - provider_creator creator; - std::unique_ptr provider; - - provider = creator.try_create("Dummy audio provider", [&]() { - return agi::util::make_unique(filename); - }); - - // Try a PCM provider first - if (!provider) - provider = creator.try_create("PCM audio provider", [&]() { return CreatePCMAudioProvider(filename); }); - - if (!provider) { - std::vector list = GetClasses(OPT_GET("Audio/Provider")->GetString()); - if (list.empty()) throw agi::NoAudioProvidersError("No audio providers are available.", nullptr); - - for (auto const& name : list) { - provider = creator.try_create(name, [&]() { return Create(name, filename); }); - if (provider) break; + msg += std::string(factory->name) + ": " + err.GetChainedMessage() + "\n"; } } if (!provider) { - if (creator.found_audio) - throw agi::AudioProviderOpenError(creator.msg, nullptr); - if (creator.found_file) - throw agi::AudioDataNotFoundError(creator.msg, nullptr); + if (found_audio) + throw agi::AudioProviderOpenError(msg, nullptr); + if (found_file) + throw agi::AudioDataNotFoundError(msg, nullptr); throw agi::fs::FileNotFound(filename); } @@ -184,24 +203,15 @@ std::unique_ptr AudioProviderFactory::GetProvider(agi::fs::path c // Change provider to RAM/HD cache if needed int cache = OPT_GET("Audio/Cache/Type")->GetInt(); if (!cache || !needsCache) - return agi::util::make_unique(std::move(provider)); + return CreateLockAudioProvider(std::move(provider)); DialogProgress progress(wxGetApp().frame, _("Load audio")); // Convert to RAM - if (cache == 1) return agi::util::make_unique(std::move(provider), &progress); + if (cache == 1) return CreateRAMAudioProvider(std::move(provider), &progress); // Convert to HD - if (cache == 2) return agi::util::make_unique(std::move(provider), &progress); + if (cache == 2) return CreateHDAudioProvider(std::move(provider), &progress); throw agi::AudioCacheOpenError("Unknown caching method", nullptr); } - -void AudioProviderFactory::RegisterProviders() { -#ifdef WITH_AVISYNTH - Register("Avisynth"); -#endif -#ifdef WITH_FFMS2 - Register("FFmpegSource"); -#endif -} diff --git a/src/audio_provider_avs.cpp b/src/audio_provider_avs.cpp index 9dba5c098..a46d6d123 100644 --- a/src/audio_provider_avs.cpp +++ b/src/audio_provider_avs.cpp @@ -35,8 +35,10 @@ #include "config.h" #ifdef WITH_AVISYNTH -#include "audio_provider_avs.h" +#include "include/aegisub/audio_provider.h" +#include "avisynth.h" +#include "avisynth_wrap.h" #include "audio_controller.h" #include "options.h" #include "utils.h" @@ -45,9 +47,24 @@ #include #include #include +#include #include +namespace { +class AvisynthAudioProvider final : public AudioProvider { + AviSynthWrapper avs_wrapper; + PClip clip; + + void LoadFromClip(AVSValue clip); + void FillBuffer(void *buf, int64_t start, int64_t count) const; + +public: + AvisynthAudioProvider(agi::fs::path const& filename); + + bool NeedsCache() const override { return true; } +}; + AvisynthAudioProvider::AvisynthAudioProvider(agi::fs::path const& filename) { this->filename = filename; @@ -128,4 +145,9 @@ void AvisynthAudioProvider::LoadFromClip(AVSValue clip) { void AvisynthAudioProvider::FillBuffer(void *buf, int64_t start, int64_t count) const { clip->GetAudio(buf, start, count, avs_wrapper.GetEnv()); } +} + +std::unique_ptr CreateAvisynthAudioProvider(agi::fs::path const& file) { + return agi::util::make_unique(file); +} #endif diff --git a/src/audio_provider_avs.h b/src/audio_provider_avs.h deleted file mode 100644 index fe4e7c3a2..000000000 --- a/src/audio_provider_avs.h +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2005-2006, Rodrigo Braz Monteiro, Fredrik Mellbin -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name of the Aegisub Group nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -// -// Aegisub Project http://www.aegisub.org/ - -/// @file audio_provider_avs.h -/// @see audio_provider_avs.cpp -/// @ingroup audio_input -/// - -#ifdef WITH_AVISYNTH -#include "include/aegisub/audio_provider.h" - -#include "avisynth.h" -#include "avisynth_wrap.h" - -class AvisynthAudioProvider final : public AudioProvider { - AviSynthWrapper avs_wrapper; - PClip clip; - - void LoadFromClip(AVSValue clip); - void FillBuffer(void *buf, int64_t start, int64_t count) const; - -public: - AvisynthAudioProvider(agi::fs::path const& filename); - - bool NeedsCache() const { return true; } -}; -#endif diff --git a/src/audio_provider_convert.cpp b/src/audio_provider_convert.cpp index 4e2c9b98e..5592db5ce 100644 --- a/src/audio_provider_convert.cpp +++ b/src/audio_provider_convert.cpp @@ -21,10 +21,9 @@ #include "config.h" -#include "audio_provider_convert.h" +#include "include/aegisub/audio_provider.h" #include "audio_controller.h" -#include "include/aegisub/audio_provider.h" #include #include diff --git a/src/audio_provider_convert.h b/src/audio_provider_convert.h deleted file mode 100644 index a66dc6f5a..000000000 --- a/src/audio_provider_convert.h +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) 2011, Thomas Goyne -// -// Permission to use, copy, modify, and distribute this software for any -// purpose with or without fee is hereby granted, provided that the above -// copyright notice and this permission notice appear in all copies. -// -// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -// -// Aegisub Project http://www.aegisub.org/ - -/// @file audio_provider_convert.h -/// @see audio_provider_convert.cpp -/// @ingroup audio_input -/// - -#include - -class AudioProvider; - -/// Get an audio provider which supplies audio in a format supported by Aegisub's players -std::unique_ptr CreateConvertAudioProvider(std::unique_ptr source_provider); diff --git a/src/audio_provider_dummy.cpp b/src/audio_provider_dummy.cpp index d9f60d6bb..f308ece72 100644 --- a/src/audio_provider_dummy.cpp +++ b/src/audio_provider_dummy.cpp @@ -34,10 +34,10 @@ #include "config.h" -#include "audio_provider_dummy.h" -#include "utils.h" +#include "include/aegisub/audio_provider.h" #include +#include #include @@ -61,25 +61,35 @@ * in every channel even if one would be LFE. * "ln", length of signal in samples. ln/sr gives signal length in seconds. */ -DummyAudioProvider::DummyAudioProvider(agi::fs::path const& uri) { - if (!boost::starts_with(uri.string(), "dummy-audio:")) - throw agi::fs::FileNotFound(std::string("Not a dummy audio URI")); - noise = boost::contains(uri.string(), ":noise?"); - channels = 1; - sample_rate = 44100; - bytes_per_sample = 2; - float_samples = false; - num_samples = (int64_t)5*30*60*1000 * sample_rate / 1000; +namespace { +class DummyAudioProvider final : public AudioProvider { + bool noise; + void FillBuffer(void *buf, int64_t start, int64_t count) const override { + if (noise) { + auto workbuf = static_cast(buf); + while (count-- > 0) + *workbuf++ = (rand() - RAND_MAX/2) * 10000 / RAND_MAX; + } + else { + memset(buf, 0, count * bytes_per_sample); + } + } + +public: + DummyAudioProvider(agi::fs::path const& uri) { + noise = boost::contains(uri.string(), ":noise?"); + channels = 1; + sample_rate = 44100; + bytes_per_sample = 2; + float_samples = false; + num_samples = (int64_t)5*30*60*1000 * sample_rate / 1000; + } +}; } -void DummyAudioProvider::FillBuffer(void *buf, int64_t, int64_t count) const { - if (noise) { - short *workbuf = (short*)buf; - while (count-- > 0) - *workbuf++ = (rand() - RAND_MAX/2) * 10000 / RAND_MAX; - } - else { - memset(buf, 0, count * bytes_per_sample); - } +std::unique_ptr CreateDummyAudioProvider(agi::fs::path const& file) { + if (!boost::starts_with(file.string(), "dummy-audio:")) + return {}; + return agi::util::make_unique(file); } diff --git a/src/audio_provider_dummy.h b/src/audio_provider_dummy.h deleted file mode 100644 index 196e43ab5..000000000 --- a/src/audio_provider_dummy.h +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) 2006, Niels Martin Hansen -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name of the Aegisub Group nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -// -// Aegisub Project http://www.aegisub.org/ - -/// @file audio_provider_dummy.h -/// @see audio_provider_dummy.cpp -/// @ingroup audio_input -/// - -#include "include/aegisub/audio_provider.h" - -class DummyAudioProvider final : public AudioProvider { - bool noise; - void FillBuffer(void *buf, int64_t start, int64_t count) const override; - -public: - DummyAudioProvider(agi::fs::path const& uri); -}; diff --git a/src/audio_provider_ffmpegsource.cpp b/src/audio_provider_ffmpegsource.cpp index 534d49c84..1cf95f93c 100644 --- a/src/audio_provider_ffmpegsource.cpp +++ b/src/audio_provider_ffmpegsource.cpp @@ -35,15 +35,37 @@ #include "config.h" #ifdef WITH_FFMS2 -#include "audio_provider_ffmpegsource.h" +#include "include/aegisub/audio_provider.h" #include "audio_controller.h" +#include "ffmpegsource_common.h" #include "options.h" #include +#include #include +namespace { +class FFmpegSourceAudioProvider final : public AudioProvider, FFmpegSourceProvider { + /// audio source object + agi::scoped_holder AudioSource; + + mutable char FFMSErrMsg[1024]; ///< FFMS error message + mutable FFMS_ErrorInfo ErrInfo; ///< FFMS error codes/messages + + void LoadAudio(agi::fs::path const& filename); + void FillBuffer(void *Buf, int64_t Start, int64_t Count) const override { + if (FFMS_GetAudio(AudioSource, Buf, Start, Count, &ErrInfo)) + throw AudioDecodeError(std::string("Failed to get audio samples: ") + ErrInfo.Buffer); + } + +public: + FFmpegSourceAudioProvider(agi::fs::path const& filename); + + bool NeedsCache() const override { return true; } +}; + /// @brief Constructor /// @param filename The filename to open FFmpegSourceAudioProvider::FFmpegSourceAudioProvider(agi::fs::path const& filename) try @@ -182,8 +204,10 @@ void FFmpegSourceAudioProvider::LoadAudio(agi::fs::path const& filename) { #endif } -void FFmpegSourceAudioProvider::FillBuffer(void *Buf, int64_t Start, int64_t Count) const { - if (FFMS_GetAudio(AudioSource, Buf, Start, Count, &ErrInfo)) - throw AudioDecodeError(std::string("Failed to get audio samples: ") + ErrInfo.Buffer); } + +std::unique_ptr CreateFFmpegSourceAudioProvider(agi::fs::path const& file) { + return agi::util::make_unique(file); +} + #endif /* WITH_FFMS2 */ diff --git a/src/audio_provider_ffmpegsource.h b/src/audio_provider_ffmpegsource.h deleted file mode 100644 index 184d39251..000000000 --- a/src/audio_provider_ffmpegsource.h +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2008-2009, Karl Blomster -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name of the Aegisub Group nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -// -// Aegisub Project http://www.aegisub.org/ - -/// @file audio_provider_ffmpegsource.h -/// @see audio_provider_ffmpegsource.cpp -/// @ingroup audio_input ffms -/// - -#ifdef WITH_FFMS2 -#include "include/aegisub/audio_provider.h" - -#include "ffmpegsource_common.h" - -/// @class FFmpegSourceAudioProvider -/// @brief Implements audio loading with the FFMS library. -class FFmpegSourceAudioProvider final : public AudioProvider, FFmpegSourceProvider { - /// audio source object - agi::scoped_holder AudioSource; - - mutable char FFMSErrMsg[1024]; ///< FFMS error message - mutable FFMS_ErrorInfo ErrInfo; ///< FFMS error codes/messages - - void LoadAudio(agi::fs::path const& filename); - void FillBuffer(void *buf, int64_t start, int64_t count) const override; - -public: - FFmpegSourceAudioProvider(agi::fs::path const& filename); - - bool NeedsCache() const override { return true; } -}; -#endif diff --git a/src/audio_provider_hd.cpp b/src/audio_provider_hd.cpp index 611ab9976..4c7f31e25 100644 --- a/src/audio_provider_hd.cpp +++ b/src/audio_provider_hd.cpp @@ -16,7 +16,7 @@ #include "config.h" -#include "audio_provider_hd.h" +#include "include/aegisub/audio_provider.h" #include "audio_controller.h" #include "compat.h" @@ -33,43 +33,53 @@ #include #include #include +#include -HDAudioProvider::HDAudioProvider(std::unique_ptr src, agi::BackgroundRunner *br) -: AudioProviderWrapper(std::move(src)) -{ - auto path = OPT_GET("Audio/Cache/HD/Location")->GetString(); - if (path == "default") - path = "?temp"; - auto cache_dir = config::path->MakeAbsolute(config::path->Decode(path), "?temp"); +namespace { +class HDAudioProvider final : public AudioProviderWrapper { + std::unique_ptr file; - auto bps = bytes_per_sample * channels; + void FillBuffer(void *buf, int64_t start, int64_t count) const override { + start *= channels * bytes_per_sample; + count *= channels * bytes_per_sample; + memcpy(buf, file->read(start, count), count); + } - // Check free space - if ((uint64_t)num_samples * bps > agi::fs::FreeSpace(cache_dir)) - throw agi::AudioCacheOpenError("Not enough free disk space in " + cache_dir.string() + " to cache the audio", nullptr); +public: + HDAudioProvider(std::unique_ptr src, agi::BackgroundRunner *br) + : AudioProviderWrapper(std::move(src)) + { + auto path = OPT_GET("Audio/Cache/HD/Location")->GetString(); + if (path == "default") + path = "?temp"; + auto cache_dir = config::path->MakeAbsolute(config::path->Decode(path), "?temp"); - auto filename = str(boost::format("audio-%lld-%lld") - % (long long)time(nullptr) - % (long long)boost::interprocess::ipcdetail::get_current_process_id()); + auto bps = bytes_per_sample * channels; - file = agi::util::make_unique(cache_dir / filename, num_samples * bps); - br->Run([&] (agi::ProgressSink *ps) { - ps->SetMessage(from_wx(_("Reading to Hard Disk cache"))); + // Check free space + if ((uint64_t)num_samples * bps > agi::fs::FreeSpace(cache_dir)) + throw agi::AudioCacheOpenError("Not enough free disk space in " + cache_dir.string() + " to cache the audio", nullptr); - int64_t block = 65536; - for (int64_t i = 0; i < num_samples; i += block) { - block = std::min(block, num_samples - i); - source->GetAudio(file->write(i * bps, block * bps), i, block); - ps->SetProgress(i, num_samples); - if (ps->IsCancelled()) return; - } - }); + auto filename = str(boost::format("audio-%lld-%lld") + % (long long)time(nullptr) + % (long long)boost::interprocess::ipcdetail::get_current_process_id()); + + file = agi::util::make_unique(cache_dir / filename, num_samples * bps); + br->Run([&] (agi::ProgressSink *ps) { + ps->SetMessage(from_wx(_("Reading to Hard Disk cache"))); + + int64_t block = 65536; + for (int64_t i = 0; i < num_samples; i += block) { + block = std::min(block, num_samples - i); + source->GetAudio(file->write(i * bps, block * bps), i, block); + ps->SetProgress(i, num_samples); + if (ps->IsCancelled()) return; + } + }); + } +}; } -HDAudioProvider::~HDAudioProvider() { } - -void HDAudioProvider::FillBuffer(void *buf, int64_t start, int64_t count) const { - start *= channels * bytes_per_sample; - count *= channels * bytes_per_sample; - memcpy(buf, file->read(start, count), count); +std::unique_ptr CreateHDAudioProvider(std::unique_ptr src, agi::BackgroundRunner *br) { + return agi::util::make_unique(std::move(src), br); } diff --git a/src/audio_provider_hd.h b/src/audio_provider_hd.h deleted file mode 100644 index 549fd8fd0..000000000 --- a/src/audio_provider_hd.h +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) 2014, Thomas Goyne -// -// Permission to use, copy, modify, and distribute this software for any -// purpose with or without fee is hereby granted, provided that the above -// copyright notice and this permission notice appear in all copies. -// -// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -// -// Aegisub Project http://www.aegisub.org/ - -#include "include/aegisub/audio_provider.h" - -namespace agi { - class BackgroundRunner; - class temp_file_mapping; -} - -class HDAudioProvider final : public AudioProviderWrapper { - std::unique_ptr file; - - void FillBuffer(void *buf, int64_t start, int64_t count) const override; - -public: - HDAudioProvider(std::unique_ptr source, agi::BackgroundRunner *br); - ~HDAudioProvider(); -}; diff --git a/src/audio_provider_lock.cpp b/src/audio_provider_lock.cpp index d4ecbdf2c..ed82755e9 100644 --- a/src/audio_provider_lock.cpp +++ b/src/audio_provider_lock.cpp @@ -18,14 +18,30 @@ #include "config.h" -#include "audio_provider_lock.h" +#include "include/aegisub/audio_provider.h" -LockAudioProvider::LockAudioProvider(std::unique_ptr src) -: AudioProviderWrapper(std::move(src)) -{ +#include + +#include +#include + +namespace { +class LockAudioProvider final : public AudioProviderWrapper { + mutable std::mutex mutex; + + void FillBuffer(void *buf, int64_t start, int64_t count) const override { + std::unique_lock lock(mutex); + source->GetAudio(buf, start, count); + } + +public: + LockAudioProvider(std::unique_ptr src) + : AudioProviderWrapper(std::move(src)) + { + } +}; } -void LockAudioProvider::FillBuffer(void *buf, int64_t start, int64_t count) const { - std::unique_lock lock(mutex); - source->GetAudio(buf, start, count); -} +std::unique_ptr CreateLockAudioProvider(std::unique_ptr src) { + return agi::util::make_unique(std::move(src)); +} \ No newline at end of file diff --git a/src/audio_provider_lock.h b/src/audio_provider_lock.h deleted file mode 100644 index e998b81c8..000000000 --- a/src/audio_provider_lock.h +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) 2012, Thomas Goyne -// -// Permission to use, copy, modify, and distribute this software for any -// purpose with or without fee is hereby granted, provided that the above -// copyright notice and this permission notice appear in all copies. -// -// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -/// @file audio_provider_lock.h -/// @brief An audio provider adapter for un-threadsafe audio providers -/// @ingroup audio_input - -#include "include/aegisub/audio_provider.h" - -#include -#include - -class LockAudioProvider final : public AudioProviderWrapper { - mutable std::mutex mutex; - - void FillBuffer(void *buf, int64_t start, int64_t count) const override; -public: - LockAudioProvider(std::unique_ptr source); -}; diff --git a/src/audio_provider_ram.cpp b/src/audio_provider_ram.cpp index fe88c1bf9..72450b059 100644 --- a/src/audio_provider_ram.cpp +++ b/src/audio_provider_ram.cpp @@ -34,44 +34,55 @@ #include "config.h" -#include "audio_provider_ram.h" +#include "include/aegisub/audio_provider.h" #include "audio_controller.h" #include "compat.h" -#include "options.h" -#include "utils.h" #include +#include + +#include +#include +#include + +namespace { #define CacheBits 22 #define CacheBlockSize (1 << CacheBits) -RAMAudioProvider::RAMAudioProvider(std::unique_ptr src, agi::BackgroundRunner *br) -: AudioProviderWrapper(std::move(src)) -{ - try { - blockcache.resize((source->GetNumSamples() * source->GetBytesPerSample() + CacheBlockSize - 1) >> CacheBits); - } - catch (std::bad_alloc const&) { - throw agi::AudioCacheOpenError("Couldn't open audio, not enough ram available.", nullptr); - } +class RAMAudioProvider final : public AudioProviderWrapper { +#ifdef _MSC_VER + boost::container::stable_vector blockcache; +#else + boost::container::stable_vector> blockcache; +#endif - br->Run(std::bind(&RAMAudioProvider::FillCache, this, source.get(), std::placeholders::_1)); -} + void FillBuffer(void *buf, int64_t start, int64_t count) const override; -void RAMAudioProvider::FillCache(AudioProvider *source, agi::ProgressSink *ps) { - ps->SetMessage(from_wx(_("Reading into RAM"))); - - int64_t readsize = CacheBlockSize / source->GetBytesPerSample(); - for (size_t i = 0; i < blockcache.size(); i++) { - ps->SetProgress(i + 1, blockcache.size()); - source->GetAudio(&blockcache[i][0], i * readsize, std::min(readsize, num_samples - i * readsize)); - - if (ps->IsCancelled()) { - return; +public: + RAMAudioProvider(std::unique_ptr src, agi::BackgroundRunner *br) + : AudioProviderWrapper(std::move(src)) + { + try { + blockcache.resize((source->GetNumSamples() * source->GetBytesPerSample() + CacheBlockSize - 1) >> CacheBits); } + catch (std::bad_alloc const&) { + throw agi::AudioCacheOpenError("Couldn't open audio, not enough ram available.", nullptr); + } + + br->Run([&](agi::ProgressSink *ps) { + ps->SetMessage(from_wx(_("Reading into RAM"))); + + int64_t readsize = CacheBlockSize / source->GetBytesPerSample(); + for (size_t i = 0; i < blockcache.size(); i++) { + if (ps->IsCancelled()) return; + ps->SetProgress(i + 1, blockcache.size()); + source->GetAudio(&blockcache[i][0], i * readsize, std::min(readsize, num_samples - i * readsize)); + } + }); } -} +}; void RAMAudioProvider::FillBuffer(void *buf, int64_t start, int64_t count) const { char *charbuf = static_cast(buf); @@ -90,3 +101,8 @@ void RAMAudioProvider::FillBuffer(void *buf, int64_t start, int64_t count) const bytesremaining -= readsize; } } +} + +std::unique_ptr CreateRAMAudioProvider(std::unique_ptr src, agi::BackgroundRunner *br) { + return agi::util::make_unique(std::move(src), br); +} diff --git a/src/audio_provider_ram.h b/src/audio_provider_ram.h deleted file mode 100644 index a9056d40d..000000000 --- a/src/audio_provider_ram.h +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2006, Rodrigo Braz Monteiro -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name of the Aegisub Group nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -// -// Aegisub Project http://www.aegisub.org/ - -/// @file audio_provider_ram.h -/// @see audio_provider_ram.cpp -/// @ingroup audio_input -/// - -#include "include/aegisub/audio_provider.h" - -#include -#include - -namespace agi { - class BackgroundRunner; - class ProgressSink; -} - -class RAMAudioProvider final : public AudioProviderWrapper { -#ifdef _MSC_VER - boost::container::stable_vector blockcache; -#else - boost::container::stable_vector> blockcache; -#endif - - void FillCache(AudioProvider *source, agi::ProgressSink *ps); - void FillBuffer(void *buf, int64_t start, int64_t count) const override; - -public: - RAMAudioProvider(std::unique_ptr source, agi::BackgroundRunner *br); -}; diff --git a/src/include/aegisub/audio_provider.h b/src/include/aegisub/audio_provider.h index fc1c22aaa..0de3e45de 100644 --- a/src/include/aegisub/audio_provider.h +++ b/src/include/aegisub/audio_provider.h @@ -34,8 +34,6 @@ #pragma once -#include "factory_manager.h" - #include #include @@ -90,9 +88,8 @@ public: } }; -class AudioProviderFactory final : public Factory { -public: - static void RegisterProviders(); +struct AudioProviderFactory { + static std::vector GetClasses(); /// Get a provider for the file /// @param filename URI to open diff --git a/src/plugin_manager.cpp b/src/plugin_manager.cpp index 07f8d7e52..dad56f01d 100644 --- a/src/plugin_manager.cpp +++ b/src/plugin_manager.cpp @@ -35,7 +35,6 @@ #include "config.h" #include "include/aegisub/audio_player.h" -#include "include/aegisub/audio_provider.h" #include "include/aegisub/spellchecker.h" #include "include/aegisub/subtitles_provider.h" #include "plugin_manager.h" @@ -46,7 +45,6 @@ void RegisterBuiltInPlugins() { VideoProviderFactory::RegisterProviders(); - AudioProviderFactory::RegisterProviders(); AudioPlayerFactory::RegisterProviders(); SubtitlesProviderFactory::RegisterProviders(); SpellCheckerFactory::RegisterProviders();