From bed7f3ed8ddf7707e4fd45e64e557e1e7c886c19 Mon Sep 17 00:00:00 2001 From: Rodrigo Braz Monteiro Date: Thu, 6 Mar 2008 19:20:25 +0000 Subject: [PATCH] Modified the video provider interface to be a true interface, and moved all caching routines to another video provider that can be chained. Originally committed to SVN as r1918. --- aegisub/video_provider.cpp | 109 ++----------------- aegisub/video_provider.h | 57 ++++------ aegisub/video_provider_avs.cpp | 2 +- aegisub/video_provider_avs.h | 2 +- aegisub/video_provider_cache.cpp | 176 +++++++++++++++++++++++++++++++ aegisub/video_provider_cache.h | 93 ++++++++++++++++ aegisub/video_provider_dshow.h | 3 +- aegisub/video_provider_dummy.cpp | 2 +- aegisub/video_provider_dummy.h | 4 +- aegisub/video_provider_lavc.cpp | 2 +- aegisub/video_provider_lavc.h | 2 +- 11 files changed, 306 insertions(+), 146 deletions(-) create mode 100644 aegisub/video_provider_cache.cpp create mode 100644 aegisub/video_provider_cache.h diff --git a/aegisub/video_provider.cpp b/aegisub/video_provider.cpp index 7975454b4..e0bcd1200 100644 --- a/aegisub/video_provider.cpp +++ b/aegisub/video_provider.cpp @@ -50,105 +50,7 @@ #include "video_provider_lavc.h" #endif #include "video_provider_dummy.h" - - -/////////////// -// Constructor -VideoProvider::VideoProvider() { - cacheMax = 0; -} - - -////////////// -// Destructor -VideoProvider::~VideoProvider() { - ClearCache(); - tempRGBFrame.Clear(); -} - - -///////////// -// Get frame -const AegiVideoFrame VideoProvider::GetFrame(int n,int format) { - // See if frame is cached - CachedFrame cached; - for (std::list::iterator cur=cache.begin();cur!=cache.end();cur++) { - cached = *cur; - if (cached.n == n) { - cache.erase(cur); - cache.push_back(cached); - return cached.frame; - } - } - - // Not cached, retrieve it - const AegiVideoFrame frame = DoGetFrame(n); - const AegiVideoFrame *srcFrame = &frame; - - // Convert to compatible format - if (!(frame.format & format)) { - if (format & FORMAT_RGB32) tempRGBFrame.format = FORMAT_RGB32; - else throw _T("Unable to negotiate video frame format."); - tempRGBFrame.w = frame.w; - tempRGBFrame.h = frame.h; - tempRGBFrame.pitch[0] = frame.w * 4; - tempRGBFrame.ConvertFrom(frame); - srcFrame = &tempRGBFrame; - } - - // Cache frame - Cache(n,*srcFrame); - return *srcFrame; -} - - -//////////////// -// Get as float -void VideoProvider::GetFloatFrame(float* buffer, int n) { - const AegiVideoFrame frame = GetFrame(n); - frame.GetFloat(buffer); -} - - -////////////////////////// -// Set maximum cache size -void VideoProvider::SetCacheMax(int n) { - if (n < 0) n = 0; - cacheMax = n; -} - - -//////////////// -// Add to cache -void VideoProvider::Cache(int n,const AegiVideoFrame frame) { - // Cache enabled? - if (cacheMax == 0) return; - - // Cache full, use frame at front - if (cache.size() >= cacheMax) { - cache.push_back(cache.front()); - cache.pop_front(); - } - - // Cache not full, insert new one - else { - cache.push_back(CachedFrame()); - } - - // Cache - cache.front().n = n; - cache.front().frame.CopyFrom(frame); -} - - -/////////////// -// Clear cache -void VideoProvider::ClearCache() { - while (cache.size()) { - cache.front().frame.Clear(); - cache.pop_front(); - } -} +#include "video_provider_cache.h" //////////////// @@ -175,8 +77,15 @@ VideoProvider *VideoProviderFactory::GetProvider(wxString video,double fps) { wxString error; for (unsigned int i=0;iCreateProvider(video,fps); - if (provider) return provider; + if (provider) { + // Cache if necessary + if (provider->GetDesiredCacheSize()) { + provider = new VideoProviderCache(provider); + } + return provider; + } } catch (wxString err) { error += list[i] + _T(" factory: ") + err + _T("\n"); } catch (const wxChar *err) { error += list[i] + _T(" factory: ") + wxString(err) + _T("\n"); } diff --git a/aegisub/video_provider.h b/aegisub/video_provider.h index 41f65475e..49a4bdded 100644 --- a/aegisub/video_provider.h +++ b/aegisub/video_provider.h @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2007, Rodrigo Braz Monteiro, Fredrik Mellbin +// Copyright (c) 2006-2008, Rodrigo Braz Monteiro, Fredrik Mellbin // All rights reserved. // // Redistribution and use in source and binary forms, with or without @@ -39,7 +39,6 @@ ////////// // Headers -#include #include #include "video_frame.h" #include "factory.h" @@ -50,54 +49,38 @@ class SubtitlesProvider; -//////////////// -// Cached frame -class CachedFrame { -public: - AegiVideoFrame frame; - int n; -}; - - //////////////////////////// // Video Provider interface class VideoProvider { -private: - unsigned int cacheMax; - std::list cache; - AegiVideoFrame tempRGBFrame; - - void Cache(int n,const AegiVideoFrame frame); - AegiVideoFrame GetCachedFrame(int n); - -protected: - // Override this method to actually get frames - virtual const AegiVideoFrame DoGetFrame(int n)=0; // Get frame as AegiVideoFrame - - // Cache functions - void SetCacheMax(int n_frames); - void ClearCache(); - public: - // Base methods - void GetFloatFrame(float* Buffer, int n); // Get frame as float - const AegiVideoFrame GetFrame(int n, int formatMask=FORMAT_RGB32); - VideoProvider(); - virtual ~VideoProvider(); + // Virtual destructor + virtual ~VideoProvider() {} - // Subtitles - virtual SubtitlesProvider *GetAsSubtitlesProvider() { return NULL; } // Get subtitles provider + // Override this method to actually get frames + virtual const AegiVideoFrame GetFrame(int n, int formatMask)=0; - // Override the following methods: + // Override the following methods to get video information: virtual int GetPosition()=0; // Get the number of the last frame loaded virtual int GetFrameCount()=0; // Get total number of frames virtual int GetWidth()=0; // Returns the video width in pixels virtual int GetHeight()=0; // Returns the video height in pixels virtual double GetFPS()=0; // Get framerate in frames per second - virtual void OverrideFrameTimeList(wxArrayInt list) {} // Override the list with the provided one, for VFR handling - virtual bool IsNativelyByFrames() { return false; } + + // Use this to set any post-loading warnings, such as "being loaded with unreliable seeking" virtual wxString GetWarning() { return _T(""); } + + // Name of decoder, e.g. "Avisynth/FFMPegSource" virtual wxString GetDecoderName() { return _("Unknown"); } + + // How many frames does this provider wants that Aegisub caches? Set to 0 if it doesn't require caching. + virtual int GetDesiredCacheSize() { return 0; } + + // For providers that are natively time-based (e.g. DirectShow) + virtual bool IsNativelyByFrames() { return true; } + virtual void OverrideFrameTimeList(wxArrayInt list) {} // Override the list with the provided one, for VFR handling + + // If this video provider has a built-in subtitles provider, return that + virtual SubtitlesProvider *GetAsSubtitlesProvider() { return NULL; } }; diff --git a/aegisub/video_provider_avs.cpp b/aegisub/video_provider_avs.cpp index 536b6212e..c1a07017e 100644 --- a/aegisub/video_provider_avs.cpp +++ b/aegisub/video_provider_avs.cpp @@ -302,7 +302,7 @@ PClip AvisynthVideoProvider::OpenVideo(wxString _filename, bool mpeg2dec3_priori //////////////////////// // Actually get a frame -const AegiVideoFrame AvisynthVideoProvider::DoGetFrame(int _n) { +const AegiVideoFrame AvisynthVideoProvider::GetFrame(int _n,int formatMask) { // Transform n if overriden int n = _n; if (frameTime.Count()) { diff --git a/aegisub/video_provider_avs.h b/aegisub/video_provider_avs.h index 2b6b3d20e..963afb445 100644 --- a/aegisub/video_provider_avs.h +++ b/aegisub/video_provider_avs.h @@ -79,7 +79,7 @@ public: void LoadSubtitles(AssFile *subs); bool LockedToVideo() { return true; } - const AegiVideoFrame DoGetFrame(int n); + const AegiVideoFrame GetFrame(int n,int formatMask); void GetFloatFrame(float* Buffer, int n); // properties diff --git a/aegisub/video_provider_cache.cpp b/aegisub/video_provider_cache.cpp new file mode 100644 index 000000000..00c13929b --- /dev/null +++ b/aegisub/video_provider_cache.cpp @@ -0,0 +1,176 @@ +// Copyright (c) 2008, 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 +// +// Website: http://aegisub.cellosoft.com +// Contact: mailto:zeratul@cellosoft.com +// + + +/////////// +// Headers +#include "video_provider_cache.h" + + +/////////////// +// Constructor +VideoProviderCache::VideoProviderCache(VideoProvider *parent) { + master = parent; + cacheMax = 0; + SetCacheMax(parent->GetDesiredCacheSize()); +} + + +////////////// +// Destructor +VideoProviderCache::~VideoProviderCache() { + delete master; + ClearCache(); + tempRGBFrame.Clear(); +} + + +///////////// +// Get frame +const AegiVideoFrame VideoProviderCache::GetFrame(int n,int format) { + // See if frame is cached + CachedFrame cached; + for (std::list::iterator cur=cache.begin();cur!=cache.end();cur++) { + cached = *cur; + if (cached.n == n) { + cache.erase(cur); + cache.push_back(cached); + return cached.frame; + } + } + + // Not cached, retrieve it + const AegiVideoFrame frame = master->GetFrame(n,FORMAT_RGB32); + const AegiVideoFrame *srcFrame = &frame; + + // Convert to compatible format + if (!(frame.format & format)) { + if (format & FORMAT_RGB32) tempRGBFrame.format = FORMAT_RGB32; + else throw _T("Unable to negotiate video frame format."); + tempRGBFrame.w = frame.w; + tempRGBFrame.h = frame.h; + tempRGBFrame.pitch[0] = frame.w * 4; + tempRGBFrame.ConvertFrom(frame); + srcFrame = &tempRGBFrame; + } + + // Cache frame + pos = n; + Cache(n,*srcFrame); + return *srcFrame; +} + + +//////////////// +// Get as float +void VideoProviderCache::GetFloatFrame(float* buffer, int n) { + const AegiVideoFrame frame = GetFrame(n,FORMAT_RGB32); + frame.GetFloat(buffer); +} + + +////////////////////////// +// Set maximum cache size +void VideoProviderCache::SetCacheMax(int n) { + if (n < 0) n = 0; + cacheMax = n; +} + + +//////////////// +// Add to cache +void VideoProviderCache::Cache(int n,const AegiVideoFrame frame) { + // Cache enabled? + if (cacheMax == 0) return; + + // Cache full, use frame at front + if (cache.size() >= cacheMax) { + cache.push_back(cache.front()); + cache.pop_front(); + } + + // Cache not full, insert new one + else { + cache.push_back(CachedFrame()); + } + + // Cache + cache.front().n = n; + cache.front().frame.CopyFrom(frame); +} + + +/////////////// +// Clear cache +void VideoProviderCache::ClearCache() { + while (cache.size()) { + cache.front().frame.Clear(); + cache.pop_front(); + } +} + + +/////////////////// +// Wrapper methods +SubtitlesProvider *VideoProviderCache::GetAsSubtitlesProvider() { + return master->GetAsSubtitlesProvider(); +} +int VideoProviderCache::GetPosition() { + return pos; +} +int VideoProviderCache::GetFrameCount() { + return master->GetFrameCount(); +} +int VideoProviderCache::GetWidth() { + return master->GetWidth(); +} +int VideoProviderCache::GetHeight() { + return master->GetHeight(); +} +double VideoProviderCache::GetFPS() { + return master->GetFPS(); +} +void VideoProviderCache::OverrideFrameTimeList(wxArrayInt list) { + master->OverrideFrameTimeList(list); +} +bool VideoProviderCache::IsNativelyByFrames() { + return master->IsNativelyByFrames(); +} +wxString VideoProviderCache::GetWarning() { + return master->GetWarning(); +} +wxString VideoProviderCache::GetDecoderName() { + return master->GetDecoderName(); +} diff --git a/aegisub/video_provider_cache.h b/aegisub/video_provider_cache.h new file mode 100644 index 000000000..f15613582 --- /dev/null +++ b/aegisub/video_provider_cache.h @@ -0,0 +1,93 @@ +// Copyright (c) 2008, 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 +// +// Website: http://aegisub.cellosoft.com +// Contact: mailto:zeratul@cellosoft.com +// + + +#pragma once + + +////////// +// Headers +#include +#include "video_provider.h" + + +//////////////// +// Cached frame +class CachedFrame { +public: + AegiVideoFrame frame; + int n; +}; + + +//////////////////////////// +// Video Provider interface +class VideoProviderCache : public VideoProvider { +private: + VideoProvider *master; + unsigned int cacheMax; + std::list cache; + AegiVideoFrame tempRGBFrame; + int pos; + + void Cache(int n,const AegiVideoFrame frame); + AegiVideoFrame GetCachedFrame(int n); + +protected: + // Cache functions + void SetCacheMax(int n_frames); + void ClearCache(); + +public: + // Base methods + void GetFloatFrame(float* Buffer, int n); // Get frame as float + const AegiVideoFrame GetFrame(int n, int formatMask); + VideoProviderCache(VideoProvider *master); + virtual ~VideoProviderCache(); + + // Subtitles + virtual SubtitlesProvider *GetAsSubtitlesProvider(); // Get subtitles provider + + // Override the following methods: + virtual int GetPosition(); // Get the number of the last frame loaded + virtual int GetFrameCount(); // Get total number of frames + virtual int GetWidth(); // Returns the video width in pixels + virtual int GetHeight(); // Returns the video height in pixels + virtual double GetFPS(); // Get framerate in frames per second + virtual void OverrideFrameTimeList(wxArrayInt list); // Override the list with the provided one, for VFR handling + virtual bool IsNativelyByFrames(); + virtual wxString GetWarning(); + virtual wxString GetDecoderName(); +}; diff --git a/aegisub/video_provider_dshow.h b/aegisub/video_provider_dshow.h index 33ad2ffcf..631d9e9ee 100644 --- a/aegisub/video_provider_dshow.h +++ b/aegisub/video_provider_dshow.h @@ -102,7 +102,7 @@ public: void RefreshSubtitles(); - const AegiVideoFrame DoGetFrame(int n); + const AegiVideoFrame GetFrame(int n, int formatMask); void GetFloatFrame(float* Buffer, int n); int GetPosition() { return last_fnum; }; @@ -111,6 +111,7 @@ public: int GetWidth() { return width; }; int GetHeight() { return height; }; wxString GetDecoderName() { return _("DirectShow"); } + bool IsNativelyByFrames() { return false; } void OverrideFrameTimeList(wxArrayInt list); }; diff --git a/aegisub/video_provider_dummy.cpp b/aegisub/video_provider_dummy.cpp index 8274bfdf9..3422fbf1e 100644 --- a/aegisub/video_provider_dummy.cpp +++ b/aegisub/video_provider_dummy.cpp @@ -203,7 +203,7 @@ wxString DummyVideoProvider::MakeFilename(double fps, int frames, int _width, in ///////////// // Get frame -const AegiVideoFrame DummyVideoProvider::DoGetFrame(int n) { +const AegiVideoFrame DummyVideoProvider::GetFrame(int n,int formatMask) { lastFrame = n; return frame; } diff --git a/aegisub/video_provider_dummy.h b/aegisub/video_provider_dummy.h index aaff8c3fb..90dd11102 100644 --- a/aegisub/video_provider_dummy.h +++ b/aegisub/video_provider_dummy.h @@ -58,14 +58,12 @@ private: void Create(double fps, int frames, int _width, int _height, const wxColour &colour, bool pattern); -protected: - const AegiVideoFrame DoGetFrame(int n); - public: DummyVideoProvider(wxString filename, double fps); DummyVideoProvider(double fps, int frames, int _width, int _height, const wxColour &colour, bool pattern); ~DummyVideoProvider(); + const AegiVideoFrame GetFrame(int n, int formatMask); static wxString MakeFilename(double fps, int frames, int _width, int _height, const wxColour &colour, bool pattern); int GetPosition(); diff --git a/aegisub/video_provider_lavc.cpp b/aegisub/video_provider_lavc.cpp index 84c3b17ac..9877cf310 100644 --- a/aegisub/video_provider_lavc.cpp +++ b/aegisub/video_provider_lavc.cpp @@ -298,7 +298,7 @@ wxBitmap LAVCVideoProvider::AVFrameToWX(AVFrame *source, int n) { ///////////// // Get frame -const AegiVideoFrame LAVCVideoProvider::DoGetFrame(int n) { +const AegiVideoFrame LAVCVideoProvider::GetFrame(int n,int formatType) { // Return stored frame n = MID(0,n,GetFrameCount()-1); if (n == frameNumber) { diff --git a/aegisub/video_provider_lavc.h b/aegisub/video_provider_lavc.h index c357b5f7c..120e70bf3 100644 --- a/aegisub/video_provider_lavc.h +++ b/aegisub/video_provider_lavc.h @@ -92,12 +92,12 @@ private: void Close(); protected: - const AegiVideoFrame DoGetFrame(int n); public: LAVCVideoProvider(wxString filename, double fps); ~LAVCVideoProvider(); + const AegiVideoFrame GetFrame(int n,int formatType); int GetPosition(); int GetFrameCount();