diff --git a/app/decoder/ffmpeg/ffmpegdecoder.cpp b/app/decoder/ffmpeg/ffmpegdecoder.cpp index b9a567257..55145aaea 100644 --- a/app/decoder/ffmpeg/ffmpegdecoder.cpp +++ b/app/decoder/ffmpeg/ffmpegdecoder.cpp @@ -327,7 +327,7 @@ int64_t FFmpegDecoder::GetTimestampFromTime(const rational &time) } // Convert timecode to AVStream timebase - int64_t target_ts = qFloor(time.toDouble() * rational(avstream_->time_base).flipped().toDouble()); + int64_t target_ts = qRound64(time.toDouble() * rational(avstream_->time_base).flipped().toDouble()); // Find closest actual timebase in the file target_ts = GetClosestTimestampInIndex(target_ts); diff --git a/app/node/processor/renderer/renderer.cpp b/app/node/processor/renderer/renderer.cpp index cb1fae40a..3a4f78f3d 100644 --- a/app/node/processor/renderer/renderer.cpp +++ b/app/node/processor/renderer/renderer.cpp @@ -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 cache_hash_list_; + QList 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); }; diff --git a/app/node/processor/renderer/rendererdownloadthread.cpp b/app/node/processor/renderer/rendererdownloadthread.cpp index 3da1069eb..91f030d94 100644 --- a/app/node/processor/renderer/rendererdownloadthread.cpp +++ b/app/node/processor/renderer/rendererdownloadthread.cpp @@ -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); } diff --git a/app/node/processor/renderer/rendererdownloadthread.h b/app/node/processor/renderer/rendererdownloadthread.h index 376a69232..9c7b6bc45 100644 --- a/app/node/processor/renderer/rendererdownloadthread.h +++ b/app/node/processor/renderer/rendererdownloadthread.h @@ -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; }; diff --git a/app/node/processor/renderer/rendererprocessthread.cpp b/app/node/processor/renderer/rendererprocessthread.cpp index 3dac12a65..eb12b1f01 100644 --- a/app/node/processor/renderer/rendererprocessthread.cpp +++ b/app/node/processor/renderer/rendererprocessthread.cpp @@ -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(); 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_); } } } diff --git a/app/node/processor/renderer/rendererprocessthread.h b/app/node/processor/renderer/rendererprocessthread.h index a9eedaa38..48cca8d5b 100644 --- a/app/node/processor/renderer/rendererprocessthread.h +++ b/app/node/processor/renderer/rendererprocessthread.h @@ -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_;