updated exporter to work with new frame flow

This commit is contained in:
itsmattkc
2020-01-08 02:27:47 +11:00
parent c8baf4aa3e
commit b8aabb7e01
15 changed files with 232 additions and 43 deletions
+1 -1
View File
@@ -96,7 +96,7 @@ void Encoder::Open()
} }
} }
void Encoder::Write(FramePtr frame) void Encoder::WriteFrame(FramePtr frame)
{ {
if (open_) { if (open_) {
WriteInternal(frame); WriteInternal(frame);
+3 -1
View File
@@ -61,7 +61,7 @@ public:
public slots: public slots:
void Open(); void Open();
void Write(FramePtr frame); void WriteFrame(FramePtr frame);
virtual void WriteAudio(const AudioRenderingParams& pcm_info, const QString& pcm_filename) = 0; virtual void WriteAudio(const AudioRenderingParams& pcm_info, const QString& pcm_filename) = 0;
void Close(); void Close();
@@ -71,6 +71,8 @@ signals:
void Closed(); void Closed();
void AudioComplete();
protected: protected:
virtual bool OpenInternal() = 0; virtual bool OpenInternal() = 0;
virtual void WriteInternal(FramePtr frame) = 0; virtual void WriteInternal(FramePtr frame) = 0;
+2
View File
@@ -89,6 +89,8 @@ void FFmpegEncoder::WriteAudio(const AudioRenderingParams &pcm_info, const QStri
pcm.close(); pcm.close();
} }
emit AudioComplete();
} }
bool FFmpegEncoder::OpenInternal() bool FFmpegEncoder::OpenInternal()
+89 -10
View File
@@ -20,7 +20,9 @@ Exporter::Exporter(ViewerOutput* viewer,
color_processor_(color_processor), color_processor_(color_processor),
encoder_(encoder), encoder_(encoder),
export_status_(false), export_status_(false),
export_msg_(tr("Export hasn't started yet")) export_msg_(tr("Export hasn't started yet")),
video_done_(false),
audio_done_(false)
{ {
connect(this, &Exporter::ExportEnded, this, &Exporter::deleteLater); connect(this, &Exporter::ExportEnded, this, &Exporter::deleteLater);
} }
@@ -53,20 +55,16 @@ void Exporter::StartExporting()
video_params_.time_base(), video_params_.time_base(),
video_params_.format(), video_params_.format(),
video_params_.mode())); video_params_.mode()));
video_backend_->SetExportMode(true);
audio_backend_->SetViewerNode(viewer_node_); audio_backend_->SetViewerNode(viewer_node_);
audio_backend_->SetParameters(audio_params_); audio_backend_->SetParameters(audio_params_);
// Connect to renderers
connect(video_backend_, &VideoRenderBackend::CachedFrameReady, this, &Exporter::FrameRendered);
connect(audio_backend_, &AudioRenderBackend::QueueComplete, this, &Exporter::AudioRendered);
// Create renderers // Create renderers
waiting_for_frame_ = 0; waiting_for_frame_ = 0;
// Open encoder and wait for result // Open encoder and wait for result
connect(encoder_, &Encoder::OpenSucceeded, this, &Exporter::EncoderOpenedSuccessfully, Qt::QueuedConnection); connect(encoder_, &Encoder::OpenSucceeded, this, &Exporter::EncoderOpenedSuccessfully, Qt::QueuedConnection);
connect(encoder_, &Encoder::OpenFailed, this, &Exporter::EncoderOpenFailed, Qt::QueuedConnection); connect(encoder_, &Encoder::OpenFailed, this, &Exporter::EncoderOpenFailed, Qt::QueuedConnection);
connect(encoder_, &Encoder::AudioComplete, this, &Exporter::AudioEncodeComplete, Qt::QueuedConnection);
connect(encoder_, &Encoder::Closed, encoder_, &Encoder::deleteLater, Qt::QueuedConnection); connect(encoder_, &Encoder::Closed, encoder_, &Encoder::deleteLater, Qt::QueuedConnection);
QMetaObject::invokeMethod(encoder_, QMetaObject::invokeMethod(encoder_,
@@ -81,6 +79,10 @@ void Exporter::SetExportMessage(const QString &s)
void Exporter::ExportSucceeded() void Exporter::ExportSucceeded()
{ {
if (!audio_done_ || !video_done_) {
return;
}
Cleanup(); Cleanup();
video_backend_->deleteLater(); video_backend_->deleteLater();
@@ -99,10 +101,8 @@ void Exporter::ExportFailed()
emit ExportEnded(); emit ExportEnded();
} }
void Exporter::FrameRendered(const rational &time, QVariant value) void Exporter::EncodeFrame(const rational &time, QVariant value)
{ {
qDebug() << "Received" << time.toDouble() << "- waiting for" << waiting_for_frame_.toDouble();
if (time == waiting_for_frame_) { if (time == waiting_for_frame_) {
bool get_cached = false; bool get_cached = false;
@@ -132,7 +132,7 @@ void Exporter::FrameRendered(const rational &time, QVariant value)
// Encode (may require re-associating alpha?) // Encode (may require re-associating alpha?)
QMetaObject::invokeMethod(encoder_, QMetaObject::invokeMethod(encoder_,
"Write", "WriteFrame",
Qt::QueuedConnection, Qt::QueuedConnection,
Q_ARG(FramePtr, frame)); Q_ARG(FramePtr, frame));
@@ -145,6 +145,8 @@ void Exporter::FrameRendered(const rational &time, QVariant value)
} while (cached_frames_.contains(waiting_for_frame_)); } while (cached_frames_.contains(waiting_for_frame_));
if (waiting_for_frame_ >= viewer_node_->Length()) { if (waiting_for_frame_ >= viewer_node_->Length()) {
video_done_ = true;
ExportSucceeded(); ExportSucceeded();
} }
} else { } else {
@@ -152,6 +154,23 @@ void Exporter::FrameRendered(const rational &time, QVariant value)
} }
} }
void Exporter::FrameRendered(const rational &time, QVariant value)
{
qDebug() << "Received" << time.toDouble() << "- waiting for" << waiting_for_frame_.toDouble();
const QMap<rational, QByteArray>& time_hash_map = video_backend_->frame_cache()->time_hash_map();
QByteArray map_hash = time_hash_map.value(time);
EncodeFrame(time, value);
QList<rational> matching_times = matched_frames_.value(map_hash);
foreach (const rational& t, matching_times) {
qDebug() << " Also matches" << t;
EncodeFrame(t, value);
}
}
void Exporter::AudioRendered() void Exporter::AudioRendered()
{ {
// Retrieve the audio filename // Retrieve the audio filename
@@ -167,14 +186,28 @@ void Exporter::AudioRendered()
audio_backend_->deleteLater(); audio_backend_->deleteLater();
} }
void Exporter::AudioEncodeComplete()
{
audio_done_ = true;
ExportSucceeded();
}
void Exporter::EncoderOpenedSuccessfully() void Exporter::EncoderOpenedSuccessfully()
{ {
// Invalidate caches // Invalidate caches
if (encoder_->params().video_enabled()) { if (encoder_->params().video_enabled()) {
// First we generate the hashes so we know exactly how many frames we need
video_backend_->SetOperatingMode(VideoRenderWorker::kHashOnly);
connect(video_backend_, &VideoRenderBackend::QueueComplete, this, &Exporter::VideoHashesComplete);
video_backend_->InvalidateCache(0, viewer_node_->Length()); video_backend_->InvalidateCache(0, viewer_node_->Length());
} }
if (encoder_->params().audio_enabled()) { if (encoder_->params().audio_enabled()) {
// We set the audio backend to render the full sequence to the disk
connect(audio_backend_, &AudioRenderBackend::QueueComplete, this, &Exporter::AudioRendered);
audio_backend_->InvalidateCache(0, viewer_node_->Length()); audio_backend_->InvalidateCache(0, viewer_node_->Length());
} }
} }
@@ -190,3 +223,49 @@ void Exporter::EncoderClosed()
emit ProgressChanged(100); emit ProgressChanged(100);
emit ExportEnded(); emit ExportEnded();
} }
void Exporter::VideoHashesComplete()
{
// We've got our hashes, time to kick off actual rendering
disconnect(video_backend_, &VideoRenderBackend::QueueComplete, this, &Exporter::VideoHashesComplete);
// Determine what frames will be hashed
TimeRangeList ranges;
ranges.append(TimeRange(0, viewer_node_->Length()));
QMap<rational, QByteArray>::const_iterator i;
QMap<rational, QByteArray>::iterator j;
// Copy time hash map
QMap<rational, QByteArray> time_hash_map = video_backend_->frame_cache()->time_hash_map();
// Check for any times that share duplicate hashes
for (i=time_hash_map.begin();i!=time_hash_map.end();i++) {
j = time_hash_map.begin();
while (j != time_hash_map.end()) {
if (i != j && i.value() == j.value()) {
// Remove the time range from this and
ranges.RemoveTimeRange(TimeRange(j.key(), j.key() + video_backend_->params().time_base()));
QList<rational> times_with_this_hash = matched_frames_.value(i.value());
times_with_this_hash.append(j.key());
matched_frames_.insert(i.value(), times_with_this_hash);
j = time_hash_map.erase(j);
} else {
j++;
}
}
}
// Set video backend to render mode but NOT hash or download
video_backend_->SetOperatingMode(VideoRenderWorker::kRenderOnly);
video_backend_->SetOnlySignalLastFrameRequested(false);
connect(video_backend_, &VideoRenderBackend::CachedFrameReady, this, &Exporter::FrameRendered);
foreach (const TimeRange& range, ranges) {
video_backend_->InvalidateCache(range.in(), range.out());
}
}
+12
View File
@@ -61,6 +61,8 @@ private:
void ExportFailed(); void ExportFailed();
void EncodeFrame(const rational &time, QVariant value);
ColorProcessorPtr color_processor_; ColorProcessorPtr color_processor_;
Encoder* encoder_; Encoder* encoder_;
@@ -73,17 +75,27 @@ private:
QHash<rational, QVariant> cached_frames_; QHash<rational, QVariant> cached_frames_;
QHash< QByteArray, QList<rational> > matched_frames_;
bool video_done_;
bool audio_done_;
private slots: private slots:
void FrameRendered(const rational& time, QVariant value); void FrameRendered(const rational& time, QVariant value);
void AudioRendered(); void AudioRendered();
void AudioEncodeComplete();
void EncoderOpenedSuccessfully(); void EncoderOpenedSuccessfully();
void EncoderOpenFailed(); void EncoderOpenFailed();
void EncoderClosed(); void EncoderClosed();
void VideoHashesComplete();
}; };
#endif // EXPORTER_H #endif // EXPORTER_H
+2 -4
View File
@@ -141,7 +141,7 @@ void OpenGLBackend::DecompileInternal()
shader_cache_.Clear(); shader_cache_.Clear();
} }
void OpenGLBackend::EmitCachedFrameReady(const QList<rational> &times, const QVariant &value, qint64 job_time) void OpenGLBackend::EmitCachedFrameReady(const rational &time, const QVariant &value, qint64 job_time)
{ {
OpenGLTextureCache::ReferencePtr ref = value.value<OpenGLTextureCache::ReferencePtr>(); OpenGLTextureCache::ReferencePtr ref = value.value<OpenGLTextureCache::ReferencePtr>();
OpenGLTexturePtr tex; OpenGLTexturePtr tex;
@@ -152,9 +152,7 @@ void OpenGLBackend::EmitCachedFrameReady(const QList<rational> &times, const QVa
tex = nullptr; tex = nullptr;
} }
foreach (const rational& t, times) { emit CachedFrameReady(time, QVariant::fromValue(tex), job_time);
emit CachedFrameReady(t, QVariant::fromValue(tex), job_time);
}
} }
OpenGLTexturePtr OpenGLBackend::CopyTexture(OpenGLTexturePtr input) OpenGLTexturePtr OpenGLBackend::CopyTexture(OpenGLTexturePtr input)
+1 -1
View File
@@ -28,7 +28,7 @@ protected:
virtual void DecompileInternal() override; virtual void DecompileInternal() override;
virtual void EmitCachedFrameReady(const QList<rational> &times, const QVariant& value, qint64 job_time) override; virtual void EmitCachedFrameReady(const rational &time, const QVariant& value, qint64 job_time) override;
private: private:
OpenGLTexturePtr CopyTexture(OpenGLTexturePtr input); OpenGLTexturePtr CopyTexture(OpenGLTexturePtr input);
+4 -1
View File
@@ -237,7 +237,10 @@ void RenderBackend::CacheNext()
} }
if (cache_queue_.isEmpty()) { if (cache_queue_.isEmpty()) {
emit QueueComplete(); if (AllProcessorsAreAvailable()) {
emit QueueComplete();
}
return; return;
} }
+1 -2
View File
@@ -89,6 +89,7 @@ protected:
void QueueValueUpdate(); void QueueValueUpdate();
bool AllProcessorsAreAvailable() const;
bool WorkerIsBusy(RenderWorker* worker) const; bool WorkerIsBusy(RenderWorker* worker) const;
void SetWorkerBusyState(RenderWorker* worker, bool busy); void SetWorkerBusyState(RenderWorker* worker, bool busy);
@@ -104,8 +105,6 @@ protected slots:
void QueueRecompile(); void QueueRecompile();
private: private:
bool AllProcessorsAreAvailable() const;
/** /**
* @brief Internal list of RenderProcessThreads * @brief Internal list of RenderProcessThreads
*/ */
+34 -7
View File
@@ -33,7 +33,8 @@
VideoRenderBackend::VideoRenderBackend(QObject *parent) : VideoRenderBackend::VideoRenderBackend(QObject *parent) :
RenderBackend(parent), RenderBackend(parent),
export_mode_(false) operating_mode_(VideoRenderWorker::kHashRenderCache),
only_signal_last_frame_requested_(true)
{ {
} }
@@ -71,12 +72,15 @@ const VideoRenderingParams &VideoRenderBackend::params() const
void VideoRenderBackend::SetParameters(const VideoRenderingParams& params) void VideoRenderBackend::SetParameters(const VideoRenderingParams& params)
{ {
if (!AllProcessorsAreAvailable()) {
qCritical() << "Attempted to set parameters on a backend whose workers are still busy";
return;
}
// Set new parameters // Set new parameters
params_ = params; params_ = params;
// Set params on all processors // Set params on all processors
// FIXME: Undefined behavior if the processors are currently working, this may need to be delayed like the
// recompile signal
foreach (RenderWorker* worker, processors_) { foreach (RenderWorker* worker, processors_) {
static_cast<VideoRenderWorker*>(worker)->SetParameters(params_); static_cast<VideoRenderWorker*>(worker)->SetParameters(params_);
} }
@@ -85,9 +89,23 @@ void VideoRenderBackend::SetParameters(const VideoRenderingParams& params)
RegenerateCacheID(); RegenerateCacheID();
} }
void VideoRenderBackend::SetExportMode(bool enabled) void VideoRenderBackend::SetOperatingMode(const VideoRenderWorker::OperatingMode &mode)
{ {
export_mode_ = enabled; if (!AllProcessorsAreAvailable()) {
qCritical() << "Attempted to set operating mode on a backend whose workers are still busy";
return;
}
operating_mode_ = mode;
foreach (RenderWorker* worker, processors_) {
static_cast<VideoRenderWorker*>(worker)->SetOperatingMode(operating_mode_);
}
}
void VideoRenderBackend::SetOnlySignalLastFrameRequested(bool enabled)
{
only_signal_last_frame_requested_ = enabled;
} }
bool VideoRenderBackend::IsRendered(const rational &time) const bool VideoRenderBackend::IsRendered(const rational &time) const
@@ -121,6 +139,8 @@ void VideoRenderBackend::ConnectWorkerToThis(RenderWorker *processor)
{ {
VideoRenderWorker* video_processor = static_cast<VideoRenderWorker*>(processor); VideoRenderWorker* video_processor = static_cast<VideoRenderWorker*>(processor);
video_processor->SetOperatingMode(operating_mode_);
connect(video_processor, &VideoRenderWorker::CompletedFrame, this, &VideoRenderBackend::ThreadCompletedFrame); connect(video_processor, &VideoRenderWorker::CompletedFrame, this, &VideoRenderBackend::ThreadCompletedFrame);
connect(video_processor, &VideoRenderWorker::HashAlreadyBeingCached, this, &VideoRenderBackend::ThreadSkippedFrame); connect(video_processor, &VideoRenderWorker::HashAlreadyBeingCached, this, &VideoRenderBackend::ThreadSkippedFrame);
connect(video_processor, &VideoRenderWorker::CompletedDownload, this, &VideoRenderBackend::ThreadCompletedDownload); connect(video_processor, &VideoRenderWorker::CompletedDownload, this, &VideoRenderBackend::ThreadCompletedDownload);
@@ -206,8 +226,15 @@ TimeRange VideoRenderBackend::PopNextFrameFromQueue()
void VideoRenderBackend::ThreadCompletedFrame(NodeDependency path, qint64 job_time, QByteArray hash, QVariant value) void VideoRenderBackend::ThreadCompletedFrame(NodeDependency path, qint64 job_time, QByteArray hash, QVariant value)
{ {
if (last_time_requested_ == path.in() || frame_cache_.TimeToHash(last_time_requested_) == hash) { if (!only_signal_last_frame_requested_ || last_time_requested_ == path.in() || frame_cache_.TimeToHash(last_time_requested_) == hash) {
EmitCachedFrameReady({last_time_requested_}, value, job_time); EmitCachedFrameReady(path.in(), value, job_time);
}
if (!(operating_mode_ & VideoRenderWorker::kDownloadOnly)) {
// If we're not downloading, the worker is done here
SetWorkerBusyState(static_cast<RenderWorker*>(sender()), false);
CacheNext();
} }
} }
+12 -7
View File
@@ -29,6 +29,7 @@
#include "render/pixelformat.h" #include "render/pixelformat.h"
#include "render/rendermodes.h" #include "render/rendermodes.h"
#include "videorenderframecache.h" #include "videorenderframecache.h"
#include "videorenderworker.h"
/** /**
* @brief A multithreaded OpenGL based renderer for node systems * @brief A multithreaded OpenGL based renderer for node systems
@@ -53,10 +54,16 @@ public:
*/ */
void SetParameters(const VideoRenderingParams &params); void SetParameters(const VideoRenderingParams &params);
void SetExportMode(bool enabled); void SetOperatingMode(const VideoRenderWorker::OperatingMode& mode);
void SetOnlySignalLastFrameRequested(bool enabled);
bool IsRendered(const rational& time) const; bool IsRendered(const rational& time) const;
VideoRenderFrameCache* frame_cache();
const VideoRenderingParams& params() const;
protected: protected:
/** /**
* @brief Allocate and start the multithreaded backend * @brief Allocate and start the multithreaded backend
@@ -85,10 +92,6 @@ protected:
virtual TimeRange PopNextFrameFromQueue() override; virtual TimeRange PopNextFrameFromQueue() override;
VideoRenderFrameCache* frame_cache();
const VideoRenderingParams& params() const;
/** /**
* @brief Internal function for generating the cache ID * @brief Internal function for generating the cache ID
*/ */
@@ -98,9 +101,9 @@ protected:
virtual void ConnectWorkerToThis(RenderWorker* processor) override; virtual void ConnectWorkerToThis(RenderWorker* processor) override;
virtual void EmitCachedFrameReady(const QList<rational> &times, const QVariant& value, qint64 job_time) = 0; virtual void EmitCachedFrameReady(const rational &time, const QVariant& value, qint64 job_time) = 0;
bool export_mode_; VideoRenderWorker::OperatingMode operating_mode_;
signals: signals:
void CachedFrameReady(const rational& time, QVariant value, qint64 job_time); void CachedFrameReady(const rational& time, QVariant value, qint64 job_time);
@@ -121,6 +124,8 @@ private:
rational last_time_requested_; rational last_time_requested_;
bool only_signal_last_frame_requested_;
private slots: private slots:
void ThreadCompletedFrame(NodeDependency path, qint64 job_time, QByteArray hash, QVariant value); void ThreadCompletedFrame(NodeDependency path, qint64 job_time, QByteArray hash, QVariant value);
void ThreadCompletedDownload(NodeDependency dep, qint64 job_time, QByteArray hash); void ThreadCompletedDownload(NodeDependency dep, qint64 job_time, QByteArray hash);
@@ -109,6 +109,11 @@ QList<rational> VideoRenderFrameCache::FramesWithHash(const QByteArray &hash)
return times; return times;
} }
const QMap<rational, QByteArray> &VideoRenderFrameCache::time_hash_map() const
{
return time_hash_map_;
}
QString VideoRenderFrameCache::CachePathName(const QByteArray &hash) const QString VideoRenderFrameCache::CachePathName(const QByteArray &hash) const
{ {
QDir this_cache_dir = QDir(GetMediaCacheLocation()).filePath(cache_id_); QDir this_cache_dir = QDir(GetMediaCacheLocation()).filePath(cache_id_);
@@ -45,6 +45,8 @@ public:
QList<rational> FramesWithHash(const QByteArray& hash); QList<rational> FramesWithHash(const QByteArray& hash);
const QMap<rational, QByteArray>& time_hash_map() const;
private: private:
QMap<rational, QByteArray> time_hash_map_; QMap<rational, QByteArray> time_hash_map_;
+31 -9
View File
@@ -8,7 +8,8 @@
VideoRenderWorker::VideoRenderWorker(VideoRenderFrameCache *frame_cache, QObject *parent) : VideoRenderWorker::VideoRenderWorker(VideoRenderFrameCache *frame_cache, QObject *parent) :
RenderWorker(parent), RenderWorker(parent),
frame_cache_(frame_cache) frame_cache_(frame_cache),
operating_mode_(kHashRenderCache)
{ {
} }
@@ -22,16 +23,27 @@ NodeValueTable VideoRenderWorker::RenderInternal(const NodeDependency& path, con
{ {
// Get hash of node graph // Get hash of node graph
// We use SHA-1 for speed (benchmarks show it's the fastest hash available to us) // We use SHA-1 for speed (benchmarks show it's the fastest hash available to us)
QCryptographicHash hasher(QCryptographicHash::Sha1); QByteArray hash;
HashNodeRecursively(&hasher, path.node(), path.in()); if (operating_mode_ & kHashOnly) {
QByteArray hash = hasher.result(); QCryptographicHash hasher(QCryptographicHash::Sha1);
HashNodeRecursively(&hasher, path.node(), path.in());
hash = hasher.result();
}
NodeValueTable value; NodeValueTable value;
if (frame_cache_->HasHash(hash)) { if (!(operating_mode_ & kRenderOnly)) {
// Emit only the hash
emit CompletedDownload(path, job_time, hash);
} else if ((operating_mode_ & kHashOnly) && frame_cache_->HasHash(hash)) {
// We've already cached this hash, no need to continue // We've already cached this hash, no need to continue
emit HashAlreadyExists(path, job_time, hash); emit HashAlreadyExists(path, job_time, hash);
} else if (frame_cache_->TryCache(path.in(), hash)) {
} else if (!(operating_mode_ & kHashOnly) || frame_cache_->TryCache(path.in(), hash)) {
// This hash is available for us to cache, start traversing graph // This hash is available for us to cache, start traversing graph
value = ProcessNode(path); value = ProcessNode(path);
@@ -42,17 +54,22 @@ NodeValueTable VideoRenderWorker::RenderInternal(const NodeDependency& path, con
emit CompletedFrame(path, job_time, hash, texture); emit CompletedFrame(path, job_time, hash, texture);
// If we actually have a texture, download it into the disk cache // If we actually have a texture, download it into the disk cache
if (!texture.isNull()) { if ((operating_mode_ & kDownloadOnly) && !texture.isNull()) {
Download(path, hash, texture, frame_cache_->CachePathName(hash)); Download(path, hash, texture, frame_cache_->CachePathName(hash));
} }
frame_cache_->RemoveHashFromCurrentlyCaching(hash); frame_cache_->RemoveHashFromCurrentlyCaching(hash);
// Signal that this job is complete if (operating_mode_ & kDownloadOnly) {
emit CompletedDownload(path, job_time, hash); // Signal that this job is complete
emit CompletedDownload(path, job_time, hash);
}
} else { } else {
// Another thread must be caching this already, nothing to be done // Another thread must be caching this already, nothing to be done
emit HashAlreadyBeingCached(path, job_time, hash); emit HashAlreadyBeingCached(path, job_time, hash);
} }
return value; return value;
@@ -161,6 +178,11 @@ void VideoRenderWorker::SetParameters(const VideoRenderingParams &video_params)
ParametersChangedEvent(); ParametersChangedEvent();
} }
void VideoRenderWorker::SetOperatingMode(const VideoRenderWorker::OperatingMode &mode)
{
operating_mode_ = mode;
}
bool VideoRenderWorker::InitInternal() bool VideoRenderWorker::InitInternal()
{ {
download_buffer_.resize(PixelService::GetBufferSize(video_params().format(), video_params().effective_width(), video_params().effective_height())); download_buffer_.resize(PixelService::GetBufferSize(video_params().format(), video_params().effective_width(), video_params().effective_height()));
+33
View File
@@ -12,10 +12,41 @@
class VideoRenderWorker : public RenderWorker { class VideoRenderWorker : public RenderWorker {
Q_OBJECT Q_OBJECT
public: public:
/**
* @brief VideoRenderWorker uses hashes to recognize frames that are identical to others in the render queue
*
* This mode can modify the behavior of the worker, either to disable hash verification or only generate hashes and
* not render. These are only used in the context of exporting.
*
* These are also flags that can be or'd together, mostly for the convenience of checking which functionalities are
* disabled and enabled.
*/
enum OperatingMode {
/// Generate hashes but don't render or download anything
kHashOnly = 0x1,
/// Render but don't download or hash
kRenderOnly = 0x2,
/// Enable download (NEVER USE THIS ON ITS OWN, this is only here for checking flags, download-only mode makes no sense)
kDownloadOnly = 0x4,
/// Use hash verification and render, but don't cache any frames to disk
kHashAndRenderOnly = 0x3,
/// Render and download, but don't use hash verification
kRenderAndCacheOnly = 0x6,
/// Render and use hashes to identify exact matches (default)
kHashRenderCache = 0x7
};
VideoRenderWorker(VideoRenderFrameCache* frame_cache, QObject* parent = nullptr); VideoRenderWorker(VideoRenderFrameCache* frame_cache, QObject* parent = nullptr);
void SetParameters(const VideoRenderingParams& video_params); void SetParameters(const VideoRenderingParams& video_params);
void SetOperatingMode(const OperatingMode& mode);
signals: signals:
void CompletedFrame(NodeDependency path, qint64 job_time, QByteArray hash, QVariant value); void CompletedFrame(NodeDependency path, qint64 job_time, QByteArray hash, QVariant value);
@@ -57,6 +88,8 @@ private:
QByteArray download_buffer_; QByteArray download_buffer_;
OperatingMode operating_mode_;
private slots: private slots:
}; };