viewer: ignore scrub events when time changes programmatically

This commit is contained in:
itsmattkc
2022-08-21 10:03:07 -07:00
parent 92949c50dd
commit b361ba8c51
3 changed files with 52 additions and 29 deletions
+2
View File
@@ -60,6 +60,7 @@ void FootageViewerWidget::ConnectNodeEvent(ViewerOutput *n)
{
super::ConnectNodeEvent(n);
IgnoreNextScrubEvent();
SetTime(cached_timestamps_.value(n, 0));
}
@@ -70,6 +71,7 @@ void FootageViewerWidget::DisconnectNodeEvent(ViewerOutput *n)
super::DisconnectNodeEvent(n);
IgnoreNextScrubEvent();
SetTime(0);
}
+41 -29
View File
@@ -73,7 +73,8 @@ ViewerWidget::ViewerWidget(QWidget *parent) :
recording_(false),
first_requeue_watcher_(nullptr),
enable_audio_scrubbing_(true),
waveform_mode_(kWFAutomatic)
waveform_mode_(kWFAutomatic),
ignore_scrub_(0)
{
// Set up main layout
QVBoxLayout* layout = new QVBoxLayout(this);
@@ -257,6 +258,7 @@ void ViewerWidget::DisconnectNodeEvent(ViewerOutput *n)
disconnect(n, &ViewerOutput::TextureInputChanged, this, &ViewerWidget::UpdateWaveformViewFromMode);
CloseAudioProcessor();
audio_scrub_watchers_.clear();
SetDisplayImage(QVariant());
@@ -487,7 +489,7 @@ void ViewerWidget::DisarmRecording()
void ViewerWidget::UpdateAudioProcessor()
{
if (GetConnectedNode()) {
audio_processor_.Close();
CloseAudioProcessor();
AudioParams ap = GetConnectedNode()->GetAudioParams();
AudioParams packed(OLIVE_CONFIG("AudioOutputSampleRate").toInt(),
@@ -681,30 +683,33 @@ void ViewerWidget::ReceivedAudioBufferForPlayback()
void ViewerWidget::ReceivedAudioBufferForScrubbing()
{
// NOTE: Might be good to organize a queue for this in the event that audio takes a long time to
// keep the scrubbed chunks ordered, similar to the playback_queue_ or audio_playback_queue_
RenderTicketWatcher *watcher = static_cast<RenderTicketWatcher *>(sender());
if (watcher->HasResult()) {
SampleBuffer samples = watcher->Get().value<SampleBuffer>();
if (samples.is_allocated()) {
if (samples.audio_params().channel_count() > 0) {
AudioProcessor::Buffer buf;
int r = audio_processor_.Convert(samples.to_raw_ptrs().data(), samples.sample_count(), &buf);
while (!audio_scrub_watchers_.empty() && audio_scrub_watchers_.front() != watcher) {
audio_scrub_watchers_.pop_front();
}
if (r >= 0) {
if (!buf.empty()) {
QString error;
const QByteArray &packed = buf.at(0);
AudioManager::instance()->ClearBufferedOutput();
if (!AudioManager::instance()->PushToOutput(audio_processor_.to(), packed, &error)) {
Core::instance()->ShowStatusBarMessage(tr("Audio scrubbing failed: %1").arg(error));
if (!audio_scrub_watchers_.empty()) {
if (watcher->HasResult()) {
SampleBuffer samples = watcher->Get().value<SampleBuffer>();
if (samples.is_allocated()) {
if (samples.audio_params().channel_count() > 0) {
AudioProcessor::Buffer buf;
int r = audio_processor_.Convert(samples.to_raw_ptrs().data(), samples.sample_count(), &buf);
if (r >= 0) {
if (!buf.empty()) {
QString error;
const QByteArray &packed = buf.at(0);
AudioManager::instance()->ClearBufferedOutput();
if (!AudioManager::instance()->PushToOutput(audio_processor_.to(), packed, &error)) {
Core::instance()->ShowStatusBarMessage(tr("Audio scrubbing failed: %1").arg(error));
}
AudioMonitor::PushSampleBufferOnAll(samples);
}
AudioMonitor::PushSampleBufferOnAll(samples);
} else {
qCritical() << "Failed to process audio for scrubbing:" << r;
}
} else {
qCritical() << "Failed to process audio for scrubbing:" << r;
}
}
}
@@ -937,16 +942,23 @@ void ViewerWidget::PauseInternal()
void ViewerWidget::PushScrubbedAudio()
{
if (!IsPlaying() && GetConnectedNode() && OLIVE_CONFIG("AudioScrubbing").toBool() && enable_audio_scrubbing_) {
// Get audio src device from renderer
const AudioParams& params = GetConnectedNode()->audio_playback_cache()->GetParameters();
if (ignore_scrub_ > 0) {
ignore_scrub_--;
}
if (params.is_valid()) {
// NOTE: Hardcoded scrubbing interval (20ms)
rational interval = rational(20, 1000);
if (ignore_scrub_ == 0) {
// Get audio src device from renderer
const AudioParams& params = GetConnectedNode()->audio_playback_cache()->GetParameters();
RenderTicketWatcher *watcher = new RenderTicketWatcher();
connect(watcher, &RenderTicketWatcher::Finished, this, &ViewerWidget::ReceivedAudioBufferForScrubbing);
watcher->SetTicket(auto_cacher_.GetRangeOfAudio(TimeRange(GetTime(), GetTime() + interval)));
if (params.is_valid()) {
// NOTE: Hardcoded scrubbing interval (20ms)
rational interval = rational(20, 1000);
RenderTicketWatcher *watcher = new RenderTicketWatcher();
connect(watcher, &RenderTicketWatcher::Finished, this, &ViewerWidget::ReceivedAudioBufferForScrubbing);
audio_scrub_watchers_.push_back(watcher);
watcher->SetTicket(auto_cacher_.GetRangeOfAudio(TimeRange(GetTime(), GetTime() + interval)));
}
}
}
}
+9
View File
@@ -177,6 +177,11 @@ protected:
return display_widget_;
}
void IgnoreNextScrubEvent()
{
ignore_scrub_++;
}
private:
int64_t GetTimestamp() const
{
@@ -281,6 +286,8 @@ private:
static QVector<ViewerWidget*> instances_;
std::list<RenderTicketWatcher*> audio_scrub_watchers_;
bool record_armed_;
bool recording_;
TimelineWidget *recording_callback_;
@@ -297,6 +304,8 @@ private:
QVector<RenderTicketWatcher*> dry_run_watchers_;
int ignore_scrub_;
private slots:
void PlaybackTimerUpdate();