diff --git a/aegisub/src/video_provider_cache.cpp b/aegisub/src/video_provider_cache.cpp index dd73810ab..009e4c083 100644 --- a/aegisub/src/video_provider_cache.cpp +++ b/aegisub/src/video_provider_cache.cpp @@ -41,88 +41,54 @@ #include "main.h" #include "video_frame.h" +#ifndef AGI_PRE +#include +#include +#endif -/// DOCME -/// @class CachedFrame -/// @brief DOCME -/// -/// DOCME -struct CachedFrame { - /// DOCME - AegiVideoFrame frame; - - /// DOCME - int n; +/// A video frame and its frame number +struct CachedFrame : public AegiVideoFrame { + int frame_number; }; -/// @brief Constructor -/// @param parent -/// VideoProviderCache::VideoProviderCache(VideoProvider *parent) : master(parent) -, cacheMax(OPT_GET("Provider/Video/Cache/Size")->GetInt() << 20) // convert MB to bytes +, max_cache_size(OPT_GET("Provider/Video/Cache/Size")->GetInt() << 20) // convert MB to bytes { } -/// @brief Destructor -/// VideoProviderCache::~VideoProviderCache() { - while (cache.size()) { - cache.front().frame.Clear(); - cache.pop_front(); - } + for_each(cache.begin(), cache.end(), std::tr1::mem_fn(&AegiVideoFrame::Clear)); } -/// @brief Get frame -/// @param n -/// @return -/// const AegiVideoFrame VideoProviderCache::GetFrame(int n) { + size_t total_size = 0; + // See if frame is cached - CachedFrame cached; - for (std::list::iterator cur=cache.begin();cur!=cache.end();cur++) { - cached = *cur; - if (cached.n == n) { + for (std::list::iterator cur = cache.begin(); cur != cache.end(); ++cur) { + if (cur->frame_number == n) { + cache.push_front(*cur); cache.erase(cur); - cache.push_back(cached); - return cached.frame; + return cache.front(); } + + total_size += cur->memSize; } // Not cached, retrieve it const AegiVideoFrame frame = master->GetFrame(n); - const AegiVideoFrame *srcFrame = &frame; - // Cache frame - Cache(n,*srcFrame); - return *srcFrame; -} - -/// @brief Add to cache -/// @param n -/// @param frame -void VideoProviderCache::Cache(int n,const AegiVideoFrame frame) { - // Cache full, use frame at front - if (GetCurCacheSize() >= cacheMax) { - cache.push_back(cache.front()); - cache.pop_front(); + // Cache full, use oldest frame + if (total_size >= max_cache_size) { + cache.push_front(cache.back()); + cache.pop_back(); } - // Cache not full, insert new one - else { - cache.push_back(CachedFrame()); - } + else + cache.push_front(CachedFrame()); // Cache - cache.back().n = n; - cache.back().frame.CopyFrom(frame); -} - -/// @brief Get the current size of the cache -/// @return Returns the size in bytes -unsigned VideoProviderCache::GetCurCacheSize() { - int sz = 0; - for (std::list::iterator i = cache.begin(); i != cache.end(); i++) - sz += i->frame.memSize; - return sz; + cache.front().frame_number = n; + cache.front().CopyFrom(frame); + return cache.front(); } diff --git a/aegisub/src/video_provider_cache.h b/aegisub/src/video_provider_cache.h index 5e1003748..387a495fe 100644 --- a/aegisub/src/video_provider_cache.h +++ b/aegisub/src/video_provider_cache.h @@ -36,41 +36,35 @@ #ifndef AGI_PRE #include -#include #endif #include "include/aegisub/video_provider.h" +#include + struct CachedFrame; -/// DOCME /// @class VideoProviderCache -/// @brief DOCME -/// -/// DOCME +/// @brief A wrapper around a video provider which provides LRU caching class VideoProviderCache : public VideoProvider { - /// DOCME - std::auto_ptr master; + /// The source provider to get frames from + agi::scoped_ptr master; - /// DOCME - unsigned int cacheMax; + /// @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; - /// DOCME + /// Cache of video frames with the most recently used ones at the front std::list cache; - void Cache(int n,const AegiVideoFrame frame); - AegiVideoFrame GetCachedFrame(int n); - - // Cache functions - unsigned GetCurCacheSize(); - public: - // Base methods - const AegiVideoFrame GetFrame(int n); VideoProviderCache(VideoProvider *master); - virtual ~VideoProviderCache(); + ~VideoProviderCache(); + + const AegiVideoFrame GetFrame(int n); - // Override the following methods: int GetFrameCount() const { return master->GetFrameCount(); } int GetWidth() const { return master->GetWidth(); } int GetHeight() const { return master->GetHeight(); }