Clean up VideoProviderCache a bit

Originally committed to SVN as r6454.
This commit is contained in:
Thomas Goyne 2012-02-07 23:16:41 +00:00
parent 1075b71976
commit 003322813e
2 changed files with 40 additions and 80 deletions

View file

@ -41,88 +41,54 @@
#include "main.h"
#include "video_frame.h"
#ifndef AGI_PRE
#include <algorithm>
#include <tr1/functional>
#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<CachedFrame>::iterator cur=cache.begin();cur!=cache.end();cur++) {
cached = *cur;
if (cached.n == n) {
for (std::list<CachedFrame>::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;
// Cache full, use oldest frame
if (total_size >= max_cache_size) {
cache.push_front(cache.back());
cache.pop_back();
}
/// @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 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<CachedFrame>::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();
}

View file

@ -36,41 +36,35 @@
#ifndef AGI_PRE
#include <list>
#include <memory>
#endif
#include "include/aegisub/video_provider.h"
#include <libaegisub/scoped_ptr.h>
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<VideoProvider> master;
/// The source provider to get frames from
agi::scoped_ptr<VideoProvider> 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<CachedFrame> 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(); }