Convert VideoProviderManager to AudioProviderManager's new design

This commit is contained in:
Thomas Goyne 2014-03-24 07:05:01 -07:00
parent 36a71be19f
commit 470f85d365
18 changed files with 361 additions and 509 deletions

View file

@ -243,12 +243,8 @@
<ClInclude Include="$(SrcDir)video_display.h" />
<ClInclude Include="$(SrcDir)video_frame.h" />
<ClInclude Include="$(SrcDir)video_out_gl.h" />
<ClInclude Include="$(SrcDir)video_provider_avs.h" />
<ClInclude Include="$(SrcDir)video_provider_cache.h" />
<ClInclude Include="$(SrcDir)video_provider_dummy.h" />
<ClInclude Include="$(SrcDir)video_provider_ffmpegsource.h" />
<ClInclude Include="$(SrcDir)video_provider_manager.h" />
<ClInclude Include="$(SrcDir)video_provider_yuv4mpeg.h" />
<ClInclude Include="$(SrcDir)video_slider.h" />
<ClInclude Include="$(SrcDir)visual_feature.h" />
<ClInclude Include="$(SrcDir)visual_tool.h" />

View file

@ -390,21 +390,9 @@
<ClInclude Include="$(SrcDir)video_out_gl.h">
<Filter>Video\UI</Filter>
</ClInclude>
<ClInclude Include="$(SrcDir)video_provider_avs.h">
<Filter>Video\Providers</Filter>
</ClInclude>
<ClInclude Include="$(SrcDir)video_provider_yuv4mpeg.h">
<Filter>Video\Providers</Filter>
</ClInclude>
<ClInclude Include="$(SrcDir)video_provider_cache.h">
<Filter>Video\Providers</Filter>
</ClInclude>
<ClInclude Include="$(SrcDir)video_provider_dummy.h">
<Filter>Video\Providers</Filter>
</ClInclude>
<ClInclude Include="$(SrcDir)video_provider_ffmpegsource.h">
<Filter>Video\Providers</Filter>
</ClInclude>
<ClInclude Include="$(SrcDir)video_provider_manager.h">
<Filter>Video\Providers</Filter>
</ClInclude>

View file

@ -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 <boost/rational.hpp>

View file

@ -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 <boost/algorithm/string/predicate.hpp>

View file

@ -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 <libaegisub/util.h>
void RegisterBuiltInPlugins() {
VideoProviderFactory::RegisterProviders();
AudioPlayerFactory::RegisterProviders();
SubtitlesProviderFactory::RegisterProviders();
SpellCheckerFactory::RegisterProviders();

View file

@ -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"

View file

@ -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 <libaegisub/fs.h>
#include <libaegisub/log.h>
#include <libaegisub/path.h>
#include <libaegisub/util.h>
#include <boost/algorithm/string/predicate.hpp>
#include <mutex>
@ -53,8 +54,42 @@
#include <vfw.h>
#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<int> 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<VideoFrame> 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<int> 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<std::mutex> lock(avs.GetMutex());
@ -273,4 +308,9 @@ std::shared_ptr<VideoFrame> AvisynthVideoProvider::GetFrame(int n) {
auto frame = RGB32Video->GetFrame(n, avs.GetEnv());
return std::make_shared<VideoFrame>(frame->GetReadPtr(), frame->GetRowSize() / 4, frame->GetHeight(), frame->GetPitch(), true);
}
}
std::unique_ptr<VideoProvider> CreateAvisynthVideoProvider(agi::fs::path const& path, std::string const& colormatrix) {
return agi::util::make_unique<AvisynthVideoProvider>(path, colormatrix);
}
#endif // HAVE_AVISYNTH

View file

@ -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<int> 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<VideoFrame> 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<int> GetKeyFrames() const { return keyframes; }
std::string GetWarning() const { return warning; }
std::string GetDecoderName() const { return decoder_name; }
std::string GetColorSpace() const { return colorspace; }
};
#endif

View file

@ -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 <algorithm>
#include <boost/version.hpp>
#include <libaegisub/util.h>
#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 <list>
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<VideoProvider> 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<VideoProvider> 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<CachedFrame> cache;
public:
VideoProviderCache(std::unique_ptr<VideoProvider> master)
: master(std::move(master))
, max_cache_size(OPT_GET("Provider/Video/Cache/Size")->GetInt() << 20) // convert MB to bytes
{
}
std::shared_ptr<VideoFrame> 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<int> 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<VideoFrame> 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<VideoFrame>(cache.front());
}
@ -83,3 +92,8 @@ std::shared_ptr<VideoFrame> VideoProviderCache::GetFrame(int n) {
return frame;
}
}
std::unique_ptr<VideoProvider> CreateCacheVideoProvider(std::unique_ptr<VideoProvider> parent) {
return agi::util::make_unique<VideoProviderCache>(std::move(parent));
}

View file

@ -1,53 +0,0 @@
// Copyright (c) 2013, Thomas Goyne <plorkyeran@aegisub.org>
//
// 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 <boost/container/list.hpp>
#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<VideoProvider> 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<CachedFrame> cache;
public:
VideoProviderCache(std::unique_ptr<VideoProvider> master);
~VideoProviderCache();
std::shared_ptr<VideoFrame> 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<int> 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(); }
};

View file

@ -49,13 +49,18 @@
#include <boost/format.hpp>
#include <boost/gil/gil_all.hpp>
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<VideoFrame> DummyVideoProvider::GetFrame(int) {
return std::make_shared<VideoFrame>(data.data(), width, height, width * 4, false);
}
std::unique_ptr<VideoProvider> 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<std::string> 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<VideoFrame> DummyVideoProvider::GetFrame(int) {
return std::make_shared<VideoFrame>(data.data(), width, height, width * 4, false);
}
return agi::util::make_unique<DummyVideoProvider>(fps, frames, width, height, agi::Color(red, green, blue), pattern);
}

View file

@ -50,21 +50,7 @@ class DummyVideoProvider final : public VideoProvider {
/// The data for the image returned for all frames
std::vector<unsigned char> 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

View file

@ -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 <libaegisub/fs.h>
#include <libaegisub/util.h>
#include <wx/choicdlg.h>
#include <wx/msgdlg.h>
namespace {
/// @class FFmpegSourceVideoProvider
/// @brief Implements video loading through the FFMS library.
class FFmpegSourceVideoProvider final : public VideoProvider, FFmpegSourceProvider {
/// video source object
agi::scoped_holder<FFMS_VideoSource*, void (FFMS_CC*)(FFMS_VideoSource*)> 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<int> 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<VideoFrame> 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<int> 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<VideoFrame> FFmpegSourceVideoProvider::GetFrame(int n) {
return std::make_shared<VideoFrame>(frame->Data[0], Width, Height, frame->Linesize[0], false);
}
}
std::unique_ptr<VideoProvider> CreateFFmpegSourceVideoProvider(agi::fs::path const& path, std::string const& colormatrix) {
return agi::util::make_unique<FFmpegSourceVideoProvider>(path, colormatrix);
}
#endif /* WITH_FFMS2 */

View file

@ -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<FFMS_VideoSource*, void (FFMS_CC*)(FFMS_VideoSource*)> 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<int> 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<VideoFrame> 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<int> GetKeyFrames() const override { return KeyFramesList; };
std::string GetDecoderName() const override { return "FFmpegSource"; }
bool WantsCaching() const override { return true; }
};
#endif /* WITH_FFMS2 */

View file

@ -1,68 +1,95 @@
// Copyright (c) 2006, Rodrigo Braz Monteiro
// All rights reserved.
// Copyright (c) 2014, Thomas Goyne <plorkyeran@aegisub.org>
//
// 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 <libaegisub/fs.h>
#include <libaegisub/log.h>
#include <libaegisub/util.h>
std::unique_ptr<VideoProvider> VideoProviderFactory::GetProvider(agi::fs::path const& video_file, std::string const& colormatrix) {
std::vector<std::string> factories = GetClasses(OPT_GET("Video/Provider")->GetString());
factories.insert(factories.begin(), "YUV4MPEG");
factories.insert(factories.begin(), "Dummy");
std::unique_ptr<VideoProvider> CreateDummyVideoProvider(agi::fs::path const&, std::string const&);
std::unique_ptr<VideoProvider> CreateYUV4MPEGVideoProvider(agi::fs::path const&, std::string const&);
std::unique_ptr<VideoProvider> CreateFFmpegSourceVideoProvider(agi::fs::path const&, std::string const&);
std::unique_ptr<VideoProvider> CreateAvisynthVideoProvider(agi::fs::path const&, std::string const&);
std::unique_ptr<VideoProvider> CreateCacheVideoProvider(std::unique_ptr<VideoProvider>);
namespace {
using factory_fn = std::unique_ptr<VideoProvider> (*)(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<std::string> VideoProviderFactory::GetClasses() {
std::vector<std::string> list;
for (auto const& provider : providers) {
if (!provider.hidden)
list.push_back(provider.name);
}
return list;
}
std::unique_ptr<VideoProvider> VideoProviderFactory::GetProvider(agi::fs::path const& filename, std::string const& colormatrix) {
auto preferred = OPT_GET("Video/Provider")->GetString();
std::vector<const factory *> 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<VideoProviderCache>(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<VideoProvider> 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<AvisynthVideoProvider>("Avisynth");
#endif
#ifdef WITH_FFMS2
Register<FFmpegSourceVideoProvider>("FFmpegSource");
#endif
Register<DummyVideoProvider>("Dummy", true);
Register<YUV4MPEGVideoProvider>("YUV4MPEG", true);
}

View file

@ -1,4 +1,4 @@
// Copyright (c) 2013, Thomas Goyne <plorkyeran@aegisub.org>
// Copyright (c) 2014, Thomas Goyne <plorkyeran@aegisub.org>
//
// 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 <libaegisub/fs_fwd.h>
class VideoProviderFactory final : public Factory<VideoProvider, agi::fs::path, std::string> {
public:
#include <memory>
#include <string>
#include <vector>
class VideoProvider;
struct VideoProviderFactory {
static std::vector<std::string> GetClasses();
static std::unique_ptr<VideoProvider> GetProvider(agi::fs::path const& video_file, std::string const& colormatrix);
static void RegisterProviders();
};

View file

@ -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 <boost/algorithm/string/case_conv.hpp>
#include <boost/filesystem/path.hpp>
#include <memory>
#include <vector>
/// 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<uint64_t> seek_table;
void CheckFileFormat();
void ParseFileHeader(const std::vector<std::string>& tags);
Y4M_FrameFlags ParseFrameHeader(const std::vector<std::string>& tags);
std::vector<std::string> ReadHeader(uint64_t &startpos);
int IndexFile(uint64_t pos);
public:
YUV4MPEGVideoProvider(agi::fs::path const& filename);
std::shared_ptr<VideoFrame> 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<int> 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<agi::read_file_mapping>(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<std::string> YUV4MPEGVideoProvider::ReadHeader(uint64_t &pos) {
std::vector<std::string> tags;
if (pos >= file->size())
if (pos >= file.size())
return tags;
auto len = std::min<uint64_t>(YUV4MPEG_HEADER_MAXLEN, file->size() - pos);
auto buff = file->read(pos, len);
auto len = std::min<uint64_t>(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<VideoFrame> YUV4MPEGVideoProvider::GetFrame(int n) {
throw "YUV4MPEG video provider: GetFrame: Unsupported source colorspace";
}
auto src_y = reinterpret_cast<const unsigned char *>(file->read(seek_table[n], luma_sz + chroma_sz * 2));
auto src_y = reinterpret_cast<const unsigned char *>(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<unsigned char> data;
@ -337,3 +446,8 @@ std::shared_ptr<VideoFrame> YUV4MPEGVideoProvider::GetFrame(int n) {
return std::make_shared<VideoFrame>(data.data(), w, h, w * 4, false);
}
}
std::unique_ptr<VideoProvider> CreateYUV4MPEGVideoProvider(agi::fs::path const& path, std::string const&) {
return agi::util::make_unique<YUV4MPEGVideoProvider>(path);
}

View file

@ -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 <memory>
#include <vector>
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<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<uint64_t> seek_table;
void CheckFileFormat();
void ParseFileHeader(const std::vector<std::string>& tags);
Y4M_FrameFlags ParseFrameHeader(const std::vector<std::string>& tags);
std::vector<std::string> ReadHeader(uint64_t &startpos);
int IndexFile(uint64_t pos);
public:
YUV4MPEGVideoProvider(agi::fs::path const& filename, std::string const&);
~YUV4MPEGVideoProvider();
std::shared_ptr<VideoFrame> 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<int> 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; }
};