fixed flicker issue when previewing some media
This commit is contained in:
@@ -276,14 +276,9 @@ void RendererProcessor::Start()
|
||||
SLOT(ThreadCallback(RenderTexturePtr, const rational&, const QByteArray&)),
|
||||
Qt::QueuedConnection);
|
||||
connect(threads_.first().get(),
|
||||
SIGNAL(FrameExists(const rational&, const QByteArray&)),
|
||||
SIGNAL(FrameSkipped(const rational&, const QByteArray&)),
|
||||
this,
|
||||
SLOT(ThreadFrameAlreadyExists(const rational&, const QByteArray&)),
|
||||
Qt::QueuedConnection);
|
||||
connect(threads_.first().get(),
|
||||
SIGNAL(FrameIgnored()),
|
||||
this,
|
||||
SLOT(ThreadIgnoredFrame()),
|
||||
SLOT(ThreadSkippedFrame(const rational&, const QByteArray&)),
|
||||
Qt::QueuedConnection);
|
||||
|
||||
download_threads_.resize(background_thread_count);
|
||||
@@ -294,9 +289,9 @@ void RendererProcessor::Start()
|
||||
download_threads_[i]->StartThread(QThread::LowPriority);
|
||||
|
||||
connect(download_threads_[i].get(),
|
||||
SIGNAL(Downloaded(const rational&, const QByteArray&)),
|
||||
SIGNAL(Downloaded(const QByteArray&)),
|
||||
this,
|
||||
SLOT(MapHashToTimecode(const rational&, const QByteArray&)),
|
||||
SLOT(DownloadThreadComplete(const QByteArray&)),
|
||||
Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
@@ -364,7 +359,7 @@ void RendererProcessor::CacheNext()
|
||||
|
||||
rational cache_frame = cache_queue_.takeFirst();
|
||||
|
||||
qDebug() << "[RendererProcessor] Caching" << cache_frame.toDouble();
|
||||
//qDebug() << "[RendererProcessor] Caching" << cache_frame.toDouble();
|
||||
|
||||
threads_.first()->Queue(NodeDependency(texture_input_->get_connected_output(), cache_frame), true);
|
||||
|
||||
@@ -381,6 +376,11 @@ QString RendererProcessor::CachePathName(const QByteArray &hash)
|
||||
return this_cache_dir.filePath(filename);
|
||||
}
|
||||
|
||||
void RendererProcessor::DeferMap(const rational &time, const QByteArray &hash)
|
||||
{
|
||||
deferred_maps_.append({time, hash});
|
||||
}
|
||||
|
||||
bool RendererProcessor::HasHash(const QByteArray &hash)
|
||||
{
|
||||
return QFileInfo::exists(CachePathName(hash));
|
||||
@@ -423,19 +423,20 @@ void RendererProcessor::ThreadCallback(RenderTexturePtr texture, const rational&
|
||||
// Threads are all done now, time to proceed
|
||||
caching_ = false;
|
||||
|
||||
DeferMap(time, hash);
|
||||
|
||||
if (texture != nullptr) {
|
||||
// We received a texture, time to start downloading it
|
||||
QString fn = CachePathName(hash);
|
||||
|
||||
download_threads_[last_download_thread_%download_threads_.size()]->Queue(texture,
|
||||
fn,
|
||||
time,
|
||||
hash);
|
||||
|
||||
last_download_thread_++;
|
||||
} else {
|
||||
// There was no texture here, we must update the viewer
|
||||
MapHashToTimecode(time, hash);
|
||||
DownloadThreadComplete(hash);
|
||||
}
|
||||
|
||||
// If the connected output is using this time, signal it to update
|
||||
@@ -458,39 +459,43 @@ void RendererProcessor::ThreadRequestSibling(NodeDependency dep)
|
||||
}
|
||||
}
|
||||
|
||||
void RendererProcessor::ThreadFrameAlreadyExists(const rational &time, const QByteArray &hash)
|
||||
void RendererProcessor::ThreadSkippedFrame(const rational& time, const QByteArray& hash)
|
||||
{
|
||||
caching_ = false;
|
||||
|
||||
// Update hash map with new hash
|
||||
MapHashToTimecode(time, hash);
|
||||
DeferMap(time, hash);
|
||||
|
||||
// Signal output to update value
|
||||
if (texture_output_->IsConnected()
|
||||
&& texture_output_->LastRequestedTime() == time) {
|
||||
texture_output_->ClearCachedValue();
|
||||
SendInvalidateCache(time, time);
|
||||
if (!IsCaching(hash)) {
|
||||
DownloadThreadComplete(hash);
|
||||
|
||||
// Signal output to update value
|
||||
if (texture_output_->IsConnected()
|
||||
&& texture_output_->LastRequestedTime() == time) {
|
||||
texture_output_->ClearCachedValue();
|
||||
SendInvalidateCache(time, time);
|
||||
}
|
||||
}
|
||||
|
||||
// Start caching the next frame
|
||||
CacheNext();
|
||||
}
|
||||
|
||||
void RendererProcessor::MapHashToTimecode(const rational& time, const QByteArray& hash)
|
||||
void RendererProcessor::DownloadThreadComplete(const QByteArray &hash)
|
||||
{
|
||||
// Insert into hash map
|
||||
time_hash_map_.insert(time, hash);
|
||||
|
||||
cache_hash_list_mutex_.lock();
|
||||
cache_hash_list_.removeAll(hash);
|
||||
cache_hash_list_mutex_.unlock();
|
||||
}
|
||||
|
||||
void RendererProcessor::ThreadIgnoredFrame()
|
||||
{
|
||||
caching_ = false;
|
||||
for (int i=0;i<deferred_maps_.size();i++) {
|
||||
const HashTimeMapping& deferred = deferred_maps_.at(i);
|
||||
|
||||
CacheNext();
|
||||
if (deferred_maps_.at(i).hash == hash) {
|
||||
// Insert into hash map
|
||||
time_hash_map_.insert(deferred.time, deferred.hash);
|
||||
|
||||
deferred_maps_.removeAt(i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RendererThreadBase* RendererProcessor::CurrentThread()
|
||||
|
||||
@@ -119,6 +119,11 @@ protected:
|
||||
virtual QVariant Value(NodeOutput* output, const rational& time) override;
|
||||
|
||||
private:
|
||||
struct HashTimeMapping {
|
||||
rational time;
|
||||
QByteArray hash;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Allocate and start the multithreaded backend
|
||||
*/
|
||||
@@ -148,6 +153,8 @@ private:
|
||||
*/
|
||||
QString CachePathName(const QByteArray &hash);
|
||||
|
||||
void DeferMap(const rational &time, const QByteArray &hash);
|
||||
|
||||
/**
|
||||
* @brief Internal list of RenderProcessThreads
|
||||
*/
|
||||
@@ -198,16 +205,16 @@ private:
|
||||
QMutex cache_hash_list_mutex_;
|
||||
QVector<QByteArray> cache_hash_list_;
|
||||
|
||||
QList<HashTimeMapping> deferred_maps_;
|
||||
|
||||
private slots:
|
||||
void ThreadCallback(RenderTexturePtr texture, const rational& time, const QByteArray& hash);
|
||||
|
||||
void ThreadRequestSibling(NodeDependency dep);
|
||||
|
||||
void ThreadFrameAlreadyExists(const rational &time, const QByteArray &hash);
|
||||
void ThreadSkippedFrame(const rational &time, const QByteArray &hash);
|
||||
|
||||
void MapHashToTimecode(const rational &time, const QByteArray &hash);
|
||||
|
||||
void ThreadIgnoredFrame();
|
||||
void DownloadThreadComplete(const QByteArray &hash);
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -18,11 +18,11 @@ RendererDownloadThread::RendererDownloadThread(QOpenGLContext *share_ctx,
|
||||
{
|
||||
}
|
||||
|
||||
void RendererDownloadThread::Queue(RenderTexturePtr texture, const QString& fn, const rational& time, const QByteArray &hash)
|
||||
void RendererDownloadThread::Queue(RenderTexturePtr texture, const QString& fn, const QByteArray &hash)
|
||||
{
|
||||
texture_queue_lock_.lock();
|
||||
|
||||
texture_queue_.append({texture, fn, time, hash});
|
||||
texture_queue_.append({texture, fn, hash});
|
||||
|
||||
wait_cond_.wakeAll();
|
||||
|
||||
@@ -118,7 +118,7 @@ void RendererDownloadThread::ProcessLoop()
|
||||
out->write_image(format_info.oiio_desc, data_buffer.data());
|
||||
out->close();
|
||||
|
||||
emit Downloaded(entry.time, entry.hash);
|
||||
emit Downloaded(entry.hash);
|
||||
} else {
|
||||
qWarning() << tr("Failed to open output file \"%1\"").arg(entry.filename);
|
||||
}
|
||||
|
||||
@@ -9,17 +9,18 @@ class RendererDownloadThread : public RendererThreadBase
|
||||
public:
|
||||
RendererDownloadThread(QOpenGLContext* share_ctx,
|
||||
const int& width,
|
||||
const int& height, const int ÷r,
|
||||
const int& height,
|
||||
const int ÷r,
|
||||
const olive::PixelFormat& format,
|
||||
const olive::RenderMode& mode);
|
||||
|
||||
void Queue(RenderTexturePtr texture, const QString &fn, const rational &time, const QByteArray &hash);
|
||||
void Queue(RenderTexturePtr texture, const QString &fn, const QByteArray &hash);
|
||||
|
||||
public slots:
|
||||
virtual void Cancel() override;
|
||||
|
||||
signals:
|
||||
void Downloaded(const rational& time, const QByteArray& hash);
|
||||
void Downloaded(const QByteArray& hash);
|
||||
|
||||
protected:
|
||||
virtual void ProcessLoop() override;
|
||||
@@ -28,7 +29,6 @@ private:
|
||||
struct DownloadQueueEntry {
|
||||
RenderTexturePtr texture;
|
||||
QString filename;
|
||||
rational time;
|
||||
QByteArray hash;
|
||||
};
|
||||
|
||||
|
||||
@@ -79,8 +79,6 @@ void RendererProcessThread::ProcessLoop()
|
||||
// Main waiting condition
|
||||
wait_cond_.wait(&mutex_);
|
||||
|
||||
qDebug() << this << "woke for a queued frame";
|
||||
|
||||
if (cancelled_) {
|
||||
break;
|
||||
}
|
||||
@@ -111,8 +109,6 @@ void RendererProcessThread::ProcessLoop()
|
||||
bool has_hash = parent_->HasHash(hash_);
|
||||
bool can_cache = false;
|
||||
|
||||
qDebug() << this << "starting background cache of frame" << path_.time().toDouble();
|
||||
|
||||
if (!has_hash){
|
||||
|
||||
if ((can_cache = parent_->TryCache(hash_))) {
|
||||
@@ -127,17 +123,10 @@ void RendererProcessThread::ProcessLoop()
|
||||
}
|
||||
|
||||
// Get the requested value
|
||||
qDebug() << this << "starting cache of" << hash_.toHex();
|
||||
texture_ = output_to_process->get_value(path_.time()).value<RenderTexturePtr>();
|
||||
|
||||
render_instance()->context()->functions()->glFinish();
|
||||
|
||||
qDebug() << this << "completed cache of" << hash_.toHex();
|
||||
} else {
|
||||
qDebug() << this << "hash is in use";
|
||||
}
|
||||
} else {
|
||||
qDebug() << this << "hash" << hash_.toHex() << "exists";
|
||||
}
|
||||
|
||||
foreach (Node* dep, all_deps) {
|
||||
@@ -146,15 +135,12 @@ void RendererProcessThread::ProcessLoop()
|
||||
|
||||
node_to_process->Unlock();
|
||||
|
||||
if (has_hash && !parent_->IsCaching(hash_)) {
|
||||
// This hash already exists, no need to cache, just record it
|
||||
emit FrameExists(path_.time(), hash_);
|
||||
} else if (can_cache) {
|
||||
if (can_cache) {
|
||||
// We cached this frame, signal that it will need to be downloaded to disk
|
||||
emit CachedFrame(texture_, path_.time(), hash_);
|
||||
} else {
|
||||
// Some other dork is caching this frame, skip it
|
||||
emit FrameIgnored();
|
||||
// This hash already exists, no need to cache, just map it
|
||||
emit FrameSkipped(path_.time(), hash_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,9 +49,7 @@ signals:
|
||||
|
||||
void CachedFrame(RenderTexturePtr texture, const rational& time, const QByteArray& hash);
|
||||
|
||||
void FrameExists(const rational& time, const QByteArray& hash);
|
||||
|
||||
void FrameIgnored();
|
||||
void FrameSkipped(const rational& time, const QByteArray& hash);
|
||||
|
||||
private:
|
||||
RendererProcessor* parent_;
|
||||
|
||||
Reference in New Issue
Block a user