diff --git a/app/codec/decoder.cpp b/app/codec/decoder.cpp index 2672e1b96..77537a079 100644 --- a/app/codec/decoder.cpp +++ b/app/codec/decoder.cpp @@ -57,12 +57,12 @@ void Decoder::set_stream(StreamPtr fs) stream_ = fs; } -FramePtr Decoder::RetrieveVideo(const rational &/*timecode*/) +FramePtr Decoder::RetrieveVideo(const rational &/*timecode*/, const QAtomicInt* cancelled) { return nullptr; } -FramePtr Decoder::RetrieveAudio(const rational &/*timecode*/, const rational &/*length*/, const AudioRenderingParams &/*params*/) +FramePtr Decoder::RetrieveAudio(const rational &/*timecode*/, const rational &/*length*/, const AudioRenderingParams &/*params*/, const QAtomicInt* cancelled) { return nullptr; } @@ -93,7 +93,7 @@ QVector ReceiveListOfAllDecoders() { return decoders; } -bool Decoder::ProbeMedia(Footage *f) +bool Decoder::ProbeMedia(Footage *f, const QAtomicInt* cancelled) { // Check for a valid filename if (f->filename().isEmpty()) { @@ -116,9 +116,13 @@ bool Decoder::ProbeMedia(Footage *f) // Pass Footage through each Decoder's probe function for (int i=0;iProbe(f)) { + if (decoder->Probe(f, cancelled)) { // We found a Decoder, so we can set this media as valid f->set_status(Footage::kReady); @@ -168,13 +172,13 @@ DecoderPtr Decoder::CreateFromID(const QString &id) return nullptr; } -void Decoder::Conform(const AudioRenderingParams ¶ms) +void Decoder::Conform(const AudioRenderingParams ¶ms, const QAtomicInt* cancelled) { Q_UNUSED(params) qCritical() << "Conform called on an audio decoder that does not have a handler for it:" << id(); abort(); } -void Decoder::Index() +void Decoder::Index(const QAtomicInt *cancelled) { } diff --git a/app/codec/decoder.h b/app/codec/decoder.h index 17d13c94a..e613a5c01 100644 --- a/app/codec/decoder.h +++ b/app/codec/decoder.h @@ -91,7 +91,7 @@ public: * TRUE if the Decoder was able to decode this file. FALSE if not. This function should have filled the Footage * object with metadata if it returns TRUE. Otherwise, the Footage object should be untouched. */ - virtual bool Probe(Footage* f) = 0; + virtual bool Probe(Footage* f, const QAtomicInt* cancelled) = 0; /** * @brief Open media/allocate memory @@ -127,7 +127,7 @@ public: * A FramePtr of valid data at this timecode or nullptr if there was nothing to retrieve at the provided timecode or * the media could not be opened. */ - virtual FramePtr RetrieveVideo(const rational& timecode); + virtual FramePtr RetrieveVideo(const rational& timecode, const QAtomicInt* cancelled); /** * @brief Retrieve video frame @@ -153,7 +153,7 @@ public: * A FramePtr of valid data at this timecode of the requested length or nullptr if there was nothing to retrieve at * the provided timecode or the media could not be opened. */ - virtual FramePtr RetrieveAudio(const rational& timecode, const rational& length, const AudioRenderingParams& params); + virtual FramePtr RetrieveAudio(const rational& timecode, const rational& length, const AudioRenderingParams& params, const QAtomicInt* cancelled); virtual bool SupportsVideo(); virtual bool SupportsAudio(); @@ -174,7 +174,7 @@ public: * * Used to determine which frame will be served at a given time, useful for caching. */ - virtual int64_t GetTimestampFromTime(const rational& time) = 0; + virtual int64_t GetTimestampFromTime(const rational& time, const QAtomicInt* cancelled) = 0; /** * @brief Try to probe a Footage file by passing it through all available Decoders @@ -195,7 +195,7 @@ public: * * TRUE if a Decoder was successfully able to parse and probe this file. FALSE if not. */ - static bool ProbeMedia(Footage* f); + static bool ProbeMedia(Footage* f, const QAtomicInt *cancelled); /** * @brief Create a Decoder instance using a Decoder ID @@ -217,7 +217,7 @@ public: * All audio decoders must override this. It's not pure since video decoders don't need to use this, but default * behavior will abort since it should never be called. */ - virtual void Conform(const AudioRenderingParams& params); + virtual void Conform(const AudioRenderingParams& params, const QAtomicInt* cancelled); /** * @brief Create an index for this media @@ -228,7 +228,7 @@ public: * Indexing is slow so it's recommended to do it in a background thread. Index() must be called while the Decoder is * open, and does not automatically call Open() and Close() the Decoder. The caller must call thse manually. */ - virtual void Index(); + virtual void Index(const QAtomicInt* cancelled); protected: bool open_; diff --git a/app/codec/ffmpeg/ffmpegdecoder.cpp b/app/codec/ffmpeg/ffmpegdecoder.cpp index a49ab8fa8..5b47c1970 100644 --- a/app/codec/ffmpeg/ffmpegdecoder.cpp +++ b/app/codec/ffmpeg/ffmpegdecoder.cpp @@ -192,7 +192,7 @@ bool FFmpegDecoder::Open() return true; } -FramePtr FFmpegDecoder::RetrieveVideo(const rational &timecode) +FramePtr FFmpegDecoder::RetrieveVideo(const rational &timecode, const QAtomicInt* cancelled) { if (!open_ && !Open()) { return nullptr; @@ -203,7 +203,7 @@ FramePtr FFmpegDecoder::RetrieveVideo(const rational &timecode) } // Convert timecode to AVStream timebase - int64_t target_ts = GetTimestampFromTime(timecode); + int64_t target_ts = GetTimestampFromTime(timecode, cancelled); if (target_ts < 0) { Error(QStringLiteral("Index failed to produce a valid timestamp")); @@ -318,7 +318,7 @@ FramePtr FFmpegDecoder::RetrieveVideo(const rational &timecode) return nullptr; } -FramePtr FFmpegDecoder::RetrieveAudio(const rational &timecode, const rational &length, const AudioRenderingParams ¶ms) +FramePtr FFmpegDecoder::RetrieveAudio(const rational &timecode, const rational &length, const AudioRenderingParams ¶ms, const QAtomicInt* cancelled) { if (!open_ && !Open()) { return nullptr; @@ -328,9 +328,9 @@ FramePtr FFmpegDecoder::RetrieveAudio(const rational &timecode, const rational & return nullptr; } - Index(); + Index(cancelled); - Conform(params); + Conform(params, cancelled); WaveInput input(GetConformedFilename(params)); @@ -395,7 +395,7 @@ QString FFmpegDecoder::id() return "ffmpeg"; } -int64_t FFmpegDecoder::GetTimestampFromTime(const rational &time) +int64_t FFmpegDecoder::GetTimestampFromTime(const rational &time, const QAtomicInt* cancelled) { if (!open_ && !Open()) { return -1; @@ -408,19 +408,19 @@ int64_t FFmpegDecoder::GetTimestampFromTime(const rational &time) target_ts += avstream_->start_time; // Find closest actual timebase in the file - target_ts = GetClosestTimestampInIndex(target_ts); + target_ts = GetClosestTimestampInIndex(target_ts, cancelled); return target_ts; } -void FFmpegDecoder::Conform(const AudioRenderingParams ¶ms) +void FFmpegDecoder::Conform(const AudioRenderingParams ¶ms, const QAtomicInt* cancelled) { if (avstream_->codecpar->codec_type != AVMEDIA_TYPE_AUDIO) { // Nothing to be done return; } - Index(); + Index(cancelled); // Get indexed WAV file WaveInput input(GetIndexFilename()); @@ -470,6 +470,10 @@ void FFmpegDecoder::Conform(const AudioRenderingParams ¶ms) int input_buffer_sz = input.params().time_to_bytes(1); while (!input.at_end()) { + if (cancelled && *cancelled) { + break; + } + // Read up to one second of audio from WAV file QByteArray read_samples = input.read(input_buffer_sz); @@ -486,6 +490,11 @@ void FFmpegDecoder::Conform(const AudioRenderingParams ¶ms) swr_free(&resampler); conformed_output.close(); input.close(); + + // If we cancelled, the conform didn't finish so remove it + if (cancelled && *cancelled) { + QFile(conformed_fn).remove(); + } } else { qWarning() << "Failed to conform file:" << stream()->footage()->filename(); } @@ -531,7 +540,7 @@ void FFmpegDecoder::ConformInternal(SwrContext* resampler, WaveOutput* output, c output->write(out_samples); } -bool FFmpegDecoder::Probe(Footage *f) +bool FFmpegDecoder::Probe(Footage *f, const QAtomicInt* cancelled) { if (open_) { qWarning() << "Probe must be called while the Decoder is closed"; @@ -648,7 +657,7 @@ bool FFmpegDecoder::Probe(Footage *f) Open(); // Use index to find duration - Index(); + Index(cancelled); // Use last frame index as the duration // FIXME: Does this skip the last frame? @@ -688,7 +697,7 @@ void FFmpegDecoder::Error(const QString &s) Close(); } -void FFmpegDecoder::Index() +void FFmpegDecoder::Index(const QAtomicInt* cancelled) { if (!open_) { qWarning() << "Indexing function tried to run while decoder was closed"; @@ -699,11 +708,11 @@ void FFmpegDecoder::Index() if (stream()->type() == Stream::kVideo) { - ValidateVideoIndex(); + ValidateVideoIndex(cancelled); } else if (stream()->type() == Stream::kAudio) { if (!QFileInfo::exists(GetIndexFilename())) { - UnconditionalAudioIndex(pkt_, frame_); + UnconditionalAudioIndex(pkt_, frame_, cancelled); } } } @@ -746,7 +755,7 @@ QString FFmpegDecoder::GetConformedFilename(const AudioRenderingParams ¶ms) return index_fn; } -void FFmpegDecoder::UnconditionalAudioIndex(AVPacket *pkt, AVFrame *frame) +void FFmpegDecoder::UnconditionalAudioIndex(AVPacket *pkt, AVFrame *frame, const QAtomicInt* cancelled) { // Iterate through each audio frame and extract the PCM data @@ -792,6 +801,11 @@ void FFmpegDecoder::UnconditionalAudioIndex(AVPacket *pkt, AVFrame *frame) if (wave_out.open()) { while (true) { + // Check if we have a `cancelled` ptr and its value + if (cancelled && *cancelled) { + break; + } + ret = GetFrame(pkt, frame); if (ret < 0) { @@ -837,6 +851,11 @@ void FFmpegDecoder::UnconditionalAudioIndex(AVPacket *pkt, AVFrame *frame) } wave_out.close(); + + if (cancelled && *cancelled) { + // Audio index didn't complete, delete it + QFile(GetIndexFilename()).remove(); + } } else { qWarning() << "Failed to open WAVE output for indexing"; } @@ -848,7 +867,7 @@ void FFmpegDecoder::UnconditionalAudioIndex(AVPacket *pkt, AVFrame *frame) Seek(0); } -void FFmpegDecoder::UnconditionalVideoIndex(AVPacket* pkt, AVFrame* frame) +void FFmpegDecoder::UnconditionalVideoIndex(AVPacket* pkt, AVFrame* frame, const QAtomicInt* cancelled) { VideoStreamPtr video_stream = std::static_pointer_cast(stream()); @@ -863,6 +882,11 @@ void FFmpegDecoder::UnconditionalVideoIndex(AVPacket* pkt, AVFrame* frame) int ret; while (true) { + // Check if we have a `cancelled` ptr and its value + if (cancelled && *cancelled) { + break; + } + ret = GetFrame(pkt, frame); if (ret >= 0) { @@ -875,11 +899,16 @@ void FFmpegDecoder::UnconditionalVideoIndex(AVPacket* pkt, AVFrame* frame) } } - video_stream->append_frame_index(VideoStream::kEndTimestamp); + // Check if we have a `cancelled` ptr and its value + if (cancelled && *cancelled) { + video_stream->clear_frame_index(); + } else { + video_stream->append_frame_index(VideoStream::kEndTimestamp); - // Save index to file - if (!video_stream->save_frame_index(GetIndexFilename())) { - qWarning() << QStringLiteral("Failed to save index for %1").arg(stream()->footage()->filename()); + // Save index to file + if (!video_stream->save_frame_index(GetIndexFilename())) { + qWarning() << QStringLiteral("Failed to save index for %1").arg(stream()->footage()->filename()); + } } Seek(0); @@ -930,7 +959,7 @@ int FFmpegDecoder::GetFrame(AVPacket *pkt, AVFrame *frame) return ret; } -int64_t FFmpegDecoder::GetClosestTimestampInIndex(const int64_t &ts) +int64_t FFmpegDecoder::GetClosestTimestampInIndex(const int64_t &ts, const QAtomicInt* cancelled) { VideoStreamPtr video_stream = std::static_pointer_cast(stream()); @@ -942,7 +971,7 @@ int64_t FFmpegDecoder::GetClosestTimestampInIndex(const int64_t &ts) // If not, check if the frame index has been populated if (!video_stream->is_frame_index_ready()) { // If not, make a frame index - ValidateVideoIndex(); + ValidateVideoIndex(cancelled); } video_stream->index_process_lock()->unlock(); @@ -954,6 +983,10 @@ int64_t FFmpegDecoder::GetClosestTimestampInIndex(const int64_t &ts) int64_t closest_ts = -1; do { + if (cancelled && *cancelled) { + return -1; + } + if (index_is_being_created && video_stream->index_process_lock()->tryLock()) { index_is_being_created = false; video_stream->index_process_lock()->unlock(); @@ -969,7 +1002,7 @@ int64_t FFmpegDecoder::GetClosestTimestampInIndex(const int64_t &ts) return closest_ts; } -void FFmpegDecoder::ValidateVideoIndex() +void FFmpegDecoder::ValidateVideoIndex(const QAtomicInt* cancelled) { VideoStreamPtr video_stream = std::static_pointer_cast(stream()); @@ -981,7 +1014,7 @@ void FFmpegDecoder::ValidateVideoIndex() // Reset state Seek(0); - UnconditionalVideoIndex(pkt_, frame_); + UnconditionalVideoIndex(pkt_, frame_, cancelled); Seek(0); } diff --git a/app/codec/ffmpeg/ffmpegdecoder.h b/app/codec/ffmpeg/ffmpegdecoder.h index ff27b63fa..eae48d23b 100644 --- a/app/codec/ffmpeg/ffmpegdecoder.h +++ b/app/codec/ffmpeg/ffmpegdecoder.h @@ -47,25 +47,25 @@ public: // Destructor virtual ~FFmpegDecoder() override; - virtual bool Probe(Footage *f) override; + virtual bool Probe(Footage *f, const QAtomicInt *cancelled) override; virtual bool Open() override; - virtual FramePtr RetrieveVideo(const rational &timecode) override; - virtual FramePtr RetrieveAudio(const rational &timecode, const rational &length, const AudioRenderingParams& params) override; + virtual FramePtr RetrieveVideo(const rational &timecode, const QAtomicInt *cancelled) override; + virtual FramePtr RetrieveAudio(const rational &timecode, const rational &length, const AudioRenderingParams& params, const QAtomicInt *cancelled) override; virtual void Close() override; virtual QString id() override; - virtual int64_t GetTimestampFromTime(const rational& time) override; + virtual int64_t GetTimestampFromTime(const rational& time, const QAtomicInt *cancelled) override; - virtual void Conform(const AudioRenderingParams& params) override; + virtual void Conform(const AudioRenderingParams& params, const QAtomicInt *cancelled) override; virtual bool SupportsVideo() override; virtual bool SupportsAudio() override; void SetMultithreading(bool e); - virtual void Index() override; + virtual void Index(const QAtomicInt *cancelled) override; private: void ConformInternal(SwrContext *resampler, WaveOutput *output, const char *in_data, int in_sample_count); @@ -110,12 +110,12 @@ private: */ QString GetConformedFilename(const AudioRenderingParams ¶ms); - void UnconditionalAudioIndex(AVPacket* pkt, AVFrame* frame); - void UnconditionalVideoIndex(AVPacket* pkt, AVFrame* frame); + void UnconditionalAudioIndex(AVPacket* pkt, AVFrame* frame, const QAtomicInt* cancelled); + void UnconditionalVideoIndex(AVPacket* pkt, AVFrame* frame, const QAtomicInt* cancelled); - int64_t GetClosestTimestampInIndex(const int64_t& ts); + int64_t GetClosestTimestampInIndex(const int64_t& ts, const QAtomicInt *cancelled); - void ValidateVideoIndex(); + void ValidateVideoIndex(const QAtomicInt* cancelled); void Seek(int64_t timestamp); diff --git a/app/codec/oiio/oiiodecoder.cpp b/app/codec/oiio/oiiodecoder.cpp index da179de99..f47de4488 100644 --- a/app/codec/oiio/oiiodecoder.cpp +++ b/app/codec/oiio/oiiodecoder.cpp @@ -38,7 +38,7 @@ QString OIIODecoder::id() return "oiio"; } -bool OIIODecoder::Probe(Footage *f) +bool OIIODecoder::Probe(Footage *f, const QAtomicInt *cancelled) { // We prioritize OIIO over FFmpeg to pick up still images more effectively, but some OIIO decoders (notably OpenJPEG) // will segfault entirely if given unexpected data (an MPEG-4 for instance). To workaround this issue, we use OIIO's @@ -133,7 +133,7 @@ bool OIIODecoder::Open() return true; } -FramePtr OIIODecoder::RetrieveVideo(const rational &timecode) +FramePtr OIIODecoder::RetrieveVideo(const rational &timecode, const QAtomicInt *cancelled) { if (!open_ && !Open()) { return nullptr; @@ -174,7 +174,7 @@ void OIIODecoder::Close() frame_ = nullptr; } -int64_t OIIODecoder::GetTimestampFromTime(const rational &time) +int64_t OIIODecoder::GetTimestampFromTime(const rational &time, const QAtomicInt *cancelled) { Q_UNUSED(time) diff --git a/app/codec/oiio/oiiodecoder.h b/app/codec/oiio/oiiodecoder.h index f4977c40f..4574d7505 100644 --- a/app/codec/oiio/oiiodecoder.h +++ b/app/codec/oiio/oiiodecoder.h @@ -33,15 +33,15 @@ public: virtual QString id() override; - virtual bool Probe(Footage *f) override; + virtual bool Probe(Footage *f, const QAtomicInt* cancelled) override; virtual bool Open() override; - virtual FramePtr RetrieveVideo(const rational &timecode) override; + virtual FramePtr RetrieveVideo(const rational &timecode, const QAtomicInt* cancelled) override; virtual void Close() override; - virtual int64_t GetTimestampFromTime(const rational &time) override; + virtual int64_t GetTimestampFromTime(const rational &time, const QAtomicInt* cancelled) override; virtual bool SupportsVideo() override; diff --git a/app/common/CMakeLists.txt b/app/common/CMakeLists.txt index c4dbe01c2..1d123450b 100644 --- a/app/common/CMakeLists.txt +++ b/app/common/CMakeLists.txt @@ -18,6 +18,7 @@ set(OLIVE_SOURCES ${OLIVE_SOURCES} common/bezier.h common/bezier.cpp + common/cancelableobject.h common/channellayout.h common/clamp.h common/constructors.h diff --git a/app/common/cancelableobject.h b/app/common/cancelableobject.h new file mode 100644 index 000000000..008a97bfe --- /dev/null +++ b/app/common/cancelableobject.h @@ -0,0 +1,26 @@ +#ifndef CANCELABLEOBJECT_H +#define CANCELABLEOBJECT_H + +#include + +class CancelableObject { +public: + CancelableObject() : + cancelled_(false) + { + } + + void Cancel() { + cancelled_ = true; + } + + const QAtomicInt& IsCancelled() const { + return cancelled_; + } + +private: + QAtomicInt cancelled_; + +}; + +#endif // CANCELABLEOBJECT_H diff --git a/app/node/input.cpp b/app/node/input.cpp index 85a211568..77d5c63b9 100644 --- a/app/node/input.cpp +++ b/app/node/input.cpp @@ -86,21 +86,33 @@ QString NodeInput::name() return NodeParam::name(); } -void NodeInput::Load(QXmlStreamReader *reader, QHash& param_ptrs, QList &input_connections, QList& footage_connections) +void NodeInput::Load(QXmlStreamReader *reader, QHash& param_ptrs, QList &input_connections, QList& footage_connections, const QAtomicInt *cancelled) { XMLAttributeLoop(reader, attr) { + if (cancelled && *cancelled) { + return; + } + if (attr.name() == "keyframing") { set_is_keyframing(attr.value() == "1"); } } XMLReadLoop(reader, "input") { + if (cancelled && *cancelled) { + return; + } + if (reader->isStartElement()) { if (reader->name() == "standard") { // Load standard value int val_index = 0; XMLReadLoop(reader, "standard") { + if (cancelled && *cancelled) { + return; + } + if (reader->isStartElement() && reader->name() == "value") { reader->readNext(); @@ -119,8 +131,16 @@ void NodeInput::Load(QXmlStreamReader *reader, QHash& par int track = 0; XMLReadLoop(reader, "keyframes") { + if (cancelled && *cancelled) { + return; + } + if (reader->isStartElement() && reader->name() == "track") { XMLReadLoop(reader, "track") { + if (cancelled && *cancelled) { + return; + } + if (reader->name() == "key") { rational key_time; NodeKeyframe::Type key_type; @@ -129,6 +149,10 @@ void NodeInput::Load(QXmlStreamReader *reader, QHash& par QPointF key_out_handle; XMLAttributeLoop(reader, attr) { + if (cancelled && *cancelled) { + return; + } + if (attr.name() == "time") { key_time = rational::fromString(attr.value().toString()); } else if (attr.name() == "type") { @@ -161,6 +185,10 @@ void NodeInput::Load(QXmlStreamReader *reader, QHash& par } } else if (reader->name() == "connections") { XMLReadLoop(reader, "connections") { + if (cancelled && *cancelled) { + return; + } + if (reader->isStartElement() && reader->name() == "connection") { reader->readNext(); @@ -168,7 +196,7 @@ void NodeInput::Load(QXmlStreamReader *reader, QHash& par } } } else { - LoadInternal(reader, param_ptrs, input_connections, footage_connections); + LoadInternal(reader, param_ptrs, input_connections, footage_connections, cancelled); } } } @@ -242,7 +270,7 @@ const NodeParam::DataType &NodeInput::data_type() const return data_type_; } -void NodeInput::LoadInternal(QXmlStreamReader*, QHash&, QList&, QList&) +void NodeInput::LoadInternal(QXmlStreamReader*, QHash&, QList&, QList&, const QAtomicInt*) { } diff --git a/app/node/input.h b/app/node/input.h index 80f703ba5..6957c7bfc 100644 --- a/app/node/input.h +++ b/app/node/input.h @@ -54,7 +54,7 @@ public: virtual QString name() override; - virtual void Load(QXmlStreamReader* reader, QHash& param_ptrs, QList &input_connections, QList& footage_connections) override; + virtual void Load(QXmlStreamReader* reader, QHash& param_ptrs, QList &input_connections, QList& footage_connections, const QAtomicInt* cancelled) override; virtual void Save(QXmlStreamWriter* writer) const override; @@ -243,7 +243,7 @@ signals: void KeyframeRemoved(NodeKeyframePtr key); protected: - virtual void LoadInternal(QXmlStreamReader* reader, QHash& param_ptrs, QList &input_connections, QList& footage_connections); + virtual void LoadInternal(QXmlStreamReader* reader, QHash& param_ptrs, QList &input_connections, QList& footage_connections, const QAtomicInt* cancelled); virtual void SaveInternal(QXmlStreamWriter* writer) const; diff --git a/app/node/inputarray.cpp b/app/node/inputarray.cpp index 7cc68015f..e7d0e0e01 100644 --- a/app/node/inputarray.cpp +++ b/app/node/inputarray.cpp @@ -164,13 +164,13 @@ void NodeInputArray::RemoveAt(int index) RemoveLast(); } -void NodeInputArray::LoadInternal(QXmlStreamReader *reader, QHash& param_ptrs, QList &input_connections, QList& footage_connections) +void NodeInputArray::LoadInternal(QXmlStreamReader *reader, QHash& param_ptrs, QList &input_connections, QList& footage_connections, const QAtomicInt* cancelled) { if (reader->name() == "subparameters") { XMLReadLoop(reader, "subparameters") { if (reader->name() == "input") { Append(); - At(GetSize() - 1)->Load(reader, param_ptrs, input_connections, footage_connections); + At(GetSize() - 1)->Load(reader, param_ptrs, input_connections, footage_connections, cancelled); } } } diff --git a/app/node/inputarray.h b/app/node/inputarray.h index d4a913164..a0a36d6c1 100644 --- a/app/node/inputarray.h +++ b/app/node/inputarray.h @@ -33,7 +33,7 @@ signals: void SizeChanged(int size); protected: - virtual void LoadInternal(QXmlStreamReader* reader, QHash ¶m_ptrs, QList &input_connections, QList& footage_connections) override; + virtual void LoadInternal(QXmlStreamReader* reader, QHash ¶m_ptrs, QList &input_connections, QList& footage_connections, const QAtomicInt *cancelled) override; virtual void SaveInternal(QXmlStreamWriter* writer) const override; diff --git a/app/node/node.cpp b/app/node/node.cpp index 77d10fac5..38a3b6500 100644 --- a/app/node/node.cpp +++ b/app/node/node.cpp @@ -50,9 +50,13 @@ Node::~Node() } } -void Node::Load(QXmlStreamReader *reader, QHash &output_ptrs, QList& input_connections, QList& footage_connections, const QString& element) +void Node::Load(QXmlStreamReader *reader, QHash &output_ptrs, QList& input_connections, QList& footage_connections, const QAtomicInt* cancelled, const QString& element) { XMLReadLoop(reader, (element.isEmpty() ? "node" : element)) { + if (cancelled && *cancelled) { + return; + } + if (reader->isStartElement()) { if (reader->name() == "input" || reader->name() == "output") { QString param_id; @@ -77,7 +81,7 @@ void Node::Load(QXmlStreamReader *reader, QHash &output_ continue; } - param->Load(reader, output_ptrs, input_connections, footage_connections); + param->Load(reader, output_ptrs, input_connections, footage_connections, cancelled); } } } diff --git a/app/node/node.h b/app/node/node.h index 355b39b50..d14fef691 100644 --- a/app/node/node.h +++ b/app/node/node.h @@ -67,7 +67,7 @@ public: /** * @brief Clear current node variables and replace them with */ - void Load(QXmlStreamReader* reader, QHash& param_ptrs, QList &input_connections, QList& footage_connections, const QString &element = QString()); + void Load(QXmlStreamReader* reader, QHash& param_ptrs, QList &input_connections, QList& footage_connections, const QAtomicInt *cancelled, const QString &element = QString()); /** * @brief Save this node into a text/XML format diff --git a/app/node/output.cpp b/app/node/output.cpp index a19f094c5..dd87ac9c1 100644 --- a/app/node/output.cpp +++ b/app/node/output.cpp @@ -42,9 +42,13 @@ QString NodeOutput::name() return NodeParam::name(); } -void NodeOutput::Load(QXmlStreamReader* reader, QHash& param_ptrs, QList&, QList&) +void NodeOutput::Load(QXmlStreamReader* reader, QHash& param_ptrs, QList&, QList&, const QAtomicInt *cancelled) { XMLAttributeLoop(reader, attr) { + if (cancelled && *cancelled) { + return; + } + if (attr.name() == "ptr") { quintptr saved_ptr = attr.value().toULongLong(); diff --git a/app/node/output.h b/app/node/output.h index 6107aaf50..0bbf594e7 100644 --- a/app/node/output.h +++ b/app/node/output.h @@ -42,7 +42,7 @@ public: virtual QString name() override; - virtual void Load(QXmlStreamReader* reader, QHash& param_ptrs, QList &input_connections, QList& footage_connections) override; + virtual void Load(QXmlStreamReader* reader, QHash& param_ptrs, QList &input_connections, QList& footage_connections, const QAtomicInt* cancelled) override; virtual void Save(QXmlStreamWriter* writer) const override; diff --git a/app/node/param.h b/app/node/param.h index c88b1fb1b..dc6ac7557 100644 --- a/app/node/param.h +++ b/app/node/param.h @@ -242,7 +242,7 @@ public: /** * @brief Load function */ - virtual void Load(QXmlStreamReader* reader, QHash& param_ptrs, QList &input_connections, QList& footage_connections) = 0; + virtual void Load(QXmlStreamReader* reader, QHash& param_ptrs, QList &input_connections, QList& footage_connections, const QAtomicInt* cancelled) = 0; /** * @brief Save function diff --git a/app/project/item/folder/folder.cpp b/app/project/item/folder/folder.cpp index 5f26b0d29..35a516332 100644 --- a/app/project/item/folder/folder.cpp +++ b/app/project/item/folder/folder.cpp @@ -44,15 +44,23 @@ QIcon Folder::icon() return icon::Folder; } -void Folder::Load(QXmlStreamReader *reader, QHash &footage_ptrs, QList& footage_connections) +void Folder::Load(QXmlStreamReader *reader, QHash &footage_ptrs, QList& footage_connections, const QAtomicInt *cancelled) { XMLAttributeLoop(reader, attr) { + if (cancelled && *cancelled) { + return; + } + if (attr.name() == "name") { set_name(attr.value().toString()); } } XMLReadLoop(reader, "folder") { + if (cancelled && *cancelled) { + return; + } + if (reader->isStartElement()) { ItemPtr child; @@ -67,7 +75,7 @@ void Folder::Load(QXmlStreamReader *reader, QHash &footage_ } add_child(child); - child->Load(reader, footage_ptrs, footage_connections); + child->Load(reader, footage_ptrs, footage_connections, cancelled); } } } diff --git a/app/project/item/folder/folder.h b/app/project/item/folder/folder.h index 84e9498a9..145f3cd47 100644 --- a/app/project/item/folder/folder.h +++ b/app/project/item/folder/folder.h @@ -42,7 +42,7 @@ public: virtual QIcon icon() override; - virtual void Load(QXmlStreamReader* reader, QHash &footage_ptrs, QList &footage_connections) override; + virtual void Load(QXmlStreamReader* reader, QHash &footage_ptrs, QList &footage_connections, const QAtomicInt *cancelled) override; virtual void Save(QXmlStreamWriter* writer) const override; diff --git a/app/project/item/footage/footage.cpp b/app/project/item/footage/footage.cpp index ca06e4f04..180a6ce92 100644 --- a/app/project/item/footage/footage.cpp +++ b/app/project/item/footage/footage.cpp @@ -37,7 +37,7 @@ Footage::~Footage() ClearStreams(); } -void Footage::Load(QXmlStreamReader *reader, QHash& footage_ptrs, QList&) +void Footage::Load(QXmlStreamReader *reader, QHash& footage_ptrs, QList&, const QAtomicInt* cancelled) { QXmlStreamAttributes attributes = reader->attributes(); @@ -49,15 +49,23 @@ void Footage::Load(QXmlStreamReader *reader, QHash& footage } } - Decoder::ProbeMedia(this); + Decoder::ProbeMedia(this, cancelled); XMLReadLoop(reader, "footage") { + if (cancelled && *cancelled) { + return; + } + if (reader->isStartElement()) { if (reader->name() == "stream") { int stream_index = -1; quintptr stream_ptr = 0; XMLAttributeLoop(reader, attr) { + if (cancelled && *cancelled) { + return; + } + if (attr.name() == "index") { stream_index = attr.value().toInt(); } else if (attr.name() == "ptr") { diff --git a/app/project/item/footage/footage.h b/app/project/item/footage/footage.h index d5c7def03..42226d64d 100644 --- a/app/project/item/footage/footage.h +++ b/app/project/item/footage/footage.h @@ -63,7 +63,7 @@ public: /** * @brief Load function */ - virtual void Load(QXmlStreamReader* reader, QHash &footage_ptrs, QList &footage_connections) override; + virtual void Load(QXmlStreamReader* reader, QHash &footage_ptrs, QList &footage_connections, const QAtomicInt *cancelled) override; /** * @brief Save function diff --git a/app/project/item/sequence/sequence.cpp b/app/project/item/sequence/sequence.cpp index b6d5dcbe8..edb0b5ab7 100644 --- a/app/project/item/sequence/sequence.cpp +++ b/app/project/item/sequence/sequence.cpp @@ -42,9 +42,13 @@ Sequence::Sequence() AddNode(viewer_output_); } -void Sequence::Load(QXmlStreamReader *reader, QHash &, QList& footage_connections) +void Sequence::Load(QXmlStreamReader *reader, QHash &, QList& footage_connections, const QAtomicInt *cancelled) { XMLAttributeLoop(reader, attr) { + if (cancelled && *cancelled) { + return; + } + if (attr.name() == "name") { set_name(attr.value().toString()); @@ -56,12 +60,20 @@ void Sequence::Load(QXmlStreamReader *reader, QHash &, QLis QList desired_connections; XMLReadLoop(reader, "sequence") { + if (cancelled && *cancelled) { + return; + } + if (reader->isStartElement()) { if (reader->name() == "video") { int video_width, video_height; rational video_timebase; XMLReadLoop(reader, "video") { + if (cancelled && *cancelled) { + return; + } + if (reader->isStartElement()) { if (reader->name() == "width") { reader->readNext(); @@ -125,7 +137,7 @@ void Sequence::Load(QXmlStreamReader *reader, QHash &, QLis } if (node) { - node->Load(reader, output_ptrs, desired_connections, footage_connections, reader->name().toString()); + node->Load(reader, output_ptrs, desired_connections, footage_connections, cancelled, reader->name().toString()); AddNode(node); } diff --git a/app/project/item/sequence/sequence.h b/app/project/item/sequence/sequence.h index 33be50326..c4ad7f4e8 100644 --- a/app/project/item/sequence/sequence.h +++ b/app/project/item/sequence/sequence.h @@ -42,7 +42,7 @@ public: /** * @brief Load function */ - virtual void Load(QXmlStreamReader* reader, QHash &footage_ptrs, QList &footage_connections) override; + virtual void Load(QXmlStreamReader* reader, QHash &footage_ptrs, QList &footage_connections, const QAtomicInt* cancelled) override; /** * @brief Save function diff --git a/app/project/project.cpp b/app/project/project.cpp index 2459a285d..4cb69bd59 100644 --- a/app/project/project.cpp +++ b/app/project/project.cpp @@ -25,7 +25,7 @@ #include "common/xmlreadloop.h" #include "core.h" -#include "dialog/loadsave/loadsave.h" +#include "dialog/progress/progress.h" #include "window/mainwindow/mainwindow.h" Project::Project() @@ -33,7 +33,7 @@ Project::Project() root_.set_project(this); } -void Project::Load(QXmlStreamReader *reader) +void Project::Load(QXmlStreamReader *reader, const QAtomicInt* cancelled) { QHash footage_ptrs; QList footage_connections; @@ -43,7 +43,7 @@ void Project::Load(QXmlStreamReader *reader) if (reader->name() == "folder") { // Assume this folder is our root - root_.Load(reader, footage_ptrs, footage_connections); + root_.Load(reader, footage_ptrs, footage_connections, cancelled); } else if (reader->name() == "colormanagement") { diff --git a/app/project/project.h b/app/project/project.h index 2c32068c0..b7ee369e1 100644 --- a/app/project/project.h +++ b/app/project/project.h @@ -44,7 +44,7 @@ class Project : public QObject public: Project(); - void Load(QXmlStreamReader* reader); + void Load(QXmlStreamReader* reader, const QAtomicInt* cancelled); void Save(QXmlStreamWriter* writer) const;