implemented audio exporting
The encoder was moved to its own thread and will transcode the PCM from the audio renderer into the chosen codec while the video frames are still received. The implementation isn't perfect and could use some cleaning up, but it is functional at the moment.
This commit is contained in:
@@ -46,4 +46,6 @@ private:
|
||||
SampleFormat format_;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(AudioRenderingParams)
|
||||
|
||||
#endif // AUDIOPARAMS_H
|
||||
|
||||
@@ -22,6 +22,8 @@ public:
|
||||
|
||||
const AudioRenderingParams& params();
|
||||
|
||||
QString CachePathName();
|
||||
|
||||
public slots:
|
||||
virtual void InvalidateCache(const rational &start_range, const rational &end_range) override;
|
||||
|
||||
@@ -37,8 +39,6 @@ protected:
|
||||
|
||||
virtual NodeInput* GetDependentInput() override;
|
||||
|
||||
QString CachePathName();
|
||||
|
||||
virtual bool CanRender() override;
|
||||
|
||||
private:
|
||||
|
||||
@@ -3,12 +3,19 @@
|
||||
#include "render/colormanager.h"
|
||||
#include "render/pixelservice.h"
|
||||
|
||||
Exporter::Exporter(ViewerOutput* viewer, const VideoRenderingParams& params, const QMatrix4x4 &transform, ColorProcessorPtr color_processor, EncoderPtr encoder, QObject* parent) :
|
||||
Exporter::Exporter(ViewerOutput* viewer,
|
||||
const VideoRenderingParams& video_params,
|
||||
const AudioRenderingParams& audio_params,
|
||||
const QMatrix4x4 &transform,
|
||||
ColorProcessorPtr color_processor,
|
||||
Encoder *encoder,
|
||||
QObject* parent) :
|
||||
QObject(parent),
|
||||
video_backend_(nullptr),
|
||||
audio_backend_(nullptr),
|
||||
viewer_node_(viewer),
|
||||
params_(params),
|
||||
video_params_(video_params),
|
||||
audio_params_(audio_params),
|
||||
transform_(transform),
|
||||
color_processor_(color_processor),
|
||||
encoder_(encoder),
|
||||
@@ -35,6 +42,7 @@ void Exporter::StartExporting()
|
||||
|
||||
// Create renderers
|
||||
if (!Initialize()) {
|
||||
SetExportMessage("Failed to initialize exporter");
|
||||
ExportFailed();
|
||||
return;
|
||||
}
|
||||
@@ -42,26 +50,28 @@ void Exporter::StartExporting()
|
||||
video_backend_->SetViewerNode(viewer_node_);
|
||||
video_backend_->SetParameters(VideoRenderingParams(viewer_node_->video_params().width(),
|
||||
viewer_node_->video_params().height(),
|
||||
params_.time_base(),
|
||||
olive::PIX_FMT_RGBA32F,
|
||||
olive::kOnline));
|
||||
video_params_.time_base(),
|
||||
video_params_.format(),
|
||||
video_params_.mode()));
|
||||
video_backend_->SetExportMode(true);
|
||||
video_backend_->Compile();
|
||||
//audio_backend_->SetViewerNode(viewer_node_);
|
||||
//audio_renderer_->SetParameters(AudioRenderingParams(viewer_node_->audio_params(), SAMPLE_FMT_FLT));
|
||||
audio_backend_->SetViewerNode(viewer_node_);
|
||||
audio_backend_->SetParameters(audio_params_);
|
||||
|
||||
// Connect to renderers
|
||||
connect(video_backend_, SIGNAL(CachedFrameReady(const rational&, QVariant)), this, SLOT(FrameRendered(const rational&, QVariant)));
|
||||
connect(audio_backend_, SIGNAL(QueueComplete()), this, SLOT(AudioRendered()));
|
||||
|
||||
// Create renderers
|
||||
waiting_for_frame_ = 0;
|
||||
|
||||
// Open encoder
|
||||
encoder_->Open();
|
||||
// Open encoder and wait for result
|
||||
connect(encoder_, SIGNAL(OpenSucceeded()), this, SLOT(EncoderOpenedSuccessfully()), Qt::QueuedConnection);
|
||||
connect(encoder_, SIGNAL(OpenFailed()), this, SLOT(EncoderOpenFailed()), Qt::QueuedConnection);
|
||||
connect(encoder_, SIGNAL(Closed()), encoder_, SLOT(deleteLater()), Qt::QueuedConnection);
|
||||
|
||||
// Invalidate caches
|
||||
video_backend_->InvalidateCache(0, viewer_node_->Length());
|
||||
//viewer_node_->InvalidateCache(0, viewer_node_->Length(), viewer_node_->samples_input());
|
||||
QMetaObject::invokeMethod(encoder_,
|
||||
"Open",
|
||||
Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
void Exporter::SetExportMessage(const QString &s)
|
||||
@@ -74,14 +84,14 @@ void Exporter::ExportSucceeded()
|
||||
Cleanup();
|
||||
|
||||
video_backend_->deleteLater();
|
||||
audio_backend_->deleteLater();
|
||||
|
||||
export_status_ = true;
|
||||
|
||||
encoder_->Close();
|
||||
connect(encoder_, SIGNAL(Closed()), this, SLOT(EncoderClosed()));
|
||||
|
||||
emit ProgressChanged(100);
|
||||
emit ExportEnded();
|
||||
QMetaObject::invokeMethod(encoder_,
|
||||
"Close",
|
||||
Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
void Exporter::ExportFailed()
|
||||
@@ -121,9 +131,12 @@ void Exporter::FrameRendered(const rational &time, QVariant value)
|
||||
frame->set_timestamp(waiting_for_frame_);
|
||||
|
||||
// Encode (may require re-associating alpha?)
|
||||
encoder_->Write(frame);
|
||||
QMetaObject::invokeMethod(encoder_,
|
||||
"Write",
|
||||
Qt::QueuedConnection,
|
||||
Q_ARG(FramePtr, frame));
|
||||
|
||||
waiting_for_frame_ += params_.time_base();
|
||||
waiting_for_frame_ += video_params_.time_base();
|
||||
|
||||
// Calculate progress
|
||||
int progress = qRound(100.0 * (waiting_for_frame_.toDouble() / viewer_node_->Length().toDouble()));
|
||||
@@ -132,9 +145,48 @@ void Exporter::FrameRendered(const rational &time, QVariant value)
|
||||
} while (cached_frames_.contains(waiting_for_frame_));
|
||||
|
||||
if (waiting_for_frame_ >= viewer_node_->Length()) {
|
||||
ExportSucceeded();
|
||||
S ExportSucceeded();
|
||||
}
|
||||
} else {
|
||||
cached_frames_.insert(time, value);
|
||||
}
|
||||
}
|
||||
|
||||
void Exporter::AudioRendered()
|
||||
{
|
||||
// Retrieve the audio filename
|
||||
QString cache_fn = audio_backend_->CachePathName();
|
||||
|
||||
QMetaObject::invokeMethod(encoder_,
|
||||
"WriteAudio",
|
||||
Qt::QueuedConnection,
|
||||
Q_ARG(const AudioRenderingParams&, audio_backend_->params()),
|
||||
Q_ARG(const QString&, cache_fn));
|
||||
|
||||
// We don't need the audio backend anymore
|
||||
audio_backend_->deleteLater();
|
||||
}
|
||||
|
||||
void Exporter::EncoderOpenedSuccessfully()
|
||||
{
|
||||
// Invalidate caches
|
||||
if (encoder_->params().video_enabled()) {
|
||||
video_backend_->InvalidateCache(0, viewer_node_->Length());
|
||||
}
|
||||
|
||||
if (encoder_->params().audio_enabled()) {
|
||||
audio_backend_->InvalidateCache(0, viewer_node_->Length());
|
||||
}
|
||||
}
|
||||
|
||||
void Exporter::EncoderOpenFailed()
|
||||
{
|
||||
SetExportMessage("Failed to open encoder");
|
||||
ExportFailed();
|
||||
}
|
||||
|
||||
void Exporter::EncoderClosed()
|
||||
{
|
||||
emit ProgressChanged(100);
|
||||
emit ExportEnded();
|
||||
}
|
||||
|
||||
@@ -16,10 +16,11 @@ class Exporter : public QObject
|
||||
Q_OBJECT
|
||||
public:
|
||||
Exporter(ViewerOutput* viewer,
|
||||
const VideoRenderingParams& params,
|
||||
const VideoRenderingParams& video_params,
|
||||
const AudioRenderingParams& audio_params,
|
||||
const QMatrix4x4& transform,
|
||||
ColorProcessorPtr color_processor,
|
||||
EncoderPtr encoder,
|
||||
Encoder* encoder,
|
||||
QObject* parent = nullptr);
|
||||
|
||||
bool GetExportStatus() const;
|
||||
@@ -49,7 +50,8 @@ protected:
|
||||
ViewerOutput* viewer_node_;
|
||||
|
||||
// Export parameters
|
||||
VideoRenderingParams params_;
|
||||
VideoRenderingParams video_params_;
|
||||
AudioRenderingParams audio_params_;
|
||||
|
||||
// Export transform
|
||||
QMatrix4x4 transform_;
|
||||
@@ -61,7 +63,7 @@ private:
|
||||
|
||||
ColorProcessorPtr color_processor_;
|
||||
|
||||
EncoderPtr encoder_;
|
||||
Encoder* encoder_;
|
||||
|
||||
bool export_status_;
|
||||
|
||||
@@ -74,6 +76,14 @@ private:
|
||||
private slots:
|
||||
void FrameRendered(const rational& time, QVariant value);
|
||||
|
||||
void AudioRendered();
|
||||
|
||||
void EncoderOpenedSuccessfully();
|
||||
|
||||
void EncoderOpenFailed();
|
||||
|
||||
void EncoderClosed();
|
||||
|
||||
};
|
||||
|
||||
#endif // EXPORTER_H
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
#include "render/backend/opengl/functions.h"
|
||||
#include "render/pixelservice.h"
|
||||
|
||||
OpenGLExporter::OpenGLExporter(ViewerOutput* viewer, const VideoRenderingParams& params, const QMatrix4x4 &transform, ColorProcessorPtr color_processor, EncoderPtr encoder, QObject* parent) :
|
||||
Exporter(viewer, params, transform, color_processor, encoder, parent)
|
||||
OpenGLExporter::OpenGLExporter(ViewerOutput* viewer, const VideoRenderingParams& video_params, const AudioRenderingParams &audio_params, const QMatrix4x4 &transform, ColorProcessorPtr color_processor, Encoder *encoder, QObject* parent) :
|
||||
Exporter(viewer, video_params, audio_params, transform, color_processor, encoder, parent)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ bool OpenGLExporter::Initialize()
|
||||
buffer_.Create(ctx);
|
||||
|
||||
texture_ = std::make_shared<OpenGLTexture>();
|
||||
texture_->Create(ctx, params_.effective_width(), params_.effective_height(), params_.format());
|
||||
texture_->Create(ctx, video_params_.effective_width(), video_params_.effective_height(), video_params_.format());
|
||||
|
||||
pipeline_ = OpenGLShader::CreateDefault();
|
||||
|
||||
@@ -40,9 +40,9 @@ void OpenGLExporter::Cleanup()
|
||||
FramePtr OpenGLExporter::TextureToFrame(const QVariant& texture)
|
||||
{
|
||||
FramePtr frame = Frame::Create();
|
||||
frame->set_width(params_.width());
|
||||
frame->set_height(params_.height());
|
||||
frame->set_format(params_.format());
|
||||
frame->set_width(video_params_.width());
|
||||
frame->set_height(video_params_.height());
|
||||
frame->set_format(video_params_.format());
|
||||
frame->allocate();
|
||||
|
||||
// Blit for transform if the width/height are different
|
||||
@@ -65,7 +65,7 @@ FramePtr OpenGLExporter::TextureToFrame(const QVariant& texture)
|
||||
buffer_.Attach(texture_);
|
||||
buffer_.Bind();
|
||||
|
||||
PixelFormatInfo format_info = PixelService::GetPixelFormatInfo(params_.format());
|
||||
PixelFormatInfo format_info = PixelService::GetPixelFormatInfo(video_params_.format());
|
||||
|
||||
f->glReadPixels(0,
|
||||
0,
|
||||
|
||||
@@ -11,10 +11,11 @@ class OpenGLExporter : public Exporter
|
||||
{
|
||||
public:
|
||||
OpenGLExporter(ViewerOutput* viewer,
|
||||
const VideoRenderingParams& params,
|
||||
const VideoRenderingParams& video_params,
|
||||
const AudioRenderingParams& audio_params,
|
||||
const QMatrix4x4& transform,
|
||||
ColorProcessorPtr color_processor,
|
||||
EncoderPtr encoder,
|
||||
Encoder* encoder,
|
||||
QObject* parent = nullptr);
|
||||
|
||||
virtual ~OpenGLExporter() override;
|
||||
|
||||
@@ -210,12 +210,16 @@ void RenderBackend::DisconnectViewer(ViewerOutput *node)
|
||||
void RenderBackend::CacheNext()
|
||||
{
|
||||
if (!Init()
|
||||
|| cache_queue_.isEmpty()
|
||||
|| !ViewerIsConnected()
|
||||
|| !CanRender()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (cache_queue_.isEmpty()) {
|
||||
emit QueueComplete();
|
||||
return;
|
||||
}
|
||||
|
||||
if ((input_update_queued_ || recompile_queued_) && !AllProcessorsAreAvailable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -36,6 +36,9 @@ public slots:
|
||||
|
||||
void Decompile();
|
||||
|
||||
signals:
|
||||
void QueueComplete();
|
||||
|
||||
protected:
|
||||
void RegenerateCacheID();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user