memorymanager: rewrote entire memory management system

This commit is contained in:
itsmattkc
2020-02-23 20:29:51 +11:00
parent 3a90e76fec
commit 48cdb3a6dd
10 changed files with 143 additions and 147 deletions
+2
View File
@@ -22,5 +22,7 @@ set(OLIVE_SOURCES
codec/ffmpeg/ffmpegdecoder.cpp
codec/ffmpeg/ffmpegencoder.h
codec/ffmpeg/ffmpegencoder.cpp
codec/ffmpeg/ffmpegframecache.h
codec/ffmpeg/ffmpegframecache.cpp
PARENT_SCOPE
)
+11 -33
View File
@@ -1,4 +1,4 @@
/***
/***
Olive - Non-Linear Video Editor
Copyright (C) 2019 Olive Team
@@ -39,7 +39,6 @@ extern "C" {
#include "common/timecodefunctions.h"
#include "ffmpegcommon.h"
#include "render/diskmanager.h"
#include "render/memorymanager.h"
#include "render/pixelservice.h"
FFmpegDecoder::FFmpegDecoder() :
@@ -50,17 +49,13 @@ FFmpegDecoder::FFmpegDecoder() :
cache_at_eof_(false),
opts_(nullptr)
{
connect(MemoryManager::instance(), &MemoryManager::FreeMemory, this, &FFmpegDecoder::FreeMemory, Qt::DirectConnection);
clear_timer_.setInterval(5000);
clear_timer_.setSingleShot(true);
connect(&clear_timer_, &QTimer::timeout, this, &FFmpegDecoder::ClearTimerEvent);
}
FFmpegDecoder::~FFmpegDecoder()
{
Close();
clear_timer_.stop();
}
bool FFmpegDecoder::Open()
@@ -182,6 +177,8 @@ bool FFmpegDecoder::Open()
}
second_ts_ = qRound64(av_q2d(av_inv_q(avstream_->time_base)));
clear_timer_.start();
}
// All allocation succeeded so we set the state to open
@@ -215,9 +212,6 @@ FramePtr FFmpegDecoder::RetrieveVideo(const rational &timecode)
{
QMutexLocker locker(&mutex_);
// Reset clear timer
QMetaObject::invokeMethod(this, "RestartClearTimer", Qt::QueuedConnection);
if (!open_) {
qWarning() << "Tried to retrieve video on a decoder that's still closed";
return nullptr;
@@ -242,10 +236,12 @@ FramePtr FFmpegDecoder::RetrieveVideo(const rational &timecode)
if (cache_at_zero_ && target_ts < cached_frames_.first()->pts) {
found_frame = cached_frames_.first();
cached_frames_.accessedFirst();
} else if (cache_at_eof_ && target_ts > cached_frames_.last()->pts) {
found_frame = cached_frames_.last();
cached_frames_.accessedLast();
} else if (target_ts >= cached_frames_.first()->pts
&& target_ts <= cached_frames_.last()->pts) {
@@ -258,6 +254,7 @@ FramePtr FFmpegDecoder::RetrieveVideo(const rational &timecode)
|| (i < cached_frames_.size() - 1 && cached_frames_.at(i+1)->pts > target_ts)) { // Or for this frame to be the "closest"
found_frame = this_frame;
cached_frames_.accessed(i);
break;
@@ -385,10 +382,6 @@ FramePtr FFmpegDecoder::RetrieveVideo(const rational &timecode)
}
}
if (MemoryManager::instance()->RegisterMemory()) {
RemoveFirstFromFrameCache();
}
// Whatever it is, keep this frame in memory for the time being just in case
cached_frames_.append(working_frame);
}
@@ -484,6 +477,8 @@ void FFmpegDecoder::Close()
QMutexLocker locker(&mutex_);
ClearResources();
clear_timer_.stop();
}
QString FFmpegDecoder::id()
@@ -921,7 +916,7 @@ void FFmpegDecoder::CacheFrameToDisk(AVFrame *f)
}
}
void FFmpegDecoder::RemoveFirstFromFrameCache()
/*void FFmpegDecoder::RemoveFirstFromFrameCache()
{
if (cached_frames_.isEmpty()) {
return;
@@ -941,7 +936,7 @@ void FFmpegDecoder::RemoveLastFromFrameCache()
AVFrame* last = cached_frames_.takeLast();
av_frame_free(&last);
cache_at_eof_ = false;
}
}*/
void FFmpegDecoder::ClearFrameCache()
{
@@ -982,26 +977,9 @@ void FFmpegDecoder::ClearResources()
open_ = false;
}
void FFmpegDecoder::FreeMemory()
{
if (mutex_.tryLock()) {
if (cached_frames_.size() > 1) {
RemoveFirstFromFrameCache();
}
mutex_.unlock();
}
}
void FFmpegDecoder::ClearTimerEvent()
{
QMutexLocker locker(&mutex_);
ClearFrameCache();
}
void FFmpegDecoder::RestartClearTimer()
{
clear_timer_.stop();
clear_timer_.start();
cached_frames_.remove_old_frames(QDateTime::currentMSecsSinceEpoch() - 5000);
}
+4 -7
View File
@@ -34,6 +34,7 @@ extern "C" {
#include "audio/sampleformat.h"
#include "codec/decoder.h"
#include "codec/waveoutput.h"
#include "ffmpegframecache.h"
#include "project/item/footage/videostream.h"
/**
@@ -101,8 +102,8 @@ private:
void CacheFrameToDisk(AVFrame* f);
void RemoveFirstFromFrameCache();
void RemoveLastFromFrameCache();
//void RemoveFirstFromFrameCache();
//void RemoveLastFromFrameCache();
void ClearFrameCache();
void ClearResources();
@@ -116,7 +117,7 @@ private:
SwsContext* scale_ctx_;
QList<AVFrame*> cached_frames_;
FFmpegFrameCache cached_frames_;
bool cache_at_zero_;
bool cache_at_eof_;
@@ -127,12 +128,8 @@ private:
QTimer clear_timer_;
private slots:
void FreeMemory();
void ClearTimerEvent();
void RestartClearTimer();
};
#endif // FFMPEGDECODER_H
+80
View File
@@ -0,0 +1,80 @@
#include "ffmpegframecache.h"
#include <QDateTime>
#include <QDebug>
int FFmpegFrameCache::global_frame_count_ = 0;
FFmpegFrameCache::FFmpegFrameCache()
{
}
void FFmpegFrameCache::append(AVFrame *f)
{
global_frame_count_++;
frames_.append({f, QDateTime::currentMSecsSinceEpoch()});
}
void FFmpegFrameCache::clear()
{
global_frame_count_ -= frames_.size();
frames_.clear();
}
bool FFmpegFrameCache::isEmpty() const
{
return frames_.isEmpty();
}
AVFrame *FFmpegFrameCache::first() const
{
return frames_.first().frame;
}
AVFrame *FFmpegFrameCache::at(int i) const
{
return frames_.at(i).frame;
}
AVFrame *FFmpegFrameCache::last() const
{
return frames_.last().frame;
}
int FFmpegFrameCache::size() const
{
return frames_.size();
}
void FFmpegFrameCache::accessedFirst()
{
frames_.first().accessed = QDateTime::currentMSecsSinceEpoch();
}
void FFmpegFrameCache::accessedLast()
{
frames_.last().accessed = QDateTime::currentMSecsSinceEpoch();
}
void FFmpegFrameCache::accessed(int i)
{
frames_[i].accessed = QDateTime::currentMSecsSinceEpoch();
}
void FFmpegFrameCache::remove_old_frames(qint64 older_than)
{
int counter = 0;
while (!frames_.isEmpty() && frames_.first().accessed < older_than) {
CachedFrame cf = frames_.takeFirst();
av_frame_free(&cf.frame);
counter++;
}
qDebug() << " * Removed" << counter << "frames";
global_frame_count_ -= counter;
qDebug() << " * Global frames:" << global_frame_count_;
}
+43
View File
@@ -0,0 +1,43 @@
#ifndef FFMPEGFRAMECACHE_H
#define FFMPEGFRAMECACHE_H
extern "C" {
#include <libavformat/avformat.h>
}
#include <QList>
#include <QTimer>
class FFmpegFrameCache
{
public:
FFmpegFrameCache();
void append(AVFrame* f);
void clear();
bool isEmpty() const;
AVFrame* first() const;
AVFrame* at(int i) const;
AVFrame* last() const;
int size() const;
void accessedFirst();
void accessedLast();
void accessed(int i);
void remove_old_frames(qint64 older_than);
private:
struct CachedFrame {
AVFrame* frame;
qint64 accessed;
};
QList<CachedFrame> frames_;
static int global_frame_count_;
};
#endif // FFMPEGFRAMECACHE_H
-6
View File
@@ -48,7 +48,6 @@
#include "render/backend/opengl/opengltexturecache.h"
#include "render/colormanager.h"
#include "render/diskmanager.h"
#include "render/memorymanager.h"
#include "render/pixelservice.h"
#include "task/taskmanager.h"
#include "ui/style/style.h"
@@ -112,9 +111,6 @@ void Core::Start()
// Set up the index manager for renderers
IndexManager::CreateInstance();
// Set up memory manager
MemoryManager::CreateInstance();
// Load application config
Config::Load();
@@ -155,8 +151,6 @@ void Core::Stop()
IndexManager::DestroyInstance();
MemoryManager::DestroyInstance();
delete main_window_;
}
-2
View File
@@ -26,8 +26,6 @@ set(OLIVE_SOURCES
render/colorprocessor.cpp
render/diskmanager.h
render/diskmanager.cpp
render/memorymanager.h
render/memorymanager.cpp
render/pixelformat.h
render/pixelformat.cpp
render/pixelservice.h
+3 -2
View File
@@ -63,9 +63,10 @@ DecoderPtr RenderWorker::ResolveDecoderFromInput(StreamPtr stream)
QMutexLocker locker(decoder_cache_->lock());
// Access a map of Node inputs and decoder instances and retrieve a frame!
DecoderPtr decoder = decoder_cache_->Get(stream.get());
if (decoder == nullptr && stream != nullptr) {
if (!decoder && stream) {
// Create a new Decoder here
decoder = Decoder::CreateFromID(stream->footage()->decoder());
decoder->set_stream(stream);
@@ -74,7 +75,7 @@ DecoderPtr RenderWorker::ResolveDecoderFromInput(StreamPtr stream)
decoder_cache_->Add(stream.get(), decoder);
} else {
decoder = nullptr;
qWarning() << "Failed to open decoder for" << stream->footage()->filename();
qWarning() << "Failed to open decoder for" << stream->footage()->filename() << "::" << stream->index();
}
}
-65
View File
@@ -1,65 +0,0 @@
#include "memorymanager.h"
#include <QDebug>
#ifdef Q_OS_WINDOWS
#include <windows.h>
#else
#include <unistd.h>
#endif
MemoryManager* MemoryManager::instance_ = nullptr;
// FIXME: Hardcoded, should be a preference
const uint64_t MemoryManager::minimum_available_memory_ = 2147483648;
MemoryManager::MemoryManager(QObject* parent) :
QObject(parent)
{
}
void MemoryManager::CreateInstance()
{
instance_ = new MemoryManager();
}
MemoryManager *MemoryManager::instance()
{
return instance_;
}
void MemoryManager::DestroyInstance()
{
delete instance_;
instance_ = nullptr;
}
bool MemoryManager::ShouldFreeMemory()
{
return (GetAvailableMemory() < minimum_available_memory_);
}
bool MemoryManager::RegisterMemory()
{
if (ShouldFreeMemory()) {
emit FreeMemory();
return true;
}
return false;
}
uint64_t MemoryManager::GetAvailableMemory()
{
#ifdef Q_OS_WINDOWS
MEMORYSTATUSEX status;
status.dwLength = sizeof(status);
GlobalMemoryStatusEx(&status);
return status.ullAvailPhys;
#else
long pages = sysconf(_SC_AVPHYS_PAGES);
long page_size = sysconf(_SC_PAGE_SIZE);
return pages * page_size;
#endif
}
-32
View File
@@ -1,32 +0,0 @@
#ifndef MEMORYMANAGER_H
#define MEMORYMANAGER_H
#include <QObject>
class MemoryManager : public QObject
{
Q_OBJECT
public:
MemoryManager(QObject* parent = nullptr);
static void CreateInstance();
static MemoryManager* instance();
static void DestroyInstance();
static bool ShouldFreeMemory();
bool RegisterMemory();
signals:
void FreeMemory();
private:
static uint64_t GetAvailableMemory();
static MemoryManager* instance_;
static const uint64_t minimum_available_memory_;
};
#endif // MEMORYMANAGER_H