From 61e3641bcc877ac6b1a1155bbbbc043cab425b9a Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Thu, 23 Apr 2020 03:02:04 +1000 Subject: [PATCH] export: fixed bug where null frames never got signalled and hung exporting --- app/codec/encoder.cpp | 4 ++-- app/codec/encoder.h | 4 ++-- app/codec/ffmpeg/ffmpegencoder.cpp | 4 ++-- app/codec/ffmpeg/ffmpegencoder.h | 2 +- app/render/backend/exporter.cpp | 25 +++++++++++++++++++----- app/render/backend/videorenderworker.cpp | 8 ++++++-- 6 files changed, 33 insertions(+), 14 deletions(-) diff --git a/app/codec/encoder.cpp b/app/codec/encoder.cpp index 301232219..26ef71989 100644 --- a/app/codec/encoder.cpp +++ b/app/codec/encoder.cpp @@ -173,10 +173,10 @@ void Encoder::Open() } } -void Encoder::WriteFrame(FramePtr frame) +void Encoder::WriteFrame(FramePtr frame, rational time) { if (open_) { - WriteInternal(frame); + WriteInternal(frame, time); } } diff --git a/app/codec/encoder.h b/app/codec/encoder.h index e5868335b..198697991 100644 --- a/app/codec/encoder.h +++ b/app/codec/encoder.h @@ -103,7 +103,7 @@ public: public slots: void Open(); - void WriteFrame(OLIVE_NAMESPACE::FramePtr frame); + void WriteFrame(OLIVE_NAMESPACE::FramePtr frame, OLIVE_NAMESPACE::rational time); virtual void WriteAudio(OLIVE_NAMESPACE::AudioRenderingParams pcm_info, const QString& pcm_filename, OLIVE_NAMESPACE::TimeRange range) = 0; void Close(); @@ -117,7 +117,7 @@ signals: protected: virtual bool OpenInternal() = 0; - virtual void WriteInternal(FramePtr frame) = 0; + virtual void WriteInternal(FramePtr frame, rational time) = 0; virtual void CloseInternal() = 0; bool IsOpen() const; diff --git a/app/codec/ffmpeg/ffmpegencoder.cpp b/app/codec/ffmpeg/ffmpegencoder.cpp index 7146a0941..24c753acd 100644 --- a/app/codec/ffmpeg/ffmpegencoder.cpp +++ b/app/codec/ffmpeg/ffmpegencoder.cpp @@ -228,7 +228,7 @@ bool FFmpegEncoder::OpenInternal() return true; } -void FFmpegEncoder::WriteInternal(FramePtr frame) +void FFmpegEncoder::WriteInternal(FramePtr frame, rational time) { AVFrame* encoded_frame = av_frame_alloc(); @@ -267,7 +267,7 @@ void FFmpegEncoder::WriteInternal(FramePtr frame) goto fail; } - encoded_frame->pts = qRound(frame->timestamp().toDouble() / av_q2d(video_codec_ctx_->time_base)); + encoded_frame->pts = qRound64(time.toDouble() / av_q2d(video_codec_ctx_->time_base)); WriteAVFrame(encoded_frame, video_codec_ctx_, video_stream_); diff --git a/app/codec/ffmpeg/ffmpegencoder.h b/app/codec/ffmpeg/ffmpegencoder.h index e995cb4ba..8130db773 100644 --- a/app/codec/ffmpeg/ffmpegencoder.h +++ b/app/codec/ffmpeg/ffmpegencoder.h @@ -43,7 +43,7 @@ public slots: protected: virtual bool OpenInternal() override; - virtual void WriteInternal(FramePtr frame) override; + virtual void WriteInternal(FramePtr frame, rational time) override; virtual void CloseInternal() override; private: diff --git a/app/render/backend/exporter.cpp b/app/render/backend/exporter.cpp index e79f21837..5b92a663f 100644 --- a/app/render/backend/exporter.cpp +++ b/app/render/backend/exporter.cpp @@ -87,12 +87,14 @@ void Exporter::Cancel() { if (video_backend_) { video_backend_->CancelQueue(); + video_backend_->Close(); video_backend_->deleteLater(); video_backend_ = nullptr; } if (audio_backend_) { audio_backend_->CancelQueue(); + audio_backend_->Close(); audio_backend_->deleteLater(); audio_backend_ = nullptr; } @@ -150,6 +152,7 @@ void Exporter::ExportSucceeded() } if (video_backend_) { + video_backend_->Close(); video_backend_->deleteLater(); video_backend_ = nullptr; } @@ -185,14 +188,12 @@ void Exporter::EncodeFrame() // Convert color space color_processor_->ConvertFrame(frame); - // Set frame timestamp - frame->set_timestamp(waiting_for_frame_); - // Encode (may require re-associating alpha?) QMetaObject::invokeMethod(encoder_, "WriteFrame", Qt::QueuedConnection, - OLIVE_NS_ARG(FramePtr, frame)); + OLIVE_NS_ARG(FramePtr, frame), + OLIVE_NS_ARG(rational, waiting_for_frame_)); waiting_for_frame_ += params_.video_params().time_base(); @@ -269,7 +270,8 @@ void Exporter::AudioRendered() Q_ARG(const QString&, cache_fn), OLIVE_NS_ARG(TimeRange, export_range_)); - // We don't need the audio backend anymore + // We don't need the audio backend anymorea + audio_backend_->Close(); audio_backend_->deleteLater(); audio_backend_ = nullptr; } @@ -328,6 +330,19 @@ void Exporter::VideoHashesComplete() connect(video_backend_, &VideoRenderBackend::GeneratedFrame, this, &Exporter::FrameRendered); + // Remove duplicate frames from cache invalidation + const QMap& time_hash_map = video_backend_->frame_cache()->time_hash_map(); + QList hashes_already_seen; + QMap::const_iterator i; + + for (i=time_hash_map.begin(); i!=time_hash_map.end(); i++) { + if (hashes_already_seen.contains(i.value())) { + ranges.RemoveTimeRange(TimeRange(i.key(), i.key() + params_.video_params().time_base())); + } else { + hashes_already_seen.append(i.value()); + } + } + foreach (const TimeRange& range, ranges) { video_backend_->InvalidateCache(range); } diff --git a/app/render/backend/videorenderworker.cpp b/app/render/backend/videorenderworker.cpp index 968d826df..ec1a4ad47 100644 --- a/app/render/backend/videorenderworker.cpp +++ b/app/render/backend/videorenderworker.cpp @@ -100,7 +100,7 @@ NodeValueTable VideoRenderWorker::RenderInternal(const NodeDependency& path, con QVariant texture = value.Get(NodeParam::kTexture); // If we actually have a texture, download it into the disk cache - if (!texture.isNull()) { + if (!texture.isNull() || (!(operating_mode_ & kDownloadOnly))) { Download(path.in(), texture, frame_cache_->CachePathName(hash, video_params_.format())); } @@ -371,7 +371,11 @@ void VideoRenderWorker::Download(const rational& time, QVariant texture, QString frame->allocate(); - TextureToBuffer(texture, frame->width(), frame->height(), frame_gen_mat_, frame->data(), frame->linesize_pixels()); + if (texture.isNull()) { + memset(frame->data(), 0, frame->allocated_size()); + } else { + TextureToBuffer(texture, frame->width(), frame->height(), frame_gen_mat_, frame->data(), frame->linesize_pixels()); + } emit GeneratedFrame(time, frame);