export: fixed bug where null frames never got signalled and hung exporting
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -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;
|
||||
|
||||
@@ -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_);
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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<rational, QByteArray>& time_hash_map = video_backend_->frame_cache()->time_hash_map();
|
||||
QList<QByteArray> hashes_already_seen;
|
||||
QMap<rational, QByteArray>::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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user