#pragma once
#include <memory>
#include <mutex>
#include <vector>
#include "frame/Frame.hpp"
#include "logger/Logger.hpp"
#define FRAME_DATA_ALIGN_IN_BYTE 16
namespace libobsensor {
class FrameMemoryAllocator {
private:
FrameMemoryAllocator();
static std::mutex instanceMutex_;
static std::weak_ptr<FrameMemoryAllocator> instanceWeakPtr_;
public:
static std::shared_ptr<FrameMemoryAllocator> getInstance();
~FrameMemoryAllocator() noexcept;
void setMaxFrameMemorySize(uint64_t sizeInMb);
uint8_t *allocate(size_t size);
void deallocate(uint8_t *ptr, size_t size);
private:
uint64_t maxSizeInByte_;
uint64_t usedSize_;
std::mutex mutex_;
std::shared_ptr<Logger> logger_; };
class IFrameBufferManager {
public:
virtual ~IFrameBufferManager() noexcept {};
virtual void reclaimBuffer(void *buffer) = 0;
virtual void releaseIdleBuffer() = 0;
virtual size_t getFrameDataBufferSize() = 0;
private:
virtual std::shared_ptr<Frame> acquireFrame() = 0;
friend class FrameFactory;
};
inline double byteToMB(uint64_t sizeInByte) {
return (double)sizeInByte / 1024.0 / 1024.0;
}
class FrameBufferManagerBase : public IFrameBufferManager {
public:
FrameBufferManagerBase(size_t frameDataBufferSize, size_t frameObjSize);
virtual ~FrameBufferManagerBase() noexcept override;
void reclaimBuffer(void *buffer) override;
void releaseIdleBuffer() override;
size_t getFrameDataBufferSize() override {
return frameDataBufferSize_;
}
std::unique_lock<std::recursive_mutex> lockBuffers();
protected:
uint8_t *acquireBuffer();
protected:
std::recursive_mutex mutex_;
size_t frameDataBufferSize_;
size_t frameObjSize_;
size_t frameTotalSize_;
private:
std::vector<uint8_t *> availableFrameBuffers_;
std::shared_ptr<FrameMemoryAllocator> frameMemoryAllocator_;
};
class FrameMemoryPool;
template <typename T> class FrameBufferManager : public FrameBufferManagerBase, public std::enable_shared_from_this<FrameBufferManager<T>> {
private:
FrameBufferManager(size_t frameDataBufferSize) : FrameBufferManagerBase(frameDataBufferSize, sizeof(T)) {
LOG_DEBUG("FrameBufferManager created! frame type:{0}, obj addr:0x{1:x}, frame obj total size:{2:.3f}MB", typeid(T).name(), uintptr_t(this),
byteToMB(frameTotalSize_));
}
friend class FrameMemoryPool;
public:
virtual ~FrameBufferManager() override {
LOG_DEBUG("FrameBufferManager destroying...! frame type: {0}, obj addr:0x{1:x}", typeid(T).name(), uint64_t(this));
}
private:
virtual std::shared_ptr<Frame> acquireFrame() override {
uint8_t *bufferPtr = acquireBuffer();
if(bufferPtr != nullptr) {
static uint16_t align = FRAME_DATA_ALIGN_IN_BYTE;
uint16_t alignOffset = (align - (uint64_t)(bufferPtr + frameObjSize_) % align) % align;
auto bufMgr = this->shared_from_this();
return std::shared_ptr<T>(new(bufferPtr) T(bufferPtr + frameObjSize_ + alignOffset, frameDataBufferSize_,
[bufMgr, bufferPtr]() { bufMgr->reclaimBuffer(bufferPtr);
}),
[bufMgr](T *frame) mutable { auto lk = bufMgr->lockBuffers();
frame->~T();
lk.unlock();
bufMgr.reset();
});
}
return nullptr;
}
friend class FrameFactory;
};
}