diff --git a/prs/prs_file.cpp b/prs/prs_file.cpp index 9cd897ea7..9415dd3d3 100644 --- a/prs/prs_file.cpp +++ b/prs/prs_file.cpp @@ -49,6 +49,9 @@ /////////////// // Constructor PRSFile::PRSFile () { + // Cache data + cacheMemSize = 0; + maxCache = 8 << 20; } @@ -56,6 +59,7 @@ PRSFile::PRSFile () { // Destructor PRSFile::~PRSFile() { Reset(); + ClearCache(); } @@ -71,6 +75,17 @@ void PRSFile::Reset() { } +/////////////////// +// Clear the cache +void PRSFile::ClearCache() { + // Clear list of cached frames + frameCache.clear(); + + // Zero size + cacheMemSize = 0; +} + + //////// // Save void PRSFile::Save(std::string path) { @@ -251,23 +266,61 @@ void PRSFile::DrawFrame(int n,PRSVideoFrame *frame) { // Draw the blocks int nblocks = (int) blocks.size(); for (int i=0;iid); - if (!image) continue; - - // Decode PNG - PRSVideoFrame *overFrame = image->GetDecodedFrame(); + PRSVideoFrame *overFrame = CachedGetFrameByID(display->id); // Draw image on frame if (overFrame) overFrame->Overlay(frame,display->x,display->y,display->alpha,display->blend); - // Clean up - delete overFrame; + // DON'T delete the frame! + // The cache takes care of doing so. } } +/////////////////////////////////////////////////////////////////// +// Gets a frame from cache, or load it there if it's not available +PRSVideoFrame* PRSFile::CachedGetFrameByID(int id) { + // Check if the image is already decoded on cache, fetch it if it is + PRSVideoFrame *frame = NULL; + std::list::iterator cur; + for (cur=frameCache.begin();cur!=frameCache.end();cur++) { + if ((*cur).id == id) { + return (*cur).frame; + } + } + + // It isn't; decode and add it to cache + // Get image + PRSImage *image = GetImageByID(id); + if (!image) return NULL; + + // Get frame + frame = image->GetDecodedFrame(); + + // Add to cache + if (frame) { + // Add and raise size + PRSCachedFrame cached; + cached.frame = frame; + cached.id = id; + frameCache.push_front(cached); + cached.frame = NULL; + cacheMemSize += frame->GetSize(); + + // If memory has been exceeded, remove stuff from the back until it isn't anymore + while (cacheMemSize > maxCache && frameCache.size() > 1) { + cacheMemSize -= frameCache.back().frame->GetSize(); + frameCache.pop_back(); + } + } + + // Return it + return frame; +} + + //////////////////////////////////////////////// // Finds which display blocks are at a position void PRSFile::GetDisplayBlocksAtFrame(int n,std::vector &blocks) { diff --git a/prs/prs_file.h b/prs/prs_file.h index 39cdd885c..455931840 100644 --- a/prs/prs_file.h +++ b/prs/prs_file.h @@ -56,6 +56,9 @@ class PRSDisplay; class PRSFile { private: std::list entryList; + std::list frameCache; + int cacheMemSize; + int maxCache; void Reset(); public: @@ -74,6 +77,8 @@ public: bool HasDataAtFrame(int n); void DrawFrame(int n,PRSVideoFrame *frame); PRSImage *GetImageByID(int id); + PRSVideoFrame *CachedGetFrameByID(int id); + void ClearCache(); PRSImage *FindDuplicateImage(PRSImage *img); }; diff --git a/prs/prs_video_frame.cpp b/prs/prs_video_frame.cpp index 5cf5eecb8..e1c339546 100644 --- a/prs/prs_video_frame.cpp +++ b/prs/prs_video_frame.cpp @@ -141,3 +141,26 @@ void PRSVideoFrame::Overlay(PRSVideoFrame *dstFrame,int x,int y,unsigned char al } } } + + +////////////////// +// Get frame size +int PRSVideoFrame::GetSize() { + return sizeof(PRSVideoFrame) + pitch * h; +} + + +////////////////////// +// Cached constructor +PRSCachedFrame::PRSCachedFrame () { + frame = 0; + id = -1; +} + + +///////////////////// +// Cached destructor +PRSCachedFrame::~PRSCachedFrame() { + delete frame; + frame = 0; +} diff --git a/prs/prs_video_frame.h b/prs/prs_video_frame.h index e60852a85..3738e927b 100644 --- a/prs/prs_video_frame.h +++ b/prs/prs_video_frame.h @@ -64,4 +64,17 @@ public: ~PRSVideoFrame(); void Overlay(PRSVideoFrame *dst,int x,int y,unsigned char alpha=255,unsigned char blend=0); + int GetSize(); +}; + + +/////////////////////////// +// Video frame cache class +class PRSCachedFrame { +public: + PRSCachedFrame(); + ~PRSCachedFrame(); + + PRSVideoFrame *frame; + int id; };