diff --git a/app/codec/encoder.h b/app/codec/encoder.h index adc20dd19..769299fe8 100644 --- a/app/codec/encoder.h +++ b/app/codec/encoder.h @@ -108,7 +108,7 @@ public: virtual bool WriteFrame(OLIVE_NAMESPACE::FramePtr frame, OLIVE_NAMESPACE::rational time) = 0; virtual void WriteAudio(OLIVE_NAMESPACE::AudioRenderingParams pcm_info, - const QString& pcm_filename, OLIVE_NAMESPACE::TimeRange range) = 0; + const QString& pcm_filename) = 0; virtual void Close() = 0; diff --git a/app/codec/ffmpeg/ffmpegencoder.cpp b/app/codec/ffmpeg/ffmpegencoder.cpp index a95880372..f45e73226 100644 --- a/app/codec/ffmpeg/ffmpegencoder.cpp +++ b/app/codec/ffmpeg/ffmpegencoder.cpp @@ -170,7 +170,7 @@ fail: return success; } -void FFmpegEncoder::WriteAudio(AudioRenderingParams pcm_info, const QString &pcm_filename, TimeRange range) +void FFmpegEncoder::WriteAudio(AudioRenderingParams pcm_info, const QString &pcm_filename) { QFile pcm(pcm_filename); if (pcm.open(QFile::ReadOnly)) { @@ -213,13 +213,6 @@ void FFmpegEncoder::WriteAudio(AudioRenderingParams pcm_info, const QString &pcm // Keep track of sample count to use as each frame's timebase int sample_counter = 0; - // Go to start range if one was set - if (range.in() > 0) { - pcm.seek(pcm_info.time_to_bytes(range.in())); - } - - int end_in_bytes = pcm_info.time_to_bytes(range.out()); - while (true) { // Calculate how many samples should input this frame int64_t samples_needed = av_rescale_rnd(maximum_frame_samples + swr_get_delay(swr_ctx, pcm_info.sample_rate()), @@ -230,11 +223,6 @@ void FFmpegEncoder::WriteAudio(AudioRenderingParams pcm_info, const QString &pcm // Calculate how many bytes this is int max_read = pcm_info.samples_to_bytes(samples_needed); - // Limit read to end time if necessary - if (pcm.pos() + max_read > end_in_bytes) { - max_read = end_in_bytes - pcm.pos(); - } - // Read bytes from PCM QByteArray input_data = pcm.read(max_read); @@ -270,7 +258,7 @@ void FFmpegEncoder::WriteAudio(AudioRenderingParams pcm_info, const QString &pcm } // Break if we've reached the end point - if (pcm.atEnd() || pcm.pos() == end_in_bytes) { + if (pcm.atEnd()) { break; } } diff --git a/app/codec/ffmpeg/ffmpegencoder.h b/app/codec/ffmpeg/ffmpegencoder.h index 1a6e8261c..e22568d97 100644 --- a/app/codec/ffmpeg/ffmpegencoder.h +++ b/app/codec/ffmpeg/ffmpegencoder.h @@ -43,7 +43,7 @@ public: virtual bool WriteFrame(OLIVE_NAMESPACE::FramePtr frame, OLIVE_NAMESPACE::rational time) override; virtual void WriteAudio(OLIVE_NAMESPACE::AudioRenderingParams pcm_info, - const QString& pcm_filename, OLIVE_NAMESPACE::TimeRange range) override; + const QString& pcm_filename) override; virtual void Close() override; diff --git a/app/core.cpp b/app/core.cpp index 62a22c524..0434a06e4 100644 --- a/app/core.cpp +++ b/app/core.cpp @@ -1121,7 +1121,18 @@ void Core::CacheActiveSequence(bool in_out_only) if (p && p->GetConnectedViewer()) { // FIXME: Hardcoded divider... // FIXME: Consider preventing caching the footage viewer - CacheTask* task = new CacheTask(p->GetConnectedViewer(), 2, in_out_only); + VideoRenderingParams vrp(p->GetConnectedViewer()->video_params(), + PixelFormat::instance()->GetConfiguredFormatForMode(RenderMode::kOffline), + RenderMode::kOffline, + 2); + + AudioRenderingParams arp(p->GetConnectedViewer()->audio_params(), + SampleFormat::kInternalFormat); + + CacheTask* task = new CacheTask(p->GetConnectedViewer(), + vrp, + arp, + in_out_only); TaskDialog* dialog = new TaskDialog(task, tr("Caching Sequence"), main_window_); dialog->open(); diff --git a/app/render/backend/renderbackend.cpp b/app/render/backend/renderbackend.cpp index 59434a2b1..e672da19a 100644 --- a/app/render/backend/renderbackend.cpp +++ b/app/render/backend/renderbackend.cpp @@ -34,11 +34,7 @@ OLIVE_NAMESPACE_ENTER RenderBackend::RenderBackend(QObject *parent) : QObject(parent), viewer_node_(nullptr), - audio_mode_(kAudioPreview), - divider_(1), - render_mode_(RenderMode::kOnline), - pix_fmt_(PixelFormat::PIX_FMT_RGBA32F), - sample_fmt_(SampleFormat::SAMPLE_FMT_FLT), + auto_audio_(true), ic_from_conform_(false) { // FIXME: Don't create in CLI mode @@ -91,7 +87,7 @@ void RenderBackend::SetViewerNode(ViewerOutput *viewer_node) this, &RenderBackend::NodeGraphChanged); - if (audio_mode_ == kAudioPreview) { + if (auto_audio_) { // Listen for audio invalidation signals connect(viewer_node_->audio_playback_cache(), &AudioPlaybackCache::Invalidated, @@ -136,24 +132,23 @@ QFuture RenderBackend::RenderFrame(const rational &time, bool clear_qu block_for_update); } -void RenderBackend::SetDivider(const int ÷r) +QFuture RenderBackend::RenderAudio(const TimeRange &r, bool block_for_update) { - divider_ = divider; + return QtConcurrent::run(&audio_pool_.threads, + GetInstanceFromPool(audio_pool_), + &RenderWorker::RenderAudio, + r, + block_for_update); } -void RenderBackend::SetMode(const RenderMode::Mode &mode) +void RenderBackend::SetVideoParams(const VideoRenderingParams ¶ms) { - render_mode_ = mode; + video_params_ = params; } -void RenderBackend::SetPixelFormat(const PixelFormat::Format &pix_fmt) +void RenderBackend::SetAudioParams(const AudioRenderingParams ¶ms) { - pix_fmt_ = pix_fmt; -} - -void RenderBackend::SetSampleFormat(const SampleFormat::Format &sample_fmt) -{ - sample_fmt_ = sample_fmt; + audio_params_ = params; } void RenderBackend::SetVideoDownloadMatrix(const QMatrix4x4 &mat) @@ -161,9 +156,9 @@ void RenderBackend::SetVideoDownloadMatrix(const QMatrix4x4 &mat) video_download_matrix_ = mat; } -void RenderBackend::SetAudioMode(AudioMode e) +void RenderBackend::SetAutomaticAudio(bool e) { - audio_mode_ = e; + auto_audio_ = e; } void RenderBackend::WorkerStartedRenderingAudio(const TimeRange &r) @@ -173,6 +168,23 @@ void RenderBackend::WorkerStartedRenderingAudio(const TimeRange &r) queued_audio_lock_.unlock(); } +QList RenderBackend::SplitRangeIntoChunks(const TimeRange &r) +{ + const int chunk_size = 2; + + QList split_ranges; + + int start_time = qFloor(r.in().toDouble() / static_cast(chunk_size)) * chunk_size; + int end_time = qCeil(r.out().toDouble() / static_cast(chunk_size)) * chunk_size; + + for (int i=start_time; iSetAvailable(false); instance->ProcessQueue(); - instance->SetVideoParams(video_params()); - instance->SetAudioParams(audio_params()); + instance->SetVideoParams(video_params_); + instance->SetAudioParams(audio_params_); instance->SetVideoDownloadMatrix(video_download_matrix_); + instance->SetAudioModeIsPreview(auto_audio_); } void RenderBackend::Close() @@ -198,16 +211,6 @@ void RenderBackend::Close() hash_pool_.Destroy(); } -VideoRenderingParams RenderBackend::video_params() const -{ - return VideoRenderingParams(viewer_node_->video_params(), pix_fmt_, render_mode_, divider_); -} - -AudioRenderingParams RenderBackend::audio_params() const -{ - return AudioRenderingParams(viewer_node_->audio_params(), sample_fmt_); -} - RenderWorker *RenderBackend::GetInstanceFromPool(RenderPool& pool) { RenderWorker* instance = nullptr; @@ -361,15 +364,9 @@ void RenderBackend::AudioInvalidated(const TimeRange& r) } // Split into 2 second chunks, one for each thread - const int chunk_size = 2; + QList split_ranges = SplitRangeIntoChunks(r); - QList split_ranges; - - int start_time = qFloor(r.in().toDouble() / static_cast(chunk_size)) * chunk_size; - int end_time = qCeil(r.out().toDouble() / static_cast(chunk_size)) * chunk_size; - for (int i=start_time; isetFuture(QtConcurrent::run(&audio_pool_.threads, - GetInstanceFromPool(audio_pool_), - &RenderWorker::RenderAudio, - this_range, - audio_mode_ == kAudioPreview)); + watcher->setFuture(RenderAudio(this_range, auto_audio_)); } } diff --git a/app/render/backend/renderbackend.h b/app/render/backend/renderbackend.h index f14a94b45..ced46478a 100644 --- a/app/render/backend/renderbackend.h +++ b/app/render/backend/renderbackend.h @@ -54,26 +54,23 @@ public: */ QFuture RenderFrame(const rational& time, bool clear_queue, bool block_for_update); - void SetDivider(const int& divider); + /** + * @brief Asynchronously generate a chunk of audio + */ + QFuture RenderAudio(const TimeRange& r, bool block_for_update); - void SetMode(const RenderMode::Mode& mode); + void SetVideoParams(const VideoRenderingParams& params); - void SetPixelFormat(const PixelFormat::Format& pix_fmt); - - void SetSampleFormat(const SampleFormat::Format& sample_fmt); + void SetAudioParams(const AudioRenderingParams& params); void SetVideoDownloadMatrix(const QMatrix4x4& mat); - enum AudioMode { - kAudioDisabled, - kAudioPreview, - kAudioRender - }; - - void SetAudioMode(AudioMode e); + void SetAutomaticAudio(bool e); void WorkerStartedRenderingAudio(const TimeRange& r); + static QList SplitRangeIntoChunks(const TimeRange& r); + public slots: void NodeGraphChanged(NodeInput *source); @@ -84,10 +81,6 @@ protected: void Close(); - VideoRenderingParams video_params() const; - - AudioRenderingParams audio_params() const; - private: struct RenderPool { QVector instances; @@ -113,16 +106,14 @@ private: QMutex queued_audio_lock_; TimeRangeList queued_audio_; - AudioMode audio_mode_; + bool auto_audio_; // VIDEO MEMBERS - int divider_; - RenderMode::Mode render_mode_; - PixelFormat::Format pix_fmt_; + VideoRenderingParams video_params_; QMatrix4x4 video_download_matrix_; // AUDIO MEMBERS - SampleFormat::Format sample_fmt_; + AudioRenderingParams audio_params_; QHash< QFutureWatcher*, TimeRange > audio_jobs_; struct ConformWaitInfo { diff --git a/app/render/backend/renderworker.cpp b/app/render/backend/renderworker.cpp index 9310875fd..81ba8334a 100644 --- a/app/render/backend/renderworker.cpp +++ b/app/render/backend/renderworker.cpp @@ -25,6 +25,7 @@ #include "audio/sumsamples.h" #include "config/config.h" #include "node/block/clip/clip.h" +#include "task/conform/conform.h" #include "renderbackend.h" OLIVE_NAMESPACE_ENTER @@ -32,7 +33,8 @@ OLIVE_NAMESPACE_ENTER RenderWorker::RenderWorker(RenderBackend* parent) : parent_(parent), viewer_(nullptr), - available_(true) + available_(true), + audio_mode_is_preview_(false) { } @@ -359,8 +361,51 @@ NodeValue RenderWorker::GetDataFromStream(StreamPtr stream, const TimeRange &inp if (decoder) { if (stream->type() == Stream::kVideo || stream->type() == Stream::kImage) { + + // Return a texture from the derived class return FrameToTexture(decoder, stream, input_time); + } else if (stream->type() == Stream::kAudio) { + + // See if we have a conformed version of this audio + if (!decoder->HasConformedVersion(audio_params())) { + + // If not, check what audio mode we're in + if (audio_mode_is_preview_) { + + // For preview, we report the conform is missing and finish the render without it + // temporarily. The backend that picks up this signal will recache this section once the + // conform is available. + emit AudioConformUnavailable(decoder->stream(), + audio_render_time_, + input_time.out(), + audio_params()); + + } else { + + // For online rendering/export, it's a waste of time to render the audio until we have + // all we need, so we try to handle the conform ourselves + AudioStreamPtr as = std::static_pointer_cast(stream); + + // Check if any other threads are conforming this audio + if (as->try_start_conforming(audio_params())) { + + // If not, conform it ourselves + decoder->ConformAudio(&IsCancelled(), audio_params()); + + } else { + + // If another thread is conforming already, hackily try to wait until it's done. + do { + QThread::msleep(1000); + } while (!as->has_conformed_version(audio_params()) && !IsCancelled()); + + } + } + + } + + if (decoder->HasConformedVersion(audio_params())) { SampleBufferPtr frame = decoder->RetrieveAudio(input_time.in(), input_time.length(), audio_params()); @@ -368,9 +413,6 @@ NodeValue RenderWorker::GetDataFromStream(StreamPtr stream, const TimeRange &inp if (frame) { return NodeValue(NodeParam::kSamples, QVariant::fromValue(frame)); } - } else { - emit AudioConformUnavailable(decoder->stream(), audio_render_time_, - input_time.out(), audio_params()); } } } diff --git a/app/render/backend/renderworker.h b/app/render/backend/renderworker.h index c5c835c68..ebfe74ff1 100644 --- a/app/render/backend/renderworker.h +++ b/app/render/backend/renderworker.h @@ -75,6 +75,11 @@ public: video_download_matrix_ = mat; } + void SetAudioModeIsPreview(bool audio_mode_is_preview) + { + audio_mode_is_preview_ = audio_mode_is_preview; + } + /** * @brief Return a unique ID for the image generated at this time * @@ -166,6 +171,8 @@ private: QHash copy_map_; bool available_; + bool audio_mode_is_preview_; + QMutex lock_; }; diff --git a/app/task/cache/cache.cpp b/app/task/cache/cache.cpp index 35bd1bd79..44b717ae9 100644 --- a/app/task/cache/cache.cpp +++ b/app/task/cache/cache.cpp @@ -27,10 +27,9 @@ OLIVE_NAMESPACE_ENTER -CacheTask::CacheTask(ViewerOutput* viewer, int divider, bool in_out_only) : - RenderTask(viewer), - in_out_only_(in_out_only), - divider_(divider) +CacheTask::CacheTask(ViewerOutput* viewer, const VideoRenderingParams& vparams, const AudioRenderingParams &aparams, bool in_out_only) : + RenderTask(viewer, vparams, aparams), + in_out_only_(in_out_only) { SetTitle(tr("Caching \"%1\"").arg(viewer->media_name())); } @@ -49,7 +48,7 @@ bool CacheTask::Run() } } - Render(range_to_cache, RenderMode::kOffline, QMatrix4x4(), false, divider_); + Render(range_to_cache, QMatrix4x4(), false); return true; } diff --git a/app/task/cache/cache.h b/app/task/cache/cache.h index 9efbd13dd..fce79c154 100644 --- a/app/task/cache/cache.h +++ b/app/task/cache/cache.h @@ -31,7 +31,10 @@ class CacheTask : public RenderTask { Q_OBJECT public: - CacheTask(ViewerOutput* viewer, int divider, bool in_out_only); + CacheTask(ViewerOutput* viewer, + const VideoRenderingParams &vparams, + const AudioRenderingParams &aparams, + bool in_out_only); public slots: virtual bool Run() override; @@ -44,8 +47,6 @@ protected: private: bool in_out_only_; - int divider_; - }; OLIVE_NAMESPACE_EXIT diff --git a/app/task/export/export.cpp b/app/task/export/export.cpp index e57732170..2db6038e3 100644 --- a/app/task/export/export.cpp +++ b/app/task/export/export.cpp @@ -28,7 +28,7 @@ OLIVE_NAMESPACE_ENTER ExportTask::ExportTask(ViewerOutput* viewer_node, ColorManager* color_manager, const ExportParams& params) : - RenderTask(viewer_node), + RenderTask(viewer_node, params.video_params(), params.audio_params()), color_manager_(color_manager), params_(params) { @@ -80,9 +80,14 @@ bool ExportTask::Run() params_.color_transform()); } + if (params_.audio_enabled()) { + audio_data_.SetParameters(audio_params()); + } + + // Start render process TimeRangeList ranges; ranges.InsertTimeRange(range); - Render(ranges, RenderMode::kOnline, mat, true, 1); + Render(ranges, mat, params_.audio_enabled()); bool success = true; @@ -95,6 +100,11 @@ bool ExportTask::Run() } } + if (params_.audio_enabled()) { + // Write audio data now + encoder_->WriteAudio(audio_params(), audio_data_.GetCacheFilename()); + } + encoder_->Close(); encoder_->deleteLater(); @@ -104,8 +114,6 @@ bool ExportTask::Run() void FrameColorConvert(ColorProcessorPtr processor, FramePtr frame) { - qDebug() << "Converting" << frame->timestamp() << "from" << frame->format(); - // OCIO conversion requires a frame in 32F format if (frame->format() != PixelFormat::PIX_FMT_RGBA32F) { frame = PixelFormat::ConvertPixelFormat(frame, PixelFormat::PIX_FMT_RGBA32F); @@ -153,4 +161,17 @@ void ExportTask::FrameDownloaded(const QByteArray &hash, const QLinkedList& times) override; + virtual void AudioDownloaded(const TimeRange& range, SampleBufferPtr samples) override; + private: QHash rendered_frame_; @@ -60,6 +62,8 @@ private: int64_t frame_time_; + AudioPlaybackCache audio_data_; + }; OLIVE_NAMESPACE_EXIT diff --git a/app/task/render/render.cpp b/app/task/render/render.cpp index 6e8d1aaf2..16d88c19e 100644 --- a/app/task/render/render.cpp +++ b/app/task/render/render.cpp @@ -25,10 +25,11 @@ OLIVE_NAMESPACE_ENTER -RenderTask::RenderTask(ViewerOutput* viewer) : - viewer_(viewer) +RenderTask::RenderTask(ViewerOutput* viewer, const VideoRenderingParams &vparams, const AudioRenderingParams &aparams) : + viewer_(viewer), + video_params_(vparams), + audio_params_(aparams) { - } struct TimeHashFuturePair { @@ -46,50 +47,52 @@ struct HashFrameFuturePair { QFuture frame_future; }; +struct RangeSampleFuturePair { + TimeRange range; + QFuture sample_future; +}; + struct HashDownloadFuturePair { QByteArray hash; QFuture download_future; }; -void RenderTask::Render(TimeRangeList range_to_cache, - RenderMode::Mode mode, +void RenderTask::Render(const TimeRangeList& range_to_cache, const QMatrix4x4& mat, - bool audio_enabled, - int divider) + bool audio_enabled) { OpenGLBackend backend; - PixelFormat::Format format = PixelFormat::instance()->GetConfiguredFormatForMode(mode); - - backend.SetAudioMode(audio_enabled ? RenderBackend::kAudioRender : RenderBackend::kAudioDisabled); + backend.SetAutomaticAudio(false); backend.SetViewerNode(viewer_); - backend.SetPixelFormat(format); - backend.SetMode(mode); - backend.SetDivider(divider); - backend.SetSampleFormat(SampleFormat::kInternalFormat); + backend.SetVideoParams(video_params_); + backend.SetAudioParams(audio_params_); backend.SetVideoDownloadMatrix(mat); // Get hashes for each frame QLinkedList hash_list; - while (!range_to_cache.isEmpty()) { - const TimeRange& range = range_to_cache.first(); + { + TimeRangeList range_list = range_to_cache; + while (!range_list.isEmpty()) { + const TimeRange& range = range_list.first(); - const rational& timebase = viewer_->video_params().time_base(); + const rational& timebase = viewer_->video_params().time_base(); - rational time = range.in(); - rational snapped = Timecode::snap_time_to_timebase(time, timebase); - rational next; + rational time = range.in(); + rational snapped = Timecode::snap_time_to_timebase(time, timebase); + rational next; - if (snapped > time) { - next = snapped; - snapped -= timebase; - } else { - next = snapped + timebase; + if (snapped > time) { + next = snapped; + snapped -= timebase; + } else { + next = snapped + timebase; + } + + hash_list.append({snapped, backend.Hash(snapped, false)}); + range_list.RemoveTimeRange(TimeRange(snapped, next)); } - - hash_list.append({snapped, backend.Hash(snapped, false)}); - range_to_cache.RemoveTimeRange(TimeRange(snapped, next)); } // Determine any duplicates @@ -130,12 +133,18 @@ void RenderTask::Render(TimeRangeList range_to_cache, } } + QLinkedList audio_lookup_table; + if (audio_enabled) { + foreach (const TimeRange& r, range_to_cache) { + QList ranges = RenderBackend::SplitRangeIntoChunks(r); + + foreach (const TimeRange& split, ranges) { + audio_lookup_table.append({split, backend.RenderAudio(split, false)}); + } + } + } + // Start downloading frames that have finished - OIIO::TypeDesc output_desc = PixelFormat::GetOIIOTypeDesc(format); - OIIO::ImageSpec output_spec(viewer()->video_params().width() / divider, - viewer()->video_params().height() / divider, - PixelFormat::ChannelCount(format), - output_desc); int counter = 0; int nb_frames = render_lookup_table.size(); @@ -145,8 +154,12 @@ void RenderTask::Render(TimeRangeList range_to_cache, // Iterators QLinkedList::iterator i; QLinkedList::iterator j; + QLinkedList::iterator k; + + while (!render_lookup_table.isEmpty() + || !download_futures.isEmpty() + || !audio_lookup_table.isEmpty()) { - while (!render_lookup_table.isEmpty() || !download_futures.isEmpty()) { i = render_lookup_table.begin(); while (i != render_lookup_table.end()) { @@ -178,7 +191,25 @@ void RenderTask::Render(TimeRangeList range_to_cache, j++; } } + + if (audio_enabled) { + k = audio_lookup_table.begin(); + + while (k != audio_lookup_table.end()) { + if (k->sample_future.isFinished()) { + AudioDownloaded(k->range, k->sample_future.result()); + + k = audio_lookup_table.erase(k); + } else { + k++; + } + } + } } } +void RenderTask::AudioDownloaded(const TimeRange &, SampleBufferPtr) +{ +} + OLIVE_NAMESPACE_EXIT diff --git a/app/task/render/render.h b/app/task/render/render.h index d3a565ac6..4a6889ba3 100644 --- a/app/task/render/render.h +++ b/app/task/render/render.h @@ -31,23 +31,39 @@ OLIVE_NAMESPACE_ENTER class RenderTask : public Task { public: - RenderTask(ViewerOutput* viewer); + RenderTask(ViewerOutput* viewer, const VideoRenderingParams &vparams, const AudioRenderingParams &aparams); protected: - void Render(TimeRangeList range_to_cache, RenderMode::Mode mode, const QMatrix4x4 &mat, bool audio_enabled, int divider); + void Render(const TimeRangeList &range_to_cache, const QMatrix4x4 &mat, bool audio_enabled); + + virtual QFuture DownloadFrame(FramePtr frame, const QByteArray &hash) = 0; + + virtual void FrameDownloaded(const QByteArray& hash, const QLinkedList& times) = 0; + + virtual void AudioDownloaded(const TimeRange& range, SampleBufferPtr samples); ViewerOutput* viewer() const { return viewer_; } - virtual QFuture DownloadFrame(FramePtr frame, const QByteArray &hash) = 0; + VideoRenderingParams video_params() const + { + return video_params_; + } - virtual void FrameDownloaded(const QByteArray& hash, const QLinkedList& times) = 0; + AudioRenderingParams audio_params() const + { + return audio_params_; + } private: ViewerOutput* viewer_; + VideoRenderingParams video_params_; + + AudioRenderingParams audio_params_; + }; OLIVE_NAMESPACE_EXIT diff --git a/app/widget/viewer/viewer.cpp b/app/widget/viewer/viewer.cpp index 459b67d7a..1371aaf64 100644 --- a/app/widget/viewer/viewer.cpp +++ b/app/widget/viewer/viewer.cpp @@ -723,15 +723,15 @@ void ViewerWidget::RendererGeneratedFrameForQueue() void ViewerWidget::UpdateRendererParameters() { - RenderMode::Mode render_mode = RenderMode::kOffline; + renderer_->SetVideoParams(VideoRenderingParams(GetConnectedNode()->video_params(), + GetCurrentPixelFormat(), + RenderMode::kOffline, + divider_)); - renderer_->SetDivider(divider_); - renderer_->SetMode(render_mode); - renderer_->SetPixelFormat(GetCurrentPixelFormat()); + renderer_->SetAudioParams(AudioRenderingParams(GetConnectedNode()->audio_params(), + SampleFormat::kInternalFormat)); display_widget_->SetVideoParams(GetConnectedNode()->video_params()); - - renderer_->SetSampleFormat(SampleFormat::kInternalFormat); } void ViewerWidget::ShowContextMenu(const QPoint &pos)