diff --git a/app/codec/CMakeLists.txt b/app/codec/CMakeLists.txt
index 791500cdd..606efc295 100644
--- a/app/codec/CMakeLists.txt
+++ b/app/codec/CMakeLists.txt
@@ -25,6 +25,8 @@ set(OLIVE_SOURCES
codec/encoder.cpp
codec/frame.h
codec/frame.cpp
+ codec/framepool.h
+ codec/framepool.cpp
codec/samplebuffer.h
codec/samplebuffer.cpp
codec/waveinput.h
diff --git a/app/codec/ffmpeg/CMakeLists.txt b/app/codec/ffmpeg/CMakeLists.txt
index bee2d0e9e..5cac2e216 100644
--- a/app/codec/ffmpeg/CMakeLists.txt
+++ b/app/codec/ffmpeg/CMakeLists.txt
@@ -23,7 +23,5 @@ 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
)
diff --git a/app/codec/ffmpeg/avframeptr.h b/app/codec/ffmpeg/avframeptr.h
index b0f4bda95..232470910 100644
--- a/app/codec/ffmpeg/avframeptr.h
+++ b/app/codec/ffmpeg/avframeptr.h
@@ -1,3 +1,23 @@
+/***
+
+ Olive - Non-Linear Video Editor
+ Copyright (C) 2019 Olive Team
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+***/
+
#ifndef AVFRAMEPTR_H
#define AVFRAMEPTR_H
@@ -17,8 +37,6 @@ class AVFrameWrapper {
public:
AVFrameWrapper() {
frame_ = av_frame_alloc();
- birthtime_ = QDateTime::currentMSecsSinceEpoch();
- accessed_ = birthtime_;
}
virtual ~AVFrameWrapper() {
@@ -31,25 +49,9 @@ public:
return frame_;
}
- inline const qint64& birthtime() const {
- return birthtime_;
- }
-
- inline const qint64& last_accessed() const {
- return accessed_;
- }
-
- void access() {
- accessed_ = QDateTime::currentMSecsSinceEpoch();
- }
-
private:
AVFrame* frame_;
- qint64 birthtime_;
-
- qint64 accessed_;
-
};
using AVFramePtr = std::shared_ptr;
diff --git a/app/codec/ffmpeg/ffmpegdecoder.cpp b/app/codec/ffmpeg/ffmpegdecoder.cpp
index fbbb869ee..154b61877 100644
--- a/app/codec/ffmpeg/ffmpegdecoder.cpp
+++ b/app/codec/ffmpeg/ffmpegdecoder.cpp
@@ -57,6 +57,8 @@ FFmpegDecoder::FFmpegDecoder() :
clear_timer_.setInterval(kMaxFrameLife);
clear_timer_.moveToThread(qApp->thread());
connect(&clear_timer_, &QTimer::timeout, this, &FFmpegDecoder::ClearTimerEvent);
+
+ av_buffer_pool_init(20, av_buffer_allocz);
}
FFmpegDecoder::~FFmpegDecoder()
@@ -197,39 +199,33 @@ FramePtr FFmpegDecoder::RetrieveVideo(const rational &timecode, const int &divid
i->cache_lock()->unlock();
break;
- } else if (i->CacheWillContainTime(target_ts)) {
+ } else if (i->CacheWillContainTime(target_ts) || i->CacheCouldContainTime(target_ts)) {
// Found our instance, allow others to enter the list
list_locker.unlock();
- do {
- // Allow instance to continue to the next frame
- i->cache_wait_cond()->wait(i->cache_lock());
+ if (i->IsWorking()) {
+ do {
+ // Allow instance to continue to the next frame
+ i->cache_wait_cond()->wait(i->cache_lock());
- // See if the cache now contains this frame, if so we'll exit this loop
- if (i->CacheContainsTime(target_ts)) {
- return_frame = i->GetFrameFromCache(target_ts);
+ // See if the cache now contains this frame, if so we'll exit this loop
+ if (i->CacheContainsTime(target_ts)) {
+ return_frame = i->GetFrameFromCache(target_ts);
+ } else if (!i->IsWorking()) {
+ // Grab this instance and continue it
+ working_instance = i;
+ break;
+ }
+ } while (!return_frame);
+
+ if (working_instance != i) {
+ // We don't unlock if we're continuing this instance ourselves
+ i->cache_lock()->unlock();
}
- } while (!return_frame);
-
- // Got our frame, allow cache to continue
- i->cache_lock()->unlock();
- break;
-
- } else if (i->CacheCouldContainTime(target_ts)) {
-
- // Found our instance, allow others to enter the list
- list_locker.unlock();
-
- // Wait for this instance to finish working
- while (i->IsWorking()) {
- i->cache_wait_cond()->wait(i->cache_lock());
+ } else {
+ working_instance = i;
}
-
- // Grab this instance
- working_instance = i;
-
- // We DON'T unlock here, since we'll be starting our own retrieve
break;
} else if (i->IsWorking()) {
@@ -877,7 +873,7 @@ void FFmpegDecoderInstance::ClearFrameCache()
cache_at_zero_ = false;
}
-AVFramePtr FFmpegDecoderInstance::RetrieveFrame(const int64_t& target_ts, bool cache_is_locked)
+FramePool::ElementPtr FFmpegDecoderInstance::RetrieveFrame(const int64_t& target_ts, bool cache_is_locked)
{
if (!cache_is_locked) {
cache_lock_.lock();
@@ -889,9 +885,7 @@ AVFramePtr FFmpegDecoderInstance::RetrieveFrame(const int64_t& target_ts, bool c
cache_target_time_ = target_ts;
// If the frame wasn't in the frame cache, see if this frame cache is too old to use
- if (cached_frames_.isEmpty()
- || target_ts < cached_frames_.first()->frame()->pts
- || target_ts > cached_frames_.last()->frame()->pts + 2*second_ts_) {
+ if (!CacheCouldContainTime(target_ts)) {
ClearFrameCache();
Seek(seek_ts);
@@ -904,7 +898,7 @@ AVFramePtr FFmpegDecoderInstance::RetrieveFrame(const int64_t& target_ts, bool c
int ret;
AVPacket* pkt = av_packet_alloc();
- AVFramePtr return_frame = nullptr;
+ FramePool::ElementPtr return_frame = nullptr;
// Allocate a new frame
AVFrameWrapper working_frame;
@@ -960,16 +954,17 @@ AVFramePtr FFmpegDecoderInstance::RetrieveFrame(const int64_t& target_ts, bool c
} else {
// Whatever it is, keep this frame in memory for the time being just in case
- AVFramePtr cached = cached_frames_.append(working_frame.frame());
+ FramePool::ElementPtr cached = frame_pool_.Get();
+ cached->set_timestamp(working_frame.frame()->pts);
cache_wait_cond_.wakeAll();
cache_lock_.unlock();
// If this is a valid frame, see if this or the frame before it are the one we need
- if (cached->frame()->pts == target_ts) {
+ if (cached->timestamp() == target_ts) {
return_frame = cached;
break;
- } else if (cached->frame()->pts > target_ts) {
+ } else if (cached->timestamp() > target_ts) {
if (cached_frames_.isEmpty() && cache_at_zero_) {
return_frame = cached;
break;
@@ -1029,7 +1024,7 @@ int64_t FFmpegDecoderInstance::RangeStart() const
if (cached_frames_.isEmpty()) {
return AV_NOPTS_VALUE;
}
- return cached_frames_.first()->frame()->pts;
+ return cached_frames_.first()->timestamp();
}
int64_t FFmpegDecoderInstance::RangeEnd() const
@@ -1037,25 +1032,25 @@ int64_t FFmpegDecoderInstance::RangeEnd() const
if (cached_frames_.isEmpty()) {
return AV_NOPTS_VALUE;
}
- return cached_frames_.last()->frame()->pts;
+ return cached_frames_.last()->timestamp();
}
bool FFmpegDecoderInstance::CacheContainsTime(const int64_t &t) const
{
return !cached_frames_.isEmpty()
&& ((RangeStart() <= t && RangeEnd() >= t)
- || (cache_at_zero_ && t < cached_frames_.first()->frame()->pts)
- || (cache_at_eof_ && t > cached_frames_.last()->frame()->pts));
+ || (cache_at_zero_ && t < cached_frames_.first()->timestamp())
+ || (cache_at_eof_ && t > cached_frames_.last()->timestamp()));
}
bool FFmpegDecoderInstance::CacheWillContainTime(const int64_t &t) const
{
- return !cached_frames_.isEmpty() && t >= cached_frames_.first()->frame()->pts && t <= cache_target_time_;
+ return !cached_frames_.isEmpty() && t >= cached_frames_.first()->timestamp() && t <= cache_target_time_;
}
bool FFmpegDecoderInstance::CacheCouldContainTime(const int64_t &t) const
{
- return !cached_frames_.isEmpty() && t >= cached_frames_.first()->frame()->pts && t <= (cache_target_time_ + 2*second_ts_);
+ return !cached_frames_.isEmpty() && t >= cached_frames_.first()->timestamp() && t <= (cache_target_time_ + 2*second_ts_);
}
bool FFmpegDecoderInstance::CacheIsEmpty() const
@@ -1063,15 +1058,15 @@ bool FFmpegDecoderInstance::CacheIsEmpty() const
return cached_frames_.isEmpty();
}
-AVFramePtr FFmpegDecoderInstance::GetFrameFromCache(const int64_t &t) const
+FramePool::ElementPtr FFmpegDecoderInstance::GetFrameFromCache(const int64_t &t) const
{
- if (t < cached_frames_.first()->frame()->pts) {
+ if (t < cached_frames_.first()->timestamp()) {
if (cache_at_zero_) {
return cached_frames_.first();
}
- } else if (t > cached_frames_.last()->frame()->pts) {
+ } else if (t > cached_frames_.last()->timestamp()) {
if (cache_at_eof_) {
return cached_frames_.last();
@@ -1081,10 +1076,10 @@ AVFramePtr FFmpegDecoderInstance::GetFrameFromCache(const int64_t &t) const
// We already have this frame in the cache, find it
for (int i=0;iframe()->pts == t // Test for an exact match
- || (i < cached_frames_.size() - 1 && cached_frames_.at(i+1)->frame()->pts > t)) { // Or for this frame to be the "closest"
+ if (this_frame->timestamp() == t // Test for an exact match
+ || (i < cached_frames_.size() - 1 && cached_frames_.at(i+1)->timestamp() > t)) { // Or for this frame to be the "closest"
return this_frame;
@@ -1097,7 +1092,8 @@ AVFramePtr FFmpegDecoderInstance::GetFrameFromCache(const int64_t &t) const
void FFmpegDecoderInstance::RemoveFramesBefore(const qint64 &t)
{
- if (cached_frames_.remove_old_frames(t)) {
+ while (cached_frames_.size() > 1 && cached_frames_.first()->last_accessed() < t) {
+ cached_frames_.removeFirst();
cache_at_zero_ = false;
}
}
@@ -1186,6 +1182,14 @@ FFmpegDecoderInstance::FFmpegDecoderInstance(const char *filename, int stream_in
return;
}
+ // Create buffer pool
+ if (avstream_->codecpar->codec_type == AVMEDIA_TYPE_VIDEO
+ && !frame_pool_.Allocate()) {
+ qDebug() << "Failed to allocate frame pool";
+ ClearResources();
+ return;
+ }
+
// Store one second in the source's timebase
second_ts_ = qRound64(av_q2d(av_inv_q(avstream_->time_base)));
}
@@ -1218,6 +1222,8 @@ void FFmpegDecoderInstance::ClearResources()
avformat_close_input(&fmt_ctx_);
fmt_ctx_ = nullptr;
}
+
+ frame_pool_.Destroy();
}
void FFmpegDecoder::ClearTimerEvent()
diff --git a/app/codec/ffmpeg/ffmpegdecoder.h b/app/codec/ffmpeg/ffmpegdecoder.h
index 40643c7a4..746446f1e 100644
--- a/app/codec/ffmpeg/ffmpegdecoder.h
+++ b/app/codec/ffmpeg/ffmpegdecoder.h
@@ -35,8 +35,8 @@ extern "C" {
#include "audio/sampleformat.h"
#include "avframeptr.h"
#include "codec/decoder.h"
+#include "codec/framepool.h"
#include "codec/waveoutput.h"
-#include "ffmpegframecache.h"
#include "project/item/footage/videostream.h"
OLIVE_NAMESPACE_ENTER
@@ -56,7 +56,7 @@ public:
bool CacheWillContainTime(const int64_t& t) const;
bool CacheCouldContainTime(const int64_t& t) const;
bool CacheIsEmpty() const;
- AVFramePtr GetFrameFromCache(const int64_t& t) const;
+ FramePool::ElementPtr GetFrameFromCache(const int64_t& t) const;
void RemoveFramesBefore(const qint64& t);
@@ -65,7 +65,7 @@ public:
void ClearFrameCache();
- AVFramePtr RetrieveFrame(const int64_t &target_ts, bool cache_is_locked);
+ FramePool::ElementPtr RetrieveFrame(const int64_t &target_ts, bool cache_is_locked);
/**
* @brief Uses the FFmpeg API to retrieve a packet (stored in pkt_) and decode it (stored in frame_)
@@ -96,8 +96,8 @@ private:
QWaitCondition cache_wait_cond_;
QMutex cache_lock_;
- //QList cached_frames_;
- FFmpegFrameCache::Client cached_frames_;
+ QList cached_frames_;
+ FramePool frame_pool_;
int64_t cache_target_time_;
diff --git a/app/codec/ffmpeg/ffmpegframecache.cpp b/app/codec/ffmpeg/ffmpegframecache.cpp
deleted file mode 100644
index d64ac8c37..000000000
--- a/app/codec/ffmpeg/ffmpegframecache.cpp
+++ /dev/null
@@ -1,144 +0,0 @@
-/***
-
- Olive - Non-Linear Video Editor
- Copyright (C) 2019 Olive Team
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see .
-
-***/
-
-#include "ffmpegframecache.h"
-
-#include
-#include
-
-OLIVE_NAMESPACE_ENTER
-
-QMutex FFmpegFrameCache::pool_lock_;
-QLinkedList FFmpegFrameCache::frame_pool_;
-
-AVFramePtr FFmpegFrameCache::Client::append(int width, int height, int format)
-{
- AVFramePtr f = FFmpegFrameCache::Get(width, height, format);
-
- frames_.append(f);
-
- return f;
-}
-
-AVFramePtr FFmpegFrameCache::Client::append(AVFrame *copy)
-{
- AVFramePtr f = append(copy->width, copy->height, copy->format);
-
- av_frame_copy(f->frame(), copy);
- f->frame()->pts = copy->pts;
-
- return f;
-}
-
-void FFmpegFrameCache::Client::clear()
-{
- foreach (AVFramePtr cf, frames_) {
- FFmpegFrameCache::Release(cf);
- }
- frames_.clear();
-}
-
-bool FFmpegFrameCache::Client::isEmpty() const
-{
- return frames_.isEmpty();
-}
-
-AVFramePtr FFmpegFrameCache::Client::first() const
-{
- return frames_.first();
-}
-
-AVFramePtr FFmpegFrameCache::Client::at(int i) const
-{
- return frames_.at(i);
-}
-
-AVFramePtr FFmpegFrameCache::Client::last() const
-{
- return frames_.last();
-}
-
-int FFmpegFrameCache::Client::size() const
-{
- return frames_.size();
-}
-
-void FFmpegFrameCache::Client::accessedFirst()
-{
- frames_.first()->access();
-}
-
-void FFmpegFrameCache::Client::accessedLast()
-{
- frames_.last()->access();
-}
-
-void FFmpegFrameCache::Client::accessed(int i)
-{
- frames_[i]->access();
-}
-
-int FFmpegFrameCache::Client::remove_old_frames(qint64 older_than)
-{
- int counter = 0;
-
- while (frames_.size() > 1 && frames_.first()->last_accessed() < older_than) {
- FFmpegFrameCache::Release(frames_.takeFirst());
- counter++;
- }
-
- return counter;
-}
-
-AVFramePtr FFmpegFrameCache::Get(int width, int height, int format)
-{
- QMutexLocker locker(&pool_lock_);
-
- // See if we have a frame matching this description in the pool
- QLinkedList::iterator i;
- for (i=frame_pool_.begin();i!=frame_pool_.end();i++) {
- AVFramePtr f = (*i);
-
- if (f->frame()->width == width
- && f->frame()->height == height
- && f->frame()->format == format) {
- frame_pool_.erase(i);
- return f;
- }
- }
-
- // Otherwise we'll need to create one
- AVFramePtr f = std::make_shared();
- f->frame()->width = width;
- f->frame()->height = height;
- f->frame()->format = format;
- av_frame_get_buffer(f->frame(), 1);
-
- return f;
-}
-
-void FFmpegFrameCache::Release(AVFramePtr f)
-{
- QMutexLocker locker(&pool_lock_);
-
- frame_pool_.append(f);
-}
-
-OLIVE_NAMESPACE_EXIT
diff --git a/app/codec/ffmpeg/ffmpegframecache.h b/app/codec/ffmpeg/ffmpegframecache.h
deleted file mode 100644
index 084b5e869..000000000
--- a/app/codec/ffmpeg/ffmpegframecache.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/***
-
- Olive - Non-Linear Video Editor
- Copyright (C) 2019 Olive Team
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see .
-
-***/
-
-#ifndef FFMPEGFRAMECACHE_H
-#define FFMPEGFRAMECACHE_H
-
-#include
-#include
-
-#include "avframeptr.h"
-#include "render/videoparams.h"
-
-OLIVE_NAMESPACE_ENTER
-
-class FFmpegFrameCache
-{
-public:
- FFmpegFrameCache() = default;
-
- static AVFramePtr Get(int width, int height, int format);
-
- static void Release(AVFramePtr f);
-
- class Client
- {
- public:
- Client() = default;
-
- AVFramePtr append(int width, int height, int format);
- AVFramePtr append(AVFrame *copy);
- void clear();
-
- bool isEmpty() const;
- AVFramePtr first() const;
- AVFramePtr at(int i) const;
- AVFramePtr last() const;
- int size() const;
-
- void accessedFirst();
- void accessedLast();
- void accessed(int i);
-
- int remove_old_frames(qint64 older_than);
-
- private:
- QList frames_;
-
- };
-
-private:
- static QMutex pool_lock_;
-
- static QLinkedList frame_pool_;
-
-};
-
-OLIVE_NAMESPACE_EXIT
-
-#endif // FFMPEGFRAMECACHE_H
diff --git a/app/codec/framepool.cpp b/app/codec/framepool.cpp
new file mode 100644
index 000000000..d0fceaa14
--- /dev/null
+++ b/app/codec/framepool.cpp
@@ -0,0 +1,97 @@
+/***
+
+ Olive - Non-Linear Video Editor
+ Copyright (C) 2019 Olive Team
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+***/
+
+#include "framepool.h"
+
+OLIVE_NAMESPACE_ENTER
+
+FramePool::FramePool()
+{
+ data_ = nullptr;
+}
+
+bool FramePool::Allocate(int width, int height, PixelFormat::Format format, int nb_elements)
+{
+ delete [] data_;
+
+ element_sz_ = width * height * PixelFormat::BytesPerPixel(format);
+
+ if ((data_ = new char[element_sz_ * nb_elements])) {
+ // Only allocate available array if data allocation succeeded
+ available_.resize(nb_elements);
+ available_.fill(true);
+
+ return true;
+ } else {
+ available_.clear();
+
+ return false;
+ }
+}
+
+void FramePool::Destroy()
+{
+ delete [] data_;
+ available_.clear();
+}
+
+FramePool::~FramePool()
+{
+ delete [] data_;
+}
+
+FramePool::ElementPtr FramePool::Get()
+{
+ for (int i=0;i(this, data_ + i * element_sz_);
+ }
+ }
+
+ return nullptr;
+}
+
+void FramePool::Release(FramePool::Element *e)
+{
+ quintptr offs = reinterpret_cast(e->data());
+ quintptr start = reinterpret_cast(data_);
+
+ quintptr diff = offs - start;
+
+ int index = diff / element_sz_;
+
+ available_.replace(index, true);
+}
+
+FramePool::Element::Element(FramePool *parent, char *data)
+{
+ parent_ = parent;
+ data_ = data;
+ accessed_ = QDateTime::currentMSecsSinceEpoch();
+}
+
+FramePool::Element::~Element()
+{
+ parent_->Release(this);
+}
+
+OLIVE_NAMESPACE_EXIT
diff --git a/app/codec/framepool.h b/app/codec/framepool.h
new file mode 100644
index 000000000..86da3bed2
--- /dev/null
+++ b/app/codec/framepool.h
@@ -0,0 +1,97 @@
+/***
+
+ Olive - Non-Linear Video Editor
+ Copyright (C) 2019 Olive Team
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+***/
+
+#ifndef FRAMEPOOL_H
+#define FRAMEPOOL_H
+
+#include
+#include
+
+#include "render/pixelformat.h"
+
+OLIVE_NAMESPACE_ENTER
+
+class FramePool
+{
+public:
+ FramePool();
+
+ ~FramePool();
+
+ bool Allocate(int width, int height, PixelFormat::Format format, int nb_elements);
+
+ void Destroy();
+
+ DISABLE_COPY_MOVE(FramePool)
+
+ class Element {
+ public:
+ Element(FramePool* parent, char* data);
+ ~Element();
+
+ inline char* data() const {
+ return data_;
+ }
+
+ inline const int64_t& timestamp() const {
+ return timestamp_;
+ }
+
+ inline void set_timestamp(const int64_t& timestamp) {
+ timestamp_ = timestamp;
+ }
+
+ inline void access() {
+ accessed_ = QDateTime::currentMSecsSinceEpoch();
+ }
+
+ inline const int64_t& last_accessed() const {
+ return accessed_;
+ }
+
+ private:
+ FramePool* parent_;
+
+ char* data_;
+
+ int64_t timestamp_;
+
+ int64_t accessed_;
+
+ };
+
+ using ElementPtr = std::shared_ptr;
+
+ ElementPtr Get();
+
+ void Release(Element* e);
+
+private:
+ char* data_;
+
+ int element_sz_;
+
+ QVector available_;
+
+};
+
+OLIVE_NAMESPACE_EXIT
+
+#endif // FRAMEPOOL_H