Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .git-blame-ignore-revs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# [qtAliceVision] Reformat all sequence cache-related files
d304d8655de26ed5702966b4d855b031f85268f1
# [qtAliceVision] Apply clang-format on modified files
d0fd33d78af7d73f4c1c5ba0de7a1d49d263f5d0
# Reformat all plugins with latest clang-format rules
Expand Down
247 changes: 247 additions & 0 deletions src/qtAliceVision/AsyncFetcher.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
#include "AsyncFetcher.hpp"

#include <QMutexLocker>
#include <QPoint>

#include <thread>
#include <chrono>

using namespace aliceVision;

namespace qtAliceVision {
namespace imgserve {

AsyncFetcher::AsyncFetcher()
{
_resizeRatio = 0.001;
_isAsynchronous = false;
_requestSynchronous = false;
}

AsyncFetcher::~AsyncFetcher() {}

void AsyncFetcher::setSequence(const std::vector<std::string>& paths)
{
// Sequence can't be changed while thread is running
if (_isAsynchronous)
{
return;
}

_sequence = paths;
_currentIndex = 0;

for (unsigned idx = 0; idx < _sequence.size(); idx++)
{
_pathToSeqId[_sequence[idx]] = idx;
}
}

void AsyncFetcher::setResizeRatio(double ratio)
{
QMutexLocker locker(&_mutexResizeRatio);
_resizeRatio = ratio;
}

void AsyncFetcher::setCache(ImageCache::uptr&& cache)
{
// Cache can't be changed while thread is running
if (_isAsynchronous)
{
return;
}
_cache = std::move(cache);
}

void AsyncFetcher::run()
{
using namespace std::chrono_literals;

_isAsynchronous = true;
_requestSynchronous = false;

std::size_t previousCacheSize = getDiskLoads();

while (1)
{
if (_requestSynchronous)
{
_requestSynchronous = false;
break;
}

if (_sequence.size() == 0)
{
std::this_thread::sleep_for(100ms);
}
else
{
const std::string& lpath = _sequence[static_cast<std::size_t>(_currentIndex)];

// Load in cache
if (_cache)
{
double ratio;
{
QMutexLocker locker(&_mutexResizeRatio);
ratio = _resizeRatio;
}

_cache->get<image::RGBAfColor>(lpath, static_cast<unsigned int>(_currentIndex), ratio, false);
}

_currentIndex++;

int size = static_cast<int>(_sequence.size());
if (_currentIndex >= size)
{
_currentIndex = 0;
}

std::this_thread::sleep_for(1ms);
}

std::size_t cacheSize = getDiskLoads();
if (cacheSize != previousCacheSize)
{
previousCacheSize = cacheSize;
Q_EMIT onAsyncFetchProgressed();
}
}

_requestSynchronous = false;
_isAsynchronous = false;
}

void AsyncFetcher::stopAsync()
{
_requestSynchronous = true;
}

void AsyncFetcher::updateCacheMemory(std::size_t maxMemory)
{
if (_cache)
{
_cache->updateMaxMemory(maxMemory);
}
}

std::size_t AsyncFetcher::getCacheSize() const
{
return (_cache) ? static_cast<std::size_t>(_cache->info().getContentSize()) : 0;
}

std::size_t AsyncFetcher::getDiskLoads() const
{
return (_cache) ? static_cast<std::size_t>(_cache->info().getLoadFromDisk()) : 0;
}

QVariantList AsyncFetcher::getCachedFrames() const
{
QVariantList intervals;

if (!_cache)
{
return intervals;
}

// Accumulator variables
auto region = std::make_pair(-1, -1);
bool regionOpen = false;

size_t size = _sequence.size();

{
// Build cached frames intervals
for (std::size_t i = 0; i < size; ++i)
{
const int frame = static_cast<int>(i);

// Check if current frame is in cache
if (_cache->contains<aliceVision::image::RGBAfColor>(_sequence[i], _resizeRatio))
{
// Either grow currently open region or create a new region
if (regionOpen)
{
region.second = frame;
}
else
{
region.first = frame;
region.second = frame;
regionOpen = true;
}
}
else
{
// Close currently open region
if (regionOpen)
{
intervals.append(QPoint(region.first, region.second));
regionOpen = false;
}
}
}
}

// Last region may still be open
if (regionOpen)
{
intervals.append(QPoint(region.first, region.second));
}

return intervals;
}

bool AsyncFetcher::getFrame(const std::string& path,
std::shared_ptr<image::Image<image::RGBAfColor>>& image,
oiio::ParamValueList& metadatas,
size_t& originalWidth,
size_t& originalHeight)
{
// Need a cache
if (!_cache)
{
return false;
}

// First try getting the image
bool onlyCache = _isAsynchronous;

// Upgrade the thread with the current Index
for (std::size_t idx = 0; idx < _sequence.size(); ++idx)
{
if (_sequence[idx] == path)
{
_currentIndex = static_cast<int>(idx);
break;
}
}

std::optional<CacheValue> ovalue = _cache->get<aliceVision::image::RGBAfColor>(path, _currentIndex, _resizeRatio, onlyCache);

if (ovalue.has_value())
{
auto& value = ovalue.value();
image = value.get<aliceVision::image::RGBAfColor>();

oiio::ParamValueList copy_metadatas = value.getMetadatas();
metadatas = copy_metadatas;
originalWidth = value.getOriginalWidth();
originalHeight = value.getOriginalHeight();

if (image)
{
_cache->setReferenceFrameId(_currentIndex);
}

return true;
}

return false;
}

} // namespace imgserve
} // namespace qtAliceVision

#include "AsyncFetcher.moc"
112 changes: 112 additions & 0 deletions src/qtAliceVision/AsyncFetcher.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
#pragma once

#include <QObject>
#include <QRunnable>
#include <QMutex>
#include <QVariantList>

#include "ImageCache.hpp"

namespace qtAliceVision {
namespace imgserve {

class AsyncFetcher : public QObject, public QRunnable
{
Q_OBJECT

public:
AsyncFetcher();
~AsyncFetcher();

/**
* @brief Cache object is created externally.
* Pass it to the Fetcher for use (Fetcher get ownership)
* @param cache the cache object to store
*/
void setCache(ImageCache::uptr&& cache);

/**
* @brief set the image sequence
* The image sequence is a list of image paths which is ordered
* The Fetcher must not be in asynchronous mode for this function to work
* As such, the _sequence object is only used in read mode during async mode.
*/
void setSequence(const std::vector<std::string>& paths);

/**
* @brief update the resize ratio of the image
* @param ratio the coefficient of resize of the loaded images
*/
void setResizeRatio(double ratio);

/**
* @brief retrieve a frame from the cache in both sync and async mode
* @param path the image path which should be contained in _sequence.
* @param image the result image pointer
* @param metadatas the image metadatas found in the file
* @param originalWidth the image width before the resize
* @param originalHeight the image height before the resize
* @return true if the image was succesfully found in the cache
*/
bool getFrame(const std::string& path,
std::shared_ptr<aliceVision::image::Image<aliceVision::image::RGBAfColor>>& image,
oiio::ParamValueList& metadatas,
std::size_t& originalWidth,
std::size_t& originalHeight);

/**
* @brief Internal function for QT to start the asynchronous mode
*/
Q_SLOT void run() override;

/**
* @brief stop asynchronous mode
* The caller have to wait on the thread pool to guarantee the effective end
*/
void stopAsync();

bool isAsync() const { return _isAsynchronous; }

/**
* @brief get the cache content size in bytes
* @return the cache content size in bytes
*/
std::size_t getCacheSize() const;

/**
* @brief get the number of images loaded
* @return the count of images loaded since the creation of the cache object
*/
std::size_t getDiskLoads() const;

/**
* @brief update maxMemory for the cache
* @param maxMemory the number of bytes allowed in the cache
*/
void updateCacheMemory(std::size_t maxMemory);

/**
* @brief get a list of regions containing the image frames
* @return a list of two values (begin, end)
*/
QVariantList getCachedFrames() const;

public:
Q_SIGNAL void onAsyncFetchProgressed();

private:
ImageCache::uptr _cache;

std::vector<std::string> _sequence;
std::unordered_map<std::string, unsigned> _pathToSeqId;

QAtomicInt _currentIndex;
QAtomicInt _isAsynchronous;
QAtomicInt _requestSynchronous;

double _resizeRatio;
QMutex _mutexResizeRatio;
};

} // namespace imgserve
} // namespace qtAliceVision
6 changes: 6 additions & 0 deletions src/qtAliceVision/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ set(PLUGIN_SOURCES
Painter.cpp
SequenceCache.cpp
SingleImageLoader.cpp
ImageCache.cpp
AsyncFetcher.cpp
)

set(PLUGIN_HEADERS
Expand All @@ -32,6 +34,9 @@ set(PLUGIN_HEADERS
ImageServer.hpp
SequenceCache.hpp
SingleImageLoader.hpp
ImageCache.hpp
AsyncFetcher.hpp

)

set(PLUGIN_MOCS
Expand All @@ -43,6 +48,7 @@ set(PLUGIN_MOCS
MSfMDataStats.hpp
SequenceCache.hpp
SingleImageLoader.hpp
AsyncFetcher.hpp
)


Expand Down
Loading