From 470f85d365e3c79f90cadb7a333494e612c9f275 Mon Sep 17 00:00:00 2001 From: Thomas Goyne Date: Mon, 24 Mar 2014 07:05:01 -0700 Subject: [PATCH] Convert VideoProviderManager to AudioProviderManager's new design --- build/Aegisub/Aegisub.vcxproj | 4 - build/Aegisub/Aegisub.vcxproj.filters | 12 --- src/dialog_video_details.cpp | 2 +- src/frame_main.cpp | 2 +- src/plugin_manager.cpp | 2 - src/threaded_frame_source.cpp | 1 + src/video_provider_avs.cpp | 46 +++++++- src/video_provider_avs.h | 71 ------------ src/video_provider_cache.cpp | 70 +++++++----- src/video_provider_cache.h | 53 --------- src/video_provider_dummy.cpp | 43 ++++---- src/video_provider_dummy.h | 14 --- src/video_provider_ffmpegsource.cpp | 45 +++++++- src/video_provider_ffmpegsource.h | 73 ------------- src/video_provider_manager.cpp | 132 +++++++++++++---------- src/video_provider_manager.h | 16 +-- src/video_provider_yuv4mpeg.cpp | 136 +++++++++++++++++++++-- src/video_provider_yuv4mpeg.h | 148 -------------------------- 18 files changed, 361 insertions(+), 509 deletions(-) delete mode 100644 src/video_provider_avs.h delete mode 100644 src/video_provider_cache.h delete mode 100644 src/video_provider_ffmpegsource.h delete mode 100644 src/video_provider_yuv4mpeg.h diff --git a/build/Aegisub/Aegisub.vcxproj b/build/Aegisub/Aegisub.vcxproj index c27d76d5a..c504b4202 100644 --- a/build/Aegisub/Aegisub.vcxproj +++ b/build/Aegisub/Aegisub.vcxproj @@ -243,12 +243,8 @@ - - - - diff --git a/build/Aegisub/Aegisub.vcxproj.filters b/build/Aegisub/Aegisub.vcxproj.filters index 74d10b631..02e122708 100644 --- a/build/Aegisub/Aegisub.vcxproj.filters +++ b/build/Aegisub/Aegisub.vcxproj.filters @@ -390,21 +390,9 @@ Video\UI - - Video\Providers - - - Video\Providers - - - Video\Providers - Video\Providers - - Video\Providers - Video\Providers diff --git a/src/dialog_video_details.cpp b/src/dialog_video_details.cpp index 66796c07b..0a871a176 100644 --- a/src/dialog_video_details.cpp +++ b/src/dialog_video_details.cpp @@ -39,8 +39,8 @@ #include "ass_time.h" #include "compat.h" #include "include/aegisub/context.h" +#include "include/aegisub/video_provider.h" #include "video_context.h" -#include "video_provider_manager.h" #include diff --git a/src/frame_main.cpp b/src/frame_main.cpp index 4c262760f..49f6a23c8 100644 --- a/src/frame_main.cpp +++ b/src/frame_main.cpp @@ -44,6 +44,7 @@ #include "include/aegisub/menu.h" #include "include/aegisub/toolbar.h" #include "include/aegisub/hotkey.h" +#include "include/aegisub/video_provider.h" #include "ass_file.h" #include "audio_controller.h" @@ -69,7 +70,6 @@ #include "video_box.h" #include "video_context.h" #include "video_display.h" -#include "video_provider_manager.h" #include "video_slider.h" #include diff --git a/src/plugin_manager.cpp b/src/plugin_manager.cpp index dad56f01d..7044e1ec5 100644 --- a/src/plugin_manager.cpp +++ b/src/plugin_manager.cpp @@ -38,13 +38,11 @@ #include "include/aegisub/spellchecker.h" #include "include/aegisub/subtitles_provider.h" #include "plugin_manager.h" -#include "video_provider_manager.h" #include "auto4_lua_factory.h" #include void RegisterBuiltInPlugins() { - VideoProviderFactory::RegisterProviders(); AudioPlayerFactory::RegisterProviders(); SubtitlesProviderFactory::RegisterProviders(); SpellCheckerFactory::RegisterProviders(); diff --git a/src/threaded_frame_source.cpp b/src/threaded_frame_source.cpp index 1334edaae..99f8850fb 100644 --- a/src/threaded_frame_source.cpp +++ b/src/threaded_frame_source.cpp @@ -25,6 +25,7 @@ #include "ass_file.h" #include "export_fixstyle.h" #include "include/aegisub/subtitles_provider.h" +#include "include/aegisub/video_provider.h" #include "video_frame.h" #include "video_provider_manager.h" diff --git a/src/video_provider_avs.cpp b/src/video_provider_avs.cpp index 8c2777102..e9bd50ce5 100644 --- a/src/video_provider_avs.cpp +++ b/src/video_provider_avs.cpp @@ -35,7 +35,7 @@ #include "config.h" #ifdef WITH_AVISYNTH -#include "video_provider_avs.h" +#include "include/aegisub/video_provider.h" #include "options.h" #include "video_frame.h" @@ -45,6 +45,7 @@ #include #include #include +#include #include #include @@ -53,8 +54,42 @@ #include #endif -AvisynthVideoProvider::AvisynthVideoProvider(agi::fs::path const& filename, std::string const& colormatrix) -{ +#define VideoFrame AVSVideoFrame +#include "avisynth.h" +#undef VideoFrame +#include "avisynth_wrap.h" + +namespace { +class AvisynthVideoProvider: public VideoProvider { + AviSynthWrapper avs; + std::string decoder_name; + agi::vfr::Framerate fps; + std::vector keyframes; + std::string warning; + std::string colorspace; + + PClip RGB32Video; + VideoInfo vi; + + AVSValue Open(agi::fs::path const& filename); + +public: + AvisynthVideoProvider(agi::fs::path const& filename, std::string const& colormatrix); + + std::shared_ptr GetFrame(int n); + + int GetFrameCount() const override { return vi.num_frames; } + agi::vfr::Framerate GetFPS() const override { return fps; } + int GetWidth() const override { return vi.width; } + int GetHeight() const override { return vi.height; } + double GetDAR() const override { return 0; } + std::vector GetKeyFrames() const override { return keyframes; } + std::string GetWarning() const override { return warning; } + std::string GetDecoderName() const override { return decoder_name; } + std::string GetColorSpace() const override { return colorspace; } +}; + +AvisynthVideoProvider::AvisynthVideoProvider(agi::fs::path const& filename, std::string const& colormatrix) { agi::acs::CheckFileRead(filename); std::lock_guard lock(avs.GetMutex()); @@ -273,4 +308,9 @@ std::shared_ptr AvisynthVideoProvider::GetFrame(int n) { auto frame = RGB32Video->GetFrame(n, avs.GetEnv()); return std::make_shared(frame->GetReadPtr(), frame->GetRowSize() / 4, frame->GetHeight(), frame->GetPitch(), true); } +} + +std::unique_ptr CreateAvisynthVideoProvider(agi::fs::path const& path, std::string const& colormatrix) { + return agi::util::make_unique(path, colormatrix); +} #endif // HAVE_AVISYNTH diff --git a/src/video_provider_avs.h b/src/video_provider_avs.h deleted file mode 100644 index 93942e338..000000000 --- a/src/video_provider_avs.h +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) 2006, 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 video_provider_avs.h -/// @see video_provider_avs.cpp -/// @ingroup video_input -/// - -#ifdef WITH_AVISYNTH -#include "include/aegisub/video_provider.h" - -#define VideoFrame AVSVideoFrame -#include "avisynth.h" -#undef VideoFrame -#include "avisynth_wrap.h" - -class AvisynthVideoProvider: public VideoProvider { - AviSynthWrapper avs; - std::string decoder_name; - agi::vfr::Framerate fps; - std::vector keyframes; - std::string warning; - std::string colorspace; - - PClip RGB32Video; - VideoInfo vi; - - AVSValue Open(agi::fs::path const& filename); - -public: - AvisynthVideoProvider(agi::fs::path const& filename, std::string const& colormatrix); - - std::shared_ptr GetFrame(int n); - - int GetFrameCount() const { return vi.num_frames; } - agi::vfr::Framerate GetFPS() const { return fps; } - int GetWidth() const { return vi.width; } - int GetHeight() const { return vi.height; } - double GetDAR() const { return 0; } - std::vector GetKeyFrames() const { return keyframes; } - std::string GetWarning() const { return warning; } - std::string GetDecoderName() const { return decoder_name; } - std::string GetColorSpace() const { return colorspace; } -}; -#endif diff --git a/src/video_provider_cache.cpp b/src/video_provider_cache.cpp index a56e552fd..69a03dd7f 100644 --- a/src/video_provider_cache.cpp +++ b/src/video_provider_cache.cpp @@ -16,25 +16,16 @@ #include "config.h" -#include "video_provider_cache.h" +#include "include/aegisub/video_provider.h" #include "options.h" #include "video_frame.h" -#include -#include +#include -#if BOOST_VERSION <= 105200 -// Compilation fails without this with boost 1.52. I have no idea why. -static bool operator==(VideoFrame const& a, VideoFrame const& b) { - return a.width == b.width - && a.height == b.height - && a.pitch == b.pitch - && a.flipped == b.flipped - && a.data == b.data; -} -#endif +#include +namespace { /// A video frame and its frame number struct CachedFrame final : public VideoFrame { int frame_number; @@ -46,29 +37,47 @@ struct CachedFrame final : public VideoFrame { } }; -VideoProviderCache::VideoProviderCache(std::unique_ptr parent) -: master(std::move(parent)) -, max_cache_size(OPT_GET("Provider/Video/Cache/Size")->GetInt() << 20) // convert MB to bytes -{ -} +/// @class VideoProviderCache +/// @brief A wrapper around a video provider which provides LRU caching +class VideoProviderCache final : public VideoProvider { + /// The source provider to get frames from + std::unique_ptr master; -VideoProviderCache::~VideoProviderCache() { -} + /// @brief Maximum size of the cache in bytes + /// + /// Note that this is a soft limit. The cache stops allocating new frames + /// once it has exceeded the limit, but it never tries to shrink + const size_t max_cache_size; + + /// Cache of video frames with the most recently used ones at the front + std::list cache; + +public: + VideoProviderCache(std::unique_ptr master) + : master(std::move(master)) + , max_cache_size(OPT_GET("Provider/Video/Cache/Size")->GetInt() << 20) // convert MB to bytes + { + } + + std::shared_ptr GetFrame(int n) override; + + int GetFrameCount() const override { return master->GetFrameCount(); } + int GetWidth() const override { return master->GetWidth(); } + int GetHeight() const override { return master->GetHeight(); } + double GetDAR() const override { return master->GetDAR(); } + agi::vfr::Framerate GetFPS() const override { return master->GetFPS(); } + std::vector GetKeyFrames() const override { return master->GetKeyFrames(); } + std::string GetWarning() const override { return master->GetWarning(); } + std::string GetDecoderName() const override { return master->GetDecoderName(); } + std::string GetColorSpace() const override { return master->GetColorSpace(); } +}; std::shared_ptr VideoProviderCache::GetFrame(int n) { size_t total_size = 0; for (auto cur = cache.begin(); cur != cache.end(); ++cur) { if (cur->frame_number == n) { -#if BOOST_VERSION <= 105200 - // Until boost 1.52, boost::container::list incorrectly asserted - // that this != &other, so do an extra splice through an empty list - decltype(cache) temp; - temp.splice(temp.begin(), cache, cur); - cache.splice(cache.begin(), temp, temp.begin()); -#else cache.splice(cache.begin(), cache, cur); // Move to front -#endif return std::make_shared(cache.front()); } @@ -83,3 +92,8 @@ std::shared_ptr VideoProviderCache::GetFrame(int n) { return frame; } +} + +std::unique_ptr CreateCacheVideoProvider(std::unique_ptr parent) { + return agi::util::make_unique(std::move(parent)); +} diff --git a/src/video_provider_cache.h b/src/video_provider_cache.h deleted file mode 100644 index 8fe033087..000000000 --- a/src/video_provider_cache.h +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2013, 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 "include/aegisub/video_provider.h" - -struct CachedFrame; - -/// @class VideoProviderCache -/// @brief A wrapper around a video provider which provides LRU caching -class VideoProviderCache final : public VideoProvider { - /// The source provider to get frames from - std::unique_ptr master; - - /// @brief Maximum size of the cache in bytes - /// - /// Note that this is a soft limit. The cache stops allocating new frames - /// once it has exceeded the limit, but it never tries to shrink - const size_t max_cache_size; - - /// Cache of video frames with the most recently used ones at the front - boost::container::list cache; - -public: - VideoProviderCache(std::unique_ptr master); - ~VideoProviderCache(); - - std::shared_ptr GetFrame(int n) override; - - int GetFrameCount() const override { return master->GetFrameCount(); } - int GetWidth() const override { return master->GetWidth(); } - int GetHeight() const override { return master->GetHeight(); } - double GetDAR() const override { return master->GetDAR(); } - agi::vfr::Framerate GetFPS() const override { return master->GetFPS(); } - std::vector GetKeyFrames() const override { return master->GetKeyFrames(); } - std::string GetWarning() const override { return master->GetWarning(); } - std::string GetDecoderName() const override { return master->GetDecoderName(); } - std::string GetColorSpace() const override { return master->GetColorSpace(); } -}; diff --git a/src/video_provider_dummy.cpp b/src/video_provider_dummy.cpp index 609242d35..3c70357ae 100644 --- a/src/video_provider_dummy.cpp +++ b/src/video_provider_dummy.cpp @@ -49,13 +49,18 @@ #include #include -void DummyVideoProvider::Create(double fps, int frames, int width, int height, unsigned char red, unsigned char green, unsigned char blue, bool pattern) { - this->framecount = frames; - this->fps = fps; - this->width = width; - this->height = height; +DummyVideoProvider::DummyVideoProvider(double fps, int frames, int width, int height, agi::Color colour, bool pattern) +: framecount(frames) +, fps(fps) +, width(width) +, height(height) +{ data.resize(width * height * 4); + auto red = colour.r; + auto green = colour.g; + auto blue = colour.b; + using namespace boost::gil; auto dst = interleaved_view(width, height, (bgra8_pixel_t*)data.data(), 4 * width); @@ -84,9 +89,17 @@ void DummyVideoProvider::Create(double fps, int frames, int width, int height, u } } -DummyVideoProvider::DummyVideoProvider(agi::fs::path const& filename, std::string const&) { +std::string DummyVideoProvider::MakeFilename(double fps, int frames, int width, int height, agi::Color colour, bool pattern) { + return str(boost::format("?dummy:%f:%d:%d:%d:%d:%d:%d:%s") % fps % frames % width % height % (int)colour.r % (int)colour.g % (int)colour.b % (pattern ? "c" : "")); +} + +std::shared_ptr DummyVideoProvider::GetFrame(int) { + return std::make_shared(data.data(), width, height, width * 4, false); +} + +std::unique_ptr CreateDummyVideoProvider(agi::fs::path const& filename, std::string const&) { if (!boost::starts_with(filename.string(), "?dummy")) - throw agi::fs::FileNotFound(std::string("Attempted creating dummy video provider with non-dummy filename")); + return {}; std::vector toks; auto const& fields = filename.string().substr(7); @@ -109,17 +122,5 @@ DummyVideoProvider::DummyVideoProvider(agi::fs::path const& filename, std::strin bool pattern = toks[i] == "c"; - Create(fps, frames, width, height, red, green, blue, pattern); -} - -DummyVideoProvider::DummyVideoProvider(double fps, int frames, int width, int height, agi::Color colour, bool pattern) { - Create(fps, frames, width, height, colour.r, colour.g, colour.b, pattern); -} - -std::string DummyVideoProvider::MakeFilename(double fps, int frames, int width, int height, agi::Color colour, bool pattern) { - return str(boost::format("?dummy:%f:%d:%d:%d:%d:%d:%d:%s") % fps % frames % width % height % (int)colour.r % (int)colour.g % (int)colour.b % (pattern ? "c" : "")); -} - -std::shared_ptr DummyVideoProvider::GetFrame(int) { - return std::make_shared(data.data(), width, height, width * 4, false); -} + return agi::util::make_unique(fps, frames, width, height, agi::Color(red, green, blue), pattern); +} \ No newline at end of file diff --git a/src/video_provider_dummy.h b/src/video_provider_dummy.h index 97d31e602..8826e6594 100644 --- a/src/video_provider_dummy.h +++ b/src/video_provider_dummy.h @@ -50,21 +50,7 @@ class DummyVideoProvider final : public VideoProvider { /// The data for the image returned for all frames std::vector data; - /// Create the dummy frame from the given parameters - /// @param fps Frame rate of the dummy video - /// @param frames Length in frames of the dummy video - /// @param width Width in pixels of the dummy video - /// @param height Height in pixels of the dummy video - /// @param red Red component of the primary colour of the dummy video - /// @param green Green component of the primary colour of the dummy video - /// @param blue Blue component of the primary colour of the dummy video - /// @param pattern Use a checkerboard pattern rather than a solid colour - void Create(double fps, int frames, int width, int height, unsigned char red, unsigned char green, unsigned char blue, bool pattern); - public: - /// Create a dummy video from a string returned from MakeFilename - DummyVideoProvider(agi::fs::path const& filename, std::string const& colormatix); - /// Create a dummy video from separate parameters /// @param fps Frame rate of the dummy video /// @param frames Length in frames of the dummy video diff --git a/src/video_provider_ffmpegsource.cpp b/src/video_provider_ffmpegsource.cpp index b0d359dc4..7a43ee348 100644 --- a/src/video_provider_ffmpegsource.cpp +++ b/src/video_provider_ffmpegsource.cpp @@ -35,7 +35,8 @@ #include "config.h" #ifdef WITH_FFMS2 -#include "video_provider_ffmpegsource.h" +#include "ffmpegsource_common.h" +#include "include/aegisub/video_provider.h" #include "compat.h" #include "options.h" @@ -44,11 +45,47 @@ #include "video_frame.h" #include +#include #include #include namespace { +/// @class FFmpegSourceVideoProvider +/// @brief Implements video loading through the FFMS library. +class FFmpegSourceVideoProvider final : public VideoProvider, FFmpegSourceProvider { + /// video source object + agi::scoped_holder VideoSource; + const FFMS_VideoProperties *VideoInfo = nullptr; ///< video properties + + int Width = -1; ///< width in pixels + int Height = -1; ///< height in pixels + double DAR; ///< display aspect ratio + std::vector KeyFramesList; ///< list of keyframes + agi::vfr::Framerate Timecodes; ///< vfr object + std::string ColorSpace; ///< Colorspace name + + char FFMSErrMsg[1024]; ///< FFMS error message + FFMS_ErrorInfo ErrInfo; ///< FFMS error codes/messages + + void LoadVideo(agi::fs::path const& filename, std::string const& colormatrix); + +public: + FFmpegSourceVideoProvider(agi::fs::path const& filename, std::string const& colormatrix); + + std::shared_ptr GetFrame(int n) override; + + int GetFrameCount() const override { return VideoInfo->NumFrames; } + int GetWidth() const override { return Width; } + int GetHeight() const override { return Height; } + double GetDAR() const override { return DAR; } + agi::vfr::Framerate GetFPS() const override { return Timecodes; } + std::string GetColorSpace() const override { return ColorSpace; } + std::vector GetKeyFrames() const override { return KeyFramesList; }; + std::string GetDecoderName() const override { return "FFmpegSource"; } + bool WantsCaching() const override { return true; } +}; + std::string colormatrix_description(int cs, int cr) { // Assuming TV for unspecified std::string str = cr == FFMS_CR_JPEG ? "PC" : "TV"; @@ -70,7 +107,6 @@ std::string colormatrix_description(int cs, int cr) { throw VideoOpenError("Unknown video color space"); } } -} FFmpegSourceVideoProvider::FFmpegSourceVideoProvider(agi::fs::path const& filename, std::string const& colormatrix) try : VideoSource(nullptr, FFMS_DestroyVideoSource) @@ -247,5 +283,10 @@ std::shared_ptr FFmpegSourceVideoProvider::GetFrame(int n) { return std::make_shared(frame->Data[0], Width, Height, frame->Linesize[0], false); } +} + +std::unique_ptr CreateFFmpegSourceVideoProvider(agi::fs::path const& path, std::string const& colormatrix) { + return agi::util::make_unique(path, colormatrix); +} #endif /* WITH_FFMS2 */ diff --git a/src/video_provider_ffmpegsource.h b/src/video_provider_ffmpegsource.h deleted file mode 100644 index 76139b473..000000000 --- a/src/video_provider_ffmpegsource.h +++ /dev/null @@ -1,73 +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 video_provider_ffmpegsource.h -/// @see video_provider_ffmpegsource.cpp -/// @ingroup video_input ffms -/// - -#ifdef WITH_FFMS2 -#include "ffmpegsource_common.h" -#include "include/aegisub/video_provider.h" - -/// @class FFmpegSourceVideoProvider -/// @brief Implements video loading through the FFMS library. -class FFmpegSourceVideoProvider final : public VideoProvider, FFmpegSourceProvider { - /// video source object - agi::scoped_holder VideoSource; - const FFMS_VideoProperties *VideoInfo = nullptr; ///< video properties - - int Width = -1; ///< width in pixels - int Height = -1; ///< height in pixels - double DAR; ///< display aspect ratio - std::vector KeyFramesList; ///< list of keyframes - agi::vfr::Framerate Timecodes; ///< vfr object - std::string ColorSpace; ///< Colorspace name - - char FFMSErrMsg[1024]; ///< FFMS error message - FFMS_ErrorInfo ErrInfo; ///< FFMS error codes/messages - - void LoadVideo(agi::fs::path const& filename, std::string const& colormatrix); - -public: - FFmpegSourceVideoProvider(agi::fs::path const& filename, std::string const& colormatrix); - - std::shared_ptr GetFrame(int n) override; - - int GetFrameCount() const override { return VideoInfo->NumFrames; } - int GetWidth() const override { return Width; } - int GetHeight() const override { return Height; } - double GetDAR() const override { return DAR; } - agi::vfr::Framerate GetFPS() const override { return Timecodes; } - std::string GetColorSpace() const override { return ColorSpace; } - std::vector GetKeyFrames() const override { return KeyFramesList; }; - std::string GetDecoderName() const override { return "FFmpegSource"; } - bool WantsCaching() const override { return true; } -}; -#endif /* WITH_FFMS2 */ diff --git a/src/video_provider_manager.cpp b/src/video_provider_manager.cpp index 116feac81..b74697350 100644 --- a/src/video_provider_manager.cpp +++ b/src/video_provider_manager.cpp @@ -1,68 +1,95 @@ -// Copyright (c) 2006, Rodrigo Braz Monteiro -// All rights reserved. +// Copyright (c) 2014, Thomas Goyne // -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: +// 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. // -// * 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. +// 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 video_provider_manager.cpp -/// @brief Keep track of installed video providers -/// @ingroup video_input -/// - #include "config.h" #include "video_provider_manager.h" +#include "include/aegisub/video_provider.h" #include "options.h" -#include "video_provider_avs.h" -#include "video_provider_cache.h" -#include "video_provider_dummy.h" -#include "video_provider_ffmpegsource.h" -#include "video_provider_yuv4mpeg.h" #include #include #include -std::unique_ptr VideoProviderFactory::GetProvider(agi::fs::path const& video_file, std::string const& colormatrix) { - std::vector factories = GetClasses(OPT_GET("Video/Provider")->GetString()); - factories.insert(factories.begin(), "YUV4MPEG"); - factories.insert(factories.begin(), "Dummy"); +std::unique_ptr CreateDummyVideoProvider(agi::fs::path const&, std::string const&); +std::unique_ptr CreateYUV4MPEGVideoProvider(agi::fs::path const&, std::string const&); +std::unique_ptr CreateFFmpegSourceVideoProvider(agi::fs::path const&, std::string const&); +std::unique_ptr CreateAvisynthVideoProvider(agi::fs::path const&, std::string const&); + +std::unique_ptr CreateCacheVideoProvider(std::unique_ptr); + +namespace { + using factory_fn = std::unique_ptr (*)(agi::fs::path const&, std::string const&); + struct factory { + const char *name; + factory_fn create; + bool hidden; + }; + + const factory providers[] = { + {"Dummy", CreateDummyVideoProvider, true}, + {"YUV4MPEG", CreateYUV4MPEGVideoProvider, true}, +#ifdef WITH_FFMS2 + {"FFmpegSource", CreateFFmpegSourceVideoProvider, false}, +#endif +#ifdef WITH_AVISYNTH + {"Avisynth", CreateAvisynthVideoProvider, false}, +#endif + }; +} + +std::vector VideoProviderFactory::GetClasses() { + std::vector list; + for (auto const& provider : providers) { + if (!provider.hidden) + list.push_back(provider.name); + } + return list; +} + +std::unique_ptr VideoProviderFactory::GetProvider(agi::fs::path const& filename, std::string const& colormatrix) { + auto preferred = OPT_GET("Video/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); + } bool found = false; bool supported = false; std::string errors; errors.reserve(1024); - for (auto const& factory : factories) { + for (auto factory : sorted) { std::string err; try { - auto provider = Create(factory, video_file, colormatrix); - LOG_I("manager/video/provider") << factory << ": opened " << video_file; - return provider->WantsCaching() ? agi::util::make_unique(std::move(provider)) : std::move(provider); + auto provider = factory->create(filename, colormatrix); + if (!provider) continue; + LOG_I("manager/video/provider") << factory->name << ": opened " << filename; + return provider->WantsCaching() ? CreateCacheVideoProvider(std::move(provider)) : std::move(provider); } catch (agi::fs::FileNotFound const&) { err = "file not found."; @@ -82,26 +109,15 @@ std::unique_ptr VideoProviderFactory::GetProvider(agi::fs::path c err = ex.GetMessage(); } - errors += factory + ": " + err + "\n"; - LOG_D("manager/video/provider") << factory << ": " << err; + errors += std::string(factory->name) + ": " + err + "\n"; + LOG_D("manager/video/provider") << factory->name << ": " << err; } // No provider could open the file - LOG_E("manager/video/provider") << "Could not open " << video_file; - std::string msg = "Could not open " + video_file.string() + ":\n" + errors; + LOG_E("manager/video/provider") << "Could not open " << filename; + std::string msg = "Could not open " + filename.string() + ":\n" + errors; - if (!found) throw agi::fs::FileNotFound(video_file.string()); + if (!found) throw agi::fs::FileNotFound(filename.string()); if (!supported) throw VideoNotSupported(msg); throw VideoOpenError(msg); } - -void VideoProviderFactory::RegisterProviders() { -#ifdef WITH_AVISYNTH - Register("Avisynth"); -#endif -#ifdef WITH_FFMS2 - Register("FFmpegSource"); -#endif - Register("Dummy", true); - Register("YUV4MPEG", true); -} diff --git a/src/video_provider_manager.h b/src/video_provider_manager.h index 6632f75ef..718401e73 100644 --- a/src/video_provider_manager.h +++ b/src/video_provider_manager.h @@ -1,4 +1,4 @@ -// Copyright (c) 2013, Thomas Goyne +// 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 @@ -14,13 +14,15 @@ // // Aegisub Project http://www.aegisub.org/ -#include "factory_manager.h" -#include "include/aegisub/video_provider.h" - #include -class VideoProviderFactory final : public Factory { -public: +#include +#include +#include + +class VideoProvider; + +struct VideoProviderFactory { + static std::vector GetClasses(); static std::unique_ptr GetProvider(agi::fs::path const& video_file, std::string const& colormatrix); - static void RegisterProviders(); }; diff --git a/src/video_provider_yuv4mpeg.cpp b/src/video_provider_yuv4mpeg.cpp index 527bf958f..3bed2812e 100644 --- a/src/video_provider_yuv4mpeg.cpp +++ b/src/video_provider_yuv4mpeg.cpp @@ -34,7 +34,7 @@ #include "config.h" -#include "video_provider_yuv4mpeg.h" +#include "include/aegisub/video_provider.h" #include "compat.h" #include "utils.h" @@ -47,11 +47,122 @@ #include #include +#include +#include + +/// the maximum allowed header length, in bytes +#define YUV4MPEG_HEADER_MAXLEN 128 + +namespace { + +/// @class YUV4MPEGVideoProvider +/// @brief Implements reading of YUV4MPEG uncompressed video files +class YUV4MPEGVideoProvider final : public VideoProvider { + /// Pixel formats + enum Y4M_PixelFormat { + Y4M_PIXFMT_NONE = -1, /// not set/unknown + + /// 4:2:0 sampling variants. + /// afaict the only difference between these three + /// is the chroma sample location, and nobody cares about that. + Y4M_PIXFMT_420JPEG, /// 4:2:0, H/V centered, for JPEG/MPEG-1 + Y4M_PIXFMT_420MPEG2, /// 4:2:0, H cosited, for MPEG-2 + Y4M_PIXFMT_420PALDV, /// 4:2:0, alternating Cb/Cr, for PAL-DV + + Y4M_PIXFMT_411, /// 4:1:1, H cosited + Y4M_PIXFMT_422, /// 4:2:2, H cosited + Y4M_PIXFMT_444, /// 4:4:4, i.e. no chroma subsampling + Y4M_PIXFMT_444ALPHA, /// 4:4:4 plus alpha channel + + Y4M_PIXFMT_MONO /// luma only (grayscale) + }; + + + /// Interlacing mode for an entire stream + enum Y4M_InterlacingMode { + Y4M_ILACE_NOTSET = -1, /// undefined + Y4M_ILACE_PROGRESSIVE, /// progressive (no interlacing) + + Y4M_ILACE_TFF, /// interlaced, top field first + Y4M_ILACE_BFF, /// interlaced, bottom field first + + Y4M_ILACE_MIXED, /// mixed interlaced/progressive, possibly with RFF flags + Y4M_ILACE_UNKNOWN /// unknown interlacing mode (not the same as undefined) + }; + + + /// Frame information flags + enum Y4M_FrameFlags { + Y4M_FFLAG_NOTSET = -1, /// undefined + Y4M_FFLAG_NONE = 0x0000, /// no flags set + + /// field order/repeat field flags + Y4M_FFLAG_R_TFF = 0x0001, /// top field first + Y4M_FFLAG_R_TFF_R = 0x0002, /// top field first, and repeat that field + Y4M_FFLAG_R_BFF = 0x0004, /// bottom field first + Y4M_FFLAG_R_BFF_R = 0x0008, /// bottom field first, and repeat that field + Y4M_FFLAG_R_P = 0x0010, /// progressive + Y4M_FFLAG_R_P_R = 0x0020, /// progressive, and repeat frame once + Y4M_FFLAG_R_P_RR = 0x0040, /// progressive, and repeat frame twice + + /// temporal sampling flags + Y4M_FFLAG_T_P = 0x0080, /// progressive (fields sampled at the same time) + Y4M_FFLAG_T_I = 0x0100, /// interlaced (fields sampled at different times) + + /// chroma subsampling flags + Y4M_FFLAG_C_P = 0x0200, /// progressive (whole frame subsampled) + Y4M_FFLAG_C_I = 0x0400, /// interlaced (fields subsampled independently) + Y4M_FFLAG_C_UNKNOWN = 0x0800 /// unknown (only allowed for non-4:2:0 sampling) + }; + + agi::read_file_mapping file; + bool inited = false; /// initialization state + + int w = 0, h = 0; /// frame width/height + int num_frames = -1; /// length of file in frames + int frame_sz; /// size of each frame in bytes + int luma_sz; /// size of the luma plane of each frame, in bytes + int chroma_sz; /// size of one of the two chroma planes of each frame, in bytes + + Y4M_PixelFormat pixfmt = Y4M_PIXFMT_NONE; /// colorspace/pixel format + Y4M_InterlacingMode imode = Y4M_ILACE_NOTSET; /// interlacing mode (for the entire stream) + struct { + int num = -1; /// numerator + int den = 1; /// denominator + } fps_rat; /// framerate + + agi::vfr::Framerate fps; + + /// a list of byte positions detailing where in the file + /// each frame header can be found + std::vector seek_table; + + void CheckFileFormat(); + void ParseFileHeader(const std::vector& tags); + Y4M_FrameFlags ParseFrameHeader(const std::vector& tags); + std::vector ReadHeader(uint64_t &startpos); + int IndexFile(uint64_t pos); + +public: + YUV4MPEGVideoProvider(agi::fs::path const& filename); + + std::shared_ptr GetFrame(int n) override; + + int GetFrameCount() const override { return num_frames; } + int GetWidth() const override { return w; } + int GetHeight() const override { return h; } + double GetDAR() const override { return 0; } + agi::vfr::Framerate GetFPS() const override { return fps; } + std::vector GetKeyFrames() const override { return {}; } + std::string GetColorSpace() const override { return "TV.601"; } + std::string GetDecoderName() const override { return "YU4MPEG"; } + bool WantsCaching() const override { return true; } +}; /// @brief Constructor /// @param filename The filename to open -YUV4MPEGVideoProvider::YUV4MPEGVideoProvider(agi::fs::path const& filename, std::string const&) -: file(agi::util::make_unique(filename)) +YUV4MPEGVideoProvider::YUV4MPEGVideoProvider(agi::fs::path const& filename) +: file(filename) { CheckFileFormat(); @@ -89,15 +200,13 @@ YUV4MPEGVideoProvider::YUV4MPEGVideoProvider(agi::fs::path const& filename, std: throw VideoOpenError("Unable to determine file length"); } -YUV4MPEGVideoProvider::~YUV4MPEGVideoProvider() { } - /// @brief Checks if the file is an YUV4MPEG file or not /// Note that it reports the error by throwing an exception, /// not by returning a false value. void YUV4MPEGVideoProvider::CheckFileFormat() { - if (file->size() < 10) + if (file.size() < 10) throw VideoNotSupported("CheckFileFormat: File is not a YUV4MPEG file (too small)"); - if (strncmp("YUV4MPEG2 ", file->read(0, 10), 10)) + if (strncmp("YUV4MPEG2 ", file.read(0, 10), 10)) throw VideoNotSupported("CheckFileFormat: File is not a YUV4MPEG file (bad magic)"); } @@ -106,11 +215,11 @@ void YUV4MPEGVideoProvider::CheckFileFormat() { /// @return A list of parameters std::vector YUV4MPEGVideoProvider::ReadHeader(uint64_t &pos) { std::vector tags; - if (pos >= file->size()) + if (pos >= file.size()) return tags; - auto len = std::min(YUV4MPEG_HEADER_MAXLEN, file->size() - pos); - auto buff = file->read(pos, len); + auto len = std::min(YUV4MPEG_HEADER_MAXLEN, file.size() - pos); + auto buff = file.read(pos, len); // read header until terminating newline (0x0A) is found auto curtag = buff; @@ -307,7 +416,7 @@ std::shared_ptr YUV4MPEGVideoProvider::GetFrame(int n) { throw "YUV4MPEG video provider: GetFrame: Unsupported source colorspace"; } - auto src_y = reinterpret_cast(file->read(seek_table[n], luma_sz + chroma_sz * 2)); + auto src_y = reinterpret_cast(file.read(seek_table[n], luma_sz + chroma_sz * 2)); auto src_u = src_y + luma_sz; auto src_v = src_u + chroma_sz; std::vector data; @@ -337,3 +446,8 @@ std::shared_ptr YUV4MPEGVideoProvider::GetFrame(int n) { return std::make_shared(data.data(), w, h, w * 4, false); } +} + +std::unique_ptr CreateYUV4MPEGVideoProvider(agi::fs::path const& path, std::string const&) { + return agi::util::make_unique(path); +} diff --git a/src/video_provider_yuv4mpeg.h b/src/video_provider_yuv4mpeg.h deleted file mode 100644 index ac57502cd..000000000 --- a/src/video_provider_yuv4mpeg.h +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright (c) 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 video_provider_yuv4mpeg.h -/// @see video_provider_yuv4mpeg.cpp -/// @ingroup video_input -/// - -#include "include/aegisub/video_provider.h" - -#include -#include - -namespace agi { class read_file_mapping; } - -/// the maximum allowed header length, in bytes -#define YUV4MPEG_HEADER_MAXLEN 128 - -/// @class YUV4MPEGVideoProvider -/// @brief Implements reading of YUV4MPEG uncompressed video files -class YUV4MPEGVideoProvider final : public VideoProvider { - /// Pixel formats - enum Y4M_PixelFormat { - Y4M_PIXFMT_NONE = -1, /// not set/unknown - - /// 4:2:0 sampling variants. - /// afaict the only difference between these three - /// is the chroma sample location, and nobody cares about that. - Y4M_PIXFMT_420JPEG, /// 4:2:0, H/V centered, for JPEG/MPEG-1 - Y4M_PIXFMT_420MPEG2, /// 4:2:0, H cosited, for MPEG-2 - Y4M_PIXFMT_420PALDV, /// 4:2:0, alternating Cb/Cr, for PAL-DV - - Y4M_PIXFMT_411, /// 4:1:1, H cosited - Y4M_PIXFMT_422, /// 4:2:2, H cosited - Y4M_PIXFMT_444, /// 4:4:4, i.e. no chroma subsampling - Y4M_PIXFMT_444ALPHA, /// 4:4:4 plus alpha channel - - Y4M_PIXFMT_MONO /// luma only (grayscale) - }; - - - /// Interlacing mode for an entire stream - enum Y4M_InterlacingMode { - Y4M_ILACE_NOTSET = -1, /// undefined - Y4M_ILACE_PROGRESSIVE, /// progressive (no interlacing) - - Y4M_ILACE_TFF, /// interlaced, top field first - Y4M_ILACE_BFF, /// interlaced, bottom field first - - Y4M_ILACE_MIXED, /// mixed interlaced/progressive, possibly with RFF flags - Y4M_ILACE_UNKNOWN /// unknown interlacing mode (not the same as undefined) - }; - - - /// Frame information flags - enum Y4M_FrameFlags { - Y4M_FFLAG_NOTSET = -1, /// undefined - Y4M_FFLAG_NONE = 0x0000, /// no flags set - - /// field order/repeat field flags - Y4M_FFLAG_R_TFF = 0x0001, /// top field first - Y4M_FFLAG_R_TFF_R = 0x0002, /// top field first, and repeat that field - Y4M_FFLAG_R_BFF = 0x0004, /// bottom field first - Y4M_FFLAG_R_BFF_R = 0x0008, /// bottom field first, and repeat that field - Y4M_FFLAG_R_P = 0x0010, /// progressive - Y4M_FFLAG_R_P_R = 0x0020, /// progressive, and repeat frame once - Y4M_FFLAG_R_P_RR = 0x0040, /// progressive, and repeat frame twice - - /// temporal sampling flags - Y4M_FFLAG_T_P = 0x0080, /// progressive (fields sampled at the same time) - Y4M_FFLAG_T_I = 0x0100, /// interlaced (fields sampled at different times) - - /// chroma subsampling flags - Y4M_FFLAG_C_P = 0x0200, /// progressive (whole frame subsampled) - Y4M_FFLAG_C_I = 0x0400, /// interlaced (fields subsampled independently) - Y4M_FFLAG_C_UNKNOWN = 0x0800 /// unknown (only allowed for non-4:2:0 sampling) - }; - - std::unique_ptr file; - bool inited = false; /// initialization state - - int w = 0, h = 0; /// frame width/height - int num_frames = -1; /// length of file in frames - int frame_sz; /// size of each frame in bytes - int luma_sz; /// size of the luma plane of each frame, in bytes - int chroma_sz; /// size of one of the two chroma planes of each frame, in bytes - - Y4M_PixelFormat pixfmt = Y4M_PIXFMT_NONE; /// colorspace/pixel format - Y4M_InterlacingMode imode = Y4M_ILACE_NOTSET; /// interlacing mode (for the entire stream) - struct { - int num = -1; /// numerator - int den = 1; /// denominator - } fps_rat; /// framerate - - agi::vfr::Framerate fps; - - /// a list of byte positions detailing where in the file - /// each frame header can be found - std::vector seek_table; - - void CheckFileFormat(); - void ParseFileHeader(const std::vector& tags); - Y4M_FrameFlags ParseFrameHeader(const std::vector& tags); - std::vector ReadHeader(uint64_t &startpos); - int IndexFile(uint64_t pos); - -public: - YUV4MPEGVideoProvider(agi::fs::path const& filename, std::string const&); - ~YUV4MPEGVideoProvider(); - - std::shared_ptr GetFrame(int n) override; - - int GetFrameCount() const override { return num_frames; } - int GetWidth() const override { return w; } - int GetHeight() const override { return h; } - double GetDAR() const override { return 0; } - agi::vfr::Framerate GetFPS() const override { return fps; } - std::vector GetKeyFrames() const override { return {}; } - std::string GetColorSpace() const override { return "TV.601"; } - std::string GetDecoderName() const override { return "YU4MPEG"; } - bool WantsCaching() const override { return true; } -};