diff --git a/app/task/export/export.cpp b/app/task/export/export.cpp index ae7446b1c..819d9251e 100644 --- a/app/task/export/export.cpp +++ b/app/task/export/export.cpp @@ -156,7 +156,7 @@ bool ExportTask::Run() return success; } -void ExportTask::FrameDownloaded(FramePtr f, const QByteArray &hash, const QVector ×) +bool ExportTask::FrameDownloaded(FramePtr f, const QByteArray &hash, const QVector ×) { Q_UNUSED(hash) @@ -180,14 +180,19 @@ void ExportTask::FrameDownloaded(FramePtr f, const QByteArray &hash, const QVect // Unfortunately this can't be done in another thread since the frames need to be sent // one after the other chronologically. - encoder_->WriteFrame(time_map_.take(real_time), real_time); + if (!encoder_->WriteFrame(time_map_.take(real_time), real_time)) { + SetError(encoder_->GetError()); + return false; + } frame_time_++; emit ProgressChanged(double(frame_time_) / double(GetTotalNumberOfFrames())); } + + return true; } -void ExportTask::AudioDownloaded(const TimeRange &range, SampleBufferPtr samples) +bool ExportTask::AudioDownloaded(const TimeRange &range, SampleBufferPtr samples) { TimeRange adjusted_range = range; @@ -196,20 +201,33 @@ void ExportTask::AudioDownloaded(const TimeRange &range, SampleBufferPtr samples } if (adjusted_range.in() == audio_time_) { - WriteAudioLoop(adjusted_range, samples); + if (!WriteAudioLoop(adjusted_range, samples)) { + return false; + } } else { audio_map_.insert(adjusted_range, samples); } + + return true; } -void ExportTask::EncodeSubtitle(const SubtitleBlock *sub) +bool ExportTask::EncodeSubtitle(const SubtitleBlock *sub) { - encoder_->WriteSubtitle(sub); + if (!encoder_->WriteSubtitle(sub)) { + SetError(encoder_->GetError()); + return false; + } else { + return true; + } } -void ExportTask::WriteAudioLoop(const TimeRange& time, SampleBufferPtr samples) +bool ExportTask::WriteAudioLoop(const TimeRange& time, SampleBufferPtr samples) { - encoder_->WriteAudio(samples); + if (!encoder_->WriteAudio(samples)) { + SetError(encoder_->GetError()); + return false; + } + audio_time_ = time.out(); for (auto it=audio_map_.begin(); it!=audio_map_.end(); it++) { @@ -221,12 +239,16 @@ void ExportTask::WriteAudioLoop(const TimeRange& time, SampleBufferPtr samples) audio_map_.erase(it); // Call recursively to write the next sample buffer - WriteAudioLoop(t, s); + if (!WriteAudioLoop(t, s)) { + return false; + } // Break out of loop break; } } + + return true; } } diff --git a/app/task/export/export.h b/app/task/export/export.h index f05440a8f..2efade730 100644 --- a/app/task/export/export.h +++ b/app/task/export/export.h @@ -38,11 +38,11 @@ public: protected: virtual bool Run() override; - virtual void FrameDownloaded(FramePtr frame, const QByteArray& hash, const QVector& times) override; + virtual bool FrameDownloaded(FramePtr frame, const QByteArray& hash, const QVector& times) override; - virtual void AudioDownloaded(const TimeRange& range, SampleBufferPtr samples) override; + virtual bool AudioDownloaded(const TimeRange& range, SampleBufferPtr samples) override; - virtual void EncodeSubtitle(const SubtitleBlock *sub) override; + virtual bool EncodeSubtitle(const SubtitleBlock *sub) override; virtual bool TwoStepFrameRendering() const override { @@ -50,7 +50,7 @@ protected: } private: - void WriteAudioLoop(const TimeRange &time, SampleBufferPtr samples); + bool WriteAudioLoop(const TimeRange &time, SampleBufferPtr samples); QHash time_map_; diff --git a/app/task/precache/precachetask.cpp b/app/task/precache/precachetask.cpp index 033b64399..bb1af998f 100644 --- a/app/task/precache/precachetask.cpp +++ b/app/task/precache/precachetask.cpp @@ -85,7 +85,7 @@ bool PreCacheTask::Run() return true; } -void PreCacheTask::FrameDownloaded(FramePtr frame, const QByteArray &hash, const QVector ×) +bool PreCacheTask::FrameDownloaded(FramePtr frame, const QByteArray &hash, const QVector ×) { // Do nothing. Pre-cache essentially just creates more frames in the cache, it doesn't need to do // anything else. @@ -93,14 +93,18 @@ void PreCacheTask::FrameDownloaded(FramePtr frame, const QByteArray &hash, const Q_UNUSED(frame) Q_UNUSED(hash) Q_UNUSED(times) + + return true; } -void PreCacheTask::AudioDownloaded(const TimeRange &range, SampleBufferPtr samples) +bool PreCacheTask::AudioDownloaded(const TimeRange &range, SampleBufferPtr samples) { // Pre-cache doesn't cache any audio Q_UNUSED(range) Q_UNUSED(samples) + + return true; } } diff --git a/app/task/precache/precachetask.h b/app/task/precache/precachetask.h index a9bf6497d..78e153744 100644 --- a/app/task/precache/precachetask.h +++ b/app/task/precache/precachetask.h @@ -38,9 +38,9 @@ public: protected: virtual bool Run() override; - virtual void FrameDownloaded(FramePtr frame, const QByteArray& hash, const QVector& times) override; + virtual bool FrameDownloaded(FramePtr frame, const QByteArray& hash, const QVector& times) override; - virtual void AudioDownloaded(const TimeRange& range, SampleBufferPtr samples) override; + virtual bool AudioDownloaded(const TimeRange& range, SampleBufferPtr samples) override; private: Project* project_; diff --git a/app/task/render/render.cpp b/app/task/render/render.cpp index a9f4dc6b6..f3cd07d5c 100644 --- a/app/task/render/render.cpp +++ b/app/task/render/render.cpp @@ -128,6 +128,8 @@ bool RenderTask::Render(ColorManager* manager, mode, cache, force_size, force_matrix, force_format, force_color_output); } + bool result = true; + // Subtitle loop, loops over all blocks in sequence on all tracks if (!subtitle_range.length().isNull()) { Sequence *sequence = dynamic_cast(viewer_); @@ -163,7 +165,10 @@ bool RenderTask::Render(ColorManager* manager, Block *this_block = this_track->Blocks().at(block_indexes.at(tracks_to_push.at(i))); if (const SubtitleBlock *sub = dynamic_cast(this_block)) { - EncodeSubtitle(sub); + if (!EncodeSubtitle(sub)) { + result = false; + break; + } } block_indexes[tracks_to_push.at(i)]++; @@ -174,8 +179,8 @@ bool RenderTask::Render(ColorManager* manager, finished_watcher_mutex_.lock(); - while (!IsCancelled()) { - while (!finished_watchers_.empty() && !IsCancelled()) { + while (result && !IsCancelled()) { + while (!finished_watchers_.empty() && !IsCancelled() && result) { RenderTicketWatcher* watcher = finished_watchers_.front(); finished_watchers_.pop_front(); @@ -188,7 +193,9 @@ bool RenderTask::Render(ColorManager* manager, TimeRange range = watcher->property("range").value(); - AudioDownloaded(range, watcher->Get().value()); + if (!AudioDownloaded(range, watcher->Get().value())) { + result = false; + } // Don't count audio progress, since it's generally a lot faster than video and is weighted at // 50%, which makes the progress bar look weird to the uninitiated @@ -197,9 +204,11 @@ bool RenderTask::Render(ColorManager* manager, } else if (ticket_type == RenderManager::kTypeVideo && TwoStepFrameRendering()) { - DownloadFrame(&watcher_thread, - watcher->Get().value(), - watcher->property("hash").toByteArray()); + if (!DownloadFrame(&watcher_thread, + watcher->Get().value(), + watcher->property("hash").toByteArray())) { + result = false; + } if (native_progress_signalling_) { progress_counter += 0.5; @@ -210,7 +219,9 @@ bool RenderTask::Render(ColorManager* manager, // Assume single-step video or video download ticket QByteArray rendered_hash = watcher->property("hash").toByteArray(); - FrameDownloaded(watcher->Get().value(), rendered_hash, time_map.value(rendered_hash)); + if (!FrameDownloaded(watcher->Get().value(), rendered_hash, time_map.value(rendered_hash))) { + result = false; + } if (native_progress_signalling_) { double progress_to_add = 1.0; @@ -237,7 +248,7 @@ bool RenderTask::Render(ColorManager* manager, finished_watcher_mutex_.lock(); } - if (IsCancelled()) { + if (IsCancelled() || !result) { break; } @@ -252,7 +263,7 @@ bool RenderTask::Render(ColorManager* manager, finished_watcher_mutex_.unlock(); - if (IsCancelled()) { + if (IsCancelled() || !result) { // Cancel every watcher we created foreach (RenderTicketWatcher* watcher, running_watchers_) { disconnect(watcher, &RenderTicketWatcher::Finished, this, &RenderTask::TicketDone); @@ -263,10 +274,10 @@ bool RenderTask::Render(ColorManager* manager, watcher_thread.quit(); watcher_thread.wait(); - return true; + return result; } -void RenderTask::DownloadFrame(QThread *thread, FramePtr frame, const QByteArray &hash) +bool RenderTask::DownloadFrame(QThread *thread, FramePtr frame, const QByteArray &hash) { RenderTicketWatcher* watcher = new RenderTicketWatcher(); watcher->setProperty("hash", hash); @@ -277,11 +288,15 @@ void RenderTask::DownloadFrame(QThread *thread, FramePtr frame, const QByteArray watcher->SetTicket(RenderManager::instance()->SaveFrameToCache(viewer_->video_frame_cache(), frame, hash)); + + // NOTE: Doesn't reflect the actual return result of SaveFrameToCache + return true; } -void RenderTask::EncodeSubtitle(const SubtitleBlock *subtitle) +bool RenderTask::EncodeSubtitle(const SubtitleBlock *subtitle) { Q_UNUSED(subtitle) + return true; } void RenderTask::PrepareWatcher(RenderTicketWatcher *watcher, QThread *thread) diff --git a/app/task/render/render.h b/app/task/render/render.h index dd1e3fddb..75d6c73c0 100644 --- a/app/task/render/render.h +++ b/app/task/render/render.h @@ -49,13 +49,13 @@ protected: VideoParams::Format force_format = VideoParams::kFormatInvalid, ColorProcessorPtr force_color_output = nullptr); - virtual void DownloadFrame(QThread* thread, FramePtr frame, const QByteArray &hash); + virtual bool DownloadFrame(QThread* thread, FramePtr frame, const QByteArray &hash); - virtual void FrameDownloaded(FramePtr frame, const QByteArray& hash, const QVector& times) = 0; + virtual bool FrameDownloaded(FramePtr frame, const QByteArray& hash, const QVector& times) = 0; - virtual void AudioDownloaded(const TimeRange& range, SampleBufferPtr samples) = 0; + virtual bool AudioDownloaded(const TimeRange& range, SampleBufferPtr samples) = 0; - virtual void EncodeSubtitle(const SubtitleBlock *subtitle); + virtual bool EncodeSubtitle(const SubtitleBlock *subtitle); ViewerOutput* viewer() const {