diff --git a/panels/viewer.cpp b/panels/viewer.cpp index b91c00d07..76d93f1fb 100644 --- a/panels/viewer.cpp +++ b/panels/viewer.cpp @@ -63,7 +63,6 @@ extern "C" { Viewer::Viewer(QWidget *parent) : Panel(parent), playing(false), - just_played_(false), media(nullptr), seq(nullptr), created_sequence(false), @@ -419,7 +418,7 @@ void Viewer::play(bool in_to_out) { playhead_start = seq->playhead; playing = true; - just_played_ = true; + SetAudioWakeObject(this); set_playpause_icon(false); start_msecs = QDateTime::currentMSecsSinceEpoch(); @@ -428,17 +427,14 @@ void Viewer::play(bool in_to_out) { } void Viewer::play_wake() { - if (just_played_) { - start_msecs = QDateTime::currentMSecsSinceEpoch(); - playback_updater.start(); - if (audio_thread != nullptr) audio_thread->notifyReceiver(); - just_played_ = false; - } + start_msecs = QDateTime::currentMSecsSinceEpoch(); + playback_updater.start(); + if (audio_thread != nullptr) audio_thread->notifyReceiver(); } void Viewer::pause() { playing = false; - just_played_ = false; + SetAudioWakeObject(nullptr); set_playpause_icon(true); playback_updater.stop(); playback_speed = 0; @@ -479,11 +475,6 @@ void Viewer::pause() { } } -bool Viewer::WaitingForPlayWake() -{ - return just_played_; -} - void Viewer::update_playhead_timecode(long p) { current_timecode_slider->SetValue(p); } diff --git a/panels/viewer.h b/panels/viewer.h index a96b2a5b6..e4c233d4e 100644 --- a/panels/viewer.h +++ b/panels/viewer.h @@ -71,7 +71,6 @@ public: void seek(long p); void play(bool in_to_out = false); void pause(); - bool WaitingForPlayWake(); bool playing; long playhead_start; qint64 start_msecs; @@ -145,7 +144,6 @@ private: double minimum_zoom; bool playing_in_to_out; long last_playhead; - bool just_played_; void set_zoom_value(double d); void set_sb_max(); void set_playback_speed(int s); diff --git a/rendering/audio.cpp b/rendering/audio.cpp index 02fdbf150..b27e73a98 100644 --- a/rendering/audio.cpp +++ b/rendering/audio.cpp @@ -401,3 +401,23 @@ void combobox_audio_sample_rates(QComboBox *combobox) { combobox->addItem("88200 Hz", 88200); combobox->addItem("96000 Hz", 96000); } + +QObject* audio_wake_object = nullptr; +QMutex audio_wake_mutex; + +QObject* GetAudioWakeObject() +{ + audio_wake_mutex.lock(); + + QObject* wake_object = audio_wake_object; + audio_wake_object = nullptr; + + audio_wake_mutex.unlock(); + + return wake_object; +} + +void SetAudioWakeObject(QObject *o) +{ + audio_wake_object = o; +} diff --git a/rendering/audio.h b/rendering/audio.h index 2a3488b53..42af7975d 100644 --- a/rendering/audio.h +++ b/rendering/audio.h @@ -65,6 +65,9 @@ extern bool audio_rendering; extern int audio_rendering_rate; void clear_audio_ibuffer(); +QObject *GetAudioWakeObject(); +void SetAudioWakeObject(QObject* o); + int current_audio_freq(); bool is_audio_device_set(); diff --git a/rendering/cacher.cpp b/rendering/cacher.cpp index ad79b7463..1b793c186 100644 --- a/rendering/cacher.cpp +++ b/rendering/cacher.cpp @@ -460,8 +460,11 @@ void Cacher::CacheAudioWorker() { } } - QMetaObject::invokeMethod(panel_footage_viewer, "play_wake", Qt::QueuedConnection); - QMetaObject::invokeMethod(panel_sequence_viewer, "play_wake", Qt::QueuedConnection); + // If there's a QObject waiting for audio to be rendered, wake it now + QObject* audio_wake_object = GetAudioWakeObject(); + if (audio_wake_object != nullptr) { + QMetaObject::invokeMethod(audio_wake_object, "play_wake", Qt::QueuedConnection); + } } bool Cacher::IsReversed() diff --git a/rendering/exportthread.cpp b/rendering/exportthread.cpp index bce22158c..abb8e837e 100644 --- a/rendering/exportthread.cpp +++ b/rendering/exportthread.cpp @@ -217,6 +217,8 @@ bool ExportThread::SetupVideo() { } bool ExportThread::SetupAudio() { + // if video is disabled, no setup necessary + if (!params_.audio_enabled) return true; // Find encoder for this codec acodec = avcodec_find_encoder(static_cast(params_.audio_codec)); @@ -375,12 +377,12 @@ void ExportThread::Export() } // If video is enabled, set it up in the container now - if (params_.video_enabled && !SetupVideo()) { + if (!SetupVideo()) { return; } // If audio is enabled, set it up in the container now - if (params_.audio_enabled && !SetupAudio()) { + if (!SetupAudio()) { return; } @@ -423,6 +425,8 @@ void ExportThread::Export() // If we're exporting audio, run compose_audio() which will write mixed audio to the internal audio buffer if (params_.audio_enabled) { + waiting_for_audio_ = true; + SetAudioWakeObject(this); olive::rendering::compose_audio(nullptr, olive::ActiveSequence.get(), 1, true); } @@ -486,6 +490,13 @@ void ExportThread::Export() // If we're exporting audio, copy audio from the buffer into an AVFrame for encoding if (params_.audio_enabled) { + if (waiting_for_audio_) { + waitCond.wait(&mutex); + } + + // Make sure nothing is writing while we're retrieving + audio_write_lock.lock(); + // Check if the count of encoded samples exceeds the current Sequence playhead, in which case we don't need to // encode any audio at this moment while (!interrupt_ && file_audio_samples <= (timecode_secs*params_.audio_sampling_rate)) { @@ -520,6 +531,9 @@ void ExportThread::Export() // Increment by the frame's number of samples file_audio_samples += swr_frame->nb_samples; } + + audio_write_lock.unlock(); + } // Generating encoding statistics (e.g. the time it took to encode this frame/estimated remaining time) @@ -674,6 +688,14 @@ void ExportThread::Interrupt() interrupt_ = true; } +void ExportThread::play_wake() +{ + mutex.lock(); + waiting_for_audio_ = false; + waitCond.wakeAll(); + mutex.unlock(); +} + void ExportThread::wake() { mutex.lock(); waitCond.wakeAll(); diff --git a/rendering/exportthread.h b/rendering/exportthread.h index 3db7288ed..328221727 100644 --- a/rendering/exportthread.h +++ b/rendering/exportthread.h @@ -82,6 +82,8 @@ signals: void ProgressChanged(int value, qint64 remaining_ms); public slots: void Interrupt(); + + void play_wake(); private: bool Encode(AVFormatContext* ofmt_ctx, AVCodecContext* codec_ctx, AVFrame* frame, AVPacket* packet, AVStream* stream); bool SetupVideo(); @@ -124,6 +126,8 @@ private: QWaitCondition waitCond; QString export_error; + + bool waiting_for_audio_; private slots: void wake(); }; diff --git a/rendering/renderfunctions.cpp b/rendering/renderfunctions.cpp index 25db7e8f9..889474e79 100644 --- a/rendering/renderfunctions.cpp +++ b/rendering/renderfunctions.cpp @@ -600,17 +600,6 @@ GLuint olive::rendering::compose_sequence(ComposeSequenceParams ¶ms) { // == END FINAL DRAW ON SEQUENCE BUFFER == } - // prepare gizmos - /* - if ((*params.gizmos) != nullptr - && params.nests.isEmpty() - && ((*params.gizmos) == first_gizmo_effect - || (*params.gizmos) == selected_effect)) { - (*params.gizmos)->gizmo_draw(timecode, coords); // set correct gizmo coords - (*params.gizmos)->gizmo_world_to_screen(); // convert gizmo coords to screen coords - } - */ - glPopMatrix(); } } else { @@ -631,22 +620,6 @@ GLuint olive::rendering::compose_sequence(ComposeSequenceParams ¶ms) { } } - - /* - // visually update all the keyframe values - if (c->sequence == params.seq) { // only if you can currently see them - double ts = (playhead - c->timeline_in(true) + c->clip_in(true))/s->frame_rate; - for (int i=0;ieffects.size();i++) { - EffectPtr e = c->effects.at(i); - for (int j=0;jrow_count();j++) { - EffectRow* r = e->row(j); - for (int k=0;kfieldCount();k++) { - r->field(k)->validate_keyframe_data(ts); - } - } - } - } - */ } } else { params.texture_failed = true; diff --git a/ui/viewerwidget.cpp b/ui/viewerwidget.cpp index b00081370..fa95624cf 100644 --- a/ui/viewerwidget.cpp +++ b/ui/viewerwidget.cpp @@ -229,7 +229,7 @@ void ViewerWidget::frame_update() { } // render the audio - olive::rendering::compose_audio(viewer, viewer->seq.get(), viewer->get_playback_speed(), viewer->WaitingForPlayWake()); + olive::rendering::compose_audio(viewer, viewer->seq.get(), viewer->get_playback_speed(), false); } }